summaryrefslogtreecommitdiff
path: root/Utilities
diff options
context:
space:
mode:
authorMyungJoo Ham <myungjoo.ham@samsung.com>2017-10-11 15:16:57 +0900
committerMyungJoo Ham <myungjoo.ham@samsung.com>2017-10-11 15:16:57 +0900
commit915c76ded744c0f5f151402b9fa69f3fd8452573 (patch)
treeca6a387466543248890f346847acaa8343989b22 /Utilities
parent317dbdb79761ef65e45c7358cfc7571c6afa54ad (diff)
downloadcmake-915c76ded744c0f5f151402b9fa69f3fd8452573.tar.gz
cmake-915c76ded744c0f5f151402b9fa69f3fd8452573.tar.bz2
cmake-915c76ded744c0f5f151402b9fa69f3fd8452573.zip
Imported Upstream version 3.9.4upstream/3.9.4
Diffstat (limited to 'Utilities')
-rw-r--r--Utilities/.clang-tidy6
-rw-r--r--Utilities/.gitattributes5
-rw-r--r--Utilities/CMakeLists.txt193
-rw-r--r--Utilities/Doxygen/CMakeLists.txt105
-rw-r--r--Utilities/Doxygen/DeveloperReference/mainpage.dox8
-rw-r--r--Utilities/Doxygen/authors.txt17
-rwxr-xr-xUtilities/Doxygen/doc_makeall.sh.in248
-rw-r--r--Utilities/Doxygen/doxyfile.in36
-rwxr-xr-xUtilities/Git/commit-msg13
-rwxr-xr-xUtilities/Git/pre-commit28
-rwxr-xr-xUtilities/Git/prepare-commit-msg13
-rw-r--r--Utilities/GitSetup/.gitattributes5
-rw-r--r--Utilities/GitSetup/README7
-rw-r--r--Utilities/GitSetup/config9
-rw-r--r--Utilities/GitSetup/config.sample10
-rwxr-xr-xUtilities/GitSetup/git-gerrit-push74
-rwxr-xr-xUtilities/GitSetup/git-gitlab-push177
-rwxr-xr-xUtilities/GitSetup/setup-gerrit15
-rwxr-xr-xUtilities/GitSetup/setup-gitlab140
-rwxr-xr-xUtilities/GitSetup/setup-hooks1
-rwxr-xr-xUtilities/GitSetup/setup-stage9
-rwxr-xr-xUtilities/GitSetup/setup-upstream104
-rw-r--r--Utilities/IWYU/mapping.imp161
-rw-r--r--Utilities/KWIML/.gitattributes1
-rw-r--r--Utilities/KWIML/ABI.h.in492
-rw-r--r--Utilities/KWIML/CMakeLists.txt145
-rw-r--r--Utilities/KWIML/Copyright.txt2
-rw-r--r--Utilities/KWIML/INT.h.in861
-rw-r--r--Utilities/KWIML/README.md36
-rw-r--r--Utilities/KWIML/README.txt29
-rw-r--r--Utilities/KWIML/include/kwiml/abi.h566
-rw-r--r--Utilities/KWIML/include/kwiml/int.h1069
-rw-r--r--Utilities/KWIML/src/kwiml-config.cmake.in1
-rw-r--r--Utilities/KWIML/src/version.h.in59
-rw-r--r--Utilities/KWIML/test/CMakeLists.txt54
-rw-r--r--Utilities/KWIML/test/test.c32
-rw-r--r--Utilities/KWIML/test/test.cxx16
-rw-r--r--Utilities/KWIML/test/test.h31
-rw-r--r--Utilities/KWIML/test/test_ABI_C.c22
-rw-r--r--Utilities/KWIML/test/test_ABI_CXX.cxx22
-rw-r--r--Utilities/KWIML/test/test_ABI_endian.h.in47
-rw-r--r--Utilities/KWIML/test/test_INT_C.c22
-rw-r--r--Utilities/KWIML/test/test_INT_CXX.cxx22
-rw-r--r--Utilities/KWIML/test/test_INT_format.h.in200
-rw-r--r--Utilities/KWIML/test/test_abi_C.c19
-rw-r--r--Utilities/KWIML/test/test_abi_CXX.cxx19
-rw-r--r--Utilities/KWIML/test/test_abi_endian.h41
-rw-r--r--Utilities/KWIML/test/test_include_C.c20
-rw-r--r--Utilities/KWIML/test/test_include_CXX.cxx20
-rw-r--r--Utilities/KWIML/test/test_int_C.c19
-rw-r--r--Utilities/KWIML/test/test_int_CXX.cxx19
-rw-r--r--Utilities/KWIML/test/test_int_format.h203
-rw-r--r--Utilities/KWStyle/CMake.kws.xml.in11
-rw-r--r--Utilities/KWStyle/CMakeFiles.txt.in15
-rw-r--r--Utilities/KWStyle/CMakeLists.txt78
-rw-r--r--Utilities/KWStyle/CMakeMoreChecks.kws.xml.in30
-rw-r--r--Utilities/KWStyle/CMakeOverwrite.txt0
-rw-r--r--Utilities/KWStyle/Headers/CMakeHeader.h11
-rw-r--r--Utilities/Release/Cygwin/CMakeLists.txt25
-rw-r--r--Utilities/Release/Cygwin/README.cygwin.in42
-rwxr-xr-xUtilities/Release/Cygwin/cygwin-package.sh.in90
-rw-r--r--Utilities/Release/Cygwin/cygwin-patch.diff.in0
-rw-r--r--Utilities/Release/Cygwin/cygwin-setup.hint.in5
-rw-r--r--Utilities/Release/README5
-rw-r--r--Utilities/Release/WiX/CMakeLists.txt12
-rw-r--r--Utilities/Release/WiX/CustomAction/CMakeLists.txt13
-rw-r--r--Utilities/Release/WiX/CustomAction/detect_nsis_overwrite.cpp43
-rw-r--r--Utilities/Release/WiX/CustomAction/exports.def2
-rw-r--r--Utilities/Release/WiX/WIX.template.in57
-rw-r--r--Utilities/Release/WiX/cmake_extra_dialog.wxs36
-rw-r--r--Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs21
-rw-r--r--Utilities/Release/WiX/custom_action_dll.wxs.in6
-rw-r--r--Utilities/Release/WiX/install_dir.wxs72
-rw-r--r--Utilities/Release/WiX/patch_desktop_shortcut.xml5
-rw-r--r--Utilities/Release/WiX/patch_path_env.xml26
-rw-r--r--Utilities/Release/WiX/ui_banner.jpgbin0 -> 2607 bytes
-rw-r--r--Utilities/Release/WiX/ui_dialog.jpgbin0 -> 13369 bytes
-rwxr-xr-xUtilities/Release/consolidate-relnotes.bash27
-rw-r--r--Utilities/Release/create-cmake-release.cmake56
-rw-r--r--Utilities/Release/dash2win64_cygwin.cmake27
-rw-r--r--Utilities/Release/dash2win64_release.cmake20
-rw-r--r--Utilities/Release/dashmacmini2_release.cmake22
-rw-r--r--Utilities/Release/dashmacmini5_release.cmake24
-rw-r--r--Utilities/Release/ferrari_sgi64_release.cmake16
-rw-r--r--Utilities/Release/ferrari_sgi_release.cmake11
-rw-r--r--Utilities/Release/hythloth_release.cmake10
-rw-r--r--Utilities/Release/linux64_release.cmake50
-rw-r--r--Utilities/Release/magrathea_release.cmake22
-rw-r--r--Utilities/Release/osx_release.cmake33
-rw-r--r--Utilities/Release/release_cmake.cmake67
-rwxr-xr-xUtilities/Release/release_cmake.sh.in36
-rw-r--r--Utilities/Release/upload_release.cmake15
-rw-r--r--Utilities/Release/v20n250_aix_release.cmake22
-rw-r--r--Utilities/Release/win32_release.cmake33
-rw-r--r--Utilities/Release/win64_release.cmake34
-rw-r--r--Utilities/Scripts/BoostScanDeps.cmake207
-rwxr-xr-xUtilities/Scripts/clang-format.bash117
-rwxr-xr-xUtilities/Scripts/update-curl.bash39
-rwxr-xr-xUtilities/Scripts/update-expat.bash50
-rwxr-xr-xUtilities/Scripts/update-gitsetup.bash20
-rwxr-xr-xUtilities/Scripts/update-kwiml.bash20
-rwxr-xr-xUtilities/Scripts/update-kwsys.bash24
-rwxr-xr-xUtilities/Scripts/update-libarchive.bash31
-rwxr-xr-xUtilities/Scripts/update-liblzma.bash30
-rwxr-xr-xUtilities/Scripts/update-librhash.bash45
-rwxr-xr-xUtilities/Scripts/update-libuv.bash26
-rw-r--r--Utilities/Scripts/update-third-party.bash177
-rwxr-xr-xUtilities/Scripts/update-vim-syntax.bash24
-rwxr-xr-xUtilities/SetupForDevelopment.sh7
-rw-r--r--Utilities/Sphinx/.gitignore1
-rw-r--r--Utilities/Sphinx/CMakeLists.txt195
-rw-r--r--Utilities/Sphinx/apply_qthelp_css_workaround.cmake19
-rw-r--r--Utilities/Sphinx/cmake.py401
-rw-r--r--Utilities/Sphinx/conf.py.in83
-rwxr-xr-xUtilities/Sphinx/create_identifiers.py46
-rw-r--r--Utilities/Sphinx/fixup_qthelp_names.cmake32
-rw-r--r--Utilities/Sphinx/static/cmake-favicon.icobin0 -> 1150 bytes
-rw-r--r--Utilities/Sphinx/static/cmake-logo-16.pngbin0 -> 761 bytes
-rw-r--r--Utilities/Sphinx/static/cmake.css8
-rw-r--r--Utilities/Sphinx/templates/layout.html31
-rw-r--r--Utilities/cmThirdParty.h.in23
-rw-r--r--Utilities/cm_bzlib.h21
-rw-r--r--Utilities/cm_curl.h21
-rw-r--r--Utilities/cm_expat.h21
-rw-r--r--Utilities/cm_jsoncpp_reader.h14
-rw-r--r--Utilities/cm_jsoncpp_value.h14
-rw-r--r--Utilities/cm_jsoncpp_writer.h14
-rw-r--r--Utilities/cm_kwiml.h16
-rw-r--r--Utilities/cm_libarchive.h25
-rw-r--r--Utilities/cm_lzma.h14
-rw-r--r--Utilities/cm_rhash.h14
-rw-r--r--Utilities/cm_uv.h14
-rw-r--r--Utilities/cm_xmlrpc.h21
-rw-r--r--Utilities/cm_zlib.h21
-rw-r--r--Utilities/cmake.m453
-rw-r--r--Utilities/cmbzip2/compress.c2
-rw-r--r--Utilities/cmcompress/cmcompress.h6
-rw-r--r--Utilities/cmcurl/.gitattributes (renamed from Utilities/xml/.gitattributes)0
-rw-r--r--Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake75
-rw-r--r--Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake83
-rw-r--r--Utilities/cmcurl/CMake/CurlSymbolHiding.cmake61
-rw-r--r--Utilities/cmcurl/CMake/CurlTests.c581
-rw-r--r--Utilities/cmcurl/CMake/FindCARES.cmake42
-rw-r--r--Utilities/cmcurl/CMake/FindGSS.cmake289
-rw-r--r--Utilities/cmcurl/CMake/FindLibSSH2.cmake35
-rw-r--r--Utilities/cmcurl/CMake/FindMbedTLS.cmake13
-rw-r--r--Utilities/cmcurl/CMake/FindNGHTTP2.cmake18
-rw-r--r--Utilities/cmcurl/CMake/Macros.cmake95
-rw-r--r--Utilities/cmcurl/CMake/OtherTests.cmake414
-rw-r--r--Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake122
-rw-r--r--Utilities/cmcurl/CMake/Utilities.cmake44
-rw-r--r--Utilities/cmcurl/CMakeLists.txt1977
-rw-r--r--Utilities/cmcurl/COPYING3
-rw-r--r--Utilities/cmcurl/Platforms/WindowsCache.cmake120
-rw-r--r--Utilities/cmcurl/Platforms/config-aix.h483
-rw-r--r--Utilities/cmcurl/Testing/CMakeLists.txt19
-rw-r--r--Utilities/cmcurl/Testing/curlgtk.c95
-rw-r--r--Utilities/cmcurl/Testing/ftpget.c84
-rw-r--r--Utilities/cmcurl/Testing/ftpgetresp.c64
-rw-r--r--Utilities/cmcurl/Testing/ftpupload.c93
-rw-r--r--Utilities/cmcurl/Testing/getinmemory.c83
-rw-r--r--Utilities/cmcurl/Testing/http-post.c35
-rw-r--r--Utilities/cmcurl/Testing/httpput.c100
-rw-r--r--Utilities/cmcurl/Testing/multithread.c70
-rw-r--r--Utilities/cmcurl/Testing/persistant.c53
-rw-r--r--Utilities/cmcurl/Testing/postit2.c92
-rw-r--r--Utilities/cmcurl/Testing/sepheaders.c80
-rw-r--r--Utilities/cmcurl/Testing/simple.c28
-rw-r--r--Utilities/cmcurl/Testing/simplessl.c120
-rw-r--r--Utilities/cmcurl/Testing/testconfig.h.in7
-rw-r--r--Utilities/cmcurl/Testing/win32sockets.c49
-rw-r--r--Utilities/cmcurl/amigaos.c74
-rw-r--r--Utilities/cmcurl/amigaos.h58
-rw-r--r--Utilities/cmcurl/arpa_telnet.h101
-rw-r--r--Utilities/cmcurl/base64.c366
-rw-r--r--Utilities/cmcurl/base64.h28
-rw-r--r--Utilities/cmcurl/ca-bundle.h1
-rw-r--r--Utilities/cmcurl/config.h.in720
-rw-r--r--Utilities/cmcurl/connect.c905
-rw-r--r--Utilities/cmcurl/connect.h46
-rw-r--r--Utilities/cmcurl/content_encoding.c424
-rw-r--r--Utilities/cmcurl/content_encoding.h41
-rw-r--r--Utilities/cmcurl/cookie.c1019
-rw-r--r--Utilities/cmcurl/cookie.h107
-rw-r--r--Utilities/cmcurl/curl/curl.h1644
-rw-r--r--Utilities/cmcurl/curl/curlver.h56
-rw-r--r--Utilities/cmcurl/curl/easy.h81
-rw-r--r--Utilities/cmcurl/curl/mprintf.h80
-rw-r--r--Utilities/cmcurl/curl/multi.h327
-rw-r--r--Utilities/cmcurl/curl/stdcheaders.h34
-rw-r--r--Utilities/cmcurl/curl/types.h1
-rw-r--r--Utilities/cmcurl/curltest.c (renamed from Utilities/cmcurl/Testing/curltest.c)0
-rw-r--r--Utilities/cmcurl/curlx.h107
-rw-r--r--Utilities/cmcurl/dict.c280
-rw-r--r--Utilities/cmcurl/dict.h30
-rw-r--r--Utilities/cmcurl/easy.c895
-rw-r--r--Utilities/cmcurl/easyif.h40
-rw-r--r--Utilities/cmcurl/escape.c181
-rw-r--r--Utilities/cmcurl/escape.h30
-rw-r--r--Utilities/cmcurl/file.c407
-rw-r--r--Utilities/cmcurl/file.h31
-rw-r--r--Utilities/cmcurl/formdata.c1694
-rw-r--r--Utilities/cmcurl/formdata.h97
-rw-r--r--Utilities/cmcurl/ftp.c3865
-rw-r--r--Utilities/cmcurl/ftp.h43
-rw-r--r--Utilities/cmcurl/getenv.c69
-rw-r--r--Utilities/cmcurl/getinfo.c234
-rw-r--r--Utilities/cmcurl/getinfo.h28
-rw-r--r--Utilities/cmcurl/gtls.c640
-rw-r--r--Utilities/cmcurl/gtls.h46
-rw-r--r--Utilities/cmcurl/hash.c315
-rw-r--r--Utilities/cmcurl/hash.h61
-rw-r--r--Utilities/cmcurl/hostares.c307
-rw-r--r--Utilities/cmcurl/hostasyn.c174
-rw-r--r--Utilities/cmcurl/hostip.c636
-rw-r--r--Utilities/cmcurl/hostip.h271
-rw-r--r--Utilities/cmcurl/hostip4.c389
-rw-r--r--Utilities/cmcurl/hostip6.c306
-rw-r--r--Utilities/cmcurl/hostsyn.c138
-rw-r--r--Utilities/cmcurl/hostthre.c840
-rw-r--r--Utilities/cmcurl/http.c2422
-rw-r--r--Utilities/cmcurl/http.h85
-rw-r--r--Utilities/cmcurl/http_chunks.c360
-rw-r--r--Utilities/cmcurl/http_chunks.h104
-rw-r--r--Utilities/cmcurl/http_digest.c504
-rw-r--r--Utilities/cmcurl/http_digest.h58
-rw-r--r--Utilities/cmcurl/http_negotiate.c327
-rw-r--r--Utilities/cmcurl/http_negotiate.h39
-rw-r--r--Utilities/cmcurl/http_ntlm.c1111
-rw-r--r--Utilities/cmcurl/http_ntlm.h146
-rw-r--r--Utilities/cmcurl/if2ip.c134
-rw-r--r--Utilities/cmcurl/if2ip.h67
-rw-r--r--Utilities/cmcurl/include/curl/curl.h2555
-rw-r--r--Utilities/cmcurl/include/curl/curlbuild.h.cmake218
-rw-r--r--Utilities/cmcurl/include/curl/curlrules.h239
-rw-r--r--Utilities/cmcurl/include/curl/curlver.h77
-rw-r--r--Utilities/cmcurl/include/curl/easy.h102
-rw-r--r--Utilities/cmcurl/include/curl/mprintf.h50
-rw-r--r--Utilities/cmcurl/include/curl/multi.h439
-rw-r--r--Utilities/cmcurl/include/curl/stdcheaders.h33
-rw-r--r--Utilities/cmcurl/include/curl/system.h484
-rw-r--r--Utilities/cmcurl/include/curl/typecheck-gcc.h668
-rw-r--r--Utilities/cmcurl/inet_ntoa_r.h44
-rw-r--r--Utilities/cmcurl/inet_ntop.c224
-rw-r--r--Utilities/cmcurl/inet_ntop.h37
-rw-r--r--Utilities/cmcurl/inet_pton.c241
-rw-r--r--Utilities/cmcurl/inet_pton.h42
-rw-r--r--Utilities/cmcurl/krb4.c425
-rw-r--r--Utilities/cmcurl/krb4.h70
-rw-r--r--Utilities/cmcurl/ldap.c702
-rw-r--r--Utilities/cmcurl/ldap.h29
-rw-r--r--Utilities/cmcurl/lib/CMakeLists.txt134
-rw-r--r--Utilities/cmcurl/lib/Makefile.inc80
-rw-r--r--Utilities/cmcurl/lib/amigaos.c77
-rw-r--r--Utilities/cmcurl/lib/amigaos.h39
-rw-r--r--Utilities/cmcurl/lib/arpa_telnet.h104
-rw-r--r--Utilities/cmcurl/lib/asyn-ares.c700
-rw-r--r--Utilities/cmcurl/lib/asyn-thread.c707
-rw-r--r--Utilities/cmcurl/lib/asyn.h168
-rw-r--r--Utilities/cmcurl/lib/base64.c320
-rw-r--r--Utilities/cmcurl/lib/conncache.c360
-rw-r--r--Utilities/cmcurl/lib/conncache.h68
-rw-r--r--Utilities/cmcurl/lib/connect.c1418
-rw-r--r--Utilities/cmcurl/lib/connect.h147
-rw-r--r--Utilities/cmcurl/lib/content_encoding.c431
-rw-r--r--Utilities/cmcurl/lib/content_encoding.h48
-rw-r--r--Utilities/cmcurl/lib/cookie.c1449
-rw-r--r--Utilities/cmcurl/lib/cookie.h104
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.c616
-rw-r--r--Utilities/cmcurl/lib/curl_addrinfo.h110
-rw-r--r--Utilities/cmcurl/lib/curl_base64.h35
-rw-r--r--Utilities/cmcurl/lib/curl_config.h.cmake1006
-rw-r--r--Utilities/cmcurl/lib/curl_des.c63
-rw-r--r--Utilities/cmcurl/lib/curl_des.h34
-rw-r--r--Utilities/cmcurl/lib/curl_endian.c124
-rw-r--r--Utilities/cmcurl/lib/curl_endian.h46
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.c424
-rw-r--r--Utilities/cmcurl/lib/curl_fnmatch.h44
-rw-r--r--Utilities/cmcurl/lib/curl_gethostname.c100
-rw-r--r--Utilities/cmcurl/lib/curl_gethostname.h31
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.c131
-rw-r--r--Utilities/cmcurl/lib/curl_gssapi.h75
-rw-r--r--Utilities/cmcurl/lib/curl_hmac.h67
-rw-r--r--Utilities/cmcurl/lib/curl_ldap.h35
-rw-r--r--Utilities/cmcurl/lib/curl_md4.h35
-rw-r--r--Utilities/cmcurl/lib/curl_md5.h63
-rw-r--r--Utilities/cmcurl/lib/curl_memory.h156
-rw-r--r--Utilities/cmcurl/lib/curl_memrchr.c61
-rw-r--r--Utilities/cmcurl/lib/curl_memrchr.h44
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.c84
-rw-r--r--Utilities/cmcurl/lib/curl_multibyte.h92
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.c794
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_core.h101
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.c431
-rw-r--r--Utilities/cmcurl/lib/curl_ntlm_wb.h38
-rw-r--r--Utilities/cmcurl/lib/curl_printf.h56
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.c307
-rw-r--r--Utilities/cmcurl/lib/curl_rtmp.h33
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.c626
-rw-r--r--Utilities/cmcurl/lib/curl_sasl.h143
-rw-r--r--Utilities/cmcurl/lib/curl_sec.h51
-rw-r--r--Utilities/cmcurl/lib/curl_setup.h773
-rw-r--r--Utilities/cmcurl/lib/curl_setup_once.h551
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.c235
-rw-r--r--Utilities/cmcurl/lib/curl_sspi.h350
-rw-r--r--Utilities/cmcurl/lib/curl_threads.c139
-rw-r--r--Utilities/cmcurl/lib/curl_threads.h63
-rw-r--r--Utilities/cmcurl/lib/curlx.h115
-rw-r--r--Utilities/cmcurl/lib/dict.c278
-rw-r--r--Utilities/cmcurl/lib/dict.h29
-rw-r--r--Utilities/cmcurl/lib/dotdot.c180
-rw-r--r--Utilities/cmcurl/lib/dotdot.h25
-rw-r--r--Utilities/cmcurl/lib/easy.c1139
-rw-r--r--Utilities/cmcurl/lib/easyif.h33
-rw-r--r--Utilities/cmcurl/lib/escape.c242
-rw-r--r--Utilities/cmcurl/lib/escape.h33
-rw-r--r--Utilities/cmcurl/lib/file.c594
-rw-r--r--Utilities/cmcurl/lib/file.h41
-rw-r--r--Utilities/cmcurl/lib/fileinfo.c46
-rw-r--r--Utilities/cmcurl/lib/fileinfo.h37
-rw-r--r--Utilities/cmcurl/lib/formdata.c1595
-rw-r--r--Utilities/cmcurl/lib/formdata.h99
-rw-r--r--Utilities/cmcurl/lib/ftp.c4546
-rw-r--r--Utilities/cmcurl/lib/ftp.h159
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.c1024
-rw-r--r--Utilities/cmcurl/lib/ftplistparser.h41
-rw-r--r--Utilities/cmcurl/lib/getenv.c54
-rw-r--r--Utilities/cmcurl/lib/getinfo.c442
-rw-r--r--Utilities/cmcurl/lib/getinfo.h27
-rw-r--r--Utilities/cmcurl/lib/gopher.c166
-rw-r--r--Utilities/cmcurl/lib/gopher.h29
-rw-r--r--Utilities/cmcurl/lib/hash.c354
-rw-r--r--Utilities/cmcurl/lib/hash.h100
-rw-r--r--Utilities/cmcurl/lib/hmac.c132
-rw-r--r--Utilities/cmcurl/lib/hostasyn.c153
-rw-r--r--Utilities/cmcurl/lib/hostcheck.c150
-rw-r--r--Utilities/cmcurl/lib/hostcheck.h32
-rw-r--r--Utilities/cmcurl/lib/hostip.c884
-rw-r--r--Utilities/cmcurl/lib/hostip.h250
-rw-r--r--Utilities/cmcurl/lib/hostip4.c307
-rw-r--r--Utilities/cmcurl/lib/hostip6.c234
-rw-r--r--Utilities/cmcurl/lib/hostsyn.c107
-rw-r--r--Utilities/cmcurl/lib/http.c3784
-rw-r--r--Utilities/cmcurl/lib/http.h258
-rw-r--r--Utilities/cmcurl/lib/http2.c2236
-rw-r--r--Utilities/cmcurl/lib/http2.h79
-rw-r--r--Utilities/cmcurl/lib/http_chunks.c381
-rw-r--r--Utilities/cmcurl/lib/http_chunks.h91
-rw-r--r--Utilities/cmcurl/lib/http_digest.c180
-rw-r--r--Utilities/cmcurl/lib/http_digest.h42
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.c138
-rw-r--r--Utilities/cmcurl/lib/http_negotiate.h38
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.c238
-rw-r--r--Utilities/cmcurl/lib/http_ntlm.h40
-rw-r--r--Utilities/cmcurl/lib/http_proxy.c656
-rw-r--r--Utilities/cmcurl/lib/http_proxy.h41
-rw-r--r--Utilities/cmcurl/lib/idn_win32.c111
-rw-r--r--Utilities/cmcurl/lib/if2ip.c272
-rw-r--r--Utilities/cmcurl/lib/if2ip.h83
-rw-r--r--Utilities/cmcurl/lib/imap.c2132
-rw-r--r--Utilities/cmcurl/lib/imap.h96
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.c197
-rw-r--r--Utilities/cmcurl/lib/inet_ntop.h38
-rw-r--r--Utilities/cmcurl/lib/inet_pton.c236
-rw-r--r--Utilities/cmcurl/lib/inet_pton.h37
-rw-r--r--Utilities/cmcurl/lib/krb5.c342
-rw-r--r--Utilities/cmcurl/lib/ldap.c1084
-rw-r--r--Utilities/cmcurl/lib/libcurl.rc63
-rw-r--r--Utilities/cmcurl/lib/llist.c193
-rw-r--r--Utilities/cmcurl/lib/llist.h54
-rw-r--r--Utilities/cmcurl/lib/md4.c307
-rw-r--r--Utilities/cmcurl/lib/md5.c563
-rw-r--r--Utilities/cmcurl/lib/memdebug.c484
-rw-r--r--Utilities/cmcurl/lib/memdebug.h173
-rw-r--r--Utilities/cmcurl/lib/mprintf.c1177
-rw-r--r--Utilities/cmcurl/lib/multi.c3131
-rw-r--r--Utilities/cmcurl/lib/multihandle.h155
-rw-r--r--Utilities/cmcurl/lib/multiif.h99
-rw-r--r--Utilities/cmcurl/lib/netrc.c201
-rw-r--r--Utilities/cmcurl/lib/netrc.h36
-rw-r--r--Utilities/cmcurl/lib/non-ascii.c338
-rw-r--r--Utilities/cmcurl/lib/non-ascii.h63
-rw-r--r--Utilities/cmcurl/lib/nonblock.c90
-rw-r--r--Utilities/cmcurl/lib/nonblock.h31
-rw-r--r--Utilities/cmcurl/lib/nwlib.c327
-rw-r--r--Utilities/cmcurl/lib/nwos.c88
-rw-r--r--Utilities/cmcurl/lib/openldap.c711
-rw-r--r--Utilities/cmcurl/lib/parsedate.c585
-rw-r--r--Utilities/cmcurl/lib/parsedate.h31
-rw-r--r--Utilities/cmcurl/lib/pingpong.c513
-rw-r--r--Utilities/cmcurl/lib/pingpong.h150
-rw-r--r--Utilities/cmcurl/lib/pipeline.c410
-rw-r--r--Utilities/cmcurl/lib/pipeline.h56
-rw-r--r--Utilities/cmcurl/lib/pop3.c1612
-rw-r--r--Utilities/cmcurl/lib/pop3.h95
-rw-r--r--Utilities/cmcurl/lib/progress.c567
-rw-r--r--Utilities/cmcurl/lib/progress.h77
-rw-r--r--Utilities/cmcurl/lib/rand.c179
-rw-r--r--Utilities/cmcurl/lib/rand.h47
-rw-r--r--Utilities/cmcurl/lib/rtsp.c815
-rw-r--r--Utilities/cmcurl/lib/rtsp.h69
-rw-r--r--Utilities/cmcurl/lib/security.c588
-rw-r--r--Utilities/cmcurl/lib/select.c583
-rw-r--r--Utilities/cmcurl/lib/select.h115
-rw-r--r--Utilities/cmcurl/lib/sendf.c855
-rw-r--r--Utilities/cmcurl/lib/sendf.h94
-rw-r--r--Utilities/cmcurl/lib/setup-os400.h223
-rw-r--r--Utilities/cmcurl/lib/setup-vms.h443
-rw-r--r--Utilities/cmcurl/lib/share.c244
-rw-r--r--Utilities/cmcurl/lib/share.h61
-rw-r--r--Utilities/cmcurl/lib/sigpipe.h78
-rw-r--r--Utilities/cmcurl/lib/slist.c145
-rw-r--r--Utilities/cmcurl/lib/slist.h40
-rw-r--r--Utilities/cmcurl/lib/smb.c982
-rw-r--r--Utilities/cmcurl/lib/smb.h271
-rw-r--r--Utilities/cmcurl/lib/smtp.c1673
-rw-r--r--Utilities/cmcurl/lib/smtp.h91
-rw-r--r--Utilities/cmcurl/lib/sockaddr.h43
-rw-r--r--Utilities/cmcurl/lib/socks.c782
-rw-r--r--Utilities/cmcurl/lib/socks.h76
-rw-r--r--Utilities/cmcurl/lib/socks_gssapi.c526
-rw-r--r--Utilities/cmcurl/lib/socks_sspi.c605
-rw-r--r--Utilities/cmcurl/lib/speedcheck.c73
-rw-r--r--Utilities/cmcurl/lib/speedcheck.h33
-rw-r--r--Utilities/cmcurl/lib/splay.c274
-rw-r--r--Utilities/cmcurl/lib/splay.h67
-rw-r--r--Utilities/cmcurl/lib/ssh.c3447
-rw-r--r--Utilities/cmcurl/lib/ssh.h198
-rw-r--r--Utilities/cmcurl/lib/strcase.c176
-rw-r--r--Utilities/cmcurl/lib/strcase.h51
-rw-r--r--Utilities/cmcurl/lib/strdup.c100
-rw-r--r--Utilities/cmcurl/lib/strdup.h32
-rw-r--r--Utilities/cmcurl/lib/strerror.c1072
-rw-r--r--Utilities/cmcurl/lib/strerror.h37
-rw-r--r--Utilities/cmcurl/lib/strtok.c66
-rw-r--r--Utilities/cmcurl/lib/strtok.h34
-rw-r--r--Utilities/cmcurl/lib/strtoofft.c188
-rw-r--r--Utilities/cmcurl/lib/strtoofft.h75
-rw-r--r--Utilities/cmcurl/lib/system_win32.c329
-rw-r--r--Utilities/cmcurl/lib/system_win32.h61
-rw-r--r--Utilities/cmcurl/lib/telnet.c1698
-rw-r--r--Utilities/cmcurl/lib/telnet.h29
-rw-r--r--Utilities/cmcurl/lib/tftp.c1396
-rw-r--r--Utilities/cmcurl/lib/tftp.h29
-rw-r--r--Utilities/cmcurl/lib/timeval.c143
-rw-r--r--Utilities/cmcurl/lib/timeval.h56
-rw-r--r--Utilities/cmcurl/lib/transfer.c1965
-rw-r--r--Utilities/cmcurl/lib/transfer.h68
-rw-r--r--Utilities/cmcurl/lib/url.c7136
-rw-r--r--Utilities/cmcurl/lib/url.h93
-rw-r--r--Utilities/cmcurl/lib/urldata.h1886
-rw-r--r--Utilities/cmcurl/lib/vauth/cleartext.c165
-rw-r--r--Utilities/cmcurl/lib/vauth/cram.c138
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.c893
-rw-r--r--Utilities/cmcurl/lib/vauth/digest.h43
-rw-r--r--Utilities/cmcurl/lib/vauth/digest_sspi.c628
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_gssapi.c401
-rw-r--r--Utilities/cmcurl/lib/vauth/krb5_sspi.c518
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.c856
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm.h143
-rw-r--r--Utilities/cmcurl/lib/vauth/ntlm_sspi.c335
-rw-r--r--Utilities/cmcurl/lib/vauth/oauth2.c86
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_gssapi.c274
-rw-r--r--Utilities/cmcurl/lib/vauth/spnego_sspi.c324
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.c147
-rw-r--r--Utilities/cmcurl/lib/vauth/vauth.h204
-rw-r--r--Utilities/cmcurl/lib/version.c399
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.c706
-rw-r--r--Utilities/cmcurl/lib/vtls/axtls.h71
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.c954
-rw-r--r--Utilities/cmcurl/lib/vtls/cyassl.h92
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.c2847
-rw-r--r--Utilities/cmcurl/lib/vtls/darwinssl.h100
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.c1337
-rw-r--r--Utilities/cmcurl/lib/vtls/gskit.h74
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.c1790
-rw-r--r--Utilities/cmcurl/lib/vtls/gtls.h96
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.c1010
-rw-r--r--Utilities/cmcurl/lib/vtls/mbedtls.h82
-rw-r--r--Utilities/cmcurl/lib/vtls/nss.c2311
-rw-r--r--Utilities/cmcurl/lib/vtls/nssg.h108
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.c3377
-rw-r--r--Utilities/cmcurl/lib/vtls/openssl.h126
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.c873
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl.h82
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl_threadlock.c153
-rw-r--r--Utilities/cmcurl/lib/vtls/polarssl_threadlock.h53
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.c1728
-rw-r--r--Utilities/cmcurl/lib/vtls/schannel.h121
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.c987
-rw-r--r--Utilities/cmcurl/lib/vtls/vtls.h202
-rw-r--r--Utilities/cmcurl/lib/warnless.c546
-rw-r--r--Utilities/cmcurl/lib/warnless.h113
-rw-r--r--Utilities/cmcurl/lib/wildcard.c63
-rw-r--r--Utilities/cmcurl/lib/wildcard.h61
-rw-r--r--Utilities/cmcurl/lib/x509asn1.c1200
-rw-r--r--Utilities/cmcurl/lib/x509asn1.h134
-rw-r--r--Utilities/cmcurl/llist.c138
-rw-r--r--Utilities/cmcurl/llist.h60
-rw-r--r--Utilities/cmcurl/md5.c352
-rw-r--r--Utilities/cmcurl/md5.h29
-rw-r--r--Utilities/cmcurl/memdebug.c298
-rw-r--r--Utilities/cmcurl/memdebug.h125
-rw-r--r--Utilities/cmcurl/memory.h50
-rw-r--r--Utilities/cmcurl/mprintf.c1218
-rw-r--r--Utilities/cmcurl/multi.c1988
-rw-r--r--Utilities/cmcurl/multiif.h46
-rw-r--r--Utilities/cmcurl/netrc.c247
-rw-r--r--Utilities/cmcurl/netrc.h34
-rw-r--r--Utilities/cmcurl/nwlib.c300
-rw-r--r--Utilities/cmcurl/parsedate.c425
-rw-r--r--Utilities/cmcurl/parsedate.h28
-rw-r--r--Utilities/cmcurl/progress.c424
-rw-r--r--Utilities/cmcurl/progress.h70
-rw-r--r--Utilities/cmcurl/security.c493
-rw-r--r--Utilities/cmcurl/select.c315
-rw-r--r--Utilities/cmcurl/select.h60
-rw-r--r--Utilities/cmcurl/sendf.c663
-rw-r--r--Utilities/cmcurl/sendf.h72
-rw-r--r--Utilities/cmcurl/setup.h390
-rw-r--r--Utilities/cmcurl/setup_once.h153
-rw-r--r--Utilities/cmcurl/share.c219
-rw-r--r--Utilities/cmcurl/share.h56
-rw-r--r--Utilities/cmcurl/sockaddr.h38
-rw-r--r--Utilities/cmcurl/socks.c592
-rw-r--r--Utilities/cmcurl/socks.h41
-rw-r--r--Utilities/cmcurl/speedcheck.c75
-rw-r--r--Utilities/cmcurl/speedcheck.h34
-rw-r--r--Utilities/cmcurl/splay.c425
-rw-r--r--Utilities/cmcurl/splay.h54
-rw-r--r--Utilities/cmcurl/ssh.c979
-rw-r--r--Utilities/cmcurl/ssh.h49
-rw-r--r--Utilities/cmcurl/sslgen.c618
-rw-r--r--Utilities/cmcurl/sslgen.h84
-rw-r--r--Utilities/cmcurl/ssluse.c1950
-rw-r--r--Utilities/cmcurl/ssluse.h71
-rw-r--r--Utilities/cmcurl/strdup.c46
-rw-r--r--Utilities/cmcurl/strdup.h34
-rw-r--r--Utilities/cmcurl/strequal.c101
-rw-r--r--Utilities/cmcurl/strequal.h38
-rw-r--r--Utilities/cmcurl/strerror.c751
-rw-r--r--Utilities/cmcurl/strerror.h34
-rw-r--r--Utilities/cmcurl/strtok.c68
-rw-r--r--Utilities/cmcurl/strtok.h38
-rw-r--r--Utilities/cmcurl/strtoofft.c165
-rw-r--r--Utilities/cmcurl/strtoofft.h73
-rw-r--r--Utilities/cmcurl/telnet.c1403
-rw-r--r--Utilities/cmcurl/telnet.h30
-rw-r--r--Utilities/cmcurl/tftp.c816
-rw-r--r--Utilities/cmcurl/tftp.h31
-rw-r--r--Utilities/cmcurl/timeval.c116
-rw-r--r--Utilities/cmcurl/timeval.h76
-rw-r--r--Utilities/cmcurl/transfer.c2494
-rw-r--r--Utilities/cmcurl/transfer.h51
-rw-r--r--Utilities/cmcurl/url.c4252
-rw-r--r--Utilities/cmcurl/url.h85
-rw-r--r--Utilities/cmcurl/urldata.h1340
-rw-r--r--Utilities/cmcurl/version.c249
-rw-r--r--Utilities/cmexpat/.NoDartCoverage1
-rw-r--r--Utilities/cmexpat/.gitattributes1
-rw-r--r--Utilities/cmexpat/CMakeLists.txt52
-rw-r--r--Utilities/cmexpat/COPYING4
-rw-r--r--Utilities/cmexpat/ConfigureChecks.cmake44
-rw-r--r--Utilities/cmexpat/README.md126
-rw-r--r--Utilities/cmexpat/ascii.h86
-rw-r--r--Utilities/cmexpat/asciitab.h37
-rw-r--r--Utilities/cmexpat/cm_expat_mangle.h87
-rw-r--r--Utilities/cmexpat/expat.h740
-rw-r--r--Utilities/cmexpat/expatConfig.h.in43
-rw-r--r--Utilities/cmexpat/expatDllConfig.h.in6
-rw-r--r--Utilities/cmexpat/expat_config.h.cmake76
-rw-r--r--Utilities/cmexpat/iasciitab.h38
-rw-r--r--Utilities/cmexpat/latin1tab.h37
-rw-r--r--Utilities/cmexpat/lib/ascii.h92
-rw-r--r--Utilities/cmexpat/lib/asciitab.h36
-rw-r--r--Utilities/cmexpat/lib/expat.h1057
-rw-r--r--Utilities/cmexpat/lib/expat_external.h134
-rw-r--r--Utilities/cmexpat/lib/iasciitab.h37
-rw-r--r--Utilities/cmexpat/lib/internal.h95
-rw-r--r--Utilities/cmexpat/lib/latin1tab.h36
-rw-r--r--Utilities/cmexpat/lib/loadlibrary.c141
-rw-r--r--Utilities/cmexpat/lib/nametab.h (renamed from Utilities/cmexpat/nametab.h)0
-rw-r--r--Utilities/cmexpat/lib/siphash.h377
-rw-r--r--Utilities/cmexpat/lib/utf8tab.h37
-rw-r--r--Utilities/cmexpat/lib/winconfig.h44
-rw-r--r--Utilities/cmexpat/lib/xmlparse.c7215
-rw-r--r--Utilities/cmexpat/lib/xmlrole.c1358
-rw-r--r--Utilities/cmexpat/lib/xmlrole.h114
-rw-r--r--Utilities/cmexpat/lib/xmltok.c1754
-rw-r--r--Utilities/cmexpat/lib/xmltok.h322
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.c1806
-rw-r--r--Utilities/cmexpat/lib/xmltok_impl.h (renamed from Utilities/cmexpat/xmltok_impl.h)0
-rw-r--r--Utilities/cmexpat/lib/xmltok_ns.c115
-rw-r--r--Utilities/cmexpat/utf8tab.h38
-rw-r--r--Utilities/cmexpat/xmlparse.c4622
-rw-r--r--Utilities/cmexpat/xmlrole.c1401
-rw-r--r--Utilities/cmexpat/xmlrole.h100
-rw-r--r--Utilities/cmexpat/xmltok.c1584
-rw-r--r--Utilities/cmexpat/xmltok.h299
-rw-r--r--Utilities/cmexpat/xmltok_impl.c1775
-rw-r--r--Utilities/cmexpat/xmltok_ns.c98
-rw-r--r--Utilities/cmjsoncpp/.gitattributes1
-rw-r--r--Utilities/cmjsoncpp/CMakeLists.txt27
-rw-r--r--Utilities/cmjsoncpp/LICENSE55
-rw-r--r--Utilities/cmjsoncpp/README-CMake.txt66
-rw-r--r--Utilities/cmjsoncpp/include/json/assertions.h41
-rw-r--r--Utilities/cmjsoncpp/include/json/config.h119
-rw-r--r--Utilities/cmjsoncpp/include/json/features.h57
-rw-r--r--Utilities/cmjsoncpp/include/json/forwards.h43
-rw-r--r--Utilities/cmjsoncpp/include/json/json.h14
-rw-r--r--Utilities/cmjsoncpp/include/json/reader.h274
-rw-r--r--Utilities/cmjsoncpp/include/json/value.h1088
-rw-r--r--Utilities/cmjsoncpp/include/json/version.h14
-rw-r--r--Utilities/cmjsoncpp/include/json/writer.h213
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h121
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl360
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl473
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_reader.cpp885
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_tool.h87
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_value.cpp1482
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl241
-rw-r--r--Utilities/cmjsoncpp/src/lib_json/json_writer.cpp724
-rw-r--r--Utilities/cmlibarchive/.gitattributes3
-rw-r--r--Utilities/cmlibarchive/CMakeLists.txt328
-rw-r--r--Utilities/cmlibarchive/COPYING5
-rw-r--r--Utilities/cmlibarchive/README-CMake.txt66
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake2
-rw-r--r--Utilities/cmlibarchive/build/cmake/CheckStructMember.cmake43
-rw-r--r--Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake33
-rw-r--r--Utilities/cmlibarchive/build/cmake/FindLZMA.cmake48
-rw-r--r--Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake68
-rw-r--r--Utilities/cmlibarchive/build/cmake/config.h.in104
-rw-r--r--Utilities/cmlibarchive/build/version2
-rw-r--r--Utilities/cmlibarchive/libarchive/CMakeLists.txt46
-rw-r--r--Utilities/cmlibarchive/libarchive/archive.h288
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_acl.c1639
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_acl_private.h22
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_crypto.c1429
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_crypto_private.h376
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor.c450
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_cryptor_private.h163
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_digest.c1463
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_digest_private.h377
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.c405
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry.h158
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_acl.3335
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_locale.h10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_paths.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_perms.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_private.h5
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_sparse.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_stat.34
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_strmode.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_time.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_entry_xattr.c10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_getdate.c19
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_getdate.h39
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_hmac.c254
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_hmac_private.h106
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_match.c27
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h48
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h48
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_options.c17
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pack_dev.c329
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pack_dev.h49
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_pathmatch.c8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_platform.h50
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7.c5
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_private.h19
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_random.c269
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_random_private.h36
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_rb.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read.34
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read.c158
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.374
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c186
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_append_filter.c8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_data.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk.36
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c1122
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c187
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_private.h13
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c88
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_extract.c147
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_extract2.c155
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_filter.323
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open.34
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_fd.c29
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_file.c10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_filename.c22
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_open_memory.c15
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_private.h77
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_set_options.322
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_set_options.c39
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c24
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c742
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c18
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c47
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c198
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c246
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c1
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c47
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c19
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c48
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c120
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c491
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c694
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c179
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c501
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c824
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c162
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c3638
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string.c211
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string.h8
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_string_composition.h2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_util.c200
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_virtual.c16
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_windows.c14
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_windows.h20
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.315
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write.c35
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter.c1
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c1
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c9
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c707
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c17
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c46
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_data.314
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk.310
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c539
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c690
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c13
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c29
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_filter.332
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_finish_entry.32
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_format.3124
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open.313
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_filename.c5
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_open_memory.c3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_private.h17
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c10
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c3
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c5
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_filter_by_ext.c142
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c48
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c88
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c47
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c220
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c125
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c4
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c11
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c9
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c445
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c89
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c1646
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_options.363
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.374
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.c95
-rw-r--r--Utilities/cmlibarchive/libarchive/archive_xxhash.h47
-rw-r--r--Utilities/cmlibarchive/libarchive/config_freebsd.h2
-rw-r--r--Utilities/cmlibarchive/libarchive/filter_fork_windows.c2
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive-formats.560
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive.34
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive_changes.32
-rw-r--r--Utilities/cmlibarchive/libarchive/libarchive_internals.32
-rw-r--r--Utilities/cmlibarchive/libarchive/mtree.596
-rw-r--r--Utilities/cmlibarchive/libarchive/tar.513
-rw-r--r--Utilities/cmlibarchive/libarchive/xxhash.c515
-rw-r--r--Utilities/cmliblzma/.gitattributes1
-rw-r--r--Utilities/cmliblzma/CMakeLists.txt220
-rw-r--r--Utilities/cmliblzma/COPYING65
-rw-r--r--Utilities/cmliblzma/common/common_w32res.rc50
-rw-r--r--Utilities/cmliblzma/common/sysdefs.h202
-rw-r--r--Utilities/cmliblzma/common/tuklib_integer.h514
-rw-r--r--Utilities/cmliblzma/config.h.in289
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma.h313
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/base.h601
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/bcj.h90
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/block.h533
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/check.h150
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/container.h424
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/delta.h77
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/filter.h424
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/hardware.h50
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/index.h682
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/index_hash.h107
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/lzma.h420
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/stream_flags.h223
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/version.h121
-rw-r--r--Utilities/cmliblzma/liblzma/api/lzma/vli.h166
-rw-r--r--Utilities/cmliblzma/liblzma/check/check.c174
-rw-r--r--Utilities/cmliblzma/liblzma/check/check.h95
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_fast.c86
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_small.c61
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table.c19
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table_be.h525
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_table_le.h525
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_tablegen.c117
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc32_x86.S304
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_fast.c74
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_small.c53
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table.c19
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table_be.h521
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_table_le.h521
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_tablegen.c88
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc64_x86.S287
-rw-r--r--Utilities/cmliblzma/liblzma/check/crc_macros.h30
-rw-r--r--Utilities/cmliblzma/liblzma/check/sha256.c204
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_decoder.c236
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_decoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/alone_encoder.c155
-rw-r--r--Utilities/cmliblzma/liblzma/common/auto_decoder.c186
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_buffer_decoder.c82
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_buffer_encoder.c315
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_decoder.c242
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_decoder.h22
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_encoder.c217
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_encoder.h47
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_header_decoder.c121
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_header_encoder.c137
-rw-r--r--Utilities/cmliblzma/liblzma/common/block_util.c95
-rw-r--r--Utilities/cmliblzma/liblzma/common/common.c390
-rw-r--r--Utilities/cmliblzma/liblzma/common/common.h305
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_buffer_encoder.c27
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_decoder_memusage.c24
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_encoder.c25
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_encoder_memusage.c24
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_preset.c27
-rw-r--r--Utilities/cmliblzma/liblzma/common/easy_preset.h32
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_buffer_decoder.c91
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_buffer_encoder.c57
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_common.c342
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_common.h48
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_decoder.c185
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_decoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_encoder.c297
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_encoder.h27
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_flags_decoder.c48
-rw-r--r--Utilities/cmliblzma/liblzma/common/filter_flags_encoder.c57
-rw-r--r--Utilities/cmliblzma/liblzma/common/hardware_physmem.c25
-rw-r--r--Utilities/cmliblzma/liblzma/common/index.c1276
-rw-r--r--Utilities/cmliblzma/liblzma/common/index.h73
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_decoder.c347
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_encoder.c257
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/index_hash.c336
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_buffer_decoder.c93
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_buffer_encoder.c140
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_decoder.c459
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_decoder.h21
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_encoder.c338
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_common.c47
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_common.h33
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_decoder.c86
-rw-r--r--Utilities/cmliblzma/liblzma/common/stream_flags_encoder.c90
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_decoder.c86
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_encoder.c69
-rw-r--r--Utilities/cmliblzma/liblzma/common/vli_size.c31
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_common.c72
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_common.h20
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_decoder.c79
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_decoder.h25
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_encoder.c124
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/delta/delta_private.h37
-rw-r--r--Utilities/cmliblzma/liblzma/liblzma.pc.in19
-rw-r--r--Utilities/cmliblzma/liblzma/liblzma_w32res.rc14
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_decoder.c307
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_decoder.h236
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder.c594
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder.h328
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_hash.h105
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_hash_table.h68
-rw-r--r--Utilities/cmliblzma/liblzma/lz/lz_encoder_mf.c814
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos.h142
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos_table.c519
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/fastpos_tablegen.c56
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.c305
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.h28
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.c399
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.h41
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_common.h226
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_decoder.c1075
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_decoder.h52
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c695
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder.h54
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c185
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_normal.c925
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_presets.c64
-rw-r--r--Utilities/cmliblzma/liblzma/lzma/lzma_encoder_private.h148
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price.h92
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price_table.c22
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/price_tablegen.c87
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_common.h74
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_decoder.h179
-rw-r--r--Utilities/cmliblzma/liblzma/rangecoder/range_encoder.h232
-rw-r--r--Utilities/cmliblzma/liblzma/simple/arm.c69
-rw-r--r--Utilities/cmliblzma/liblzma/simple/armthumb.c74
-rw-r--r--Utilities/cmliblzma/liblzma/simple/ia64.c116
-rw-r--r--Utilities/cmliblzma/liblzma/simple/powerpc.c73
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_coder.c283
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_coder.h60
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_decoder.c41
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_decoder.h22
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_encoder.c38
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_encoder.h23
-rw-r--r--Utilities/cmliblzma/liblzma/simple/simple_private.h75
-rw-r--r--Utilities/cmliblzma/liblzma/simple/sparc.c82
-rw-r--r--Utilities/cmliblzma/liblzma/simple/x86.c161
-rw-r--r--Utilities/cmlibrhash/.gitattributes1
-rw-r--r--Utilities/cmlibrhash/CMakeLists.txt40
-rw-r--r--Utilities/cmlibrhash/COPYING15
-rw-r--r--Utilities/cmlibrhash/README7
-rw-r--r--Utilities/cmlibrhash/librhash/algorithms.c220
-rw-r--r--Utilities/cmlibrhash/librhash/algorithms.h120
-rw-r--r--Utilities/cmlibrhash/librhash/byte_order.c150
-rw-r--r--Utilities/cmlibrhash/librhash/byte_order.h156
-rw-r--r--Utilities/cmlibrhash/librhash/hex.c188
-rw-r--r--Utilities/cmlibrhash/librhash/hex.h25
-rw-r--r--Utilities/cmlibrhash/librhash/md5.c236
-rw-r--r--Utilities/cmlibrhash/librhash/md5.h31
-rw-r--r--Utilities/cmlibrhash/librhash/rhash.c872
-rw-r--r--Utilities/cmlibrhash/librhash/rhash.h288
-rw-r--r--Utilities/cmlibrhash/librhash/sha1.c196
-rw-r--r--Utilities/cmlibrhash/librhash/sha1.h31
-rw-r--r--Utilities/cmlibrhash/librhash/sha256.c241
-rw-r--r--Utilities/cmlibrhash/librhash/sha256.h32
-rw-r--r--Utilities/cmlibrhash/librhash/sha3.c356
-rw-r--r--Utilities/cmlibrhash/librhash/sha3.h54
-rw-r--r--Utilities/cmlibrhash/librhash/sha512.c255
-rw-r--r--Utilities/cmlibrhash/librhash/sha512.h32
-rw-r--r--Utilities/cmlibrhash/librhash/ustd.h39
-rw-r--r--Utilities/cmlibrhash/librhash/util.h31
-rw-r--r--Utilities/cmlibuv/.gitattributes1
-rw-r--r--Utilities/cmlibuv/CMakeLists.txt289
-rw-r--r--Utilities/cmlibuv/LICENSE70
-rw-r--r--Utilities/cmlibuv/include/android-ifaddrs.h54
-rw-r--r--Utilities/cmlibuv/include/pthread-barrier.h68
-rw-r--r--Utilities/cmlibuv/include/stdint-msvc2008.h247
-rw-r--r--Utilities/cmlibuv/include/tree.h768
-rw-r--r--Utilities/cmlibuv/include/uv-aix.h32
-rw-r--r--Utilities/cmlibuv/include/uv-bsd.h34
-rw-r--r--Utilities/cmlibuv/include/uv-darwin.h61
-rw-r--r--Utilities/cmlibuv/include/uv-errno.h419
-rw-r--r--Utilities/cmlibuv/include/uv-linux.h34
-rw-r--r--Utilities/cmlibuv/include/uv-os390.h30
-rw-r--r--Utilities/cmlibuv/include/uv-posix.h31
-rw-r--r--Utilities/cmlibuv/include/uv-sunos.h44
-rw-r--r--Utilities/cmlibuv/include/uv-threadpool.h37
-rw-r--r--Utilities/cmlibuv/include/uv-unix.h368
-rw-r--r--Utilities/cmlibuv/include/uv-version.h43
-rw-r--r--Utilities/cmlibuv/include/uv-win.h661
-rw-r--r--Utilities/cmlibuv/include/uv.h1511
-rw-r--r--Utilities/cmlibuv/src/fs-poll.c256
-rw-r--r--Utilities/cmlibuv/src/heap-inl.h245
-rw-r--r--Utilities/cmlibuv/src/inet.c309
-rw-r--r--Utilities/cmlibuv/src/queue.h108
-rw-r--r--Utilities/cmlibuv/src/threadpool.c312
-rw-r--r--Utilities/cmlibuv/src/unix/aix.c1243
-rw-r--r--Utilities/cmlibuv/src/unix/android-ifaddrs.c703
-rw-r--r--Utilities/cmlibuv/src/unix/async.c269
-rw-r--r--Utilities/cmlibuv/src/unix/atomic-ops.h97
-rw-r--r--Utilities/cmlibuv/src/unix/bsd-ifaddrs.c139
-rw-r--r--Utilities/cmlibuv/src/unix/core.c1326
-rw-r--r--Utilities/cmlibuv/src/unix/cygwin.c54
-rw-r--r--Utilities/cmlibuv/src/unix/darwin-proctitle.c206
-rw-r--r--Utilities/cmlibuv/src/unix/darwin.c231
-rw-r--r--Utilities/cmlibuv/src/unix/dl.c80
-rw-r--r--Utilities/cmlibuv/src/unix/freebsd.c346
-rw-r--r--Utilities/cmlibuv/src/unix/fs.c1379
-rw-r--r--Utilities/cmlibuv/src/unix/fsevents.c901
-rw-r--r--Utilities/cmlibuv/src/unix/getaddrinfo.c202
-rw-r--r--Utilities/cmlibuv/src/unix/getnameinfo.c120
-rw-r--r--Utilities/cmlibuv/src/unix/internal.h326
-rw-r--r--Utilities/cmlibuv/src/unix/kqueue.c497
-rw-r--r--Utilities/cmlibuv/src/unix/linux-core.c951
-rw-r--r--Utilities/cmlibuv/src/unix/linux-inotify.c352
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.c471
-rw-r--r--Utilities/cmlibuv/src/unix/linux-syscalls.h151
-rw-r--r--Utilities/cmlibuv/src/unix/loop-watcher.c68
-rw-r--r--Utilities/cmlibuv/src/unix/loop.c193
-rw-r--r--Utilities/cmlibuv/src/unix/netbsd.c272
-rw-r--r--Utilities/cmlibuv/src/unix/no-fsevents.c42
-rw-r--r--Utilities/cmlibuv/src/unix/no-proctitle.c42
-rw-r--r--Utilities/cmlibuv/src/unix/openbsd.c284
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.c334
-rw-r--r--Utilities/cmlibuv/src/unix/os390-syscalls.h69
-rw-r--r--Utilities/cmlibuv/src/unix/os390.c849
-rw-r--r--Utilities/cmlibuv/src/unix/pipe.c302
-rw-r--r--Utilities/cmlibuv/src/unix/poll.c130
-rw-r--r--Utilities/cmlibuv/src/unix/posix-hrtime.c35
-rw-r--r--Utilities/cmlibuv/src/unix/posix-poll.c324
-rw-r--r--Utilities/cmlibuv/src/unix/process.c563
-rw-r--r--Utilities/cmlibuv/src/unix/procfs-exepath.c45
-rw-r--r--Utilities/cmlibuv/src/unix/proctitle.c111
-rw-r--r--Utilities/cmlibuv/src/unix/pthread-barrier.c121
-rw-r--r--Utilities/cmlibuv/src/unix/pthread-fixes.c56
-rw-r--r--Utilities/cmlibuv/src/unix/signal.c559
-rw-r--r--Utilities/cmlibuv/src/unix/spinlock.h53
-rw-r--r--Utilities/cmlibuv/src/unix/stream.c1677
-rw-r--r--Utilities/cmlibuv/src/unix/sunos.c825
-rw-r--r--Utilities/cmlibuv/src/unix/sysinfo-loadavg.c36
-rw-r--r--Utilities/cmlibuv/src/unix/sysinfo-memory.c42
-rw-r--r--Utilities/cmlibuv/src/unix/tcp.c395
-rw-r--r--Utilities/cmlibuv/src/unix/thread.c575
-rw-r--r--Utilities/cmlibuv/src/unix/timer.c172
-rw-r--r--Utilities/cmlibuv/src/unix/tty.c333
-rw-r--r--Utilities/cmlibuv/src/unix/udp.c900
-rw-r--r--Utilities/cmlibuv/src/uv-common.c664
-rw-r--r--Utilities/cmlibuv/src/uv-common.h254
-rw-r--r--Utilities/cmlibuv/src/version.c45
-rw-r--r--Utilities/cmlibuv/src/win/async.c98
-rw-r--r--Utilities/cmlibuv/src/win/atomicops-inl.h57
-rw-r--r--Utilities/cmlibuv/src/win/core.c605
-rw-r--r--Utilities/cmlibuv/src/win/detect-wakeup.c35
-rw-r--r--Utilities/cmlibuv/src/win/dl.c118
-rw-r--r--Utilities/cmlibuv/src/win/error.c171
-rw-r--r--Utilities/cmlibuv/src/win/fs-event.c561
-rw-r--r--Utilities/cmlibuv/src/win/fs.c2492
-rw-r--r--Utilities/cmlibuv/src/win/getaddrinfo.c382
-rw-r--r--Utilities/cmlibuv/src/win/getnameinfo.c149
-rw-r--r--Utilities/cmlibuv/src/win/handle-inl.h179
-rw-r--r--Utilities/cmlibuv/src/win/handle.c154
-rw-r--r--Utilities/cmlibuv/src/win/internal.h399
-rw-r--r--Utilities/cmlibuv/src/win/loop-watcher.c122
-rw-r--r--Utilities/cmlibuv/src/win/pipe.c2125
-rw-r--r--Utilities/cmlibuv/src/win/poll.c644
-rw-r--r--Utilities/cmlibuv/src/win/process-stdio.c511
-rw-r--r--Utilities/cmlibuv/src/win/process.c1246
-rw-r--r--Utilities/cmlibuv/src/win/req-inl.h221
-rw-r--r--Utilities/cmlibuv/src/win/req.c25
-rw-r--r--Utilities/cmlibuv/src/win/signal.c277
-rw-r--r--Utilities/cmlibuv/src/win/snprintf.c42
-rw-r--r--Utilities/cmlibuv/src/win/stream-inl.h55
-rw-r--r--Utilities/cmlibuv/src/win/stream.c248
-rw-r--r--Utilities/cmlibuv/src/win/tcp.c1505
-rw-r--r--Utilities/cmlibuv/src/win/thread.c697
-rw-r--r--Utilities/cmlibuv/src/win/timer.c195
-rw-r--r--Utilities/cmlibuv/src/win/tty.c2281
-rw-r--r--Utilities/cmlibuv/src/win/udp.c926
-rw-r--r--Utilities/cmlibuv/src/win/util.c1576
-rw-r--r--Utilities/cmlibuv/src/win/winapi.c159
-rw-r--r--Utilities/cmlibuv/src/win/winapi.h4761
-rw-r--r--Utilities/cmlibuv/src/win/winsock.c561
-rw-r--r--Utilities/cmlibuv/src/win/winsock.h191
-rw-r--r--Utilities/cmvssetup/.gitattributes1
-rw-r--r--Utilities/cmvssetup/Setup.Configuration.h991
-rw-r--r--Utilities/cmzlib/CMakeLists.txt18
-rw-r--r--Utilities/cmzlib/zconf.h2
-rw-r--r--Utilities/cmzlib/zutil.h6
-rw-r--r--Utilities/xml/docbook-4.5/ChangeLog106
-rw-r--r--Utilities/xml/docbook-4.5/README8
-rw-r--r--Utilities/xml/docbook-4.5/calstblx.dtd215
-rw-r--r--Utilities/xml/docbook-4.5/catalog.xml124
-rw-r--r--Utilities/xml/docbook-4.5/dbcentx.mod384
-rw-r--r--Utilities/xml/docbook-4.5/dbgenent.mod41
-rw-r--r--Utilities/xml/docbook-4.5/dbhierx.mod2193
-rw-r--r--Utilities/xml/docbook-4.5/dbnotnx.mod101
-rw-r--r--Utilities/xml/docbook-4.5/dbpoolx.mod8701
-rw-r--r--Utilities/xml/docbook-4.5/docbook.cat113
-rw-r--r--Utilities/xml/docbook-4.5/docbookx.dtd170
-rw-r--r--Utilities/xml/docbook-4.5/ent/README14
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamsa.ent97
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamsb.ent83
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamsc.ent51
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamsn.ent103
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamso.ent59
-rw-r--r--Utilities/xml/docbook-4.5/ent/isoamsr.ent125
-rw-r--r--Utilities/xml/docbook-4.5/ent/isobox.ent81
-rw-r--r--Utilities/xml/docbook-4.5/ent/isocyr1.ent108
-rw-r--r--Utilities/xml/docbook-4.5/ent/isocyr2.ent67
-rw-r--r--Utilities/xml/docbook-4.5/ent/isodia.ent55
-rw-r--r--Utilities/xml/docbook-4.5/ent/isogrk1.ent90
-rw-r--r--Utilities/xml/docbook-4.5/ent/isogrk2.ent61
-rw-r--r--Utilities/xml/docbook-4.5/ent/isogrk3.ent84
-rw-r--r--Utilities/xml/docbook-4.5/ent/isogrk4.ent84
-rw-r--r--Utilities/xml/docbook-4.5/ent/isolat1.ent103
-rw-r--r--Utilities/xml/docbook-4.5/ent/isolat2.ent162
-rw-r--r--Utilities/xml/docbook-4.5/ent/isonum.ent117
-rw-r--r--Utilities/xml/docbook-4.5/ent/isopub.ent125
-rw-r--r--Utilities/xml/docbook-4.5/ent/isotech.ent103
-rw-r--r--Utilities/xml/docbook-4.5/htmltblx.mod245
-rw-r--r--Utilities/xml/docbook-4.5/soextblx.dtd321
-rw-r--r--Utilities/xml/xhtml1/xhtml-lat1.ent196
-rw-r--r--Utilities/xml/xhtml1/xhtml-special.ent80
-rw-r--r--Utilities/xml/xhtml1/xhtml-symbol.ent237
-rw-r--r--Utilities/xml/xhtml1/xhtml1-strict.dtd977
1103 files changed, 246289 insertions, 90800 deletions
diff --git a/Utilities/.clang-tidy b/Utilities/.clang-tidy
new file mode 100644
index 000000000..381a0f45a
--- /dev/null
+++ b/Utilities/.clang-tidy
@@ -0,0 +1,6 @@
+---
+# We want to disable all checks for 3rd party code. However, clang-tidy will
+# assume we did not configure it correctly. Just add one check that will never
+# be found.
+Checks: '-*,llvm-twine-local'
+...
diff --git a/Utilities/.gitattributes b/Utilities/.gitattributes
index e3a9e6105..bd978021b 100644
--- a/Utilities/.gitattributes
+++ b/Utilities/.gitattributes
@@ -1,2 +1,7 @@
/Git export-ignore
+/GitSetup export-ignore
SetupForDevelopment.sh export-ignore
+
+# Do not format third-party sources.
+/KWIML/** -format.clang-format
+/cm*/** -format.clang-format
diff --git a/Utilities/CMakeLists.txt b/Utilities/CMakeLists.txt
index bad8d630e..056454019 100644
--- a/Utilities/CMakeLists.txt
+++ b/Utilities/CMakeLists.txt
@@ -1,167 +1,34 @@
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-subdirs(Doxygen KWStyle)
-
-make_directory(${CMake_BINARY_DIR}/Docs)
-
-# Add a documentation target.
-set(DOC_FILES "")
-
-set(MAN_FILES
- ${CMake_BINARY_DIR}/Docs/cmake.1
- ${CMake_BINARY_DIR}/Docs/cmakecommands.1
- ${CMake_BINARY_DIR}/Docs/cmakecompat.1
- ${CMake_BINARY_DIR}/Docs/cmakeprops.1
- ${CMake_BINARY_DIR}/Docs/cmakepolicies.1
- ${CMake_BINARY_DIR}/Docs/cmakevars.1
- ${CMake_BINARY_DIR}/Docs/cmakemodules.1
- )
-set(TEXT_FILES
- ${CMake_BINARY_DIR}/Docs/cmake.txt
- ${CMake_BINARY_DIR}/Docs/cmake-policies.txt
- ${CMake_BINARY_DIR}/Docs/cmake-properties.txt
- ${CMake_BINARY_DIR}/Docs/cmake-variables.txt
- ${CMake_BINARY_DIR}/Docs/cmake-modules.txt
- ${CMake_BINARY_DIR}/Docs/cmake-commands.txt
- ${CMake_BINARY_DIR}/Docs/cmake-compatcommands.txt
- )
-set(HTML_FILES
- ${CMake_BINARY_DIR}/Docs/cmake.html
- ${CMake_BINARY_DIR}/Docs/cmake-policies.html
- ${CMake_BINARY_DIR}/Docs/cmake-properties.html
- ${CMake_BINARY_DIR}/Docs/cmake-variables.html
- ${CMake_BINARY_DIR}/Docs/cmake-modules.html
- ${CMake_BINARY_DIR}/Docs/cmake-commands.html
- ${CMake_BINARY_DIR}/Docs/cmake-compatcommands.html
- )
-set(DOCBOOK_FILES
- ${CMake_BINARY_DIR}/Docs/cmake.docbook
- )
-
-macro(ADD_DOCS target dependency)
- # Generate documentation for "ctest" executable.
- get_target_property(CMD ${target} LOCATION)
- # only generate the documentation if the target is actually built
- if(CMD)
- add_custom_command(
- OUTPUT ${CMake_BINARY_DIR}/Docs/${target}.txt
- ${${target}-PATH} # Possibly set PATH, see below.
- COMMAND ${CMD}
- ARGS --help-full ${CMake_BINARY_DIR}/Docs/${target}.txt
- --help-full ${CMake_BINARY_DIR}/Docs/${target}.html
- --help-full ${CMake_BINARY_DIR}/Docs/${target}.1
- --help-full ${CMake_BINARY_DIR}/Docs/${target}.docbook
- DEPENDS ${target}
- MAIN_DEPENDENCY ${dependency}
- )
- set(DOC_FILES ${DOC_FILES} ${CMake_BINARY_DIR}/Docs/${target}.txt)
- list(APPEND MAN_FILES ${CMake_BINARY_DIR}/Docs/${target}.1)
- list(APPEND TEXT_FILES ${CMake_BINARY_DIR}/Docs/${target}.txt)
- list(APPEND HTML_FILES ${CMake_BINARY_DIR}/Docs/${target}.html)
- list(APPEND DOCBOOK_FILES ${CMake_BINARY_DIR}/Docs/${target}.docbook)
- endif()
-endmacro()
-
-# Help cmake-gui find the Qt DLLs on Windows.
-if(TARGET cmake-gui)
- get_property(Qt_BIN_DIR TARGET cmake-gui PROPERTY Qt_BIN_DIR)
- set(WIN_SHELL_GENS "Visual Studio|NMake|MinGW|Watcom|Borland")
- if(Qt_BIN_DIR AND "${CMAKE_GENERATOR}" MATCHES "${WIN_SHELL_GENS}"
- AND NOT CMAKE_NO_AUTO_QT_ENV)
- # Tell the macro to set the path before running cmake-gui.
- string(REPLACE ";" "\\;" _PATH "PATH=${Qt_BIN_DIR};%PATH%")
- set(cmake-gui-PATH COMMAND set "${_PATH}")
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+subdirs(Doxygen)
+
+if(CMAKE_DOC_TARBALL)
+ # Undocumented option to extract and install pre-built documentation.
+ # This is intended for use during packaging of CMake itself.
+ if(CMAKE_DOC_TARBALL MATCHES "/([^/]+)\\.tar\\.gz$")
+ set(dir "${CMAKE_MATCH_1}")
+ else()
+ message(FATAL_ERROR "CMAKE_DOC_TARBALL must end in .tar.gz")
endif()
+ add_custom_command(
+ OUTPUT ${dir}.stamp
+ COMMAND cmake -E remove_directory ${dir}
+ COMMAND cmake -E tar xf ${CMAKE_DOC_TARBALL}
+ COMMAND cmake -E touch ${dir}.stamp
+ DEPENDS ${CMAKE_DOC_TARBALL}
+ )
+ add_custom_target(documentation ALL DEPENDS ${dir}.stamp)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${dir}/
+ DESTINATION . USE_SOURCE_PERMISSIONS)
+else()
+ # Normal documentation build.
+ add_subdirectory(Sphinx)
endif()
-# add the docs for the executables
-ADD_DOCS(ctest ${CMake_SOURCE_DIR}/Utilities/Doxygen/authors.txt)
-ADD_DOCS(cpack ${CMake_SOURCE_DIR}/Utilities/Doxygen/authors.txt)
-ADD_DOCS(ccmake ${CMake_SOURCE_DIR}/Utilities/Doxygen/authors.txt)
-ADD_DOCS(CMakeSetup ${CMake_SOURCE_DIR}/Utilities/Doxygen/doxyfile.in)
-ADD_DOCS(cmake-gui ${CMake_SOURCE_DIR}/Utilities/Doxygen/doxyfile.in)
-
-# add the documentation for cmake itself
-
-get_target_property(CMD cmake LOCATION)
-add_custom_command(
- OUTPUT ${CMake_BINARY_DIR}/Docs/cmake.txt
- COMMAND ${CMD}
- ARGS --copyright ${CMake_BINARY_DIR}/Docs/Copyright.txt
- --help-full ${CMake_BINARY_DIR}/Docs/cmake.txt
- --help-full ${CMake_BINARY_DIR}/Docs/cmake.html
- --help-full ${CMake_BINARY_DIR}/Docs/cmake.1
- --help-full ${CMake_BINARY_DIR}/Docs/cmake.docbook
- --help-policies ${CMake_BINARY_DIR}/Docs/cmake-policies.txt
- --help-policies ${CMake_BINARY_DIR}/Docs/cmake-policies.html
- --help-policies ${CMake_BINARY_DIR}/Docs/cmakepolicies.1
- --help-properties ${CMake_BINARY_DIR}/Docs/cmake-properties.txt
- --help-properties ${CMake_BINARY_DIR}/Docs/cmake-properties.html
- --help-properties ${CMake_BINARY_DIR}/Docs/cmakeprops.1
- --help-variables ${CMake_BINARY_DIR}/Docs/cmake-variables.txt
- --help-variables ${CMake_BINARY_DIR}/Docs/cmake-variables.html
- --help-variables ${CMake_BINARY_DIR}/Docs/cmakevars.1
- --help-modules ${CMake_BINARY_DIR}/Docs/cmake-modules.txt
- --help-modules ${CMake_BINARY_DIR}/Docs/cmake-modules.html
- --help-modules ${CMake_BINARY_DIR}/Docs/cmakemodules.1
- --help-commands ${CMake_BINARY_DIR}/Docs/cmake-commands.txt
- --help-commands ${CMake_BINARY_DIR}/Docs/cmake-commands.html
- --help-commands ${CMake_BINARY_DIR}/Docs/cmakecommands.1
- --help-compatcommands ${CMake_BINARY_DIR}/Docs/cmake-compatcommands.txt
- --help-compatcommands ${CMake_BINARY_DIR}/Docs/cmake-compatcommands.html
- --help-compatcommands ${CMake_BINARY_DIR}/Docs/cmakecompat.1
- DEPENDS cmake
- MAIN_DEPENDENCY ${CMake_SOURCE_DIR}/Utilities/Doxygen/authors.txt
- )
-
-install(FILES ${MAN_FILES} DESTINATION ${CMAKE_MAN_DIR}/man1)
-install(FILES
- ${TEXT_FILES}
- ${HTML_FILES}
- ${DOCBOOK_FILES}
- DESTINATION ${CMAKE_DOC_DIR}
- )
-install(FILES cmake.m4 DESTINATION share/aclocal)
-
-# Drive documentation generation.
-add_custom_target(documentation ALL DEPENDS ${DOC_FILES} ${CMake_BINARY_DIR}/Docs/cmake.txt )
-
-# Documentation testing.
-if(BUILD_TESTING)
- find_package(LibXml2 QUIET)
- if(NOT DEFINED LIBXML2_XMLLINT_EXECUTABLE)
- find_program(LIBXML2_XMLLINT_EXECUTABLE xmllint)
- endif()
- mark_as_advanced(LIBXML2_XMLLINT_EXECUTABLE)
- if(LIBXML2_XMLLINT_EXECUTABLE)
- execute_process(COMMAND ${LIBXML2_XMLLINT_EXECUTABLE} --help
- OUTPUT_VARIABLE _help ERROR_VARIABLE _err)
- if("${_help}" MATCHES "--path" AND "${_help}" MATCHES "--nonet")
- # We provide DTDs in the 'xml' directory so that xmllint can run without
- # network access. Note that xmllints's --path option accepts a
- # space-separated list of url-encoded paths.
- set(_dtd_dir "${CMAKE_CURRENT_SOURCE_DIR}/xml")
- string(REPLACE " " "%20" _dtd_dir "${_dtd_dir}")
- string(REPLACE ":" "%3A" _dtd_dir "${_dtd_dir}")
- add_test(CMake.HTML
- ${LIBXML2_XMLLINT_EXECUTABLE} --valid --noout --nonet
- --path ${_dtd_dir}/xhtml1
- ${HTML_FILES}
- )
- add_test(CMake.DocBook
- ${LIBXML2_XMLLINT_EXECUTABLE} --valid --noout --nonet
- --path ${_dtd_dir}/docbook-4.5
- ${DOCBOOK_FILES}
- )
- endif()
- endif()
+if(WIX_CUSTOM_ACTION_ENABLED)
+ add_subdirectory(Release/WiX)
endif()
+
+# Make sure generated files use the same clang-tidy checks (none).
+configure_file(.clang-tidy .clang-tidy COPYONLY)
diff --git a/Utilities/Doxygen/CMakeLists.txt b/Utilities/Doxygen/CMakeLists.txt
index 813e34daf..f1e8f95e7 100644
--- a/Utilities/Doxygen/CMakeLists.txt
+++ b/Utilities/Doxygen/CMakeLists.txt
@@ -1,39 +1,96 @@
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT CMake_SOURCE_DIR)
+ set(CMakeDeveloperReference_STANDALONE 1)
+ cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR)
+ get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
+ get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
+ include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
+ include(${CMake_SOURCE_DIR}/Source/CMakeVersionCompute.cmake)
+ include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake)
+ unset(CMAKE_DATA_DIR)
+ unset(CMAKE_DATA_DIR CACHE)
+ macro(CMake_OPTIONAL_COMPONENT)
+ set(COMPONENT "")
+ endmacro()
+endif()
+
+project(CMakeDeveloperReference NONE)
#
-# Build the documentation
+# Build the reference
#
-include (${CMAKE_ROOT}/Modules/Documentation.cmake OPTIONAL)
-if (BUILD_DOCUMENTATION)
+if (CMake_BUILD_DEVELOPER_REFERENCE OR CMakeDeveloperReference_STANDALONE)
+
+ find_package(Doxygen REQUIRED)
+
+ #
+ ## Output formats
+ #
+
+ option(CMake_BUILD_DEVELOPER_REFERENCE_HTML "Build CMake Developer Reference - HTML format" ON)
+ mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
+ if(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
+ set(GENERATE_HTML YES)
+ else()
+ set(GENERATE_HTML NO)
+ endif()
+
+ option(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP "Build CMake Developer Reference - QtHelp format" OFF)
+ mark_as_advanced(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP)
+ if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP)
+ set(GENERATE_QHP YES)
+ find_program(QHELPGENERATOR_EXECUTABLE
+ NAMES qhelpgenerator
+ DOC "qhelpgenerator tool"
+ )
+ if(NOT QHELPGENERATOR_EXECUTABLE)
+ message(FATAL_ERROR "QHELPGENERATOR_EXECUTABLE (qhelpgenerator) not found!")
+ endif()
+ else()
+ set(GENERATE_QHP NO)
+ endif()
#
# Configure the script and the doxyfile, then add target
#
+
+ if(DOXYGEN_DOT_FOUND)
+ set(HAVE_DOT YES)
+ else()
+ set(HAVE_DOT NO)
+ endif()
+
if(NOT DOT_PATH)
- get_filename_component(DOT_PATH ${DOT} PATH)
+ get_filename_component(DOT_PATH ${DOXYGEN_DOT_EXECUTABLE} PATH)
endif()
- configure_file(
- ${CMake_SOURCE_DIR}/Utilities/Doxygen/doxyfile.in
- ${CMake_BINARY_DIR}/Utilities/Doxygen/doxyfile)
+ configure_file(doxyfile.in doxyfile @ONLY)
+
+ add_custom_target(cmake-developer-reference-all
+ ${DOXYGEN_EXECUTABLE} doxyfile
+ WORKING_DIRECTORY ${CMakeDeveloperReference_BINARY_DIR})
- configure_file(
- ${CMake_SOURCE_DIR}/Utilities/Doxygen/doc_makeall.sh.in
- ${CMake_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh)
+ add_custom_target(cmake-developer-reference ALL DEPENDS cmake-developer-reference-all)
- add_custom_target(DoxygenDoc
- ${BASH}
- ${CMake_BINARY_DIR}/Utilities/Doxygen/doc_makeall.sh)
+ #
+ # Installation
+ #
+
+ if(CMake_BUILD_DEVELOPER_REFERENCE_HTML)
+ CMake_OPTIONAL_COMPONENT(cmake-developer-reference-html)
+ install(DIRECTORY "${CMakeDeveloperReference_BINARY_DIR}/developer-reference/html"
+ DESTINATION ${CMAKE_DOC_DIR}/developer-reference
+ ${COMPONENT})
+ endif()
+
+ if(CMake_BUILD_DEVELOPER_REFERENCE_QTHELP)
+ CMake_OPTIONAL_COMPONENT(cmake-developer-reference-qthelp)
+ install(FILES "${CMakeDeveloperReference_BINARY_DIR}/developer-reference/CMakeDeveloperReference-${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}.qch"
+ DESTINATION ${CMAKE_DOC_DIR}/developer-reference
+ ${COMPONENT})
+ endif()
endif ()
diff --git a/Utilities/Doxygen/DeveloperReference/mainpage.dox b/Utilities/Doxygen/DeveloperReference/mainpage.dox
new file mode 100644
index 000000000..a37927fb7
--- /dev/null
+++ b/Utilities/Doxygen/DeveloperReference/mainpage.dox
@@ -0,0 +1,8 @@
+/*!
+
+\mainpage CMake Developer Reference
+
+This manual is intended for reference by developers modifying the CMake
+source tree itself.
+
+*/
diff --git a/Utilities/Doxygen/authors.txt b/Utilities/Doxygen/authors.txt
deleted file mode 100644
index 9ba6ccac4..000000000
--- a/Utilities/Doxygen/authors.txt
+++ /dev/null
@@ -1,17 +0,0 @@
-andy: Cedilnik, Andy (andy.cedilnik@kitware.com)
-barre: Barre, Sebastien (sebastien.barre@kitware.com)
-berk: Geveci, Berk (berk.geveci@kitware.com)
-bettingf: Bettinger, Franck (bettingf@cs.man.ac.uk)
-biddi: Biddiscombe, John (jbiddiscombe@skippingmouse.co.uk)
-blezek: Blezek, Dan (blezek@crd.ge.com)
-geoff: Cross, Geoffrey (geoff@robots.ox.ac.uk)
-hoffman: Hoffman, Bill (bill.hoffman@kitware.com)
-ibanez: Ibanez, Luis (luis.ibanez@kitware.com)
-iscott: Scott, Ian (ian.m.scott@stud.man.ac.uk)
-king: King, Brad (brad.king@kitware.com)
-lorensen: Lorensen, Bill (lorensen@crd.ge.com)
-martink, lymbdemo: Martin, Ken (ken.martin@kitware.com)
-millerjv: Miller, Jim (millerjv@crd.ge.com)
-perera: Perera, Amitha (perera@cs.rpi.edu)
-starreveld: Starreveld, Yves (ystarrev@julian.uwo.ca)
-will, schroede: Schroeder, Will (will.schroeder@kitware.com)
diff --git a/Utilities/Doxygen/doc_makeall.sh.in b/Utilities/Doxygen/doc_makeall.sh.in
deleted file mode 100755
index ed7b521e4..000000000
--- a/Utilities/Doxygen/doc_makeall.sh.in
+++ /dev/null
@@ -1,248 +0,0 @@
-# -------------------------------------------------------------------------
-# Doxygen documentation batch
-# modified by S. Barre (Time-stamp: <2003-01-16 14:04:41 barre>
-# -------------------------------------------------------------------------
-
-# Path to several tools (_PROG to avoid the typical GZIP env var pb)
-# Example:
-# DOXYGEN_PROG=@DOXYGEN@ (INCLUDE(${CMAKE_ROOT}/Modules/FindDoxygen.cmake))
-# GZIP_PROG=@GZIP@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake))
-# HHC_PROG=@HHC@ (INCLUDE(${CMAKE_ROOT}/Modules/FindHhc.cmake))
-# MV_PROG=@MV@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake))
-# PERL_PROG=@PERL@ (INCLUDE(${CMAKE_ROOT}/Modules/FindPerl.cmake))
-# RM_PROG=@RM@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake))
-# TAR_PROG=@TAR@ (INCLUDE(${CMAKE_ROOT}/Modules/FindCygwin.cmake))
-# WGET_PROG=@WGET@ (INCLUDE(${CMAKE_ROOT}/Modules/FindWget.cmake))
-#
-export DOXYGEN_PROG="@DOXYGEN@" # Doxygen
-export GZIP_PROG="@GZIP@" # gzip (Unix-like 'gzip compressor')
-export GNUPLOT_PROG="@GNUPLOT@" # gnuplot (data plotting program)
-export HHC_PROG="@HTML_HELP_COMPILER@" # HTML Help Compiler
-export MV_PROG="@MV@" # mv (Unix-like 'move/rename files')
-export PERL_PROG="@PERL@" # Perl
-export RM_PROG="@RM@" # rm (Unix-like 'remove files')
-export TAR_PROG="@TAR@" # tar (Unix-like 'archiver')
-export WGET_PROG="@WGET@" # wget (remote file retrieval)
-
-# PROJECT_NAME:
-# Documentation/project name. Used in some of the resulting file names and
-# xrefs to uniquify two or more projects linked together through their
-# Doxygen's tag files. Mandatory for each documentation set.
-# Note: might be the same as the doxyfile's PROJECT_NAME
-# Example:
-# PROJECT_NAME=VTK
-#
-export PROJECT_NAME=CMake
-
-# PATH_TO_VTK_DOX_SCRIPTS:
-# Path to the directory holding the Perl scripts used to produce the VTK doc
-# in Doxygen format. You need the VTK source files or a local copy of
-# these scripts.
-# Example:
-# PATH_TO_VTK_DOX_SCRIPTS=@VTK_SOURCE_DIR@/Utilities/Doxygen
-#
-export PATH_TO_VTK_DOX_SCRIPTS="@VTK_SOURCE_DIR@/Utilities/Doxygen"
-
-# SOURCE_DIR:
-# Source directory. The top directory of the source files.
-# Example:
-# SOURCE_DIR=@VTK_SOURCE_DIR@
-#
-export SOURCE_DIR="@CMake_SOURCE_DIR@"
-
-# REL_PATH_TO_TOP:
-# Relative path from the top directory of the source files to the directory
-# (or top directory) holding the files to document. Useful if several parts
-# of the same source directory should be documented separately.
-# Example:
-# REL_PATH_TO_TOP=.
-# REL_PATH_TO_TOP=framework/src
-#
-# export REL_PATH_TO_TOP=Source
-export REL_PATH_TO_TOP=.
-
-# INTERMEDIATE_DOX_DIR:
-# Directory where the intermediate Doxygen files should be stored (mainly
-# these headers files converted from the VTK format to the Doxygen format).
-# This directory is erased at the end of this script, unless you comment
-# the corresponding line.
-# DOXTEMP might be used to simplify the syntax.
-# Example:
-# DOXTEMP=DOXTEMP=@VTK_BINARY_DIR@/Utilities/Doxygen
-# INTERMEDIATE_DOX_DIR=$DOXTEMP/dox
-#
-export DOXTEMP="@CMake_BINARY_DIR@/Utilities/Doxygen"
-export INTERMEDIATE_DOX_DIR="$DOXTEMP/dox"
-
-# DOXYFILE:
-# Path to the Doxygen configuration file (i.e. doxyfile).
-# Example:
-# DOXYFILE=$DOXTEMP/doxyfile
-#
-export DOXYFILE="$DOXTEMP/doxyfile"
-
-# OUTPUT_DIRECTORY ALLOW_ERASE_OUTPUT_DIRECTORY:
-# Path to the Doxygen output directory (where the resulting doc is stored).
-# Note: should be the same as your doxyfile's OUTPUT_DIRECTORY
-# If ON, allows the output directory to be erased when some advanced output
-# file have been produced (HTML Help, or TAR archive for example).
-# Example:
-# OUTPUT_DIRECTORY=$DOXTEMP/doc
-# ALLOW_ERASE_OUTPUT_DIRECTORY=ON
-#
-export OUTPUT_DIRECTORY="$DOXTEMP/doc"
-export ALLOW_ERASE_OUTPUT_DIRECTORY=ON
-
-# COMPILE_HTML_HELP RESULTING_HTML_HELP_FILE:
-# Compile the CHM (Compressed HTML) HTML Help file, name of the resulting
-# file. If set to ON and name is non-empty these options will actually
-# trigger the HTML-Help compiler to create the CHM. The resulting
-# file (usually index.chm) will be renamed to this name.
-# Note: if ON, the whole $OUTPUT_DIRECTORY will be erased at the end of
-# this script, since this file is considered to be one of the
-# advanced final output, unless ALLOW_ERASE_OUTPUT_DIRECTORY is OFF
-# Note: your doxyfile should be configured to enable HTML Help creation
-# (using GENERATE_HTML = YES, GENERATE_HTMLHELP = YES)
-# Example:
-# COMPILE_HTML_HELP=ON
-# COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@
-# RESULTING_HTML_HELP_FILE=$DOXTEMP/vtk4.chm
-#
-export COMPILE_HTML_HELP=@DOCUMENTATION_HTML_HELP@
-export RESULTING_HTML_HELP_FILE="$DOXTEMP/$PROJECT_NAME.chm"
-
-# CREATE_HTML_TARZ_ARCHIVE RESULTING_HTML_TARZ_ARCHIVE_FILE:
-# Create a compressed (gzip) tar archive of the html directory (located
-# under the OUTPUT_DIRECTORY), and name of the resulting archive file.
-# Note: your doxyfile should be configured to enable HTML creation
-# (using GENERATE_HTML = YES)
-# Example:
-# CREATE_HTML_TARZ_ARCHIVE=ON
-# CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@
-# RESULTING_HTML_TARZ_ARCHIVE_FILE=$DOXTEMP/vtk4-html.tar.gz
-# RESULTING_HTML_TARZ_ARCHIVE_FILE=$DOXTEMP/$PROJECT_NAME-html.tar.gz
-#
-export CREATE_HTML_TARZ_ARCHIVE=@DOCUMENTATION_HTML_TARZ@
-export RESULTING_HTML_TARZ_ARCHIVE_FILE="$DOXTEMP/$PROJECT_NAME-html.tar.gz"
-
-# ----------------------------------------------------------------------------
-# Build the contributors list.
-
-if test "x@VTK_SOURCE_DIR@" != "x" ; then
- if test "x$PERL_PROG" != "xNOTFOUND" ; then
- $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_contributors.pl" \
- --authors "$SOURCE_DIR/Utilities/Doxygen/authors.txt" \
- --cachedir "$DOXTEMP/cache" \
- --class_group '^(cm[A-Z0-9][A-Za-z0-9]+)\.(?:c|cpp|cxx|h|fl)$' \
- --files_in '(?:^hints|dummy|README|^Makefile\.borland|\.(?:c|cmake|cpp|cxx|h|html|in|java|fl|pl|py|tcl|txt))$' \
- --files_out '(?:^ChangeLog\.txt)$' \
- --gnuplot_file "$DOXTEMP/contrib/history.plt" \
- --history_img "|lines|$DOXTEMP/contrib/history.png" \
- --history_img "365|lines|$DOXTEMP/contrib/history2y.png" \
- --history_img "180|linespoints|$DOXTEMP/contrib/history6m.png" \
- --history_dir "$DOXTEMP/contrib" \
- --history_max_nb 10 \
- --lines_add 1.0 \
- --lines_rem 0.5 \
- --massive 50 \
- --max_class_nb 10 \
- --max_file_nb 5 \
- --min_class 0.02 \
- --min_file 0.01 \
- --min_contrib 0.05 \
- --min_gcontrib 0.0001 \
- --store "doc_""$PROJECT_NAME""_contributors.dox" \
- --relativeto "$SOURCE_DIR/$REL_PATH_TO_TOP" \
- --to "$INTERMEDIATE_DOX_DIR" \
- "$SOURCE_DIR/$REL_PATH_TO_TOP"
- fi
-
- if test "x$GNUPLOT_PROG" != "xNOTFOUND" ; then
- $GNUPLOT_PROG "$DOXTEMP/contrib/history.plt"
- fi
-fi
-
-# ----------------------------------------------------------------------------
-# Create the Doxygen doc.
-
-if test "x$DOXYGEN_PROG" != "xNOTFOUND" ; then
-
- if test "x$RM_PROG" != "xNOTFOUND" ; then
- $RM_PROG -fr "$OUTPUT_DIRECTORY"
- fi
-
- "$DOXYGEN_PROG" "$DOXYFILE"
-
- # yes, a second time, to get the contrib, I don't know why
- "$DOXYGEN_PROG" "$DOXYFILE"
-fi
-
-# ----------------------------------------------------------------------------
-# Clean the HTML pages to remove the path to the intermediate Doxygen dir.
-
-if test "x@VTK_SOURCE_DIR@" != "x" ; then
- if test "x$PERL_PROG" != "xNOTFOUND" ; then
- $PERL_PROG "$PATH_TO_VTK_DOX_SCRIPTS/doc_rmpath.pl" \
- --verbose \
- --to "$INTERMEDIATE_DOX_DIR" \
- --html "$OUTPUT_DIRECTORY/html"
- fi
-fi
-
-# ----------------------------------------------------------------------------
-# Create the CHM HTML HELP doc.
-
-if test "x$COMPILE_HTML_HELP" == "xON" ; then
- if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then
- cd $OUTPUT_DIRECTORY/html
- if test "x$HHC_PROG" != "xNOTFOUND" ; then
- "$HHC_PROG" index.hhp
- if test "x$MV_PROG" != "xNOTFOUND" ; then
- $MV_PROG -f index.chm "$RESULTING_HTML_HELP_FILE"
- fi
- fi
- fi
-fi
-
-# ----------------------------------------------------------------------------
-# Create the compressed tar archive.
-
-if test "x$CREATE_HTML_TARZ_ARCHIVE" == "xON" ; then
- if test "x$RESULTING_HTML_TARZ_ARCHIVE_FILE" != "x" ; then
- cd "$OUTPUT_DIRECTORY"
- if test "x$TAR_PROG" != "xNOTFOUND" ; then
- if test "x$RM_PROG" != "xNOTFOUND" ; then
- $RM_PROG -f html.tar
- fi
- $TAR_PROG -cf html.tar html
- if test "x$GZIP_PROG" != "xNOTFOUND" ; then
- if test "x$RM_PROG" != "xNOTFOUND" ; then
- $RM_PROG -f html.tar.gz
- fi
- $GZIP_PROG html.tar
- $MV_PROG -f html.tar.gz "$RESULTING_HTML_TARZ_ARCHIVE_FILE"
- fi
- fi
- fi
-fi
-
-# ----------------------------------------------------------------------------
-# Clean-up.
-
-if test "x$RM_PROG" != "xNOTFOUND" ; then
- $RM_PROG -fr "$INTERMEDIATE_DOX_DIR"
-
- if test "x$DOWNLOAD_VTK_TAGFILE" == "xON" ; then
- if test "x$VTK_TAGFILE" != "x" ; then
- $RM_PROG -f "$VTK_TAGFILE_DEST_DIR/$VTK_TAGFILE"
- fi
- fi
-
- if test "x$COMPILE_HTML_HELP" == "xON" ; then
- if test "x$RESULTING_HTML_HELP_FILE" != "x" ; then
- if test "x$ALLOW_ERASE_OUTPUT_DIRECTORY" == "xON" ; then
- $RM_PROG -fr "$OUTPUT_DIRECTORY"
- fi
- fi
- fi
-fi
diff --git a/Utilities/Doxygen/doxyfile.in b/Utilities/Doxygen/doxyfile.in
index 9743af721..73333406d 100644
--- a/Utilities/Doxygen/doxyfile.in
+++ b/Utilities/Doxygen/doxyfile.in
@@ -1,24 +1,30 @@
# -------------------------------------------------------------------------
-# doxyfile for CMake
-# modified by S. Barre (Time-stamp: <2002-02-13 18:24:35 barre>
+# doxyfile for CMakeReference
# -------------------------------------------------------------------------
PROJECT_NAME = CMake
+PROJECT_BRIEF = "Cross-platform Make"
+PROJECT_NUMBER = "@CMake_VERSION@"
+PROJECT_LOGO = "@CMake_SOURCE_DIR@/Source/QtDialog/CMakeSetup64.png"
FULL_PATH_NAMES = YES
+STRIP_FROM_PATH = \
+ "@CMake_SOURCE_DIR@/" \
+ "@CMake_BINARY_DIR@/"
+
WARN_IF_UNDOCUMENTED = NO
GENERATE_TREEVIEW = NO
GENERATE_TODOLIST = YES
GENERATE_BUGLIST = YES
-GENERATE_HTML = YES
+GENERATE_HTML = @GENERATE_HTML@
GENERATE_HTMLHELP = YES
+GENERATE_QHP = @GENERATE_QHP@
GENERATE_LATEX = NO
GENERATE_MAN = NO
GENERATE_RTF = NO
-HAVE_DOT = YES
-#HAVE_DOT = NO
+HAVE_DOT = @HAVE_DOT@
DOT_PATH = "@DOT_PATH@"
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
@@ -33,19 +39,21 @@ REFERENCES_RELATION = YES
ALLEXTERNALS = NO
-IMAGE_PATH = "@CMake_BINARY_DIR@/Utilities/Doxygen/contrib"
-
-OUTPUT_DIRECTORY = "@CMake_BINARY_DIR@/Utilities/Doxygen/doc"
+OUTPUT_DIRECTORY = "@CMakeDeveloperReference_BINARY_DIR@/developer-reference"
INPUT = \
+ "@CMake_SOURCE_DIR@/Utilities/Doxygen/DeveloperReference" \
"@CMake_SOURCE_DIR@/Source" \
"@CMake_SOURCE_DIR@/Source/CPack" \
+ "@CMake_SOURCE_DIR@/Source/CPack/IFW" \
+ "@CMake_SOURCE_DIR@/Source/CPack/WiX" \
"@CMake_SOURCE_DIR@/Source/CTest" \
"@CMake_SOURCE_DIR@/Source/CursesDialog" \
- "@CMake_SOURCE_DIR@/Source/MFCDialog" \
+ "@CMake_SOURCE_DIR@/Source/kwsys" \
+ "@CMake_SOURCE_DIR@/Source/QtDialog" \
+ "@CMake_BINARY_DIR@/Source" \
"@CMake_BINARY_DIR@/Source/kwsys" \
- "@CMake_BINARY_DIR@/Source/cmsys" \
- "@CMake_BINARY_DIR@/Utilities/Doxygen/dox/doc_CMake_contributors.dox" \
+ "@CMake_BINARY_DIR@/Source/cmsys"
EXTRACT_ALL = YES
EXTRACT_PRIVATE = NO
@@ -63,7 +71,7 @@ SORT_MEMBER_DOCS = NO
DISTRIBUTE_GROUP_DOC = YES
TAB_SIZE = 3
-FILE_PATTERNS = *.h *.hxx *.cxx
+FILE_PATTERNS = *.h *.hxx *.cxx *.dox
RECURSIVE = NO
EXCLUDE_PATTERNS =
@@ -77,3 +85,7 @@ MACRO_EXPANSION = YES
SEARCH_INCLUDES = YES
INCLUDE_PATH =
EXPAND_ONLY_PREDEF = YES
+
+QHP_NAMESPACE = org.cmake.developer-reference.@CMake_VERSION_MAJOR@@CMake_VERSION_MINOR@@CMake_VERSION_PATCH@
+QCH_FILE = ../CMakeDeveloperReference-@CMake_VERSION_MAJOR@@CMake_VERSION_MINOR@@CMake_VERSION_PATCH@.qch
+QHG_LOCATION = "@QHELPGENERATOR_EXECUTABLE@"
diff --git a/Utilities/Git/commit-msg b/Utilities/Git/commit-msg
index 9a5d1c1b3..348c3eaa1 100755
--- a/Utilities/Git/commit-msg
+++ b/Utilities/Git/commit-msg
@@ -1,15 +1,6 @@
#!/usr/bin/env bash
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
die() {
echo 'commit-msg hook failure' 1>&2
diff --git a/Utilities/Git/pre-commit b/Utilities/Git/pre-commit
index a35d11102..b63ae5e33 100755
--- a/Utilities/Git/pre-commit
+++ b/Utilities/Git/pre-commit
@@ -1,15 +1,6 @@
#!/usr/bin/env bash
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
die() {
echo 'pre-commit hook failure' 1>&2
@@ -38,6 +29,19 @@ die 'The following changes add lines too long for our C++ style:
Use lines strictly less than '"$line_too_long"' characters in C++ code.'
+#-----------------------------------------------------------------------------
+
+# Check that development setup is up-to-date.
+lastSetupForDevelopment=$(git config --get hooks.SetupForDevelopment || echo 0)
+eval $(grep '^SetupForDevelopment_VERSION=' "${BASH_SOURCE%/*}/../SetupForDevelopment.sh")
+test -n "$SetupForDevelopment_VERSION" || SetupForDevelopment_VERSION=0
+if test $lastSetupForDevelopment -lt $SetupForDevelopment_VERSION; then
+ die 'Developer setup in this work tree is out of date. Please re-run
+
+ Utilities/SetupForDevelopment.sh
+'
+fi
+
#-------------------------------------------------------------------------------
if test -z "$HOOKS_ALLOW_KWSYS"; then
# Disallow changes to KWSys
@@ -50,7 +54,7 @@ if test -z "$HOOKS_ALLOW_KWSYS"; then
should not be made directly in CMake. KWSys is kept in its own Git
repository and shared by several projects. Please visit
- http://public.kitware.com/Wiki/KWSys/Git
+ https://gitlab.kitware.com/utils/kwsys
to contribute changes directly to KWSys. Run
diff --git a/Utilities/Git/prepare-commit-msg b/Utilities/Git/prepare-commit-msg
index 1517bb2db..511472e19 100755
--- a/Utilities/Git/prepare-commit-msg
+++ b/Utilities/Git/prepare-commit-msg
@@ -1,15 +1,6 @@
#!/usr/bin/env bash
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2011 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
# This is a placeholder for future prepare-commit-msg hooks.
exit 0
diff --git a/Utilities/GitSetup/.gitattributes b/Utilities/GitSetup/.gitattributes
index facbbb21c..e96d1f8c5 100644
--- a/Utilities/GitSetup/.gitattributes
+++ b/Utilities/GitSetup/.gitattributes
@@ -1,7 +1,6 @@
.git* export-ignore
-# Exclude from source archives files specific to Git work tree.
-* export-ignore
-
+config* eol=lf whitespace=indent-with-non-tab
+git-* eol=lf whitespace=indent-with-non-tab
tips eol=lf whitespace=indent-with-non-tab
setup-* eol=lf whitespace=indent-with-non-tab
diff --git a/Utilities/GitSetup/README b/Utilities/GitSetup/README
index cf468fb68..2f9f1ec07 100644
--- a/Utilities/GitSetup/README
+++ b/Utilities/GitSetup/README
@@ -37,6 +37,13 @@ Commit the merge with an informative message:
the general GitSetup repository "setup" branch.
------------------------------------------------------------------------
+Optionally add to the project ".gitattributes" file the line
+
+ /Utilities/GitSetup export-ignore
+
+to exclude the GitSetup directory from inclusion by "git archive"
+since it does not make sense in source tarballs.
+
Configuration
-------------
diff --git a/Utilities/GitSetup/config b/Utilities/GitSetup/config
index b7d54235c..2b4f03703 100644
--- a/Utilities/GitSetup/config
+++ b/Utilities/GitSetup/config
@@ -1,9 +1,2 @@
[hooks]
- url = http://cmake.org/cmake.git
-[ssh]
- host = cmake.org
- key = id_git_cmake
- request-url = https://www.kitware.com/Admin/SendPassword.cgi
-[stage]
- url = git://cmake.org/stage/cmake.git
- pushurl = git@cmake.org:stage/cmake.git
+ url = https://gitlab.kitware.com/utils/gitsetup.git
diff --git a/Utilities/GitSetup/config.sample b/Utilities/GitSetup/config.sample
index bba2382c3..eeb468ba1 100644
--- a/Utilities/GitSetup/config.sample
+++ b/Utilities/GitSetup/config.sample
@@ -20,3 +20,13 @@
site = http://review.source.kitware.com
# pushurl placeholder "$username" is literal
pushurl = $username@review.source.kitware.com:Project
+
+[upstream]
+ url = git://public.kitware.com/Project.git
+
+[gitlab]
+ host = gitlab.kitware.com
+ group-path = group
+ group-name = Group
+ project-path = project
+ project-name = Project
diff --git a/Utilities/GitSetup/git-gerrit-push b/Utilities/GitSetup/git-gerrit-push
new file mode 100755
index 000000000..b46f753eb
--- /dev/null
+++ b/Utilities/GitSetup/git-gerrit-push
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2010-2015 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+USAGE="[<remote>] [--no-topic] [--dry-run] [--]"
+OPTIONS_SPEC=
+SUBDIRECTORY_OK=Yes
+. "$(git --exec-path)/git-sh-setup"
+
+#-----------------------------------------------------------------------------
+
+remote=''
+refspecs=''
+no_topic=''
+dry_run=''
+
+# Parse the command line options.
+while test $# != 0; do
+ case "$1" in
+ --no-topic) no_topic=1 ;;
+ --dry-run) dry_run=--dry-run ;;
+ --) shift; break ;;
+ -*) usage ;;
+ *) test -z "$remote" || usage ; remote="$1" ;;
+ esac
+ shift
+done
+test $# = 0 || usage
+
+# Default remote.
+test -n "$remote" || remote="gerrit"
+
+if test -z "$no_topic"; then
+ # Identify and validate the topic branch name.
+ head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic=''
+ if test -z "$topic" -o "$topic" = "master"; then
+ die 'Please name your topic:
+ git checkout -b descriptive-name'
+ fi
+ # The topic branch will be pushed by name.
+ refspecs="HEAD:refs/for/master/$topic $refspecs"
+fi
+
+# Fetch the current upstream master branch head.
+# This helps computation of a minimal pack to push.
+echo "Fetching $remote master"
+fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out"
+
+# Exit early if we have nothing to push.
+if test -z "$refspecs"; then
+ echo 'Nothing to push!'
+ exit 0
+fi
+
+# Push. Save output and exit code.
+echo "Pushing to $remote"
+push_stdout=$(git push --porcelain $dry_run "$remote" $refspecs); push_exit=$?
+echo "$push_stdout"
+
+# Reproduce the push exit code.
+exit $push_exit
diff --git a/Utilities/GitSetup/git-gitlab-push b/Utilities/GitSetup/git-gitlab-push
new file mode 100755
index 000000000..768f8534e
--- /dev/null
+++ b/Utilities/GitSetup/git-gitlab-push
@@ -0,0 +1,177 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2010-2015 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+USAGE='[<remote>] [<options>...] [--]
+
+OPTIONS
+
+--dry-run
+ Show what would be pushed without actually updating the destination
+
+-f,--force
+ Force-push the topic HEAD to rewrite the destination branch
+
+--no-default
+ Do not push the default branch (e.g. master)
+
+--no-topic
+ Do not push the topic HEAD.
+'
+OPTIONS_SPEC=
+SUBDIRECTORY_OK=Yes
+. "$(git --exec-path)/git-sh-setup"
+
+egrep-q() {
+ egrep "$@" >/dev/null 2>/dev/null
+}
+
+# Load the project configuration.
+gitlab_upstream='' &&
+gitlab_configured='' &&
+config="${BASH_SOURCE%/*}/config" &&
+protocol=$(git config -f "$config" --get gitlab.protocol ||
+ echo "https") &&
+host=$(git config -f "$config" --get gitlab.host) &&
+site=$(git config -f "$config" --get gitlab.site ||
+ echo "$protocol://$host") &&
+group_path=$(git config -f "$config" --get gitlab.group-path) &&
+project_path=$(git config -f "$config" --get gitlab.project-path) &&
+gitlab_upstream="$site/$group_path/$project_path.git" &&
+gitlab_pushurl=$(git config --get remote.gitlab.pushurl ||
+ git config --get remote.gitlab.url) &&
+gitlab_configured=1
+
+#-----------------------------------------------------------------------------
+
+remote=''
+refspecs=''
+force=''
+lease=false
+lease_flag=''
+no_topic=''
+no_default=''
+dry_run=''
+
+# Parse the command line options.
+while test $# != 0; do
+ case "$1" in
+ -f|--force) force='+'; lease=true ;;
+ --no-topic) no_topic=1 ;;
+ --dry-run) dry_run=--dry-run ;;
+ --no-default) no_default=1 ;;
+ --) shift; break ;;
+ -*) usage ;;
+ *) test -z "$remote" || usage ; remote="$1" ;;
+ esac
+ shift
+done
+test $# = 0 || usage
+
+# Default remote.
+test -n "$remote" || remote="gitlab"
+
+if test -z "$no_topic"; then
+ # Identify and validate the topic branch name.
+ head="$(git symbolic-ref HEAD)" && topic="${head#refs/heads/}" || topic=''
+ if test -z "$topic" -o "$topic" = "master"; then
+ die 'Please name your topic:
+ git checkout -b descriptive-name'
+ fi
+
+ if $lease; then
+ have_ref=false
+ remoteref="refs/remotes/$remote/$topic"
+ if git rev-parse --verify -q "$remoteref"; then
+ have_ref=true
+ else
+ die "It seems that a local ref for the branch is
+missing; forcing a push is dangerous and may overwrite
+previous work. Fetch from the $remote remote first or
+push without '-f' or '--force'."
+ fi
+
+ have_lease_flag=false
+ if git push -h | egrep-q -e '--force-with-lease'; then
+ have_lease_flag=true
+ fi
+
+ if $have_lease_flag && $have_ref; then
+ # Set the lease flag.
+ lease_flag="--force-with-lease=$topic:$remoteref"
+ # Clear the force string.
+ force=''
+ fi
+ fi
+
+ # The topic branch will be pushed by name.
+ refspecs="${force}HEAD:refs/heads/$topic $refspecs"
+fi
+
+# Fetch the current remote master branch head.
+# This helps computation of a minimal pack to push.
+echo "Fetching $remote master"
+fetch_out=$(git fetch "$remote" master 2>&1) || die "$fetch_out"
+gitlab_head=$(git rev-parse FETCH_HEAD) || exit
+
+# Fetch the current upstream master branch head.
+if origin_fetchurl=$(git config --get remote.origin.url) &&
+ test "$origin_fetchurl" = "$gitlab_upstream"; then
+ upstream_remote='origin'
+else
+ upstream_remote="$gitlab_upstream"
+fi
+echo "Fetching $upstream_remote master"
+fetch_out=$(git fetch "$upstream_remote" master 2>&1) || die "$fetch_out"
+upstream_head=$(git rev-parse FETCH_HEAD) || exit
+
+# Add a refspec to keep the remote master up to date if possible.
+if test -z "$no_default" &&
+ base=$(git merge-base "$gitlab_head" "$upstream_head") &&
+ test "$base" = "$gitlab_head"; then
+ refspecs="$upstream_head:refs/heads/master $refspecs"
+fi
+
+# Exit early if we have nothing to push.
+if test -z "$refspecs"; then
+ echo 'Nothing to push!'
+ exit 0
+fi
+
+# Push. Save output and exit code.
+echo "Pushing to $remote"
+push_config='-c advice.pushUpdateRejected=false'
+push_stdout=$(git $push_config push $lease_flag --porcelain $dry_run "$remote" $refspecs); push_exit=$?
+echo "$push_stdout"
+
+if test "$push_exit" -ne 0 && test -z "$force"; then
+ # Advise the user to fetch if needed.
+ if echo "$push_stdout" | egrep-q 'stale info'; then
+ echo "
+You have pushed to your branch from another machine; you may be overwriting
+commits unintentionally. Fetch from the $remote remote and check that you are
+not pushing an outdated branch."
+ fi
+
+ # Advise the user to force-push if needed.
+ if echo "$push_stdout" | egrep-q 'non-fast-forward'; then
+ echo '
+Add "-f" or "--force" to push a rewritten topic.'
+ fi
+fi
+
+# Reproduce the push exit code.
+exit $push_exit
diff --git a/Utilities/GitSetup/setup-gerrit b/Utilities/GitSetup/setup-gerrit
index 9e8fa6237..6d46e3ccf 100755
--- a/Utilities/GitSetup/setup-gerrit
+++ b/Utilities/GitSetup/setup-gerrit
@@ -28,6 +28,7 @@
# gerrit.pushurl = Review site push URL with "$username" placeholder
# gerrit.remote = Gerrit remote name, if not "gerrit"
# gerrit.url = Gerrit project URL, if not "$site/p/$project"
+# optionally with "$username" placeholder
die() {
echo 1>&2 "$@" ; exit 1
@@ -39,11 +40,12 @@ cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
site=$(git config -f config --get gerrit.site) &&
project=$(git config -f config --get gerrit.project) &&
-pushurl_=$(git config -f config --get gerrit.pushurl) &&
remote=$(git config -f config --get gerrit.remote ||
echo "gerrit") &&
-fetchurl=$(git config -f config --get gerrit.url ||
- echo "$site/p/$project") ||
+fetchurl_=$(git config -f config --get gerrit.url ||
+ echo "$site/p/$project") &&
+pushurl_=$(git config -f config --get gerrit.pushurl ||
+ git config -f config --get gerrit.url) ||
die 'This project is not configured to use Gerrit.'
# Get current gerrit push URL.
@@ -67,7 +69,7 @@ else
'"$project"' changes must be pushed to our Gerrit Code Review site:
- '"$fetchurl"'
+ '"$site/p/$project"'
Register a Gerrit account and select a username (used below).
You will need an OpenID:
@@ -96,13 +98,16 @@ Add your SSH public keys at
if test -z "$gu"; then
gu="$USER"
fi &&
+ fetchurl="${fetchurl_/\$username/$gu}" &&
if test -z "$pushurl"; then
git remote add "$remote" "$fetchurl"
else
git config remote."$remote".url "$fetchurl"
fi &&
pushurl="${pushurl_/\$username/$gu}" &&
- git config remote."$remote".pushurl "$pushurl" &&
+ if test "$pushurl" != "$fetchurl"; then
+ git config remote."$remote".pushurl "$pushurl"
+ fi &&
echo 'Remote "'"$remote"'" is now configured to push to
'"$pushurl"'
diff --git a/Utilities/GitSetup/setup-gitlab b/Utilities/GitSetup/setup-gitlab
new file mode 100755
index 000000000..9c7574d1e
--- /dev/null
+++ b/Utilities/GitSetup/setup-gitlab
@@ -0,0 +1,140 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2010-2015 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+# Run this script to set up the local Git repository to push to
+# a personal fork for this project in GitLab.
+
+# Project configuration instructions:
+#
+# - Run a GitLab server
+#
+# - Populate adjacent "config" file with:
+# gitlab.protocol = Top GitLab protocol, if not 'https'
+# gitlab.host = Top GitLab fully qualified host name
+# gitlab.site = Top GitLab URL, if not "<protocol>://<host>"
+# gitlab.group-name = Name of group containing project in GitLab
+# gitlab.group-path = Path of group containing project in GitLab
+# gitlab.project-name = Name of project within GitLab group
+# gitlab.project-path = Path of project within GitLab group
+# gitlab.url = GitLab push URL with "$username" placeholder,
+# if not "<site>/$username/<project-path>.git"
+# gitlab.pushurl = GitLab push URL with "$username" placeholder,
+# if not "git@<host>:$username/<project-path>.git"
+# gitlab.remote = GitLab remote name, if not "gitlab"
+
+die() {
+ echo 1>&2 "$@" ; exit 1
+}
+
+# Make sure we are inside the repository.
+cd "${BASH_SOURCE%/*}" &&
+
+# Load the project configuration.
+protocol=$(git config -f config --get gitlab.protocol ||
+ echo "https") &&
+host=$(git config -f config --get gitlab.host) &&
+site=$(git config -f config --get gitlab.site ||
+ echo "$protocol://$host") &&
+group_path=$(git config -f config --get gitlab.group-path) &&
+group_name=$(git config -f config --get gitlab.group-name) &&
+project_name=$(git config -f config --get gitlab.project-name) &&
+project_path=$(git config -f config --get gitlab.project-path) &&
+pushurl_=$(git config -f config --get gitlab.pushurl ||
+ echo "git@$host:\$username/$project_path.git") &&
+remote=$(git config -f config --get gitlab.remote ||
+ echo "gitlab") &&
+fetchurl_=$(git config -f config --get gitlab.url ||
+ echo "$site/\$username/$project_path.git") ||
+die 'This project is not configured to use GitLab.'
+
+# Get current gitlab push URL.
+pushurl=$(git config --get remote."$remote".pushurl ||
+ git config --get remote."$remote".url || echo '') &&
+
+# Tell user about current configuration.
+if test -n "$pushurl"; then
+ echo 'Remote "'"$remote"'" is currently configured to push to
+
+ '"$pushurl"'
+' &&
+ read -ep 'Reconfigure GitLab? [y/N]: ' ans &&
+ if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
+ setup=1
+ else
+ setup=''
+ fi
+else
+ echo 'Remote "'"$remote"'" is not yet configured.
+' &&
+ read -ep 'Configure GitLab to contribute to '"$project_name"'? [Y/n]: ' ans &&
+ if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
+ exit 0
+ else
+ setup=1
+ fi
+fi &&
+
+setup_instructions='Add your SSH public keys at
+
+ '"$site"'/profile/keys
+
+Then visit the main repository at:
+
+ '"$site/$group_path/$project_path"'
+
+and use the Fork button in the upper right.
+'
+
+# Perform setup if necessary.
+if test -n "$setup"; then
+ echo 'Sign-in to GitLab to get/set your username at
+
+ '"$site/profile/account"'
+
+'"$setup_instructions" &&
+ read -ep "GitLab username? [$USER]: " gu &&
+ if test -z "$gu"; then
+ gu="$USER"
+ fi &&
+ fetchurl="${fetchurl_/\$username/$gu}" &&
+ if test -z "$pushurl"; then
+ git remote add "$remote" "$fetchurl"
+ else
+ git config remote."$remote".url "$fetchurl"
+ fi &&
+ pushurl="${pushurl_/\$username/$gu}" &&
+ git config remote."$remote".pushurl "$pushurl" &&
+ echo 'Remote "'"$remote"'" is now configured to push to
+
+ '"$pushurl"'
+'
+fi &&
+
+# Optionally test GitLab access.
+if test -n "$pushurl"; then
+ read -ep 'Test access to GitLab (SSH)? [y/N]: ' ans &&
+ if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
+ echo -n 'Testing GitLab access by SSH...'
+ if git ls-remote --heads "$pushurl" >/dev/null; then
+ echo 'passed.'
+ else
+ echo 'failed.' &&
+ die 'Could not access your GitLab fork of this project.
+'"$setup_instructions"
+ fi
+ fi
+fi
diff --git a/Utilities/GitSetup/setup-hooks b/Utilities/GitSetup/setup-hooks
index c07985ae5..ca07712d5 100755
--- a/Utilities/GitSetup/setup-hooks
+++ b/Utilities/GitSetup/setup-hooks
@@ -55,6 +55,7 @@ fi &&
# Populate ".git/hooks".
echo 'Setting up git hooks...' &&
git_dir=$(git rev-parse --git-dir) &&
+mkdir -p "$git_dir/hooks" &&
cd "$git_dir/hooks" &&
if ! test -e .git; then
git init -q || die 'Could not run git init for hooks.'
diff --git a/Utilities/GitSetup/setup-stage b/Utilities/GitSetup/setup-stage
index 323e47aea..ce6ec4574 100755
--- a/Utilities/GitSetup/setup-stage
+++ b/Utilities/GitSetup/setup-stage
@@ -37,8 +37,8 @@ die() {
cd "${BASH_SOURCE%/*}" &&
# Load the project configuration.
-fetchurl=$(git config -f config --get stage.url) &&
-pushurl_=$(git config -f config --get stage.pushurl || echo '') &&
+fetchurl_=$(git config -f config --get stage.url) &&
+pushurl_=$(git config -f config --get stage.pushurl || echo "$fetchurl_") &&
remote=$(git config -f config --get stage.remote || echo 'stage') ||
die 'This project is not configured to use a topic stage.'
@@ -65,13 +65,16 @@ fi
# Perform setup if necessary.
if test -n "$setup"; then
echo 'Setting up the topic stage...' &&
+ fetchurl="${fetchurl_}" &&
if test -z "$pushurl"; then
git remote add "$remote" "$fetchurl"
else
git config remote."$remote".url "$fetchurl"
fi &&
pushurl="${pushurl_}" &&
- git config remote."$remote".pushurl "$pushurl" &&
+ if test "$pushurl" != "$fetchurl"; then
+ git config remote."$remote".pushurl "$pushurl"
+ fi &&
echo 'Remote "'"$remote"'" is now configured to push to
'"$pushurl"'
diff --git a/Utilities/GitSetup/setup-upstream b/Utilities/GitSetup/setup-upstream
new file mode 100755
index 000000000..92ce1dae5
--- /dev/null
+++ b/Utilities/GitSetup/setup-upstream
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2010-2015 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+# Run this script to set up the local Git repository to use the
+# preferred upstream repository URLs.
+
+# Project configuration instructions:
+#
+# - Populate adjacent "config" file with:
+# upstream.url = Preferred fetch url for upstream remote
+# upstream.remote = Preferred name for upstream remote, if not "origin"
+
+die() {
+ echo 1>&2 "$@" ; exit 1
+}
+
+# Make sure we are inside the repository.
+cd "${BASH_SOURCE%/*}" &&
+
+# Load the project configuration.
+url=$(git config -f config --get upstream.url) &&
+remote=$(git config -f config --get upstream.remote ||
+ echo 'origin') ||
+die 'This project is not configured to use a preferred upstream repository.'
+
+# Get current upstream URLs.
+fetchurl=$(git config --get remote."$remote".url || echo '') &&
+pushurl=$(git config --get remote."$remote".pushurl || echo '') &&
+
+if test "$fetchurl" = "$url"; then
+ echo 'Remote "'"$remote"'" already uses recommended upstream repository.'
+ exit 0
+fi
+
+upstream_recommend='
+We recommended configuring the "'"$remote"'" remote to fetch from upstream at
+
+ '"$url"'
+'
+
+# Tell user about current configuration.
+if test -n "$fetchurl"; then
+ echo 'Remote "'"$remote"'" is currently configured to fetch from
+
+ '"$fetchurl"'
+' &&
+ if test -n "$pushurl"; then
+ echo 'and push to
+
+ '"$pushurl"
+ fi &&
+ echo "$upstream_recommend" &&
+ if test -n "$pushurl"; then
+ echo 'and to never push to it directly.
+'
+ fi &&
+
+ read -ep 'Reconfigure "'"$remote"'" remote as recommended? [y/N]: ' ans &&
+ if [ "$ans" == "y" ] || [ "$ans" == "Y" ]; then
+ setup=1
+ else
+ setup=''
+ fi
+else
+ echo 'Remote "'"$remote"'" is not yet configured.' &&
+ echo "$upstream_recommend" &&
+ read -ep 'Configure "'"$remote"'" remote as recommended? [Y/n]: ' ans &&
+ if [ "$ans" == "n" ] || [ "$ans" == "N" ]; then
+ exit 0
+ else
+ setup=1
+ fi
+fi &&
+
+# Perform setup if necessary.
+if test -n "$setup"; then
+ if test -z "$fetchurl"; then
+ git remote add "$remote" "$url"
+ else
+ git config remote."$remote".url "$url" &&
+ if old=$(git config --get remote."$remote".pushurl); then
+ git config --unset remote."$remote".pushurl ||
+ echo 'Warning: failed to unset remote.'"$remote"'.pushurl'
+ fi
+ fi &&
+ echo 'Remote "'"$remote"'" is now configured to fetch from
+
+ '"$url"'
+'
+fi
diff --git a/Utilities/IWYU/mapping.imp b/Utilities/IWYU/mapping.imp
new file mode 100644
index 000000000..fe0f7df71
--- /dev/null
+++ b/Utilities/IWYU/mapping.imp
@@ -0,0 +1,161 @@
+[
+ # C++ alternatives to C standard headers
+ { include: [ "<assert.h>", public, "<cassert>", public ] },
+ { include: [ "<complex.h>", public, "<ccomplex>", public ] },
+ { include: [ "<ctype.h>", public, "<cctype>", public ] },
+ { include: [ "<errno.h>", public, "<cerrno>", public ] },
+ { include: [ "<float.h>", public, "<cfloat>", public ] },
+ { include: [ "<iso646.h>", public, "<ciso646>", public ] },
+ { include: [ "<limits.h>", public, "<climits>", public ] },
+ { include: [ "<locale.h>", public, "<clocale>", public ] },
+ { include: [ "<math.h>", public, "<cmath>", public ] },
+ { include: [ "<setjmp.h>", public, "<csetjmp>", public ] },
+ { include: [ "<signal.h>", public, "<csignal>", public ] },
+ { include: [ "<stdarg.h>", public, "<cstdarg>", public ] },
+ { include: [ "<stddef.h>", public, "<cstddef>", public ] },
+ { include: [ "<stdio.h>", public, "<cstdio>", public ] },
+ { include: [ "<stdlib.h>", public, "<cstdlib>", public ] },
+ { include: [ "<string.h>", public, "<cstring>", public ] },
+ { include: [ "<time.h>", public, "<ctime>", public ] },
+ { include: [ "<wchar.h>", public, "<cwchar>", public ] },
+ { include: [ "<wctype.h>", public, "<cwctype>", public ] },
+
+ # HACK: check whether this can be removed with next iwyu release.
+ { include: [ "<bits/std_function.h>", private, "<functional>", public ] },
+ { include: [ "<bits/time.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/clock_t.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_timespec.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_timeval.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/struct_tm.h>", private, "<time.h>", public ] },
+ { include: [ "<bits/types/time_t.h>", private, "<time.h>", public ] },
+
+ # HACK: check whether this can be removed with next iwyu release.
+ { symbol: [ "__GLIBC__", private, "<stdlib.h>", public ] },
+ { symbol: [ "_Noreturn", private, "<stdlib.h>", public ] },
+
+ # HACK: iwyu wrongly thinks that including <iosfwd> is sufficient.
+ { symbol: [ "std::stringstream", private, "<sstream>", public ] },
+ { symbol: [ "std::istringstream", private, "<sstream>", public ] },
+ { symbol: [ "std::ostringstream", private, "<sstream>", public ] },
+
+ # HACK: iwyu suggests those two files each time vector[] is used.
+ # https://github.com/include-what-you-use/include-what-you-use/issues/166
+ { include: [ "<ext/alloc_traits.h>", private, "<vector>", public ] },
+ { include: [ "<memory>", public, "<vector>", public ] },
+
+ # TODO: enable this block and remove some <utility> includes?
+ #{ symbol: [ "std::pair", private, "<utility>", public ] },
+ #{ symbol: [ "std::pair", private, "<map>", public ] },
+ #{ symbol: [ "std::pair", private, "<set>", public ] },
+
+ # IWYU wrongly suggests to include "cm_auto_ptr.hxx" in some places. This
+ # might be a misinterpretation of a template specialization in <utility>.
+ # As a workaround, map the symbol auto_ptr to "cmConfigure.h".
+ # This will still correctly require "cm_auto_ptr.hxx" for CM_AUTO_PTR.
+ { symbol: [ "cm::auto_ptr", private, "\"cmConfigure.h\"", public ] },
+
+ # __decay_and_strip is used internally in the C++11 standard library.
+ # IWYU does not classify it as internal and suggests to add <type_traits>.
+ # To ignore it, we simply map it to a file that is included anyway.
+ # TODO: Can this be simplified with an @-expression?
+ #{ symbol: [ "@std::__decay_and_strip<.*>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<cmCommand *&>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<cmGeneratorTarget *&>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<cmFindCommon::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<const std::basic_string<char> &>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<cmFindPackageCommand::PathLabel &>::__type", private, "\"cmConfigure.h\"", public ] },
+ { symbol: [ "std::__decay_and_strip<__gnu_cxx::__normal_iterator<const cmCTestTestHandler::cmCTestTestProperties *, std::vector<cmCTestTestHandler::cmCTestTestProperties, std::allocator<cmCTestTestHandler::cmCTestTestProperties> > > &>::__type", private, "\"cmConfigure.h\"", public ] },
+
+ # Wrappers for headers added in TR1 / C++11
+ # { include: [ "<array>", public, "\"cm_array.hxx\"", public ] },
+ # { include: [ "<functional>", public, "\"cm_functional.hxx\"", public ] },
+ # { include: [ "<memory>", public, "\"cm_memory.hxx\"", public ] },
+ { include: [ "<unordered_map>", public, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "<unordered_set>", public, "\"cm_unordered_set.hxx\"", public ] },
+ # { include: [ "<tr1/array>", public, "\"cm_array.hxx\"", public ] },
+ # { include: [ "<tr1/functional>", public, "\"cm_functional.hxx\"", public ] },
+ # { include: [ "<tr1/memory>", public, "\"cm_memory.hxx\"", public ] },
+ { include: [ "<tr1/unordered_map>", public, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "<tr1/unordered_set>", public, "\"cm_unordered_set.hxx\"", public ] },
+
+ # KWIML
+ { include: [ "<stdint.h>", public, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<inttypes.h>", public, "\"cm_kwiml.h\"", public ] },
+
+ # Self-sufficient wrapper for <sys/stat.h>
+ { include: [ "<sys/stat.h>", public, "\"cm_sys_stat.h\"", public ] },
+ { symbol: [ "mode_t", private, "\"cm_sys_stat.h\"", public ] },
+
+ # TODO: remove once TR1 / C++11 is required.
+ { include: [ "\"cmsys/hash_fun.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_fun.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_map.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hash_set.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+ { include: [ "\"cmsys/hashtable.hxx\"", private, "\"cm_unordered_map.hxx\"", public ] },
+ { include: [ "\"cmsys/hashtable.hxx\"", private, "\"cm_unordered_set.hxx\"", public ] },
+
+ # Wrappers for 3rd-party libraries used from the system.
+ { include: [ "<archive.h>", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "<archive_entry.h>", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "@<curl/.+\\.h>", private, "\"cm_curl.h\"", public ] },
+ { include: [ "<expat.h>", private, "\"cm_expat.h\"", public ] },
+ { include: [ "<expat_external.h>", private, "\"cm_expat.h\"", public ] },
+ { include: [ "<json/reader.h>", private, "\"cm_jsoncpp_reader.h\"", public ] },
+ { include: [ "<json/value.h>", private, "\"cm_jsoncpp_value.h\"", public ] },
+ { include: [ "<json/writer.h>", private, "\"cm_jsoncpp_writer.h\"", public ] },
+ { include: [ "<rhash.h>", private, "\"cm_rhash.h\"", public ] },
+ { include: [ "<uv.h>", private, "\"cm_uv.h\"", public ] },
+ { include: [ "@<uv-.+\\.h>", private, "\"cm_uv.h\"", public ] },
+ { include: [ "<kwiml/abi.h>", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<kwiml/int.h>", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "<xmlrpc.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "<xmlrpc_client.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "@<xmlrpc-c/.+\\.h>", private, "\"cm_xmlrpc.h\"", public ] },
+ { include: [ "<zconf.h>", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "<zlib.h>", private, "\"cm_zlib.h\"", public ] },
+
+ # Wrappers for bundled 3rd-party libraries.
+ { include: [ "\"cmlibarchive/libarchive/archive.h\"", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "\"cmlibarchive/libarchive/archive_entry.h\"", private, "\"cm_libarchive.h\"", public ] },
+ { include: [ "@\"cmcurl/include/curl/.+\\.h\"", private, "\"cm_curl.h\"", public ] },
+ { include: [ "\"cmexpat/lib/expat.h\"", private, "\"cm_expat.h\"", public ] },
+ { include: [ "\"cmexpat/lib/expat_external.h\"", private, "\"cm_expat.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/reader.h\"", private, "\"cm_jsoncpp_reader.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/value.h\"", private, "\"cm_jsoncpp_value.h\"", public ] },
+ { include: [ "\"cmjsoncpp/include/json/writer.h\"", private, "\"cm_jsoncpp_writer.h\"", public ] },
+ { include: [ "\"cmlibrhash/librhash/rhash.h\"", private, "\"cm_rhash.h\"", public ] },
+ { include: [ "\"cmlibuv/include/uv.h\"", private, "\"cm_uv.h\"", public ] },
+ { include: [ "@\"cmlibuv/include/uv-.+\\.h\"", private, "\"cm_uv.h\"", public ] },
+ { include: [ "\"KWIML/include/kwiml/abi.h\"", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "\"KWIML/include/kwiml/int.h\"", private, "\"cm_kwiml.h\"", public ] },
+ { include: [ "\"cmzlib/cm_zlib_mangle.h\"", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "\"cmzlib/zconf.h\"", private, "\"cm_zlib.h\"", public ] },
+ { include: [ "\"cmzlib/zlib.h\"", private, "\"cm_zlib.h\"", public ] },
+
+ # System symbols used by libuv
+ { symbol: [ "SIGHUP", private, "\"cm_uv.h\"", public ] },
+ { symbol: [ "SIGINT", private, "\"cm_uv.h\"", public ] },
+ { symbol: [ "ssize_t", private, "\"cm_uv.h\"", public ] },
+
+ { symbol: [ "std::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "std::ofstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "cmsys::ifstream", private, "\"cmsys/FStream.hxx\"", public ] },
+ { symbol: [ "cmsys::ofstream", private, "\"cmsys/FStream.hxx\"", public ] },
+
+ { include: [ "<istream>", public, "\"cmsys/FStream.hxx\"", public ] },
+ { include: [ "<ostream>", public, "\"cmsys/FStream.hxx\"", public ] },
+ { include: [ "<fstream>", public, "\"cmsys/FStream.hxx\"", public ] },
+
+ # major and minor are used as macro arguments. Those are false matches.
+ { symbol: [ "major", private, "\"cm_kwiml.h\"", public ] },
+ { symbol: [ "minor", private, "\"cm_kwiml.h\"", public ] },
+ { symbol: [ "major", private, "\"cmVersion.h\"", public ] },
+ { symbol: [ "minor", private, "\"cmVersion.h\"", public ] },
+
+ { include: [ "<curses.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
+ { include: [ "\"form.h\"", private, "\"cmCursesStandardIncludes.h\"", public ] },
+ { include: [ "<form.h>", private, "\"cmCursesStandardIncludes.h\"", public ] },
+]
+
+# vim: set ft=toml:
diff --git a/Utilities/KWIML/.gitattributes b/Utilities/KWIML/.gitattributes
new file mode 100644
index 000000000..ecbf2196c
--- /dev/null
+++ b/Utilities/KWIML/.gitattributes
@@ -0,0 +1 @@
+*.md conflict-marker-size=78
diff --git a/Utilities/KWIML/ABI.h.in b/Utilities/KWIML/ABI.h.in
deleted file mode 100644
index b71cdfb9f..000000000
--- a/Utilities/KWIML/ABI.h.in
+++ /dev/null
@@ -1,492 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 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:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * 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.
-
- * Neither the name of Kitware, Inc. nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-============================================================================*/
-#ifndef @KWIML@_ABI_H
-#define @KWIML@_ABI_H
-/*
-This header defines macros with information about the C ABI.
-Only information that can be determined using the preprocessor at
-compilation time is available. No try-compile results may be added
-here. Instead we memorize results on platforms of interest.
-
-An includer may optionally define the following macros to suppress errors:
-
- @KWIML@_ABI_NO_VERIFY = skip verification declarations
- @KWIML@_ABI_NO_ERROR_CHAR_SIGN = signedness of 'char' may be unknown
- @KWIML@_ABI_NO_ERROR_LONG_LONG = existence of 'long long' may be unknown
- @KWIML@_ABI_NO_ERROR_ENDIAN = byte order of CPU may be unknown
-
-An includer may test the following macros after inclusion:
-
- @KWIML@_ABI_SIZEOF_DATA_PTR = sizeof(void*)
- @KWIML@_ABI_SIZEOF_CODE_PTR = sizeof(void(*)(void))
- @KWIML@_ABI_SIZEOF_FLOAT = sizeof(float)
- @KWIML@_ABI_SIZEOF_DOUBLE = sizeof(double)
- @KWIML@_ABI_SIZEOF_CHAR = sizeof(char)
- @KWIML@_ABI_SIZEOF_SHORT = sizeof(short)
- @KWIML@_ABI_SIZEOF_INT = sizeof(int)
- @KWIML@_ABI_SIZEOF_LONG = sizeof(long)
-
- @KWIML@_ABI_SIZEOF_LONG_LONG = sizeof(long long) or 0 if not a type
- Undefined if existence is unknown and error suppression macro
- @KWIML@_ABI_NO_ERROR_LONG_LONG was defined.
-
- @KWIML@_ABI_SIZEOF___INT64 = 8 if '__int64' exists or 0 if not
- Undefined if existence is unknown.
-
- @KWIML@_ABI___INT64_IS_LONG = 1 if '__int64' is 'long' (same type)
- Undefined otherwise.
- @KWIML@_ABI___INT64_IS_LONG_LONG = 1 if '__int64' is 'long long' (same type)
- Undefined otherwise.
- @KWIML@_ABI___INT64_IS_UNIQUE = 1 if '__int64' is a distinct type
- Undefined otherwise.
-
- @KWIML@_ABI_CHAR_IS_UNSIGNED = 1 if 'char' is unsigned, else undefined
- @KWIML@_ABI_CHAR_IS_SIGNED = 1 if 'char' is signed, else undefined
- One of these is defined unless signedness of 'char' is unknown and
- error suppression macro @KWIML@_ABI_NO_ERROR_CHAR_SIGN was defined.
-
- @KWIML@_ABI_ENDIAN_ID_BIG = id for big-endian (always defined)
- @KWIML@_ABI_ENDIAN_ID_LITTLE = id for little-endian (always defined)
- @KWIML@_ABI_ENDIAN_ID = id of byte order of target CPU
- Defined to @KWIML@_ABI_ENDIAN_ID_BIG or @KWIML@_ABI_ENDIAN_ID_LITTLE
- unless byte order is unknown and error suppression macro
- @KWIML@_ABI_NO_ERROR_ENDIAN was defined.
-
-We verify most results using dummy "extern" declarations that are
-invalid if the macros are wrong. Verification is disabled if
-suppression macro @KWIML@_ABI_NO_VERIFY was defined.
-*/
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_DATA_PTR)
-# if defined(__SIZEOF_POINTER__)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR __SIZEOF_POINTER__
-# elif defined(_SIZE_PTR)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR (_SIZE_PTR >> 3)
-# elif defined(_LP64) || defined(__LP64__)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(_ILP32)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 4
-# elif defined(__64BIT__) /* IBM XL */
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(_M_X64)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(__ia64)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(__sparcv9)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(__x86_64) || defined(__x86_64__)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(__amd64) || defined(__amd64__)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 8
-# elif defined(__i386) || defined(__i386__)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 4
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_DATA_PTR)
-# define @KWIML@_ABI_SIZEOF_DATA_PTR 4
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_CODE_PTR)
-# define @KWIML@_ABI_SIZEOF_CODE_PTR @KWIML@_ABI_SIZEOF_DATA_PTR
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_CHAR)
-# define @KWIML@_ABI_SIZEOF_CHAR 1
-#endif
-
-#if !defined(@KWIML@_ABI_CHAR_IS_UNSIGNED) && !defined(@KWIML@_ABI_CHAR_IS_SIGNED)
-# if defined(__CHAR_UNSIGNED__) /* GNU, some IBM XL, others? */
-# define @KWIML@_ABI_CHAR_IS_UNSIGNED 1
-# elif defined(_CHAR_UNSIGNED) /* Intel, IBM XL, MSVC, Borland, others? */
-# define @KWIML@_ABI_CHAR_IS_UNSIGNED 1
-# elif defined(_CHAR_SIGNED) /* IBM XL, others? */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__CHAR_SIGNED__) /* IBM XL, Watcom, others? */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__SIGNED_CHARS__) /* EDG, Intel, SGI MIPSpro */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(_CHAR_IS_SIGNED) /* Some SunPro, others? */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(_CHAR_IS_UNSIGNED) /* SunPro, others? */
-# define @KWIML@_ABI_CHAR_IS_UNSIGNED 1
-# elif defined(__GNUC__) /* GNU default */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* SunPro default */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__HP_cc) || defined(__HP_aCC) /* HP default (unless +uc) */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(_SGI_COMPILER_VERSION) /* SGI MIPSpro default */
-# define @KWIML@_ABI_CHAR_IS_UNSIGNED 1
-# elif defined(__PGIC__) /* PGI default */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(_MSC_VER) /* MSVC default */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__WATCOMC__) /* Watcom default */
-# define @KWIML@_ABI_CHAR_IS_UNSIGNED 1
-# elif defined(__BORLANDC__) /* Borland default */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1
-# elif defined(__hpux) /* Old HP: no __HP_cc/__HP_aCC/__GNUC__ above */
-# define @KWIML@_ABI_CHAR_IS_SIGNED 1 /* (unless +uc) */
-# endif
-#endif
-#if !defined(@KWIML@_ABI_CHAR_IS_UNSIGNED) && !defined(@KWIML@_ABI_CHAR_IS_SIGNED) \
- && !defined(@KWIML@_ABI_NO_ERROR_CHAR_SIGN)
-# error "Signedness of 'char' unknown."
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_SHORT)
-# if defined(__SIZEOF_SHORT__)
-# define @KWIML@_ABI_SIZEOF_SHORT __SIZEOF_SHORT__
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_SHORT)
-# define @KWIML@_ABI_SIZEOF_SHORT 2
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_INT)
-# if defined(__SIZEOF_INT__)
-# define @KWIML@_ABI_SIZEOF_INT __SIZEOF_INT__
-# elif defined(_SIZE_INT)
-# define @KWIML@_ABI_SIZEOF_INT (_SIZE_INT >> 3)
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_INT)
-# define @KWIML@_ABI_SIZEOF_INT 4
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_LONG)
-# if defined(__SIZEOF_LONG__)
-# define @KWIML@_ABI_SIZEOF_LONG __SIZEOF_LONG__
-# elif defined(_SIZE_LONG)
-# define @KWIML@_ABI_SIZEOF_LONG (_SIZE_LONG >> 3)
-# elif defined(__LONG_MAX__)
-# if __LONG_MAX__ == 0x7fffffff
-# define @KWIML@_ABI_SIZEOF_LONG 4
-# elif __LONG_MAX__>>32 == 0x7fffffff
-# define @KWIML@_ABI_SIZEOF_LONG 8
-# endif
-# elif defined(_MSC_VER) /* MSVC and Intel on Windows */
-# define @KWIML@_ABI_SIZEOF_LONG 4
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_LONG)
-# define @KWIML@_ABI_SIZEOF_LONG @KWIML@_ABI_SIZEOF_DATA_PTR
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_LONG_LONG)
-# if defined(__SIZEOF_LONG_LONG__)
-# define @KWIML@_ABI_SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
-# elif defined(__LONG_LONG_MAX__)
-# if __LONG_LONG_MAX__ == 0x7fffffff
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 4
-# elif __LONG_LONG_MAX__>>32 == 0x7fffffff
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# endif
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_LONG_LONG)
-# if defined(_LONGLONG) /* SGI, some GNU, perhaps others. */ \
- && !defined(_MSC_VER)
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(_LONG_LONG) /* IBM XL, perhaps others. */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__NO_LONG_LONG) /* EDG */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 0
-# elif defined(__cplusplus) && __cplusplus > 199711L /* C++0x */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* SunPro */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__HP_cc) || defined(__HP_aCC) /* HP */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__PGIC__) /* PGI */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__WATCOMC__) /* Watcom */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__INTEL_COMPILER) /* Intel */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__BORLANDC__) /* Borland */
-# if __BORLANDC__ >= 0x0560
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# else
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 0
-# endif
-# elif defined(_MSC_VER) /* Microsoft */
-# if _MSC_VER >= 1310
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# else
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 0
-# endif
-# elif defined(__GNUC__) /* GNU */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# elif defined(__hpux) /* Old HP: no __HP_cc/__HP_aCC/__GNUC__ above */
-# define @KWIML@_ABI_SIZEOF_LONG_LONG 8
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && !defined(@KWIML@_ABI_NO_ERROR_LONG_LONG)
-# error "Existence of 'long long' unknown."
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF___INT64)
-# if defined(__INTEL_COMPILER)
-# define @KWIML@_ABI_SIZEOF___INT64 8
-# elif defined(_MSC_VER)
-# define @KWIML@_ABI_SIZEOF___INT64 8
-# elif defined(__BORLANDC__)
-# define @KWIML@_ABI_SIZEOF___INT64 8
-# else
-# define @KWIML@_ABI_SIZEOF___INT64 0
-# endif
-#endif
-
-#if defined(@KWIML@_ABI_SIZEOF___INT64) && @KWIML@_ABI_SIZEOF___INT64 > 0
-# if @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_ABI___INT64_IS_LONG 1
-# elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# define @KWIML@_ABI___INT64_IS_LONG_LONG 1
-# else
-# define @KWIML@_ABI___INT64_IS_UNIQUE 1
-# endif
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_FLOAT)
-# if defined(__SIZEOF_FLOAT__)
-# define @KWIML@_ABI_SIZEOF_FLOAT __SIZEOF_FLOAT__
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_FLOAT)
-# define @KWIML@_ABI_SIZEOF_FLOAT 4
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_SIZEOF_DOUBLE)
-# if defined(__SIZEOF_DOUBLE__)
-# define @KWIML@_ABI_SIZEOF_DOUBLE __SIZEOF_DOUBLE__
-# endif
-#endif
-#if !defined(@KWIML@_ABI_SIZEOF_DOUBLE)
-# define @KWIML@_ABI_SIZEOF_DOUBLE 8
-#endif
-
-/*--------------------------------------------------------------------------*/
-/* Identify possible endian cases. The macro @KWIML@_ABI_ENDIAN_ID will be
- defined to one of these, or undefined if unknown. */
-#if !defined(@KWIML@_ABI_ENDIAN_ID_BIG)
-# define @KWIML@_ABI_ENDIAN_ID_BIG 4321
-#endif
-#if !defined(@KWIML@_ABI_ENDIAN_ID_LITTLE)
-# define @KWIML@_ABI_ENDIAN_ID_LITTLE 1234
-#endif
-#if @KWIML@_ABI_ENDIAN_ID_BIG == @KWIML@_ABI_ENDIAN_ID_LITTLE
-# error "@KWIML@_ABI_ENDIAN_ID_BIG == @KWIML@_ABI_ENDIAN_ID_LITTLE"
-#endif
-
-#if defined(@KWIML@_ABI_ENDIAN_ID) /* Skip #elif cases if already defined. */
-
-/* Use dedicated symbols if the compiler defines them. Do this first
- because some architectures allow runtime byte order selection by
- the operating system (values for such architectures below are
- guesses for compilers that do not define a dedicated symbol).
- Ensure that only one is defined in case the platform or a header
- defines both as possible values for some third symbol. */
-#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-#elif defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-#elif defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* Alpha */
-#elif defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* Arm */
-#elif defined(__arm__)
-# if !defined(__ARMEB__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-# else
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-# endif
-
-/* Intel x86 */
-#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-#elif defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-#elif defined(__MWERKS__) && defined(__INTEL__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* Intel x86-64 */
-#elif defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-#elif defined(__amd64) || defined(__amd64__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* Intel Architecture-64 (Itanium) */
-#elif defined(__ia64) || defined(__ia64__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-#elif defined(_IA64) || defined(__IA64__) || defined(_M_IA64)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* PowerPC */
-#elif defined(__powerpc) || defined(__powerpc__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-#elif defined(__ppc) || defined(__ppc__) || defined(__POWERPC__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* SPARC */
-#elif defined(__sparc) || defined(__sparc__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* HP/PA RISC */
-#elif defined(__hppa) || defined(__hppa__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* Motorola 68k */
-#elif defined(__m68k__) || defined(M68000)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* MIPSel (MIPS little endian) */
-#elif defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-
-/* MIPSeb (MIPS big endian) */
-#elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* MIPS (fallback, big endian) */
-#elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* RS/6000 */
-#elif defined(__THW_RS600) || defined(_IBMR2) || defined(_POWER)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-#elif defined(_ARCH_PWR) || defined(_ARCH_PWR2)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* System/370 */
-#elif defined(__370__) || defined(__THW_370__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* System/390 */
-#elif defined(__s390__) || defined(__s390x__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* z/Architecture */
-#elif defined(__SYSC_ZARCH__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* VAX */
-#elif defined(__vax__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-
-/* Aarch64 */
-#elif defined(__aarch64__)
-# if !defined(__AARCH64EB__)
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_LITTLE
-# else
-# define @KWIML@_ABI_ENDIAN_ID @KWIML@_ABI_ENDIAN_ID_BIG
-# endif
-
-/* Unknown CPU */
-#elif !defined(@KWIML@_ABI_NO_ERROR_ENDIAN)
-# error "Byte order of target CPU unknown."
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_ABI_NO_VERIFY)
-#define @KWIML@_ABI__VERIFY(n, x, y) extern int (*n)[x]; extern int (*n)[y]
-#define @KWIML@_ABI__VERIFY2(n, x, y) extern int (*n)(x*); extern int (*n)(y*)
-#if defined(__cplusplus)
-# define @KWIML@_ABI__VERIFY3(n, x, y) extern int* n(x*); extern char* n(y*)
-#else
-# define @KWIML@_ABI__VERIFY3(n, x, y) extern int* n(x*) /* TODO: possible? */
-#endif
-#define @KWIML@_ABI__VERIFY_BOOL(m, b) @KWIML@_ABI__VERIFY(m##__VERIFY__, 2, (b)?2:3)
-#define @KWIML@_ABI__VERIFY_SIZE(m, t) @KWIML@_ABI__VERIFY(m##__VERIFY__, m, sizeof(t))
-#define @KWIML@_ABI__VERIFY_SAME(m, x, y) @KWIML@_ABI__VERIFY2(m##__VERIFY__, x, y)
-#define @KWIML@_ABI__VERIFY_DIFF(m, x, y) @KWIML@_ABI__VERIFY3(m##__VERIFY__, x, y)
-
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_DATA_PTR, int*);
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_CODE_PTR, int(*)(int));
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_CHAR, char);
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_SHORT, short);
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_INT, int);
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_LONG, long);
-#if defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG > 0
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_LONG_LONG, long long);
-#endif
-#if defined(@KWIML@_ABI_SIZEOF___INT64) && @KWIML@_ABI_SIZEOF___INT64 > 0
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF___INT64, __int64);
-#endif
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_FLOAT, float);
-@KWIML@_ABI__VERIFY_SIZE(@KWIML@_ABI_SIZEOF_DOUBLE, double);
-
-#if defined(@KWIML@_ABI___INT64_IS_LONG)
-@KWIML@_ABI__VERIFY_SAME(@KWIML@_ABI___INT64_IS_LONG, __int64, long);
-#elif defined(@KWIML@_ABI___INT64_IS_LONG_LONG)
-@KWIML@_ABI__VERIFY_SAME(@KWIML@_ABI___INT64_IS_LONG_LONG, __int64, long long);
-#elif defined(@KWIML@_ABI_SIZEOF___INT64) && @KWIML@_ABI_SIZEOF___INT64 > 0
-@KWIML@_ABI__VERIFY_DIFF(@KWIML@_ABI___INT64_NOT_LONG, __int64, long);
-# if defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG > 0
-@KWIML@_ABI__VERIFY_DIFF(@KWIML@_ABI___INT64_NOT_LONG_LONG, __int64, long long);
-# endif
-#endif
-
-#if defined(@KWIML@_ABI_CHAR_IS_UNSIGNED)
-@KWIML@_ABI__VERIFY_BOOL(@KWIML@_ABI_CHAR_IS_UNSIGNED, (char)0x80 > 0);
-#elif defined(@KWIML@_ABI_CHAR_IS_SIGNED)
-@KWIML@_ABI__VERIFY_BOOL(@KWIML@_ABI_CHAR_IS_SIGNED, (char)0x80 < 0);
-#endif
-
-#undef @KWIML@_ABI__VERIFY_DIFF
-#undef @KWIML@_ABI__VERIFY_SAME
-#undef @KWIML@_ABI__VERIFY_SIZE
-#undef @KWIML@_ABI__VERIFY_BOOL
-#undef @KWIML@_ABI__VERIFY3
-#undef @KWIML@_ABI__VERIFY2
-#undef @KWIML@_ABI__VERIFY
-
-#endif
-
-#endif
diff --git a/Utilities/KWIML/CMakeLists.txt b/Utilities/KWIML/CMakeLists.txt
index 62b6fffb7..15e65e5c7 100644
--- a/Utilities/KWIML/CMakeLists.txt
+++ b/Utilities/KWIML/CMakeLists.txt
@@ -1,52 +1,29 @@
-#=============================================================================
-# Kitware Information Macro Library
-# Copyright 2010-2011 Kitware, Inc.
#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
+# Copyright Kitware, Inc.
+# Distributed under the OSI-approved BSD 3-Clause License.
+# See accompanying file Copyright.txt for details.
#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-
-# Import the KWIML directory tree into a subdirectory under a parent
-# project and configure the library as follows:
-#
-# set(KWIML myIML)
-# subdirs(KWIML)
-#
-# Optional settings are as follows:
-#
-# KWIML_HEADER_ROOT = build tree directory to hold KWIML headers.
-# Headers will go in a directory called "${KWIML}" under this root.
-# For example:
-#
-# set(KWIML_HEADER_ROOT ${PROJECT_BINARY_DIR})
-# include_directories(${PROJECT_BINARY_DIR})
-#
-# KWIML_INSTALL_INCLUDE_DIR = install KWIML with "make install"
-# Specify a value relative to the install prefix and do NOT start with '/'.
-# KWIML_INSTALL_INCLUDE_OPTIONS = extra header installation options
-# Specify options for the install(FILES) command.
-#
-# KWIML_LABELS_TEST = list of labels for KWIML tests
-
-cmake_minimum_required(VERSION 2.6.3 FATAL_ERROR)
-
-#-----------------------------------------------------------------------------
-if(NOT DEFINED KWIML)
- if(NOT "${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
- message(FATAL_ERROR "Set KWIML namespace in parent directory!")
- endif()
- set(KWIML KWIML)
- set(KWIML_STANDALONE 1)
+if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
+ cmake_minimum_required(VERSION 3.0 FATAL_ERROR)
+ set(kwiml_standalone 1)
project(KWIML)
include(CTest)
mark_as_advanced(BUILD_TESTING)
+ if(BUILD_TESTING)
+ set(KWIML_TEST_ENABLE 1)
+ endif()
+ if(NOT DEFINED KWIML_INSTALL_INCLUDE_DIR)
+ set(KWIML_INSTALL_INCLUDE_DIR include)
+ endif()
+ set(KWIML_INCLUDE_PREFIX kwiml)
+else()
+ cmake_minimum_required(VERSION 2.8.2 FATAL_ERROR)
+ set(kwiml_standalone 0)
+ if(KWIML_INSTALL_INCLUDE_DIR AND NOT DEFINED KWIML_INCLUDE_PREFIX)
+ message(FATAL_ERROR "Host project must set KWIML_INCLUDE_PREFIX")
+ endif()
endif()
-#-----------------------------------------------------------------------------
get_property(KWIML_LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(lang ${KWIML_LANGUAGES})
set(KWIML_LANGUAGE_${lang} 1)
@@ -55,25 +32,73 @@ if(NOT KWIML_LANGUAGE_C AND NOT KWIML_LANGUAGE_CXX)
set(BUILD_TESTING OFF)
endif()
-#-----------------------------------------------------------------------------
-if(NOT KWIML_HEADER_ROOT)
- set(KWIML_HEADER_ROOT "${PROJECT_BINARY_DIR}")
+if(KWIML_INSTALL_INCLUDE_DIR)
+ install(FILES
+ include/kwiml/abi.h
+ include/kwiml/int.h
+ DESTINATION ${KWIML_INSTALL_INCLUDE_DIR}/${KWIML_INCLUDE_PREFIX}
+ ${KWIML_INSTALL_INCLUDE_OPTIONS}
+ )
endif()
-set(KWIML_HEADER_DIR "${KWIML_HEADER_ROOT}/${KWIML}")
-include_directories(${KWIML_HEADER_ROOT})
-#-----------------------------------------------------------------------------
-foreach(h ABI INT)
- set(header ${KWIML_HEADER_DIR}/${h}.h)
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${h}.h.in ${header} @ONLY)
- if(KWIML_INSTALL_INCLUDE_DIR)
- install(FILES ${header}
- DESTINATION ${KWIML_INSTALL_INCLUDE_DIR}/${KWIML}
- ${KWIML_INSTALL_INCLUDE_OPTIONS})
- endif()
-endforeach()
-
-#-----------------------------------------------------------------------------
-if(BUILD_TESTING)
+if(KWIML_TEST_ENABLE)
add_subdirectory(test)
endif()
+
+if(NOT kwiml_standalone)
+ return()
+endif()
+
+#----------------------------------------------------------------------------
+set(KWIML_VERSION 1.0.0)
+if(KWIML_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(KWIML_VERSION_MAJOR "${CMAKE_MATCH_1}")
+ set(KWIML_VERSION_MINOR "${CMAKE_MATCH_2}")
+ set(KWIML_VERSION_PATCH "${CMAKE_MATCH_3}")
+ math(EXPR KWIML_VERSION_DECIMAL
+ "${KWIML_VERSION_MAJOR}*1000000 + ${KWIML_VERSION_MINOR}*1000 + ${KWIML_VERSION_PATCH}")
+else()
+ message(FATAL_ERROR "Failed to parse KWIML_VERSION='${KWIML_VERSION}'")
+endif()
+
+configure_file(src/version.h.in include/kwiml/version.h @ONLY)
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/include/kwiml/version.h
+ DESTINATION ${KWIML_INSTALL_INCLUDE_DIR}/kwiml
+ )
+
+if(NOT KWIML_INSTALL_PACKAGE_DIR)
+ set(KWIML_INSTALL_PACKAGE_DIR share/cmake/kwiml-${KWIML_VERSION_MAJOR}.${KWIML_VERSION_MINOR})
+endif()
+
+add_library(kwiml INTERFACE)
+target_include_directories(kwiml INTERFACE
+ $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/${KWIML_INSTALL_INCLUDE_DIR}>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
+ $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
+ )
+export(TARGETS kwiml
+ NAMESPACE kwiml::
+ FILE kwiml-targets.cmake
+ )
+install(TARGETS kwiml
+ DESTINATION lib
+ EXPORT kwiml-targets
+ )
+install(EXPORT kwiml-targets
+ NAMESPACE kwiml::
+ DESTINATION ${KWIML_INSTALL_PACKAGE_DIR}
+ )
+
+configure_file(src/kwiml-config.cmake.in kwiml-config.cmake @ONLY)
+include(CMakePackageConfigHelpers)
+write_basic_package_version_file(
+ "${CMAKE_CURRENT_BINARY_DIR}/kwiml-config-version.cmake"
+ VERSION ${KWIML_VERSION}
+ COMPATIBILITY AnyNewerVersion
+ )
+install(FILES
+ ${CMAKE_CURRENT_BINARY_DIR}/kwiml-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/kwiml-config-version.cmake
+ DESTINATION ${KWIML_INSTALL_PACKAGE_DIR}
+ )
diff --git a/Utilities/KWIML/Copyright.txt b/Utilities/KWIML/Copyright.txt
index c1e5ebc3f..515c4ebc4 100644
--- a/Utilities/KWIML/Copyright.txt
+++ b/Utilities/KWIML/Copyright.txt
@@ -1,5 +1,5 @@
Kitware Information Macro Library
-Copyright 2010-2011 Kitware, Inc.
+Copyright 2010-2016 Kitware, Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Utilities/KWIML/INT.h.in b/Utilities/KWIML/INT.h.in
deleted file mode 100644
index d2eda6387..000000000
--- a/Utilities/KWIML/INT.h.in
+++ /dev/null
@@ -1,861 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 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:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
- * 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.
-
- * Neither the name of Kitware, Inc. nor the names of its contributors
- may be used to endorse or promote products derived from this
- software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-============================================================================*/
-#ifndef @KWIML@_INT_H
-#define @KWIML@_INT_H
-/*
-This header defines macros with information about sized integer types.
-Only information that can be determined using the preprocessor at
-compilation time is available. No try-compile results may be added
-here. Instead we memorize results on platforms of interest.
-
-An includer may optionally define the following macros to suppress errors:
-
-Input:
- @KWIML@_INT_NO_VERIFY = skip verification declarations
- @KWIML@_INT_NO_ERROR_INT64_T = type '@KWIML@_INT_int64_t' is optional (*)
- @KWIML@_INT_NO_ERROR_UINT64_T = type '@KWIML@_INT_uint64_t' is optional (*)
- @KWIML@_INT_NO_ERROR_INTPTR_T = type '@KWIML@_INT_intptr_t' is optional (*)
- @KWIML@_INT_NO_ERROR_UINTPTR_T = type '@KWIML@_INT_uintptr_t' is optional (*)
-
-An includer may optionally define the following macros to override defaults.
-Either way, an includer may test these macros after inclusion:
-
- @KWIML@_INT_HAVE_STDINT_H = include <stdint.h>
- @KWIML@_INT_NO_STDINT_H = do not include <stdint.h>
- @KWIML@_INT_HAVE_INTTYPES_H = include <inttypes.h>
- @KWIML@_INT_NO_INTTYPES_H = do not include <inttypes.h>
-
-An includer may test the following macros after inclusion:
-
- @KWIML@_INT_HAVE_INT#_T = type 'int#_t' is available
- @KWIML@_INT_HAVE_UINT#_T = type 'uint#_t' is available
- # = 8, 16, 32, 64, PTR
-
- @KWIML@_INT_int#_t = signed integer type exactly # bits wide
- @KWIML@_INT_uint#_t = unsigned integer type exactly # bits wide
- # = 8, 16, 32, 64 (*), ptr (*)
-
- @KWIML@_INT_NO_INT64_T = type '@KWIML@_INT_int64_t' not available
- @KWIML@_INT_NO_UINT64_T = type '@KWIML@_INT_uint64_t' not available
- @KWIML@_INT_NO_INTPTR_T = type '@KWIML@_INT_intptr_t' not available
- @KWIML@_INT_NO_UINTPTR_T = type '@KWIML@_INT_uintptr_t' not available
-
- @KWIML@_INT_INT#_C(c) = signed integer constant at least # bits wide
- @KWIML@_INT_UINT#_C(c) = unsigned integer constant at least # bits wide
- # = 8, 16, 32, 64 (*)
-
- @KWIML@_INT_<fmt># = print or scan format, <fmt> in table below
- # = 8, 16, 32, 64, PTR (*)
-
- signed unsigned
- ----------- ------------------------------
- | decimal | decimal octal hexadecimal |
- print | PRId PRIi | PRIu PRIo PRIx PRIX |
- scan | SCNd SCNi | SCNu SCNo SCNx |
- ----------- ------------------------------
-
- The SCN*8 and SCN*64 format macros will not be defined on systems
- with scanf implementations known not to support them.
-
- @KWIML@_INT_BROKEN_<fmt># = macro <fmt># is incorrect if defined
- Some compilers define integer format macros incorrectly for their
- own formatted print/scan implementations.
-
- @KWIML@_INT_BROKEN_INT#_C = macro INT#_C is incorrect if defined
- @KWIML@_INT_BROKEN_UINT#_C = macro UINT#_C is incorrect if defined
- Some compilers define integer constant macros incorrectly and
- cannot handle literals as large as the integer type or even
- produce bad preprocessor syntax.
-
- @KWIML@_INT_BROKEN_INT8_T = type 'int8_t' is available but incorrect
- Some compilers have a flag to make 'char' (un)signed but do not account
- for it while defining int8_t in the non-default case.
-
- The broken cases do not affect correctness of the macros documented above.
-*/
-
-#include "ABI.h"
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_STDINT_H) /* Already defined. */
-#elif defined(@KWIML@_INT_NO_STDINT_H) /* Already defined. */
-#elif defined(HAVE_STDINT_H) /* Optionally provided by includer. */
-# define @KWIML@_INT_HAVE_STDINT_H 1
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
-# define @KWIML@_INT_HAVE_STDINT_H 1
-#elif defined(_MSC_VER) /* MSVC */
-# if _MSC_VER >= 1600
-# define @KWIML@_INT_HAVE_STDINT_H 1
-# else
-# define @KWIML@_INT_NO_STDINT_H 1
-# endif
-#elif defined(__BORLANDC__) /* Borland */
-# if __BORLANDC__ >= 0x560
-# define @KWIML@_INT_HAVE_STDINT_H 1
-# else
-# define @KWIML@_INT_NO_STDINT_H 1
-# endif
-#elif defined(__WATCOMC__) /* Watcom */
-# define @KWIML@_INT_NO_STDINT_H 1
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INTTYPES_H) /* Already defined. */
-#elif defined(@KWIML@_INT_NO_INTTYPES_H) /* Already defined. */
-#elif defined(HAVE_INTTYPES_H) /* Optionally provided by includer. */
-# define @KWIML@_INT_HAVE_INTTYPES_H 1
-#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
-# define @KWIML@_INT_HAVE_INTTYPES_H 1
-#elif defined(_MSC_VER) /* MSVC */
-# define @KWIML@_INT_NO_INTTYPES_H 1
-#elif defined(__BORLANDC__) /* Borland */
-# define @KWIML@_INT_NO_INTTYPES_H 1
-#elif defined(__WATCOMC__) /* Watcom */
-# define @KWIML@_INT_NO_INTTYPES_H 1
-#else /* Assume it exists. */
-# define @KWIML@_INT_HAVE_INTTYPES_H 1
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_STDINT_H) && defined(@KWIML@_INT_NO_STDINT_H)
-# error "Both @KWIML@_INT_HAVE_STDINT_H and @KWIML@_INT_NO_STDINT_H defined!"
-#endif
-#if defined(@KWIML@_INT_HAVE_INTTYPES_H) && defined(@KWIML@_INT_NO_INTTYPES_H)
-# error "Both @KWIML@_INT_HAVE_INTTYPES_H and @KWIML@_INT_NO_INTTYPES_H defined!"
-#endif
-
-#if defined(@KWIML@_INT_HAVE_STDINT_H)
-# include <stdint.h>
-#endif
-#if defined(@KWIML@_INT_HAVE_INTTYPES_H)
-# if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS)
-# define __STDC_FORMAT_MACROS
-# endif
-# include <inttypes.h>
-#endif
-
-#if defined(@KWIML@_INT_HAVE_STDINT_H) || defined(@KWIML@_INT_HAVE_INTTYPES_H)
-#define @KWIML@_INT_HAVE_INT8_T 1
-#define @KWIML@_INT_HAVE_UINT8_T 1
-#define @KWIML@_INT_HAVE_INT16_T 1
-#define @KWIML@_INT_HAVE_UINT16_T 1
-#define @KWIML@_INT_HAVE_INT32_T 1
-#define @KWIML@_INT_HAVE_UINT32_T 1
-#define @KWIML@_INT_HAVE_INT64_T 1
-#define @KWIML@_INT_HAVE_UINT64_T 1
-#define @KWIML@_INT_HAVE_INTPTR_T 1
-#define @KWIML@_INT_HAVE_UINTPTR_T 1
-#endif
-
-#if defined(_AIX43) && !defined(_AIX50) && !defined(_AIX51)
- /* AIX 4.3 defines these incorrectly with % and no quotes. */
-# define @KWIML@_INT_BROKEN_PRId8
-# define @KWIML@_INT_BROKEN_SCNd8
-# define @KWIML@_INT_BROKEN_PRIi8
-# define @KWIML@_INT_BROKEN_SCNi8
-# define @KWIML@_INT_BROKEN_PRIo8
-# define @KWIML@_INT_BROKEN_SCNo8
-# define @KWIML@_INT_BROKEN_PRIu8
-# define @KWIML@_INT_BROKEN_SCNu8
-# define @KWIML@_INT_BROKEN_PRIx8
-# define @KWIML@_INT_BROKEN_SCNx8
-# define @KWIML@_INT_BROKEN_PRIX8
-# define @KWIML@_INT_BROKEN_PRId16
-# define @KWIML@_INT_BROKEN_SCNd16
-# define @KWIML@_INT_BROKEN_PRIi16
-# define @KWIML@_INT_BROKEN_SCNi16
-# define @KWIML@_INT_BROKEN_PRIo16
-# define @KWIML@_INT_BROKEN_SCNo16
-# define @KWIML@_INT_BROKEN_PRIu16
-# define @KWIML@_INT_BROKEN_SCNu16
-# define @KWIML@_INT_BROKEN_PRIx16
-# define @KWIML@_INT_BROKEN_SCNx16
-# define @KWIML@_INT_BROKEN_PRIX16
-# define @KWIML@_INT_BROKEN_PRId32
-# define @KWIML@_INT_BROKEN_SCNd32
-# define @KWIML@_INT_BROKEN_PRIi32
-# define @KWIML@_INT_BROKEN_SCNi32
-# define @KWIML@_INT_BROKEN_PRIo32
-# define @KWIML@_INT_BROKEN_SCNo32
-# define @KWIML@_INT_BROKEN_PRIu32
-# define @KWIML@_INT_BROKEN_SCNu32
-# define @KWIML@_INT_BROKEN_PRIx32
-# define @KWIML@_INT_BROKEN_SCNx32
-# define @KWIML@_INT_BROKEN_PRIX32
-# define @KWIML@_INT_BROKEN_PRId64
-# define @KWIML@_INT_BROKEN_SCNd64
-# define @KWIML@_INT_BROKEN_PRIi64
-# define @KWIML@_INT_BROKEN_SCNi64
-# define @KWIML@_INT_BROKEN_PRIo64
-# define @KWIML@_INT_BROKEN_SCNo64
-# define @KWIML@_INT_BROKEN_PRIu64
-# define @KWIML@_INT_BROKEN_SCNu64
-# define @KWIML@_INT_BROKEN_PRIx64
-# define @KWIML@_INT_BROKEN_SCNx64
-# define @KWIML@_INT_BROKEN_PRIX64
-# define @KWIML@_INT_BROKEN_PRIdPTR
-# define @KWIML@_INT_BROKEN_SCNdPTR
-# define @KWIML@_INT_BROKEN_PRIiPTR
-# define @KWIML@_INT_BROKEN_SCNiPTR
-# define @KWIML@_INT_BROKEN_PRIoPTR
-# define @KWIML@_INT_BROKEN_SCNoPTR
-# define @KWIML@_INT_BROKEN_PRIuPTR
-# define @KWIML@_INT_BROKEN_SCNuPTR
-# define @KWIML@_INT_BROKEN_PRIxPTR
-# define @KWIML@_INT_BROKEN_SCNxPTR
-# define @KWIML@_INT_BROKEN_PRIXPTR
-#endif
-
-#if (defined(__SUNPRO_C)||defined(__SUNPRO_CC)) && defined(_CHAR_IS_UNSIGNED)
-# define @KWIML@_INT_BROKEN_INT8_T /* system type defined incorrectly */
-#elif defined(__BORLANDC__) && defined(_CHAR_UNSIGNED)
-# define @KWIML@_INT_BROKEN_INT8_T /* system type defined incorrectly */
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INT8_T) && !defined(@KWIML@_INT_BROKEN_INT8_T)
-# define @KWIML@_INT_int8_t int8_t
-#else
-# define @KWIML@_INT_int8_t signed char
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T)
-# define @KWIML@_INT_uint8_t uint8_t
-#else
-# define @KWIML@_INT_uint8_t unsigned char
-#endif
-
-#if defined(__INTEL_COMPILER)
-# if defined(_WIN32)
-# define @KWIML@_INT__NO_SCN8
-# endif
-#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
-# define @KWIML@_INT__NO_SCN8
-#elif defined(__BORLANDC__)
-# define @KWIML@_INT__NO_SCN8
-# define @KWIML@_INT__NO_SCN64
-#elif defined(_MSC_VER)
-# define @KWIML@_INT__NO_SCN8
-#elif defined(__WATCOMC__)
-# define @KWIML@_INT__NO_SCN8
-# elif defined(__hpux) /* HP runtime lacks support (any compiler) */
-# define @KWIML@_INT__NO_SCN8
-#endif
-
-/* 8-bit d, i */
-#if defined(@KWIML@_INT_HAVE_INT8_T) && defined(PRId8) \
- && !defined(@KWIML@_INT_BROKEN_PRId8)
-# define @KWIML@_INT_PRId8 PRId8
-#else
-# define @KWIML@_INT_PRId8 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT8_T) && defined(SCNd8) \
- && !defined(@KWIML@_INT_BROKEN_SCNd8)
-# define @KWIML@_INT_SCNd8 SCNd8
-#elif !defined(@KWIML@_INT__NO_SCN8)
-# define @KWIML@_INT_SCNd8 "hhd"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT8_T) && defined(PRIi8) \
- && !defined(@KWIML@_INT_BROKEN_PRIi8)
-# define @KWIML@_INT_PRIi8 PRIi8
-#else
-# define @KWIML@_INT_PRIi8 "i"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT8_T) && defined(SCNi8) \
- && !defined(@KWIML@_INT_BROKEN_SCNi8)
-# define @KWIML@_INT_SCNi8 SCNi8
-#elif !defined(@KWIML@_INT__NO_SCN8)
-# define @KWIML@_INT_SCNi8 "hhi"
-#endif
-
-/* 8-bit o, u, x, X */
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(PRIo8) \
- && !defined(@KWIML@_INT_BROKEN_PRIo8)
-# define @KWIML@_INT_PRIo8 PRIo8
-#else
-# define @KWIML@_INT_PRIo8 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(SCNo8) \
- && !defined(@KWIML@_INT_BROKEN_SCNo8)
-# define @KWIML@_INT_SCNo8 SCNo8
-#elif !defined(@KWIML@_INT__NO_SCN8)
-# define @KWIML@_INT_SCNo8 "hho"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(PRIu8) \
- && !defined(@KWIML@_INT_BROKEN_PRIu8)
-# define @KWIML@_INT_PRIu8 PRIu8
-#else
-# define @KWIML@_INT_PRIu8 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(SCNu8) \
- && !defined(@KWIML@_INT_BROKEN_SCNu8)
-# define @KWIML@_INT_SCNu8 SCNu8
-#elif !defined(@KWIML@_INT__NO_SCN8)
-# define @KWIML@_INT_SCNu8 "hhu"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(PRIx8) \
- && !defined(@KWIML@_INT_BROKEN_PRIx8)
-# define @KWIML@_INT_PRIx8 PRIx8
-#else
-# define @KWIML@_INT_PRIx8 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(SCNx8) \
- && !defined(@KWIML@_INT_BROKEN_SCNx8)
-# define @KWIML@_INT_SCNx8 SCNx8
-#elif !defined(@KWIML@_INT__NO_SCN8)
-# define @KWIML@_INT_SCNx8 "hhx"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT8_T) && defined(PRIX8) \
- && !defined(@KWIML@_INT_BROKEN_PRIX8)
-# define @KWIML@_INT_PRIX8 PRIX8
-#else
-# define @KWIML@_INT_PRIX8 "X"
-#endif
-
-/* 8-bit constants */
-#if defined(INT8_C) && !defined(@KWIML@_INT_BROKEN_INT8_C)
-# define @KWIML@_INT_INT8_C(c) INT8_C(c)
-#else
-# define @KWIML@_INT_INT8_C(c) c
-#endif
-#if defined(UINT8_C) && !defined(@KWIML@_INT_BROKEN_UINT8_C)
-# define @KWIML@_INT_UINT8_C(c) UINT8_C(c)
-#else
-# define @KWIML@_INT_UINT8_C(c) c ## u
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INT16_T)
-# define @KWIML@_INT_int16_t int16_t
-#else
-# define @KWIML@_INT_int16_t signed short
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T)
-# define @KWIML@_INT_uint16_t uint16_t
-#else
-# define @KWIML@_INT_uint16_t unsigned short
-#endif
-
-/* 16-bit d, i */
-#if defined(@KWIML@_INT_HAVE_INT16_T) && defined(PRId16) \
- && !defined(@KWIML@_INT_BROKEN_PRId16)
-# define @KWIML@_INT_PRId16 PRId16
-#else
-# define @KWIML@_INT_PRId16 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT16_T) && defined(SCNd16) \
- && !defined(@KWIML@_INT_BROKEN_SCNd16)
-# define @KWIML@_INT_SCNd16 SCNd16
-#else
-# define @KWIML@_INT_SCNd16 "hd"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT16_T) && defined(PRIi16) \
- && !defined(@KWIML@_INT_BROKEN_PRIi16)
-# define @KWIML@_INT_PRIi16 PRIi16
-#else
-# define @KWIML@_INT_PRIi16 "i"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT16_T) && defined(SCNi16) \
- && !defined(@KWIML@_INT_BROKEN_SCNi16)
-# define @KWIML@_INT_SCNi16 SCNi16
-#else
-# define @KWIML@_INT_SCNi16 "hi"
-#endif
-
-/* 16-bit o, u, x, X */
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(PRIo16) \
- && !defined(@KWIML@_INT_BROKEN_PRIo16)
-# define @KWIML@_INT_PRIo16 PRIo16
-#else
-# define @KWIML@_INT_PRIo16 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(SCNo16) \
- && !defined(@KWIML@_INT_BROKEN_SCNo16)
-# define @KWIML@_INT_SCNo16 SCNo16
-#else
-# define @KWIML@_INT_SCNo16 "ho"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(PRIu16) \
- && !defined(@KWIML@_INT_BROKEN_PRIu16)
-# define @KWIML@_INT_PRIu16 PRIu16
-#else
-# define @KWIML@_INT_PRIu16 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(SCNu16) \
- && !defined(@KWIML@_INT_BROKEN_SCNu16)
-# define @KWIML@_INT_SCNu16 SCNu16
-#else
-# define @KWIML@_INT_SCNu16 "hu"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(PRIx16) \
- && !defined(@KWIML@_INT_BROKEN_PRIx16)
-# define @KWIML@_INT_PRIx16 PRIx16
-#else
-# define @KWIML@_INT_PRIx16 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(SCNx16) \
- && !defined(@KWIML@_INT_BROKEN_SCNx16)
-# define @KWIML@_INT_SCNx16 SCNx16
-#else
-# define @KWIML@_INT_SCNx16 "hx"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT16_T) && defined(PRIX16) \
- && !defined(@KWIML@_INT_BROKEN_PRIX16)
-# define @KWIML@_INT_PRIX16 PRIX16
-#else
-# define @KWIML@_INT_PRIX16 "X"
-#endif
-
-/* 16-bit constants */
-#if defined(INT16_C) && !defined(@KWIML@_INT_BROKEN_INT16_C)
-# define @KWIML@_INT_INT16_C(c) INT16_C(c)
-#else
-# define @KWIML@_INT_INT16_C(c) c
-#endif
-#if defined(UINT16_C) && !defined(@KWIML@_INT_BROKEN_UINT16_C)
-# define @KWIML@_INT_UINT16_C(c) UINT16_C(c)
-#else
-# define @KWIML@_INT_UINT16_C(c) c ## u
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INT32_T)
-# define @KWIML@_INT_int32_t int32_t
-#else
-# define @KWIML@_INT_int32_t signed int
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T)
-# define @KWIML@_INT_uint32_t uint32_t
-#else
-# define @KWIML@_INT_uint32_t unsigned int
-#endif
-
-/* 32-bit d, i */
-#if defined(@KWIML@_INT_HAVE_INT32_T) && defined(PRId32) \
- && !defined(@KWIML@_INT_BROKEN_PRId32)
-# define @KWIML@_INT_PRId32 PRId32
-#else
-# define @KWIML@_INT_PRId32 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT32_T) && defined(SCNd32) \
- && !defined(@KWIML@_INT_BROKEN_SCNd32)
-# define @KWIML@_INT_SCNd32 SCNd32
-#else
-# define @KWIML@_INT_SCNd32 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT32_T) && defined(PRIi32) \
- && !defined(@KWIML@_INT_BROKEN_PRIi32)
-# define @KWIML@_INT_PRIi32 PRIi32
-#else
-# define @KWIML@_INT_PRIi32 "i"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT32_T) && defined(SCNi32) \
- && !defined(@KWIML@_INT_BROKEN_SCNi32)
-# define @KWIML@_INT_SCNi32 SCNi32
-#else
-# define @KWIML@_INT_SCNi32 "i"
-#endif
-
-/* 32-bit o, u, x, X */
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(PRIo32) \
- && !defined(@KWIML@_INT_BROKEN_PRIo32)
-# define @KWIML@_INT_PRIo32 PRIo32
-#else
-# define @KWIML@_INT_PRIo32 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(SCNo32) \
- && !defined(@KWIML@_INT_BROKEN_SCNo32)
-# define @KWIML@_INT_SCNo32 SCNo32
-#else
-# define @KWIML@_INT_SCNo32 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(PRIu32) \
- && !defined(@KWIML@_INT_BROKEN_PRIu32)
-# define @KWIML@_INT_PRIu32 PRIu32
-#else
-# define @KWIML@_INT_PRIu32 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(SCNu32) \
- && !defined(@KWIML@_INT_BROKEN_SCNu32)
-# define @KWIML@_INT_SCNu32 SCNu32
-#else
-# define @KWIML@_INT_SCNu32 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(PRIx32) \
- && !defined(@KWIML@_INT_BROKEN_PRIx32)
-# define @KWIML@_INT_PRIx32 PRIx32
-#else
-# define @KWIML@_INT_PRIx32 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(SCNx32) \
- && !defined(@KWIML@_INT_BROKEN_SCNx32)
-# define @KWIML@_INT_SCNx32 SCNx32
-#else
-# define @KWIML@_INT_SCNx32 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT32_T) && defined(PRIX32) \
- && !defined(@KWIML@_INT_BROKEN_PRIX32)
-# define @KWIML@_INT_PRIX32 PRIX32
-#else
-# define @KWIML@_INT_PRIX32 "X"
-#endif
-
-#if defined(__hpux) && defined(__GNUC__) && !defined(__LP64__) \
- && defined(__CONCAT__) && defined(__CONCAT_U__)
- /* Some HPs define UINT32_C incorrectly and break GNU. */
-# define @KWIML@_INT_BROKEN_UINT32_C
-#endif
-
-/* 32-bit constants */
-#if defined(INT32_C) && !defined(@KWIML@_INT_BROKEN_INT32_C)
-# define @KWIML@_INT_INT32_C(c) INT32_C(c)
-#else
-# define @KWIML@_INT_INT32_C(c) c
-#endif
-#if defined(UINT32_C) && !defined(@KWIML@_INT_BROKEN_UINT32_C)
-# define @KWIML@_INT_UINT32_C(c) UINT32_C(c)
-#else
-# define @KWIML@_INT_UINT32_C(c) c ## u
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INT64_T)
-# define @KWIML@_INT_int64_t int64_t
-#elif @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_INT_int64_t signed long
-#elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# define @KWIML@_INT_int64_t signed long long
-#elif defined(@KWIML@_ABI_SIZEOF___INT64)
-# define @KWIML@_INT_int64_t signed __int64
-#elif defined(@KWIML@_INT_NO_ERROR_INT64_T)
-# define @KWIML@_INT_NO_INT64_T
-#else
-# error "No type known for 'int64_t'."
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T)
-# define @KWIML@_INT_uint64_t uint64_t
-#elif @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_INT_uint64_t unsigned long
-#elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# define @KWIML@_INT_uint64_t unsigned long long
-#elif defined(@KWIML@_ABI_SIZEOF___INT64)
-# define @KWIML@_INT_uint64_t unsigned __int64
-#elif defined(@KWIML@_INT_NO_ERROR_UINT64_T)
-# define @KWIML@_INT_NO_UINT64_T
-#else
-# error "No type known for 'uint64_t'."
-#endif
-
-#if defined(__INTEL_COMPILER)
-#elif defined(__BORLANDC__)
-# define @KWIML@_INT__NO_FMTLL /* type 'long long' but not 'll' format */
-# define @KWIML@_INT_BROKEN_INT64_C /* system macro defined incorrectly */
-# define @KWIML@_INT_BROKEN_UINT64_C /* system macro defined incorrectly */
-#elif defined(_MSC_VER) && _MSC_VER < 1400
-# define @KWIML@_INT__NO_FMTLL /* type 'long long' but not 'll' format */
-#endif
-
-#if @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_INT__FMT64 "l"
-#elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# if !defined(@KWIML@_INT__NO_FMTLL)
-# define @KWIML@_INT__FMT64 "ll"
-# else
-# define @KWIML@_INT__FMT64 "I64"
-# endif
-#elif defined(@KWIML@_ABI_SIZEOF___INT64)
-# if defined(__BORLANDC__)
-# define @KWIML@_INT__FMT64 "L"
-# else
-# define @KWIML@_INT__FMT64 "I64"
-# endif
-#endif
-
-/* 64-bit d, i */
-#if defined(@KWIML@_INT_HAVE_INT64_T) && defined(PRId64) \
- && !defined(@KWIML@_INT_BROKEN_PRId64)
-# define @KWIML@_INT_PRId64 PRId64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRId64 @KWIML@_INT__FMT64 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT64_T) && defined(SCNd64) \
- && !defined(@KWIML@_INT_BROKEN_SCNd64)
-# define @KWIML@_INT_SCNd64 SCNd64
-#elif defined(@KWIML@_INT__FMT64) && !defined(@KWIML@_INT__NO_SCN64)
-# define @KWIML@_INT_SCNd64 @KWIML@_INT__FMT64 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT64_T) && defined(PRIi64) \
- && !defined(@KWIML@_INT_BROKEN_PRIi64)
-# define @KWIML@_INT_PRIi64 PRIi64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRIi64 @KWIML@_INT__FMT64 "d"
-#endif
-#if defined(@KWIML@_INT_HAVE_INT64_T) && defined(SCNi64) \
- && !defined(@KWIML@_INT_BROKEN_SCNi64)
-# define @KWIML@_INT_SCNi64 SCNi64
-#elif defined(@KWIML@_INT__FMT64) && !defined(@KWIML@_INT__NO_SCN64)
-# define @KWIML@_INT_SCNi64 @KWIML@_INT__FMT64 "d"
-#endif
-
-/* 64-bit o, u, x, X */
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(PRIo64) \
- && !defined(@KWIML@_INT_BROKEN_PRIo64)
-# define @KWIML@_INT_PRIo64 PRIo64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRIo64 @KWIML@_INT__FMT64 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(SCNo64) \
- && !defined(@KWIML@_INT_BROKEN_SCNo64)
-# define @KWIML@_INT_SCNo64 SCNo64
-#elif defined(@KWIML@_INT__FMT64) && !defined(@KWIML@_INT__NO_SCN64)
-# define @KWIML@_INT_SCNo64 @KWIML@_INT__FMT64 "o"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(PRIu64) \
- && !defined(@KWIML@_INT_BROKEN_PRIu64)
-# define @KWIML@_INT_PRIu64 PRIu64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRIu64 @KWIML@_INT__FMT64 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(SCNu64) \
- && !defined(@KWIML@_INT_BROKEN_SCNu64)
-# define @KWIML@_INT_SCNu64 SCNu64
-#elif defined(@KWIML@_INT__FMT64) && !defined(@KWIML@_INT__NO_SCN64)
-# define @KWIML@_INT_SCNu64 @KWIML@_INT__FMT64 "u"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(PRIx64) \
- && !defined(@KWIML@_INT_BROKEN_PRIx64)
-# define @KWIML@_INT_PRIx64 PRIx64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRIx64 @KWIML@_INT__FMT64 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(SCNx64) \
- && !defined(@KWIML@_INT_BROKEN_SCNx64)
-# define @KWIML@_INT_SCNx64 SCNx64
-#elif defined(@KWIML@_INT__FMT64) && !defined(@KWIML@_INT__NO_SCN64)
-# define @KWIML@_INT_SCNx64 @KWIML@_INT__FMT64 "x"
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(PRIX64) \
- && !defined(@KWIML@_INT_BROKEN_PRIX64)
-# define @KWIML@_INT_PRIX64 PRIX64
-#elif defined(@KWIML@_INT__FMT64)
-# define @KWIML@_INT_PRIX64 @KWIML@_INT__FMT64 "X"
-#endif
-
-/* 64-bit constants */
-#if defined(@KWIML@_INT_HAVE_INT64_T) && defined(INT64_C) \
- && !defined(@KWIML@_INT_BROKEN_INT64_C)
-# define @KWIML@_INT_INT64_C(c) INT64_C(c)
-#elif @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_INT_INT64_C(c) c ## l
-#elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# define @KWIML@_INT_INT64_C(c) c ## ll
-#elif defined(@KWIML@_ABI_SIZEOF___INT64)
-# define @KWIML@_INT_INT64_C(c) c ## i64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINT64_T) && defined(UINT64_C) \
- && !defined(@KWIML@_INT_BROKEN_UINT64_C)
-# define @KWIML@_INT_UINT64_C(c) UINT64_C(c)
-#elif @KWIML@_ABI_SIZEOF_LONG == 8
-# define @KWIML@_INT_UINT64_C(c) c ## ul
-#elif defined(@KWIML@_ABI_SIZEOF_LONG_LONG) && @KWIML@_ABI_SIZEOF_LONG_LONG == 8
-# define @KWIML@_INT_UINT64_C(c) c ## ull
-#elif defined(@KWIML@_ABI_SIZEOF___INT64)
-# define @KWIML@_INT_UINT64_C(c) c ## ui64
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if defined(@KWIML@_INT_HAVE_INTPTR_T)
-# define @KWIML@_INT_intptr_t intptr_t
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_intptr_t @KWIML@_INT_int32_t
-#elif !defined(@KWIML@_INT_NO_INT64_T)
-# define @KWIML@_INT_intptr_t @KWIML@_INT_int64_t
-#elif defined(@KWIML@_INT_NO_ERROR_INTPTR_T)
-# define @KWIML@_INT_NO_INTPTR_T
-#else
-# error "No type known for 'intptr_t'."
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T)
-# define @KWIML@_INT_uintptr_t uintptr_t
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_uintptr_t @KWIML@_INT_uint32_t
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_uintptr_t @KWIML@_INT_uint64_t
-#elif defined(@KWIML@_INT_NO_ERROR_UINTPTR_T)
-# define @KWIML@_INT_NO_UINTPTR_T
-#else
-# error "No type known for 'uintptr_t'."
-#endif
-
-#if defined(@KWIML@_INT_HAVE_INTPTR_T) && defined(PRIdPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIdPTR)
-# define @KWIML@_INT_PRIdPTR PRIdPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIdPTR @KWIML@_INT_PRId32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIdPTR @KWIML@_INT_PRId64
-#endif
-#if defined(@KWIML@_INT_HAVE_INTPTR_T) && defined(SCNdPTR) \
- && !defined(@KWIML@_INT_BROKEN_SCNdPTR)
-# define @KWIML@_INT_SCNdPTR SCNdPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_SCNdPTR @KWIML@_INT_SCNd32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_SCNdPTR @KWIML@_INT_SCNd64
-#endif
-#if defined(@KWIML@_INT_HAVE_INTPTR_T) && defined(PRIiPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIiPTR)
-# define @KWIML@_INT_PRIiPTR PRIiPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIiPTR @KWIML@_INT_PRIi32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIiPTR @KWIML@_INT_PRIi64
-#endif
-#if defined(@KWIML@_INT_HAVE_INTPTR_T) && defined(SCNiPTR) \
- && !defined(@KWIML@_INT_BROKEN_SCNiPTR)
-# define @KWIML@_INT_SCNiPTR SCNiPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_SCNiPTR @KWIML@_INT_SCNi32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_SCNiPTR @KWIML@_INT_SCNi64
-#endif
-
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(PRIoPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIoPTR)
-# define @KWIML@_INT_PRIoPTR PRIoPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIoPTR @KWIML@_INT_PRIo32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIoPTR @KWIML@_INT_PRIo64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(SCNoPTR) \
- && !defined(@KWIML@_INT_BROKEN_SCNoPTR)
-# define @KWIML@_INT_SCNoPTR SCNoPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_SCNoPTR @KWIML@_INT_SCNo32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_SCNoPTR @KWIML@_INT_SCNo64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(PRIuPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIuPTR)
-# define @KWIML@_INT_PRIuPTR PRIuPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIuPTR @KWIML@_INT_PRIu32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIuPTR @KWIML@_INT_PRIu64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(SCNuPTR) \
- && !defined(@KWIML@_INT_BROKEN_SCNuPTR)
-# define @KWIML@_INT_SCNuPTR SCNuPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_SCNuPTR @KWIML@_INT_SCNu32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_SCNuPTR @KWIML@_INT_SCNu64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(PRIxPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIxPTR)
-# define @KWIML@_INT_PRIxPTR PRIxPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIxPTR @KWIML@_INT_PRIx32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIxPTR @KWIML@_INT_PRIx64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(SCNxPTR) \
- && !defined(@KWIML@_INT_BROKEN_SCNxPTR)
-# define @KWIML@_INT_SCNxPTR SCNxPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_SCNxPTR @KWIML@_INT_SCNx32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_SCNxPTR @KWIML@_INT_SCNx64
-#endif
-#if defined(@KWIML@_INT_HAVE_UINTPTR_T) && defined(PRIXPTR) \
- && !defined(@KWIML@_INT_BROKEN_PRIXPTR)
-# define @KWIML@_INT_PRIXPTR PRIXPTR
-#elif @KWIML@_ABI_SIZEOF_DATA_PTR == 4
-# define @KWIML@_INT_PRIXPTR @KWIML@_INT_PRIX32
-#elif !defined(@KWIML@_INT_NO_UINT64_T)
-# define @KWIML@_INT_PRIXPTR @KWIML@_INT_PRIX64
-#endif
-
-/*--------------------------------------------------------------------------*/
-#if !defined(@KWIML@_INT_NO_VERIFY)
-#define @KWIML@_INT__VERIFY(n, x, y) extern int (*n)[x]; extern int (*n)[y]
-#define @KWIML@_INT__VERIFY_BOOL(m, b) @KWIML@_INT__VERIFY(m##__VERIFY__, 2, (b)?2:3)
-#define @KWIML@_INT__VERIFY_TYPE(t, s) @KWIML@_INT__VERIFY(t##__VERIFY__, s, sizeof(t))
-#define @KWIML@_INT__VERIFY_SIGN(t, u, o) @KWIML@_INT__VERIFY_BOOL(t##__SIGN, (t)((u)1 << ((sizeof(t)<<3)-1)) o 0)
-
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_int8_t, 1);
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_uint8_t, 1);
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_int16_t, 2);
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_uint16_t, 2);
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_int32_t, 4);
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_uint32_t, 4);
-#if !defined(@KWIML@_INT_NO_INT64_T)
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_int64_t, 8);
-#endif
-#if !defined(@KWIML@_INT_NO_UINT64_T)
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_uint64_t, 8);
-#endif
-#if !defined(@KWIML@_INT_NO_INTPTR_T)
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_intptr_t, sizeof(void*));
-#endif
-#if !defined(@KWIML@_INT_NO_UINTPTR_T)
-@KWIML@_INT__VERIFY_TYPE(@KWIML@_INT_uintptr_t, sizeof(void*));
-#endif
-
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_int8_t, @KWIML@_INT_uint8_t, <);
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_uint8_t, @KWIML@_INT_uint8_t, >);
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_int16_t, @KWIML@_INT_uint16_t, <);
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_uint16_t, @KWIML@_INT_uint16_t, >);
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_int32_t, @KWIML@_INT_uint32_t, <);
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_uint32_t, @KWIML@_INT_uint32_t, >);
-#if !defined(@KWIML@_INT_NO_INT64_T)
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_int64_t, @KWIML@_INT_uint64_t, <);
-#endif
-#if !defined(@KWIML@_INT_NO_UINT64_T)
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_uint64_t, @KWIML@_INT_uint64_t, >);
-#endif
-#if !defined(@KWIML@_INT_NO_INTPTR_T)
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_intptr_t, @KWIML@_INT_uintptr_t, <);
-#endif
-#if !defined(@KWIML@_INT_NO_UINTPTR_T)
-@KWIML@_INT__VERIFY_SIGN(@KWIML@_INT_uintptr_t, @KWIML@_INT_uintptr_t, >);
-#endif
-
-#undef @KWIML@_INT__VERIFY_SIGN
-#undef @KWIML@_INT__VERIFY_TYPE
-#undef @KWIML@_INT__VERIFY_BOOL
-#undef @KWIML@_INT__VERIFY
-
-#endif
-
-#endif
diff --git a/Utilities/KWIML/README.md b/Utilities/KWIML/README.md
new file mode 100644
index 000000000..37d72d1b1
--- /dev/null
+++ b/Utilities/KWIML/README.md
@@ -0,0 +1,36 @@
+Kitware Information Macro Library (KWIML)
+=========================================
+
+KWIML provides header files that use preprocessor tests to detect and
+provide information about the compiler and its target architecture.
+The headers contain no configuration-time test results and thus may
+be installed into an architecture-independent include directory.
+This makes them suitable for use in the public interface of any package.
+
+The following headers are provided. See header comments for details:
+
+* [kwiml/abi.h][]: Fundamental type size and representation.
+
+* [kwiml/int.h][]: Fixed-size integer types and format specifiers.
+
+* [kwiml/version.h][]: Information about this version of KWIML.
+
+The [test][] subdirectory builds tests that verify correctness of the
+information provided by each header.
+
+License
+=======
+
+KWIML is distributed under the OSI-approved 3-clause BSD License.
+
+Files used only for build and test purposes contain a copyright notice and
+reference [Copyright.txt][] for details. Headers meant for installation and
+distribution outside the source tree come with full inlined copies of the
+copyright notice and license text. This makes them suitable for distribution
+with any package under compatible license terms.
+
+[Copyright.txt]: Copyright.txt
+[kwiml/abi.h]: include/kwiml/abi.h
+[kwiml/int.h]: include/kwiml/int.h
+[kwiml/version.h]: src/version.h.in
+[test]: test/
diff --git a/Utilities/KWIML/README.txt b/Utilities/KWIML/README.txt
deleted file mode 100644
index 6bdf859d9..000000000
--- a/Utilities/KWIML/README.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-KWIML - The Kitware Information Macro Library
-
-KWIML provides header files that use preprocessor tests to detect and
-provide information about the compiler and its target architecture. The
-headers contain no configuration-time test results and thus may be
-installed into an architecture-independent include directory. This
-makes them suitable for use in the public interface of any package.
-
-This source tree is intended for distribution inside the source trees of
-other packages. In order to avoid name collisions among multiple
-packages the KWIML headers are configured with a per-package prefix on
-both the header locations and the macros they define. See comments in
-CMakeLists.txt for instructions to include KWIML inside another project.
-
-The entire KWIML source tree is distributed under the OSI-approved
-3-clause BSD License. Files used only for build and test purposes
-contain a copyright notice and reference Copyright.txt for details.
-Headers meant for installation and distribution outside the source tree
-come with full inlined copies of the copyright notice and license text.
-This makes them suitable for distribution with any package under
-compatible license terms.
-
-The following components are provided. See header comments for details:
-
- ABI.h = Fundamental type size and representation
- INT.h = Fixed-size integer types and format specifiers
-
-The "test" subdirectory builds tests that verify correctness of the
-information provided by each header.
diff --git a/Utilities/KWIML/include/kwiml/abi.h b/Utilities/KWIML/include/kwiml/abi.h
new file mode 100644
index 000000000..5ffd542cf
--- /dev/null
+++ b/Utilities/KWIML/include/kwiml/abi.h
@@ -0,0 +1,566 @@
+/*============================================================================
+ Kitware Information Macro Library
+ Copyright 2010-2016 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:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * 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.
+
+ * Neither the name of Kitware, Inc. nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+============================================================================*/
+/*
+This header defines macros with information about the C ABI.
+Only information that can be determined using the preprocessor at
+compilation time is available. No try-compile results may be added
+here. Instead we memorize results on platforms of interest.
+
+An includer may optionally define the following macros to suppress errors:
+
+ KWIML_ABI_NO_VERIFY = skip verification declarations
+ KWIML_ABI_NO_ERROR_CHAR_SIGN = signedness of 'char' may be unknown
+ KWIML_ABI_NO_ERROR_LONG_LONG = existence of 'long long' may be unknown
+ KWIML_ABI_NO_ERROR_ENDIAN = byte order of CPU may be unknown
+
+An includer may test the following macros after inclusion:
+
+ KWIML_ABI_VERSION = interface version number # of this header
+
+ KWIML_ABI_SIZEOF_DATA_PTR = sizeof(void*)
+ KWIML_ABI_SIZEOF_CODE_PTR = sizeof(void(*)(void))
+ KWIML_ABI_SIZEOF_FLOAT = sizeof(float)
+ KWIML_ABI_SIZEOF_DOUBLE = sizeof(double)
+ KWIML_ABI_SIZEOF_CHAR = sizeof(char)
+ KWIML_ABI_SIZEOF_SHORT = sizeof(short)
+ KWIML_ABI_SIZEOF_INT = sizeof(int)
+ KWIML_ABI_SIZEOF_LONG = sizeof(long)
+
+ KWIML_ABI_SIZEOF_LONG_LONG = sizeof(long long) or 0 if not a type
+ Undefined if existence is unknown and error suppression macro
+ KWIML_ABI_NO_ERROR_LONG_LONG was defined.
+
+ KWIML_ABI_SIZEOF___INT64 = 8 if '__int64' exists or 0 if not
+ Undefined if existence is unknown.
+
+ KWIML_ABI___INT64_IS_LONG = 1 if '__int64' is 'long' (same type)
+ Undefined otherwise.
+ KWIML_ABI___INT64_IS_LONG_LONG = 1 if '__int64' is 'long long' (same type)
+ Undefined otherwise.
+ KWIML_ABI___INT64_IS_UNIQUE = 1 if '__int64' is a distinct type
+ Undefined otherwise.
+
+ KWIML_ABI_CHAR_IS_UNSIGNED = 1 if 'char' is unsigned, else undefined
+ KWIML_ABI_CHAR_IS_SIGNED = 1 if 'char' is signed, else undefined
+ One of these is defined unless signedness of 'char' is unknown and
+ error suppression macro KWIML_ABI_NO_ERROR_CHAR_SIGN was defined.
+
+ KWIML_ABI_ENDIAN_ID_BIG = id for big-endian (always defined)
+ KWIML_ABI_ENDIAN_ID_LITTLE = id for little-endian (always defined)
+ KWIML_ABI_ENDIAN_ID = id of byte order of target CPU
+ Defined to KWIML_ABI_ENDIAN_ID_BIG or KWIML_ABI_ENDIAN_ID_LITTLE
+ unless byte order is unknown and error suppression macro
+ KWIML_ABI_NO_ERROR_ENDIAN was defined.
+
+We verify most results using dummy "extern" declarations that are
+invalid if the macros are wrong. Verification is disabled if
+suppression macro KWIML_ABI_NO_VERIFY was defined.
+*/
+
+#define KWIML_ABI_private_VERSION 1
+
+/* Guard definition of this version. */
+#ifndef KWIML_ABI_detail_DEFINED_VERSION_1
+# define KWIML_ABI_detail_DEFINED_VERSION_1 1
+# define KWIML_ABI_private_DO_DEFINE
+#endif
+
+/* Guard verification of this version. */
+#if !defined(KWIML_ABI_NO_VERIFY)
+# ifndef KWIML_ABI_detail_VERIFIED_VERSION_1
+# define KWIML_ABI_detail_VERIFIED_VERSION_1
+# define KWIML_ABI_private_DO_VERIFY
+# endif
+#endif
+
+#ifdef KWIML_ABI_private_DO_DEFINE
+#undef KWIML_ABI_private_DO_DEFINE
+
+/* Define version as most recent of those included. */
+#if !defined(KWIML_ABI_VERSION) || KWIML_ABI_VERSION < KWIML_ABI_private_VERSION
+# undef KWIML_ABI_VERSION
+# define KWIML_ABI_VERSION 1
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_DATA_PTR)
+# if defined(__SIZEOF_POINTER__)
+# define KWIML_ABI_SIZEOF_DATA_PTR __SIZEOF_POINTER__
+# elif defined(_SIZE_PTR)
+# define KWIML_ABI_SIZEOF_DATA_PTR (_SIZE_PTR >> 3)
+# elif defined(_LP64) || defined(__LP64__)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(_ILP32)
+# define KWIML_ABI_SIZEOF_DATA_PTR 4
+# elif defined(__64BIT__) /* IBM XL */
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(_M_X64)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(__ia64)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(__sparcv9)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(__x86_64) || defined(__x86_64__)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(__amd64) || defined(__amd64__)
+# define KWIML_ABI_SIZEOF_DATA_PTR 8
+# elif defined(__i386) || defined(__i386__)
+# define KWIML_ABI_SIZEOF_DATA_PTR 4
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_DATA_PTR)
+# define KWIML_ABI_SIZEOF_DATA_PTR 4
+#endif
+#if !defined(KWIML_ABI_SIZEOF_CODE_PTR)
+# define KWIML_ABI_SIZEOF_CODE_PTR KWIML_ABI_SIZEOF_DATA_PTR
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_CHAR)
+# define KWIML_ABI_SIZEOF_CHAR 1
+#endif
+
+#if !defined(KWIML_ABI_CHAR_IS_UNSIGNED) && !defined(KWIML_ABI_CHAR_IS_SIGNED)
+# if defined(__CHAR_UNSIGNED__) /* GNU, some IBM XL, others? */
+# define KWIML_ABI_CHAR_IS_UNSIGNED 1
+# elif defined(_CHAR_UNSIGNED) /* Intel, IBM XL, MSVC, Borland, others? */
+# define KWIML_ABI_CHAR_IS_UNSIGNED 1
+# elif defined(_CHAR_SIGNED) /* IBM XL, others? */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__CHAR_SIGNED__) /* IBM XL, Watcom, others? */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__SIGNED_CHARS__) /* EDG, Intel, SGI MIPSpro */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(_CHAR_IS_SIGNED) /* Some SunPro, others? */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(_CHAR_IS_UNSIGNED) /* SunPro, others? */
+# define KWIML_ABI_CHAR_IS_UNSIGNED 1
+# elif defined(__GNUC__) /* GNU default */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* SunPro default */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__HP_cc) || defined(__HP_aCC) /* HP default (unless +uc) */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(_SGI_COMPILER_VERSION) /* SGI MIPSpro default */
+# define KWIML_ABI_CHAR_IS_UNSIGNED 1
+# elif defined(__PGIC__) /* PGI default */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(_MSC_VER) /* MSVC default */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__WATCOMC__) /* Watcom default */
+# define KWIML_ABI_CHAR_IS_UNSIGNED 1
+# elif defined(__BORLANDC__) /* Borland default */
+# define KWIML_ABI_CHAR_IS_SIGNED 1
+# elif defined(__hpux) /* Old HP: no __HP_cc/__HP_aCC/__GNUC__ above */
+# define KWIML_ABI_CHAR_IS_SIGNED 1 /* (unless +uc) */
+# endif
+#endif
+#if !defined(KWIML_ABI_CHAR_IS_UNSIGNED) && !defined(KWIML_ABI_CHAR_IS_SIGNED) \
+ && !defined(KWIML_ABI_NO_ERROR_CHAR_SIGN)
+# error "Signedness of 'char' unknown."
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_SHORT)
+# if defined(__SIZEOF_SHORT__)
+# define KWIML_ABI_SIZEOF_SHORT __SIZEOF_SHORT__
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_SHORT)
+# define KWIML_ABI_SIZEOF_SHORT 2
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_INT)
+# if defined(__SIZEOF_INT__)
+# define KWIML_ABI_SIZEOF_INT __SIZEOF_INT__
+# elif defined(_SIZE_INT)
+# define KWIML_ABI_SIZEOF_INT (_SIZE_INT >> 3)
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_INT)
+# define KWIML_ABI_SIZEOF_INT 4
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_LONG)
+# if defined(__SIZEOF_LONG__)
+# define KWIML_ABI_SIZEOF_LONG __SIZEOF_LONG__
+# elif defined(_SIZE_LONG)
+# define KWIML_ABI_SIZEOF_LONG (_SIZE_LONG >> 3)
+# elif defined(__LONG_MAX__)
+# if __LONG_MAX__ == 0x7fffffff
+# define KWIML_ABI_SIZEOF_LONG 4
+# elif __LONG_MAX__>>32 == 0x7fffffff
+# define KWIML_ABI_SIZEOF_LONG 8
+# endif
+# elif defined(_MSC_VER) /* MSVC and Intel on Windows */
+# define KWIML_ABI_SIZEOF_LONG 4
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_LONG)
+# define KWIML_ABI_SIZEOF_LONG KWIML_ABI_SIZEOF_DATA_PTR
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_LONG_LONG)
+# if defined(__SIZEOF_LONG_LONG__)
+# define KWIML_ABI_SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
+# elif defined(__LONG_LONG_MAX__)
+# if __LONG_LONG_MAX__ == 0x7fffffff
+# define KWIML_ABI_SIZEOF_LONG_LONG 4
+# elif __LONG_LONG_MAX__>>32 == 0x7fffffff
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# endif
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_LONG_LONG)
+# if defined(_LONGLONG) /* SGI, some GNU, perhaps others. */ \
+ && !defined(_MSC_VER)
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(_LONG_LONG) /* IBM XL, perhaps others. */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__NO_LONG_LONG) /* EDG */
+# define KWIML_ABI_SIZEOF_LONG_LONG 0
+# elif defined(__cplusplus) && __cplusplus > 199711L /* C++0x */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__SUNPRO_C) || defined(__SUNPRO_CC) /* SunPro */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__HP_cc) || defined(__HP_aCC) /* HP */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__PGIC__) /* PGI */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__WATCOMC__) /* Watcom */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__INTEL_COMPILER) /* Intel */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__BORLANDC__) /* Borland */
+# if __BORLANDC__ >= 0x0560
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# else
+# define KWIML_ABI_SIZEOF_LONG_LONG 0
+# endif
+# elif defined(_MSC_VER) /* Microsoft */
+# if _MSC_VER >= 1310
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# else
+# define KWIML_ABI_SIZEOF_LONG_LONG 0
+# endif
+# elif defined(__GNUC__) /* GNU */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# elif defined(__hpux) /* Old HP: no __HP_cc/__HP_aCC/__GNUC__ above */
+# define KWIML_ABI_SIZEOF_LONG_LONG 8
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_LONG_LONG) && !defined(KWIML_ABI_NO_ERROR_LONG_LONG)
+# error "Existence of 'long long' unknown."
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF___INT64)
+# if defined(__INTEL_COMPILER)
+# define KWIML_ABI_SIZEOF___INT64 8
+# elif defined(_MSC_VER)
+# define KWIML_ABI_SIZEOF___INT64 8
+# elif defined(__BORLANDC__)
+# define KWIML_ABI_SIZEOF___INT64 8
+# else
+# define KWIML_ABI_SIZEOF___INT64 0
+# endif
+#endif
+
+#if defined(KWIML_ABI_SIZEOF___INT64) && KWIML_ABI_SIZEOF___INT64 > 0
+# if KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_ABI___INT64_IS_LONG 1
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# define KWIML_ABI___INT64_IS_LONG_LONG 1
+# else
+# define KWIML_ABI___INT64_IS_UNIQUE 1
+# endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_FLOAT)
+# if defined(__SIZEOF_FLOAT__)
+# define KWIML_ABI_SIZEOF_FLOAT __SIZEOF_FLOAT__
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_FLOAT)
+# define KWIML_ABI_SIZEOF_FLOAT 4
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_ABI_SIZEOF_DOUBLE)
+# if defined(__SIZEOF_DOUBLE__)
+# define KWIML_ABI_SIZEOF_DOUBLE __SIZEOF_DOUBLE__
+# endif
+#endif
+#if !defined(KWIML_ABI_SIZEOF_DOUBLE)
+# define KWIML_ABI_SIZEOF_DOUBLE 8
+#endif
+
+/*--------------------------------------------------------------------------*/
+/* Identify possible endian cases. The macro KWIML_ABI_ENDIAN_ID will be
+ defined to one of these, or undefined if unknown. */
+#if !defined(KWIML_ABI_ENDIAN_ID_BIG)
+# define KWIML_ABI_ENDIAN_ID_BIG 4321
+#endif
+#if !defined(KWIML_ABI_ENDIAN_ID_LITTLE)
+# define KWIML_ABI_ENDIAN_ID_LITTLE 1234
+#endif
+#if KWIML_ABI_ENDIAN_ID_BIG == KWIML_ABI_ENDIAN_ID_LITTLE
+# error "KWIML_ABI_ENDIAN_ID_BIG == KWIML_ABI_ENDIAN_ID_LITTLE"
+#endif
+
+#if defined(KWIML_ABI_ENDIAN_ID) /* Skip #elif cases if already defined. */
+
+/* Use dedicated symbols if the compiler defines them. Do this first
+ because some architectures allow runtime byte order selection by
+ the operating system (values for such architectures below are
+ guesses for compilers that do not define a dedicated symbol).
+ Ensure that only one is defined in case the platform or a header
+ defines both as possible values for some third symbol. */
+#elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+#elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+#elif defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+#elif defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* Alpha */
+#elif defined(__alpha) || defined(__alpha__) || defined(_M_ALPHA)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* Arm */
+#elif defined(__arm__)
+# if !defined(__ARMEB__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+# else
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+# endif
+
+/* Intel x86 */
+#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+#elif defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+#elif defined(__MWERKS__) && defined(__INTEL__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* Intel x86-64 */
+#elif defined(__x86_64) || defined(__x86_64__) || defined(_M_X64)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+#elif defined(__amd64) || defined(__amd64__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* Intel Architecture-64 (Itanium) */
+#elif defined(__ia64) || defined(__ia64__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+#elif defined(_IA64) || defined(__IA64__) || defined(_M_IA64)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* PowerPC */
+#elif defined(__powerpc) || defined(__powerpc__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+#elif defined(__ppc) || defined(__ppc__) || defined(__POWERPC__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* SPARC */
+#elif defined(__sparc) || defined(__sparc__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* HP/PA RISC */
+#elif defined(__hppa) || defined(__hppa__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* Motorola 68k */
+#elif defined(__m68k__) || defined(M68000)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* MIPSel (MIPS little endian) */
+#elif defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* MIPSeb (MIPS big endian) */
+#elif defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* MIPS (fallback, big endian) */
+#elif defined(__mips) || defined(__mips__) || defined(__MIPS__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* NIOS2 */
+#elif defined(__NIOS2__) || defined(__NIOS2) || defined(__nios2__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* OpenRISC 1000 */
+#elif defined(__or1k__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* RS/6000 */
+#elif defined(__THW_RS600) || defined(_IBMR2) || defined(_POWER)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+#elif defined(_ARCH_PWR) || defined(_ARCH_PWR2)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* System/370 */
+#elif defined(__370__) || defined(__THW_370__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* System/390 */
+#elif defined(__s390__) || defined(__s390x__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* z/Architecture */
+#elif defined(__SYSC_ZARCH__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* VAX */
+#elif defined(__vax__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+
+/* Aarch64 */
+#elif defined(__aarch64__)
+# if !defined(__AARCH64EB__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+# else
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+# endif
+
+/* Xtensa */
+#elif defined(__XTENSA_EB__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_BIG
+#elif defined(__XTENSA_EL__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* RISC-V */
+#elif defined(__riscv__)
+# define KWIML_ABI_ENDIAN_ID KWIML_ABI_ENDIAN_ID_LITTLE
+
+/* Unknown CPU */
+#elif !defined(KWIML_ABI_NO_ERROR_ENDIAN)
+# error "Byte order of target CPU unknown."
+#endif
+
+#endif /* KWIML_ABI_private_DO_DEFINE */
+
+/*--------------------------------------------------------------------------*/
+#ifdef KWIML_ABI_private_DO_VERIFY
+#undef KWIML_ABI_private_DO_VERIFY
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4310) /* cast truncates constant value */
+#endif
+
+#define KWIML_ABI_private_VERIFY(n, x, y) KWIML_ABI_private_VERIFY_0(KWIML_ABI_private_VERSION, n, x, y)
+#define KWIML_ABI_private_VERIFY_0(V, n, x, y) KWIML_ABI_private_VERIFY_1(V, n, x, y)
+#define KWIML_ABI_private_VERIFY_1(V, n, x, y) extern int (*n##_v##V)[x]; extern int (*n##_v##V)[y]
+
+#define KWIML_ABI_private_VERIFY_SAME_IMPL(n, x, y) KWIML_ABI_private_VERIFY_SAME_IMPL_0(KWIML_ABI_private_VERSION, n, x, y)
+#define KWIML_ABI_private_VERIFY_SAME_IMPL_0(V, n, x, y) KWIML_ABI_private_VERIFY_SAME_IMPL_1(V, n, x, y)
+#define KWIML_ABI_private_VERIFY_SAME_IMPL_1(V, n, x, y) extern int (*n##_v##V)(x*); extern int (*n##_v##V)(y*)
+
+#define KWIML_ABI_private_VERIFY_DIFF_IMPL(n, x, y) KWIML_ABI_private_VERIFY_DIFF_IMPL_0(KWIML_ABI_private_VERSION, n, x, y)
+#define KWIML_ABI_private_VERIFY_DIFF_IMPL_0(V, n, x, y) KWIML_ABI_private_VERIFY_DIFF_IMPL_1(V, n, x, y)
+#if defined(__cplusplus)
+# define KWIML_ABI_private_VERIFY_DIFF_IMPL_1(V, n, x, y) extern int* n##_v##V(x*); extern char* n##_v##V(y*)
+#else
+# define KWIML_ABI_private_VERIFY_DIFF_IMPL_1(V, n, x, y) extern int* n##_v##V(x*) /* TODO: possible? */
+#endif
+
+#define KWIML_ABI_private_VERIFY_BOOL(m, b) KWIML_ABI_private_VERIFY(KWIML_ABI_detail_VERIFY_##m, 2, (b)?2:3)
+#define KWIML_ABI_private_VERIFY_SIZE(m, t) KWIML_ABI_private_VERIFY(KWIML_ABI_detail_VERIFY_##m, m, sizeof(t))
+#define KWIML_ABI_private_VERIFY_SAME(m, x, y) KWIML_ABI_private_VERIFY_SAME_IMPL(KWIML_ABI_detail_VERIFY_##m, x, y)
+#define KWIML_ABI_private_VERIFY_DIFF(m, x, y) KWIML_ABI_private_VERIFY_DIFF_IMPL(KWIML_ABI_detail_VERIFY_##m, x, y)
+
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_DATA_PTR, int*);
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_CODE_PTR, int(*)(int));
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_CHAR, char);
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_SHORT, short);
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_INT, int);
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_LONG, long);
+#if defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG > 0
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_LONG_LONG, long long);
+#endif
+#if defined(KWIML_ABI_SIZEOF___INT64) && KWIML_ABI_SIZEOF___INT64 > 0
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF___INT64, __int64);
+#endif
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_FLOAT, float);
+KWIML_ABI_private_VERIFY_SIZE(KWIML_ABI_SIZEOF_DOUBLE, double);
+
+#if defined(KWIML_ABI___INT64_IS_LONG)
+KWIML_ABI_private_VERIFY_SAME(KWIML_ABI___INT64_IS_LONG, __int64, long);
+#elif defined(KWIML_ABI___INT64_IS_LONG_LONG)
+KWIML_ABI_private_VERIFY_SAME(KWIML_ABI___INT64_IS_LONG_LONG, __int64, long long);
+#elif defined(KWIML_ABI_SIZEOF___INT64) && KWIML_ABI_SIZEOF___INT64 > 0
+KWIML_ABI_private_VERIFY_DIFF(KWIML_ABI___INT64_NOT_LONG, __int64, long);
+# if defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG > 0
+KWIML_ABI_private_VERIFY_DIFF(KWIML_ABI___INT64_NOT_LONG_LONG, __int64, long long);
+# endif
+#endif
+
+#if defined(KWIML_ABI_CHAR_IS_UNSIGNED)
+KWIML_ABI_private_VERIFY_BOOL(KWIML_ABI_CHAR_IS_UNSIGNED, (char)0x80 > 0);
+#elif defined(KWIML_ABI_CHAR_IS_SIGNED)
+KWIML_ABI_private_VERIFY_BOOL(KWIML_ABI_CHAR_IS_SIGNED, (char)0x80 < 0);
+#endif
+
+#undef KWIML_ABI_private_VERIFY_DIFF
+#undef KWIML_ABI_private_VERIFY_SAME
+#undef KWIML_ABI_private_VERIFY_SIZE
+#undef KWIML_ABI_private_VERIFY_BOOL
+
+#undef KWIML_ABI_private_VERIFY_DIFF_IMPL_1
+#undef KWIML_ABI_private_VERIFY_DIFF_IMPL_0
+#undef KWIML_ABI_private_VERIFY_DIFF_IMPL
+
+#undef KWIML_ABI_private_VERIFY_SAME_IMPL_1
+#undef KWIML_ABI_private_VERIFY_SAME_IMPL_0
+#undef KWIML_ABI_private_VERIFY_SAME_IMPL
+
+#undef KWIML_ABI_private_VERIFY_1
+#undef KWIML_ABI_private_VERIFY_0
+#undef KWIML_ABI_private_VERIFY
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
+
+#endif /* KWIML_ABI_private_DO_VERIFY */
+
+#undef KWIML_ABI_private_VERSION
diff --git a/Utilities/KWIML/include/kwiml/int.h b/Utilities/KWIML/include/kwiml/int.h
new file mode 100644
index 000000000..489c60325
--- /dev/null
+++ b/Utilities/KWIML/include/kwiml/int.h
@@ -0,0 +1,1069 @@
+/*============================================================================
+ Kitware Information Macro Library
+ Copyright 2010-2016 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:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * 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.
+
+ * Neither the name of Kitware, Inc. nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+============================================================================*/
+/*
+This header defines macros with information about sized integer types.
+Only information that can be determined using the preprocessor at
+compilation time is available. No try-compile results may be added
+here. Instead we memorize results on platforms of interest.
+
+An includer may optionally define the following macros to suppress errors:
+
+Input:
+ KWIML_INT_NO_VERIFY = skip verification declarations
+ KWIML_INT_NO_ERROR_INT64_T = type 'KWIML_INT_int64_t' is optional (*)
+ KWIML_INT_NO_ERROR_UINT64_T = type 'KWIML_INT_uint64_t' is optional (*)
+ KWIML_INT_NO_ERROR_INTPTR_T = type 'KWIML_INT_intptr_t' is optional (*)
+ KWIML_INT_NO_ERROR_UINTPTR_T = type 'KWIML_INT_uintptr_t' is optional (*)
+
+An includer may optionally define the following macros to override defaults.
+Either way, an includer may test these macros after inclusion:
+
+ KWIML_INT_HAVE_STDINT_H = include <stdint.h>
+ KWIML_INT_NO_STDINT_H = do not include <stdint.h>
+ KWIML_INT_HAVE_INTTYPES_H = include <inttypes.h>
+ KWIML_INT_NO_INTTYPES_H = do not include <inttypes.h>
+
+An includer may test the following macros after inclusion:
+
+ KWIML_INT_VERSION = interface version number # of this header
+
+ KWIML_INT_HAVE_INT#_T = type 'int#_t' is available
+ KWIML_INT_HAVE_UINT#_T = type 'uint#_t' is available
+ # = 8, 16, 32, 64, PTR
+
+ KWIML_INT_int#_t = signed integer type exactly # bits wide
+ KWIML_INT_uint#_t = unsigned integer type exactly # bits wide
+ # = 8, 16, 32, 64 (*), ptr (*)
+
+ KWIML_INT_NO_INT64_T = type 'KWIML_INT_int64_t' not available
+ KWIML_INT_NO_UINT64_T = type 'KWIML_INT_uint64_t' not available
+ KWIML_INT_NO_INTPTR_T = type 'KWIML_INT_intptr_t' not available
+ KWIML_INT_NO_UINTPTR_T = type 'KWIML_INT_uintptr_t' not available
+
+ KWIML_INT_INT#_C(c) = signed integer constant at least # bits wide
+ KWIML_INT_UINT#_C(c) = unsigned integer constant at least # bits wide
+ # = 8, 16, 32, 64 (*)
+
+ KWIML_INT_<fmt># = print or scan format, <fmt> in table below
+ # = 8, 16, 32, 64, PTR (*)
+
+ signed unsigned
+ ----------- ------------------------------
+ | decimal | decimal octal hexadecimal |
+ print | PRId PRIi | PRIu PRIo PRIx PRIX |
+ scan | SCNd SCNi | SCNu SCNo SCNx |
+ ----------- ------------------------------
+
+ The SCN*8 and SCN*64 format macros will not be defined on systems
+ with scanf implementations known not to support them.
+
+ KWIML_INT_BROKEN_<fmt># = macro <fmt># is incorrect if defined
+ Some compilers define integer format macros incorrectly for their
+ own formatted print/scan implementations.
+
+ KWIML_INT_BROKEN_INT#_C = macro INT#_C is incorrect if defined
+ KWIML_INT_BROKEN_UINT#_C = macro UINT#_C is incorrect if defined
+ Some compilers define integer constant macros incorrectly and
+ cannot handle literals as large as the integer type or even
+ produce bad preprocessor syntax.
+
+ KWIML_INT_BROKEN_INT8_T = type 'int8_t' is available but incorrect
+ Some compilers have a flag to make 'char' (un)signed but do not account
+ for it while defining int8_t in the non-default case.
+
+ The broken cases do not affect correctness of the macros documented above.
+*/
+
+#include "abi.h"
+
+#define KWIML_INT_private_VERSION 1
+
+/* Guard definition of this version. */
+#ifndef KWIML_INT_detail_DEFINED_VERSION_1
+# define KWIML_INT_detail_DEFINED_VERSION_1 1
+# define KWIML_INT_private_DO_DEFINE
+#endif
+
+/* Guard verification of this version. */
+#if !defined(KWIML_INT_NO_VERIFY)
+# ifndef KWIML_INT_detail_VERIFIED_VERSION_1
+# define KWIML_INT_detail_VERIFIED_VERSION_1
+# define KWIML_INT_private_DO_VERIFY
+# endif
+#endif
+
+#ifdef KWIML_INT_private_DO_DEFINE
+#undef KWIML_INT_private_DO_DEFINE
+
+/* Define version as most recent of those included. */
+#if !defined(KWIML_INT_VERSION) || KWIML_INT_VERSION < KWIML_INT_private_VERSION
+# undef KWIML_INT_VERSION
+# define KWIML_INT_VERSION 1
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if defined(KWIML_INT_HAVE_STDINT_H) /* Already defined. */
+#elif defined(KWIML_INT_NO_STDINT_H) /* Already defined. */
+#elif defined(HAVE_STDINT_H) /* Optionally provided by includer. */
+# define KWIML_INT_HAVE_STDINT_H 1
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define KWIML_INT_HAVE_STDINT_H 1
+#elif defined(_MSC_VER) /* MSVC */
+# if _MSC_VER >= 1600
+# define KWIML_INT_HAVE_STDINT_H 1
+# else
+# define KWIML_INT_NO_STDINT_H 1
+# endif
+#elif defined(__BORLANDC__) /* Borland */
+# if __BORLANDC__ >= 0x560
+# define KWIML_INT_HAVE_STDINT_H 1
+# else
+# define KWIML_INT_NO_STDINT_H 1
+# endif
+#elif defined(__WATCOMC__) /* Watcom */
+# define KWIML_INT_NO_STDINT_H 1
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if defined(KWIML_INT_HAVE_INTTYPES_H) /* Already defined. */
+#elif defined(KWIML_INT_NO_INTTYPES_H) /* Already defined. */
+#elif defined(HAVE_INTTYPES_H) /* Optionally provided by includer. */
+# define KWIML_INT_HAVE_INTTYPES_H 1
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# define KWIML_INT_HAVE_INTTYPES_H 1
+#elif defined(_MSC_VER) /* MSVC */
+# define KWIML_INT_NO_INTTYPES_H 1
+#elif defined(__BORLANDC__) /* Borland */
+# define KWIML_INT_NO_INTTYPES_H 1
+#elif defined(__WATCOMC__) /* Watcom */
+# define KWIML_INT_NO_INTTYPES_H 1
+#else /* Assume it exists. */
+# define KWIML_INT_HAVE_INTTYPES_H 1
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if defined(KWIML_INT_HAVE_STDINT_H) && defined(KWIML_INT_NO_STDINT_H)
+# error "Both KWIML_INT_HAVE_STDINT_H and KWIML_INT_NO_STDINT_H defined!"
+#endif
+#if defined(KWIML_INT_HAVE_INTTYPES_H) && defined(KWIML_INT_NO_INTTYPES_H)
+# error "Both KWIML_INT_HAVE_INTTYPES_H and KWIML_INT_NO_INTTYPES_H defined!"
+#endif
+
+#if defined(KWIML_INT_HAVE_STDINT_H)
+# ifndef KWIML_INT_detail_INCLUDED_STDINT_H
+# define KWIML_INT_detail_INCLUDED_STDINT_H
+# include <stdint.h>
+# endif
+#endif
+#if defined(KWIML_INT_HAVE_INTTYPES_H)
+# ifndef KWIML_INT_detail_INCLUDED_INTTYPES_H
+# define KWIML_INT_detail_INCLUDED_INTTYPES_H
+# if defined(__cplusplus) && !defined(__STDC_FORMAT_MACROS)
+# define __STDC_FORMAT_MACROS
+# endif
+# include <inttypes.h>
+# endif
+#endif
+
+#if defined(KWIML_INT_HAVE_STDINT_H) || defined(KWIML_INT_HAVE_INTTYPES_H)
+#define KWIML_INT_HAVE_INT8_T 1
+#define KWIML_INT_HAVE_UINT8_T 1
+#define KWIML_INT_HAVE_INT16_T 1
+#define KWIML_INT_HAVE_UINT16_T 1
+#define KWIML_INT_HAVE_INT32_T 1
+#define KWIML_INT_HAVE_UINT32_T 1
+#define KWIML_INT_HAVE_INT64_T 1
+#define KWIML_INT_HAVE_UINT64_T 1
+#define KWIML_INT_HAVE_INTPTR_T 1
+#define KWIML_INT_HAVE_UINTPTR_T 1
+# if defined(__cplusplus)
+# define KWIML_INT_detail_GLOBAL_NS(T) ::T
+# else
+# define KWIML_INT_detail_GLOBAL_NS(T) T
+# endif
+#endif
+
+#if defined(_AIX43) && !defined(_AIX50) && !defined(_AIX51)
+ /* AIX 4.3 defines these incorrectly with % and no quotes. */
+# define KWIML_INT_BROKEN_PRId8 1
+# define KWIML_INT_BROKEN_SCNd8 1
+# define KWIML_INT_BROKEN_PRIi8 1
+# define KWIML_INT_BROKEN_SCNi8 1
+# define KWIML_INT_BROKEN_PRIo8 1
+# define KWIML_INT_BROKEN_SCNo8 1
+# define KWIML_INT_BROKEN_PRIu8 1
+# define KWIML_INT_BROKEN_SCNu8 1
+# define KWIML_INT_BROKEN_PRIx8 1
+# define KWIML_INT_BROKEN_SCNx8 1
+# define KWIML_INT_BROKEN_PRIX8 1
+# define KWIML_INT_BROKEN_PRId16 1
+# define KWIML_INT_BROKEN_SCNd16 1
+# define KWIML_INT_BROKEN_PRIi16 1
+# define KWIML_INT_BROKEN_SCNi16 1
+# define KWIML_INT_BROKEN_PRIo16 1
+# define KWIML_INT_BROKEN_SCNo16 1
+# define KWIML_INT_BROKEN_PRIu16 1
+# define KWIML_INT_BROKEN_SCNu16 1
+# define KWIML_INT_BROKEN_PRIx16 1
+# define KWIML_INT_BROKEN_SCNx16 1
+# define KWIML_INT_BROKEN_PRIX16 1
+# define KWIML_INT_BROKEN_PRId32 1
+# define KWIML_INT_BROKEN_SCNd32 1
+# define KWIML_INT_BROKEN_PRIi32 1
+# define KWIML_INT_BROKEN_SCNi32 1
+# define KWIML_INT_BROKEN_PRIo32 1
+# define KWIML_INT_BROKEN_SCNo32 1
+# define KWIML_INT_BROKEN_PRIu32 1
+# define KWIML_INT_BROKEN_SCNu32 1
+# define KWIML_INT_BROKEN_PRIx32 1
+# define KWIML_INT_BROKEN_SCNx32 1
+# define KWIML_INT_BROKEN_PRIX32 1
+# define KWIML_INT_BROKEN_PRId64 1
+# define KWIML_INT_BROKEN_SCNd64 1
+# define KWIML_INT_BROKEN_PRIi64 1
+# define KWIML_INT_BROKEN_SCNi64 1
+# define KWIML_INT_BROKEN_PRIo64 1
+# define KWIML_INT_BROKEN_SCNo64 1
+# define KWIML_INT_BROKEN_PRIu64 1
+# define KWIML_INT_BROKEN_SCNu64 1
+# define KWIML_INT_BROKEN_PRIx64 1
+# define KWIML_INT_BROKEN_SCNx64 1
+# define KWIML_INT_BROKEN_PRIX64 1
+# define KWIML_INT_BROKEN_PRIdPTR 1
+# define KWIML_INT_BROKEN_SCNdPTR 1
+# define KWIML_INT_BROKEN_PRIiPTR 1
+# define KWIML_INT_BROKEN_SCNiPTR 1
+# define KWIML_INT_BROKEN_PRIoPTR 1
+# define KWIML_INT_BROKEN_SCNoPTR 1
+# define KWIML_INT_BROKEN_PRIuPTR 1
+# define KWIML_INT_BROKEN_SCNuPTR 1
+# define KWIML_INT_BROKEN_PRIxPTR 1
+# define KWIML_INT_BROKEN_SCNxPTR 1
+# define KWIML_INT_BROKEN_PRIXPTR 1
+#endif
+
+#if (defined(__SUNPRO_C)||defined(__SUNPRO_CC)) && defined(_CHAR_IS_UNSIGNED)
+# define KWIML_INT_BROKEN_INT8_T 1 /* system type defined incorrectly */
+#elif defined(__BORLANDC__) && defined(_CHAR_UNSIGNED)
+# define KWIML_INT_BROKEN_INT8_T 1 /* system type defined incorrectly */
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_INT_int8_t)
+# if defined(KWIML_INT_HAVE_INT8_T) && !defined(KWIML_INT_BROKEN_INT8_T)
+# define KWIML_INT_int8_t KWIML_INT_detail_GLOBAL_NS(int8_t)
+# else
+# define KWIML_INT_int8_t signed char
+# endif
+#endif
+#if !defined(KWIML_INT_uint8_t)
+# if defined(KWIML_INT_HAVE_UINT8_T)
+# define KWIML_INT_uint8_t KWIML_INT_detail_GLOBAL_NS(uint8_t)
+# else
+# define KWIML_INT_uint8_t unsigned char
+# endif
+#endif
+
+#if defined(__INTEL_COMPILER)
+# if defined(_WIN32)
+# define KWIML_INT_private_NO_SCN8
+# endif
+#elif defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# define KWIML_INT_private_NO_SCN8
+#elif defined(__BORLANDC__)
+# define KWIML_INT_private_NO_SCN8
+# define KWIML_INT_private_NO_SCN64
+#elif defined(_MSC_VER)
+# define KWIML_INT_private_NO_SCN8
+#elif defined(__WATCOMC__)
+# define KWIML_INT_private_NO_SCN8
+# elif defined(__hpux) /* HP runtime lacks support (any compiler) */
+# define KWIML_INT_private_NO_SCN8
+#endif
+
+/* 8-bit d, i */
+#if !defined(KWIML_INT_PRId8)
+# if defined(KWIML_INT_HAVE_INT8_T) && defined(PRId8) \
+ && !defined(KWIML_INT_BROKEN_PRId8)
+# define KWIML_INT_PRId8 PRId8
+# else
+# define KWIML_INT_PRId8 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNd8)
+# if defined(KWIML_INT_HAVE_INT8_T) && defined(SCNd8) \
+ && !defined(KWIML_INT_BROKEN_SCNd8)
+# define KWIML_INT_SCNd8 SCNd8
+# elif !defined(KWIML_INT_private_NO_SCN8)
+# define KWIML_INT_SCNd8 "hhd"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIi8)
+# if defined(KWIML_INT_HAVE_INT8_T) && defined(PRIi8) \
+ && !defined(KWIML_INT_BROKEN_PRIi8)
+# define KWIML_INT_PRIi8 PRIi8
+# else
+# define KWIML_INT_PRIi8 "i"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNi8)
+# if defined(KWIML_INT_HAVE_INT8_T) && defined(SCNi8) \
+ && !defined(KWIML_INT_BROKEN_SCNi8)
+# define KWIML_INT_SCNi8 SCNi8
+# elif !defined(KWIML_INT_private_NO_SCN8)
+# define KWIML_INT_SCNi8 "hhi"
+# endif
+#endif
+
+/* 8-bit o, u, x, X */
+#if !defined(KWIML_INT_PRIo8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(PRIo8) \
+ && !defined(KWIML_INT_BROKEN_PRIo8)
+# define KWIML_INT_PRIo8 PRIo8
+# else
+# define KWIML_INT_PRIo8 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNo8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(SCNo8) \
+ && !defined(KWIML_INT_BROKEN_SCNo8)
+# define KWIML_INT_SCNo8 SCNo8
+# elif !defined(KWIML_INT_private_NO_SCN8)
+# define KWIML_INT_SCNo8 "hho"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIu8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(PRIu8) \
+ && !defined(KWIML_INT_BROKEN_PRIu8)
+# define KWIML_INT_PRIu8 PRIu8
+# else
+# define KWIML_INT_PRIu8 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNu8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(SCNu8) \
+ && !defined(KWIML_INT_BROKEN_SCNu8)
+# define KWIML_INT_SCNu8 SCNu8
+# elif !defined(KWIML_INT_private_NO_SCN8)
+# define KWIML_INT_SCNu8 "hhu"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIx8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(PRIx8) \
+ && !defined(KWIML_INT_BROKEN_PRIx8)
+# define KWIML_INT_PRIx8 PRIx8
+# else
+# define KWIML_INT_PRIx8 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNx8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(SCNx8) \
+ && !defined(KWIML_INT_BROKEN_SCNx8)
+# define KWIML_INT_SCNx8 SCNx8
+# elif !defined(KWIML_INT_private_NO_SCN8)
+# define KWIML_INT_SCNx8 "hhx"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIX8)
+# if defined(KWIML_INT_HAVE_UINT8_T) && defined(PRIX8) \
+ && !defined(KWIML_INT_BROKEN_PRIX8)
+# define KWIML_INT_PRIX8 PRIX8
+# else
+# define KWIML_INT_PRIX8 "X"
+# endif
+#endif
+
+/* 8-bit constants */
+#if !defined(KWIML_INT_INT8_C)
+# if defined(INT8_C) && !defined(KWIML_INT_BROKEN_INT8_C)
+# define KWIML_INT_INT8_C(c) INT8_C(c)
+# else
+# define KWIML_INT_INT8_C(c) c
+# endif
+#endif
+#if !defined(KWIML_INT_UINT8_C)
+# if defined(UINT8_C) && !defined(KWIML_INT_BROKEN_UINT8_C)
+# define KWIML_INT_UINT8_C(c) UINT8_C(c)
+# else
+# define KWIML_INT_UINT8_C(c) c ## u
+# endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_INT_int16_t)
+# if defined(KWIML_INT_HAVE_INT16_T)
+# define KWIML_INT_int16_t KWIML_INT_detail_GLOBAL_NS(int16_t)
+# else
+# define KWIML_INT_int16_t signed short
+# endif
+#endif
+#if !defined(KWIML_INT_uint16_t)
+# if defined(KWIML_INT_HAVE_UINT16_T)
+# define KWIML_INT_uint16_t KWIML_INT_detail_GLOBAL_NS(uint16_t)
+# else
+# define KWIML_INT_uint16_t unsigned short
+# endif
+#endif
+
+/* 16-bit d, i */
+#if !defined(KWIML_INT_PRId16)
+# if defined(KWIML_INT_HAVE_INT16_T) && defined(PRId16) \
+ && !defined(KWIML_INT_BROKEN_PRId16)
+# define KWIML_INT_PRId16 PRId16
+# else
+# define KWIML_INT_PRId16 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNd16)
+# if defined(KWIML_INT_HAVE_INT16_T) && defined(SCNd16) \
+ && !defined(KWIML_INT_BROKEN_SCNd16)
+# define KWIML_INT_SCNd16 SCNd16
+# else
+# define KWIML_INT_SCNd16 "hd"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIi16)
+# if defined(KWIML_INT_HAVE_INT16_T) && defined(PRIi16) \
+ && !defined(KWIML_INT_BROKEN_PRIi16)
+# define KWIML_INT_PRIi16 PRIi16
+# else
+# define KWIML_INT_PRIi16 "i"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNi16)
+# if defined(KWIML_INT_HAVE_INT16_T) && defined(SCNi16) \
+ && !defined(KWIML_INT_BROKEN_SCNi16)
+# define KWIML_INT_SCNi16 SCNi16
+# else
+# define KWIML_INT_SCNi16 "hi"
+# endif
+#endif
+
+/* 16-bit o, u, x, X */
+#if !defined(KWIML_INT_PRIo16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(PRIo16) \
+ && !defined(KWIML_INT_BROKEN_PRIo16)
+# define KWIML_INT_PRIo16 PRIo16
+# else
+# define KWIML_INT_PRIo16 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNo16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(SCNo16) \
+ && !defined(KWIML_INT_BROKEN_SCNo16)
+# define KWIML_INT_SCNo16 SCNo16
+# else
+# define KWIML_INT_SCNo16 "ho"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIu16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(PRIu16) \
+ && !defined(KWIML_INT_BROKEN_PRIu16)
+# define KWIML_INT_PRIu16 PRIu16
+# else
+# define KWIML_INT_PRIu16 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNu16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(SCNu16) \
+ && !defined(KWIML_INT_BROKEN_SCNu16)
+# define KWIML_INT_SCNu16 SCNu16
+# else
+# define KWIML_INT_SCNu16 "hu"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIx16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(PRIx16) \
+ && !defined(KWIML_INT_BROKEN_PRIx16)
+# define KWIML_INT_PRIx16 PRIx16
+# else
+# define KWIML_INT_PRIx16 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNx16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(SCNx16) \
+ && !defined(KWIML_INT_BROKEN_SCNx16)
+# define KWIML_INT_SCNx16 SCNx16
+# else
+# define KWIML_INT_SCNx16 "hx"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIX16)
+# if defined(KWIML_INT_HAVE_UINT16_T) && defined(PRIX16) \
+ && !defined(KWIML_INT_BROKEN_PRIX16)
+# define KWIML_INT_PRIX16 PRIX16
+# else
+# define KWIML_INT_PRIX16 "X"
+# endif
+#endif
+
+/* 16-bit constants */
+#if !defined(KWIML_INT_INT16_C)
+# if defined(INT16_C) && !defined(KWIML_INT_BROKEN_INT16_C)
+# define KWIML_INT_INT16_C(c) INT16_C(c)
+# else
+# define KWIML_INT_INT16_C(c) c
+# endif
+#endif
+#if !defined(KWIML_INT_UINT16_C)
+# if defined(UINT16_C) && !defined(KWIML_INT_BROKEN_UINT16_C)
+# define KWIML_INT_UINT16_C(c) UINT16_C(c)
+# else
+# define KWIML_INT_UINT16_C(c) c ## u
+# endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_INT_int32_t)
+# if defined(KWIML_INT_HAVE_INT32_T)
+# define KWIML_INT_int32_t KWIML_INT_detail_GLOBAL_NS(int32_t)
+# else
+# define KWIML_INT_int32_t signed int
+# endif
+#endif
+#if !defined(KWIML_INT_uint32_t)
+# if defined(KWIML_INT_HAVE_UINT32_T)
+# define KWIML_INT_uint32_t KWIML_INT_detail_GLOBAL_NS(uint32_t)
+# else
+# define KWIML_INT_uint32_t unsigned int
+# endif
+#endif
+
+/* 32-bit d, i */
+#if !defined(KWIML_INT_PRId32)
+# if defined(KWIML_INT_HAVE_INT32_T) && defined(PRId32) \
+ && !defined(KWIML_INT_BROKEN_PRId32)
+# define KWIML_INT_PRId32 PRId32
+# else
+# define KWIML_INT_PRId32 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNd32)
+# if defined(KWIML_INT_HAVE_INT32_T) && defined(SCNd32) \
+ && !defined(KWIML_INT_BROKEN_SCNd32)
+# define KWIML_INT_SCNd32 SCNd32
+# else
+# define KWIML_INT_SCNd32 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIi32)
+# if defined(KWIML_INT_HAVE_INT32_T) && defined(PRIi32) \
+ && !defined(KWIML_INT_BROKEN_PRIi32)
+# define KWIML_INT_PRIi32 PRIi32
+# else
+# define KWIML_INT_PRIi32 "i"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNi32)
+# if defined(KWIML_INT_HAVE_INT32_T) && defined(SCNi32) \
+ && !defined(KWIML_INT_BROKEN_SCNi32)
+# define KWIML_INT_SCNi32 SCNi32
+# else
+# define KWIML_INT_SCNi32 "i"
+# endif
+#endif
+
+/* 32-bit o, u, x, X */
+#if !defined(KWIML_INT_PRIo32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(PRIo32) \
+ && !defined(KWIML_INT_BROKEN_PRIo32)
+# define KWIML_INT_PRIo32 PRIo32
+# else
+# define KWIML_INT_PRIo32 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNo32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(SCNo32) \
+ && !defined(KWIML_INT_BROKEN_SCNo32)
+# define KWIML_INT_SCNo32 SCNo32
+# else
+# define KWIML_INT_SCNo32 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIu32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(PRIu32) \
+ && !defined(KWIML_INT_BROKEN_PRIu32)
+# define KWIML_INT_PRIu32 PRIu32
+# else
+# define KWIML_INT_PRIu32 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNu32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(SCNu32) \
+ && !defined(KWIML_INT_BROKEN_SCNu32)
+# define KWIML_INT_SCNu32 SCNu32
+# else
+# define KWIML_INT_SCNu32 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIx32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(PRIx32) \
+ && !defined(KWIML_INT_BROKEN_PRIx32)
+# define KWIML_INT_PRIx32 PRIx32
+# else
+# define KWIML_INT_PRIx32 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNx32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(SCNx32) \
+ && !defined(KWIML_INT_BROKEN_SCNx32)
+# define KWIML_INT_SCNx32 SCNx32
+# else
+# define KWIML_INT_SCNx32 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIX32)
+# if defined(KWIML_INT_HAVE_UINT32_T) && defined(PRIX32) \
+ && !defined(KWIML_INT_BROKEN_PRIX32)
+# define KWIML_INT_PRIX32 PRIX32
+# else
+# define KWIML_INT_PRIX32 "X"
+# endif
+#endif
+
+#if defined(__hpux) && defined(__GNUC__) && !defined(__LP64__) \
+ && defined(__CONCAT__) && defined(__CONCAT_U__)
+ /* Some HPs define UINT32_C incorrectly and break GNU. */
+# define KWIML_INT_BROKEN_UINT32_C 1
+#endif
+
+/* 32-bit constants */
+#if !defined(KWIML_INT_INT32_C)
+# if defined(INT32_C) && !defined(KWIML_INT_BROKEN_INT32_C)
+# define KWIML_INT_INT32_C(c) INT32_C(c)
+# else
+# define KWIML_INT_INT32_C(c) c
+# endif
+#endif
+#if !defined(KWIML_INT_UINT32_C)
+# if defined(UINT32_C) && !defined(KWIML_INT_BROKEN_UINT32_C)
+# define KWIML_INT_UINT32_C(c) UINT32_C(c)
+# else
+# define KWIML_INT_UINT32_C(c) c ## u
+# endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_INT_int64_t) && !defined(KWIML_INT_NO_INT64_T)
+# if defined(KWIML_INT_HAVE_INT64_T)
+# define KWIML_INT_int64_t KWIML_INT_detail_GLOBAL_NS(int64_t)
+# elif KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_INT_int64_t signed long
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# define KWIML_INT_int64_t signed long long
+# elif defined(KWIML_ABI_SIZEOF___INT64)
+# define KWIML_INT_int64_t signed __int64
+# elif defined(KWIML_INT_NO_ERROR_INT64_T)
+# define KWIML_INT_NO_INT64_T
+# else
+# error "No type known for 'int64_t'."
+# endif
+#endif
+#if !defined(KWIML_INT_uint64_t) && !defined(KWIML_INT_NO_UINT64_T)
+# if defined(KWIML_INT_HAVE_UINT64_T)
+# define KWIML_INT_uint64_t KWIML_INT_detail_GLOBAL_NS(uint64_t)
+# elif KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_INT_uint64_t unsigned long
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# define KWIML_INT_uint64_t unsigned long long
+# elif defined(KWIML_ABI_SIZEOF___INT64)
+# define KWIML_INT_uint64_t unsigned __int64
+# elif defined(KWIML_INT_NO_ERROR_UINT64_T)
+# define KWIML_INT_NO_UINT64_T
+# else
+# error "No type known for 'uint64_t'."
+# endif
+#endif
+
+#if defined(__INTEL_COMPILER)
+#elif defined(__BORLANDC__)
+# define KWIML_INT_private_NO_FMTLL /* type 'long long' but not 'll' format */
+# define KWIML_INT_BROKEN_INT64_C 1 /* system macro defined incorrectly */
+# define KWIML_INT_BROKEN_UINT64_C 1 /* system macro defined incorrectly */
+#elif defined(_MSC_VER) && _MSC_VER < 1400
+# define KWIML_INT_private_NO_FMTLL /* type 'long long' but not 'll' format */
+#endif
+
+#if !defined(KWIML_INT_detail_FMT64)
+# if KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_INT_detail_FMT64 "l"
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# if !defined(KWIML_INT_private_NO_FMTLL)
+# define KWIML_INT_detail_FMT64 "ll"
+# else
+# define KWIML_INT_detail_FMT64 "I64"
+# endif
+# elif defined(KWIML_ABI_SIZEOF___INT64)
+# if defined(__BORLANDC__)
+# define KWIML_INT_detail_FMT64 "L"
+# else
+# define KWIML_INT_detail_FMT64 "I64"
+# endif
+# endif
+#endif
+
+#undef KWIML_INT_private_NO_FMTLL
+
+/* 64-bit d, i */
+#if !defined(KWIML_INT_PRId64)
+# if defined(KWIML_INT_HAVE_INT64_T) && defined(PRId64) \
+ && !defined(KWIML_INT_BROKEN_PRId64)
+# define KWIML_INT_PRId64 PRId64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRId64 KWIML_INT_detail_FMT64 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNd64)
+# if defined(KWIML_INT_HAVE_INT64_T) && defined(SCNd64) \
+ && !defined(KWIML_INT_BROKEN_SCNd64)
+# define KWIML_INT_SCNd64 SCNd64
+# elif defined(KWIML_INT_detail_FMT64) && !defined(KWIML_INT_private_NO_SCN64)
+# define KWIML_INT_SCNd64 KWIML_INT_detail_FMT64 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIi64)
+# if defined(KWIML_INT_HAVE_INT64_T) && defined(PRIi64) \
+ && !defined(KWIML_INT_BROKEN_PRIi64)
+# define KWIML_INT_PRIi64 PRIi64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRIi64 KWIML_INT_detail_FMT64 "d"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNi64)
+# if defined(KWIML_INT_HAVE_INT64_T) && defined(SCNi64) \
+ && !defined(KWIML_INT_BROKEN_SCNi64)
+# define KWIML_INT_SCNi64 SCNi64
+# elif defined(KWIML_INT_detail_FMT64) && !defined(KWIML_INT_private_NO_SCN64)
+# define KWIML_INT_SCNi64 KWIML_INT_detail_FMT64 "d"
+# endif
+#endif
+
+/* 64-bit o, u, x, X */
+#if !defined(KWIML_INT_PRIo64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(PRIo64) \
+ && !defined(KWIML_INT_BROKEN_PRIo64)
+# define KWIML_INT_PRIo64 PRIo64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRIo64 KWIML_INT_detail_FMT64 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNo64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(SCNo64) \
+ && !defined(KWIML_INT_BROKEN_SCNo64)
+# define KWIML_INT_SCNo64 SCNo64
+# elif defined(KWIML_INT_detail_FMT64) && !defined(KWIML_INT_private_NO_SCN64)
+# define KWIML_INT_SCNo64 KWIML_INT_detail_FMT64 "o"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIu64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(PRIu64) \
+ && !defined(KWIML_INT_BROKEN_PRIu64)
+# define KWIML_INT_PRIu64 PRIu64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRIu64 KWIML_INT_detail_FMT64 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNu64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(SCNu64) \
+ && !defined(KWIML_INT_BROKEN_SCNu64)
+# define KWIML_INT_SCNu64 SCNu64
+# elif defined(KWIML_INT_detail_FMT64) && !defined(KWIML_INT_private_NO_SCN64)
+# define KWIML_INT_SCNu64 KWIML_INT_detail_FMT64 "u"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIx64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(PRIx64) \
+ && !defined(KWIML_INT_BROKEN_PRIx64)
+# define KWIML_INT_PRIx64 PRIx64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRIx64 KWIML_INT_detail_FMT64 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_SCNx64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(SCNx64) \
+ && !defined(KWIML_INT_BROKEN_SCNx64)
+# define KWIML_INT_SCNx64 SCNx64
+# elif defined(KWIML_INT_detail_FMT64) && !defined(KWIML_INT_private_NO_SCN64)
+# define KWIML_INT_SCNx64 KWIML_INT_detail_FMT64 "x"
+# endif
+#endif
+#if !defined(KWIML_INT_PRIX64)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(PRIX64) \
+ && !defined(KWIML_INT_BROKEN_PRIX64)
+# define KWIML_INT_PRIX64 PRIX64
+# elif defined(KWIML_INT_detail_FMT64)
+# define KWIML_INT_PRIX64 KWIML_INT_detail_FMT64 "X"
+# endif
+#endif
+
+/* 64-bit constants */
+#if !defined(KWIML_INT_INT64_C)
+# if defined(KWIML_INT_HAVE_INT64_T) && defined(INT64_C) \
+ && !defined(KWIML_INT_BROKEN_INT64_C)
+# define KWIML_INT_INT64_C(c) INT64_C(c)
+# elif KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_INT_INT64_C(c) c ## l
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# define KWIML_INT_INT64_C(c) c ## ll
+# elif defined(KWIML_ABI_SIZEOF___INT64)
+# define KWIML_INT_INT64_C(c) c ## i64
+# endif
+#endif
+#if !defined(KWIML_INT_UINT64_C)
+# if defined(KWIML_INT_HAVE_UINT64_T) && defined(UINT64_C) \
+ && !defined(KWIML_INT_BROKEN_UINT64_C)
+# define KWIML_INT_UINT64_C(c) UINT64_C(c)
+# elif KWIML_ABI_SIZEOF_LONG == 8
+# define KWIML_INT_UINT64_C(c) c ## ul
+# elif defined(KWIML_ABI_SIZEOF_LONG_LONG) && KWIML_ABI_SIZEOF_LONG_LONG == 8
+# define KWIML_INT_UINT64_C(c) c ## ull
+# elif defined(KWIML_ABI_SIZEOF___INT64)
+# define KWIML_INT_UINT64_C(c) c ## ui64
+# endif
+#endif
+
+/*--------------------------------------------------------------------------*/
+#if !defined(KWIML_INT_intptr_t) && !defined(KWIML_INT_NO_INTPTR_T)
+# if defined(KWIML_INT_HAVE_INTPTR_T)
+# define KWIML_INT_intptr_t KWIML_INT_detail_GLOBAL_NS(intptr_t)
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_intptr_t KWIML_INT_int32_t
+# elif !defined(KWIML_INT_NO_INT64_T)
+# define KWIML_INT_intptr_t KWIML_INT_int64_t
+# elif defined(KWIML_INT_NO_ERROR_INTPTR_T)
+# define KWIML_INT_NO_INTPTR_T
+# else
+# error "No type known for 'intptr_t'."
+# endif
+#endif
+#if !defined(KWIML_INT_uintptr_t) && !defined(KWIML_INT_NO_UINTPTR_T)
+# if defined(KWIML_INT_HAVE_UINTPTR_T)
+# define KWIML_INT_uintptr_t KWIML_INT_detail_GLOBAL_NS(uintptr_t)
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_uintptr_t KWIML_INT_uint32_t
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_uintptr_t KWIML_INT_uint64_t
+# elif defined(KWIML_INT_NO_ERROR_UINTPTR_T)
+# define KWIML_INT_NO_UINTPTR_T
+# else
+# error "No type known for 'uintptr_t'."
+# endif
+#endif
+
+#if !defined(KWIML_INT_PRIdPTR)
+# if defined(KWIML_INT_HAVE_INTPTR_T) && defined(PRIdPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIdPTR)
+# define KWIML_INT_PRIdPTR PRIdPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIdPTR KWIML_INT_PRId32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIdPTR KWIML_INT_PRId64
+# endif
+#endif
+#if !defined(KWIML_INT_SCNdPTR)
+# if defined(KWIML_INT_HAVE_INTPTR_T) && defined(SCNdPTR) \
+ && !defined(KWIML_INT_BROKEN_SCNdPTR)
+# define KWIML_INT_SCNdPTR SCNdPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_SCNdPTR KWIML_INT_SCNd32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_SCNdPTR KWIML_INT_SCNd64
+# endif
+#endif
+#if !defined(KWIML_INT_PRIiPTR)
+# if defined(KWIML_INT_HAVE_INTPTR_T) && defined(PRIiPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIiPTR)
+# define KWIML_INT_PRIiPTR PRIiPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIiPTR KWIML_INT_PRIi32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIiPTR KWIML_INT_PRIi64
+# endif
+#endif
+#if !defined(KWIML_INT_SCNiPTR)
+# if defined(KWIML_INT_HAVE_INTPTR_T) && defined(SCNiPTR) \
+ && !defined(KWIML_INT_BROKEN_SCNiPTR)
+# define KWIML_INT_SCNiPTR SCNiPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_SCNiPTR KWIML_INT_SCNi32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_SCNiPTR KWIML_INT_SCNi64
+# endif
+#endif
+
+#if !defined(KWIML_INT_PRIoPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(PRIoPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIoPTR)
+# define KWIML_INT_PRIoPTR PRIoPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIoPTR KWIML_INT_PRIo32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIoPTR KWIML_INT_PRIo64
+# endif
+#endif
+#if !defined(KWIML_INT_SCNoPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(SCNoPTR) \
+ && !defined(KWIML_INT_BROKEN_SCNoPTR)
+# define KWIML_INT_SCNoPTR SCNoPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_SCNoPTR KWIML_INT_SCNo32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_SCNoPTR KWIML_INT_SCNo64
+# endif
+#endif
+#if !defined(KWIML_INT_PRIuPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(PRIuPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIuPTR)
+# define KWIML_INT_PRIuPTR PRIuPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIuPTR KWIML_INT_PRIu32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIuPTR KWIML_INT_PRIu64
+# endif
+#endif
+#if !defined(KWIML_INT_SCNuPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(SCNuPTR) \
+ && !defined(KWIML_INT_BROKEN_SCNuPTR)
+# define KWIML_INT_SCNuPTR SCNuPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_SCNuPTR KWIML_INT_SCNu32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_SCNuPTR KWIML_INT_SCNu64
+# endif
+#endif
+#if !defined(KWIML_INT_PRIxPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(PRIxPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIxPTR)
+# define KWIML_INT_PRIxPTR PRIxPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIxPTR KWIML_INT_PRIx32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIxPTR KWIML_INT_PRIx64
+# endif
+#endif
+#if !defined(KWIML_INT_SCNxPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(SCNxPTR) \
+ && !defined(KWIML_INT_BROKEN_SCNxPTR)
+# define KWIML_INT_SCNxPTR SCNxPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_SCNxPTR KWIML_INT_SCNx32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_SCNxPTR KWIML_INT_SCNx64
+# endif
+#endif
+#if !defined(KWIML_INT_PRIXPTR)
+# if defined(KWIML_INT_HAVE_UINTPTR_T) && defined(PRIXPTR) \
+ && !defined(KWIML_INT_BROKEN_PRIXPTR)
+# define KWIML_INT_PRIXPTR PRIXPTR
+# elif KWIML_ABI_SIZEOF_DATA_PTR == 4
+# define KWIML_INT_PRIXPTR KWIML_INT_PRIX32
+# elif !defined(KWIML_INT_NO_UINT64_T)
+# define KWIML_INT_PRIXPTR KWIML_INT_PRIX64
+# endif
+#endif
+
+#undef KWIML_INT_private_NO_SCN64
+#undef KWIML_INT_private_NO_SCN8
+
+#endif /* KWIML_INT_private_DO_DEFINE */
+
+/*--------------------------------------------------------------------------*/
+#ifdef KWIML_INT_private_DO_VERIFY
+#undef KWIML_INT_private_DO_VERIFY
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4310) /* cast truncates constant value */
+#endif
+
+#define KWIML_INT_private_VERIFY(n, x, y) KWIML_INT_private_VERIFY_0(KWIML_INT_private_VERSION, n, x, y)
+#define KWIML_INT_private_VERIFY_0(V, n, x, y) KWIML_INT_private_VERIFY_1(V, n, x, y)
+#define KWIML_INT_private_VERIFY_1(V, n, x, y) extern int (*n##_v##V)[x]; extern int (*n##_v##V)[y]
+
+#define KWIML_INT_private_VERIFY_BOOL(m, b) KWIML_INT_private_VERIFY(KWIML_INT_detail_VERIFY_##m, 2, (b)?2:3)
+#define KWIML_INT_private_VERIFY_TYPE(t, s) KWIML_INT_private_VERIFY(KWIML_INT_detail_VERIFY_##t, s, sizeof(t))
+#define KWIML_INT_private_VERIFY_SIGN(t, u, o) KWIML_INT_private_VERIFY_BOOL(SIGN_##t, (t)((u)1 << ((sizeof(t)<<3)-1)) o 0)
+
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_int8_t, 1);
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_uint8_t, 1);
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_int16_t, 2);
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_uint16_t, 2);
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_int32_t, 4);
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_uint32_t, 4);
+#if !defined(KWIML_INT_NO_INT64_T)
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_int64_t, 8);
+#endif
+#if !defined(KWIML_INT_NO_UINT64_T)
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_uint64_t, 8);
+#endif
+#if !defined(KWIML_INT_NO_INTPTR_T)
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_intptr_t, sizeof(void*));
+#endif
+#if !defined(KWIML_INT_NO_UINTPTR_T)
+KWIML_INT_private_VERIFY_TYPE(KWIML_INT_uintptr_t, sizeof(void*));
+#endif
+
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_int8_t, KWIML_INT_uint8_t, <);
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_uint8_t, KWIML_INT_uint8_t, >);
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_int16_t, KWIML_INT_uint16_t, <);
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_uint16_t, KWIML_INT_uint16_t, >);
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_int32_t, KWIML_INT_uint32_t, <);
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_uint32_t, KWIML_INT_uint32_t, >);
+#if !defined(KWIML_INT_NO_INT64_T)
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_int64_t, KWIML_INT_uint64_t, <);
+#endif
+#if !defined(KWIML_INT_NO_UINT64_T)
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_uint64_t, KWIML_INT_uint64_t, >);
+#endif
+#if !defined(KWIML_INT_NO_INTPTR_T)
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_intptr_t, KWIML_INT_uintptr_t, <);
+#endif
+#if !defined(KWIML_INT_NO_UINTPTR_T)
+KWIML_INT_private_VERIFY_SIGN(KWIML_INT_uintptr_t, KWIML_INT_uintptr_t, >);
+#endif
+
+#undef KWIML_INT_private_VERIFY_SIGN
+#undef KWIML_INT_private_VERIFY_TYPE
+#undef KWIML_INT_private_VERIFY_BOOL
+
+#undef KWIML_INT_private_VERIFY_1
+#undef KWIML_INT_private_VERIFY_0
+#undef KWIML_INT_private_VERIFY
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
+
+#endif /* KWIML_INT_private_DO_VERIFY */
+
+#undef KWIML_INT_private_VERSION
diff --git a/Utilities/KWIML/src/kwiml-config.cmake.in b/Utilities/KWIML/src/kwiml-config.cmake.in
new file mode 100644
index 000000000..124f0fc55
--- /dev/null
+++ b/Utilities/KWIML/src/kwiml-config.cmake.in
@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/kwiml-targets.cmake)
diff --git a/Utilities/KWIML/src/version.h.in b/Utilities/KWIML/src/version.h.in
new file mode 100644
index 000000000..0ac8854f2
--- /dev/null
+++ b/Utilities/KWIML/src/version.h.in
@@ -0,0 +1,59 @@
+/*============================================================================
+ Kitware Information Macro Library
+ Copyright 2010-2016 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:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * 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.
+
+ * Neither the name of Kitware, Inc. nor the names of its contributors
+ may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+============================================================================*/
+#ifndef KWIML_VERSION_H
+#define KWIML_VERSION_H
+/*
+This header defines macros with information about this version of KWIML.
+
+An includer may test the following macros after inclusion:
+
+ KWIML_VERSION = KWIML version number encoded in an integer as
+ `printf("%d%03d%03d", MAJOR, MINOR, PATCH)`.
+ MAJOR is incremented on incompatible changes.
+ MINOR is incremented on interface additions.
+ PATCH is incremented on implementation updates.
+
+ KWIML_VERSION_STRING = KWIML version number in string formatted as
+ `printf("%d.%d.%d", MAJOR, MINOR PATCH)`.
+
+ KWIML_VERSION_HAS_ABI_H = header 'kwiml/abi.h' is available
+ KWIML_VERSION_HAS_INT_H = header 'kwiml/int.h' is available
+*/
+
+#define KWIML_VERSION @KWIML_VERSION_DECIMAL@
+#define KWIML_VERSION_STRING "@KWIML_VERSION@"
+
+#define KWIML_VERSION_HAS_ABI_H 1
+#define KWIML_VERSION_HAS_INT_H 1
+
+#endif
diff --git a/Utilities/KWIML/test/CMakeLists.txt b/Utilities/KWIML/test/CMakeLists.txt
index a2359cce1..40fe62f20 100644
--- a/Utilities/KWIML/test/CMakeLists.txt
+++ b/Utilities/KWIML/test/CMakeLists.txt
@@ -1,27 +1,16 @@
-#=============================================================================
-# Kitware Information Macro Library
-# Copyright 2010-2011 Kitware, Inc.
#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
+# Copyright Kitware, Inc.
+# Distributed under the OSI-approved BSD 3-Clause License.
+# See accompanying file Copyright.txt for details.
#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-
-set(test_defs KWIML_NAMESPACE=${KWIML})
-
-# Tell CMake how to follow dependencies of sources in this directory.
-set_property(DIRECTORY
- PROPERTY IMPLICIT_DEPENDS_INCLUDE_TRANSFORM
- "KWIML_HEADER(%)=<${KWIML}/%>"
- )
+if(NOT KWIML_TEST_PREFIX)
+ set(KWIML_TEST_PREFIX kwiml)
+endif()
# Suppress printf/scanf format warnings; we test if the sizes match.
foreach(lang C CXX)
- if(KWIML_LANGUAGE_${lang} AND "${CMAKE_${lang}_COMPILER_ID}" STREQUAL GNU)
- set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -Wno-format")
+ if(KWIML_LANGUAGE_${lang} AND CMAKE_${lang}_COMPILER_ID STREQUAL "GNU")
+ set(CMAKE_${lang}_FLAGS "${CMAKE_${lang}_FLAGS} -Wno-format -Wno-format-security")
endif()
endforeach()
@@ -33,38 +22,35 @@ endif()
if(KWIML_LANGUAGE_C)
list(APPEND test_defs KWIML_LANGUAGE_C)
list(APPEND test_srcs
- test_ABI_C.c
- test_INT_C.c
+ test_abi_C.c
+ test_int_C.c
test_include_C.c
)
endif()
if(KWIML_LANGUAGE_CXX)
list(APPEND test_defs KWIML_LANGUAGE_CXX)
list(APPEND test_srcs
- test_ABI_CXX.cxx
- test_INT_CXX.cxx
+ test_abi_CXX.cxx
+ test_int_CXX.cxx
test_include_CXX.cxx
)
endif()
-foreach(th test_ABI_endian test_INT_format)
- configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${th}.h.in
- ${CMAKE_CURRENT_BINARY_DIR}/${th}.h @ONLY)
-endforeach()
-include_directories(BEFORE ${CMAKE_CURRENT_BINARY_DIR})
-add_executable(${KWIML}_test ${test_srcs})
-set_property(TARGET ${KWIML}_test PROPERTY COMPILE_DEFINITIONS ${test_defs})
-set_property(TARGET ${KWIML}_test PROPERTY
+add_executable(kwiml_test ${test_srcs})
+set_property(TARGET kwiml_test PROPERTY COMPILE_DEFINITIONS ${test_defs})
+set_property(TARGET kwiml_test PROPERTY C_INCLUDE_WHAT_YOU_USE "")
+set_property(TARGET kwiml_test PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
+set_property(TARGET kwiml_test PROPERTY
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
-add_test(${KWIML}.test ${CMAKE_CURRENT_BINARY_DIR}/${KWIML}_test)
-set_property(TEST ${KWIML}.test PROPERTY LABELS ${KWIML_LABELS_TEST})
+add_test(NAME ${KWIML_TEST_PREFIX}.test COMMAND kwiml_test)
+set_property(TEST ${KWIML_TEST_PREFIX}.test PROPERTY LABELS ${KWIML_TEST_LABELS})
# Xcode 2.x forgets to create the output directory before linking
# the individual architectures.
if(CMAKE_OSX_ARCHITECTURES AND XCODE
AND NOT "${XCODE_VERSION}" MATCHES "^[^12]")
add_custom_command(
- TARGET ${KWIML}_test
+ TARGET kwiml_test
PRE_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_CFG_INTDIR}"
)
endif()
diff --git a/Utilities/KWIML/test/test.c b/Utilities/KWIML/test/test.c
index 131c81f92..5f5b5d776 100644
--- a/Utilities/KWIML/test/test.c
+++ b/Utilities/KWIML/test/test.c
@@ -1,21 +1,15 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
#ifdef __cplusplus
extern "C" {
#endif
-extern int test_ABI_C(void);
-extern int test_INT_C(void);
-extern int test_ABI_CXX(void);
-extern int test_INT_CXX(void);
+extern int test_abi_C(void);
+extern int test_int_C(void);
+extern int test_abi_CXX(void);
+extern int test_int_CXX(void);
extern int test_include_C(void);
extern int test_include_CXX(void);
#ifdef __cplusplus
@@ -26,13 +20,13 @@ int main(void)
{
int result = 1;
#ifdef KWIML_LANGUAGE_C
- result = test_ABI_C() && result;
- result = test_INT_C() && result;
+ result = test_abi_C() && result;
+ result = test_int_C() && result;
result = test_include_C() && result;
#endif
#ifdef KWIML_LANGUAGE_CXX
- result = test_ABI_CXX() && result;
- result = test_INT_CXX() && result;
+ result = test_abi_CXX() && result;
+ result = test_int_CXX() && result;
result = test_include_CXX() && result;
#endif
return result? 0 : 1;
diff --git a/Utilities/KWIML/test/test.cxx b/Utilities/KWIML/test/test.cxx
index bf614218a..464325ba4 100644
--- a/Utilities/KWIML/test/test.cxx
+++ b/Utilities/KWIML/test/test.cxx
@@ -1,12 +1,6 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
#include "test.c"
diff --git a/Utilities/KWIML/test/test.h b/Utilities/KWIML/test/test.h
index b87a0e7e9..44add3faf 100644
--- a/Utilities/KWIML/test/test.h
+++ b/Utilities/KWIML/test/test.h
@@ -1,31 +1,10 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef KWIML_NAMESPACE
-# error "Do not include test.h outside of KWIML test files."
-#endif
-
-#ifndef KWIML_TEST_H
-#define KWIML_TEST_H
-
/*
- Define KWIML_HEADER macro to help the test files include kwiml
- headers from the configured namespace directory. The macro can be
- used like this:
-
- #include KWIML_HEADER(ABI.h)
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
*/
-#define KWIML_HEADER(x) KWIML_HEADER0(KWIML_NAMESPACE/x)
-#define KWIML_HEADER0(x) KWIML_HEADER1(x)
-#define KWIML_HEADER1(x) <x>
+#ifndef KWIML_TEST_H
+#define KWIML_TEST_H
/* Quiet MS standard library deprecation warnings. */
#ifndef _CRT_SECURE_NO_DEPRECATE
diff --git a/Utilities/KWIML/test/test_ABI_C.c b/Utilities/KWIML/test/test_ABI_C.c
deleted file mode 100644
index 3ca4ad390..000000000
--- a/Utilities/KWIML/test/test_ABI_C.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include "test.h"
-#include KWIML_HEADER(ABI.h)
-#include "test_ABI_endian.h"
-int test_ABI_C(void)
-{
- if(!test_ABI_endian())
- {
- return 0;
- }
- return 1;
-}
diff --git a/Utilities/KWIML/test/test_ABI_CXX.cxx b/Utilities/KWIML/test/test_ABI_CXX.cxx
deleted file mode 100644
index 7ede20e09..000000000
--- a/Utilities/KWIML/test/test_ABI_CXX.cxx
+++ /dev/null
@@ -1,22 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include "test.h"
-#include KWIML_HEADER(ABI.h)
-#include "test_ABI_endian.h"
-extern "C" int test_ABI_CXX(void)
-{
- if(!test_ABI_endian())
- {
- return 0;
- }
- return 1;
-}
diff --git a/Utilities/KWIML/test/test_ABI_endian.h.in b/Utilities/KWIML/test/test_ABI_endian.h.in
deleted file mode 100644
index 992baeaeb..000000000
--- a/Utilities/KWIML/test/test_ABI_endian.h.in
+++ /dev/null
@@ -1,47 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include <stdio.h>
-
-#ifdef __cplusplus
-# define LANG "C++ "
-#else
-# define LANG "C "
-#endif
-
-static int test_ABI_endian(void)
-{
- int result = 1;
- {
-#if defined(@KWIML@_ABI_ENDIAN_ID)
- int expect;
- union { short s; unsigned char c[sizeof(short)]; } x;
- x.s = 1;
- expect = (x.c[0] == 1 ?
- @KWIML@_ABI_ENDIAN_ID_LITTLE : @KWIML@_ABI_ENDIAN_ID_BIG);
- printf(LANG "@KWIML@_ABI_ENDIAN_ID: expected [%d], got [%d]",
- expect, @KWIML@_ABI_ENDIAN_ID);
- if(@KWIML@_ABI_ENDIAN_ID == expect)
- {
- printf(", PASSED\n");
- }
- else
- {
- printf(", FAILED\n");
- result = 0;
- }
-#else
- printf(LANG "@KWIML@_ABI_ENDIAN_ID: unknown, FAILED\n");
- result = 0;
-#endif
- }
- return result;
-}
diff --git a/Utilities/KWIML/test/test_INT_C.c b/Utilities/KWIML/test/test_INT_C.c
deleted file mode 100644
index 5513a0bd8..000000000
--- a/Utilities/KWIML/test/test_INT_C.c
+++ /dev/null
@@ -1,22 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include "test.h"
-#include KWIML_HEADER(INT.h)
-#include "test_INT_format.h"
-int test_INT_C(void)
-{
- if(!test_INT_format())
- {
- return 0;
- }
- return 1;
-}
diff --git a/Utilities/KWIML/test/test_INT_CXX.cxx b/Utilities/KWIML/test/test_INT_CXX.cxx
deleted file mode 100644
index 9f74e9680..000000000
--- a/Utilities/KWIML/test/test_INT_CXX.cxx
+++ /dev/null
@@ -1,22 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include "test.h"
-#include KWIML_HEADER(INT.h)
-#include "test_INT_format.h"
-extern "C" int test_INT_CXX(void)
-{
- if(!test_INT_format())
- {
- return 0;
- }
- return 1;
-}
diff --git a/Utilities/KWIML/test/test_INT_format.h.in b/Utilities/KWIML/test/test_INT_format.h.in
deleted file mode 100644
index 71b443d6e..000000000
--- a/Utilities/KWIML/test/test_INT_format.h.in
+++ /dev/null
@@ -1,200 +0,0 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#include <stdio.h>
-#include <string.h>
-
-#ifdef __cplusplus
-# define LANG "C++ "
-#else
-# define LANG "C "
-#endif
-
-#define VALUE(T, U) (T)((U)0xab << ((sizeof(T)-1)<<3))
-
-#define TEST_C_(C, V, PRI, T, U) \
- { \
- T const x = VALUE(T, U); \
- T y = C(V); \
- printf(LANG #C ":" \
- " expression [%" @KWIML@_INT_PRI##PRI "]," \
- " literal [%" @KWIML@_INT_PRI##PRI "]", x, y); \
- if(x == y) \
- { \
- printf(", PASSED\n"); \
- } \
- else \
- { \
- printf(", FAILED\n"); \
- result = 0; \
- } \
- }
-
-#define TEST_PRI_(PRI, T, U, STR) \
- { \
- T const x = VALUE(T, U); \
- char const* str = STR; \
- sprintf(buf, "%" @KWIML@_INT_PRI##PRI, x); \
- printf(LANG "@KWIML@_INT_PRI" #PRI ":" \
- " expected [%s], got [%s]", str, buf); \
- if(strcmp(str, buf) == 0) \
- { \
- printf(", PASSED\n"); \
- } \
- else \
- { \
- printf(", FAILED\n"); \
- result = 0; \
- } \
- }
-
-#define TEST_SCN_(SCN, T, U, STR) TEST_SCN2_(SCN, SCN, T, U, STR)
-#define TEST_SCN2_(PRI, SCN, T, U, STR) \
- { \
- T const x = VALUE(T, U); \
- T y; \
- char const* str = STR; \
- if(sscanf(str, "%" @KWIML@_INT_SCN##SCN, &y) != 1) \
- { \
- y = 0; \
- } \
- printf(LANG "@KWIML@_INT_SCN" #SCN ":" \
- " expected [%" @KWIML@_INT_PRI##PRI "]," \
- " got [%" @KWIML@_INT_PRI##PRI "]", x, y); \
- if(x == y) \
- { \
- printf(", PASSED\n"); \
- } \
- else \
- { \
- printf(", FAILED\n"); \
- result = 0; \
- } \
- }
-
-#define TEST_(FMT, T, U, STR) TEST2_(FMT, FMT, T, U, STR)
-#define TEST2_(PRI, SCN, T, U, STR) \
- TEST_PRI_(PRI, T, U, STR) \
- TEST_SCN2_(PRI, SCN, T, U, STR)
-
-/* Concatenate T and U now to avoid expanding them. */
-#define TEST(FMT, T, U, STR) \
- TEST_(FMT, @KWIML@_INT_##T, @KWIML@_INT_##U, STR)
-#define TEST2(PRI, SCN, T, U, STR) \
- TEST2_(PRI, SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR)
-#define TEST_C(C, V, PRI, T, U) \
- TEST_C_(@KWIML@_INT_##C, V, PRI, @KWIML@_INT_##T, @KWIML@_INT_##U)
-#define TEST_PRI(PRI, T, U, STR) \
- TEST_PRI_(PRI, @KWIML@_INT_##T, @KWIML@_INT_##U, STR)
-#define TEST_SCN(SCN, T, U, STR) \
- TEST_SCN_(SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR)
-#define TEST_SCN2(PRI, SCN, T, U, STR) \
- TEST_SCN2_(PRI, SCN, @KWIML@_INT_##T, @KWIML@_INT_##U, STR)
-
-static int test_INT_format(void)
-{
- int result = 1;
- char buf[256];
- TEST_PRI(i8, int8_t, uint8_t, "-85")
-#if defined(@KWIML@_INT_SCNi8)
- TEST_SCN(i8, int8_t, uint8_t, "-85")
-#endif
- TEST_PRI(d8, int8_t, uint8_t, "-85")
-#if defined(@KWIML@_INT_SCNd8)
- TEST_SCN(d8, int8_t, uint8_t, "-85")
-#endif
- TEST_PRI(o8, uint8_t, uint8_t, "253")
-#if defined(@KWIML@_INT_SCNo8)
- TEST_SCN(o8, uint8_t, uint8_t, "253")
-#endif
- TEST_PRI(u8, uint8_t, uint8_t, "171")
-#if defined(@KWIML@_INT_SCNu8)
- TEST_SCN(u8, uint8_t, uint8_t, "171")
-#endif
- TEST_PRI(x8, uint8_t, uint8_t, "ab")
- TEST_PRI(X8, uint8_t, uint8_t, "AB")
-#if defined(@KWIML@_INT_SCNx8)
- TEST_SCN(x8, uint8_t, uint8_t, "ab")
- TEST_SCN2(X8, x8, uint8_t, uint8_t, "AB")
-#endif
-
- TEST(i16, int16_t, uint16_t, "-21760")
- TEST(d16, int16_t, uint16_t, "-21760")
- TEST(o16, uint16_t, uint16_t, "125400")
- TEST(u16, uint16_t, uint16_t, "43776")
- TEST(x16, uint16_t, uint16_t, "ab00")
- TEST2(X16, x16, uint16_t, uint16_t, "AB00")
-
- TEST(i32, int32_t, uint32_t, "-1426063360")
- TEST(d32, int32_t, uint32_t, "-1426063360")
- TEST(o32, uint32_t, uint32_t, "25300000000")
- TEST(u32, uint32_t, uint32_t, "2868903936")
- TEST(x32, uint32_t, uint32_t, "ab000000")
- TEST2(X32, x32, uint32_t, uint32_t, "AB000000")
-
- TEST_PRI(i64, int64_t, uint64_t, "-6124895493223874560")
-#if defined(@KWIML@_INT_SCNi64)
- TEST_SCN(i64, int64_t, uint64_t, "-6124895493223874560")
-#endif
- TEST_PRI(d64, int64_t, uint64_t, "-6124895493223874560")
-#if defined(@KWIML@_INT_SCNd64)
- TEST_SCN(d64, int64_t, uint64_t, "-6124895493223874560")
-#endif
- TEST_PRI(o64, uint64_t, uint64_t, "1254000000000000000000")
-#if defined(@KWIML@_INT_SCNo64)
- TEST_SCN(o64, uint64_t, uint64_t, "1254000000000000000000")
-#endif
- TEST_PRI(u64, uint64_t, uint64_t, "12321848580485677056")
-#if defined(@KWIML@_INT_SCNu64)
- TEST_SCN(u64, uint64_t, uint64_t, "12321848580485677056")
-#endif
- TEST_PRI(x64, uint64_t, uint64_t, "ab00000000000000")
- TEST_PRI(X64, uint64_t, uint64_t, "AB00000000000000")
-#if defined(@KWIML@_INT_SCNx64)
- TEST_SCN(x64, uint64_t, uint64_t, "ab00000000000000")
- TEST_SCN2(X64, x64, uint64_t, uint64_t, "AB00000000000000")
-#endif
-
-#if !defined(@KWIML@_INT_NO_INTPTR_T)
-# if @KWIML@_ABI_SIZEOF_DATA_PTR == 4
- TEST(iPTR, intptr_t, uint32_t, "-1426063360")
- TEST(dPTR, intptr_t, uint32_t, "-1426063360")
-# else
- TEST(iPTR, intptr_t, uint64_t, "-6124895493223874560")
- TEST(dPTR, intptr_t, uint64_t, "-6124895493223874560")
-# endif
-#endif
-
-#if !defined(@KWIML@_INT_NO_UINTPTR_T)
-# if @KWIML@_ABI_SIZEOF_DATA_PTR == 4
- TEST(oPTR, uintptr_t, uintptr_t, "25300000000")
- TEST(uPTR, uintptr_t, uintptr_t, "2868903936")
- TEST(xPTR, uintptr_t, uintptr_t, "ab000000")
- TEST2(XPTR, xPTR, uintptr_t, uintptr_t, "AB000000")
-# else
- TEST(oPTR, uintptr_t, uintptr_t, "1254000000000000000000")
- TEST(uPTR, uintptr_t, uintptr_t, "12321848580485677056")
- TEST(xPTR, uintptr_t, uintptr_t, "ab00000000000000")
- TEST2(XPTR, xPTR, uintptr_t, uintptr_t, "AB00000000000000")
-# endif
-#endif
-
- TEST_C(INT8_C, -0x55, i8, int8_t, uint8_t)
- TEST_C(UINT8_C, 0xAB, u8, uint8_t, uint8_t)
- TEST_C(INT16_C, -0x5500, i16, int16_t, uint16_t)
- TEST_C(UINT16_C, 0xAB00, u16, uint16_t, uint16_t)
- TEST_C(INT32_C, -0x55000000, i32, int32_t, uint32_t)
- TEST_C(UINT32_C, 0xAB000000, u32, uint32_t, uint32_t)
- TEST_C(INT64_C, -0x5500000000000000, i64, int64_t, uint64_t)
- TEST_C(UINT64_C, 0xAB00000000000000, u64, uint64_t, uint64_t)
-
- return result;
-}
diff --git a/Utilities/KWIML/test/test_abi_C.c b/Utilities/KWIML/test/test_abi_C.c
new file mode 100644
index 000000000..18b639f4a
--- /dev/null
+++ b/Utilities/KWIML/test/test_abi_C.c
@@ -0,0 +1,19 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include "test.h"
+#include "../include/kwiml/abi.h"
+#include "test_abi_endian.h"
+#ifndef KWIML_ABI_VERSION
+# error "KWIML_ABI_VERSION not defined!"
+#endif
+int test_abi_C(void)
+{
+ if(!test_abi_endian())
+ {
+ return 0;
+ }
+ return 1;
+}
diff --git a/Utilities/KWIML/test/test_abi_CXX.cxx b/Utilities/KWIML/test/test_abi_CXX.cxx
new file mode 100644
index 000000000..e8feb44d2
--- /dev/null
+++ b/Utilities/KWIML/test/test_abi_CXX.cxx
@@ -0,0 +1,19 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include "test.h"
+#include "../include/kwiml/abi.h"
+#include "test_abi_endian.h"
+#ifndef KWIML_ABI_VERSION
+# error "KWIML_ABI_VERSION not defined!"
+#endif
+extern "C" int test_abi_CXX(void)
+{
+ if(!test_abi_endian())
+ {
+ return 0;
+ }
+ return 1;
+}
diff --git a/Utilities/KWIML/test/test_abi_endian.h b/Utilities/KWIML/test/test_abi_endian.h
new file mode 100644
index 000000000..334b018a1
--- /dev/null
+++ b/Utilities/KWIML/test/test_abi_endian.h
@@ -0,0 +1,41 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include <stdio.h>
+
+#ifdef __cplusplus
+# define LANG "C++ "
+#else
+# define LANG "C "
+#endif
+
+static int test_abi_endian(void)
+{
+ int result = 1;
+ {
+#if defined(KWIML_ABI_ENDIAN_ID)
+ int expect;
+ union { short s; unsigned char c[sizeof(short)]; } x;
+ x.s = 1;
+ expect = (x.c[0] == 1 ?
+ KWIML_ABI_ENDIAN_ID_LITTLE : KWIML_ABI_ENDIAN_ID_BIG);
+ printf(LANG "KWIML_ABI_ENDIAN_ID: expected [%d], got [%d]",
+ expect, KWIML_ABI_ENDIAN_ID);
+ if(KWIML_ABI_ENDIAN_ID == expect)
+ {
+ printf(", PASSED\n");
+ }
+ else
+ {
+ printf(", FAILED\n");
+ result = 0;
+ }
+#else
+ printf(LANG "KWIML_ABI_ENDIAN_ID: unknown, FAILED\n");
+ result = 0;
+#endif
+ }
+ return result;
+}
diff --git a/Utilities/KWIML/test/test_include_C.c b/Utilities/KWIML/test/test_include_C.c
index fb3e4cf7f..518544d25 100644
--- a/Utilities/KWIML/test/test_include_C.c
+++ b/Utilities/KWIML/test/test_include_C.c
@@ -1,20 +1,14 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
#include <stdio.h>
/* Test KWIML header inclusion after above system headers. */
#include "test.h"
-#include KWIML_HEADER(ABI.h)
-#include KWIML_HEADER(INT.h)
+#include "../include/kwiml/abi.h"
+#include "../include/kwiml/int.h"
int test_include_C(void)
{
diff --git a/Utilities/KWIML/test/test_include_CXX.cxx b/Utilities/KWIML/test/test_include_CXX.cxx
index 111311a84..82aa54616 100644
--- a/Utilities/KWIML/test/test_include_CXX.cxx
+++ b/Utilities/KWIML/test/test_include_CXX.cxx
@@ -1,14 +1,8 @@
-/*============================================================================
- Kitware Information Macro Library
- Copyright 2010-2011 Kitware, Inc.
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
#include <string>
#if defined(_MSC_VER) && defined(NDEBUG)
@@ -19,8 +13,8 @@ std::string test_include_CXX_use_stl_string;
/* Test KWIML header inclusion after above system headers. */
#include "test.h"
-#include KWIML_HEADER(ABI.h)
-#include KWIML_HEADER(INT.h)
+#include "../include/kwiml/abi.h"
+#include "../include/kwiml/int.h"
extern "C" int test_include_CXX(void)
{
diff --git a/Utilities/KWIML/test/test_int_C.c b/Utilities/KWIML/test/test_int_C.c
new file mode 100644
index 000000000..fe8ee8e3c
--- /dev/null
+++ b/Utilities/KWIML/test/test_int_C.c
@@ -0,0 +1,19 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include "test.h"
+#include "../include/kwiml/int.h"
+#include "test_int_format.h"
+#ifndef KWIML_INT_VERSION
+# error "KWIML_INT_VERSION not defined!"
+#endif
+int test_int_C(void)
+{
+ if(!test_int_format())
+ {
+ return 0;
+ }
+ return 1;
+}
diff --git a/Utilities/KWIML/test/test_int_CXX.cxx b/Utilities/KWIML/test/test_int_CXX.cxx
new file mode 100644
index 000000000..ffa4c9b08
--- /dev/null
+++ b/Utilities/KWIML/test/test_int_CXX.cxx
@@ -0,0 +1,19 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include "test.h"
+#include "../include/kwiml/int.h"
+#include "test_int_format.h"
+#ifndef KWIML_INT_VERSION
+# error "KWIML_INT_VERSION not defined!"
+#endif
+extern "C" int test_int_CXX(void)
+{
+ if(!test_int_format())
+ {
+ return 0;
+ }
+ return 1;
+}
diff --git a/Utilities/KWIML/test/test_int_format.h b/Utilities/KWIML/test/test_int_format.h
new file mode 100644
index 000000000..24dcdfba6
--- /dev/null
+++ b/Utilities/KWIML/test/test_int_format.h
@@ -0,0 +1,203 @@
+/*
+ Copyright Kitware, Inc.
+ Distributed under the OSI-approved BSD 3-Clause License.
+ See accompanying file Copyright.txt for details.
+*/
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_MSC_VER)
+# pragma warning (push)
+# pragma warning (disable:4310) /* cast truncates constant value */
+#endif
+
+#ifdef __cplusplus
+# define LANG "C++ "
+#else
+# define LANG "C "
+#endif
+
+#define VALUE(T, U) (T)((U)0xab << ((sizeof(T)-1)<<3))
+
+#define TEST_C_(C, V, PRI, T, U) \
+ { \
+ T const x = VALUE(T, U); \
+ T y = C(V); \
+ printf(LANG #C ":" \
+ " expression [%" KWIML_INT_PRI##PRI "]," \
+ " literal [%" KWIML_INT_PRI##PRI "]", x, y); \
+ if(x == y) \
+ { \
+ printf(", PASSED\n"); \
+ } \
+ else \
+ { \
+ printf(", FAILED\n"); \
+ result = 0; \
+ } \
+ }
+
+#define TEST_PRI_(PRI, T, U, STR) \
+ { \
+ T const x = VALUE(T, U); \
+ char const* str = STR; \
+ sprintf(buf, "%" KWIML_INT_PRI##PRI, x); \
+ printf(LANG "KWIML_INT_PRI" #PRI ":" \
+ " expected [%s], got [%s]", str, buf); \
+ if(strcmp(str, buf) == 0) \
+ { \
+ printf(", PASSED\n"); \
+ } \
+ else \
+ { \
+ printf(", FAILED\n"); \
+ result = 0; \
+ } \
+ }
+
+#define TEST_SCN_(SCN, T, U, STR) TEST_SCN2_(SCN, SCN, T, U, STR)
+#define TEST_SCN2_(PRI, SCN, T, U, STR) \
+ { \
+ T const x = VALUE(T, U); \
+ T y; \
+ char const* str = STR; \
+ if(sscanf(str, "%" KWIML_INT_SCN##SCN, &y) != 1) \
+ { \
+ y = 0; \
+ } \
+ printf(LANG "KWIML_INT_SCN" #SCN ":" \
+ " expected [%" KWIML_INT_PRI##PRI "]," \
+ " got [%" KWIML_INT_PRI##PRI "]", x, y); \
+ if(x == y) \
+ { \
+ printf(", PASSED\n"); \
+ } \
+ else \
+ { \
+ printf(", FAILED\n"); \
+ result = 0; \
+ } \
+ }
+
+#define TEST_(FMT, T, U, STR) TEST2_(FMT, FMT, T, U, STR)
+#define TEST2_(PRI, SCN, T, U, STR) \
+ TEST_PRI_(PRI, T, U, STR) \
+ TEST_SCN2_(PRI, SCN, T, U, STR)
+
+/* Concatenate T and U now to avoid expanding them. */
+#define TEST(FMT, T, U, STR) \
+ TEST_(FMT, KWIML_INT_##T, KWIML_INT_##U, STR)
+#define TEST2(PRI, SCN, T, U, STR) \
+ TEST2_(PRI, SCN, KWIML_INT_##T, KWIML_INT_##U, STR)
+#define TEST_C(C, V, PRI, T, U) \
+ TEST_C_(KWIML_INT_##C, V, PRI, KWIML_INT_##T, KWIML_INT_##U)
+#define TEST_PRI(PRI, T, U, STR) \
+ TEST_PRI_(PRI, KWIML_INT_##T, KWIML_INT_##U, STR)
+#define TEST_SCN(SCN, T, U, STR) \
+ TEST_SCN_(SCN, KWIML_INT_##T, KWIML_INT_##U, STR)
+#define TEST_SCN2(PRI, SCN, T, U, STR) \
+ TEST_SCN2_(PRI, SCN, KWIML_INT_##T, KWIML_INT_##U, STR)
+
+static int test_int_format(void)
+{
+ int result = 1;
+ char buf[256];
+ TEST_PRI(i8, int8_t, uint8_t, "-85")
+#if defined(KWIML_INT_SCNi8)
+ TEST_SCN(i8, int8_t, uint8_t, "-85")
+#endif
+ TEST_PRI(d8, int8_t, uint8_t, "-85")
+#if defined(KWIML_INT_SCNd8)
+ TEST_SCN(d8, int8_t, uint8_t, "-85")
+#endif
+ TEST_PRI(o8, uint8_t, uint8_t, "253")
+#if defined(KWIML_INT_SCNo8)
+ TEST_SCN(o8, uint8_t, uint8_t, "253")
+#endif
+ TEST_PRI(u8, uint8_t, uint8_t, "171")
+#if defined(KWIML_INT_SCNu8)
+ TEST_SCN(u8, uint8_t, uint8_t, "171")
+#endif
+ TEST_PRI(x8, uint8_t, uint8_t, "ab")
+ TEST_PRI(X8, uint8_t, uint8_t, "AB")
+#if defined(KWIML_INT_SCNx8)
+ TEST_SCN(x8, uint8_t, uint8_t, "ab")
+ TEST_SCN2(X8, x8, uint8_t, uint8_t, "AB")
+#endif
+
+ TEST(i16, int16_t, uint16_t, "-21760")
+ TEST(d16, int16_t, uint16_t, "-21760")
+ TEST(o16, uint16_t, uint16_t, "125400")
+ TEST(u16, uint16_t, uint16_t, "43776")
+ TEST(x16, uint16_t, uint16_t, "ab00")
+ TEST2(X16, x16, uint16_t, uint16_t, "AB00")
+
+ TEST(i32, int32_t, uint32_t, "-1426063360")
+ TEST(d32, int32_t, uint32_t, "-1426063360")
+ TEST(o32, uint32_t, uint32_t, "25300000000")
+ TEST(u32, uint32_t, uint32_t, "2868903936")
+ TEST(x32, uint32_t, uint32_t, "ab000000")
+ TEST2(X32, x32, uint32_t, uint32_t, "AB000000")
+
+ TEST_PRI(i64, int64_t, uint64_t, "-6124895493223874560")
+#if defined(KWIML_INT_SCNi64)
+ TEST_SCN(i64, int64_t, uint64_t, "-6124895493223874560")
+#endif
+ TEST_PRI(d64, int64_t, uint64_t, "-6124895493223874560")
+#if defined(KWIML_INT_SCNd64)
+ TEST_SCN(d64, int64_t, uint64_t, "-6124895493223874560")
+#endif
+ TEST_PRI(o64, uint64_t, uint64_t, "1254000000000000000000")
+#if defined(KWIML_INT_SCNo64)
+ TEST_SCN(o64, uint64_t, uint64_t, "1254000000000000000000")
+#endif
+ TEST_PRI(u64, uint64_t, uint64_t, "12321848580485677056")
+#if defined(KWIML_INT_SCNu64)
+ TEST_SCN(u64, uint64_t, uint64_t, "12321848580485677056")
+#endif
+ TEST_PRI(x64, uint64_t, uint64_t, "ab00000000000000")
+ TEST_PRI(X64, uint64_t, uint64_t, "AB00000000000000")
+#if defined(KWIML_INT_SCNx64)
+ TEST_SCN(x64, uint64_t, uint64_t, "ab00000000000000")
+ TEST_SCN2(X64, x64, uint64_t, uint64_t, "AB00000000000000")
+#endif
+
+#if !defined(KWIML_INT_NO_INTPTR_T)
+# if KWIML_ABI_SIZEOF_DATA_PTR == 4
+ TEST(iPTR, intptr_t, uint32_t, "-1426063360")
+ TEST(dPTR, intptr_t, uint32_t, "-1426063360")
+# else
+ TEST(iPTR, intptr_t, uint64_t, "-6124895493223874560")
+ TEST(dPTR, intptr_t, uint64_t, "-6124895493223874560")
+# endif
+#endif
+
+#if !defined(KWIML_INT_NO_UINTPTR_T)
+# if KWIML_ABI_SIZEOF_DATA_PTR == 4
+ TEST(oPTR, uintptr_t, uintptr_t, "25300000000")
+ TEST(uPTR, uintptr_t, uintptr_t, "2868903936")
+ TEST(xPTR, uintptr_t, uintptr_t, "ab000000")
+ TEST2(XPTR, xPTR, uintptr_t, uintptr_t, "AB000000")
+# else
+ TEST(oPTR, uintptr_t, uintptr_t, "1254000000000000000000")
+ TEST(uPTR, uintptr_t, uintptr_t, "12321848580485677056")
+ TEST(xPTR, uintptr_t, uintptr_t, "ab00000000000000")
+ TEST2(XPTR, xPTR, uintptr_t, uintptr_t, "AB00000000000000")
+# endif
+#endif
+
+ TEST_C(INT8_C, -0x55, i8, int8_t, uint8_t)
+ TEST_C(UINT8_C, 0xAB, u8, uint8_t, uint8_t)
+ TEST_C(INT16_C, -0x5500, i16, int16_t, uint16_t)
+ TEST_C(UINT16_C, 0xAB00, u16, uint16_t, uint16_t)
+ TEST_C(INT32_C, -0x55000000, i32, int32_t, uint32_t)
+ TEST_C(UINT32_C, 0xAB000000, u32, uint32_t, uint32_t)
+ TEST_C(INT64_C, -0x5500000000000000, i64, int64_t, uint64_t)
+ TEST_C(UINT64_C, 0xAB00000000000000, u64, uint64_t, uint64_t)
+
+ return result;
+}
+
+#if defined(_MSC_VER)
+# pragma warning (pop)
+#endif
diff --git a/Utilities/KWStyle/CMake.kws.xml.in b/Utilities/KWStyle/CMake.kws.xml.in
deleted file mode 100644
index c2b442940..000000000
--- a/Utilities/KWStyle/CMake.kws.xml.in
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<Description>
-<LineLength>79</LineLength>
-<!--
-<Header>"@CMake_SOURCE_DIR@/Utilities/KWStyle/Headers",false,true</Header>
-<Functions>
-<regex>[A-Z]</regex>
-<length>100</length>
-</Functions>
--->
-</Description>
diff --git a/Utilities/KWStyle/CMakeFiles.txt.in b/Utilities/KWStyle/CMakeFiles.txt.in
deleted file mode 100644
index a95aac655..000000000
--- a/Utilities/KWStyle/CMakeFiles.txt.in
+++ /dev/null
@@ -1,15 +0,0 @@
-"@CMake_SOURCE_DIR@/Source/*.txx"
-"@CMake_SOURCE_DIR@/Source/*.cxx"
-"@CMake_SOURCE_DIR@/Source/*.h*"
-"@CMake_SOURCE_DIR@/Source/CPack/*.txx"
-"@CMake_SOURCE_DIR@/Source/CPack/*.cxx"
-"@CMake_SOURCE_DIR@/Source/CPack/*.h*"
-"@CMake_SOURCE_DIR@/Source/CTest/*.txx"
-"@CMake_SOURCE_DIR@/Source/CTest/*.cxx"
-"@CMake_SOURCE_DIR@/Source/CTest/*.h*"
-"@CMake_SOURCE_DIR@/Source/CurseDialog/*.h*"
-"@CMake_SOURCE_DIR@/Source/CurseDialog/*.cxx"
-"@CMake_SOURCE_DIR@/Source/CurseDialog/*.txx"
--f (Lexer\.h)
--f (Lexer\.cxx)
--f (Parser\.cxx)
diff --git a/Utilities/KWStyle/CMakeLists.txt b/Utilities/KWStyle/CMakeLists.txt
deleted file mode 100644
index b2c798c0f..000000000
--- a/Utilities/KWStyle/CMakeLists.txt
+++ /dev/null
@@ -1,78 +0,0 @@
-#=============================================================================
-# CMake - Cross Platform Makefile Generator
-# Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-#
-# Distributed under the OSI-approved BSD License (the "License");
-# see accompanying file Copyright.txt for details.
-#
-# This software is distributed WITHOUT ANY WARRANTY; without even the
-# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-# See the License for more information.
-#=============================================================================
-
-#-----------------------------------------------------------------------------
-# CMake uses KWStyle for checking the coding style
-
-# Search for a built-from-source KWStyle under Dashboards/Support on a typical
-# dashboard machines:
-#
-set(home "$ENV{HOME}")
-if(NOT home)
- string(REPLACE "\\" "/" home "$ENV{USERPROFILE}")
-endif()
-
-find_program(KWSTYLE_EXECUTABLE
- NAMES KWStyle
- PATHS
- "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Kitware Inc.\\KWStyle 1.0.0]/bin"
- "${home}/Dashboards/Support/KWStyle/bin"
- )
-mark_as_advanced(KWSTYLE_EXECUTABLE)
-
-set(CMAKE_USE_KWSTYLE_DEFAULT OFF)
-if(KWSTYLE_EXECUTABLE)
- set(CMAKE_USE_KWSTYLE_DEFAULT ON)
-endif()
-
-option(CMAKE_USE_KWSTYLE
- "Add StyleCheck target and KWStyle test: run KWStyle to check for coding standard violations."
- ${CMAKE_USE_KWSTYLE_DEFAULT})
-mark_as_advanced(CMAKE_USE_KWSTYLE)
-
-if(CMAKE_USE_KWSTYLE)
- option(KWSTYLE_USE_VIM_FORMAT "Set KWStyle to generate errors with a VIM-compatible format." OFF)
- option(KWSTYLE_USE_MSVC_FORMAT "Set KWStyle to generate errors with a VisualStudio-compatible format." OFF)
- mark_as_advanced(KWSTYLE_USE_VIM_FORMAT)
- mark_as_advanced(KWSTYLE_USE_MSVC_FORMAT)
-
- if(KWSTYLE_USE_VIM_FORMAT)
- set(KWSTYLE_ARGUMENTS -vim ${KWSTYLE_ARGUMENTS})
- endif()
-
- if(KWSTYLE_USE_MSVC_FORMAT)
- set(KWSTYLE_ARGUMENTS -msvc ${KWSTYLE_ARGUMENTS})
- endif()
-
- configure_file(${CMake_SOURCE_DIR}/Utilities/KWStyle/CMake.kws.xml.in
- ${CMake_BINARY_DIR}/CMake.kws.xml)
- configure_file(${CMake_SOURCE_DIR}/Utilities/KWStyle/CMakeMoreChecks.kws.xml.in
- ${CMake_BINARY_DIR}/CMakeMoreChecks.kws.xml)
-
- configure_file(${CMake_SOURCE_DIR}/Utilities/KWStyle/CMakeFiles.txt.in
- ${CMake_BINARY_DIR}/CMakeKWSFiles.txt)
-
- add_custom_command(
- OUTPUT ${CMake_BINARY_DIR}/KWStyleReport.txt
- COMMAND ${KWSTYLE_EXECUTABLE}
- ARGS -xml ${CMake_BINARY_DIR}/CMake.kws.xml -o ${CMake_SOURCE_DIR}/Utilities/KWStyle/CMakeOverwrite.txt -v ${KWSTYLE_ARGUMENTS} -D ${CMake_BINARY_DIR}/CMakeKWSFiles.txt
- COMMENT "Coding Style Checker"
- )
-
- add_custom_target(MoreStyleChecks
- COMMAND ${KWSTYLE_EXECUTABLE}
- -xml ${CMake_BINARY_DIR}/CMakeMoreChecks.kws.xml -html ${CMake_BINARY_DIR}/html -o ${CMake_SOURCE_DIR}/Utilities/KWStyle/CMakeOverwrite.txt -v ${KWSTYLE_ARGUMENTS} -D ${CMake_BINARY_DIR}/CMakeKWSFiles.txt
- COMMENT "Coding Style Checker, more checks enabled"
- )
-
- add_custom_target(StyleCheck DEPENDS ${CMake_BINARY_DIR}/KWStyleReport.txt)
-endif()
diff --git a/Utilities/KWStyle/CMakeMoreChecks.kws.xml.in b/Utilities/KWStyle/CMakeMoreChecks.kws.xml.in
deleted file mode 100644
index c48e92f77..000000000
--- a/Utilities/KWStyle/CMakeMoreChecks.kws.xml.in
+++ /dev/null
@@ -1,30 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1"?>
-<Description>
- <ErrorThreshold>10</ErrorThreshold>
- <LineLength>79</LineLength>
- <Header>"@CMake_SOURCE_DIR@/Utilities/KWStyle/Headers",false,true</Header>
- <Functions>
- <regex>^(cm)?[A-Z]</regex>
- <length>200</length>
- </Functions>
- <InternalVariables>
- <regex>^[A-Z]</regex>
- <alignment>0</alignment>
- </InternalVariables>
- <SemicolonSpace>0</SemicolonSpace>
- <DeclarationOrder>
- <public>0</public>
- <protected>1</protected>
- <private>2</private>
- </DeclarationOrder>
- <Tabs>1</Tabs>
- <EmptyLines>4</EmptyLines>
- <StatementPerLine>
- <maxNumber>1</maxNumber>
- <checkInline>0</checkInline>
- </StatementPerLine>
- <VariablePerLine>
- <maxNumber>1</maxNumber>
- </VariablePerLine>
- <BadCharacters>true</BadCharacters>
-</Description>
diff --git a/Utilities/KWStyle/CMakeOverwrite.txt b/Utilities/KWStyle/CMakeOverwrite.txt
deleted file mode 100644
index e69de29bb..000000000
--- a/Utilities/KWStyle/CMakeOverwrite.txt
+++ /dev/null
diff --git a/Utilities/KWStyle/Headers/CMakeHeader.h b/Utilities/KWStyle/Headers/CMakeHeader.h
deleted file mode 100644
index 3d7702e1a..000000000
--- a/Utilities/KWStyle/Headers/CMakeHeader.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
diff --git a/Utilities/Release/Cygwin/CMakeLists.txt b/Utilities/Release/Cygwin/CMakeLists.txt
deleted file mode 100644
index c59a6fa94..000000000
--- a/Utilities/Release/Cygwin/CMakeLists.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-file(GLOB INSTALLED_CURSES /usr/bin/cygncurses-*.dll)
-set(MAX 0)
-foreach(f ${INSTALLED_CURSES})
- if(NOT "${f}" MATCHES "\\+")
- string(REGEX REPLACE ".*-([0-9]*).dll" "\\1" NUMBER "${f}")
- if(NUMBER GREATER MAX)
- set(MAX ${NUMBER})
- endif()
- endif()
-endforeach()
-string(REGEX REPLACE "/usr/bin/" "\\1" NUMBER "${f}")
-set(CMAKE_NCURSES_VERSION "libncurses${MAX}")
-message(STATUS "Using curses version: libncurses${MAX}")
-configure_file("${CMake_SOURCE_DIR}/Utilities/Release/Cygwin/cygwin-setup.hint.in"
- "${CMake_BINARY_DIR}/setup.hint")
-configure_file("${CMake_SOURCE_DIR}/Utilities/Release/Cygwin/README.cygwin.in"
- "${CMake_BINARY_DIR}/Docs/@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.README")
-install_files(/share/doc/Cygwin FILES
- ${CMake_BINARY_DIR}/Docs/@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.README
- )
-configure_file("${CMake_SOURCE_DIR}/Utilities/Release/Cygwin/cygwin-package.sh.in"
- ${CPACK_CYGWIN_BUILD_SCRIPT})
-configure_file("${CMake_SOURCE_DIR}/Utilities/Release/Cygwin/cygwin-patch.diff.in"
- ${CPACK_CYGWIN_PATCH_FILE})
-
diff --git a/Utilities/Release/Cygwin/README.cygwin.in b/Utilities/Release/Cygwin/README.cygwin.in
deleted file mode 100644
index 6c42a4c20..000000000
--- a/Utilities/Release/Cygwin/README.cygwin.in
+++ /dev/null
@@ -1,42 +0,0 @@
-cmake
---------------------------------------
-Runtime requirements:
- cygwin-1.5.21(0.156/4/2) or newer
-
-Build requirements
- cygwin-1.5.21(0.156/4/2) or newer
- make
-
-Canonical homepage:
- http://www.cmake.org
-
-Canonical download:
- ftp://www.cmake.org/pub/cmake/
-
-------------------------------------
-
-Build instructions:
- unpack @CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@-src.tar.bz2
- if you use setup to install this src package, it will be
- unpacked under /usr/src automatically
- cd /usr/src
- ./@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.sh all
-
-This will create:
- /usr/src/@CPACK_PACKAGE_FILE_NAME@.tar.bz2
- /usr/src/@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@-src.tar.bz2
-
--------------------------------------------
-
-Port Notes:
-
-The directory /usr/share/@CPACK_PACKAGE_FILE_NAME@/include is purposely not
-located at /usr/include/@CPACK_PACKAGE_FILE_NAME@ or /usr/include/cmake. The
-files it contains are not meant for inclusion in any C or C++ program.
-They are used for compiling dynamically loadable CMake commands inside
-projects that provide them. CMake will automatically provide the
-proper include path when the files are needed.
-
-------------------
-
-Cygwin port maintained by: CMake Developers <cmake@www.cmake.org>
diff --git a/Utilities/Release/Cygwin/cygwin-package.sh.in b/Utilities/Release/Cygwin/cygwin-package.sh.in
deleted file mode 100755
index dff27f14d..000000000
--- a/Utilities/Release/Cygwin/cygwin-package.sh.in
+++ /dev/null
@@ -1,90 +0,0 @@
-TOP_DIR=`cd \`echo "$0" | sed -n '/\//{s/\/[^\/]*$//;p;}'\`;pwd`
-
-# create build directory
-mkdirs()
-{
- (
- mkdir -p "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build"
- )
-}
-
-# cd into
-# untar source tree and apply patch
-prep()
-{
- (
- cd "$TOP_DIR" &&
- tar xvfj @CPACK_PACKAGE_FILE_NAME@.tar.bz2
- patch -p0 < "@CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.patch" &&
- mkdirs
- )
-}
-
-conf()
-{
- (
- cd "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build" &&
- ../bootstrap --parallel=2
- )
-}
-
-build()
-{
- (
- cd "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build" &&
- make -j2 &&
- make test
- )
-}
-
-clean()
-{
- (
- cd "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build" &&
- make clean
- )
-}
-
-pkg()
-{
- (
- cd "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build" &&
- ./bin/cpack &&
- mv @CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@.tar.bz2 "$TOP_DIR"
- )
-}
-
-spkg()
-{
- (
- cd "$TOP_DIR/@CPACK_PACKAGE_FILE_NAME@/.build" &&
- ./bin/cpack --config CPackSourceConfig.cmake &&
- mv @CPACK_PACKAGE_FILE_NAME@-@CPACK_CYGWIN_PATCH_NUMBER@-src.tar.bz2 "$TOP_DIR"
- )
-}
-
-finish()
-{
- (
- rm -rf "@CPACK_PACKAGE_FILE_NAME@"
- )
-}
-
-case $1 in
- prep) prep ; STATUS=$? ;;
- mkdirs) mkdirs ; STATUS=$? ;;
- conf) conf ; STATUS=$? ;;
- build) build ; STATUS=$? ;;
- clean) clean ; STATUS=$? ;;
- package) pkg ; STATUS=$? ;;
- pkg) pkg ; STATUS=$? ;;
- src-package) spkg ; STATUS=$? ;;
- spkg) spkg ; STATUS=$? ;;
- finish) finish ; STATUS=$? ;;
- all) (
- prep && conf && build && pkg && spkg && finish ;
- STATUS=$?
- ) ;;
- *) echo "Error: bad argument (all or one of these: prep mkdirs conf build clean package pkg src-package spkg finish)" ; exit 1 ;;
-esac
-exit ${STATUS}
diff --git a/Utilities/Release/Cygwin/cygwin-patch.diff.in b/Utilities/Release/Cygwin/cygwin-patch.diff.in
deleted file mode 100644
index e69de29bb..000000000
--- a/Utilities/Release/Cygwin/cygwin-patch.diff.in
+++ /dev/null
diff --git a/Utilities/Release/Cygwin/cygwin-setup.hint.in b/Utilities/Release/Cygwin/cygwin-setup.hint.in
deleted file mode 100644
index a2532fc68..000000000
--- a/Utilities/Release/Cygwin/cygwin-setup.hint.in
+++ /dev/null
@@ -1,5 +0,0 @@
-# CMake setup.hint file for cygwin setup.exe program
-category: Devel
-requires: libgcc1 libidn11 @CMAKE_NCURSES_VERSION@ libstdc++6
-sdesc: "A cross platform build manager"
-ldesc: "CMake is a cross platform build manager. It allows you to specify build parameters for C and C++ programs in a cross platform manner. For cygwin Makefiles will be generated. CMake is also capable of generating microsoft project files, nmake, and borland makefiles. CMake can also perform system inspection operations like finding installed libraries and header files."
diff --git a/Utilities/Release/README b/Utilities/Release/README
index 12eafe18f..11de1c325 100644
--- a/Utilities/Release/README
+++ b/Utilities/Release/README
@@ -1,7 +1,7 @@
To create a cmake release, make sure the "release" tag is pointing to the
expected git commit:
-http://cmake.org/gitweb?p=cmake.git;a=shortlog;h=refs/heads/release
+https://cmake.org/gitweb?p=cmake.git;a=shortlog;h=refs/heads/release
Then as kitware@hythloth, using an up-to-date CMake:
@@ -15,7 +15,4 @@ Then as kitware@hythloth, using an up-to-date CMake:
create-cmake-release.cmake: script to run to create release sh scripts
Add or remove machines in create-cmake-release.cmake.
-Cygwin -> directory that contains cpack cygwin package files used in
- CMakeCPack.cmake
-
machine_release.cmake : config files for each machine
diff --git a/Utilities/Release/WiX/CMakeLists.txt b/Utilities/Release/WiX/CMakeLists.txt
new file mode 100644
index 000000000..cc0dbe1a6
--- /dev/null
+++ b/Utilities/Release/WiX/CMakeLists.txt
@@ -0,0 +1,12 @@
+add_subdirectory(CustomAction)
+
+if(CMAKE_CONFIGURATION_TYPES)
+ set(CUSTOM_ACTION_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/custom_action_dll-$<CONFIG>.wxs")
+else()
+ set(CUSTOM_ACTION_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/custom_action_dll.wxs")
+endif()
+
+file(GENERATE
+ OUTPUT "${CUSTOM_ACTION_OUTPUT}"
+ INPUT "${CMAKE_CURRENT_SOURCE_DIR}/custom_action_dll.wxs.in"
+ )
diff --git a/Utilities/Release/WiX/CustomAction/CMakeLists.txt b/Utilities/Release/WiX/CustomAction/CMakeLists.txt
new file mode 100644
index 000000000..7efd01e00
--- /dev/null
+++ b/Utilities/Release/WiX/CustomAction/CMakeLists.txt
@@ -0,0 +1,13 @@
+foreach(CONFIG DEBUG MINSIZEREL RELEASE RELWITHDEBINFO)
+ string(REPLACE "/MD" "/MT"
+ "CMAKE_CXX_FLAGS_${CONFIG}"
+ "${CMAKE_CXX_FLAGS_${CONFIG}}"
+ )
+endforeach()
+
+add_library(CMakeWiXCustomActions MODULE
+ detect_nsis_overwrite.cpp
+ exports.def
+)
+
+target_link_libraries(CMakeWiXCustomActions PRIVATE msi)
diff --git a/Utilities/Release/WiX/CustomAction/detect_nsis_overwrite.cpp b/Utilities/Release/WiX/CustomAction/detect_nsis_overwrite.cpp
new file mode 100644
index 000000000..4b178759d
--- /dev/null
+++ b/Utilities/Release/WiX/CustomAction/detect_nsis_overwrite.cpp
@@ -0,0 +1,43 @@
+#include <windows.h>
+
+#include <msi.h>
+#include <msiquery.h>
+
+#include <string>
+#include <vector>
+
+std::wstring get_property(MSIHANDLE msi_handle, std::wstring const& name)
+{
+ DWORD size = 0;
+
+ UINT status = MsiGetPropertyW(msi_handle, name.c_str(), L"", &size);
+
+ if (status == ERROR_MORE_DATA) {
+ std::vector<wchar_t> buffer(size + 1);
+ MsiGetPropertyW(msi_handle, name.c_str(), &buffer[0], &size);
+ return std::wstring(&buffer[0]);
+ } else {
+ return std::wstring();
+ }
+}
+
+void set_property(MSIHANDLE msi_handle, std::wstring const& name,
+ std::wstring const& value)
+{
+ MsiSetPropertyW(msi_handle, name.c_str(), value.c_str());
+}
+
+extern "C" UINT __stdcall DetectNsisOverwrite(MSIHANDLE msi_handle)
+{
+ std::wstring install_root = get_property(msi_handle, L"INSTALL_ROOT");
+
+ std::wstring uninstall_exe = install_root + L"\\uninstall.exe";
+
+ bool uninstall_exe_exists =
+ GetFileAttributesW(uninstall_exe.c_str()) != INVALID_FILE_ATTRIBUTES;
+
+ set_property(msi_handle, L"CMAKE_NSIS_OVERWRITE_DETECTED",
+ uninstall_exe_exists ? L"1" : L"0");
+
+ return ERROR_SUCCESS;
+}
diff --git a/Utilities/Release/WiX/CustomAction/exports.def b/Utilities/Release/WiX/CustomAction/exports.def
new file mode 100644
index 000000000..0e448b20e
--- /dev/null
+++ b/Utilities/Release/WiX/CustomAction/exports.def
@@ -0,0 +1,2 @@
+EXPORTS
+ DetectNsisOverwrite=DetectNsisOverwrite
diff --git a/Utilities/Release/WiX/WIX.template.in b/Utilities/Release/WiX/WIX.template.in
new file mode 100644
index 000000000..fe176ca90
--- /dev/null
+++ b/Utilities/Release/WiX/WIX.template.in
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<?include "cpack_variables.wxi"?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
+ RequiredVersion="3.6.3303.0">
+
+ <Product Id="$(var.CPACK_WIX_PRODUCT_GUID)"
+ Name="$(var.CPACK_PACKAGE_NAME)"
+ Language="1033"
+ Version="$(var.CPACK_PACKAGE_VERSION)"
+ Manufacturer="$(var.CPACK_PACKAGE_VENDOR)"
+ UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)">
+
+ <Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine"/>
+
+ <Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
+
+ <MajorUpgrade
+ Schedule="afterInstallInitialize"
+ AllowDowngrades="yes"/>
+
+ <WixVariable Id="WixUILicenseRtf" Value="$(var.CPACK_WIX_LICENSE_RTF)"/>
+ <Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/>
+
+ <?ifdef CPACK_WIX_PRODUCT_ICON?>
+ <Property Id="ARPPRODUCTICON">ProductIcon.ico</Property>
+ <Icon Id="ProductIcon.ico" SourceFile="$(var.CPACK_WIX_PRODUCT_ICON)"/>
+ <?endif?>
+
+ <?ifdef CPACK_WIX_UI_BANNER?>
+ <WixVariable Id="WixUIBannerBmp" Value="$(var.CPACK_WIX_UI_BANNER)"/>
+ <?endif?>
+
+ <?ifdef CPACK_WIX_UI_DIALOG?>
+ <WixVariable Id="WixUIDialogBmp" Value="$(var.CPACK_WIX_UI_DIALOG)"/>
+ <?endif?>
+
+ <DirectoryRef Id="TARGETDIR">
+ <Component Id="CMakeRegistry">
+ <RegistryKey Root="HKLM" Key="Software\Kitware\CMake">
+ <RegistryValue Type="string" Name="InstallDir"
+ Value="[INSTALL_ROOT]" KeyPath="yes"/>
+ </RegistryKey>
+ </Component>
+ </DirectoryRef>
+
+ <FeatureRef Id="ProductFeature">
+ <ComponentRef Id="CMakeRegistry"/>
+ </FeatureRef>
+
+ <UIRef Id="$(var.CPACK_WIX_UI_REF)" />
+
+ <?include "properties.wxi"?>
+ <?include "product_fragment.wxi"?>
+ </Product>
+</Wix>
diff --git a/Utilities/Release/WiX/cmake_extra_dialog.wxs b/Utilities/Release/WiX/cmake_extra_dialog.wxs
new file mode 100644
index 000000000..0ee3d99e7
--- /dev/null
+++ b/Utilities/Release/WiX/cmake_extra_dialog.wxs
@@ -0,0 +1,36 @@
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI>
+ <Property Id="ADD_CMAKE_TO_PATH" Value="None"/>
+ <Dialog Id="CMakeExtraDialog" Width="370" Height="270" Title="Install Options">
+
+ <Control Id="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Default="yes" Text="!(loc.WixUINext)"/>
+ <Control Id="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Text="!(loc.WixUIBack)"/>
+
+ <Control Id="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Cancel="yes" Text="!(loc.WixUICancel)">
+ <Publish Event="SpawnDialog" Value="CancelDlg">1</Publish>
+ </Control>
+
+ <Control Id="Description" Type="Text" X="25" Y="23" Width="280" Height="15" Transparent="yes" NoPrefix="yes" Text="Choose options for installing CMake [ProductVersion]"/>
+ <Control Id="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Transparent="yes" NoPrefix="yes" Text="Install Options"/>
+ <Control Id="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" TabSkip="no" Text="!(loc.InstallDirDlgBannerBitmap)"/>
+ <Control Id="BannerLine" Type="Line" X="0" Y="44" Width="370" Height="0"/>
+ <Control Id="BottomLine" Type="Line" X="0" Y="234" Width="370" Height="0"/>
+
+ <Control Id="Hint" Type="Text" X="26" Y="60" Width="250" Height="16" Transparent="yes" Text="By default CMake does not add its directory to the system PATH."/>
+
+ <Control Id="ADD_CMAKE_TO_PATHOption" Type="RadioButtonGroup" X="26" Y="100" Width="305" Height="65" Property="ADD_CMAKE_TO_PATH">
+ <RadioButtonGroup Property="ADD_CMAKE_TO_PATH">
+ <RadioButton Value="None" X="0" Y="0" Width="295" Height="16" Text="Do not add CMake to the system PATH"/>
+ <RadioButton Value="System" X="0" Y="20" Width="295" Height="16" Text="Add CMake to the system PATH for all users"/>
+ <RadioButton Value="User" X="0" Y="40" Width="295" Height="16" Text="Add CMake to the system PATH for the current user"/>
+ </RadioButtonGroup>
+ </Control>
+
+ <?ifdef BUILD_QtDialog ?>
+ <Control Id="DesktopShortcutCheckBox" Type="CheckBox" X="20" Y="170" Width="330" Height="18" CheckBoxValue="1" Property="DESKTOP_SHORTCUT_REQUESTED" Text="Create CMake Desktop Icon"/>
+ <?endif ?>
+ </Dialog>
+ </UI>
+ </Fragment>
+</Wix>
diff --git a/Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs b/Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs
new file mode 100644
index 000000000..8fe60f2cd
--- /dev/null
+++ b/Utilities/Release/WiX/cmake_nsis_overwrite_dialog.wxs
@@ -0,0 +1,21 @@
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI>
+ <Dialog Id="CMakeNsisOverwriteDialog" Width="310" Height="120" Title="NSIS Installation Conflict">
+ <Control Id="OK" Type="PushButton" X="122" Y="90" Width="56" Height="17" Default="yes" Cancel="yes" Text="!(loc.WixUIOK)">
+ <Publish Event="EndDialog" Value="Return">1</Publish>
+ </Control>
+ <Control Id="Text" Type="Text" X="48" Y="22" Width="260" Height="60">
+ <Text>
+ Uninstall.exe was detected in your chosen installation prefix.
+ This indicates a conflicting NSIS based installation of CMake.
+
+ Please uninstall your old CMake installation or choose a different
+ installation directory.
+ </Text>
+ </Control>
+ <Control Id="Icon" Type="Icon" X="15" Y="15" Width="24" Height="24" ToolTip="!(loc.InvalidDirDlgIconTooltip)" FixedSize="yes" IconSize="32" Text="!(loc.InvalidDirDlgIcon)" />
+ </Dialog>
+ </UI>
+ </Fragment>
+</Wix>
diff --git a/Utilities/Release/WiX/custom_action_dll.wxs.in b/Utilities/Release/WiX/custom_action_dll.wxs.in
new file mode 100644
index 000000000..021e63c5f
--- /dev/null
+++ b/Utilities/Release/WiX/custom_action_dll.wxs.in
@@ -0,0 +1,6 @@
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <Binary Id="CMakeCustomActionsDll"
+ SourceFile="$<TARGET_FILE:CMakeWiXCustomActions>"/>
+ </Fragment>
+</Wix>
diff --git a/Utilities/Release/WiX/install_dir.wxs b/Utilities/Release/WiX/install_dir.wxs
new file mode 100644
index 000000000..49b74e37d
--- /dev/null
+++ b/Utilities/Release/WiX/install_dir.wxs
@@ -0,0 +1,72 @@
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Fragment>
+ <UI Id="CMakeUI_InstallDir">
+ <TextStyle Id="WixUI_Font_Normal" FaceName="Tahoma" Size="8" />
+ <TextStyle Id="WixUI_Font_Bigger" FaceName="Tahoma" Size="12" />
+ <TextStyle Id="WixUI_Font_Title" FaceName="Tahoma" Size="9" Bold="yes" />
+
+ <Property Id="DefaultUIFont" Value="WixUI_Font_Normal" />
+ <Property Id="WixUI_Mode" Value="InstallDir" />
+
+ <DialogRef Id="CMakeExtraDialog" />
+ <?ifdef CHECK_NSIS ?>
+ <DialogRef Id="CMakeNsisOverwriteDialog" />
+ <?endif ?>
+
+ <DialogRef Id="BrowseDlg" />
+ <DialogRef Id="DiskCostDlg" />
+ <DialogRef Id="ErrorDlg" />
+ <DialogRef Id="FatalError" />
+ <DialogRef Id="FilesInUse" />
+ <DialogRef Id="MsiRMFilesInUse" />
+ <DialogRef Id="PrepareDlg" />
+ <DialogRef Id="ProgressDlg" />
+ <DialogRef Id="ResumeDlg" />
+ <DialogRef Id="UserExit" />
+
+ <Publish Dialog="BrowseDlg" Control="OK" Event="DoAction" Value="WixUIValidatePath" Order="3">1</Publish>
+ <Publish Dialog="BrowseDlg" Control="OK" Event="SpawnDialog" Value="InvalidDirDlg" Order="4"><![CDATA[WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+
+ <Publish Dialog="ExitDialog" Control="Finish" Event="EndDialog" Value="Return" Order="999">1</Publish>
+
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="LicenseAgreementDlg">NOT Installed</Publish>
+ <Publish Dialog="WelcomeDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg">Installed AND PATCH</Publish>
+
+ <Publish Dialog="LicenseAgreementDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg">1</Publish>
+ <Publish Dialog="LicenseAgreementDlg" Control="Next" Event="NewDialog" Value="CMakeExtraDialog">LicenseAccepted = "1"</Publish>
+
+ <Publish Dialog="InstallDirDlg" Control="Back" Event="NewDialog" Value="CMakeExtraDialog">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="SetTargetPath" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="WixUIValidatePath" Order="2">NOT WIXUI_DONTVALIDATEPATH</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="InvalidDirDlg" Order="3"><![CDATA[NOT WIXUI_DONTVALIDATEPATH AND WIXUI_INSTALLDIR_VALID<>"1"]]></Publish>
+ <?ifdef CHECK_NSIS ?>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="DoAction" Value="CMakeDetectNsisOverwrite" Order="4">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="SpawnDialog" Value="CMakeNsisOverwriteDialog" Order="5">CMAKE_NSIS_OVERWRITE_DETECTED="1"</Publish>
+ <?endif ?>
+ <Publish Dialog="InstallDirDlg" Control="Next" Event="NewDialog" Value="VerifyReadyDlg" Order="6"><![CDATA[(WIXUI_DONTVALIDATEPATH OR WIXUI_INSTALLDIR_VALID="1") AND CMAKE_NSIS_OVERWRITE_DETECTED<>1]]></Publish>
+ <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Property="_BrowseProperty" Value="[WIXUI_INSTALLDIR]" Order="1">1</Publish>
+ <Publish Dialog="InstallDirDlg" Control="ChangeFolder" Event="SpawnDialog" Value="BrowseDlg" Order="2">1</Publish>
+
+ <Publish Dialog="CMakeExtraDialog" Control="Back" Event="NewDialog" Value="LicenseAgreementDlg">1</Publish>
+ <Publish Dialog="CMakeExtraDialog" Control="Next" Event="NewDialog" Value="InstallDirDlg">1</Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="InstallDirDlg" Order="1">NOT Installed</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="MaintenanceTypeDlg" Order="2">Installed AND NOT PATCH</Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back" Event="NewDialog" Value="WelcomeDlg" Order="2">Installed AND PATCH</Publish>
+
+ <Publish Dialog="MaintenanceWelcomeDlg" Control="Next" Event="NewDialog" Value="MaintenanceTypeDlg">1</Publish>
+
+ <Publish Dialog="MaintenanceTypeDlg" Control="RepairButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="RemoveButton" Event="NewDialog" Value="VerifyReadyDlg">1</Publish>
+ <Publish Dialog="MaintenanceTypeDlg" Control="Back" Event="NewDialog" Value="MaintenanceWelcomeDlg">1</Publish>
+
+ <Property Id="ARPNOMODIFY" Value="1" />
+ </UI>
+
+ <UIRef Id="WixUI_Common" />
+
+ <?ifdef CHECK_NSIS ?>
+ <CustomAction Id="CMakeDetectNsisOverwrite" BinaryKey="CMakeCustomActionsDll" DllEntry="DetectNsisOverwrite"/>
+ <?endif ?>
+ </Fragment>
+</Wix>
diff --git a/Utilities/Release/WiX/patch_desktop_shortcut.xml b/Utilities/Release/WiX/patch_desktop_shortcut.xml
new file mode 100644
index 000000000..d30705dd1
--- /dev/null
+++ b/Utilities/Release/WiX/patch_desktop_shortcut.xml
@@ -0,0 +1,5 @@
+<CPackWiXPatch>
+ <CPackWiXFragment Id="CM_SHORTCUT_DESKTOP">
+ <Condition>DESKTOP_SHORTCUT_REQUESTED = 1</Condition>
+ </CPackWiXFragment>
+</CPackWiXPatch>
diff --git a/Utilities/Release/WiX/patch_path_env.xml b/Utilities/Release/WiX/patch_path_env.xml
new file mode 100644
index 000000000..0e335c4d5
--- /dev/null
+++ b/Utilities/Release/WiX/patch_path_env.xml
@@ -0,0 +1,26 @@
+<CPackWiXPatch>
+ <CPackWiXFragment Id="CM_DP_bin">
+ <Component Id="CMakeSystemPathEntryCMP" KeyPath="yes" Guid="0E782367-5D68-4539-81D1-B9757AE496A1">
+
+ <Condition>ADD_CMAKE_TO_PATH = "System"</Condition>
+
+ <Environment Id="CMakeSystemPathEntryENV" Action="set" Part="last"
+ Name="PATH" Value="[INSTALL_ROOT]bin"
+ System="yes"/>
+ </Component>
+
+ <Component Id="CMakeUserPathEntryCMP" KeyPath="yes" Guid="392E524D-D5BF-4F16-A7AF-A82B07482CB9">
+
+ <Condition>ADD_CMAKE_TO_PATH = "User"</Condition>
+
+ <Environment Id="CMakeUserPathEntryENV" Action="set" Part="last"
+ Name="PATH" Value="[INSTALL_ROOT]bin"
+ System="no"/>
+ </Component>
+ </CPackWiXFragment>
+
+ <CPackWiXFragment Id="#PRODUCTFEATURE">
+ <ComponentRef Id="CMakeSystemPathEntryCMP"/>
+ <ComponentRef Id="CMakeUserPathEntryCMP"/>
+ </CPackWiXFragment>
+</CPackWiXPatch>
diff --git a/Utilities/Release/WiX/ui_banner.jpg b/Utilities/Release/WiX/ui_banner.jpg
new file mode 100644
index 000000000..8d950a6ba
--- /dev/null
+++ b/Utilities/Release/WiX/ui_banner.jpg
Binary files differ
diff --git a/Utilities/Release/WiX/ui_dialog.jpg b/Utilities/Release/WiX/ui_dialog.jpg
new file mode 100644
index 000000000..bb6fa5ba7
--- /dev/null
+++ b/Utilities/Release/WiX/ui_dialog.jpg
Binary files differ
diff --git a/Utilities/Release/consolidate-relnotes.bash b/Utilities/Release/consolidate-relnotes.bash
new file mode 100755
index 000000000..91307ac51
--- /dev/null
+++ b/Utilities/Release/consolidate-relnotes.bash
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+set -e
+
+usage='usage: consolidate-relnotes.bash <new-release-version> <prev-release-version>'
+
+die() {
+ echo "$@" 1>&2; exit 1
+}
+
+test "$#" = 2 || die "$usage"
+
+files="$(ls Help/release/dev/* | grep -v Help/release/dev/0-sample-topic.rst)"
+title="CMake $1 Release Notes"
+underline="$(echo "$title" | sed 's/./*/g')"
+echo "$title
+$underline
+
+.. only:: html
+
+ .. contents::
+
+Changes made since CMake $2 include the following." > Help/release/"$1".rst
+tail -q -n +3 $files >> Help/release/"$1".rst
+sed -i "/^ $2 / i\\
+ $1 <$1>" Help/release/index.rst
+rm $files
diff --git a/Utilities/Release/create-cmake-release.cmake b/Utilities/Release/create-cmake-release.cmake
index 37e223d28..3af1b035f 100644
--- a/Utilities/Release/create-cmake-release.cmake
+++ b/Utilities/Release/create-cmake-release.cmake
@@ -6,17 +6,13 @@ endif()
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/logs)
set(RELEASE_SCRIPTS_BATCH_1
- dash2win64_release.cmake # Windows
- dashmacmini2_release.cmake # Mac Darwin universal ppc;i386
- dashmacmini5_release.cmake # Mac Darwin64 universal x86_64;i386
- magrathea_release.cmake # Linux
- v20n250_aix_release.cmake # AIX 5.3
- ferrari_sgi64_release.cmake # IRIX 64
- ferrari_sgi_release.cmake # IRIX
+ win32_release.cmake # Windows x86
+ osx_release.cmake # OS X x86_64
+ linux64_release.cmake # Linux x86_64
)
set(RELEASE_SCRIPTS_BATCH_2
- dash2win64_cygwin.cmake # Cygwin
+ win64_release.cmake # Windows x64
)
function(write_batch_shell_script filename)
@@ -28,15 +24,53 @@ function(write_batch_shell_script filename)
math(EXPR y "160*(${i}%4)")
file(APPEND ${filename}
"
-${CMAKE_COMMAND} -DCMAKE_CREATE_VERSION=${CMAKE_CREATE_VERSION} -P ${CMAKE_ROOT}/Utilities/Release/${f} < /dev/null >& ${CMAKE_CURRENT_SOURCE_DIR}/logs/${f}-${CMAKE_CREATE_VERSION}.log &
-xterm -geometry 64x6+${x}+${y} -sb -sl 2000 -T ${f}-${CMAKE_CREATE_VERSION}.log -e tail -f ${CMAKE_CURRENT_SOURCE_DIR}/logs/${f}-${CMAKE_CREATE_VERSION}.log&
+\"${CMAKE_COMMAND}\" -DCMAKE_CREATE_VERSION=${CMAKE_CREATE_VERSION} -DCMAKE_DOC_TARBALL=\"${CMAKE_DOC_TARBALL}\" -P \"${CMAKE_ROOT}/Utilities/Release/${f}\" < /dev/null >& \"${CMAKE_CURRENT_SOURCE_DIR}/logs/${f}-${CMAKE_CREATE_VERSION}.log\" &
+xterm -geometry 64x6+${x}+${y} -sb -sl 2000 -T ${f}-${CMAKE_CREATE_VERSION}.log -e tail -f \"${CMAKE_CURRENT_SOURCE_DIR}/logs/${f}-${CMAKE_CREATE_VERSION}.log\" &
")
math(EXPR i "${i}+1")
endforeach()
execute_process(COMMAND chmod a+x ${filename})
endfunction()
+function(write_docs_shell_script filename)
+ find_program(SPHINX_EXECUTABLE
+ NAMES sphinx-build sphinx-build.py
+ DOC "Sphinx Documentation Builder (sphinx-doc.org)"
+ )
+ if(NOT SPHINX_EXECUTABLE)
+ message(FATAL_ERROR "SPHINX_EXECUTABLE (sphinx-build) is not found!")
+ endif()
+
+ set(name cmake-${CMAKE_CREATE_VERSION}-docs)
+ file(WRITE "${filename}" "#!/usr/bin/env bash
+
+name=${name} &&
+inst=\"\$PWD/\$name\"
+(GIT_WORK_TREE=x git archive --prefix=\${name}-src/ ${CMAKE_CREATE_VERSION}) | tar x &&
+rm -rf \${name}-build &&
+mkdir \${name}-build &&
+cd \${name}-build &&
+\"${CMAKE_COMMAND}\" ../\${name}-src/Utilities/Sphinx \\
+ -DCMAKE_INSTALL_PREFIX=\"\$inst/\" \\
+ -DCMAKE_DOC_DIR=doc/cmake \\
+ -DSPHINX_EXECUTABLE=\"${SPHINX_EXECUTABLE}\" \\
+ -DSPHINX_HTML=ON -DSPHINX_MAN=ON &&
+make install &&
+cd .. &&
+tar czf \${name}.tar.gz \${name} ||
+echo 'Failed to create \${name}.tar.gz'
+")
+ execute_process(COMMAND chmod a+x ${filename})
+ set(CMAKE_DOC_TARBALL "${name}.tar.gz" PARENT_SCOPE)
+endfunction()
+
+write_docs_shell_script("create-${CMAKE_CREATE_VERSION}-docs.sh")
write_batch_shell_script("create-${CMAKE_CREATE_VERSION}-batch1.sh" ${RELEASE_SCRIPTS_BATCH_1})
write_batch_shell_script("create-${CMAKE_CREATE_VERSION}-batch2.sh" ${RELEASE_SCRIPTS_BATCH_2})
-message("Run ./create-${CMAKE_CREATE_VERSION}-batch1.sh, then after all those builds complete, run ./create-${CMAKE_CREATE_VERSION}-batch2.sh")
+message("Run one at a time:
+ ./create-${CMAKE_CREATE_VERSION}-docs.sh &&
+ ./create-${CMAKE_CREATE_VERSION}-batch1.sh &&
+ ./create-${CMAKE_CREATE_VERSION}-batch2.sh &&
+ echo done
+")
diff --git a/Utilities/Release/dash2win64_cygwin.cmake b/Utilities/Release/dash2win64_cygwin.cmake
deleted file mode 100644
index 663c61581..000000000
--- a/Utilities/Release/dash2win64_cygwin.cmake
+++ /dev/null
@@ -1,27 +0,0 @@
-set(CMAKE_RELEASE_DIRECTORY "c:/cygwin/home/dashboard/CMakeReleaseCygwin")
-set(PROCESSORS 9)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -j8")
-set(HOST dash2win64)
-set(CPACK_BINARY_GENERATORS "CygwinBinary")
-set(CPACK_SOURCE_GENERATORS "CygwinSource")
-set(MAKE_PROGRAM "make")
-set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_Fortran_COMPILER_FULLPATH:FILEPATH=FALSE
-CTEST_TEST_TIMEOUT:STRING=7200
-DART_TESTING_TIMEOUT:STRING=7200
-")
-set(CXX g++)
-set(CC gcc)
-set(SCRIPT_NAME dash2win64cygwin)
-set(GIT_EXTRA "git config core.autocrlf true")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-
-# WARNING: Temporary fix!! This exclusion of the ExternalProject test
-# is temporary until we can set up a new cygwin build machine.
-# It only fails because of cygwin/non-cygwin "svn" mismatches in this
-# particular environment. This is less than ideal, but at least it
-# allows us to produce cygwin builds in the short term.
-set(EXTRA_CTEST_ARGS "-E ExternalProject")
-
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/dash2win64_release.cmake b/Utilities/Release/dash2win64_release.cmake
deleted file mode 100644
index 6d1ac767e..000000000
--- a/Utilities/Release/dash2win64_release.cmake
+++ /dev/null
@@ -1,20 +0,0 @@
-set(CMAKE_RELEASE_DIRECTORY "c:/cygwin/home/dashboard/CMakeReleaseDirectory")
-set(CONFIGURE_WITH_CMAKE TRUE)
-set(CMAKE_CONFIGURE_PATH "c:/Program\\ Files\\ \\(x86\\)/CMake\\ 2.8/bin/cmake.exe")
-set(PROCESSORS 8)
-set(HOST dash2win64)
-set(CPACK_BINARY_GENERATORS "NSIS ZIP")
-set(CPACK_SOURCE_GENERATORS "ZIP")
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -j8")
-set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_USE_OPENSSL:BOOL=ON
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-CMAKE_Fortran_COMPILER:FILEPATH=FALSE
-CMAKE_GENERATOR:INTERNAL=Unix Makefiles
-BUILD_QtDialog:BOOL:=TRUE
-QT_QMAKE_EXECUTABLE:FILEPATH=c:/Dashboards/Support/qt-build/Qt/bin/qmake.exe
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-set(GIT_EXTRA "git config core.autocrlf true")
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/dashmacmini2_release.cmake b/Utilities/Release/dashmacmini2_release.cmake
deleted file mode 100644
index 5e57a70b2..000000000
--- a/Utilities/Release/dashmacmini2_release.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-set(PROCESSORS 2)
-set(CMAKE_RELEASE_DIRECTORY /Users/kitware/CMakeReleaseDirectory)
-set(USER_OVERRIDE "set(CMAKE_CXX_LINK_EXECUTABLE \\\"gcc <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -shared-libgcc -lstdc++-static\\\")")
-set(INSTALL_PREFIX /)
-set(HOST dashmacmini2)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -j2")
-set(CPACK_BINARY_GENERATORS "PackageMaker TGZ TZ")
-set(INITIAL_CACHE "
-CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_OSX_ARCHITECTURES:STRING=ppc;i386
-CMAKE_USE_OPENSSL:BOOL=ON
-OPENSSL_CRYPTO_LIBRARY:FILEPATH=/Users/kitware/openssl-1.0.1c-install/lib/libcrypto.a
-OPENSSL_INCLUDE_DIR:PATH=/Users/kitware/openssl-1.0.1c-install/include
-OPENSSL_SSL_LIBRARY:FILEPATH=/Users/kitware/openssl-1.0.1c-install/lib/libssl.a
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-CPACK_SYSTEM_NAME:STRING=Darwin-universal
-BUILD_QtDialog:BOOL=TRUE
-QT_QMAKE_EXECUTABLE:FILEPATH=/Users/kitware/Support/qt-4.8.0/install/bin/qmake
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/dashmacmini5_release.cmake b/Utilities/Release/dashmacmini5_release.cmake
deleted file mode 100644
index 36b095287..000000000
--- a/Utilities/Release/dashmacmini5_release.cmake
+++ /dev/null
@@ -1,24 +0,0 @@
-set(PROCESSORS 4)
-set(CMAKE_RELEASE_DIRECTORY /Users/kitware/CMakeReleaseDirectory)
-# set(USER_OVERRIDE "set(CMAKE_CXX_LINK_EXECUTABLE \\\"gcc <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES> -shared-libgcc -lstdc++-static\\\")")
-set(INSTALL_PREFIX /)
-set(HOST dashmacmini5)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -j5")
-set(CPACK_BINARY_GENERATORS "PackageMaker TGZ TZ")
-set(CPACK_SOURCE_GENERATORS "TGZ TZ")
-set(INITIAL_CACHE "
-CMAKE_USE_OPENSSL:BOOL=ON
-OPENSSL_CRYPTO_LIBRARY:FILEPATH=/Users/kitware/openssl-1.0.1c-install/lib/libcrypto.a
-OPENSSL_INCLUDE_DIR:PATH=/Users/kitware/openssl-1.0.1c-install/include
-OPENSSL_SSL_LIBRARY:FILEPATH=/Users/kitware/openssl-1.0.1c-install/lib/libssl.a
-CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_OSX_ARCHITECTURES:STRING=x86_64;i386
-CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.5
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-CPACK_SYSTEM_NAME:STRING=Darwin64-universal
-BUILD_QtDialog:BOOL=TRUE
-QT_QMAKE_EXECUTABLE:FILEPATH=/Users/kitware/Support/qt-4.8.0/install/bin/qmake
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/ferrari_sgi64_release.cmake b/Utilities/Release/ferrari_sgi64_release.cmake
deleted file mode 100644
index 4425f0557..000000000
--- a/Utilities/Release/ferrari_sgi64_release.cmake
+++ /dev/null
@@ -1,16 +0,0 @@
-set(CMAKE_RELEASE_DIRECTORY "/home/whoffman/CMakeReleaseDirectory64")
-set(PROCESSORS 2)
-set(CFLAGS "-64")
-set(FFLAGS "-64")
-set(CXXFLAGS "-64")
-set(LDFLAGS="-64")
-set(HOST sgi)
-set(SCRIPT_NAME sgi64)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -P")
-set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-CPACK_SYSTEM_NAME:STRING=IRIX64-64
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/ferrari_sgi_release.cmake b/Utilities/Release/ferrari_sgi_release.cmake
deleted file mode 100644
index ee5121a9b..000000000
--- a/Utilities/Release/ferrari_sgi_release.cmake
+++ /dev/null
@@ -1,11 +0,0 @@
-set(CMAKE_RELEASE_DIRECTORY "/home/whoffman/CMakeReleaseDirectory")
-set(PROCESSORS 2)
-set(HOST sgi)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -P")
-set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-CPACK_SYSTEM_NAME:STRING=IRIX64-n32
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/hythloth_release.cmake b/Utilities/Release/hythloth_release.cmake
deleted file mode 100644
index d2f4ba58c..000000000
--- a/Utilities/Release/hythloth_release.cmake
+++ /dev/null
@@ -1,10 +0,0 @@
-set(PROCESSORS 2)
-set(HOST hythloth)
-set(MAKE_PROGRAM "make")
-set(MAKE "${MAKE_PROGRAM} -j2")
-set(INITIAL_CACHE "
-CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/linux64_release.cmake b/Utilities/Release/linux64_release.cmake
new file mode 100644
index 000000000..3d8ddba3c
--- /dev/null
+++ b/Utilities/Release/linux64_release.cmake
@@ -0,0 +1,50 @@
+set(PROCESSORS 4)
+set(BOOTSTRAP_ARGS "--docdir=doc/cmake")
+set(HOST linux64)
+set(MAKE_PROGRAM "make")
+set(CPACK_BINARY_GENERATORS "STGZ TGZ")
+set(CC /opt/gcc-6.1.0/bin/gcc)
+set(CXX /opt/gcc-6.1.0/bin/g++)
+set(CFLAGS "")
+set(CXXFLAGS "")
+set(qt_prefix "/home/kitware/qt-5.7.0")
+set(qt_xcb_libs
+ ${qt_prefix}/plugins/platforms/libqxcb.a
+ ${qt_prefix}/lib/libQt5XcbQpa.a
+ ${qt_prefix}/lib/libQt5PlatformSupport.a
+ ${qt_prefix}/lib/libxcb-static.a
+ -lX11-xcb
+ -lX11
+ -lxcb
+ -lfontconfig
+ -lfreetype
+ )
+set(INITIAL_CACHE "
+CMAKE_BUILD_TYPE:STRING=Release
+CMAKE_C_STANDARD:STRING=11
+CMAKE_CXX_STANDARD:STRING=14
+CMAKE_C_FLAGS:STRING=-D_POSIX_C_SOURCE=199506L -D_POSIX_SOURCE=1 -D_SVID_SOURCE=1 -D_BSD_SOURCE=1
+CMAKE_EXE_LINKER_FLAGS:STRING=-static-libstdc++ -static-libgcc
+CURSES_LIBRARY:FILEPATH=/home/kitware/ncurses-5.9/lib/libncurses.a
+CURSES_INCLUDE_PATH:PATH=/home/kitware/ncurses-5.9/include
+FORM_LIBRARY:FILEPATH=/home/kitware/ncurses-5.9/lib/libform.a
+CMAKE_USE_OPENSSL:BOOL=ON
+OPENSSL_CRYPTO_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2j/lib/libcrypto.a
+OPENSSL_INCLUDE_DIR:PATH=/home/kitware/openssl-1.0.2j/include
+OPENSSL_SSL_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.2j/lib/libssl.a
+PYTHON_EXECUTABLE:FILEPATH=/usr/bin/python3
+CPACK_SYSTEM_NAME:STRING=Linux-x86_64
+BUILD_QtDialog:BOOL:=TRUE
+CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
+CMake_ENABLE_SERVER_MODE:BOOL=TRUE
+CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
+CMAKE_PREFIX_PATH:STRING=${qt_prefix}
+CMake_QT_STATIC_QXcbIntegrationPlugin_LIBRARIES:STRING=${qt_xcb_libs}
+")
+
+# Exclude Qt5 tests because our Qt5 is static.
+set(EXTRA_CTEST_ARGS "-E Qt5")
+
+get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/magrathea_release.cmake b/Utilities/Release/magrathea_release.cmake
deleted file mode 100644
index 4783fdad3..000000000
--- a/Utilities/Release/magrathea_release.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-set(PROCESSORS 1)
-set(HOST magrathea)
-set(MAKE_PROGRAM "make")
-set(CC gcc332s)
-set(CXX c++332s)
-set(CFLAGS -DDT_RUNPATH=29)
-set(CXXFLAGS -DDT_RUNPATH=29)
-set(INITIAL_CACHE "
-CMAKE_BUILD_TYPE:STRING=Release
-CURSES_LIBRARY:FILEPATH=/usr/i686-gcc-332s/lib/libncurses.a
-CURSES_INCLUDE_PATH:PATH=/usr/i686-gcc-332s/include/ncurses
-FORM_LIBRARY:FILEPATH=/usr/i686-gcc-332s/lib/libform.a
-CMAKE_USE_OPENSSL:BOOL=ON
-OPENSSL_CRYPTO_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.1c-install/lib/libcrypto.a
-OPENSSL_INCLUDE_DIR:PATH=/home/kitware/openssl-1.0.1c-install/include
-OPENSSL_SSL_LIBRARY:FILEPATH=/home/kitware/openssl-1.0.1c-install/lib/libssl.a
-CPACK_SYSTEM_NAME:STRING=Linux-i386
-BUILD_QtDialog:BOOL:=TRUE
-QT_QMAKE_EXECUTABLE:FILEPATH=/home/kitware/qt-4.43-install/bin/qmake
-")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/osx_release.cmake b/Utilities/Release/osx_release.cmake
new file mode 100644
index 000000000..36498a7ce
--- /dev/null
+++ b/Utilities/Release/osx_release.cmake
@@ -0,0 +1,33 @@
+set(PROCESSORS 4)
+set(CMAKE_RELEASE_DIRECTORY /Users/kitware/CMakeReleaseDirectory)
+set(BOOTSTRAP_ARGS "--prefix=/ --docdir=doc/cmake")
+set(HOST dragnipur)
+set(MAKE_PROGRAM "make")
+set(MAKE "${MAKE_PROGRAM} -j5")
+set(CPACK_BINARY_GENERATORS "DragNDrop TGZ")
+set(CPACK_SOURCE_GENERATORS "TGZ TZ")
+set(CPACK_DMG_FORMAT "UDBZ") #build using bzip2 for smaller package size
+set(CC clang)
+set(CXX clang++)
+set(CFLAGS "")
+set(CXXFLAGS "-stdlib=libc++")
+set(INITIAL_CACHE "
+CMAKE_BUILD_TYPE:STRING=Release
+CMAKE_C_STANDARD:STRING=11
+CMAKE_CXX_STANDARD:STRING=14
+CMAKE_OSX_ARCHITECTURES:STRING=x86_64
+CMAKE_OSX_DEPLOYMENT_TARGET:STRING=10.7
+CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
+CPACK_SYSTEM_NAME:STRING=Darwin-x86_64
+BUILD_QtDialog:BOOL=TRUE
+CMake_ENABLE_SERVER_MODE:BOOL=TRUE
+CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
+CMAKE_SKIP_RPATH:BOOL=TRUE
+CMake_TEST_NO_FindPackageModeMakefileTest:BOOL=TRUE
+")
+set(ENV [[
+export CMAKE_PREFIX_PATH='/Users/kitware/SDKs/qt-5.6.2-clang-x64'
+]])
+get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
+include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/release_cmake.cmake b/Utilities/Release/release_cmake.cmake
index f351ac8c0..b2c21b7dc 100644
--- a/Utilities/Release/release_cmake.cmake
+++ b/Utilities/Release/release_cmake.cmake
@@ -4,9 +4,6 @@ get_filename_component(SCRIPT_PATH "${CMAKE_CURRENT_LIST_FILE}" PATH)
if(NOT DEFINED CPACK_BINARY_GENERATORS)
set(CPACK_BINARY_GENERATORS "STGZ TGZ TZ")
endif()
-if(DEFINED EXTRA_COPY)
- set(HAS_EXTRA_COPY 1)
-endif()
if(NOT DEFINED CMAKE_RELEASE_DIRECTORY)
set(CMAKE_RELEASE_DIRECTORY "~/CMakeReleaseDirectory")
endif()
@@ -22,6 +19,9 @@ endif()
if(NOT DEFINED RUN_SHELL)
set(RUN_SHELL "/bin/sh")
endif()
+if(NOT DEFINED RUN_LAUNCHER)
+ set(RUN_LAUNCHER "")
+endif()
if(NOT DEFINED PROCESSORS)
set(PROCESSORS 1)
endif()
@@ -32,9 +32,16 @@ if(NOT DEFINED GIT_COMMAND)
set(GIT_COMMAND git)
endif()
-if(${CMAKE_CREATE_VERSION} MATCHES "^(release|maint|next|nightly)$")
+if(CMAKE_CREATE_VERSION MATCHES "^(master|release)$")
+ set(GIT_FETCH "")
set(GIT_BRANCH origin/${CMAKE_CREATE_VERSION})
+elseif(CMAKE_CREATE_VERSION STREQUAL "nightly")
+ set(nightly stage/master/nightly/latest)
+ set(GIT_FETCH "${GIT_COMMAND} fetch origin refs/${nightly}:refs/remotes/origin/${nightly}")
+ set(GIT_BRANCH origin/${nightly})
else()
+ set(stage stage/master/head)
+ set(GIT_FETCH "${GIT_COMMAND} fetch origin refs/${stage}:refs/remotes/origin/${stage}")
set(GIT_BRANCH ${CMAKE_CREATE_VERSION})
endif()
@@ -55,17 +62,29 @@ message("Creating CMake release ${CMAKE_CREATE_VERSION} on ${HOST} with parallel
macro(remote_command comment command)
message("${comment}")
if(${ARGC} GREATER 2)
- message("ssh ${HOST} ${EXTRA_HOP} ${command}")
- execute_process(COMMAND ssh ${HOST} ${EXTRA_HOP} ${command} RESULT_VARIABLE result INPUT_FILE ${ARGV2})
+ message("ssh ${HOST} ${RUN_LAUNCHER} ${command}")
+ execute_process(COMMAND ssh ${HOST} ${RUN_LAUNCHER} ${command} RESULT_VARIABLE result INPUT_FILE ${ARGV2})
else()
- message("ssh ${HOST} ${EXTRA_HOP} ${command}")
- execute_process(COMMAND ssh ${HOST} ${EXTRA_HOP} ${command} RESULT_VARIABLE result)
+ message("ssh ${HOST} ${RUN_LAUNCHER} ${command}")
+ execute_process(COMMAND ssh ${HOST} ${RUN_LAUNCHER} ${command} RESULT_VARIABLE result)
endif()
if(${result} GREATER 0)
message(FATAL_ERROR "Error running command: ${command}, return value = ${result}")
endif()
endmacro()
+if(CMAKE_DOC_TARBALL)
+ get_filename_component(CMAKE_DOC_TARBALL_NAME "${CMAKE_DOC_TARBALL}" NAME)
+ string(REPLACE ".tar.gz" "-${SCRIPT_NAME}.tar.gz" CMAKE_DOC_TARBALL_STAGED "${CMAKE_DOC_TARBALL_NAME}")
+ message("scp '${CMAKE_DOC_TARBALL}' '${HOST}:${CMAKE_DOC_TARBALL_STAGED}'")
+ execute_process(COMMAND
+ scp ${CMAKE_DOC_TARBALL} ${HOST}:${CMAKE_DOC_TARBALL_STAGED}
+ RESULT_VARIABLE result)
+ if(${result} GREATER 0)
+ message("error sending doc tarball with scp '${CMAKE_DOC_TARBALL}' '${HOST}:${CMAKE_DOC_TARBALL_STAGED}'")
+ endif()
+endif()
+
# set this so configure file will work from script mode
# create the script specific for the given host
set(SCRIPT_FILE release_cmake-${SCRIPT_NAME}.sh)
@@ -90,19 +109,18 @@ foreach(gen ${generators})
if("${gen}" STREQUAL "STGZ")
set(SUFFIXES ${SUFFIXES} "*.sh")
endif()
- if("${gen}" STREQUAL "PackageMaker")
+ if("${gen}" STREQUAL "DragNDrop")
set(SUFFIXES ${SUFFIXES} "*.dmg")
endif()
if("${gen}" STREQUAL "TBZ2")
set(SUFFIXES ${SUFFIXES} "*.tar.bz2")
endif()
- if("${gen}" MATCHES "Cygwin")
- set(SUFFIXES ${SUFFIXES} "*.tar.bz2")
- set(extra_files setup.hint)
- endif()
if("${gen}" STREQUAL "TZ")
set(SUFFIXES ${SUFFIXES} "*.tar.Z")
endif()
+ if("${gen}" STREQUAL "WIX")
+ set(SUFFIXES ${SUFFIXES} "*.msi")
+ endif()
if("${gen}" STREQUAL "ZIP")
set(SUFFIXES ${SUFFIXES} "*.zip")
endif()
@@ -110,27 +128,38 @@ foreach(gen ${generators})
set(SUFFIXES ${SUFFIXES} "*.exe")
endif()
endforeach()
+
+if(SUFFIXES)
+ list(REMOVE_DUPLICATES SUFFIXES)
+endif()
+
+if(LOCAL_DIR)
+ file(MAKE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${LOCAL_DIR}")
+else()
+ set(LOCAL_DIR .)
+endif()
+
# copy all the files over from the remote machine
set(PROJECT_PREFIX cmake-)
foreach(suffix ${SUFFIXES})
- message("scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} .")
+ message("scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} ${LOCAL_DIR}")
execute_process(COMMAND
- scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} .
+ scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} ${LOCAL_DIR}
RESULT_VARIABLE result)
if(${result} GREATER 0)
- message("error getting file back scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} .")
+ message("error getting file back scp ${HOST}:${FINAL_PATH}/${PROJECT_PREFIX}${suffix} ${LOCAL_DIR}")
endif()
endforeach()
# if there are extra files to copy get them as well
if(extra_files)
foreach(f ${extra_files})
- message("scp ${HOST}:${FINAL_PATH}/${f} .")
+ message("scp ${HOST}:${FINAL_PATH}/${f} ${LOCAL_DIR}")
execute_process(COMMAND
- scp ${HOST}:${FINAL_PATH}/${f} .
+ scp ${HOST}:${FINAL_PATH}/${f} ${LOCAL_DIR}
RESULT_VARIABLE result)
if(${result} GREATER 0)
- message("error getting file back scp ${HOST}:${FINAL_PATH}/${f} .")
+ message("error getting file back scp ${HOST}:${FINAL_PATH}/${f} ${LOCAL_DIR}")
endif()
endforeach()
endif()
diff --git a/Utilities/Release/release_cmake.sh.in b/Utilities/Release/release_cmake.sh.in
index 82c039b43..f363b3d8a 100755
--- a/Utilities/Release/release_cmake.sh.in
+++ b/Utilities/Release/release_cmake.sh.in
@@ -5,6 +5,7 @@ echo ""
echo "remove and create working directory @CMAKE_RELEASE_DIRECTORY@"
rm -rf @CMAKE_RELEASE_DIRECTORY@
mkdir @CMAKE_RELEASE_DIRECTORY@
+@ENV@
check_exit_value()
{
@@ -15,6 +16,13 @@ check_exit_value()
fi
}
+CMAKE_DOC_TARBALL=""
+if [ ! -z "@CMAKE_DOC_TARBALL_NAME@" ] ; then
+ CMAKE_DOC_TARBALL=@CMAKE_RELEASE_DIRECTORY@/@CMAKE_DOC_TARBALL_NAME@
+ mv "$HOME/@CMAKE_DOC_TARBALL_STAGED@" "$CMAKE_DOC_TARBALL"
+ check_exit_value $? "mv doc tarball" || exit 1
+fi
+
if [ ! -z "@CC@" ]; then
export CC="@CC@"
check_exit_value $? "set CC compiler env var" || exit 1
@@ -76,18 +84,25 @@ if [ ! -z "@USER_OVERRIDE@" ]; then
echo "CMAKE_USER_MAKE_RULES_OVERRIDE:FILEPATH=@CMAKE_RELEASE_DIRECTORY@/@CMAKE_CREATE_VERSION@-build/user.txt" >> @CMAKE_RELEASE_DIRECTORY@/@CMAKE_CREATE_VERSION@-build/CMakeCache.txt
fi
+# Point build at pre-built documentation tarball, if any.
+if [ ! -z "$CMAKE_DOC_TARBALL" ]; then
+ echo "CMAKE_DOC_TARBALL:FILEPATH=$CMAKE_DOC_TARBALL" >> @CMAKE_RELEASE_DIRECTORY@/@CMAKE_CREATE_VERSION@-build/CMakeCache.txt
+fi
+
echo "Checkout the source for @CMAKE_CREATE_VERSION@"
cd @CMAKE_RELEASE_DIRECTORY@
if [ ! -z "@GIT_COMMAND@" ]; then
# clone the repo without creating any source files in the directory
# matching the branch being built (i.e. master CMake-2-8, etc)
- @GIT_COMMAND@ clone -n git://cmake.org/cmake.git @CMAKE_CREATE_VERSION@
- check_exit_value $? "Checkout git cmake source" || exit 1
+ @GIT_COMMAND@ clone -n https://gitlab.kitware.com/cmake/cmake.git @CMAKE_CREATE_VERSION@
+ check_exit_value $? "git clone cmake source" || exit 1
# go into the git directory
cd @CMAKE_CREATE_VERSION@
# run any extra commands if they exist
@GIT_EXTRA@
check_exit_value $? "git extra cmake source" || exit 1
+ @GIT_FETCH@
+ check_exit_value $? "git extra fetch" || exit 1
# now checkout a copy on the local branch working
@GIT_COMMAND@ checkout -b working @GIT_BRANCH@
check_exit_value $? "git checkout" || exit 1
@@ -104,15 +119,9 @@ if [ ! -z "@CONFIGURE_WITH_CMAKE@" ]; then
@CMAKE_CONFIGURE_PATH@ ../@CMAKE_CREATE_VERSION@
check_exit_value $? "Configure cmake" || exit 1
else
- if [ -z "@INSTALL_PREFIX@" ]; then
- echo "Run cmake bootstrap --parallel=@PROCESSORS@"
- ../@CMAKE_CREATE_VERSION@/bootstrap --parallel=@PROCESSORS@
- check_exit_value $? "Bootstrap cmake" || exit 1
- else
- echo "Run cmake bootstrap --prefix=@INSTALL_PREFIX@ --parallel=@PROCESSORS@"
- ../@CMAKE_CREATE_VERSION@/bootstrap --prefix=@INSTALL_PREFIX@ --parallel=@PROCESSORS@
- check_exit_value $? "Bootstrap cmake" || exit 1
- fi
+ echo "Run cmake bootstrap @BOOTSTRAP_ARGS@ --parallel=@PROCESSORS@"
+ ../@CMAKE_CREATE_VERSION@/bootstrap @BOOTSTRAP_ARGS@ --parallel=@PROCESSORS@
+ check_exit_value $? "Bootstrap cmake" || exit 1
fi
echo "Build cmake with @MAKE@"
@@ -143,11 +152,6 @@ done
-# need to add an extra copy thing here
-if [ ! -z "@EXTRA_COPY@" ]; then
- @EXTRA_COPY@
- check_exit_value $? "Extra copy step @EXTRA_COPY@" || exit 1
-fi
echo "End release"
date
echo ""
diff --git a/Utilities/Release/upload_release.cmake b/Utilities/Release/upload_release.cmake
index 9bf35236d..5b2cc5732 100644
--- a/Utilities/Release/upload_release.cmake
+++ b/Utilities/Release/upload_release.cmake
@@ -1,20 +1,19 @@
set(CTEST_RUN_CURRENT_SCRIPT 0)
-if(NOT DEFINED PROJECT_PREFIX)
- set(PROJECT_PREFIX cmake-)
-endif()
if(NOT VERSION)
- set(VERSION 2.8)
+ set(VERSION 3.9)
+endif()
+if(NOT DEFINED PROJECT_PREFIX)
+ set(PROJECT_PREFIX cmake-${VERSION})
endif()
-set(dir "v${VERSION}")
-if("${VERSION}" MATCHES "master")
- set(dir "dev")
+if(NOT DEFINED DIR)
+ set(DIR "v${VERSION}")
endif()
file(GLOB FILES ${CMAKE_CURRENT_SOURCE_DIR} "${PROJECT_PREFIX}*")
list(SORT FILES)
list(REVERSE FILES)
message("${FILES}")
set(UPLOAD_LOC
- "kitware@www.cmake.org:/projects/FTP/pub/cmake/${dir}")
+ "kitware@www.cmake.org:/projects/FTP/pub/cmake/${DIR}")
set(count 0)
foreach(file ${FILES})
if(NOT IS_DIRECTORY ${file})
diff --git a/Utilities/Release/v20n250_aix_release.cmake b/Utilities/Release/v20n250_aix_release.cmake
deleted file mode 100644
index cc8cd058b..000000000
--- a/Utilities/Release/v20n250_aix_release.cmake
+++ /dev/null
@@ -1,22 +0,0 @@
-set(CMAKE_RELEASE_DIRECTORY "/bench1/noibm34/CMakeReleaseDirectory")
-set(FINAL_PATH /u/noibm34/cmake-release)
-set(PROCESSORS 2)
-set(HOST "sshserv.centers.ihost.com")
-set(EXTRA_HOP "rsh p90n03")
-set(MAKE_PROGRAM "make")
-set(CC "xlc_r")
-set(CXX "xlC_r")
-set(FC "xlf")
-set(LDFLAGS "-Wl,-bmaxdata:0x80000000") # Push "Segmentation fault in extend_brk" over horizon
-set(INITIAL_CACHE "
-CMAKE_BUILD_TYPE:STRING=Release
-CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
-")
-set(EXTRA_COPY "
-rm -rf ~/cmake-release
-mkdir ~/cmake-release
-mv *.sh ~/cmake-release
-mv *.Z ~/cmake-release
-mv *.gz ~/cmake-release")
-get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
-include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/win32_release.cmake b/Utilities/Release/win32_release.cmake
new file mode 100644
index 000000000..df9fe275b
--- /dev/null
+++ b/Utilities/Release/win32_release.cmake
@@ -0,0 +1,33 @@
+set(CMAKE_RELEASE_DIRECTORY "c:/msys64/home/dashboard/CMakeReleaseDirectory")
+set(CONFIGURE_WITH_CMAKE TRUE)
+set(CMAKE_CONFIGURE_PATH "c:/Program\\ Files/CMake/bin/cmake.exe")
+set(PROCESSORS 8)
+set(HOST dash3win7)
+set(RUN_LAUNCHER ~/rel/run)
+set(CPACK_BINARY_GENERATORS "WIX ZIP")
+set(CPACK_SOURCE_GENERATORS "ZIP")
+set(MAKE_PROGRAM "ninja")
+set(MAKE "${MAKE_PROGRAM} -j8")
+set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
+CMAKE_DOC_DIR:STRING=doc/cmake
+CMAKE_USE_OPENSSL:BOOL=OFF
+CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
+CMAKE_Fortran_COMPILER:FILEPATH=FALSE
+CMAKE_GENERATOR:INTERNAL=Ninja
+BUILD_QtDialog:BOOL:=TRUE
+CMake_ENABLE_SERVER_MODE:BOOL=TRUE
+CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
+CMAKE_EXE_LINKER_FLAGS:STRING=-machine:x86 -subsystem:console,5.01
+")
+set(ppflags "-D_WIN32_WINNT=0x501 -DNTDDI_VERSION=0x05010000 -D_USING_V110_SDK71_")
+set(CFLAGS "${ppflags}")
+set(CXXFLAGS "${ppflags}")
+set(ENV ". ~/rel/env")
+get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(GIT_EXTRA "git config core.autocrlf true")
+if(CMAKE_CREATE_VERSION STREQUAL "nightly")
+ # Some tests fail spuriously too often.
+ set(EXTRA_CTEST_ARGS "-E 'Qt5Autogen|ConsoleBuf'")
+endif()
+include(${path}/release_cmake.cmake)
diff --git a/Utilities/Release/win64_release.cmake b/Utilities/Release/win64_release.cmake
new file mode 100644
index 000000000..ab52d794d
--- /dev/null
+++ b/Utilities/Release/win64_release.cmake
@@ -0,0 +1,34 @@
+set(CMAKE_RELEASE_DIRECTORY "c:/msys64/home/dashboard/CMakeReleaseDirectory64")
+set(CONFIGURE_WITH_CMAKE TRUE)
+set(CMAKE_CONFIGURE_PATH "c:/Program\\ Files/CMake/bin/cmake.exe")
+set(PROCESSORS 8)
+set(HOST dash3win7)
+set(SCRIPT_NAME dash3win7x64)
+set(RUN_LAUNCHER ~/rel/run)
+set(CPACK_BINARY_GENERATORS "WIX ZIP")
+set(CPACK_SOURCE_GENERATORS "")
+set(MAKE_PROGRAM "ninja")
+set(MAKE "${MAKE_PROGRAM} -j8")
+set(INITIAL_CACHE "CMAKE_BUILD_TYPE:STRING=Release
+CMAKE_DOC_DIR:STRING=doc/cmake
+CMAKE_USE_OPENSSL:BOOL=OFF
+CMAKE_SKIP_BOOTSTRAP_TEST:STRING=TRUE
+CMAKE_Fortran_COMPILER:FILEPATH=FALSE
+CMAKE_GENERATOR:INTERNAL=Ninja
+BUILD_QtDialog:BOOL:=TRUE
+CMake_ENABLE_SERVER_MODE:BOOL=TRUE
+CMake_GUI_DISTRIBUTE_WITH_Qt_LGPL:STRING=3
+CMake_INSTALL_DEPENDENCIES:BOOL=ON
+CMAKE_EXE_LINKER_FLAGS:STRING=-machine:x64 -subsystem:console,5.02
+")
+set(ppflags "-D_WIN32_WINNT=0x502 -DNTDDI_VERSION=0x05020000 -D_USING_V110_SDK71_")
+set(CFLAGS "${ppflags}")
+set(CXXFLAGS "${ppflags}")
+set(ENV ". ~/rel/env64")
+get_filename_component(path "${CMAKE_CURRENT_LIST_FILE}" PATH)
+set(GIT_EXTRA "git config core.autocrlf true")
+if(CMAKE_CREATE_VERSION STREQUAL "nightly")
+ # Some tests fail spuriously too often.
+ set(EXTRA_CTEST_ARGS "-E 'Qt5Autogen|ConsoleBuf'")
+endif()
+include(${path}/release_cmake.cmake)
diff --git a/Utilities/Scripts/BoostScanDeps.cmake b/Utilities/Scripts/BoostScanDeps.cmake
new file mode 100644
index 000000000..2fd8f8633
--- /dev/null
+++ b/Utilities/Scripts/BoostScanDeps.cmake
@@ -0,0 +1,207 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+# Scan the Boost headers and determine the library dependencies. Note
+# that this script only scans one Boost version at once; invoke once
+# for each Boost release. Note that this does require the headers for
+# a given component to match the library name, since this computes
+# inter-library dependencies. Library components for which this
+# assumption does not hold true and which have dependencies on other
+# Boost libraries will require special-casing. It also doesn't handle
+# private dependencies not described in the headers, for static
+# library dependencies--this is also a limitation of auto-linking, and
+# I'm unaware of any specific instances where this would be
+# problematic.
+#
+# Invoke in script mode, defining these variables:
+# BOOST_DIR - the root of the boost includes
+#
+# The script will process each directory under the root as a
+# "component". For each component, all the headers will be scanned to
+# determine the components it depends upon by following all the
+# possible includes from this component. This is to match the
+# behaviour of autolinking.
+
+# Written by Roger Leigh <rleigh@codelibre.net>
+
+# Determine header dependencies on libraries using the embedded dependency information.
+#
+# component - the component to check (uses all headers from boost/${component})
+# includedir - the path to the Boost headers
+# _ret_libs - list of library dependencies
+#
+function(_Boost_FIND_COMPONENT_DEPENDENCIES component includedir _ret_libs)
+ # _boost_unprocessed_headers - list of headers requiring parsing
+ # _boost_processed_headers - headers already parsed (or currently being parsed)
+ # _boost_new_headers - new headers discovered for future processing
+
+ set(library_component FALSE)
+
+ # Start by finding all headers for the component; header
+ # dependencies via #include will be solved by future passes
+
+ # Special-case since it is part of mpi; look only in boost/mpi/python*
+ if(component STREQUAL "mpi_python")
+ set(_boost_DEPS "python")
+ set(library_component TRUE)
+ file(GLOB_RECURSE _boost_unprocessed_headers
+ RELATIVE "${includedir}"
+ "${includedir}/boost/mpi/python/*")
+ list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/mpi/python.hpp")
+ # Special-case since it is a serialization variant; look in boost/serialization
+ elseif(component STREQUAL "wserialization")
+ set(library_component TRUE)
+ file(GLOB_RECURSE _boost_unprocessed_headers
+ RELATIVE "${includedir}"
+ "${includedir}/boost/serialization/*")
+ list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/serialization.hpp")
+ # Not really a library in its own right, but treat it as one
+ elseif(component STREQUAL "math")
+ set(library_component TRUE)
+ file(GLOB_RECURSE _boost_unprocessed_headers
+ RELATIVE "${includedir}"
+ "${includedir}/boost/math/*")
+ list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/math.hpp")
+ # Single test header
+ elseif(component STREQUAL "unit_test_framework")
+ set(library_component TRUE)
+ set(_boost_unprocessed_headers "${BOOST_DIR}/test/unit_test.hpp")
+ # Single test header
+ elseif(component STREQUAL "prg_exec_monitor")
+ set(library_component TRUE)
+ set(_boost_unprocessed_headers "${BOOST_DIR}/test/prg_exec_monitor.hpp")
+ # Single test header
+ elseif(component STREQUAL "test_exec_monitor")
+ set(library_component TRUE)
+ set(_boost_unprocessed_headers "${BOOST_DIR}/test/test_exec_monitor.hpp")
+ else()
+ # Default behaviour where header directory is the same as the library name.
+ file(GLOB_RECURSE _boost_unprocessed_headers
+ RELATIVE "${includedir}"
+ "${includedir}/boost/${component}/*")
+ list(INSERT _boost_unprocessed_headers 0 "${includedir}/boost/${component}.hpp")
+ endif()
+
+ while(_boost_unprocessed_headers)
+ list(APPEND _boost_processed_headers ${_boost_unprocessed_headers})
+ foreach(header ${_boost_unprocessed_headers})
+ if(EXISTS "${includedir}/${header}")
+ file(STRINGS "${includedir}/${header}" _boost_header_includes REGEX "^#[ \t]*include[ \t]*<boost/[^>][^>]*>")
+ # The optional whitespace before "#" is intentional
+ # (boost/serialization/config.hpp bug).
+ file(STRINGS "${includedir}/${header}" _boost_header_deps REGEX "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_")
+
+ foreach(line ${_boost_header_includes})
+ string(REGEX REPLACE "^#[ \t]*include[ \t]*<(boost/[^>][^>]*)>.*" "\\1" _boost_header_match "${line}")
+ list(FIND _boost_processed_headers "${_boost_header_match}" _boost_header_processed)
+ list(FIND _boost_new_headers "${_boost_header_match}" _boost_header_new)
+ if (_boost_header_processed EQUAL -1 AND _boost_header_new EQUAL -1)
+ list(APPEND _boost_new_headers ${_boost_header_match})
+ endif()
+ endforeach()
+
+ foreach(line ${_boost_header_deps})
+ string(REGEX REPLACE "^[ \t]*#[ \t]*define[ \t][ \t]*BOOST_LIB_NAME[ \t][ \t]*boost_([^ \t][^ \t]*).*" "\\1" _boost_component_match "${line}")
+ list(FIND _boost_DEPS "${_boost_component_match}" _boost_dep_found)
+ if(_boost_component_match STREQUAL "bzip2" OR
+ _boost_component_match STREQUAL "zlib")
+ # These components may or may not be required; not
+ # possible to tell without knowing where and when
+ # BOOST_BZIP2_BINARY and BOOST_ZLIB_BINARY are defined.
+ # If building against an external zlib or bzip2, this is
+ # undesirable.
+ continue()
+ endif()
+ if(component STREQUAL "mpi" AND
+ (_boost_component_match STREQUAL "mpi_python" OR
+ _boost_component_match STREQUAL "python"))
+ # Optional python dependency; skip to avoid making it a
+ # hard dependency (handle as special-case for mpi_python).
+ continue()
+ endif()
+ if (_boost_dep_found EQUAL -1 AND
+ NOT "${_boost_component_match}" STREQUAL "${component}")
+ list(APPEND _boost_DEPS "${_boost_component_match}")
+ endif()
+ if("${_boost_component_match}" STREQUAL "${component}")
+ set(library_component TRUE)
+ endif()
+ endforeach()
+ endif()
+ endforeach()
+ set(_boost_unprocessed_headers ${_boost_new_headers})
+ unset(_boost_new_headers)
+ endwhile()
+
+ # message(STATUS "Unfiltered dependencies for Boost::${component}: ${_boost_DEPS}")
+
+ if(NOT library_component)
+ unset(_boost_DEPS)
+ endif()
+ set(${_ret_libs} ${_boost_DEPS} PARENT_SCOPE)
+
+ #string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_boost_DEPS}")
+ #if (NOT _boost_DEPS_STRING)
+ # set(_boost_DEPS_STRING "(none)")
+ #endif()
+ #message(STATUS "Dependencies for Boost::${component}: ${_boost_DEPS_STRING}")
+endfunction()
+
+
+message(STATUS "Scanning ${BOOST_DIR}")
+
+# List of all directories and files
+file(GLOB boost_contents RELATIVE "${BOOST_DIR}/boost" "${BOOST_DIR}/boost/*")
+
+# Components as directories
+foreach(component ${boost_contents})
+ if(IS_DIRECTORY "${BOOST_DIR}/boost/${component}")
+ list(APPEND boost_components "${component}")
+ endif()
+endforeach()
+
+# The following components are not top-level directories, so require
+# special-casing:
+
+# Special-case mpi_python, since it's a part of mpi
+if(IS_DIRECTORY "${BOOST_DIR}/boost/mpi" AND
+ IS_DIRECTORY "${BOOST_DIR}/boost/python")
+ list(APPEND boost_components "mpi_python")
+endif()
+# Special-case wserialization, which is a variant of serialization
+if(IS_DIRECTORY "${BOOST_DIR}/boost/serialization")
+ list(APPEND boost_components "wserialization")
+endif()
+# Special-case math* since there are six libraries, but no actual math
+# library component. Handle specially when scanning above.
+#
+# Special-case separate test libraries, which are all part of test
+if(EXISTS "${BOOST_DIR}/test/unit_test.hpp")
+ list(APPEND boost_components "unit_test_framework")
+endif()
+if(EXISTS "${BOOST_DIR}/test/prg_exec_monitor.hpp")
+ list(APPEND boost_components "prg_exec_monitor")
+endif()
+if(EXISTS "${BOOST_DIR}/test/test_exec_monitor.hpp")
+ list(APPEND boost_components "test_exec_monitor")
+endif()
+
+if(boost_components)
+ list(SORT boost_components)
+endif()
+
+# Process each component defined above
+foreach(component ${boost_components})
+ string(TOUPPER ${component} UPPERCOMPONENT)
+ _Boost_FIND_COMPONENT_DEPENDENCIES("${component}" "${BOOST_DIR}"
+ _Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
+endforeach()
+
+# Output results
+foreach(component ${boost_components})
+ string(TOUPPER ${component} UPPERCOMPONENT)
+ if(_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES)
+ string(REGEX REPLACE ";" " " _boost_DEPS_STRING "${_Boost_${UPPERCOMPONENT}_LIBRARY_DEPENDENCIES}")
+ message(STATUS "set(_Boost_${UPPERCOMPONENT}_DEPENDENCIES ${_boost_DEPS_STRING})")
+ endif()
+endforeach()
diff --git a/Utilities/Scripts/clang-format.bash b/Utilities/Scripts/clang-format.bash
new file mode 100755
index 000000000..edcda77b9
--- /dev/null
+++ b/Utilities/Scripts/clang-format.bash
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+#=============================================================================
+# Copyright 2015-2017 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+usage='usage: clang-format.bash [<options>] [--]
+
+ --help Print usage plus more detailed help.
+
+ --clang-format <tool> Use given clang-format tool.
+
+ --amend Filter files changed by HEAD.
+ --cached Filter files locally staged for commit.
+ --modified Filter files locally modified from HEAD.
+ --tracked Filter files tracked by Git.
+'
+
+help="$usage"'
+Example to format locally modified files:
+
+ Utilities/Scripts/clang-format.bash --modified
+
+Example to format locally modified files staged for commit:
+
+ Utilities/Scripts/clang-format.bash --cached
+
+Example to format files modified by the most recent commit:
+
+ Utilities/Scripts/clang-format.bash --amend
+
+Example to format all files:
+
+ Utilities/Scripts/clang-format.bash --tracked
+
+Example to format the current topic:
+
+ git filter-branch \
+ --tree-filter "Utilities/Scripts/clang-format.bash --tracked" \
+ master..
+'
+
+die() {
+ echo "$@" 1>&2; exit 1
+}
+
+#-----------------------------------------------------------------------------
+
+# Parse command-line arguments.
+clang_format=''
+mode=''
+while test "$#" != 0; do
+ case "$1" in
+ --amend) mode="amend" ;;
+ --cached) mode="cached" ;;
+ --clang-format) shift; clang_format="$1" ;;
+ --help) echo "$help"; exit 0 ;;
+ --modified) mode="modified" ;;
+ --tracked) mode="tracked" ;;
+ --) shift ; break ;;
+ -*) die "$usage" ;;
+ *) break ;;
+ esac
+ shift
+done
+test "$#" = 0 || die "$usage"
+
+# Find a default tool.
+tools='
+ clang-format
+ clang-format-3.8
+'
+if test "x$clang_format" = "x"; then
+ for tool in $tools; do
+ if type -p "$tool" >/dev/null; then
+ clang_format="$tool"
+ break
+ fi
+ done
+fi
+
+# Verify that we have a tool.
+if ! type -p "$clang_format" >/dev/null; then
+ echo "Unable to locate '$clang_format'"
+ exit 1
+fi
+
+# Select listing mode.
+case "$mode" in
+ '') echo "$usage"; exit 0 ;;
+ amend) git_ls='git diff-tree --diff-filter=AM --name-only HEAD -r --no-commit-id' ;;
+ cached) git_ls='git diff-index --diff-filter=AM --name-only HEAD --cached' ;;
+ modified) git_ls='git diff-index --diff-filter=AM --name-only HEAD' ;;
+ tracked) git_ls='git ls-files' ;;
+ *) die "invalid mode: $mode" ;;
+esac
+
+# List files as selected above.
+$git_ls |
+
+ # Select sources with our attribute.
+ git check-attr --stdin format.clang-format |
+ sed -n '/: format\.clang-format: set$/ {s/:[^:]*:[^:]*$//p}' |
+
+ # Update sources in-place.
+ xargs -d '\n' "$clang_format" -i
diff --git a/Utilities/Scripts/update-curl.bash b/Utilities/Scripts/update-curl.bash
new file mode 100755
index 000000000..465841a02
--- /dev/null
+++ b/Utilities/Scripts/update-curl.bash
@@ -0,0 +1,39 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="curl"
+readonly ownership="Curl Upstream <curl-library@cool.haxx.se>"
+readonly subtree="Utilities/cmcurl"
+readonly repo="https://github.com/curl/curl.git"
+readonly tag="curl-7_54_1"
+readonly shortlog=false
+readonly paths="
+ CMake/*
+ CMakeLists.txt
+ COPYING
+ include/curl/*.h
+ include/curl/curlbuild.h.cmake
+ lib/*.c
+ lib/*.h
+ lib/CMakeLists.txt
+ lib/Makefile.inc
+ lib/curl_config.h.cmake
+ lib/libcurl.rc
+ lib/vauth/*.c
+ lib/vauth/*.h
+ lib/vtls/*.c
+ lib/vtls/*.h
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ rm lib/config-*.h
+ echo "* -whitespace" > .gitattributes
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-expat.bash b/Utilities/Scripts/update-expat.bash
new file mode 100755
index 000000000..4ac5ef32c
--- /dev/null
+++ b/Utilities/Scripts/update-expat.bash
@@ -0,0 +1,50 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="expat"
+readonly ownership="Expat Upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmexpat"
+readonly repo="https://github.com/libexpat/libexpat.git"
+readonly tag="R_2_2_3"
+readonly shortlog=false
+readonly paths="
+ expat/lib/asciitab.h
+ expat/lib/expat.h
+ expat/lib/xmltok.h
+ expat/lib/internal.h
+ expat/lib/xmlrole.h
+ expat/lib/iasciitab.h
+ expat/lib/latin1tab.h
+ expat/lib/loadlibrary.c
+ expat/lib/xmlrole.c
+ expat/lib/utf8tab.h
+ expat/lib/nametab.h
+ expat/lib/ascii.h
+ expat/lib/siphash.h
+ expat/lib/xmltok_impl.h
+ expat/lib/xmltok_ns.c
+ expat/lib/winconfig.h
+ expat/lib/expat_external.h
+ expat/lib/xmltok.c
+ expat/lib/xmlparse.c
+ expat/lib/xmltok_impl.c
+ expat/README.md
+ expat/ConfigureChecks.cmake
+ expat/expat_config.h.cmake
+ expat/COPYING
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ fromdos expat/ConfigureChecks.cmake expat/CMakeLists.txt expat/expat_config.h.cmake
+ chmod a-x expat/ConfigureChecks.cmake expat/CMakeLists.txt expat/expat_config.h.cmake
+ mv expat/* .
+ rmdir expat
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-gitsetup.bash b/Utilities/Scripts/update-gitsetup.bash
new file mode 100755
index 000000000..8f0da7682
--- /dev/null
+++ b/Utilities/Scripts/update-gitsetup.bash
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="GitSetup"
+readonly ownership="GitSetup Upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/GitSetup"
+readonly repo="https://gitlab.kitware.com/utils/gitsetup.git"
+readonly tag="setup"
+readonly shortlog=false
+readonly paths="
+"
+
+extract_source () {
+ git_archive
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-kwiml.bash b/Utilities/Scripts/update-kwiml.bash
new file mode 100755
index 000000000..4497c9201
--- /dev/null
+++ b/Utilities/Scripts/update-kwiml.bash
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="KWIML"
+readonly ownership="KWIML Upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/KWIML"
+readonly repo="https://gitlab.kitware.com/utils/kwiml.git"
+readonly tag="master"
+readonly shortlog=true
+readonly paths="
+"
+
+extract_source () {
+ git_archive
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-kwsys.bash b/Utilities/Scripts/update-kwsys.bash
new file mode 100755
index 000000000..dfbd3666b
--- /dev/null
+++ b/Utilities/Scripts/update-kwsys.bash
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="KWSys"
+readonly ownership="KWSys Upstream <kwrobot@kitware.com>"
+readonly subtree="Source/kwsys"
+readonly repo="https://gitlab.kitware.com/utils/kwsys.git"
+readonly tag="master"
+readonly shortlog=true
+readonly paths="
+"
+
+extract_source () {
+ git_archive
+ sed -i -e '/import off/,/import on/d' "$extractdir/$name-reduced/.gitattributes"
+ sed -i -e 's/project=KWSys/project=PublicDashboard/' "$extractdir/$name-reduced/CTestConfig.cmake"
+}
+
+export HOOKS_ALLOW_KWSYS=1
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-libarchive.bash b/Utilities/Scripts/update-libarchive.bash
new file mode 100755
index 000000000..41c6a66d6
--- /dev/null
+++ b/Utilities/Scripts/update-libarchive.bash
@@ -0,0 +1,31 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="LibArchive"
+readonly ownership="LibArchive Upstream <libarchive-discuss@googlegroups.com>"
+readonly subtree="Utilities/cmlibarchive"
+readonly repo="https://github.com/libarchive/libarchive.git"
+readonly tag="v3.3.1"
+readonly shortlog=false
+readonly paths="
+ CMakeLists.txt
+ COPYING
+ CTestConfig.cmake
+ build/cmake
+ build/pkgconfig
+ build/utils
+ build/version
+ libarchive/*.*
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ fromdos build/cmake/Find*.cmake
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-liblzma.bash b/Utilities/Scripts/update-liblzma.bash
new file mode 100755
index 000000000..088eb91e0
--- /dev/null
+++ b/Utilities/Scripts/update-liblzma.bash
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="liblzma"
+readonly ownership="liblzma upstream <xz-devel@tukaani.org>"
+readonly subtree="Utilities/cmliblzma"
+readonly repo="http://git.tukaani.org/xz.git"
+readonly tag="v5.0.8"
+readonly shortlog=false
+readonly paths="
+ COPYING
+ src/common/common_w32res.rc
+ src/common/sysdefs.h
+ src/common/tuklib_integer.h
+ src/liblzma/
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ mv src/common .
+ mv src/liblzma .
+ rmdir src
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-librhash.bash b/Utilities/Scripts/update-librhash.bash
new file mode 100755
index 000000000..009ce320a
--- /dev/null
+++ b/Utilities/Scripts/update-librhash.bash
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="librhash"
+readonly ownership="librhash upstream <kwrobot@kitware.com>"
+readonly subtree="Utilities/cmlibrhash"
+readonly repo="https://github.com/rhash/rhash.git"
+readonly tag="master"
+readonly shortlog=false
+readonly paths="
+ COPYING
+ README
+ librhash/algorithms.c
+ librhash/algorithms.h
+ librhash/byte_order.c
+ librhash/byte_order.h
+ librhash/hex.c
+ librhash/hex.h
+ librhash/md5.c
+ librhash/md5.h
+ librhash/rhash.c
+ librhash/rhash.h
+ librhash/sha1.c
+ librhash/sha1.h
+ librhash/sha256.c
+ librhash/sha256.h
+ librhash/sha3.c
+ librhash/sha3.h
+ librhash/sha512.c
+ librhash/sha512.h
+ librhash/ustd.h
+ librhash/util.h
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ echo "* -whitespace" > .gitattributes
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-libuv.bash b/Utilities/Scripts/update-libuv.bash
new file mode 100755
index 000000000..d7a7d1f28
--- /dev/null
+++ b/Utilities/Scripts/update-libuv.bash
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="libuv"
+readonly ownership="libuv upstream <libuv@googlegroups.com>"
+readonly subtree="Utilities/cmlibuv"
+readonly repo="https://github.com/libuv/libuv.git"
+readonly tag="v1.x"
+readonly shortlog=false
+readonly paths="
+ LICENSE
+ include
+ src
+"
+
+extract_source () {
+ git_archive
+ pushd "${extractdir}/${name}-reduced"
+ echo "* -whitespace" > .gitattributes
+ popd
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/Scripts/update-third-party.bash b/Utilities/Scripts/update-third-party.bash
new file mode 100644
index 000000000..670946ef4
--- /dev/null
+++ b/Utilities/Scripts/update-third-party.bash
@@ -0,0 +1,177 @@
+#=============================================================================
+# Copyright 2015-2016 Kitware, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#=============================================================================
+
+########################################################################
+# Script for updating third party packages.
+#
+# This script should be sourced in a project-specific script which sets
+# the following variables:
+#
+# name
+# The name of the project.
+# ownership
+# A git author name/email for the commits.
+# subtree
+# The location of the thirdparty package within the main source
+# tree.
+# repo
+# The git repository to use as upstream.
+# tag
+# The tag, branch or commit hash to use for upstream.
+# shortlog
+# Optional. Set to 'true' to get a shortlog in the commit message.
+#
+# Additionally, an "extract_source" function must be defined. It will be
+# run within the checkout of the project on the requested tag. It should
+# should place the desired tree into $extractdir/$name-reduced. This
+# directory will be used as the newest commit for the project.
+#
+# For convenience, the function may use the "git_archive" function which
+# does a standard "git archive" extraction using the (optional) "paths"
+# variable to only extract a subset of the source tree.
+########################################################################
+
+########################################################################
+# Utility functions
+########################################################################
+git_archive () {
+ git archive --worktree-attributes --prefix="$name-reduced/" HEAD -- $paths | \
+ tar -C "$extractdir" -x
+}
+
+disable_custom_gitattributes() {
+ pushd "${extractdir}/${name}-reduced"
+ # Git does not allow custom attributes in a subdirectory where we
+ # are about to merge the `.gitattributes` file, so disable them.
+ sed -i '/^\[attr\]/ {s/^/#/}' .gitattributes
+ popd
+}
+
+die () {
+ echo >&2 "$@"
+ exit 1
+}
+
+warn () {
+ echo >&2 "warning: $@"
+}
+
+readonly regex_date='20[0-9][0-9]-[0-9][0-9]-[0-9][0-9]'
+readonly basehash_regex="$name $regex_date ([0-9a-f]*)"
+readonly basehash="$( git rev-list --author="$ownership" --grep="$basehash_regex" -n 1 HEAD )"
+readonly upstream_old_short="$( git cat-file commit "$basehash" | sed -n '/'"$basehash_regex"'/ {s/.*(//;s/)//;p}' | egrep '^[0-9a-f]+$' )"
+
+########################################################################
+# Sanity checking
+########################################################################
+[ -n "$name" ] || \
+ die "'name' is empty"
+[ -n "$ownership" ] || \
+ die "'ownership' is empty"
+[ -n "$subtree" ] || \
+ die "'subtree' is empty"
+[ -n "$repo" ] || \
+ die "'repo' is empty"
+[ -n "$tag" ] || \
+ die "'tag' is empty"
+[ -n "$basehash" ] || \
+ warn "'basehash' is empty; performing initial import"
+readonly do_shortlog="${shortlog-false}"
+
+readonly workdir="$PWD/work"
+readonly upstreamdir="$workdir/upstream"
+readonly extractdir="$workdir/extract"
+
+[ -d "$workdir" ] && \
+ die "error: workdir '$workdir' already exists"
+
+trap "rm -rf '$workdir'" EXIT
+
+# Get upstream
+git clone "$repo" "$upstreamdir"
+
+if [ -n "$basehash" ]; then
+ # Use the existing package's history
+ git worktree add "$extractdir" "$basehash"
+ # Clear out the working tree
+ pushd "$extractdir"
+ git ls-files | xargs rm -v
+ find . -type d -empty -delete
+ popd
+else
+ # Create a repo to hold this package's history
+ mkdir -p "$extractdir"
+ git -C "$extractdir" init
+fi
+
+# Extract the subset of upstream we care about
+pushd "$upstreamdir"
+git checkout "$tag"
+readonly upstream_hash="$( git rev-parse HEAD )"
+readonly upstream_hash_short="$( git rev-parse --short=8 "$upstream_hash" )"
+readonly upstream_datetime="$( git rev-list "$upstream_hash" --format='%ci' -n 1 | grep -e "^$regex_date" )"
+readonly upstream_date="$( echo "$upstream_datetime" | grep -o -e "$regex_date" )"
+if $do_shortlog && [ -n "$basehash" ]; then
+ readonly commit_shortlog="
+
+Upstream Shortlog
+-----------------
+
+$( git shortlog --no-merges --abbrev=8 --format='%h %s' "$upstream_old_short".."$upstream_hash" )"
+else
+ readonly commit_shortlog=""
+fi
+extract_source || \
+ die "failed to extract source"
+popd
+
+[ -d "$extractdir/$name-reduced" ] || \
+ die "expected directory to extract does not exist"
+readonly commit_summary="$name $upstream_date ($upstream_hash_short)"
+
+# Commit the subset
+pushd "$extractdir"
+mv -v "$name-reduced/"* .
+rmdir "$name-reduced/"
+git add -A .
+git commit -n --author="$ownership" --date="$upstream_datetime" -F - <<-EOF
+$commit_summary
+
+Code extracted from:
+
+ $repo
+
+at commit $upstream_hash ($tag).$commit_shortlog
+EOF
+git branch -f "upstream-$name"
+popd
+
+# Merge the subset into this repository
+if [ -n "$basehash" ]; then
+ git merge --log -s recursive "-Xsubtree=$subtree/" --no-commit "upstream-$name"
+else
+ unrelated_histories_flag=""
+ if git merge --help | grep -q -e allow-unrelated-histories; then
+ unrelated_histories_flag="--allow-unrelated-histories "
+ fi
+ readonly unrelated_histories_flag
+
+ git fetch "$extractdir" "upstream-$name:upstream-$name"
+ git merge --log -s ours --no-commit $unrelated_histories_flag "upstream-$name"
+ git read-tree -u --prefix="$subtree/" "upstream-$name"
+fi
+git commit --no-edit
+git branch -d "upstream-$name"
diff --git a/Utilities/Scripts/update-vim-syntax.bash b/Utilities/Scripts/update-vim-syntax.bash
new file mode 100755
index 000000000..bb1468399
--- /dev/null
+++ b/Utilities/Scripts/update-vim-syntax.bash
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+
+set -e
+set -x
+shopt -s dotglob
+
+readonly name="vim-cmake-syntax"
+readonly ownership="vim-cmake-syntax upstream <kwrobot@kitware.com>"
+readonly subtree="Auxiliary/vim"
+readonly repo="https://github.com/pboettch/vim-cmake-syntax.git"
+readonly tag="master"
+readonly shortlog=true
+readonly paths="
+ indent
+ syntax
+ cmake.vim.in
+ extract-upper-case.pl
+"
+
+extract_source () {
+ git_archive
+}
+
+. "${BASH_SOURCE%/*}/update-third-party.bash"
diff --git a/Utilities/SetupForDevelopment.sh b/Utilities/SetupForDevelopment.sh
index 0a9df7e83..ff64a8402 100755
--- a/Utilities/SetupForDevelopment.sh
+++ b/Utilities/SetupForDevelopment.sh
@@ -3,11 +3,12 @@
cd "${BASH_SOURCE%/*}/.." &&
Utilities/GitSetup/setup-user && echo &&
Utilities/GitSetup/setup-hooks && echo &&
-Utilities/GitSetup/setup-stage && echo &&
-(Utilities/GitSetup/setup-ssh ||
- echo 'Failed to setup SSH. Run this again to retry.') && echo &&
Utilities/GitSetup/tips
# Rebase master by default
git config rebase.stat true
git config branch.master.rebase true
+
+# Record the version of this setup so Git/pre-commit can check it.
+SetupForDevelopment_VERSION=2
+git config hooks.SetupForDevelopment ${SetupForDevelopment_VERSION}
diff --git a/Utilities/Sphinx/.gitignore b/Utilities/Sphinx/.gitignore
new file mode 100644
index 000000000..0d20b6487
--- /dev/null
+++ b/Utilities/Sphinx/.gitignore
@@ -0,0 +1 @@
+*.pyc
diff --git a/Utilities/Sphinx/CMakeLists.txt b/Utilities/Sphinx/CMakeLists.txt
new file mode 100644
index 000000000..a29380c95
--- /dev/null
+++ b/Utilities/Sphinx/CMakeLists.txt
@@ -0,0 +1,195 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+if(NOT CMake_SOURCE_DIR)
+ set(CMakeHelp_STANDALONE 1)
+ cmake_minimum_required(VERSION 2.8.12.2 FATAL_ERROR)
+ get_filename_component(tmp "${CMAKE_CURRENT_SOURCE_DIR}" PATH)
+ get_filename_component(CMake_SOURCE_DIR "${tmp}" PATH)
+ include(${CMake_SOURCE_DIR}/Modules/CTestUseLaunchers.cmake)
+ include(${CMake_SOURCE_DIR}/Source/CMakeVersionCompute.cmake)
+ include(${CMake_SOURCE_DIR}/Source/CMakeInstallDestinations.cmake)
+ unset(CMAKE_DATA_DIR)
+ unset(CMAKE_DATA_DIR CACHE)
+ macro(CMake_OPTIONAL_COMPONENT)
+ set(COMPONENT "")
+ endmacro()
+endif()
+project(CMakeHelp NONE)
+
+option(SPHINX_MAN "Build man pages with Sphinx" OFF)
+option(SPHINX_HTML "Build html help with Sphinx" OFF)
+option(SPHINX_SINGLEHTML "Build html single page help with Sphinx" OFF)
+option(SPHINX_QTHELP "Build Qt help with Sphinx" OFF)
+option(SPHINX_TEXT "Build text help with Sphinx (not installed)" OFF)
+find_program(SPHINX_EXECUTABLE
+ NAMES sphinx-build
+ DOC "Sphinx Documentation Builder (sphinx-doc.org)"
+ )
+set(SPHINX_FLAGS "" CACHE STRING "Flags to pass to sphinx-build")
+separate_arguments(sphinx_flags UNIX_COMMAND "${SPHINX_FLAGS}")
+
+mark_as_advanced(SPHINX_TEXT)
+mark_as_advanced(SPHINX_FLAGS)
+
+if(NOT SPHINX_MAN AND NOT SPHINX_HTML AND NOT SPHINX_SINGLEHTML AND NOT SPHINX_QTHELP AND NOT SPHINX_TEXT)
+ return()
+elseif(NOT SPHINX_EXECUTABLE)
+ message(FATAL_ERROR "SPHINX_EXECUTABLE (sphinx-build) is not found!")
+endif()
+
+set(copyright_line_regex "^Copyright (2000-20[0-9][0-9] Kitware.*)")
+file(STRINGS "${CMake_SOURCE_DIR}/Copyright.txt" copyright_line
+ LIMIT_COUNT 1 REGEX "${copyright_line_regex}")
+if(copyright_line MATCHES "${copyright_line_regex}")
+ set(conf_copyright "${CMAKE_MATCH_1}")
+else()
+ set(conf_copyright "Kitware, Inc.")
+endif()
+
+set(conf_docs "${CMake_SOURCE_DIR}/Help")
+set(conf_path "${CMAKE_CURRENT_SOURCE_DIR}")
+set(conf_version "${CMake_VERSION_MAJOR}.${CMake_VERSION_MINOR}.${CMake_VERSION_PATCH}")
+set(conf_release "${CMake_VERSION}")
+configure_file(conf.py.in conf.py @ONLY)
+
+set(doc_formats "")
+if(SPHINX_HTML)
+ list(APPEND doc_formats html)
+endif()
+if(SPHINX_MAN)
+ list(APPEND doc_formats man)
+endif()
+if(SPHINX_SINGLEHTML)
+ list(APPEND doc_formats singlehtml)
+endif()
+if(SPHINX_TEXT)
+ list(APPEND doc_formats text)
+endif()
+if(SPHINX_QTHELP)
+ find_package(PythonInterp REQUIRED)
+
+ find_program(QCOLLECTIONGENERATOR_EXECUTABLE
+ NAMES qcollectiongenerator
+ DOC "qcollectiongenerator tool"
+ )
+ if (NOT QCOLLECTIONGENERATOR_EXECUTABLE)
+ message(FATAL_ERROR "QCOLLECTIONGENERATOR_EXECUTABLE (qcollectiongenerator) not found!")
+ endif()
+ list(APPEND doc_formats qthelp)
+
+ set(qthelp_extra_commands
+ # Workaround for assistant prior to
+ # https://codereview.qt-project.org/#change,82250 in Qt 4.
+ COMMAND ${CMAKE_COMMAND} "-DCSS_DIR=${CMAKE_CURRENT_BINARY_DIR}/qthelp/_static"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/apply_qthelp_css_workaround.cmake"
+ # Workaround sphinx configurability:
+ # https://bitbucket.org/birkenfeld/sphinx/issue/1448/make-qthelp-more-configurable
+ COMMAND ${CMAKE_COMMAND} "-DQTHELP_DIR=${CMAKE_CURRENT_BINARY_DIR}/qthelp/"
+ "-DCMake_VERSION=${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}"
+ -P "${CMAKE_CURRENT_SOURCE_DIR}/fixup_qthelp_names.cmake"
+
+ # Create proper identifiers. Workaround for
+ # https://bitbucket.org/birkenfeld/sphinx/issue/1491/qthelp-should-generate-identifiers-for
+ COMMAND "${PYTHON_EXECUTABLE}"
+ "${CMAKE_CURRENT_SOURCE_DIR}/create_identifiers.py"
+ "${CMAKE_CURRENT_BINARY_DIR}/qthelp/"
+
+ COMMAND ${QCOLLECTIONGENERATOR_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake.qhcp
+ )
+endif()
+
+
+set(doc_format_outputs "")
+set(doc_format_last "")
+foreach(format ${doc_formats})
+ set(doc_format_output "doc_format_${format}")
+ set(doc_format_log "build-${format}.log")
+ add_custom_command(
+ OUTPUT ${doc_format_output}
+ COMMAND ${SPHINX_EXECUTABLE}
+ -c ${CMAKE_CURRENT_BINARY_DIR}
+ -d ${CMAKE_CURRENT_BINARY_DIR}/doctrees
+ -b ${format}
+ ${sphinx_flags}
+ ${CMake_SOURCE_DIR}/Help
+ ${CMAKE_CURRENT_BINARY_DIR}/${format}
+ > ${doc_format_log} # log stdout, pass stderr
+ ${${format}_extra_commands}
+ DEPENDS ${doc_format_last}
+ COMMENT "sphinx-build ${format}: see Utilities/Sphinx/${doc_format_log}"
+ VERBATIM
+ )
+ set_property(SOURCE ${doc_format_output} PROPERTY SYMBOLIC 1)
+ list(APPEND doc_format_outputs ${doc_format_output})
+ set(doc_format_last ${doc_format_output})
+endforeach()
+
+add_custom_target(documentation ALL DEPENDS ${doc_format_outputs})
+
+if(CMake_SPHINX_DEPEND_ON_EXECUTABLES)
+ foreach(t
+ cmake
+ ccmake
+ cmake-gui
+ cpack
+ ctest
+ )
+ if(TARGET ${t})
+ # Build documentation after main executables.
+ add_dependencies(documentation ${t})
+ endif()
+ endforeach()
+endif()
+
+if(SPHINX_MAN)
+ file(GLOB man_rst RELATIVE ${CMake_SOURCE_DIR}/Help/manual
+ ${CMake_SOURCE_DIR}/Help/manual/*.[1-9].rst)
+ foreach(m ${man_rst})
+ if("x${m}" MATCHES "^x(.+)\\.([1-9])\\.rst$")
+ set(name "${CMAKE_MATCH_1}")
+ set(sec "${CMAKE_MATCH_2}")
+ set(skip FALSE)
+ if(NOT CMakeHelp_STANDALONE)
+ if(name STREQUAL "ccmake" AND NOT BUILD_CursesDialog)
+ set(skip TRUE)
+ elseif(name STREQUAL "cmake-gui" AND NOT BUILD_QtDialog)
+ set(skip TRUE)
+ endif()
+ endif()
+ if(NOT skip)
+ CMake_OPTIONAL_COMPONENT(sphinx-man)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/man/${name}.${sec}
+ DESTINATION ${CMAKE_MAN_DIR}/man${sec}
+ ${COMPONENT})
+ endif()
+ unset(skip)
+ endif()
+ endforeach()
+endif()
+
+if(SPHINX_HTML)
+ CMake_OPTIONAL_COMPONENT(sphinx-html)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/html
+ DESTINATION ${CMAKE_DOC_DIR}
+ ${COMPONENT}
+ PATTERN .buildinfo EXCLUDE
+ )
+endif()
+
+if(SPHINX_SINGLEHTML)
+ CMake_OPTIONAL_COMPONENT(sphinx-singlehtml)
+ install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/singlehtml
+ DESTINATION ${CMAKE_DOC_DIR}
+ ${COMPONENT}
+ PATTERN .buildinfo EXCLUDE
+ )
+endif()
+
+if(SPHINX_QTHELP)
+ CMake_OPTIONAL_COMPONENT(sphinx-qthelp)
+ install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qthelp/CMake-${CMake_VERSION_MAJOR}${CMake_VERSION_MINOR}${CMake_VERSION_PATCH}.qch
+ DESTINATION ${CMAKE_DOC_DIR} ${COMPONENT}
+ )
+endif()
diff --git a/Utilities/Sphinx/apply_qthelp_css_workaround.cmake b/Utilities/Sphinx/apply_qthelp_css_workaround.cmake
new file mode 100644
index 000000000..288f370ea
--- /dev/null
+++ b/Utilities/Sphinx/apply_qthelp_css_workaround.cmake
@@ -0,0 +1,19 @@
+
+file(READ "${CSS_DIR}/basic.css" BasicCssContent)
+
+if(EXISTS "${CSS_DIR}/default.css")
+ file(READ "${CSS_DIR}/default.css" DefaultCssContent)
+ string(REPLACE
+ "@import url(\"basic.css\")" "${BasicCssContent}"
+ DefaultCssContent "${DefaultCssContent}"
+ )
+else()
+ set(DefaultCssContent "${BasicCssContent}")
+endif()
+
+file(READ "${CSS_DIR}/cmake.css" CMakeCssContent)
+string(REPLACE
+ "@import url(\"default.css\")" "${DefaultCssContent}"
+ CMakeCssContent "${CMakeCssContent}"
+)
+file(WRITE "${CSS_DIR}/cmake.css" "${CMakeCssContent}")
diff --git a/Utilities/Sphinx/cmake.py b/Utilities/Sphinx/cmake.py
new file mode 100644
index 000000000..cfda2d479
--- /dev/null
+++ b/Utilities/Sphinx/cmake.py
@@ -0,0 +1,401 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+import os
+import re
+
+# Monkey patch for pygments reporting an error when generator expressions are
+# used.
+# https://bitbucket.org/birkenfeld/pygments-main/issue/942/cmake-generator-expressions-not-handled
+from pygments.lexers import CMakeLexer
+from pygments.token import Name, Operator
+from pygments.lexer import bygroups
+CMakeLexer.tokens["args"].append(('(\\$<)(.+?)(>)',
+ bygroups(Operator, Name.Variable, Operator)))
+
+# Monkey patch for sphinx generating invalid content for qcollectiongenerator
+# https://bitbucket.org/birkenfeld/sphinx/issue/1435/qthelp-builder-should-htmlescape-keywords
+from sphinx.util.pycompat import htmlescape
+from sphinx.builders.qthelp import QtHelpBuilder
+old_build_keywords = QtHelpBuilder.build_keywords
+def new_build_keywords(self, title, refs, subitems):
+ old_items = old_build_keywords(self, title, refs, subitems)
+ new_items = []
+ for item in old_items:
+ before, rest = item.split("ref=\"", 1)
+ ref, after = rest.split("\"")
+ if ("<" in ref and ">" in ref):
+ new_items.append(before + "ref=\"" + htmlescape(ref) + "\"" + after)
+ else:
+ new_items.append(item)
+ return new_items
+QtHelpBuilder.build_keywords = new_build_keywords
+
+
+from docutils.parsers.rst import Directive, directives
+from docutils.transforms import Transform
+try:
+ from docutils.utils.error_reporting import SafeString, ErrorString
+except ImportError:
+ # error_reporting was not in utils before version 0.11:
+ from docutils.error_reporting import SafeString, ErrorString
+
+from docutils import io, nodes
+
+from sphinx.directives import ObjectDescription
+from sphinx.domains import Domain, ObjType
+from sphinx.roles import XRefRole
+from sphinx.util.nodes import make_refnode
+from sphinx import addnodes
+
+# Needed for checking if Sphinx version is >= 1.4.
+# See https://github.com/sphinx-doc/sphinx/issues/2673
+old_sphinx = False
+
+try:
+ from sphinx import version_info
+ if version_info < (1, 4):
+ old_sphinx = True
+except ImportError:
+ # The `sphinx.version_info` tuple was added in Sphinx v1.2:
+ old_sphinx = True
+
+
+class CMakeModule(Directive):
+ required_arguments = 1
+ optional_arguments = 0
+ final_argument_whitespace = True
+ option_spec = {'encoding': directives.encoding}
+
+ def __init__(self, *args, **keys):
+ self.re_start = re.compile(r'^#\[(?P<eq>=*)\[\.rst:$')
+ Directive.__init__(self, *args, **keys)
+
+ def run(self):
+ settings = self.state.document.settings
+ if not settings.file_insertion_enabled:
+ raise self.warning('"%s" directive disabled.' % self.name)
+
+ env = self.state.document.settings.env
+ rel_path, path = env.relfn2path(self.arguments[0])
+ path = os.path.normpath(path)
+ encoding = self.options.get('encoding', settings.input_encoding)
+ e_handler = settings.input_encoding_error_handler
+ try:
+ settings.record_dependencies.add(path)
+ f = io.FileInput(source_path=path, encoding=encoding,
+ error_handler=e_handler)
+ except UnicodeEncodeError as error:
+ raise self.severe('Problems with "%s" directive path:\n'
+ 'Cannot encode input file path "%s" '
+ '(wrong locale?).' %
+ (self.name, SafeString(path)))
+ except IOError as error:
+ raise self.severe('Problems with "%s" directive path:\n%s.' %
+ (self.name, ErrorString(error)))
+ raw_lines = f.read().splitlines()
+ f.close()
+ rst = None
+ lines = []
+ for line in raw_lines:
+ if rst is not None and rst != '#':
+ # Bracket mode: check for end bracket
+ pos = line.find(rst)
+ if pos >= 0:
+ if line[0] == '#':
+ line = ''
+ else:
+ line = line[0:pos]
+ rst = None
+ else:
+ # Line mode: check for .rst start (bracket or line)
+ m = self.re_start.match(line)
+ if m:
+ rst = ']%s]' % m.group('eq')
+ line = ''
+ elif line == '#.rst:':
+ rst = '#'
+ line = ''
+ elif rst == '#':
+ if line == '#' or line[:2] == '# ':
+ line = line[2:]
+ else:
+ rst = None
+ line = ''
+ elif rst is None:
+ line = ''
+ lines.append(line)
+ if rst is not None and rst != '#':
+ raise self.warning('"%s" found unclosed bracket "#[%s[.rst:" in %s' %
+ (self.name, rst[1:-1], path))
+ self.state_machine.insert_input(lines, path)
+ return []
+
+class _cmake_index_entry:
+ def __init__(self, desc):
+ self.desc = desc
+
+ def __call__(self, title, targetid, main = 'main'):
+ # See https://github.com/sphinx-doc/sphinx/issues/2673
+ if old_sphinx:
+ return ('pair', u'%s ; %s' % (self.desc, title), targetid, main)
+ else:
+ return ('pair', u'%s ; %s' % (self.desc, title), targetid, main, None)
+
+_cmake_index_objs = {
+ 'command': _cmake_index_entry('command'),
+ 'generator': _cmake_index_entry('generator'),
+ 'manual': _cmake_index_entry('manual'),
+ 'module': _cmake_index_entry('module'),
+ 'policy': _cmake_index_entry('policy'),
+ 'prop_cache': _cmake_index_entry('cache property'),
+ 'prop_dir': _cmake_index_entry('directory property'),
+ 'prop_gbl': _cmake_index_entry('global property'),
+ 'prop_inst': _cmake_index_entry('installed file property'),
+ 'prop_sf': _cmake_index_entry('source file property'),
+ 'prop_test': _cmake_index_entry('test property'),
+ 'prop_tgt': _cmake_index_entry('target property'),
+ 'variable': _cmake_index_entry('variable'),
+ }
+
+def _cmake_object_inventory(env, document, line, objtype, targetid):
+ inv = env.domaindata['cmake']['objects']
+ if targetid in inv:
+ document.reporter.warning(
+ 'CMake object "%s" also described in "%s".' %
+ (targetid, env.doc2path(inv[targetid][0])), line=line)
+ inv[targetid] = (env.docname, objtype)
+
+class CMakeTransform(Transform):
+
+ # Run this transform early since we insert nodes we want
+ # treated as if they were written in the documents.
+ default_priority = 210
+
+ def __init__(self, document, startnode):
+ Transform.__init__(self, document, startnode)
+ self.titles = {}
+
+ def parse_title(self, docname):
+ """Parse a document title as the first line starting in [A-Za-z0-9<]
+ or fall back to the document basename if no such line exists.
+ The cmake --help-*-list commands also depend on this convention.
+ Return the title or False if the document file does not exist.
+ """
+ env = self.document.settings.env
+ title = self.titles.get(docname)
+ if title is None:
+ fname = os.path.join(env.srcdir, docname+'.rst')
+ try:
+ f = open(fname, 'r')
+ except IOError:
+ title = False
+ else:
+ for line in f:
+ if len(line) > 0 and (line[0].isalnum() or line[0] == '<'):
+ title = line.rstrip()
+ break
+ f.close()
+ if title is None:
+ title = os.path.basename(docname)
+ self.titles[docname] = title
+ return title
+
+ def apply(self):
+ env = self.document.settings.env
+
+ # Treat some documents as cmake domain objects.
+ objtype, sep, tail = env.docname.rpartition('/')
+ make_index_entry = _cmake_index_objs.get(objtype)
+ if make_index_entry:
+ title = self.parse_title(env.docname)
+ # Insert the object link target.
+ if objtype == 'command':
+ targetname = title.lower()
+ else:
+ targetname = title
+ targetid = '%s:%s' % (objtype, targetname)
+ targetnode = nodes.target('', '', ids=[targetid])
+ self.document.note_explicit_target(targetnode)
+ self.document.insert(0, targetnode)
+ # Insert the object index entry.
+ indexnode = addnodes.index()
+ indexnode['entries'] = [make_index_entry(title, targetid)]
+ self.document.insert(0, indexnode)
+ # Add to cmake domain object inventory
+ _cmake_object_inventory(env, self.document, 1, objtype, targetid)
+
+class CMakeObject(ObjectDescription):
+
+ def handle_signature(self, sig, signode):
+ # called from sphinx.directives.ObjectDescription.run()
+ signode += addnodes.desc_name(sig, sig)
+ return sig
+
+ def add_target_and_index(self, name, sig, signode):
+ if self.objtype == 'command':
+ targetname = name.lower()
+ else:
+ targetname = name
+ targetid = '%s:%s' % (self.objtype, targetname)
+ if targetid not in self.state.document.ids:
+ signode['names'].append(targetid)
+ signode['ids'].append(targetid)
+ signode['first'] = (not self.names)
+ self.state.document.note_explicit_target(signode)
+ _cmake_object_inventory(self.env, self.state.document,
+ self.lineno, self.objtype, targetid)
+
+ make_index_entry = _cmake_index_objs.get(self.objtype)
+ if make_index_entry:
+ self.indexnode['entries'].append(make_index_entry(name, targetid))
+
+class CMakeXRefRole(XRefRole):
+
+ # See sphinx.util.nodes.explicit_title_re; \x00 escapes '<'.
+ _re = re.compile(r'^(.+?)(\s*)(?<!\x00)<(.*?)>$', re.DOTALL)
+ _re_sub = re.compile(r'^([^()\s]+)\s*\(([^()]*)\)$', re.DOTALL)
+
+ def __call__(self, typ, rawtext, text, *args, **keys):
+ # Translate CMake command cross-references of the form:
+ # `command_name(SUB_COMMAND)`
+ # to have an explicit target:
+ # `command_name(SUB_COMMAND) <command_name>`
+ if typ == 'cmake:command':
+ m = CMakeXRefRole._re_sub.match(text)
+ if m:
+ text = '%s <%s>' % (text, m.group(1))
+ # CMake cross-reference targets frequently contain '<' so escape
+ # any explicit `<target>` with '<' not preceded by whitespace.
+ while True:
+ m = CMakeXRefRole._re.match(text)
+ if m and len(m.group(2)) == 0:
+ text = '%s\x00<%s>' % (m.group(1), m.group(3))
+ else:
+ break
+ return XRefRole.__call__(self, typ, rawtext, text, *args, **keys)
+
+ # We cannot insert index nodes using the result_nodes method
+ # because CMakeXRefRole is processed before substitution_reference
+ # nodes are evaluated so target nodes (with 'ids' fields) would be
+ # duplicated in each evaluted substitution replacement. The
+ # docutils substitution transform does not allow this. Instead we
+ # use our own CMakeXRefTransform below to add index entries after
+ # substitutions are completed.
+ #
+ # def result_nodes(self, document, env, node, is_ref):
+ # pass
+
+class CMakeXRefTransform(Transform):
+
+ # Run this transform early since we insert nodes we want
+ # treated as if they were written in the documents, but
+ # after the sphinx (210) and docutils (220) substitutions.
+ default_priority = 221
+
+ def apply(self):
+ env = self.document.settings.env
+
+ # Find CMake cross-reference nodes and add index and target
+ # nodes for them.
+ for ref in self.document.traverse(addnodes.pending_xref):
+ if not ref['refdomain'] == 'cmake':
+ continue
+
+ objtype = ref['reftype']
+ make_index_entry = _cmake_index_objs.get(objtype)
+ if not make_index_entry:
+ continue
+
+ objname = ref['reftarget']
+ targetnum = env.new_serialno('index-%s:%s' % (objtype, objname))
+
+ targetid = 'index-%s-%s:%s' % (targetnum, objtype, objname)
+ targetnode = nodes.target('', '', ids=[targetid])
+ self.document.note_explicit_target(targetnode)
+
+ indexnode = addnodes.index()
+ indexnode['entries'] = [make_index_entry(objname, targetid, '')]
+ ref.replace_self([indexnode, targetnode, ref])
+
+class CMakeDomain(Domain):
+ """CMake domain."""
+ name = 'cmake'
+ label = 'CMake'
+ object_types = {
+ 'command': ObjType('command', 'command'),
+ 'generator': ObjType('generator', 'generator'),
+ 'variable': ObjType('variable', 'variable'),
+ 'module': ObjType('module', 'module'),
+ 'policy': ObjType('policy', 'policy'),
+ 'prop_cache': ObjType('prop_cache', 'prop_cache'),
+ 'prop_dir': ObjType('prop_dir', 'prop_dir'),
+ 'prop_gbl': ObjType('prop_gbl', 'prop_gbl'),
+ 'prop_inst': ObjType('prop_inst', 'prop_inst'),
+ 'prop_sf': ObjType('prop_sf', 'prop_sf'),
+ 'prop_test': ObjType('prop_test', 'prop_test'),
+ 'prop_tgt': ObjType('prop_tgt', 'prop_tgt'),
+ 'manual': ObjType('manual', 'manual'),
+ }
+ directives = {
+ 'command': CMakeObject,
+ 'variable': CMakeObject,
+ # Other object types cannot be created except by the CMakeTransform
+ # 'generator': CMakeObject,
+ # 'module': CMakeObject,
+ # 'policy': CMakeObject,
+ # 'prop_cache': CMakeObject,
+ # 'prop_dir': CMakeObject,
+ # 'prop_gbl': CMakeObject,
+ # 'prop_inst': CMakeObject,
+ # 'prop_sf': CMakeObject,
+ # 'prop_test': CMakeObject,
+ # 'prop_tgt': CMakeObject,
+ # 'manual': CMakeObject,
+ }
+ roles = {
+ 'command': CMakeXRefRole(fix_parens = True, lowercase = True),
+ 'generator': CMakeXRefRole(),
+ 'variable': CMakeXRefRole(),
+ 'module': CMakeXRefRole(),
+ 'policy': CMakeXRefRole(),
+ 'prop_cache': CMakeXRefRole(),
+ 'prop_dir': CMakeXRefRole(),
+ 'prop_gbl': CMakeXRefRole(),
+ 'prop_inst': CMakeXRefRole(),
+ 'prop_sf': CMakeXRefRole(),
+ 'prop_test': CMakeXRefRole(),
+ 'prop_tgt': CMakeXRefRole(),
+ 'manual': CMakeXRefRole(),
+ }
+ initial_data = {
+ 'objects': {}, # fullname -> docname, objtype
+ }
+
+ def clear_doc(self, docname):
+ to_clear = set()
+ for fullname, (fn, _) in self.data['objects'].items():
+ if fn == docname:
+ to_clear.add(fullname)
+ for fullname in to_clear:
+ del self.data['objects'][fullname]
+
+ def resolve_xref(self, env, fromdocname, builder,
+ typ, target, node, contnode):
+ targetid = '%s:%s' % (typ, target)
+ obj = self.data['objects'].get(targetid)
+ if obj is None:
+ # TODO: warn somehow?
+ return None
+ return make_refnode(builder, fromdocname, obj[0], targetid,
+ contnode, target)
+
+ def get_objects(self):
+ for refname, (docname, type) in self.data['objects'].items():
+ yield (refname, refname, type, docname, refname, 1)
+
+def setup(app):
+ app.add_directive('cmake-module', CMakeModule)
+ app.add_transform(CMakeTransform)
+ app.add_transform(CMakeXRefTransform)
+ app.add_domain(CMakeDomain)
diff --git a/Utilities/Sphinx/conf.py.in b/Utilities/Sphinx/conf.py.in
new file mode 100644
index 000000000..7878ad20a
--- /dev/null
+++ b/Utilities/Sphinx/conf.py.in
@@ -0,0 +1,83 @@
+# Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+# file Copyright.txt or https://cmake.org/licensing for details.
+
+import sys
+import os
+import re
+import glob
+
+sys.path.insert(0, r'@conf_path@')
+
+source_suffix = '.rst'
+master_doc = 'index'
+
+project = 'CMake'
+copyright = '@conf_copyright@'
+version = '@conf_version@' # feature version
+release = '@conf_release@' # full version string
+
+primary_domain = 'cmake'
+
+exclude_patterns = [
+ 'dev', # ignore developer-only documentation
+ ]
+
+extensions = ['cmake']
+templates_path = ['@conf_path@/templates']
+
+nitpicky = True
+
+cmake_manuals = sorted(glob.glob(r'@conf_docs@/manual/*.rst'))
+cmake_manual_description = re.compile('^\.\. cmake-manual-description:(.*)$')
+man_pages = []
+for fpath in cmake_manuals:
+ try:
+ name, sec, rst = os.path.basename(fpath).split('.')
+ desc = None
+ f = open(fpath, 'r')
+ for l in f:
+ m = cmake_manual_description.match(l)
+ if m:
+ desc = m.group(1).strip()
+ break
+ f.close()
+ if desc:
+ man_pages.append(('manual/%s.%s' % (name, sec),
+ name, desc, [], int(sec)))
+ else:
+ sys.stderr.write("ERROR: No cmake-manual-description in '%s'\n" % fpath)
+ except Exception as e:
+ sys.stderr.write("ERROR: %s\n" % str(e))
+man_show_urls = False
+
+html_show_sourcelink = True
+html_static_path = ['@conf_path@/static']
+html_style = 'cmake.css'
+html_theme = 'default'
+html_theme_options = {
+ 'footerbgcolor': '#00182d',
+ 'footertextcolor': '#ffffff',
+ 'sidebarbgcolor': '#e4ece8',
+ 'sidebarbtncolor': '#00a94f',
+ 'sidebartextcolor': '#333333',
+ 'sidebarlinkcolor': '#00a94f',
+ 'relbarbgcolor': '#00529b',
+ 'relbartextcolor': '#ffffff',
+ 'relbarlinkcolor': '#ffffff',
+ 'bgcolor': '#ffffff',
+ 'textcolor': '#444444',
+ 'headbgcolor': '#f2f2f2',
+ 'headtextcolor': '#003564',
+ 'headlinkcolor': '#3d8ff2',
+ 'linkcolor': '#2b63a8',
+ 'visitedlinkcolor': '#2b63a8',
+ 'codebgcolor': '#eeeeee',
+ 'codetextcolor': '#333333',
+}
+html_title = 'CMake %s Documentation' % release
+html_short_title = '%s Documentation' % release
+html_favicon = '@conf_path@/static/cmake-favicon.ico'
+# Not supported yet by sphinx:
+# https://bitbucket.org/birkenfeld/sphinx/issue/1448/make-qthelp-more-configurable
+# qthelp_namespace = "org.cmake"
+# qthelp_qch_name = "CMake-300.qch"
diff --git a/Utilities/Sphinx/create_identifiers.py b/Utilities/Sphinx/create_identifiers.py
new file mode 100755
index 000000000..3fe3fcbe5
--- /dev/null
+++ b/Utilities/Sphinx/create_identifiers.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+
+import sys, os
+
+if len(sys.argv) != 2:
+ sys.exit(-1)
+name = sys.argv[1] + "/CMake.qhp"
+
+f = open(name)
+
+if not f:
+ sys.exit(-1)
+
+lines = f.read().splitlines()
+
+if not lines:
+ sys.exit(-1)
+
+newlines = []
+
+for line in lines:
+
+ mapping = (("command", "command"),
+ ("variable", "variable"),
+ ("target property", "prop_tgt"),
+ ("test property", "prop_test"),
+ ("source file property", "prop_sf"),
+ ("global property", "prop_gbl"),
+ ("module", "module"),
+ ("directory property", "prop_dir"),
+ ("cache property", "prop_cache"),
+ ("policy", "policy"),
+ ("installed file property", "prop_inst"))
+
+ for domain_object_string, domain_object_type in mapping:
+ if "<keyword name=\"" + domain_object_string + "\"" in line:
+ if not "id=\"" in line and not "#index-" in line:
+ prefix = "<keyword name=\"" + domain_object_string + "\" "
+ part1, part2 = line.split(prefix)
+ head, tail = part2.split("#" + domain_object_type + ":")
+ domain_object, rest = tail.split("\"")
+ line = part1 + prefix + "id=\"" + domain_object_type + "/" + domain_object + "\" " + part2
+ newlines.append(line + "\n")
+
+f = open(name, "w")
+f.writelines(newlines)
diff --git a/Utilities/Sphinx/fixup_qthelp_names.cmake b/Utilities/Sphinx/fixup_qthelp_names.cmake
new file mode 100644
index 000000000..e35ef25be
--- /dev/null
+++ b/Utilities/Sphinx/fixup_qthelp_names.cmake
@@ -0,0 +1,32 @@
+
+file(READ "${QTHELP_DIR}/CMake.qhcp" QHCP_CONTENT)
+
+string(REPLACE
+ "<homePage>qthelp://org.sphinx.cmake" "<homePage>qthelp://org.cmake"
+ QHCP_CONTENT "${QHCP_CONTENT}"
+)
+string(REPLACE
+ "<startPage>qthelp://org.sphinx.cmake" "<startPage>qthelp://org.cmake"
+ QHCP_CONTENT "${QHCP_CONTENT}"
+)
+
+string(REPLACE
+ "<output>CMake.qch" "<output>CMake-${CMake_VERSION}.qch"
+ QHCP_CONTENT "${QHCP_CONTENT}"
+)
+string(REPLACE
+ "<file>CMake.qch" "<file>CMake-${CMake_VERSION}.qch"
+ QHCP_CONTENT "${QHCP_CONTENT}"
+)
+
+file(WRITE "${QTHELP_DIR}/CMake.qhcp" "${QHCP_CONTENT}")
+
+
+file(READ "${QTHELP_DIR}/CMake.qhp" QHP_CONTENT)
+
+string(REPLACE
+ "<namespace>org.sphinx.cmake" "<namespace>org.cmake"
+ QHP_CONTENT "${QHP_CONTENT}"
+)
+
+file(WRITE "${QTHELP_DIR}/CMake.qhp" "${QHP_CONTENT}")
diff --git a/Utilities/Sphinx/static/cmake-favicon.ico b/Utilities/Sphinx/static/cmake-favicon.ico
new file mode 100644
index 000000000..fce8f922f
--- /dev/null
+++ b/Utilities/Sphinx/static/cmake-favicon.ico
Binary files differ
diff --git a/Utilities/Sphinx/static/cmake-logo-16.png b/Utilities/Sphinx/static/cmake-logo-16.png
new file mode 100644
index 000000000..2039c25b0
--- /dev/null
+++ b/Utilities/Sphinx/static/cmake-logo-16.png
Binary files differ
diff --git a/Utilities/Sphinx/static/cmake.css b/Utilities/Sphinx/static/cmake.css
new file mode 100644
index 000000000..2a326d47d
--- /dev/null
+++ b/Utilities/Sphinx/static/cmake.css
@@ -0,0 +1,8 @@
+/* Import the Sphinx theme style. */
+@import url("default.css");
+
+/* Wrap sidebar content even within words so that long
+ document names do not escape sidebar borders. */
+div.sphinxsidebarwrapper {
+ word-wrap: break-word;
+}
diff --git a/Utilities/Sphinx/templates/layout.html b/Utilities/Sphinx/templates/layout.html
new file mode 100644
index 000000000..be2660caa
--- /dev/null
+++ b/Utilities/Sphinx/templates/layout.html
@@ -0,0 +1,31 @@
+{% extends "!layout.html" %}
+{% block rootrellink %}
+ <li>
+ <img src="{{ pathto('_static/cmake-logo-16.png', 1) }}" alt=""
+ style="vertical-align: middle; margin-top: -2px" />
+ </li>
+ <li>
+ <a href="https://cmake.org/">CMake</a>{{ reldelim1 }}
+ </li>
+ <li>
+ {%- if versionswitch is defined %}
+ <span class="version_switch">{{ release }}</span>
+ <a href="{{ pathto(master_doc) }}">{% trans %}Documentation{% endtrans %}</a>{{ reldelim1 }}
+ {%- else %}
+ <a href="{{ pathto(master_doc) }}">{{ shorttitle|e }}</a>{{ reldelim1 }}
+ {%- endif %}
+ </li>
+{% endblock %}
+
+{% block extrahead %}
+ {% if versionswitch is defined %}
+ <script type="text/javascript" src="{{ pathto('../version_switch.js', 1) }}"></script>
+ {% endif %}
+{{ super() }}
+{% endblock %}
+
+{# Put some context in the html title element. Workaround for #}
+{# https://bitbucket.org/birkenfeld/sphinx/issue/1492/qthelp-generate-html-title-element-should #}
+{% block htmltitle %}
+ <title>{{ title|striptags|e }} {{ "&mdash;"|safe }} {{ docstitle|e }}</title>
+{% endblock %}
diff --git a/Utilities/cmThirdParty.h.in b/Utilities/cmThirdParty.h.in
index c8240850e..a547f0da7 100644
--- a/Utilities/cmThirdParty.h.in
+++ b/Utilities/cmThirdParty.h.in
@@ -1,23 +1,20 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cmThirdParty_h
-#define __cmThirdParty_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cmThirdParty_h
+#define cmThirdParty_h
/* Whether CMake is using its own utility libraries. */
#cmakedefine CMAKE_USE_SYSTEM_CURL
#cmakedefine CMAKE_USE_SYSTEM_EXPAT
+#cmakedefine CMAKE_USE_SYSTEM_KWIML
#cmakedefine CMAKE_USE_SYSTEM_ZLIB
#cmakedefine CMAKE_USE_SYSTEM_BZIP2
#cmakedefine CMAKE_USE_SYSTEM_LIBARCHIVE
+#cmakedefine CMAKE_USE_SYSTEM_LIBLZMA
+#cmakedefine CMAKE_USE_SYSTEM_FORM
+#cmakedefine CMAKE_USE_SYSTEM_JSONCPP
+#cmakedefine CMAKE_USE_SYSTEM_LIBRHASH
+#cmakedefine CMAKE_USE_SYSTEM_LIBUV
#cmakedefine CTEST_USE_XMLRPC
#endif
diff --git a/Utilities/cm_bzlib.h b/Utilities/cm_bzlib.h
index d1fffa1aa..e7f6d8990 100644
--- a/Utilities/cm_bzlib.h
+++ b/Utilities/cm_bzlib.h
@@ -1,23 +1,14 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2012 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_bzlib_h
-#define __cm_bzlib_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_bzlib_h
+#define cm_bzlib_h
/* Use the bzip2 library configured for CMake. */
#include "cmThirdParty.h"
#ifdef CMAKE_USE_SYSTEM_BZIP2
-# include <bzlib.h>
+#include <bzlib.h>
#else
-# include <cmbzip2/bzlib.h>
+#include <cmbzip2/bzlib.h>
#endif
#endif
diff --git a/Utilities/cm_curl.h b/Utilities/cm_curl.h
index 43944a3f4..fc2b8ab8a 100644
--- a/Utilities/cm_curl.h
+++ b/Utilities/cm_curl.h
@@ -1,23 +1,14 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_curl_h
-#define __cm_curl_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_curl_h
+#define cm_curl_h
/* Use the curl library configured for CMake. */
#include "cmThirdParty.h"
#ifdef CMAKE_USE_SYSTEM_CURL
-# include <curl/curl.h>
+#include <curl/curl.h>
#else
-# include <cmcurl/curl/curl.h>
+#include <cmcurl/include/curl/curl.h>
#endif
#endif
diff --git a/Utilities/cm_expat.h b/Utilities/cm_expat.h
index 91f4a7b52..d87933715 100644
--- a/Utilities/cm_expat.h
+++ b/Utilities/cm_expat.h
@@ -1,23 +1,14 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_expat_h
-#define __cm_expat_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_expat_h
+#define cm_expat_h
/* Use the expat library configured for CMake. */
#include "cmThirdParty.h"
#ifdef CMAKE_USE_SYSTEM_EXPAT
-# include <expat.h>
+#include <expat.h>
#else
-# include <cmexpat/expat.h>
+#include <cmexpat/lib/expat.h>
#endif
#endif
diff --git a/Utilities/cm_jsoncpp_reader.h b/Utilities/cm_jsoncpp_reader.h
new file mode 100644
index 000000000..e78ec1e0c
--- /dev/null
+++ b/Utilities/cm_jsoncpp_reader.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_jsoncpp_reader_h
+#define cm_jsoncpp_reader_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_JSONCPP
+#include <json/reader.h>
+#else
+#include <cmjsoncpp/include/json/reader.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_jsoncpp_value.h b/Utilities/cm_jsoncpp_value.h
new file mode 100644
index 000000000..cf3775859
--- /dev/null
+++ b/Utilities/cm_jsoncpp_value.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_jsoncpp_value_h
+#define cm_jsoncpp_value_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_JSONCPP
+#include <json/value.h>
+#else
+#include <cmjsoncpp/include/json/value.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_jsoncpp_writer.h b/Utilities/cm_jsoncpp_writer.h
new file mode 100644
index 000000000..33b246847
--- /dev/null
+++ b/Utilities/cm_jsoncpp_writer.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_jsoncpp_writer_h
+#define cm_jsoncpp_writer_h
+
+/* Use the jsoncpp library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_JSONCPP
+#include <json/writer.h>
+#else
+#include <cmjsoncpp/include/json/writer.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_kwiml.h b/Utilities/cm_kwiml.h
new file mode 100644
index 000000000..65cb35f96
--- /dev/null
+++ b/Utilities/cm_kwiml.h
@@ -0,0 +1,16 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_kwiml_h
+#define cm_kwiml_h
+
+/* Use the KWIML library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_KWIML
+#include <kwiml/abi.h>
+#include <kwiml/int.h>
+#else
+#include "KWIML/include/kwiml/abi.h"
+#include "KWIML/include/kwiml/int.h"
+#endif
+
+#endif
diff --git a/Utilities/cm_libarchive.h b/Utilities/cm_libarchive.h
index 1469baeb4..226952601 100644
--- a/Utilities/cm_libarchive.h
+++ b/Utilities/cm_libarchive.h
@@ -1,25 +1,16 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2010 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_libarchive_h
-#define __cm_libarchive_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_libarchive_h
+#define cm_libarchive_h
/* Use the libarchive configured for CMake. */
#include "cmThirdParty.h"
#ifdef CMAKE_USE_SYSTEM_LIBARCHIVE
-# include <archive.h>
-# include <archive_entry.h>
+#include <archive.h>
+#include <archive_entry.h>
#else
-# include <cmlibarchive/libarchive/archive.h>
-# include <cmlibarchive/libarchive/archive_entry.h>
+#include <cmlibarchive/libarchive/archive.h>
+#include <cmlibarchive/libarchive/archive_entry.h>
#endif
#endif
diff --git a/Utilities/cm_lzma.h b/Utilities/cm_lzma.h
new file mode 100644
index 000000000..013c724b9
--- /dev/null
+++ b/Utilities/cm_lzma.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_lzma_h
+#define cm_lzma_h
+
+/* Use the liblzma configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_LIBLZMA
+#include <lzma.h>
+#else
+#include <cmliblzma/liblzma/api/lzma.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_rhash.h b/Utilities/cm_rhash.h
new file mode 100644
index 000000000..c79362775
--- /dev/null
+++ b/Utilities/cm_rhash.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_rhash_h
+#define cm_rhash_h
+
+/* Use the LibRHash library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_LIBRHASH
+#include <rhash.h>
+#else
+#include <cmlibrhash/librhash/rhash.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_uv.h b/Utilities/cm_uv.h
new file mode 100644
index 000000000..6d4813de1
--- /dev/null
+++ b/Utilities/cm_uv.h
@@ -0,0 +1,14 @@
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_uv_h
+#define cm_uv_h
+
+/* Use the libuv library configured for CMake. */
+#include "cmThirdParty.h"
+#ifdef CMAKE_USE_SYSTEM_LIBUV
+#include <uv.h>
+#else
+#include <cmlibuv/include/uv.h>
+#endif
+
+#endif
diff --git a/Utilities/cm_xmlrpc.h b/Utilities/cm_xmlrpc.h
index a6b375da8..08db89f60 100644
--- a/Utilities/cm_xmlrpc.h
+++ b/Utilities/cm_xmlrpc.h
@@ -1,22 +1,13 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_xmlrpc_h
-#define __cm_xmlrpc_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_xmlrpc_h
+#define cm_xmlrpc_h
/* Use the xmlrpc library configured for CMake. */
#include "cmThirdParty.h"
#ifdef CTEST_USE_XMLRPC
-# include <xmlrpc.h>
-# include <xmlrpc_client.h>
+#include <xmlrpc.h>
+#include <xmlrpc_client.h>
#endif
#endif
diff --git a/Utilities/cm_zlib.h b/Utilities/cm_zlib.h
index fb5832e35..2aee9f194 100644
--- a/Utilities/cm_zlib.h
+++ b/Utilities/cm_zlib.h
@@ -1,23 +1,14 @@
-/*============================================================================
- CMake - Cross Platform Makefile Generator
- Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
-
- Distributed under the OSI-approved BSD License (the "License");
- see accompanying file Copyright.txt for details.
-
- This software is distributed WITHOUT ANY WARRANTY; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the License for more information.
-============================================================================*/
-#ifndef __cm_zlib_h
-#define __cm_zlib_h
+/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying
+ file Copyright.txt or https://cmake.org/licensing for details. */
+#ifndef cm_zlib_h
+#define cm_zlib_h
/* Use the zlib library configured for CMake. */
#include "cmThirdParty.h"
#ifdef CMAKE_USE_SYSTEM_ZLIB
-# include <zlib.h>
+#include <zlib.h>
#else
-# include <cmzlib/zlib.h>
+#include <cmzlib/zlib.h>
#endif
#endif
diff --git a/Utilities/cmake.m4 b/Utilities/cmake.m4
deleted file mode 100644
index a374a3bfb..000000000
--- a/Utilities/cmake.m4
+++ /dev/null
@@ -1,53 +0,0 @@
-dnl ============================================================================
-dnl CMake - Cross Platform Makefile Generator
-dnl Copyright 2011 Matthias Kretz, kretz@kde.org
-dnl
-dnl Distributed under the OSI-approved BSD License (the "License");
-dnl see accompanying file Copyright.txt for details.
-dnl
-dnl This software is distributed WITHOUT ANY WARRANTY; without even the
-dnl implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-dnl See the License for more information.
-dnl ============================================================================
-
-AC_DEFUN([CMAKE_FIND_BINARY],
-[AC_ARG_VAR([CMAKE_BINARY], [path to the cmake binary])dnl
-
-if test "x$ac_cv_env_CMAKE_BINARY_set" != "xset"; then
- AC_PATH_TOOL([CMAKE_BINARY], [cmake])dnl
-fi
-])dnl
-
-# $1: package name
-# $2: language (e.g. C/CXX/Fortran)
-# $3: The compiler ID, defaults to GNU.
-# Possible values are: GNU, Intel, Clang, SunPro, HP, XL, VisualAge, PGI,
-# PathScale, Cray, SCO, MIPSpro, MSVC
-# $4: optional extra arguments to cmake, e.g. "-DCMAKE_SIZEOF_VOID_P=8"
-# $5: optional path to cmake binary
-AC_DEFUN([CMAKE_FIND_PACKAGE], [
-AC_REQUIRE([CMAKE_FIND_BINARY])dnl
-
-AC_ARG_VAR([$1][_][$2][FLAGS], [$2 compiler flags for $1. This overrides the cmake output])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1. This overrides the cmake output])dnl
-
-failed=false
-AC_MSG_CHECKING([for $1])
-if test -n "$1[]_$2[]FLAGS"; then
- $1[]_$2[]FLAGS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=COMPILE $4` || failed=true
-fi
-if test -n "$1[]_LIBS"; then
- $1[]_LIBS=`$CMAKE_BINARY --find-package "-DNAME=$1" "-DCOMPILER_ID=m4_default([$3], [GNU])" "-DLANGUAGE=$2" -DMODE=LINK $4` || failed=true
-fi
-
-if $failed; then
- unset $1[]_$2[]FLAGS
- unset $1[]_LIBS
-
- AC_MSG_RESULT([no])
- $6
-else
- AC_MSG_RESULT([yes])
- $5
-fi[]dnl
-])
diff --git a/Utilities/cmbzip2/compress.c b/Utilities/cmbzip2/compress.c
index 7d9b3da75..feea233c2 100644
--- a/Utilities/cmbzip2/compress.c
+++ b/Utilities/cmbzip2/compress.c
@@ -239,7 +239,7 @@ static
void sendMTFValues ( EState* s )
{
Int32 v, t, i, j, gs, ge, totc, bt, bc, iter;
- Int32 nSelectors, alphaSize, minLen, maxLen, selCtr;
+ Int32 nSelectors = 0, alphaSize, minLen, maxLen, selCtr;
Int32 nGroups, nBytes;
/*--
diff --git a/Utilities/cmcompress/cmcompress.h b/Utilities/cmcompress/cmcompress.h
index fdb0d90b7..4cd3a1c3e 100644
--- a/Utilities/cmcompress/cmcompress.h
+++ b/Utilities/cmcompress/cmcompress.h
@@ -35,8 +35,8 @@
* SUCH DAMAGE.
*/
-#ifndef __cmcompress__h_
-#define __cmcompress__h_
+#ifndef cmcompress__h_
+#define cmcompress__h_
#include <stdio.h>
@@ -192,4 +192,4 @@ extern "C"
#endif
-#endif /* __cmcompress__h_ */
+#endif /* cmcompress__h_ */
diff --git a/Utilities/xml/.gitattributes b/Utilities/cmcurl/.gitattributes
index 562b12e16..562b12e16 100644
--- a/Utilities/xml/.gitattributes
+++ b/Utilities/cmcurl/.gitattributes
diff --git a/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake b/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake
deleted file mode 100644
index d025769aa..000000000
--- a/Utilities/cmcurl/CMake/CurlCheckCSourceCompiles.cmake
+++ /dev/null
@@ -1,75 +0,0 @@
-# - Check if the source code provided in the SOURCE argument compiles.
-# CURL_CHECK_C_SOURCE_COMPILES(SOURCE VAR)
-# - macro which checks if the source code compiles
-# SOURCE - source code to try to compile
-# VAR - variable to store whether the source code compiled
-#
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-MACRO(CURL_CHECK_C_SOURCE_COMPILES SOURCE VAR)
- IF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
- SET(message "${VAR}")
- # If the number of arguments is greater than 2 (SOURCE VAR)
- IF(${ARGC} GREATER 2)
- # then add the third argument as a message
- SET(message "${ARGV2} (${VAR})")
- ENDIF(${ARGC} GREATER 2)
- SET(MACRO_CHECK_FUNCTION_DEFINITIONS
- "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
- IF(CMAKE_REQUIRED_LIBRARIES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- ELSE(CMAKE_REQUIRED_LIBRARIES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
- ENDIF(CMAKE_REQUIRED_LIBRARIES)
- IF(CMAKE_REQUIRED_INCLUDES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
- "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
- ELSE(CMAKE_REQUIRED_INCLUDES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
- ENDIF(CMAKE_REQUIRED_INCLUDES)
- SET(src "")
- FOREACH(def ${EXTRA_DEFINES})
- SET(src "${src}#define ${def} 1\n")
- ENDFOREACH(def)
- FOREACH(inc ${HEADER_INCLUDES})
- SET(src "${src}#include <${inc}>\n")
- ENDFOREACH(inc)
-
- SET(src "${src}\nint main() { ${SOURCE} ; return 0; }")
- SET(CMAKE_CONFIGURABLE_FILE_CONTENT "${src}")
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeConfigurableFile.in
- "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
- IMMEDIATE)
- MESSAGE(STATUS "Performing Test ${message}")
- TRY_COMPILE(${VAR}
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- "${CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
- "${CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
- OUTPUT_VARIABLE OUTPUT)
- IF(${VAR})
- SET(${VAR} 1 CACHE INTERNAL "Test ${message}")
- MESSAGE(STATUS "Performing Test ${message} - Success")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing C SOURCE FILE Test ${message} succeded with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${src}\n")
- ELSE(${VAR})
- MESSAGE(STATUS "Performing Test ${message} - Failed")
- SET(${VAR} "" CACHE INTERNAL "Test ${message}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C SOURCE FILE Test ${message} failed with the following output:\n"
- "${OUTPUT}\n"
- "Source file was:\n${src}\n")
- ENDIF(${VAR})
- ENDIF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
-ENDMACRO(CURL_CHECK_C_SOURCE_COMPILES)
diff --git a/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake b/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake
deleted file mode 100644
index 19681bd85..000000000
--- a/Utilities/cmcurl/CMake/CurlCheckCSourceRuns.cmake
+++ /dev/null
@@ -1,83 +0,0 @@
-# - Check if the source code provided in the SOURCE argument compiles and runs.
-# CURL_CHECK_C_SOURCE_RUNS(SOURCE VAR)
-# - macro which checks if the source code runs
-# SOURCE - source code to try to compile
-# VAR - variable to store size if the type exists.
-#
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-# CMAKE_REQUIRED_LIBRARIES = list of libraries to link
-
-MACRO(CURL_CHECK_C_SOURCE_RUNS SOURCE VAR)
- IF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
- SET(message "${VAR}")
- # If the number of arguments is greater than 2 (SOURCE VAR)
- IF(${ARGC} GREATER 2)
- # then add the third argument as a message
- SET(message "${ARGV2} (${VAR})")
- ENDIF(${ARGC} GREATER 2)
- SET(MACRO_CHECK_FUNCTION_DEFINITIONS
- "-D${VAR} ${CMAKE_REQUIRED_FLAGS}")
- IF(CMAKE_REQUIRED_LIBRARIES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- ELSE(CMAKE_REQUIRED_LIBRARIES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES)
- ENDIF(CMAKE_REQUIRED_LIBRARIES)
- IF(CMAKE_REQUIRED_INCLUDES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES
- "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_REQUIRED_INCLUDES}")
- ELSE(CMAKE_REQUIRED_INCLUDES)
- SET(CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES)
- ENDIF(CMAKE_REQUIRED_INCLUDES)
- SET(src "")
- FOREACH(def ${EXTRA_DEFINES})
- SET(src "${src}#define ${def} 1\n")
- ENDFOREACH(def)
- FOREACH(inc ${HEADER_INCLUDES})
- SET(src "${src}#include <${inc}>\n")
- ENDFOREACH(inc)
-
- SET(src "${src}\nint main() { ${SOURCE} ; return 0; }")
- SET(CMAKE_CONFIGURABLE_FILE_CONTENT "${src}")
- CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/CMake/CMakeConfigurableFile.in
- "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c"
- IMMEDIATE)
- MESSAGE(STATUS "Performing Test ${message}")
- TRY_RUN(${VAR} ${VAR}_COMPILED
- ${CMAKE_BINARY_DIR}
- ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/src.c
- COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS}
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- "${CURL_CHECK_C_SOURCE_COMPILES_ADD_LIBRARIES}"
- "${CURL_CHECK_C_SOURCE_COMPILES_ADD_INCLUDES}"
- OUTPUT_VARIABLE OUTPUT)
- # if it did not compile make the return value fail code of 1
- IF(NOT ${VAR}_COMPILED)
- SET(${VAR} 1)
- ENDIF(NOT ${VAR}_COMPILED)
- # if the return value was 0 then it worked
- SET(result_var ${${VAR}})
- IF("${result_var}" EQUAL 0)
- SET(${VAR} 1 CACHE INTERNAL "Test ${message}")
- MESSAGE(STATUS "Performing Test ${message} - Success")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing C SOURCE FILE Test ${message} succeded with the following output:\n"
- "${OUTPUT}\n"
- "Return value: ${${VAR}}\n"
- "Source file was:\n${src}\n")
- ELSE("${result_var}" EQUAL 0)
- MESSAGE(STATUS "Performing Test ${message} - Failed")
- SET(${VAR} "" CACHE INTERNAL "Test ${message}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing C SOURCE FILE Test ${message} failed with the following output:\n"
- "${OUTPUT}\n"
- "Return value: ${result_var}\n"
- "Source file was:\n${src}\n")
- ENDIF("${result_var}" EQUAL 0)
- ENDIF("${VAR}" MATCHES "^${VAR}$" OR "${VAR}" MATCHES "UNKNOWN")
-ENDMACRO(CURL_CHECK_C_SOURCE_RUNS)
diff --git a/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
new file mode 100644
index 000000000..9f7d29633
--- /dev/null
+++ b/Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
@@ -0,0 +1,61 @@
+include(CheckCSourceCompiles)
+
+option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
+mark_as_advanced(CURL_HIDDEN_SYMBOLS)
+
+if(CURL_HIDDEN_SYMBOLS)
+ set(SUPPORTS_SYMBOL_HIDING FALSE)
+
+ if(CMAKE_C_COMPILER_ID MATCHES "Clang")
+ set(SUPPORTS_SYMBOL_HIDING TRUE)
+ set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
+ set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+ elseif(CMAKE_COMPILER_IS_GNUCC)
+ if(NOT CMAKE_VERSION VERSION_LESS 2.8.10)
+ set(GCC_VERSION ${CMAKE_C_COMPILER_VERSION})
+ else()
+ execute_process(COMMAND ${CMAKE_C_COMPILER} -dumpversion
+ OUTPUT_VARIABLE GCC_VERSION)
+ endif()
+ if(NOT GCC_VERSION VERSION_LESS 3.4)
+ # note: this is considered buggy prior to 4.0 but the autotools don't care, so let's ignore that fact
+ set(SUPPORTS_SYMBOL_HIDING TRUE)
+ set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
+ set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+ endif()
+ elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 8.0)
+ set(SUPPORTS_SYMBOL_HIDING TRUE)
+ set(_SYMBOL_EXTERN "__global")
+ set(_CFLAG_SYMBOLS_HIDE "-xldscope=hidden")
+ elseif(CMAKE_C_COMPILER_ID MATCHES "Intel" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.0)
+ # note: this should probably just check for version 9.1.045 but I'm not 100% sure
+ # so let's to it the same way autotools do.
+ set(SUPPORTS_SYMBOL_HIDING TRUE)
+ set(_SYMBOL_EXTERN "__attribute__ ((__visibility__ (\"default\")))")
+ set(_CFLAG_SYMBOLS_HIDE "-fvisibility=hidden")
+ check_c_source_compiles("#include <stdio.h>
+ int main (void) { printf(\"icc fvisibility bug test\"); return 0; }" _no_bug)
+ if(NOT _no_bug)
+ set(SUPPORTS_SYMBOL_HIDING FALSE)
+ set(_SYMBOL_EXTERN "")
+ set(_CFLAG_SYMBOLS_HIDE "")
+ endif()
+ elseif(MSVC)
+ set(SUPPORTS_SYMBOL_HIDING TRUE)
+ endif()
+
+ set(HIDES_CURL_PRIVATE_SYMBOLS ${SUPPORTS_SYMBOL_HIDING})
+elseif(MSVC)
+ if(NOT CMAKE_VERSION VERSION_LESS 3.7)
+ set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE) #present since 3.4.3 but broken
+ set(HIDES_CURL_PRIVATE_SYMBOLS FALSE)
+ else()
+ message(WARNING "Hiding private symbols regardless CURL_HIDDEN_SYMBOLS being disabled.")
+ set(HIDES_CURL_PRIVATE_SYMBOLS TRUE)
+ endif()
+elseif()
+ set(HIDES_CURL_PRIVATE_SYMBOLS FALSE)
+endif()
+
+set(CURL_CFLAG_SYMBOLS_HIDE ${_CFLAG_SYMBOLS_HIDE})
+set(CURL_EXTERN_SYMBOL ${_SYMBOL_EXTERN})
diff --git a/Utilities/cmcurl/CMake/CurlTests.c b/Utilities/cmcurl/CMake/CurlTests.c
index d74a4f016..bc36c8ef7 100644
--- a/Utilities/cmcurl/CMake/CurlTests.c
+++ b/Utilities/cmcurl/CMake/CurlTests.c
@@ -1,6 +1,27 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
#ifdef TIME_WITH_SYS_TIME
/* Time with sys/time test */
-
+
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
@@ -16,295 +37,122 @@ return 0;
#endif
-#ifdef HAVE_O_NONBLOCK
+#ifdef HAVE_FCNTL_O_NONBLOCK
+/* headers for FCNTL_O_NONBLOCK test */
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
-
-int
-main ()
-{
- /* try to compile O_NONBLOCK */
-
-#if defined(sun) || defined(__sun__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+/* */
+#if defined(sun) || defined(__sun__) || \
+ defined(__SUNPRO_C) || defined(__SUNPRO_CC)
# if defined(__SVR4) || defined(__srv4__)
# define PLATFORM_SOLARIS
# else
# define PLATFORM_SUNOS4
# endif
#endif
-#if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX4)
+#if (defined(_AIX) || defined(__xlC__)) && !defined(_AIX41)
# define PLATFORM_AIX_V3
#endif
-
-#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || (defined(__BEOS__) && !defined(__HAIKU__))
+/* */
+#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || defined(__BEOS__)
#error "O_NONBLOCK does not work on this platform"
#endif
- int socket;
- int flags = fcntl(socket, F_SETFL, flags | O_NONBLOCK);
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_5
-#include <sys/types.h>
-#include <netdb.h>
int
main ()
{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-struct hostent_data hdata;
-int rc;
-#ifndef gethostbyaddr_r
- (void)gethostbyaddr_r;
-#endif
-rc = gethostbyaddr_r(address, length, type, &h, &hdata);
- ;
- return 0;
+ /* O_NONBLOCK source test */
+ int flags = 0;
+ if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
+ return 1;
+ return 0;
}
#endif
-#ifdef HAVE_GETHOSTBYADDR_R_5_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-char * address;
-int length;q
-int type;
-struct hostent h;
-struct hostent_data hdata;
-int rc;
-#ifndef gethostbyaddr_r
- (void)gethostbyaddr_r;
-#endif
-rc = gethostbyaddr_r(address, length, type, &h, &hdata);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_7
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-
-#ifndef gethostbyaddr_r
- (void)gethostbyaddr_r;
-#endif
-hp = gethostbyaddr_r(address, length, type, &h,
- buffer, 8192, &h_errnop);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_7_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-
-#ifndef gethostbyaddr_r
- (void)gethostbyaddr_r;
-#endif
-hp = gethostbyaddr_r(address, length, type, &h,
- buffer, 8192, &h_errnop);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_8
+/* tests for gethostbyaddr_r or gethostbyname_r */
+#if defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
+ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
+ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
+ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT) || \
+ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
+ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+# define _REENTRANT
+ /* no idea whether _REENTRANT is always set, just invent a new flag */
+# define TEST_GETHOSTBYFOO_REENTRANT
+#endif
+#if defined(HAVE_GETHOSTBYADDR_R_5) || \
+ defined(HAVE_GETHOSTBYADDR_R_7) || \
+ defined(HAVE_GETHOSTBYADDR_R_8) || \
+ defined(HAVE_GETHOSTBYNAME_R_3) || \
+ defined(HAVE_GETHOSTBYNAME_R_5) || \
+ defined(HAVE_GETHOSTBYNAME_R_6) || \
+ defined(TEST_GETHOSTBYFOO_REENTRANT)
#include <sys/types.h>
#include <netdb.h>
-int
-main ()
+int main(void)
{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-int rc;
-
-#ifndef gethostbyaddr_r
- (void)gethostbyaddr_r;
+ char *address = "example.com";
+ int length = 0;
+ int type = 0;
+ struct hostent h;
+ int rc = 0;
+#if defined(HAVE_GETHOSTBYADDR_R_5) || \
+ defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT) || \
+ \
+ defined(HAVE_GETHOSTBYNAME_R_3) || \
+ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
+ struct hostent_data hdata;
+#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
+ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT) || \
+ defined(HAVE_GETHOSTBYADDR_R_8) || \
+ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT) || \
+ \
+ defined(HAVE_GETHOSTBYNAME_R_5) || \
+ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT) || \
+ defined(HAVE_GETHOSTBYNAME_R_6) || \
+ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+ char buffer[8192];
+ int h_errnop;
+ struct hostent *hp;
#endif
-rc = gethostbyaddr_r(address, length, type, &h,
- buffer, 8192, &hp, &h_errnop);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYADDR_R_8_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-int
-main ()
-{
-
-char * address;
-int length;
-int type;
-struct hostent h;
-char buffer[8192];
-int h_errnop;
-struct hostent * hp;
-int rc;
#ifndef gethostbyaddr_r
(void)gethostbyaddr_r;
#endif
-rc = gethostbyaddr_r(address, length, type, &h,
- buffer, 8192, &hp, &h_errnop);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_3
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-int
-main ()
-{
-
-struct hostent_data data;
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_3_REENTRANT
-#define _REENTRANT
-#include <string.h>
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-struct hostent_data data;
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL);
- ;
+#if defined(HAVE_GETHOSTBYADDR_R_5) || \
+ defined(HAVE_GETHOSTBYADDR_R_5_REENTRANT)
+ rc = gethostbyaddr_r(address, length, type, &h, &hdata);
+#elif defined(HAVE_GETHOSTBYADDR_R_7) || \
+ defined(HAVE_GETHOSTBYADDR_R_7_REENTRANT)
+ hp = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &h_errnop);
+ (void)hp;
+#elif defined(HAVE_GETHOSTBYADDR_R_8) || \
+ defined(HAVE_GETHOSTBYADDR_R_8_REENTRANT)
+ rc = gethostbyaddr_r(address, length, type, &h, buffer, 8192, &hp, &h_errnop);
+#endif
+
+#if defined(HAVE_GETHOSTBYNAME_R_3) || \
+ defined(HAVE_GETHOSTBYNAME_R_3_REENTRANT)
+ rc = gethostbyname_r(address, &h, &hdata);
+#elif defined(HAVE_GETHOSTBYNAME_R_5) || \
+ defined(HAVE_GETHOSTBYNAME_R_5_REENTRANT)
+ rc = gethostbyname_r(address, &h, buffer, 8192, &h_errnop);
+ (void)hp; /* not used for test */
+#elif defined(HAVE_GETHOSTBYNAME_R_6) || \
+ defined(HAVE_GETHOSTBYNAME_R_6_REENTRANT)
+ rc = gethostbyname_r(address, &h, buffer, 8192, &hp, &h_errnop);
+#endif
+
+ (void)length;
+ (void)type;
+ (void)rc;
return 0;
}
#endif
-#ifdef HAVE_GETHOSTBYNAME_R_5
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-int
-main ()
-{
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_5_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_6
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
- ;
- return 0;
-}
-#endif
-#ifdef HAVE_GETHOSTBYNAME_R_6_REENTRANT
-#define _REENTRANT
-#include <sys/types.h>
-#include <netdb.h>
-#undef NULL
-#define NULL (void *)0
-
-int
-main ()
-{
-
-#ifndef gethostbyname_r
- (void)gethostbyname_r;
-#endif
-gethostbyname_r(NULL, NULL, NULL, 0, NULL, NULL);
- ;
- return 0;
-}
-#endif
#ifdef HAVE_SOCKLEN_T
#ifdef _WIN32
#include <ws2tcpip.h>
@@ -339,6 +187,24 @@ if (sizeof (in_addr_t))
return 0;
}
#endif
+
+#ifdef HAVE_BOOL_T
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_STDBOOL_H
+#include <stdbool.h>
+#endif
+int
+main ()
+{
+if (sizeof (bool *) )
+ return 0;
+ ;
+ return 0;
+}
+#endif
+
#ifdef STDC_HEADERS
#include <stdlib.h>
#include <stdarg.h>
@@ -432,7 +298,20 @@ int main(void) {
int main () { ; return 0; }
#endif
#ifdef HAVE_IOCTLSOCKET
-#include <windows.h>
+/* includes start */
+#ifdef HAVE_WINDOWS_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+#endif
int
main ()
@@ -447,52 +326,182 @@ main ()
}
#endif
-#ifdef HAVE_IOCTLSOCKET_CASE
-#include <windows.h>
+#ifdef HAVE_IOCTLSOCKET_CAMEL
+/* includes start */
+#ifdef HAVE_WINDOWS_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+#endif
int
main ()
{
/* IoctlSocket source code */
- int socket;
- int flags = IoctlSocket(socket, FIONBIO, (long)1);
+ if(0 != IoctlSocket(0, 0, 0))
+ return 1;
+ ;
+ return 0;
+}
+#endif
+#ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+/* includes start */
+#ifdef HAVE_WINDOWS_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+#endif
+
+int
+main ()
+{
+
+/* IoctlSocket source code */
+ long flags = 0;
+ if(0 != ioctlsocket(0, FIONBIO, &flags))
+ return 1;
+ ;
+ return 0;
+}
+#endif
+#ifdef HAVE_IOCTLSOCKET_FIONBIO
+/* includes start */
+#ifdef HAVE_WINDOWS_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+#endif
+
+int
+main ()
+{
+
+ int flags = 0;
+ if(0 != ioctlsocket(0, FIONBIO, &flags))
+ return 1;
;
return 0;
}
#endif
-#ifdef HAVE_FIONBIO
+#ifdef HAVE_IOCTL_FIONBIO
/* headers for FIONBIO test */
-#include <unistd.h>
-#include <stropts.h>
+/* includes start */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_STROPTS_H
+# include <stropts.h>
+#endif
int
main ()
{
-/* FIONBIO source test (old-style unix) */
- int socket;
- int flags = ioctl(socket, FIONBIO, &flags);
+ int flags = 0;
+ if(0 != ioctl(0, FIONBIO, &flags))
+ return 1;
;
return 0;
}
#endif
-#ifdef HAVE_SO_NONBLOCK
+#ifdef HAVE_IOCTL_SIOCGIFADDR
+/* headers for FIONBIO test */
+/* includes start */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_STROPTS_H
+# include <stropts.h>
+#endif
+#include <net/if.h>
-/* headers for SO_NONBLOCK test (BeOS) */
-#include <sys/types.h>
-#include <unistd.h>
-#include <fcntl.h>
+int
+main ()
+{
+ struct ifreq ifr;
+ if(0 != ioctl(0, SIOCGIFADDR, &ifr))
+ return 1;
-int main()
+ ;
+ return 0;
+}
+#endif
+#ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
+/* includes start */
+#ifdef HAVE_WINDOWS_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+#endif
+/* includes start */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+/* includes end */
+
+int
+main ()
{
-/* SO_NONBLOCK source code */
- long b = 1;
- int socket;
- int flags = setsockopt(socket, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
- return 0;
+ if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
+ return 1;
+ ;
+ return 0;
}
#endif
#ifdef HAVE_GLIBC_STRERROR_R
@@ -524,3 +533,19 @@ main () {
return 0;
}
#endif
+#ifdef HAVE_FSETXATTR_6
+#include <sys/xattr.h> /* header from libc, not from libattr */
+int
+main() {
+ fsetxattr(0, 0, 0, 0, 0, 0);
+ return 0;
+}
+#endif
+#ifdef HAVE_FSETXATTR_5
+#include <sys/xattr.h> /* header from libc, not from libattr */
+int
+main() {
+ fsetxattr(0, 0, 0, 0, 0);
+ return 0;
+}
+#endif
diff --git a/Utilities/cmcurl/CMake/FindCARES.cmake b/Utilities/cmcurl/CMake/FindCARES.cmake
new file mode 100644
index 000000000..c4ab5f132
--- /dev/null
+++ b/Utilities/cmcurl/CMake/FindCARES.cmake
@@ -0,0 +1,42 @@
+# - Find c-ares
+# Find the c-ares includes and library
+# This module defines
+# CARES_INCLUDE_DIR, where to find ares.h, etc.
+# CARES_LIBRARIES, the libraries needed to use c-ares.
+# CARES_FOUND, If false, do not try to use c-ares.
+# also defined, but not for general use are
+# CARES_LIBRARY, where to find the c-ares library.
+
+FIND_PATH(CARES_INCLUDE_DIR ares.h
+ /usr/local/include
+ /usr/include
+ )
+
+SET(CARES_NAMES ${CARES_NAMES} cares)
+FIND_LIBRARY(CARES_LIBRARY
+ NAMES ${CARES_NAMES}
+ PATHS /usr/lib /usr/local/lib
+ )
+
+IF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
+ SET(CARES_LIBRARIES ${CARES_LIBRARY})
+ SET(CARES_FOUND "YES")
+ELSE (CARES_LIBRARY AND CARES_INCLUDE_DIR)
+ SET(CARES_FOUND "NO")
+ENDIF (CARES_LIBRARY AND CARES_INCLUDE_DIR)
+
+
+IF (CARES_FOUND)
+ IF (NOT CARES_FIND_QUIETLY)
+ MESSAGE(STATUS "Found c-ares: ${CARES_LIBRARIES}")
+ ENDIF (NOT CARES_FIND_QUIETLY)
+ELSE (CARES_FOUND)
+ IF (CARES_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find c-ares library")
+ ENDIF (CARES_FIND_REQUIRED)
+ENDIF (CARES_FOUND)
+
+MARK_AS_ADVANCED(
+ CARES_LIBRARY
+ CARES_INCLUDE_DIR
+ )
diff --git a/Utilities/cmcurl/CMake/FindGSS.cmake b/Utilities/cmcurl/CMake/FindGSS.cmake
new file mode 100644
index 000000000..60dcb73c9
--- /dev/null
+++ b/Utilities/cmcurl/CMake/FindGSS.cmake
@@ -0,0 +1,289 @@
+# - Try to find the GSS Kerberos library
+# Once done this will define
+#
+# GSS_ROOT_DIR - Set this variable to the root installation of GSS
+#
+# Read-Only variables:
+# GSS_FOUND - system has the Heimdal library
+# GSS_FLAVOUR - "MIT" or "Heimdal" if anything found.
+# GSS_INCLUDE_DIR - the Heimdal include directory
+# GSS_LIBRARIES - The libraries needed to use GSS
+# GSS_LINK_DIRECTORIES - Directories to add to linker search path
+# GSS_LINKER_FLAGS - Additional linker flags
+# GSS_COMPILER_FLAGS - Additional compiler flags
+# GSS_VERSION - This is set to version advertised by pkg-config or read from manifest.
+# In case the library is found but no version info available it'll be set to "unknown"
+
+set(_MIT_MODNAME mit-krb5-gssapi)
+set(_HEIMDAL_MODNAME heimdal-gssapi)
+
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckTypeSize)
+
+set(_GSS_ROOT_HINTS
+ "${GSS_ROOT_DIR}"
+ "$ENV{GSS_ROOT_DIR}"
+)
+
+# try to find library using system pkg-config if user didn't specify root dir
+if(NOT GSS_ROOT_DIR AND NOT "$ENV{GSS_ROOT_DIR}")
+ if(UNIX)
+ find_package(PkgConfig QUIET)
+ pkg_search_module(_GSS_PKG ${_MIT_MODNAME} ${_HEIMDAL_MODNAME})
+ list(APPEND _GSS_ROOT_HINTS "${_GSS_PKG_PREFIX}")
+ elseif(WIN32)
+ list(APPEND _GSS_ROOT_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos;InstallDir]")
+ endif()
+endif()
+
+if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
+ find_file(_GSS_CONFIGURE_SCRIPT
+ NAMES
+ "krb5-config"
+ HINTS
+ ${_GSS_ROOT_HINTS}
+ PATH_SUFFIXES
+ bin
+ NO_CMAKE_PATH
+ NO_CMAKE_ENVIRONMENT_PATH
+ )
+
+ # if not found in user-supplied directories, maybe system knows better
+ find_file(_GSS_CONFIGURE_SCRIPT
+ NAMES
+ "krb5-config"
+ PATH_SUFFIXES
+ bin
+ )
+
+ if(_GSS_CONFIGURE_SCRIPT)
+ execute_process(
+ COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
+ OUTPUT_VARIABLE _GSS_CFLAGS
+ RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+ )
+message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
+ if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
+ # should also work in an odd case when multiple directories are given
+ string(STRIP "${_GSS_CFLAGS}" _GSS_CFLAGS)
+ string(REGEX REPLACE " +-I" ";" _GSS_CFLAGS "${_GSS_CFLAGS}")
+ string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1"_GSS_CFLAGS "${_GSS_CFLAGS}")
+
+ foreach(_flag ${_GSS_CFLAGS})
+ if(_flag MATCHES "^-I.*")
+ string(REGEX REPLACE "^-I" "" _val "${_flag}")
+ list(APPEND _GSS_INCLUDE_DIR "${_val}")
+ else()
+ list(APPEND _GSS_COMPILER_FLAGS "${_flag}")
+ endif()
+ endforeach()
+ endif()
+
+ execute_process(
+ COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
+ OUTPUT_VARIABLE _GSS_LIB_FLAGS
+ RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+ )
+message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")
+ if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
+ # this script gives us libraries and link directories. Blah. We have to deal with it.
+ string(STRIP "${_GSS_LIB_FLAGS}" _GSS_LIB_FLAGS)
+ string(REGEX REPLACE " +-(L|l)" ";-\\1" _GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
+ string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1"_GSS_LIB_FLAGS "${_GSS_LIB_FLAGS}")
+
+ foreach(_flag ${_GSS_LIB_FLAGS})
+ if(_flag MATCHES "^-l.*")
+ string(REGEX REPLACE "^-l" "" _val "${_flag}")
+ list(APPEND _GSS_LIBRARIES "${_val}")
+ elseif(_flag MATCHES "^-L.*")
+ string(REGEX REPLACE "^-L" "" _val "${_flag}")
+ list(APPEND _GSS_LINK_DIRECTORIES "${_val}")
+ else()
+ list(APPEND _GSS_LINKER_FLAGS "${_flag}")
+ endif()
+ endforeach()
+ endif()
+
+
+ execute_process(
+ COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
+ OUTPUT_VARIABLE _GSS_VERSION
+ RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+ )
+
+ # older versions may not have the "--version" parameter. In this case we just don't care.
+ if(_GSS_CONFIGURE_FAILED)
+ set(_GSS_VERSION 0)
+ endif()
+
+
+ execute_process(
+ COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
+ OUTPUT_VARIABLE _GSS_VENDOR
+ RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+ )
+
+ # older versions may not have the "--vendor" parameter. In this case we just don't care.
+ if(_GSS_CONFIGURE_FAILED)
+ set(GSS_FLAVOUR "Heimdal") # most probably, shouldn't really matter
+ else()
+ if(_GSS_VENDOR MATCHES ".*H|heimdal.*")
+ set(GSS_FLAVOUR "Heimdal")
+ else()
+ set(GSS_FLAVOUR "MIT")
+ endif()
+ endif()
+
+ else() # either there is no config script or we are on platform that doesn't provide one (Windows?)
+
+ find_path(_GSS_INCLUDE_DIR
+ NAMES
+ "gssapi/gssapi.h"
+ HINTS
+ ${_GSS_ROOT_HINTS}
+ PATH_SUFFIXES
+ include
+ inc
+ )
+
+ if(_GSS_INCLUDE_DIR) #jay, we've found something
+ set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIR}")
+ check_include_files( "gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _GSS_HAVE_MIT_HEADERS)
+
+ if(_GSS_HAVE_MIT_HEADERS)
+ set(GSS_FLAVOUR "MIT")
+ else()
+ # prevent compiling the header - just check if we can include it
+ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D__ROKEN_H__")
+ check_include_file( "roken.h" _GSS_HAVE_ROKEN_H)
+
+ check_include_file( "heimdal/roken.h" _GSS_HAVE_HEIMDAL_ROKEN_H)
+ if(_GSS_HAVE_ROKEN_H OR _GSS_HAVE_HEIMDAL_ROKEN_H)
+ set(GSS_FLAVOUR "Heimdal")
+ endif()
+ set(CMAKE_REQUIRED_DEFINITIONS "")
+ endif()
+ else()
+ # I'm not convienced if this is the right way but this is what autotools do at the moment
+ find_path(_GSS_INCLUDE_DIR
+ NAMES
+ "gssapi.h"
+ HINTS
+ ${_GSS_ROOT_HINTS}
+ PATH_SUFFIXES
+ include
+ inc
+ )
+
+ if(_GSS_INCLUDE_DIR)
+ set(GSS_FLAVOUR "Heimdal")
+ endif()
+ endif()
+
+ # if we have headers, check if we can link libraries
+ if(GSS_FLAVOUR)
+ set(_GSS_LIBDIR_SUFFIXES "")
+ set(_GSS_LIBDIR_HINTS ${_GSS_ROOT_HINTS})
+ get_filename_component(_GSS_CALCULATED_POTENTIAL_ROOT "${_GSS_INCLUDE_DIR}" PATH)
+ list(APPEND _GSS_LIBDIR_HINTS ${_GSS_CALCULATED_POTENTIAL_ROOT})
+
+ if(WIN32)
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND _GSS_LIBDIR_SUFFIXES "lib/AMD64")
+ if(GSS_FLAVOUR STREQUAL "MIT")
+ set(_GSS_LIBNAME "gssapi64")
+ else()
+ set(_GSS_LIBNAME "libgssapi")
+ endif()
+ else()
+ list(APPEND _GSS_LIBDIR_SUFFIXES "lib/i386")
+ if(GSS_FLAVOUR STREQUAL "MIT")
+ set(_GSS_LIBNAME "gssapi32")
+ else()
+ set(_GSS_LIBNAME "libgssapi")
+ endif()
+ endif()
+ else()
+ list(APPEND _GSS_LIBDIR_SUFFIXES "lib;lib64") # those suffixes are not checked for HINTS
+ if(GSS_FLAVOUR STREQUAL "MIT")
+ set(_GSS_LIBNAME "gssapi_krb5")
+ else()
+ set(_GSS_LIBNAME "gssapi")
+ endif()
+ endif()
+
+ find_library(_GSS_LIBRARIES
+ NAMES
+ ${_GSS_LIBNAME}
+ HINTS
+ ${_GSS_LIBDIR_HINTS}
+ PATH_SUFFIXES
+ ${_GSS_LIBDIR_SUFFIXES}
+ )
+
+ endif()
+
+ endif()
+else()
+ if(_GSS_PKG_${_MIT_MODNAME}_VERSION)
+ set(GSS_FLAVOUR "MIT")
+ set(_GSS_VERSION _GSS_PKG_${_MIT_MODNAME}_VERSION)
+ else()
+ set(GSS_FLAVOUR "Heimdal")
+ set(_GSS_VERSION _GSS_PKG_${_MIT_HEIMDAL}_VERSION)
+ endif()
+endif()
+
+set(GSS_INCLUDE_DIR ${_GSS_INCLUDE_DIR})
+set(GSS_LIBRARIES ${_GSS_LIBRARIES})
+set(GSS_LINK_DIRECTORIES ${_GSS_LINK_DIRECTORIES})
+set(GSS_LINKER_FLAGS ${_GSS_LINKER_FLAGS})
+set(GSS_COMPILER_FLAGS ${_GSS_COMPILER_FLAGS})
+set(GSS_VERSION ${_GSS_VERSION})
+
+if(GSS_FLAVOUR)
+
+ if(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "Heimdal")
+ if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.amd64.manifest")
+ else()
+ set(HEIMDAL_MANIFEST_FILE "Heimdal.Application.x86.manifest")
+ endif()
+
+ if(EXISTS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}")
+ file(STRINGS "${GSS_INCLUDE_DIR}/${HEIMDAL_MANIFEST_FILE}" heimdal_version_str
+ REGEX "^.*version=\"[0-9]\\.[^\"]+\".*$")
+
+ string(REGEX MATCH "[0-9]\\.[^\"]+"
+ GSS_VERSION "${heimdal_version_str}")
+ endif()
+
+ if(NOT GSS_VERSION)
+ set(GSS_VERSION "Heimdal Unknown")
+ endif()
+ elseif(NOT GSS_VERSION AND GSS_FLAVOUR STREQUAL "MIT")
+ get_filename_component(_MIT_VERSION "[HKEY_LOCAL_MACHINE\\SOFTWARE\\MIT\\Kerberos\\SDK\\CurrentVersion;VersionString]" NAME CACHE)
+ if(WIN32 AND _MIT_VERSION)
+ set(GSS_VERSION "${_MIT_VERSION}")
+ else()
+ set(GSS_VERSION "MIT Unknown")
+ endif()
+ endif()
+endif()
+
+
+include(FindPackageHandleStandardArgs)
+
+set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)
+
+find_package_handle_standard_args(GSS
+ REQUIRED_VARS
+ ${_GSS_REQUIRED_VARS}
+ VERSION_VAR
+ GSS_VERSION
+ FAIL_MESSAGE
+ "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
+)
+
+mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)
diff --git a/Utilities/cmcurl/CMake/FindLibSSH2.cmake b/Utilities/cmcurl/CMake/FindLibSSH2.cmake
new file mode 100644
index 000000000..12a7c612b
--- /dev/null
+++ b/Utilities/cmcurl/CMake/FindLibSSH2.cmake
@@ -0,0 +1,35 @@
+# - Try to find the libssh2 library
+# Once done this will define
+#
+# LIBSSH2_FOUND - system has the libssh2 library
+# LIBSSH2_INCLUDE_DIR - the libssh2 include directory
+# LIBSSH2_LIBRARY - the libssh2 library name
+
+if (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY)
+ set(LibSSH2_FIND_QUIETLY TRUE)
+endif (LIBSSH2_INCLUDE_DIR AND LIBSSH2_LIBRARY)
+
+FIND_PATH(LIBSSH2_INCLUDE_DIR libssh2.h
+)
+
+FIND_LIBRARY(LIBSSH2_LIBRARY NAMES ssh2
+)
+
+if(LIBSSH2_INCLUDE_DIR)
+ file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" libssh2_version_str REGEX "^#define[\t ]+LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9][0-9][0-9].*")
+
+ string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MAJOR "${libssh2_version_str}")
+ string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_MINOR "${libssh2_version_str}")
+ string(REGEX REPLACE "^.*LIBSSH2_VERSION_NUM[\t ]+0x[0-9][0-9][0-9][0-9]([0-9][0-9]).*$" "\\1" LIBSSH2_VERSION_PATCH "${libssh2_version_str}")
+
+ string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MAJOR "${LIBSSH2_VERSION_MAJOR}")
+ string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_MINOR "${LIBSSH2_VERSION_MINOR}")
+ string(REGEX REPLACE "^0(.+)" "\\1" LIBSSH2_VERSION_PATCH "${LIBSSH2_VERSION_PATCH}")
+
+ set(LIBSSH2_VERSION "${LIBSSH2_VERSION_MAJOR}.${LIBSSH2_VERSION_MINOR}.${LIBSSH2_VERSION_PATCH}")
+endif(LIBSSH2_INCLUDE_DIR)
+
+include(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LibSSH2 DEFAULT_MSG LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY )
+
+MARK_AS_ADVANCED(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY LIBSSH2_VERSION_MAJOR LIBSSH2_VERSION_MINOR LIBSSH2_VERSION_PATCH LIBSSH2_VERSION)
diff --git a/Utilities/cmcurl/CMake/FindMbedTLS.cmake b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
new file mode 100644
index 000000000..a91639589
--- /dev/null
+++ b/Utilities/cmcurl/CMake/FindMbedTLS.cmake
@@ -0,0 +1,13 @@
+find_path(MBEDTLS_INCLUDE_DIRS mbedtls/ssl.h)
+
+find_library(MBEDTLS_LIBRARY mbedtls)
+find_library(MBEDX509_LIBRARY mbedx509)
+find_library(MBEDCRYPTO_LIBRARY mbedcrypto)
+
+set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_LIBRARY}")
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MBEDTLS DEFAULT_MSG
+ MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+
+mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
diff --git a/Utilities/cmcurl/CMake/FindNGHTTP2.cmake b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake
new file mode 100644
index 000000000..4e566cf02
--- /dev/null
+++ b/Utilities/cmcurl/CMake/FindNGHTTP2.cmake
@@ -0,0 +1,18 @@
+include(FindPackageHandleStandardArgs)
+
+find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")
+
+find_library(NGHTTP2_LIBRARY NAMES nghttp2)
+
+find_package_handle_standard_args(NGHTTP2
+ FOUND_VAR
+ NGHTTP2_FOUND
+ REQUIRED_VARS
+ NGHTTP2_LIBRARY
+ NGHTTP2_INCLUDE_DIR
+ FAIL_MESSAGE
+ "Could NOT find NGHTTP2"
+)
+
+set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR} )
+set(NGHTTP2_LIBRARIES ${NGHTTP2_LIBRARY})
diff --git a/Utilities/cmcurl/CMake/Macros.cmake b/Utilities/cmcurl/CMake/Macros.cmake
new file mode 100644
index 000000000..dab005f73
--- /dev/null
+++ b/Utilities/cmcurl/CMake/Macros.cmake
@@ -0,0 +1,95 @@
+#File defines convenience macros for available feature testing
+
+# This macro checks if the symbol exists in the library and if it
+# does, it prepends library to the list. It is intended to be called
+# multiple times with a sequence of possibly dependent libraries in
+# order of least-to-most-dependent. Some libraries depend on others
+# to link correctly.
+macro(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE)
+ check_library_exists("${LIBRARY};${CURL_LIBS}" ${SYMBOL} "${CMAKE_LIBRARY_PATH}"
+ ${VARIABLE})
+ if(${VARIABLE})
+ set(CURL_LIBS ${LIBRARY} ${CURL_LIBS})
+ endif(${VARIABLE})
+endmacro(CHECK_LIBRARY_EXISTS_CONCAT)
+
+# Check if header file exists and add it to the list.
+# This macro is intended to be called multiple times with a sequence of
+# possibly dependent header files. Some headers depend on others to be
+# compiled correctly.
+macro(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE)
+ check_include_files("${CURL_INCLUDES};${FILE}" ${VARIABLE})
+ if(${VARIABLE})
+ set(CURL_INCLUDES ${CURL_INCLUDES} ${FILE})
+ set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -D${VARIABLE}")
+ endif(${VARIABLE})
+endmacro(CHECK_INCLUDE_FILE_CONCAT)
+
+# For other curl specific tests, use this macro.
+macro(CURL_INTERNAL_TEST CURL_TEST)
+ if(NOT DEFINED "${CURL_TEST}")
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-D${CURL_TEST} ${CURL_TEST_DEFINES} ${CMAKE_REQUIRED_FLAGS}")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CURL_TEST_ADD_LIBRARIES
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ endif(CMAKE_REQUIRED_LIBRARIES)
+
+ message(STATUS "Performing Curl Test ${CURL_TEST}")
+ try_compile(${CURL_TEST}
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CURL_TEST_ADD_LIBRARIES}"
+ OUTPUT_VARIABLE OUTPUT)
+ if(${CURL_TEST})
+ set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
+ message(STATUS "Performing Curl Test ${CURL_TEST} - Success")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
+ "Performing Curl Test ${CURL_TEST} passed with the following output:\n"
+ "${OUTPUT}\n")
+ else(${CURL_TEST})
+ message(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
+ set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
+ file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
+ "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
+ "${OUTPUT}\n")
+ endif(${CURL_TEST})
+ endif()
+endmacro(CURL_INTERNAL_TEST)
+
+macro(CURL_INTERNAL_TEST_RUN CURL_TEST)
+ if(NOT DEFINED "${CURL_TEST}_COMPILE")
+ set(MACRO_CHECK_FUNCTION_DEFINITIONS
+ "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}")
+ if(CMAKE_REQUIRED_LIBRARIES)
+ set(CURL_TEST_ADD_LIBRARIES
+ "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
+ endif(CMAKE_REQUIRED_LIBRARIES)
+
+ message(STATUS "Performing Curl Test ${CURL_TEST}")
+ try_run(${CURL_TEST} ${CURL_TEST}_COMPILE
+ ${CMAKE_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c
+ CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
+ "${CURL_TEST_ADD_LIBRARIES}"
+ OUTPUT_VARIABLE OUTPUT)
+ if(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+ set(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
+ message(STATUS "Performing Curl Test ${CURL_TEST} - Success")
+ else(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+ message(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
+ set(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
+ file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log"
+ "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
+ "${OUTPUT}")
+ if(${CURL_TEST}_COMPILE)
+ file(APPEND
+ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log"
+ "There was a problem running this test\n")
+ endif(${CURL_TEST}_COMPILE)
+ file(APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log"
+ "\n\n")
+ endif(${CURL_TEST}_COMPILE AND NOT ${CURL_TEST})
+ endif()
+endmacro(CURL_INTERNAL_TEST_RUN)
diff --git a/Utilities/cmcurl/CMake/OtherTests.cmake b/Utilities/cmcurl/CMake/OtherTests.cmake
index 7d2c66fa1..3b203c538 100644
--- a/Utilities/cmcurl/CMake/OtherTests.cmake
+++ b/Utilities/cmcurl/CMake/OtherTests.cmake
@@ -1,242 +1,232 @@
-INCLUDE(CurlCheckCSourceCompiles)
-SET(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2")
-SET(HEADER_INCLUDES)
-SET(headers_hack)
+include(CheckCSourceCompiles)
+# The begin of the sources (macros and includes)
+set(_source_epilogue "#undef inline")
-MACRO(add_header_include check header)
- IF(${check})
- SET(headers_hack
- "${headers_hack}\n#include <${header}>")
- #SET(HEADER_INCLUDES
- # ${HEADER_INCLUDES}
- # "${header}")
- ENDIF(${check})
-ENDMACRO(add_header_include)
+macro(add_header_include check header)
+ if(${check})
+ set(_source_epilogue "${_source_epilogue}\n#include <${header}>")
+ endif(${check})
+endmacro(add_header_include)
-SET(signature_call_conv)
-IF(HAVE_WINDOWS_H)
- add_header_include(HAVE_WINDOWS_H "windows.h")
+set(signature_call_conv)
+if(HAVE_WINDOWS_H)
add_header_include(HAVE_WINSOCK2_H "winsock2.h")
+ add_header_include(HAVE_WINDOWS_H "windows.h")
add_header_include(HAVE_WINSOCK_H "winsock.h")
- SET(EXTRA_DEFINES ${EXTRA_DEFINES}
- "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3")
- SET(signature_call_conv "PASCAL")
-ELSE(HAVE_WINDOWS_H)
+ set(_source_epilogue
+ "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
+ set(signature_call_conv "PASCAL")
+ if(HAVE_LIBWS2_32)
+ set(CMAKE_REQUIRED_LIBRARIES ws2_32)
+ endif()
+else(HAVE_WINDOWS_H)
add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
-ENDIF(HAVE_WINDOWS_H)
+endif(HAVE_WINDOWS_H)
-SET(EXTRA_DEFINES_BACKUP "${EXTRA_DEFINES}")
-SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
-CURL_CHECK_C_SOURCE_COMPILES("recv(0, 0, 0, 0)" curl_cv_recv)
-IF(curl_cv_recv)
- # AC_CACHE_CHECK([types of arguments and return type for recv],
- #[curl_cv_func_recv_args], [
- #SET(curl_cv_func_recv_args "unknown")
- #for recv_retv in 'int' 'ssize_t'; do
- IF(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
- FOREACH(recv_retv "int" "ssize_t" )
- FOREACH(recv_arg1 "int" "ssize_t" "SOCKET")
- FOREACH(recv_arg2 "void *" "char *")
- FOREACH(recv_arg3 "size_t" "int" "socklen_t" "unsigned int")
- FOREACH(recv_arg4 "int" "unsigned int")
- IF(NOT curl_cv_func_recv_done)
- SET(curl_cv_func_recv_test "UNKNOWN")
- SET(extern_line "extern ${recv_retv} ${signature_call_conv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})\;")
- SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
- CURL_CHECK_C_SOURCE_COMPILES("
+check_c_source_compiles("${_source_epilogue}
+int main(void) {
+ recv(0, 0, 0, 0);
+ return 0;
+}" curl_cv_recv)
+if(curl_cv_recv)
+ if(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
+ foreach(recv_retv "int" "ssize_t" )
+ foreach(recv_arg1 "int" "ssize_t" "SOCKET")
+ foreach(recv_arg2 "void *" "char *")
+ foreach(recv_arg3 "size_t" "int" "socklen_t" "unsigned int")
+ foreach(recv_arg4 "int" "unsigned int")
+ if(NOT curl_cv_func_recv_done)
+ unset(curl_cv_func_recv_test CACHE)
+ check_c_source_compiles("
+ ${_source_epilogue}
+ extern ${recv_retv} ${signature_call_conv}
+ recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4});
+ int main(void) {
${recv_arg1} s=0;
${recv_arg2} buf=0;
${recv_arg3} len=0;
${recv_arg4} flags=0;
- ${recv_retv} res = recv(s, buf, len, flags)"
- curl_cv_func_recv_test
- "${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})")
- IF(curl_cv_func_recv_test)
- SET(curl_cv_func_recv_args
+ ${recv_retv} res = recv(s, buf, len, flags);
+ (void) res;
+ return 0;
+ }"
+ curl_cv_func_recv_test)
+ message(STATUS
+ "Tested: ${recv_retv} recv(${recv_arg1}, ${recv_arg2}, ${recv_arg3}, ${recv_arg4})")
+ if(curl_cv_func_recv_test)
+ set(curl_cv_func_recv_args
"${recv_arg1},${recv_arg2},${recv_arg3},${recv_arg4},${recv_retv}")
- SET(RECV_TYPE_ARG1 "${recv_arg1}")
- SET(RECV_TYPE_ARG2 "${recv_arg2}")
- SET(RECV_TYPE_ARG3 "${recv_arg3}")
- SET(RECV_TYPE_ARG4 "${recv_arg4}")
- SET(RECV_TYPE_RETV "${recv_retv}")
- SET(HAVE_RECV 1)
- SET(curl_cv_func_recv_done 1)
- ENDIF(curl_cv_func_recv_test)
- ENDIF(NOT curl_cv_func_recv_done)
- ENDFOREACH(recv_arg4)
- ENDFOREACH(recv_arg3)
- ENDFOREACH(recv_arg2)
- ENDFOREACH(recv_arg1)
- ENDFOREACH(recv_retv)
- ELSE(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
- STRING(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG1 "${curl_cv_func_recv_args}")
- STRING(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG2 "${curl_cv_func_recv_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG3 "${curl_cv_func_recv_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" RECV_TYPE_ARG4 "${curl_cv_func_recv_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}")
- #MESSAGE("RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}")
- #MESSAGE("RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}")
- #MESSAGE("RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}")
- #MESSAGE("RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}")
- #MESSAGE("RECV_TYPE_RETV ${RECV_TYPE_RETV}")
- ENDIF(NOT DEFINED curl_cv_func_recv_args OR "${curl_cv_func_recv_args}" STREQUAL "unknown")
-
- IF("${curl_cv_func_recv_args}" STREQUAL "unknown")
- MESSAGE(FATAL_ERROR "Cannot find proper types to use for recv args")
- ENDIF("${curl_cv_func_recv_args}" STREQUAL "unknown")
-ELSE(curl_cv_recv)
- MESSAGE(FATAL_ERROR "Unable to link function recv")
-ENDIF(curl_cv_recv)
-SET(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv")
-SET(HAVE_RECV 1)
+ set(RECV_TYPE_ARG1 "${recv_arg1}")
+ set(RECV_TYPE_ARG2 "${recv_arg2}")
+ set(RECV_TYPE_ARG3 "${recv_arg3}")
+ set(RECV_TYPE_ARG4 "${recv_arg4}")
+ set(RECV_TYPE_RETV "${recv_retv}")
+ set(HAVE_RECV 1)
+ set(curl_cv_func_recv_done 1)
+ endif(curl_cv_func_recv_test)
+ endif(NOT curl_cv_func_recv_done)
+ endforeach(recv_arg4)
+ endforeach(recv_arg3)
+ endforeach(recv_arg2)
+ endforeach(recv_arg1)
+ endforeach(recv_retv)
+ else()
+ string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG1 "${curl_cv_func_recv_args}")
+ string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG2 "${curl_cv_func_recv_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" RECV_TYPE_ARG3 "${curl_cv_func_recv_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" RECV_TYPE_ARG4 "${curl_cv_func_recv_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" RECV_TYPE_RETV "${curl_cv_func_recv_args}")
+ endif()
-CURL_CHECK_C_SOURCE_COMPILES("send(0, 0, 0, 0)" curl_cv_send)
-IF(curl_cv_send)
- # AC_CACHE_CHECK([types of arguments and return type for send],
- #[curl_cv_func_send_args], [
- #SET(curl_cv_func_send_args "unknown")
- #for send_retv in 'int' 'ssize_t'; do
- IF(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
- FOREACH(send_retv "int" "ssize_t" )
- FOREACH(send_arg1 "int" "ssize_t" "SOCKET")
- FOREACH(send_arg2 "const void *" "void *" "char *" "const char *")
- FOREACH(send_arg3 "size_t" "int" "socklen_t" "unsigned int")
- FOREACH(send_arg4 "int" "unsigned int")
- IF(NOT curl_cv_func_send_done)
- SET(curl_cv_func_send_test "UNKNOWN")
- SET(extern_line "extern ${send_retv} ${signature_call_conv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})\;")
- SET(EXTRA_DEFINES "${EXTRA_DEFINES_BACKUP}\n${headers_hack}\n${extern_line}\n#define __unused5")
- CURL_CHECK_C_SOURCE_COMPILES("
+ if("${curl_cv_func_recv_args}" STREQUAL "unknown")
+ message(FATAL_ERROR "Cannot find proper types to use for recv args")
+ endif("${curl_cv_func_recv_args}" STREQUAL "unknown")
+else(curl_cv_recv)
+ message(FATAL_ERROR "Unable to link function recv")
+endif(curl_cv_recv)
+set(curl_cv_func_recv_args "${curl_cv_func_recv_args}" CACHE INTERNAL "Arguments for recv")
+set(HAVE_RECV 1)
+
+check_c_source_compiles("${_source_epilogue}
+int main(void) {
+ send(0, 0, 0, 0);
+ return 0;
+}" curl_cv_send)
+if(curl_cv_send)
+ if(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
+ foreach(send_retv "int" "ssize_t" )
+ foreach(send_arg1 "int" "ssize_t" "SOCKET")
+ foreach(send_arg2 "const void *" "void *" "char *" "const char *")
+ foreach(send_arg3 "size_t" "int" "socklen_t" "unsigned int")
+ foreach(send_arg4 "int" "unsigned int")
+ if(NOT curl_cv_func_send_done)
+ unset(curl_cv_func_send_test CACHE)
+ check_c_source_compiles("
+ ${_source_epilogue}
+ extern ${send_retv} ${signature_call_conv}
+ send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4});
+ int main(void) {
${send_arg1} s=0;
${send_arg2} buf=0;
${send_arg3} len=0;
${send_arg4} flags=0;
- ${send_retv} res = send(s, buf, len, flags)"
- curl_cv_func_send_test
- "${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})")
- IF(curl_cv_func_send_test)
- #MESSAGE("Found arguments: ${curl_cv_func_send_test}")
- STRING(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}")
- STRING(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}")
- SET(curl_cv_func_send_args
+ ${send_retv} res = send(s, buf, len, flags);
+ (void) res;
+ return 0;
+ }"
+ curl_cv_func_send_test)
+ message(STATUS
+ "Tested: ${send_retv} send(${send_arg1}, ${send_arg2}, ${send_arg3}, ${send_arg4})")
+ if(curl_cv_func_send_test)
+ string(REGEX REPLACE "(const) .*" "\\1" send_qual_arg2 "${send_arg2}")
+ string(REGEX REPLACE "const (.*)" "\\1" send_arg2 "${send_arg2}")
+ set(curl_cv_func_send_args
"${send_arg1},${send_arg2},${send_arg3},${send_arg4},${send_retv},${send_qual_arg2}")
- SET(SEND_TYPE_ARG1 "${send_arg1}")
- SET(SEND_TYPE_ARG2 "${send_arg2}")
- SET(SEND_TYPE_ARG3 "${send_arg3}")
- SET(SEND_TYPE_ARG4 "${send_arg4}")
- SET(SEND_TYPE_RETV "${send_retv}")
- SET(HAVE_SEND 1)
- SET(curl_cv_func_send_done 1)
- ENDIF(curl_cv_func_send_test)
- ENDIF(NOT curl_cv_func_send_done)
- ENDFOREACH(send_arg4)
- ENDFOREACH(send_arg3)
- ENDFOREACH(send_arg2)
- ENDFOREACH(send_arg1)
- ENDFOREACH(send_retv)
- ELSE(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
- STRING(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG1 "${curl_cv_func_send_args}")
- STRING(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG2 "${curl_cv_func_send_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG3 "${curl_cv_func_send_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG4 "${curl_cv_func_send_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" SEND_TYPE_RETV "${curl_cv_func_send_args}")
- STRING(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" SEND_QUAL_ARG2 "${curl_cv_func_send_args}")
- #MESSAGE("SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}")
- #MESSAGE("SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}")
- #MESSAGE("SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}")
- #MESSAGE("SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}")
- #MESSAGE("SEND_TYPE_RETV ${SEND_TYPE_RETV}")
- #MESSAGE("SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}")
- ENDIF(NOT DEFINED curl_cv_func_send_args OR "${curl_cv_func_send_args}" STREQUAL "unknown")
-
- IF("${curl_cv_func_send_args}" STREQUAL "unknown")
- MESSAGE(FATAL_ERROR "Cannot find proper types to use for send args")
- ENDIF("${curl_cv_func_send_args}" STREQUAL "unknown")
- SET(SEND_QUAL_ARG2 "const")
-ELSE(curl_cv_send)
- MESSAGE(FATAL_ERROR "Unable to link function send")
-ENDIF(curl_cv_send)
-SET(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send")
-SET(HAVE_SEND 1)
-
-SET(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5")
-CURL_CHECK_C_SOURCE_COMPILES("int flag = MSG_NOSIGNAL" HAVE_MSG_NOSIGNAL)
+ set(SEND_TYPE_ARG1 "${send_arg1}")
+ set(SEND_TYPE_ARG2 "${send_arg2}")
+ set(SEND_TYPE_ARG3 "${send_arg3}")
+ set(SEND_TYPE_ARG4 "${send_arg4}")
+ set(SEND_TYPE_RETV "${send_retv}")
+ set(HAVE_SEND 1)
+ set(curl_cv_func_send_done 1)
+ endif(curl_cv_func_send_test)
+ endif(NOT curl_cv_func_send_done)
+ endforeach(send_arg4)
+ endforeach(send_arg3)
+ endforeach(send_arg2)
+ endforeach(send_arg1)
+ endforeach(send_retv)
+ else()
+ string(REGEX REPLACE "^([^,]*),[^,]*,[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG1 "${curl_cv_func_send_args}")
+ string(REGEX REPLACE "^[^,]*,([^,]*),[^,]*,[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG2 "${curl_cv_func_send_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,([^,]*),[^,]*,[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG3 "${curl_cv_func_send_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,([^,]*),[^,]*,[^,]*$" "\\1" SEND_TYPE_ARG4 "${curl_cv_func_send_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,([^,]*),[^,]*$" "\\1" SEND_TYPE_RETV "${curl_cv_func_send_args}")
+ string(REGEX REPLACE "^[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,([^,]*)$" "\\1" SEND_QUAL_ARG2 "${curl_cv_func_send_args}")
+ endif()
-SET(EXTRA_DEFINES "__unused1\n#undef inline\n#define __unused2")
-SET(HEADER_INCLUDES)
-SET(headers_hack)
+ if("${curl_cv_func_send_args}" STREQUAL "unknown")
+ message(FATAL_ERROR "Cannot find proper types to use for send args")
+ endif("${curl_cv_func_send_args}" STREQUAL "unknown")
+ set(SEND_QUAL_ARG2 "const")
+else(curl_cv_send)
+ message(FATAL_ERROR "Unable to link function send")
+endif(curl_cv_send)
+set(curl_cv_func_send_args "${curl_cv_func_send_args}" CACHE INTERNAL "Arguments for send")
+set(HAVE_SEND 1)
-MACRO(add_header_include check header)
- IF(${check})
- SET(headers_hack
- "${headers_hack}\n#include <${header}>")
- #SET(HEADER_INCLUDES
- # ${HEADER_INCLUDES}
- # "${header}")
- ENDIF(${check})
-ENDMACRO(add_header_include header)
+check_c_source_compiles("${_source_epilogue}
+ int main(void) {
+ int flag = MSG_NOSIGNAL;
+ (void)flag;
+ return 0;
+ }" HAVE_MSG_NOSIGNAL)
-IF(HAVE_WINDOWS_H)
- SET(EXTRA_DEFINES ${EXTRA_DEFINES}
- "__unused7\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif\n#define __unused3")
- add_header_include(HAVE_WINDOWS_H "windows.h")
- add_header_include(HAVE_WINSOCK2_H "winsock2.h")
- add_header_include(HAVE_WINSOCK_H "winsock.h")
-ELSE(HAVE_WINDOWS_H)
- add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
+if(NOT HAVE_WINDOWS_H)
add_header_include(HAVE_SYS_TIME_H "sys/time.h")
add_header_include(TIME_WITH_SYS_TIME "time.h")
add_header_include(HAVE_TIME_H "time.h")
-ENDIF(HAVE_WINDOWS_H)
-SET(EXTRA_DEFINES "${EXTRA_DEFINES}\n${headers_hack}\n#define __unused5")
-CURL_CHECK_C_SOURCE_COMPILES("struct timeval ts;\nts.tv_sec = 0;\nts.tv_usec = 0" HAVE_STRUCT_TIMEVAL)
+endif()
+check_c_source_compiles("${_source_epilogue}
+int main(void) {
+ struct timeval ts;
+ ts.tv_sec = 0;
+ ts.tv_usec = 0;
+ (void)ts;
+ return 0;
+}" HAVE_STRUCT_TIMEVAL)
-SET(HAVE_SIG_ATOMIC_T 1)
-SET(EXTRA_DEFINES)
-SET(HEADER_INCLUDES)
-IF(HAVE_SIGNAL_H)
- SET(HEADER_INCLUDES "signal.h")
- SET(CMAKE_EXTRA_INCLUDE_FILES "signal.h")
-ENDIF(HAVE_SIGNAL_H)
-CHECK_TYPE_SIZE("sig_atomic_t" SIZEOF_SIG_ATOMIC_T)
-IF(HAVE_SIZEOF_SIG_ATOMIC_T)
- CURL_CHECK_C_SOURCE_COMPILES("static volatile sig_atomic_t dummy = 0" HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
- IF(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
- SET(HAVE_SIG_ATOMIC_T_VOLATILE 1)
- ENDIF(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
-ENDIF(HAVE_SIZEOF_SIG_ATOMIC_T)
+include(CheckCSourceRuns)
+# See HAVE_POLL in CMakeLists.txt for why poll is disabled on macOS
+if(NOT APPLE)
+ set(CMAKE_REQUIRED_FLAGS)
+ if(HAVE_SYS_POLL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_SYS_POLL_H")
+ endif(HAVE_SYS_POLL_H)
+ check_c_source_runs("
+ #ifdef HAVE_SYS_POLL_H
+ # include <sys/poll.h>
+ #endif
+ int main(void) {
+ return poll((void *)0, 0, 10 /*ms*/);
+ }" HAVE_POLL_FINE)
+endif()
-SET(CHECK_TYPE_SIZE_PREINCLUDE
- "#undef inline")
+set(HAVE_SIG_ATOMIC_T 1)
+set(CMAKE_REQUIRED_FLAGS)
+if(HAVE_SIGNAL_H)
+ set(CMAKE_REQUIRED_FLAGS "-DHAVE_SIGNAL_H")
+ set(CMAKE_EXTRA_INCLUDE_FILES "signal.h")
+endif(HAVE_SIGNAL_H)
+check_type_size("sig_atomic_t" SIZEOF_SIG_ATOMIC_T)
+if(HAVE_SIZEOF_SIG_ATOMIC_T)
+ check_c_source_compiles("
+ #ifdef HAVE_SIGNAL_H
+ # include <signal.h>
+ #endif
+ int main(void) {
+ static volatile sig_atomic_t dummy = 0;
+ (void)dummy;
+ return 0;
+ }" HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+ if(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+ set(HAVE_SIG_ATOMIC_T_VOLATILE 1)
+ endif(NOT HAVE_SIG_ATOMIC_T_NOT_VOLATILE)
+endif(HAVE_SIZEOF_SIG_ATOMIC_T)
-IF(HAVE_WINDOWS_H)
- SET(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE}
- #ifndef WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #endif
- #include <windows.h>")
- IF(HAVE_WINSOCK2_H)
- SET(CHECK_TYPE_SIZE_PREINCLUDE "${CHECK_TYPE_SIZE_PREINCLUDE}\n#include <winsock2.h>")
- ENDIF(HAVE_WINSOCK2_H)
-ELSE(HAVE_WINDOWS_H)
- IF(HAVE_SYS_SOCKET_H)
- SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
- "sys/socket.h")
- ENDIF(HAVE_SYS_SOCKET_H)
- IF(HAVE_NETINET_IN_H)
- SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
- "netinet/in.h")
- ENDIF(HAVE_NETINET_IN_H)
- IF(HAVE_ARPA_INET_H)
- SET(CMAKE_EXTRA_INCLUDE_FILES ${CMAKE_EXTRA_INCLUDE_FILES}
- "arpa/inet.h")
- ENDIF(HAVE_ARPA_INET_H)
-ENDIF(HAVE_WINDOWS_H)
+if(HAVE_WINDOWS_H)
+ set(CMAKE_EXTRA_INCLUDE_FILES winsock2.h)
+else()
+ set(CMAKE_EXTRA_INCLUDE_FILES)
+ if(HAVE_SYS_SOCKET_H)
+ set(CMAKE_EXTRA_INCLUDE_FILES sys/socket.h)
+ endif(HAVE_SYS_SOCKET_H)
+endif()
-CHECK_TYPE_SIZE("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
-IF(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
- SET(HAVE_STRUCT_SOCKADDR_STORAGE 1)
-ENDIF(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
+check_type_size("struct sockaddr_storage" SIZEOF_STRUCT_SOCKADDR_STORAGE)
+if(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
+ set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+endif(HAVE_SIZEOF_STRUCT_SOCKADDR_STORAGE)
diff --git a/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
new file mode 100644
index 000000000..53d0a5e88
--- /dev/null
+++ b/Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
@@ -0,0 +1,122 @@
+if(NOT UNIX)
+ if(WIN32)
+ set(HAVE_LIBDL 0)
+ set(HAVE_LIBUCB 0)
+ set(HAVE_LIBSOCKET 0)
+ set(NOT_NEED_LIBNSL 0)
+ set(HAVE_LIBNSL 0)
+ set(HAVE_GETHOSTNAME 1)
+ set(HAVE_LIBZ 0)
+ set(HAVE_LIBCRYPTO 0)
+
+ set(HAVE_DLOPEN 0)
+
+ set(HAVE_ALLOCA_H 0)
+ set(HAVE_ARPA_INET_H 0)
+ set(HAVE_DLFCN_H 0)
+ set(HAVE_FCNTL_H 1)
+ set(HAVE_INTTYPES_H 0)
+ set(HAVE_IO_H 1)
+ set(HAVE_MALLOC_H 1)
+ set(HAVE_MEMORY_H 1)
+ set(HAVE_NETDB_H 0)
+ set(HAVE_NETINET_IF_ETHER_H 0)
+ set(HAVE_NETINET_IN_H 0)
+ set(HAVE_NET_IF_H 0)
+ set(HAVE_PROCESS_H 1)
+ set(HAVE_PWD_H 0)
+ set(HAVE_SETJMP_H 1)
+ set(HAVE_SGTTY_H 0)
+ set(HAVE_SIGNAL_H 1)
+ set(HAVE_SOCKIO_H 0)
+ set(HAVE_STDINT_H 0)
+ set(HAVE_STDLIB_H 1)
+ set(HAVE_STRINGS_H 0)
+ set(HAVE_STRING_H 1)
+ set(HAVE_SYS_PARAM_H 0)
+ set(HAVE_SYS_POLL_H 0)
+ set(HAVE_SYS_SELECT_H 0)
+ set(HAVE_SYS_SOCKET_H 0)
+ set(HAVE_SYS_SOCKIO_H 0)
+ set(HAVE_SYS_STAT_H 1)
+ set(HAVE_SYS_TIME_H 0)
+ set(HAVE_SYS_TYPES_H 1)
+ set(HAVE_SYS_UTIME_H 1)
+ set(HAVE_TERMIOS_H 0)
+ set(HAVE_TERMIO_H 0)
+ set(HAVE_TIME_H 1)
+ set(HAVE_UNISTD_H 0)
+ set(HAVE_UTIME_H 0)
+ set(HAVE_X509_H 0)
+ set(HAVE_ZLIB_H 0)
+
+ set(HAVE_SOCKET 1)
+ set(HAVE_POLL 0)
+ set(HAVE_SELECT 1)
+ set(HAVE_STRDUP 1)
+ set(HAVE_STRSTR 1)
+ set(HAVE_STRTOK_R 0)
+ set(HAVE_STRFTIME 1)
+ set(HAVE_UNAME 0)
+ set(HAVE_STRCASECMP 0)
+ set(HAVE_STRICMP 1)
+ set(HAVE_STRCMPI 1)
+ set(HAVE_GETHOSTBYADDR 1)
+ set(HAVE_GETTIMEOFDAY 0)
+ set(HAVE_INET_ADDR 1)
+ set(HAVE_INET_NTOA 1)
+ set(HAVE_INET_NTOA_R 0)
+ set(HAVE_TCGETATTR 0)
+ set(HAVE_TCSETATTR 0)
+ set(HAVE_PERROR 1)
+ set(HAVE_CLOSESOCKET 1)
+ set(HAVE_SETVBUF 0)
+ set(HAVE_SIGSETJMP 0)
+ set(HAVE_GETPASS_R 0)
+ set(HAVE_STRLCAT 0)
+ set(HAVE_GETPWUID 0)
+ set(HAVE_GETEUID 0)
+ set(HAVE_UTIME 1)
+ set(HAVE_RAND_EGD 0)
+ set(HAVE_RAND_SCREEN 0)
+ set(HAVE_RAND_STATUS 0)
+ set(HAVE_GMTIME_R 0)
+ set(HAVE_LOCALTIME_R 0)
+ set(HAVE_GETHOSTBYADDR_R 0)
+ set(HAVE_GETHOSTBYNAME_R 0)
+ set(HAVE_SIGNAL_FUNC 1)
+ set(HAVE_SIGNAL_MACRO 0)
+
+ set(HAVE_GETHOSTBYADDR_R_5 0)
+ set(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0)
+ set(HAVE_GETHOSTBYADDR_R_7 0)
+ set(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0)
+ set(HAVE_GETHOSTBYADDR_R_8 0)
+ set(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0)
+ set(HAVE_GETHOSTBYNAME_R_3 0)
+ set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
+ set(HAVE_GETHOSTBYNAME_R_5 0)
+ set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
+ set(HAVE_GETHOSTBYNAME_R_6 0)
+ set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
+
+ set(TIME_WITH_SYS_TIME 0)
+ set(HAVE_O_NONBLOCK 0)
+ set(HAVE_IN_ADDR_T 0)
+ set(HAVE_INET_NTOA_R_DECL 0)
+ set(HAVE_INET_NTOA_R_DECL_REENTRANT 0)
+ if(ENABLE_IPV6)
+ set(HAVE_GETADDRINFO 1)
+ else()
+ set(HAVE_GETADDRINFO 0)
+ endif()
+ set(STDC_HEADERS 1)
+ set(RETSIGTYPE_TEST 1)
+
+ set(HAVE_SIGACTION 0)
+ set(HAVE_MACRO_SIGSETJMP 0)
+ else(WIN32)
+ message("This file should be included on Windows platform only")
+ endif(WIN32)
+endif(NOT UNIX)
+
diff --git a/Utilities/cmcurl/CMake/Utilities.cmake b/Utilities/cmcurl/CMake/Utilities.cmake
new file mode 100644
index 000000000..8b6276df6
--- /dev/null
+++ b/Utilities/cmcurl/CMake/Utilities.cmake
@@ -0,0 +1,44 @@
+# File containing various utilities
+
+# Converts a CMake list to a string containing elements separated by spaces
+function(TO_LIST_SPACES _LIST_NAME OUTPUT_VAR)
+ set(NEW_LIST_SPACE)
+ foreach(ITEM ${${_LIST_NAME}})
+ set(NEW_LIST_SPACE "${NEW_LIST_SPACE} ${ITEM}")
+ endforeach()
+ string(STRIP ${NEW_LIST_SPACE} NEW_LIST_SPACE)
+ set(${OUTPUT_VAR} "${NEW_LIST_SPACE}" PARENT_SCOPE)
+endfunction()
+
+# Appends a lis of item to a string which is a space-separated list, if they don't already exist.
+function(LIST_SPACES_APPEND_ONCE LIST_NAME)
+ string(REPLACE " " ";" _LIST ${${LIST_NAME}})
+ list(APPEND _LIST ${ARGN})
+ list(REMOVE_DUPLICATES _LIST)
+ to_list_spaces(_LIST NEW_LIST_SPACE)
+ set(${LIST_NAME} "${NEW_LIST_SPACE}" PARENT_SCOPE)
+endfunction()
+
+# Convinience function that does the same as LIST(FIND ...) but with a TRUE/FALSE return value.
+# Ex: IN_STR_LIST(MY_LIST "Searched item" WAS_FOUND)
+function(IN_STR_LIST LIST_NAME ITEM_SEARCHED RETVAL)
+ list(FIND ${LIST_NAME} ${ITEM_SEARCHED} FIND_POS)
+ if(${FIND_POS} EQUAL -1)
+ set(${RETVAL} FALSE PARENT_SCOPE)
+ else()
+ set(${RETVAL} TRUE PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Returns a list of arguments that evaluate to true
+function(collect_true output_var output_count_var)
+ set(${output_var})
+ foreach(option_var IN LISTS ARGN)
+ if(${option_var})
+ list(APPEND ${output_var} ${option_var})
+ endif()
+ endforeach()
+ set(${output_var} ${${output_var}} PARENT_SCOPE)
+ list(LENGTH ${output_var} ${output_count_var})
+ set(${output_count_var} ${${output_count_var}} PARENT_SCOPE)
+endfunction()
diff --git a/Utilities/cmcurl/CMakeLists.txt b/Utilities/cmcurl/CMakeLists.txt
index 74a713dd8..d85f366c0 100644
--- a/Utilities/cmcurl/CMakeLists.txt
+++ b/Utilities/cmcurl/CMakeLists.txt
@@ -1,549 +1,1051 @@
-CMAKE_MINIMUM_REQUIRED(VERSION 2.6.3 FATAL_ERROR)
-PROJECT(LIBCURL C)
+# Set curl options as needed for CMake build
+set(BUILD_CURL_EXE OFF CACHE INTERNAL "No curl exe")
+set(BUILD_DASHBOARD_REPORTS OFF CACHE INTERNAL "No curl dashboard reports")
+set(BUILD_RELEASE_DEBUG_DIRS OFF CACHE INTERNAL "No curl release/debug dirs")
+set(CMAKE_USE_GSSAPI OFF CACHE INTERNAL "Disable curl gssapi")
+set(CMAKE_USE_LIBSSH2 OFF CACHE INTERNAL "Disable curl libssh2")
+set(CMAKE_USE_OPENLDAP OFF CACHE INTERNAL "No curl OpenLDAP")
+set(CURL_DISABLE_COOKIES OFF CACHE INTERNAL "Do not disable curl cookie support")
+set(CURL_DISABLE_CRYPTO_AUTH OFF CACHE INTERNAL "Do not disable curl crypto auth")
+set(CURL_DISABLE_DICT ON CACHE INTERNAL "Disable curl dict protocol?")
+set(CURL_DISABLE_FILE OFF CACHE INTERNAL "Disable curl file protocol?")
+set(CURL_DISABLE_FTP OFF CACHE INTERNAL "Disable curl ftp protocol?")
+set(CURL_DISABLE_GOPHER ON CACHE INTERNAL "Disable curl gopher protocol?")
+set(CURL_DISABLE_HTTP OFF CACHE INTERNAL "Disable curl http protocol?")
+set(CURL_DISABLE_IMAP ON CACHE INTERNAL "Disable curl imap protocol?")
+set(CURL_DISABLE_LDAP ON CACHE INTERNAL "Disable curl ldap protocol?")
+set(CURL_DISABLE_LDAPS ON CACHE INTERNAL "Disable curl ldaps protocol?")
+set(CURL_DISABLE_POP3 ON CACHE INTERNAL "Disable curl pop3 protocol?")
+set(CURL_DISABLE_PROXY OFF CACHE INTERNAL "Do not disable curl proxy")
+set(CURL_DISABLE_RTSP ON CACHE INTERNAL "Disable curl rtsp protocol?")
+set(CURL_DISABLE_SMTP ON CACHE INTERNAL "Disable curl smtp protocol?")
+set(CURL_DISABLE_TELNET ON CACHE INTERNAL "Disable curl telnet protocol?")
+set(CURL_DISABLE_TFTP ON CACHE INTERNAL "Disable curl tftp protocol?")
+set(CURL_DISABLE_VERBOSE_STRINGS OFF CACHE INTERNAL "Do not disable curl verbosity")
+set(CURL_HIDDEN_SYMBOLS OFF CACHE INTERNAL "No curl hidden symbols")
+set(CURL_STATICLIB ON CACHE INTERNAL "Static curl")
+set(DISABLED_THREADSAFE OFF CACHE INTERNAL "Curl can use thread-safe functions")
+set(ENABLE_ARES OFF CACHE INTERNAL "No curl c-ares support")
+set(ENABLE_CURLDEBUG OFF CACHE INTERNAL "No curl TrackMemory features")
+set(ENABLE_DEBUG OFF CACHE INTERNAL "No curl debug features")
+set(ENABLE_IPV6 OFF CACHE INTERNAL "No curl IPv6 support")
+set(ENABLE_MANUAL OFF CACHE INTERNAL "No curl built-in manual")
+set(ENABLE_THREADED_RESOLVER OFF CACHE INTERNAL "No curl POSIX threaded DNS lookup")
+set(ENABLE_UNIX_SOCKETS OFF CACHE INTERNAL "No curl Unix domain sockets support")
+set(HTTP_ONLY OFF CACHE INTERNAL "Curl is not http-only")
+set(USE_WIN32_LDAP OFF CACHE INTERNAL "No curl Windows LDAP")
+if(CMAKE_USE_OPENSSL)
+elseif(WIN32)
+ set(CMAKE_USE_WINSSL ON CACHE INTERNAL "enable Windows native SSL/TLS")
+ set(CURL_WINDOWS_SSPI ON CACHE INTERNAL "Use windows libraries to allow NTLM authentication without openssl")
+elseif(APPLE)
+ # Use OS X SSL/TLS native implementation if available on target version.
+ if(CMAKE_OSX_DEPLOYMENT_TARGET)
+ set(OSX_VERSION ${CMAKE_OSX_DEPLOYMENT_TARGET})
+ else()
+ execute_process(
+ COMMAND sw_vers -productVersion
+ OUTPUT_VARIABLE OSX_VERSION
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ endif()
+ if(NOT OSX_VERSION VERSION_LESS 10.6 AND
+ CMAKE_C_COMPILER_ID MATCHES "GNU|Clang|AppleClang")
+ set(CMAKE_USE_DARWINSSL ON CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ else()
+ set(CMAKE_USE_DARWINSSL OFF CACHE INTERNAL "enable Apple OS native SSL/TLS")
+ endif()
+endif()
+set(CMAKE_USE_MBEDTLS OFF CACHE INTERNAL "Enable mbedTLS for SSL/TLS")
+
+# Windows Vista and above have inet_pton, but this will link on
+# older versions and then the executable will fail to launch at
+# runtime on older versions because no DLL provides the symbol.
+if(WIN32)
+ set(HAVE_INET_PTON 0 CACHE INTERNAL "Do not use inet_pton")
+endif()
+
+# Starting with OSX 10.11 there is an unrelated libnetwork library which will
+# be picked up during curl configuration. Linking against this library is
+# unnecessary and breaks backward compatibility of the resulting binaries
+# because libnetwork is unavailable on older OSX versions.
+if(APPLE)
+ set(HAVE_LIBNETWORK 0 CACHE INTERNAL "Do not use libnetwork")
+endif(APPLE)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
+# curl/libcurl CMake script
+# by Tetetest and Sukender (Benoit Neil)
+
+# TODO:
+# The output .so file lacks the soname number which we currently have within the lib/Makefile.am file
+# Add full (4 or 5 libs) SSL support
+# Add INSTALL target (EXTRA_DIST variables in Makefile.am may be moved to Makefile.inc so that CMake/CPack is aware of what's to include).
+# Add CTests(?)
+# Check on all possible platforms
+# Test with as many configurations possible (With or without any option)
+# Create scripts that help keeping the CMake build system up to date (to reduce maintenance). According to Tetetest:
+# - lists of headers that 'configure' checks for;
+# - curl-specific tests (the ones that are in m4/curl-*.m4 files);
+# - (most obvious thing:) curl version numbers.
+# Add documentation subproject
+#
+# To check:
+# (From Daniel Stenberg) The cmake build selected to run gcc with -fPIC on my box while the plain configure script did not.
+# (From Daniel Stenberg) The gcc command line use neither -g nor any -O options. As a developer, I also treasure our configure scripts's --enable-debug option that sets a long range of "picky" compiler options.
+cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
+set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake;${CMAKE_MODULE_PATH}")
+include(Utilities)
+include(Macros)
+include(CMakeDependentOption)
+
+project( CURL C )
+
+if(0) # This code not needed for building within CMake.
+message(WARNING "the curl cmake build system is poorly maintained. Be aware")
+endif()
+
+file (READ ${CURL_SOURCE_DIR}/include/curl/curlver.h CURL_VERSION_H_CONTENTS)
+string (REGEX MATCH "#define LIBCURL_VERSION \"[^\"]*"
+ CURL_VERSION ${CURL_VERSION_H_CONTENTS})
+string (REGEX REPLACE "[^\"]+\"" "" CURL_VERSION ${CURL_VERSION})
+string (REGEX MATCH "#define LIBCURL_VERSION_NUM 0x[0-9a-fA-F]+"
+ CURL_VERSION_NUM ${CURL_VERSION_H_CONTENTS})
+string (REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})
+
+include_regular_expression("^.*$") # Sukender: Is it necessary?
# Setup package meta-data
-SET(PACKAGE "curl")
-SET(VERSION "7.16.1")
-SET(PACKAGE_TARNAME "curl")
-SET(PACKAGE_BUGREPORT " ")
-SET(PACKAGE_NAME "curl")
-SET(PACKAGE_VERSION "-")
-SET(PACKAGE_STRING "curl-")
-SET(PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/")
-SET(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
+# SET(PACKAGE "curl")
+if(0) # This code not needed for building within CMake.
+message(STATUS "curl version=[${CURL_VERSION}]")
+endif()
+# SET(PACKAGE_TARNAME "curl")
+# SET(PACKAGE_NAME "curl")
+# SET(PACKAGE_VERSION "-")
+# SET(PACKAGE_STRING "curl-")
+# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.haxx.se/mail/")
+set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
+set(OS "\"${CMAKE_SYSTEM_NAME}\"")
+
+include_directories(${PROJECT_BINARY_DIR}/include/curl)
+include_directories( ${CURL_SOURCE_DIR}/include )
+
+option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
+option(CURL_STATICLIB "Set to ON to build libcurl with static linking." OFF)
+option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
+if(WIN32)
+ CMAKE_DEPENDENT_OPTION(ENABLE_THREADED_RESOLVER
+ "Set to ON to enable threaded DNS lookup"
+ ON "NOT ENABLE_ARES"
+ OFF)
+else()
+ option(ENABLE_THREADED_RESOLVER "Set to ON to enable POSIX threaded DNS lookup" OFF)
+endif()
+option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
+option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
+
+if (ENABLE_DEBUG)
+ # DEBUGBUILD will be defined only for Debug builds
+ if(NOT CMAKE_VERSION VERSION_LESS 3.0)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
+ else()
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_DEBUG DEBUGBUILD)
+ endif()
+ set(ENABLE_CURLDEBUG ON)
+endif()
+
+if (ENABLE_CURLDEBUG)
+ set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS CURLDEBUG)
+endif()
+
+# initialize CURL_LIBS
+set(CURL_LIBS "")
+
+if(ENABLE_THREADED_RESOLVER AND ENABLE_ARES)
+ message(FATAL_ERROR "Options ENABLE_THREADED_RESOLVER and ENABLE_ARES are mutually exclusive")
+endif()
+
+if(ENABLE_ARES)
+ set(USE_ARES 1)
+ find_package(CARES REQUIRED)
+ list(APPEND CURL_LIBS ${CARES_LIBRARY} )
+ set(CURL_LIBS ${CURL_LIBS} ${CARES_LIBRARY})
+endif()
+
+if(MSVC)
+ option(BUILD_RELEASE_DEBUG_DIRS "Set OFF to build each configuration to a separate directory" OFF)
+ mark_as_advanced(BUILD_RELEASE_DEBUG_DIRS)
+endif()
+
+if(0) # This code not needed for building within CMake.
+include(CurlSymbolHiding)
+endif()
+
+option(HTTP_ONLY "disables all protocols except HTTP (This overrides all CURL_DISABLE_* options)" OFF)
+mark_as_advanced(HTTP_ONLY)
+option(CURL_DISABLE_FTP "disables FTP" OFF)
+mark_as_advanced(CURL_DISABLE_FTP)
+option(CURL_DISABLE_LDAP "disables LDAP" OFF)
+mark_as_advanced(CURL_DISABLE_LDAP)
+option(CURL_DISABLE_TELNET "disables Telnet" OFF)
+mark_as_advanced(CURL_DISABLE_TELNET)
+option(CURL_DISABLE_DICT "disables DICT" OFF)
+mark_as_advanced(CURL_DISABLE_DICT)
+option(CURL_DISABLE_FILE "disables FILE" OFF)
+mark_as_advanced(CURL_DISABLE_FILE)
+option(CURL_DISABLE_TFTP "disables TFTP" OFF)
+mark_as_advanced(CURL_DISABLE_TFTP)
+option(CURL_DISABLE_HTTP "disables HTTP" OFF)
+mark_as_advanced(CURL_DISABLE_HTTP)
+
+option(CURL_DISABLE_LDAPS "to disable LDAPS" OFF)
+mark_as_advanced(CURL_DISABLE_LDAPS)
+
+option(CURL_DISABLE_RTSP "to disable RTSP" OFF)
+mark_as_advanced(CURL_DISABLE_RTSP)
+option(CURL_DISABLE_PROXY "to disable proxy" OFF)
+mark_as_advanced(CURL_DISABLE_PROXY)
+option(CURL_DISABLE_POP3 "to disable POP3" OFF)
+mark_as_advanced(CURL_DISABLE_POP3)
+option(CURL_DISABLE_IMAP "to disable IMAP" OFF)
+mark_as_advanced(CURL_DISABLE_IMAP)
+option(CURL_DISABLE_SMTP "to disable SMTP" OFF)
+mark_as_advanced(CURL_DISABLE_SMTP)
+option(CURL_DISABLE_GOPHER "to disable Gopher" OFF)
+mark_as_advanced(CURL_DISABLE_GOPHER)
+
+if(HTTP_ONLY)
+ set(CURL_DISABLE_FTP ON)
+ set(CURL_DISABLE_LDAP ON)
+ set(CURL_DISABLE_LDAPS ON)
+ set(CURL_DISABLE_TELNET ON)
+ set(CURL_DISABLE_DICT ON)
+ set(CURL_DISABLE_FILE ON)
+ set(CURL_DISABLE_TFTP ON)
+ set(CURL_DISABLE_RTSP ON)
+ set(CURL_DISABLE_POP3 ON)
+ set(CURL_DISABLE_IMAP ON)
+ set(CURL_DISABLE_SMTP ON)
+ set(CURL_DISABLE_GOPHER ON)
+endif()
+
+option(CURL_DISABLE_COOKIES "to disable cookies support" OFF)
+mark_as_advanced(CURL_DISABLE_COOKIES)
+
+option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
+mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
+option(CURL_DISABLE_VERBOSE_STRINGS "to disable verbose strings" OFF)
+mark_as_advanced(CURL_DISABLE_VERBOSE_STRINGS)
+option(DISABLED_THREADSAFE "Set to explicitly specify we don't want to use thread-safe functions" OFF)
+mark_as_advanced(DISABLED_THREADSAFE)
+option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
+mark_as_advanced(ENABLE_IPV6)
+if(ENABLE_IPV6 AND NOT WIN32)
+ include(CheckStructHasMember)
+ check_struct_has_member("struct sockaddr_in6" sin6_addr "netinet/in.h"
+ HAVE_SOCKADDR_IN6_SIN6_ADDR)
+ check_struct_has_member("struct sockaddr_in6" sin6_scope_id "netinet/in.h"
+ HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if(NOT HAVE_SOCKADDR_IN6_SIN6_ADDR)
+ message(WARNING "struct sockaddr_in6 not available, disabling IPv6 support")
+ # Force the feature off as this name is used as guard macro...
+ set(ENABLE_IPV6 OFF
+ CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
+ endif()
+endif()
+
+option(ENABLE_MANUAL "to provide the built-in manual" ON)
+unset(USE_MANUAL CACHE) # TODO: cache NROFF/NROFF_MANOPT/USE_MANUAL vars?
+if(ENABLE_MANUAL)
+ find_program(NROFF NAMES gnroff nroff)
+ if(NROFF)
+ # Need a way to write to stdin, this will do
+ file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt" "test")
+ # Tests for a valid nroff option to generate a manpage
+ foreach(_MANOPT "-man" "-mandoc")
+ execute_process(COMMAND "${NROFF}" ${_MANOPT}
+ OUTPUT_VARIABLE NROFF_MANOPT_OUTPUT
+ INPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt"
+ ERROR_QUIET)
+ # Save the option if it was valid
+ if(NROFF_MANOPT_OUTPUT)
+ message("Found *nroff option: -- ${_MANOPT}")
+ set(NROFF_MANOPT ${_MANOPT})
+ set(USE_MANUAL 1)
+ break()
+ endif()
+ endforeach()
+ # No need for the temporary file
+ file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/nroff-input.txt")
+ if(NOT USE_MANUAL)
+ message(WARNING "Found no *nroff option to get plaintext from man pages")
+ endif()
+ else()
+ message(WARNING "Found no *nroff program")
+ endif()
+endif()
+
+if(0) # This code not needed for building within CMake.
+# Required for building manual, docs, tests
+find_package(Perl REQUIRED)
+endif()
# We need ansi c-flags, especially on HP
-SET(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
-SET(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
+set(CMAKE_C_FLAGS "${CMAKE_ANSI_CFLAGS} ${CMAKE_C_FLAGS}")
+set(CMAKE_REQUIRED_FLAGS ${CMAKE_ANSI_CFLAGS})
# Disable warnings on Borland to avoid changing 3rd party code.
-IF(BORLAND)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
-ENDIF(BORLAND)
+if(BORLAND)
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
+endif(BORLAND)
# If we are on AIX, do the _ALL_SOURCE magic
-IF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
- SET(_ALL_SOURCE 1)
-ENDIF(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+if(${CMAKE_SYSTEM_NAME} MATCHES AIX)
+ set(_ALL_SOURCE 1)
+endif(${CMAKE_SYSTEM_NAME} MATCHES AIX)
# Include all the necessary files for macros
-SET(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
-INCLUDE (CheckFunctionExists)
-INCLUDE (CheckIncludeFile)
-INCLUDE (CheckIncludeFiles)
-INCLUDE (CheckLibraryExists)
-INCLUDE (CheckSymbolExists)
-INCLUDE (CheckTypeSize)
-
-SET(libCurl_SRCS
- # amigaos.c - does not build on AmigaOS
- base64.c
- connect.c
- content_encoding.c
- cookie.c
- dict.c
- easy.c
- escape.c
- file.c
- formdata.c
- ftp.c
- getenv.c
- getinfo.c
- gtls.c
- hash.c
- hostares.c
- hostasyn.c
- hostip4.c
- hostip6.c
- hostip.c
- hostsyn.c
- hostthre.c
- http.c
- http_chunks.c
- http_digest.c
- http_negotiate.c
- http_ntlm.c
- if2ip.c
- inet_ntop.c
- inet_pton.c
- krb4.c
- ldap.c
- llist.c
- md5.c
-# memdebug.c -not used
- mprintf.c
- multi.c
- netrc.c
- # nwlib.c - Not used
- parsedate.c
- progress.c
- security.c
- select.c
- sendf.c
- share.c
- socks.c
- speedcheck.c
- splay.c
- ssh.c
- sslgen.c
- ssluse.c
- strdup.c
- strequal.c
- strerror.c
- # strtok.c - specify later
- # strtoofft.c - specify later
- telnet.c
- tftp.c
- timeval.c
- transfer.c
- url.c
- version.c
- )
-
-SET(CURL_DISABLE_LDAP 1)
-IF(NOT CURL_DISABLE_LDAP)
- SET(libCurl_SRCS
- ${libCurl_SRCS}
- ldap.c
- )
-ENDIF(NOT CURL_DISABLE_LDAP)
-
-# if we have Kerberos 4, right now this is never on
-#OPTION(CURL_KRB4 "Use Kerberos 4" OFF)
-IF(CURL_KRB4)
- SET(libCurl_SRCS ${libCurl_SRCS}
- krb4.c
- security.c
- )
-ENDIF(CURL_KRB4)
-
-#OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
-MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
-IF(CURL_MALLOC_DEBUG)
- SET(libCurl_SRCS ${libCurl_SRCS}
- memdebug.c
- )
-ENDIF(CURL_MALLOC_DEBUG)
+include (CheckFunctionExists)
+include (CheckIncludeFile)
+include (CheckIncludeFiles)
+include (CheckLibraryExists)
+include (CheckSymbolExists)
+include (CheckTypeSize)
+include (CheckCSourceCompiles)
# On windows preload settings
-IF(WIN32 AND NOT MINGW)
- INCLUDE(${LIBCURL_SOURCE_DIR}/Platforms/WindowsCache.cmake)
-ENDIF()
-
-# This macro checks if the symbol exists in the library and if it
-# does, it appends library to the list.
-SET(CURL_LIBS "")
-MACRO(CHECK_LIBRARY_EXISTS_CONCAT LIBRARY SYMBOL VARIABLE)
- CHECK_LIBRARY_EXISTS("${LIBRARY};${CURL_LIBS}" ${SYMBOL} ""
- ${VARIABLE})
- IF(${VARIABLE})
- SET(CURL_LIBS ${CURL_LIBS} ${LIBRARY})
- ENDIF(${VARIABLE})
-ENDMACRO(CHECK_LIBRARY_EXISTS_CONCAT)
+if(WIN32)
+ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WINSOCKAPI_=")
+ include(${CMAKE_CURRENT_SOURCE_DIR}/CMake/Platforms/WindowsCache.cmake)
+endif(WIN32)
+
+if(ENABLE_THREADED_RESOLVER)
+ if(WIN32)
+ set(USE_THREADS_WIN32 ON)
+ else()
+ check_include_file_concat("pthread.h" HAVE_PTHREAD_H)
+ if(HAVE_PTHREAD_H)
+ set(CMAKE_THREAD_PREFER_PTHREAD 1)
+ find_package(Threads)
+ if(CMAKE_USE_PTHREADS_INIT)
+ set(CURL_LIBS ${CURL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
+ set(USE_THREADS_POSIX 1)
+ endif()
+ endif()
+ endif()
+endif()
# Check for all needed libraries
-# use the cmake defined dl libs as dl is should not be used
-# on HPUX, but rather dld this avoids a warning
-SET(CURL_LIBS ${CURL_LIBS} ${CMAKE_DL_LIBS})
-#CHECK_LIBRARY_EXISTS_CONCAT("dl" dlopen HAVE_LIBDL)
-#CHECK_LIBRARY_EXISTS_CONCAT("ucb" gethostname HAVE_LIBUCB)
-CHECK_LIBRARY_EXISTS_CONCAT("socket" connect HAVE_LIBSOCKET)
-CHECK_LIBRARY_EXISTS("c" gethostbyname "" NOT_NEED_LIBNSL)
+if(0) # This code not needed for building within CMake.
+check_library_exists_concat("dl" dlopen HAVE_LIBDL)
+else()
+ # Use the cmake-defined dl libs as dl is should not be used
+ # on HPUX, but rather dld this avoids a warning
+ list(APPEND CURL_LIBS ${CMAKE_DL_LIBS})
+endif()
+check_library_exists_concat("socket" connect HAVE_LIBSOCKET)
+check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL)
# Yellowtab Zeta needs different libraries than BeOS 5.
-IF(BEOS)
- SET(NOT_NEED_LIBNSL 1)
- CHECK_LIBRARY_EXISTS_CONCAT("bind" gethostbyname HAVE_LIBBIND)
- CHECK_LIBRARY_EXISTS_CONCAT("bnetapi" closesocket HAVE_LIBBNETAPI)
-ENDIF(BEOS)
-
-CHECK_LIBRARY_EXISTS_CONCAT("network" recv HAVE_LIBNETWORK)
-
-IF(NOT NOT_NEED_LIBNSL)
- CHECK_LIBRARY_EXISTS_CONCAT("nsl" gethostbyname HAVE_LIBNSL)
-ENDIF(NOT NOT_NEED_LIBNSL)
-
-CHECK_LIBRARY_EXISTS_CONCAT("ws2_32" getch HAVE_LIBWS2_32)
-CHECK_LIBRARY_EXISTS_CONCAT("winmm" getch HAVE_LIBWINMM)
-IF(NOT CURL_SPECIAL_LIBZ)
- CHECK_LIBRARY_EXISTS_CONCAT("z" inflateEnd HAVE_LIBZ)
-ENDIF(NOT CURL_SPECIAL_LIBZ)
-
-OPTION(CMAKE_USE_OPENSSL "Use OpenSSL code with curl." OFF)
-MARK_AS_ADVANCED(CMAKE_USE_OPENSSL)
-IF(CMAKE_USE_OPENSSL)
- SET(USE_SSLEAY TRUE)
- SET(USE_OPENSSL TRUE)
- FIND_PACKAGE(OpenSSL REQUIRED)
- INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
- SET(CURL_LIBS ${CURL_LIBS} ${OPENSSL_LIBRARIES})
- SET(CURL_CA_BUNDLE "" CACHE FILEPATH "Path to SSL CA Certificate Bundle")
- MARK_AS_ADVANCED(CURL_CA_BUNDLE)
- IF(CURL_CA_BUNDLE)
- ADD_DEFINITIONS(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}")
- ENDIF(CURL_CA_BUNDLE)
- # for windows we want to install OPENSSL_LIBRARIES dlls
- # and also copy them into the build tree so that testing
- # can find them.
- IF(WIN32)
- FIND_FILE(CMAKE_EAY_DLL NAME libeay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
- FIND_FILE(CMAKE_SSL_DLL NAME ssleay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
- MARK_AS_ADVANCED(CMAKE_EAY_DLL CMAKE_SSL_DLL)
- IF(CMAKE_SSL_DLL AND CMAKE_EAY_DLL)
- SET(CMAKE_CURL_SSL_DLLS ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll
- ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll)
- ADD_CUSTOM_COMMAND(OUTPUT
- ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll
- DEPENDS ${CMAKE_EAY_DLL}
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_EAY_DLL}
- ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll)
- ADD_CUSTOM_COMMAND(OUTPUT
- ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll
- DEPENDS ${CMAKE_SSL_DLL}
- COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SSL_DLL}
- ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll)
- INSTALL(PROGRAMS ${CMAKE_EAY_DLL} ${CMAKE_SSL_DLL} DESTINATION bin)
- ENDIF()
- ENDIF()
-ENDIF(CMAKE_USE_OPENSSL)
+if(BEOS)
+ set(NOT_NEED_LIBNSL 1)
+ check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND)
+ check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI)
+endif(BEOS)
+
+check_library_exists_concat("network" recv HAVE_LIBNETWORK)
+
+if(NOT NOT_NEED_LIBNSL)
+ check_library_exists_concat("nsl" gethostbyname HAVE_LIBNSL)
+endif(NOT NOT_NEED_LIBNSL)
+
+check_function_exists(gethostname HAVE_GETHOSTNAME)
+
+if(WIN32)
+ check_library_exists_concat("ws2_32" getch HAVE_LIBWS2_32)
+ check_library_exists_concat("winmm" getch HAVE_LIBWINMM)
+endif()
+
+# check SSL libraries
+# TODO support GNUTLS, NSS, POLARSSL, AXTLS, CYASSL
+
+if(APPLE)
+ option(CMAKE_USE_DARWINSSL "enable Apple OS native SSL/TLS" OFF)
+endif()
+if(WIN32)
+ option(CMAKE_USE_WINSSL "enable Windows native SSL/TLS" OFF)
+ cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
+ CMAKE_USE_WINSSL OFF)
+endif()
+option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
+
+set(openssl_default ON)
+if(WIN32 OR CMAKE_USE_DARWINSSL OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS)
+ set(openssl_default OFF)
+endif()
+
+collect_true(enabled_ssl_options enabled_ssl_options_count
+ CMAKE_USE_WINSSL
+ CMAKE_USE_DARWINSSL
+ CMAKE_USE_OPENSSL
+ CMAKE_USE_MBEDTLS
+)
+if(enabled_ssl_options_count GREATER 1)
+ message(FATAL_ERROR "Multiple SSL options specified: ${enabled_ssl_options}. Please pick at most one and disable the rest.")
+endif()
+
+if(CMAKE_USE_WINSSL)
+ set(SSL_ENABLED ON)
+ set(USE_SCHANNEL ON) # Windows native SSL/TLS support
+ set(USE_WINDOWS_SSPI ON) # CMAKE_USE_WINSSL implies CURL_WINDOWS_SSPI
+ list(APPEND CURL_LIBS "crypt32")
+endif()
+if(CURL_WINDOWS_SSPI)
+ set(USE_WINDOWS_SSPI ON)
+ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DSECURITY_WIN32")
+endif()
+
+if(CMAKE_USE_DARWINSSL)
+ find_library(COREFOUNDATION_FRAMEWORK "CoreFoundation")
+ if(NOT COREFOUNDATION_FRAMEWORK)
+ message(FATAL_ERROR "CoreFoundation framework not found")
+ endif()
+
+ find_library(SECURITY_FRAMEWORK "Security")
+ if(NOT SECURITY_FRAMEWORK)
+ message(FATAL_ERROR "Security framework not found")
+ endif()
+
+ set(SSL_ENABLED ON)
+ set(USE_DARWINSSL ON)
+ list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}")
+endif()
+
+if(CMAKE_USE_OPENSSL)
+ find_package(OpenSSL REQUIRED)
+ set(SSL_ENABLED ON)
+ set(USE_OPENSSL ON)
+ set(HAVE_LIBCRYPTO ON)
+ set(HAVE_LIBSSL ON)
+ list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
+ include_directories(${OPENSSL_INCLUDE_DIR})
+ set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
+ check_include_file("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
+ check_include_file("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
+ check_include_file("openssl/err.h" HAVE_OPENSSL_ERR_H)
+ check_include_file("openssl/pem.h" HAVE_OPENSSL_PEM_H)
+ check_include_file("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H)
+ check_include_file("openssl/rsa.h" HAVE_OPENSSL_RSA_H)
+ check_include_file("openssl/ssl.h" HAVE_OPENSSL_SSL_H)
+ check_include_file("openssl/x509.h" HAVE_OPENSSL_X509_H)
+ check_include_file("openssl/rand.h" HAVE_OPENSSL_RAND_H)
+ check_symbol_exists(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS)
+ check_symbol_exists(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
+ check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD)
+
+ # Optionally build with a specific CA cert bundle.
+ if(CURL_CA_BUNDLE)
+ add_definitions(-DCURL_CA_BUNDLE="${CURL_CA_BUNDLE}")
+ endif()
+ # Optionally build with a specific CA cert dir.
+ if(CURL_CA_PATH)
+ add_definitions(-DCURL_CA_PATH="${CURL_CA_PATH}")
+ endif()
+endif()
+
+if(CMAKE_USE_MBEDTLS)
+ find_package(MbedTLS REQUIRED)
+ set(SSL_ENABLED ON)
+ set(USE_MBEDTLS ON)
+ list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES})
+ include_directories(${MBEDTLS_INCLUDE_DIRS})
+endif()
+
+option(USE_NGHTTP2 "Use Nghttp2 library" OFF)
+if(USE_NGHTTP2)
+ find_package(NGHTTP2 REQUIRED)
+ include_directories(${NGHTTP2_INCLUDE_DIRS})
+ list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
+endif()
+
+if(NOT CURL_DISABLE_LDAP)
+ if(WIN32)
+ option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
+ if(USE_WIN32_LDAP)
+ check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
+ if(NOT HAVE_WLDAP32)
+ set(USE_WIN32_LDAP OFF)
+ endif()
+ endif()
+ endif()
+
+ option(CMAKE_USE_OPENLDAP "Use OpenLDAP code." OFF)
+ mark_as_advanced(CMAKE_USE_OPENLDAP)
+ set(CMAKE_LDAP_LIB "ldap" CACHE STRING "Name or full path to ldap library")
+ set(CMAKE_LBER_LIB "lber" CACHE STRING "Name or full path to lber library")
+
+ if(CMAKE_USE_OPENLDAP AND USE_WIN32_LDAP)
+ message(FATAL_ERROR "Cannot use USE_WIN32_LDAP and CMAKE_USE_OPENLDAP at the same time")
+ endif()
+
+ # Now that we know, we're not using windows LDAP...
+ if(USE_WIN32_LDAP)
+ check_include_file_concat("winldap.h" HAVE_WINLDAP_H)
+ check_include_file_concat("winber.h" HAVE_WINBER_H)
+ else()
+ # Check for LDAP
+ set(CMAKE_REQUIRED_LIBRARIES ${OPENSSL_LIBRARIES})
+ check_library_exists_concat(${CMAKE_LDAP_LIB} ldap_init HAVE_LIBLDAP)
+ check_library_exists_concat(${CMAKE_LBER_LIB} ber_init HAVE_LIBLBER)
+
+ set(CMAKE_REQUIRED_INCLUDES_BAK ${CMAKE_REQUIRED_INCLUDES})
+ set(CMAKE_LDAP_INCLUDE_DIR "" CACHE STRING "Path to LDAP include directory")
+ if(CMAKE_LDAP_INCLUDE_DIR)
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${CMAKE_LDAP_INCLUDE_DIR})
+ endif()
+ check_include_file_concat("ldap.h" HAVE_LDAP_H)
+ check_include_file_concat("lber.h" HAVE_LBER_H)
+
+ if(NOT HAVE_LDAP_H)
+ message(STATUS "LDAP_H not found CURL_DISABLE_LDAP set ON")
+ set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
+ elseif(NOT HAVE_LIBLDAP)
+ message(STATUS "LDAP library '${CMAKE_LDAP_LIB}' not found CURL_DISABLE_LDAP set ON")
+ set(CURL_DISABLE_LDAP ON CACHE BOOL "" FORCE)
+ set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_BAK}) #LDAP includes won't be used
+ else()
+ if(CMAKE_USE_OPENLDAP)
+ set(USE_OPENLDAP ON)
+ endif()
+ if(CMAKE_LDAP_INCLUDE_DIR)
+ include_directories(${CMAKE_LDAP_INCLUDE_DIR})
+ endif()
+ set(NEED_LBER_H ON)
+ set(_HEADER_LIST)
+ if(HAVE_WINDOWS_H)
+ list(APPEND _HEADER_LIST "windows.h")
+ endif()
+ if(HAVE_SYS_TYPES_H)
+ list(APPEND _HEADER_LIST "sys/types.h")
+ endif()
+ list(APPEND _HEADER_LIST "ldap.h")
+
+ set(_SRC_STRING "")
+ foreach(_HEADER ${_HEADER_LIST})
+ set(_INCLUDE_STRING "${_INCLUDE_STRING}#include <${_HEADER}>\n")
+ endforeach()
+
+ set(_SRC_STRING
+ "
+ ${_INCLUDE_STRING}
+ int main(int argc, char ** argv)
+ {
+ BerValue *bvp = NULL;
+ BerElement *bep = ber_init(bvp);
+ ber_free(bep, 1);
+ return 0;
+ }"
+ )
+ set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -DLDAP_DEPRECATED=1")
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LDAP_LIB})
+ if(HAVE_LIBLBER)
+ list(APPEND CMAKE_REQUIRED_LIBRARIES ${CMAKE_LBER_LIB})
+ endif()
+ check_c_source_compiles("${_SRC_STRING}" NOT_NEED_LBER_H)
+
+ if(NOT_NEED_LBER_H)
+ set(NEED_LBER_H OFF)
+ else()
+ set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DNEED_LBER_H")
+ endif()
+ endif()
+ endif()
+
+endif()
+
+# No ldap, no ldaps.
+if(CURL_DISABLE_LDAP)
+ if(NOT CURL_DISABLE_LDAPS)
+ message(STATUS "LDAP needs to be enabled to support LDAPS")
+ set(CURL_DISABLE_LDAPS ON CACHE BOOL "" FORCE)
+ endif()
+endif()
+
+if(NOT CURL_DISABLE_LDAPS)
+ check_include_file_concat("ldap_ssl.h" HAVE_LDAP_SSL_H)
+ check_include_file_concat("ldapssl.h" HAVE_LDAPSSL_H)
+endif()
# Check for idn
-CHECK_LIBRARY_EXISTS_CONCAT("idn" idna_to_ascii_lz HAVE_LIBIDN)
+check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
# Check for symbol dlopen (same as HAVE_LIBDL)
-CHECK_LIBRARY_EXISTS("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
-
-# For other tests to use the same libraries
-SET(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBS})
-
-IF(CURL_SPECIAL_LIBZ)
- SET(CURL_LIBS ${CURL_LIBS} "${CURL_SPECIAL_LIBZ}")
- INCLUDE_DIRECTORIES(${CURL_SPECIAL_LIBZ_INCLUDES})
- SET(HAVE_LIBZ 0)
- SET(HAVE_ZLIB_H 0)
-ENDIF(CURL_SPECIAL_LIBZ)
-
-# do we have process.h
-CHECK_INCLUDE_FILE("process.h" HAVE_PROCESS_H)
-
-# If we have features.h, then do the _BSD_SOURCE magic
-CHECK_INCLUDE_FILE("features.h" HAVE_FEATURES_H)
-IF(HAVE_FEATURES_H)
- SET_SOURCE_FILES_PROPERTIES(
- cookie.c
- easy.c
- formdata.c
- getenv.c
- hash.c
- http.c
- if2ip.c
- mprintf.c
- multi.c
- sendf.c
- telnet.c
- transfer.c
- url.c
- COMPILE_FLAGS -D_BSD_SOURCE)
-ENDIF(HAVE_FEATURES_H)
-
-# Check if header file exists and add it to the list.
-MACRO(CHECK_INCLUDE_FILE_CONCAT FILE VARIABLE)
- CHECK_INCLUDE_FILES("${CURL_INCLUDES};${FILE}" ${VARIABLE})
- IF(${VARIABLE})
- SET(CURL_INCLUDES ${CURL_INCLUDES} ${FILE})
- ENDIF(${VARIABLE})
-ENDMACRO(CHECK_INCLUDE_FILE_CONCAT)
+check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
+
+if(0) # This code not needed for building within CMake.
+option(CURL_ZLIB "Set to ON to enable building curl with zlib support." ON)
+set(HAVE_LIBZ OFF)
+set(HAVE_ZLIB_H OFF)
+set(HAVE_ZLIB OFF)
+if(CURL_ZLIB)
+ find_package(ZLIB QUIET)
+ if(ZLIB_FOUND)
+ set(HAVE_ZLIB_H ON)
+ set(HAVE_ZLIB ON)
+ set(HAVE_LIBZ ON)
+ list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
+ include_directories(${ZLIB_INCLUDE_DIRS})
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
+ endif()
+endif()
+endif()
+
+#-----------------------------------------------------------------------------
+# CMake-specific curl code.
+
+if(CURL_SPECIAL_LIBZ)
+ set(CURL_LIBS ${CURL_LIBS} "${CURL_SPECIAL_LIBZ}")
+ include_directories(${CURL_SPECIAL_LIBZ_INCLUDES})
+ set(HAVE_LIBZ 0)
+ set(HAVE_ZLIB_H 0)
+endif()
+
+#libSSH2
+option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
+mark_as_advanced(CMAKE_USE_LIBSSH2)
+set(USE_LIBSSH2 OFF)
+set(HAVE_LIBSSH2 OFF)
+set(HAVE_LIBSSH2_H OFF)
+
+if(CMAKE_USE_LIBSSH2)
+ find_package(LibSSH2)
+ if(LIBSSH2_FOUND)
+ list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
+ set(CMAKE_REQUIRED_LIBRARIES ${LIBSSH2_LIBRARY})
+ list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
+ include_directories("${LIBSSH2_INCLUDE_DIR}")
+ set(HAVE_LIBSSH2 ON)
+ set(USE_LIBSSH2 ON)
+
+ # find_package has already found the headers
+ set(HAVE_LIBSSH2_H ON)
+ set(CURL_INCLUDES ${CURL_INCLUDES} "${LIBSSH2_INCLUDE_DIR}/libssh2.h")
+ set(CURL_TEST_DEFINES "${CURL_TEST_DEFINES} -DHAVE_LIBSSH2_H")
+
+ # now check for specific libssh2 symbols as they were added in different versions
+ set(CMAKE_EXTRA_INCLUDE_FILES "libssh2.h")
+ check_function_exists(libssh2_version HAVE_LIBSSH2_VERSION)
+ check_function_exists(libssh2_init HAVE_LIBSSH2_INIT)
+ check_function_exists(libssh2_exit HAVE_LIBSSH2_EXIT)
+ check_function_exists(libssh2_scp_send64 HAVE_LIBSSH2_SCP_SEND64)
+ check_function_exists(libssh2_session_handshake HAVE_LIBSSH2_SESSION_HANDSHAKE)
+ set(CMAKE_EXTRA_INCLUDE_FILES "")
+
+ endif(LIBSSH2_FOUND)
+endif(CMAKE_USE_LIBSSH2)
+
+option(CMAKE_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
+mark_as_advanced(CMAKE_USE_GSSAPI)
+
+if(CMAKE_USE_GSSAPI)
+ find_package(GSS)
+
+ set(HAVE_GSSAPI ${GSS_FOUND})
+ if(GSS_FOUND)
+
+ message(STATUS "Found ${GSS_FLAVOUR} GSSAPI version: \"${GSS_VERSION}\"")
+
+ list(APPEND CMAKE_REQUIRED_INCLUDES ${GSS_INCLUDE_DIRECTORIES})
+ check_include_file_concat("gssapi/gssapi.h" HAVE_GSSAPI_GSSAPI_H)
+ check_include_file_concat("gssapi/gssapi_generic.h" HAVE_GSSAPI_GSSAPI_GENERIC_H)
+ check_include_file_concat("gssapi/gssapi_krb5.h" HAVE_GSSAPI_GSSAPI_KRB5_H)
+
+ if(GSS_FLAVOUR STREQUAL "Heimdal")
+ set(HAVE_GSSHEIMDAL ON)
+ else() # MIT
+ set(HAVE_GSSMIT ON)
+ set(_INCLUDE_LIST "")
+ if(HAVE_GSSAPI_GSSAPI_H)
+ list(APPEND _INCLUDE_LIST "gssapi/gssapi.h")
+ endif()
+ if(HAVE_GSSAPI_GSSAPI_GENERIC_H)
+ list(APPEND _INCLUDE_LIST "gssapi/gssapi_generic.h")
+ endif()
+ if(HAVE_GSSAPI_GSSAPI_KRB5_H)
+ list(APPEND _INCLUDE_LIST "gssapi/gssapi_krb5.h")
+ endif()
+
+ string(REPLACE ";" " " _COMPILER_FLAGS_STR "${GSS_COMPILER_FLAGS}")
+ string(REPLACE ";" " " _LINKER_FLAGS_STR "${GSS_LINKER_FLAGS}")
+
+ foreach(_dir ${GSS_LINK_DIRECTORIES})
+ set(_LINKER_FLAGS_STR "${_LINKER_FLAGS_STR} -L\"${_dir}\"")
+ endforeach()
+
+ set(CMAKE_REQUIRED_FLAGS "${_COMPILER_FLAGS_STR} ${_LINKER_FLAGS_STR}")
+ set(CMAKE_REQUIRED_LIBRARIES ${GSS_LIBRARIES})
+ check_symbol_exists("GSS_C_NT_HOSTBASED_SERVICE" ${_INCLUDE_LIST} HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+ if(NOT HAVE_GSS_C_NT_HOSTBASED_SERVICE)
+ set(HAVE_OLD_GSSMIT ON)
+ endif()
+
+ endif()
+
+ include_directories(${GSS_INCLUDE_DIRECTORIES})
+ link_directories(${GSS_LINK_DIRECTORIES})
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GSS_COMPILER_FLAGS}")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
+ list(APPEND CURL_LIBS ${GSS_LIBRARIES})
+
+ else()
+ message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
+ endif()
+endif()
+
+option(ENABLE_UNIX_SOCKETS "Define if you want Unix domain sockets support" ON)
+if(ENABLE_UNIX_SOCKETS)
+ include(CheckStructHasMember)
+ check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS)
+else()
+ unset(USE_UNIX_SOCKETS CACHE)
+endif()
+
+
+if(0) # This code not needed for building within CMake.
+#
+# CA handling
+#
+set(CURL_CA_BUNDLE "auto" CACHE STRING
+ "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+set(CURL_CA_FALLBACK OFF CACHE BOOL
+ "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
+set(CURL_CA_PATH "auto" CACHE STRING
+ "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+
+if("${CURL_CA_BUNDLE}" STREQUAL "")
+ message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
+elseif("${CURL_CA_BUNDLE}" STREQUAL "none")
+ unset(CURL_CA_BUNDLE CACHE)
+elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
+ unset(CURL_CA_BUNDLE CACHE)
+ set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+else()
+ set(CURL_CA_BUNDLE_SET TRUE)
+endif()
+
+if("${CURL_CA_PATH}" STREQUAL "")
+ message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.")
+elseif("${CURL_CA_PATH}" STREQUAL "none")
+ unset(CURL_CA_PATH CACHE)
+elseif("${CURL_CA_PATH}" STREQUAL "auto")
+ unset(CURL_CA_PATH CACHE)
+ set(CURL_CA_PATH_AUTODETECT TRUE)
+else()
+ set(CURL_CA_PATH_SET TRUE)
+endif()
+
+if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT)
+ # Skip autodetection of unset CA path because CA bundle is set explicitly
+elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT)
+ # Skip autodetection of unset CA bundle because CA path is set explicitly
+elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT)
+ # first try autodetecting a CA bundle, then a CA path
+
+ if(CURL_CA_BUNDLE_AUTODETECT)
+ set(SEARCH_CA_BUNDLE_PATHS
+ /etc/ssl/certs/ca-certificates.crt
+ /etc/pki/tls/certs/ca-bundle.crt
+ /usr/share/ssl/certs/ca-bundle.crt
+ /usr/local/share/certs/ca-root-nss.crt
+ /etc/ssl/cert.pem)
+
+ foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
+ if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
+ message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
+ set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}")
+ set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
+ break()
+ endif()
+ endforeach()
+ endif()
+
+ if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET))
+ if(EXISTS "/etc/ssl/certs")
+ set(CURL_CA_PATH "/etc/ssl/certs")
+ set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
+ endif()
+ endif()
+endif()
+
+if(CURL_CA_PATH_SET AND NOT USE_OPENSSL AND NOT USE_MBEDTLS)
+ message(FATAL_ERROR
+ "CA path only supported by OpenSSL, GnuTLS or mbed TLS. "
+ "Set CURL_CA_PATH=none or enable one of those TLS backends.")
+endif()
+endif()
+
# Check for header files
-IF(UNIX)
- SET(HAVE_WINDOWS_H 0)
- SET(HAVE_WINSOCK_H 0)
- SET(HAVE_WS2TCPIP_H 0)
- SET(HAVE_WINSOCK2_H 0)
-ENDIF(UNIX)
-IF(NOT UNIX)
- CHECK_INCLUDE_FILE_CONCAT("ws2tcpip.h" HAVE_WS2TCPIP_H)
- CHECK_INCLUDE_FILE_CONCAT("winsock2.h" HAVE_WINSOCK2_H)
-ENDIF(NOT UNIX)
-CHECK_INCLUDE_FILE_CONCAT("stdio.h" HAVE_STDIO_H)
-IF(NOT UNIX)
- CHECK_INCLUDE_FILE_CONCAT("windows.h" HAVE_WINDOWS_H)
- CHECK_INCLUDE_FILE_CONCAT("winsock.h" HAVE_WINSOCK_H)
-ENDIF(NOT UNIX)
-CHECK_INCLUDE_FILE_CONCAT("stddef.h" HAVE_STDDEF_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/types.h" HAVE_SYS_TYPES_H)
-CHECK_INCLUDE_FILE_CONCAT("inttypes.h" HAVE_INTTYPES_H)
-CHECK_INCLUDE_FILE_CONCAT("alloca.h" HAVE_ALLOCA_H)
-CHECK_INCLUDE_FILE_CONCAT("arpa/inet.h" HAVE_ARPA_INET_H)
-CHECK_INCLUDE_FILE_CONCAT("dlfcn.h" HAVE_DLFCN_H)
-CHECK_INCLUDE_FILE_CONCAT("fcntl.h" HAVE_FCNTL_H)
-CHECK_INCLUDE_FILE_CONCAT("malloc.h" HAVE_MALLOC_H)
-CHECK_INCLUDE_FILE_CONCAT("memory.h" HAVE_MEMORY_H)
-CHECK_INCLUDE_FILE_CONCAT("netdb.h" HAVE_NETDB_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/poll.h" HAVE_SYS_POLL_H)
-CHECK_INCLUDE_FILE_CONCAT("assert.h" HAVE_ASSERT_H)
-CHECK_INCLUDE_FILE_CONCAT("limits.h" HAVE_LIMITS_H)
-
-IF(CMAKE_USE_OPENSSL)
- CHECK_INCLUDE_FILE_CONCAT("openssl/x509.h" HAVE_OPENSSL_X509_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/engine.h" HAVE_OPENSSL_ENGINE_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/rsa.h" HAVE_OPENSSL_RSA_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/pem.h" HAVE_OPENSSL_PEM_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/ssl.h" HAVE_OPENSSL_SSL_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/err.h" HAVE_OPENSSL_ERR_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/rand.h" HAVE_OPENSSL_RAND_H)
- CHECK_INCLUDE_FILE_CONCAT("openssl/pkcs12.h" HAVE_OPENSSL_PKCS12_H)
-ENDIF(CMAKE_USE_OPENSSL)
-
-IF(NOT CURL_SPECIAL_LIBZ)
- CHECK_INCLUDE_FILE_CONCAT("zlib.h" HAVE_ZLIB_H)
-ENDIF(NOT CURL_SPECIAL_LIBZ)
-CHECK_INCLUDE_FILE_CONCAT("sys/socket.h" HAVE_SYS_SOCKET_H)
-CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" HAVE_NETINET_IN_H)
-CHECK_INCLUDE_FILE_CONCAT("net/if.h" HAVE_NET_IF_H)
-CHECK_INCLUDE_FILE_CONCAT("netinet/if_ether.h"
- HAVE_NETINET_IF_ETHER_H)
-CHECK_INCLUDE_FILE_CONCAT("netinet/tcp.h"
- HAVE_NETINET_TCP_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/select.h" HAVE_SYS_SELECT_H)
-CHECK_INCLUDE_FILE_CONCAT("utime.h" HAVE_UTIME_H)
-CHECK_INCLUDE_FILE_CONCAT("netinet/in.h" HAVE_NETINET_IN_H)
-CHECK_INCLUDE_FILE_CONCAT("pwd.h" HAVE_PWD_H)
-CHECK_INCLUDE_FILE_CONCAT("sgtty.h" HAVE_SGTTY_H)
-CHECK_INCLUDE_FILE_CONCAT("stdint.h" HAVE_STDINT_H)
-CHECK_INCLUDE_FILE_CONCAT("stdlib.h" HAVE_STDLIB_H)
-CHECK_INCLUDE_FILE_CONCAT("string.h" HAVE_STRING_H)
-CHECK_INCLUDE_FILE_CONCAT("strings.h" HAVE_STRINGS_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/param.h" HAVE_SYS_PARAM_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/stat.h" HAVE_SYS_STAT_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/time.h" HAVE_SYS_TIME_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/resource.h" HAVE_SYS_RESOURCE_H)
-CHECK_INCLUDE_FILE_CONCAT("termios.h" HAVE_TERMIOS_H)
-CHECK_INCLUDE_FILE_CONCAT("termio.h" HAVE_TERMIO_H)
-CHECK_INCLUDE_FILE_CONCAT("io.h" HAVE_IO_H)
-CHECK_INCLUDE_FILE_CONCAT("time.h" HAVE_TIME_H)
-CHECK_INCLUDE_FILE_CONCAT("unistd.h" HAVE_UNISTD_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/utime.h" HAVE_SYS_UTIME_H)
-CHECK_INCLUDE_FILE_CONCAT("sockio.h" HAVE_SOCKIO_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/sockio.h" HAVE_SYS_SOCKIO_H)
-CHECK_INCLUDE_FILE_CONCAT("x509.h" HAVE_X509_H)
-CHECK_INCLUDE_FILE_CONCAT("locale.h" HAVE_LOCALE_H)
-CHECK_INCLUDE_FILE_CONCAT("setjmp.h" HAVE_SETJMP_H)
-CHECK_INCLUDE_FILE_CONCAT("signal.h" HAVE_SIGNAL_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/ioctl.h" HAVE_SYS_IOCTL_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/utsname.h" HAVE_SYS_UTSNAME_H)
-CHECK_INCLUDE_FILE_CONCAT("idn-free.h" HAVE_IDN_FREE_H)
-CHECK_INCLUDE_FILE_CONCAT("idna.h" HAVE_IDNA_H)
-CHECK_INCLUDE_FILE_CONCAT("tld.h" HAVE_TLD_H)
-CHECK_INCLUDE_FILE_CONCAT("arpa/tftp.h" HAVE_ARPA_TFTP_H)
-CHECK_INCLUDE_FILE_CONCAT("errno.h" HAVE_ERRNO_H)
-CHECK_INCLUDE_FILE_CONCAT("libgen.h" HAVE_LIBGEN_H)
-CHECK_INCLUDE_FILE_CONCAT("sys/filio.h" HAVE_SYS_FILIO_H)
-CHECK_TYPE_SIZE(size_t SIZEOF_SIZE_T)
-CHECK_TYPE_SIZE(ssize_t SIZEOF_SSIZE_T)
-CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
-CHECK_TYPE_SIZE("long" SIZEOF_LONG)
-CHECK_TYPE_SIZE("__int64" SIZEOF___INT64)
-CHECK_TYPE_SIZE("time_t" SIZEOF_TIME_T)
-
-IF(HAVE_SIZEOF_LONG_LONG)
- SET(HAVE_LONGLONG 1)
- SET(HAVE_LL 1)
-ENDIF(HAVE_SIZEOF_LONG_LONG)
-
-FIND_FILE(RANDOM_FILE urandom /dev)
-MARK_AS_ADVANCED(RANDOM_FILE)
-
-#strtoll \
-#socket \
-#select \
-#strdup \
-#strstr \
-#strtok_r \
-#uname \
-#strcasecmp \
-#stricmp \
-#strcmpi \
-#gethostbyaddr \
-#gettimeofday \
-#inet_addr \
-#inet_ntoa \
-#inet_pton \
-#perror \
-#closesocket \
-#siginterrupt \
-#sigaction \
-#signal \
-#getpass_r \
-#getpwuid \
-#geteuid \
-#dlopen \
-#utime \
-#sigsetjmp \
-#basename \
-#setlocale \
-#ftruncate \
-#pipe \
-#poll \
-#getprotobyname \
-#getrlimit \
-#setrlimit \
-#fork
+if(NOT UNIX)
+ check_include_file_concat("windows.h" HAVE_WINDOWS_H)
+ check_include_file_concat("winsock.h" HAVE_WINSOCK_H)
+ check_include_file_concat("ws2tcpip.h" HAVE_WS2TCPIP_H)
+ check_include_file_concat("winsock2.h" HAVE_WINSOCK2_H)
+ if(NOT CURL_WINDOWS_SSPI AND USE_OPENSSL)
+ set(CURL_LIBS ${CURL_LIBS} "crypt32")
+ endif()
+else()
+ set(HAVE_WINDOWS_H 0)
+ set(HAVE_WINSOCK_H 0)
+ set(HAVE_WS2TCPIP_H 0)
+ set(HAVE_WINSOCK2_H 0)
+endif()
+
+check_include_file_concat("stdio.h" HAVE_STDIO_H)
+check_include_file_concat("inttypes.h" HAVE_INTTYPES_H)
+check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H)
+check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H)
+check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H)
+check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H)
+check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H)
+check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H)
+check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H)
+check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H)
+check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H)
+check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H)
+check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H)
+check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H)
+check_include_file_concat("sys/un.h" HAVE_SYS_UN_H)
+check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H)
+check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H)
+check_include_file_concat("alloca.h" HAVE_ALLOCA_H)
+check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H)
+check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H)
+check_include_file_concat("assert.h" HAVE_ASSERT_H)
+check_include_file_concat("crypto.h" HAVE_CRYPTO_H)
+check_include_file_concat("des.h" HAVE_DES_H)
+check_include_file_concat("err.h" HAVE_ERR_H)
+check_include_file_concat("errno.h" HAVE_ERRNO_H)
+check_include_file_concat("fcntl.h" HAVE_FCNTL_H)
+check_include_file_concat("idn2.h" HAVE_IDN2_H)
+check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H)
+check_include_file_concat("io.h" HAVE_IO_H)
+check_include_file_concat("krb.h" HAVE_KRB_H)
+check_include_file_concat("libgen.h" HAVE_LIBGEN_H)
+check_include_file_concat("limits.h" HAVE_LIMITS_H)
+check_include_file_concat("locale.h" HAVE_LOCALE_H)
+check_include_file_concat("net/if.h" HAVE_NET_IF_H)
+check_include_file_concat("netdb.h" HAVE_NETDB_H)
+check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H)
+check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H)
+
+check_include_file_concat("pem.h" HAVE_PEM_H)
+check_include_file_concat("poll.h" HAVE_POLL_H)
+check_include_file_concat("pwd.h" HAVE_PWD_H)
+check_include_file_concat("rsa.h" HAVE_RSA_H)
+check_include_file_concat("setjmp.h" HAVE_SETJMP_H)
+check_include_file_concat("sgtty.h" HAVE_SGTTY_H)
+check_include_file_concat("signal.h" HAVE_SIGNAL_H)
+check_include_file_concat("ssl.h" HAVE_SSL_H)
+check_include_file_concat("stdbool.h" HAVE_STDBOOL_H)
+check_include_file_concat("stdint.h" HAVE_STDINT_H)
+check_include_file_concat("stdio.h" HAVE_STDIO_H)
+check_include_file_concat("stdlib.h" HAVE_STDLIB_H)
+check_include_file_concat("string.h" HAVE_STRING_H)
+check_include_file_concat("strings.h" HAVE_STRINGS_H)
+check_include_file_concat("stropts.h" HAVE_STROPTS_H)
+check_include_file_concat("termio.h" HAVE_TERMIO_H)
+check_include_file_concat("termios.h" HAVE_TERMIOS_H)
+check_include_file_concat("time.h" HAVE_TIME_H)
+check_include_file_concat("unistd.h" HAVE_UNISTD_H)
+check_include_file_concat("utime.h" HAVE_UTIME_H)
+check_include_file_concat("x509.h" HAVE_X509_H)
+
+check_include_file_concat("process.h" HAVE_PROCESS_H)
+check_include_file_concat("stddef.h" HAVE_STDDEF_H)
+check_include_file_concat("dlfcn.h" HAVE_DLFCN_H)
+check_include_file_concat("malloc.h" HAVE_MALLOC_H)
+check_include_file_concat("memory.h" HAVE_MEMORY_H)
+check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H)
+check_include_file_concat("stdint.h" HAVE_STDINT_H)
+check_include_file_concat("sockio.h" HAVE_SOCKIO_H)
+check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H)
+
+check_type_size(size_t SIZEOF_SIZE_T)
+check_type_size(ssize_t SIZEOF_SSIZE_T)
+check_type_size("long long" SIZEOF_LONG_LONG)
+check_type_size("long" SIZEOF_LONG)
+check_type_size("short" SIZEOF_SHORT)
+check_type_size("int" SIZEOF_INT)
+check_type_size("__int64" SIZEOF___INT64)
+check_type_size("time_t" SIZEOF_TIME_T)
+
+# Make public versions of some type sizes for curlbuild.h.
+foreach(t INT LONG LONG_LONG SSIZE_T)
+ string(REPLACE "SIZEOF_" "CURL_SIZEOF_" CURL_SIZEOF_${t}_CODE "${SIZEOF_${t}_CODE}")
+endforeach()
+
+if(HAVE_SIZEOF_LONG_LONG)
+ set(HAVE_LONGLONG 1)
+ set(HAVE_LL 1)
+endif(HAVE_SIZEOF_LONG_LONG)
+
+find_file(RANDOM_FILE urandom /dev)
+mark_as_advanced(RANDOM_FILE)
# Check for some functions that are used
-CHECK_SYMBOL_EXISTS(basename "${CURL_INCLUDES}" HAVE_BASENAME)
-CHECK_SYMBOL_EXISTS(socket "${CURL_INCLUDES}" HAVE_SOCKET)
-CHECK_SYMBOL_EXISTS(poll "${CURL_INCLUDES}" HAVE_POLL)
-CHECK_SYMBOL_EXISTS(select "${CURL_INCLUDES}" HAVE_SELECT)
-CHECK_SYMBOL_EXISTS(strdup "${CURL_INCLUDES}" HAVE_STRDUP)
-CHECK_SYMBOL_EXISTS(strstr "${CURL_INCLUDES}" HAVE_STRSTR)
-CHECK_SYMBOL_EXISTS(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R)
-CHECK_SYMBOL_EXISTS(strftime "${CURL_INCLUDES}" HAVE_STRFTIME)
-CHECK_SYMBOL_EXISTS(uname "${CURL_INCLUDES}" HAVE_UNAME)
-CHECK_SYMBOL_EXISTS(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP)
-CHECK_SYMBOL_EXISTS(stricmp "${CURL_INCLUDES}" HAVE_STRICMP)
-CHECK_SYMBOL_EXISTS(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI)
-CHECK_SYMBOL_EXISTS(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI)
-CHECK_SYMBOL_EXISTS(basename "${CURL_INCLUDES}" HAVE_BASENAME)
-IF(NOT HAVE_STRNCMPI)
- SET(HAVE_STRCMPI)
-ENDIF(NOT HAVE_STRNCMPI)
-CHECK_SYMBOL_EXISTS(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
-CHECK_SYMBOL_EXISTS(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
-CHECK_SYMBOL_EXISTS(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR)
-# windows only has this for vista, but will link with it and say
-# that it has it at link time! So, force it off
-IF(WIN32)
- SET(HAVE_INET_PTON 0 CACHE "" INTERNAL )
-ENDIF(WIN32)
-CHECK_SYMBOL_EXISTS(inet_pton "${CURL_INCLUDES}" HAVE_INET_PTON)
-CHECK_SYMBOL_EXISTS(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA)
-CHECK_SYMBOL_EXISTS(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
-CHECK_SYMBOL_EXISTS(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR)
-CHECK_SYMBOL_EXISTS(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR)
-CHECK_SYMBOL_EXISTS(perror "${CURL_INCLUDES}" HAVE_PERROR)
-CHECK_SYMBOL_EXISTS(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
-CHECK_SYMBOL_EXISTS(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF)
-CHECK_SYMBOL_EXISTS(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP)
-CHECK_SYMBOL_EXISTS(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R)
-CHECK_SYMBOL_EXISTS(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID)
-CHECK_SYMBOL_EXISTS(geteuid "${CURL_INCLUDES}" HAVE_GETEUID)
-CHECK_SYMBOL_EXISTS(utime "${CURL_INCLUDES}" HAVE_UTIME)
-IF(CMAKE_USE_OPENSSL)
- CHECK_SYMBOL_EXISTS(RAND_status "${CURL_INCLUDES}" HAVE_RAND_STATUS)
- CHECK_SYMBOL_EXISTS(RAND_screen "${CURL_INCLUDES}" HAVE_RAND_SCREEN)
- CHECK_SYMBOL_EXISTS(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD)
- CHECK_SYMBOL_EXISTS(CRYPTO_cleanup_all_ex_data "${CURL_INCLUDES}"
- HAVE_CRYPTO_CLEANUP_ALL_EX_DATA)
-ENDIF(CMAKE_USE_OPENSSL)
-CHECK_SYMBOL_EXISTS(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R)
-CHECK_SYMBOL_EXISTS(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
-
-CHECK_SYMBOL_EXISTS(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
-CHECK_SYMBOL_EXISTS(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
-CHECK_SYMBOL_EXISTS(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
-
-CHECK_SYMBOL_EXISTS(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
-CHECK_SYMBOL_EXISTS(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
-IF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
- SET(HAVE_SIGNAL 1)
-ENDIF(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
-CHECK_SYMBOL_EXISTS(uname "${CURL_INCLUDES}" HAVE_UNAME)
-CHECK_SYMBOL_EXISTS(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL)
-CHECK_SYMBOL_EXISTS(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64)
-CHECK_SYMBOL_EXISTS(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R)
-CHECK_SYMBOL_EXISTS(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
-CHECK_SYMBOL_EXISTS(perror "${CURL_INCLUDES}" HAVE_PERROR)
-CHECK_SYMBOL_EXISTS(fork "${CURL_INCLUDES}" HAVE_FORK)
-CHECK_SYMBOL_EXISTS(pipe "${CURL_INCLUDES}" HAVE_PIPE)
-CHECK_SYMBOL_EXISTS(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE)
-CHECK_SYMBOL_EXISTS(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
-CHECK_SYMBOL_EXISTS(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT)
-CHECK_SYMBOL_EXISTS(idn_free "${CURL_INCLUDES}" HAVE_IDN_FREE)
-CHECK_SYMBOL_EXISTS(idna_strerror "${CURL_INCLUDES}" HAVE_IDNA_STRERROR)
-CHECK_SYMBOL_EXISTS(tld_strerror "${CURL_INCLUDES}" HAVE_TLD_STRERROR)
-CHECK_SYMBOL_EXISTS(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE)
-CHECK_SYMBOL_EXISTS(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT)
-
-# only build compat strtok if we need to
-IF (NOT HAVE_STRTOK_R)
- SET(libCurl_SRCS ${libCurl_SRCS}
- strtok.c
- )
-ENDIF (NOT HAVE_STRTOK_R)
-
-# only build compat strtoofft if we need to
-IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
- SET(libCurl_SRCS ${libCurl_SRCS}
- strtoofft.c
- )
-ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
+if(HAVE_LIBWS2_32)
+ set(CMAKE_REQUIRED_LIBRARIES ws2_32)
+elseif(HAVE_LIBSOCKET)
+ set(CMAKE_REQUIRED_LIBRARIES socket)
+elseif(HAVE_LIBNETWORK)
+ set(CMAKE_REQUIRED_LIBRARIES network)
+endif()
+
+check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME)
+check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET)
+# poll on macOS is unreliable, it first did not exist, then was broken until
+# fixed in 10.9 only to break again in 10.12.
+if(NOT APPLE)
+ check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL)
+endif()
+check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT)
+check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP)
+check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR)
+check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R)
+check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME)
+check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME)
+check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP)
+check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP)
+check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI)
+check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI)
+check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM)
+if(NOT HAVE_STRNCMPI)
+ set(HAVE_STRCMPI)
+endif(NOT HAVE_STRNCMPI)
+check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
+check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
+check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
+check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR)
+check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA)
+check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
+check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR)
+check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR)
+check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR)
+check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
+check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF)
+check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP)
+check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R)
+check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT)
+check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID)
+check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID)
+check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME)
+check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R)
+check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R)
+
+check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME)
+check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
+
+check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC)
+check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO)
+if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+ set(HAVE_SIGNAL 1)
+endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO)
+check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME)
+check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL)
+check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64)
+check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R)
+check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
+check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR)
+check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK)
+check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO)
+check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
+check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS)
+check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE)
+check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE)
+check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME)
+check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT)
+check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE)
+check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT)
+check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL)
+check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL)
+check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT)
+
+# symbol exists in win32, but function does not.
+check_function_exists(inet_pton HAVE_INET_PTON)
+
+check_symbol_exists(fsetxattr "${CURL_INCLUDES}" HAVE_FSETXATTR)
+if(HAVE_FSETXATTR)
+ foreach(CURL_TEST HAVE_FSETXATTR_5 HAVE_FSETXATTR_6)
+ curl_internal_test_run(${CURL_TEST})
+ endforeach(CURL_TEST)
+endif(HAVE_FSETXATTR)
# sigaction and sigsetjmp are special. Use special mechanism for
# detecting those, but only if previous attempt failed.
-IF(HAVE_SIGNAL_H)
- CHECK_SYMBOL_EXISTS(sigaction "signal.h" HAVE_SIGACTION)
-ENDIF(HAVE_SIGNAL_H)
-
-IF(NOT HAVE_SIGSETJMP)
- IF(HAVE_SETJMP_H)
- CHECK_SYMBOL_EXISTS(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP)
- IF(HAVE_MACRO_SIGSETJMP)
- SET(HAVE_SIGSETJMP 1)
- ENDIF(HAVE_MACRO_SIGSETJMP)
- ENDIF(HAVE_SETJMP_H)
-ENDIF(NOT HAVE_SIGSETJMP)
-
-# For other curl specific tests, use this macro.
-MACRO(CURL_INTERNAL_TEST CURL_TEST)
- IF("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
- SET(MACRO_CHECK_FUNCTION_DEFINITIONS
- "-D${CURL_TEST} ${CMAKE_REQUIRED_FLAGS}")
- IF(CMAKE_REQUIRED_LIBRARIES)
- SET(CURL_TEST_ADD_LIBRARIES
- "-DLINK_LIBRARIES:STRING=${CMAKE_REQUIRED_LIBRARIES}")
- ENDIF(CMAKE_REQUIRED_LIBRARIES)
-
- MESSAGE(STATUS "Performing Curl Test ${CURL_TEST}")
- TRY_COMPILE(${CURL_TEST}
- ${CMAKE_BINARY_DIR}
- ${LIBCURL_SOURCE_DIR}/CMake/CurlTests.c
- CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS}
- "${CURL_TEST_ADD_LIBRARIES}"
- OUTPUT_VARIABLE OUTPUT)
- IF(${CURL_TEST})
- SET(${CURL_TEST} 1 CACHE INTERNAL "Curl test ${FUNCTION}")
- MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Success")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
- "Performing Curl Test ${CURL_TEST} passed with the following output:\n"
- "${OUTPUT}\n")
- ELSE(${CURL_TEST})
- MESSAGE(STATUS "Performing Curl Test ${CURL_TEST} - Failed")
- SET(${CURL_TEST} "" CACHE INTERNAL "Curl test ${FUNCTION}")
- FILE(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
- "Performing Curl Test ${CURL_TEST} failed with the following output:\n"
- "${OUTPUT}\n")
- ENDIF(${CURL_TEST})
- ENDIF("${CURL_TEST}" MATCHES "^${CURL_TEST}$")
-ENDMACRO(CURL_INTERNAL_TEST)
+if(HAVE_SIGNAL_H)
+ check_symbol_exists(sigaction "signal.h" HAVE_SIGACTION)
+endif(HAVE_SIGNAL_H)
+
+if(NOT HAVE_SIGSETJMP)
+ if(HAVE_SETJMP_H)
+ check_symbol_exists(sigsetjmp "setjmp.h" HAVE_MACRO_SIGSETJMP)
+ if(HAVE_MACRO_SIGSETJMP)
+ set(HAVE_SIGSETJMP 1)
+ endif(HAVE_MACRO_SIGSETJMP)
+ endif(HAVE_SETJMP_H)
+endif(NOT HAVE_SIGSETJMP)
+
+# If there is no stricmp(), do not allow LDAP to parse URLs
+if(NOT HAVE_STRICMP)
+ set(HAVE_LDAP_URL_PARSE 1)
+endif(NOT HAVE_STRICMP)
# Do curl specific tests
-#OPTION(CURL_HAVE_DISABLED_NONBLOCKING "Disable non-blocking socket detection" OFF)
-SET(CURL_NONBLOCKING_TESTS)
-IF(NOT CURL_HAVE_DISABLED_NONBLOCKING)
- SET(CURL_NONBLOCKING_TESTS
- HAVE_FIONBIO
+foreach(CURL_TEST
+ HAVE_FCNTL_O_NONBLOCK
HAVE_IOCTLSOCKET
- HAVE_IOCTLSOCKET_CASE
- HAVE_O_NONBLOCK
- HAVE_SO_NONBLOCK
- )
-ENDIF(NOT CURL_HAVE_DISABLED_NONBLOCKING)
-FOREACH(CURL_TEST
- ${CURL_NONBLOCKING_TESTS}
+ HAVE_IOCTLSOCKET_CAMEL
+ HAVE_IOCTLSOCKET_CAMEL_FIONBIO
+ HAVE_IOCTLSOCKET_FIONBIO
+ HAVE_IOCTL_FIONBIO
+ HAVE_IOCTL_SIOCGIFADDR
+ HAVE_SETSOCKOPT_SO_NONBLOCK
+ HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
TIME_WITH_SYS_TIME
- HAVE_O_NONBLOCKHAVE_GETHOSTBYADDR_R_5
+ HAVE_O_NONBLOCK
+ HAVE_GETHOSTBYADDR_R_5
HAVE_GETHOSTBYADDR_R_7
HAVE_GETHOSTBYADDR_R_8
HAVE_GETHOSTBYADDR_R_5_REENTRANT
@@ -557,6 +1059,7 @@ FOREACH(CURL_TEST
HAVE_GETHOSTBYNAME_R_6_REENTRANT
HAVE_SOCKLEN_T
HAVE_IN_ADDR_T
+ HAVE_BOOL_T
STDC_HEADERS
RETSIGTYPE_TEST
HAVE_INET_NTOA_R_DECL
@@ -564,14 +1067,25 @@ FOREACH(CURL_TEST
HAVE_GETADDRINFO
HAVE_FILE_OFFSET_BITS
)
- CURL_INTERNAL_TEST(${CURL_TEST})
-ENDFOREACH(CURL_TEST)
-IF(HAVE_FILE_OFFSET_BITS)
- SET(_FILE_OFFSET_BITS 64)
-ENDIF(HAVE_FILE_OFFSET_BITS)
+ curl_internal_test(${CURL_TEST})
+endforeach(CURL_TEST)
+
+if(HAVE_FILE_OFFSET_BITS)
+ set(_FILE_OFFSET_BITS 64)
+ set(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
+endif(HAVE_FILE_OFFSET_BITS)
+check_type_size("off_t" SIZEOF_OFF_T)
+set(CMAKE_REQUIRED_FLAGS)
+
+foreach(CURL_TEST
+ HAVE_GLIBC_STRERROR_R
+ HAVE_POSIX_STRERROR_R
+ )
+ curl_internal_test_run(${CURL_TEST})
+endforeach(CURL_TEST)
# Check for reentrant
-FOREACH(CURL_TEST
+foreach(CURL_TEST
HAVE_GETHOSTBYADDR_R_5
HAVE_GETHOSTBYADDR_R_7
HAVE_GETHOSTBYADDR_R_8
@@ -579,156 +1093,321 @@ FOREACH(CURL_TEST
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6
HAVE_INET_NTOA_R_DECL_REENTRANT)
- IF(NOT ${CURL_TEST})
- IF(${CURL_TEST}_REENTRANT)
- SET(NEED_REENTRANT 1)
- ENDIF(${CURL_TEST}_REENTRANT)
- ENDIF(NOT ${CURL_TEST})
-ENDFOREACH(CURL_TEST)
-
-IF(NEED_REENTRANT)
- FOREACH(CURL_TEST
+ if(NOT ${CURL_TEST})
+ if(${CURL_TEST}_REENTRANT)
+ set(NEED_REENTRANT 1)
+ endif(${CURL_TEST}_REENTRANT)
+ endif(NOT ${CURL_TEST})
+endforeach(CURL_TEST)
+
+if(NEED_REENTRANT)
+ foreach(CURL_TEST
HAVE_GETHOSTBYADDR_R_5
HAVE_GETHOSTBYADDR_R_7
HAVE_GETHOSTBYADDR_R_8
HAVE_GETHOSTBYNAME_R_3
HAVE_GETHOSTBYNAME_R_5
HAVE_GETHOSTBYNAME_R_6)
- SET(${CURL_TEST} 0)
- IF(${CURL_TEST}_REENTRANT)
- SET(${CURL_TEST} 1)
- ENDIF(${CURL_TEST}_REENTRANT)
- ENDFOREACH(CURL_TEST)
-ENDIF(NEED_REENTRANT)
-
-IF(HAVE_INET_NTOA_R_DECL_REENTRANT)
- SET(HAVE_INET_NTOA_R_DECL 1)
- SET(NEED_REENTRANT 1)
-ENDIF(HAVE_INET_NTOA_R_DECL_REENTRANT)
+ set(${CURL_TEST} 0)
+ if(${CURL_TEST}_REENTRANT)
+ set(${CURL_TEST} 1)
+ endif(${CURL_TEST}_REENTRANT)
+ endforeach(CURL_TEST)
+endif(NEED_REENTRANT)
+
+if(HAVE_INET_NTOA_R_DECL_REENTRANT)
+ set(HAVE_INET_NTOA_R_DECL 1)
+ set(NEED_REENTRANT 1)
+endif(HAVE_INET_NTOA_R_DECL_REENTRANT)
# Some other minor tests
-IF(NOT HAVE_SOCKLEN_T)
- SET(socklen_t "int")
-ENDIF(NOT HAVE_SOCKLEN_T)
-
-IF(NOT HAVE_IN_ADDR_T)
- SET(in_addr_t "unsigned long")
-ENDIF(NOT HAVE_IN_ADDR_T)
+if(NOT HAVE_IN_ADDR_T)
+ set(in_addr_t "unsigned long")
+endif(NOT HAVE_IN_ADDR_T)
# Fix libz / zlib.h
-IF(NOT CURL_SPECIAL_LIBZ)
- IF(NOT HAVE_LIBZ)
- SET(HAVE_ZLIB_H 0)
- ENDIF(NOT HAVE_LIBZ)
-
- IF(NOT HAVE_ZLIB_H)
- SET(HAVE_LIBZ 0)
- ENDIF(NOT HAVE_ZLIB_H)
-ENDIF(NOT CURL_SPECIAL_LIBZ)
-
-IF(_FILE_OFFSET_BITS)
- SET(_FILE_OFFSET_BITS 64)
-ENDIF(_FILE_OFFSET_BITS)
-SET(CMAKE_REQUIRED_FLAGS "-D_FILE_OFFSET_BITS=64")
-SET(CMAKE_EXTRA_INCLUDE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/curl/curl.h")
-CHECK_TYPE_SIZE("curl_off_t" SIZEOF_CURL_OFF_T)
-SET(CMAKE_EXTRA_INCLUDE_FILES)
-SET(CMAKE_REQUIRED_FLAGS)
+if(NOT CURL_SPECIAL_LIBZ)
+ if(NOT HAVE_LIBZ)
+ set(HAVE_ZLIB_H 0)
+ endif(NOT HAVE_LIBZ)
+ if(NOT HAVE_ZLIB_H)
+ set(HAVE_LIBZ 0)
+ endif(NOT HAVE_ZLIB_H)
+endif(NOT CURL_SPECIAL_LIBZ)
# Check for nonblocking
-SET(HAVE_DISABLED_NONBLOCKING 1)
-IF(HAVE_FIONBIO OR
+set(HAVE_DISABLED_NONBLOCKING 1)
+if(HAVE_FIONBIO OR
HAVE_IOCTLSOCKET OR
HAVE_IOCTLSOCKET_CASE OR
HAVE_O_NONBLOCK)
- SET(HAVE_DISABLED_NONBLOCKING)
-ENDIF(HAVE_FIONBIO OR
+ set(HAVE_DISABLED_NONBLOCKING)
+endif(HAVE_FIONBIO OR
HAVE_IOCTLSOCKET OR
HAVE_IOCTLSOCKET_CASE OR
HAVE_O_NONBLOCK)
-IF(RETSIGTYPE_TEST)
- SET(RETSIGTYPE void)
-ELSE(RETSIGTYPE_TEST)
- SET(RETSIGTYPE int)
-ENDIF(RETSIGTYPE_TEST)
+if(RETSIGTYPE_TEST)
+ set(RETSIGTYPE void)
+else(RETSIGTYPE_TEST)
+ set(RETSIGTYPE int)
+endif(RETSIGTYPE_TEST)
-IF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
- INCLUDE(CheckCCompilerFlag)
- CHECK_C_COMPILER_FLAG(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
- IF(HAVE_C_FLAG_Wno_long_double)
+if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
+ include(CheckCCompilerFlag)
+ check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
+ if(HAVE_C_FLAG_Wno_long_double)
# The Mac version of GCC warns about use of long double. Disable it.
- GET_SOURCE_FILE_PROPERTY(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
- IF(MPRINTF_COMPILE_FLAGS)
- SET(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
- ELSE(MPRINTF_COMPILE_FLAGS)
- SET(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
- ENDIF(MPRINTF_COMPILE_FLAGS)
- SET_SOURCE_FILES_PROPERTIES(mprintf.c PROPERTIES
+ get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
+ if(MPRINTF_COMPILE_FLAGS)
+ set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
+ else(MPRINTF_COMPILE_FLAGS)
+ set(MPRINTF_COMPILE_FLAGS "-Wno-long-double")
+ endif(MPRINTF_COMPILE_FLAGS)
+ set_source_files_properties(mprintf.c PROPERTIES
COMPILE_FLAGS ${MPRINTF_COMPILE_FLAGS})
- ENDIF(HAVE_C_FLAG_Wno_long_double)
-ENDIF(CMAKE_COMPILER_IS_GNUCC AND APPLE)
-
-INCLUDE(CMake/OtherTests.cmake)
-
-# The rest of the build
-
-INCLUDE_DIRECTORIES(${LIBCURL_SOURCE_DIR})
-INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR})
-OPTION(CMAKE_BUILD_CURL_SHARED "Should curl be built shared" TRUE)
-IF(CMAKE_BUILD_CURL_SHARED)
- SET(LIBRARY_TYPE SHARED)
- ADD_DEFINITIONS(-DHAVE_CONFIG_H)
-ELSE(CMAKE_BUILD_CURL_SHARED)
- ADD_DEFINITIONS(-DHAVE_CONFIG_H
- -DCURL_STATICLIB)
-ENDIF(CMAKE_BUILD_CURL_SHARED)
-SET(CURL_STATICLIB)
-
-# Support CheckTypeSize module from CMake 2.8.0 and lower.
-FOREACH(var
- SIZEOF_CURL_OFF_T
- SIZEOF_LONG
- SIZEOF_LONG_LONG
- SIZEOF___INT64
- SIZEOF_SIZE_T
- SIZEOF_SSIZE_T
- SIZEOF_TIME_T
- )
- IF(NOT ${var}_CODE)
- MESSAGE("creating ${var}_CODE")
- IF(${var})
- SET(${var}_CODE "#define ${var} ${${var}}")
- ELSE()
- SET(${var}_CODE "/* #undef ${var} */")
- ENDIF()
- ENDIF()
-ENDFOREACH()
-
-CONFIGURE_FILE(${LIBCURL_SOURCE_DIR}/config.h.in
- ${LIBCURL_BINARY_DIR}/config.h)
-
-ADD_LIBRARY(cmcurl ${LIBRARY_TYPE} ${libCurl_SRCS} ${CMAKE_CURL_SSL_DLLS})
-TARGET_LINK_LIBRARIES(cmcurl ${CURL_LIBS})
-IF(CMAKE_BUILD_CURL_SHARED)
- SET_TARGET_PROPERTIES(cmcurl PROPERTIES DEFINE_SYMBOL BUILDING_LIBCURL
- RUNTIME_OUTPUT_DIRECTORY ${CMake_BIN_DIR})
- INSTALL(TARGETS cmcurl RUNTIME DESTINATION bin)
-ENDIF(CMAKE_BUILD_CURL_SHARED)
-
-OPTION(CURL_TESTING "Do libCurl testing" OFF)
-IF(CURL_TESTING)
- SUBDIRS(Testing)
-ENDIF(CURL_TESTING)
-
-ADD_EXECUTABLE(LIBCURL Testing/curltest.c)
-TARGET_LINK_LIBRARIES(LIBCURL cmcurl ${CMAKE_DL_LIBS})
-
-IF(CMAKE_CURL_TEST_URL)
- ADD_TEST(curl LIBCURL ${CMAKE_CURL_TEST_URL})
-ENDIF(CMAKE_CURL_TEST_URL)
-
-INSTALL(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl)
+ endif(HAVE_C_FLAG_Wno_long_double)
+endif(CMAKE_COMPILER_IS_GNUCC AND APPLE)
+
+if(HAVE_SOCKLEN_T)
+ set(CURL_HAVE_SOCKLEN_T 1)
+ set(CURL_TYPEOF_CURL_SOCKLEN_T "socklen_t")
+ if(WIN32)
+ set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h;ws2tcpip.h")
+ elseif(HAVE_SYS_SOCKET_H)
+ set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
+ endif()
+ check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T)
+ set(CMAKE_EXTRA_INCLUDE_FILES)
+ if(NOT HAVE_CURL_SIZEOF_CURL_SOCKLEN_T)
+ message(FATAL_ERROR
+ "Check for sizeof socklen_t failed, see CMakeFiles/CMakerror.log")
+ endif()
+else()
+ set(CURL_HAVE_SOCKLEN_T 0)
+endif()
+
+# TODO test which of these headers are required for the typedefs used in curlbuild.h
+if(WIN32)
+ set(CURL_PULL_WS2TCPIP_H ${HAVE_WS2TCPIP_H})
+else()
+ set(CURL_PULL_SYS_TYPES_H ${HAVE_SYS_TYPES_H})
+ set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
+ set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
+endif()
+set(CURL_PULL_STDINT_H ${HAVE_STDINT_H})
+set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H})
+
+include(CMake/OtherTests.cmake)
+
+add_definitions(-DHAVE_CONFIG_H)
+
+# For windows, do not allow the compiler to use default target (Vista).
+if(WIN32)
+ add_definitions(-D_WIN32_WINNT=0x0501)
+endif(WIN32)
+
+# For windows, all compilers used by cmake should support large files
+if(WIN32)
+ set(USE_WIN32_LARGE_FILES ON)
+endif(WIN32)
+
+if(MSVC)
+ add_definitions(-D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
+endif(MSVC)
+
+# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
+function(TRANSFORM_MAKEFILE_INC INPUT_FILE OUTPUT_FILE)
+ file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
+ string(REPLACE "$(top_srcdir)" "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
+ string(REPLACE "$(top_builddir)" "\${CURL_BINARY_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
+
+ string(REGEX REPLACE "\\\\\n" "!π!α!" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
+ string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
+ string(REPLACE "!π!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
+
+ string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace $() with ${}
+ string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT}) # Replace @@ with ${}, even if that may not be read by CMake scripts.
+ file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT})
+
+endfunction()
+
+if(0) # This code not needed for building within CMake.
+add_subdirectory(docs)
+endif()
+add_subdirectory(lib)
+if(BUILD_CURL_EXE)
+ add_subdirectory(src)
+endif()
+
+#-----------------------------------------------------------------------------
+# CMake-specific curl code.
+add_executable(LIBCURL curltest.c)
+target_link_libraries(LIBCURL cmcurl)
+
+if(CMAKE_CURL_TEST_URL)
+ add_test(curl LIBCURL ${CMAKE_CURL_TEST_URL})
+endif()
+
+install(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmcurl)
+#-----------------------------------------------------------------------------
+
+if(0) # This code not needed for building within CMake.
+include(CTest)
+if(BUILD_TESTING)
+ add_subdirectory(tests)
+endif()
+
+# Helper to populate a list (_items) with a label when conditions (the remaining
+# args) are satisfied
+function(_add_if label)
+ # TODO need to disable policy CMP0054 (CMake 3.1) to allow this indirection
+ if(${ARGN})
+ set(_items ${_items} "${label}" PARENT_SCOPE)
+ endif()
+endfunction()
+
+# Clear list and try to detect available features
+set(_items)
+_add_if("WinSSL" SSL_ENABLED AND USE_WINDOWS_SSPI)
+_add_if("OpenSSL" SSL_ENABLED AND USE_OPENSSL)
+_add_if("DarwinSSL" SSL_ENABLED AND USE_DARWINSSL)
+_add_if("mbedTLS" SSL_ENABLED AND USE_MBEDTLS)
+_add_if("IPv6" ENABLE_IPV6)
+_add_if("unix-sockets" USE_UNIX_SOCKETS)
+_add_if("libz" HAVE_LIBZ)
+_add_if("AsynchDNS" USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
+_add_if("IDN" HAVE_LIBIDN2)
+_add_if("Largefile" (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND
+ ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
+# TODO SSP1 (WinSSL) check is missing
+_add_if("SSPI" USE_WINDOWS_SSPI)
+_add_if("GSS-API" HAVE_GSSAPI)
+# TODO SSP1 missing for SPNEGO
+_add_if("SPNEGO" NOT CURL_DISABLE_CRYPTO_AUTH AND
+ (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
+_add_if("Kerberos" NOT CURL_DISABLE_CRYPTO_AUTH AND
+ (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
+# NTLM support requires crypto function adaptions from various SSL libs
+# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
+if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_WINDOWS_SSPI OR USE_DARWINSSL OR USE_MBEDTLS))
+ _add_if("NTLM" 1)
+ # TODO missing option (autoconf: --enable-ntlm-wb)
+ _add_if("NTLM_WB" NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
+endif()
+# TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
+_add_if("TLS-SRP" USE_TLS_SRP)
+# TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
+_add_if("HTTP2" USE_NGHTTP2)
+string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
+message(STATUS "Enabled features: ${SUPPORT_FEATURES}")
+
+# Clear list and try to detect available protocols
+set(_items)
+_add_if("HTTP" NOT CURL_DISABLE_HTTP)
+_add_if("HTTPS" NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
+_add_if("FTP" NOT CURL_DISABLE_FTP)
+_add_if("FTPS" NOT CURL_DISABLE_FTP AND SSL_ENABLED)
+_add_if("FILE" NOT CURL_DISABLE_FILE)
+_add_if("TELNET" NOT CURL_DISABLE_TELNET)
+_add_if("LDAP" NOT CURL_DISABLE_LDAP)
+# CURL_DISABLE_LDAP implies CURL_DISABLE_LDAPS
+# TODO check HAVE_LDAP_SSL (in autoconf this is enabled with --enable-ldaps)
+_add_if("LDAPS" NOT CURL_DISABLE_LDAPS AND
+ ((USE_OPENLDAP AND SSL_ENABLED) OR
+ (NOT USE_OPENLDAP AND HAVE_LDAP_SSL)))
+_add_if("DICT" NOT CURL_DISABLE_DICT)
+_add_if("TFTP" NOT CURL_DISABLE_TFTP)
+_add_if("GOPHER" NOT CURL_DISABLE_GOPHER)
+_add_if("POP3" NOT CURL_DISABLE_POP3)
+_add_if("POP3S" NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
+_add_if("IMAP" NOT CURL_DISABLE_IMAP)
+_add_if("IMAPS" NOT CURL_DISABLE_IMAP AND SSL_ENABLED)
+_add_if("SMTP" NOT CURL_DISABLE_SMTP)
+_add_if("SMTPS" NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
+_add_if("SCP" USE_LIBSSH2)
+_add_if("SFTP" USE_LIBSSH2)
+_add_if("RTSP" NOT CURL_DISABLE_RTSP)
+_add_if("RTMP" USE_LIBRTMP)
+list(SORT _items)
+string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")
+message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")
+
+# curl-config needs the following options to be set.
+set(CC "${CMAKE_C_COMPILER}")
+# TODO probably put a -D... options here?
+set(CONFIGURE_OPTIONS "")
+# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB?
+set(CPPFLAG_CURL_STATICLIB "")
+set(CURLVERSION "${CURL_VERSION}")
+set(ENABLE_SHARED "yes")
+if(CURL_STATICLIB)
+ set(ENABLE_STATIC "yes")
+else()
+ set(ENABLE_STATIC "no")
+endif()
+set(exec_prefix "\${prefix}")
+set(includedir "\${prefix}/include")
+set(LDFLAGS "${CMAKE_SHARED_LINKER_FLAGS}")
+set(LIBCURL_LIBS "")
+set(libdir "${CMAKE_INSTALL_PREFIX}/lib")
+foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
+ if(_lib MATCHES ".*/.*")
+ set(LIBCURL_LIBS "${LIBCURL_LIBS} ${_lib}")
+ else()
+ set(LIBCURL_LIBS "${LIBCURL_LIBS} -l${_lib}")
+ endif()
+endforeach()
+# "a" (Linux) or "lib" (Windows)
+string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}")
+set(prefix "${CMAKE_INSTALL_PREFIX}")
+# Set this to "yes" to append all libraries on which -lcurl is dependent
+set(REQUIRE_LIB_DEPS "no")
+# SUPPORT_FEATURES
+# SUPPORT_PROTOCOLS
+set(VERSIONNUM "${CURL_VERSION_NUM}")
+
+# Finally generate a "curl-config" matching this config
+configure_file("${CURL_SOURCE_DIR}/curl-config.in"
+ "${CURL_BINARY_DIR}/curl-config" @ONLY)
+install(FILES "${CURL_BINARY_DIR}/curl-config"
+ DESTINATION bin
+ PERMISSIONS
+ OWNER_READ OWNER_WRITE OWNER_EXECUTE
+ GROUP_READ GROUP_EXECUTE
+ WORLD_READ WORLD_EXECUTE)
+
+# Finally generate a pkg-config file matching this config
+configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
+ "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
+install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
+ DESTINATION lib/pkgconfig)
+
+# This needs to be run very last so other parts of the scripts can take advantage of this.
+if(NOT CURL_CONFIG_HAS_BEEN_RUN_BEFORE)
+ set(CURL_CONFIG_HAS_BEEN_RUN_BEFORE 1 CACHE INTERNAL "Flag to track whether this is the first time running CMake or if CMake has been configured before")
+endif()
+
+# Installation.
+# First, install generated curlbuild.h
+install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/curl/curlbuild.h"
+ DESTINATION include/curl )
+# Next, install other headers excluding curlbuild.h
+install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl"
+ DESTINATION include
+ FILES_MATCHING PATTERN "*.h"
+ PATTERN "curlbuild.h" EXCLUDE)
+
+
+# Workaround for MSVS10 to avoid the Dialog Hell
+# FIXME: This could be removed with future version of CMake.
+if(MSVC_VERSION EQUAL 1600)
+ set(CURL_SLN_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/CURL.sln")
+ if(EXISTS "${CURL_SLN_FILENAME}")
+ file(APPEND "${CURL_SLN_FILENAME}" "\n# This should be regenerated!\n")
+ endif()
+endif()
+endif()
diff --git a/Utilities/cmcurl/COPYING b/Utilities/cmcurl/COPYING
index 048cf5657..1e45a5e2c 100644
--- a/Utilities/cmcurl/COPYING
+++ b/Utilities/cmcurl/COPYING
@@ -1,6 +1,7 @@
COPYRIGHT AND PERMISSION NOTICE
-Copyright (c) 1996 - 2009, Daniel Stenberg, <daniel@haxx.se>.
+Copyright (c) 1996 - 2017, Daniel Stenberg, <daniel@haxx.se>, and many
+contributors, see the THANKS file.
All rights reserved.
diff --git a/Utilities/cmcurl/Platforms/WindowsCache.cmake b/Utilities/cmcurl/Platforms/WindowsCache.cmake
deleted file mode 100644
index 57ab30be3..000000000
--- a/Utilities/cmcurl/Platforms/WindowsCache.cmake
+++ /dev/null
@@ -1,120 +0,0 @@
-IF(NOT UNIX)
- IF(WIN32)
- SET(HAVE_LIBDL 0)
- SET(HAVE_LIBUCB 0)
- SET(HAVE_LIBSOCKET 0)
- SET(NOT_NEED_LIBNSL 0)
- SET(HAVE_LIBNSL 0)
- SET(HAVE_LIBZ 0)
- SET(HAVE_LIBCRYPTO 0)
-
- SET(HAVE_DLOPEN 0)
-
- SET(HAVE_ALLOCA_H 0)
- SET(HAVE_ARPA_INET_H 0)
- SET(HAVE_DLFCN_H 0)
- SET(HAVE_FCNTL_H 1)
- SET(HAVE_FEATURES_H 0)
- SET(HAVE_INTTYPES_H 0)
- SET(HAVE_IO_H 1)
- SET(HAVE_MALLOC_H 1)
- SET(HAVE_MEMORY_H 1)
- SET(HAVE_NETDB_H 0)
- SET(HAVE_NETINET_IF_ETHER_H 0)
- SET(HAVE_NETINET_IN_H 0)
- SET(HAVE_NET_IF_H 0)
- SET(HAVE_PROCESS_H 1)
- SET(HAVE_PWD_H 0)
- SET(HAVE_SETJMP_H 1)
- SET(HAVE_SGTTY_H 0)
- SET(HAVE_SIGNAL_H 1)
- SET(HAVE_SOCKIO_H 0)
- SET(HAVE_STDINT_H 0)
- SET(HAVE_STDLIB_H 1)
- SET(HAVE_STRINGS_H 0)
- SET(HAVE_STRING_H 1)
- SET(HAVE_SYS_PARAM_H 0)
- SET(HAVE_SYS_POLL_H 0)
- SET(HAVE_SYS_SELECT_H 0)
- SET(HAVE_SYS_SOCKET_H 0)
- SET(HAVE_SYS_SOCKIO_H 0)
- SET(HAVE_SYS_STAT_H 1)
- SET(HAVE_SYS_TIME_H 0)
- SET(HAVE_SYS_TYPES_H 1)
- SET(HAVE_SYS_UTIME_H 1)
- SET(HAVE_TERMIOS_H 0)
- SET(HAVE_TERMIO_H 0)
- SET(HAVE_TIME_H 1)
- SET(HAVE_UNISTD_H 0)
- SET(HAVE_UTIME_H 0)
- SET(HAVE_X509_H 0)
- SET(HAVE_ZLIB_H 0)
-
- SET(HAVE_SIZEOF_LONG_DOUBLE 1)
- SET(SIZEOF_LONG_DOUBLE 8)
-
- SET(HAVE_SOCKET 1)
- SET(HAVE_POLL 0)
- SET(HAVE_SELECT 1)
- SET(HAVE_STRDUP 1)
- SET(HAVE_STRSTR 1)
- SET(HAVE_STRTOK_R 0)
- SET(HAVE_STRFTIME 1)
- SET(HAVE_UNAME 0)
- SET(HAVE_STRCASECMP 0)
- SET(HAVE_STRICMP 1)
- SET(HAVE_STRCMPI 1)
- SET(HAVE_GETHOSTBYADDR 1)
- SET(HAVE_GETTIMEOFDAY 0)
- SET(HAVE_INET_ADDR 1)
- SET(HAVE_INET_NTOA 1)
- SET(HAVE_INET_NTOA_R 0)
- SET(HAVE_TCGETATTR 0)
- SET(HAVE_TCSETATTR 0)
- SET(HAVE_PERROR 1)
- SET(HAVE_CLOSESOCKET 1)
- SET(HAVE_SETVBUF 0)
- SET(HAVE_SIGSETJMP 0)
- SET(HAVE_GETPASS_R 0)
- SET(HAVE_GETPWUID 0)
- SET(HAVE_GETEUID 0)
- SET(HAVE_UTIME 1)
- SET(HAVE_RAND_EGD 0)
- SET(HAVE_RAND_SCREEN 0)
- SET(HAVE_RAND_STATUS 0)
- SET(HAVE_GMTIME_R 0)
- SET(HAVE_LOCALTIME_R 0)
- SET(HAVE_GETHOSTBYADDR_R 0)
- SET(HAVE_GETHOSTBYNAME_R 0)
- SET(HAVE_SIGNAL_FUNC 1)
- SET(HAVE_SIGNAL_MACRO 0)
-
- SET(HAVE_GETHOSTBYADDR_R_5 0)
- SET(HAVE_GETHOSTBYADDR_R_5_REENTRANT 0)
- SET(HAVE_GETHOSTBYADDR_R_7 0)
- SET(HAVE_GETHOSTBYADDR_R_7_REENTRANT 0)
- SET(HAVE_GETHOSTBYADDR_R_8 0)
- SET(HAVE_GETHOSTBYADDR_R_8_REENTRANT 0)
- SET(HAVE_GETHOSTBYNAME_R_3 0)
- SET(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
- SET(HAVE_GETHOSTBYNAME_R_5 0)
- SET(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
- SET(HAVE_GETHOSTBYNAME_R_6 0)
- SET(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
-
- SET(TIME_WITH_SYS_TIME 0)
- SET(HAVE_O_NONBLOCK 0)
- SET(HAVE_IN_ADDR_T 0)
- SET(HAVE_INET_NTOA_R_DECL 0)
- SET(HAVE_INET_NTOA_R_DECL_REENTRANT 0)
- SET(HAVE_GETADDRINFO 0)
- SET(STDC_HEADERS 1)
- SET(RETSIGTYPE_TEST 1)
-
- SET(HAVE_SIGACTION 0)
- SET(HAVE_MACRO_SIGSETJMP 0)
- ELSE(WIN32)
- MESSAGE("This file should be included on Windows platform only")
- ENDIF(WIN32)
-ENDIF(NOT UNIX)
-
diff --git a/Utilities/cmcurl/Platforms/config-aix.h b/Utilities/cmcurl/Platforms/config-aix.h
deleted file mode 100644
index c98b10fdd..000000000
--- a/Utilities/cmcurl/Platforms/config-aix.h
+++ /dev/null
@@ -1,483 +0,0 @@
-/* lib/config.h. Generated by configure. */
-/* lib/config.h.in. Generated from configure.in by autoheader. */
-/* Name of this package! */
-#define PACKAGE "curl"
-
-/* Version number of this archive. */
-#define VERSION "7.10.2"
-
-/* Define if you have the getpass function. */
-/* #undef HAVE_GETPASS */
-
-/* Define cpu-machine-OS */
-#define OS "powerpc-ibm-aix5.1.0.0"
-
-/* Define if you have the gethostbyaddr_r() function with 5 arguments */
-#define HAVE_GETHOSTBYADDR_R_5 1
-
-/* Define if you have the gethostbyaddr_r() function with 7 arguments */
-/* #undef HAVE_GETHOSTBYADDR_R_7 */
-
-/* Define if you have the gethostbyaddr_r() function with 8 arguments */
-/* #undef HAVE_GETHOSTBYADDR_R_8 */
-
-/* Define if you have the gethostbyname_r() function with 3 arguments */
-#define HAVE_GETHOSTBYNAME_R_3 1
-
-/* Define if you have the gethostbyname_r() function with 5 arguments */
-/* #undef HAVE_GETHOSTBYNAME_R_5 */
-
-/* Define if you have the gethostbyname_r() function with 6 arguments */
-/* #undef HAVE_GETHOSTBYNAME_R_6 */
-
-/* Define if you have the inet_ntoa_r function declared. */
-/* #undef HAVE_INET_NTOA_R_DECL */
-
-/* Define if you need the _REENTRANT define for some functions */
-/* #undef NEED_REENTRANT */
-
-/* Define if you have the Kerberos4 libraries (including -ldes) */
-/* #undef KRB4 */
-
-/* Define if you want to enable IPv6 support */
-#define ENABLE_IPV6 1
-
-/* Define this to 'int' if ssize_t is not an available typedefed type */
-/* #undef ssize_t */
-
-/* Define this to 'int' if socklen_t is not an available typedefed type */
-/* #undef socklen_t */
-
-/* Define this as a suitable file to read random data from */
-/* #undef RANDOM_FILE */
-
-/* Define this to your Entropy Gathering Daemon socket pathname */
-/* #undef EGD_SOCKET */
-
-/* Define if you have a working OpenSSL installation */
-/* #undef OPENSSL_ENABLED */
-
-/* Define the one correct non-blocking socket method below */
-/* #undef HAVE_FIONBIO */
-/* #undef HAVE_IOCTLSOCKET */
-/* #undef HAVE_IOCTLSOCKET_CASE */
-/* #undef HAVE_O_NONBLOCK */
-#define HAVE_DISABLED_NONBLOCKING 1
-
-/* Define this to 'int' if in_addr_t is not an available typedefed type */
-/* #undef in_addr_t */
-
-/* Define to disable DICT */
-/* #undef CURL_DISABLE_DICT */
-
-/* Define to disable FILE */
-/* #undef CURL_DISABLE_FILE */
-
-/* Define to disable FTP */
-/* #undef CURL_DISABLE_FTP */
-
-/* Define to disable GOPHER */
-/* #undef CURL_DISABLE_GOPHER */
-
-/* Define to disable HTTP */
-/* #undef CURL_DISABLE_HTTP */
-
-/* Define to disable LDAP */
-/* #undef CURL_DISABLE_LDAP */
-
-/* Define to disable TELNET */
-/* #undef CURL_DISABLE_TELNET */
-
-/* Define if you have zlib present */
-#define HAVE_LIBZ 1
-
-/* CA bundle full path name */
-#define CURL_CA_BUNDLE "/usr/local/share/curl/curl-ca-bundle.crt"
-
-/* to disable FILE */
-/* #undef CURL_DISABLE_FILE */
-
-/* to disable FTP */
-/* #undef CURL_DISABLE_FTP */
-
-/* to disable GOPHER */
-/* #undef CURL_DISABLE_GOPHER */
-
-/* to disable HTTP */
-/* #undef CURL_DISABLE_HTTP */
-
-/* to disable LDAP */
-/* #undef CURL_DISABLE_LDAP */
-
-/* to disable TELNET */
-/* #undef CURL_DISABLE_TELNET */
-
-/* Set to explicitly specify we don't want to use thread-safe functions */
-/* #undef DISABLED_THREADSAFE */
-
-/* your Entropy Gathering Daemon socket pathname */
-/* #undef EGD_SOCKET */
-
-/* Define if you want to enable IPv6 support */
-#define ENABLE_IPV6 1
-
-/* Define to 1 if you have the <alloca.h> header file. */
-#define HAVE_ALLOCA_H 1
-
-/* Define to 1 if you have the <arpa/inet.h> header file. */
-#define HAVE_ARPA_INET_H 1
-
-/* Define to 1 if you have the `closesocket' function. */
-/* #undef HAVE_CLOSESOCKET */
-
-/* Define to 1 if you have the <crypto.h> header file. */
-/* #undef HAVE_CRYPTO_H */
-
-/* Define to 1 if you have the <des.h> header file. */
-/* #undef HAVE_DES_H */
-
-/* to disable NON-BLOCKING connections */
-#define HAVE_DISABLED_NONBLOCKING 1
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#define HAVE_DLFCN_H 1
-
-/* Define to 1 if you have the `dlopen' function. */
-#define HAVE_DLOPEN 1
-
-/* Define to 1 if you have the <err.h> header file. */
-/* #undef HAVE_ERR_H */
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#define HAVE_FCNTL_H 1
-
-/* Define if getaddrinfo exists and works */
-#define HAVE_GETADDRINFO 1
-
-/* Define to 1 if you have the `geteuid' function. */
-#define HAVE_GETEUID 1
-
-/* Define to 1 if you have the `gethostbyaddr' function. */
-#define HAVE_GETHOSTBYADDR 1
-
-/* Define to 1 if you have the `gethostbyaddr_r' function. */
-#define HAVE_GETHOSTBYADDR_R 1
-
-/* Define to 1 if you have the `gethostbyname_r' function. */
-#define HAVE_GETHOSTBYNAME_R 1
-
-/* Define to 1 if you have the `getpass_r' function. */
-/* #undef HAVE_GETPASS_R */
-
-/* Define to 1 if you have the `getpwuid' function. */
-#define HAVE_GETPWUID 1
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#define HAVE_GETTIMEOFDAY 1
-
-/* Define to 1 if you have the `gmtime_r' function. */
-#define HAVE_GMTIME_R 1
-
-/* Define to 1 if you have the `inet_addr' function. */
-#define HAVE_INET_ADDR 1
-
-/* Define to 1 if you have the `inet_ntoa' function. */
-#define HAVE_INET_NTOA 1
-
-/* Define to 1 if you have the `inet_ntoa_r' function. */
-#define HAVE_INET_NTOA_R 1
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#define HAVE_INTTYPES_H 1
-
-/* Define to 1 if you have the <io.h> header file. */
-/* #undef HAVE_IO_H */
-
-/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
-/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
-
-/* Define to 1 if you have the <krb.h> header file. */
-/* #undef HAVE_KRB_H */
-
-/* Define to 1 if you have the `crypto' library (-lcrypto). */
-/* #undef HAVE_LIBCRYPTO */
-
-/* Define to 1 if you have the `dl' library (-ldl). */
-/* #undef HAVE_LIBDL */
-
-/* Define to 1 if you have the `nsl' library (-lnsl). */
-/* #undef HAVE_LIBNSL */
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-/* #undef HAVE_LIBRESOLV */
-
-/* Define to 1 if you have the `resolve' library (-lresolve). */
-/* #undef HAVE_LIBRESOLVE */
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-/* #undef HAVE_LIBSOCKET */
-
-/* Define to 1 if you have the `ssl' library (-lssl). */
-/* #undef HAVE_LIBSSL */
-
-/* If zlib is available */
-#define HAVE_LIBZ 1
-
-/* Define to 1 if you have the `localtime_r' function. */
-#define HAVE_LOCALTIME_R 1
-
-/* Define to 1 if you have the <malloc.h> header file. */
-#define HAVE_MALLOC_H 1
-
-/* Define to 1 if you have the <memory.h> header file. */
-#define HAVE_MEMORY_H 1
-
-/* Define to 1 if you have the <netdb.h> header file. */
-#define HAVE_NETDB_H 1
-
-/* Define to 1 if you have the <netinet/if_ether.h> header file. */
-#define HAVE_NETINET_IF_ETHER_H 1
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-#define HAVE_NETINET_IN_H 1
-
-/* Define to 1 if you have the <net/if.h> header file. */
-#define HAVE_NET_IF_H 1
-
-/* Define to 1 if you have the <openssl/crypto.h> header file. */
-/* #undef HAVE_OPENSSL_CRYPTO_H */
-
-/* Define to 1 if you have the <openssl/engine.h> header file. */
-/* #undef HAVE_OPENSSL_ENGINE_H */
-
-/* Define to 1 if you have the <openssl/err.h> header file. */
-/* #undef HAVE_OPENSSL_ERR_H */
-
-/* Define to 1 if you have the <openssl/pem.h> header file. */
-/* #undef HAVE_OPENSSL_PEM_H */
-
-/* Define to 1 if you have the <openssl/rsa.h> header file. */
-/* #undef HAVE_OPENSSL_RSA_H */
-
-/* Define to 1 if you have the <openssl/ssl.h> header file. */
-/* #undef HAVE_OPENSSL_SSL_H */
-
-/* Define to 1 if you have the <openssl/x509.h> header file. */
-/* #undef HAVE_OPENSSL_X509_H */
-
-/* Define to 1 if you have the <pem.h> header file. */
-/* #undef HAVE_PEM_H */
-
-/* Define to 1 if you have the `perror' function. */
-#define HAVE_PERROR 1
-
-/* Define to 1 if you have the `poll' function. */
-#define HAVE_POLL 1
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#define HAVE_PWD_H 1
-
-/* Define to 1 if you have the `RAND_egd' function. */
-/* #undef HAVE_RAND_EGD */
-
-/* Define to 1 if you have the `RAND_screen' function. */
-/* #undef HAVE_RAND_SCREEN */
-
-/* Define to 1 if you have the `RAND_status' function. */
-/* #undef HAVE_RAND_STATUS */
-
-/* Define to 1 if you have the <rsa.h> header file. */
-/* #undef HAVE_RSA_H */
-
-/* Define to 1 if you have the `select' function. */
-#define HAVE_SELECT 1
-
-/* Define to 1 if you have the <setjmp.h> header file. */
-#define HAVE_SETJMP_H 1
-
-/* Define to 1 if you have the `setvbuf' function. */
-#define HAVE_SETVBUF 1
-
-/* Define to 1 if you have the <sgtty.h> header file. */
-#define HAVE_SGTTY_H 1
-
-/* Define to 1 if you have the `sigaction' function. */
-#define HAVE_SIGACTION 1
-
-/* Define to 1 if you have the `signal' function. */
-#define HAVE_SIGNAL 1
-
-/* If you have sigsetjmp */
-#define HAVE_SIGSETJMP 1
-
-/* Define to 1 if you have the `socket' function. */
-#define HAVE_SOCKET 1
-
-/* Define to 1 if you have the <ssl.h> header file. */
-/* #undef HAVE_SSL_H */
-
-/* Define to 1 if you have the <stdint.h> header file. */
-/* #undef HAVE_STDINT_H */
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#define HAVE_STDLIB_H 1
-
-/* Define to 1 if you have the `strcasecmp' function. */
-#define HAVE_STRCASECMP 1
-
-/* Define to 1 if you have the `strcmpi' function. */
-/* #undef HAVE_STRCMPI */
-
-/* Define to 1 if you have the `strdup' function. */
-#define HAVE_STRDUP 1
-
-/* Define to 1 if you have the `strftime' function. */
-#define HAVE_STRFTIME 1
-
-/* Define to 1 if you have the `stricmp' function. */
-/* #undef HAVE_STRICMP */
-
-/* Define to 1 if you have the <strings.h> header file. */
-#define HAVE_STRINGS_H 1
-
-/* Define to 1 if you have the <string.h> header file. */
-#define HAVE_STRING_H 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-/* #undef HAVE_STRLCPY */
-
-/* Define to 1 if you have the `strstr' function. */
-#define HAVE_STRSTR 1
-
-/* Define to 1 if you have the `strtok_r' function. */
-#define HAVE_STRTOK_R 1
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#define HAVE_SYS_PARAM_H 1
-
-/* Define to 1 if you have the <sys/poll.h> header file. */
-#define HAVE_SYS_POLL_H 1
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#define HAVE_SYS_SELECT_H 1
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#define HAVE_SYS_SOCKET_H 1
-
-/* Define to 1 if you have the <sys/sockio.h> header file. */
-/* #undef HAVE_SYS_SOCKIO_H */
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#define HAVE_SYS_STAT_H 1
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#define HAVE_SYS_TIME_H 1
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#define HAVE_SYS_TYPES_H 1
-
-/* Define to 1 if you have the <sys/utime.h> header file. */
-/* #undef HAVE_SYS_UTIME_H */
-
-/* Define to 1 if you have the `tcgetattr' function. */
-#define HAVE_TCGETATTR 1
-
-/* Define to 1 if you have the `tcsetattr' function. */
-#define HAVE_TCSETATTR 1
-
-/* Define to 1 if you have the <termios.h> header file. */
-#define HAVE_TERMIOS_H 1
-
-/* Define to 1 if you have the <termio.h> header file. */
-#define HAVE_TERMIO_H 1
-
-/* Define to 1 if you have the <time.h> header file. */
-#define HAVE_TIME_H 1
-
-/* Define to 1 if you have the `uname' function. */
-#define HAVE_UNAME 1
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#define HAVE_UNISTD_H 1
-
-/* Define to 1 if you have the `utime' function. */
-#define HAVE_UTIME 1
-
-/* Define to 1 if you have the <utime.h> header file. */
-#define HAVE_UTIME_H 1
-
-/* Define to 1 if you have the <winsock.h> header file. */
-/* #undef HAVE_WINSOCK_H */
-
-/* Define to 1 if you have the <x509.h> header file. */
-/* #undef HAVE_X509_H */
-
-/* if you have the zlib.h header file */
-/* #undef HAVE_ZLIB_H */
-
-/* if you have the Kerberos4 libraries (including -ldes) */
-/* #undef KRB4 */
-
-/* cpu-machine-OS */
-#define OS "powerpc-ibm-aix5.1.0.0"
-
-/* Name of package */
-#define PACKAGE "curl"
-
-/* Define to the address where bug reports for this package should be sent. */
-#define PACKAGE_BUGREPORT ""
-
-/* Define to the full name of this package. */
-#define PACKAGE_NAME ""
-
-/* Define to the full name and version of this package. */
-#define PACKAGE_STRING ""
-
-/* Define to the one symbol short name of this package. */
-#define PACKAGE_TARNAME ""
-
-/* Define to the version of this package. */
-#define PACKAGE_VERSION ""
-
-/* a suitable file to read random data from */
-/* #undef RANDOM_FILE */
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#define RETSIGTYPE void
-
-/* Define to 1 if you have the ANSI C header files. */
-#define STDC_HEADERS 1
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#define TIME_WITH_SYS_TIME 1
-
-/* Version number of package */
-#define VERSION "7.10.2"
-
-/* Define to 1 if on AIX 3.
- System headers sometimes define this.
- We just want to avoid a redefinition error message. */
-#ifndef _ALL_SOURCE
-# define _ALL_SOURCE 1
-#endif
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-/* #undef _FILE_OFFSET_BITS */
-
-/* Define for large files, on AIX-style hosts. */
-#define _LARGE_FILES 1
-
-/* Define to empty if `const' does not conform to ANSI C. */
-/* #undef const */
-
-/* type to use in place of in_addr_t if not defined */
-/* #undef in_addr_t */
-
-/* Define to `unsigned' if <sys/types.h> does not define. */
-/* #undef size_t */
-
-/* type to use in place of socklen_t if not defined */
-/* #undef socklen_t */
-
-/* Define to `int' if <sys/types.h> does not define. */
-/* #undef ssize_t */
diff --git a/Utilities/cmcurl/Testing/CMakeLists.txt b/Utilities/cmcurl/Testing/CMakeLists.txt
deleted file mode 100644
index 214410fd5..000000000
--- a/Utilities/cmcurl/Testing/CMakeLists.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-SET(CURL_TESTS
- ftpget
- ftpgetresp
- ftpupload
- getinmemory
- persistant
- sepheaders
- simple
- )
-
-CONFIGURE_FILE(${LIBCURL_SOURCE_DIR}/Testing/testconfig.h.in
- ${LIBCURL_BINARY_DIR}/Testing/testconfig.h)
-
-INCLUDE_DIRECTORIES(${LIBCURL_BINARY_DIR}/Testing)
-
-FOREACH(TEST ${CURL_TESTS})
- ADD_EXECUTABLE(${TEST} ${TEST}.c)
- TARGET_LINK_LIBRARIES(${TEST} cmcurl)
-ENDFOREACH(TEST)
diff --git a/Utilities/cmcurl/Testing/curlgtk.c b/Utilities/cmcurl/Testing/curlgtk.c
deleted file mode 100644
index 7c9ce2a1b..000000000
--- a/Utilities/cmcurl/Testing/curlgtk.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-/* Copyright (c) 2000 David Odin (aka DindinX) for MandrakeSoft */
-/* an attempt to use the curl library in concert with a gtk-threaded application */
-
-#include <stdio.h>
-#include <gtk/gtk.h>
-
-#include <curl/curl.h>
-#include <curl/types.h> /* new for v7 */
-#include <curl/easy.h> /* new for v7 */
-
-#include <pthread.h>
-
-GtkWidget *Bar;
-
-size_t my_read_func(void *ptr, size_t size, size_t nmemb, FILE *stream)
-{
- return fread(ptr, size, nmemb, stream);
-}
-
-int my_progress_func(GtkWidget *Bar, int t, int d)
-{
-/* printf("%d / %d (%g %%)\n", d, t, d*100.0/t);*/
- gdk_threads_enter();
- gtk_progress_set_value(GTK_PROGRESS(Bar), d*100.0/t);
- gdk_threads_leave();
- return 0;
-}
-
-void *curl_thread(void *ptr)
-{
- CURL *curl;
- CURLcode res;
- FILE *outfile;
- gchar *url = ptr;
-
- curl = curl_easy_init();
- if(curl)
- {
- outfile = fopen("/tmp/test.curl", "w");
-
- curl_easy_setopt(curl, CURLOPT_URL, url);
- curl_easy_setopt(curl, CURLOPT_FILE, outfile);
- curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_read_func);
- curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, my_progress_func);
- curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, Bar);
-
- res = curl_easy_perform(curl);
-
- fclose(outfile);
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- return NULL;
-}
-
-int main(int argc, char **argv)
-{
- GtkWidget *Window, *Frame, *Frame2;
- GtkAdjustment *adj;
- pthread_t curl_tid;
-
- /* Init thread */
- g_thread_init(NULL);
-
- gtk_init(&argc, &argv);
- Window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
- Frame = gtk_frame_new(NULL);
- gtk_frame_set_shadow_type(GTK_FRAME(Frame), GTK_SHADOW_OUT);
- gtk_container_add(GTK_CONTAINER(Window), Frame);
- Frame2 = gtk_frame_new(NULL);
- gtk_frame_set_shadow_type(GTK_FRAME(Frame2), GTK_SHADOW_IN);
- gtk_container_add(GTK_CONTAINER(Frame), Frame2);
- gtk_container_set_border_width(GTK_CONTAINER(Frame2), 5);
- adj = (GtkAdjustment*)gtk_adjustment_new(0, 0, 100, 0, 0, 0);
- Bar = gtk_progress_bar_new_with_adjustment(adj);
- gtk_container_add(GTK_CONTAINER(Frame2), Bar);
- gtk_widget_show_all(Window);
-
- pthread_create(&curl_tid, NULL, curl_thread, argv[1]);
-
- gdk_threads_enter();
- gtk_main();
- gdk_threads_leave();
- return 0;
-}
-
diff --git a/Utilities/cmcurl/Testing/ftpget.c b/Utilities/cmcurl/Testing/ftpget.c
deleted file mode 100644
index 1a3633ec9..000000000
--- a/Utilities/cmcurl/Testing/ftpget.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include "curl/curl.h"
-#include "curl/types.h"
-#include "curl/easy.h"
-#include "setup.h"
-
-#include "testconfig.h"
-
-/*
- * This is an example showing how to get a single file from an FTP server.
- * It delays the actual destination file creation until the first write
- * callback so that it won't create an empty file in case the remote file
- * doesn't exist or something else fails.
- */
-
-struct FtpFile {
- char *filename;
- FILE *stream;
-};
-
-int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
-{
- struct FtpFile *out=(struct FtpFile *)stream;
- if(out && !out->stream) {
- /* open file for writing */
- out->stream=fopen(out->filename, "wb");
- if(!out->stream)
- return -1; /* failure, can't open file to write */
- }
- return fwrite(buffer, size, nmemb, out->stream);
-}
-
-
-int main(void)
-{
- CURL *curl;
- CURLcode res;
- struct FtpFile ftpfile={
- LIBCURL_BINARY_DIR "/Testing/ftpget-download.txt", /* name to store the file as if succesful */
- NULL
- };
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
-
- curl = curl_easy_init();
- if(curl) {
- /* Get curl 7.9.2 from sunet.se's FTP site: */
- curl_easy_setopt(curl, CURLOPT_URL,
- "ftp://public.kitware.com/pub/cmake/cygwin/setup.hint");
- /* Define our callback to get called when there's data to be written */
- curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
- /* Set a pointer to our struct to pass to the callback */
- curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile);
-
- /* Switch on full protocol/debug output */
- curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE);
-
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
-
- if(CURLE_OK != res) {
- /* we failed */
- fprintf(stderr, "curl told us %d\n", res);
- }
- }
-
- if(ftpfile.stream)
- fclose(ftpfile.stream); /* close the local file */
-
- curl_global_cleanup();
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/ftpgetresp.c b/Utilities/cmcurl/Testing/ftpgetresp.c
deleted file mode 100644
index 9548b2a34..000000000
--- a/Utilities/cmcurl/Testing/ftpgetresp.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include "curl/curl.h"
-#include "curl/types.h"
-#include "curl/easy.h"
-
-#include "testconfig.h"
-
-/*
- * Similar to ftpget.c but this also stores the received response-lines
- * in a separate file using our own callback!
- *
- * This functionality was introduced in libcurl 7.9.3.
- */
-
-size_t
-write_response(void *ptr, size_t size, size_t nmemb, void *data)
-{
- FILE *writehere = (FILE *)data;
- return fwrite(ptr, size, nmemb, writehere);
-}
-
-int main(int argc, char **argv)
-{
- CURL *curl;
- CURLcode res;
- FILE *ftpfile;
- FILE *respfile;
- (void)argc; (void)argv;
-
- /* local file name to store the file as */
- ftpfile = fopen(LIBCURL_BINARY_DIR "/Testing/ftpgetresp-list.txt", "wb"); /* b is binary, needed on win32 */
-
- /* local file name to store the FTP server's response lines in */
- respfile = fopen(LIBCURL_BINARY_DIR "/Testing/ftpgetresp-responses.txt", "wb"); /* b is binary, needed on win32 */
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
-
- curl = curl_easy_init();
- if(curl) {
- /* Get a file listing from sunet */
- curl_easy_setopt(curl, CURLOPT_URL, "ftp://public.kitware.com/");
- curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
- curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response);
- curl_easy_setopt(curl, CURLOPT_WRITEHEADER, respfile);
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
-
- fclose(ftpfile); /* close the local file */
- fclose(respfile); /* close the response file */
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/ftpupload.c b/Utilities/cmcurl/Testing/ftpupload.c
deleted file mode 100644
index 780c9cd27..000000000
--- a/Utilities/cmcurl/Testing/ftpupload.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include "curl/curl.h"
-#include "setup.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include "testconfig.h"
-
-/*
- * This example shows an FTP upload, with a rename of the file just after
- * a successful upload.
- *
- * Example based on source code provided by Erick Nuwendam. Thanks!
- */
-
-#define LOCAL_FILE LIBCURL_SOURCE_DIR "/Testing/ftpupload.c"
-#define UPLOAD_FILE_AS "while-uploading.txt"
-#define REMOTE_URL "ftp://public.kitware.com/incoming/" UPLOAD_FILE_AS
-#define RENAME_FILE_TO "renamed-and-fine.txt"
-
-int main(int argc, char **argv)
-{
- CURL *curl;
- CURLcode res;
- FILE *ftpfile;
- FILE * hd_src ;
- int hd ;
- struct stat file_info;
-
- struct curl_slist *headerlist=NULL;
- char buf_1 [] = "RNFR " UPLOAD_FILE_AS;
- char buf_2 [] = "RNTO " RENAME_FILE_TO;
-
- /* get the file size of the local file */
- hd = open(LOCAL_FILE, O_RDONLY) ;
- fstat(hd, &file_info);
- close(hd) ;
-
- /* get a FILE * of the same file, could also be made with
- fdopen() from the previous descriptor, but hey this is just
- an example! */
- hd_src = fopen(LOCAL_FILE, "rb");
-
- /* In windows, this will init the winsock stuff */
- curl_global_init(CURL_GLOBAL_ALL);
-
- /* get a curl handle */
- curl = curl_easy_init();
- if(curl) {
- /* build a list of commands to pass to libcurl */
- headerlist = curl_slist_append(headerlist, buf_1);
- headerlist = curl_slist_append(headerlist, buf_2);
-
- /* enable uploading */
- curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
-
- /* specify target */
- curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL);
-
- /* pass in that last of FTP commands to run after the transfer */
- curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
-
- /* now specify which file to upload */
- curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
-
- /* and give the size of the upload (optional) */
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, (long)file_info.st_size);
-
- /* Now run off and do what you've been told! */
- res = curl_easy_perform(curl);
-
- /* clean up the FTP commands list */
- curl_slist_free_all (headerlist);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- fclose(hd_src); /* close the local file */
-
- curl_global_cleanup();
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/getinmemory.c b/Utilities/cmcurl/Testing/getinmemory.c
deleted file mode 100644
index a8872da77..000000000
--- a/Utilities/cmcurl/Testing/getinmemory.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- *
- * Example source code to show how the callback function can be used to
- * download data into a chunk of memory instead of storing it in a file.
- *
- * This exact source code has not been verified to work.
- */
-
-/* to make this work under windows, use the win32-functions from the
- win32socket.c file as well */
-
-#include "curl/curl.h"
-#include "curl/types.h"
-#include "curl/easy.h"
-
-struct MemoryStruct {
- char *memory;
- size_t size;
-};
-
-size_t
-WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
-{
- register int realsize = size * nmemb;
- struct MemoryStruct *mem = (struct MemoryStruct *)data;
-
- mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
- if (mem->memory) {
- memcpy(&(mem->memory[mem->size]), ptr, realsize);
- mem->size += realsize;
- mem->memory[mem->size] = 0;
- }
- return realsize;
-}
-
-int main(int argc, char **argv)
-{
- CURL *curl_handle;
-
- struct MemoryStruct chunk;
-
- chunk.memory=NULL; /* we expect realloc(NULL, size) to work */
- chunk.size = 0; /* no data at this point */
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
-
- /* init the curl session */
- curl_handle = curl_easy_init();
-
- /* specify URL to get */
- curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
-
- /* send all data to this function */
- curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
-
- /* we pass our 'chunk' struct to the callback function */
- curl_easy_setopt(curl_handle, CURLOPT_FILE, (void *)&chunk);
-
- /* get it! */
- curl_easy_perform(curl_handle);
-
- /* cleanup curl stuff */
- curl_easy_cleanup(curl_handle);
-
- /*
- * Now, our chunk.memory points to a memory block that is chunk.size
- * bytes big and contains the remote file.
- *
- * Do something nice with it!
- */
-
- /* For example display it... */
- write(1, chunk.memory, chunk.size);
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/http-post.c b/Utilities/cmcurl/Testing/http-post.c
deleted file mode 100644
index 1b4154fbf..000000000
--- a/Utilities/cmcurl/Testing/http-post.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include <stdio.h>
-#include <curl/curl.h>
-
-int main(void)
-{
- CURL *curl;
- CURLcode res;
-
- curl = curl_easy_init();
- if(curl) {
- /* First set the URL that is about to receive our POST. This URL can
- just as well be a https:// URL if that is what should receive the
- data. */
- curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
- /* Now specify the POST data */
- curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
-
- /* Perform the request, res will get the return code */
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/httpput.c b/Utilities/cmcurl/Testing/httpput.c
deleted file mode 100644
index 78275c40a..000000000
--- a/Utilities/cmcurl/Testing/httpput.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-
-#include <curl/curl.h>
-
-/*
- * This example shows a HTTP PUT operation. PUTs a file given as a command
- * line argument to the URL also given on the command line.
- *
- * This example also uses its own read callback.
- */
-
-size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
-{
- size_t retcode;
-
- /* in real-world cases, this would probably get this data differently
- as this fread() stuff is exactly what the library already would do
- by default internally */
- retcode = fread(ptr, size, nmemb, stream);
-
- fprintf(stderr, "*** We read %d bytes from file\n", retcode);
-
- return retcode;
-}
-
-int main(int argc, char **argv)
-{
- CURL *curl;
- CURLcode res;
- FILE *ftpfile;
- FILE * hd_src ;
- int hd ;
- struct stat file_info;
-
- char *file;
- char *url;
-
- if(argc < 3)
- return 1;
-
- file= argv[1];
- url = argv[2];
-
- /* get the file size of the local file */
- hd = open(file, O_RDONLY) ;
- fstat(hd, &file_info);
- close(hd) ;
-
- /* get a FILE * of the same file, could also be made with
- fdopen() from the previous descriptor, but hey this is just
- an example! */
- hd_src = fopen(file, "rb");
-
- /* In windows, this will init the winsock stuff */
- curl_global_init(CURL_GLOBAL_ALL);
-
- /* get a curl handle */
- curl = curl_easy_init();
- if(curl) {
- /* we want to use our own read function */
- curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
-
- /* enable uploading */
- curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
-
- /* HTTP PUT please */
- curl_easy_setopt(curl, CURLOPT_PUT, TRUE);
-
- /* specify target */
- curl_easy_setopt(curl,CURLOPT_URL, url);
-
- /* now specify which file to upload */
- curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
-
- /* and give the size of the upload (optional) */
- curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_info.st_size);
-
- /* Now run off and do what you've been told! */
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- fclose(hd_src); /* close the local file */
-
- curl_global_cleanup();
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/multithread.c b/Utilities/cmcurl/Testing/multithread.c
deleted file mode 100644
index c3936ef4a..000000000
--- a/Utilities/cmcurl/Testing/multithread.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-/* A multi-threaded example that uses pthreads extensively to fetch
- * X remote files at once */
-
-#include <stdio.h>
-#include <pthread.h>
-#include <curl/curl.h>
-
-/* silly list of test-URLs */
-char *urls[]= {
- "http://curl.haxx.se/",
- "ftp://cool.haxx.se/",
- "http://www.contactor.se/",
- "www.haxx.se"
-};
-
-void *pull_one_url(void *url)
-{
- CURL *curl;
-
- curl = curl_easy_init();
-
- curl_easy_setopt(curl, CURLOPT_URL, url);
- curl_easy_perform(curl);
-
- curl_easy_cleanup(curl);
-
- return NULL;
-}
-
-
-/*
- int pthread_create(pthread_t *new_thread_ID,
- const pthread_attr_t *attr,
- void * (*start_func)(void *), void *arg);
-*/
-
-int main(int argc, char **argv)
-{
- pthread_t tid[4];
- int i;
- int error;
- for(i=0; i< 4; i++) {
- error = pthread_create(&tid[i],
- NULL, /* default attributes please */
- pull_one_url,
- urls[i]);
- if(0 != error)
- fprintf(stderr, "Couldn't run thread number %d, errno %d\n", i, error);
- else
- fprintf(stderr, "Thread %d, gets %s\n", i, urls[i]);
- }
-
- /* now wait for all threads to terminate */
- for(i=0; i< 4; i++) {
- error = pthread_join(tid[i], NULL);
- fprintf(stderr, "Thread %d terminated\n", i);
- }
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/persistant.c b/Utilities/cmcurl/Testing/persistant.c
deleted file mode 100644
index 853470345..000000000
--- a/Utilities/cmcurl/Testing/persistant.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include <stdio.h>
-
-#include "curl/curl.h"
-
-/* to make this work under windows, use the win32-functions from the
- docs/examples/win32socket.c file as well */
-
-/* This example REQUIRES libcurl 7.7 or later */
-#if (LIBCURL_VERSION_NUM < 0x070700)
-#error Too old libcurl version, upgrade or stay away.
-#endif
-
-int main(int argc, char **argv)
-{
- CURL *curl;
- CURLcode res;
-
-#ifdef MALLOCDEBUG
- /* this sends all memory debug messages to a specified logfile */
- curl_memdebug("memdump");
-#endif
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
- curl = curl_easy_init();
- if(curl) {
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
- curl_easy_setopt(curl, CURLOPT_HEADER, 1);
-
- /* get the first document */
- curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/");
- res = curl_easy_perform(curl);
-
- /* get another document from the same server using the same
- connection */
- curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/postit2.c b/Utilities/cmcurl/Testing/postit2.c
deleted file mode 100644
index 9b7cda07e..000000000
--- a/Utilities/cmcurl/Testing/postit2.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- *
- * Example code that uploads a file name 'foo' to a remote script that accepts
- * "HTML form based" (as described in RFC1738) uploads using HTTP POST.
- *
- * The imaginary form we'll fill in looks like:
- *
- * <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
- * Enter file: <input type="file" name="sendfile" size="40">
- * Enter file name: <input type="text" name="filename" size="30">
- * <input type="submit" value="send" name="submit">
- * </form>
- *
- * This exact source code has not been verified to work.
- */
-
-/* to make this work under windows, use the win32-functions from the
- win32socket.c file as well */
-
-#include <stdio.h>
-#include <string.h>
-
-#include <curl/curl.h>
-#include <curl/types.h>
-#include <curl/easy.h>
-
-#if LIBCURL_VERSION_NUM < 0x070900
-#error "curl_formadd() is not introduced until libcurl 7.9 and later"
-#endif
-
-int main(int argc, char *argv[])
-{
- CURL *curl;
- CURLcode res;
-
- struct HttpPost *formpost=NULL;
- struct HttpPost *lastptr=NULL;
- struct curl_slist *headerlist=NULL;
- char buf[] = "Expect:";
-
- /* Fill in the file upload field */
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "sendfile",
- CURLFORM_FILE, "postit2.c",
- CURLFORM_END);
-
- /* Fill in the filename field */
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "filename",
- CURLFORM_COPYCONTENTS, "postit2.c",
- CURLFORM_END);
-
-
- /* Fill in the submit field too, even if this is rarely needed */
- curl_formadd(&formpost,
- &lastptr,
- CURLFORM_COPYNAME, "submit",
- CURLFORM_COPYCONTENTS, "send",
- CURLFORM_END);
-
- curl = curl_easy_init();
- /* initalize custom header list (stating that Expect: 100-continue is not
- wanted */
- headerlist = curl_slist_append(headerlist, buf);
- if(curl) {
- /* what URL that receives this POST */
- curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi");
- if ( (argc == 2) && (!strcmp(argv[1], "noexpectheader")) )
- /* only disable 100-continue header if explicitly requested */
- curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
- curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
-
- /* then cleanup the formpost chain */
- curl_formfree(formpost);
- /* free slist */
- curl_slist_free_all (headerlist);
- }
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/sepheaders.c b/Utilities/cmcurl/Testing/sepheaders.c
deleted file mode 100644
index fc5b783bc..000000000
--- a/Utilities/cmcurl/Testing/sepheaders.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-/* to make this work under windows, use the win32-functions from the
- win32socket.c file as well */
-
-#include "curl/curl.h"
-#include "curl/types.h"
-#include "curl/easy.h"
-
-#include "testconfig.h"
-
-size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream)
-{
- int written = fwrite(ptr, size, nmemb, (FILE *)stream);
- return written;
-}
-
-int main(int argc, char **argv)
-{
- CURL *curl_handle;
- char *headerfilename = LIBCURL_BINARY_DIR "/Testing/sepheaders-head.out";
- FILE *headerfile;
- char *bodyfilename = LIBCURL_BINARY_DIR "/Testing/sepheaders-body.out";
- FILE *bodyfile;
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
- /* init the curl session */
- curl_handle = curl_easy_init();
-
- /* set URL to get */
- curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
-
- /* no progress meter please */
- curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1);
-
- /* shut up completely */
- //curl_easy_setopt(curl_handle, CURLOPT_MUTE, 1);
-
- /* send all data to this function */
- curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data);
-
- /* open the files */
- headerfile = fopen(headerfilename,"w");
- if (headerfile == NULL) {
- curl_easy_cleanup(curl_handle);
- return -1;
- }
- bodyfile = fopen(bodyfilename,"w");
- if (bodyfile == NULL) {
- curl_easy_cleanup(curl_handle);
- fclose(headerfile);
- return -1;
- }
-
- /* we want the headers to this file handle */
- curl_easy_setopt(curl_handle, CURLOPT_WRITEHEADER ,headerfile);
-
- /* we want the body to this file handle */
- curl_easy_setopt(curl_handle, CURLOPT_FILE ,bodyfile);
-
- /* get it! */
- curl_easy_perform(curl_handle);
-
- /* close the header file */
- fclose(headerfile);
- fclose(bodyfile);
-
- /* cleanup curl stuff */
- curl_easy_cleanup(curl_handle);
-
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/simple.c b/Utilities/cmcurl/Testing/simple.c
deleted file mode 100644
index 6dd6050ec..000000000
--- a/Utilities/cmcurl/Testing/simple.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include "curl/curl.h"
-
-int main(void)
-{
- CURL *curl;
- CURLcode res;
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
- curl = curl_easy_init();
- if(curl) {
- curl_easy_setopt(curl, CURLOPT_URL, "http://www.cmake.org/HTML/Index.html");
- res = curl_easy_perform(curl);
-
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/simplessl.c b/Utilities/cmcurl/Testing/simplessl.c
deleted file mode 100644
index e307eaa6f..000000000
--- a/Utilities/cmcurl/Testing/simplessl.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*****************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * $Id$
- */
-
-#include <stdio.h>
-
-#include <curl/curl.h>
-#include <curl/types.h>
-#include <curl/easy.h>
-
-
-/* some requirements for this to work:
- 1. set pCertFile to the file with the client certificate
- 2. if the key is passphrase protected, set pPassphrase to the
- passphrase you use
- 3. if you are using a crypto engine:
- 3.1. set a #define USE_ENGINE
- 3.2. set pEngine to the name of the crypto engine you use
- 3.3. set pKeyName to the key identifier you want to use
- 4. if you don't use a crypto engine:
- 4.1. set pKeyName to the file name of your client key
- 4.2. if the format of the key file is DER, set pKeyType to "DER"
-
- !! verify of the server certificate is not implemented here !!
-
- **** This example only works with libcurl 7.9.3 and later! ****
-
-*/
-
-int main(int argc, char **argv)
-{
- CURL *curl;
- CURLcode res;
- FILE *headerfile;
-
- const char *pCertFile = "testcert.pem";
- const char *pCACertFile="cacert.pem"
-
- const char *pKeyName;
- const char *pKeyType;
-
- const char *pEngine;
-
-#if USE_ENGINE
- pKeyName = "rsa_test";
- pKeyType = "ENG";
- pEngine = "chil"; /* for nChiper HSM... */
-#else
- pKeyName = "testkey.pem";
- pKeyType = "PEM";
- pEngine = NULL;
-#endif
-
- const char *pPassphrase = NULL;
-
- headerfile = fopen("dumpit", "w");
-
- curl_global_init(CURL_GLOBAL_DEFAULT);
-
- curl = curl_easy_init();
- if(curl) {
- /* what call to write: */
- curl_easy_setopt(curl, CURLOPT_URL, "HTTPS://curl.haxx.se");
- curl_easy_setopt(curl, CURLOPT_WRITEHEADER, headerfile);
-
- while(1) /* do some ugly short cut... */
- {
- if (pEngine) /* use crypto engine */
- {
- if (curl_easy_setopt(curl, CURLOPT_SSLENGINE,pEngine) != CURLE_OK)
- { /* load the crypto engine */
- fprintf(stderr,"can't set crypto engine\n");
- break;
- }
- if (curl_easy_setopt(curl, CURLOPT_SSLENGINE_DEFAULT,1) != CURLE_OK)
- { /* set the crypto engine as default */
- /* only needed for the first time you load
- a engine in a curl object... */
- fprintf(stderr,"can't set crypto engine as default\n");
- break;
- }
- }
- /* cert is stored PEM coded in file... */
- /* since PEM is default, we needn't set it for PEM */
- curl_easy_setopt(curl,CURLOPT_SSLCERTTYPE,"PEM");
- /* set the cert for client authentication */
- curl_easy_setopt(curl,CURLOPT_SSLCERT,pCertFile);
- /* sorry, for engine we must set the passphrase
- (if the key has one...) */
- if (pPassphrase)
- curl_easy_setopt(curl,CURLOPT_SSLKEYPASSWD,pPassphrase);
- /* if we use a key stored in a crypto engine,
- we must set the key type to "ENG" */
- curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE,pKeyType);
- /* set the private key (file or ID in engine) */
- curl_easy_setopt(curl,CURLOPT_SSLKEY,pKeyName);
- /* set the file with the certs vaildating the server */
- curl_easy_setopt(curl,CURLOPT_CAINFO,pCACertFile);
- /* disconnect if we can't validate server's cert */
- curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,1);
-
- res = curl_easy_perform(curl);
- break; /* we are done... */
- }
- /* always cleanup */
- curl_easy_cleanup(curl);
- }
-
- curl_global_cleanup();
-
- if (headerfile)
- fclose(headerfile);
- return 0;
-}
diff --git a/Utilities/cmcurl/Testing/testconfig.h.in b/Utilities/cmcurl/Testing/testconfig.h.in
deleted file mode 100644
index faab46223..000000000
--- a/Utilities/cmcurl/Testing/testconfig.h.in
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __testconfig_h__
-#define __testconfig_h__
-
-#define LIBCURL_SOURCE_DIR "${LIBCURL_SOURCE_DIR}"
-#define LIBCURL_BINARY_DIR "${LIBCURL_BINARY_DIR}"
-
-#endif /* __testconfig_h__ */
diff --git a/Utilities/cmcurl/Testing/win32sockets.c b/Utilities/cmcurl/Testing/win32sockets.c
deleted file mode 100644
index 5f791c8b5..000000000
--- a/Utilities/cmcurl/Testing/win32sockets.c
+++ /dev/null
@@ -1,49 +0,0 @@
-
-/*
- * Note: This is only required if you use curl 7.8 or lower, later
- * versions provide an option to curl_global_init() that does the
- * win32 initialization for you.
- */
-
-/*
- * These are example functions doing socket init that Windows
- * require. If you don't use windows, you can safely ignore this crap.
- */
-
-#include <windows.h>
-
-void win32_cleanup(void)
-{
- WSACleanup();
-}
-
-int win32_init(void)
-{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
- wVersionRequested = MAKEWORD(1, 1);
-
- err = WSAStartup(wVersionRequested, &wsaData);
-
- if (err != 0)
- /* Tell the user that we couldn't find a useable */
- /* winsock.dll. */
- return 1;
-
- /* Confirm that the Windows Sockets DLL supports 1.1.*/
- /* Note that if the DLL supports versions greater */
- /* than 1.1 in addition to 1.1, it will still return */
- /* 1.1 in wVersion since that is the version we */
- /* requested. */
-
- if ( LOBYTE( wsaData.wVersion ) != 1 ||
- HIBYTE( wsaData.wVersion ) != 1 ) {
- /* Tell the user that we couldn't find a useable */
-
- /* winsock.dll. */
- WSACleanup();
- return 1;
- }
- return 0; /* 0 is ok */
-}
diff --git a/Utilities/cmcurl/amigaos.c b/Utilities/cmcurl/amigaos.c
deleted file mode 100644
index 7106f8daf..000000000
--- a/Utilities/cmcurl/amigaos.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "amigaos.h"
-#include <amitcp/socketbasetags.h>
-
-struct Library *SocketBase = NULL;
-extern int errno, h_errno;
-
-#ifdef __libnix__
-#include <stabs.h>
-void __request(const char *msg);
-#else
-# define __request( msg ) Printf( msg "\n\a")
-#endif
-
-void amiga_cleanup()
-{
- if(SocketBase) {
- CloseLibrary(SocketBase);
- SocketBase = NULL;
- }
-}
-
-BOOL amiga_init()
-{
- if(!SocketBase)
- SocketBase = OpenLibrary("bsdsocket.library", 4);
-
- if(!SocketBase) {
- __request("No TCP/IP Stack running!");
- return FALSE;
- }
-
- if(SocketBaseTags(
- SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
-// SBTM_SETVAL(SBTC_HERRNOLONGPTR), (ULONG) &h_errno,
- SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL",
- TAG_DONE)) {
-
- __request("SocketBaseTags ERROR");
- return FALSE;
- }
-
-#ifndef __libnix__
- atexit(amiga_cleanup);
-#endif
-
- return TRUE;
-}
-
-#ifdef __libnix__
-ADD2EXIT(amiga_cleanup,-50);
-#endif
diff --git a/Utilities/cmcurl/amigaos.h b/Utilities/cmcurl/amigaos.h
deleted file mode 100644
index e5786d482..000000000
--- a/Utilities/cmcurl/amigaos.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifndef LIBCURL_AMIGAOS_H
-#define LIBCURL_AMIGAOS_H
-
-#ifndef __ixemul__
-
-#include <exec/types.h>
-#include <exec/execbase.h>
-
-#include <proto/exec.h>
-#include <proto/dos.h>
-
-#include <sys/socket.h>
-
-#include "config-amigaos.h"
-
-#ifndef select
-# define select(args...) WaitSelect( args, NULL)
-#endif
-#ifndef inet_ntoa
-# define inet_ntoa(x) Inet_NtoA( x ## .s_addr)
-#endif
-#ifndef ioctl
-# define ioctl(a,b,c,d) IoctlSocket( (LONG)a, (ULONG)b, (char*)c)
-#endif
-#define _AMIGASF 1
-
-extern void amiga_cleanup();
-extern BOOL amiga_init();
-
-#else /* __ixemul__ */
-
-#warning compiling with ixemul...
-
-#endif /* __ixemul__ */
-#endif /* LIBCURL_AMIGAOS_H */
diff --git a/Utilities/cmcurl/arpa_telnet.h b/Utilities/cmcurl/arpa_telnet.h
deleted file mode 100644
index e6a04dcef..000000000
--- a/Utilities/cmcurl/arpa_telnet.h
+++ /dev/null
@@ -1,101 +0,0 @@
-#ifndef __ARPA_TELNET_H
-#define __ARPA_TELNET_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_TELNET
-/*
- * Telnet option defines. Add more here if in need.
- */
-#define CURL_TELOPT_BINARY 0 /* binary 8bit data */
-#define CURL_TELOPT_SGA 3 /* Supress Go Ahead */
-#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */
-#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */
-#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
-
-#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
-#define CURL_NEW_ENV_VAR 0
-#define CURL_NEW_ENV_VALUE 1
-
-/*
- * The telnet options represented as strings
- */
-static const char * const telnetoptions[]=
-{
- "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD",
- "NAME", "STATUS", "TIMING MARK", "RCTE",
- "NAOL", "NAOP", "NAOCRD", "NAOHTS",
- "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD",
- "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
- "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION",
- "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING",
- "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS",
- "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
- "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
-};
-
-#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
-
-#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
-#define CURL_TELOPT(x) telnetoptions[x]
-
-#define CURL_NTELOPTS 40
-
-/*
- * First some defines
- */
-#define CURL_xEOF 236 /* End Of File */
-#define CURL_SE 240 /* Sub negotiation End */
-#define CURL_NOP 241 /* No OPeration */
-#define CURL_DM 242 /* Data Mark */
-#define CURL_GA 249 /* Go Ahead, reverse the line */
-#define CURL_SB 250 /* SuBnegotiation */
-#define CURL_WILL 251 /* Our side WILL use this option */
-#define CURL_WONT 252 /* Our side WON'T use this option */
-#define CURL_DO 253 /* DO use this option! */
-#define CURL_DONT 254 /* DON'T use this option! */
-#define CURL_IAC 255 /* Interpret As Command */
-
-/*
- * Then those numbers represented as strings:
- */
-static const char * const telnetcmds[]=
-{
- "EOF", "SUSP", "ABORT", "EOR", "SE",
- "NOP", "DMARK", "BRK", "IP", "AO",
- "AYT", "EC", "EL", "GA", "SB",
- "WILL", "WONT", "DO", "DONT", "IAC"
-};
-
-#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
-#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
-
-#define CURL_TELQUAL_IS 0
-#define CURL_TELQUAL_SEND 1
-#define CURL_TELQUAL_INFO 2
-#define CURL_TELQUAL_NAME 3
-
-#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
- ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
-#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
-#endif
-#endif
diff --git a/Utilities/cmcurl/base64.c b/Utilities/cmcurl/base64.c
deleted file mode 100644
index aa03f8346..000000000
--- a/Utilities/cmcurl/base64.c
+++ /dev/null
@@ -1,366 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* Base64 encoding/decoding
- *
- * Test harnesses down the bottom - compile with -DTEST_ENCODE for
- * a program that will read in raw data from stdin and write out
- * a base64-encoded version to stdout, and the length returned by the
- * encoding function to stderr. Compile with -DTEST_DECODE for a program that
- * will go the other way.
- *
- * This code will break if int is smaller than 32 bits
- */
-
-#include "setup.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "urldata.h" /* for the SessionHandle definition */
-#include "easyif.h" /* for Curl_convert_... prototypes */
-#include "base64.h"
-#include "memory.h"
-
-/* include memdebug.h last */
-#include "memdebug.h"
-
-/* ---- Base64 Encoding/Decoding Table --- */
-static const char table64[]=
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-static void decodeQuantum(unsigned char *dest, const char *src)
-{
- unsigned int x = 0;
- int i;
- char *found;
-
- for(i = 0; i < 4; i++) {
- if((found = strchr(table64, src[i])))
- x = (x << 6) + (unsigned int)(found - table64);
- else if(src[i] == '=')
- x = (x << 6);
- }
-
- dest[2] = (unsigned char)(x & 255);
- x >>= 8;
- dest[1] = (unsigned char)(x & 255);
- x >>= 8;
- dest[0] = (unsigned char)(x & 255);
-}
-
-/*
- * Curl_base64_decode()
- *
- * Given a base64 string at src, decode it and return an allocated memory in
- * the *outptr. Returns the length of the decoded data.
- */
-size_t Curl_base64_decode(const char *src, unsigned char **outptr)
-{
- int length = 0;
- int equalsTerm = 0;
- int i;
- int numQuantums;
- unsigned char lastQuantum[3];
- size_t rawlen=0;
- unsigned char *newstr;
-
- *outptr = NULL;
-
- while((src[length] != '=') && src[length])
- length++;
- /* A maximum of two = padding characters is allowed */
- if(src[length] == '=') {
- equalsTerm++;
- if(src[length+equalsTerm] == '=')
- equalsTerm++;
- }
- numQuantums = (length + equalsTerm) / 4;
-
- /* Don't allocate a buffer if the decoded length is 0 */
- if (numQuantums <= 0)
- return 0;
-
- rawlen = (numQuantums * 3) - equalsTerm;
-
- /* The buffer must be large enough to make room for the last quantum
- (which may be partially thrown out) and the zero terminator. */
- newstr = malloc(rawlen+4);
- if(!newstr)
- return 0;
-
- *outptr = newstr;
-
- /* Decode all but the last quantum (which may not decode to a
- multiple of 3 bytes) */
- for(i = 0; i < numQuantums - 1; i++) {
- decodeQuantum((unsigned char *)newstr, src);
- newstr += 3; src += 4;
- }
-
- /* This final decode may actually read slightly past the end of the buffer
- if the input string is missing pad bytes. This will almost always be
- harmless. */
- decodeQuantum(lastQuantum, src);
- for(i = 0; i < 3 - equalsTerm; i++)
- newstr[i] = lastQuantum[i];
-
- newstr[i] = 0; /* zero terminate */
- return rawlen;
-}
-
-/*
- * Curl_base64_encode()
- *
- * Returns the length of the newly created base64 string. The third argument
- * is a pointer to an allocated area holding the base64 data. If something
- * went wrong, -1 is returned.
- *
- */
-size_t Curl_base64_encode(struct SessionHandle *data,
- const char *inp, size_t insize, char **outptr)
-{
- unsigned char ibuf[3];
- unsigned char obuf[4];
- int i;
- int inputparts;
- char *output;
- char *base64data;
-#ifdef CURL_DOES_CONVERSIONS
- char *convbuf;
-#endif
-
- char *indata = (char *)inp;
-
- *outptr = NULL; /* set to NULL in case of failure before we reach the end */
-
- if(0 == insize)
- insize = strlen(indata);
-
- base64data = output = (char*)malloc(insize*4/3+4);
- if(NULL == output)
- return 0;
-
-#ifdef CURL_DOES_CONVERSIONS
- /*
- * The base64 data needs to be created using the network encoding
- * not the host encoding. And we can't change the actual input
- * so we copy it to a buffer, translate it, and use that instead.
- */
- if(data) {
- convbuf = (char*)malloc(insize);
- if(!convbuf) {
- return 0;
- }
- memcpy(convbuf, indata, insize);
- if(CURLE_OK != Curl_convert_to_network(data, convbuf, insize)) {
- free(convbuf);
- return 0;
- }
- indata = convbuf; /* switch to the converted buffer */
- }
-#else
- (void)data;
-#endif
-
- while(insize > 0) {
- for (i = inputparts = 0; i < 3; i++) {
- if(insize > 0) {
- inputparts++;
- ibuf[i] = *indata;
- indata++;
- insize--;
- }
- else
- ibuf[i] = 0;
- }
-
- obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
- obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
- ((ibuf[1] & 0xF0) >> 4));
- obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
- ((ibuf[2] & 0xC0) >> 6));
- obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
-
- switch(inputparts) {
- case 1: /* only one byte read */
- snprintf(output, 5, "%c%c==",
- table64[obuf[0]],
- table64[obuf[1]]);
- break;
- case 2: /* two bytes read */
- snprintf(output, 5, "%c%c%c=",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]]);
- break;
- default:
- snprintf(output, 5, "%c%c%c%c",
- table64[obuf[0]],
- table64[obuf[1]],
- table64[obuf[2]],
- table64[obuf[3]] );
- break;
- }
- output += 4;
- }
- *output=0;
- *outptr = base64data; /* make it return the actual data memory */
-
-#ifdef CURL_DOES_CONVERSIONS
- if(data)
- free(convbuf);
-#endif
- return strlen(base64data); /* return the length of the new data */
-}
-/* ---- End of Base64 Encoding ---- */
-
-/************* TEST HARNESS STUFF ****************/
-
-
-#ifdef TEST_ENCODE
-/* encoding test harness. Read in standard input and write out the length
- * returned by Curl_base64_encode, followed by the base64'd data itself
- */
-#include <stdio.h>
-
-#define TEST_NEED_SUCK
-void *suck(int *);
-
-int main(int argc, char **argv, char **envp)
-{
- char *base64;
- size_t base64Len;
- unsigned char *data;
- int dataLen;
- struct SessionHandle *handle = NULL;
-
-#ifdef CURL_DOES_CONVERSIONS
- /* get a Curl handle so Curl_base64_encode can translate properly */
- handle = curl_easy_init();
- if(handle == NULL) {
- fprintf(stderr, "Error: curl_easy_init failed\n");
- return 0;
- }
-#endif
- data = (unsigned char *)suck(&dataLen);
- base64Len = Curl_base64_encode(handle, data, dataLen, &base64);
-
- fprintf(stderr, "%d\n", base64Len);
- fprintf(stdout, "%s\n", base64);
-
- free(base64); free(data);
-#ifdef CURL_DOES_CONVERSIONS
- curl_easy_cleanup(handle);
-#endif
- return 0;
-}
-#endif
-
-#ifdef TEST_DECODE
-/* decoding test harness. Read in a base64 string from stdin and write out the
- * length returned by Curl_base64_decode, followed by the decoded data itself
- *
- * gcc -DTEST_DECODE base64.c -o base64 mprintf.o memdebug.o
- */
-#include <stdio.h>
-
-#define TEST_NEED_SUCK
-void *suck(int *);
-
-int main(int argc, char **argv, char **envp)
-{
- char *base64;
- int base64Len;
- unsigned char *data;
- int dataLen;
- int i, j;
-#ifdef CURL_DOES_CONVERSIONS
- /* get a Curl handle so main can translate properly */
- struct SessionHandle *handle = curl_easy_init();
- if(handle == NULL) {
- fprintf(stderr, "Error: curl_easy_init failed\n");
- return 0;
- }
-#endif
-
- base64 = (char *)suck(&base64Len);
- dataLen = Curl_base64_decode(base64, &data);
-
- fprintf(stderr, "%d\n", dataLen);
-
- for(i=0; i < dataLen; i+=0x10) {
- printf("0x%02x: ", i);
- for(j=0; j < 0x10; j++)
- if((j+i) < dataLen)
- printf("%02x ", data[i+j]);
- else
- printf(" ");
-
- printf(" | ");
-
- for(j=0; j < 0x10; j++)
- if((j+i) < dataLen) {
-#ifdef CURL_DOES_CONVERSIONS
- if(CURLE_OK !=
- Curl_convert_from_network(handle, &data[i+j], (size_t)1))
- data[i+j] = '.';
-#endif /* CURL_DOES_CONVERSIONS */
- printf("%c", ISGRAPH(data[i+j])?data[i+j]:'.');
- } else
- break;
- puts("");
- }
-
-#ifdef CURL_DOES_CONVERSIONS
- curl_easy_cleanup(handle);
-#endif
- free(base64); free(data);
- return 0;
-}
-#endif
-
-#ifdef TEST_NEED_SUCK
-/* this function 'sucks' in as much as possible from stdin */
-void *suck(int *lenptr)
-{
- int cursize = 8192;
- unsigned char *buf = NULL;
- int lastread;
- int len = 0;
-
- do {
- cursize *= 2;
- buf = (unsigned char *)realloc(buf, cursize);
- memset(buf + len, 0, cursize - len);
- lastread = fread(buf + len, 1, cursize - len, stdin);
- len += lastread;
- } while(!feof(stdin));
-
- lenptr[0] = len;
- return (void *)buf;
-}
-#endif
diff --git a/Utilities/cmcurl/base64.h b/Utilities/cmcurl/base64.h
deleted file mode 100644
index 59742bcd3..000000000
--- a/Utilities/cmcurl/base64.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __BASE64_H
-#define __BASE64_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-size_t Curl_base64_encode(struct SessionHandle *data,
- const char *input, size_t size, char **str);
-size_t Curl_base64_decode(const char *source, unsigned char **outptr);
-#endif
diff --git a/Utilities/cmcurl/ca-bundle.h b/Utilities/cmcurl/ca-bundle.h
deleted file mode 100644
index 12390bc7b..000000000
--- a/Utilities/cmcurl/ca-bundle.h
+++ /dev/null
@@ -1 +0,0 @@
-/* ca bundle path set in here*/
diff --git a/Utilities/cmcurl/config.h.in b/Utilities/cmcurl/config.h.in
deleted file mode 100644
index 148722b2f..000000000
--- a/Utilities/cmcurl/config.h.in
+++ /dev/null
@@ -1,720 +0,0 @@
-/* lib/config.h.in. Generated from configure.ac by autoheader. */
-
-/* when building libcurl itself */
-#cmakedefine BUILDING_LIBCURL ${BUILDING_LIBCURL}
-
-/* to disable cookies support */
-#cmakedefine CURL_DISABLE_COOKIES ${CURL_DISABLE_COOKIES}
-
-/* to disable cryptographic authentication */
-#cmakedefine CURL_DISABLE_CRYPTO_AUTH ${CURL_DISABLE_CRYPTO_AUTH}
-
-/* to disable DICT */
-#cmakedefine CURL_DISABLE_DICT ${CURL_DISABLE_DICT}
-
-/* to disable FILE */
-#cmakedefine CURL_DISABLE_FILE ${CURL_DISABLE_FILE}
-
-/* to disable FTP */
-#cmakedefine CURL_DISABLE_FTP ${CURL_DISABLE_FTP}
-
-/* to disable HTTP */
-#cmakedefine CURL_DISABLE_HTTP ${CURL_DISABLE_HTTP}
-
-/* to disable LDAP */
-#cmakedefine CURL_DISABLE_LDAP ${CURL_DISABLE_LDAP}
-
-/* to disable TELNET */
-#cmakedefine CURL_DISABLE_TELNET ${CURL_DISABLE_TELNET}
-
-/* to disable TFTP */
-#cmakedefine CURL_DISABLE_TFTP ${CURL_DISABLE_TFTP}
-
-/* to disable verbose strings */
-#cmakedefine CURL_DISABLE_VERBOSE_STRINGS ${CURL_DISABLE_VERBOSE_STRINGS}
-
-/* to make a symbol visible */
-#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
-
-/* to enable hidden symbols */
-#cmakedefine CURL_HIDDEN_SYMBOLS ${CURL_HIDDEN_SYMBOLS}
-
-/* when not building a shared library */
-#cmakedefine CURL_STATICLIB ${CURL_STATICLIB}
-
-/* Set to explicitly specify we don't want to use thread-safe functions */
-#cmakedefine DISABLED_THREADSAFE ${DISABLED_THREADSAFE}
-
-/* lber dynamic library file */
-#cmakedefine DL_LBER_FILE ${DL_LBER_FILE}
-
-/* ldap dynamic library file */
-#cmakedefine DL_LDAP_FILE ${DL_LDAP_FILE}
-
-/* your Entropy Gathering Daemon socket pathname */
-#cmakedefine EGD_SOCKET ${EGD_SOCKET}
-
-/* Define if you want to enable IPv6 support */
-#cmakedefine ENABLE_IPV6 ${ENABLE_IPV6}
-
-/* Define to the type qualifier of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
-
-/* Define to the type of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
-
-/* Define to the type of arg 2 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
-
-/* Define to the type of args 4 and 6 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
-
-/* Define to the type of arg 7 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
-
-/* Define to 1 if you have the <alloca.h> header file. */
-#cmakedefine HAVE_ALLOCA_H ${HAVE_ALLOCA_H}
-
-/* Define to 1 if you have the <arpa/inet.h> header file. */
-#cmakedefine HAVE_ARPA_INET_H ${HAVE_ARPA_INET_H}
-
-/* Define to 1 if you have the <arpa/tftp.h> header file. */
-#cmakedefine HAVE_ARPA_TFTP_H ${HAVE_ARPA_TFTP_H}
-
-/* Define to 1 if you have the <assert.h> header file. */
-#cmakedefine HAVE_ASSERT_H ${HAVE_ASSERT_H}
-
-/* Define to 1 if you have the `basename' function. */
-#cmakedefine HAVE_BASENAME ${HAVE_BASENAME}
-
-/* Define to 1 if you have the `closesocket' function. */
-#cmakedefine HAVE_CLOSESOCKET ${HAVE_CLOSESOCKET}
-
-/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
-#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA ${HAVE_CRYPTO_CLEANUP_ALL_EX_DATA}
-
-/* Define to 1 if you have the <crypto.h> header file. */
-#cmakedefine HAVE_CRYPTO_H ${HAVE_CRYPTO_H}
-
-/* Define to 1 if you have the <des.h> header file. */
-#cmakedefine HAVE_DES_H ${HAVE_DES_H}
-
-/* disabled non-blocking sockets */
-#cmakedefine HAVE_DISABLED_NONBLOCKING ${HAVE_DISABLED_NONBLOCKING}
-
-/* Define to 1 if you have the <dlfcn.h> header file. */
-#cmakedefine HAVE_DLFCN_H ${HAVE_DLFCN_H}
-
-/* Define to 1 if you have the `dlopen' function. */
-#cmakedefine HAVE_DLOPEN ${HAVE_DLOPEN}
-
-/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
-#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES ${HAVE_ENGINE_LOAD_BUILTIN_ENGINES}
-
-/* Define to 1 if you have the <errno.h> header file. */
-#cmakedefine HAVE_ERRNO_H ${HAVE_ERRNO_H}
-
-/* Define to 1 if you have the <err.h> header file. */
-#cmakedefine HAVE_ERR_H ${HAVE_ERR_H}
-
-/* Define to 1 if you have the <fcntl.h> header file. */
-#cmakedefine HAVE_FCNTL_H ${HAVE_FCNTL_H}
-
-/* use FIONBIO for non-blocking sockets */
-#cmakedefine HAVE_FIONBIO ${HAVE_FIONBIO}
-
-/* Define to 1 if you have the `fork' function. */
-#cmakedefine HAVE_FORK ${HAVE_FORK}
-
-/* Define to 1 if you have the `ftruncate' function. */
-#cmakedefine HAVE_FTRUNCATE ${HAVE_FTRUNCATE}
-
-/* Define if getaddrinfo exists and works */
-#cmakedefine HAVE_GETADDRINFO ${HAVE_GETADDRINFO}
-
-/* Define to 1 if you have the `geteuid' function. */
-#cmakedefine HAVE_GETEUID ${HAVE_GETEUID}
-
-/* Define to 1 if you have the `gethostbyaddr' function. */
-#cmakedefine HAVE_GETHOSTBYADDR ${HAVE_GETHOSTBYADDR}
-
-/* If you have gethostbyname */
-#cmakedefine HAVE_GETHOSTBYNAME ${HAVE_GETHOSTBYNAME}
-
-/* Define to 1 if you have the `gethostbyname_r' function. */
-#cmakedefine HAVE_GETHOSTBYNAME_R ${HAVE_GETHOSTBYNAME_R}
-
-/* gethostbyname_r() takes 3 args */
-#cmakedefine HAVE_GETHOSTBYNAME_R_3 ${HAVE_GETHOSTBYNAME_R_3}
-
-/* gethostbyname_r() takes 5 args */
-#cmakedefine HAVE_GETHOSTBYNAME_R_5 ${HAVE_GETHOSTBYNAME_R_5}
-
-/* gethostbyname_r() takes 6 args */
-#cmakedefine HAVE_GETHOSTBYNAME_R_6 ${HAVE_GETHOSTBYNAME_R_6}
-
-/* Define to 1 if you have the getnameinfo function. */
-#cmakedefine HAVE_GETNAMEINFO ${HAVE_GETNAMEINFO}
-
-/* Define to 1 if you have the `getpass_r' function. */
-#cmakedefine HAVE_GETPASS_R ${HAVE_GETPASS_R}
-
-/* Define to 1 if you have the `getprotobyname' function. */
-#cmakedefine HAVE_GETPROTOBYNAME ${HAVE_GETPROTOBYNAME}
-
-/* Define to 1 if you have the `getpwuid' function. */
-#cmakedefine HAVE_GETPWUID ${HAVE_GETPWUID}
-
-/* Define to 1 if you have the `getrlimit' function. */
-#cmakedefine HAVE_GETRLIMIT ${HAVE_GETRLIMIT}
-
-/* Define to 1 if you have the `gettimeofday' function. */
-#cmakedefine HAVE_GETTIMEOFDAY ${HAVE_GETTIMEOFDAY}
-
-/* Define to 1 if you have the `gmtime_r' function. */
-#cmakedefine HAVE_GMTIME_R ${HAVE_GMTIME_R}
-
-/* if you have the gssapi libraries */
-#cmakedefine HAVE_GSSAPI ${HAVE_GSSAPI}
-
-/* if you have the GNU gssapi libraries */
-#cmakedefine HAVE_GSSGNU ${HAVE_GSSGNU}
-
-/* if you have the Heimdal gssapi libraries */
-#cmakedefine HAVE_GSSHEIMDAL ${HAVE_GSSHEIMDAL}
-
-/* if you have the MIT gssapi libraries */
-#cmakedefine HAVE_GSSMIT ${HAVE_GSSMIT}
-
-/* Define to 1 if you have the `idna_strerror' function. */
-#cmakedefine HAVE_IDNA_STRERROR ${HAVE_IDNA_STRERROR}
-
-/* Define to 1 if you have the `idn_free' function. */
-#cmakedefine HAVE_IDN_FREE ${HAVE_IDN_FREE}
-
-/* Define to 1 if you have the <idn-free.h> header file. */
-#cmakedefine HAVE_IDN_FREE_H ${HAVE_IDN_FREE_H}
-
-/* Define to 1 if you have the `inet_addr' function. */
-#cmakedefine HAVE_INET_ADDR ${HAVE_INET_ADDR}
-
-/* Define to 1 if you have the `inet_ntoa' function. */
-#cmakedefine HAVE_INET_NTOA ${HAVE_INET_NTOA}
-
-/* Define to 1 if you have the `inet_ntoa_r' function. */
-#cmakedefine HAVE_INET_NTOA_R ${HAVE_INET_NTOA_R}
-
-/* inet_ntoa_r() is declared */
-#cmakedefine HAVE_INET_NTOA_R_DECL ${HAVE_INET_NTOA_R_DECL}
-
-/* Define to 1 if you have the `inet_pton' function. */
-#cmakedefine HAVE_INET_PTON ${HAVE_INET_PTON}
-
-/* Define to 1 if you have the <inttypes.h> header file. */
-#cmakedefine HAVE_INTTYPES_H ${HAVE_INTTYPES_H}
-
-/* use ioctlsocket() for non-blocking sockets */
-#cmakedefine HAVE_IOCTLSOCKET ${HAVE_IOCTLSOCKET}
-
-/* use Ioctlsocket() for non-blocking sockets */
-#cmakedefine HAVE_IOCTLSOCKET_CASE ${HAVE_IOCTLSOCKET_CASE}
-
-/* Define to 1 if you have the <io.h> header file. */
-#cmakedefine HAVE_IO_H ${HAVE_IO_H}
-
-/* if you have the Kerberos4 libraries (including -ldes) */
-#cmakedefine HAVE_KRB4 ${HAVE_KRB4}
-
-/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
-#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM ${HAVE_KRB_GET_OUR_IP_FOR_REALM}
-
-/* Define to 1 if you have the <krb.h> header file. */
-#cmakedefine HAVE_KRB_H ${HAVE_KRB_H}
-
-/* Define to 1 if you have the `dl' library (-ldl). */
-#cmakedefine HAVE_LIBDL ${HAVE_LIBDL}
-
-/* Define to 1 if you have the <libgen.h> header file. */
-#cmakedefine HAVE_LIBGEN_H ${HAVE_LIBGEN_H}
-
-/* Define to 1 if you have the `idn' library (-lidn). */
-#cmakedefine HAVE_LIBIDN ${HAVE_LIBIDN}
-
-/* Define to 1 if you have the `resolv' library (-lresolv). */
-#cmakedefine HAVE_LIBRESOLV ${HAVE_LIBRESOLV}
-
-/* Define to 1 if you have the `resolve' library (-lresolve). */
-#cmakedefine HAVE_LIBRESOLVE ${HAVE_LIBRESOLVE}
-
-/* Define to 1 if you have the `socket' library (-lsocket). */
-#cmakedefine HAVE_LIBSOCKET ${HAVE_LIBSOCKET}
-
-/* Define to 1 if you have the `ssh2' library (-lssh2). */
-#cmakedefine HAVE_LIBSSH2 ${HAVE_LIBSSH2}
-
-/* Define to 1 if you have the <libssh2.h> header file. */
-#cmakedefine HAVE_LIBSSH2_H ${HAVE_LIBSSH2_H}
-
-/* if zlib is available */
-#cmakedefine HAVE_LIBZ ${HAVE_LIBZ}
-
-/* Define to 1 if you have the <limits.h> header file. */
-#cmakedefine HAVE_LIMITS_H ${HAVE_LIMITS_H}
-
-/* if your compiler supports LL */
-#cmakedefine HAVE_LL ${HAVE_LL}
-
-/* Define to 1 if you have the <locale.h> header file. */
-#cmakedefine HAVE_LOCALE_H ${HAVE_LOCALE_H}
-
-/* Define to 1 if you have the `localtime_r' function. */
-#cmakedefine HAVE_LOCALTIME_R ${HAVE_LOCALTIME_R}
-
-/* if your compiler supports long long */
-#cmakedefine HAVE_LONGLONG ${HAVE_LONGLONG}
-
-/* Define to 1 if you have the malloc.h header file. */
-#cmakedefine HAVE_MALLOC_H ${HAVE_MALLOC_H}
-
-/* Define to 1 if you have the <memory.h> header file. */
-#cmakedefine HAVE_MEMORY_H ${HAVE_MEMORY_H}
-
-/* Define to 1 if you have the MSG_NOSIGNAL flag. */
-#cmakedefine HAVE_MSG_NOSIGNAL ${HAVE_MSG_NOSIGNAL}
-
-/* Define to 1 if you have the <netdb.h> header file. */
-#cmakedefine HAVE_NETDB_H ${HAVE_NETDB_H}
-
-/* Define to 1 if you have the <netinet/in.h> header file. */
-#cmakedefine HAVE_NETINET_IN_H ${HAVE_NETINET_IN_H}
-
-/* Define to 1 if you have the <netinet/tcp.h> header file. */
-#cmakedefine HAVE_NETINET_TCP_H ${HAVE_NETINET_TCP_H}
-
-/* Define to 1 if you have the <net/if.h> header file. */
-#cmakedefine HAVE_NET_IF_H ${HAVE_NET_IF_H}
-
-/* Define to 1 if NI_WITHSCOPEID exists and works. */
-#cmakedefine HAVE_NI_WITHSCOPEID ${HAVE_NI_WITHSCOPEID}
-
-/* Defined if no inet_pton() prototype available */
-#cmakedefine HAVE_NO_INET_PTON_PROTO ${HAVE_NO_INET_PTON_PROTO}
-
-/* we have no strerror_r() proto */
-#cmakedefine HAVE_NO_STRERROR_R_DECL ${HAVE_NO_STRERROR_R_DECL}
-
-/* Define to 1 if you have the <openssl/crypto.h> header file. */
-#cmakedefine HAVE_OPENSSL_CRYPTO_H ${HAVE_OPENSSL_CRYPTO_H}
-
-/* Define to 1 if you have the <openssl/engine.h> header file. */
-#cmakedefine HAVE_OPENSSL_ENGINE_H ${HAVE_OPENSSL_ENGINE_H}
-
-/* Define to 1 if you have the <openssl/err.h> header file. */
-#cmakedefine HAVE_OPENSSL_ERR_H ${HAVE_OPENSSL_ERR_H}
-
-/* Define to 1 if you have the <openssl/pem.h> header file. */
-#cmakedefine HAVE_OPENSSL_PEM_H ${HAVE_OPENSSL_PEM_H}
-
-/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
-#cmakedefine HAVE_OPENSSL_PKCS12_H ${HAVE_OPENSSL_PKCS12_H}
-
-/* Define to 1 if you have the <openssl/rsa.h> header file. */
-#cmakedefine HAVE_OPENSSL_RSA_H ${HAVE_OPENSSL_RSA_H}
-
-/* Define to 1 if you have the <openssl/ssl.h> header file. */
-#cmakedefine HAVE_OPENSSL_SSL_H ${HAVE_OPENSSL_SSL_H}
-
-/* Define to 1 if you have the <openssl/x509.h> header file. */
-#cmakedefine HAVE_OPENSSL_X509_H ${HAVE_OPENSSL_X509_H}
-
-/* use O_NONBLOCK for non-blocking sockets */
-#cmakedefine HAVE_O_NONBLOCK ${HAVE_O_NONBLOCK}
-
-/* Define to 1 if you have the <pem.h> header file. */
-#cmakedefine HAVE_PEM_H ${HAVE_PEM_H}
-
-/* Define to 1 if you have the `perror' function. */
-#cmakedefine HAVE_PERROR ${HAVE_PERROR}
-
-/* Define to 1 if you have the `pipe' function. */
-#cmakedefine HAVE_PIPE ${HAVE_PIPE}
-
-/* Define to 1 if you have the `poll' function. */
-#cmakedefine HAVE_POLL ${HAVE_POLL}
-
-/* Define to 1 if you have the <process.h> header file. */
-#cmakedefine HAVE_PROCESS_H ${HAVE_PROCESS_H}
-
-/* Define to 1 if you have the <pwd.h> header file. */
-#cmakedefine HAVE_PWD_H ${HAVE_PWD_H}
-
-/* Define to 1 if you have the `RAND_egd' function. */
-#cmakedefine HAVE_RAND_EGD ${HAVE_RAND_EGD}
-
-/* Define to 1 if you have the `RAND_screen' function. */
-#cmakedefine HAVE_RAND_SCREEN ${HAVE_RAND_SCREEN}
-
-/* Define to 1 if you have the `RAND_status' function. */
-#cmakedefine HAVE_RAND_STATUS ${HAVE_RAND_STATUS}
-
-/* Define to 1 if you have the recv function. */
-#cmakedefine HAVE_RECV ${HAVE_RECV}
-
-/* Define to 1 if you have the <rsa.h> header file. */
-#cmakedefine HAVE_RSA_H ${HAVE_RSA_H}
-
-/* Define to 1 if you have the select function. */
-#cmakedefine HAVE_SELECT ${HAVE_SELECT}
-
-/* Define to 1 if you have the send function. */
-#cmakedefine HAVE_SEND ${HAVE_SEND}
-
-/* Define to 1 if you have the <setjmp.h> header file. */
-#cmakedefine HAVE_SETJMP_H ${HAVE_SETJMP_H}
-
-/* Define to 1 if you have the `setlocale' function. */
-#cmakedefine HAVE_SETLOCALE ${HAVE_SETLOCALE}
-
-/* Define to 1 if you have the `setrlimit' function. */
-#cmakedefine HAVE_SETRLIMIT ${HAVE_SETRLIMIT}
-
-/* Define to 1 if you have the <sgtty.h> header file. */
-#cmakedefine HAVE_SGTTY_H ${HAVE_SGTTY_H}
-
-/* Define to 1 if you have the `sigaction' function. */
-#cmakedefine HAVE_SIGACTION ${HAVE_SIGACTION}
-
-/* Define to 1 if you have the `siginterrupt' function. */
-#cmakedefine HAVE_SIGINTERRUPT ${HAVE_SIGINTERRUPT}
-
-/* Define to 1 if you have the `signal' function. */
-#cmakedefine HAVE_SIGNAL ${HAVE_SIGNAL}
-
-/* Define to 1 if you have the <signal.h> header file. */
-#cmakedefine HAVE_SIGNAL_H ${HAVE_SIGNAL_H}
-
-/* If you have sigsetjmp */
-#cmakedefine HAVE_SIGSETJMP ${HAVE_SIGSETJMP}
-
-/* Define to 1 if sig_atomic_t is an available typedef. */
-#cmakedefine HAVE_SIG_ATOMIC_T ${HAVE_SIG_ATOMIC_T}
-
-/* Define to 1 if sig_atomic_t is already defined as volatile. */
-#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE ${HAVE_SIG_ATOMIC_T_VOLATILE}
-
-/* Define to 1 if you have the `socket' function. */
-#cmakedefine HAVE_SOCKET ${HAVE_SOCKET}
-
-/* use SO_NONBLOCK for non-blocking sockets */
-#cmakedefine HAVE_SO_NONBLOCK ${HAVE_SO_NONBLOCK}
-
-/* Define this if you have the SPNEGO library fbopenssl */
-#cmakedefine HAVE_SPNEGO ${HAVE_SPNEGO}
-
-/* Define to 1 if you have the <ssl.h> header file. */
-#cmakedefine HAVE_SSL_H ${HAVE_SSL_H}
-
-/* Define to 1 if you have the <stdint.h> header file. */
-#cmakedefine HAVE_STDINT_H ${HAVE_STDINT_H}
-
-/* Define to 1 if you have the <stdio.h> header file. */
-#cmakedefine HAVE_STDIO_H ${HAVE_STDIO_H}
-
-/* Define to 1 if you have the <stdlib.h> header file. */
-#cmakedefine HAVE_STDLIB_H ${HAVE_STDLIB_H}
-
-/* Define to 1 if you have the `strcasecmp' function. */
-#cmakedefine HAVE_STRCASECMP ${HAVE_STRCASECMP}
-
-/* Define to 1 if you have the `strcmpi' function. */
-#cmakedefine HAVE_STRCMPI ${HAVE_STRCMPI}
-
-/* Define to 1 if you have the `strdup' function. */
-#cmakedefine HAVE_STRDUP ${HAVE_STRDUP}
-
-/* Define to 1 if you have the `stricmp' function. */
-#cmakedefine HAVE_STRICMP ${HAVE_STRICMP}
-
-/* Define to 1 if you have the <strings.h> header file. */
-#cmakedefine HAVE_STRINGS_H ${HAVE_STRINGS_H}
-
-/* Define to 1 if you have the <string.h> header file. */
-#cmakedefine HAVE_STRING_H ${HAVE_STRING_H}
-
-/* Define to 1 if you have the `strlcpy' function. */
-#cmakedefine HAVE_STRLCPY ${HAVE_STRLCPY}
-
-/* Define to 1 if you have the `strstr' function. */
-#cmakedefine HAVE_STRSTR ${HAVE_STRSTR}
-
-/* Define to 1 if you have the `strtok_r' function. */
-#cmakedefine HAVE_STRTOK_R ${HAVE_STRTOK_R}
-
-/* Define to 1 if you have the `strtoll' function. */
-#cmakedefine HAVE_STRTOLL ${HAVE_STRTOLL}
-
-/* if struct sockaddr_storage is defined */
-#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE ${HAVE_STRUCT_SOCKADDR_STORAGE}
-
-/* Define to 1 if you have the timeval struct. */
-#cmakedefine HAVE_STRUCT_TIMEVAL ${HAVE_STRUCT_TIMEVAL}
-
-/* Define to 1 if you have the <sys/filio.h> header file. */
-#cmakedefine HAVE_SYS_FILIO_H ${HAVE_SYS_FILIO_H}
-
-/* Define to 1 if you have the <sys/ioctl.h> header file. */
-#cmakedefine HAVE_SYS_IOCTL_H ${HAVE_SYS_IOCTL_H}
-
-/* Define to 1 if you have the <sys/param.h> header file. */
-#cmakedefine HAVE_SYS_PARAM_H ${HAVE_SYS_PARAM_H}
-
-/* Define to 1 if you have the <sys/poll.h> header file. */
-#cmakedefine HAVE_SYS_POLL_H ${HAVE_SYS_POLL_H}
-
-/* Define to 1 if you have the <sys/resource.h> header file. */
-#cmakedefine HAVE_SYS_RESOURCE_H ${HAVE_SYS_RESOURCE_H}
-
-/* Define to 1 if you have the <sys/select.h> header file. */
-#cmakedefine HAVE_SYS_SELECT_H ${HAVE_SYS_SELECT_H}
-
-/* Define to 1 if you have the <sys/socket.h> header file. */
-#cmakedefine HAVE_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H}
-
-/* Define to 1 if you have the <sys/sockio.h> header file. */
-#cmakedefine HAVE_SYS_SOCKIO_H ${HAVE_SYS_SOCKIO_H}
-
-/* Define to 1 if you have the <sys/stat.h> header file. */
-#cmakedefine HAVE_SYS_STAT_H ${HAVE_SYS_STAT_H}
-
-/* Define to 1 if you have the <sys/time.h> header file. */
-#cmakedefine HAVE_SYS_TIME_H ${HAVE_SYS_TIME_H}
-
-/* Define to 1 if you have the <sys/types.h> header file. */
-#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
-
-/* Define to 1 if you have the <sys/utime.h> header file. */
-#cmakedefine HAVE_SYS_UTIME_H ${HAVE_SYS_UTIME_H}
-
-/* Define to 1 if you have the <termios.h> header file. */
-#cmakedefine HAVE_TERMIOS_H ${HAVE_TERMIOS_H}
-
-/* Define to 1 if you have the <termio.h> header file. */
-#cmakedefine HAVE_TERMIO_H ${HAVE_TERMIO_H}
-
-/* Define to 1 if you have the <time.h> header file. */
-#cmakedefine HAVE_TIME_H ${HAVE_TIME_H}
-
-/* Define to 1 if you have the <tld.h> header file. */
-#cmakedefine HAVE_TLD_H ${HAVE_TLD_H}
-
-/* Define to 1 if you have the `tld_strerror' function. */
-#cmakedefine HAVE_TLD_STRERROR ${HAVE_TLD_STRERROR}
-
-/* Define to 1 if you have the `uname' function. */
-#cmakedefine HAVE_UNAME ${HAVE_UNAME}
-
-/* Define to 1 if you have the <unistd.h> header file. */
-#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
-
-/* Define to 1 if you have the `utime' function. */
-#cmakedefine HAVE_UTIME ${HAVE_UTIME}
-
-/* Define to 1 if you have the <utime.h> header file. */
-#cmakedefine HAVE_UTIME_H ${HAVE_UTIME_H}
-
-/* Define to 1 if you have the windows.h header file. */
-#cmakedefine HAVE_WINDOWS_H ${HAVE_WINDOWS_H}
-
-/* Define to 1 if you have the winsock2.h header file. */
-#cmakedefine HAVE_WINSOCK2_H ${HAVE_WINSOCK2_H}
-
-/* Define to 1 if you have the winsock.h header file. */
-#cmakedefine HAVE_WINSOCK_H ${HAVE_WINSOCK_H}
-
-/* Define this symbol if your OS supports changing the contents of argv */
-#cmakedefine HAVE_WRITABLE_ARGV ${HAVE_WRITABLE_ARGV}
-
-/* Define to 1 if you have the ws2tcpip.h header file. */
-#cmakedefine HAVE_WS2TCPIP_H ${HAVE_WS2TCPIP_H}
-
-/* Define to 1 if you have the <x509.h> header file. */
-#cmakedefine HAVE_X509_H ${HAVE_X509_H}
-
-/* if you have the zlib.h header file */
-#cmakedefine HAVE_ZLIB_H ${HAVE_ZLIB_H}
-
-/* If you lack a fine basename() prototype */
-#cmakedefine NEED_BASENAME_PROTO ${NEED_BASENAME_PROTO}
-
-/* Define to 1 if you need the malloc.h header file even with stdlib.h */
-#cmakedefine NEED_MALLOC_H ${NEED_MALLOC_H}
-
-/* need REENTRANT defined */
-#cmakedefine NEED_REENTRANT ${NEED_REENTRANT}
-
-/* cpu-machine-OS */
-#define OS "${OPERATING_SYSTEM}"
-
-/* Name of package */
-#cmakedefine PACKAGE "${PACKAGE}"
-
-/* Define to the address where bug reports for this package should be sent. */
-#cmakedefine PACKAGE_BUGREPORT "${PACKAGE_BUGREPORT}"
-
-/* Define to the full name of this package. */
-#cmakedefine PACKAGE_NAME "${PACKAGE_NAME}"
-
-/* Define to the full name and version of this package. */
-#cmakedefine PACKAGE_STRING "${PACKAGE_STRING}"
-
-/* Define to the one symbol short name of this package. */
-#cmakedefine PACKAGE_TARNAME "${PACKAGE_TARNAME}"
-
-/* Define to the version of this package. */
-#cmakedefine PACKAGE_VERSION "${PACKAGE_VERSION}"
-
-/* a suitable file to read random data from */
-#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
-
-/* Define to the type of arg 1 for recv. */
-#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}
-
-/* Define to the type of arg 2 for recv. */
-#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}
-
-/* Define to the type of arg 3 for recv. */
-#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}
-
-/* Define to the type of arg 4 for recv. */
-#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}
-
-/* Define to the function return type for recv. */
-#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
-
-/* Define as the return type of signal handlers (`int' or `void'). */
-#cmakedefine RETSIGTYPE ${RETSIGTYPE}
-
-/* Define to the type of arg 1 for `select'. */
-#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1}
-
-/* Define to the type of args 2, 3 and 4 for `select'. */
-#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234}
-
-/* Define to the type of arg 5 for `select'. */
-#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
-
-/* Define to the type qualifier of arg 2 for send. */
-#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}
-
-/* Define to the type of arg 1 for send. */
-#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}
-
-/* Define to the type of arg 2 for send. */
-#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}
-
-/* Define to the type of arg 3 for send. */
-#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}
-
-/* Define to the type of arg 4 for send. */
-#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}
-
-/* Define to the function return type for send. */
-#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV}
-
-/* The size of `curl_off_t', as computed by sizeof. */
-@SIZEOF_CURL_OFF_T_CODE@
-
-/* The size of `long', as computed by sizeof. */
-@SIZEOF_LONG_CODE@
-
-/* The size of `long long', as computed by sizeof. */
-@SIZEOF_LONG_LONG_CODE@
-
-/* The size of `__int64', as computed by sizeof. */
-@SIZEOF___INT64_CODE@
-
-/* The size of `size_t', as computed by sizeof. */
-@SIZEOF_SIZE_T_CODE@
-
-/* The size of `ssize_t', as computed by sizeof. */
-@SIZEOF_SSIZE_T_CODE@
-
-/* The size of `time_t', as computed by sizeof. */
-@SIZEOF_TIME_T_CODE@
-
-/* Define to 1 if you have the ANSI C header files. */
-#cmakedefine STDC_HEADERS ${STDC_HEADERS}
-
-/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
-#cmakedefine TIME_WITH_SYS_TIME ${TIME_WITH_SYS_TIME}
-
-/* Define if you want to enable ares support */
-#cmakedefine USE_ARES ${USE_ARES}
-
-/* if GnuTLS is enabled */
-#cmakedefine USE_GNUTLS ${USE_GNUTLS}
-
-/* if libSSH2 is in use */
-#cmakedefine USE_LIBSSH2 ${USE_LIBSSH2}
-
-/* If you want to build curl with the built-in manual */
-#cmakedefine USE_MANUAL ${USE_MANUAL}
-
-/* if OpenSSL is in use */
-#cmakedefine USE_OPENSSL ${USE_OPENSSL}
-
-/* if SSL is enabled */
-#cmakedefine USE_SSLEAY ${USE_SSLEAY}
-
-/* to enable SSPI support */
-#cmakedefine USE_WINDOWS_SSPI ${USE_WINDOWS_SSPI}
-
-/* Version number of package */
-#cmakedefine VERSION "${VERSION}"
-
-/* Define to avoid automatic inclusion of winsock.h */
-#cmakedefine WIN32_LEAN_AND_MEAN ${WIN32_LEAN_AND_MEAN}
-
-/* Define to 1 if on AIX 3.
- System headers sometimes define this.
- We just want to avoid a redefinition error message. */
-#ifndef _ALL_SOURCE
-#cmakedefine _ALL_SOURCE ${_ALL_SOURCE}
-#endif
-
-/* Number of bits in a file offset, on hosts where this is settable. */
-#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
-
-/* Define for large files, on AIX-style hosts. */
-#cmakedefine _LARGE_FILES ${_LARGE_FILES}
-
-/* define this if you need it to compile thread-safe code */
-#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
-
-/* Define to empty if `const' does not conform to ANSI C. */
-#cmakedefine const ${const}
-
-/* type to use in place of in_addr_t if not defined */
-#cmakedefine in_addr_t ${in_addr_t}
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-#cmakedefine size_t ${size_t}
-
-/* type to use in place of socklen_t if not defined */
-#cmakedefine socklen_t ${socklen_t}
-
-/* the signed version of size_t */
-#ifndef SIZEOF_SSIZE_T
-# if SIZEOF_LONG == SIZEOF_SIZE_T
- typedef long ssize_t;
-# elif SIZEOF_LONG_LONG == SIZEOF_SIZE_T
- typedef long long ssize_t;
-# elif SIZEOF___INT64 == SIZEOF_SIZE_T
- typedef __int64 ssize_t;
-# else
- typedef int ssize_t;
-# endif
-#endif
-
-/* Special handling of zlib library */
-#cmakedefine CURL_SPECIAL_ZLIB_H "${CURL_SPECIAL_ZLIB_H}"
diff --git a/Utilities/cmcurl/connect.c b/Utilities/cmcurl/connect.c
deleted file mode 100644
index 2b3897204..000000000
--- a/Utilities/cmcurl/connect.c
+++ /dev/null
@@ -1,905 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef WIN32
-/* headers for non-win32 */
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h> /* <netinet/tcp.h> may need it */
-#endif
-#ifdef HAVE_NETINET_TCP_H
-#include <netinet/tcp.h> /* for TCP_NODELAY */
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototype, without it, this crashes
- on macos 68K */
-#endif
-#if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
-#include <sys/filio.h>
-#endif
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#endif
-
-#endif
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#ifdef USE_WINSOCK
-#define EINPROGRESS WSAEINPROGRESS
-#define EWOULDBLOCK WSAEWOULDBLOCK
-#define EISCONN WSAEISCONN
-#define ENOTSOCK WSAENOTSOCK
-#define ECONNREFUSED WSAECONNREFUSED
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "if2ip.h"
-#include "strerror.h"
-#include "connect.h"
-#include "memory.h"
-#include "select.h"
-#include "url.h" /* for Curl_safefree() */
-#include "multiif.h"
-#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "inet_ntop.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-static bool verifyconnect(curl_socket_t sockfd, int *error);
-
-static curl_socket_t
-singleipconnect(struct connectdata *conn,
- const Curl_addrinfo *ai, /* start connecting to this */
- long timeout_ms,
- bool *connected);
-
-/*
- * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this
- * platform to hide platform specific for the function that calls this.
- */
-int Curl_sockerrno(void)
-{
-#ifdef USE_WINSOCK
- return (int)WSAGetLastError();
-#else
- return errno;
-#endif
-}
-
-/*
- * Curl_nonblock() set the given socket to either blocking or non-blocking
- * mode based on the 'nonblock' boolean argument. This function is highly
- * portable.
- */
-int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
- int nonblock /* TRUE or FALSE */)
-{
-#undef SETBLOCK
-#define SETBLOCK 0
-#ifdef HAVE_O_NONBLOCK
- /* most recent unix versions */
- int flags;
-
- flags = fcntl(sockfd, F_GETFL, 0);
- if (TRUE == nonblock)
- return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
- else
- return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
-#undef SETBLOCK
-#define SETBLOCK 1
-#endif
-
-#if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
- /* older unix versions */
- int flags;
-
- flags = nonblock;
- return ioctl(sockfd, FIONBIO, &flags);
-#undef SETBLOCK
-#define SETBLOCK 2
-#endif
-
-#if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
- /* Windows? */
- unsigned long flags;
- flags = nonblock;
-
- return ioctlsocket(sockfd, FIONBIO, &flags);
-#undef SETBLOCK
-#define SETBLOCK 3
-#endif
-
-#if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
- /* presumably for Amiga */
- return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
-#undef SETBLOCK
-#define SETBLOCK 4
-#endif
-
-#if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
- /* BeOS */
- long b = nonblock ? 1 : 0;
- return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
-#undef SETBLOCK
-#define SETBLOCK 5
-#endif
-
-#ifdef HAVE_DISABLED_NONBLOCKING
- return 0; /* returns success */
-#undef SETBLOCK
-#define SETBLOCK 6
-#endif
-
-#if (SETBLOCK == 0)
-#error "no non-blocking method was found/used/set"
-#endif
-}
-
-/*
- * waitconnect() waits for a TCP connect on the given socket for the specified
- * number if milliseconds. It returns:
- * 0 fine connect
- * -1 select() error
- * 1 select() timeout
- * 2 select() returned with an error condition fd_set
- */
-
-#define WAITCONN_CONNECTED 0
-#define WAITCONN_SELECT_ERROR -1
-#define WAITCONN_TIMEOUT 1
-#define WAITCONN_FDSET_ERROR 2
-
-static
-int waitconnect(curl_socket_t sockfd, /* socket */
- long timeout_msec)
-{
- int rc;
-#ifdef mpeix
- /* Call this function once now, and ignore the results. We do this to
- "clear" the error state on the socket so that we can later read it
- reliably. This is reported necessary on the MPE/iX operating system. */
- (void)verifyconnect(sockfd, NULL);
-#endif
-
- /* now select() until we get connect or timeout */
- rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
- if(-1 == rc)
- /* error, no connect here, try next */
- return WAITCONN_SELECT_ERROR;
-
- else if(0 == rc)
- /* timeout, no connect today */
- return WAITCONN_TIMEOUT;
-
- if(rc & CSELECT_ERR)
- /* error condition caught */
- return WAITCONN_FDSET_ERROR;
-
- /* we have a connect! */
- return WAITCONN_CONNECTED;
-}
-
-static CURLcode bindlocal(struct connectdata *conn,
- curl_socket_t sockfd)
-{
- struct SessionHandle *data = conn->data;
- struct sockaddr_in me;
- struct sockaddr *sock = NULL; /* bind to this address */
- socklen_t socksize; /* size of the data sock points to */
- unsigned short port = data->set.localport; /* use this port number, 0 for
- "random" */
- /* how many port numbers to try to bind to, increasing one at a time */
- int portnum = data->set.localportrange;
-
- /*************************************************************
- * Select device to bind socket to
- *************************************************************/
- if (data->set.device && (strlen(data->set.device)<255) ) {
- struct Curl_dns_entry *h=NULL;
- char myhost[256] = "";
- in_addr_t in;
- int rc;
- bool was_iface = FALSE;
-
- /* First check if the given name is an IP address */
- in=inet_addr(data->set.device);
-
- if((in == CURL_INADDR_NONE) &&
- Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
- /*
- * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
- */
- rc = Curl_resolv(conn, myhost, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- (void)Curl_wait_for_resolv(conn, &h);
-
- if(h) {
- was_iface = TRUE;
- Curl_resolv_unlock(data, h);
- }
- }
-
- if(!was_iface) {
- /*
- * This was not an interface, resolve the name as a host name
- * or IP number
- */
- rc = Curl_resolv(conn, data->set.device, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- (void)Curl_wait_for_resolv(conn, &h);
-
- if(h) {
- if(in == CURL_INADDR_NONE)
- /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
- Curl_inet_ntop(h->addr->ai_addr->sa_family,
- &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
- myhost, sizeof myhost);
- else
- /* we know data->set.device is shorter than the myhost array */
- strcpy(myhost, data->set.device);
- Curl_resolv_unlock(data, h);
- }
- }
-
- if(! *myhost) {
- /* need to fix this
- h=Curl_gethost(data,
- getmyhost(*myhost,sizeof(myhost)),
- hostent_buf,
- sizeof(hostent_buf));
- */
- failf(data, "Couldn't bind to '%s'", data->set.device);
- return CURLE_HTTP_PORT_FAILED;
- }
-
- infof(data, "Bind local address to %s\n", myhost);
-
-#ifdef SO_BINDTODEVICE
- /* I am not sure any other OSs than Linux that provide this feature, and
- * at the least I cannot test. --Ben
- *
- * This feature allows one to tightly bind the local socket to a
- * particular interface. This will force even requests to other local
- * interfaces to go out the external interface.
- *
- */
- if (was_iface) {
- /* Only bind to the interface when specified as interface, not just as a
- * hostname or ip address.
- */
- if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
- data->set.device, strlen(data->set.device)+1) != 0) {
- /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
- sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */
- infof(data, "SO_BINDTODEVICE %s failed\n",
- data->set.device);
- /* This is typically "errno 1, error: Operation not permitted" if
- you're not running as root or another suitable privileged user */
- }
- }
-#endif
-
- in=inet_addr(myhost);
- if (CURL_INADDR_NONE == in) {
- failf(data,"couldn't find my own IP address (%s)", myhost);
- return CURLE_HTTP_PORT_FAILED;
- } /* end of inet_addr */
-
- if ( h ) {
- Curl_addrinfo *addr = h->addr;
- sock = addr->ai_addr;
- socksize = addr->ai_addrlen;
- }
- else
- return CURLE_HTTP_PORT_FAILED;
-
- }
- else if(port) {
- /* if a local port number is requested but no local IP, extract the
- address from the socket */
- memset(&me, 0, sizeof(struct sockaddr));
- me.sin_family = AF_INET;
- me.sin_addr.s_addr = INADDR_ANY;
-
- sock = (struct sockaddr *)&me;
- socksize = sizeof(struct sockaddr);
-
- }
- else
- /* no local kind of binding was requested */
- return CURLE_OK;
-
- do {
-
- /* Set port number to bind to, 0 makes the system pick one */
- if(sock->sa_family == AF_INET)
- ((struct sockaddr_in *)sock)->sin_port = htons(port);
-#ifdef ENABLE_IPV6
- else
- ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
-#endif
-
- if( bind(sockfd, sock, socksize) >= 0) {
- /* we succeeded to bind */
- struct Curl_sockaddr_storage add;
- socklen_t size;
-
- size = sizeof(add);
- if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
- failf(data, "getsockname() failed");
- return CURLE_HTTP_PORT_FAILED;
- }
- /* We re-use/clobber the port variable here below */
- if(((struct sockaddr *)&add)->sa_family == AF_INET)
- port = ntohs(((struct sockaddr_in *)&add)->sin_port);
-#ifdef ENABLE_IPV6
- else
- port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
-#endif
- infof(data, "Local port: %d\n", port);
- return CURLE_OK;
- }
- if(--portnum > 0) {
- infof(data, "Bind to local port %d failed, trying next\n", port);
- port++; /* try next port */
- }
- else
- break;
- } while(1);
-
- data->state.os_errno = Curl_sockerrno();
- failf(data, "bind failure: %s",
- Curl_strerror(conn, data->state.os_errno));
- return CURLE_HTTP_PORT_FAILED;
-
-}
-
-/*
- * verifyconnect() returns TRUE if the connect really has happened.
- */
-static bool verifyconnect(curl_socket_t sockfd, int *error)
-{
- bool rc = TRUE;
-#ifdef SO_ERROR
- int err = 0;
- socklen_t errSize = sizeof(err);
-
-#ifdef WIN32
- /*
- * In October 2003 we effectively nullified this function on Windows due to
- * problems with it using all CPU in multi-threaded cases.
- *
- * In May 2004, we bring it back to offer more info back on connect failures.
- * Gisle Vanem could reproduce the former problems with this function, but
- * could avoid them by adding this SleepEx() call below:
- *
- * "I don't have Rational Quantify, but the hint from his post was
- * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
- * just Sleep(0) would be enough?) would release whatever
- * mutex/critical-section the ntdll call is waiting on.
- *
- * Someone got to verify this on Win-NT 4.0, 2000."
- */
-
-#ifdef _WIN32_WCE
- Sleep(0);
-#else
- SleepEx(0, FALSE);
-#endif
-
-#endif
-
- if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
- (void *)&err, &errSize))
- err = Curl_sockerrno();
-
-#ifdef _WIN32_WCE
- /* Always returns this error, bug in CE? */
- if(WSAENOPROTOOPT==err)
- err=0;
-#endif
-
- if ((0 == err) || (EISCONN == err))
- /* we are connected, awesome! */
- rc = TRUE;
- else
- /* This wasn't a successful connect */
- rc = FALSE;
- if (error)
- *error = err;
-#else
- (void)sockfd;
- if (error)
- *error = Curl_sockerrno();
-#endif
- return rc;
-}
-
-CURLcode Curl_store_ip_addr(struct connectdata *conn)
-{
- char addrbuf[256];
- Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
-
- /* save the string */
- Curl_safefree(conn->ip_addr_str);
- conn->ip_addr_str = strdup(addrbuf);
- if(!conn->ip_addr_str)
- return CURLE_OUT_OF_MEMORY; /* FAIL */
-
-#ifdef PF_INET6
- if(conn->ip_addr->ai_family == PF_INET6)
- conn->bits.ipv6 = TRUE;
-#endif
-
- return CURLE_OK;
-}
-
-/* Used within the multi interface. Try next IP address, return TRUE if no
- more address exists */
-static bool trynextip(struct connectdata *conn,
- int sockindex,
- bool *connected)
-{
- curl_socket_t sockfd;
- Curl_addrinfo *ai;
-
- /* first close the failed socket */
- sclose(conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
- *connected = FALSE;
-
- if(sockindex != FIRSTSOCKET)
- return TRUE; /* no next */
-
- /* try the next address */
- ai = conn->ip_addr->ai_next;
-
- while (ai) {
- sockfd = singleipconnect(conn, ai, 0L, connected);
- if(sockfd != CURL_SOCKET_BAD) {
- /* store the new socket descriptor */
- conn->sock[sockindex] = sockfd;
- conn->ip_addr = ai;
-
- Curl_store_ip_addr(conn);
- return FALSE;
- }
- ai = ai->ai_next;
- }
- return TRUE;
-}
-
-/*
- * Curl_is_connected() is used from the multi interface to check if the
- * firstsocket has connected.
- */
-
-CURLcode Curl_is_connected(struct connectdata *conn,
- int sockindex,
- bool *connected)
-{
- int rc;
- struct SessionHandle *data = conn->data;
- CURLcode code = CURLE_OK;
- curl_socket_t sockfd = conn->sock[sockindex];
- long allow = DEFAULT_CONNECT_TIMEOUT;
- long allow_total = 0;
- long has_passed;
-
- curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
-
- *connected = FALSE; /* a very negative world view is best */
-
- /* Evaluate in milliseconds how much time that has passed */
- has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
- /* subtract the most strict timeout of the ones */
- if(data->set.timeout && data->set.connecttimeout) {
- if (data->set.timeout < data->set.connecttimeout)
- allow_total = allow = data->set.timeout*1000;
- else
- allow = data->set.connecttimeout*1000;
- }
- else if(data->set.timeout) {
- allow_total = allow = data->set.timeout*1000;
- }
- else if(data->set.connecttimeout) {
- allow = data->set.connecttimeout*1000;
- }
-
- if(has_passed > allow ) {
- /* time-out, bail out, go home */
- failf(data, "Connection time-out after %ld ms", has_passed);
- return CURLE_OPERATION_TIMEOUTED;
- }
- if(conn->bits.tcpconnect) {
- /* we are connected already! */
- Curl_expire(data, allow_total);
- *connected = TRUE;
- return CURLE_OK;
- }
-
- Curl_expire(data, allow);
-
- /* check for connect without timeout as we want to return immediately */
- rc = waitconnect(sockfd, 0);
-
- if(WAITCONN_CONNECTED == rc) {
- int error;
- if (verifyconnect(sockfd, &error)) {
- /* we are connected, awesome! */
- *connected = TRUE;
- return CURLE_OK;
- }
- /* nope, not connected for real */
- data->state.os_errno = error;
- infof(data, "Connection failed\n");
- if(trynextip(conn, sockindex, connected)) {
- code = CURLE_COULDNT_CONNECT;
- }
- }
- else if(WAITCONN_TIMEOUT != rc) {
- int error = 0;
-
- /* nope, not connected */
- if (WAITCONN_FDSET_ERROR == rc) {
- (void)verifyconnect(sockfd, &error);
- data->state.os_errno = error;
- infof(data, "%s\n",Curl_strerror(conn,error));
- }
- else
- infof(data, "Connection failed\n");
-
- if(trynextip(conn, sockindex, connected)) {
- error = Curl_sockerrno();
- data->state.os_errno = error;
- failf(data, "Failed connect to %s:%d; %s",
- conn->host.name, conn->port, Curl_strerror(conn,error));
- code = CURLE_COULDNT_CONNECT;
- }
- }
- /*
- * If the connection failed here, we should attempt to connect to the "next
- * address" for the given host.
- */
-
- return code;
-}
-
-static void tcpnodelay(struct connectdata *conn,
- curl_socket_t sockfd)
-{
-#ifdef TCP_NODELAY
- struct SessionHandle *data= conn->data;
- socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
- int proto = IPPROTO_TCP;
-
-#ifdef HAVE_GETPROTOBYNAME
- struct protoent *pe = getprotobyname("tcp");
- if (pe)
- proto = pe->p_proto;
-#endif
-
- if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
- sizeof(onoff)) < 0)
- infof(data, "Could not set TCP_NODELAY: %s\n",
- Curl_strerror(conn, Curl_sockerrno()));
- else
- infof(data,"TCP_NODELAY set\n");
-#else
- (void)conn;
- (void)sockfd;
-#endif
-}
-
-#ifdef SO_NOSIGPIPE
-/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
- sending data to a dead peer (instead of relying on the 4th argument to send
- being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
- systems? */
-static void nosigpipe(struct connectdata *conn,
- curl_socket_t sockfd)
-{
- struct SessionHandle *data= conn->data;
- int onoff = 1;
- if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
- sizeof(onoff)) < 0)
- infof(data, "Could not set SO_NOSIGPIPE: %s\n",
- Curl_strerror(conn, Curl_sockerrno()));
-}
-#else
-#define nosigpipe(x,y)
-#endif
-
-/* singleipconnect() connects to the given IP only, and it may return without
- having connected if used from the multi interface. */
-static curl_socket_t
-singleipconnect(struct connectdata *conn,
- const Curl_addrinfo *ai,
- long timeout_ms,
- bool *connected)
-{
- char addr_buf[128];
- int rc;
- int error;
- bool isconnected;
- struct SessionHandle *data = conn->data;
- curl_socket_t sockfd;
- CURLcode res;
-
- sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
- if (sockfd == CURL_SOCKET_BAD)
- return CURL_SOCKET_BAD;
-
- *connected = FALSE; /* default is not connected */
-
- Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
- infof(data, " Trying %s... ", addr_buf);
-
- if(data->set.tcp_nodelay)
- tcpnodelay(conn, sockfd);
-
- nosigpipe(conn, sockfd);
-
- if(data->set.fsockopt) {
- /* activate callback for setting socket options */
- error = data->set.fsockopt(data->set.sockopt_client,
- sockfd,
- CURLSOCKTYPE_IPCXN);
- if (error) {
- sclose(sockfd); /* close the socket and bail out */
- return CURL_SOCKET_BAD;
- }
- }
-
- /* possibly bind the local end to an IP, interface or port */
- res = bindlocal(conn, sockfd);
- if(res) {
- sclose(sockfd); /* close socket and bail out */
- return CURL_SOCKET_BAD;
- }
-
- /* set socket non-blocking */
- Curl_nonblock(sockfd, TRUE);
-
- /* Connect TCP sockets, bind UDP */
- if(conn->socktype == SOCK_STREAM)
- rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
- else
- rc = 0;
-
- if(-1 == rc) {
- error = Curl_sockerrno();
-
- switch (error) {
- case EINPROGRESS:
- case EWOULDBLOCK:
-#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
- /* On some platforms EAGAIN and EWOULDBLOCK are the
- * same value, and on others they are different, hence
- * the odd #if
- */
- case EAGAIN:
-#endif
- rc = waitconnect(sockfd, timeout_ms);
- break;
- default:
- /* unknown error, fallthrough and try another address! */
- failf(data, "Failed to connect to %s: %s",
- addr_buf, Curl_strerror(conn,error));
- data->state.os_errno = error;
- break;
- }
- }
-
- /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
- connect(). We can be sure of this since connect() cannot return 1. */
- if((WAITCONN_TIMEOUT == rc) &&
- (data->state.used_interface == Curl_if_multi)) {
- /* Timeout when running the multi interface */
- return sockfd;
- }
-
- isconnected = verifyconnect(sockfd, &error);
-
- if(!rc && isconnected) {
- /* we are connected, awesome! */
- *connected = TRUE; /* this is a true connect */
- infof(data, "connected\n");
- return sockfd;
- }
- else if(WAITCONN_TIMEOUT == rc)
- infof(data, "Timeout\n");
- else {
- data->state.os_errno = error;
- infof(data, "%s\n", Curl_strerror(conn, error));
- }
-
- /* connect failed or timed out */
- sclose(sockfd);
-
- return CURL_SOCKET_BAD;
-}
-
-/*
- * TCP connect to the given host with timeout, proxy or remote doesn't matter.
- * There might be more than one IP address to try out. Fill in the passed
- * pointer with the connected socket.
- */
-
-CURLcode Curl_connecthost(struct connectdata *conn, /* context */
- const struct Curl_dns_entry *remotehost, /* use this one */
- curl_socket_t *sockconn, /* the connected socket */
- Curl_addrinfo **addr, /* the one we used */
- bool *connected) /* really connected? */
-{
- struct SessionHandle *data = conn->data;
- curl_socket_t sockfd = CURL_SOCKET_BAD;
- int aliasindex;
- int num_addr;
- Curl_addrinfo *ai;
- Curl_addrinfo *curr_addr;
-
- struct timeval after;
- struct timeval before = Curl_tvnow();
-
- /*************************************************************
- * Figure out what maximum time we have left
- *************************************************************/
- long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
- long timeout_per_addr;
-
- *connected = FALSE; /* default to not connected */
-
- if(data->set.timeout || data->set.connecttimeout) {
- long has_passed;
-
- /* Evaluate in milliseconds how much time that has passed */
- has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
- /* get the most strict timeout of the ones converted to milliseconds */
- if(data->set.timeout && data->set.connecttimeout) {
- if (data->set.timeout < data->set.connecttimeout)
- timeout_ms = data->set.timeout*1000;
- else
- timeout_ms = data->set.connecttimeout*1000;
- }
- else if(data->set.timeout)
- timeout_ms = data->set.timeout*1000;
- else
- timeout_ms = data->set.connecttimeout*1000;
-
- /* subtract the passed time */
- timeout_ms -= has_passed;
-
- if(timeout_ms < 0) {
- /* a precaution, no need to continue if time already is up */
- failf(data, "Connection time-out");
- return CURLE_OPERATION_TIMEOUTED;
- }
- }
- Curl_expire(data, timeout_ms);
-
- /* Max time for each address */
- num_addr = Curl_num_addresses(remotehost->addr);
- timeout_per_addr = timeout_ms / num_addr;
-
- ai = remotehost->addr;
-
- /* Below is the loop that attempts to connect to all IP-addresses we
- * know for the given host. One by one until one IP succeeds.
- */
-
- if(data->state.used_interface == Curl_if_multi)
- /* don't hang when doing multi */
- timeout_per_addr = 0;
-
- /*
- * Connecting with a Curl_addrinfo chain
- */
- for (curr_addr = ai, aliasindex=0; curr_addr;
- curr_addr = curr_addr->ai_next, aliasindex++) {
-
- /* start connecting to the IP curr_addr points to */
- sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
-
- if(sockfd != CURL_SOCKET_BAD)
- break;
-
- /* get a new timeout for next attempt */
- after = Curl_tvnow();
- timeout_ms -= Curl_tvdiff(after, before);
- if(timeout_ms < 0) {
- failf(data, "connect() timed out!");
- return CURLE_OPERATION_TIMEOUTED;
- }
- before = after;
- } /* end of connect-to-each-address loop */
-
- if (sockfd == CURL_SOCKET_BAD) {
- /* no good connect was made */
- *sockconn = CURL_SOCKET_BAD;
- failf(data, "couldn't connect to host");
- return CURLE_COULDNT_CONNECT;
- }
-
- /* leave the socket in non-blocking mode */
-
- /* store the address we use */
- if(addr)
- *addr = curr_addr;
-
- /* allow NULL-pointers to get passed in */
- if(sockconn)
- *sockconn = sockfd; /* the socket descriptor we've connected */
-
- data->info.numconnects++; /* to track the number of connections made */
-
- return CURLE_OK;
-}
diff --git a/Utilities/cmcurl/connect.h b/Utilities/cmcurl/connect.h
deleted file mode 100644
index 599572b27..000000000
--- a/Utilities/cmcurl/connect.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __CONNECT_H
-#define __CONNECT_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
- int nonblock /* TRUE or FALSE */);
-
-CURLcode Curl_is_connected(struct connectdata *conn,
- int sockindex,
- bool *connected);
-
-CURLcode Curl_connecthost(struct connectdata *conn,
- const struct Curl_dns_entry *host, /* connect to this */
- curl_socket_t *sockconn, /* not set if error */
- Curl_addrinfo **addr, /* the one we used */
- bool *connected /* truly connected? */
- );
-
-int Curl_sockerrno(void);
-
-CURLcode Curl_store_ip_addr(struct connectdata *conn);
-
-#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
-
-#endif
diff --git a/Utilities/cmcurl/content_encoding.c b/Utilities/cmcurl/content_encoding.c
deleted file mode 100644
index 97f834177..000000000
--- a/Utilities/cmcurl/content_encoding.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifdef HAVE_LIBZ
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "sendf.h"
-#include "content_encoding.h"
-#include "memory.h"
-
-#include "memdebug.h"
-
-/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
- (doing so will reduce code size slightly). */
-#define OLD_ZLIB_SUPPORT 1
-
-#define DSIZ 0x10000 /* buffer size for decompressed data */
-
-#define GZIP_MAGIC_0 0x1f
-#define GZIP_MAGIC_1 0x8b
-
-/* gzip flag byte */
-#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
-#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
-#define COMMENT 0x10 /* bit 4 set: file comment present */
-#define RESERVED 0xE0 /* bits 5..7: reserved */
-
-enum zlibState {
- ZLIB_UNINIT, /* uninitialized */
- ZLIB_INIT, /* initialized */
- ZLIB_GZIP_HEADER, /* reading gzip header */
- ZLIB_GZIP_INFLATING, /* inflating gzip stream */
- ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
-};
-
-static CURLcode
-process_zlib_error(struct connectdata *conn, z_stream *z)
-{
- struct SessionHandle *data = conn->data;
- if (z->msg)
- failf (data, "Error while processing content unencoding: %s",
- z->msg);
- else
- failf (data, "Error while processing content unencoding: "
- "Unknown failure within decompression software.");
-
- return CURLE_BAD_CONTENT_ENCODING;
-}
-
-static CURLcode
-exit_zlib(z_stream *z, bool *zlib_init, CURLcode result)
-{
- inflateEnd(z);
- *zlib_init = ZLIB_UNINIT;
- return result;
-}
-
-static CURLcode
-inflate_stream(struct connectdata *conn,
- struct Curl_transfer_keeper *k)
-{
- int allow_restart = 1;
- z_stream *z = &k->z; /* zlib state structure */
- uInt nread = z->avail_in;
- Bytef *orig_in = z->next_in;
- int status; /* zlib status */
- CURLcode result = CURLE_OK; /* Curl_client_write status */
- char *decomp; /* Put the decompressed data here. */
-
- /* Dynamically allocate a buffer for decompression because it's uncommonly
- large to hold on the stack */
- decomp = (char*)malloc(DSIZ);
- if (decomp == NULL) {
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
- }
-
- /* because the buffer size is fixed, iteratively decompress and transfer to
- the client via client_write. */
- for (;;) {
- /* (re)set buffer for decompressed output for every iteration */
- z->next_out = (Bytef *)decomp;
- z->avail_out = DSIZ;
-
- status = inflate(z, Z_SYNC_FLUSH);
- if (status == Z_OK || status == Z_STREAM_END) {
- allow_restart = 0;
- if(DSIZ - z->avail_out) {
- result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
- DSIZ - z->avail_out);
- /* if !CURLE_OK, clean up, return */
- if (result) {
- free(decomp);
- return exit_zlib(z, &k->zlib_init, result);
- }
- }
-
- /* Done? clean up, return */
- if (status == Z_STREAM_END) {
- free(decomp);
- if (inflateEnd(z) == Z_OK)
- return exit_zlib(z, &k->zlib_init, result);
- else
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
- }
-
- /* Done with these bytes, exit */
- if (status == Z_OK && z->avail_in == 0) {
- free(decomp);
- return result;
- }
- }
- else if (allow_restart && status == Z_DATA_ERROR) {
- /* some servers seem to not generate zlib headers, so this is an attempt
- to fix and continue anyway */
-
- inflateReset(z);
- if (inflateInit2(z, -MAX_WBITS) != Z_OK) {
- return process_zlib_error(conn, z);
- }
- z->next_in = orig_in;
- z->avail_in = nread;
- allow_restart = 0;
- continue;
- }
- else { /* Error; exit loop, handle below */
- free(decomp);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
- }
- }
- /* Will never get here */
-}
-
-CURLcode
-Curl_unencode_deflate_write(struct connectdata *conn,
- struct Curl_transfer_keeper *k,
- ssize_t nread)
-{
- z_stream *z = &k->z; /* zlib state structure */
-
- /* Initialize zlib? */
- if (k->zlib_init == ZLIB_UNINIT) {
- z->zalloc = (alloc_func)Z_NULL;
- z->zfree = (free_func)Z_NULL;
- z->opaque = 0;
- z->next_in = NULL;
- z->avail_in = 0;
- if (inflateInit(z) != Z_OK)
- return process_zlib_error(conn, z);
- k->zlib_init = ZLIB_INIT;
- }
-
- /* Set the compressed input when this function is called */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
-
- /* Now uncompress the data */
- return inflate_stream(conn, k);
-}
-
-#ifdef OLD_ZLIB_SUPPORT
-/* Skip over the gzip header */
-static enum {
- GZIP_OK,
- GZIP_BAD,
- GZIP_UNDERFLOW
-} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
-{
- int method, flags;
- const ssize_t totallen = len;
-
- /* The shortest header is 10 bytes */
- if (len < 10)
- return GZIP_UNDERFLOW;
-
- if ((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
- return GZIP_BAD;
-
- method = data[2];
- flags = data[3];
-
- if (method != Z_DEFLATED || (flags & RESERVED) != 0) {
- /* Can't handle this compression method or unknown flag */
- return GZIP_BAD;
- }
-
- /* Skip over time, xflags, OS code and all previous bytes */
- len -= 10;
- data += 10;
-
- if (flags & EXTRA_FIELD) {
- ssize_t extra_len;
-
- if (len < 2)
- return GZIP_UNDERFLOW;
-
- extra_len = (data[1] << 8) | data[0];
-
- if (len < (extra_len+2))
- return GZIP_UNDERFLOW;
-
- len -= (extra_len + 2);
- data += (extra_len + 2);
- }
-
- if (flags & ORIG_NAME) {
- /* Skip over NUL-terminated file name */
- while (len && *data) {
- --len;
- ++data;
- }
- if (!len || *data)
- return GZIP_UNDERFLOW;
-
- /* Skip over the NUL */
- --len;
- ++data;
- }
-
- if (flags & COMMENT) {
- /* Skip over NUL-terminated comment */
- while (len && *data) {
- --len;
- ++data;
- }
- if (!len || *data)
- return GZIP_UNDERFLOW;
-
- /* Skip over the NUL */
- --len;
- ++data;
- }
-
- if (flags & HEAD_CRC) {
- if (len < 2)
- return GZIP_UNDERFLOW;
-
- len -= 2;
- data += 2;
- }
-
- *headerlen = totallen - len;
- return GZIP_OK;
-}
-#endif
-
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
- struct Curl_transfer_keeper *k,
- ssize_t nread)
-{
- z_stream *z = &k->z; /* zlib state structure */
-
- /* Initialize zlib? */
- if (k->zlib_init == ZLIB_UNINIT) {
- z->zalloc = (alloc_func)Z_NULL;
- z->zfree = (free_func)Z_NULL;
- z->opaque = 0;
- z->next_in = NULL;
- z->avail_in = 0;
-
- if (strcmp(zlibVersion(), "1.2.0.4") >= 0) {
- /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
- if (inflateInit2(z, MAX_WBITS+32) != Z_OK) {
- return process_zlib_error(conn, z);
- }
- k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
-
- } else {
- /* we must parse the gzip header ourselves */
- if (inflateInit2(z, -MAX_WBITS) != Z_OK) {
- return process_zlib_error(conn, z);
- }
- k->zlib_init = ZLIB_INIT; /* Initial call state */
- }
- }
-
- if (k->zlib_init == ZLIB_INIT_GZIP) {
- /* Let zlib handle the gzip decompression entirely */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
- /* Now uncompress the data */
- return inflate_stream(conn, k);
- }
-
-#ifndef OLD_ZLIB_SUPPORT
- /* Support for old zlib versions is compiled away and we are running with
- an old version, so return an error. */
- return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);
-
-#else
- /* This next mess is to get around the potential case where there isn't
- * enough data passed in to skip over the gzip header. If that happens, we
- * malloc a block and copy what we have then wait for the next call. If
- * there still isn't enough (this is definitely a worst-case scenario), we
- * make the block bigger, copy the next part in and keep waiting.
- *
- * This is only required with zlib versions < 1.2.0.4 as newer versions
- * can handle the gzip header themselves.
- */
-
- switch (k->zlib_init) {
- /* Skip over gzip header? */
- case ZLIB_INIT:
- {
- /* Initial call state */
- ssize_t hlen;
-
- switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
- case GZIP_OK:
- z->next_in = (Bytef *)k->str + hlen;
- z->avail_in = (uInt)(nread - hlen);
- k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
- break;
-
- case GZIP_UNDERFLOW:
- /* We need more data so we can find the end of the gzip header. It's
- * possible that the memory block we malloc here will never be freed if
- * the transfer abruptly aborts after this point. Since it's unlikely
- * that circumstances will be right for this code path to be followed in
- * the first place, and it's even more unlikely for a transfer to fail
- * immediately afterwards, it should seldom be a problem.
- */
- z->avail_in = (uInt)nread;
- z->next_in = malloc(z->avail_in);
- if (z->next_in == NULL) {
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
- }
- memcpy(z->next_in, k->str, z->avail_in);
- k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
- /* We don't have any data to inflate yet */
- return CURLE_OK;
-
- case GZIP_BAD:
- default:
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
- }
-
- }
- break;
-
- case ZLIB_GZIP_HEADER:
- {
- /* Need more gzip header data state */
- ssize_t hlen;
- unsigned char *oldblock = z->next_in;
-
- z->avail_in += nread;
- z->next_in = realloc(z->next_in, z->avail_in);
- if (z->next_in == NULL) {
- free(oldblock);
- return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
- }
- /* Append the new block of data to the previous one */
- memcpy(z->next_in + z->avail_in - nread, k->str, nread);
-
- switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
- case GZIP_OK:
- /* This is the zlib stream data */
- free(z->next_in);
- /* Don't point into the malloced block since we just freed it */
- z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
- z->avail_in = (uInt)(z->avail_in - hlen);
- k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
- break;
-
- case GZIP_UNDERFLOW:
- /* We still don't have any data to inflate! */
- return CURLE_OK;
-
- case GZIP_BAD:
- default:
- free(z->next_in);
- return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
- }
-
- }
- break;
-
- case ZLIB_GZIP_INFLATING:
- default:
- /* Inflating stream state */
- z->next_in = (Bytef *)k->str;
- z->avail_in = (uInt)nread;
- break;
- }
-
- if (z->avail_in == 0) {
- /* We don't have any data to inflate; wait until next time */
- return CURLE_OK;
- }
-
- /* We've parsed the header, now uncompress the data */
- return inflate_stream(conn, k);
-#endif
-}
-#endif /* HAVE_LIBZ */
diff --git a/Utilities/cmcurl/content_encoding.h b/Utilities/cmcurl/content_encoding.h
deleted file mode 100644
index b31669be4..000000000
--- a/Utilities/cmcurl/content_encoding.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-/*
- * Comma-separated list all supported Content-Encodings ('identity' is implied)
- */
-#ifdef HAVE_LIBZ
-#define ALL_CONTENT_ENCODINGS "deflate, gzip"
-#else
-#define ALL_CONTENT_ENCODINGS "identity"
-#endif
-
-CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
- struct Curl_transfer_keeper *k,
- ssize_t nread);
-
-CURLcode
-Curl_unencode_gzip_write(struct connectdata *conn,
- struct Curl_transfer_keeper *k,
- ssize_t nread);
diff --git a/Utilities/cmcurl/cookie.c b/Utilities/cmcurl/cookie.c
deleted file mode 100644
index d8ea24196..000000000
--- a/Utilities/cmcurl/cookie.c
+++ /dev/null
@@ -1,1019 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/***
-
-
-RECEIVING COOKIE INFORMATION
-============================
-
-struct CookieInfo *cookie_init(char *file);
-
- Inits a cookie struct to store data in a local file. This is always
- called before any cookies are set.
-
-int cookies_set(struct CookieInfo *cookie, char *cookie_line);
-
- The 'cookie_line' parameter is a full "Set-cookie:" line as
- received from a server.
-
- The function need to replace previously stored lines that this new
- line superceeds.
-
- It may remove lines that are expired.
-
- It should return an indication of success/error.
-
-
-SENDING COOKIE INFORMATION
-==========================
-
-struct Cookies *cookie_getlist(struct CookieInfo *cookie,
- char *host, char *path, bool secure);
-
- For a given host and path, return a linked list of cookies that
- the client should send to the server if used now. The secure
- boolean informs the cookie if a secure connection is achieved or
- not.
-
- It shall only return cookies that haven't expired.
-
-
-Example set of cookies:
-
- Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
- Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
- domain=.fidelity.com; path=/ftgw; secure
- Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
- domain=.fidelity.com; path=/; secure
- Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
- domain=.fidelity.com; path=/; secure
- Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
- domain=.fidelity.com; path=/; secure
- Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
- domain=.fidelity.com; path=/; secure
- Set-cookie:
- Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
- 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
-****/
-
-
-#include "setup.h"
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
-
-#include <stdlib.h>
-#include <string.h>
-
-#define _MPRINTF_REPLACE /* without this on windows OS we get undefined reference to snprintf */
-#include <curl/mprintf.h>
-
-#include "urldata.h"
-#include "cookie.h"
-#include "strequal.h"
-#include "strtok.h"
-#include "sendf.h"
-#include "memory.h"
-#include "share.h"
-#include "strtoofft.h"
-
-/* The last #include file should be: */
-#ifdef CURLDEBUG
-#include "memdebug.h"
-#endif
-
-#define my_isspace(x) ((x == ' ') || (x == '\t'))
-
-static void freecookie(struct Cookie *co)
-{
- if(co->expirestr)
- free(co->expirestr);
- if(co->domain)
- free(co->domain);
- if(co->path)
- free(co->path);
- if(co->name)
- free(co->name);
- if(co->value)
- free(co->value);
- if(co->maxage)
- free(co->maxage);
- if(co->version)
- free(co->version);
-
- free(co);
-}
-
-static bool tailmatch(const char *little, const char *bigone)
-{
- size_t littlelen = strlen(little);
- size_t biglen = strlen(bigone);
-
- if(littlelen > biglen)
- return FALSE;
-
- return (bool)strequal(little, bigone+biglen-littlelen);
-}
-
-/*
- * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
- */
-void Curl_cookie_loadfiles(struct SessionHandle *data)
-{
- struct curl_slist *list = data->change.cookielist;
- if(list) {
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- while(list) {
- data->cookies = Curl_cookie_init(data,
- list->data,
- data->cookies,
- data->set.cookiesession);
- list = list->next;
- }
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- curl_slist_free_all(data->change.cookielist); /* clean up list */
- data->change.cookielist = NULL; /* don't do this again! */
- }
-}
-
-/****************************************************************************
- *
- * Curl_cookie_add()
- *
- * Add a single cookie line to the cookie keeping object.
- *
- ***************************************************************************/
-
-struct Cookie *
-Curl_cookie_add(struct SessionHandle *data,
- /* The 'data' pointer here may be NULL at times, and thus
- must only be used very carefully for things that can deal
- with data being NULL. Such as infof() and similar */
-
- struct CookieInfo *c,
- bool httpheader, /* TRUE if HTTP header-style line */
- char *lineptr, /* first character of the line */
- char *domain, /* default domain */
- char *path) /* full path used when this cookie is set,
- used to get default path for the cookie
- unless set */
-{
- struct Cookie *clist;
- char *what;
- char name[MAX_NAME];
- char *ptr;
- char *semiptr;
- struct Cookie *co;
- struct Cookie *lastc=NULL;
- time_t now = time(NULL);
- bool replace_old = FALSE;
- bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
-
- /* First, alloc and init a new struct for it */
- co = (struct Cookie *)calloc(sizeof(struct Cookie), 1);
- if(!co)
- return NULL; /* bail out if we're this low on memory */
-
- if(httpheader) {
- /* This line was read off a HTTP-header */
- char *sep;
-
- what = malloc(MAX_COOKIE_LINE);
- if(!what) {
- free(co);
- return NULL;
- }
-
- semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
-
- while(*lineptr && my_isspace(*lineptr))
- lineptr++;
-
- ptr = lineptr;
- do {
- /* we have a <what>=<this> pair or a 'secure' word here */
- sep = strchr(ptr, '=');
- if(sep && (!semiptr || (semiptr>sep)) ) {
- /*
- * There is a = sign and if there was a semicolon too, which make sure
- * that the semicolon comes _after_ the equal sign.
- */
-
- name[0]=what[0]=0; /* init the buffers */
- if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
- MAX_COOKIE_LINE_TXT "[^;\r\n]",
- name, what)) {
- /* this is a <name>=<what> pair */
-
- char *whatptr;
-
- /* Strip off trailing whitespace from the 'what' */
- size_t len=strlen(what);
- while(len && my_isspace(what[len-1])) {
- what[len-1]=0;
- len--;
- }
-
- /* Skip leading whitespace from the 'what' */
- whatptr=what;
- while(my_isspace(*whatptr)) {
- whatptr++;
- }
-
- if(strequal("path", name)) {
- co->path=strdup(whatptr);
- if(!co->path) {
- badcookie = TRUE; /* out of memory bad */
- break;
- }
- }
- else if(strequal("domain", name)) {
- /* note that this name may or may not have a preceeding dot, but
- we don't care about that, we treat the names the same anyway */
-
- const char *domptr=whatptr;
- int dotcount=1;
-
- /* Count the dots, we need to make sure that there are enough
- of them. */
-
- if('.' == whatptr[0])
- /* don't count the initial dot, assume it */
- domptr++;
-
- do {
- domptr = strchr(domptr, '.');
- if(domptr) {
- domptr++;
- dotcount++;
- }
- } while(domptr);
-
- /* The original Netscape cookie spec defined that this domain name
- MUST have three dots (or two if one of the seven holy TLDs),
- but it seems that these kinds of cookies are in use "out there"
- so we cannot be that strict. I've therefore lowered the check
- to not allow less than two dots. */
-
- if(dotcount < 2) {
- /* Received and skipped a cookie with a domain using too few
- dots. */
- badcookie=TRUE; /* mark this as a bad cookie */
- infof(data, "skipped cookie with illegal dotcount domain: %s\n",
- whatptr);
- }
- else {
- /* Now, we make sure that our host is within the given domain,
- or the given domain is not valid and thus cannot be set. */
-
- if('.' == whatptr[0])
- whatptr++; /* ignore preceeding dot */
-
- if(!domain || tailmatch(whatptr, domain)) {
- const char *tailptr=whatptr;
- if(tailptr[0] == '.')
- tailptr++;
- co->domain=strdup(tailptr); /* don't prefix w/dots
- internally */
- if(!co->domain) {
- badcookie = TRUE;
- break;
- }
- co->tailmatch=TRUE; /* we always do that if the domain name was
- given */
- }
- else {
- /* we did not get a tailmatch and then the attempted set domain
- is not a domain to which the current host belongs. Mark as
- bad. */
- badcookie=TRUE;
- infof(data, "skipped cookie with bad tailmatch domain: %s\n",
- whatptr);
- }
- }
- }
- else if(strequal("version", name)) {
- co->version=strdup(whatptr);
- if(!co->version) {
- badcookie = TRUE;
- break;
- }
- }
- else if(strequal("max-age", name)) {
- /* Defined in RFC2109:
-
- Optional. The Max-Age attribute defines the lifetime of the
- cookie, in seconds. The delta-seconds value is a decimal non-
- negative integer. After delta-seconds seconds elapse, the
- client should discard the cookie. A value of zero means the
- cookie should be discarded immediately.
-
- */
- co->maxage = strdup(whatptr);
- if(!co->maxage) {
- badcookie = TRUE;
- break;
- }
- co->expires =
- atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + (long)now;
- }
- else if(strequal("expires", name)) {
- co->expirestr=strdup(whatptr);
- if(!co->expirestr) {
- badcookie = TRUE;
- break;
- }
- co->expires = curl_getdate(what, &now);
- }
- else if(!co->name) {
- co->name = strdup(name);
- co->value = strdup(whatptr);
- if(!co->name || !co->value) {
- badcookie = TRUE;
- break;
- }
- }
- /*
- else this is the second (or more) name we don't know
- about! */
- }
- else {
- /* this is an "illegal" <what>=<this> pair */
- }
- }
- else {
- if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
- what)) {
- if(strequal("secure", what))
- co->secure = TRUE;
- /* else,
- unsupported keyword without assign! */
-
- }
- }
- if(!semiptr || !*semiptr) {
- /* we already know there are no more cookies */
- semiptr = NULL;
- continue;
- }
-
- ptr=semiptr+1;
- while(ptr && *ptr && my_isspace(*ptr))
- ptr++;
- semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
-
- if(!semiptr && *ptr)
- /* There are no more semicolons, but there's a final name=value pair
- coming up */
- semiptr=strchr(ptr, '\0');
- } while(semiptr);
-
- if(!badcookie && !co->domain) {
- if(domain) {
- /* no domain was given in the header line, set the default */
- co->domain=strdup(domain);
- if(!co->domain)
- badcookie = TRUE;
- }
- }
-
- if(!badcookie && !co->path && path) {
- /* no path was given in the header line, set the default */
- char *endslash = strrchr(path, '/');
- if(endslash) {
- size_t pathlen = endslash-path+1; /* include the ending slash */
- co->path=malloc(pathlen+1); /* one extra for the zero byte */
- if(co->path) {
- memcpy(co->path, path, pathlen);
- co->path[pathlen]=0; /* zero terminate */
- }
- else
- badcookie = TRUE;
- }
- }
-
- free(what);
-
- if(badcookie || !co->name) {
- /* we didn't get a cookie name or a bad one,
- this is an illegal line, bail out */
- freecookie(co);
- return NULL;
- }
-
- }
- else {
- /* This line is NOT a HTTP header style line, we do offer support for
- reading the odd netscape cookies-file format here */
- char *firstptr;
- char *tok_buf;
- int fields;
-
- if(lineptr[0]=='#') {
- /* don't even try the comments */
- free(co);
- return NULL;
- }
- /* strip off the possible end-of-line characters */
- ptr=strchr(lineptr, '\r');
- if(ptr)
- *ptr=0; /* clear it */
- ptr=strchr(lineptr, '\n');
- if(ptr)
- *ptr=0; /* clear it */
-
- firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
-
- /* Here's a quick check to eliminate normal HTTP-headers from this */
- if(!firstptr || strchr(firstptr, ':')) {
- free(co);
- return NULL;
- }
-
- /* Now loop through the fields and init the struct we already have
- allocated */
- for(ptr=firstptr, fields=0; ptr && !badcookie;
- ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
- switch(fields) {
- case 0:
- if(ptr[0]=='.') /* skip preceeding dots */
- ptr++;
- co->domain = strdup(ptr);
- if(!co->domain)
- badcookie = TRUE;
- break;
- case 1:
- /* This field got its explanation on the 23rd of May 2001 by
- Andrés García:
-
- flag: A TRUE/FALSE value indicating if all machines within a given
- domain can access the variable. This value is set automatically by
- the browser, depending on the value you set for the domain.
-
- As far as I can see, it is set to true when the cookie says
- .domain.com and to false when the domain is complete www.domain.com
- */
- co->tailmatch=(bool)strequal(ptr, "TRUE"); /* store information */
- break;
- case 2:
- /* It turns out, that sometimes the file format allows the path
- field to remain not filled in, we try to detect this and work
- around it! Andrés García made us aware of this... */
- if (strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
- /* only if the path doesn't look like a boolean option! */
- co->path = strdup(ptr);
- if(!co->path)
- badcookie = TRUE;
- break;
- }
- /* this doesn't look like a path, make one up! */
- co->path = strdup("/");
- if(!co->path)
- badcookie = TRUE;
- fields++; /* add a field and fall down to secure */
- /* FALLTHROUGH */
- case 3:
- co->secure = (bool)strequal(ptr, "TRUE");
- break;
- case 4:
- co->expires = curlx_strtoofft(ptr, NULL, 10);
- break;
- case 5:
- co->name = strdup(ptr);
- if(!co->name)
- badcookie = TRUE;
- break;
- case 6:
- co->value = strdup(ptr);
- if(!co->value)
- badcookie = TRUE;
- break;
- }
- }
- if(6 == fields) {
- /* we got a cookie with blank contents, fix it */
- co->value = strdup("");
- if(!co->value)
- badcookie = TRUE;
- else
- fields++;
- }
-
- if(!badcookie && (7 != fields))
- /* we did not find the sufficient number of fields */
- badcookie = TRUE;
-
- if(badcookie) {
- freecookie(co);
- return NULL;
- }
-
- }
-
- if(!c->running && /* read from a file */
- c->newsession && /* clean session cookies */
- !co->expires) { /* this is a session cookie since it doesn't expire! */
- freecookie(co);
- return NULL;
- }
-
- co->livecookie = c->running;
-
- /* now, we have parsed the incoming line, we must now check if this
- superceeds an already existing cookie, which it may if the previous have
- the same domain and path as this */
-
- clist = c->cookies;
- replace_old = FALSE;
- while(clist) {
- if(strequal(clist->name, co->name)) {
- /* the names are identical */
-
- if(clist->domain && co->domain) {
- if(strequal(clist->domain, co->domain))
- /* The domains are identical */
- replace_old=TRUE;
- }
- else if(!clist->domain && !co->domain)
- replace_old = TRUE;
-
- if(replace_old) {
- /* the domains were identical */
-
- if(clist->path && co->path) {
- if(strequal(clist->path, co->path)) {
- replace_old = TRUE;
- }
- else
- replace_old = FALSE;
- }
- else if(!clist->path && !co->path)
- replace_old = TRUE;
- else
- replace_old = FALSE;
-
- }
-
- if(replace_old && !co->livecookie && clist->livecookie) {
- /* Both cookies matched fine, except that the already present
- cookie is "live", which means it was set from a header, while
- the new one isn't "live" and thus only read from a file. We let
- live cookies stay alive */
-
- /* Free the newcomer and get out of here! */
- freecookie(co);
- return NULL;
- }
-
- if(replace_old) {
- co->next = clist->next; /* get the next-pointer first */
-
- /* then free all the old pointers */
- if(clist->name)
- free(clist->name);
- if(clist->value)
- free(clist->value);
- if(clist->domain)
- free(clist->domain);
- if(clist->path)
- free(clist->path);
- if(clist->expirestr)
- free(clist->expirestr);
-
- if(clist->version)
- free(clist->version);
- if(clist->maxage)
- free(clist->maxage);
-
- *clist = *co; /* then store all the new data */
-
- free(co); /* free the newly alloced memory */
- co = clist; /* point to the previous struct instead */
-
- /* We have replaced a cookie, now skip the rest of the list but
- make sure the 'lastc' pointer is properly set */
- do {
- lastc = clist;
- clist = clist->next;
- } while(clist);
- break;
- }
- }
- lastc = clist;
- clist = clist->next;
- }
-
- if(c->running)
- /* Only show this when NOT reading the cookies from a file */
- infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, expire %d\n",
- replace_old?"Replaced":"Added", co->name, co->value,
- co->domain, co->path, co->expires);
-
- if(!replace_old) {
- /* then make the last item point on this new one */
- if(lastc)
- lastc->next = co;
- else
- c->cookies = co;
- }
-
- c->numcookies++; /* one more cookie in the jar */
- return co;
-}
-
-/*****************************************************************************
- *
- * Curl_cookie_init()
- *
- * Inits a cookie struct to read data from a local file. This is always
- * called before any cookies are set. File may be NULL.
- *
- * If 'newsession' is TRUE, discard all "session cookies" on read from file.
- *
- ****************************************************************************/
-struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
- char *file,
- struct CookieInfo *inc,
- bool newsession)
-{
- struct CookieInfo *c;
- FILE *fp;
- bool fromfile=TRUE;
-
- if(NULL == inc) {
- /* we didn't get a struct, create one */
- c = (struct CookieInfo *)calloc(1, sizeof(struct CookieInfo));
- if(!c)
- return NULL; /* failed to get memory */
- c->filename = strdup(file?file:"none"); /* copy the name just in case */
- }
- else {
- /* we got an already existing one, use that */
- c = inc;
- }
- c->running = FALSE; /* this is not running, this is init */
-
- if(file && strequal(file, "-")) {
- fp = stdin;
- fromfile=FALSE;
- }
- else if(file && !*file) {
- /* points to a "" string */
- fp = NULL;
- }
- else
- fp = file?fopen(file, "r"):NULL;
-
- c->newsession = newsession; /* new session? */
-
- if(fp) {
- char *lineptr;
- bool headerline;
-
- char *line = (char *)malloc(MAX_COOKIE_LINE);
- if(line) {
- while(fgets(line, MAX_COOKIE_LINE, fp)) {
- if(checkprefix("Set-Cookie:", line)) {
- /* This is a cookie line, get it! */
- lineptr=&line[11];
- headerline=TRUE;
- }
- else {
- lineptr=line;
- headerline=FALSE;
- }
- while(*lineptr && my_isspace(*lineptr))
- lineptr++;
-
- Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
- }
- free(line); /* free the line buffer */
- }
- if(fromfile)
- fclose(fp);
- }
-
- c->running = TRUE; /* now, we're running */
-
- return c;
-}
-
-/*****************************************************************************
- *
- * Curl_cookie_getlist()
- *
- * For a given host and path, return a linked list of cookies that the
- * client should send to the server if used now. The secure boolean informs
- * the cookie if a secure connection is achieved or not.
- *
- * It shall only return cookies that haven't expired.
- *
- ****************************************************************************/
-
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
- char *host, char *path, bool secure)
-{
- struct Cookie *newco;
- struct Cookie *co;
- time_t now = time(NULL);
- struct Cookie *mainco=NULL;
-
- if(!c || !c->cookies)
- return NULL; /* no cookie struct or no cookies in the struct */
-
- co = c->cookies;
-
- while(co) {
- /* only process this cookie if it is not expired or had no expire
- date AND that if the cookie requires we're secure we must only
- continue if we are! */
- if( (co->expires<=0 || (co->expires> now)) &&
- (co->secure?secure:TRUE) ) {
-
- /* now check if the domain is correct */
- if(!co->domain ||
- (co->tailmatch && tailmatch(co->domain, host)) ||
- (!co->tailmatch && strequal(host, co->domain)) ) {
- /* the right part of the host matches the domain stuff in the
- cookie data */
-
- /* now check the left part of the path with the cookies path
- requirement */
- if(!co->path ||
- /* not using checkprefix() because matching should be
- case-sensitive */
- !strncmp(co->path, path, strlen(co->path)) ) {
-
- /* and now, we know this is a match and we should create an
- entry for the return-linked-list */
-
- newco = (struct Cookie *)malloc(sizeof(struct Cookie));
- if(newco) {
- /* first, copy the whole source cookie: */
- memcpy(newco, co, sizeof(struct Cookie));
-
- /* then modify our next */
- newco->next = mainco;
-
- /* point the main to us */
- mainco = newco;
- }
- else {
- /* failure, clear up the allocated chain and return NULL */
- while(mainco) {
- co = mainco->next;
- free(mainco);
- mainco = co;
- }
-
- return NULL;
- }
- }
- }
- }
- co = co->next;
- }
-
- return mainco; /* return the new list */
-}
-
-/*****************************************************************************
- *
- * Curl_cookie_clearall()
- *
- * Clear all existing cookies and reset the counter.
- *
- ****************************************************************************/
-void Curl_cookie_clearall(struct CookieInfo *cookies)
-{
- if(cookies) {
- Curl_cookie_freelist(cookies->cookies);
- cookies->cookies = NULL;
- cookies->numcookies = 0;
- }
-}
-
-/*****************************************************************************
- *
- * Curl_cookie_freelist()
- *
- * Free a list of cookies previously returned by Curl_cookie_getlist();
- *
- ****************************************************************************/
-
-void Curl_cookie_freelist(struct Cookie *co)
-{
- struct Cookie *next;
- if(co) {
- while(co) {
- next = co->next;
- free(co); /* we only free the struct since the "members" are all
- just copied! */
- co = next;
- }
- }
-}
-
-
-/*****************************************************************************
- *
- * Curl_cookie_clearsess()
- *
- * Free all session cookies in the cookies list.
- *
- ****************************************************************************/
-void Curl_cookie_clearsess(struct CookieInfo *cookies)
-{
- struct Cookie *first, *curr, *next, *prev = NULL;
-
- if(!cookies->cookies)
- return;
-
- first = curr = prev = cookies->cookies;
-
- for(; curr; curr = next) {
- next = curr->next;
- if(!curr->expires) {
- if(first == curr)
- first = next;
-
- if(prev == curr)
- prev = next;
- else
- prev->next = next;
-
- free(curr);
- cookies->numcookies--;
- }
- else
- prev = curr;
- }
-
- cookies->cookies = first;
-}
-
-
-/*****************************************************************************
- *
- * Curl_cookie_cleanup()
- *
- * Free a "cookie object" previous created with cookie_init().
- *
- ****************************************************************************/
-void Curl_cookie_cleanup(struct CookieInfo *c)
-{
- struct Cookie *co;
- struct Cookie *next;
- if(c) {
- if(c->filename)
- free(c->filename);
- co = c->cookies;
-
- while(co) {
- next = co->next;
- freecookie(co);
- co = next;
- }
- free(c); /* free the base struct as well */
- }
-}
-
-/* get_netscape_format()
- *
- * Formats a string for Netscape output file, w/o a newline at the end.
- *
- * Function returns a char * to a formatted line. Has to be free()d
-*/
-static char *get_netscape_format(const struct Cookie *co)
-{
- return aprintf(
- "%s%s\t" /* domain */
- "%s\t" /* tailmatch */
- "%s\t" /* path */
- "%s\t" /* secure */
- "%" FORMAT_OFF_T "\t" /* expires */
- "%s\t" /* name */
- "%s", /* value */
- /* Make sure all domains are prefixed with a dot if they allow
- tailmatching. This is Mozilla-style. */
- (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
- co->domain?co->domain:"unknown",
- co->tailmatch?"TRUE":"FALSE",
- co->path?co->path:"/",
- co->secure?"TRUE":"FALSE",
- co->expires,
- co->name,
- co->value?co->value:"");
-}
-
-/*
- * Curl_cookie_output()
- *
- * Writes all internally known cookies to the specified file. Specify
- * "-" as file name to write to stdout.
- *
- * The function returns non-zero on write failure.
- */
-int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
-{
- struct Cookie *co;
- FILE *out;
- bool use_stdout=FALSE;
-
- if((NULL == c) || (0 == c->numcookies))
- /* If there are no known cookies, we don't write or even create any
- destination file */
- return 0;
-
- if(strequal("-", dumphere)) {
- /* use stdout */
- out = stdout;
- use_stdout=TRUE;
- }
- else {
- out = fopen(dumphere, "w");
- if(!out)
- return 1; /* failure */
- }
-
- if(c) {
- char *format_ptr;
-
- fputs("# Netscape HTTP Cookie File\n"
- "# http://curlm.haxx.se/rfc/cookie_spec.html\n"
- "# This file was generated by libcurl! Edit at your own risk.\n\n",
- out);
- co = c->cookies;
-
- while(co) {
- format_ptr = get_netscape_format(co);
- if (format_ptr == NULL) {
- fprintf(out, "#\n# Fatal libcurl error\n");
- if(!use_stdout)
- fclose(out);
- return 1;
- }
- fprintf(out, "%s\n", format_ptr);
- free(format_ptr);
- co=co->next;
- }
- }
-
- if(!use_stdout)
- fclose(out);
-
- return 0;
-}
-
-struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
-{
- struct curl_slist *list = NULL;
- struct curl_slist *beg;
- struct Cookie *c;
- char *line;
-
- if ((data->cookies == NULL) ||
- (data->cookies->numcookies == 0))
- return NULL;
-
- c = data->cookies->cookies;
-
- beg = list;
- while (c) {
- /* fill the list with _all_ the cookies we know */
- line = get_netscape_format(c);
- if (line == NULL) {
- /* get_netscape_format returns null only if we run out of memory */
-
- curl_slist_free_all(beg); /* free some memory */
- return NULL;
- }
- list = curl_slist_append(list, line);
- free(line);
- c = c->next;
- }
-
- return list;
-}
-
-#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
diff --git a/Utilities/cmcurl/cookie.h b/Utilities/cmcurl/cookie.h
deleted file mode 100644
index 57c3acbdd..000000000
--- a/Utilities/cmcurl/cookie.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef __COOKIE_H
-#define __COOKIE_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <stdio.h>
-#if defined(WIN32)
-#include <time.h>
-#else
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#endif
-
-#include <curl/curl.h>
-
-struct Cookie {
- struct Cookie *next; /* next in the chain */
- char *name; /* <this> = value */
- char *value; /* name = <this> */
- char *path; /* path = <this> */
- char *domain; /* domain = <this> */
- curl_off_t expires; /* expires = <this> */
- char *expirestr; /* the plain text version */
- bool tailmatch; /* weather we do tail-matchning of the domain name */
-
- /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
- char *version; /* Version = <value> */
- char *maxage; /* Max-Age = <value> */
-
- bool secure; /* whether the 'secure' keyword was used */
- bool livecookie; /* updated from a server, not a stored file */
-};
-
-struct CookieInfo {
- /* linked list of cookies we know of */
- struct Cookie *cookies;
-
- char *filename; /* file we read from/write to */
- bool running; /* state info, for cookie adding information */
- long numcookies; /* number of cookies in the "jar" */
- bool newsession; /* new session, discard session cookies on load */
-};
-
-/* This is the maximum line length we accept for a cookie line. RFC 2109
- section 6.3 says:
-
- "at least 4096 bytes per cookie (as measured by the size of the characters
- that comprise the cookie non-terminal in the syntax description of the
- Set-Cookie header)"
-
-*/
-#define MAX_COOKIE_LINE 5000
-#define MAX_COOKIE_LINE_TXT "4999"
-
-/* This is the maximum length of a cookie name we deal with: */
-#define MAX_NAME 1024
-#define MAX_NAME_TXT "1023"
-
-struct SessionHandle;
-/*
- * Add a cookie to the internal list of cookies. The domain and path arguments
- * are only used if the header boolean is TRUE.
- */
-
-struct Cookie *Curl_cookie_add(struct SessionHandle *data,
- struct CookieInfo *, bool header, char *line,
- char *domain, char *path);
-
-struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
- char *, struct CookieInfo *, bool);
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);
-void Curl_cookie_freelist(struct Cookie *);
-void Curl_cookie_clearall(struct CookieInfo *cookies);
-void Curl_cookie_clearsess(struct CookieInfo *cookies);
-void Curl_cookie_cleanup(struct CookieInfo *);
-int Curl_cookie_output(struct CookieInfo *, char *);
-
-#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
-#define Curl_cookie_list(x) NULL
-#define Curl_cookie_loadfiles(x) do { } while (0)
-#else
-struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
-void Curl_cookie_loadfiles(struct SessionHandle *data);
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/curl/curl.h b/Utilities/cmcurl/curl/curl.h
deleted file mode 100644
index e586c4a8c..000000000
--- a/Utilities/cmcurl/curl/curl.h
+++ /dev/null
@@ -1,1644 +0,0 @@
-#ifndef __CURL_CURL_H
-#define __CURL_CURL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* If you have problems, all libcurl docs and details are found here:
- http://curl.haxx.se/libcurl/
-*/
-
-#include "curlver.h" /* the libcurl version defines */
-
-#include <stdio.h>
-#include <limits.h>
-
-/* The include stuff here below is mainly for time_t! */
-#ifdef vms
-# include <types.h>
-# include <time.h>
-#else
-# include <sys/types.h>
-# include <time.h>
-#endif /* defined (vms) */
-
-typedef void CURL;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/*
- * Decorate exportable functions for Win32 DLL linking.
- * This avoids using a .def file for building libcurl.dll.
- */
-#if (defined(WIN32) || defined(_WIN32)) && !defined(CURL_STATICLIB)
-#if defined(BUILDING_LIBCURL)
-#define CURL_EXTERN __declspec(dllexport)
-#else
-#define CURL_EXTERN __declspec(dllimport)
-#endif
-#else
-
-#ifdef CURL_HIDDEN_SYMBOLS
-/*
- * This definition is used to make external definitions visibile in the
- * shared library when symbols are hidden by default. It makes no
- * difference when compiling applications whether this is set or not,
- * only when compiling the library.
- */
-#define CURL_EXTERN CURL_EXTERN_SYMBOL
-#else
-#define CURL_EXTERN
-#endif
-#endif
-
-/*
- * We want the typedef curl_off_t setup for large file support on all
- * platforms. We also provide a CURL_FORMAT_OFF_T define to use in *printf
- * format strings when outputting a variable of type curl_off_t.
- *
- * Note: "pocc -Ze" is MSVC compatibily mode and this sets _MSC_VER!
- */
-
-#if (defined(_MSC_VER) && !defined(__POCC__)) || (defined(__LCC__) && defined(WIN32))
-/* MSVC */
-#ifdef _WIN32_WCE
- typedef long curl_off_t;
-#define CURL_FORMAT_OFF_T "%ld"
-#else
- typedef signed __int64 curl_off_t;
-#define CURL_FORMAT_OFF_T "%I64d"
-#endif
-#else /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */
-#if (defined(__GNUC__) && defined(WIN32)) || defined(__WATCOMC__)
-/* gcc on windows or Watcom */
- typedef long long curl_off_t;
-#define CURL_FORMAT_OFF_T "%I64d"
-#else /* GCC or Watcom on Windows */
-
-/* "normal" POSIX approach, do note that this does not necessarily mean that
- the type is >32 bits, see the SIZEOF_CURL_OFF_T define for that! */
- typedef off_t curl_off_t;
-
-/* Check a range of defines to detect large file support. On Linux it seems
- none of these are set by default, so if you don't explicitly switches on
- large file support, this define will be made for "small file" support. */
-#ifndef _FILE_OFFSET_BITS
-#define _FILE_OFFSET_BITS 0 /* to prevent warnings in the check below */
-#define UNDEF_FILE_OFFSET_BITS
-#endif
-#ifndef FILESIZEBITS
-#define FILESIZEBITS 0 /* to prevent warnings in the check below */
-#define UNDEF_FILESIZEBITS
-#endif
-
-#if defined(_LARGE_FILES) || (_FILE_OFFSET_BITS > 32) || (FILESIZEBITS > 32) \
- || defined(_LARGEFILE_SOURCE) || defined(_LARGEFILE64_SOURCE)
- /* For now, we assume at least one of these to be set for large files to
- work! */
-#define CURL_FORMAT_OFF_T "%lld"
-#else /* LARGE_FILE support */
-#define CURL_FORMAT_OFF_T "%ld"
-#endif
-#endif /* GCC or Watcom on Windows */
-#endif /* (_MSC_VER && !__POCC__) || (__LCC__ && WIN32) */
-
-#ifdef UNDEF_FILE_OFFSET_BITS
-/* this was defined above for our checks, undefine it again */
-#undef _FILE_OFFSET_BITS
-#endif
-
-#ifdef UNDEF_FILESIZEBITS
-/* this was defined above for our checks, undefine it again */
-#undef FILESIZEBITS
-#endif
-
-#if defined(_WIN32) && !defined(WIN32)
-/* Chris Lewis mentioned that he doesn't get WIN32 defined, only _WIN32 so we
- make this adjustment to catch this. */
-#define WIN32 1
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \
- !defined(__CYGWIN__) || defined(__MINGW32__)
-#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H))
-/* The check above prevents the winsock2 inclusion if winsock.h already was
- included, since they can't co-exist without problems */
-#include <winsock2.h>
-#endif
-#else
-
-/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
- libc5-based Linux systems. Only include it on system that are known to
- require it! */
-#if defined(_AIX) || defined(NETWARE) || defined(__NetBSD__) || defined(__minix)
-#include <sys/select.h>
-#endif
-
-#ifndef _WIN32_WCE
-#include <sys/socket.h>
-#endif
-#ifndef __WATCOMC__
-#include <sys/time.h>
-#endif
-#include <sys/types.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef curl_socket_typedef
-/* socket typedef */
-#ifdef WIN32
-typedef SOCKET curl_socket_t;
-#define CURL_SOCKET_BAD INVALID_SOCKET
-#else
-typedef int curl_socket_t;
-#define CURL_SOCKET_BAD -1
-#endif
-#define curl_socket_typedef
-#endif /* curl_socket_typedef */
-
-struct curl_httppost {
- struct curl_httppost *next; /* next entry in the list */
- char *name; /* pointer to allocated name */
- long namelength; /* length of name length */
- char *contents; /* pointer to allocated data contents */
- long contentslength; /* length of contents field */
- char *buffer; /* pointer to allocated buffer contents */
- long bufferlength; /* length of buffer field */
- char *contenttype; /* Content-Type */
- struct curl_slist* contentheader; /* list of extra headers for this form */
- struct curl_httppost *more; /* if one field name has more than one
- file, this link should link to following
- files */
- long flags; /* as defined below */
-#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
-#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
-#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
- do not free in formfree */
-#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
- do not free in formfree */
-#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */
-#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */
-
- char *showfilename; /* The file name to show. If not set, the
- actual file name will be used (if this
- is a file part) */
-};
-
-typedef int (*curl_progress_callback)(void *clientp,
- double dltotal,
- double dlnow,
- double ultotal,
- double ulnow);
-
- /* Tests have proven that 20K is a very bad buffer size for uploads on
- Windows, while 16K for some odd reason performed a lot better. */
-#define CURL_MAX_WRITE_SIZE 16384
-
-typedef size_t (*curl_write_callback)(char *buffer,
- size_t size,
- size_t nitems,
- void *outstream);
-
-/* This is a return code for the read callback that, when returned, will
- signal libcurl to immediately abort the current transfer. */
-#define CURL_READFUNC_ABORT 0x10000000
-typedef size_t (*curl_read_callback)(char *buffer,
- size_t size,
- size_t nitems,
- void *instream);
-
-typedef enum {
- CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
- CURLSOCKTYPE_LAST /* never use */
-} curlsocktype;
-
-typedef int (*curl_sockopt_callback)(void *clientp,
- curl_socket_t curlfd,
- curlsocktype purpose);
-
-#ifndef CURL_NO_OLDIES
- /* not used since 7.10.8, will be removed in a future release */
-typedef int (*curl_passwd_callback)(void *clientp,
- const char *prompt,
- char *buffer,
- int buflen);
-#endif
-
-typedef enum {
- CURLIOE_OK, /* I/O operation successful */
- CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
- CURLIOE_FAILRESTART, /* failed to restart the read */
- CURLIOE_LAST /* never use */
-} curlioerr;
-
-typedef enum {
- CURLIOCMD_NOP, /* no operation */
- CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
- CURLIOCMD_LAST /* never use */
-} curliocmd;
-
-typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
- int cmd,
- void *clientp);
-
-/*
- * The following typedef's are signatures of malloc, free, realloc, strdup and
- * calloc respectively. Function pointers of these types can be passed to the
- * curl_global_init_mem() function to set user defined memory management
- * callback routines.
- */
-typedef void *(*curl_malloc_callback)(size_t size);
-typedef void (*curl_free_callback)(void *ptr);
-typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
-typedef char *(*curl_strdup_callback)(const char *str);
-typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
-
-/* the kind of data that is passed to information_callback*/
-typedef enum {
- CURLINFO_TEXT = 0,
- CURLINFO_HEADER_IN, /* 1 */
- CURLINFO_HEADER_OUT, /* 2 */
- CURLINFO_DATA_IN, /* 3 */
- CURLINFO_DATA_OUT, /* 4 */
- CURLINFO_SSL_DATA_IN, /* 5 */
- CURLINFO_SSL_DATA_OUT, /* 6 */
- CURLINFO_END
-} curl_infotype;
-
-typedef int (*curl_debug_callback)
- (CURL *handle, /* the handle/transfer this concerns */
- curl_infotype type, /* what kind of data */
- char *data, /* points to the data */
- size_t size, /* size of the data pointed to */
- void *userptr); /* whatever the user please */
-
-/* All possible error codes from all sorts of curl functions. Future versions
- may return other values, stay prepared.
-
- Always add new return codes last. Never *EVER* remove any. The return
- codes must remain the same!
- */
-
-typedef enum {
- CURLE_OK = 0,
- CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
- CURLE_FAILED_INIT, /* 2 */
- CURLE_URL_MALFORMAT, /* 3 */
- CURLE_NOT_BUILT_IN, /* 4 */
- CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
- CURLE_COULDNT_RESOLVE_HOST, /* 6 */
- CURLE_COULDNT_CONNECT, /* 7 */
- CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */
- CURLE_FTP_ACCESS_DENIED, /* 9 a service was denied by the FTP server
- due to lack of access - when login fails
- this is not returned. */
- CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 - NOT USED */
- CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
- CURLE_FTP_WEIRD_USER_REPLY, /* 12 */
- CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
- CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
- CURLE_FTP_CANT_GET_HOST, /* 15 */
- CURLE_FTP_CANT_RECONNECT, /* 16 */
- CURLE_FTP_COULDNT_SET_BINARY, /* 17 */
- CURLE_PARTIAL_FILE, /* 18 */
- CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
- CURLE_FTP_WRITE_ERROR, /* 20 */
- CURLE_FTP_QUOTE_ERROR, /* 21 */
- CURLE_HTTP_RETURNED_ERROR, /* 22 */
- CURLE_WRITE_ERROR, /* 23 */
- CURLE_MALFORMAT_USER, /* 24 - NOT USED */
- CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */
- CURLE_READ_ERROR, /* 26 - could open/read from file */
- CURLE_OUT_OF_MEMORY, /* 27 */
- /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
- instead of a memory allocation error if CURL_DOES_CONVERSIONS
- is defined
- */
- CURLE_OPERATION_TIMEOUTED, /* 28 - the timeout time was reached */
- CURLE_FTP_COULDNT_SET_ASCII, /* 29 - TYPE A failed */
- CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
- CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
- CURLE_FTP_COULDNT_GET_SIZE, /* 32 - the SIZE command failed */
- CURLE_HTTP_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
- CURLE_HTTP_POST_ERROR, /* 34 */
- CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
- CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
- CURLE_FILE_COULDNT_READ_FILE, /* 37 */
- CURLE_LDAP_CANNOT_BIND, /* 38 */
- CURLE_LDAP_SEARCH_FAILED, /* 39 */
- CURLE_LIBRARY_NOT_FOUND, /* 40 */
- CURLE_FUNCTION_NOT_FOUND, /* 41 */
- CURLE_ABORTED_BY_CALLBACK, /* 42 */
- CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
- CURLE_BAD_CALLING_ORDER, /* 44 - NOT USED */
- CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */
- CURLE_BAD_PASSWORD_ENTERED, /* 46 - NOT USED */
- CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */
- CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */
- CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */
- CURLE_OBSOLETE, /* 50 - NOT USED */
- CURLE_SSL_PEER_CERTIFICATE, /* 51 - peer's certificate wasn't ok */
- CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
- CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
- CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as
- default */
- CURLE_SEND_ERROR, /* 55 - failed sending network data */
- CURLE_RECV_ERROR, /* 56 - failure in receiving network data */
- CURLE_SHARE_IN_USE, /* 57 - share is in use */
- CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
- CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
- CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
- CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized transfer encoding */
- CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
- CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
- CURLE_FTP_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
- CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
- that failed */
- CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
- CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
- accepted and we failed to login */
- CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */
- CURLE_TFTP_PERM, /* 69 - permission problem on server */
- CURLE_TFTP_DISKFULL, /* 70 - out of disk space on server */
- CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */
- CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */
- CURLE_TFTP_EXISTS, /* 73 - File already exists */
- CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */
- CURLE_CONV_FAILED, /* 75 - conversion failed */
- CURLE_CONV_REQD, /* 76 - caller must register conversion
- callbacks using curl_easy_setopt options
- CURLOPT_CONV_FROM_NETWORK_FUNCTION,
- CURLOPT_CONV_TO_NETWORK_FUNCTION, and
- CURLOPT_CONV_FROM_UTF8_FUNCTION */
- CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing
- or wrong format */
- CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */
- CURLE_SSH, /* 79 - error from the SSH layer, somewhat
- generic so the error message will be of
- interest when this has happened */
-
- CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
- connection */
- CURL_LAST /* never use! */
-} CURLcode;
-
-/* This prototype applies to all conversion callbacks */
-typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
-
-typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
- void *ssl_ctx, /* actually an
- OpenSSL SSL_CTX */
- void *userptr);
-
-/* Make a spelling correction for the operation timed-out define */
-#define CURLE_OPERATION_TIMEDOUT CURLE_OPERATION_TIMEOUTED
-
-#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
- the obsolete stuff removed! */
-/* backwards compatibility with older names */
-#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
-#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
-#endif
-
-typedef enum {
- CURLPROXY_HTTP = 0,
- CURLPROXY_SOCKS4 = 4,
- CURLPROXY_SOCKS5 = 5
-} curl_proxytype;
-
-#define CURLAUTH_NONE 0 /* nothing */
-#define CURLAUTH_BASIC (1<<0) /* Basic (default) */
-#define CURLAUTH_DIGEST (1<<1) /* Digest */
-#define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */
-#define CURLAUTH_NTLM (1<<3) /* NTLM */
-#define CURLAUTH_ANY ~0 /* all types set */
-#define CURLAUTH_ANYSAFE (~CURLAUTH_BASIC)
-
-#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */
-#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */
-#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
-#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
-#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
-#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
-#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
-
-#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
- the obsolete stuff removed! */
-/* this was the error code 50 in 7.7.3 and a few earlier versions, this
- is no longer used by libcurl but is instead #defined here only to not
- make programs break */
-#define CURLE_ALREADY_COMPLETE 99999
-
-/* These are just to make older programs not break: */
-#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
-#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
-#endif
-
-#define CURL_ERROR_SIZE 256
-
-/* parameter for the CURLOPT_FTP_SSL option */
-typedef enum {
- CURLFTPSSL_NONE, /* do not attempt to use SSL */
- CURLFTPSSL_TRY, /* try using SSL, proceed anyway otherwise */
- CURLFTPSSL_CONTROL, /* SSL for the control connection or fail */
- CURLFTPSSL_ALL, /* SSL for all communication or fail */
- CURLFTPSSL_LAST /* not an option, never use */
-} curl_ftpssl;
-
-/* parameter for the CURLOPT_FTPSSLAUTH option */
-typedef enum {
- CURLFTPAUTH_DEFAULT, /* let libcurl decide */
- CURLFTPAUTH_SSL, /* use "AUTH SSL" */
- CURLFTPAUTH_TLS, /* use "AUTH TLS" */
- CURLFTPAUTH_LAST /* not an option, never use */
-} curl_ftpauth;
-
-/* parameter for the CURLOPT_FTP_FILEMETHOD option */
-typedef enum {
- CURLFTPMETHOD_DEFAULT, /* let libcurl pick */
- CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */
- CURLFTPMETHOD_NOCWD, /* no CWD at all */
- CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
- CURLFTPMETHOD_LAST /* not an option, never use */
-} curl_ftpmethod;
-
-/* long may be 32 or 64 bits, but we should never depend on anything else
- but 32 */
-#define CURLOPTTYPE_LONG 0
-#define CURLOPTTYPE_OBJECTPOINT 10000
-#define CURLOPTTYPE_FUNCTIONPOINT 20000
-#define CURLOPTTYPE_OFF_T 30000
-
-/* name is uppercase CURLOPT_<name>,
- type is one of the defined CURLOPTTYPE_<type>
- number is unique identifier */
-#ifdef CINIT
-#undef CINIT
-#endif
-/*
- * Figure out if we can use the ## operator, which is supported by ISO/ANSI C
- * and C++. Some compilers support it without setting __STDC__ or __cplusplus
- * so we need to carefully check for them too. We don't use configure-checks
- * for these since we want these headers to remain generic and working for all
- * platforms.
- */
-#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
- defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
- defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__)
- /* This compiler is believed to have an ISO compatible preprocessor */
-#define CURL_ISOCPP
-#else
- /* This compiler is believed NOT to have an ISO compatible preprocessor */
-#undef CURL_ISOCPP
-#endif
-
-#ifdef CURL_ISOCPP
-#define CINIT(name,type,number) CURLOPT_ ## name = CURLOPTTYPE_ ## type + number
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define LONG CURLOPTTYPE_LONG
-#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
-#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
-#define OFF_T CURLOPTTYPE_OFF_T
-#define CINIT(name,type,number) CURLOPT_/**/name = type + number
-#endif
-
-/*
- * This macro-mania below setups the CURLOPT_[what] enum, to be used with
- * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
- * word.
- */
-
-typedef enum {
- /* This is the FILE * or void * the regular output should be written to. */
- CINIT(FILE, OBJECTPOINT, 1),
-
- /* The full URL to get/put */
- CINIT(URL, OBJECTPOINT, 2),
-
- /* Port number to connect to, if other than default. */
- CINIT(PORT, LONG, 3),
-
- /* Name of proxy to use. */
- CINIT(PROXY, OBJECTPOINT, 4),
-
- /* "name:password" to use when fetching. */
- CINIT(USERPWD, OBJECTPOINT, 5),
-
- /* "name:password" to use with proxy. */
- CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
-
- /* Range to get, specified as an ASCII string. */
- CINIT(RANGE, OBJECTPOINT, 7),
-
- /* not used */
-
- /* Specified file stream to upload from (use as input): */
- CINIT(INFILE, OBJECTPOINT, 9),
-
- /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
- * bytes big. If this is not used, error messages go to stderr instead: */
- CINIT(ERRORBUFFER, OBJECTPOINT, 10),
-
- /* Function that will be called to store the output (instead of fwrite). The
- * parameters will use fwrite() syntax, make sure to follow them. */
- CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
-
- /* Function that will be called to read the input (instead of fread). The
- * parameters will use fread() syntax, make sure to follow them. */
- CINIT(READFUNCTION, FUNCTIONPOINT, 12),
-
- /* Time-out the read operation after this amount of seconds */
- CINIT(TIMEOUT, LONG, 13),
-
- /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
- * how large the file being sent really is. That allows better error
- * checking and better verifies that the upload was succcessful. -1 means
- * unknown size.
- *
- * For large file support, there is also a _LARGE version of the key
- * which takes an off_t type, allowing platforms with larger off_t
- * sizes to handle larger files. See below for INFILESIZE_LARGE.
- */
- CINIT(INFILESIZE, LONG, 14),
-
- /* POST input fields. */
- CINIT(POSTFIELDS, OBJECTPOINT, 15),
-
- /* Set the referer page (needed by some CGIs) */
- CINIT(REFERER, OBJECTPOINT, 16),
-
- /* Set the FTP PORT string (interface name, named or numerical IP address)
- Use i.e '-' to use default address. */
- CINIT(FTPPORT, OBJECTPOINT, 17),
-
- /* Set the User-Agent string (examined by some CGIs) */
- CINIT(USERAGENT, OBJECTPOINT, 18),
-
- /* If the download receives less than "low speed limit" bytes/second
- * during "low speed time" seconds, the operations is aborted.
- * You could i.e if you have a pretty high speed connection, abort if
- * it is less than 2000 bytes/sec during 20 seconds.
- */
-
- /* Set the "low speed limit" */
- CINIT(LOW_SPEED_LIMIT, LONG , 19),
-
- /* Set the "low speed time" */
- CINIT(LOW_SPEED_TIME, LONG, 20),
-
- /* Set the continuation offset.
- *
- * Note there is also a _LARGE version of this key which uses
- * off_t types, allowing for large file offsets on platforms which
- * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
- */
- CINIT(RESUME_FROM, LONG, 21),
-
- /* Set cookie in request: */
- CINIT(COOKIE, OBJECTPOINT, 22),
-
- /* This points to a linked list of headers, struct curl_slist kind */
- CINIT(HTTPHEADER, OBJECTPOINT, 23),
-
- /* This points to a linked list of post entries, struct HttpPost */
- CINIT(HTTPPOST, OBJECTPOINT, 24),
-
- /* name of the file keeping your private SSL-certificate */
- CINIT(SSLCERT, OBJECTPOINT, 25),
-
- /* password for the SSL-private key, keep this for compatibility */
- CINIT(SSLCERTPASSWD, OBJECTPOINT, 26),
- /* password for the SSL private key */
- CINIT(SSLKEYPASSWD, OBJECTPOINT, 26),
-
- /* send TYPE parameter? */
- CINIT(CRLF, LONG, 27),
-
- /* send linked-list of QUOTE commands */
- CINIT(QUOTE, OBJECTPOINT, 28),
-
- /* send FILE * or void * to store headers to, if you use a callback it
- is simply passed to the callback unmodified */
- CINIT(WRITEHEADER, OBJECTPOINT, 29),
-
- /* point to a file to read the initial cookies from, also enables
- "cookie awareness" */
- CINIT(COOKIEFILE, OBJECTPOINT, 31),
-
- /* What version to specifly try to use.
- See CURL_SSLVERSION defines below. */
- CINIT(SSLVERSION, LONG, 32),
-
- /* What kind of HTTP time condition to use, see defines */
- CINIT(TIMECONDITION, LONG, 33),
-
- /* Time to use with the above condition. Specified in number of seconds
- since 1 Jan 1970 */
- CINIT(TIMEVALUE, LONG, 34),
-
- /* 35 = OBSOLETE */
-
- /* Custom request, for customizing the get command like
- HTTP: DELETE, TRACE and others
- FTP: to use a different list command
- */
- CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
-
- /* HTTP request, for odd commands like DELETE, TRACE and others */
- CINIT(STDERR, OBJECTPOINT, 37),
-
- /* 38 is not used */
-
- /* send linked-list of post-transfer QUOTE commands */
- CINIT(POSTQUOTE, OBJECTPOINT, 39),
-
- /* Pass a pointer to string of the output using full variable-replacement
- as described elsewhere. */
- CINIT(WRITEINFO, OBJECTPOINT, 40),
-
- CINIT(VERBOSE, LONG, 41), /* talk a lot */
- CINIT(HEADER, LONG, 42), /* throw the header out too */
- CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
- CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
- CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */
- CINIT(UPLOAD, LONG, 46), /* this is an upload */
- CINIT(POST, LONG, 47), /* HTTP POST method */
- CINIT(FTPLISTONLY, LONG, 48), /* Use NLST when listing ftp dir */
-
- CINIT(FTPAPPEND, LONG, 50), /* Append instead of overwrite on upload! */
-
- /* Specify whether to read the user+password from the .netrc or the URL.
- * This must be one of the CURL_NETRC_* enums below. */
- CINIT(NETRC, LONG, 51),
-
- CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */
-
- CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
- CINIT(PUT, LONG, 54), /* HTTP PUT */
-
- /* 55 = OBSOLETE */
-
- /* Function that will be called instead of the internal progress display
- * function. This function should be defined as the curl_progress_callback
- * prototype defines. */
- CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
-
- /* Data passed to the progress callback */
- CINIT(PROGRESSDATA, OBJECTPOINT, 57),
-
- /* We want the referer field set automatically when following locations */
- CINIT(AUTOREFERER, LONG, 58),
-
- /* Port of the proxy, can be set in the proxy string as well with:
- "[host]:[port]" */
- CINIT(PROXYPORT, LONG, 59),
-
- /* size of the POST input data, if strlen() is not good to use */
- CINIT(POSTFIELDSIZE, LONG, 60),
-
- /* tunnel non-http operations through a HTTP proxy */
- CINIT(HTTPPROXYTUNNEL, LONG, 61),
-
- /* Set the interface string to use as outgoing network interface */
- CINIT(INTERFACE, OBJECTPOINT, 62),
-
- /* Set the krb4 security level, this also enables krb4 awareness. This is a
- * string, 'clear', 'safe', 'confidential' or 'private'. If the string is
- * set but doesn't match one of these, 'private' will be used. */
- CINIT(KRB4LEVEL, OBJECTPOINT, 63),
-
- /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
- CINIT(SSL_VERIFYPEER, LONG, 64),
-
- /* The CApath or CAfile used to validate the peer certificate
- this option is used only if SSL_VERIFYPEER is true */
- CINIT(CAINFO, OBJECTPOINT, 65),
-
- /* 66 = OBSOLETE */
- /* 67 = OBSOLETE */
-
- /* Maximum number of http redirects to follow */
- CINIT(MAXREDIRS, LONG, 68),
-
- /* Pass a long set to 1 to get the date of the requested document (if
- possible)! Pass a zero to shut it off. */
- CINIT(FILETIME, LONG, 69),
-
- /* This points to a linked list of telnet options */
- CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
-
- /* Max amount of cached alive connections */
- CINIT(MAXCONNECTS, LONG, 71),
-
- /* What policy to use when closing connections when the cache is filled
- up */
- CINIT(CLOSEPOLICY, LONG, 72),
-
- /* 73 = OBSOLETE */
-
- /* Set to explicitly use a new connection for the upcoming transfer.
- Do not use this unless you're absolutely sure of this, as it makes the
- operation slower and is less friendly for the network. */
- CINIT(FRESH_CONNECT, LONG, 74),
-
- /* Set to explicitly forbid the upcoming transfer's connection to be re-used
- when done. Do not use this unless you're absolutely sure of this, as it
- makes the operation slower and is less friendly for the network. */
- CINIT(FORBID_REUSE, LONG, 75),
-
- /* Set to a file name that contains random data for libcurl to use to
- seed the random engine when doing SSL connects. */
- CINIT(RANDOM_FILE, OBJECTPOINT, 76),
-
- /* Set to the Entropy Gathering Daemon socket pathname */
- CINIT(EGDSOCKET, OBJECTPOINT, 77),
-
- /* Time-out connect operations after this amount of seconds, if connects
- are OK within this time, then fine... This only aborts the connect
- phase. [Only works on unix-style/SIGALRM operating systems] */
- CINIT(CONNECTTIMEOUT, LONG, 78),
-
- /* Function that will be called to store headers (instead of fwrite). The
- * parameters will use fwrite() syntax, make sure to follow them. */
- CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
-
- /* Set this to force the HTTP request to get back to GET. Only really usable
- if POST, PUT or a custom request have been used first.
- */
- CINIT(HTTPGET, LONG, 80),
-
- /* Set if we should verify the Common name from the peer certificate in ssl
- * handshake, set 1 to check existence, 2 to ensure that it matches the
- * provided hostname. */
- CINIT(SSL_VERIFYHOST, LONG, 81),
-
- /* Specify which file name to write all known cookies in after completed
- operation. Set file name to "-" (dash) to make it go to stdout. */
- CINIT(COOKIEJAR, OBJECTPOINT, 82),
-
- /* Specify which SSL ciphers to use */
- CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
-
- /* Specify which HTTP version to use! This must be set to one of the
- CURL_HTTP_VERSION* enums set below. */
- CINIT(HTTP_VERSION, LONG, 84),
-
- /* Specificly switch on or off the FTP engine's use of the EPSV command. By
- default, that one will always be attempted before the more traditional
- PASV command. */
- CINIT(FTP_USE_EPSV, LONG, 85),
-
- /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
- CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
-
- /* name of the file keeping your private SSL-key */
- CINIT(SSLKEY, OBJECTPOINT, 87),
-
- /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
- CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
-
- /* crypto engine for the SSL-sub system */
- CINIT(SSLENGINE, OBJECTPOINT, 89),
-
- /* set the crypto engine for the SSL-sub system as default
- the param has no meaning...
- */
- CINIT(SSLENGINE_DEFAULT, LONG, 90),
-
- /* Non-zero value means to use the global dns cache */
- CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To becomeO BSOLETE soon */
-
- /* DNS cache timeout */
- CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
-
- /* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/
- CINIT(PREQUOTE, OBJECTPOINT, 93),
-
- /* set the debug function */
- CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
-
- /* set the data for the debug function */
- CINIT(DEBUGDATA, OBJECTPOINT, 95),
-
- /* mark this as start of a cookie session */
- CINIT(COOKIESESSION, LONG, 96),
-
- /* The CApath directory used to validate the peer certificate
- this option is used only if SSL_VERIFYPEER is true */
- CINIT(CAPATH, OBJECTPOINT, 97),
-
- /* Instruct libcurl to use a smaller receive buffer */
- CINIT(BUFFERSIZE, LONG, 98),
-
- /* Instruct libcurl to not use any signal/alarm handlers, even when using
- timeouts. This option is useful for multi-threaded applications.
- See libcurl-the-guide for more background information. */
- CINIT(NOSIGNAL, LONG, 99),
-
- /* Provide a CURLShare for mutexing non-ts data */
- CINIT(SHARE, OBJECTPOINT, 100),
-
- /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
- CURLPROXY_SOCKS4 and CURLPROXY_SOCKS5. */
- CINIT(PROXYTYPE, LONG, 101),
-
- /* Set the Accept-Encoding string. Use this to tell a server you would like
- the response to be compressed. */
- CINIT(ENCODING, OBJECTPOINT, 102),
-
- /* Set pointer to private data */
- CINIT(PRIVATE, OBJECTPOINT, 103),
-
- /* Set aliases for HTTP 200 in the HTTP Response header */
- CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
-
- /* Continue to send authentication (user+password) when following locations,
- even when hostname changed. This can potentionally send off the name
- and password to whatever host the server decides. */
- CINIT(UNRESTRICTED_AUTH, LONG, 105),
-
- /* Specificly switch on or off the FTP engine's use of the EPRT command ( it
- also disables the LPRT attempt). By default, those ones will always be
- attempted before the good old traditional PORT command. */
- CINIT(FTP_USE_EPRT, LONG, 106),
-
- /* Set this to a bitmask value to enable the particular authentications
- methods you like. Use this in combination with CURLOPT_USERPWD.
- Note that setting multiple bits may cause extra network round-trips. */
- CINIT(HTTPAUTH, LONG, 107),
-
- /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
- in second argument. The function must be matching the
- curl_ssl_ctx_callback proto. */
- CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
-
- /* Set the userdata for the ssl context callback function's third
- argument */
- CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
-
- /* FTP Option that causes missing dirs to be created on the remote server */
- CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
-
- /* Set this to a bitmask value to enable the particular authentications
- methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
- Note that setting multiple bits may cause extra network round-trips. */
- CINIT(PROXYAUTH, LONG, 111),
-
- /* FTP option that changes the timeout, in seconds, associated with
- getting a response. This is different from transfer timeout time and
- essentially places a demand on the FTP server to acknowledge commands
- in a timely manner. */
- CINIT(FTP_RESPONSE_TIMEOUT, LONG , 112),
-
- /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
- tell libcurl to resolve names to those IP versions only. This only has
- affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
- CINIT(IPRESOLVE, LONG, 113),
-
- /* Set this option to limit the size of a file that will be downloaded from
- an HTTP or FTP server.
-
- Note there is also _LARGE version which adds large file support for
- platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
- CINIT(MAXFILESIZE, LONG, 114),
-
- /* See the comment for INFILESIZE above, but in short, specifies
- * the size of the file being uploaded. -1 means unknown.
- */
- CINIT(INFILESIZE_LARGE, OFF_T, 115),
-
- /* Sets the continuation offset. There is also a LONG version of this;
- * look above for RESUME_FROM.
- */
- CINIT(RESUME_FROM_LARGE, OFF_T, 116),
-
- /* Sets the maximum size of data that will be downloaded from
- * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
- */
- CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
-
- /* Set this option to the file name of your .netrc file you want libcurl
- to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
- a poor attempt to find the user's home directory and check for a .netrc
- file in there. */
- CINIT(NETRC_FILE, OBJECTPOINT, 118),
-
- /* Enable SSL/TLS for FTP, pick one of:
- CURLFTPSSL_TRY - try using SSL, proceed anyway otherwise
- CURLFTPSSL_CONTROL - SSL for the control connection or fail
- CURLFTPSSL_ALL - SSL for all communication or fail
- */
- CINIT(FTP_SSL, LONG, 119),
-
- /* The _LARGE version of the standard POSTFIELDSIZE option */
- CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
-
- /* Enable/disable the TCP Nagle algorithm */
- CINIT(TCP_NODELAY, LONG, 121),
-
- /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
- /* 123 OBSOLETE. Gone in 7.16.0 */
- /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
- /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
- /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
- /* 127 OBSOLETE. Gone in 7.16.0 */
- /* 128 OBSOLETE. Gone in 7.16.0 */
-
- /* When FTP over SSL/TLS is selected (with CURLOPT_FTP_SSL), this option
- can be used to change libcurl's default action which is to first try
- "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
- response has been received.
-
- Available parameters are:
- CURLFTPAUTH_DEFAULT - let libcurl decide
- CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS
- CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL
- */
- CINIT(FTPSSLAUTH, LONG, 129),
-
- CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
- CINIT(IOCTLDATA, OBJECTPOINT, 131),
-
- /* 132 OBSOLETE. Gone in 7.16.0 */
- /* 133 OBSOLETE. Gone in 7.16.0 */
-
- /* zero terminated string for pass on to the FTP server when asked for
- "account" info */
- CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
-
- /* feed cookies into cookie engine */
- CINIT(COOKIELIST, OBJECTPOINT, 135),
-
- /* ignore Content-Length */
- CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
-
- /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
- response. Typically used for FTP-SSL purposes but is not restricted to
- that. libcurl will then instead use the same IP address it used for the
- control connection. */
- CINIT(FTP_SKIP_PASV_IP, LONG, 137),
-
- /* Select "file method" to use when doing FTP, see the curl_ftpmethod
- above. */
- CINIT(FTP_FILEMETHOD, LONG, 138),
-
- /* Local port number to bind the socket to */
- CINIT(LOCALPORT, LONG, 139),
-
- /* Number of ports to try, including the first one set with LOCALPORT.
- Thus, setting it to 1 will make no additional attempts but the first.
- */
- CINIT(LOCALPORTRANGE, LONG, 140),
-
- /* no transfer, set up connection and let application use the socket by
- extracting it with CURLINFO_LASTSOCKET */
- CINIT(CONNECT_ONLY, LONG, 141),
-
- /* Function that will be called to convert from the
- network encoding (instead of using the iconv calls in libcurl) */
- CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
-
- /* Function that will be called to convert to the
- network encoding (instead of using the iconv calls in libcurl) */
- CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
-
- /* Function that will be called to convert from UTF8
- (instead of using the iconv calls in libcurl)
- Note that this is used only for SSL certificate processing */
- CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
-
- /* if the connection proceeds too quickly then need to slow it down */
- /* limit-rate: maximum number of bytes per second to send or receive */
- CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
- CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
-
- /* Pointer to command string to send if USER/PASS fails. */
- CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
-
- /* callback function for setting socket options */
- CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
- CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
-
- /* set to 0 to disable session ID re-use for this transfer, default is
- enabled (== 1) */
- CINIT(SSL_SESSIONID_CACHE, LONG, 150),
-
- /* allowed SSH authentication methods */
- CINIT(SSH_AUTH_TYPES, LONG, 151),
-
- /* Used by scp/sftp to do public/private key authentication */
- CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
- CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
-
- /* Send CCC (Clear Command Channel) after authentication */
- CINIT(FTP_SSL_CCC, LONG, 154),
-
- CURLOPT_LASTENTRY /* the last unused */
-} CURLoption;
-
- /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
- name resolves addresses using more than one IP protocol version, this
- option might be handy to force libcurl to use a specific IP version. */
-#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
- versions that your system allows */
-#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */
-#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */
-
- /* three convenient "aliases" that follow the name scheme better */
-#define CURLOPT_WRITEDATA CURLOPT_FILE
-#define CURLOPT_READDATA CURLOPT_INFILE
-#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
-
-#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
- the obsolete stuff removed! */
-#else
-/* This is set if CURL_NO_OLDIES is defined at compile-time */
-#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
-#endif
-
-
- /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
-enum {
- CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
- like the library to choose the best possible
- for us! */
- CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
- CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
-
- CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
-};
-
- /* These enums are for use with the CURLOPT_NETRC option. */
-enum CURL_NETRC_OPTION {
- CURL_NETRC_IGNORED, /* The .netrc will never be read.
- * This is the default. */
- CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred
- * to one in the .netrc. */
- CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored.
- * Unless one is set programmatically, the .netrc
- * will be queried. */
- CURL_NETRC_LAST
-};
-
-enum {
- CURL_SSLVERSION_DEFAULT,
- CURL_SSLVERSION_TLSv1,
- CURL_SSLVERSION_SSLv2,
- CURL_SSLVERSION_SSLv3,
-
- CURL_SSLVERSION_LAST /* never use, keep last */
-};
-
-
-typedef enum {
- CURL_TIMECOND_NONE,
-
- CURL_TIMECOND_IFMODSINCE,
- CURL_TIMECOND_IFUNMODSINCE,
- CURL_TIMECOND_LASTMOD,
-
- CURL_TIMECOND_LAST
-} curl_TimeCond;
-
-#ifdef __cplusplus
-}
-#endif
-
-#if defined __BEOS__ || defined __HAIKU__
-#include <support/SupportDefs.h>
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* curl_strequal() and curl_strnequal() are subject for removal in a future
- libcurl, see lib/README.curlx for details */
-CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
-CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
-
-/* name is uppercase CURLFORM_<name> */
-#ifdef CFINIT
-#undef CFINIT
-#endif
-
-#ifdef CURL_ISOCPP
-#define CFINIT(name) CURLFORM_ ## name
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define CFINIT(name) CURLFORM_/**/name
-#endif
-
-typedef enum {
- CFINIT(NOTHING), /********* the first one is unused ************/
-
- /* */
- CFINIT(COPYNAME),
- CFINIT(PTRNAME),
- CFINIT(NAMELENGTH),
- CFINIT(COPYCONTENTS),
- CFINIT(PTRCONTENTS),
- CFINIT(CONTENTSLENGTH),
- CFINIT(FILECONTENT),
- CFINIT(ARRAY),
- CFINIT(OBSOLETE),
- CFINIT(FILE),
-
- CFINIT(BUFFER),
- CFINIT(BUFFERPTR),
- CFINIT(BUFFERLENGTH),
-
- CFINIT(CONTENTTYPE),
- CFINIT(CONTENTHEADER),
- CFINIT(FILENAME),
- CFINIT(END),
- CFINIT(OBSOLETE2),
-
- CURLFORM_LASTENTRY /* the last unusued */
-} CURLformoption;
-
-#undef CFINIT /* done */
-
-/* structure to be used as parameter for CURLFORM_ARRAY */
-struct curl_forms {
- CURLformoption option;
- const char *value;
-};
-
-/* use this for multipart formpost building */
-/* Returns code for curl_formadd()
- *
- * Returns:
- * CURL_FORMADD_OK on success
- * CURL_FORMADD_MEMORY if the FormInfo allocation fails
- * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
- * CURL_FORMADD_NULL if a null pointer was given for a char
- * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
- * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
- * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
- * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
- * CURL_FORMADD_MEMORY if some allocation for string copying failed.
- * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
- *
- ***************************************************************************/
-typedef enum {
- CURL_FORMADD_OK, /* first, no error */
-
- CURL_FORMADD_MEMORY,
- CURL_FORMADD_OPTION_TWICE,
- CURL_FORMADD_NULL,
- CURL_FORMADD_UNKNOWN_OPTION,
- CURL_FORMADD_INCOMPLETE,
- CURL_FORMADD_ILLEGAL_ARRAY,
- CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
-
- CURL_FORMADD_LAST /* last */
-} CURLFORMcode;
-
-/*
- * NAME curl_formadd()
- *
- * DESCRIPTION
- *
- * Pretty advanved function for building multi-part formposts. Each invoke
- * adds one part that together construct a full post. Then use
- * CURLOPT_HTTPPOST to send it off to libcurl.
- */
-CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...);
-
-/*
- * callback function for curl_formget()
- * The void *arg pointer will be the one passed as second argument to curl_formget().
- * The character buffer passed to it must not be freed.
- * Should return the buffer length passed to it as the argument "len" on success.
- */
-typedef size_t (*curl_formget_callback)(void *arg, const char *buf, size_t len);
-
-/*
- * NAME curl_formget()
- *
- * DESCRIPTION
- *
- * Serialize a curl_httppost struct built with curl_formadd().
- * Accepts a void pointer as second argument which will be passed to
- * the curl_formget_callback function.
- * Returns 0 on success.
- */
-CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
- curl_formget_callback append);
-/*
- * NAME curl_formfree()
- *
- * DESCRIPTION
- *
- * Free a multipart formpost previously built with curl_formadd().
- */
-CURL_EXTERN void curl_formfree(struct curl_httppost *form);
-
-/*
- * NAME curl_getenv()
- *
- * DESCRIPTION
- *
- * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
- * complete. DEPRECATED - see lib/README.curlx
- */
-CURL_EXTERN char *curl_getenv(const char *variable);
-
-/*
- * NAME curl_version()
- *
- * DESCRIPTION
- *
- * Returns a static ascii string of the libcurl version.
- */
-CURL_EXTERN char *curl_version(void);
-
-/*
- * NAME curl_easy_escape()
- *
- * DESCRIPTION
- *
- * Escapes URL strings (converts all letters consider illegal in URLs to their
- * %XX versions). This function returns a new allocated string or NULL if an
- * error occurred.
- */
-CURL_EXTERN char *curl_easy_escape(CURL *handle,
- const char *string,
- int length);
-
-/* the previous version: */
-CURL_EXTERN char *curl_escape(const char *string,
- int length);
-
-
-/*
- * NAME curl_easy_unescape()
- *
- * DESCRIPTION
- *
- * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
- * versions). This function returns a new allocated string or NULL if an error
- * occurred.
- * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
- * converted into the host encoding.
- */
-CURL_EXTERN char *curl_easy_unescape(CURL *handle,
- const char *string,
- int length,
- int *outlength);
-
-/* the previous version */
-CURL_EXTERN char *curl_unescape(const char *string,
- int length);
-
-/*
- * NAME curl_free()
- *
- * DESCRIPTION
- *
- * Provided for de-allocation in the same translation unit that did the
- * allocation. Added in libcurl 7.10
- */
-CURL_EXTERN void curl_free(void *p);
-
-/*
- * NAME curl_global_init()
- *
- * DESCRIPTION
- *
- * curl_global_init() should be invoked exactly once for each application that
- * uses libcurl
- */
-CURL_EXTERN CURLcode curl_global_init(long flags);
-
-/*
- * NAME curl_global_init_mem()
- *
- * DESCRIPTION
- *
- * curl_global_init() or curl_global_init_mem() should be invoked exactly once
- * for each application that uses libcurl. This function can be used to
- * initialize libcurl and set user defined memory management callback
- * functions. Users can implement memory management routines to check for
- * memory leaks, check for mis-use of the curl library etc. User registered
- * callback routines with be invoked by this library instead of the system
- * memory management routines like malloc, free etc.
- */
-CURL_EXTERN CURLcode curl_global_init_mem(long flags,
- curl_malloc_callback m,
- curl_free_callback f,
- curl_realloc_callback r,
- curl_strdup_callback s,
- curl_calloc_callback c);
-
-/*
- * NAME curl_global_cleanup()
- *
- * DESCRIPTION
- *
- * curl_global_cleanup() should be invoked exactly once for each application
- * that uses libcurl
- */
-CURL_EXTERN void curl_global_cleanup(void);
-
-/* linked-list structure for the CURLOPT_QUOTE option (and other) */
-struct curl_slist {
- char *data;
- struct curl_slist *next;
-};
-
-/*
- * NAME curl_slist_append()
- *
- * DESCRIPTION
- *
- * Appends a string to a linked list. If no list exists, it will be created
- * first. Returns the new list, after appending.
- */
-CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
- const char *);
-
-/*
- * NAME curl_slist_free_all()
- *
- * DESCRIPTION
- *
- * free a previously built curl_slist.
- */
-CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
-
-/*
- * NAME curl_getdate()
- *
- * DESCRIPTION
- *
- * Returns the time, in seconds since 1 Jan 1970 of the time string given in
- * the first argument. The time argument in the second parameter is unused
- * and should be set to NULL.
- */
-CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
-
-#define CURLINFO_STRING 0x100000
-#define CURLINFO_LONG 0x200000
-#define CURLINFO_DOUBLE 0x300000
-#define CURLINFO_SLIST 0x400000
-#define CURLINFO_MASK 0x0fffff
-#define CURLINFO_TYPEMASK 0xf00000
-
-typedef enum {
- CURLINFO_NONE, /* first, never use this */
- CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1,
- CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
- CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3,
- CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
- CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
- CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
- CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7,
- CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8,
- CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9,
- CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10,
- CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11,
- CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
- CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
- CURLINFO_FILETIME = CURLINFO_LONG + 14,
- CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
- CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
- CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
- CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
- CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
- CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
- CURLINFO_PRIVATE = CURLINFO_STRING + 21,
- CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22,
- CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23,
- CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24,
- CURLINFO_OS_ERRNO = CURLINFO_LONG + 25,
- CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
- CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
- CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
- CURLINFO_LASTSOCKET = CURLINFO_LONG + 29,
- CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30,
- /* Fill in new entries below here! */
-
- CURLINFO_LASTONE = 30
-} CURLINFO;
-
-/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
- CURLINFO_HTTP_CODE */
-#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
-
-typedef enum {
- CURLCLOSEPOLICY_NONE, /* first, never use this */
-
- CURLCLOSEPOLICY_OLDEST,
- CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
- CURLCLOSEPOLICY_LEAST_TRAFFIC,
- CURLCLOSEPOLICY_SLOWEST,
- CURLCLOSEPOLICY_CALLBACK,
-
- CURLCLOSEPOLICY_LAST /* last, never use this */
-} curl_closepolicy;
-
-#define CURL_GLOBAL_SSL (1<<0)
-#define CURL_GLOBAL_WIN32 (1<<1)
-#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
-#define CURL_GLOBAL_NOTHING 0
-#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
-
-
-/*****************************************************************************
- * Setup defines, protos etc for the sharing stuff.
- */
-
-/* Different data locks for a single share */
-typedef enum {
- CURL_LOCK_DATA_NONE = 0,
- /* CURL_LOCK_DATA_SHARE is used internaly to say that
- * the locking is just made to change the internal state of the share
- * itself.
- */
- CURL_LOCK_DATA_SHARE,
- CURL_LOCK_DATA_COOKIE,
- CURL_LOCK_DATA_DNS,
- CURL_LOCK_DATA_SSL_SESSION,
- CURL_LOCK_DATA_CONNECT,
- CURL_LOCK_DATA_LAST
-} curl_lock_data;
-
-/* Different lock access types */
-typedef enum {
- CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */
- CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
- CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
- CURL_LOCK_ACCESS_LAST /* never use */
-} curl_lock_access;
-
-typedef void (*curl_lock_function)(CURL *handle,
- curl_lock_data data,
- curl_lock_access locktype,
- void *userptr);
-typedef void (*curl_unlock_function)(CURL *handle,
- curl_lock_data data,
- void *userptr);
-
-typedef void CURLSH;
-
-typedef enum {
- CURLSHE_OK, /* all is fine */
- CURLSHE_BAD_OPTION, /* 1 */
- CURLSHE_IN_USE, /* 2 */
- CURLSHE_INVALID, /* 3 */
- CURLSHE_NOMEM, /* out of memory */
- CURLSHE_LAST /* never use */
-} CURLSHcode;
-
-typedef enum {
- CURLSHOPT_NONE, /* don't use */
- CURLSHOPT_SHARE, /* specify a data type to share */
- CURLSHOPT_UNSHARE, /* specify shich data type to stop sharing */
- CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
- CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
- CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock
- callback functions */
- CURLSHOPT_LAST /* never use */
-} CURLSHoption;
-
-CURL_EXTERN CURLSH *curl_share_init(void);
-CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
-CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
-
-/****************************************************************************
- * Structures for querying information about the curl library at runtime.
- */
-
-typedef enum {
- CURLVERSION_FIRST,
- CURLVERSION_SECOND,
- CURLVERSION_THIRD,
- CURLVERSION_FOURTH,
- CURLVERSION_LAST /* never actually use this */
-} CURLversion;
-
-/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
- basicly all programs ever, that want to get version information. It is
- meant to be a built-in version number for what kind of struct the caller
- expects. If the struct ever changes, we redefine the NOW to another enum
- from above. */
-#define CURLVERSION_NOW CURLVERSION_FOURTH
-
-typedef struct {
- CURLversion age; /* age of the returned struct */
- const char *version; /* LIBCURL_VERSION */
- unsigned int version_num; /* LIBCURL_VERSION_NUM */
- const char *host; /* OS/host/cpu/machine when configured */
- int features; /* bitmask, see defines below */
- const char *ssl_version; /* human readable string */
- long ssl_version_num; /* not used anymore, always 0 */
- const char *libz_version; /* human readable string */
- /* protocols is terminated by an entry with a NULL protoname */
- const char * const *protocols;
-
- /* The fields below this were added in CURLVERSION_SECOND */
- const char *ares;
- int ares_num;
-
- /* This field was added in CURLVERSION_THIRD */
- const char *libidn;
-
- /* These field were added in CURLVERSION_FOURTH */
-
- /* Same as '_libiconv_version' if built with HAVE_ICONV */
- int iconv_ver_num;
-
- const char *libssh_version; /* human readable string */
-
-} curl_version_info_data;
-
-#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
-#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */
-#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
-#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
-#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
-#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
-#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */
-#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */
-#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */
-#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */
-#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */
-#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */
-#define CURL_VERSION_CONV (1<<12) /* character conversions are
- supported */
-
-/*
- * NAME curl_version_info()
- *
- * DESCRIPTION
- *
- * This function returns a pointer to a static copy of the version info
- * struct. See above.
- */
-CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
-
-/*
- * NAME curl_easy_strerror()
- *
- * DESCRIPTION
- *
- * The curl_easy_strerror function may be used to turn a CURLcode value
- * into the equivalent human readable error string. This is useful
- * for printing meaningful error messages.
- */
-CURL_EXTERN const char *curl_easy_strerror(CURLcode);
-
-/*
- * NAME curl_share_strerror()
- *
- * DESCRIPTION
- *
- * The curl_share_strerror function may be used to turn a CURLSHcode value
- * into the equivalent human readable error string. This is useful
- * for printing meaningful error messages.
- */
-CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
-
-#ifdef __cplusplus
-}
-#endif
-
-/* unfortunately, the easy.h and multi.h include files need options and info
- stuff before they can be included! */
-#include "easy.h" /* nothing in curl is fun without the easy stuff */
-#include "multi.h"
-
-#endif /* __CURL_CURL_H */
diff --git a/Utilities/cmcurl/curl/curlver.h b/Utilities/cmcurl/curl/curlver.h
deleted file mode 100644
index 938002285..000000000
--- a/Utilities/cmcurl/curl/curlver.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __CURL_CURLVER_H
-#define __CURL_CURLVER_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* This header file contains nothing but libcurl version info, generated by
- a script at release-time. This was made its own header file in 7.11.2 */
-
-/* This is the version number of the libcurl package from which this header
- file origins: */
-#define LIBCURL_VERSION "7.16.1"
-
-/* The numeric version number is also available "in parts" by using these
- defines: */
-#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 16
-#define LIBCURL_VERSION_PATCH 1
-
-/* This is the numeric version of the libcurl version number, meant for easier
- parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
- always follow this syntax:
-
- 0xXXYYZZ
-
- Where XX, YY and ZZ are the main version, release and patch numbers in
- hexadecimal (using 8 bits each). All three numbers are always represented
- using two digits. 1.2 would appear as "0x010200" while version 9.11.7
- appears as "0x090b07".
-
- This 6-digit (24 bits) hexadecimal number does not show pre-release number,
- and it is always a greater number in a more recent release. It makes
- comparisons with greater than and less than work.
-*/
-#define LIBCURL_VERSION_NUM 0x071001
-
-#endif /* __CURL_CURLVER_H */
diff --git a/Utilities/cmcurl/curl/easy.h b/Utilities/cmcurl/curl/easy.h
deleted file mode 100644
index 17de21070..000000000
--- a/Utilities/cmcurl/curl/easy.h
+++ /dev/null
@@ -1,81 +0,0 @@
-#ifndef __CURL_EASY_H
-#define __CURL_EASY_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-CURL_EXTERN CURL *curl_easy_init(void);
-CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
-CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
-CURL_EXTERN void curl_easy_cleanup(CURL *curl);
-
-/*
- * NAME curl_easy_getinfo()
- *
- * DESCRIPTION
- *
- * Request internal information from the curl session with this function. The
- * third argument MUST be a pointer to a long, a pointer to a char * or a
- * pointer to a double (as the documentation describes elsewhere). The data
- * pointed to will be filled in accordingly and can be relied upon only if the
- * function returns CURLE_OK. This function is intended to get used *AFTER* a
- * performed transfer, all results from this function are undefined until the
- * transfer is completed.
- */
-CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
-
-
-/*
- * NAME curl_easy_duphandle()
- *
- * DESCRIPTION
- *
- * Creates a new curl session handle with the same options set for the handle
- * passed in. Duplicating a handle could only be a matter of cloning data and
- * options, internal state info and things like persistant connections cannot
- * be transfered. It is useful in multithreaded applications when you can run
- * curl_easy_duphandle() for each new thread to avoid a series of identical
- * curl_easy_setopt() invokes in every thread.
- */
-CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
-
-/*
- * NAME curl_easy_reset()
- *
- * DESCRIPTION
- *
- * Re-initializes a CURL handle to the default values. This puts back the
- * handle to the same state as it was in when it was just created.
- *
- * It does keep: live connections, the Session ID cache, the DNS cache and the
- * cookies.
- */
-CURL_EXTERN void curl_easy_reset(CURL *curl);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/curl/mprintf.h b/Utilities/cmcurl/curl/mprintf.h
deleted file mode 100644
index 5c526882f..000000000
--- a/Utilities/cmcurl/curl/mprintf.h
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef __CURL_MPRINTF_H
-#define __CURL_MPRINTF_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <stdarg.h>
-#include <stdio.h> /* needed for FILE */
-
-#include "curl.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-CURL_EXTERN int curl_mprintf(const char *format, ...);
-CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
-CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
-CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...);
-CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
-CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
-CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
-CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format, va_list args);
-CURL_EXTERN char *curl_maprintf(const char *format, ...);
-CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
-
-#ifdef _MPRINTF_REPLACE
-# undef printf
-# undef fprintf
-# undef sprintf
-# undef vsprintf
-# undef snprintf
-# undef vprintf
-# undef vfprintf
-# undef vsnprintf
-# undef aprintf
-# undef vaprintf
-# define printf curl_mprintf
-# define fprintf curl_mfprintf
-#ifdef CURLDEBUG
-/* When built with CURLDEBUG we define away the sprintf() functions since we
- don't want internal code to be using them */
-# define sprintf sprintf_was_used
-# define vsprintf vsprintf_was_used
-#else
-# define sprintf curl_msprintf
-# define vsprintf curl_mvsprintf
-#endif
-# define snprintf curl_msnprintf
-# define vprintf curl_mvprintf
-# define vfprintf curl_mvfprintf
-# define vsnprintf curl_mvsnprintf
-# define aprintf curl_maprintf
-# define vaprintf curl_mvaprintf
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __CURL_MPRINTF_H */
diff --git a/Utilities/cmcurl/curl/multi.h b/Utilities/cmcurl/curl/multi.h
deleted file mode 100644
index 1b6674768..000000000
--- a/Utilities/cmcurl/curl/multi.h
+++ /dev/null
@@ -1,327 +0,0 @@
-#ifndef __CURL_MULTI_H
-#define __CURL_MULTI_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-/*
- This is an "external" header file. Don't give away any internals here!
-
- GOALS
-
- o Enable a "pull" interface. The application that uses libcurl decides where
- and when to ask libcurl to get/send data.
-
- o Enable multiple simultaneous transfers in the same thread without making it
- complicated for the application.
-
- o Enable the application to select() on its own file descriptors and curl's
- file descriptors simultaneous easily.
-
-*/
-
-/*
- * This header file should not really need to include "curl.h" since curl.h
- * itself includes this file and we expect user applications to do #include
- * <curl/curl.h> without the need for especially including multi.h.
- *
- * For some reason we added this include here at one point, and rather than to
- * break existing (wrongly written) libcurl applications, we leave it as-is
- * but with this warning attached.
- */
-#include "curl.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void CURLM;
-
-typedef enum {
- CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
- curl_multi_socket*() soon */
- CURLM_OK,
- CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
- CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
- CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
- CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
- CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
- CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
- CURLM_LAST
-} CURLMcode;
-
-/* just to make code nicer when using curl_multi_socket() you can now check
- for CURLM_CALL_MULTI_SOCKET too in the same style it works for
- curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
-#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
-
-typedef enum {
- CURLMSG_NONE, /* first, not used */
- CURLMSG_DONE, /* This easy handle has completed. 'result' contains
- the CURLcode of the transfer */
- CURLMSG_LAST /* last, not used */
-} CURLMSG;
-
-struct CURLMsg {
- CURLMSG msg; /* what this message means */
- CURL *easy_handle; /* the handle it concerns */
- union {
- void *whatever; /* message-specific data */
- CURLcode result; /* return code for transfer */
- } data;
-};
-typedef struct CURLMsg CURLMsg;
-
-/*
- * Name: curl_multi_init()
- *
- * Desc: inititalize multi-style curl usage
- *
- * Returns: a new CURLM handle to use in all 'curl_multi' functions.
- */
-CURL_EXTERN CURLM *curl_multi_init(void);
-
-/*
- * Name: curl_multi_add_handle()
- *
- * Desc: add a standard curl handle to the multi stack
- *
- * Returns: CURLMcode type, general multi error code.
- */
-CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
- CURL *curl_handle);
-
- /*
- * Name: curl_multi_remove_handle()
- *
- * Desc: removes a curl handle from the multi stack again
- *
- * Returns: CURLMcode type, general multi error code.
- */
-CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
- CURL *curl_handle);
-
- /*
- * Name: curl_multi_fdset()
- *
- * Desc: Ask curl for its fd_set sets. The app can use these to select() or
- * poll() on. We want curl_multi_perform() called as soon as one of
- * them are ready.
- *
- * Returns: CURLMcode type, general multi error code.
- */
-CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- fd_set *exc_fd_set,
- int *max_fd);
-
- /*
- * Name: curl_multi_perform()
- *
- * Desc: When the app thinks there's data available for curl it calls this
- * function to read/write whatever there is right now. This returns
- * as soon as the reads and writes are done. This function does not
- * require that there actually is data available for reading or that
- * data can be written, it can be called just in case. It returns
- * the number of handles that still transfer data in the second
- * argument's integer-pointer.
- *
- * Returns: CURLMcode type, general multi error code. *NOTE* that this only
- * returns errors etc regarding the whole multi stack. There might
- * still have occurred problems on invidual transfers even when this
- * returns OK.
- */
-CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
- int *running_handles);
-
- /*
- * Name: curl_multi_cleanup()
- *
- * Desc: Cleans up and removes a whole multi stack. It does not free or
- * touch any individual easy handles in any way. We need to define
- * in what state those handles will be if this function is called
- * in the middle of a transfer.
- *
- * Returns: CURLMcode type, general multi error code.
- */
-CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
-
-/*
- * Name: curl_multi_info_read()
- *
- * Desc: Ask the multi handle if there's any messages/informationals from
- * the individual transfers. Messages include informationals such as
- * error code from the transfer or just the fact that a transfer is
- * completed. More details on these should be written down as well.
- *
- * Repeated calls to this function will return a new struct each
- * time, until a special "end of msgs" struct is returned as a signal
- * that there is no more to get at this point.
- *
- * The data the returned pointer points to will not survive calling
- * curl_multi_cleanup().
- *
- * The 'CURLMsg' struct is meant to be very simple and only contain
- * very basic information. If more involved information is wanted,
- * we will provide the particular "transfer handle" in that struct
- * and that should/could/would be used in subsequent
- * curl_easy_getinfo() calls (or similar). The point being that we
- * must never expose complex structs to applications, as then we'll
- * undoubtably get backwards compatibility problems in the future.
- *
- * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
- * of structs. It also writes the number of messages left in the
- * queue (after this read) in the integer the second argument points
- * to.
- */
-CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
- int *msgs_in_queue);
-
-/*
- * Name: curl_multi_strerror()
- *
- * Desc: The curl_multi_strerror function may be used to turn a CURLMcode
- * value into the equivalent human readable error string. This is
- * useful for printing meaningful error messages.
- *
- * Returns: A pointer to a zero-terminated error message.
- */
-CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
-
-/*
- * Name: curl_multi_socket() and
- * curl_multi_socket_all()
- *
- * Desc: An alternative version of curl_multi_perform() that allows the
- * application to pass in one of the file descriptors that have been
- * detected to have "action" on them and let libcurl perform.
- * See man page for details.
- */
-#define CURL_POLL_NONE 0
-#define CURL_POLL_IN 1
-#define CURL_POLL_OUT 2
-#define CURL_POLL_INOUT 3
-#define CURL_POLL_REMOVE 4
-
-#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
-
-typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
- curl_socket_t s, /* socket */
- int what, /* see above */
- void *userp, /* private callback
- pointer */
- void *socketp); /* private socket
- pointer */
-/*
- * Name: curl_multi_timer_callback
- *
- * Desc: Called by libcurl whenever the library detects a change in the
- * maximum number of milliseconds the app is allowed to wait before
- * curl_multi_socket() or curl_multi_perform() must be called
- * (to allow libcurl's timed events to take place).
- *
- * Returns: The callback should return zero.
- */
-typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
- long timeout_ms, /* see above */
- void *userp); /* private callback
- pointer */
-
-CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
- int *running_handles);
-
-CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
- int *running_handles);
-
-/*
- * Name: curl_multi_timeout()
- *
- * Desc: Returns the maximum number of milliseconds the app is allowed to
- * wait before curl_multi_socket() or curl_multi_perform() must be
- * called (to allow libcurl's timed events to take place).
- *
- * Returns: CURLM error code.
- */
-CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
- long *milliseconds);
-
-#undef CINIT /* re-using the same name as in curl.h */
-
-#ifdef CURL_ISOCPP
-#define CINIT(name,type,number) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + number
-#else
-/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
-#define LONG CURLOPTTYPE_LONG
-#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
-#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
-#define OFF_T CURLOPTTYPE_OFF_T
-#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
-#endif
-
-typedef enum {
- /* This is the socket callback function pointer */
- CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
-
- /* This is the argument passed to the socket callback */
- CINIT(SOCKETDATA, OBJECTPOINT, 2),
-
- /* set to 1 to enable pipelining for this multi handle */
- CINIT(PIPELINING, LONG, 3),
-
- /* This is the timer callback function pointer */
- CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
-
- /* This is the argument passed to the timer callback */
- CINIT(TIMERDATA, OBJECTPOINT, 5),
-
- CURLMOPT_LASTENTRY /* the last unused */
-} CURLMoption;
-
-
-/*
- * Name: curl_multi_setopt()
- *
- * Desc: Sets options for the multi handle.
- *
- * Returns: CURLM error code.
- */
-CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
- CURLMoption option, ...);
-
-
-/*
- * Name: curl_multi_assign()
- *
- * Desc: This function sets an association in the multi handle between the
- * given socket and a private pointer of the application. This is
- * (only) useful for curl_multi_socket uses.
- *
- * Returns: CURLM error code.
- */
-CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
- curl_socket_t sockfd, void *sockp);
-
-#ifdef __cplusplus
-} /* end of extern "C" */
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/curl/stdcheaders.h b/Utilities/cmcurl/curl/stdcheaders.h
deleted file mode 100644
index 11c1e2f6e..000000000
--- a/Utilities/cmcurl/curl/stdcheaders.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __STDC_HEADERS_H
-#define __STDC_HEADERS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <sys/types.h>
-
-size_t fread (void *, size_t, size_t, FILE *);
-size_t fwrite (const void *, size_t, size_t, FILE *);
-
-int strcasecmp(const char *, const char *);
-int strncasecmp(const char *, const char *, size_t);
-
-#endif
diff --git a/Utilities/cmcurl/curl/types.h b/Utilities/cmcurl/curl/types.h
deleted file mode 100644
index d37d6ae9e..000000000
--- a/Utilities/cmcurl/curl/types.h
+++ /dev/null
@@ -1 +0,0 @@
-/* not used */
diff --git a/Utilities/cmcurl/Testing/curltest.c b/Utilities/cmcurl/curltest.c
index 210868e36..210868e36 100644
--- a/Utilities/cmcurl/Testing/curltest.c
+++ b/Utilities/cmcurl/curltest.c
diff --git a/Utilities/cmcurl/curlx.h b/Utilities/cmcurl/curlx.h
deleted file mode 100644
index 26948d305..000000000
--- a/Utilities/cmcurl/curlx.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef __CURLX_H
-#define __CURLX_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * Defines protos and includes all header files that provide the curlx_*
- * functions. The curlx_* functions are not part of the libcurl API, but are
- * stand-alone functions whose sources can be built and linked by apps if need
- * be.
- */
-
-#include <curl/mprintf.h>
-/* this is still a public header file that provides the curl_mprintf()
- functions while they still are offered publicly. They will be made library-
- private one day */
-
-#include "strequal.h"
-/* "strequal.h" provides the strequal protos */
-
-#include "strtoofft.h"
-/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
- curl_off_t number from a given string.
-*/
-
-#include "timeval.h"
-/*
- "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
- don't have one and has protos for these functions:
-
- curlx_tvnow()
- curlx_tvdiff()
- curlx_tvdiff_secs()
-*/
-
-/* Now setup curlx_ * names for the functions that are to become curlx_ and
- be removed from a future libcurl official API:
- curlx_getenv
- curlx_mprintf (and its variations)
- curlx_strequal
- curlx_strnequal
-
-*/
-
-#define curlx_getenv curl_getenv
-#define curlx_strequal curl_strequal
-#define curlx_strnequal curl_strnequal
-#define curlx_mvsnprintf curl_mvsnprintf
-#define curlx_msnprintf curl_msnprintf
-#define curlx_maprintf curl_maprintf
-#define curlx_mvaprintf curl_mvaprintf
-#define curlx_msprintf curl_msprintf
-#define curlx_mprintf curl_mprintf
-#define curlx_mfprintf curl_mfprintf
-#define curlx_mvsprintf curl_mvsprintf
-#define curlx_mvprintf curl_mvprintf
-#define curlx_mvfprintf curl_mvfprintf
-
-#ifdef ENABLE_CURLX_PRINTF
-/* If this define is set, we define all "standard" printf() functions to use
- the curlx_* version instead. It makes the source code transparant and
- easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE
- is set. */
-# undef printf
-# undef fprintf
-# undef sprintf
-# undef snprintf
-# undef vprintf
-# undef vfprintf
-# undef vsprintf
-# undef vsnprintf
-# undef aprintf
-# undef vaprintf
-
-# define printf curlx_mprintf
-# define fprintf curlx_mfprintf
-# define sprintf curlx_msprintf
-# define snprintf curlx_msnprintf
-# define vprintf curlx_mvprintf
-# define vfprintf curlx_mvfprintf
-# define vsprintf curlx_mvsprintf
-# define vsnprintf curlx_mvsnprintf
-# define aprintf curlx_maprintf
-# define vaprintf curlx_mvaprintf
-#endif /* ENABLE_CURLX_PRINTF */
-
-#endif /* __CURLX_H */
diff --git a/Utilities/cmcurl/dict.c b/Utilities/cmcurl/dict.c
deleted file mode 100644
index d6443f4b9..000000000
--- a/Utilities/cmcurl/dict.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_DICT
-
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "transfer.h"
-#include "sendf.h"
-
-#include "progress.h"
-#include "strequal.h"
-#include "dict.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-static char *unescape_word(struct SessionHandle *data, char *inp)
-{
- char *newp;
- char *dictp;
- char *ptr;
- int len;
- unsigned char byte;
- int olen=0;
-
- newp = curl_easy_unescape(data, inp, 0, &len);
- if(!newp)
- return NULL;
-
- dictp = malloc(len*2 + 1); /* add one for terminating zero */
- if(dictp) {
- /* According to RFC2229 section 2.2, these letters need to be escaped with
- \[letter] */
- for(ptr = newp;
- (byte = (unsigned char)*ptr) != 0;
- ptr++) {
- if ((byte <= 32) || (byte == 127) ||
- (byte == '\'') || (byte == '\"') || (byte == '\\')) {
- dictp[olen++] = '\\';
- }
- dictp[olen++] = byte;
- }
- dictp[olen]=0;
-
- free(newp);
- }
- return dictp;
-}
-
-CURLcode Curl_dict(struct connectdata *conn, bool *done)
-{
- char *word;
- char *eword;
- char *ppath;
- char *database = NULL;
- char *strategy = NULL;
- char *nthdef = NULL; /* This is not part of the protocol, but required
- by RFC 2229 */
- CURLcode result=CURLE_OK;
- struct SessionHandle *data=conn->data;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-
- char *path = data->reqdata.path;
- curl_off_t *bytecount = &data->reqdata.keep.bytecount;
-
- *done = TRUE; /* unconditionally */
-
- if(conn->bits.user_passwd) {
- /* AUTH is missing */
- }
-
- if (strnequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
- strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
- strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
-
- word = strchr(path, ':');
- if (word) {
- word++;
- database = strchr(word, ':');
- if (database) {
- *database++ = (char)0;
- strategy = strchr(database, ':');
- if (strategy) {
- *strategy++ = (char)0;
- nthdef = strchr(strategy, ':');
- if (nthdef) {
- *nthdef++ = (char)0;
- }
- }
- }
- }
-
- if ((word == NULL) || (*word == (char)0)) {
- failf(data, "lookup word is missing");
- }
- if ((database == NULL) || (*database == (char)0)) {
- database = (char *)"!";
- }
- if ((strategy == NULL) || (*strategy == (char)0)) {
- strategy = (char *)".";
- }
-
- eword = unescape_word(data, word);
- if(!eword)
- return CURLE_OUT_OF_MEMORY;
-
- result = Curl_sendf(sockfd, conn,
- "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
- "MATCH "
- "%s " /* database */
- "%s " /* strategy */
- "%s\r\n" /* word */
- "QUIT\r\n",
-
- database,
- strategy,
- eword
- );
-
- free(eword);
-
- if(result)
- failf(data, "Failed sending DICT request");
- else
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL); /* no upload */
- if(result)
- return result;
- }
- else if (strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
- strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
- strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
-
- word = strchr(path, ':');
- if (word) {
- word++;
- database = strchr(word, ':');
- if (database) {
- *database++ = (char)0;
- nthdef = strchr(database, ':');
- if (nthdef) {
- *nthdef++ = (char)0;
- }
- }
- }
-
- if ((word == NULL) || (*word == (char)0)) {
- failf(data, "lookup word is missing");
- }
- if ((database == NULL) || (*database == (char)0)) {
- database = (char *)"!";
- }
-
- eword = unescape_word(data, word);
- if(!eword)
- return CURLE_OUT_OF_MEMORY;
-
- result = Curl_sendf(sockfd, conn,
- "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
- "DEFINE "
- "%s " /* database */
- "%s\r\n" /* word */
- "QUIT\r\n",
- database,
- eword);
-
- free(eword);
-
- if(result)
- failf(data, "Failed sending DICT request");
- else
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL); /* no upload */
-
- if(result)
- return result;
-
- }
- else {
-
- ppath = strchr(path, '/');
- if (ppath) {
- int i;
-
- ppath++;
- for (i = 0; ppath[i]; i++) {
- if (ppath[i] == ':')
- ppath[i] = ' ';
- }
- result = Curl_sendf(sockfd, conn,
- "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
- "%s\r\n"
- "QUIT\r\n", ppath);
- if(result)
- failf(data, "Failed sending DICT request");
- else
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
- -1, NULL);
- if(result)
- return result;
- }
- }
-
- return CURLE_OK;
-}
-#endif /*CURL_DISABLE_DICT*/
diff --git a/Utilities/cmcurl/dict.h b/Utilities/cmcurl/dict.h
deleted file mode 100644
index d3da1936f..000000000
--- a/Utilities/cmcurl/dict.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __DICT_H
-#define __DICT_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_DICT
-CURLcode Curl_dict(struct connectdata *conn, bool *done);
-CURLcode Curl_dict_done(struct connectdata *conn);
-#endif
-#endif
diff --git a/Utilities/cmcurl/easy.c b/Utilities/cmcurl/easy.c
deleted file mode 100644
index 209d1c3e0..000000000
--- a/Utilities/cmcurl/easy.c
+++ /dev/null
@@ -1,895 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#include <errno.h>
-
-#include "strequal.h"
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#endif /* WIN32 ... */
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "transfer.h"
-#include "sslgen.h"
-#include "url.h"
-#include "getinfo.h"
-#include "hostip.h"
-#include "share.h"
-#include "strdup.h"
-#include "memory.h"
-#include "progress.h"
-#include "easyif.h"
-#include "sendf.h" /* for failf function prototype */
-#include <ca-bundle.h>
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
-#include <iconv.h>
-/* set default codesets for iconv */
-#ifndef CURL_ICONV_CODESET_OF_NETWORK
-#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
-#endif
-#ifndef CURL_ICONV_CODESET_FOR_UTF8
-#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
-#endif
-#define ICONV_ERROR (size_t)-1
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#ifdef USE_WINSOCK
-/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
- of win32_init() */
-static void win32_cleanup(void)
-{
- WSACleanup();
-}
-
-/* win32_init() performs win32 socket initialization to properly setup the
- stack to allow networking */
-static CURLcode win32_init(void)
-{
- WORD wVersionRequested;
- WSADATA wsaData;
- int err;
-
-#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
- Error IPV6_requires_winsock2
-#endif
-
- wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
-
- err = WSAStartup(wVersionRequested, &wsaData);
-
- if (err != 0)
- /* Tell the user that we couldn't find a useable */
- /* winsock.dll. */
- return CURLE_FAILED_INIT;
-
- /* Confirm that the Windows Sockets DLL supports what we need.*/
- /* Note that if the DLL supports versions greater */
- /* than wVersionRequested, it will still return */
- /* wVersionRequested in wVersion. wHighVersion contains the */
- /* highest supported version. */
-
- if ( LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
- HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
- /* Tell the user that we couldn't find a useable */
-
- /* winsock.dll. */
- WSACleanup();
- return CURLE_FAILED_INIT;
- }
- /* The Windows Sockets DLL is acceptable. Proceed. */
- return CURLE_OK;
-}
-
-#else
-/* These functions exist merely to prevent compiler warnings */
-static CURLcode win32_init(void) { return CURLE_OK; }
-static void win32_cleanup(void) { }
-#endif
-
-#ifdef USE_LIBIDN
-/*
- * Initialise use of IDNA library.
- * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
- * idna_to_ascii_lz().
- */
-static void idna_init (void)
-{
-#ifdef WIN32
- char buf[60];
- UINT cp = GetACP();
-
- if (!getenv("CHARSET") && cp > 0) {
- snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
- putenv(buf);
- }
-#else
- /* to do? */
-#endif
-}
-#endif /* USE_LIBIDN */
-
-/* true globals -- for curl_global_init() and curl_global_cleanup() */
-static unsigned int initialized;
-static long init_flags;
-
-/*
- * strdup (and other memory functions) is redefined in complicated
- * ways, but at this point it must be defined as the system-supplied strdup
- * so the callback pointer is initialized correctly.
- */
-#if defined(_WIN32_WCE)
-#define system_strdup _strdup
-#elif !defined(HAVE_STRDUP)
-#define system_strdup curlx_strdup
-#else
-#define system_strdup strdup
-#endif
-
-/*
- * If a memory-using function (like curl_getenv) is used before
- * curl_global_init() is called, we need to have these pointers set already.
- */
-
-curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
-curl_free_callback Curl_cfree = (curl_free_callback)free;
-curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
-curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
-curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
-
-/**
- * curl_global_init() globally initializes cURL given a bitwise set of the
- * different features of what to initialize.
- */
-CURLcode curl_global_init(long flags)
-{
- if (initialized++)
- return CURLE_OK;
-
- /* Setup the default memory functions here (again) */
- Curl_cmalloc = (curl_malloc_callback)malloc;
- Curl_cfree = (curl_free_callback)free;
- Curl_crealloc = (curl_realloc_callback)realloc;
- Curl_cstrdup = (curl_strdup_callback)system_strdup;
- Curl_ccalloc = (curl_calloc_callback)calloc;
-
- if (flags & CURL_GLOBAL_SSL)
- if (!Curl_ssl_init())
- return CURLE_FAILED_INIT;
-
- if (flags & CURL_GLOBAL_WIN32)
- if (win32_init() != CURLE_OK)
- return CURLE_FAILED_INIT;
-
-#ifdef _AMIGASF
- if(!amiga_init())
- return CURLE_FAILED_INIT;
-#endif
-
-#ifdef USE_LIBIDN
- idna_init();
-#endif
-
- init_flags = flags;
-
- return CURLE_OK;
-}
-
-/*
- * curl_global_init_mem() globally initializes cURL and also registers the
- * user provided callback routines.
- */
-CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
- curl_free_callback f, curl_realloc_callback r,
- curl_strdup_callback s, curl_calloc_callback c)
-{
- CURLcode code = CURLE_OK;
-
- /* Invalid input, return immediately */
- if (!m || !f || !r || !s || !c)
- return CURLE_FAILED_INIT;
-
- /* Already initialized, don't do it again */
- if ( initialized )
- return CURLE_OK;
-
- /* Call the actual init function first */
- code = curl_global_init(flags);
- if (code == CURLE_OK) {
- Curl_cmalloc = m;
- Curl_cfree = f;
- Curl_cstrdup = s;
- Curl_crealloc = r;
- Curl_ccalloc = c;
- }
-
- return code;
-}
-
-/**
- * curl_global_cleanup() globally cleanups cURL, uses the value of
- * "init_flags" to determine what needs to be cleaned up and what doesn't.
- */
-void curl_global_cleanup(void)
-{
- if (!initialized)
- return;
-
- if (--initialized)
- return;
-
- Curl_global_host_cache_dtor();
-
- if (init_flags & CURL_GLOBAL_SSL)
- Curl_ssl_cleanup();
-
- if (init_flags & CURL_GLOBAL_WIN32)
- win32_cleanup();
-
-#ifdef _AMIGASF
- amiga_cleanup();
-#endif
-
- init_flags = 0;
-}
-
-/*
- * curl_easy_init() is the external interface to alloc, setup and init an
- * easy handle that is returned. If anything goes wrong, NULL is returned.
- */
-CURL *curl_easy_init(void)
-{
- CURLcode res;
- struct SessionHandle *data;
-
- /* Make sure we inited the global SSL stuff */
- if (!initialized) {
- res = curl_global_init(CURL_GLOBAL_DEFAULT);
- if(res)
- /* something in the global init failed, return nothing */
- return NULL;
- }
-
- /* We use curl_open() with undefined URL so far */
- res = Curl_open(&data);
- if(res != CURLE_OK)
- return NULL;
-
- return data;
-}
-
-/*
- * curl_easy_setopt() is the external interface for setting options on an
- * easy handle.
- */
-
-CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
-{
- va_list arg;
- struct SessionHandle *data = curl;
- CURLcode ret;
-
- if(!curl)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- va_start(arg, tag);
-
- ret = Curl_setopt(data, tag, arg);
-
- va_end(arg);
- return ret;
-}
-
-#ifdef CURL_MULTIEASY
-/***************************************************************************
- * This function is still only for testing purposes. It makes a great way
- * to run the full test suite on the multi interface instead of the easy one.
- ***************************************************************************
- *
- * The *new* curl_easy_perform() is the external interface that performs a
- * transfer previously setup.
- *
- * Wrapper-function that: creates a multi handle, adds the easy handle to it,
- * runs curl_multi_perform() until the transfer is done, then detaches the
- * easy handle, destroys the multi handle and returns the easy handle's return
- * code. This will make everything internally use and assume multi interface.
- */
-CURLcode curl_easy_perform(CURL *easy)
-{
- CURLM *multi;
- CURLMcode mcode;
- CURLcode code = CURLE_OK;
- int still_running;
- struct timeval timeout;
- int rc;
- CURLMsg *msg;
- fd_set fdread;
- fd_set fdwrite;
- fd_set fdexcep;
- int maxfd;
-
- if(!easy)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- multi = curl_multi_init();
- if(!multi)
- return CURLE_OUT_OF_MEMORY;
-
- mcode = curl_multi_add_handle(multi, easy);
- if(mcode) {
- curl_multi_cleanup(multi);
- return CURLE_FAILED_INIT;
- }
-
- /* we start some action by calling perform right away */
-
- do {
- while(CURLM_CALL_MULTI_PERFORM ==
- curl_multi_perform(multi, &still_running));
-
- if(!still_running)
- break;
-
- FD_ZERO(&fdread);
- FD_ZERO(&fdwrite);
- FD_ZERO(&fdexcep);
-
- /* timeout once per second */
- timeout.tv_sec = 1;
- timeout.tv_usec = 0;
-
- /* get file descriptors from the transfers */
- curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
-
- rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
-
- if(rc == -1)
- /* select error */
- break;
-
- /* timeout or data to send/receive => loop! */
- } while(still_running);
-
- msg = curl_multi_info_read(multi, &rc);
- if(msg)
- code = msg->data.result;
-
- mcode = curl_multi_remove_handle(multi, easy);
- /* what to do if it fails? */
-
- mcode = curl_multi_cleanup(multi);
- /* what to do if it fails? */
-
- return code;
-}
-#else
-/*
- * curl_easy_perform() is the external interface that performs a transfer
- * previously setup.
- */
-CURLcode curl_easy_perform(CURL *curl)
-{
- struct SessionHandle *data = (struct SessionHandle *)curl;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- if ( ! (data->share && data->share->hostcache) ) {
-
- if (Curl_global_host_cache_use(data) &&
- (data->dns.hostcachetype != HCACHE_GLOBAL)) {
- if (data->dns.hostcachetype == HCACHE_PRIVATE)
- Curl_hash_destroy(data->dns.hostcache);
- data->dns.hostcache = Curl_global_host_cache_get();
- data->dns.hostcachetype = HCACHE_GLOBAL;
- }
-
- if (!data->dns.hostcache) {
- data->dns.hostcachetype = HCACHE_PRIVATE;
- data->dns.hostcache = Curl_mk_dnscache();
-
- if(!data->dns.hostcache)
- /* While we possibly could survive and do good without a host cache,
- the fact that creating it failed indicates that things are truly
- screwed up and we should bail out! */
- return CURLE_OUT_OF_MEMORY;
- }
-
- }
-
- if(!data->state.connc) {
- /* oops, no connection cache, make one up */
- data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
- if(!data->state.connc)
- return CURLE_OUT_OF_MEMORY;
- }
-
- return Curl_perform(data);
-}
-#endif
-
-/*
- * curl_easy_cleanup() is the external interface to cleaning/freeing the given
- * easy handle.
- */
-void curl_easy_cleanup(CURL *curl)
-{
- struct SessionHandle *data = (struct SessionHandle *)curl;
-
- if(!data)
- return;
-
- Curl_close(data);
-}
-
-/*
- * Store a pointed to the multi handle within the easy handle's data struct.
- */
-void Curl_easy_addmulti(struct SessionHandle *data,
- void *multi)
-{
- data->multi = multi;
-}
-
-void Curl_easy_initHandleData(struct SessionHandle *data)
-{
- memset(&data->reqdata, 0, sizeof(struct HandleData));
-
- data->reqdata.maxdownload = -1;
-}
-
-/*
- * curl_easy_getinfo() is an external interface that allows an app to retrieve
- * information from a performed transfer and similar.
- */
-CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...)
-{
- va_list arg;
- void *paramp;
- struct SessionHandle *data = (struct SessionHandle *)curl;
-
- va_start(arg, info);
- paramp = va_arg(arg, void *);
-
- return Curl_getinfo(data, info, paramp);
-}
-
-/*
- * curl_easy_duphandle() is an external interface to allow duplication of a
- * given input easy handle. The returned handle will be a new working handle
- * with all options set exactly as the input source handle.
- */
-CURL *curl_easy_duphandle(CURL *incurl)
-{
- bool fail = TRUE;
- struct SessionHandle *data=(struct SessionHandle *)incurl;
-
- struct SessionHandle *outcurl = (struct SessionHandle *)
- calloc(sizeof(struct SessionHandle), 1);
-
- if(NULL == outcurl)
- return NULL; /* failure */
-
- do {
-
- /*
- * We setup a few buffers we need. We should probably make them
- * get setup on-demand in the code, as that would probably decrease
- * the likeliness of us forgetting to init a buffer here in the future.
- */
- outcurl->state.headerbuff=(char*)malloc(HEADERSIZE);
- if(!outcurl->state.headerbuff) {
- break;
- }
- outcurl->state.headersize=HEADERSIZE;
-
- /* copy all userdefined values */
- outcurl->set = data->set;
-
- if(data->state.used_interface == Curl_if_multi)
- outcurl->state.connc = data->state.connc;
- else
- outcurl->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, -1);
-
- if(!outcurl->state.connc)
- break;
-
- outcurl->state.lastconnect = -1;
-
- outcurl->progress.flags = data->progress.flags;
- outcurl->progress.callback = data->progress.callback;
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- if(data->cookies) {
- /* If cookies are enabled in the parent handle, we enable them
- in the clone as well! */
- outcurl->cookies = Curl_cookie_init(data,
- data->cookies->filename,
- outcurl->cookies,
- data->set.cookiesession);
- if(!outcurl->cookies) {
- break;
- }
- }
-#endif /* CURL_DISABLE_HTTP */
-
- /* duplicate all values in 'change' */
-
- if(data->change.url) {
- outcurl->change.url = strdup(data->change.url);
- if(!outcurl->change.url)
- break;
- outcurl->change.url_alloc = TRUE;
- }
-
- if(data->change.referer) {
- outcurl->change.referer = strdup(data->change.referer);
- if(!outcurl->change.referer)
- break;
- outcurl->change.referer_alloc = TRUE;
- }
-
-#ifdef USE_ARES
- /* If we use ares, we setup a new ares channel for the new handle */
- if(ARES_SUCCESS != ares_init(&outcurl->state.areschannel))
- break;
-#endif
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
- outcurl->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_OF_NETWORK);
- outcurl->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
- CURL_ICONV_CODESET_OF_HOST);
- outcurl->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_FOR_UTF8);
-#endif
-
- Curl_easy_initHandleData(outcurl);
-
- outcurl->magic = CURLEASY_MAGIC_NUMBER;
-
- fail = FALSE; /* we reach this point and thus we are OK */
-
- } while(0);
-
- if(fail) {
- if(outcurl) {
- if(outcurl->state.connc->type == CONNCACHE_PRIVATE)
- Curl_rm_connc(outcurl->state.connc);
- if(outcurl->state.headerbuff)
- free(outcurl->state.headerbuff);
- if(outcurl->change.url)
- free(outcurl->change.url);
- if(outcurl->change.referer)
- free(outcurl->change.referer);
- free(outcurl); /* free the memory again */
- outcurl = NULL;
- }
- }
-
- return outcurl;
-}
-
-/*
- * curl_easy_reset() is an external interface that allows an app to re-
- * initialize a session handle to the default values.
- */
-void curl_easy_reset(CURL *curl)
-{
- struct SessionHandle *data = (struct SessionHandle *)curl;
-
- Curl_safefree(data->reqdata.pathbuffer);
- data->reqdata.pathbuffer=NULL;
-
- Curl_safefree(data->reqdata.proto.generic);
- data->reqdata.proto.generic=NULL;
-
- /* zero out UserDefined data: */
- memset(&data->set, 0, sizeof(struct UserDefined));
-
- /* zero out Progress data: */
- memset(&data->progress, 0, sizeof(struct Progress));
-
- /* init Handle data */
- Curl_easy_initHandleData(data);
-
- /* The remainder of these calls have been taken from Curl_open() */
-
- data->set.out = stdout; /* default output to stdout */
- data->set.in = stdin; /* default input from stdin */
- data->set.err = stderr; /* default stderr to stderr */
-
- /* use fwrite as default function to store output */
- data->set.fwrite = (curl_write_callback)fwrite;
-
- /* use fread as default function to read input */
- data->set.fread = (curl_read_callback)fread;
-
- data->set.infilesize = -1; /* we don't know any size */
- data->set.postfieldsize = -1;
-
- data->state.current_speed = -1; /* init to negative == impossible */
-
- data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
- data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
- data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
-
- data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
-
- /* make libcurl quiet by default: */
- data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
- data->progress.flags |= PGRS_HIDE;
-
- /* Set the default size of the SSL session ID cache */
- data->set.ssl.numsessions = 5;
-
- data->set.proxyport = 1080;
- data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
- data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */
- data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
-
- /*
- * libcurl 7.10 introduced SSL verification *by default*! This needs to be
- * switched off unless wanted.
- */
- data->set.ssl.verifypeer = TRUE;
- data->set.ssl.verifyhost = 2;
-#ifdef CURL_CA_BUNDLE
- /* This is our preferred CA cert bundle since install time */
- data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
-#endif
-
- data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
- type */
-}
-
-#ifdef CURL_DOES_CONVERSIONS
-/*
- * Curl_convert_to_network() is an internal function
- * for performing ASCII conversions on non-ASCII platforms.
- */
-CURLcode Curl_convert_to_network(struct SessionHandle *data,
- char *buffer, size_t length)
-{
- CURLcode rc;
-
- if(data->set.convtonetwork) {
- /* use translation callback */
- rc = data->set.convtonetwork(buffer, length);
- if(rc != CURLE_OK) {
- failf(data,
- "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %i: %s",
- rc, curl_easy_strerror(rc));
- }
- return(rc);
- } else {
-#ifdef HAVE_ICONV
- /* do the translation ourselves */
- char *input_ptr, *output_ptr;
- size_t in_bytes, out_bytes, rc;
-
- /* open an iconv conversion descriptor if necessary */
- if(data->outbound_cd == (iconv_t)-1) {
- data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
- CURL_ICONV_CODESET_OF_HOST);
- if(data->outbound_cd == (iconv_t)-1) {
- failf(data,
- "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
- CURL_ICONV_CODESET_OF_NETWORK,
- CURL_ICONV_CODESET_OF_HOST,
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
- }
- /* call iconv */
- input_ptr = output_ptr = buffer;
- in_bytes = out_bytes = length;
- rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
- &output_ptr, &out_bytes);
- if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
- failf(data,
- "The Curl_convert_to_network iconv call failed with errno %i: %s",
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
-#else
- failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
- return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
- }
-
- return CURLE_OK;
-}
-
-/*
- * Curl_convert_from_network() is an internal function
- * for performing ASCII conversions on non-ASCII platforms.
- */
-CURLcode Curl_convert_from_network(struct SessionHandle *data,
- char *buffer, size_t length)
-{
- CURLcode rc;
-
- if(data->set.convfromnetwork) {
- /* use translation callback */
- rc = data->set.convfromnetwork(buffer, length);
- if(rc != CURLE_OK) {
- failf(data,
- "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %i: %s",
- rc, curl_easy_strerror(rc));
- }
- return(rc);
- } else {
-#ifdef HAVE_ICONV
- /* do the translation ourselves */
- char *input_ptr, *output_ptr;
- size_t in_bytes, out_bytes, rc;
-
- /* open an iconv conversion descriptor if necessary */
- if(data->inbound_cd == (iconv_t)-1) {
- data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_OF_NETWORK);
- if(data->inbound_cd == (iconv_t)-1) {
- failf(data,
- "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
- CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_OF_NETWORK,
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
- }
- /* call iconv */
- input_ptr = output_ptr = buffer;
- in_bytes = out_bytes = length;
- rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
- &output_ptr, &out_bytes);
- if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
- failf(data,
- "The Curl_convert_from_network iconv call failed with errno %i: %s",
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
-#else
- failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
- return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
- }
-
- return CURLE_OK;
-}
-
-/*
- * Curl_convert_from_utf8() is an internal function
- * for performing UTF-8 conversions on non-ASCII platforms.
- */
-CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
- char *buffer, size_t length)
-{
- CURLcode rc;
-
- if(data->set.convfromutf8) {
- /* use translation callback */
- rc = data->set.convfromutf8(buffer, length);
- if(rc != CURLE_OK) {
- failf(data,
- "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %i: %s",
- rc, curl_easy_strerror(rc));
- }
- return(rc);
- } else {
-#ifdef HAVE_ICONV
- /* do the translation ourselves */
- char *input_ptr, *output_ptr;
- size_t in_bytes, out_bytes, rc;
-
- /* open an iconv conversion descriptor if necessary */
- if(data->utf8_cd == (iconv_t)-1) {
- data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_FOR_UTF8);
- if(data->utf8_cd == (iconv_t)-1) {
- failf(data,
- "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
- CURL_ICONV_CODESET_OF_HOST,
- CURL_ICONV_CODESET_FOR_UTF8,
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
- }
- /* call iconv */
- input_ptr = output_ptr = buffer;
- in_bytes = out_bytes = length;
- rc = iconv(data->utf8_cd, (const char**)&input_ptr, &in_bytes,
- &output_ptr, &out_bytes);
- if ((rc == ICONV_ERROR) || (in_bytes != 0)) {
- failf(data,
- "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
- errno, strerror(errno));
- return CURLE_CONV_FAILED;
- }
- if (output_ptr < input_ptr) {
- /* null terminate the now shorter output string */
- *output_ptr = 0x00;
- }
-#else
- failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
- return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
- }
-
- return CURLE_OK;
-}
-
-#endif /* CURL_DOES_CONVERSIONS */
diff --git a/Utilities/cmcurl/easyif.h b/Utilities/cmcurl/easyif.h
deleted file mode 100644
index 4c0f7e795..000000000
--- a/Utilities/cmcurl/easyif.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __EASYIF_H
-#define __EASYIF_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * Prototypes for library-wide functions provided by easy.c
- */
-void Curl_easy_addmulti(struct SessionHandle *data, void *multi);
-
-void Curl_easy_initHandleData(struct SessionHandle *data);
-
-CURLcode Curl_convert_to_network(struct SessionHandle *data,
- char *buffer, size_t length);
-CURLcode Curl_convert_from_network(struct SessionHandle *data,
- char *buffer, size_t length);
-CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
- char *buffer, size_t length);
-
-#endif /* __EASYIF_H */
diff --git a/Utilities/cmcurl/escape.c b/Utilities/cmcurl/escape.c
deleted file mode 100644
index 9552b0f31..000000000
--- a/Utilities/cmcurl/escape.c
+++ /dev/null
@@ -1,181 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* Escape and unescape URL encoding in strings. The functions return a new
- * allocated string or NULL if an error occurred. */
-
-#include "setup.h"
-#include <ctype.h>
-#include <curl/curl.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "memory.h"
-/* urldata.h and easyif.h are included for Curl_convert_... prototypes */
-#include "urldata.h"
-#include "easyif.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* for ABI-compatibility with previous versions */
-char *curl_escape(const char *string, int inlength)
-{
- return curl_easy_escape(NULL, string, inlength);
-}
-
-/* for ABI-compatibility with previous versions */
-char *curl_unescape(const char *string, int length)
-{
- return curl_easy_unescape(NULL, string, length, NULL);
-}
-
-char *curl_easy_escape(CURL *handle, const char *string, int inlength)
-{
- size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
- char *ns;
- char *testing_ptr = NULL;
- unsigned char in;
- size_t newlen = alloc;
- int strindex=0;
- size_t length;
-
-#ifndef CURL_DOES_CONVERSIONS
- /* avoid compiler warnings */
- (void)handle;
-#endif
- ns = malloc(alloc);
- if(!ns)
- return NULL;
-
- length = alloc-1;
- while(length--) {
- in = *string;
- if(!(in >= 'a' && in <= 'z') &&
- !(in >= 'A' && in <= 'Z') &&
- !(in >= '0' && in <= '9')) {
- /* encode it */
- newlen += 2; /* the size grows with two, since this'll become a %XX */
- if(newlen > alloc) {
- alloc *= 2;
- testing_ptr = realloc(ns, alloc);
- if(!testing_ptr) {
- free( ns );
- return NULL;
- }
- else {
- ns = testing_ptr;
- }
- }
-
-#ifdef CURL_DOES_CONVERSIONS
-/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
- if (!handle ||
- (Curl_convert_to_network(handle, &in, 1) != CURLE_OK)) {
- /* Curl_convert_to_network calls failf if unsuccessful */
- free(ns);
- return NULL;
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- snprintf(&ns[strindex], 4, "%%%02X", in);
-
- strindex+=3;
- }
- else {
- /* just copy this */
- ns[strindex++]=in;
- }
- string++;
- }
- ns[strindex]=0; /* terminate it */
- return ns;
-}
-
-char *curl_easy_unescape(CURL *handle, const char *string, int length,
- int *olen)
-{
- int alloc = (length?length:(int)strlen(string))+1;
- char *ns = malloc(alloc);
- unsigned char in;
- int strindex=0;
- long hex;
-
-#ifndef CURL_DOES_CONVERSIONS
- /* avoid compiler warnings */
- (void)handle;
-#endif
- if( !ns )
- return NULL;
-
- while(--alloc > 0) {
- in = *string;
- if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
- /* this is two hexadecimal digits following a '%' */
- char hexstr[3];
- char *ptr;
- hexstr[0] = string[1];
- hexstr[1] = string[2];
- hexstr[2] = 0;
-
- hex = strtol(hexstr, &ptr, 16);
-
- in = (unsigned char)hex; /* this long is never bigger than 255 anyway */
-
-#ifdef CURL_DOES_CONVERSIONS
-/* escape sequences are always in ASCII so convert them on non-ASCII hosts */
- if (!handle ||
- (Curl_convert_from_network(handle, &in, 1) != CURLE_OK)) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- free(ns);
- return NULL;
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- string+=2;
- alloc-=2;
- }
-
- ns[strindex++] = in;
- string++;
- }
- ns[strindex]=0; /* terminate it */
-
- if(olen)
- /* store output size */
- *olen = strindex;
- return ns;
-}
-
-/* For operating systems/environments that use different malloc/free
- ssystems for the app and for this library, we provide a free that uses
- the library's memory system */
-void curl_free(void *p)
-{
- if(p)
- free(p);
-}
diff --git a/Utilities/cmcurl/escape.h b/Utilities/cmcurl/escape.h
deleted file mode 100644
index a0a0209c4..000000000
--- a/Utilities/cmcurl/escape.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __ESCAPE_H
-#define __ESCAPE_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-/* Escape and unescape URL encoding in strings. The functions return a new
- * allocated string or NULL if an error occurred. */
-
-
-#endif
diff --git a/Utilities/cmcurl/file.c b/Utilities/cmcurl/file.c
deleted file mode 100644
index b247a7736..000000000
--- a/Utilities/cmcurl/file.c
+++ /dev/null
@@ -1,407 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_FILE
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#include <fcntl.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "progress.h"
-#include "sendf.h"
-#include "escape.h"
-#include "file.h"
-#include "speedcheck.h"
-#include "getinfo.h"
-#include "transfer.h"
-#include "url.h"
-#include "memory.h"
-#include "parsedate.h" /* for the week day and month names */
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- * Curl_file_connect() gets called from Curl_protocol_connect() to allow us to
- * do protocol-specific actions at connect-time. We emulate a
- * connect-then-transfer protocol and "connect" to the file here
- */
-CURLcode Curl_file_connect(struct connectdata *conn)
-{
- char *real_path = curl_easy_unescape(conn->data, conn->data->reqdata.path, 0, NULL);
- struct FILEPROTO *file;
- int fd;
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
- int i;
- char *actual_path;
-#endif
-
- if(!real_path)
- return CURLE_OUT_OF_MEMORY;
-
- file = (struct FILEPROTO *)calloc(sizeof(struct FILEPROTO), 1);
- if(!file) {
- free(real_path);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if (conn->data->reqdata.proto.file) {
- free(conn->data->reqdata.proto.file);
- }
-
- conn->data->reqdata.proto.file = file;
-
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
- /* If the first character is a slash, and there's
- something that looks like a drive at the beginning of
- the path, skip the slash. If we remove the initial
- slash in all cases, paths without drive letters end up
- relative to the current directory which isn't how
- browsers work.
-
- Some browsers accept | instead of : as the drive letter
- separator, so we do too.
-
- On other platforms, we need the slash to indicate an
- absolute pathname. On Windows, absolute paths start
- with a drive letter.
- */
- actual_path = real_path;
- if ((actual_path[0] == '/') &&
- actual_path[1] &&
- (actual_path[2] == ':' || actual_path[2] == '|'))
- {
- actual_path[2] = ':';
- actual_path++;
- }
-
- /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
- for (i=0; actual_path[i] != '\0'; ++i)
- if (actual_path[i] == '/')
- actual_path[i] = '\\';
-
- fd = open(actual_path, O_RDONLY | O_BINARY); /* no CR/LF translation! */
- file->path = actual_path;
-#else
- fd = open(real_path, O_RDONLY);
- file->path = real_path;
-#endif
- file->freepath = real_path; /* free this when done */
-
- file->fd = fd;
- if(!conn->data->set.upload && (fd == -1)) {
- failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path);
- Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
- return CURLE_FILE_COULDNT_READ_FILE;
- }
-
- return CURLE_OK;
-}
-
-CURLcode Curl_file_done(struct connectdata *conn,
- CURLcode status, bool premature)
-{
- struct FILEPROTO *file = conn->data->reqdata.proto.file;
- (void)status; /* not used */
- (void)premature; /* not used */
- Curl_safefree(file->freepath);
-
- if(file->fd != -1)
- close(file->fd);
-
- return CURLE_OK;
-}
-
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
-#define DIRSEP '\\'
-#else
-#define DIRSEP '/'
-#endif
-
-static CURLcode file_upload(struct connectdata *conn)
-{
- struct FILEPROTO *file = conn->data->reqdata.proto.file;
- char *dir = strchr(file->path, DIRSEP);
- FILE *fp;
- CURLcode res=CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *buf = data->state.buffer;
- size_t nread;
- size_t nwrite;
- curl_off_t bytecount = 0;
- struct timeval now = Curl_tvnow();
-
- /*
- * Since FILE: doesn't do the full init, we need to provide some extra
- * assignments here.
- */
- conn->fread = data->set.fread;
- conn->fread_in = data->set.in;
- conn->data->reqdata.upload_fromhere = buf;
-
- if(!dir)
- return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
-
- if(!dir[1])
- return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
-
- fp = fopen(file->path, "wb");
- if(!fp) {
- failf(data, "Can't open %s for writing", file->path);
- return CURLE_WRITE_ERROR;
- }
-
- if(-1 != data->set.infilesize)
- /* known size of data to "upload" */
- Curl_pgrsSetUploadSize(data, data->set.infilesize);
-
- while (res == CURLE_OK) {
- int readcount;
- res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
- if(res)
- break;
-
- if (readcount <= 0) /* fix questionable compare error. curlvms */
- break;
-
- nread = (size_t)readcount;
-
- /* write the data to the target */
- nwrite = fwrite(buf, 1, nread, fp);
- if(nwrite != nread) {
- res = CURLE_SEND_ERROR;
- break;
- }
-
- bytecount += nread;
-
- Curl_pgrsSetUploadCounter(data, bytecount);
-
- if(Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
- else
- res = Curl_speedcheck(data, now);
- }
- if(!res && Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
-
- fclose(fp);
-
- return res;
-}
-
-/*
- * Curl_file() is the protocol-specific function for the do-phase, separated
- * from the connect-phase above. Other protocols merely setup the transfer in
- * the do-phase, to have it done in the main transfer loop but since some
- * platforms we support don't allow select()ing etc on file handles (as
- * opposed to sockets) we instead perform the whole do-operation in this
- * function.
- */
-CURLcode Curl_file(struct connectdata *conn, bool *done)
-{
- /* This implementation ignores the host name in conformance with
- RFC 1738. Only local files (reachable via the standard file system)
- are supported. This means that files on remotely mounted directories
- (via NFS, Samba, NT sharing) can be accessed through a file:// URL
- */
- CURLcode res = CURLE_OK;
- struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
- Windows version to have a different struct without
- having to redefine the simple word 'stat' */
- curl_off_t expected_size=0;
- bool fstated=FALSE;
- ssize_t nread;
- struct SessionHandle *data = conn->data;
- char *buf = data->state.buffer;
- curl_off_t bytecount = 0;
- int fd;
- struct timeval now = Curl_tvnow();
-
- *done = TRUE; /* unconditionally */
-
- Curl_readwrite_init(conn);
- Curl_initinfo(data);
- Curl_pgrsStartNow(data);
-
- if(data->set.upload)
- return file_upload(conn);
-
- /* get the fd from the connection phase */
- fd = conn->data->reqdata.proto.file->fd;
-
- /* VMS: This only works reliable for STREAMLF files */
- if( -1 != fstat(fd, &statbuf)) {
- /* we could stat it, then read out the size */
- expected_size = statbuf.st_size;
- fstated = TRUE;
- }
-
- /* If we have selected NOBODY and HEADER, it means that we only want file
- information. Which for FILE can't be much more than the file size and
- date. */
- if(conn->bits.no_body && data->set.include_header && fstated) {
- CURLcode result;
- snprintf(buf, sizeof(data->state.buffer),
- "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- if(result)
- return result;
-
- result = Curl_client_write(conn, CLIENTWRITE_BOTH,
- (char *)"Accept-ranges: bytes\r\n", 0);
- if(result)
- return result;
-
- if(fstated) {
- struct tm *tm;
- time_t clock = (time_t)statbuf.st_mtime;
-#ifdef HAVE_GMTIME_R
- struct tm buffer;
- tm = (struct tm *)gmtime_r(&clock, &buffer);
-#else
- tm = gmtime(&clock);
-#endif
- /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- snprintf(buf, BUFSIZE-1,
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- }
- return result;
- }
-
- if (data->reqdata.resume_from <= expected_size)
- expected_size -= data->reqdata.resume_from;
- else {
- failf(data, "failed to resume file:// transfer");
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- if (fstated && (expected_size == 0))
- return CURLE_OK;
-
- /* The following is a shortcut implementation of file reading
- this is both more efficient than the former call to download() and
- it avoids problems with select() and recv() on file descriptors
- in Winsock */
- if(fstated)
- Curl_pgrsSetDownloadSize(data, expected_size);
-
- if(data->reqdata.resume_from) {
- if(data->reqdata.resume_from !=
- lseek(fd, data->reqdata.resume_from, SEEK_SET))
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
-
- Curl_pgrsTime(data, TIMER_STARTTRANSFER);
-
- while (res == CURLE_OK) {
- nread = read(fd, buf, BUFSIZE-1);
-
- if ( nread > 0)
- buf[nread] = 0;
-
- if (nread <= 0)
- break;
-
- bytecount += nread;
-
- res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
- if(res)
- return res;
-
- Curl_pgrsSetDownloadCounter(data, bytecount);
-
- if(Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
- else
- res = Curl_speedcheck(data, now);
- }
- if(Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
-
- return res;
-}
-
-#endif
diff --git a/Utilities/cmcurl/file.h b/Utilities/cmcurl/file.h
deleted file mode 100644
index 20a1c4c06..000000000
--- a/Utilities/cmcurl/file.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __FILE_H
-#define __FILE_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_FILE
-CURLcode Curl_file(struct connectdata *, bool *done);
-CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature);
-CURLcode Curl_file_connect(struct connectdata *);
-#endif
-#endif
diff --git a/Utilities/cmcurl/formdata.c b/Utilities/cmcurl/formdata.c
deleted file mode 100644
index f10c6c70e..000000000
--- a/Utilities/cmcurl/formdata.c
+++ /dev/null
@@ -1,1694 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- Debug the form generator stand-alone by compiling this source file with:
-
- gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -DCURLDEBUG -o formdata -I../include formdata.c strequal.c memdebug.c mprintf.c strerror.c
-
- run the 'formdata' executable the output should end with:
- All Tests seem to have worked ...
- and the following parts should be there:
-
-Content-Disposition: form-data; name="simple_COPYCONTENTS"
-value for simple COPYCONTENTS
-
-Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
-Content-Type: image/gif
-value for COPYCONTENTS + CONTENTTYPE
-
-Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
-vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
-(or you might see P^@RNAME and v^@lue at the start)
-
-Content-Disposition: form-data; name="simple_PTRCONTENTS"
-value for simple PTRCONTENTS
-
-Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
-vlue for PTRCONTENTS + CONTENTSLENGTH
-(or you might see v^@lue at the start)
-
-Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
-Content-Type: text/plain
-vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
-(or you might see v^@lue at the start)
-
-Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
-Content-Type: text/html
-...
-
-Content-Disposition: form-data; name="FILE1_+_FILE2"
-Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
-...
-Content-Disposition: attachment; filename="inet_ntoa_r.h"
-Content-Type: text/plain
-...
-Content-Disposition: attachment; filename="Makefile.b32"
-Content-Type: text/plain
-...
-
-Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
-Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
-...
-Content-Disposition: attachment; filename="inet_ntoa_r.h"
-Content-Type: text/plain
-...
-Content-Disposition: attachment; filename="Makefile.b32"
-Content-Type: text/plain
-...
-Content-Disposition: attachment; filename="inet_ntoa_r.h"
-Content-Type: text/plain
-...
-
-
-Content-Disposition: form-data; name="ARRAY: FILE1_+_FILE2_+_FILE3"
-Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
-...
-Content-Disposition: attachment; filename="inet_ntoa_r.h"
-Content-Type: text/plain
-...
-Content-Disposition: attachment; filename="Makefile.b32"
-Content-Type: text/plain
-...
-Content-Disposition: attachment; filename="inet_ntoa_r.h"
-Content-Type: text/plain
-...
-
-Content-Disposition: form-data; name="FILECONTENT"
-...
-
- */
-
-#include "setup.h"
-#include <curl/curl.h>
-
-/* Length of the random boundary string. */
-#define BOUNDARY_LENGTH 40
-
-#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <time.h>
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
-#include <libgen.h>
-#endif
-#include "urldata.h" /* for struct SessionHandle */
-#include "easyif.h" /* for Curl_convert_... prototypes */
-#include "formdata.h"
-#include "strequal.h"
-#include "memory.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
-
-#ifndef CURL_DISABLE_HTTP
-
-#if defined(HAVE_BASENAME) && defined(NEED_BASENAME_PROTO)
-/* This system has a basename() but no prototype for it! */
-char *basename(char *path);
-#endif
-
-static size_t readfromfile(struct Form *form, char *buffer, size_t size);
-
-/* What kind of Content-Type to use on un-specified files with unrecognized
- extensions. */
-#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
-
-#define FORM_FILE_SEPARATOR ','
-#define FORM_TYPE_SEPARATOR ';'
-
-/***************************************************************************
- *
- * AddHttpPost()
- *
- * Adds a HttpPost structure to the list, if parent_post is given becomes
- * a subpost of parent_post instead of a direct list element.
- *
- * Returns newly allocated HttpPost on success and NULL if malloc failed.
- *
- ***************************************************************************/
-static struct curl_httppost *
-AddHttpPost(char * name, size_t namelength,
- char * value, size_t contentslength,
- char * buffer, size_t bufferlength,
- char *contenttype,
- long flags,
- struct curl_slist* contentHeader,
- char *showfilename,
- struct curl_httppost *parent_post,
- struct curl_httppost **httppost,
- struct curl_httppost **last_post)
-{
- struct curl_httppost *post;
- post = (struct curl_httppost *)calloc(sizeof(struct curl_httppost), 1);
- if(post) {
- post->name = name;
- post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
- post->contents = value;
- post->contentslength = (long)contentslength;
- post->buffer = buffer;
- post->bufferlength = (long)bufferlength;
- post->contenttype = contenttype;
- post->contentheader = contentHeader;
- post->showfilename = showfilename;
- post->flags = flags;
- }
- else
- return NULL;
-
- if (parent_post) {
- /* now, point our 'more' to the original 'more' */
- post->more = parent_post->more;
-
- /* then move the original 'more' to point to ourselves */
- parent_post->more = post;
- }
- else {
- /* make the previous point to this */
- if(*last_post)
- (*last_post)->next = post;
- else
- (*httppost) = post;
-
- (*last_post) = post;
- }
- return post;
-}
-
-/***************************************************************************
- *
- * AddFormInfo()
- *
- * Adds a FormInfo structure to the list presented by parent_form_info.
- *
- * Returns newly allocated FormInfo on success and NULL if malloc failed/
- * parent_form_info is NULL.
- *
- ***************************************************************************/
-static FormInfo * AddFormInfo(char *value,
- char *contenttype,
- FormInfo *parent_form_info)
-{
- FormInfo *form_info;
- form_info = (FormInfo *)malloc(sizeof(FormInfo));
- if(form_info) {
- memset(form_info, 0, sizeof(FormInfo));
- if (value)
- form_info->value = value;
- if (contenttype)
- form_info->contenttype = contenttype;
- form_info->flags = HTTPPOST_FILENAME;
- }
- else
- return NULL;
-
- if (parent_form_info) {
- /* now, point our 'more' to the original 'more' */
- form_info->more = parent_form_info->more;
-
- /* then move the original 'more' to point to ourselves */
- parent_form_info->more = form_info;
- }
- else
- return NULL;
-
- return form_info;
-}
-
-/***************************************************************************
- *
- * ContentTypeForFilename()
- *
- * Provides content type for filename if one of the known types (else
- * (either the prevtype or the default is returned).
- *
- * Returns some valid contenttype for filename.
- *
- ***************************************************************************/
-static const char * ContentTypeForFilename (const char *filename,
- const char *prevtype)
-{
- const char *contenttype = NULL;
- unsigned int i;
- /*
- * No type was specified, we scan through a few well-known
- * extensions and pick the first we match!
- */
- struct ContentType {
- const char *extension;
- const char *type;
- };
- static const struct ContentType ctts[]={
- {".gif", "image/gif"},
- {".jpg", "image/jpeg"},
- {".jpeg", "image/jpeg"},
- {".txt", "text/plain"},
- {".html", "text/html"}
- };
-
- if(prevtype)
- /* default to the previously set/used! */
- contenttype = prevtype;
- else
- /* It seems RFC1867 defines no Content-Type to default to
- text/plain so we don't actually need to set this: */
- contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
-
- for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
- if(strlen(filename) >= strlen(ctts[i].extension)) {
- if(strequal(filename +
- strlen(filename) - strlen(ctts[i].extension),
- ctts[i].extension)) {
- contenttype = ctts[i].type;
- break;
- }
- }
- }
- /* we have a contenttype by now */
- return contenttype;
-}
-
-/***************************************************************************
- *
- * memdup()
- *
- * Copies the 'source' data to a newly allocated buffer buffer (that is
- * returned). Uses buffer_length if not null, else uses strlen to determine
- * the length of the buffer to be copied
- *
- * Returns the new pointer or NULL on failure.
- *
- ***************************************************************************/
-static char *memdup(const char *src, size_t buffer_length)
-{
- size_t length;
- bool add = FALSE;
- char *buffer;
-
- if (buffer_length)
- length = buffer_length;
- else {
- length = strlen(src);
- add = TRUE;
- }
- buffer = (char*)malloc(length+add);
- if (!buffer)
- return NULL; /* fail */
-
- memcpy(buffer, src, length);
-
- /* if length unknown do null termination */
- if (add)
- buffer[length] = '\0';
-
- return buffer;
-}
-
-/***************************************************************************
- *
- * FormAdd()
- *
- * Stores a formpost parameter and builds the appropriate linked list.
- *
- * Has two principal functionalities: using files and byte arrays as
- * post parts. Byte arrays are either copied or just the pointer is stored
- * (as the user requests) while for files only the filename and not the
- * content is stored.
- *
- * While you may have only one byte array for each name, multiple filenames
- * are allowed (and because of this feature CURLFORM_END is needed after
- * using CURLFORM_FILE).
- *
- * Examples:
- *
- * Simple name/value pair with copied contents:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
- *
- * name/value pair where only the content pointer is remembered:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
- * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
- *
- * storing a filename (CONTENTTYPE is optional!):
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
- * CURLFORM_END);
- *
- * storing multiple filenames:
- * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
- * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
- *
- * Returns:
- * CURL_FORMADD_OK on success
- * CURL_FORMADD_MEMORY if the FormInfo allocation fails
- * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
- * CURL_FORMADD_NULL if a null pointer was given for a char
- * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
- * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
- * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or an error)
- * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
- * CURL_FORMADD_MEMORY if some allocation for string copying failed.
- * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
- *
- ***************************************************************************/
-
-static
-CURLFORMcode FormAdd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- va_list params)
-{
- FormInfo *first_form, *current_form, *form = NULL;
- CURLFORMcode return_value = CURL_FORMADD_OK;
- const char *prevtype = NULL;
- struct curl_httppost *post = NULL;
- CURLformoption option;
- struct curl_forms *forms = NULL;
- char *array_value=NULL; /* value read from an array */
-
- /* This is a state variable, that if TRUE means that we're parsing an
- array that we got passed to us. If FALSE we're parsing the input
- va_list arguments. */
- bool array_state = FALSE;
-
- /*
- * We need to allocate the first struct to fill in.
- */
- first_form = (FormInfo *)calloc(sizeof(struct FormInfo), 1);
- if(!first_form)
- return CURL_FORMADD_MEMORY;
-
- current_form = first_form;
-
- /*
- * Loop through all the options set. Break if we have an error to report.
- */
- while (return_value == CURL_FORMADD_OK) {
-
- /* first see if we have more parts of the array param */
- if ( array_state ) {
- /* get the upcoming option from the given array */
- option = forms->option;
- array_value = (char *)forms->value;
-
- forms++; /* advance this to next entry */
- if (CURLFORM_END == option) {
- /* end of array state */
- array_state = FALSE;
- continue;
- }
- }
- else {
- /* This is not array-state, get next option */
- option = va_arg(params, CURLformoption);
- if (CURLFORM_END == option)
- break;
- }
-
- switch (option) {
- case CURLFORM_ARRAY:
- if(array_state)
- /* we don't support an array from within an array */
- return_value = CURL_FORMADD_ILLEGAL_ARRAY;
- else {
- forms = va_arg(params, struct curl_forms *);
- if (forms)
- array_state = TRUE;
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
-
- /*
- * Set the Name property.
- */
- case CURLFORM_PTRNAME:
-#ifdef CURL_DOES_CONVERSIONS
- /* treat CURLFORM_PTR like CURLFORM_COPYNAME so we'll
- have safe memory for the eventual conversion */
-#else
- current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
-#endif
- case CURLFORM_COPYNAME:
- if (current_form->name)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else {
- char *name = array_state?
- array_value:va_arg(params, char *);
- if (name)
- current_form->name = name; /* store for the moment */
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
- case CURLFORM_NAMELENGTH:
- if (current_form->namelength)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else
- current_form->namelength =
- array_state?(long)array_value:(long)va_arg(params, long);
- break;
-
- /*
- * Set the contents property.
- */
- case CURLFORM_PTRCONTENTS:
- current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
- case CURLFORM_COPYCONTENTS:
- if (current_form->value)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else {
- char *value =
- array_state?array_value:va_arg(params, char *);
- if (value)
- current_form->value = value; /* store for the moment */
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
- case CURLFORM_CONTENTSLENGTH:
- if (current_form->contentslength)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else
- current_form->contentslength =
- array_state?(long)array_value:va_arg(params, long);
- break;
-
- /* Get contents from a given file name */
- case CURLFORM_FILECONTENT:
- if (current_form->flags != 0)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else {
- char *filename = array_state?
- array_value:va_arg(params, char *);
- if (filename) {
- current_form->value = strdup(filename);
- if(!current_form->value)
- return_value = CURL_FORMADD_MEMORY;
- else {
- current_form->flags |= HTTPPOST_READFILE;
- current_form->value_alloc = TRUE;
- }
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
-
- /* We upload a file */
- case CURLFORM_FILE:
- {
- char *filename = array_state?array_value:
- va_arg(params, char *);
-
- if (current_form->value) {
- if (current_form->flags & HTTPPOST_FILENAME) {
- if (filename) {
- if ((current_form = AddFormInfo(strdup(filename),
- NULL, current_form)) == NULL)
- return_value = CURL_FORMADD_MEMORY;
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- else
- return_value = CURL_FORMADD_OPTION_TWICE;
- }
- else {
- if (filename) {
- current_form->value = strdup(filename);
- if(!current_form->value)
- return_value = CURL_FORMADD_MEMORY;
- else {
- current_form->flags |= HTTPPOST_FILENAME;
- current_form->value_alloc = TRUE;
- }
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
- }
-
- case CURLFORM_BUFFER:
- {
- char *filename = array_state?array_value:
- va_arg(params, char *);
-
- if (current_form->value) {
- if (current_form->flags & HTTPPOST_BUFFER) {
- if (filename) {
- if ((current_form = AddFormInfo(strdup(filename),
- NULL, current_form)) == NULL)
- return_value = CURL_FORMADD_MEMORY;
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- else
- return_value = CURL_FORMADD_OPTION_TWICE;
- }
- else {
- if (filename) {
- current_form->value = strdup(filename);
- if(!current_form->value)
- return_value = CURL_FORMADD_MEMORY;
- }
- else
- return_value = CURL_FORMADD_NULL;
- current_form->flags |= HTTPPOST_BUFFER;
- }
- break;
- }
-
- case CURLFORM_BUFFERPTR:
- current_form->flags |= HTTPPOST_PTRBUFFER;
- if (current_form->buffer)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else {
- char *buffer =
- array_state?array_value:va_arg(params, char *);
- if (buffer)
- current_form->buffer = buffer; /* store for the moment */
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
-
- case CURLFORM_BUFFERLENGTH:
- if (current_form->bufferlength)
- return_value = CURL_FORMADD_OPTION_TWICE;
- else
- current_form->bufferlength =
- array_state?(long)array_value:va_arg(params, long);
- break;
-
- case CURLFORM_CONTENTTYPE:
- {
- char *contenttype =
- array_state?array_value:va_arg(params, char *);
- if (current_form->contenttype) {
- if (current_form->flags & HTTPPOST_FILENAME) {
- if (contenttype) {
- if ((current_form = AddFormInfo(NULL,
- strdup(contenttype),
- current_form)) == NULL)
- return_value = CURL_FORMADD_MEMORY;
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- else
- return_value = CURL_FORMADD_OPTION_TWICE;
- }
- else {
- if (contenttype) {
- current_form->contenttype = strdup(contenttype);
- if(!current_form->contenttype)
- return_value = CURL_FORMADD_MEMORY;
- else
- current_form->contenttype_alloc = TRUE;
- }
- else
- return_value = CURL_FORMADD_NULL;
- }
- break;
- }
- case CURLFORM_CONTENTHEADER:
- {
- /* this "cast increases required alignment of target type" but
- we consider it OK anyway */
- struct curl_slist* list = array_state?
- (struct curl_slist*)array_value:
- va_arg(params, struct curl_slist*);
-
- if( current_form->contentheader )
- return_value = CURL_FORMADD_OPTION_TWICE;
- else
- current_form->contentheader = list;
-
- break;
- }
- case CURLFORM_FILENAME:
- {
- char *filename = array_state?array_value:
- va_arg(params, char *);
- if( current_form->showfilename )
- return_value = CURL_FORMADD_OPTION_TWICE;
- else {
- current_form->showfilename = strdup(filename);
- if(!current_form->showfilename)
- return_value = CURL_FORMADD_MEMORY;
- else
- current_form->showfilename_alloc = TRUE;
- }
- break;
- }
- default:
- return_value = CURL_FORMADD_UNKNOWN_OPTION;
- }
- }
-
- if(CURL_FORMADD_OK == return_value) {
- /* go through the list, check for copleteness and if everything is
- * alright add the HttpPost item otherwise set return_value accordingly */
-
- post = NULL;
- for(form = first_form;
- form != NULL;
- form = form->more) {
- if ( ((!form->name || !form->value) && !post) ||
- ( (form->contentslength) &&
- (form->flags & HTTPPOST_FILENAME) ) ||
- ( (form->flags & HTTPPOST_FILENAME) &&
- (form->flags & HTTPPOST_PTRCONTENTS) ) ||
-
- ( (!form->buffer) &&
- (form->flags & HTTPPOST_BUFFER) &&
- (form->flags & HTTPPOST_PTRBUFFER) ) ||
-
- ( (form->flags & HTTPPOST_READFILE) &&
- (form->flags & HTTPPOST_PTRCONTENTS) )
- ) {
- return_value = CURL_FORMADD_INCOMPLETE;
- break;
- }
- else {
- if ( ((form->flags & HTTPPOST_FILENAME) ||
- (form->flags & HTTPPOST_BUFFER)) &&
- !form->contenttype ) {
- /* our contenttype is missing */
- form->contenttype
- = strdup(ContentTypeForFilename(form->value, prevtype));
- if(!form->contenttype) {
- return_value = CURL_FORMADD_MEMORY;
- break;
- }
- form->contenttype_alloc = TRUE;
- }
- if ( !(form->flags & HTTPPOST_PTRNAME) &&
- (form == first_form) ) {
- /* copy name (without strdup; possibly contains null characters) */
- form->name = memdup(form->name, form->namelength);
- if (!form->name) {
- return_value = CURL_FORMADD_MEMORY;
- break;
- }
- form->name_alloc = TRUE;
- }
- if ( !(form->flags & HTTPPOST_FILENAME) &&
- !(form->flags & HTTPPOST_READFILE) &&
- !(form->flags & HTTPPOST_PTRCONTENTS) &&
- !(form->flags & HTTPPOST_PTRBUFFER) ) {
- /* copy value (without strdup; possibly contains null characters) */
- form->value = memdup(form->value, form->contentslength);
- if (!form->value) {
- return_value = CURL_FORMADD_MEMORY;
- break;
- }
- form->value_alloc = TRUE;
- }
- post = AddHttpPost(form->name, form->namelength,
- form->value, form->contentslength,
- form->buffer, form->bufferlength,
- form->contenttype, form->flags,
- form->contentheader, form->showfilename,
- post, httppost,
- last_post);
-
- if(!post) {
- return_value = CURL_FORMADD_MEMORY;
- break;
- }
-
- if (form->contenttype)
- prevtype = form->contenttype;
- }
- }
- }
-
- if(return_value) {
- /* we return on error, free possibly allocated fields */
- if(!form)
- form = current_form;
- if(form) {
- if(form->name_alloc)
- free(form->name);
- if(form->value_alloc)
- free(form->value);
- if(form->contenttype_alloc)
- free(form->contenttype);
- if(form->showfilename_alloc)
- free(form->showfilename);
- }
- }
-
- /* always delete the allocated memory before returning */
- form = first_form;
- while (form != NULL) {
- FormInfo *delete_form;
-
- delete_form = form;
- form = form->more;
- free (delete_form);
- }
-
- return return_value;
-}
-
-/*
- * curl_formadd() is a public API to add a section to the multipart formpost.
- */
-
-CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...)
-{
- va_list arg;
- CURLFORMcode result;
- va_start(arg, last_post);
- result = FormAdd(httppost, last_post, arg);
- va_end(arg);
- return result;
-}
-
-/*
- * AddFormData() adds a chunk of data to the FormData linked list.
- *
- * size is incremented by the chunk length, unless it is NULL
- */
-static CURLcode AddFormData(struct FormData **formp,
- enum formtype type,
- const void *line,
- size_t length,
- curl_off_t *size)
-{
- struct FormData *newform = (struct FormData *)
- malloc(sizeof(struct FormData));
- if (!newform)
- return CURLE_OUT_OF_MEMORY;
- newform->next = NULL;
-
- /* we make it easier for plain strings: */
- if(!length)
- length = strlen((char *)line);
-
- newform->line = (char *)malloc(length+1);
- if (!newform->line) {
- free(newform);
- return CURLE_OUT_OF_MEMORY;
- }
- memcpy(newform->line, line, length);
- newform->length = length;
- newform->line[length]=0; /* zero terminate for easier debugging */
- newform->type = type;
-
- if(*formp) {
- (*formp)->next = newform;
- *formp = newform;
- }
- else
- *formp = newform;
-
- if (size) {
- if((type == FORM_DATA) || (type == FORM_CONTENT))
- *size += length;
- else {
- /* Since this is a file to be uploaded here, add the size of the actual
- file */
- if(!strequal("-", newform->line)) {
- struct_stat file;
- if(!stat(newform->line, &file)) {
- *size += file.st_size;
- }
- }
- }
- }
- return CURLE_OK;
-}
-
-/*
- * AddFormDataf() adds printf()-style formatted data to the formdata chain.
- */
-
-static CURLcode AddFormDataf(struct FormData **formp,
- curl_off_t *size,
- const char *fmt, ...)
-{
- char s[4096];
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(s, sizeof(s), fmt, ap);
- va_end(ap);
-
- return AddFormData(formp, FORM_DATA, s, 0, size);
-}
-
-/*
- * Curl_formclean() is used from http.c, this cleans a built FormData linked
- * list
- */
-void Curl_formclean(struct FormData **form_ptr)
-{
- struct FormData *next, *form;
-
- form = *form_ptr;
- if(!form)
- return;
-
- do {
- next=form->next; /* the following form line */
- free(form->line); /* free the line */
- free(form); /* free the struct */
-
- } while ((form = next) != NULL); /* continue */
-
- *form_ptr = NULL;
-}
-
-#ifdef CURL_DOES_CONVERSIONS
-/*
- * Curl_formcovert() is used from http.c, this converts any
- form items that need to be sent in the network encoding.
- Returns CURLE_OK on success.
- */
-CURLcode Curl_formconvert(struct SessionHandle *data, struct FormData *form)
-{
- struct FormData *next;
- CURLcode rc;
-
- if(!form)
- return CURLE_OK;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- do {
- next=form->next; /* the following form line */
- if (form->type == FORM_DATA) {
- rc = Curl_convert_to_network(data, form->line, form->length);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if (rc != CURLE_OK)
- return rc;
- }
- } while ((form = next) != NULL); /* continue */
- return CURLE_OK;
-}
-#endif /* CURL_DOES_CONVERSIONS */
-
-/*
- * curl_formget()
- * Serialize a curl_httppost struct.
- * Returns 0 on success.
- */
-int curl_formget(struct curl_httppost *form, void *arg,
- curl_formget_callback append)
-{
- CURLcode rc;
- curl_off_t size;
- struct FormData *data, *ptr;
-
- rc = Curl_getFormData(&data, form, NULL, &size);
- if (rc != CURLE_OK)
- return (int)rc;
-
- for (ptr = data; ptr; ptr = ptr->next) {
- if (ptr->type == FORM_FILE) {
- char buffer[8192];
- size_t read;
- struct Form temp;
-
- Curl_FormInit(&temp, ptr);
-
- do {
- read = readfromfile(&temp, buffer, sizeof(buffer));
- if ((read == (size_t) -1) || (read != append(arg, buffer, read))) {
- if (temp.fp) {
- fclose(temp.fp);
- }
- Curl_formclean(&data);
- return -1;
- }
- } while (read == sizeof(buffer));
- } else {
- if (ptr->length != append(arg, ptr->line, ptr->length)) {
- Curl_formclean(&data);
- return -1;
- }
- }
- }
- Curl_formclean(&data);
- return 0;
-}
-
-/*
- * curl_formfree() is an external function to free up a whole form post
- * chain
- */
-void curl_formfree(struct curl_httppost *form)
-{
- struct curl_httppost *next;
-
- if(!form)
- /* no form to free, just get out of this */
- return;
-
- do {
- next=form->next; /* the following form line */
-
- /* recurse to sub-contents */
- if(form->more)
- curl_formfree(form->more);
-
- if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
- free(form->name); /* free the name */
- if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
- free(form->contents); /* free the contents */
- if(form->contenttype)
- free(form->contenttype); /* free the content type */
- if(form->showfilename)
- free(form->showfilename); /* free the faked file name */
- free(form); /* free the struct */
-
- } while ((form = next) != NULL); /* continue */
-}
-
-#ifndef HAVE_BASENAME
-/*
- (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
- Edition)
-
- The basename() function shall take the pathname pointed to by path and
- return a pointer to the final component of the pathname, deleting any
- trailing '/' characters.
-
- If the string pointed to by path consists entirely of the '/' character,
- basename() shall return a pointer to the string "/". If the string pointed
- to by path is exactly "//", it is implementation-defined whether '/' or "//"
- is returned.
-
- If path is a null pointer or points to an empty string, basename() shall
- return a pointer to the string ".".
-
- The basename() function may modify the string pointed to by path, and may
- return a pointer to static storage that may then be overwritten by a
- subsequent call to basename().
-
- The basename() function need not be reentrant. A function that is not
- required to be reentrant is not required to be thread-safe.
-
-*/
-static char *basename(char *path)
-{
- /* Ignore all the details above for now and make a quick and simple
- implementaion here */
- char *s1;
- char *s2;
-
- s1=strrchr(path, '/');
- s2=strrchr(path, '\\');
-
- if(s1 && s2) {
- path = (s1 > s2? s1 : s2)+1;
- }
- else if(s1)
- path = s1 + 1;
- else if(s2)
- path = s2 + 1;
-
- return path;
-}
-#endif
-
-static char *strippath(char *fullfile)
-{
- char *filename;
- char *base;
- filename = strdup(fullfile); /* duplicate since basename() may ruin the
- buffer it works on */
- if(!filename)
- return NULL;
- base = strdup(basename(filename));
-
- free(filename); /* free temporary buffer */
-
- return base; /* returns an allocated string! */
-}
-
-/*
- * Curl_getFormData() converts a linked list of "meta data" into a complete
- * (possibly huge) multipart formdata. The input list is in 'post', while the
- * output resulting linked lists gets stored in '*finalform'. *sizep will get
- * the total size of the whole POST.
- * A multipart/form_data content-type is built, unless a custom content-type
- * is passed in 'custom_content_type'.
- */
-
-CURLcode Curl_getFormData(struct FormData **finalform,
- struct curl_httppost *post,
- const char *custom_content_type,
- curl_off_t *sizep)
-{
- struct FormData *form = NULL;
- struct FormData *firstform;
- struct curl_httppost *file;
- CURLcode result = CURLE_OK;
-
- curl_off_t size=0; /* support potentially ENORMOUS formposts */
- char *boundary;
- char *fileboundary=NULL;
- struct curl_slist* curList;
-
- *finalform=NULL; /* default form is empty */
-
- if(!post)
- return result; /* no input => no output! */
-
- boundary = Curl_FormBoundary();
- if(!boundary)
- return CURLE_OUT_OF_MEMORY;
-
- /* Make the first line of the output */
- result = AddFormDataf(&form, NULL,
- "%s; boundary=%s\r\n",
- custom_content_type?custom_content_type:
- "Content-Type: multipart/form-data",
- boundary);
-
- if (result) {
- free(boundary);
- return result;
- }
- /* we DO NOT include that line in the total size of the POST, since it'll be
- part of the header! */
-
- firstform = form;
-
- do {
-
- if(size) {
- result = AddFormDataf(&form, &size, "\r\n");
- if (result)
- break;
- }
-
- /* boundary */
- result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
- if (result)
- break;
-
- /* Maybe later this should be disabled when a custom_content_type is
- passed, since Content-Disposition is not meaningful for all multipart
- types.
- */
- result = AddFormDataf(&form, &size,
- "Content-Disposition: form-data; name=\"");
- if (result)
- break;
-
- result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
- &size);
- if (result)
- break;
-
- result = AddFormDataf(&form, &size, "\"");
- if (result)
- break;
-
- if(post->more) {
- /* If used, this is a link to more file names, we must then do
- the magic to include several files with the same field name */
-
- fileboundary = Curl_FormBoundary();
-
- result = AddFormDataf(&form, &size,
- "\r\nContent-Type: multipart/mixed,"
- " boundary=%s\r\n",
- fileboundary);
- if (result)
- break;
- }
-
- file = post;
-
- do {
-
- /* If 'showfilename' is set, that is a faked name passed on to us
- to use to in the formpost. If that is not set, the actually used
- local file name should be added. */
-
- if(post->more) {
- /* if multiple-file */
- char *filebasename=
- (!file->showfilename)?strippath(file->contents):NULL;
-
- result = AddFormDataf(&form, &size,
- "\r\n--%s\r\nContent-Disposition: "
- "attachment; filename=\"%s\"",
- fileboundary,
- (file->showfilename?file->showfilename:
- filebasename));
- if (filebasename)
- free(filebasename);
- if (result)
- break;
- }
- else if((post->flags & HTTPPOST_FILENAME) ||
- (post->flags & HTTPPOST_BUFFER)) {
-
- char *filebasename=
- (!post->showfilename)?strippath(post->contents):NULL;
-
- result = AddFormDataf(&form, &size,
- "; filename=\"%s\"",
- (post->showfilename?post->showfilename:
- filebasename));
- if (filebasename)
- free(filebasename);
-
- if (result)
- break;
- }
-
- if(file->contenttype) {
- /* we have a specified type */
- result = AddFormDataf(&form, &size,
- "\r\nContent-Type: %s",
- file->contenttype);
- if (result)
- break;
- }
-
- curList = file->contentheader;
- while( curList ) {
- /* Process the additional headers specified for this form */
- result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
- if (result)
- break;
- curList = curList->next;
- }
- if (result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
-
-#if 0
- /* The header Content-Transfer-Encoding: seems to confuse some receivers
- * (like the built-in PHP engine). While I can't see any reason why it
- * should, I can just as well skip this to the benefit of the users who
- * are using such confused receivers.
- */
-
- if(file->contenttype &&
- !checkprefix("text/", file->contenttype)) {
- /* this is not a text content, mention our binary encoding */
- result = AddFormDataf(&form, &size,
- "\r\nContent-Transfer-Encoding: binary");
- if (result)
- break;
- }
-#endif
-
- result = AddFormDataf(&form, &size, "\r\n\r\n");
- if (result)
- break;
-
- if((post->flags & HTTPPOST_FILENAME) ||
- (post->flags & HTTPPOST_READFILE)) {
- /* we should include the contents from the specified file */
- FILE *fileread;
-
- fileread = strequal("-", file->contents)?
- stdin:fopen(file->contents, "rb"); /* binary read for win32 */
-
- /*
- * VMS: This only allows for stream files on VMS. Stream files are
- * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
- * every record needs to have a \n appended & 1 added to SIZE
- */
-
- if(fileread) {
- if(fileread != stdin) {
- /* close the file again */
- fclose(fileread);
- /* add the file name only - for later reading from this */
- result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
- }
- else {
- /* When uploading from stdin, we can't know the size of the file,
- * thus must read the full file as before. We *could* use chunked
- * transfer-encoding, but that only works for HTTP 1.1 and we
- * can't be sure we work with such a server.
- */
- size_t nread;
- char buffer[512];
- while ((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
- result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
- if (result)
- break;
- }
- }
-
- if (result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
-
- }
- else {
-#ifdef _FORM_DEBUG
- fprintf(stderr,
- "\n==> Curl_getFormData couldn't open/read \"%s\"\n",
- file->contents);
-#endif
- Curl_formclean(&firstform);
- free(boundary);
- *finalform = NULL;
- return CURLE_READ_ERROR;
- }
-
- }
- else if (post->flags & HTTPPOST_BUFFER) {
- /* include contents of buffer */
- result = AddFormData(&form, FORM_CONTENT, post->buffer,
- post->bufferlength, &size);
- if (result)
- break;
- }
-
- else {
- /* include the contents we got */
- result = AddFormData(&form, FORM_CONTENT, post->contents,
- post->contentslength, &size);
- if (result)
- break;
- }
- } while ((file = file->more) != NULL); /* for each specified file for this field */
- if (result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
-
- if(post->more) {
- /* this was a multiple-file inclusion, make a termination file
- boundary: */
- result = AddFormDataf(&form, &size,
- "\r\n--%s--",
- fileboundary);
- free(fileboundary);
- if (result)
- break;
- }
-
- } while ((post = post->next) != NULL); /* for each field */
- if (result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
-
- /* end-boundary for everything */
- result = AddFormDataf(&form, &size,
- "\r\n--%s--\r\n",
- boundary);
- if (result) {
- Curl_formclean(&firstform);
- free(boundary);
- return result;
- }
-
- *sizep = size;
-
- free(boundary);
-
- *finalform=firstform;
-
- return result;
-}
-
-/*
- * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
- * and resets the 'sent' counter.
- */
-int Curl_FormInit(struct Form *form, struct FormData *formdata )
-{
- if(!formdata)
- return 1; /* error */
-
- form->data = formdata;
- form->sent = 0;
- form->fp = NULL;
-
- return 0;
-}
-
-static size_t readfromfile(struct Form *form, char *buffer, size_t size)
-{
- size_t nread;
- if(!form->fp) {
- /* this file hasn't yet been opened */
- form->fp = fopen(form->data->line, "rb"); /* b is for binary */
- if(!form->fp)
- return (size_t)-1; /* failure */
- }
- nread = fread(buffer, 1, size, form->fp);
-
- if(nread != size) {
- /* this is the last chunk from the file, move on */
- fclose(form->fp);
- form->fp = NULL;
- form->data = form->data->next;
- }
-
- return nread;
-}
-
-/*
- * Curl_FormReader() is the fread() emulation function that will be used to
- * deliver the formdata to the transfer loop and then sent away to the peer.
- */
-size_t Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata)
-{
- struct Form *form;
- size_t wantedsize;
- size_t gotsize = 0;
-
- form=(struct Form *)mydata;
-
- wantedsize = size * nitems;
-
- if(!form->data)
- return 0; /* nothing, error, empty */
-
- if(form->data->type == FORM_FILE) {
- gotsize = readfromfile(form, buffer, wantedsize);
-
- if(gotsize)
- /* If positive or -1, return. If zero, continue! */
- return gotsize;
- }
- do {
-
- if( (form->data->length - form->sent ) > wantedsize - gotsize) {
-
- memcpy(buffer + gotsize , form->data->line + form->sent,
- wantedsize - gotsize);
-
- form->sent += wantedsize-gotsize;
-
- return wantedsize;
- }
-
- memcpy(buffer+gotsize,
- form->data->line + form->sent,
- (form->data->length - form->sent) );
- gotsize += form->data->length - form->sent;
-
- form->sent = 0;
-
- form->data = form->data->next; /* advance */
-
- } while(form->data && (form->data->type != FORM_FILE));
- /* If we got an empty line and we have more data, we proceed to the next
- line immediately to avoid returning zero before we've reached the end.
- This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
-
- return gotsize;
-}
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len)
-{
- char *header;
- struct Form *form=(struct Form *)formp;
-
- if(!form->data)
- return 0; /* nothing, ERROR! */
-
- header = form->data->line;
- *len = form->data->length;
-
- form->data = form->data->next; /* advance */
-
- return header;
-}
-
-
-#ifdef _FORM_DEBUG
-int FormAddTest(const char * errormsg,
- struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...)
-{
- int result;
- va_list arg;
- va_start(arg, last_post);
- if ((result = FormAdd(httppost, last_post, arg)))
- fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
- errormsg);
- va_end(arg);
- return result;
-}
-
-
-int main()
-{
- char name1[] = "simple_COPYCONTENTS";
- char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
- char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
- char name4[] = "simple_PTRCONTENTS";
- char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
- char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
- char name7[] = "FILE1_+_CONTENTTYPE";
- char name8[] = "FILE1_+_FILE2";
- char name9[] = "FILE1_+_FILE2_+_FILE3";
- char name10[] = "ARRAY: FILE1_+_FILE2_+_FILE3";
- char name11[] = "FILECONTENT";
- char value1[] = "value for simple COPYCONTENTS";
- char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
- char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
- char value4[] = "value for simple PTRCONTENTS";
- char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
- char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
- char value7[] = "inet_ntoa_r.h";
- char value8[] = "Makefile.b32";
- char type2[] = "image/gif";
- char type6[] = "text/plain";
- char type7[] = "text/html";
- int name3length = strlen(name3);
- int value3length = strlen(value3);
- int value5length = strlen(value4);
- int value6length = strlen(value5);
- int errors = 0;
- CURLcode rc;
- size_t size;
- size_t nread;
- char buffer[4096];
- struct curl_httppost *httppost=NULL;
- struct curl_httppost *last_post=NULL;
- struct curl_forms forms[4];
-
- struct FormData *form;
- struct Form formread;
-
- if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
- CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
- CURLFORM_END))
- ++errors;
- if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
- CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
- CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
- ++errors;
- /* make null character at start to check that contentslength works
- correctly */
- name3[1] = '\0';
- value3[1] = '\0';
- if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
- &httppost, &last_post,
- CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
- CURLFORM_CONTENTSLENGTH, value3length,
- CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
- ++errors;
- if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
- CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
- CURLFORM_END))
- ++errors;
- /* make null character at start to check that contentslength works
- correctly */
- value5[1] = '\0';
- if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
- CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
- CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
- ++errors;
- /* make null character at start to check that contentslength works
- correctly */
- value6[1] = '\0';
- if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
- &httppost, &last_post,
- CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
- CURLFORM_CONTENTSLENGTH, value6length,
- CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
- ++errors;
- if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
- CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
- CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
- ++errors;
- if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
- CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
- CURLFORM_FILE, value8, CURLFORM_END))
- ++errors;
- if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
- CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
- CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
- ++errors;
- forms[0].option = CURLFORM_FILE;
- forms[0].value = value7;
- forms[1].option = CURLFORM_FILE;
- forms[1].value = value8;
- forms[2].option = CURLFORM_FILE;
- forms[2].value = value7;
- forms[3].option = CURLFORM_END;
- if (FormAddTest("FILE1 + FILE2 + FILE3 ARRAY test", &httppost, &last_post,
- CURLFORM_COPYNAME, name10, CURLFORM_ARRAY, forms,
- CURLFORM_END))
- ++errors;
- if (FormAddTest("FILECONTENT test", &httppost, &last_post,
- CURLFORM_COPYNAME, name11, CURLFORM_FILECONTENT, value7,
- CURLFORM_END))
- ++errors;
-
- rc = Curl_getFormData(&form, httppost, NULL, &size);
- if(rc != CURLE_OK) {
- if(rc != CURLE_READ_ERROR) {
- const char *errortext = curl_easy_strerror(rc);
- fprintf(stdout, "\n==> Curl_getFormData error: %s\n", errortext);
- }
- return 0;
- }
-
- Curl_FormInit(&formread, form);
-
- do {
- nread = Curl_FormReader(buffer, 1, sizeof(buffer),
- (FILE *)&formread);
-
- if(nread < 1)
- break;
- fwrite(buffer, nread, 1, stdout);
- } while(1);
-
- fprintf(stdout, "size: %d\n", size);
- if (errors)
- fprintf(stdout, "\n==> %d Test(s) failed!\n", errors);
- else
- fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
-
- return 0;
-}
-
-#endif /* _FORM_DEBUG */
-
-#else /* CURL_DISABLE_HTTP */
-CURLFORMcode curl_formadd(struct curl_httppost **httppost,
- struct curl_httppost **last_post,
- ...)
-{
- (void)httppost;
- (void)last_post;
- return CURL_FORMADD_DISABLED;
-}
-
-int curl_formget(struct curl_httppost *form, void *arg,
- curl_formget_callback append)
-{
- (void) form;
- (void) arg;
- (void) append;
- return CURL_FORMADD_DISABLED;
-}
-
-void curl_formfree(struct curl_httppost *form)
-{
- (void)form;
- /* does nothing HTTP is disabled */
-}
-
-#endif /* CURL_DISABLE_HTTP */
-
-#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
-
-/*
- * Curl_FormBoundary() creates a suitable boundary string and returns an
- * allocated one. This is also used by SSL-code so it must be present even
- * if HTTP is disabled!
- */
-char *Curl_FormBoundary(void)
-{
- char *retstring;
- static int randomizer; /* this is just so that two boundaries within
- the same form won't be identical */
- size_t i;
-
- static const char table16[]="abcdef0123456789";
-
- retstring = (char *)malloc(BOUNDARY_LENGTH+1);
-
- if(!retstring)
- return NULL; /* failed */
-
- srand((unsigned int)time(NULL)+randomizer++); /* seed */
-
- strcpy(retstring, "----------------------------");
-
- for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++)
- retstring[i] = table16[rand()%16];
-
- /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416)
- combinations */
- retstring[BOUNDARY_LENGTH]=0; /* zero terminate */
-
- return retstring;
-}
-
-#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
diff --git a/Utilities/cmcurl/formdata.h b/Utilities/cmcurl/formdata.h
deleted file mode 100644
index 4ca0f3c5c..000000000
--- a/Utilities/cmcurl/formdata.h
+++ /dev/null
@@ -1,97 +0,0 @@
-#ifndef __FORMDATA_H
-#define __FORMDATA_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-enum formtype {
- FORM_DATA, /* form metadata (convert to network encoding if necessary) */
- FORM_CONTENT, /* form content (never convert) */
- FORM_FILE /* 'line' points to a file name we should read from
- to create the form data (never convert) */
-};
-
-/* plain and simple linked list with lines to send */
-struct FormData {
- struct FormData *next;
- enum formtype type;
- char *line;
- size_t length;
-};
-
-struct Form {
- struct FormData *data; /* current form line to send */
- size_t sent; /* number of bytes of the current line that has
- already been sent in a previous invoke */
- FILE *fp; /* file to read from */
-};
-
-/* used by FormAdd for temporary storage */
-typedef struct FormInfo {
- char *name;
- bool name_alloc;
- size_t namelength;
- char *value;
- bool value_alloc;
- size_t contentslength;
- char *contenttype;
- bool contenttype_alloc;
- long flags;
- char *buffer; /* pointer to existing buffer used for file upload */
- size_t bufferlength;
- char *showfilename; /* The file name to show. If not set, the actual
- file name will be used */
- bool showfilename_alloc;
- struct curl_slist* contentheader;
- struct FormInfo *more;
-} FormInfo;
-
-int Curl_FormInit(struct Form *form, struct FormData *formdata );
-
-CURLcode
-Curl_getFormData(struct FormData **,
- struct curl_httppost *post,
- const char *custom_contenttype,
- curl_off_t *size);
-
-/* fread() emulation */
-size_t Curl_FormReader(char *buffer,
- size_t size,
- size_t nitems,
- FILE *mydata);
-
-/*
- * Curl_formpostheader() returns the first line of the formpost, the
- * request-header part (which is not part of the request-body like the rest of
- * the post).
- */
-char *Curl_formpostheader(void *formp, size_t *len);
-
-char *Curl_FormBoundary(void);
-
-void Curl_formclean(struct FormData **);
-
-CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *);
-
-#endif
-
diff --git a/Utilities/cmcurl/ftp.c b/Utilities/cmcurl/ftp.c
deleted file mode 100644
index 3ccbc4364..000000000
--- a/Utilities/cmcurl/ftp.c
+++ /dev/null
@@ -1,3865 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_FTP
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef WIN32
-
-#else /* probably some kind of unix */
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <sys/types.h>
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#endif
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "easyif.h" /* for Curl_convert_... prototypes */
-
-#include "if2ip.h"
-#include "hostip.h"
-#include "progress.h"
-#include "transfer.h"
-#include "escape.h"
-#include "http.h" /* for HTTP proxy tunnel stuff */
-#include "ftp.h"
-
-#ifdef HAVE_KRB4
-#include "krb4.h"
-#endif
-
-#include "strtoofft.h"
-#include "strequal.h"
-#include "sslgen.h"
-#include "connect.h"
-#include "strerror.h"
-#include "memory.h"
-#include "inet_ntop.h"
-#include "select.h"
-#include "parsedate.h" /* for the week day and month names */
-#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "multiif.h"
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#ifdef CURLDEBUG
-#include "memdebug.h"
-#endif
-
-#ifdef HAVE_NI_WITHSCOPEID
-#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV | NI_WITHSCOPEID
-#else
-#define NIFLAGS NI_NUMERICHOST | NI_NUMERICSERV
-#endif
-
-/* Local API functions */
-static CURLcode ftp_sendquote(struct connectdata *conn,
- struct curl_slist *quote);
-static CURLcode ftp_quit(struct connectdata *conn);
-static CURLcode ftp_parse_url_path(struct connectdata *conn);
-static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
-static void ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost, /* ascii version */
- int port);
-static CURLcode ftp_state_post_rest(struct connectdata *conn);
-static CURLcode ftp_state_post_cwd(struct connectdata *conn);
-static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init, ftpstate instate);
-static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate state);
-static int ftp_need_type(struct connectdata *conn,
- bool ascii);
-
-/* easy-to-use macro: */
-#define FTPSENDF(x,y,z) if ((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
- return result
-#define NBFTPSENDF(x,y,z) if ((result = Curl_nbftpsendf(x,y,z)) != CURLE_OK) \
- return result
-
-static void freedirs(struct connectdata *conn)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
-
- int i;
- if(ftpc->dirs) {
- for (i=0; i < ftpc->dirdepth; i++){
- if(ftpc->dirs[i]) {
- free(ftpc->dirs[i]);
- ftpc->dirs[i]=NULL;
- }
- }
- free(ftpc->dirs);
- ftpc->dirs = NULL;
- }
- if(ftp->file) {
- free(ftp->file);
- ftp->file = NULL;
- }
-}
-
-/* Returns non-zero if the given string contains CR (\r) or LF (\n),
- which are not allowed within RFC 959 <string>.
- Note: The input string is in the client's encoding which might
- not be ASCII, so escape sequences \r & \n must be used instead
- of hex values 0x0d & 0x0a.
-*/
-static bool isBadFtpString(const char *string)
-{
- return (bool)((NULL != strchr(string, '\r')) || (NULL != strchr(string, '\n')));
-}
-
-/***********************************************************************
- *
- * AllowServerConnect()
- *
- * When we've issue the PORT command, we have told the server to connect
- * to us. This function will sit and wait here until the server has
- * connected.
- *
- */
-static CURLcode AllowServerConnect(struct connectdata *conn)
-{
- int timeout_ms;
- struct SessionHandle *data = conn->data;
- curl_socket_t sock = conn->sock[SECONDARYSOCKET];
- struct timeval now = Curl_tvnow();
- long timespent = Curl_tvdiff(Curl_tvnow(), now)/1000;
- long timeout = data->set.connecttimeout?data->set.connecttimeout:
- (data->set.timeout?data->set.timeout: 0);
-
- if(timeout) {
- timeout -= timespent;
- if(timeout<=0) {
- failf(data, "Timed out before server could connect to us");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
-
- /* We allow the server 60 seconds to connect to us, or a custom timeout.
- Note the typecast here. */
- timeout_ms = (timeout?(int)timeout:60) * 1000;
-
- switch (Curl_select(sock, CURL_SOCKET_BAD, timeout_ms)) {
- case -1: /* error */
- /* let's die here */
- failf(data, "Error while waiting for server connect");
- return CURLE_FTP_PORT_FAILED;
- case 0: /* timeout */
- /* let's die here */
- failf(data, "Timeout while waiting for server connect");
- return CURLE_FTP_PORT_FAILED;
- default:
- /* we have received data here */
- {
- curl_socket_t s = CURL_SOCKET_BAD;
-#ifdef ENABLE_IPV6
- struct Curl_sockaddr_storage add;
-#else
- struct sockaddr_in add;
-#endif
- socklen_t size = (socklen_t) sizeof(add);
-
- if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
- size = sizeof(add);
-
- s=accept(sock, (struct sockaddr *) &add, &size);
- }
- sclose(sock); /* close the first socket */
-
- if (CURL_SOCKET_BAD == s) {
- /* DIE! */
- failf(data, "Error accept()ing server connect");
- return CURLE_FTP_PORT_FAILED;
- }
- infof(data, "Connection accepted from server\n");
-
- conn->sock[SECONDARYSOCKET] = s;
- Curl_nonblock(s, TRUE); /* enable non-blocking */
- }
- break;
- }
-
- return CURLE_OK;
-}
-
-/* initialize stuff to prepare for reading a fresh new response */
-static void ftp_respinit(struct connectdata *conn)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- ftpc->nread_resp = 0;
- ftpc->linestart_resp = conn->data->state.buffer;
-}
-
-/* macro to check for the last line in an FTP server response */
-#define lastline(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
- ISDIGIT(line[2]) && (' ' == line[3]))
-
-static CURLcode ftp_readresp(curl_socket_t sockfd,
- struct connectdata *conn,
- int *ftpcode, /* return the ftp-code if done */
- size_t *size) /* size of the response */
-{
- int perline; /* count bytes per line */
- bool keepon=TRUE;
- ssize_t gotbytes;
- char *ptr;
- struct SessionHandle *data = conn->data;
- char *buf = data->state.buffer;
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- int code = 0;
-
- if (ftpcode)
- *ftpcode = 0; /* 0 for errors or not done */
-
- ptr=buf + ftpc->nread_resp;
-
- perline= (int)(ptr-ftpc->linestart_resp); /* number of bytes in the current
- line, so far */
- keepon=TRUE;
-
- while((ftpc->nread_resp<BUFSIZE) && (keepon && !result)) {
-
- if(ftpc->cache) {
- /* we had data in the "cache", copy that instead of doing an actual
- * read
- *
- * ftp->cache_size is cast to int here. This should be safe,
- * because it would have been populated with something of size
- * int to begin with, even though its datatype may be larger
- * than an int.
- */
- memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
- gotbytes = (int)ftpc->cache_size;
- free(ftpc->cache); /* free the cache */
- ftpc->cache = NULL; /* clear the pointer */
- ftpc->cache_size = 0; /* zero the size just in case */
- }
- else {
- int res = Curl_read(conn, sockfd, ptr, BUFSIZE-ftpc->nread_resp,
- &gotbytes);
- if(res < 0)
- /* EWOULDBLOCK */
- return CURLE_OK; /* return */
-
-#ifdef CURL_DOES_CONVERSIONS
- if((res == CURLE_OK) && (gotbytes > 0)) {
- /* convert from the network encoding */
- result = res = Curl_convert_from_network(data, ptr, gotbytes);
- /* Curl_convert_from_network calls failf if unsuccessful */
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(CURLE_OK != res)
- keepon = FALSE;
- }
-
- if(!keepon)
- ;
- else if(gotbytes <= 0) {
- keepon = FALSE;
- result = CURLE_RECV_ERROR;
- failf(data, "FTP response reading failed");
- }
- else {
- /* we got a whole chunk of data, which can be anything from one
- * byte to a set of lines and possible just a piece of the last
- * line */
- int i;
-
- conn->headerbytecount += gotbytes;
-
- ftpc->nread_resp += gotbytes;
- for(i = 0; i < gotbytes; ptr++, i++) {
- perline++;
- if(*ptr=='\n') {
- /* a newline is CRLF in ftp-talk, so the CR is ignored as
- the line isn't really terminated until the LF comes */
-
- /* output debug output if that is requested */
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN,
- ftpc->linestart_resp, (size_t)perline, conn);
-
- /*
- * We pass all response-lines to the callback function registered
- * for "headers". The response lines can be seen as a kind of
- * headers.
- */
- result = Curl_client_write(conn, CLIENTWRITE_HEADER,
- ftpc->linestart_resp, perline);
- if(result)
- return result;
-
- if(perline>3 && lastline(ftpc->linestart_resp)) {
- /* This is the end of the last line, copy the last line to the
- start of the buffer and zero terminate, for old times sake (and
- krb4)! */
- char *meow;
- int n;
- for(meow=ftpc->linestart_resp, n=0; meow<ptr; meow++, n++)
- buf[n] = *meow;
- *meow=0; /* zero terminate */
- keepon=FALSE;
- ftpc->linestart_resp = ptr+1; /* advance pointer */
- i++; /* skip this before getting out */
-
- *size = ftpc->nread_resp; /* size of the response */
- ftpc->nread_resp = 0; /* restart */
- break;
- }
- perline=0; /* line starts over here */
- ftpc->linestart_resp = ptr+1;
- }
- }
- if(!keepon && (i != gotbytes)) {
- /* We found the end of the response lines, but we didn't parse the
- full chunk of data we have read from the server. We therefore need
- to store the rest of the data to be checked on the next invoke as
- it may actually contain another end of response already! */
- ftpc->cache_size = gotbytes - i;
- ftpc->cache = (char *)malloc((int)ftpc->cache_size);
- if(ftpc->cache)
- memcpy(ftpc->cache, ftpc->linestart_resp, (int)ftpc->cache_size);
- else
- return CURLE_OUT_OF_MEMORY; /**BANG**/
- }
- } /* there was data */
-
- } /* while there's buffer left and loop is requested */
-
- if(!result)
- code = atoi(buf);
-
-#ifdef HAVE_KRB4
- /* handle the security-oriented responses 6xx ***/
- /* FIXME: some errorchecking perhaps... ***/
- switch(code) {
- case 631:
- Curl_sec_read_msg(conn, buf, prot_safe);
- break;
- case 632:
- Curl_sec_read_msg(conn, buf, prot_private);
- break;
- case 633:
- Curl_sec_read_msg(conn, buf, prot_confidential);
- break;
- default:
- /* normal ftp stuff we pass through! */
- break;
- }
-#endif
-
- *ftpcode=code; /* return the initial number like this */
-
-
- /* store the latest code for later retrieval */
- conn->data->info.httpcode=code;
-
- return result;
-}
-
-/* --- parse FTP server responses --- */
-
-/*
- * Curl_GetFTPResponse() is supposed to be invoked after each command sent to
- * a remote FTP server. This function will wait and read all lines of the
- * response and extract the relevant return code for the invoking function.
- */
-
-CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
- struct connectdata *conn,
- int *ftpcode) /* return the ftp-code */
-{
- /*
- * We cannot read just one byte per read() and then go back to select() as
- * the OpenSSL read() doesn't grok that properly.
- *
- * Alas, read as much as possible, split up into lines, use the ending
- * line in a response or continue reading. */
-
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
- int perline; /* count bytes per line */
- bool keepon=TRUE;
- ssize_t gotbytes;
- char *ptr;
- long timeout; /* timeout in seconds */
- int interval_ms;
- struct SessionHandle *data = conn->data;
- char *line_start;
- int code=0; /* default ftp "error code" to return */
- char *buf = data->state.buffer;
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct timeval now = Curl_tvnow();
-
- if (ftpcode)
- *ftpcode = 0; /* 0 for errors */
-
- ptr=buf;
- line_start = buf;
-
- *nreadp=0;
- perline=0;
- keepon=TRUE;
-
- while((*nreadp<BUFSIZE) && (keepon && !result)) {
- /* check and reset timeout value every lap */
- if(data->set.ftp_response_timeout )
- /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine
- remaining time. Also, use "now" as opposed to "conn->now"
- because ftp_response_timeout is only supposed to govern
- the response for any given ftp response, not for the time
- from connect to the given ftp response. */
- timeout = data->set.ftp_response_timeout - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
- else if(data->set.timeout)
- /* if timeout is requested, find out how much remaining time we have */
- timeout = data->set.timeout - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
- else
- /* Even without a requested timeout, we only wait response_time
- seconds for the full response to arrive before we bail out */
- timeout = ftpc->response_time -
- Curl_tvdiff(Curl_tvnow(), now)/1000; /* spent time */
-
- if(timeout <=0 ) {
- failf(data, "FTP response timeout");
- return CURLE_OPERATION_TIMEDOUT; /* already too little time */
- }
-
- if(!ftpc->cache) {
- interval_ms = 1 * 1000; /* use 1 second timeout intervals */
-
- switch (Curl_select(sockfd, CURL_SOCKET_BAD, interval_ms)) {
- case -1: /* select() error, stop reading */
- result = CURLE_RECV_ERROR;
- failf(data, "FTP response aborted due to select() error: %d",
- Curl_sockerrno());
- break;
- case 0: /* timeout */
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
- continue; /* just continue in our loop for the timeout duration */
-
- default:
- break;
- }
- }
- if(CURLE_OK == result) {
- /*
- * This code previously didn't use the kerberos sec_read() code
- * to read, but when we use Curl_read() it may do so. Do confirm
- * that this is still ok and then remove this comment!
- */
- if(ftpc->cache) {
- /* we had data in the "cache", copy that instead of doing an actual
- * read
- *
- * Dave Meyer, December 2003:
- * ftp->cache_size is cast to int here. This should be safe,
- * because it would have been populated with something of size
- * int to begin with, even though its datatype may be larger
- * than an int.
- */
- memcpy(ptr, ftpc->cache, (int)ftpc->cache_size);
- gotbytes = (int)ftpc->cache_size;
- free(ftpc->cache); /* free the cache */
- ftpc->cache = NULL; /* clear the pointer */
- ftpc->cache_size = 0; /* zero the size just in case */
- }
- else {
- int res = Curl_read(conn, sockfd, ptr, BUFSIZE-*nreadp, &gotbytes);
- if(res < 0)
- /* EWOULDBLOCK */
- continue; /* go looping again */
-
-#ifdef CURL_DOES_CONVERSIONS
- if((res == CURLE_OK) && (gotbytes > 0)) {
- /* convert from the network encoding */
- result = res = Curl_convert_from_network(data, ptr, gotbytes);
- /* Curl_convert_from_network calls failf if unsuccessful */
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(CURLE_OK != res)
- keepon = FALSE;
- }
-
- if(!keepon)
- ;
- else if(gotbytes <= 0) {
- keepon = FALSE;
- result = CURLE_RECV_ERROR;
- failf(data, "FTP response reading failed");
- }
- else {
- /* we got a whole chunk of data, which can be anything from one
- * byte to a set of lines and possible just a piece of the last
- * line */
- int i;
-
- conn->headerbytecount += gotbytes;
-
- *nreadp += gotbytes;
- for(i = 0; i < gotbytes; ptr++, i++) {
- perline++;
- if(*ptr=='\n') {
- /* a newline is CRLF in ftp-talk, so the CR is ignored as
- the line isn't really terminated until the LF comes */
-
- /* output debug output if that is requested */
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN,
- line_start, (size_t)perline, conn);
-
- /*
- * We pass all response-lines to the callback function registered
- * for "headers". The response lines can be seen as a kind of
- * headers.
- */
- result = Curl_client_write(conn, CLIENTWRITE_HEADER,
- line_start, perline);
- if(result)
- return result;
-
- if(perline>3 && lastline(line_start)) {
- /* This is the end of the last line, copy the last
- * line to the start of the buffer and zero terminate,
- * for old times sake (and krb4)! */
- char *meow;
- int n;
- for(meow=line_start, n=0; meow<ptr; meow++, n++)
- buf[n] = *meow;
- *meow=0; /* zero terminate */
- keepon=FALSE;
- line_start = ptr+1; /* advance pointer */
- i++; /* skip this before getting out */
- break;
- }
- perline=0; /* line starts over here */
- line_start = ptr+1;
- }
- }
- if(!keepon && (i != gotbytes)) {
- /* We found the end of the response lines, but we didn't parse the
- full chunk of data we have read from the server. We therefore
- need to store the rest of the data to be checked on the next
- invoke as it may actually contain another end of response
- already! Cleverly figured out by Eric Lavigne in December
- 2001. */
- ftpc->cache_size = gotbytes - i;
- ftpc->cache = (char *)malloc((int)ftpc->cache_size);
- if(ftpc->cache)
- memcpy(ftpc->cache, line_start, (int)ftpc->cache_size);
- else
- return CURLE_OUT_OF_MEMORY; /**BANG**/
- }
- } /* there was data */
- } /* if(no error) */
- } /* while there's buffer left and loop is requested */
-
- if(!result)
- code = atoi(buf);
-
-#ifdef HAVE_KRB4
- /* handle the security-oriented responses 6xx ***/
- /* FIXME: some errorchecking perhaps... ***/
- switch(code) {
- case 631:
- Curl_sec_read_msg(conn, buf, prot_safe);
- break;
- case 632:
- Curl_sec_read_msg(conn, buf, prot_private);
- break;
- case 633:
- Curl_sec_read_msg(conn, buf, prot_confidential);
- break;
- default:
- /* normal ftp stuff we pass through! */
- break;
- }
-#endif
-
- if(ftpcode)
- *ftpcode=code; /* return the initial number like this */
-
- /* store the latest code for later retrieval */
- conn->data->info.httpcode=code;
-
- return result;
-}
-
-/* This is the ONLY way to change FTP state! */
-static void state(struct connectdata *conn,
- ftpstate state)
-{
-#ifdef CURLDEBUG
- /* for debug purposes */
- const char *names[]={
- "STOP",
- "WAIT220",
- "AUTH",
- "USER",
- "PASS",
- "ACCT",
- "PBSZ",
- "PROT",
- "CCC",
- "PWD",
- "QUOTE",
- "RETR_PREQUOTE",
- "STOR_PREQUOTE",
- "POSTQUOTE",
- "CWD",
- "MKD",
- "MDTM",
- "TYPE",
- "LIST_TYPE",
- "RETR_TYPE",
- "STOR_TYPE",
- "SIZE",
- "RETR_SIZE",
- "STOR_SIZE",
- "REST",
- "RETR_REST",
- "PORT",
- "PASV",
- "LIST",
- "RETR",
- "STOR",
- "QUIT"
- };
-#endif
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-#ifdef CURLDEBUG
- if(ftpc->state != state)
- infof(conn->data, "FTP %p state change from %s to %s\n",
- ftpc, names[ftpc->state], names[state]);
-#endif
- ftpc->state = state;
-}
-
-static CURLcode ftp_state_user(struct connectdata *conn)
-{
- CURLcode result;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- /* send USER */
- NBFTPSENDF(conn, "USER %s", ftp->user?ftp->user:"");
-
- state(conn, FTP_USER);
- conn->data->state.ftp_trying_alternative = FALSE;
-
- return CURLE_OK;
-}
-
-static CURLcode ftp_state_pwd(struct connectdata *conn)
-{
- CURLcode result;
-
- /* send PWD to discover our entry point */
- NBFTPSENDF(conn, "PWD", NULL);
- state(conn, FTP_PWD);
-
- return CURLE_OK;
-}
-
-/* For the FTP "protocol connect" and "doing" phases only */
-int Curl_ftp_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(!numsocks)
- return GETSOCK_BLANK;
-
- socks[0] = conn->sock[FIRSTSOCKET];
-
- if(ftpc->sendleft) {
- /* write mode */
- return GETSOCK_WRITESOCK(0);
- }
-
- /* read mode */
- return GETSOCK_READSOCK(0);
-}
-
-/* This is called after the FTP_QUOTE state is passed.
-
- ftp_state_cwd() sends the range of PWD commands to the server to change to
- the correct directory. It may also need to send MKD commands to create
- missing ones, if that option is enabled.
-*/
-static CURLcode ftp_state_cwd(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(ftpc->cwddone)
- /* already done and fine */
- result = ftp_state_post_cwd(conn);
- else {
- ftpc->count2 = 0;
- if (conn->bits.reuse && ftpc->entrypath) {
- /* This is a re-used connection. Since we change directory to where the
- transfer is taking place, we must first get back to the original dir
- where we ended up after login: */
- ftpc->count1 = 0; /* we count this as the first path, then we add one
- for all upcoming ones in the ftp->dirs[] array */
- NBFTPSENDF(conn, "CWD %s", ftpc->entrypath);
- state(conn, FTP_CWD);
- }
- else {
- if(ftpc->dirdepth) {
- ftpc->count1 = 1;
- /* issue the first CWD, the rest is sent when the CWD responses are
- received... */
- NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
- state(conn, FTP_CWD);
- }
- else {
- /* No CWD necessary */
- result = ftp_state_post_cwd(conn);
- }
- }
- }
- return result;
-}
-
-typedef enum {
- EPRT,
- PORT,
- DONE
-} ftpport;
-
-static CURLcode ftp_state_use_port(struct connectdata *conn,
- ftpport fcmd) /* start with this */
-
-{
- CURLcode result = CURLE_OK;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct SessionHandle *data=conn->data;
- curl_socket_t portsock= CURL_SOCKET_BAD;
- char myhost[256] = "";
-
-#ifdef ENABLE_IPV6
- /******************************************************************
- * IPv6-specific section
- */
- struct Curl_sockaddr_storage ss;
- struct addrinfo *res, *ai;
- socklen_t sslen;
- char hbuf[NI_MAXHOST];
- struct sockaddr *sa=(struct sockaddr *)&ss;
- char tmp[1024];
- const char *mode[] = { "EPRT", "PORT", NULL };
- int rc;
- int error;
- char *host=NULL;
- struct Curl_dns_entry *h=NULL;
- unsigned short port = 0;
-
- /* Step 1, figure out what address that is requested */
-
- if(data->set.ftpport && (strlen(data->set.ftpport) > 1)) {
- /* attempt to get the address of the given interface name */
- if(!Curl_if2ip(data->set.ftpport, hbuf, sizeof(hbuf)))
- /* not an interface, use the given string as host name instead */
- host = data->set.ftpport;
- else
- host = hbuf; /* use the hbuf for host name */
- } /* data->set.ftpport */
-
- if(!host) {
- /* not an interface and not a host name, get default by extracting
- the IP from the control connection */
-
- sslen = sizeof(ss);
- if (getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)&ss, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, Curl_sockerrno()) );
- return CURLE_FTP_PORT_FAILED;
- }
-
- if (sslen > (socklen_t)sizeof(ss))
- sslen = sizeof(ss);
- rc = getnameinfo((struct sockaddr *)&ss, sslen, hbuf, sizeof(hbuf), NULL,
- 0, NIFLAGS);
- if(rc) {
- failf(data, "getnameinfo() returned %d \n", rc);
- return CURLE_FTP_PORT_FAILED;
- }
- host = hbuf; /* use this host name */
- }
-
- rc = Curl_resolv(conn, host, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- rc = Curl_wait_for_resolv(conn, &h);
- if(h) {
- res = h->addr;
- /* when we return from this function, we can forget about this entry
- to we can unlock it now already */
- Curl_resolv_unlock(data, h);
- } /* (h) */
- else
- res = NULL; /* failure! */
-
-
- /* step 2, create a socket for the requested address */
-
- portsock = CURL_SOCKET_BAD;
- error = 0;
- for (ai = res; ai; ai = ai->ai_next) {
- /*
- * Workaround for AIX5 getaddrinfo() problem (it doesn't set ai_socktype):
- */
- if (ai->ai_socktype == 0)
- ai->ai_socktype = conn->socktype;
-
- portsock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (portsock == CURL_SOCKET_BAD) {
- error = Curl_sockerrno();
- continue;
- }
- break;
- }
- if(!ai) {
- failf(data, "socket failure: %s", Curl_strerror(conn, error));
- return CURLE_FTP_PORT_FAILED;
- }
-
- /* step 3, bind to a suitable local address */
-
- /* Try binding the given address. */
- if (bind(portsock, ai->ai_addr, ai->ai_addrlen)) {
-
- /* It failed. Bind the address used for the control connection instead */
- sslen = sizeof(ss);
- if (getsockname(conn->sock[FIRSTSOCKET],
- (struct sockaddr *)sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, Curl_sockerrno()) );
- sclose(portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- /* set port number to zero to make bind() pick "any" */
- if(((struct sockaddr *)sa)->sa_family == AF_INET)
- ((struct sockaddr_in *)sa)->sin_port=0;
- else
- ((struct sockaddr_in6 *)sa)->sin6_port =0;
-
- if (sslen > (socklen_t)sizeof(ss))
- sslen = sizeof(ss);
-
- if(bind(portsock, (struct sockaddr *)sa, sslen)) {
- failf(data, "bind failed: %s", Curl_strerror(conn, Curl_sockerrno()));
- sclose(portsock);
- return CURLE_FTP_PORT_FAILED;
- }
- }
-
- /* get the name again after the bind() so that we can extract the
- port number it uses now */
- sslen = sizeof(ss);
- if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, Curl_sockerrno()) );
- sclose(portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- /* step 4, listen on the socket */
-
- if (listen(portsock, 1)) {
- failf(data, "socket failure: %s", Curl_strerror(conn, Curl_sockerrno()));
- sclose(portsock);
- return CURLE_FTP_PORT_FAILED;
- }
-
- /* step 5, send the proper FTP command */
-
- /* get a plain printable version of the numerical address to work with
- below */
- Curl_printable_address(ai, myhost, sizeof(myhost));
-
-#ifdef PF_INET6
- if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
- /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
- request and enable EPRT again! */
- conn->bits.ftp_use_eprt = TRUE;
-#endif
-
- for (; fcmd != DONE; fcmd++) {
-
- if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
- /* if disabled, goto next */
- continue;
-
- switch (sa->sa_family) {
- case AF_INET:
- port = ntohs(((struct sockaddr_in *)sa)->sin_port);
- break;
- case AF_INET6:
- port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
- break;
- default:
- break;
- }
-
- if (EPRT == fcmd) {
- /*
- * Two fine examples from RFC2428;
- *
- * EPRT |1|132.235.1.2|6275|
- *
- * EPRT |2|1080::8:800:200C:417A|5282|
- */
-
- result = Curl_nbftpsendf(conn, "%s |%d|%s|%d|", mode[fcmd],
- ai->ai_family == AF_INET?1:2,
- myhost, port);
- if(result)
- return result;
- break;
- }
- else if (PORT == fcmd) {
- char *source = myhost;
- char *dest = tmp;
-
- if ((PORT == fcmd) && ai->ai_family != AF_INET)
- continue;
-
- /* translate x.x.x.x to x,x,x,x */
- while(source && *source) {
- if(*source == '.')
- *dest=',';
- else
- *dest = *source;
- dest++;
- source++;
- }
- *dest = 0;
- snprintf(dest, 20, ",%d,%d", port>>8, port&0xff);
-
- result = Curl_nbftpsendf(conn, "%s %s", mode[fcmd], tmp);
- if(result)
- return result;
- break;
- }
- }
-
- /* store which command was sent */
- ftpc->count1 = fcmd;
-
- /* we set the secondary socket variable to this for now, it is only so that
- the cleanup function will close it in case we fail before the true
- secondary stuff is made */
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- sclose(conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = portsock;
-
-#else
- /******************************************************************
- * IPv4-specific section
- */
- struct sockaddr_in sa;
- unsigned short porttouse;
- bool sa_filled_in = FALSE;
- Curl_addrinfo *addr = NULL;
- unsigned short ip[4];
- bool freeaddr = TRUE;
- socklen_t sslen = sizeof(sa);
-
- (void)fcmd; /* not used in the IPv4 code */
- if(data->set.ftpport) {
- in_addr_t in;
-
- /* First check if the given name is an IP address */
- in=inet_addr(data->set.ftpport);
-
- if(in != CURL_INADDR_NONE)
- /* this is an IPv4 address */
- addr = Curl_ip2addr(in, data->set.ftpport, 0);
- else {
- if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
- /* The interface to IP conversion provided a dotted address */
- in=inet_addr(myhost);
- addr = Curl_ip2addr(in, myhost, 0);
- }
- else if(strlen(data->set.ftpport)> 1) {
- /* might be a host name! */
- struct Curl_dns_entry *h=NULL;
- int rc = Curl_resolv(conn, data->set.ftpport, 0, &h);
- if(rc == CURLRESOLV_PENDING)
- /* BLOCKING */
- rc = Curl_wait_for_resolv(conn, &h);
- if(h) {
- addr = h->addr;
- /* when we return from this function, we can forget about this entry
- so we can unlock it now already */
- Curl_resolv_unlock(data, h);
-
- freeaddr = FALSE; /* make sure we don't free 'addr' in this function
- since it points to a DNS cache entry! */
- } /* (h) */
- else {
- infof(data, "Failed to resolve host name %s\n", data->set.ftpport);
- }
- } /* strlen */
- } /* CURL_INADDR_NONE */
- } /* data->set.ftpport */
-
- if(!addr) {
- /* pick a suitable default here */
-
- if (getsockname(conn->sock[FIRSTSOCKET],
- (struct sockaddr *)&sa, &sslen)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, Curl_sockerrno()) );
- return CURLE_FTP_PORT_FAILED;
- }
- if (sslen > (socklen_t)sizeof(sa))
- sslen = sizeof(sa);
-
- sa_filled_in = TRUE; /* the sa struct is filled in */
- }
-
- if (addr || sa_filled_in) {
- portsock = socket(AF_INET, SOCK_STREAM, 0);
- if(CURL_SOCKET_BAD != portsock) {
-
- /* we set the secondary socket variable to this for now, it
- is only so that the cleanup function will close it in case
- we fail before the true secondary stuff is made */
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- sclose(conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = portsock;
-
- if(!sa_filled_in) {
- memcpy(&sa, addr->ai_addr, sslen);
- sa.sin_addr.s_addr = INADDR_ANY;
- }
-
- sa.sin_port = 0;
- sslen = sizeof(sa);
-
- if(bind(portsock, (struct sockaddr *)&sa, sslen) == 0) {
- /* we succeeded to bind */
- struct sockaddr_in add;
- socklen_t socksize = sizeof(add);
-
- if(getsockname(portsock, (struct sockaddr *) &add,
- &socksize)) {
- failf(data, "getsockname() failed: %s",
- Curl_strerror(conn, Curl_sockerrno()) );
- return CURLE_FTP_PORT_FAILED;
- }
- porttouse = ntohs(add.sin_port);
-
- if ( listen(portsock, 1) < 0 ) {
- failf(data, "listen(2) failed on socket");
- return CURLE_FTP_PORT_FAILED;
- }
- }
- else {
- failf(data, "bind(2) failed on socket");
- return CURLE_FTP_PORT_FAILED;
- }
- }
- else {
- failf(data, "socket(2) failed (%s)");
- return CURLE_FTP_PORT_FAILED;
- }
- }
- else {
- failf(data, "couldn't find IP address to use");
- return CURLE_FTP_PORT_FAILED;
- }
-
- if(sa_filled_in)
- Curl_inet_ntop(AF_INET, &((struct sockaddr_in *)&sa)->sin_addr,
- myhost, sizeof(myhost));
- else
- Curl_printable_address(addr, myhost, sizeof(myhost));
-
- if(4 == sscanf(myhost, "%hu.%hu.%hu.%hu",
- &ip[0], &ip[1], &ip[2], &ip[3])) {
-
- infof(data, "Telling server to connect to %d.%d.%d.%d:%d\n",
- ip[0], ip[1], ip[2], ip[3], porttouse);
-
- result=Curl_nbftpsendf(conn, "PORT %d,%d,%d,%d,%d,%d",
- ip[0], ip[1], ip[2], ip[3],
- porttouse >> 8, porttouse & 255);
- if(result)
- return result;
- }
- else
- return CURLE_FTP_PORT_FAILED;
-
- if(freeaddr)
- Curl_freeaddrinfo(addr);
-
- ftpc->count1 = PORT;
-
-#endif /* end of ipv4-specific code */
-
- /* this tcpconnect assignment below is a hackish work-around to make the
- multi interface with active FTP work - as it will not wait for a
- (passive) connect in Curl_is_connected().
-
- The *proper* fix is to make sure that the active connection from the
- server is done in a non-blocking way. Currently, it is still BLOCKING.
- */
- conn->bits.tcpconnect = TRUE;
-
- state(conn, FTP_PORT);
- return result;
-}
-
-static CURLcode ftp_state_use_pasv(struct connectdata *conn)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
- /*
- Here's the excecutive summary on what to do:
-
- PASV is RFC959, expect:
- 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
-
- LPSV is RFC1639, expect:
- 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
-
- EPSV is RFC2428, expect:
- 229 Entering Extended Passive Mode (|||port|)
-
- */
-
- const char *mode[] = { "EPSV", "PASV", NULL };
- int modeoff;
-
-#ifdef PF_INET6
- if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
- /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
- request and enable EPSV again! */
- conn->bits.ftp_use_epsv = TRUE;
-#endif
-
- modeoff = conn->bits.ftp_use_epsv?0:1;
-
- result = Curl_nbftpsendf(conn, "%s", mode[modeoff]);
- if(result)
- return result;
-
- ftpc->count1 = modeoff;
- state(conn, FTP_PASV);
- infof(conn->data, "Connect data stream passively\n");
-
- return result;
-}
-
-/* REST is the last command in the chain of commands when a "head"-like
- request is made. Thus, if an actual transfer is to be made this is where
- we take off for real. */
-static CURLcode ftp_state_post_rest(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- struct SessionHandle *data = conn->data;
-
- if(ftp->no_transfer || conn->bits.no_body) {
- /* doesn't transfer any data */
- ftp->no_transfer = TRUE;
-
- /* still possibly do PRE QUOTE jobs */
- state(conn, FTP_RETR_PREQUOTE);
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
- }
- else if(data->set.ftp_use_port) {
- /* We have chosen to use the PORT (or similar) command */
- result = ftp_state_use_port(conn, EPRT);
- }
- else {
- /* We have chosen (this is default) to use the PASV (or similar) command */
- result = ftp_state_use_pasv(conn);
- }
- return result;
-}
-
-static CURLcode ftp_state_post_size(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
-
- if(ftp->no_transfer) {
- /* if a "head"-like request is being made */
-
- /* Determine if server can respond to REST command and therefore
- whether it supports range */
- NBFTPSENDF(conn, "REST %d", 0);
-
- state(conn, FTP_REST);
- }
- else
- result = ftp_state_post_rest(conn);
-
- return result;
-}
-
-static CURLcode ftp_state_post_type(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
-
- if(ftp->no_transfer) {
- /* if a "head"-like request is being made */
-
- /* we know ftp->file is a valid pointer to a file name */
- NBFTPSENDF(conn, "SIZE %s", ftp->file);
-
- state(conn, FTP_SIZE);
- }
- else
- result = ftp_state_post_size(conn);
-
- return result;
-}
-
-static CURLcode ftp_state_post_listtype(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- /* If this output is to be machine-parsed, the NLST command might be better
- to use, since the LIST command output is not specified or standard in any
- way. It has turned out that the NLST list output is not the same on all
- servers either... */
-
- NBFTPSENDF(conn, "%s",
- data->set.customrequest?data->set.customrequest:
- (data->set.ftp_list_only?"NLST":"LIST"));
-
- state(conn, FTP_LIST);
-
- return result;
-}
-
-static CURLcode ftp_state_post_retrtype(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
-
- /* We've sent the TYPE, now we must send the list of prequote strings */
-
- result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
-
- return result;
-}
-
-static CURLcode ftp_state_post_stortype(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
-
- /* We've sent the TYPE, now we must send the list of prequote strings */
-
- result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
-
- return result;
-}
-
-static CURLcode ftp_state_post_mdtm(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- struct SessionHandle *data = conn->data;
-
- /* If we have selected NOBODY and HEADER, it means that we only want file
- information. Which in FTP can't be much more than the file size and
- date. */
- if(conn->bits.no_body && data->set.include_header && ftp->file &&
- ftp_need_type(conn, data->set.prefer_ascii)) {
- /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
- may not support it! It is however the only way we have to get a file's
- size! */
-
- ftp->no_transfer = TRUE; /* this means no actual transfer will be made */
-
- /* Some servers return different sizes for different modes, and thus we
- must set the proper type before we check the size */
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
- if (result)
- return result;
- }
- else
- result = ftp_state_post_type(conn);
-
- return result;
-}
-
-/* This is called after the CWD commands have been done in the beginning of
- the DO phase */
-static CURLcode ftp_state_post_cwd(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- struct SessionHandle *data = conn->data;
-
- /* Requested time of file or time-depended transfer? */
- if((data->set.get_filetime || data->set.timecondition) && ftp->file) {
-
- /* we have requested to get the modified-time of the file, this is a white
- spot as the MDTM is not mentioned in RFC959 */
- NBFTPSENDF(conn, "MDTM %s", ftp->file);
-
- state(conn, FTP_MDTM);
- }
- else
- result = ftp_state_post_mdtm(conn);
-
- return result;
-}
-
-
-/* This is called after the TYPE and possible quote commands have been sent */
-static CURLcode ftp_state_ul_setup(struct connectdata *conn,
- bool sizechecked)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- struct SessionHandle *data = conn->data;
- curl_off_t passed=0;
-
- if((data->reqdata.resume_from && !sizechecked) ||
- ((data->reqdata.resume_from > 0) && sizechecked)) {
- /* we're about to continue the uploading of a file */
- /* 1. get already existing file's size. We use the SIZE command for this
- which may not exist in the server! The SIZE command is not in
- RFC959. */
-
- /* 2. This used to set REST. But since we can do append, we
- don't another ftp command. We just skip the source file
- offset and then we APPEND the rest on the file instead */
-
- /* 3. pass file-size number of bytes in the source file */
- /* 4. lower the infilesize counter */
- /* => transfer as usual */
-
- if(data->reqdata.resume_from < 0 ) {
- /* Got no given size to start from, figure it out */
- NBFTPSENDF(conn, "SIZE %s", ftp->file);
- state(conn, FTP_STOR_SIZE);
- return result;
- }
-
- /* enable append */
- data->set.ftp_append = TRUE;
-
- /* Let's read off the proper amount of bytes from the input. If we knew it
- was a proper file we could've just fseek()ed but we only have a stream
- here */
-
- /* TODO: allow the ioctlfunction to provide a fast forward function that
- can be used here and use this method only as a fallback! */
- do {
- curl_off_t readthisamountnow = (data->reqdata.resume_from - passed);
- curl_off_t actuallyread;
-
- if(readthisamountnow > BUFSIZE)
- readthisamountnow = BUFSIZE;
-
- actuallyread = (curl_off_t)
- conn->fread(data->state.buffer, 1, (size_t)readthisamountnow,
- conn->fread_in);
-
- passed += actuallyread;
- if(actuallyread != readthisamountnow) {
- failf(data, "Could only read %" FORMAT_OFF_T
- " bytes from the input", passed);
- return CURLE_FTP_COULDNT_USE_REST;
- }
- } while(passed != data->reqdata.resume_from);
-
- /* now, decrease the size of the read */
- if(data->set.infilesize>0) {
- data->set.infilesize -= data->reqdata.resume_from;
-
- if(data->set.infilesize <= 0) {
- infof(data, "File already completely uploaded\n");
-
- /* no data to transfer */
- result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
- /* Set no_transfer so that we won't get any error in
- * Curl_ftp_done() because we didn't transfer anything! */
- ftp->no_transfer = TRUE;
-
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- }
- /* we've passed, proceed as normal */
- } /* resume_from */
-
- NBFTPSENDF(conn, data->set.ftp_append?"APPE %s":"STOR %s",
- ftp->file);
-
- state(conn, FTP_STOR);
-
- return result;
-}
-
-static CURLcode ftp_state_quote(struct connectdata *conn,
- bool init,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- bool quote=FALSE;
- struct curl_slist *item;
-
- switch(instate) {
- case FTP_QUOTE:
- default:
- item = data->set.quote;
- break;
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- item = data->set.prequote;
- break;
- case FTP_POSTQUOTE:
- item = data->set.postquote;
- break;
- }
-
- if(init)
- ftpc->count1 = 0;
- else
- ftpc->count1++;
-
- if(item) {
- int i = 0;
-
- /* Skip count1 items in the linked list */
- while((i< ftpc->count1) && item) {
- item = item->next;
- i++;
- }
- if(item) {
- NBFTPSENDF(conn, "%s", item->data);
- state(conn, instate);
- quote = TRUE;
- }
- }
-
- if(!quote) {
- /* No more quote to send, continue to ... */
- switch(instate) {
- case FTP_QUOTE:
- default:
- result = ftp_state_cwd(conn);
- break;
- case FTP_RETR_PREQUOTE:
- if (ftp->no_transfer)
- state(conn, FTP_STOP);
- else {
- NBFTPSENDF(conn, "SIZE %s", ftp->file);
- state(conn, FTP_RETR_SIZE);
- }
- break;
- case FTP_STOR_PREQUOTE:
- result = ftp_state_ul_setup(conn, FALSE);
- break;
- case FTP_POSTQUOTE:
- break;
- }
- }
-
- return result;
-}
-
-static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
- int ftpcode)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- struct SessionHandle *data=conn->data;
- Curl_addrinfo *conninfo;
- struct Curl_dns_entry *addr=NULL;
- int rc;
- unsigned short connectport; /* the local port connect() should use! */
- unsigned short newport=0; /* remote port */
- bool connected;
-
- /* newhost must be able to hold a full IP-style address in ASCII, which
- in the IPv6 case means 5*8-1 = 39 letters */
-#define NEWHOST_BUFSIZE 48
- char newhost[NEWHOST_BUFSIZE];
- char *str=&data->state.buffer[4]; /* start on the first letter */
-
- if((ftpc->count1 == 0) &&
- (ftpcode == 229)) {
- /* positive EPSV response */
- char *ptr = strchr(str, '(');
- if(ptr) {
- unsigned int num;
- char separator[4];
- ptr++;
- if(5 == sscanf(ptr, "%c%c%c%u%c",
- &separator[0],
- &separator[1],
- &separator[2],
- &num,
- &separator[3])) {
- const char sep1 = separator[0];
- int i;
-
- /* The four separators should be identical, or else this is an oddly
- formatted reply and we bail out immediately. */
- for(i=1; i<4; i++) {
- if(separator[i] != sep1) {
- ptr=NULL; /* set to NULL to signal error */
- break;
- }
- }
- if(ptr) {
- newport = num;
-
- if (conn->bits.tunnel_proxy)
- /* proxy tunnel -> use other host info because ip_addr_str is the
- proxy address not the ftp host */
- snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
- else
- /* use the same IP we are already connected to */
- snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
- }
- }
- else
- ptr=NULL;
- }
- if(!ptr) {
- failf(data, "Weirdly formatted EPSV reply");
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
- }
- else if((ftpc->count1 == 1) &&
- (ftpcode == 227)) {
- /* positive PASV response */
- int ip[4];
- int port[2];
-
- /*
- * Scan for a sequence of six comma-separated numbers and use them as
- * IP+port indicators.
- *
- * Found reply-strings include:
- * "227 Entering Passive Mode (127,0,0,1,4,51)"
- * "227 Data transfer will passively listen to 127,0,0,1,4,51"
- * "227 Entering passive mode. 127,0,0,1,4,51"
- */
- while(*str) {
- if (6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
- &ip[0], &ip[1], &ip[2], &ip[3],
- &port[0], &port[1]))
- break;
- str++;
- }
-
- if(!*str) {
- failf(data, "Couldn't interpret the 227-response");
- return CURLE_FTP_WEIRD_227_FORMAT;
- }
-
- /* we got OK from server */
- if(data->set.ftp_skip_ip) {
- /* told to ignore the remotely given IP but instead use the one we used
- for the control connection */
- infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
- ip[0], ip[1], ip[2], ip[3],
- conn->ip_addr_str);
- if (conn->bits.tunnel_proxy)
- /* proxy tunnel -> use other host info because ip_addr_str is the
- proxy address not the ftp host */
- snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
- else
- snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
- }
- else
- snprintf(newhost, sizeof(newhost),
- "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
- newport = (port[0]<<8) + port[1];
- }
- else if(ftpc->count1 == 0) {
- /* EPSV failed, move on to PASV */
-
- /* disable it for next transfer */
- conn->bits.ftp_use_epsv = FALSE;
- infof(data, "disabling EPSV usage\n");
-
- NBFTPSENDF(conn, "PASV", NULL);
- ftpc->count1++;
- /* remain in the FTP_PASV state */
- return result;
- }
- else {
- failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
- return CURLE_FTP_WEIRD_PASV_REPLY;
- }
-
- if(data->set.proxy && *data->set.proxy) {
- /*
- * This is a tunnel through a http proxy and we need to connect to the
- * proxy again here.
- *
- * We don't want to rely on a former host lookup that might've expired
- * now, instead we remake the lookup here and now!
- */
- rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr);
- if(rc == CURLRESOLV_PENDING)
- /* BLOCKING */
- rc = Curl_wait_for_resolv(conn, &addr);
-
- connectport =
- (unsigned short)conn->port; /* we connect to the proxy's port */
-
- }
- else {
- /* normal, direct, ftp connection */
- rc = Curl_resolv(conn, newhost, newport, &addr);
- if(rc == CURLRESOLV_PENDING)
- /* BLOCKING */
- rc = Curl_wait_for_resolv(conn, &addr);
-
- if(!addr) {
- failf(data, "Can't resolve new host %s:%d", newhost, newport);
- return CURLE_FTP_CANT_GET_HOST;
- }
- connectport = newport; /* we connect to the remote port */
- }
-
- result = Curl_connecthost(conn,
- addr,
- &conn->sock[SECONDARYSOCKET],
- &conninfo,
- &connected);
-
- Curl_resolv_unlock(data, addr); /* we're done using this address */
-
- if (result && ftpc->count1 == 0 && ftpcode == 229) {
- infof(data, "got positive EPSV response, but can't connect. "
- "Disabling EPSV\n");
- /* disable it for next transfer */
- conn->bits.ftp_use_epsv = FALSE;
- data->state.errorbuf = FALSE; /* allow error message to get rewritten */
- NBFTPSENDF(conn, "PASV", NULL);
- ftpc->count1++;
- /* remain in the FTP_PASV state */
- return result;
- }
-
- if(result)
- return result;
-
- conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */
-
- /*
- * When this is used from the multi interface, this might've returned with
- * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
- * connect to connect and we should not be "hanging" here waiting.
- */
-
- if(data->set.verbose)
- /* this just dumps information about this second connection */
- ftp_pasv_verbose(conn, conninfo, newhost, connectport);
-
-#ifndef CURL_DISABLE_HTTP
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
- /* FIX: this MUST wait for a proper connect first if 'connected' is
- * FALSE */
-
- /* BLOCKING */
- /* We want "seamless" FTP operations through HTTP proxy tunnel */
-
- /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
- * conn->proto.http; we want FTP through HTTP and we have to change the
- * member temporarily for connecting to the HTTP proxy. After
- * Curl_proxyCONNECT we have to set back the member to the original struct
- * FTP pointer
- */
- struct HTTP http_proxy;
- struct FTP *ftp_save = data->reqdata.proto.ftp;
- memset(&http_proxy, 0, sizeof(http_proxy));
- data->reqdata.proto.http = &http_proxy;
-
- result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
-
- data->reqdata.proto.ftp = ftp_save;
-
- if(CURLE_OK != result)
- return result;
- }
-#endif /* CURL_DISABLE_HTTP */
-
- state(conn, FTP_STOP); /* this phase is completed */
-
- return result;
-}
-
-static CURLcode ftp_state_port_resp(struct connectdata *conn,
- int ftpcode)
-{
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- ftpport fcmd = (ftpport)ftpc->count1;
- CURLcode result = CURLE_OK;
-
- if(ftpcode != 200) {
- /* the command failed */
-
- if (EPRT == fcmd) {
- infof(data, "disabling EPRT usage\n");
- conn->bits.ftp_use_eprt = FALSE;
- }
- fcmd++;
-
- if(fcmd == DONE) {
- failf(data, "Failed to do PORT");
- result = CURLE_FTP_PORT_FAILED;
- }
- else
- /* try next */
- result = ftp_state_use_port(conn, fcmd);
- }
- else {
- infof(data, "Connect data stream actively\n");
- state(conn, FTP_STOP); /* end of DO phase */
- }
-
- return result;
-}
-
-static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
- int ftpcode)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
-
- switch(ftpcode) {
- case 213:
- {
- /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
- last .sss part is optional and means fractions of a second */
- int year, month, day, hour, minute, second;
- char *buf = data->state.buffer;
- if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
- &year, &month, &day, &hour, &minute, &second)) {
- /* we have a time, reformat it */
- time_t secs=time(NULL);
- /* using the good old yacc/bison yuck */
- snprintf(buf, sizeof(conn->data->state.buffer),
- "%04d%02d%02d %02d:%02d:%02d GMT",
- year, month, day, hour, minute, second);
- /* now, convert this into a time() value: */
- data->info.filetime = (long)curl_getdate(buf, &secs);
- }
-
- /* If we asked for a time of the file and we actually got one as well,
- we "emulate" a HTTP-style header in our output. */
-
- if(conn->bits.no_body &&
- data->set.include_header &&
- ftp->file &&
- data->set.get_filetime &&
- (data->info.filetime>=0) ) {
- struct tm *tm;
- time_t clock = (time_t)data->info.filetime;
-#ifdef HAVE_GMTIME_R
- struct tm buffer;
- tm = (struct tm *)gmtime_r(&clock, &buffer);
-#else
- tm = gmtime(&clock);
-#endif
- /* format: "Tue, 15 Nov 1994 12:45:26" */
- snprintf(buf, BUFSIZE-1,
- "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- if(result)
- return result;
- } /* end of a ridiculous amount of conditionals */
- }
- break;
- default:
- infof(data, "unsupported MDTM reply format\n");
- break;
- case 550: /* "No such file or directory" */
- failf(data, "Given file does not exist");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- break;
- }
-
- if(data->set.timecondition) {
- if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
- switch(data->set.timecondition) {
- case CURL_TIMECOND_IFMODSINCE:
- default:
- if(data->info.filetime <= data->set.timevalue) {
- infof(data, "The requested document is not new enough\n");
- ftp->no_transfer = TRUE; /* mark this to not transfer data */
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- case CURL_TIMECOND_IFUNMODSINCE:
- if(data->info.filetime > data->set.timevalue) {
- infof(data, "The requested document is not old enough\n");
- ftp->no_transfer = TRUE; /* mark this to not transfer data */
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
- break;
- } /* switch */
- }
- else {
- infof(data, "Skipping time comparison\n");
- }
- }
-
- if(!result)
- result = ftp_state_post_mdtm(conn);
-
- return result;
-}
-
-static CURLcode ftp_state_type_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
-
- if(ftpcode/100 != 2) {
- /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
- successful 'TYPE I'. While that is not as RFC959 says, it is still a
- positive response code and we allow that. */
- failf(data, "Couldn't set desired mode");
- return CURLE_FTP_COULDNT_SET_BINARY; /* FIX */
- }
- if(ftpcode != 200)
- infof(data, "Got a %03d response code instead of the assumed 200\n",
- ftpcode);
-
- if(instate == FTP_TYPE)
- result = ftp_state_post_type(conn);
- else if(instate == FTP_LIST_TYPE)
- result = ftp_state_post_listtype(conn);
- else if(instate == FTP_RETR_TYPE)
- result = ftp_state_post_retrtype(conn);
- else if(instate == FTP_STOR_TYPE)
- result = ftp_state_post_stortype(conn);
-
- return result;
-}
-
-static CURLcode ftp_state_post_retr_size(struct connectdata *conn,
- curl_off_t filesize)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
-
- if (data->set.max_filesize && (filesize > data->set.max_filesize)) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- ftp->downloadsize = filesize;
-
- if(data->reqdata.resume_from) {
- /* We always (attempt to) get the size of downloads, so it is done before
- this even when not doing resumes. */
- if(filesize == -1) {
- infof(data, "ftp server doesn't support SIZE\n");
- /* We couldn't get the size and therefore we can't know if there really
- is a part of the file left to get, although the server will just
- close the connection when we start the connection so it won't cause
- us any harm, just not make us exit as nicely. */
- }
- else {
- /* We got a file size report, so we check that there actually is a
- part of the file left to get, or else we go home. */
- if(data->reqdata.resume_from< 0) {
- /* We're supposed to download the last abs(from) bytes */
- if(filesize < -data->reqdata.resume_from) {
- failf(data, "Offset (%" FORMAT_OFF_T
- ") was beyond file size (%" FORMAT_OFF_T ")",
- data->reqdata.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- /* convert to size to download */
- ftp->downloadsize = -data->reqdata.resume_from;
- /* download from where? */
- data->reqdata.resume_from = filesize - ftp->downloadsize;
- }
- else {
- if(filesize < data->reqdata.resume_from) {
- failf(data, "Offset (%" FORMAT_OFF_T
- ") was beyond file size (%" FORMAT_OFF_T ")",
- data->reqdata.resume_from, filesize);
- return CURLE_BAD_DOWNLOAD_RESUME;
- }
- /* Now store the number of bytes we are expected to download */
- ftp->downloadsize = filesize-data->reqdata.resume_from;
- }
- }
-
- if(ftp->downloadsize == 0) {
- /* no data to transfer */
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- infof(data, "File already completely downloaded\n");
-
- /* Set no_transfer so that we won't get any error in Curl_ftp_done()
- * because we didn't transfer the any file */
- ftp->no_transfer = TRUE;
- state(conn, FTP_STOP);
- return CURLE_OK;
- }
-
- /* Set resume file transfer offset */
- infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
- "\n", data->reqdata.resume_from);
-
- NBFTPSENDF(conn, "REST %" FORMAT_OFF_T, data->reqdata.resume_from);
-
- state(conn, FTP_RETR_REST);
-
- }
- else {
- /* no resume */
- NBFTPSENDF(conn, "RETR %s", ftp->file);
- state(conn, FTP_RETR);
- }
-
- return result;
-}
-
-static CURLcode ftp_state_size_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data=conn->data;
- curl_off_t filesize;
- char *buf = data->state.buffer;
-
- /* get the size from the ascii string: */
- filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
-
- if(instate == FTP_SIZE) {
- if(-1 != filesize) {
- snprintf(buf, sizeof(data->state.buffer),
- "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
- result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
- if(result)
- return result;
- }
- result = ftp_state_post_size(conn);
- }
- else if(instate == FTP_RETR_SIZE)
- result = ftp_state_post_retr_size(conn, filesize);
- else if(instate == FTP_STOR_SIZE) {
- data->reqdata.resume_from = filesize;
- result = ftp_state_ul_setup(conn, TRUE);
- }
-
- return result;
-}
-
-static CURLcode ftp_state_rest_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
-
- switch(instate) {
- case FTP_REST:
- default:
- if (ftpcode == 350) {
- result = Curl_client_write(conn, CLIENTWRITE_BOTH,
- (char *)"Accept-ranges: bytes\r\n", 0);
- if(result)
- return result;
- }
-
- result = ftp_state_post_rest(conn);
- break;
-
- case FTP_RETR_REST:
- if (ftpcode != 350) {
- failf(conn->data, "Couldn't use REST");
- result = CURLE_FTP_COULDNT_USE_REST;
- }
- else {
- NBFTPSENDF(conn, "RETR %s", ftp->file);
- state(conn, FTP_RETR);
- }
- break;
- }
-
- return result;
-}
-
-static CURLcode ftp_state_stor_resp(struct connectdata *conn,
- int ftpcode)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
-
- if(ftpcode>=400) {
- failf(data, "Failed FTP upload: %0d", ftpcode);
- /* oops, we never close the sockets! */
- return CURLE_FTP_COULDNT_STOR_FILE;
- }
-
- if(data->set.ftp_use_port) {
- /* BLOCKING */
- /* PORT means we are now awaiting the server to connect to us. */
- result = AllowServerConnect(conn);
- if( result )
- return result;
- }
-
- if(conn->ssl[SECONDARYSOCKET].use) {
- /* since we only have a plaintext TCP connection here, we must now
- do the TLS stuff */
- infof(data, "Doing the SSL/TLS handshake on the data stream\n");
- /* BLOCKING */
- result = Curl_ssl_connect(conn, SECONDARYSOCKET);
- if(result)
- return result;
- }
-
- *(ftp->bytecountp)=0;
-
- /* When we know we're uploading a specified file, we can get the file
- size prior to the actual upload. */
-
- Curl_pgrsSetUploadSize(data, data->set.infilesize);
-
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
- SECONDARYSOCKET, ftp->bytecountp);
- state(conn, FTP_STOP);
-
- return result;
-}
-
-/* for LIST and RETR responses */
-static CURLcode ftp_state_get_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
- char *buf = data->state.buffer;
-
- if((ftpcode == 150) || (ftpcode == 125)) {
-
- /*
- A;
- 150 Opening BINARY mode data connection for /etc/passwd (2241
- bytes). (ok, the file is being transfered)
-
- B:
- 150 Opening ASCII mode data connection for /bin/ls
-
- C:
- 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
-
- D:
- 150 Opening ASCII mode data connection for /linux/fisk/kpanelrc (0.0.0.0,0) (545 bytes).
-
- E:
- 125 Data connection already open; Transfer starting. */
-
- curl_off_t size=-1; /* default unknown size */
-
-
- /*
- * It appears that there are FTP-servers that return size 0 for files when
- * SIZE is used on the file while being in BINARY mode. To work around
- * that (stupid) behavior, we attempt to parse the RETR response even if
- * the SIZE returned size zero.
- *
- * Debugging help from Salvatore Sorrentino on February 26, 2003.
- */
-
- if((instate != FTP_LIST) &&
- !data->set.prefer_ascii &&
- (ftp->downloadsize < 1)) {
- /*
- * It seems directory listings either don't show the size or very
- * often uses size 0 anyway. ASCII transfers may very well turn out
- * that the transfered amount of data is not the same as this line
- * tells, why using this number in those cases only confuses us.
- *
- * Example D above makes this parsing a little tricky */
- char *bytes;
- bytes=strstr(buf, " bytes");
- if(bytes--) {
- long in=(long)(bytes-buf);
- /* this is a hint there is size information in there! ;-) */
- while(--in) {
- /* scan for the left parenthesis and break there */
- if('(' == *bytes)
- break;
- /* skip only digits */
- if(!ISDIGIT(*bytes)) {
- bytes=NULL;
- break;
- }
- /* one more estep backwards */
- bytes--;
- }
- /* if we have nothing but digits: */
- if(bytes++) {
- /* get the number! */
- size = curlx_strtoofft(bytes, NULL, 0);
- }
- }
- }
- else if(ftp->downloadsize > -1)
- size = ftp->downloadsize;
-
- if(data->set.ftp_use_port) {
- /* BLOCKING */
- result = AllowServerConnect(conn);
- if( result )
- return result;
- }
-
- if(conn->ssl[SECONDARYSOCKET].use) {
- /* since we only have a plaintext TCP connection here, we must now
- do the TLS stuff */
- infof(data, "Doing the SSL/TLS handshake on the data stream\n");
- result = Curl_ssl_connect(conn, SECONDARYSOCKET);
- if(result)
- return result;
- }
-
- if(size > data->reqdata.maxdownload && data->reqdata.maxdownload > 0)
- size = data->reqdata.size = data->reqdata.maxdownload;
-
- infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->reqdata.maxdownload);
-
- if(instate != FTP_LIST)
- infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
-
- /* FTP download: */
- result=Curl_setup_transfer(conn, SECONDARYSOCKET, size, FALSE,
- ftp->bytecountp,
- -1, NULL); /* no upload here */
- if(result)
- return result;
-
- state(conn, FTP_STOP);
- }
- else {
- if((instate == FTP_LIST) && (ftpcode == 450)) {
- /* simply no matching files in the dir listing */
- ftp->no_transfer = TRUE; /* don't download anything */
- state(conn, FTP_STOP); /* this phase is over */
- }
- else {
- failf(data, "RETR response: %03d", ftpcode);
- return CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
-
- return result;
-}
-
-/* after USER, PASS and ACCT */
-static CURLcode ftp_state_loggedin(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
-
-#ifdef HAVE_KRB4
- if(conn->data->set.krb4) {
- /* We are logged in, asked to use Kerberos. Set the requested
- * protection level
- */
- if(conn->sec_complete)
- /* BLOCKING */
- Curl_sec_set_protection_level(conn);
-
- /* We may need to issue a KAUTH here to have access to the files
- * do it if user supplied a password
- */
- if(conn->passwd && *conn->passwd) {
- /* BLOCKING */
- result = Curl_krb_kauth(conn);
- if(result)
- return result;
- }
- }
-#endif
- if(conn->ssl[FIRSTSOCKET].use) {
- /* PBSZ = PROTECTION BUFFER SIZE.
-
- The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
-
- Specifically, the PROT command MUST be preceded by a PBSZ
- command and a PBSZ command MUST be preceded by a successful
- security data exchange (the TLS negotiation in this case)
-
- ... (and on page 8):
-
- Thus the PBSZ command must still be issued, but must have a
- parameter of '0' to indicate that no buffering is taking place
- and the data connection should not be encapsulated.
- */
- NBFTPSENDF(conn, "PBSZ %d", 0);
- state(conn, FTP_PBSZ);
- }
- else {
- result = ftp_state_pwd(conn);
- }
- return result;
-}
-
-/* for USER and PASS responses */
-static CURLcode ftp_state_user_resp(struct connectdata *conn,
- int ftpcode,
- ftpstate instate)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- (void)instate; /* no use for this yet */
-
- if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
- /* 331 Password required for ...
- (the server requires to send the user's password too) */
- NBFTPSENDF(conn, "PASS %s", ftp->passwd?ftp->passwd:"");
- state(conn, FTP_PASS);
- }
- else if(ftpcode/100 == 2) {
- /* 230 User ... logged in.
- (the user logged in with or without password) */
- result = ftp_state_loggedin(conn);
- }
- else if(ftpcode == 332) {
- if(data->set.ftp_account) {
- NBFTPSENDF(conn, "ACCT %s", data->set.ftp_account);
- state(conn, FTP_ACCT);
- }
- else {
- failf(data, "ACCT requested but none available");
- result = CURLE_LOGIN_DENIED;
- }
- }
- else {
- /* All other response codes, like:
-
- 530 User ... access denied
- (the server denies to log the specified user) */
-
- if (conn->data->set.ftp_alternative_to_user &&
- !conn->data->state.ftp_trying_alternative) {
- /* Ok, USER failed. Let's try the supplied command. */
- NBFTPSENDF(conn, "%s", conn->data->set.ftp_alternative_to_user);
- conn->data->state.ftp_trying_alternative = TRUE;
- state(conn, FTP_USER);
- result = CURLE_OK;
- }
- else {
- failf(data, "Access denied: %03d", ftpcode);
- result = CURLE_LOGIN_DENIED;
- }
- }
- return result;
-}
-
-/* for ACCT response */
-static CURLcode ftp_state_acct_resp(struct connectdata *conn,
- int ftpcode)
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- if(ftpcode != 230) {
- failf(data, "ACCT rejected by server: %03d", ftpcode);
- result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
- }
- else
- result = ftp_state_loggedin(conn);
-
- return result;
-}
-
-
-static CURLcode ftp_statemach_act(struct connectdata *conn)
-{
- CURLcode result;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- struct SessionHandle *data=conn->data;
- int ftpcode;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- static const char * const ftpauth[] = {
- "SSL", "TLS"
- };
- size_t nread = 0;
-
- if(ftpc->sendleft) {
- /* we have a piece of a command still left to send */
- ssize_t written;
- result = Curl_write(conn, sock, ftpc->sendthis + ftpc->sendsize -
- ftpc->sendleft, ftpc->sendleft, &written);
- if(result)
- return result;
-
- if(written != (ssize_t)ftpc->sendleft) {
- /* only a fraction was sent */
- ftpc->sendleft -= written;
- }
- else {
- free(ftpc->sendthis);
- ftpc->sendthis=NULL;
- ftpc->sendleft = ftpc->sendsize = 0;
- ftpc->response = Curl_tvnow();
- }
- return CURLE_OK;
- }
-
- /* we read a piece of response */
- result = ftp_readresp(sock, conn, &ftpcode, &nread);
- if(result)
- return result;
-
- if(ftpcode) {
- /* we have now received a full FTP server response */
- switch(ftpc->state) {
- case FTP_WAIT220:
- if(ftpcode != 220) {
- failf(data, "This doesn't seem like a nice ftp-server response");
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
-
- /* We have received a 220 response fine, now we proceed. */
-#ifdef HAVE_KRB4
- if(data->set.krb4) {
- /* If not anonymous login, try a secure login. Note that this
- procedure is still BLOCKING. */
-
- Curl_sec_request_prot(conn, "private");
- /* We set private first as default, in case the line below fails to
- set a valid level */
- Curl_sec_request_prot(conn, data->set.krb4_level);
-
- if(Curl_sec_login(conn) != 0)
- infof(data, "Logging in with password in cleartext!\n");
- else
- infof(data, "Authentication successful\n");
- }
-#endif
-
- if(data->set.ftp_ssl && !conn->ssl[FIRSTSOCKET].use) {
- /* We don't have a SSL/TLS connection yet, but FTPS is
- requested. Try a FTPS connection now */
-
- ftpc->count3=0;
- switch(data->set.ftpsslauth) {
- case CURLFTPAUTH_DEFAULT:
- case CURLFTPAUTH_SSL:
- ftpc->count2 = 1; /* add one to get next */
- ftpc->count1 = 0;
- break;
- case CURLFTPAUTH_TLS:
- ftpc->count2 = -1; /* subtract one to get next */
- ftpc->count1 = 1;
- break;
- default:
- failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d\n",
- data->set.ftpsslauth);
- return CURLE_FAILED_INIT; /* we don't know what to do */
- }
- NBFTPSENDF(conn, "AUTH %s", ftpauth[ftpc->count1]);
- state(conn, FTP_AUTH);
- }
- else {
- result = ftp_state_user(conn);
- if(result)
- return result;
- }
-
- break;
-
- case FTP_AUTH:
- /* we have gotten the response to a previous AUTH command */
-
- /* RFC2228 (page 5) says:
- *
- * If the server is willing to accept the named security mechanism,
- * and does not require any security data, it must respond with
- * reply code 234/334.
- */
-
- if((ftpcode == 234) || (ftpcode == 334)) {
- /* Curl_ssl_connect is BLOCKING */
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(CURLE_OK == result) {
- conn->protocol |= PROT_FTPS;
- conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
- result = ftp_state_user(conn);
- }
- }
- else if(ftpc->count3 < 1) {
- ftpc->count3++;
- ftpc->count1 += ftpc->count2; /* get next attempt */
- result = Curl_nbftpsendf(conn, "AUTH %s", ftpauth[ftpc->count1]);
- /* remain in this same state */
- }
- else {
- if(data->set.ftp_ssl > CURLFTPSSL_TRY)
- /* we failed and CURLFTPSSL_CONTROL or CURLFTPSSL_ALL is set */
- result = CURLE_FTP_SSL_FAILED;
- else
- /* ignore the failure and continue */
- result = ftp_state_user(conn);
- }
-
- if(result)
- return result;
- break;
-
- case FTP_USER:
- case FTP_PASS:
- result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
- break;
-
- case FTP_ACCT:
- result = ftp_state_acct_resp(conn, ftpcode);
- break;
-
- case FTP_PBSZ:
- /* FIX: check response code */
-
- /* For TLS, the data connection can have one of two security levels.
-
- 1) Clear (requested by 'PROT C')
-
- 2)Private (requested by 'PROT P')
- */
- if(!conn->ssl[SECONDARYSOCKET].use) {
- NBFTPSENDF(conn, "PROT %c",
- data->set.ftp_ssl == CURLFTPSSL_CONTROL ? 'C' : 'P');
- state(conn, FTP_PROT);
- }
- else {
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- }
-
- break;
-
- case FTP_PROT:
- if(ftpcode/100 == 2)
- /* We have enabled SSL for the data connection! */
- conn->ssl[SECONDARYSOCKET].use =
- (bool)(data->set.ftp_ssl != CURLFTPSSL_CONTROL);
- /* FTP servers typically responds with 500 if they decide to reject
- our 'P' request */
- else if(data->set.ftp_ssl> CURLFTPSSL_CONTROL)
- /* we failed and bails out */
- return CURLE_FTP_SSL_FAILED;
-
- if(data->set.ftp_use_ccc) {
- /* CCC - Clear Command Channel
- */
- NBFTPSENDF(conn, "CCC", NULL);
- state(conn, FTP_CCC);
- }
- else {
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- }
- break;
-
- case FTP_CCC:
- if (ftpcode < 500) {
- /* First shut down the SSL layer (note: this call will block) */
- result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
-
- if(result) {
- failf(conn->data, "Failed to clear the command channel (CCC)");
- return result;
- }
- }
-
- /* Then continue as normal */
- result = ftp_state_pwd(conn);
- if(result)
- return result;
- break;
-
- case FTP_PWD:
- if(ftpcode == 257) {
- char *dir = (char *)malloc(nread+1);
- char *store=dir;
- char *ptr=&data->state.buffer[4]; /* start on the first letter */
-
- if(!dir)
- return CURLE_OUT_OF_MEMORY;
-
- /* Reply format is like
- 257<space>"<directory-name>"<space><commentary> and the RFC959
- says
-
- The directory name can contain any character; embedded
- double-quotes should be escaped by double-quotes (the
- "quote-doubling" convention).
- */
- if('\"' == *ptr) {
- /* it started good */
- ptr++;
- while(ptr && *ptr) {
- if('\"' == *ptr) {
- if('\"' == ptr[1]) {
- /* "quote-doubling" */
- *store = ptr[1];
- ptr++;
- }
- else {
- /* end of path */
- *store = '\0'; /* zero terminate */
- break; /* get out of this loop */
- }
- }
- else
- *store = *ptr;
- store++;
- ptr++;
- }
- ftpc->entrypath =dir; /* remember this */
- infof(data, "Entry path is '%s'\n", ftpc->entrypath);
- /* also save it where getinfo can access it: */
- data->state.most_recent_ftp_entrypath = ftpc->entrypath;
- }
- else {
- /* couldn't get the path */
- free(dir);
- infof(data, "Failed to figure out path\n");
- }
- }
- state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
- DEBUGF(infof(data, "protocol connect phase DONE\n"));
- break;
-
- case FTP_QUOTE:
- case FTP_POSTQUOTE:
- case FTP_RETR_PREQUOTE:
- case FTP_STOR_PREQUOTE:
- if(ftpcode >= 400) {
- failf(conn->data, "QUOT command failed with %03d", ftpcode);
- return CURLE_FTP_QUOTE_ERROR;
- }
- result = ftp_state_quote(conn, FALSE, ftpc->state);
- if(result)
- return result;
-
- break;
-
- case FTP_CWD:
- if(ftpcode/100 != 2) {
- /* failure to CWD there */
- if(conn->data->set.ftp_create_missing_dirs &&
- ftpc->count1 && !ftpc->count2) {
- /* try making it */
- ftpc->count2++; /* counter to prevent CWD-MKD loops */
- NBFTPSENDF(conn, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
- state(conn, FTP_MKD);
- }
- else {
- /* return failure */
- failf(data, "Server denied you to change to the given directory");
- ftpc->cwdfail = TRUE; /* don't remember this path as we failed
- to enter it */
- return CURLE_FTP_ACCESS_DENIED;
- }
- }
- else {
- /* success */
- ftpc->count2=0;
- if(++ftpc->count1 <= ftpc->dirdepth) {
- /* send next CWD */
- NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
- }
- else {
- result = ftp_state_post_cwd(conn);
- if(result)
- return result;
- }
- }
- break;
-
- case FTP_MKD:
- if(ftpcode/100 != 2) {
- /* failure to MKD the dir */
- failf(data, "Failed to MKD dir: %03d", ftpcode);
- return CURLE_FTP_ACCESS_DENIED;
- }
- state(conn, FTP_CWD);
- /* send CWD */
- NBFTPSENDF(conn, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
- break;
-
- case FTP_MDTM:
- result = ftp_state_mdtm_resp(conn, ftpcode);
- break;
-
- case FTP_TYPE:
- case FTP_LIST_TYPE:
- case FTP_RETR_TYPE:
- case FTP_STOR_TYPE:
- result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
- break;
-
- case FTP_SIZE:
- case FTP_RETR_SIZE:
- case FTP_STOR_SIZE:
- result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
- break;
-
- case FTP_REST:
- case FTP_RETR_REST:
- result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
- break;
-
- case FTP_PASV:
- result = ftp_state_pasv_resp(conn, ftpcode);
- break;
-
- case FTP_PORT:
- result = ftp_state_port_resp(conn, ftpcode);
- break;
-
- case FTP_LIST:
- case FTP_RETR:
- result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
- break;
-
- case FTP_STOR:
- result = ftp_state_stor_resp(conn, ftpcode);
- break;
-
- case FTP_QUIT:
- /* fallthrough, just stop! */
- default:
- /* internal error */
- state(conn, FTP_STOP);
- break;
- }
- } /* if(ftpcode) */
-
- return result;
-}
-
-/* Returns timeout in ms. 0 or negative number means the timeout has already
- triggered */
-static long ftp_state_timeout(struct connectdata *conn)
-{
- struct SessionHandle *data=conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- long timeout_ms=360000; /* in milliseconds */
-
- if(data->set.ftp_response_timeout )
- /* if CURLOPT_FTP_RESPONSE_TIMEOUT is set, use that to determine remaining
- time. Also, use ftp->response because FTP_RESPONSE_TIMEOUT is supposed
- to govern the response for any given ftp response, not for the time
- from connect to the given ftp response. */
- timeout_ms = data->set.ftp_response_timeout*1000 - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
- else if(data->set.timeout)
- /* if timeout is requested, find out how much remaining time we have */
- timeout_ms = data->set.timeout*1000 - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
- else
- /* Without a requested timeout, we only wait 'response_time' seconds for
- the full response to arrive before we bail out */
- timeout_ms = ftpc->response_time*1000 -
- Curl_tvdiff(Curl_tvnow(), ftpc->response); /* spent time */
-
- return timeout_ms;
-}
-
-
-/* called repeatedly until done from multi.c */
-CURLcode Curl_ftp_multi_statemach(struct connectdata *conn,
- bool *done)
-{
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- int rc;
- struct SessionHandle *data=conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
- long timeout_ms = ftp_state_timeout(conn);
-
- *done = FALSE; /* default to not done yet */
-
- if(timeout_ms <= 0) {
- failf(data, "FTP response timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
- ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
- 0);
-
- if(rc == -1) {
- failf(data, "select error");
- return CURLE_OUT_OF_MEMORY;
- }
- else if(rc != 0) {
- result = ftp_statemach_act(conn);
- *done = (bool)(ftpc->state == FTP_STOP);
- }
- /* if rc == 0, then select() timed out */
-
- return result;
-}
-
-static CURLcode ftp_easy_statemach(struct connectdata *conn)
-{
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- int rc;
- struct SessionHandle *data=conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = CURLE_OK;
-
- while(ftpc->state != FTP_STOP) {
- long timeout_ms = ftp_state_timeout(conn);
-
- if(timeout_ms <=0 ) {
- failf(data, "FTP response timeout");
- return CURLE_OPERATION_TIMEDOUT; /* already too little time */
- }
-
- rc = Curl_select(ftpc->sendleft?CURL_SOCKET_BAD:sock, /* reading */
- ftpc->sendleft?sock:CURL_SOCKET_BAD, /* writing */
- (int)timeout_ms);
-
- if(rc == -1) {
- failf(data, "select error");
- return CURLE_OUT_OF_MEMORY;
- }
- else if(rc == 0) {
- result = CURLE_OPERATION_TIMEDOUT;
- break;
- }
- else {
- result = ftp_statemach_act(conn);
- if(result)
- break;
- }
- }
-
- return result;
-}
-
-/*
- * Allocate and initialize the struct FTP for the current SessionHandle. If
- * need be.
- */
-static CURLcode ftp_init(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- struct FTP *ftp;
- if(data->reqdata.proto.ftp)
- return CURLE_OK;
-
- ftp = (struct FTP *)calloc(sizeof(struct FTP), 1);
- if(!ftp)
- return CURLE_OUT_OF_MEMORY;
-
- data->reqdata.proto.ftp = ftp;
-
- /* get some initial data into the ftp struct */
- ftp->bytecountp = &data->reqdata.keep.bytecount;
-
- /* no need to duplicate them, this connectdata struct won't change */
- ftp->user = conn->user;
- ftp->passwd = conn->passwd;
- if (isBadFtpString(ftp->user) || isBadFtpString(ftp->passwd))
- return CURLE_URL_MALFORMAT;
-
- return CURLE_OK;
-}
-
-/*
- * Curl_ftp_connect() should do everything that is to be considered a part of
- * the connection phase.
- *
- * The variable 'done' points to will be TRUE if the protocol-layer connect
- * phase is done when this function returns, or FALSE is not. When called as
- * a part of the easy interface, it will always be TRUE.
- */
-CURLcode Curl_ftp_connect(struct connectdata *conn,
- bool *done) /* see description above */
-{
- CURLcode result;
-#ifndef CURL_DISABLE_HTTP
- /* for FTP over HTTP proxy */
- struct HTTP http_proxy;
- struct FTP *ftp_save;
-#endif /* CURL_DISABLE_HTTP */
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- struct SessionHandle *data=conn->data;
-
- *done = FALSE; /* default to not done yet */
-
- if (data->reqdata.proto.ftp) {
- Curl_ftp_disconnect(conn);
- free(data->reqdata.proto.ftp);
- data->reqdata.proto.ftp = NULL;
- }
-
- result = ftp_init(conn);
- if(result)
- return result;
-
- /* We always support persistant connections on ftp */
- conn->bits.close = FALSE;
-
- ftpc->response_time = 3600; /* set default response time-out */
-
-#ifndef CURL_DISABLE_HTTP
- if (conn->bits.tunnel_proxy && conn->bits.httpproxy) {
- /* BLOCKING */
- /* We want "seamless" FTP operations through HTTP proxy tunnel */
-
- /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
- * conn->proto.http; we want FTP through HTTP and we have to change the
- * member temporarily for connecting to the HTTP proxy. After
- * Curl_proxyCONNECT we have to set back the member to the original struct
- * FTP pointer
- */
- ftp_save = data->reqdata.proto.ftp;
- memset(&http_proxy, 0, sizeof(http_proxy));
- data->reqdata.proto.http = &http_proxy;
-
- result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
- conn->host.name, conn->remote_port);
-
- data->reqdata.proto.ftp = ftp_save;
-
- if(CURLE_OK != result)
- return result;
- }
-#endif /* CURL_DISABLE_HTTP */
-
- if(conn->protocol & PROT_FTPS) {
- /* BLOCKING */
- /* FTPS is simply ftp with SSL for the control channel */
- /* now, perform the SSL initialization for this socket */
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
- }
-
- /* When we connect, we start in the state where we await the 220
- response */
- ftp_respinit(conn); /* init the response reader stuff */
- state(conn, FTP_WAIT220);
- ftpc->response = Curl_tvnow(); /* start response time-out now! */
-
- if(data->state.used_interface == Curl_if_multi)
- result = Curl_ftp_multi_statemach(conn, done);
- else {
- result = ftp_easy_statemach(conn);
- if(!result)
- *done = TRUE;
- }
-
- return result;
-}
-
-/***********************************************************************
- *
- * Curl_ftp_done()
- *
- * The DONE function. This does what needs to be done after a single DO has
- * performed.
- *
- * Input argument is already checked for validity.
- */
-CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature)
-{
- struct SessionHandle *data = conn->data;
- struct FTP *ftp = data->reqdata.proto.ftp;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- ssize_t nread;
- int ftpcode;
- CURLcode result=CURLE_OK;
- bool was_ctl_valid = ftpc->ctl_valid;
- size_t flen;
- size_t dlen;
- char *path;
- char *path_to_use = data->reqdata.path;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
-
- if(!ftp)
- /* When the easy handle is removed from the multi while libcurl is still
- * trying to resolve the host name, it seems that the ftp struct is not
- * yet initialized, but the removal action calls Curl_done() which calls
- * this function. So we simply return success if no ftp pointer is set.
- */
- return CURLE_OK;
-
- switch(status) {
- case CURLE_BAD_DOWNLOAD_RESUME:
- case CURLE_FTP_WEIRD_PASV_REPLY:
- case CURLE_FTP_PORT_FAILED:
- case CURLE_FTP_COULDNT_SET_BINARY:
- case CURLE_FTP_COULDNT_RETR_FILE:
- case CURLE_FTP_COULDNT_STOR_FILE:
- case CURLE_FTP_ACCESS_DENIED:
- /* the connection stays alive fine even though this happened */
- /* fall-through */
- case CURLE_OK: /* doesn't affect the control connection's status */
- if (!premature) {
- ftpc->ctl_valid = was_ctl_valid;
- break;
- }
- /* until we cope better with prematurely ended requests, let them
- * fallback as if in complete failure */
- default: /* by default, an error means the control connection is
- wedged and should not be used anymore */
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
- current path, as this connection is going */
- conn->bits.close = TRUE; /* marked for closure */
- break;
- }
-
- /* now store a copy of the directory we are in */
- if(ftpc->prevpath)
- free(ftpc->prevpath);
-
- /* get the "raw" path */
- path = curl_easy_unescape(data, path_to_use, 0, NULL);
- if(!path)
- return CURLE_OUT_OF_MEMORY;
-
- flen = ftp->file?strlen(ftp->file):0; /* file is "raw" already */
- dlen = strlen(path)-flen;
- if(dlen && !ftpc->cwdfail) {
- ftpc->prevpath = path;
- if(flen)
- /* if 'path' is not the whole string */
- ftpc->prevpath[dlen]=0; /* terminate */
- infof(data, "Remembering we are in dir %s\n", ftpc->prevpath);
- }
- else {
- ftpc->prevpath = NULL; /* no path */
- free(path);
- }
- /* free the dir tree and file parts */
- freedirs(conn);
-
-#ifdef HAVE_KRB4
- Curl_sec_fflush_fd(conn, conn->sock[SECONDARYSOCKET]);
-#endif
-
- /* shut down the socket to inform the server we're done */
-
-#ifdef _WIN32_WCE
- shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
-#endif
-
- sclose(conn->sock[SECONDARYSOCKET]);
-
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
-
- if(!ftp->no_transfer && !status && !premature) {
- /*
- * Let's see what the server says about the transfer we just performed,
- * but lower the timeout as sometimes this connection has died while the
- * data has been transfered. This happens when doing through NATs etc that
- * abandon old silent connections.
- */
- long old_time = ftpc->response_time;
-
- ftpc->response_time = 60; /* give it only a minute for now */
-
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
-
- ftpc->response_time = old_time; /* set this back to previous value */
-
- if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
- failf(data, "control connection looks dead");
- ftpc->ctl_valid = FALSE; /* mark control connection as bad */
- return result;
- }
-
- if(result)
- return result;
-
- if(!ftpc->dont_check) {
- /* 226 Transfer complete, 250 Requested file action okay, completed. */
- if((ftpcode != 226) && (ftpcode != 250)) {
- failf(data, "server did not report OK, got %d", ftpcode);
- result = CURLE_PARTIAL_FILE;
- }
- }
- }
-
- if(result || premature)
- /* the response code from the transfer showed an error already so no
- use checking further */
- ;
- else if(data->set.upload) {
- if((-1 != data->set.infilesize) &&
- (data->set.infilesize != *ftp->bytecountp) &&
- !data->set.crlf &&
- !ftp->no_transfer) {
- failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
- " out of %" FORMAT_OFF_T " bytes)",
- *ftp->bytecountp, data->set.infilesize);
- result = CURLE_PARTIAL_FILE;
- }
- }
- else {
- if((-1 != k->size) && (k->size != *ftp->bytecountp) &&
-#ifdef CURL_DO_LINEEND_CONV
- /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
- * we'll check to see if the discrepancy can be explained by the number
- * of CRLFs we've changed to LFs.
- */
- ((k->size + data->state.crlf_conversions) != *ftp->bytecountp) &&
-#endif /* CURL_DO_LINEEND_CONV */
- (k->maxdownload != *ftp->bytecountp)) {
- failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
- *ftp->bytecountp);
- result = CURLE_PARTIAL_FILE;
- }
- else if(!ftpc->dont_check &&
- !*ftp->bytecountp &&
- (k->size>0)) {
- failf(data, "No data was received!");
- result = CURLE_FTP_COULDNT_RETR_FILE;
- }
- }
-
- /* clear these for next connection */
- ftp->no_transfer = FALSE;
- ftpc->dont_check = FALSE;
-
- /* Send any post-transfer QUOTE strings? */
- if(!status && !result && !premature && data->set.postquote)
- result = ftp_sendquote(conn, data->set.postquote);
-
- return result;
-}
-
-/***********************************************************************
- *
- * ftp_sendquote()
- *
- * Where a 'quote' means a list of custom commands to send to the server.
- * The quote list is passed as an argument.
- */
-
-static
-CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
-{
- struct curl_slist *item;
- ssize_t nread;
- int ftpcode;
- CURLcode result;
-
- item = quote;
- while (item) {
- if (item->data) {
- FTPSENDF(conn, "%s", item->data);
-
- result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
- if (result)
- return result;
-
- if (ftpcode >= 400) {
- failf(conn->data, "QUOT string not accepted: %s", item->data);
- return CURLE_FTP_QUOTE_ERROR;
- }
- }
-
- item = item->next;
- }
-
- return CURLE_OK;
-}
-
-/***********************************************************************
- *
- * ftp_need_type()
- *
- * Returns TRUE if we in the current situation should send TYPE
- */
-static int ftp_need_type(struct connectdata *conn,
- bool ascii_wanted)
-{
- return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
-}
-
-/***********************************************************************
- *
- * ftp_nb_type()
- *
- * Set TYPE. We only deal with ASCII or BINARY so this function
- * sets one of them.
- * If the transfer type is not sent, simulate on OK response in newstate
- */
-static CURLcode ftp_nb_type(struct connectdata *conn,
- bool ascii, ftpstate newstate)
-{
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result;
- int want = ascii?'A':'I';
-
- if (ftpc->transfertype == want) {
- state(conn, newstate);
- return ftp_state_type_resp(conn, 200, newstate);
- }
-
- NBFTPSENDF(conn, "TYPE %c", want);
- state(conn, newstate);
-
- /* keep track of our current transfer type */
- ftpc->transfertype = want;
- return CURLE_OK;
-}
-
-/***************************************************************************
- *
- * ftp_pasv_verbose()
- *
- * This function only outputs some informationals about this second connection
- * when we've issued a PASV command before and thus we have connected to a
- * possibly new IP address.
- *
- */
-static void
-ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
- char *newhost, /* ascii version */
- int port)
-{
- char buf[256];
- Curl_printable_address(ai, buf, sizeof(buf));
- infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
-}
-
-/*
- Check if this is a range download, and if so, set the internal variables
- properly.
- */
-
-static CURLcode ftp_range(struct connectdata *conn)
-{
- curl_off_t from, to;
- curl_off_t totalsize=-1;
- char *ptr;
- char *ptr2;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(data->reqdata.use_range && data->reqdata.range) {
- from=curlx_strtoofft(data->reqdata.range, &ptr, 0);
- while(ptr && *ptr && (ISSPACE(*ptr) || (*ptr=='-')))
- ptr++;
- to=curlx_strtoofft(ptr, &ptr2, 0);
- if(ptr == ptr2) {
- /* we didn't get any digit */
- to=-1;
- }
- if((-1 == to) && (from>=0)) {
- /* X - */
- data->reqdata.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
- from));
- }
- else if(from < 0) {
- /* -Y */
- totalsize = -from;
- data->reqdata.maxdownload = -from;
- data->reqdata.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
- totalsize));
- }
- else {
- /* X-Y */
- totalsize = to-from;
- data->reqdata.maxdownload = totalsize+1; /* include last byte */
- data->reqdata.resume_from = from;
- DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
- " getting %" FORMAT_OFF_T " bytes\n",
- from, data->reqdata.maxdownload));
- }
- DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
- " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
- from, to, data->reqdata.maxdownload));
- ftpc->dont_check = TRUE; /* dont check for successful transfer */
- }
- return CURLE_OK;
-}
-
-
-/*
- * Curl_ftp_nextconnect()
- *
- * This function shall be called when the second FTP (data) connection is
- * connected.
- */
-
-CURLcode Curl_ftp_nextconnect(struct connectdata *conn)
-{
- struct SessionHandle *data=conn->data;
- CURLcode result = CURLE_OK;
-
- /* the ftp struct is inited in Curl_ftp_connect() */
- struct FTP *ftp = data->reqdata.proto.ftp;
-
- DEBUGF(infof(data, "DO-MORE phase starts\n"));
-
- if(!ftp->no_transfer && !conn->bits.no_body) {
- /* a transfer is about to take place */
-
- if(data->set.upload) {
- result = ftp_nb_type(conn, data->set.prefer_ascii,
- FTP_STOR_TYPE);
- if (result)
- return result;
- }
- else {
- /* download */
- ftp->downloadsize = -1; /* unknown as of yet */
-
- result = ftp_range(conn);
- if(result)
- ;
- else if((data->set.ftp_list_only) || !ftp->file) {
- /* The specified path ends with a slash, and therefore we think this
- is a directory that is requested, use LIST. But before that we
- need to set ASCII transfer mode. */
- result = ftp_nb_type(conn, 1, FTP_LIST_TYPE);
- if (result)
- return result;
- }
- else {
- result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
- if (result)
- return result;
- }
- }
- result = ftp_easy_statemach(conn);
- }
-
- if(ftp->no_transfer)
- /* no data to transfer. FIX: it feels like a kludge to have this here
- too! */
- result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
- /* end of transfer */
- DEBUGF(infof(data, "DO-MORE phase ends with %d\n", result));
-
- return result;
-}
-
-
-
-/***********************************************************************
- *
- * ftp_perform()
- *
- * This is the actual DO function for FTP. Get a file/directory according to
- * the options previously setup.
- */
-
-static
-CURLcode ftp_perform(struct connectdata *conn,
- bool *connected, /* connect status after PASV / PORT */
- bool *dophase_done)
-{
- /* this is FTP and no proxy */
- CURLcode result=CURLE_OK;
-
- DEBUGF(infof(conn->data, "DO phase starts\n"));
-
- *dophase_done = FALSE; /* not done yet */
-
- /* start the first command in the DO phase */
- result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
- if(result)
- return result;
-
- /* run the state-machine */
- if(conn->data->state.used_interface == Curl_if_multi)
- result = Curl_ftp_multi_statemach(conn, dophase_done);
- else {
- result = ftp_easy_statemach(conn);
- *dophase_done = TRUE; /* with the easy interface we are done here */
- }
- *connected = conn->bits.tcpconnect;
-
- if(*dophase_done) {
- DEBUGF(infof(conn->data, "DO phase is complete\n"));
- }
-
- return result;
-}
-
-/***********************************************************************
- *
- * Curl_ftp()
- *
- * This function is registered as 'curl_do' function. It decodes the path
- * parts etc as a wrapper to the actual DO function (ftp_perform).
- *
- * The input argument is already checked for validity.
- */
-CURLcode Curl_ftp(struct connectdata *conn, bool *done)
-{
- CURLcode retcode = CURLE_OK;
-
- *done = FALSE; /* default to false */
-
- /*
- Since connections can be re-used between SessionHandles, this might be a
- connection already existing but on a fresh SessionHandle struct so we must
- make sure we have a good 'struct FTP' to play with. For new connections,
- the struct FTP is allocated and setup in the Curl_ftp_connect() function.
- */
- retcode = ftp_init(conn);
- if(retcode)
- return retcode;
-
- retcode = ftp_parse_url_path(conn);
- if (retcode)
- return retcode;
-
- retcode = ftp_regular_transfer(conn, done);
-
- return retcode;
-}
-
-/***********************************************************************
- *
- * Curl_(nb)ftpsendf()
- *
- * Sends the formated string as a ftp command to a ftp server
- *
- * NOTE: we build the command in a fixed-length buffer, which sets length
- * restrictions on the command!
- *
- * The "nb" version is made to Never Block.
- */
-CURLcode Curl_nbftpsendf(struct connectdata *conn,
- const char *fmt, ...)
-{
- ssize_t bytes_written;
- char s[256];
- size_t write_len;
- char *sptr=s;
- CURLcode res = CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(s, 250, fmt, ap);
- va_end(ap);
-
- strcat(s, "\r\n"); /* append a trailing CRLF */
-
- bytes_written=0;
- write_len = strlen(s);
-
- ftp_respinit(conn);
-
-#ifdef CURL_DOES_CONVERSIONS
- res = Curl_convert_to_network(data, s, write_len);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(res != CURLE_OK) {
- return res;
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
- &bytes_written);
-
- if(CURLE_OK != res)
- return res;
-
- if(conn->data->set.verbose)
- Curl_debug(conn->data, CURLINFO_HEADER_OUT,
- sptr, (size_t)bytes_written, conn);
-
- if(bytes_written != (ssize_t)write_len) {
- /* the whole chunk was not sent, store the rest of the data */
- write_len -= bytes_written;
- sptr += bytes_written;
- ftpc->sendthis = malloc(write_len);
- if(ftpc->sendthis) {
- memcpy(ftpc->sendthis, sptr, write_len);
- ftpc->sendsize = ftpc->sendleft = write_len;
- }
- else {
- failf(data, "out of memory");
- res = CURLE_OUT_OF_MEMORY;
- }
- }
- else
- ftpc->response = Curl_tvnow();
-
- return res;
-}
-
-CURLcode Curl_ftpsendf(struct connectdata *conn,
- const char *fmt, ...)
-{
- ssize_t bytes_written;
- char s[256];
- size_t write_len;
- char *sptr=s;
- CURLcode res = CURLE_OK;
-
- va_list ap;
- va_start(ap, fmt);
- vsnprintf(s, 250, fmt, ap);
- va_end(ap);
-
- strcat(s, "\r\n"); /* append a trailing CRLF */
-
- bytes_written=0;
- write_len = strlen(s);
-
-#ifdef CURL_DOES_CONVERSIONS
- res = Curl_convert_to_network(conn->data, s, write_len);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(res != CURLE_OK) {
- return(res);
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- while(1) {
- res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
- &bytes_written);
-
- if(CURLE_OK != res)
- break;
-
- if(conn->data->set.verbose)
- Curl_debug(conn->data, CURLINFO_HEADER_OUT,
- sptr, (size_t)bytes_written, conn);
-
- if(bytes_written != (ssize_t)write_len) {
- write_len -= bytes_written;
- sptr += bytes_written;
- }
- else
- break;
- }
-
- return res;
-}
-
-/***********************************************************************
- *
- * ftp_quit()
- *
- * This should be called before calling sclose() on an ftp control connection
- * (not data connections). We should then wait for the response from the
- * server before returning. The calling code should then try to close the
- * connection.
- *
- */
-static CURLcode ftp_quit(struct connectdata *conn)
-{
- CURLcode result = CURLE_OK;
-
- if(conn->proto.ftpc.ctl_valid) {
- NBFTPSENDF(conn, "QUIT", NULL);
- state(conn, FTP_QUIT);
-
- result = ftp_easy_statemach(conn);
- }
-
- return result;
-}
-
-/***********************************************************************
- *
- * Curl_ftp_disconnect()
- *
- * Disconnect from an FTP server. Cleanup protocol-specific per-connection
- * resources. BLOCKING.
- */
-CURLcode Curl_ftp_disconnect(struct connectdata *conn)
-{
- struct ftp_conn *ftpc= &conn->proto.ftpc;
-
- /* We cannot send quit unconditionally. If this connection is stale or
- bad in any way, sending quit and waiting around here will make the
- disconnect wait in vain and cause more problems than we need to.
-
- ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
- will try to send the QUIT command, otherwise it will just return.
- */
-
- /* The FTP session may or may not have been allocated/setup at this point! */
- if(conn->data->reqdata.proto.ftp) {
- (void)ftp_quit(conn); /* ignore errors on the QUIT */
-
- if(ftpc->entrypath) {
- struct SessionHandle *data = conn->data;
- data->state.most_recent_ftp_entrypath = NULL;
- free(ftpc->entrypath);
- ftpc->entrypath = NULL;
- }
- if(ftpc->cache) {
- free(ftpc->cache);
- ftpc->cache = NULL;
- }
- freedirs(conn);
- if(ftpc->prevpath) {
- free(ftpc->prevpath);
- ftpc->prevpath = NULL;
- }
- }
- return CURLE_OK;
-}
-
-/***********************************************************************
- *
- * ftp_parse_url_path()
- *
- * Parse the URL path into separate path components.
- *
- */
-static
-CURLcode ftp_parse_url_path(struct connectdata *conn)
-{
- CURLcode retcode = CURLE_OK;
- struct SessionHandle *data = conn->data;
- /* the ftp struct is already inited in ftp_connect() */
- struct FTP *ftp = data->reqdata.proto.ftp;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- size_t dlen;
- char *slash_pos; /* position of the first '/' char in curpos */
- char *path_to_use = data->reqdata.path;
- char *cur_pos;
-
- cur_pos = path_to_use; /* current position in path. point at the begin
- of next path component */
-
- ftpc->ctl_valid = FALSE;
- ftpc->cwdfail = FALSE;
-
- switch(data->set.ftp_filemethod) {
- case FTPFILE_NOCWD:
- /* fastest, but less standard-compliant */
- ftp->file = data->reqdata.path; /* this is a full file path */
- break;
-
- case FTPFILE_SINGLECWD:
- /* get the last slash */
- slash_pos=strrchr(cur_pos, '/');
- if(slash_pos || !cur_pos || !*cur_pos) {
- ftpc->dirdepth = 1; /* we consider it to be a single dir */
- ftpc->dirs = (char **)calloc(1, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
-
- ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/",
- slash_pos?(int)(slash_pos-cur_pos):1,
- NULL);
- if(!ftpc->dirs[0]) {
- free(ftpc->dirs);
- return CURLE_OUT_OF_MEMORY;
- }
- ftp->file = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
- }
- else
- ftp->file = cur_pos; /* this is a file name only */
- break;
-
- default: /* allow pretty much anything */
- case FTPFILE_MULTICWD:
- ftpc->dirdepth = 0;
- ftpc->diralloc = 5; /* default dir depth to allocate */
- ftpc->dirs = (char **)calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
- if(!ftpc->dirs)
- return CURLE_OUT_OF_MEMORY;
-
- /* parse the URL path into separate path components */
- while ((slash_pos = strchr(cur_pos, '/')) != NULL) {
- /* 1 or 0 to indicate absolute directory */
- bool absolute_dir = (bool)((cur_pos - data->reqdata.path > 0) &&
- (ftpc->dirdepth == 0));
-
- /* seek out the next path component */
- if (slash_pos-cur_pos) {
- /* we skip empty path components, like "x//y" since the FTP command
- CWD requires a parameter and a non-existent parameter a) doesn't
- work on many servers and b) has no effect on the others. */
- int len = (int)(slash_pos - cur_pos + absolute_dir);
- ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data,
- cur_pos - absolute_dir,
- len, NULL);
- if (!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
- failf(data, "no memory");
- freedirs(conn);
- return CURLE_OUT_OF_MEMORY;
- }
- if (isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
- freedirs(conn);
- return CURLE_URL_MALFORMAT;
- }
- }
- else {
- cur_pos = slash_pos + 1; /* jump to the rest of the string */
- continue;
- }
-
- if(!retcode) {
- cur_pos = slash_pos + 1; /* jump to the rest of the string */
- if(++ftpc->dirdepth >= ftpc->diralloc) {
- /* enlarge array */
- char *bigger;
- ftpc->diralloc *= 2; /* double the size each time */
- bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
- if(!bigger) {
- ftpc->dirdepth--;
- freedirs(conn);
- return CURLE_OUT_OF_MEMORY;
- }
- ftpc->dirs = (char **)bigger;
- }
- }
- }
-
- ftp->file = cur_pos; /* the rest is the file name */
- }
-
- if(*ftp->file) {
- ftp->file = curl_easy_unescape(conn->data, ftp->file, 0, NULL);
- if(NULL == ftp->file) {
- freedirs(conn);
- failf(data, "no memory");
- return CURLE_OUT_OF_MEMORY;
- }
- if (isBadFtpString(ftp->file)) {
- freedirs(conn);
- return CURLE_URL_MALFORMAT;
- }
- }
- else
- ftp->file=NULL; /* instead of point to a zero byte, we make it a NULL
- pointer */
-
- if(data->set.upload && !ftp->file &&
- (!ftp->no_transfer || conn->bits.no_body)) {
- /* We need a file name when uploading. Return error! */
- failf(data, "Uploading to a URL without a file name!");
- return CURLE_URL_MALFORMAT;
- }
-
- ftpc->cwddone = FALSE; /* default to not done */
-
- if(ftpc->prevpath) {
- /* prevpath is "raw" so we convert the input path before we compare the
- strings */
- char *path = curl_easy_unescape(conn->data, data->reqdata.path, 0, NULL);
- if(!path)
- return CURLE_OUT_OF_MEMORY;
-
- dlen = strlen(path) - (ftp->file?strlen(ftp->file):0);
- if((dlen == strlen(ftpc->prevpath)) &&
- curl_strnequal(path, ftpc->prevpath, dlen)) {
- infof(data, "Request has same path as previous transfer\n");
- ftpc->cwddone = TRUE;
- }
- free(path);
- }
-
- return retcode;
-}
-
-/* call this when the DO phase has completed */
-static CURLcode ftp_dophase_done(struct connectdata *conn,
- bool connected)
-{
- CURLcode result = CURLE_OK;
- struct FTP *ftp = conn->data->reqdata.proto.ftp;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
-
- if(connected)
- result = Curl_ftp_nextconnect(conn);
-
- if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) {
- /* Failure detected, close the second socket if it was created already */
- sclose(conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- return result;
- }
-
- if(ftp->no_transfer)
- /* no data to transfer */
- result=Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- else if(!connected)
- /* since we didn't connect now, we want do_more to get called */
- conn->bits.do_more = TRUE;
-
- ftpc->ctl_valid = TRUE; /* seems good */
-
- return result;
-}
-
-/* called from multi.c while DOing */
-CURLcode Curl_ftp_doing(struct connectdata *conn,
- bool *dophase_done)
-{
- CURLcode result;
- result = Curl_ftp_multi_statemach(conn, dophase_done);
-
- if(*dophase_done) {
- result = ftp_dophase_done(conn, FALSE /* not connected */);
-
- DEBUGF(infof(conn->data, "DO phase is complete\n"));
- }
- return result;
-}
-
-/***********************************************************************
- *
- * ftp_regular_transfer()
- *
- * The input argument is already checked for validity.
- *
- * Performs all commands done before a regular transfer between a local and a
- * remote host.
- *
- * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
- * Curl_ftp_done() function without finding any major problem.
- */
-static
-CURLcode ftp_regular_transfer(struct connectdata *conn,
- bool *dophase_done)
-{
- CURLcode result=CURLE_OK;
- bool connected=0;
- struct SessionHandle *data = conn->data;
- struct ftp_conn *ftpc = &conn->proto.ftpc;
- data->reqdata.size = -1; /* make sure this is unknown at this point */
-
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
- Curl_pgrsSetUploadSize(data, 0);
- Curl_pgrsSetDownloadSize(data, 0);
-
- ftpc->ctl_valid = TRUE; /* starts good */
-
- result = ftp_perform(conn,
- &connected, /* have we connected after PASV/PORT */
- dophase_done); /* all commands in the DO-phase done? */
-
- if(CURLE_OK == result) {
-
- if(!*dophase_done)
- /* the DO phase has not completed yet */
- return CURLE_OK;
-
- result = ftp_dophase_done(conn, connected);
- if(result)
- return result;
- }
- else
- freedirs(conn);
-
- return result;
-}
-
-#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/ftp.h b/Utilities/cmcurl/ftp.h
deleted file mode 100644
index b64e70506..000000000
--- a/Utilities/cmcurl/ftp.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef __FTP_H
-#define __FTP_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifndef CURL_DISABLE_FTP
-CURLcode Curl_ftp(struct connectdata *conn, bool *done);
-CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature);
-CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done);
-CURLcode Curl_ftp_disconnect(struct connectdata *conn);
-CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
-CURLcode Curl_nbftpsendf(struct connectdata *, const char *fmt, ...);
-CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
- int *ftpcode);
-CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
-CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done);
-int Curl_ftp_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-CURLcode Curl_ftp_doing(struct connectdata *conn,
- bool *dophase_done);
-#endif /* CURL_DISABLE_FTP */
-#endif /* __FTP_H */
diff --git a/Utilities/cmcurl/getenv.c b/Utilities/cmcurl/getenv.c
deleted file mode 100644
index 4f955f893..000000000
--- a/Utilities/cmcurl/getenv.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef VMS
-#include <unixlib.h>
-#endif
-
-#include <curl/curl.h>
-#include "memory.h"
-
-#include "memdebug.h"
-
-static
-char *GetEnv(const char *variable)
-{
-#ifdef _WIN32_WCE
- return NULL;
-#else
-#ifdef WIN32
- char env[MAX_PATH]; /* MAX_PATH is from windef.h */
- char *temp = getenv(variable);
- env[0] = '\0';
- if (temp != NULL)
- ExpandEnvironmentStrings(temp, env, sizeof(env));
-#else
-#ifdef VMS
- char *env = getenv(variable);
- if (env && strcmp("HOME",variable) == 0) {
- env = decc$translate_vms(env);
- }
-#else
- /* no length control */
- char *env = getenv(variable);
-#endif
-#endif
- return (env && env[0])?strdup(env):NULL;
-#endif
-}
-
-char *curl_getenv(const char *v)
-{
- return GetEnv(v);
-}
diff --git a/Utilities/cmcurl/getinfo.c b/Utilities/cmcurl/getinfo.c
deleted file mode 100644
index 5cf3bcacd..000000000
--- a/Utilities/cmcurl/getinfo.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <curl/curl.h>
-
-#include "urldata.h"
-#include "getinfo.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include "memory.h"
-#include "sslgen.h"
-
-/* Make this the last #include */
-#include "memdebug.h"
-
-/*
- * This is supposed to be called in the beginning of a perform() session
- * and should reset all session-info variables
- */
-CURLcode Curl_initinfo(struct SessionHandle *data)
-{
- struct Progress *pro = &data->progress;
- struct PureInfo *info =&data->info;
-
- pro->t_nslookup = 0;
- pro->t_connect = 0;
- pro->t_pretransfer = 0;
- pro->t_starttransfer = 0;
- pro->timespent = 0;
- pro->t_redirect = 0;
-
- info->httpcode = 0;
- info->httpversion=0;
- info->filetime=-1; /* -1 is an illegal time and thus means unknown */
-
- if (info->contenttype)
- free(info->contenttype);
- info->contenttype = NULL;
-
- info->header_size = 0;
- info->request_size = 0;
- info->numconnects = 0;
- return CURLE_OK;
-}
-
-CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
-{
- va_list arg;
- long *param_longp=NULL;
- double *param_doublep=NULL;
- char **param_charp=NULL;
- struct curl_slist **param_slistp=NULL;
- char buf;
-
- if(!data)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- va_start(arg, info);
-
- switch(info&CURLINFO_TYPEMASK) {
- default:
- return CURLE_BAD_FUNCTION_ARGUMENT;
- case CURLINFO_STRING:
- param_charp = va_arg(arg, char **);
- if(NULL == param_charp)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- break;
- case CURLINFO_LONG:
- param_longp = va_arg(arg, long *);
- if(NULL == param_longp)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- break;
- case CURLINFO_DOUBLE:
- param_doublep = va_arg(arg, double *);
- if(NULL == param_doublep)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- break;
- case CURLINFO_SLIST:
- param_slistp = va_arg(arg, struct curl_slist **);
- if(NULL == param_slistp)
- return CURLE_BAD_FUNCTION_ARGUMENT;
- break;
- }
-
- switch(info) {
- case CURLINFO_EFFECTIVE_URL:
- *param_charp = data->change.url?data->change.url:(char *)"";
- break;
- case CURLINFO_RESPONSE_CODE:
- *param_longp = data->info.httpcode;
- break;
- case CURLINFO_HTTP_CONNECTCODE:
- *param_longp = data->info.httpproxycode;
- break;
- case CURLINFO_FILETIME:
- *param_longp = data->info.filetime;
- break;
- case CURLINFO_HEADER_SIZE:
- *param_longp = data->info.header_size;
- break;
- case CURLINFO_REQUEST_SIZE:
- *param_longp = data->info.request_size;
- break;
- case CURLINFO_TOTAL_TIME:
- *param_doublep = data->progress.timespent;
- break;
- case CURLINFO_NAMELOOKUP_TIME:
- *param_doublep = data->progress.t_nslookup;
- break;
- case CURLINFO_CONNECT_TIME:
- *param_doublep = data->progress.t_connect;
- break;
- case CURLINFO_PRETRANSFER_TIME:
- *param_doublep = data->progress.t_pretransfer;
- break;
- case CURLINFO_STARTTRANSFER_TIME:
- *param_doublep = data->progress.t_starttransfer;
- break;
- case CURLINFO_SIZE_UPLOAD:
- *param_doublep = (double)data->progress.uploaded;
- break;
- case CURLINFO_SIZE_DOWNLOAD:
- *param_doublep = (double)data->progress.downloaded;
- break;
- case CURLINFO_SPEED_DOWNLOAD:
- *param_doublep = (double)data->progress.dlspeed;
- break;
- case CURLINFO_SPEED_UPLOAD:
- *param_doublep = (double)data->progress.ulspeed;
- break;
- case CURLINFO_SSL_VERIFYRESULT:
- *param_longp = data->set.ssl.certverifyresult;
- break;
- case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
- *param_doublep = (double)data->progress.size_dl;
- break;
- case CURLINFO_CONTENT_LENGTH_UPLOAD:
- *param_doublep = (double)data->progress.size_ul;
- break;
- case CURLINFO_REDIRECT_TIME:
- *param_doublep = data->progress.t_redirect;
- break;
- case CURLINFO_REDIRECT_COUNT:
- *param_longp = data->set.followlocation;
- break;
- case CURLINFO_CONTENT_TYPE:
- *param_charp = data->info.contenttype;
- break;
- case CURLINFO_PRIVATE:
- *param_charp = data->set.private_data;
- break;
- case CURLINFO_HTTPAUTH_AVAIL:
- *param_longp = data->info.httpauthavail;
- break;
- case CURLINFO_PROXYAUTH_AVAIL:
- *param_longp = data->info.proxyauthavail;
- break;
- case CURLINFO_OS_ERRNO:
- *param_longp = data->state.os_errno;
- break;
- case CURLINFO_NUM_CONNECTS:
- *param_longp = data->info.numconnects;
- break;
- case CURLINFO_SSL_ENGINES:
- *param_slistp = Curl_ssl_engines_list(data);
- break;
- case CURLINFO_COOKIELIST:
- *param_slistp = Curl_cookie_list(data);
- break;
- case CURLINFO_FTP_ENTRY_PATH:
- /* Return the entrypath string from the most recent connection.
- This pointer was copied from the connectdata structure by FTP.
- The actual string may be free()ed by subsequent libcurl calls so
- it must be copied to a safer area before the next libcurl call.
- Callers must never free it themselves. */
- *param_charp = data->state.most_recent_ftp_entrypath;
- break;
- case CURLINFO_LASTSOCKET:
- if((data->state.lastconnect != -1) &&
- (data->state.connc->connects[data->state.lastconnect] != NULL)) {
- struct connectdata *c = data->state.connc->connects
- [data->state.lastconnect];
- *param_longp = c->sock[FIRSTSOCKET];
- /* we have a socket connected, let's determine if the server shut down */
- /* determine if ssl */
- if(c->ssl[FIRSTSOCKET].use) {
- /* use the SSL context */
- if (!Curl_ssl_check_cxn(c))
- *param_longp = -1; /* FIN received */
- }
-/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
-#ifdef MSG_PEEK
- else {
- /* use the socket */
- if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
- (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
- *param_longp = -1; /* FIN received */
- }
- }
-#endif
- }
- else
- *param_longp = -1;
- break;
- default:
- return CURLE_BAD_FUNCTION_ARGUMENT;
- }
- return CURLE_OK;
-}
diff --git a/Utilities/cmcurl/getinfo.h b/Utilities/cmcurl/getinfo.h
deleted file mode 100644
index 2fe1b5c36..000000000
--- a/Utilities/cmcurl/getinfo.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __GETINFO_H
-#define __GETINFO_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...);
-CURLcode Curl_initinfo(struct SessionHandle *data);
-
-#endif
diff --git a/Utilities/cmcurl/gtls.c b/Utilities/cmcurl/gtls.c
deleted file mode 100644
index 250ecada4..000000000
--- a/Utilities/cmcurl/gtls.c
+++ /dev/null
@@ -1,640 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
- * but sslgen.c should ever call or use these functions.
- *
- * Note: don't use the GnuTLS' *_t variable type names in this source code,
- * since they were not present in 1.0.X.
- */
-
-#include "setup.h"
-#ifdef USE_GNUTLS
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "gtls.h"
-#include "sslgen.h"
-#include "parsedate.h"
-#include "connect.h" /* for the connect timeout */
-#include "select.h"
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* Enable GnuTLS debugging by defining GTLSDEBUG */
-/*#define GTLSDEBUG */
-
-#ifdef GTLSDEBUG
-static void tls_log_func(int level, const char *str)
-{
- fprintf(stderr, "|<%d>| %s", level, str);
-}
-#endif
-
-/*
- * Custom push and pull callback functions used by GNU TLS to read and write
- * to the socket. These functions are simple wrappers to send() and recv()
- * (although here using the sread/swrite macros as defined by setup_once.h).
- * We use custom functions rather than the GNU TLS defaults because it allows
- * us to get specific about the fourth "flags" argument, and to use arbitrary
- * private data with gnutls_transport_set_ptr if we wish.
- */
-static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
-{
- return swrite(s, buf, len);
-}
-
-static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
-{
- return sread(s, buf, len);
-}
-
-/* Global GnuTLS init, called from Curl_ssl_init() */
-int Curl_gtls_init(void)
-{
- gnutls_global_init();
-#ifdef GTLSDEBUG
- gnutls_global_set_log_function(tls_log_func);
- gnutls_global_set_log_level(2);
-#endif
- return 1;
-}
-
-int Curl_gtls_cleanup(void)
-{
- gnutls_global_deinit();
- return 1;
-}
-
-static void showtime(struct SessionHandle *data,
- const char *text,
- time_t stamp)
-{
- struct tm *tm;
-#ifdef HAVE_GMTIME_R
- struct tm buffer;
- tm = (struct tm *)gmtime_r(&stamp, &buffer);
-#else
- tm = gmtime(&stamp);
-#endif
- snprintf(data->state.buffer,
- BUFSIZE,
- "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
- text,
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
- infof(data, "%s", data->state.buffer);
-}
-
-/* this function does a BLOCKING SSL/TLS (re-)handshake */
-static CURLcode handshake(struct connectdata *conn,
- gnutls_session session,
- int sockindex,
- bool duringconnect)
-{
- struct SessionHandle *data = conn->data;
- int rc;
-
- do {
- rc = gnutls_handshake(session);
-
- if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
- long timeout_ms = DEFAULT_CONNECT_TIMEOUT;
- long has_passed;
-
- if(duringconnect && data->set.connecttimeout)
- timeout_ms = data->set.connecttimeout*1000;
-
- if(data->set.timeout) {
- /* get the strictest timeout of the ones converted to milliseconds */
- if((data->set.timeout*1000) < timeout_ms)
- timeout_ms = data->set.timeout*1000;
- }
-
- /* Evaluate in milliseconds how much time that has passed */
- has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
- /* subtract the passed time */
- timeout_ms -= has_passed;
-
- if(timeout_ms < 0) {
- /* a precaution, no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEOUTED;
- }
-
- rc = Curl_select(conn->sock[sockindex],
- conn->sock[sockindex], (int)timeout_ms);
- if(rc > 0)
- /* reabable or writable, go loop*/
- continue;
- else if(0 == rc) {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
- else
- break;
- } while(1);
-
- if (rc < 0) {
- failf(data, "gnutls_handshake() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- return CURLE_OK;
-}
-
-static gnutls_x509_crt_fmt do_file_type(const char *type)
-{
- if(!type || !type[0])
- return GNUTLS_X509_FMT_PEM;
- if(curl_strequal(type, "PEM"))
- return GNUTLS_X509_FMT_PEM;
- if(curl_strequal(type, "DER"))
- return GNUTLS_X509_FMT_DER;
- return -1;
-}
-
-
-/*
- * This function is called after the TCP connect has completed. Setup the TLS
- * layer and do all necessary magic.
- */
-CURLcode
-Curl_gtls_connect(struct connectdata *conn,
- int sockindex)
-
-{
- const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
- struct SessionHandle *data = conn->data;
- gnutls_session session;
- int rc;
- unsigned int cert_list_size;
- const gnutls_datum *chainp;
- unsigned int verify_status;
- gnutls_x509_crt x509_cert;
- char certbuf[256]; /* big enough? */
- size_t size;
- unsigned int algo;
- unsigned int bits;
- time_t clock;
- const char *ptr;
- void *ssl_sessionid;
- size_t ssl_idsize;
-
- /* GnuTLS only supports TLSv1 (and SSLv3?) */
- if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
- failf(data, "GnuTLS does not support SSLv2");
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* allocate a cred struct */
- rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
- if(rc < 0) {
- failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- if(data->set.ssl.CAfile) {
- /* set the trusted CA cert bundle file */
- gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
- GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
-
- rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
- data->set.ssl.CAfile,
- GNUTLS_X509_FMT_PEM);
- if(rc < 0) {
- infof(data, "error reading ca cert file %s (%s)\n",
- data->set.ssl.CAfile, gnutls_strerror(rc));
- if (data->set.ssl.verifypeer)
- return CURLE_SSL_CACERT_BADFILE;
- }
- else
- infof(data, "found %d certificates in %s\n",
- rc, data->set.ssl.CAfile);
- }
-
- /* Initialize TLS session as a client */
- rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
- if(rc) {
- failf(data, "gnutls_init() failed: %d", rc);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* convenient assign */
- session = conn->ssl[sockindex].session;
-
- /* Use default priorities */
- rc = gnutls_set_default_priority(session);
- if(rc < 0)
- return CURLE_SSL_CONNECT_ERROR;
-
- /* Sets the priority on the certificate types supported by gnutls. Priority
- is higher for types specified before others. After specifying the types
- you want, you must append a 0. */
- rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
- if(rc < 0)
- return CURLE_SSL_CONNECT_ERROR;
-
- if(data->set.cert) {
- if( gnutls_certificate_set_x509_key_file(
- conn->ssl[sockindex].cred, data->set.cert,
- data->set.key != 0 ? data->set.key : data->set.cert,
- do_file_type(data->set.cert_type) ) ) {
- failf(data, "error reading X.509 key or certificate file");
- return CURLE_SSL_CONNECT_ERROR;
- }
- }
-
- /* put the credentials to the current session */
- rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
- conn->ssl[sockindex].cred);
-
- /* set the connection handle (file descriptor for the socket) */
- gnutls_transport_set_ptr(session,
- (gnutls_transport_ptr)conn->sock[sockindex]);
-
- /* register callback functions to send and receive data. */
- gnutls_transport_set_push_function(session, Curl_gtls_push);
- gnutls_transport_set_pull_function(session, Curl_gtls_pull);
-
- /* lowat must be set to zero when using custom push and pull functions. */
- gnutls_transport_set_lowat(session, 0);
-
- /* This might be a reconnect, so we check for a session ID in the cache
- to speed up things */
-
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
- /* we got a session id, use it! */
- gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
-
- /* Informational message */
- infof (data, "SSL re-using session ID\n");
- }
-
- rc = handshake(conn, session, sockindex, TRUE);
- if(rc)
- /* handshake() sets its own error message with failf() */
- return rc;
-
- /* This function will return the peer's raw certificate (chain) as sent by
- the peer. These certificates are in raw format (DER encoded for
- X.509). In case of a X.509 then a certificate list may be present. The
- first certificate in the list is the peer's certificate, following the
- issuer's certificate, then the issuer's issuer etc. */
-
- chainp = gnutls_certificate_get_peers(session, &cert_list_size);
- if(!chainp) {
- if(data->set.ssl.verifyhost) {
- failf(data, "failed to get server cert");
- return CURLE_SSL_PEER_CERTIFICATE;
- }
- infof(data, "\t common name: WARNING couldn't obtain\n");
- }
-
- /* This function will try to verify the peer's certificate and return its
- status (trusted, invalid etc.). The value of status should be one or more
- of the gnutls_certificate_status_t enumerated elements bitwise or'd. To
- avoid denial of service attacks some default upper limits regarding the
- certificate key size and chain size are set. To override them use
- gnutls_certificate_set_verify_limits(). */
-
- rc = gnutls_certificate_verify_peers2(session, &verify_status);
- if (rc < 0) {
- failf(data, "server cert verify failed: %d", rc);
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- /* verify_status is a bitmask of gnutls_certificate_status bits */
- if(verify_status & GNUTLS_CERT_INVALID) {
- if (data->set.ssl.verifypeer) {
- failf(data, "server certificate verification failed. CAfile: %s",
- data->set.ssl.CAfile?data->set.ssl.CAfile:"none");
- return CURLE_SSL_CACERT;
- }
- else
- infof(data, "\t server certificate verification FAILED\n");
- }
- else
- infof(data, "\t server certificate verification OK\n");
-
- /* initialize an X.509 certificate structure. */
- gnutls_x509_crt_init(&x509_cert);
-
- /* convert the given DER or PEM encoded Certificate to the native
- gnutls_x509_crt_t format */
- gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
-
- size=sizeof(certbuf);
- rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
- 0, /* the first and only one */
- FALSE,
- certbuf,
- &size);
- if(rc) {
- infof(data, "error fetching CN from cert:%s\n",
- gnutls_strerror(rc));
- }
-
- /* This function will check if the given certificate's subject matches the
- given hostname. This is a basic implementation of the matching described
- in RFC2818 (HTTPS), which takes into account wildcards, and the subject
- alternative name PKIX extension. Returns non zero on success, and zero on
- failure. */
- rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
-
- if(!rc) {
- if (data->set.ssl.verifyhost > 1) {
- failf(data, "SSL: certificate subject name (%s) does not match "
- "target host name '%s'", certbuf, conn->host.dispname);
- gnutls_x509_crt_deinit(x509_cert);
- return CURLE_SSL_PEER_CERTIFICATE;
- }
- else
- infof(data, "\t common name: %s (does not match '%s')\n",
- certbuf, conn->host.dispname);
- }
- else
- infof(data, "\t common name: %s (matched)\n", certbuf);
-
- /* Show:
-
- - ciphers used
- - subject
- - start date
- - expire date
- - common name
- - issuer
-
- */
-
- /* public key algorithm's parameters */
- algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
- infof(data, "\t certificate public key: %s\n",
- gnutls_pk_algorithm_get_name(algo));
-
- /* version of the X.509 certificate. */
- infof(data, "\t certificate version: #%d\n",
- gnutls_x509_crt_get_version(x509_cert));
-
-
- size = sizeof(certbuf);
- gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
- infof(data, "\t subject: %s\n", certbuf);
-
- clock = gnutls_x509_crt_get_activation_time(x509_cert);
- showtime(data, "start date", clock);
-
- clock = gnutls_x509_crt_get_expiration_time(x509_cert);
- showtime(data, "expire date", clock);
-
- size = sizeof(certbuf);
- gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
- infof(data, "\t issuer: %s\n", certbuf);
-
- gnutls_x509_crt_deinit(x509_cert);
-
- /* compression algorithm (if any) */
- ptr = gnutls_compression_get_name(gnutls_compression_get(session));
- /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
- infof(data, "\t compression: %s\n", ptr);
-
- /* the name of the cipher used. ie 3DES. */
- ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
- infof(data, "\t cipher: %s\n", ptr);
-
- /* the MAC algorithms name. ie SHA1 */
- ptr = gnutls_mac_get_name(gnutls_mac_get(session));
- infof(data, "\t MAC: %s\n", ptr);
-
- if(!ssl_sessionid) {
- /* this session was not previously in the cache, add it now */
-
- /* get the session ID data size */
- gnutls_session_get_data(session, NULL, &ssl_idsize);
- ssl_sessionid = malloc(ssl_idsize); /* get a buffer for it */
-
- if(ssl_sessionid) {
- /* extract session ID to the allocated buffer */
- gnutls_session_get_data(session, ssl_sessionid, &ssl_idsize);
-
- /* store this session id */
- return Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_idsize);
- }
- }
-
- return CURLE_OK;
-}
-
-
-/* return number of sent (non-SSL) bytes */
-ssize_t Curl_gtls_send(struct connectdata *conn,
- int sockindex,
- void *mem,
- size_t len)
-{
- ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
-
- if(rc < 0 ) {
- if(rc == GNUTLS_E_AGAIN)
- return 0; /* EWOULDBLOCK equivalent */
- rc = -1; /* generic error code for send failure */
- }
-
- return rc;
-}
-
-void Curl_gtls_close_all(struct SessionHandle *data)
-{
- /* FIX: make the OpenSSL code more generic and use parts of it here */
- (void)data;
-}
-
-static void close_one(struct connectdata *conn,
- int index)
-{
- if(conn->ssl[index].session) {
- gnutls_bye(conn->ssl[index].session, GNUTLS_SHUT_RDWR);
- gnutls_deinit(conn->ssl[index].session);
- }
- gnutls_certificate_free_credentials(conn->ssl[index].cred);
-}
-
-void Curl_gtls_close(struct connectdata *conn)
-{
- if(conn->ssl[0].use)
- close_one(conn, 0);
- if(conn->ssl[1].use)
- close_one(conn, 1);
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
-{
- int result;
- int retval = 0;
- struct SessionHandle *data = conn->data;
- int done = 0;
- ssize_t nread;
- char buf[120];
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(conn->ssl[sockindex].session) {
- while(!done) {
- int what = Curl_select(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- result = gnutls_record_recv(conn->ssl[sockindex].session,
- buf, sizeof(buf));
- switch(result) {
- case 0:
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = 1;
- break;
- case GNUTLS_E_AGAIN:
- case GNUTLS_E_INTERRUPTED:
- infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
- break;
- default:
- retval = -1;
- done = 1;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = 1;
- break;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
- retval = -1;
- done = 1;
- }
- }
- gnutls_deinit(conn->ssl[sockindex].session);
- }
- gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
-
- conn->ssl[sockindex].session = NULL;
- conn->ssl[sockindex].use = FALSE;
-
- return retval;
-}
-
-/*
- * If the read would block we return -1 and set 'wouldblock' to TRUE.
- * Otherwise we return the amount of data read. Other errors should return -1
- * and set 'wouldblock' to FALSE.
- */
-ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- bool *wouldblock)
-{
- ssize_t ret;
-
- ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
- if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
- *wouldblock = TRUE;
- return -1;
- }
-
- if(ret == GNUTLS_E_REHANDSHAKE) {
- /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
- proper way" takes a whole lot of work. */
- CURLcode rc = handshake(conn, conn->ssl[num].session, num, FALSE);
- if(rc)
- /* handshake() writes error message on its own */
- return rc;
- *wouldblock = TRUE; /* then return as if this was a wouldblock */
- return -1;
- }
-
- *wouldblock = FALSE;
- if (!ret) {
- failf(conn->data, "Peer closed the TLS connection");
- return -1;
- }
-
- if (ret < 0) {
- failf(conn->data, "GnuTLS recv error (%d): %s",
- (int)ret, gnutls_strerror(ret));
- return -1;
- }
-
- return ret;
-}
-
-void Curl_gtls_session_free(void *ptr)
-{
- free(ptr);
-}
-
-size_t Curl_gtls_version(char *buffer, size_t size)
-{
- return snprintf(buffer, size, " GnuTLS/%s", gnutls_check_version(NULL));
-}
-
-#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/gtls.h b/Utilities/cmcurl/gtls.h
deleted file mode 100644
index bff3f8693..000000000
--- a/Utilities/cmcurl/gtls.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __GTLS_H
-#define __GTLS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-int Curl_gtls_init(void);
-int Curl_gtls_cleanup(void);
-CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
-
-/* tell GnuTLS to close down all open information regarding connections (and
- thus session ID caching etc) */
-void Curl_gtls_close_all(struct SessionHandle *data);
-void Curl_gtls_close(struct connectdata *conn); /* close a SSL connection */
-
-/* return number of sent (non-SSL) bytes */
-ssize_t Curl_gtls_send(struct connectdata *conn, int sockindex,
- void *mem, size_t len);
-ssize_t Curl_gtls_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- bool *wouldblock);
-void Curl_gtls_session_free(void *ptr);
-size_t Curl_gtls_version(char *buffer, size_t size);
-int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
-
-#endif
diff --git a/Utilities/cmcurl/hash.c b/Utilities/cmcurl/hash.c
deleted file mode 100644
index e00462778..000000000
--- a/Utilities/cmcurl/hash.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "hash.h"
-#include "llist.h"
-#include "memory.h"
-
-/* this must be the last include file */
-#include "memdebug.h"
-
-static unsigned long
-hash_str(const char *key, size_t key_length)
-{
- char *end = (char *) key + key_length;
- unsigned long h = 5381;
-
- while (key < end) {
- h += h << 5;
- h ^= (unsigned long) *key++;
- }
-
- return h;
-}
-
-static void
-hash_element_dtor(void *user, void *element)
-{
- struct curl_hash *h = (struct curl_hash *) user;
- struct curl_hash_element *e = (struct curl_hash_element *) element;
-
- if (e->key)
- free(e->key);
-
- h->dtor(e->ptr);
-
- free(e);
-}
-
-/* return 1 on error, 0 is fine */
-int
-Curl_hash_init(struct curl_hash *h, int slots, curl_hash_dtor dtor)
-{
- int i;
-
- h->dtor = dtor;
- h->size = 0;
- h->slots = slots;
-
- h->table = (struct curl_llist **) malloc(slots * sizeof(struct curl_llist *));
- if(h->table) {
- for (i = 0; i < slots; ++i) {
- h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
- if(!h->table[i]) {
- while(i--)
- Curl_llist_destroy(h->table[i], NULL);
- free(h->table);
- return 1; /* failure */
- }
- }
- return 0; /* fine */
- }
- else
- return 1; /* failure */
-}
-
-struct curl_hash *
-Curl_hash_alloc(int slots, curl_hash_dtor dtor)
-{
- struct curl_hash *h;
-
- h = (struct curl_hash *) malloc(sizeof(struct curl_hash));
- if (h) {
- if(Curl_hash_init(h, slots, dtor)) {
- /* failure */
- free(h);
- h = NULL;
- }
- }
-
- return h;
-}
-
-static int
-hash_key_compare(char *key1, size_t key1_len, char *key2, size_t key2_len)
-{
- if (key1_len == key2_len &&
- *key1 == *key2 &&
- memcmp(key1, key2, key1_len) == 0) {
- return 1;
- }
-
- return 0;
-}
-
-static struct curl_hash_element *
-mk_hash_element(char *key, size_t key_len, const void *p)
-{
- struct curl_hash_element *he =
- (struct curl_hash_element *) malloc(sizeof(struct curl_hash_element));
-
- if(he) {
- char *dup = malloc(key_len);
- if(dup) {
- /* copy the key */
- memcpy(dup, key, key_len);
-
- he->key = dup;
- he->key_len = key_len;
- he->ptr = (void *) p;
- }
- else {
- /* failed to duplicate the key, free memory and fail */
- free(he);
- he = NULL;
- }
- }
- return he;
-}
-
-#define find_slot(__h, __k, __k_len) (hash_str(__k, __k_len) % (__h)->slots)
-
-#define FETCH_LIST(x,y,z) x->table[find_slot(x, y, z)]
-
-/* Return the data in the hash. If there already was a match in the hash,
- that data is returned. */
-void *
-Curl_hash_add(struct curl_hash *h, char *key, size_t key_len, void *p)
-{
- struct curl_hash_element *he;
- struct curl_llist_element *le;
- struct curl_llist *l = FETCH_LIST(h, key, key_len);
-
- for (le = l->head; le; le = le->next) {
- he = (struct curl_hash_element *) le->ptr;
- if (hash_key_compare(he->key, he->key_len, key, key_len)) {
- h->dtor(p); /* remove the NEW entry */
- return he->ptr; /* return the EXISTING entry */
- }
- }
-
- he = mk_hash_element(key, key_len, p);
- if (he) {
- if(Curl_llist_insert_next(l, l->tail, he)) {
- ++h->size;
- return p; /* return the new entry */
- }
- /*
- * Couldn't insert it, destroy the 'he' element and the key again. We
- * don't call hash_element_dtor() since that would also call the
- * "destructor" for the actual data 'p'. When we fail, we shall not touch
- * that data.
- */
- free(he->key);
- free(he);
- }
-
- return NULL; /* failure */
-}
-
-/* remove the identified hash entry, returns non-zero on failure */
-int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len)
-{
- struct curl_llist_element *le;
- struct curl_hash_element *he;
- struct curl_llist *l = FETCH_LIST(h, key, key_len);
-
- for (le = l->head; le; le = le->next) {
- he = le->ptr;
- if (hash_key_compare(he->key, he->key_len, key, key_len)) {
- Curl_llist_remove(l, le, (void *) h);
- return 0;
- }
- }
- return 1;
-}
-
-void *
-Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len)
-{
- struct curl_llist_element *le;
- struct curl_hash_element *he;
- struct curl_llist *l = FETCH_LIST(h, key, key_len);
-
- for (le = l->head; le; le = le->next) {
- he = le->ptr;
- if (hash_key_compare(he->key, he->key_len, key, key_len)) {
- return he->ptr;
- }
- }
-
- return NULL;
-}
-
-#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
-void
-Curl_hash_apply(curl_hash *h, void *user,
- void (*cb)(void *user, void *ptr))
-{
- struct curl_llist_element *le;
- int i;
-
- for (i = 0; i < h->slots; ++i) {
- for (le = (h->table[i])->head;
- le;
- le = le->next) {
- curl_hash_element *el = le->ptr;
- cb(user, el->ptr);
- }
- }
-}
-#endif
-
-void
-Curl_hash_clean(struct curl_hash *h)
-{
- int i;
-
- for (i = 0; i < h->slots; ++i) {
- Curl_llist_destroy(h->table[i], (void *) h);
- }
-
- free(h->table);
-}
-
-void
-Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
- int (*comp)(void *, void *))
-{
- struct curl_llist_element *le;
- struct curl_llist_element *lnext;
- struct curl_llist *list;
- int i;
-
- for (i = 0; i < h->slots; ++i) {
- list = h->table[i];
- le = list->head; /* get first list entry */
- while(le) {
- struct curl_hash_element *he = le->ptr;
- lnext = le->next;
- /* ask the callback function if we shall remove this entry or not */
- if (comp(user, he->ptr)) {
- Curl_llist_remove(list, le, (void *) h);
- --h->size; /* one less entry in the hash now */
- }
- le = lnext;
- }
- }
-}
-
-void
-Curl_hash_destroy(struct curl_hash *h)
-{
- if (!h)
- return;
-
- Curl_hash_clean(h);
- free(h);
-}
-
-#if 0 /* useful function for debugging hashes and their contents */
-void Curl_hash_print(struct curl_hash *h,
- void (*func)(void *))
-{
- int i;
- struct curl_llist_element *le;
- struct curl_llist *list;
- struct curl_hash_element *he;
- if (!h)
- return;
-
- fprintf(stderr, "=Hash dump=\n");
-
- for (i = 0; i < h->slots; i++) {
- list = h->table[i];
- le = list->head; /* get first list entry */
- if(le) {
- fprintf(stderr, "index %d:", i);
- while(le) {
- he = le->ptr;
- if(func)
- func(he->ptr);
- else
- fprintf(stderr, " [%p]", he->ptr);
- le = le->next;
- }
- fprintf(stderr, "\n");
- }
- }
-}
-#endif
diff --git a/Utilities/cmcurl/hash.h b/Utilities/cmcurl/hash.h
deleted file mode 100644
index ceebb5234..000000000
--- a/Utilities/cmcurl/hash.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __HASH_H
-#define __HASH_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stddef.h>
-
-#include "llist.h"
-
-typedef void (*curl_hash_dtor)(void *);
-
-struct curl_hash {
- struct curl_llist **table;
- curl_hash_dtor dtor;
- int slots;
- size_t size;
-};
-
-struct curl_hash_element {
- void *ptr;
- char *key;
- size_t key_len;
-};
-
-
-int Curl_hash_init(struct curl_hash *, int, curl_hash_dtor);
-struct curl_hash *Curl_hash_alloc(int, curl_hash_dtor);
-void *Curl_hash_add(struct curl_hash *, char *, size_t, void *);
-int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len);
-void *Curl_hash_pick(struct curl_hash *, char *, size_t);
-void Curl_hash_apply(struct curl_hash *h, void *user,
- void (*cb)(void *user, void *ptr));
-int Curl_hash_count(struct curl_hash *h);
-void Curl_hash_clean(struct curl_hash *h);
-void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
- int (*comp)(void *, void *));
-void Curl_hash_destroy(struct curl_hash *h);
-
-#endif
diff --git a/Utilities/cmcurl/hostares.c b/Utilities/cmcurl/hostares.c
deleted file mode 100644
index 1db0f4320..000000000
--- a/Utilities/cmcurl/hostares.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "multiif.h"
-#include "connect.h" /* for the Curl_sockerrno() proto */
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for ares-enabled builds
- **********************************************************************/
-
-#ifdef CURLRES_ARES
-
-/*
- * Curl_resolv_fdset() is called when someone from the outside world (using
- * curl_multi_fdset()) wants to get our fd_set setup and we're talking with
- * ares. The caller must make sure that this function is only called when we
- * have a working ares channel.
- *
- * Returns: CURLE_OK always!
- */
-
-int Curl_resolv_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-
-{
- struct timeval maxtime;
- struct timeval timeout;
- int max = ares_getsock(conn->data->state.areschannel,
- (int *)socks, numsocks);
-
-
- maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
- maxtime.tv_usec = 0;
-
- ares_timeout(conn->data->state.areschannel, &maxtime, &timeout);
-
- Curl_expire(conn->data,
- (timeout.tv_sec * 1000) + (timeout.tv_usec/1000) );
-
- return max;
-}
-
-/*
- * Curl_is_resolved() is called repeatedly to check if a previous name resolve
- * request has completed. It should also make sure to time-out if the
- * operation seems to take too long.
- *
- * Returns normal CURLcode errors.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
- struct Curl_dns_entry **dns)
-{
- fd_set read_fds, write_fds;
- struct timeval tv={0,0};
- struct SessionHandle *data = conn->data;
- int nfds;
-
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
-
- nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
-
- (void)select(nfds, &read_fds, &write_fds, NULL,
- (struct timeval *)&tv);
-
- /* Call ares_process() unconditonally here, even if we simply timed out
- above, as otherwise the ares name resolve won't timeout! */
- ares_process(data->state.areschannel, &read_fds, &write_fds);
-
- *dns = NULL;
-
- if(conn->async.done) {
- /* we're done, kill the ares handle */
- if(!conn->async.dns) {
- failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
- ares_strerror(conn->async.status));
- return CURLE_COULDNT_RESOLVE_HOST;
- }
- *dns = conn->async.dns;
- }
-
- return CURLE_OK;
-}
-
-/*
- * Curl_wait_for_resolv() waits for a resolve to finish. This function should
- * be avoided since using this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
- */
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
- struct Curl_dns_entry **entry)
-{
- CURLcode rc=CURLE_OK;
- struct SessionHandle *data = conn->data;
- long timeout = CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
-
- /* now, see if there's a connect timeout or a regular timeout to
- use instead of the default one */
- if(conn->data->set.connecttimeout)
- timeout = conn->data->set.connecttimeout;
- else if(conn->data->set.timeout)
- timeout = conn->data->set.timeout;
-
- /* We convert the number of seconds into number of milliseconds here: */
- if(timeout < 2147483)
- /* maximum amount of seconds that can be multiplied with 1000 and
- still fit within 31 bits */
- timeout *= 1000;
- else
- timeout = 0x7fffffff; /* ridiculous amount of time anyway */
-
- /* Wait for the name resolve query to complete. */
- while (1) {
- int nfds=0;
- fd_set read_fds, write_fds;
- struct timeval *tvp, tv, store;
- int count;
- struct timeval now = Curl_tvnow();
- long timediff;
-
- store.tv_sec = (int)timeout/1000;
- store.tv_usec = (timeout%1000)*1000;
-
- FD_ZERO(&read_fds);
- FD_ZERO(&write_fds);
- nfds = ares_fds(data->state.areschannel, &read_fds, &write_fds);
- if (nfds == 0)
- /* no file descriptors means we're done waiting */
- break;
- tvp = ares_timeout(data->state.areschannel, &store, &tv);
- count = select(nfds, &read_fds, &write_fds, NULL, tvp);
- if (count < 0 && Curl_sockerrno() != EINVAL)
- break;
-
- ares_process(data->state.areschannel, &read_fds, &write_fds);
-
- timediff = Curl_tvdiff(Curl_tvnow(), now); /* spent time */
- timeout -= timediff?timediff:1; /* always deduct at least 1 */
- if (timeout < 0) {
- /* our timeout, so we cancel the ares operation */
- ares_cancel(data->state.areschannel);
- break;
- }
- }
-
- /* Operation complete, if the lookup was successful we now have the entry
- in the cache. */
-
- if(entry)
- *entry = conn->async.dns;
-
- if(!conn->async.dns) {
- /* a name was not resolved */
- if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) {
- failf(data, "Resolving host timed out: %s", conn->host.dispname);
- rc = CURLE_OPERATION_TIMEDOUT;
- }
- else if(conn->async.done) {
- failf(data, "Could not resolve host: %s (%s)", conn->host.dispname,
- ares_strerror(conn->async.status));
- rc = CURLE_COULDNT_RESOLVE_HOST;
- }
- else
- rc = CURLE_OPERATION_TIMEDOUT;
-
- /* close the connection, since we can't return failure here without
- cleaning up this connection properly */
- conn->bits.close = TRUE;
- }
-
- return rc;
-}
-
-/*
- * Curl_getaddrinfo() - when using ares
- *
- * Returns name information about the given hostname and port number. If
- * successful, the 'hostent' is returned and the forth argument will point to
- * memory we need to free after use. That memory *MUST* be freed with
- * Curl_freeaddrinfo(), nothing else.
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- char *bufp;
- struct SessionHandle *data = conn->data;
- in_addr_t in = inet_addr(hostname);
-
- *waitp = FALSE;
-
- if (in != CURL_INADDR_NONE) {
- /* This is a dotted IP address 123.123.123.123-style */
- return Curl_ip2addr(in, hostname, port);
- }
-
- bufp = strdup(hostname);
-
- if(bufp) {
- Curl_safefree(conn->async.hostname);
- conn->async.hostname = bufp;
- conn->async.port = port;
- conn->async.done = FALSE; /* not done */
- conn->async.status = 0; /* clear */
- conn->async.dns = NULL; /* clear */
-
- /* areschannel is already setup in the Curl_open() function */
- ares_gethostbyname(data->state.areschannel, hostname, PF_INET,
- (ares_host_callback)Curl_addrinfo4_callback, conn);
-
- *waitp = TRUE; /* please wait for the response */
- }
- return NULL; /* no struct yet */
-}
-#endif /* CURLRES_ARES */
diff --git a/Utilities/cmcurl/hostasyn.c b/Utilities/cmcurl/hostasyn.c
deleted file mode 100644
index 3df147910..000000000
--- a/Utilities/cmcurl/hostasyn.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for builds using asynchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_ASYNCH
-/*
- * addrinfo_callback() gets called by ares, gethostbyname_thread() or
- * getaddrinfo_thread() when we got the name resolved (or not!).
- *
- * If the status argument is CURL_ASYNC_SUCCESS, we might need to copy the
- * address field since it might be freed when this function returns. This
- * operation stores the resolved data in the DNS cache.
- *
- * NOTE: for IPv6 operations, Curl_addrinfo_copy() returns the same
- * pointer it is given as argument!
- *
- * The storage operation locks and unlocks the DNS cache.
- */
-static CURLcode addrinfo_callback(void *arg, /* "struct connectdata *" */
- int status,
- void *addr)
-{
- struct connectdata *conn = (struct connectdata *)arg;
- struct Curl_dns_entry *dns = NULL;
- CURLcode rc = CURLE_OK;
-
- conn->async.status = status;
-
- if(CURL_ASYNC_SUCCESS == status) {
-
- /*
- * IPv4/ares: Curl_addrinfo_copy() copies the address and returns an
- * allocated version.
- *
- * IPv6: Curl_addrinfo_copy() returns the input pointer!
- */
- Curl_addrinfo *ai = Curl_addrinfo_copy(addr, conn->async.port);
- if(ai) {
- struct SessionHandle *data = conn->data;
-
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- dns = Curl_cache_addr(data, ai,
- conn->async.hostname,
- conn->async.port);
- if(!dns) {
- /* failed to store, cleanup and return error */
- Curl_freeaddrinfo(ai);
- rc = CURLE_OUT_OF_MEMORY;
- }
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
- }
- else
- rc = CURLE_OUT_OF_MEMORY;
- }
-
- conn->async.dns = dns;
-
- /* Set async.done TRUE last in this function since it may be used multi-
- threaded and once this is TRUE the other thread may read fields from the
- async struct */
- conn->async.done = TRUE;
-
- /* ipv4: The input hostent struct will be freed by ares when we return from
- this function */
- return rc;
-}
-
-CURLcode Curl_addrinfo4_callback(void *arg, /* "struct connectdata *" */
- int status,
- struct hostent *hostent)
-{
- return addrinfo_callback(arg, status, hostent);
-}
-
-#ifdef CURLRES_IPV6
-CURLcode Curl_addrinfo6_callback(void *arg, /* "struct connectdata *" */
- int status,
- struct addrinfo *ai)
-{
- /* NOTE: for CURLRES_ARES, the 'ai' argument is really a
- * 'struct hostent' pointer.
- */
- return addrinfo_callback(arg, status, ai);
-}
-#endif
-
-#endif /* CURLRES_ASYNC */
diff --git a/Utilities/cmcurl/hostip.c b/Utilities/cmcurl/hostip.c
deleted file mode 100644
index fd555ef9d..000000000
--- a/Utilities/cmcurl/hostip.c
+++ /dev/null
@@ -1,636 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "inet_ntop.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- * hostip.c explained
- * ==================
- *
- * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
- * source file are these:
- *
- * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
- * that. The host may not be able to resolve IPv6, but we don't really have to
- * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
- * defined.
- *
- * CURLRES_ARES - is defined if libcurl is built to use c-ares for
- * asynchronous name resolves. This can be Windows or *nix.
- *
- * CURLRES_THREADED - is defined if libcurl is built to run under (native)
- * Windows, and then the name resolve will be done in a new thread, and the
- * supported API will be the same as for ares-builds.
- *
- * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
- * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
- * defined.
- *
- * The host*.c sources files are split up like this:
- *
- * hostip.c - method-independent resolver functions and utility functions
- * hostasyn.c - functions for asynchronous name resolves
- * hostsyn.c - functions for synchronous name resolves
- * hostares.c - functions for ares-using name resolves
- * hostthre.c - functions for threaded name resolves
- * hostip4.c - ipv4-specific functions
- * hostip6.c - ipv6-specific functions
- *
- * The hostip.h is the united header file for all this. It defines the
- * CURLRES_* defines based on the config*.h and setup.h defines.
- */
-
-/* These two symbols are for the global DNS cache */
-static struct curl_hash hostname_cache;
-static int host_cache_initialized;
-
-static void freednsentry(void *freethis);
-
-/*
- * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
- * Global DNS cache is general badness. Do not use. This will be removed in
- * a future version. Use the share interface instead!
- */
-void Curl_global_host_cache_init(void)
-{
- if (!host_cache_initialized) {
- Curl_hash_init(&hostname_cache, 7, freednsentry);
- host_cache_initialized = 1;
- }
-}
-
-/*
- * Return a pointer to the global cache
- */
-struct curl_hash *Curl_global_host_cache_get(void)
-{
- return &hostname_cache;
-}
-
-/*
- * Destroy and cleanup the global DNS cache
- */
-void Curl_global_host_cache_dtor(void)
-{
- if (host_cache_initialized) {
- Curl_hash_clean(&hostname_cache);
- host_cache_initialized = 0;
- }
-}
-
-/*
- * Return # of adresses in a Curl_addrinfo struct
- */
-int Curl_num_addresses(const Curl_addrinfo *addr)
-{
- int i;
- for (i = 0; addr; addr = addr->ai_next, i++)
- ; /* empty loop */
- return i;
-}
-
-/*
- * Curl_printable_address() returns a printable version of the 1st address
- * given in the 'ip' argument. The result will be stored in the buf that is
- * bufsize bytes big.
- *
- * If the conversion fails, it returns NULL.
- */
-const char *Curl_printable_address(const Curl_addrinfo *ip,
- char *buf, size_t bufsize)
-{
- const void *ip4 = &((const struct sockaddr_in*)ip->ai_addr)->sin_addr;
- int af = ip->ai_family;
-#ifdef CURLRES_IPV6
- const void *ip6 = &((const struct sockaddr_in6*)ip->ai_addr)->sin6_addr;
-#else
- const void *ip6 = NULL;
-#endif
-
- return Curl_inet_ntop(af, af == AF_INET ? ip4 : ip6, buf, bufsize);
-}
-
-/*
- * Return a hostcache id string for the providing host + port, to be used by
- * the DNS caching.
- */
-static char *
-create_hostcache_id(const char *server, int port)
-{
- /* create and return the new allocated entry */
- return aprintf("%s:%d", server, port);
-}
-
-struct hostcache_prune_data {
- int cache_timeout;
- time_t now;
-};
-
-/*
- * This function is set as a callback to be called for every entry in the DNS
- * cache when we want to prune old unused entries.
- *
- * Returning non-zero means remove the entry, return 0 to keep it in the
- * cache.
- */
-static int
-hostcache_timestamp_remove(void *datap, void *hc)
-{
- struct hostcache_prune_data *data =
- (struct hostcache_prune_data *) datap;
- struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
-
- if ((data->now - c->timestamp < data->cache_timeout) ||
- c->inuse) {
- /* please don't remove */
- return 0;
- }
-
- /* fine, remove */
- return 1;
-}
-
-/*
- * Prune the DNS cache. This assumes that a lock has already been taken.
- */
-static void
-hostcache_prune(struct curl_hash *hostcache, int cache_timeout, time_t now)
-{
- struct hostcache_prune_data user;
-
- user.cache_timeout = cache_timeout;
- user.now = now;
-
- Curl_hash_clean_with_criterium(hostcache,
- (void *) &user,
- hostcache_timestamp_remove);
-}
-
-/*
- * Library-wide function for pruning the DNS cache. This function takes and
- * returns the appropriate locks.
- */
-void Curl_hostcache_prune(struct SessionHandle *data)
-{
- time_t now;
-
- if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
- /* cache forever means never prune, and NULL hostcache means
- we can't do it */
- return;
-
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- time(&now);
-
- /* Remove outdated and unused entries from the hostcache */
- hostcache_prune(data->dns.hostcache,
- data->set.dns_cache_timeout,
- now);
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-}
-
-static int
-remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
-{
- struct hostcache_prune_data user;
-
- if( !dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
- /* cache forever means never prune, and NULL hostcache means
- we can't do it */
- return 0;
-
- time(&user.now);
- user.cache_timeout = data->set.dns_cache_timeout;
-
- if ( !hostcache_timestamp_remove(&user,dns) )
- return 0;
-
- /* ok, we do need to clear the cache. although we need to remove just a
- single entry we clean the entire hash, as no explicit delete function
- is provided */
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- Curl_hash_clean_with_criterium(data->dns.hostcache,
- (void *) &user,
- hostcache_timestamp_remove);
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-
- return 1;
-}
-
-
-#ifdef HAVE_SIGSETJMP
-/* Beware this is a global and unique instance. This is used to store the
- return address that we can jump back to from inside a signal handler. This
- is not thread-safe stuff. */
-sigjmp_buf curl_jmpenv;
-#endif
-
-
-/*
- * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
- *
- * When calling Curl_resolv() has resulted in a response with a returned
- * address, we call this function to store the information in the dns
- * cache etc
- *
- * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
- */
-struct Curl_dns_entry *
-Curl_cache_addr(struct SessionHandle *data,
- Curl_addrinfo *addr,
- const char *hostname,
- int port)
-{
- char *entry_id;
- size_t entry_len;
- struct Curl_dns_entry *dns;
- struct Curl_dns_entry *dns2;
- time_t now;
-
- /* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if (!entry_id)
- return NULL;
- entry_len = strlen(entry_id);
-
- /* Create a new cache entry */
- dns = (struct Curl_dns_entry *) calloc(sizeof(struct Curl_dns_entry), 1);
- if (!dns) {
- free(entry_id);
- return NULL;
- }
-
- dns->inuse = 0; /* init to not used */
- dns->addr = addr; /* this is the address(es) */
-
- /* Store the resolved data in our DNS cache. This function may return a
- pointer to an existing struct already present in the hash, and it may
- return the same argument we pass in. Make no assumptions. */
- dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
- (void *)dns);
- if(!dns2) {
- /* Major badness, run away. */
- free(dns);
- free(entry_id);
- return NULL;
- }
- time(&now);
- dns = dns2;
-
- dns->timestamp = now; /* used now */
- dns->inuse++; /* mark entry as in-use */
-
- /* free the allocated entry_id again */
- free(entry_id);
-
- return dns;
-}
-
-/*
- * Curl_resolv() is the main name resolve function within libcurl. It resolves
- * a name and returns a pointer to the entry in the 'entry' argument (if one
- * is provided). This function might return immediately if we're using asynch
- * resolves. See the return codes.
- *
- * The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlock() later (when you're
- * done using this struct) to decrease the counter again.
- *
- * Return codes:
- *
- * CURLRESOLV_ERROR (-1) = error, no pointer
- * CURLRESOLV_RESOLVED (0) = OK, pointer provided
- * CURLRESOLV_PENDING (1) = waiting for response, no pointer
- */
-
-int Curl_resolv(struct connectdata *conn,
- const char *hostname,
- int port,
- struct Curl_dns_entry **entry)
-{
- char *entry_id = NULL;
- struct Curl_dns_entry *dns = NULL;
- size_t entry_len;
- int wait;
- struct SessionHandle *data = conn->data;
- CURLcode result;
- int rc;
- *entry = NULL;
-
-#ifdef HAVE_SIGSETJMP
- /* this allows us to time-out from the name resolver, as the timeout
- will generate a signal and we will siglongjmp() from that here */
- if(!data->set.no_signal) {
- if (sigsetjmp(curl_jmpenv, 1)) {
- /* this is coming from a siglongjmp() */
- failf(data, "name lookup timed out");
- return CURLRESOLV_ERROR;
- }
- }
-#endif
-
- /* Create an entry id, based upon the hostname and port */
- entry_id = create_hostcache_id(hostname, port);
- /* If we can't create the entry id, fail */
- if (!entry_id)
- return CURLRESOLV_ERROR;
-
- entry_len = strlen(entry_id);
-
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- /* See if its already in our dns cache */
- dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-
- /* free the allocated entry_id again */
- free(entry_id);
-
- /* See whether the returned entry is stale. Deliberately done after the
- locked block */
- if ( remove_entry_if_stale(data,dns) )
- dns = NULL; /* the memory deallocation is being handled by the hash */
-
- rc = CURLRESOLV_ERROR; /* default to failure */
-
- if (!dns) {
- /* The entry was not in the cache. Resolve it to IP address */
-
- Curl_addrinfo *addr;
-
- /* Check what IP specifics the app has requested and if we can provide it.
- * If not, bail out. */
- if(!Curl_ipvalid(data))
- return CURLRESOLV_ERROR;
-
- /* If Curl_getaddrinfo() returns NULL, 'wait' might be set to a non-zero
- value indicating that we need to wait for the response to the resolve
- call */
- addr = Curl_getaddrinfo(conn, hostname, port, &wait);
-
- if (!addr) {
- if(wait) {
- /* the response to our resolve call will come asynchronously at
- a later time, good or bad */
- /* First, check that we haven't received the info by now */
- result = Curl_is_resolved(conn, &dns);
- if(result) /* error detected */
- return CURLRESOLV_ERROR;
- if(dns)
- rc = CURLRESOLV_RESOLVED; /* pointer provided */
- else
- rc = CURLRESOLV_PENDING; /* no info yet */
- }
- }
- else {
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- /* we got a response, store it in the cache */
- dns = Curl_cache_addr(data, addr, hostname, port);
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-
- if(!dns)
- /* returned failure, bail out nicely */
- Curl_freeaddrinfo(addr);
- else
- rc = CURLRESOLV_RESOLVED;
- }
- }
- else {
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
- dns->inuse++; /* we use it! */
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
- rc = CURLRESOLV_RESOLVED;
- }
-
- *entry = dns;
-
- return rc;
-}
-
-/*
- * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
- * made, the struct may be destroyed due to pruning. It is important that only
- * one unlock is made for each Curl_resolv() call.
- */
-void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns)
-{
- curlassert(dns && (dns->inuse>0));
-
- if(data->share)
- Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
-
- dns->inuse--;
-
- if(data->share)
- Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
-}
-
-/*
- * File-internal: free a cache dns entry.
- */
-static void freednsentry(void *freethis)
-{
- struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
-
- Curl_freeaddrinfo(p->addr);
-
- free(p);
-}
-
-/*
- * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
- */
-struct curl_hash *Curl_mk_dnscache(void)
-{
- return Curl_hash_alloc(7, freednsentry);
-}
-
-#ifdef CURLRES_ADDRINFO_COPY
-
-/* align on even 64bit boundaries */
-#define MEMALIGN(x) ((x)+(8-(((unsigned long)(x))&0x7)))
-
-/*
- * Curl_addrinfo_copy() performs a "deep" copy of a hostent into a buffer and
- * returns a pointer to the malloc()ed copy. You need to call free() on the
- * returned buffer when you're done with it.
- */
-Curl_addrinfo *Curl_addrinfo_copy(const void *org, int port)
-{
- const struct hostent *orig = org;
-
- return Curl_he2ai(orig, port);
-}
-#endif /* CURLRES_ADDRINFO_COPY */
-
-/***********************************************************************
- * Only for plain-ipv4 and c-ares builds
- **********************************************************************/
-
-#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
-/*
- * This is a function for freeing name information in a protocol independent
- * way.
- */
-void Curl_freeaddrinfo(Curl_addrinfo *ai)
-{
- Curl_addrinfo *next;
-
- /* walk over the list and free all entries */
- while(ai) {
- next = ai->ai_next;
- free(ai);
- ai = next;
- }
-}
-
-struct namebuf {
- struct hostent hostentry;
- char *h_addr_list[2];
- struct in_addr addrentry;
- char h_name[16]; /* 123.123.123.123 = 15 letters is maximum */
-};
-
-/*
- * Curl_ip2addr() takes a 32bit ipv4 internet address as input parameter
- * together with a pointer to the string version of the address, and it
- * returns a Curl_addrinfo chain filled in correctly with information for this
- * address/host.
- *
- * The input parameters ARE NOT checked for validity but they are expected
- * to have been checked already when this is called.
- */
-Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port)
-{
- Curl_addrinfo *ai;
- struct hostent *h;
- struct in_addr *addrentry;
- struct namebuf buffer;
- struct namebuf *buf = &buffer;
-
- h = &buf->hostentry;
- h->h_addr_list = &buf->h_addr_list[0];
- addrentry = &buf->addrentry;
-#ifdef _CRAYC
- /* On UNICOS, s_addr is a bit field and for some reason assigning to it
- * doesn't work. There must be a better fix than this ugly hack.
- */
- memcpy(addrentry, &num, SIZEOF_in_addr);
-#else
- addrentry->s_addr = num;
-#endif
- h->h_addr_list[0] = (char*)addrentry;
- h->h_addr_list[1] = NULL;
- h->h_addrtype = AF_INET;
- h->h_length = sizeof(*addrentry);
- h->h_name = &buf->h_name[0];
- h->h_aliases = NULL;
-
- /* Now store the dotted version of the address */
- snprintf((char *)h->h_name, 16, "%s", hostname);
-
- ai = Curl_he2ai(h, port);
-
- return ai;
-}
-#endif
-
-
diff --git a/Utilities/cmcurl/hostip.h b/Utilities/cmcurl/hostip.h
deleted file mode 100644
index e6d63ca71..000000000
--- a/Utilities/cmcurl/hostip.h
+++ /dev/null
@@ -1,271 +0,0 @@
-#ifndef __HOSTIP_H
-#define __HOSTIP_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include "hash.h"
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t uint32_t
-#endif
-
-/*
- * Setup comfortable CURLRES_* defines to use in the host*.c sources.
- */
-
-#ifdef USE_ARES
-#define CURLRES_ASYNCH
-#define CURLRES_ARES
-#endif
-
-#ifdef USE_THREADING_GETHOSTBYNAME
-#define CURLRES_ASYNCH
-#define CURLRES_THREADED
-#endif
-
-#ifdef USE_THREADING_GETADDRINFO
-#define CURLRES_ASYNCH
-#define CURLRES_THREADED
-#endif
-
-#ifdef ENABLE_IPV6
-#define CURLRES_IPV6
-#else
-#define CURLRES_IPV4
-#endif
-
-#if defined(CURLRES_IPV4) || defined(CURLRES_ARES)
-#if !defined(HAVE_GETHOSTBYNAME_R) || defined(CURLRES_ASYNCH)
-/* If built for ipv4 and missing gethostbyname_r(), or if using async name
- resolve, we need the Curl_addrinfo_copy() function (which itself needs the
- Curl_he2ai() function)) */
-#define CURLRES_ADDRINFO_COPY
-#endif
-#endif /* IPv4/ares-only */
-
-#ifndef CURLRES_ASYNCH
-#define CURLRES_SYNCH
-#endif
-
-#ifndef USE_LIBIDN
-#define CURLRES_IDN
-#endif
-
-/* Allocate enough memory to hold the full name information structs and
- * everything. OSF1 is known to require at least 8872 bytes. The buffer
- * required for storing all possible aliases and IP numbers is according to
- * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
- */
-#define CURL_HOSTENT_SIZE 9000
-
-#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
- many seconds for a name resolve */
-
-#ifdef CURLRES_ARES
-#define CURL_ASYNC_SUCCESS ARES_SUCCESS
-#else
-#define CURL_ASYNC_SUCCESS CURLE_OK
-#define ares_cancel(x) do {} while(0)
-#define ares_destroy(x) do {} while(0)
-#endif
-
-/*
- * Curl_addrinfo MUST be used for all name resolved info.
- */
-#ifdef CURLRES_IPV6
-typedef struct addrinfo Curl_addrinfo;
-#else
-/* OK, so some ipv4-only include tree probably have the addrinfo struct, but
- to work even on those that don't, we provide our own look-alike! */
-struct Curl_addrinfo {
- int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */
- char *ai_canonname;
- struct sockaddr *ai_addr;
- struct Curl_addrinfo *ai_next;
-};
-typedef struct Curl_addrinfo Curl_addrinfo;
-#endif
-
-struct addrinfo;
-struct hostent;
-struct SessionHandle;
-struct connectdata;
-
-void Curl_global_host_cache_init(void);
-void Curl_global_host_cache_dtor(void);
-struct curl_hash *Curl_global_host_cache_get(void);
-
-#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
-
-struct Curl_dns_entry {
- Curl_addrinfo *addr;
- time_t timestamp;
- long inuse; /* use-counter, make very sure you decrease this
- when you're done using the address you received */
-};
-
-/*
- * Curl_resolv() returns an entry with the info for the specified host
- * and port.
- *
- * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
- * use, or we'll leak memory!
- */
-/* return codes */
-#define CURLRESOLV_ERROR -1
-#define CURLRESOLV_RESOLVED 0
-#define CURLRESOLV_PENDING 1
-int Curl_resolv(struct connectdata *conn, const char *hostname,
- int port, struct Curl_dns_entry **dnsentry);
-
-/*
- * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
- * been set and returns TRUE if they are OK.
- */
-bool Curl_ipvalid(struct SessionHandle *data);
-
-/*
- * Curl_getaddrinfo() is the generic low-level name resolve API within this
- * source file. There are several versions of this function - for different
- * name resolve layers (selected at build-time). They all take this same set
- * of arguments
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp);
-
-CURLcode Curl_is_resolved(struct connectdata *conn,
- struct Curl_dns_entry **dns);
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
- struct Curl_dns_entry **dnsentry);
-
-/* Curl_resolv_getsock() is a generic function that exists in multiple
- versions depending on what name resolve technology we've built to use. The
- function is called from the multi_getsock() function. 'sock' is a pointer
- to an array to hold the file descriptors, with 'numsock' being the size of
- that array (in number of entries). This function is supposed to return
- bitmask indicating what file descriptors (referring to array indexes in the
- 'sock' array) to wait for, read/write. */
-int Curl_resolv_getsock(struct connectdata *conn, curl_socket_t *sock,
- int numsocks);
-
-/* unlock a previously resolved dns entry */
-void Curl_resolv_unlock(struct SessionHandle *data,
- struct Curl_dns_entry *dns);
-
-/* for debugging purposes only: */
-void Curl_scan_cache_used(void *user, void *ptr);
-
-/* free name info */
-void Curl_freeaddrinfo(Curl_addrinfo *freeaddr);
-
-/* make a new dns cache and return the handle */
-struct curl_hash *Curl_mk_dnscache(void);
-
-/* prune old entries from the DNS cache */
-void Curl_hostcache_prune(struct SessionHandle *data);
-
-/* Return # of adresses in a Curl_addrinfo struct */
-int Curl_num_addresses (const Curl_addrinfo *addr);
-
-#ifdef CURLDEBUG
-void curl_dofreeaddrinfo(struct addrinfo *freethis,
- int line, const char *source);
-int curl_dogetaddrinfo(const char *hostname, const char *service,
- struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source);
-#ifdef HAVE_GETNAMEINFO
-int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
- GETNAMEINFO_TYPE_ARG2 salen,
- char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
- char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
- GETNAMEINFO_TYPE_ARG7 flags,
- int line, const char *source);
-#endif
-#endif
-
-/* This is the callback function that is used when we build with asynch
- resolve, ipv4 */
-CURLcode Curl_addrinfo4_callback(void *arg,
- int status,
- struct hostent *hostent);
-/* This is the callback function that is used when we build with asynch
- resolve, ipv6 */
-CURLcode Curl_addrinfo6_callback(void *arg,
- int status,
- struct addrinfo *ai);
-
-
-/* [ipv4/ares only] Creates a Curl_addrinfo struct from a numerical-only IP
- address */
-Curl_addrinfo *Curl_ip2addr(in_addr_t num, const char *hostname, int port);
-
-/* [ipv4/ares only] Curl_he2ai() converts a struct hostent to a Curl_addrinfo chain
- and returns it */
-Curl_addrinfo *Curl_he2ai(const struct hostent *, int port);
-
-/* Clone a Curl_addrinfo struct, works protocol independently */
-Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port);
-
-/*
- * Curl_printable_address() returns a printable version of the 1st address
- * given in the 'ip' argument. The result will be stored in the buf that is
- * bufsize bytes big.
- */
-const char *Curl_printable_address(const Curl_addrinfo *ip,
- char *buf, size_t bufsize);
-
-/*
- * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
- *
- * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
- */
-struct Curl_dns_entry *
-Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
- const char *hostname, int port);
-
-/*
- * Curl_destroy_thread_data() cleans up async resolver data.
- * Complementary of ares_destroy.
- */
-struct Curl_async; /* forward-declaration */
-void Curl_destroy_thread_data(struct Curl_async *async);
-
-#ifndef INADDR_NONE
-#define CURL_INADDR_NONE (in_addr_t) ~0
-#else
-#define CURL_INADDR_NONE INADDR_NONE
-#endif
-
-
-
-
-#endif
diff --git a/Utilities/cmcurl/hostip4.c b/Utilities/cmcurl/hostip4.c
deleted file mode 100644
index 877baa2ca..000000000
--- a/Utilities/cmcurl/hostip4.c
+++ /dev/null
@@ -1,389 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <errno.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "inet_pton.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for plain-ipv4 builds
- **********************************************************************/
-#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */
-/*
- * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
- * been set and returns TRUE if they are OK.
- */
-bool Curl_ipvalid(struct SessionHandle *data)
-{
- if(data->set.ip_version == CURL_IPRESOLVE_V6)
- /* an ipv6 address was requested and we can't get/use one */
- return FALSE;
-
- return TRUE; /* OK, proceed */
-}
-
-#ifdef CURLRES_SYNCH /* the functions below are for synchronous resolves */
-
-/*
- * Curl_getaddrinfo() - the ipv4 synchronous version.
- *
- * The original code to this function was from the Dancer source code, written
- * by Bjorn Reese, it has since been patched and modified considerably.
- *
- * gethostbyname_r() is the thread-safe version of the gethostbyname()
- * function. When we build for plain IPv4, we attempt to use this
- * function. There are _three_ different gethostbyname_r() versions, and we
- * detect which one this platform supports in the configure script and set up
- * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
- * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
- * has the corresponding rules. This is primarily on *nix. Note that some unix
- * flavours have thread-safe versions of the plain gethostbyname() etc.
- *
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- Curl_addrinfo *ai = NULL;
- struct hostent *h = NULL;
- in_addr_t in;
- struct SessionHandle *data = conn->data;
- struct hostent *buf = NULL;
-
- (void)port; /* unused in IPv4 code */
-
- *waitp = 0; /* don't wait, we act synchronously */
-
- if(1 == Curl_inet_pton(AF_INET, hostname, &in))
- /* This is a dotted IP address 123.123.123.123-style */
- return Curl_ip2addr(in, hostname, port);
-
-#if defined(HAVE_GETHOSTBYNAME_R)
- /*
- * gethostbyname_r() is the preferred resolve function for many platforms.
- * Since there are three different versions of it, the following code is
- * somewhat #ifdef-ridden.
- */
- else {
- int h_errnop;
- int res=ERANGE;
-
- buf = (struct hostent *)calloc(CURL_HOSTENT_SIZE, 1);
- if(!buf)
- return NULL; /* major failure */
- /*
- * The clearing of the buffer is a workaround for a gethostbyname_r bug in
- * qnx nto and it is also _required_ for some of these functions on some
- * platforms.
- */
-
-#ifdef HAVE_GETHOSTBYNAME_R_5
- /* Solaris, IRIX and more */
- (void)res; /* prevent compiler warning */
- h = gethostbyname_r(hostname,
- (struct hostent *)buf,
- (char *)buf + sizeof(struct hostent),
- CURL_HOSTENT_SIZE - sizeof(struct hostent),
- &h_errnop);
-
- /* If the buffer is too small, it returns NULL and sets errno to
- * ERANGE. The errno is thread safe if this is compiled with
- * -D_REENTRANT as then the 'errno' variable is a macro defined to get
- * used properly for threads.
- */
-
- if(h) {
- ;
- }
- else
-#endif /* HAVE_GETHOSTBYNAME_R_5 */
-#ifdef HAVE_GETHOSTBYNAME_R_6
- /* Linux */
-
- res=gethostbyname_r(hostname,
- (struct hostent *)buf,
- (char *)buf + sizeof(struct hostent),
- CURL_HOSTENT_SIZE - sizeof(struct hostent),
- &h, /* DIFFERENCE */
- &h_errnop);
- /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
- * sudden this function returns EAGAIN if the given buffer size is too
- * small. Previous versions are known to return ERANGE for the same
- * problem.
- *
- * This wouldn't be such a big problem if older versions wouldn't
- * sometimes return EAGAIN on a common failure case. Alas, we can't
- * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
- * glibc.
- *
- * For now, we do that and thus we may call the function repeatedly and
- * fail for older glibc versions that return EAGAIN, until we run out of
- * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
- *
- * If anyone has a better fix, please tell us!
- *
- * -------------------------------------------------------------------
- *
- * On October 23rd 2003, Dan C dug up more details on the mysteries of
- * gethostbyname_r() in glibc:
- *
- * In glibc 2.2.5 the interface is different (this has also been
- * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
- * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
- * (shipped/upgraded by Redhat 7.2) don't show this behavior!
- *
- * In this "buggy" version, the return code is -1 on error and 'errno'
- * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
- * thread-safe variable.
- */
-
- if(!h) /* failure */
-#endif/* HAVE_GETHOSTBYNAME_R_6 */
-#ifdef HAVE_GETHOSTBYNAME_R_3
- /* AIX, Digital Unix/Tru64, HPUX 10, more? */
-
- /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
- * the plain fact that it does not return unique full buffers on each
- * call, but instead several of the pointers in the hostent structs will
- * point to the same actual data! This have the unfortunate down-side that
- * our caching system breaks down horribly. Luckily for us though, AIX 4.3
- * and more recent versions have a "completely thread-safe"[*] libc where
- * all the data is stored in thread-specific memory areas making calls to
- * the plain old gethostbyname() work fine even for multi-threaded
- * programs.
- *
- * This AIX 4.3 or later detection is all made in the configure script.
- *
- * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
- *
- * [*] = much later we've found out that it isn't at all "completely
- * thread-safe", but at least the gethostbyname() function is.
- */
-
- if(CURL_HOSTENT_SIZE >=
- (sizeof(struct hostent)+sizeof(struct hostent_data))) {
-
- /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
- * that should work! September 20: Richard Prescott worked on the buffer
- * size dilemma.
- */
-
- res = gethostbyname_r(hostname,
- (struct hostent *)buf,
- (struct hostent_data *)((char *)buf +
- sizeof(struct hostent)));
- h_errnop= errno; /* we don't deal with this, but set it anyway */
- }
- else
- res = -1; /* failure, too smallish buffer size */
-
- if(!res) { /* success */
-
- h = buf; /* result expected in h */
-
- /* This is the worst kind of the different gethostbyname_r() interfaces.
- * Since we don't know how big buffer this particular lookup required,
- * we can't realloc down the huge alloc without doing closer analysis of
- * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
- * name lookup. Fixing this would require an extra malloc() and then
- * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
- * memory area to the actually used amount.
- */
- }
- else
-#endif /* HAVE_GETHOSTBYNAME_R_3 */
- {
- infof(data, "gethostbyname_r(2) failed for %s\n", hostname);
- h = NULL; /* set return code to NULL */
- free(buf);
- }
-#else /* HAVE_GETHOSTBYNAME_R */
- /*
- * Here is code for platforms that don't have gethostbyname_r() or for
- * which the gethostbyname() is the preferred() function.
- */
- else {
- h = gethostbyname(hostname);
- if (!h)
- infof(data, "gethostbyname(2) failed for %s\n", hostname);
-#endif /*HAVE_GETHOSTBYNAME_R */
- }
-
- if(h) {
- ai = Curl_he2ai(h, port);
-
- if (buf) /* used a *_r() function */
- free(buf);
- }
-
- return ai;
-}
-
-#endif /* CURLRES_SYNCH */
-#endif /* CURLRES_IPV4 */
-
-/*
- * Curl_he2ai() translates from a hostent struct to a Curl_addrinfo struct.
- * The Curl_addrinfo is meant to work like the addrinfo struct does for IPv6
- * stacks, but for all hosts and environments.
- *
- * Curl_addrinfo defined in "lib/hostip.h"
- *
- * struct Curl_addrinfo {
- * int ai_flags;
- * int ai_family;
- * int ai_socktype;
- * int ai_protocol;
- * socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo *
- * char *ai_canonname;
- * struct sockaddr *ai_addr;
- * struct Curl_addrinfo *ai_next;
- * };
- *
- * hostent defined in <netdb.h>
- *
- * struct hostent {
- * char *h_name;
- * char **h_aliases;
- * int h_addrtype;
- * int h_length;
- * char **h_addr_list;
- * };
- *
- * for backward compatibility:
- *
- * #define h_addr h_addr_list[0]
- */
-
-Curl_addrinfo *Curl_he2ai(const struct hostent *he, int port)
-{
- Curl_addrinfo *ai;
- Curl_addrinfo *prevai = NULL;
- Curl_addrinfo *firstai = NULL;
- struct sockaddr_in *addr;
- int i;
- struct in_addr *curr;
-
- if(!he)
- /* no input == no output! */
- return NULL;
-
- for(i=0; (curr = (struct in_addr *)he->h_addr_list[i]) != NULL; i++) {
-
- ai = calloc(1, sizeof(Curl_addrinfo) + sizeof(struct sockaddr_in));
-
- if(!ai)
- break;
-
- if(!firstai)
- /* store the pointer we want to return from this function */
- firstai = ai;
-
- if(prevai)
- /* make the previous entry point to this */
- prevai->ai_next = ai;
-
- ai->ai_family = AF_INET; /* we only support this */
-
- /* we return all names as STREAM, so when using this address for TFTP
- the type must be ignored and conn->socktype be used instead! */
- ai->ai_socktype = SOCK_STREAM;
-
- ai->ai_addrlen = sizeof(struct sockaddr_in);
- /* make the ai_addr point to the address immediately following this struct
- and use that area to store the address */
- ai->ai_addr = (struct sockaddr *) ((char*)ai + sizeof(Curl_addrinfo));
-
- /* leave the rest of the struct filled with zero */
-
- addr = (struct sockaddr_in *)ai->ai_addr; /* storage area for this info */
-
- memcpy((char *)&(addr->sin_addr), curr, sizeof(struct in_addr));
- addr->sin_family = he->h_addrtype;
- addr->sin_port = htons((unsigned short)port);
-
- prevai = ai;
- }
- return firstai;
-}
-
diff --git a/Utilities/cmcurl/hostip6.c b/Utilities/cmcurl/hostip6.c
deleted file mode 100644
index c8bbdb5e9..000000000
--- a/Utilities/cmcurl/hostip6.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "inet_pton.h"
-#include "connect.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for ipv6-enabled builds
- **********************************************************************/
-#ifdef CURLRES_IPV6
-#ifndef CURLRES_ARES
-/*
- * This is a wrapper function for freeing name information in a protocol
- * independent way. This takes care of using the appropriate underlaying
- * function.
- */
-void Curl_freeaddrinfo(Curl_addrinfo *p)
-{
- freeaddrinfo(p);
-}
-
-#ifdef CURLRES_ASYNCH
-/*
- * Curl_addrinfo_copy() is used by the asynch callback to copy a given
- * address. But this is an ipv6 build and then we don't copy the address, we
- * just return the same pointer!
- */
-Curl_addrinfo *Curl_addrinfo_copy(const void *orig, int port)
-{
- (void) port;
- return (Curl_addrinfo*)orig;
-}
-#endif /* CURLRES_ASYNCH */
-#endif /* CURLRES_ARES */
-
-#ifdef CURLDEBUG
-/* These are strictly for memory tracing and are using the same style as the
- * family otherwise present in memdebug.c. I put these ones here since they
- * require a bunch of structs I didn't wanna include in memdebug.c
- */
-int curl_dogetaddrinfo(const char *hostname, const char *service,
- struct addrinfo *hints,
- struct addrinfo **result,
- int line, const char *source)
-{
- int res=(getaddrinfo)(hostname, service, hints, result);
- if(0 == res) {
- /* success */
- if(logfile)
- fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
- source, line, (void *)*result);
- }
- else {
- if(logfile)
- fprintf(logfile, "ADDR %s:%d getaddrinfo() failed\n",
- source, line);
- }
- return res;
-}
-
-/*
- * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
- * (ignoring the fact c-ares doesn't return 'serv').
- */
-#ifdef HAVE_GETNAMEINFO
-int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
- GETNAMEINFO_TYPE_ARG2 salen,
- char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
- char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
- GETNAMEINFO_TYPE_ARG7 flags,
- int line, const char *source)
-{
- int res = (getnameinfo)(sa, salen,
- host, hostlen,
- serv, servlen,
- flags);
- if(0 == res) {
- /* success */
- if(logfile)
- fprintf(logfile, "GETNAME %s:%d getnameinfo()\n",
- source, line);
- }
- else {
- if(logfile)
- fprintf(logfile, "GETNAME %s:%d getnameinfo() failed = %d\n",
- source, line, res);
- }
- return res;
-}
-#endif
-
-void curl_dofreeaddrinfo(struct addrinfo *freethis,
- int line, const char *source)
-{
- (freeaddrinfo)(freethis);
- if(logfile)
- fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
- source, line, (void *)freethis);
-}
-#endif /* CURLDEBUG */
-
-/*
- * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
- * been set and returns TRUE if they are OK.
- */
-bool Curl_ipvalid(struct SessionHandle *data)
-{
- if(data->set.ip_version == CURL_IPRESOLVE_V6) {
- /* see if we have an IPv6 stack */
- curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
- if (s == CURL_SOCKET_BAD)
- /* an ipv6 address was requested and we can't get/use one */
- return FALSE;
- sclose(s);
- }
- return TRUE;
-}
-
-#if !defined(USE_THREADING_GETADDRINFO) && !defined(CURLRES_ARES)
-
-#ifdef DEBUG_ADDRINFO
-static void dump_addrinfo(struct connectdata *conn, const struct addrinfo *ai)
-{
- printf("dump_addrinfo:\n");
- for ( ; ai; ai = ai->ai_next) {
- char buf[INET6_ADDRSTRLEN];
-
- printf(" fam %2d, CNAME %s, ",
- ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
- if (Curl_printable_address(ai, buf, sizeof(buf)))
- printf("%s\n", buf);
- else
- printf("failed; %s\n", Curl_strerror(conn, Curl_sockerrno()));
- }
-}
-#else
-#define dump_addrinfo(x,y)
-#endif
-
-/*
- * Curl_getaddrinfo() when built ipv6-enabled (non-threading and
- * non-ares version).
- *
- * Returns name information about the given hostname and port number. If
- * successful, the 'addrinfo' is returned and the forth argument will point to
- * memory we need to free after use. That memory *MUST* be freed with
- * Curl_freeaddrinfo(), nothing else.
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- struct addrinfo hints, *res;
- int error;
- char sbuf[NI_MAXSERV];
- char *sbufptr = NULL;
- char addrbuf[128];
- curl_socket_t s;
- int pf;
- struct SessionHandle *data = conn->data;
-
- *waitp=0; /* don't wait, we have the response now */
-
- /* see if we have an IPv6 stack */
- s = socket(PF_INET6, SOCK_DGRAM, 0);
- if (s == CURL_SOCKET_BAD) {
- /* Some non-IPv6 stacks have been found to make very slow name resolves
- * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
- * the stack seems to be a non-ipv6 one. */
-
- pf = PF_INET;
- }
- else {
- /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
- * possible checks. And close the socket again.
- */
- sclose(s);
-
- /*
- * Check if a more limited name resolve has been requested.
- */
- switch(data->set.ip_version) {
- case CURL_IPRESOLVE_V4:
- pf = PF_INET;
- break;
- case CURL_IPRESOLVE_V6:
- pf = PF_INET6;
- break;
- default:
- pf = PF_UNSPEC;
- break;
- }
- }
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = pf;
- hints.ai_socktype = conn->socktype;
-
- if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
- (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
- /* the given address is numerical only, prevent a reverse lookup */
- hints.ai_flags = AI_NUMERICHOST;
- }
-#if 0 /* removed nov 8 2005 before 7.15.1 */
- else
- hints.ai_flags = AI_CANONNAME;
-#endif
-
- if(port) {
- snprintf(sbuf, sizeof(sbuf), "%d", port);
- sbufptr=sbuf;
- }
- error = getaddrinfo(hostname, sbufptr, &hints, &res);
- if (error) {
- infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
- return NULL;
- }
-
- dump_addrinfo(conn, res);
-
- return res;
-}
-#endif /* !USE_THREADING_GETADDRINFO && !CURLRES_ARES */
-#endif /* ipv6 */
-
diff --git a/Utilities/cmcurl/hostsyn.c b/Utilities/cmcurl/hostsyn.c
deleted file mode 100644
index 2f816b858..000000000
--- a/Utilities/cmcurl/hostsyn.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/***********************************************************************
- * Only for builds using synchronous name resolves
- **********************************************************************/
-#ifdef CURLRES_SYNCH
-
-/*
- * Curl_wait_for_resolv() for synch-builds. Curl_resolv() can never return
- * wait==TRUE, so this function will never be called. If it still gets called,
- * we return failure at once.
- *
- * We provide this function only to allow multi.c to remain unaware if we are
- * doing asynch resolves or not.
- */
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
- struct Curl_dns_entry **entry)
-{
- (void)conn;
- *entry=NULL;
- return CURLE_COULDNT_RESOLVE_HOST;
-}
-
-/*
- * This function will never be called when synch-built. If it still gets
- * called, we return failure at once.
- *
- * We provide this function only to allow multi.c to remain unaware if we are
- * doing asynch resolves or not.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
- struct Curl_dns_entry **dns)
-{
- (void)conn;
- *dns = NULL;
-
- return CURLE_COULDNT_RESOLVE_HOST;
-}
-
-/*
- * We just return OK, this function is never actually used for synch builds.
- * It is present here to keep #ifdefs out from multi.c
- */
-
-int Curl_resolv_getsock(struct connectdata *conn,
- curl_socket_t *sock,
- int numsocks)
-{
- (void)conn;
- (void)sock;
- (void)numsocks;
-
- return 0; /* no bits since we don't use any socks */
-}
-
-#endif /* truly sync */
diff --git a/Utilities/cmcurl/hostthre.c b/Utilities/cmcurl/hostthre.c
deleted file mode 100644
index 12e31ea34..000000000
--- a/Utilities/cmcurl/hostthre.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <errno.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* required for free() prototypes */
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for the close() proto */
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#include <stdlib.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifdef HAVE_PROCESS_H
-#include <process.h>
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "hostip.h"
-#include "hash.h"
-#include "share.h"
-#include "strerror.h"
-#include "url.h"
-#include "multiif.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "inet_ntop.h"
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#if defined(_MSC_VER) && defined(CURL_NO__BEGINTHREADEX)
-#pragma message ("No _beginthreadex() available in this RTL")
-#endif
-
-/***********************************************************************
- * Only for Windows threaded name resolves builds
- **********************************************************************/
-#ifdef CURLRES_THREADED
-
-/* This function is used to init a threaded resolve */
-static bool init_resolve_thread(struct connectdata *conn,
- const char *hostname, int port,
- const Curl_addrinfo *hints);
-
-#ifdef CURLRES_IPV4
- #define THREAD_FUNC gethostbyname_thread
- #define THREAD_NAME "gethostbyname_thread"
-#else
- #define THREAD_FUNC getaddrinfo_thread
- #define THREAD_NAME "getaddrinfo_thread"
-#endif
-
-#if defined(DEBUG_THREADING_GETHOSTBYNAME) || \
- defined(DEBUG_THREADING_GETADDRINFO)
-/* If this is defined, provide tracing */
-#define TRACE(args) \
- do { trace_it("%u: ", __LINE__); trace_it args; } while (0)
-
-static void trace_it (const char *fmt, ...)
-{
- static int do_trace = -1;
- va_list args;
-
- if (do_trace == -1) {
- const char *env = getenv("CURL_TRACE");
- do_trace = (env && atoi(env) > 0);
- }
- if (!do_trace)
- return;
- va_start (args, fmt);
- vfprintf (stderr, fmt, args);
- fflush (stderr);
- va_end (args);
-}
-#else
-#define TRACE(x)
-#endif
-
-#ifdef DEBUG_THREADING_GETADDRINFO
-static void dump_addrinfo (struct connectdata *conn, const struct addrinfo *ai)
-{
- TRACE(("dump_addrinfo:\n"));
- for ( ; ai; ai = ai->ai_next) {
- char buf [INET6_ADDRSTRLEN];
-
- trace_it(" fam %2d, CNAME %s, ",
- ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
- if (Curl_printable_address(ai, buf, sizeof(buf)))
- trace_it("%s\n", buf);
- else
- trace_it("failed; %s\n", Curl_strerror(conn,WSAGetLastError()));
- }
-}
-#endif
-
-struct thread_data {
- HANDLE thread_hnd;
- unsigned thread_id;
- DWORD thread_status;
- curl_socket_t dummy_sock; /* dummy for Curl_resolv_fdset() */
- HANDLE mutex_waiting; /* marks that we are still waiting for a resolve */
- HANDLE event_resolved; /* marks that the thread obtained the information */
- HANDLE event_thread_started; /* marks that the thread has initialized and
- started */
- HANDLE mutex_terminate; /* serializes access to flag_terminate */
- HANDLE event_terminate; /* flag for thread to terminate instead of calling
- callbacks */
-#ifdef CURLRES_IPV6
- struct addrinfo hints;
-#endif
-};
-
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
- HANDLE mutex_waiting; /* thread_data.mutex_waiting duplicate */
- HANDLE mutex_terminate; /* thread_data.mutex_terminate duplicate */
- HANDLE event_terminate; /* thread_data.event_terminate duplicate */
- char * hostname; /* hostname to resolve, Curl_async.hostname
- duplicate */
-};
-
-/* Destroy resolver thread synchronization data */
-static
-void destroy_thread_sync_data(struct thread_sync_data * tsd)
-{
- if (tsd->hostname) {
- free(tsd->hostname);
- tsd->hostname = NULL;
- }
- if (tsd->event_terminate) {
- CloseHandle(tsd->event_terminate);
- tsd->event_terminate = NULL;
- }
- if (tsd->mutex_terminate) {
- CloseHandle(tsd->mutex_terminate);
- tsd->mutex_terminate = NULL;
- }
- if (tsd->mutex_waiting) {
- CloseHandle(tsd->mutex_waiting);
- tsd->mutex_waiting = NULL;
- }
-}
-
-/* Initialize resolver thread synchronization data */
-static
-BOOL init_thread_sync_data(struct thread_data * td,
- char * hostname,
- struct thread_sync_data * tsd)
-{
- HANDLE curr_proc = GetCurrentProcess();
-
- memset(tsd, 0, sizeof(*tsd));
- if (!DuplicateHandle(curr_proc, td->mutex_waiting,
- curr_proc, &tsd->mutex_waiting, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- /* failed to duplicate the mutex, no point in continuing */
- destroy_thread_sync_data(tsd);
- return FALSE;
- }
- if (!DuplicateHandle(curr_proc, td->mutex_terminate,
- curr_proc, &tsd->mutex_terminate, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- /* failed to duplicate the mutex, no point in continuing */
- destroy_thread_sync_data(tsd);
- return FALSE;
- }
- if (!DuplicateHandle(curr_proc, td->event_terminate,
- curr_proc, &tsd->event_terminate, 0, FALSE,
- DUPLICATE_SAME_ACCESS)) {
- /* failed to duplicate the event, no point in continuing */
- destroy_thread_sync_data(tsd);
- return FALSE;
- }
- /* Copying hostname string because original can be destroyed by parent
- * thread during gethostbyname execution.
- */
- tsd->hostname = strdup(hostname);
- if (!tsd->hostname) {
- /* Memory allocation failed */
- destroy_thread_sync_data(tsd);
- return FALSE;
- }
- return TRUE;
-}
-
-/* acquire resolver thread synchronization */
-static
-BOOL acquire_thread_sync(struct thread_sync_data * tsd)
-{
- /* is the thread initiator still waiting for us ? */
- if (WaitForSingleObject(tsd->mutex_waiting, 0) == WAIT_TIMEOUT) {
- /* yes, it is */
-
- /* Waiting access to event_terminate */
- if (WaitForSingleObject(tsd->mutex_terminate, INFINITE) != WAIT_OBJECT_0) {
- /* Something went wrong - now just ignoring */
- }
- else {
- if (WaitForSingleObject(tsd->event_terminate, 0) != WAIT_TIMEOUT) {
- /* Parent thread signaled us to terminate.
- * This means that all data in conn->async is now destroyed
- * and we cannot use it.
- */
- }
- else {
- return TRUE;
- }
- }
- }
- return FALSE;
-}
-
-/* release resolver thread synchronization */
-static
-void release_thread_sync(struct thread_sync_data * tsd)
-{
- ReleaseMutex(tsd->mutex_terminate);
-}
-
-#if defined(CURLRES_IPV4)
-/*
- * gethostbyname_thread() resolves a name, calls the Curl_addrinfo4_callback
- * and then exits.
- *
- * For builds without ARES/ENABLE_IPV6, create a resolver thread and wait on
- * it.
- */
-static unsigned __stdcall gethostbyname_thread (void *arg)
-{
- struct connectdata *conn = (struct connectdata*) arg;
- struct thread_data *td = (struct thread_data*) conn->async.os_specific;
- struct hostent *he;
- int rc = 0;
-
- /* Duplicate the passed mutex and event handles.
- * This allows us to use it even after the container gets destroyed
- * due to a resolver timeout.
- */
- struct thread_sync_data tsd = { 0,0,0,NULL };
- if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
- /* thread synchronization data initialization failed */
- return (unsigned)-1;
- }
-
- WSASetLastError (conn->async.status = NO_DATA); /* pending status */
-
- /* Signaling that we have initialized all copies of data and handles we
- need */
- SetEvent(td->event_thread_started);
-
- he = gethostbyname (tsd.hostname);
-
- /* is parent thread waiting for us and are we able to access conn members? */
- if (acquire_thread_sync(&tsd)) {
- /* Mark that we have obtained the information, and that we are calling
- * back with it. */
- SetEvent(td->event_resolved);
- if (he) {
- rc = Curl_addrinfo4_callback(conn, CURL_ASYNC_SUCCESS, he);
- }
- else {
- rc = Curl_addrinfo4_callback(conn, (int)WSAGetLastError(), NULL);
- }
- TRACE(("Winsock-error %d, addr %s\n", conn->async.status,
- he ? inet_ntoa(*(struct in_addr*)he->h_addr) : "unknown"));
- release_thread_sync(&tsd);
- }
-
- /* clean up */
- destroy_thread_sync_data(&tsd);
-
- return (rc);
- /* An implicit _endthreadex() here */
-}
-
-#elif defined(CURLRES_IPV6)
-
-/*
- * getaddrinfo_thread() resolves a name, calls Curl_addrinfo6_callback and then
- * exits.
- *
- * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
- * and wait on it.
- */
-static unsigned __stdcall getaddrinfo_thread (void *arg)
-{
- struct connectdata *conn = (struct connectdata*) arg;
- struct thread_data *td = (struct thread_data*) conn->async.os_specific;
- struct addrinfo *res;
- char service [NI_MAXSERV];
- int rc;
- struct addrinfo hints = td->hints;
-
- /* Duplicate the passed mutex handle.
- * This allows us to use it even after the container gets destroyed
- * due to a resolver timeout.
- */
- struct thread_sync_data tsd = { 0,0,0,NULL };
- if (!init_thread_sync_data(td, conn->async.hostname, &tsd)) {
- /* thread synchronization data initialization failed */
- return -1;
- }
-
- itoa(conn->async.port, service, 10);
-
- WSASetLastError(conn->async.status = NO_DATA); /* pending status */
-
- /* Signaling that we have initialized all copies of data and handles we
- need */
- SetEvent(td->event_thread_started);
-
- rc = getaddrinfo(tsd.hostname, service, &hints, &res);
-
- /* is parent thread waiting for us and are we able to access conn members? */
- if (acquire_thread_sync(&tsd)) {
- /* Mark that we have obtained the information, and that we are calling
- back with it. */
- SetEvent(td->event_resolved);
-
- if (rc == 0) {
-#ifdef DEBUG_THREADING_GETADDRINFO
- dump_addrinfo (conn, res);
-#endif
- rc = Curl_addrinfo6_callback(conn, CURL_ASYNC_SUCCESS, res);
- }
- else {
- rc = Curl_addrinfo6_callback(conn, (int)WSAGetLastError(), NULL);
- TRACE(("Winsock-error %d, no address\n", conn->async.status));
- }
- release_thread_sync(&tsd);
- }
-
- /* clean up */
- destroy_thread_sync_data(&tsd);
-
- return (rc);
- /* An implicit _endthreadex() here */
-}
-#endif
-
-/*
- * Curl_destroy_thread_data() cleans up async resolver data and thread handle.
- * Complementary of ares_destroy.
- */
-void Curl_destroy_thread_data (struct Curl_async *async)
-{
- if (async->hostname)
- free(async->hostname);
-
- if (async->os_specific) {
- struct thread_data *td = (struct thread_data*) async->os_specific;
- curl_socket_t sock = td->dummy_sock;
-
- if (td->mutex_terminate && td->event_terminate) {
- /* Signaling resolver thread to terminate */
- if (WaitForSingleObject(td->mutex_terminate, INFINITE) == WAIT_OBJECT_0) {
- SetEvent(td->event_terminate);
- ReleaseMutex(td->mutex_terminate);
- }
- else {
- /* Something went wrong - just ignoring it */
- }
- }
-
- if (td->mutex_terminate)
- CloseHandle(td->mutex_terminate);
- if (td->event_terminate)
- CloseHandle(td->event_terminate);
- if (td->event_thread_started)
- CloseHandle(td->event_thread_started);
-
- if (sock != CURL_SOCKET_BAD)
- sclose(sock);
-
- /* destroy the synchronization objects */
- if (td->mutex_waiting)
- CloseHandle(td->mutex_waiting);
- td->mutex_waiting = NULL;
- if (td->event_resolved)
- CloseHandle(td->event_resolved);
-
- if (td->thread_hnd)
- CloseHandle(td->thread_hnd);
-
- free(async->os_specific);
- }
- async->hostname = NULL;
- async->os_specific = NULL;
-}
-
-/*
- * init_resolve_thread() starts a new thread that performs the actual
- * resolve. This function returns before the resolve is done.
- *
- * Returns FALSE in case of failure, otherwise TRUE.
- */
-static bool init_resolve_thread (struct connectdata *conn,
- const char *hostname, int port,
- const Curl_addrinfo *hints)
-{
- struct thread_data *td = calloc(sizeof(*td), 1);
- HANDLE thread_and_event[2] = {0};
-
- if (!td) {
- SetLastError(ENOMEM);
- return FALSE;
- }
-
- Curl_safefree(conn->async.hostname);
- conn->async.hostname = strdup(hostname);
- if (!conn->async.hostname) {
- free(td);
- SetLastError(ENOMEM);
- return FALSE;
- }
-
- conn->async.port = port;
- conn->async.done = FALSE;
- conn->async.status = 0;
- conn->async.dns = NULL;
- conn->async.os_specific = (void*) td;
- td->dummy_sock = CURL_SOCKET_BAD;
-
- /* Create the mutex used to inform the resolver thread that we're
- * still waiting, and take initial ownership.
- */
- td->mutex_waiting = CreateMutex(NULL, TRUE, NULL);
- if (td->mutex_waiting == NULL) {
- Curl_destroy_thread_data(&conn->async);
- SetLastError(EAGAIN);
- return FALSE;
- }
-
- /* Create the event that the thread uses to inform us that it's
- * done resolving. Do not signal it.
- */
- td->event_resolved = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (td->event_resolved == NULL) {
- Curl_destroy_thread_data(&conn->async);
- SetLastError(EAGAIN);
- return FALSE;
- }
- /* Create the mutex used to serialize access to event_terminated
- * between us and resolver thread.
- */
- td->mutex_terminate = CreateMutex(NULL, FALSE, NULL);
- if (td->mutex_terminate == NULL) {
- Curl_destroy_thread_data(&conn->async);
- SetLastError(EAGAIN);
- return FALSE;
- }
- /* Create the event used to signal thread that it should terminate.
- */
- td->event_terminate = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (td->event_terminate == NULL) {
- Curl_destroy_thread_data(&conn->async);
- SetLastError(EAGAIN);
- return FALSE;
- }
- /* Create the event used by thread to inform it has initialized its own data.
- */
- td->event_thread_started = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (td->event_thread_started == NULL) {
- Curl_destroy_thread_data(&conn->async);
- SetLastError(EAGAIN);
- return FALSE;
- }
-
-#ifdef _WIN32_WCE
- td->thread_hnd = (HANDLE) CreateThread(NULL, 0,
- (LPTHREAD_START_ROUTINE) THREAD_FUNC,
- conn, 0, &td->thread_id);
-#else
- td->thread_hnd = (HANDLE) _beginthreadex(NULL, 0, THREAD_FUNC,
- conn, 0, &td->thread_id);
-#endif
-
-#ifdef CURLRES_IPV6
- curlassert(hints);
- td->hints = *hints;
-#else
- (void) hints;
-#endif
-
- if (!td->thread_hnd) {
-#ifdef _WIN32_WCE
- TRACE(("CreateThread() failed; %s\n", Curl_strerror(conn,GetLastError())));
-#else
- SetLastError(errno);
- TRACE(("_beginthreadex() failed; %s\n", Curl_strerror(conn,errno)));
-#endif
- Curl_destroy_thread_data(&conn->async);
- return FALSE;
- }
- /* Waiting until the thread will initialize its data or it will exit due errors.
- */
- thread_and_event[0] = td->thread_hnd;
- thread_and_event[1] = td->event_thread_started;
- if (WaitForMultipleObjects(sizeof(thread_and_event) /
- sizeof(thread_and_event[0]),
- (const HANDLE*)thread_and_event, FALSE,
- INFINITE) == WAIT_FAILED) {
- /* The resolver thread has been created,
- * most probably it works now - ignoring this "minor" error
- */
- }
- /* This socket is only to keep Curl_resolv_fdset() and select() happy;
- * should never become signalled for read/write since it's unbound but
- * Windows needs atleast 1 socket in select().
- */
- td->dummy_sock = socket(AF_INET, SOCK_DGRAM, 0);
- return TRUE;
-}
-
-
-/*
- * Curl_wait_for_resolv() waits for a resolve to finish. This function should
- * be avoided since using this risk getting the multi interface to "hang".
- *
- * If 'entry' is non-NULL, make it point to the resolved dns entry
- *
- * This is the version for resolves-in-a-thread.
- */
-CURLcode Curl_wait_for_resolv(struct connectdata *conn,
- struct Curl_dns_entry **entry)
-{
- struct thread_data *td = (struct thread_data*) conn->async.os_specific;
- struct SessionHandle *data = conn->data;
- long timeout;
- DWORD status, ticks;
- CURLcode rc;
-
- curlassert (conn && td);
-
- /* now, see if there's a connect timeout or a regular timeout to
- use instead of the default one */
- timeout =
- conn->data->set.connecttimeout ? conn->data->set.connecttimeout :
- conn->data->set.timeout ? conn->data->set.timeout :
- CURL_TIMEOUT_RESOLVE; /* default name resolve timeout */
- ticks = GetTickCount();
-
- /* wait for the thread to resolve the name */
- status = WaitForSingleObject(td->event_resolved, 1000UL*timeout);
-
- /* mark that we are now done waiting */
- ReleaseMutex(td->mutex_waiting);
-
- /* close our handle to the mutex, no point in hanging on to it */
- CloseHandle(td->mutex_waiting);
- td->mutex_waiting = NULL;
-
- /* close the event handle, it's useless now */
- CloseHandle(td->event_resolved);
- td->event_resolved = NULL;
-
- /* has the resolver thread succeeded in resolving our query ? */
- if (status == WAIT_OBJECT_0) {
- /* wait for the thread to exit, it's in the callback sequence */
- if (WaitForSingleObject(td->thread_hnd, 5000) == WAIT_TIMEOUT) {
- TerminateThread(td->thread_hnd, 0);
- conn->async.done = TRUE;
- td->thread_status = (DWORD)-1;
- TRACE(("%s() thread stuck?!, ", THREAD_NAME));
- }
- else {
- /* Thread finished before timeout; propagate Winsock error to this
- * thread. 'conn->async.done = TRUE' is set in
- * Curl_addrinfo4/6_callback().
- */
- WSASetLastError(conn->async.status);
- GetExitCodeThread(td->thread_hnd, &td->thread_status);
- TRACE(("%s() status %lu, thread retval %lu, ",
- THREAD_NAME, status, td->thread_status));
- }
- }
- else {
- conn->async.done = TRUE;
- td->thread_status = (DWORD)-1;
- TRACE(("%s() timeout, ", THREAD_NAME));
- }
-
- TRACE(("elapsed %lu ms\n", GetTickCount()-ticks));
-
- if(entry)
- *entry = conn->async.dns;
-
- rc = CURLE_OK;
-
- if (!conn->async.dns) {
- /* a name was not resolved */
- if (td->thread_status == CURLE_OUT_OF_MEMORY) {
- rc = CURLE_OUT_OF_MEMORY;
- failf(data, "Could not resolve host: %s", curl_easy_strerror(rc));
- }
- else if(conn->async.done) {
- if(conn->bits.httpproxy) {
- failf(data, "Could not resolve proxy: %s; %s",
- conn->proxy.dispname, Curl_strerror(conn, conn->async.status));
- rc = CURLE_COULDNT_RESOLVE_PROXY;
- }
- else {
- failf(data, "Could not resolve host: %s; %s",
- conn->host.name, Curl_strerror(conn, conn->async.status));
- rc = CURLE_COULDNT_RESOLVE_HOST;
- }
- }
- else if (td->thread_status == (DWORD)-1 || conn->async.status == NO_DATA) {
- failf(data, "Resolving host timed out: %s", conn->host.name);
- rc = CURLE_OPERATION_TIMEDOUT;
- }
- else
- rc = CURLE_OPERATION_TIMEDOUT;
- }
-
- Curl_destroy_thread_data(&conn->async);
-
- if(!conn->async.dns)
- conn->bits.close = TRUE;
-
- return (rc);
-}
-
-/*
- * Curl_is_resolved() is called repeatedly to check if a previous name resolve
- * request has completed. It should also make sure to time-out if the
- * operation seems to take too long.
- */
-CURLcode Curl_is_resolved(struct connectdata *conn,
- struct Curl_dns_entry **entry)
-{
- *entry = NULL;
-
- if (conn->async.done) {
- /* we're done */
- Curl_destroy_thread_data(&conn->async);
- if (!conn->async.dns) {
- TRACE(("Curl_is_resolved(): CURLE_COULDNT_RESOLVE_HOST\n"));
- return CURLE_COULDNT_RESOLVE_HOST;
- }
- *entry = conn->async.dns;
- TRACE(("resolved okay, dns %p\n", *entry));
- }
- return CURLE_OK;
-}
-
-int Curl_resolv_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- const struct thread_data *td =
- (const struct thread_data *) conn->async.os_specific;
-
- if (td && td->dummy_sock != CURL_SOCKET_BAD) {
- if(numsocks) {
- /* return one socket waiting for writable, even though this is just
- a dummy */
- socks[0] = td->dummy_sock;
- return GETSOCK_WRITESOCK(0);
- }
- }
- return 0;
-}
-
-#ifdef CURLRES_IPV4
-/*
- * Curl_getaddrinfo() - for Windows threading without ENABLE_IPV6.
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- struct hostent *h = NULL;
- struct SessionHandle *data = conn->data;
- in_addr_t in;
-
- *waitp = 0; /* don't wait, we act synchronously */
-
- in = inet_addr(hostname);
- if (in != CURL_INADDR_NONE)
- /* This is a dotted IP address 123.123.123.123-style */
- return Curl_ip2addr(in, hostname, port);
-
- /* fire up a new resolver thread! */
- if (init_resolve_thread(conn, hostname, port, NULL)) {
- *waitp = TRUE; /* please wait for the response */
- return NULL;
- }
-
- /* fall-back to blocking version */
- infof(data, "init_resolve_thread() failed for %s; %s\n",
- hostname, Curl_strerror(conn,GetLastError()));
-
- h = gethostbyname(hostname);
- if (!h) {
- infof(data, "gethostbyname(2) failed for %s:%d; %s\n",
- hostname, port, Curl_strerror(conn,WSAGetLastError()));
- return NULL;
- }
- return Curl_he2ai(h, port);
-}
-#endif /* CURLRES_IPV4 */
-
-#ifdef CURLRES_IPV6
-/*
- * Curl_getaddrinfo() - for Windows threading IPv6 enabled
- */
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
-{
- struct addrinfo hints, *res;
- int error;
- char sbuf[NI_MAXSERV];
- curl_socket_t s;
- int pf;
- struct SessionHandle *data = conn->data;
-
- *waitp = FALSE; /* default to synch response */
-
- /* see if we have an IPv6 stack */
- s = socket(PF_INET6, SOCK_DGRAM, 0);
- if (s == CURL_SOCKET_BAD) {
- /* Some non-IPv6 stacks have been found to make very slow name resolves
- * when PF_UNSPEC is used, so thus we switch to a mere PF_INET lookup if
- * the stack seems to be a non-ipv6 one. */
-
- pf = PF_INET;
- }
- else {
- /* This seems to be an IPv6-capable stack, use PF_UNSPEC for the widest
- * possible checks. And close the socket again.
- */
- sclose(s);
-
- /*
- * Check if a more limited name resolve has been requested.
- */
- switch(data->set.ip_version) {
- case CURL_IPRESOLVE_V4:
- pf = PF_INET;
- break;
- case CURL_IPRESOLVE_V6:
- pf = PF_INET6;
- break;
- default:
- pf = PF_UNSPEC;
- break;
- }
- }
-
- memset(&hints, 0, sizeof(hints));
- hints.ai_family = pf;
- hints.ai_socktype = conn->socktype;
-#if 0 /* removed nov 8 2005 before 7.15.1 */
- hints.ai_flags = AI_CANONNAME;
-#endif
- itoa(port, sbuf, 10);
-
- /* fire up a new resolver thread! */
- if (init_resolve_thread(conn, hostname, port, &hints)) {
- *waitp = TRUE; /* please wait for the response */
- return NULL;
- }
-
- /* fall-back to blocking version */
- infof(data, "init_resolve_thread() failed for %s; %s\n",
- hostname, Curl_strerror(conn,GetLastError()));
-
- error = getaddrinfo(hostname, sbuf, &hints, &res);
- if (error) {
- infof(data, "getaddrinfo() failed for %s:%d; %s\n",
- hostname, port, Curl_strerror(conn,WSAGetLastError()));
- return NULL;
- }
- return res;
-}
-#endif /* CURLRES_IPV6 */
-#endif /* CURLRES_THREADED */
diff --git a/Utilities/cmcurl/http.c b/Utilities/cmcurl/http.c
deleted file mode 100644
index 5405aace1..000000000
--- a/Utilities/cmcurl/http.c
+++ /dev/null
@@ -1,2422 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_HTTP
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifdef HAVE_TIME_H
-#ifdef TIME_WITH_SYS_TIME
-#include <time.h>
-#endif
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "transfer.h"
-#include "sendf.h"
-#include "easyif.h" /* for Curl_convert_... prototypes */
-#include "formdata.h"
-#include "progress.h"
-#include "base64.h"
-#include "cookie.h"
-#include "strequal.h"
-#include "sslgen.h"
-#include "http_digest.h"
-#include "http_ntlm.h"
-#include "http_negotiate.h"
-#include "url.h"
-#include "share.h"
-#include "hostip.h"
-#include "http.h"
-#include "memory.h"
-#include "select.h"
-#include "parsedate.h" /* for the week day and month names */
-#include "strtoofft.h"
-#include "multiif.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- * checkheaders() checks the linked list of custom HTTP headers for a
- * particular header (prefix).
- *
- * Returns a pointer to the first matching header or NULL if none matched.
- */
-static char *checkheaders(struct SessionHandle *data, const char *thisheader)
-{
- struct curl_slist *head;
- size_t thislen = strlen(thisheader);
-
- for(head = data->set.headers; head; head=head->next) {
- if(strnequal(head->data, thisheader, thislen))
- return head->data;
- }
- return NULL;
-}
-
-/*
- * Curl_output_basic() sets up an Authorization: header (or the proxy version)
- * for HTTP Basic authentication.
- *
- * Returns CURLcode.
- */
-static CURLcode Curl_output_basic(struct connectdata *conn, bool proxy)
-{
- char *authorization;
- struct SessionHandle *data=conn->data;
- char **userp;
- char *user;
- char *pwd;
-
- if(proxy) {
- userp = &conn->allocptr.proxyuserpwd;
- user = conn->proxyuser;
- pwd = conn->proxypasswd;
- }
- else {
- userp = &conn->allocptr.userpwd;
- user = conn->user;
- pwd = conn->passwd;
- }
-
- snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
- if(Curl_base64_encode(data, data->state.buffer,
- strlen(data->state.buffer),
- &authorization) > 0) {
- if(*userp)
- free(*userp);
- *userp = aprintf( "%sAuthorization: Basic %s\r\n",
- proxy?"Proxy-":"",
- authorization);
- free(authorization);
- }
- else
- return CURLE_OUT_OF_MEMORY;
- return CURLE_OK;
-}
-
-/* pickoneauth() selects the most favourable authentication method from the
- * ones available and the ones we want.
- *
- * return TRUE if one was picked
- */
-static bool pickoneauth(struct auth *pick)
-{
- bool picked;
- /* only deal with authentication we want */
- long avail = pick->avail & pick->want;
- picked = TRUE;
-
- /* The order of these checks is highly relevant, as this will be the order
- of preference in case of the existence of multiple accepted types. */
- if(avail & CURLAUTH_GSSNEGOTIATE)
- pick->picked = CURLAUTH_GSSNEGOTIATE;
- else if(avail & CURLAUTH_DIGEST)
- pick->picked = CURLAUTH_DIGEST;
- else if(avail & CURLAUTH_NTLM)
- pick->picked = CURLAUTH_NTLM;
- else if(avail & CURLAUTH_BASIC)
- pick->picked = CURLAUTH_BASIC;
- else {
- pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
- picked = FALSE;
- }
- pick->avail = CURLAUTH_NONE; /* clear it here */
-
- return picked;
-}
-
-/*
- * perhapsrewind()
- *
- * If we are doing POST or PUT {
- * If we have more data to send {
- * If we are doing NTLM {
- * Keep sending since we must not disconnect
- * }
- * else {
- * If there is more than just a little data left to send, close
- * the current connection by force.
- * }
- * }
- * If we have sent any data {
- * If we don't have track of all the data {
- * call app to tell it to rewind
- * }
- * else {
- * rewind internally so that the operation can restart fine
- * }
- * }
- * }
- */
-static CURLcode perhapsrewind(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- struct HTTP *http = data->reqdata.proto.http;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- curl_off_t bytessent;
- curl_off_t expectsend = -1; /* default is unknown */
-
- if(!http)
- /* If this is still NULL, we have not reach very far and we can
- safely skip this rewinding stuff */
- return CURLE_OK;
-
- bytessent = http->writebytecount;
-
- if(conn->bits.authneg)
- /* This is a state where we are known to be negotiating and we don't send
- any data then. */
- expectsend = 0;
- else {
- /* figure out how much data we are expected to send */
- switch(data->set.httpreq) {
- case HTTPREQ_POST:
- if(data->set.postfieldsize != -1)
- expectsend = data->set.postfieldsize;
- break;
- case HTTPREQ_PUT:
- if(data->set.infilesize != -1)
- expectsend = data->set.infilesize;
- break;
- case HTTPREQ_POST_FORM:
- expectsend = http->postsize;
- break;
- default:
- break;
- }
- }
-
- conn->bits.rewindaftersend = FALSE; /* default */
-
- if((expectsend == -1) || (expectsend > bytessent)) {
- /* There is still data left to send */
- if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
- (data->state.authhost.picked == CURLAUTH_NTLM)) {
- if(((expectsend - bytessent) < 2000) ||
- (conn->ntlm.state != NTLMSTATE_NONE)) {
- /* The NTLM-negotiation has started *OR* there is just a little (<2K)
- data left to send, keep on sending. */
-
- /* rewind data when completely done sending! */
- if(!conn->bits.authneg)
- conn->bits.rewindaftersend = TRUE;
-
- return CURLE_OK;
- }
- if(conn->bits.close)
- /* this is already marked to get closed */
- return CURLE_OK;
-
- infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
- " bytes\n", (curl_off_t)(expectsend - bytessent));
- }
-
- /* This is not NTLM or NTLM with many bytes left to send: close
- */
- conn->bits.close = TRUE;
- k->size = 0; /* don't download any more than 0 bytes */
- }
-
- if(bytessent)
- return Curl_readrewind(conn);
-
- return CURLE_OK;
-}
-
-/*
- * Curl_http_auth_act() gets called when a all HTTP headers have been received
- * and it checks what authentication methods that are available and decides
- * which one (if any) to use. It will set 'newurl' if an auth metod was
- * picked.
- */
-
-CURLcode Curl_http_auth_act(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- bool pickhost = FALSE;
- bool pickproxy = FALSE;
- CURLcode code = CURLE_OK;
-
- if(100 == data->reqdata.keep.httpcode)
- /* this is a transient response code, ignore */
- return CURLE_OK;
-
- if(data->state.authproblem)
- return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
-
- if(conn->bits.user_passwd &&
- ((data->reqdata.keep.httpcode == 401) ||
- (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
- pickhost = pickoneauth(&data->state.authhost);
- if(!pickhost)
- data->state.authproblem = TRUE;
- }
- if(conn->bits.proxy_user_passwd &&
- ((data->reqdata.keep.httpcode == 407) ||
- (conn->bits.authneg && data->reqdata.keep.httpcode < 300))) {
- pickproxy = pickoneauth(&data->state.authproxy);
- if(!pickproxy)
- data->state.authproblem = TRUE;
- }
-
- if(pickhost || pickproxy) {
- data->reqdata.newurl = strdup(data->change.url); /* clone URL */
-
- if((data->set.httpreq != HTTPREQ_GET) &&
- (data->set.httpreq != HTTPREQ_HEAD) &&
- !conn->bits.rewindaftersend) {
- code = perhapsrewind(conn);
- if(code)
- return code;
- }
- }
-
- else if((data->reqdata.keep.httpcode < 300) &&
- (!data->state.authhost.done) &&
- conn->bits.authneg) {
- /* no (known) authentication available,
- authentication is not "done" yet and
- no authentication seems to be required and
- we didn't try HEAD or GET */
- if((data->set.httpreq != HTTPREQ_GET) &&
- (data->set.httpreq != HTTPREQ_HEAD)) {
- data->reqdata.newurl = strdup(data->change.url); /* clone URL */
- data->state.authhost.done = TRUE;
- }
- }
- if (Curl_http_should_fail(conn)) {
- failf (data, "The requested URL returned error: %d",
- data->reqdata.keep.httpcode);
- code = CURLE_HTTP_RETURNED_ERROR;
- }
-
- return code;
-}
-
-/**
- * Curl_http_output_auth() setups the authentication headers for the
- * host/proxy and the correct authentication
- * method. conn->data->state.authdone is set to TRUE when authentication is
- * done.
- *
- * @param conn all information about the current connection
- * @param request pointer to the request keyword
- * @param path pointer to the requested path
- * @param proxytunnel boolean if this is the request setting up a "proxy
- * tunnel"
- *
- * @returns CURLcode
- */
-static CURLcode
-Curl_http_output_auth(struct connectdata *conn,
- char *request,
- char *path,
- bool proxytunnel) /* TRUE if this is the request setting
- up the proxy tunnel */
-{
- CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
- char *auth=NULL;
- struct auth *authhost;
- struct auth *authproxy;
-
- curlassert(data);
-
- authhost = &data->state.authhost;
- authproxy = &data->state.authproxy;
-
- if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
- conn->bits.user_passwd)
- /* continue please */ ;
- else {
- authhost->done = TRUE;
- authproxy->done = TRUE;
- return CURLE_OK; /* no authentication with no user or password */
- }
-
- if(authhost->want && !authhost->picked)
- /* The app has selected one or more methods, but none has been picked
- so far by a server round-trip. Then we set the picked one to the
- want one, and if this is one single bit it'll be used instantly. */
- authhost->picked = authhost->want;
-
- if(authproxy->want && !authproxy->picked)
- /* The app has selected one or more methods, but none has been picked so
- far by a proxy round-trip. Then we set the picked one to the want one,
- and if this is one single bit it'll be used instantly. */
- authproxy->picked = authproxy->want;
-
- /* Send proxy authentication header if needed */
- if (conn->bits.httpproxy &&
- (conn->bits.tunnel_proxy == proxytunnel)) {
-#ifdef USE_NTLM
- if(authproxy->picked == CURLAUTH_NTLM) {
- auth=(char *)"NTLM";
- result = Curl_output_ntlm(conn, TRUE);
- if(result)
- return result;
- }
- else
-#endif
- if(authproxy->picked == CURLAUTH_BASIC) {
- /* Basic */
- if(conn->bits.proxy_user_passwd &&
- !checkheaders(data, "Proxy-authorization:")) {
- auth=(char *)"Basic";
- result = Curl_output_basic(conn, TRUE);
- if(result)
- return result;
- }
- /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth
- functions work that way */
- authproxy->done = TRUE;
- }
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- else if(authproxy->picked == CURLAUTH_DIGEST) {
- auth=(char *)"Digest";
- result = Curl_output_digest(conn,
- TRUE, /* proxy */
- (unsigned char *)request,
- (unsigned char *)path);
- if(result)
- return result;
- }
-#endif
- if(auth) {
- infof(data, "Proxy auth using %s with user '%s'\n",
- auth, conn->proxyuser?conn->proxyuser:"");
- authproxy->multi = (bool)(!authproxy->done);
- }
- else
- authproxy->multi = FALSE;
- }
- else
- /* we have no proxy so let's pretend we're done authenticating
- with it */
- authproxy->done = TRUE;
-
- /* To prevent the user+password to get sent to other than the original
- host due to a location-follow, we do some weirdo checks here */
- if(!data->state.this_is_a_follow ||
- conn->bits.netrc ||
- !data->state.first_host ||
- curl_strequal(data->state.first_host, conn->host.name) ||
- data->set.http_disable_hostname_check_before_authentication) {
-
- /* Send web authentication header if needed */
- {
- auth = NULL;
-#ifdef HAVE_GSSAPI
- if((authhost->picked == CURLAUTH_GSSNEGOTIATE) &&
- data->state.negotiate.context &&
- !GSS_ERROR(data->state.negotiate.status)) {
- auth=(char *)"GSS-Negotiate";
- result = Curl_output_negotiate(conn);
- if (result)
- return result;
- authhost->done = TRUE;
- }
- else
-#endif
-#ifdef USE_NTLM
- if(authhost->picked == CURLAUTH_NTLM) {
- auth=(char *)"NTLM";
- result = Curl_output_ntlm(conn, FALSE);
- if(result)
- return result;
- }
- else
-#endif
- {
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- if(authhost->picked == CURLAUTH_DIGEST) {
- auth=(char *)"Digest";
- result = Curl_output_digest(conn,
- FALSE, /* not a proxy */
- (unsigned char *)request,
- (unsigned char *)path);
- if(result)
- return result;
- } else
-#endif
- if(authhost->picked == CURLAUTH_BASIC) {
- if(conn->bits.user_passwd &&
- !checkheaders(data, "Authorization:")) {
- auth=(char *)"Basic";
- result = Curl_output_basic(conn, FALSE);
- if(result)
- return result;
- }
- /* basic is always ready */
- authhost->done = TRUE;
- }
- }
- if(auth) {
- infof(data, "Server auth using %s with user '%s'\n",
- auth, conn->user);
-
- authhost->multi = (bool)(!authhost->done);
- }
- else
- authhost->multi = FALSE;
- }
- }
- else
- authhost->done = TRUE;
-
- return result;
-}
-
-
-/*
- * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
- * headers. They are dealt with both in the transfer.c main loop and in the
- * proxy CONNECT loop.
- */
-
-CURLcode Curl_http_input_auth(struct connectdata *conn,
- int httpcode,
- char *header) /* the first non-space */
-{
- /*
- * This resource requires authentication
- */
- struct SessionHandle *data = conn->data;
-
- long *availp;
- char *start;
- struct auth *authp;
-
- if (httpcode == 407) {
- start = header+strlen("Proxy-authenticate:");
- availp = &data->info.proxyauthavail;
- authp = &data->state.authproxy;
- }
- else {
- start = header+strlen("WWW-Authenticate:");
- availp = &data->info.httpauthavail;
- authp = &data->state.authhost;
- }
-
- /* pass all white spaces */
- while(*start && ISSPACE(*start))
- start++;
-
- /*
- * Here we check if we want the specific single authentication (using ==) and
- * if we do, we initiate usage of it.
- *
- * If the provided authentication is wanted as one out of several accepted
- * types (using &), we OR this authentication type to the authavail
- * variable.
- */
-
-#ifdef HAVE_GSSAPI
- if (checkprefix("GSS-Negotiate", start) ||
- checkprefix("Negotiate", start)) {
- *availp |= CURLAUTH_GSSNEGOTIATE;
- authp->avail |= CURLAUTH_GSSNEGOTIATE;
- if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
- /* if exactly this is wanted, go */
- int neg = Curl_input_negotiate(conn, start);
- if (neg == 0) {
- data->reqdata.newurl = strdup(data->change.url);
- data->state.authproblem = (data->reqdata.newurl == NULL);
- }
- else {
- infof(data, "Authentication problem. Ignoring this.\n");
- data->state.authproblem = TRUE;
- }
- }
- }
- else
-#endif
-#ifdef USE_NTLM
- /* NTLM support requires the SSL crypto libs */
- if(checkprefix("NTLM", start)) {
- *availp |= CURLAUTH_NTLM;
- authp->avail |= CURLAUTH_NTLM;
- if(authp->picked == CURLAUTH_NTLM) {
- /* NTLM authentication is picked and activated */
- CURLntlm ntlm =
- Curl_input_ntlm(conn, (bool)(httpcode == 407), start);
-
- if(CURLNTLM_BAD != ntlm)
- data->state.authproblem = FALSE;
- else {
- infof(data, "Authentication problem. Ignoring this.\n");
- data->state.authproblem = TRUE;
- }
- }
- }
- else
-#endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
- if(checkprefix("Digest", start)) {
- if((authp->avail & CURLAUTH_DIGEST) != 0) {
- infof(data, "Ignoring duplicate digest auth header.\n");
- }
- else {
- CURLdigest dig;
- *availp |= CURLAUTH_DIGEST;
- authp->avail |= CURLAUTH_DIGEST;
-
- /* We call this function on input Digest headers even if Digest
- * authentication isn't activated yet, as we need to store the
- * incoming data from this header in case we are gonna use Digest. */
- dig = Curl_input_digest(conn, (bool)(httpcode == 407), start);
-
- if(CURLDIGEST_FINE != dig) {
- infof(data, "Authentication problem. Ignoring this.\n");
- data->state.authproblem = TRUE;
- }
- }
- }
- else
-#endif
- if(checkprefix("Basic", start)) {
- *availp |= CURLAUTH_BASIC;
- authp->avail |= CURLAUTH_BASIC;
- if(authp->picked == CURLAUTH_BASIC) {
- /* We asked for Basic authentication but got a 40X back
- anyway, which basicly means our name+password isn't
- valid. */
- authp->avail = CURLAUTH_NONE;
- infof(data, "Authentication problem. Ignoring this.\n");
- data->state.authproblem = TRUE;
- }
- }
-
- return CURLE_OK;
-}
-
-/**
- * Curl_http_should_fail() determines whether an HTTP response has gotten us
- * into an error state or not.
- *
- * @param conn all information about the current connection
- *
- * @retval 0 communications should continue
- *
- * @retval 1 communications should not continue
- */
-int Curl_http_should_fail(struct connectdata *conn)
-{
- struct SessionHandle *data;
- struct Curl_transfer_keeper *k;
-
- curlassert(conn);
- data = conn->data;
- curlassert(data);
-
- /*
- ** For readability
- */
- k = &data->reqdata.keep;
-
- /*
- ** If we haven't been asked to fail on error,
- ** don't fail.
- */
- if (!data->set.http_fail_on_error)
- return 0;
-
- /*
- ** Any code < 400 is never terminal.
- */
- if (k->httpcode < 400)
- return 0;
-
- if (data->reqdata.resume_from &&
- (data->set.httpreq==HTTPREQ_GET) &&
- (k->httpcode == 416)) {
- /* "Requested Range Not Satisfiable", just proceed and
- pretend this is no error */
- return 0;
- }
-
- /*
- ** Any code >= 400 that's not 401 or 407 is always
- ** a terminal error
- */
- if ((k->httpcode != 401) &&
- (k->httpcode != 407))
- return 1;
-
- /*
- ** All we have left to deal with is 401 and 407
- */
- curlassert((k->httpcode == 401) || (k->httpcode == 407));
-
- /*
- ** Examine the current authentication state to see if this
- ** is an error. The idea is for this function to get
- ** called after processing all the headers in a response
- ** message. So, if we've been to asked to authenticate a
- ** particular stage, and we've done it, we're OK. But, if
- ** we're already completely authenticated, it's not OK to
- ** get another 401 or 407.
- **
- ** It is possible for authentication to go stale such that
- ** the client needs to reauthenticate. Once that info is
- ** available, use it here.
- */
-#if 0 /* set to 1 when debugging this functionality */
- infof(data,"%s: authstage = %d\n",__FUNCTION__,data->state.authstage);
- infof(data,"%s: authwant = 0x%08x\n",__FUNCTION__,data->state.authwant);
- infof(data,"%s: authavail = 0x%08x\n",__FUNCTION__,data->state.authavail);
- infof(data,"%s: httpcode = %d\n",__FUNCTION__,k->httpcode);
- infof(data,"%s: authdone = %d\n",__FUNCTION__,data->state.authdone);
- infof(data,"%s: newurl = %s\n",__FUNCTION__,data->reqdata.newurl ? data->reqdata.newurl : "(null)");
- infof(data,"%s: authproblem = %d\n",__FUNCTION__,data->state.authproblem);
-#endif
-
- /*
- ** Either we're not authenticating, or we're supposed to
- ** be authenticating something else. This is an error.
- */
- if((k->httpcode == 401) && !conn->bits.user_passwd)
- return TRUE;
- if((k->httpcode == 407) && !conn->bits.proxy_user_passwd)
- return TRUE;
-
- return data->state.authproblem;
-}
-
-/*
- * readmoredata() is a "fread() emulation" to provide POST and/or request
- * data. It is used when a huge POST is to be made and the entire chunk wasn't
- * sent in the first send(). This function will then be called from the
- * transfer.c loop when more data is to be sent to the peer.
- *
- * Returns the amount of bytes it filled the buffer with.
- */
-static size_t readmoredata(char *buffer,
- size_t size,
- size_t nitems,
- void *userp)
-{
- struct connectdata *conn = (struct connectdata *)userp;
- struct HTTP *http = conn->data->reqdata.proto.http;
- size_t fullsize = size * nitems;
-
- if(0 == http->postsize)
- /* nothing to return */
- return 0;
-
- /* make sure that a HTTP request is never sent away chunked! */
- conn->bits.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST);
-
- if(http->postsize <= (curl_off_t)fullsize) {
- memcpy(buffer, http->postdata, (size_t)http->postsize);
- fullsize = (size_t)http->postsize;
-
- if(http->backup.postsize) {
- /* move backup data into focus and continue on that */
- http->postdata = http->backup.postdata;
- http->postsize = http->backup.postsize;
- conn->fread = http->backup.fread;
- conn->fread_in = http->backup.fread_in;
-
- http->sending++; /* move one step up */
-
- http->backup.postsize=0;
- }
- else
- http->postsize = 0;
-
- return fullsize;
- }
-
- memcpy(buffer, http->postdata, fullsize);
- http->postdata += fullsize;
- http->postsize -= fullsize;
-
- return fullsize;
-}
-
-/* ------------------------------------------------------------------------- */
-/*
- * The add_buffer series of functions are used to build one large memory chunk
- * from repeated function invokes. Used so that the entire HTTP request can
- * be sent in one go.
- */
-
-struct send_buffer {
- char *buffer;
- size_t size_max;
- size_t size_used;
-};
-typedef struct send_buffer send_buffer;
-
-static CURLcode add_custom_headers(struct connectdata *conn,
- send_buffer *req_buffer);
-static CURLcode
- add_buffer(send_buffer *in, const void *inptr, size_t size);
-
-/*
- * add_buffer_init() sets up and returns a fine buffer struct
- */
-static
-send_buffer *add_buffer_init(void)
-{
- send_buffer *blonk;
- blonk=(send_buffer *)malloc(sizeof(send_buffer));
- if(blonk) {
- memset(blonk, 0, sizeof(send_buffer));
- return blonk;
- }
- return NULL; /* failed, go home */
-}
-
-/*
- * add_buffer_send() sends a header buffer and frees all associated memory.
- * Body data may be appended to the header data if desired.
- *
- * Returns CURLcode
- */
-static
-CURLcode add_buffer_send(send_buffer *in,
- struct connectdata *conn,
- long *bytes_written, /* add the number of sent
- bytes to this counter */
- size_t included_body_bytes, /* how much of the buffer
- contains body data (for log tracing) */
- int socketindex)
-
-{
- ssize_t amount;
- CURLcode res;
- char *ptr;
- size_t size;
- struct HTTP *http = conn->data->reqdata.proto.http;
- size_t sendsize;
- curl_socket_t sockfd;
-
- curlassert(socketindex <= SECONDARYSOCKET);
-
- sockfd = conn->sock[socketindex];
-
- /* The looping below is required since we use non-blocking sockets, but due
- to the circumstances we will just loop and try again and again etc */
-
- ptr = in->buffer;
- size = in->size_used;
-
-#ifdef CURL_DOES_CONVERSIONS
- if(size - included_body_bytes > 0) {
- res = Curl_convert_to_network(conn->data, ptr, size - included_body_bytes);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(res != CURLE_OK) {
- /* conversion failed, free memory and return to the caller */
- if(in->buffer)
- free(in->buffer);
- free(in);
- return res;
- }
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(conn->protocol & PROT_HTTPS) {
- /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
- when we speak HTTPS, as if only a fraction of it is sent now, this data
- needs to fit into the normal read-callback buffer later on and that
- buffer is using this size.
- */
-
- sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
-
- /* OpenSSL is very picky and we must send the SAME buffer pointer to the
- library when we attempt to re-send this buffer. Sending the same data
- is not enough, we must use the exact same address. For this reason, we
- must copy the data to the uploadbuffer first, since that is the buffer
- we will be using if this send is retried later.
- */
- memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
- ptr = conn->data->state.uploadbuffer;
- }
- else
- sendsize = size;
-
- res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
-
- if(CURLE_OK == res) {
-
- if(conn->data->set.verbose) {
- /* this data _may_ contain binary stuff */
- Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr,
- (size_t)(amount-included_body_bytes), conn);
- if (included_body_bytes)
- Curl_debug(conn->data, CURLINFO_DATA_OUT,
- ptr+amount-included_body_bytes,
- (size_t)included_body_bytes, conn);
- }
-
- *bytes_written += amount;
-
- if(http) {
- if((size_t)amount != size) {
- /* The whole request could not be sent in one system call. We must
- queue it up and send it later when we get the chance. We must not
- loop here and wait until it might work again. */
-
- size -= amount;
-
- ptr = in->buffer + amount;
-
- /* backup the currently set pointers */
- http->backup.fread = conn->fread;
- http->backup.fread_in = conn->fread_in;
- http->backup.postdata = http->postdata;
- http->backup.postsize = http->postsize;
-
- /* set the new pointers for the request-sending */
- conn->fread = (curl_read_callback)readmoredata;
- conn->fread_in = (void *)conn;
- http->postdata = ptr;
- http->postsize = (curl_off_t)size;
-
- http->send_buffer = in;
- http->sending = HTTPSEND_REQUEST;
-
- return CURLE_OK;
- }
- http->sending = HTTPSEND_BODY;
- /* the full buffer was sent, clean up and return */
- }
- else {
- if((size_t)amount != size)
- /* We have no continue-send mechanism now, fail. This can only happen
- when this function is used from the CONNECT sending function. We
- currently (stupidly) assume that the whole request is always sent
- away in the first single chunk.
-
- This needs FIXing.
- */
- return CURLE_SEND_ERROR;
- else
- conn->writechannel_inuse = FALSE;
- }
- }
- if(in->buffer)
- free(in->buffer);
- free(in);
-
- return res;
-}
-
-
-/*
- * add_bufferf() add the formatted input to the buffer.
- */
-static
-CURLcode add_bufferf(send_buffer *in, const char *fmt, ...)
-{
- char *s;
- va_list ap;
- va_start(ap, fmt);
- s = vaprintf(fmt, ap); /* this allocs a new string to append */
- va_end(ap);
-
- if(s) {
- CURLcode result = add_buffer(in, s, strlen(s));
- free(s);
- if(CURLE_OK == result)
- return CURLE_OK;
- }
- /* If we failed, we cleanup the whole buffer and return error */
- if(in->buffer)
- free(in->buffer);
- free(in);
- return CURLE_OUT_OF_MEMORY;
-}
-
-/*
- * add_buffer() appends a memory chunk to the existing buffer
- */
-static
-CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size)
-{
- char *new_rb;
- size_t new_size;
-
- if(!in->buffer ||
- ((in->size_used + size) > (in->size_max - 1))) {
- new_size = (in->size_used+size)*2;
- if(in->buffer)
- /* we have a buffer, enlarge the existing one */
- new_rb = (char *)realloc(in->buffer, new_size);
- else
- /* create a new buffer */
- new_rb = (char *)malloc(new_size);
-
- if(!new_rb)
- return CURLE_OUT_OF_MEMORY;
-
- in->buffer = new_rb;
- in->size_max = new_size;
- }
- memcpy(&in->buffer[in->size_used], inptr, size);
-
- in->size_used += size;
-
- return CURLE_OK;
-}
-
-/* end of the add_buffer functions */
-/* ------------------------------------------------------------------------- */
-
-/*
- * Curl_compareheader()
- *
- * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
- * Pass headers WITH the colon.
- */
-bool
-Curl_compareheader(char *headerline, /* line to check */
- const char *header, /* header keyword _with_ colon */
- const char *content) /* content string to find */
-{
- /* RFC2616, section 4.2 says: "Each header field consists of a name followed
- * by a colon (":") and the field value. Field names are case-insensitive.
- * The field value MAY be preceded by any amount of LWS, though a single SP
- * is preferred." */
-
- size_t hlen = strlen(header);
- size_t clen;
- size_t len;
- char *start;
- char *end;
-
- if(!strnequal(headerline, header, hlen))
- return FALSE; /* doesn't start with header */
-
- /* pass the header */
- start = &headerline[hlen];
-
- /* pass all white spaces */
- while(*start && ISSPACE(*start))
- start++;
-
- /* find the end of the header line */
- end = strchr(start, '\r'); /* lines end with CRLF */
- if(!end) {
- /* in case there's a non-standard compliant line here */
- end = strchr(start, '\n');
-
- if(!end)
- /* hm, there's no line ending here, use the zero byte! */
- end = strchr(start, '\0');
- }
-
- len = end-start; /* length of the content part of the input line */
- clen = strlen(content); /* length of the word to find */
-
- /* find the content string in the rest of the line */
- for(;len>=clen;len--, start++) {
- if(strnequal(start, content, clen))
- return TRUE; /* match! */
- }
-
- return FALSE; /* no match */
-}
-
-/*
- * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
- * function will issue the necessary commands to get a seamless tunnel through
- * this proxy. After that, the socket can be used just as a normal socket.
- *
- * This badly needs to be rewritten. CONNECT should be sent and dealt with
- * like any ordinary HTTP request, and not specially crafted like this. This
- * function only remains here like this for now since the rewrite is a bit too
- * much work to do at the moment.
- *
- * This function is BLOCKING which is nasty for all multi interface using apps.
- */
-
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
- int sockindex,
- char *hostname,
- int remote_port)
-{
- int subversion=0;
- struct SessionHandle *data=conn->data;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- CURLcode result;
- int res;
- size_t nread; /* total size read */
- int perline; /* count bytes per line */
- int keepon=TRUE;
- ssize_t gotbytes;
- char *ptr;
- long timeout =
- data->set.timeout?data->set.timeout:3600; /* in seconds */
- char *line_start;
- char *host_port;
- curl_socket_t tunnelsocket = conn->sock[sockindex];
- send_buffer *req_buffer;
- curl_off_t cl=0;
- bool closeConnection = FALSE;
-
-#define SELECT_OK 0
-#define SELECT_ERROR 1
-#define SELECT_TIMEOUT 2
- int error = SELECT_OK;
-
- infof(data, "Establish HTTP proxy tunnel to %s:%d\n", hostname, remote_port);
- conn->bits.proxy_connect_closed = FALSE;
-
- do {
- if(data->reqdata.newurl) {
- /* This only happens if we've looped here due to authentication reasons,
- and we don't really use the newly cloned URL here then. Just free()
- it. */
- free(data->reqdata.newurl);
- data->reqdata.newurl = NULL;
- }
-
- /* initialize a dynamic send-buffer */
- req_buffer = add_buffer_init();
-
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
-
- host_port = aprintf("%s:%d", hostname, remote_port);
- if(!host_port)
- return CURLE_OUT_OF_MEMORY;
-
- /* Setup the proxy-authorization header, if any */
- result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE);
-
- if(CURLE_OK == result) {
- char *host=(char *)"";
- const char *proxyconn="";
- const char *useragent="";
-
- if(!checkheaders(data, "Host:")) {
- host = aprintf("Host: %s\r\n", host_port);
- if(!host)
- result = CURLE_OUT_OF_MEMORY;
- }
- if(!checkheaders(data, "Proxy-Connection:"))
- proxyconn = "Proxy-Connection: Keep-Alive\r\n";
-
- if(!checkheaders(data, "User-Agent:") && data->set.useragent)
- useragent = conn->allocptr.uagent;
-
- if(CURLE_OK == result) {
- /* Send the connect request to the proxy */
- /* BLOCKING */
- result =
- add_bufferf(req_buffer,
- "CONNECT %s:%d HTTP/1.0\r\n"
- "%s" /* Host: */
- "%s" /* Proxy-Authorization */
- "%s" /* User-Agent */
- "%s", /* Proxy-Connection */
- hostname, remote_port,
- host,
- conn->allocptr.proxyuserpwd?
- conn->allocptr.proxyuserpwd:"",
- useragent,
- proxyconn);
-
- if(CURLE_OK == result)
- result = add_custom_headers(conn, req_buffer);
-
- if(host && *host)
- free(host);
-
- if(CURLE_OK == result)
- /* CRLF terminate the request */
- result = add_bufferf(req_buffer, "\r\n");
-
- if(CURLE_OK == result)
- /* Now send off the request */
- result = add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, sockindex);
- }
- if(result)
- failf(data, "Failed sending CONNECT to proxy");
- }
- free(host_port);
- if(result)
- return result;
-
- ptr=data->state.buffer;
- line_start = ptr;
-
- nread=0;
- perline=0;
- keepon=TRUE;
-
- while((nread<BUFSIZE) && (keepon && !error)) {
-
- /* if timeout is requested, find out how much remaining time we have */
- long check = timeout - /* timeout time */
- Curl_tvdiff(Curl_tvnow(), conn->now)/1000; /* spent time */
- if(check <=0 ) {
- failf(data, "Proxy CONNECT aborted due to timeout");
- error = SELECT_TIMEOUT; /* already too little time */
- break;
- }
-
- /* timeout each second and check the timeout */
- switch (Curl_select(tunnelsocket, CURL_SOCKET_BAD, 1000)) {
- case -1: /* select() error, stop reading */
- error = SELECT_ERROR;
- failf(data, "Proxy CONNECT aborted due to select() error");
- break;
- case 0: /* timeout */
- break;
- default:
- res = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread, &gotbytes);
- if(res< 0)
- /* EWOULDBLOCK */
- continue; /* go loop yourself */
- else if(res)
- keepon = FALSE;
- else if(gotbytes <= 0) {
- keepon = FALSE;
- error = SELECT_ERROR;
- failf(data, "Proxy CONNECT aborted");
- }
- else {
- /*
- * We got a whole chunk of data, which can be anything from one byte
- * to a set of lines and possibly just a piece of the last line.
- */
- int i;
-
- nread += gotbytes;
-
- if(keepon > TRUE) {
- /* This means we are currently ignoring a response-body, so we
- simply count down our counter and make sure to break out of the
- loop when we're done! */
- cl -= gotbytes;
- if(cl<=0) {
- keepon = FALSE;
- break;
- }
- }
- else
- for(i = 0; i < gotbytes; ptr++, i++) {
- perline++; /* amount of bytes in this line so far */
- if(*ptr=='\n') {
- char letter;
- int writetype;
-
- /* output debug if that is requested */
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN,
- line_start, (size_t)perline, conn);
-
- /* send the header to the callback */
- writetype = CLIENTWRITE_HEADER;
- if(data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
-
- result = Curl_client_write(conn, writetype, line_start, perline);
- if(result)
- return result;
-
- /* Newlines are CRLF, so the CR is ignored as the line isn't
- really terminated until the LF comes. Treat a following CR
- as end-of-headers as well.*/
-
- if(('\r' == line_start[0]) ||
- ('\n' == line_start[0])) {
- /* end of response-headers from the proxy */
- if(cl && (407 == k->httpcode) && !data->state.authproblem) {
- /* If we get a 407 response code with content length when we
- * have no auth problem, we must ignore the whole
- * response-body */
- keepon = 2;
- infof(data, "Ignore %" FORMAT_OFF_T
- " bytes of response-body\n", cl);
- cl -= (gotbytes - i);/* remove the remaining chunk of what
- we already read */
- if(cl<=0)
- /* if the whole thing was already read, we are done! */
- keepon=FALSE;
- }
- else
- keepon = FALSE;
- break; /* breaks out of for-loop, not switch() */
- }
-
- /* keep a backup of the position we are about to blank */
- letter = line_start[perline];
- line_start[perline]=0; /* zero terminate the buffer */
- if((checkprefix("WWW-Authenticate:", line_start) &&
- (401 == k->httpcode)) ||
- (checkprefix("Proxy-authenticate:", line_start) &&
- (407 == k->httpcode))) {
- result = Curl_http_input_auth(conn, k->httpcode, line_start);
- if(result)
- return result;
- }
- else if(checkprefix("Content-Length:", line_start)) {
- cl = curlx_strtoofft(line_start + strlen("Content-Length:"),
- NULL, 10);
- }
- else if(Curl_compareheader(line_start,
- "Connection:", "close"))
- closeConnection = TRUE;
- else if(2 == sscanf(line_start, "HTTP/1.%d %d",
- &subversion,
- &k->httpcode)) {
- /* store the HTTP code from the proxy */
- data->info.httpproxycode = k->httpcode;
- }
- /* put back the letter we blanked out before */
- line_start[perline]= letter;
-
- perline=0; /* line starts over here */
- line_start = ptr+1; /* this skips the zero byte we wrote */
- }
- }
- }
- break;
- } /* switch */
- } /* while there's buffer left and loop is requested */
-
- if(error)
- return CURLE_RECV_ERROR;
-
- if(data->info.httpproxycode != 200)
- /* Deal with the possibly already received authenticate
- headers. 'newurl' is set to a new URL if we must loop. */
- Curl_http_auth_act(conn);
-
- if (closeConnection && data->reqdata.newurl) {
- /* Connection closed by server. Don't use it anymore */
- sclose(conn->sock[sockindex]);
- conn->sock[sockindex] = CURL_SOCKET_BAD;
- break;
- }
- } while(data->reqdata.newurl);
-
- if(200 != k->httpcode) {
- failf(data, "Received HTTP code %d from proxy after CONNECT",
- k->httpcode);
-
- if (closeConnection && data->reqdata.newurl)
- conn->bits.proxy_connect_closed = TRUE;
-
- return CURLE_RECV_ERROR;
- }
-
- /* If a proxy-authorization header was used for the proxy, then we should
- make sure that it isn't accidentally used for the document request
- after we've connected. So let's free and clear it here. */
- Curl_safefree(conn->allocptr.proxyuserpwd);
- conn->allocptr.proxyuserpwd = NULL;
-
- data->state.authproxy.done = TRUE;
-
- infof (data, "Proxy replied OK to CONNECT request\n");
- return CURLE_OK;
-}
-
-/*
- * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
- * the generic Curl_connect().
- */
-CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
-{
- struct SessionHandle *data;
- CURLcode result;
-
- data=conn->data;
-
- /* If we are not using a proxy and we want a secure connection, perform SSL
- * initialization & connection now. If using a proxy with https, then we
- * must tell the proxy to CONNECT to the host we want to talk to. Only
- * after the connect has occurred, can we start talking SSL
- */
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
-
- /* either SSL over proxy, or explicitly asked for */
- result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
- conn->host.name,
- conn->remote_port);
- if(CURLE_OK != result)
- return result;
- }
-
- if(!data->state.this_is_a_follow) {
- /* this is not a followed location, get the original host name */
- if (data->state.first_host)
- /* Free to avoid leaking memory on multiple requests*/
- free(data->state.first_host);
-
- data->state.first_host = strdup(conn->host.name);
- if(!data->state.first_host)
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(conn->protocol & PROT_HTTPS) {
- /* perform SSL initialization */
- if(data->state.used_interface == Curl_if_multi) {
- result = Curl_https_connecting(conn, done);
- if(result)
- return result;
- }
- else {
- /* BLOCKING */
- result = Curl_ssl_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
- *done = TRUE;
- }
- }
- else {
- *done = TRUE;
- }
-
- return CURLE_OK;
-}
-
-CURLcode Curl_https_connecting(struct connectdata *conn, bool *done)
-{
- CURLcode result;
- curlassert(conn->protocol & PROT_HTTPS);
-
- /* perform SSL initialization for this socket */
- result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
- if(result)
- return result;
-
- return CURLE_OK;
-}
-
-#ifdef USE_SSLEAY
-/* This function is OpenSSL-specific. It should be made to query the generic
- SSL layer instead. */
-int Curl_https_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if (conn->protocol & PROT_HTTPS) {
- struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
-
- if(!numsocks)
- return GETSOCK_BLANK;
-
- if (connssl->connecting_state == ssl_connect_2_writing) {
- /* write mode */
- socks[0] = conn->sock[FIRSTSOCKET];
- return GETSOCK_WRITESOCK(0);
- }
- else if (connssl->connecting_state == ssl_connect_2_reading) {
- /* read mode */
- socks[0] = conn->sock[FIRSTSOCKET];
- return GETSOCK_READSOCK(0);
- }
- }
- return CURLE_OK;
-}
-#else
-#ifdef USE_GNUTLS
-int Curl_https_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- (void)conn;
- (void)socks;
- (void)numsocks;
- return GETSOCK_BLANK;
-}
-#endif
-#endif
-
-/*
- * Curl_http_done() gets called from Curl_done() after a single HTTP request
- * has been performed.
- */
-
-CURLcode Curl_http_done(struct connectdata *conn,
- CURLcode status, bool premature)
-{
- struct SessionHandle *data = conn->data;
- struct HTTP *http =data->reqdata.proto.http;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- (void)premature; /* not used */
-
- /* set the proper values (possibly modified on POST) */
- conn->fread = data->set.fread; /* restore */
- conn->fread_in = data->set.in; /* restore */
-
- if (http == NULL)
- return CURLE_OK;
-
- if(http->send_buffer) {
- send_buffer *buff = http->send_buffer;
-
- free(buff->buffer);
- free(buff);
- http->send_buffer = NULL; /* clear the pointer */
- }
-
- if(HTTPREQ_POST_FORM == data->set.httpreq) {
- k->bytecount = http->readbytecount + http->writebytecount;
-
- Curl_formclean(&http->sendit); /* Now free that whole lot */
- if(http->form.fp) {
- /* a file being uploaded was left opened, close it! */
- fclose(http->form.fp);
- http->form.fp = NULL;
- }
- }
- else if(HTTPREQ_PUT == data->set.httpreq)
- k->bytecount = http->readbytecount + http->writebytecount;
-
- if (status != CURLE_OK)
- return (status);
-
- if(!conn->bits.retry &&
- ((http->readbytecount +
- conn->headerbytecount -
- conn->deductheadercount)) <= 0) {
- /* If this connection isn't simply closed to be retried, AND nothing was
- read from the HTTP server (that counts), this can't be right so we
- return an error here */
- failf(data, "Empty reply from server");
- return CURLE_GOT_NOTHING;
- }
-
- return CURLE_OK;
-}
-
-/* check and possibly add an Expect: header */
-static CURLcode expect100(struct SessionHandle *data,
- send_buffer *req_buffer)
-{
- CURLcode result = CURLE_OK;
- data->state.expect100header = FALSE; /* default to false unless it is set
- to TRUE below */
- if((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
- !checkheaders(data, "Expect:")) {
- /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
- 100-continue to the headers which actually speeds up post
- operations (as there is one packet coming back from the web
- server) */
- result = add_bufferf(req_buffer,
- "Expect: 100-continue\r\n");
- if(result == CURLE_OK)
- data->state.expect100header = TRUE;
- }
- return result;
-}
-
-static CURLcode add_custom_headers(struct connectdata *conn,
- send_buffer *req_buffer)
-{
- CURLcode result = CURLE_OK;
- char *ptr;
- struct curl_slist *headers=conn->data->set.headers;
-
- while(headers) {
- ptr = strchr(headers->data, ':');
- if(ptr) {
- /* we require a colon for this to be a true header */
-
- ptr++; /* pass the colon */
- while(*ptr && ISSPACE(*ptr))
- ptr++;
-
- if(*ptr) {
- /* only send this if the contents was non-blank */
-
- if(conn->allocptr.host &&
- /* a Host: header was sent already, don't pass on any custom Host:
- header as that will produce *two* in the same request! */
- curl_strnequal("Host:", headers->data, 5))
- ;
- else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
- /* this header (extended by formdata.c) is sent later */
- curl_strnequal("Content-Type:", headers->data,
- strlen("Content-Type:")))
- ;
- else {
- result = add_bufferf(req_buffer, "%s\r\n", headers->data);
- if(result)
- return result;
- }
- }
- }
- headers = headers->next;
- }
- return result;
-}
-
-/*
- * Curl_http() gets called from the generic Curl_do() function when a HTTP
- * request is to be performed. This creates and sends a properly constructed
- * HTTP request.
- */
-CURLcode Curl_http(struct connectdata *conn, bool *done)
-{
- struct SessionHandle *data=conn->data;
- char *buf = data->state.buffer; /* this is a short cut to the buffer */
- CURLcode result=CURLE_OK;
- struct HTTP *http;
- char *ppath = data->reqdata.path;
- char *host = conn->host.name;
- const char *te = ""; /* transfer-encoding */
- char *ptr;
- char *request;
- Curl_HttpReq httpreq = data->set.httpreq;
- char *addcookies = NULL;
- curl_off_t included_body = 0;
-
- /* Always consider the DO phase done after this function call, even if there
- may be parts of the request that is not yet sent, since we can deal with
- the rest of the request in the PERFORM phase. */
- *done = TRUE;
-
- if(!data->reqdata.proto.http) {
- /* Only allocate this struct if we don't already have it! */
-
- http = (struct HTTP *)malloc(sizeof(struct HTTP));
- if(!http)
- return CURLE_OUT_OF_MEMORY;
- memset(http, 0, sizeof(struct HTTP));
- data->reqdata.proto.http = http;
- }
- else
- http = data->reqdata.proto.http;
-
- /* We default to persistent connections */
- conn->bits.close = FALSE;
-
- if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
- data->set.upload) {
- httpreq = HTTPREQ_PUT;
- }
-
- /* Now set the 'request' pointer to the proper request string */
- if(data->set.customrequest)
- request = data->set.customrequest;
- else {
- if(conn->bits.no_body)
- request = (char *)"HEAD";
- else {
- curlassert((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
- switch(httpreq) {
- case HTTPREQ_POST:
- case HTTPREQ_POST_FORM:
- request = (char *)"POST";
- break;
- case HTTPREQ_PUT:
- request = (char *)"PUT";
- break;
- default: /* this should never happen */
- case HTTPREQ_GET:
- request = (char *)"GET";
- break;
- case HTTPREQ_HEAD:
- request = (char *)"HEAD";
- break;
- }
- }
- }
-
- /* The User-Agent string might have been allocated in url.c already, because
- it might have been used in the proxy connect, but if we have got a header
- with the user-agent string specified, we erase the previously made string
- here. */
- if(checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
- free(conn->allocptr.uagent);
- conn->allocptr.uagent=NULL;
- }
-
- /* setup the authentication headers */
- result = Curl_http_output_auth(conn, request, ppath, FALSE);
- if(result)
- return result;
-
- if((data->state.authhost.multi || data->state.authproxy.multi) &&
- (httpreq != HTTPREQ_GET) &&
- (httpreq != HTTPREQ_HEAD)) {
- /* Auth is required and we are not authenticated yet. Make a PUT or POST
- with content-length zero as a "probe". */
- conn->bits.authneg = TRUE;
- }
- else
- conn->bits.authneg = FALSE;
-
- Curl_safefree(conn->allocptr.ref);
- if(data->change.referer && !checkheaders(data, "Referer:"))
- conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
- else
- conn->allocptr.ref = NULL;
-
- if(data->set.cookie && !checkheaders(data, "Cookie:"))
- addcookies = data->set.cookie;
-
- if(!checkheaders(data, "Accept-Encoding:") &&
- data->set.encoding) {
- Curl_safefree(conn->allocptr.accept_encoding);
- conn->allocptr.accept_encoding =
- aprintf("Accept-Encoding: %s\r\n", data->set.encoding);
- if(!conn->allocptr.accept_encoding)
- return CURLE_OUT_OF_MEMORY;
- }
-
- ptr = checkheaders(data, "Transfer-Encoding:");
- if(ptr) {
- /* Some kind of TE is requested, check if 'chunked' is chosen */
- conn->bits.upload_chunky =
- Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
- }
- else {
- if (httpreq == HTTPREQ_GET)
- conn->bits.upload_chunky = FALSE;
- if(conn->bits.upload_chunky)
- te = "Transfer-Encoding: chunked\r\n";
- }
-
- Curl_safefree(conn->allocptr.host);
-
- ptr = checkheaders(data, "Host:");
- if(ptr && (!data->state.this_is_a_follow ||
- curl_strequal(data->state.first_host, conn->host.name))) {
-#if !defined(CURL_DISABLE_COOKIES)
- /* If we have a given custom Host: header, we extract the host name in
- order to possibly use it for cookie reasons later on. We only allow the
- custom Host: header if this is NOT a redirect, as setting Host: in the
- redirected request is being out on thin ice. Except if the host name
- is the same as the first one! */
- char *start = ptr+strlen("Host:");
- while(*start && ISSPACE(*start ))
- start++;
- ptr = start; /* start host-scanning here */
-
- /* scan through the string to find the end (space or colon) */
- while(*ptr && !ISSPACE(*ptr) && !(':'==*ptr))
- ptr++;
-
- if(ptr != start) {
- size_t len=ptr-start;
- Curl_safefree(conn->allocptr.cookiehost);
- conn->allocptr.cookiehost = malloc(len+1);
- if(!conn->allocptr.cookiehost)
- return CURLE_OUT_OF_MEMORY;
- memcpy(conn->allocptr.cookiehost, start, len);
- conn->allocptr.cookiehost[len]=0;
- }
-#endif
-
- conn->allocptr.host = NULL;
- }
- else {
- /* When building Host: headers, we must put the host name within
- [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
-
- if(((conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTPS)) ||
- (!(conn->protocol&PROT_HTTPS) && (conn->remote_port == PORT_HTTP)) )
- /* If (HTTPS on port 443) OR (non-HTTPS on port 80) then don't include
- the port number in the host string */
- conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
- conn->bits.ipv6_ip?"[":"",
- host,
- conn->bits.ipv6_ip?"]":"");
- else
- conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
- conn->bits.ipv6_ip?"[":"",
- host,
- conn->bits.ipv6_ip?"]":"",
- conn->remote_port);
-
- if(!conn->allocptr.host)
- /* without Host: we can't make a nice request */
- return CURLE_OUT_OF_MEMORY;
- }
-
- if (conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
- /* Using a proxy but does not tunnel through it */
-
- /* The path sent to the proxy is in fact the entire URL. But if the remote
- host is a IDN-name, we must make sure that the request we produce only
- uses the encoded host name! */
- if(conn->host.dispname != conn->host.name) {
- char *url = data->change.url;
- ptr = strstr(url, conn->host.dispname);
- if(ptr) {
- /* This is where the display name starts in the URL, now replace this
- part with the encoded name. TODO: This method of replacing the host
- name is rather crude as I believe there's a slight risk that the
- user has entered a user name or password that contain the host name
- string. */
- size_t currlen = strlen(conn->host.dispname);
- size_t newlen = strlen(conn->host.name);
- size_t urllen = strlen(url);
-
- char *newurl;
-
- newurl = malloc(urllen + newlen - currlen + 1);
- if(newurl) {
- /* copy the part before the host name */
- memcpy(newurl, url, ptr - url);
- /* append the new host name instead of the old */
- memcpy(newurl + (ptr - url), conn->host.name, newlen);
- /* append the piece after the host name */
- memcpy(newurl + newlen + (ptr - url),
- ptr + currlen, /* copy the trailing zero byte too */
- urllen - (ptr-url) - currlen + 1);
- if(data->change.url_alloc)
- free(data->change.url);
- data->change.url = newurl;
- data->change.url_alloc = TRUE;
- }
- else
- return CURLE_OUT_OF_MEMORY;
- }
- }
- ppath = data->change.url;
- }
- if(HTTPREQ_POST_FORM == httpreq) {
- /* we must build the whole darned post sequence first, so that we have
- a size of the whole shebang before we start to send it */
- result = Curl_getFormData(&http->sendit, data->set.httppost,
- checkheaders(data, "Content-Type:"),
- &http->postsize);
- if(CURLE_OK != result) {
- /* Curl_getFormData() doesn't use failf() */
- failf(data, "failed creating formpost data");
- return result;
- }
- }
-
-
- http->p_pragma =
- (!checkheaders(data, "Pragma:") &&
- (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )?
- "Pragma: no-cache\r\n":NULL;
-
- if(!checkheaders(data, "Accept:"))
- http->p_accept = "Accept: */*\r\n";
-
- if(( (HTTPREQ_POST == httpreq) ||
- (HTTPREQ_POST_FORM == httpreq) ||
- (HTTPREQ_PUT == httpreq) ) &&
- data->reqdata.resume_from) {
- /**********************************************************************
- * Resuming upload in HTTP means that we PUT or POST and that we have
- * got a resume_from value set. The resume value has already created
- * a Range: header that will be passed along. We need to "fast forward"
- * the file the given number of bytes and decrease the assume upload
- * file size before we continue this venture in the dark lands of HTTP.
- *********************************************************************/
-
- if(data->reqdata.resume_from < 0 ) {
- /*
- * This is meant to get the size of the present remote-file by itself.
- * We don't support this now. Bail out!
- */
- data->reqdata.resume_from = 0;
- }
-
- if(data->reqdata.resume_from) {
- /* do we still game? */
- curl_off_t passed=0;
-
- /* Now, let's read off the proper amount of bytes from the
- input. If we knew it was a proper file we could've just
- fseek()ed but we only have a stream here */
- do {
- size_t readthisamountnow = (size_t)(data->reqdata.resume_from - passed);
- size_t actuallyread;
-
- if(readthisamountnow > BUFSIZE)
- readthisamountnow = BUFSIZE;
-
- actuallyread =
- data->set.fread(data->state.buffer, 1, (size_t)readthisamountnow,
- data->set.in);
-
- passed += actuallyread;
- if(actuallyread != readthisamountnow) {
- failf(data, "Could only read %" FORMAT_OFF_T
- " bytes from the input",
- passed);
- return CURLE_READ_ERROR;
- }
- } while(passed != data->reqdata.resume_from); /* loop until done */
-
- /* now, decrease the size of the read */
- if(data->set.infilesize>0) {
- data->set.infilesize -= data->reqdata.resume_from;
-
- if(data->set.infilesize <= 0) {
- failf(data, "File already completely uploaded");
- return CURLE_PARTIAL_FILE;
- }
- }
- /* we've passed, proceed as normal */
- }
- }
- if(data->reqdata.use_range) {
- /*
- * A range is selected. We use different headers whether we're downloading
- * or uploading and we always let customized headers override our internal
- * ones if any such are specified.
- */
- if((httpreq == HTTPREQ_GET) &&
- !checkheaders(data, "Range:")) {
- /* if a line like this was already allocated, free the previous one */
- if(conn->allocptr.rangeline)
- free(conn->allocptr.rangeline);
- conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->reqdata.range);
- }
- else if((httpreq != HTTPREQ_GET) &&
- !checkheaders(data, "Content-Range:")) {
-
- if(data->reqdata.resume_from) {
- /* This is because "resume" was selected */
- curl_off_t total_expected_size=
- data->reqdata.resume_from + data->set.infilesize;
- conn->allocptr.rangeline =
- aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
- "/%" FORMAT_OFF_T "\r\n",
- data->reqdata.range, total_expected_size-1,
- total_expected_size);
- }
- else {
- /* Range was selected and then we just pass the incoming range and
- append total size */
- conn->allocptr.rangeline =
- aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
- data->reqdata.range, data->set.infilesize);
- }
- }
- }
-
- {
- /* Use 1.1 unless the use specificly asked for 1.0 */
- const char *httpstring=
- data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1";
-
- send_buffer *req_buffer;
- curl_off_t postsize; /* off_t type to be able to hold a large file size */
-
- /* initialize a dynamic send-buffer */
- req_buffer = add_buffer_init();
-
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
-
- /* add the main request stuff */
- result =
- add_bufferf(req_buffer,
- "%s " /* GET/HEAD/POST/PUT */
- "%s HTTP/%s\r\n" /* path + HTTP version */
- "%s" /* proxyuserpwd */
- "%s" /* userpwd */
- "%s" /* range */
- "%s" /* user agent */
- "%s" /* host */
- "%s" /* pragma */
- "%s" /* accept */
- "%s" /* accept-encoding */
- "%s" /* referer */
- "%s" /* Proxy-Connection */
- "%s",/* transfer-encoding */
-
- request,
- ppath,
- httpstring,
- conn->allocptr.proxyuserpwd?
- conn->allocptr.proxyuserpwd:"",
- conn->allocptr.userpwd?conn->allocptr.userpwd:"",
- (data->reqdata.use_range && conn->allocptr.rangeline)?
- conn->allocptr.rangeline:"",
- (data->set.useragent && *data->set.useragent && conn->allocptr.uagent)?
- conn->allocptr.uagent:"",
- (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */
- http->p_pragma?http->p_pragma:"",
- http->p_accept?http->p_accept:"",
- (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)?
- conn->allocptr.accept_encoding:"",
- (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: <data> */,
- (conn->bits.httpproxy &&
- !conn->bits.tunnel_proxy &&
- !checkheaders(data, "Proxy-Connection:"))?
- "Proxy-Connection: Keep-Alive\r\n":"",
- te
- );
-
- if(result)
- return result;
-
-#if !defined(CURL_DISABLE_COOKIES)
- if(data->cookies || addcookies) {
- struct Cookie *co=NULL; /* no cookies from start */
- int count=0;
-
- if(data->cookies) {
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- co = Curl_cookie_getlist(data->cookies,
- conn->allocptr.cookiehost?
- conn->allocptr.cookiehost:host, data->reqdata.path,
- (bool)(conn->protocol&PROT_HTTPS?TRUE:FALSE));
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- }
- if(co) {
- struct Cookie *store=co;
- /* now loop through all cookies that matched */
- while(co) {
- if(co->value) {
- if(0 == count) {
- result = add_bufferf(req_buffer, "Cookie: ");
- if(result)
- break;
- }
- result = add_bufferf(req_buffer,
- "%s%s=%s", count?"; ":"",
- co->name, co->value);
- if(result)
- break;
- count++;
- }
- co = co->next; /* next cookie please */
- }
- Curl_cookie_freelist(store); /* free the cookie list */
- }
- if(addcookies && (CURLE_OK == result)) {
- if(!count)
- result = add_bufferf(req_buffer, "Cookie: ");
- if(CURLE_OK == result) {
- result = add_bufferf(req_buffer, "%s%s",
- count?"; ":"",
- addcookies);
- count++;
- }
- }
- if(count && (CURLE_OK == result))
- result = add_buffer(req_buffer, "\r\n", 2);
-
- if(result)
- return result;
- }
-#endif
-
- if(data->set.timecondition) {
- struct tm *tm;
-
- /* Phil Karn (Fri, 13 Apr 2001) pointed out that the If-Modified-Since
- * header family should have their times set in GMT as RFC2616 defines:
- * "All HTTP date/time stamps MUST be represented in Greenwich Mean Time
- * (GMT), without exception. For the purposes of HTTP, GMT is exactly
- * equal to UTC (Coordinated Universal Time)." (see page 20 of RFC2616).
- */
-
-#ifdef HAVE_GMTIME_R
- /* thread-safe version */
- struct tm keeptime;
- tm = (struct tm *)gmtime_r(&data->set.timevalue, &keeptime);
-#else
- tm = gmtime(&data->set.timevalue);
-#endif
-
- /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
- snprintf(buf, BUFSIZE-1,
- "%s, %02d %s %4d %02d:%02d:%02d GMT",
- Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
- tm->tm_mday,
- Curl_month[tm->tm_mon],
- tm->tm_year + 1900,
- tm->tm_hour,
- tm->tm_min,
- tm->tm_sec);
-
- switch(data->set.timecondition) {
- case CURL_TIMECOND_IFMODSINCE:
- default:
- result = add_bufferf(req_buffer,
- "If-Modified-Since: %s\r\n", buf);
- break;
- case CURL_TIMECOND_IFUNMODSINCE:
- result = add_bufferf(req_buffer,
- "If-Unmodified-Since: %s\r\n", buf);
- break;
- case CURL_TIMECOND_LASTMOD:
- result = add_bufferf(req_buffer,
- "Last-Modified: %s\r\n", buf);
- break;
- }
- if(result)
- return result;
- }
-
- result = add_custom_headers(conn, req_buffer);
- if(result)
- return result;
-
- http->postdata = NULL; /* nothing to post at this point */
- Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
-
- /* If 'authdone' is FALSE, we must not set the write socket index to the
- Curl_transfer() call below, as we're not ready to actually upload any
- data yet. */
-
- switch(httpreq) {
-
- case HTTPREQ_POST_FORM:
- if(!http->sendit || conn->bits.authneg) {
- /* nothing to post! */
- result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
- if(result)
- return result;
-
- result = add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
- if(result)
- failf(data, "Failed sending POST request");
- else
- /* setup variables for the upcoming transfer */
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount,
- -1, NULL);
- break;
- }
-
- if(Curl_FormInit(&http->form, http->sendit)) {
- failf(data, "Internal HTTP POST error!");
- return CURLE_HTTP_POST_ERROR;
- }
-
- /* set the read function to read from the generated form data */
- conn->fread = (curl_read_callback)Curl_FormReader;
- conn->fread_in = &http->form;
-
- http->sending = HTTPSEND_BODY;
-
- if(!conn->bits.upload_chunky) {
- /* only add Content-Length if not uploading chunked */
- result = add_bufferf(req_buffer,
- "Content-Length: %" FORMAT_OFF_T "\r\n",
- http->postsize);
- if(result)
- return result;
- }
-
- result = expect100(data, req_buffer);
- if(result)
- return result;
-
- {
-
- /* Get Content-Type: line from Curl_formpostheader.
- */
- char *contentType;
- size_t linelength=0;
- contentType = Curl_formpostheader((void *)&http->form,
- &linelength);
- if(!contentType) {
- failf(data, "Could not get Content-Type header line!");
- return CURLE_HTTP_POST_ERROR;
- }
-
- result = add_buffer(req_buffer, contentType, linelength);
- if(result)
- return result;
- }
-
- /* make the request end in a true CRLF */
- result = add_buffer(req_buffer, "\r\n", 2);
- if(result)
- return result;
-
- /* set upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, http->postsize);
-
- /* fire away the whole request to the server */
- result = add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
- if(result)
- failf(data, "Failed sending POST request");
- else
- /* setup variables for the upcoming transfer */
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount,
- FIRSTSOCKET,
- &http->writebytecount);
-
- if(result) {
- Curl_formclean(&http->sendit); /* free that whole lot */
- return result;
- }
-#ifdef CURL_DOES_CONVERSIONS
-/* time to convert the form data... */
- result = Curl_formconvert(data, http->sendit);
- if(result) {
- Curl_formclean(&http->sendit); /* free that whole lot */
- return result;
- }
-#endif /* CURL_DOES_CONVERSIONS */
- break;
-
- case HTTPREQ_PUT: /* Let's PUT the data to the server! */
-
- if(conn->bits.authneg)
- postsize = 0;
- else
- postsize = data->set.infilesize;
-
- if((postsize != -1) && !conn->bits.upload_chunky) {
- /* only add Content-Length if not uploading chunked */
- result = add_bufferf(req_buffer,
- "Content-Length: %" FORMAT_OFF_T "\r\n",
- postsize );
- if(result)
- return result;
- }
-
- result = expect100(data, req_buffer);
- if(result)
- return result;
-
- result = add_buffer(req_buffer, "\r\n", 2); /* end of headers */
- if(result)
- return result;
-
- /* set the upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, postsize);
-
- /* this sends the buffer and frees all the buffer resources */
- result = add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
- if(result)
- failf(data, "Failed sending PUT request");
- else
- /* prepare for transfer */
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount,
- postsize?FIRSTSOCKET:-1,
- postsize?&http->writebytecount:NULL);
- if(result)
- return result;
- break;
-
- case HTTPREQ_POST:
- /* this is the simple POST, using x-www-form-urlencoded style */
-
- if(conn->bits.authneg)
- postsize = 0;
- else
- /* figure out the size of the postfields */
- postsize = (data->set.postfieldsize != -1)?
- data->set.postfieldsize:
- (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
-
- if(!conn->bits.upload_chunky) {
- /* We only set Content-Length and allow a custom Content-Length if
- we don't upload data chunked, as RFC2616 forbids us to set both
- kinds of headers (Transfer-Encoding: chunked and Content-Length) */
-
- if(!checkheaders(data, "Content-Length:")) {
- /* we allow replacing this header, although it isn't very wise to
- actually set your own */
- result = add_bufferf(req_buffer,
- "Content-Length: %" FORMAT_OFF_T"\r\n",
- postsize);
- if(result)
- return result;
- }
- }
-
- if(!checkheaders(data, "Content-Type:")) {
- result = add_bufferf(req_buffer,
- "Content-Type: application/x-www-form-urlencoded\r\n");
- if(result)
- return result;
- }
-
- if(data->set.postfields) {
-
- /* for really small posts we don't use Expect: headers at all, and for
- the somewhat bigger ones we allow the app to disable it */
- if(postsize > TINY_INITIAL_POST_SIZE) {
- result = expect100(data, req_buffer);
- if(result)
- return result;
- }
- else
- data->state.expect100header = FALSE;
-
- if(!data->state.expect100header &&
- (postsize < MAX_INITIAL_POST_SIZE)) {
- /* if we don't use expect:-100 AND
- postsize is less than MAX_INITIAL_POST_SIZE
-
- then append the post data to the HTTP request header. This limit
- is no magic limit but only set to prevent really huge POSTs to
- get the data duplicated with malloc() and family. */
-
- result = add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
- if(result)
- return result;
-
- if(!conn->bits.upload_chunky) {
- /* We're not sending it 'chunked', append it to the request
- already now to reduce the number if send() calls */
- result = add_buffer(req_buffer, data->set.postfields,
- (size_t)postsize);
- included_body = postsize;
- }
- else {
- /* Append the POST data chunky-style */
- result = add_bufferf(req_buffer, "%x\r\n", (int)postsize);
- if(CURLE_OK == result)
- result = add_buffer(req_buffer, data->set.postfields,
- (size_t)postsize);
- if(CURLE_OK == result)
- result = add_buffer(req_buffer,
- "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7);
- /* CR LF 0 CR LF CR LF */
- included_body = postsize + 7;
- }
- if(result)
- return result;
- }
- else {
- /* A huge POST coming up, do data separate from the request */
- http->postsize = postsize;
- http->postdata = data->set.postfields;
-
- http->sending = HTTPSEND_BODY;
-
- conn->fread = (curl_read_callback)readmoredata;
- conn->fread_in = (void *)conn;
-
- /* set the upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, http->postsize);
-
- add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
- }
- }
- else {
- add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
-
- if(data->set.postfieldsize) {
- /* set the upload size to the progress meter */
- Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
-
- /* set the pointer to mark that we will send the post body using
- the read callback */
- http->postdata = (char *)&http->postdata;
- }
- }
- /* issue the request */
- result = add_buffer_send(req_buffer, conn, &data->info.request_size,
- (size_t)included_body, FIRSTSOCKET);
-
- if(result)
- failf(data, "Failed sending HTTP POST request");
- else
- result =
- Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount,
- http->postdata?FIRSTSOCKET:-1,
- http->postdata?&http->writebytecount:NULL);
- break;
-
- default:
- add_buffer(req_buffer, "\r\n", 2);
-
- /* issue the request */
- result = add_buffer_send(req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
-
- if(result)
- failf(data, "Failed sending HTTP request");
- else
- /* HTTP GET/HEAD download: */
- result = Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
- &http->readbytecount,
- http->postdata?FIRSTSOCKET:-1,
- http->postdata?&http->writebytecount:NULL);
- }
- if(result)
- return result;
- }
-
- return CURLE_OK;
-}
-#endif
diff --git a/Utilities/cmcurl/http.h b/Utilities/cmcurl/http.h
deleted file mode 100644
index 0f4b58f72..000000000
--- a/Utilities/cmcurl/http.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef __HTTP_H
-#define __HTTP_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_HTTP
-bool Curl_compareheader(char *headerline, /* line to check */
- const char *header, /* header keyword _with_ colon */
- const char *content); /* content string to find */
-
-/* ftp can use this as well */
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
- int tunnelsocket,
- char *hostname, int remote_port);
-
-/* protocol-specific functions set up to be called by the main engine */
-CURLcode Curl_http(struct connectdata *conn, bool *done);
-CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
-CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
-CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
-int Curl_https_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-
-/* The following functions are defined in http_chunks.c */
-void Curl_httpchunk_init(struct connectdata *conn);
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
- ssize_t length, ssize_t *wrote);
-
-/* These functions are in http.c */
-void Curl_http_auth_stage(struct SessionHandle *data, int stage);
-CURLcode Curl_http_input_auth(struct connectdata *conn,
- int httpcode, char *header);
-CURLcode Curl_http_auth_act(struct connectdata *conn);
-
-int Curl_http_should_fail(struct connectdata *conn);
-
-/* If only the PICKNONE bit is set, there has been a round-trip and we
- selected to use no auth at all. Ie, we actively select no auth, as opposed
- to not having one selected. The other CURLAUTH_* defines are present in the
- public curl/curl.h header. */
-#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
-
-/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
- data get included in the initial data chunk sent to the server. If the
- data is larger than this, it will automatically get split up in multiple
- system calls.
-
- This value used to be fairly big (100K), but we must take into account that
- if the server rejects the POST due for authentication reasons, this data
- will always be uncondtionally sent and thus it may not be larger than can
- always be afforded to send twice.
-
- It must not be greater than 64K to work on VMS.
-*/
-#ifndef MAX_INITIAL_POST_SIZE
-#define MAX_INITIAL_POST_SIZE (64*1024)
-#endif
-
-#ifndef TINY_INITIAL_POST_SIZE
-#define TINY_INITIAL_POST_SIZE 1024
-#endif
-
-#endif
-#endif
diff --git a/Utilities/cmcurl/http_chunks.c b/Utilities/cmcurl/http_chunks.c
deleted file mode 100644
index 1b03a5569..000000000
--- a/Utilities/cmcurl/http_chunks.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-#ifndef CURL_DISABLE_HTTP
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "urldata.h" /* it includes http_chunks.h */
-#include "sendf.h" /* for the client write stuff */
-
-#include "content_encoding.h"
-#include "http.h"
-#include "memory.h"
-#include "easyif.h" /* for Curl_convert_to_network prototype */
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- * Chunk format (simplified):
- *
- * <HEX SIZE>[ chunk extension ] CRLF
- * <DATA> CRLF
- *
- * Highlights from RFC2616 section 3.6 say:
-
- The chunked encoding modifies the body of a message in order to
- transfer it as a series of chunks, each with its own size indicator,
- followed by an OPTIONAL trailer containing entity-header fields. This
- allows dynamically produced content to be transferred along with the
- information necessary for the recipient to verify that it has
- received the full message.
-
- Chunked-Body = *chunk
- last-chunk
- trailer
- CRLF
-
- chunk = chunk-size [ chunk-extension ] CRLF
- chunk-data CRLF
- chunk-size = 1*HEX
- last-chunk = 1*("0") [ chunk-extension ] CRLF
-
- chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
- chunk-ext-name = token
- chunk-ext-val = token | quoted-string
- chunk-data = chunk-size(OCTET)
- trailer = *(entity-header CRLF)
-
- The chunk-size field is a string of hex digits indicating the size of
- the chunk. The chunked encoding is ended by any chunk whose size is
- zero, followed by the trailer, which is terminated by an empty line.
-
- */
-
-
-void Curl_httpchunk_init(struct connectdata *conn)
-{
- struct Curl_chunker *chunk = &conn->data->reqdata.proto.http->chunk;
- chunk->hexindex=0; /* start at 0 */
- chunk->dataleft=0; /* no data left yet! */
- chunk->state = CHUNK_HEX; /* we get hex first! */
-}
-
-/*
- * chunk_read() returns a OK for normal operations, or a positive return code
- * for errors. STOP means this sequence of chunks is complete. The 'wrote'
- * argument is set to tell the caller how many bytes we actually passed to the
- * client (for byte-counting and whatever).
- *
- * The states and the state-machine is further explained in the header file.
- *
- * This function always uses ASCII hex values to accommodate non-ASCII hosts.
- * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
- */
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
- char *datap,
- ssize_t datalen,
- ssize_t *wrotep)
-{
- CURLcode result=CURLE_OK;
- struct SessionHandle *data = conn->data;
- struct Curl_chunker *ch = &data->reqdata.proto.http->chunk;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- size_t piece;
- size_t length = (size_t)datalen;
- size_t *wrote = (size_t *)wrotep;
-
- *wrote = 0; /* nothing's written yet */
-
- while(length) {
- switch(ch->state) {
- case CHUNK_HEX:
- /* Check for an ASCII hex digit.
- We avoid the use of isxdigit to accommodate non-ASCII hosts. */
- if((*datap >= 0x30 && *datap <= 0x39) /* 0-9 */
- || (*datap >= 0x41 && *datap <= 0x46) /* A-F */
- || (*datap >= 0x61 && *datap <= 0x66)) { /* a-f */
- if(ch->hexindex < MAXNUM_SIZE) {
- ch->hexbuffer[ch->hexindex] = *datap;
- datap++;
- length--;
- ch->hexindex++;
- }
- else {
- return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
- }
- }
- else {
- if(0 == ch->hexindex) {
- /* This is illegal data, we received junk where we expected
- a hexadecimal digit. */
- return CHUNKE_ILLEGAL_HEX;
- }
- /* length and datap are unmodified */
- ch->hexbuffer[ch->hexindex]=0;
-#ifdef CURL_DOES_CONVERSIONS
- /* convert to host encoding before calling strtoul */
- result = Curl_convert_from_network(conn->data,
- ch->hexbuffer,
- ch->hexindex);
- if(result != CURLE_OK) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- /* Treat it as a bad hex character */
- return(CHUNKE_ILLEGAL_HEX);
- }
-#endif /* CURL_DOES_CONVERSIONS */
- ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
- ch->state = CHUNK_POSTHEX;
- }
- break;
-
- case CHUNK_POSTHEX:
- /* In this state, we're waiting for CRLF to arrive. We support
- this to allow so called chunk-extensions to show up here
- before the CRLF comes. */
- if(*datap == 0x0d)
- ch->state = CHUNK_CR;
- length--;
- datap++;
- break;
-
- case CHUNK_CR:
- /* waiting for the LF */
- if(*datap == 0x0a) {
- /* we're now expecting data to come, unless size was zero! */
- if(0 == ch->datasize) {
- if (conn->bits.trailerHdrPresent!=TRUE) {
- /* No Trailer: header found - revert to original Curl processing */
- ch->state = CHUNK_STOP;
- if (1 == length) {
- /* This is the final byte, return right now */
- return CHUNKE_STOP;
- }
- }
- else {
- ch->state = CHUNK_TRAILER; /* attempt to read trailers */
- conn->trlPos=0;
- }
- }
- else
- ch->state = CHUNK_DATA;
- }
- else
- /* previously we got a fake CR, go back to CR waiting! */
- ch->state = CHUNK_CR;
- datap++;
- length--;
- break;
-
- case CHUNK_DATA:
- /* we get pure and fine data
-
- We expect another 'datasize' of data. We have 'length' right now,
- it can be more or less than 'datasize'. Get the smallest piece.
- */
- piece = (ch->datasize >= length)?length:ch->datasize;
-
- /* Write the data portion available */
-#ifdef HAVE_LIBZ
- switch (data->reqdata.keep.content_encoding) {
- case IDENTITY:
-#endif
- if(!k->ignorebody)
- result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
- piece);
-#ifdef HAVE_LIBZ
- break;
-
- case DEFLATE:
- /* update data->reqdata.keep.str to point to the chunk data. */
- data->reqdata.keep.str = datap;
- result = Curl_unencode_deflate_write(conn, &data->reqdata.keep,
- (ssize_t)piece);
- break;
-
- case GZIP:
- /* update data->reqdata.keep.str to point to the chunk data. */
- data->reqdata.keep.str = datap;
- result = Curl_unencode_gzip_write(conn, &data->reqdata.keep,
- (ssize_t)piece);
- break;
-
- case COMPRESS:
- default:
- failf (conn->data,
- "Unrecognized content encoding type. "
- "libcurl understands `identity', `deflate' and `gzip' "
- "content encodings.");
- return CHUNKE_BAD_ENCODING;
- }
-#endif
-
- if(result)
- return CHUNKE_WRITE_ERROR;
-
- *wrote += piece;
-
- ch->datasize -= piece; /* decrease amount left to expect */
- datap += piece; /* move read pointer forward */
- length -= piece; /* decrease space left in this round */
-
- if(0 == ch->datasize)
- /* end of data this round, we now expect a trailing CRLF */
- ch->state = CHUNK_POSTCR;
- break;
-
- case CHUNK_POSTCR:
- if(*datap == 0x0d) {
- ch->state = CHUNK_POSTLF;
- datap++;
- length--;
- }
- else
- return CHUNKE_BAD_CHUNK;
- break;
-
- case CHUNK_POSTLF:
- if(*datap == 0x0a) {
- /*
- * The last one before we go back to hex state and start all
- * over.
- */
- Curl_httpchunk_init(conn);
- datap++;
- length--;
- }
- else
- return CHUNKE_BAD_CHUNK;
- break;
-
- case CHUNK_TRAILER:
- /* conn->trailer is assumed to be freed in url.c on a
- connection basis */
- if (conn->trlPos >= conn->trlMax) {
- char *ptr;
- if(conn->trlMax) {
- conn->trlMax *= 2;
- ptr = (char*)realloc(conn->trailer,conn->trlMax);
- }
- else {
- conn->trlMax=128;
- ptr = (char*)malloc(conn->trlMax);
- }
- if(!ptr)
- return CHUNKE_OUT_OF_MEMORY;
- conn->trailer = ptr;
- }
- conn->trailer[conn->trlPos++]=*datap;
-
- if(*datap == 0x0d)
- ch->state = CHUNK_TRAILER_CR;
- else {
- datap++;
- length--;
- }
- break;
-
- case CHUNK_TRAILER_CR:
- if(*datap == 0x0d) {
- ch->state = CHUNK_TRAILER_POSTCR;
- datap++;
- length--;
- }
- else
- return CHUNKE_BAD_CHUNK;
- break;
-
- case CHUNK_TRAILER_POSTCR:
- if (*datap == 0x0a) {
- conn->trailer[conn->trlPos++]=0x0a;
- conn->trailer[conn->trlPos]=0;
- if (conn->trlPos==2) {
- ch->state = CHUNK_STOP;
- return CHUNKE_STOP;
- }
- else {
-#ifdef CURL_DOES_CONVERSIONS
- /* Convert to host encoding before calling Curl_client_write */
- result = Curl_convert_from_network(conn->data,
- conn->trailer,
- conn->trlPos);
- if(result != CURLE_OK) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- /* Treat it as a bad chunk */
- return(CHUNKE_BAD_CHUNK);
- }
-#endif /* CURL_DOES_CONVERSIONS */
- Curl_client_write(conn, CLIENTWRITE_HEADER,
- conn->trailer, conn->trlPos);
- }
- ch->state = CHUNK_TRAILER;
- conn->trlPos=0;
- datap++;
- length--;
- }
- else
- return CHUNKE_BAD_CHUNK;
- break;
-
- case CHUNK_STOP:
- /* If we arrive here, there is data left in the end of the buffer
- even if there's no more chunks to read */
- ch->dataleft = length;
- return CHUNKE_STOP; /* return stop */
- default:
- return CHUNKE_STATE_ERROR;
- }
- }
- return CHUNKE_OK;
-}
-#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/http_chunks.h b/Utilities/cmcurl/http_chunks.h
deleted file mode 100644
index 211818ab7..000000000
--- a/Utilities/cmcurl/http_chunks.h
+++ /dev/null
@@ -1,104 +0,0 @@
-#ifndef __HTTP_CHUNKS_H
-#define __HTTP_CHUNKS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-/*
- * The longest possible hexadecimal number we support in a chunked transfer.
- * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
- * to convert it, we "only" support 2^32 bytes chunk data.
- */
-#define MAXNUM_SIZE 16
-
-typedef enum {
- CHUNK_FIRST, /* never use */
-
- /* In this we await and buffer all hexadecimal digits until we get one
- that isn't a hexadecimal digit. When done, we go POSTHEX */
- CHUNK_HEX,
-
- /* We have received the hexadecimal digit and we eat all characters until
- we get a CRLF pair. When we see a CR we go to the CR state. */
- CHUNK_POSTHEX,
-
- /* A single CR has been found and we should get a LF right away in this
- state or we go back to POSTHEX. When LF is received, we go to DATA.
- If the size given was zero, we set state to STOP and return. */
- CHUNK_CR,
-
- /* We eat the amount of data specified. When done, we move on to the
- POST_CR state. */
- CHUNK_DATA,
-
- /* POSTCR should get a CR and nothing else, then move to POSTLF */
- CHUNK_POSTCR,
-
- /* POSTLF should get a LF and nothing else, then move back to HEX as the
- CRLF combination marks the end of a chunk */
- CHUNK_POSTLF,
-
- /* This is mainly used to really mark that we're out of the game.
- NOTE: that there's a 'dataleft' field in the struct that will tell how
- many bytes that were not passed to the client in the end of the last
- buffer! */
- CHUNK_STOP,
-
- /* At this point optional trailer headers can be found, unless the next line
- is CRLF */
- CHUNK_TRAILER,
-
- /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
- Next char must be a LF */
- CHUNK_TRAILER_CR,
-
- /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be
- signalled If this is an empty trailer CHUNKE_STOP will be signalled.
- Otherwise the trailer will be broadcasted via Curl_client_write() and the
- next state will be CHUNK_TRAILER */
- CHUNK_TRAILER_POSTCR,
-
- CHUNK_LAST /* never use */
-
-} ChunkyState;
-
-typedef enum {
- CHUNKE_STOP = -1,
- CHUNKE_OK = 0,
- CHUNKE_TOO_LONG_HEX = 1,
- CHUNKE_ILLEGAL_HEX,
- CHUNKE_BAD_CHUNK,
- CHUNKE_WRITE_ERROR,
- CHUNKE_STATE_ERROR,
- CHUNKE_BAD_ENCODING,
- CHUNKE_OUT_OF_MEMORY,
- CHUNKE_LAST
-} CHUNKcode;
-
-struct Curl_chunker {
- char hexbuffer[ MAXNUM_SIZE + 1];
- int hexindex;
- ChunkyState state;
- size_t datasize;
- size_t dataleft; /* untouched data amount at the end of the last buffer */
-};
-
-#endif
diff --git a/Utilities/cmcurl/http_digest.c b/Utilities/cmcurl/http_digest.c
deleted file mode 100644
index c223784f9..000000000
--- a/Utilities/cmcurl/http_digest.c
+++ /dev/null
@@ -1,504 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "urldata.h"
-#include "sendf.h"
-#include "strequal.h"
-#include "base64.h"
-#include "md5.h"
-#include "http_digest.h"
-#include "strtok.h"
-#include "url.h" /* for Curl_safefree() */
-#include "memory.h"
-#include "easyif.h" /* included for Curl_convert_... prototypes */
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* Test example headers:
-
-WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
-Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
-
-*/
-
-CURLdigest Curl_input_digest(struct connectdata *conn,
- bool proxy,
- char *header) /* rest of the *-authenticate:
- header */
-{
- bool more = TRUE;
- char *token = NULL;
- char *tmp = NULL;
- bool foundAuth = FALSE;
- bool foundAuthInt = FALSE;
- struct SessionHandle *data=conn->data;
- bool before = FALSE; /* got a nonce before */
- struct digestdata *d;
-
- if(proxy) {
- d = &data->state.proxydigest;
- }
- else {
- d = &data->state.digest;
- }
-
- /* skip initial whitespaces */
- while(*header && ISSPACE(*header))
- header++;
-
- if(checkprefix("Digest", header)) {
- header += strlen("Digest");
-
- /* If we already have received a nonce, keep that in mind */
- if(d->nonce)
- before = TRUE;
-
- /* clear off any former leftovers and init to defaults */
- Curl_digest_cleanup_one(d);
-
- while(more) {
- char value[32];
- char content[128];
- size_t totlen=0;
-
- while(*header && ISSPACE(*header))
- header++;
-
- /* how big can these strings be? */
- if((2 == sscanf(header, "%31[^=]=\"%127[^\"]\"",
- value, content)) ||
- /* try the same scan but without quotes around the content but don't
- include the possibly trailing comma */
- (2 == sscanf(header, "%31[^=]=%127[^,]",
- value, content)) ) {
- if(strequal(value, "nonce")) {
- d->nonce = strdup(content);
- if(!d->nonce)
- return CURLDIGEST_NOMEM;
- }
- else if(strequal(value, "stale")) {
- if(strequal(content, "true")) {
- d->stale = TRUE;
- d->nc = 1; /* we make a new nonce now */
- }
- }
- else if(strequal(value, "realm")) {
- d->realm = strdup(content);
- if(!d->realm)
- return CURLDIGEST_NOMEM;
- }
- else if(strequal(value, "opaque")) {
- d->opaque = strdup(content);
- if(!d->opaque)
- return CURLDIGEST_NOMEM;
- }
- else if(strequal(value, "qop")) {
- char *tok_buf;
- /* tokenize the list and choose auth if possible, use a temporary
- clone of the buffer since strtok_r() ruins it */
- tmp = strdup(content);
- if(!tmp)
- return CURLDIGEST_NOMEM;
- token = strtok_r(tmp, ",", &tok_buf);
- while (token != NULL) {
- if (strequal(token, "auth")) {
- foundAuth = TRUE;
- }
- else if (strequal(token, "auth-int")) {
- foundAuthInt = TRUE;
- }
- token = strtok_r(NULL, ",", &tok_buf);
- }
- free(tmp);
- /*select only auth o auth-int. Otherwise, ignore*/
- if (foundAuth) {
- d->qop = strdup("auth");
- if(!d->qop)
- return CURLDIGEST_NOMEM;
- }
- else if (foundAuthInt) {
- d->qop = strdup("auth-int");
- if(!d->qop)
- return CURLDIGEST_NOMEM;
- }
- }
- else if(strequal(value, "algorithm")) {
- d->algorithm = strdup(content);
- if(!d->algorithm)
- return CURLDIGEST_NOMEM;
- if(strequal(content, "MD5-sess"))
- d->algo = CURLDIGESTALGO_MD5SESS;
- else if(strequal(content, "MD5"))
- d->algo = CURLDIGESTALGO_MD5;
- else
- return CURLDIGEST_BADALGO;
- }
- else {
- /* unknown specifier, ignore it! */
- }
- totlen = strlen(value)+strlen(content)+1;
-
- if(header[strlen(value)+1] == '\"')
- /* the contents were within quotes, then add 2 for them to the
- length */
- totlen += 2;
- }
- else
- break; /* we're done here */
-
- header += totlen;
- if(',' == *header)
- /* allow the list to be comma-separated */
- header++;
- }
- /* We had a nonce since before, and we got another one now without
- 'stale=true'. This means we provided bad credentials in the previous
- request */
- if(before && !d->stale)
- return CURLDIGEST_BAD;
-
- /* We got this header without a nonce, that's a bad Digest line! */
- if(!d->nonce)
- return CURLDIGEST_BAD;
- }
- else
- /* else not a digest, get out */
- return CURLDIGEST_NONE;
-
- return CURLDIGEST_FINE;
-}
-
-/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
-static void md5_to_ascii(unsigned char *source, /* 16 bytes */
- unsigned char *dest) /* 33 bytes */
-{
- int i;
- for(i=0; i<16; i++)
- snprintf((char *)&dest[i*2], 3, "%02x", source[i]);
-}
-
-CURLcode Curl_output_digest(struct connectdata *conn,
- bool proxy,
- unsigned char *request,
- unsigned char *uripath)
-{
- /* We have a Digest setup for this, use it! Now, to get all the details for
- this sorted out, I must urge you dear friend to read up on the RFC2617
- section 3.2.2, */
- unsigned char md5buf[16]; /* 16 bytes/128 bits */
- unsigned char request_digest[33];
- unsigned char *md5this;
- unsigned char *ha1;
- unsigned char ha2[33];/* 32 digits and 1 zero byte */
- char cnoncebuf[7];
- char *cnonce;
- char *tmp = NULL;
- struct timeval now;
-
- char **allocuserpwd;
- char *userp;
- char *passwdp;
- struct auth *authp;
-
- struct SessionHandle *data = conn->data;
- struct digestdata *d;
-#ifdef CURL_DOES_CONVERSIONS
- CURLcode rc;
-/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
- It converts digest text to ASCII so the MD5 will be correct for
- what ultimately goes over the network.
-*/
-#define CURL_OUTPUT_DIGEST_CONV(a, b) \
- rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
- if (rc != CURLE_OK) { \
- free(b); \
- return rc; \
- }
-#else
-#define CURL_OUTPUT_DIGEST_CONV(a, b)
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(proxy) {
- d = &data->state.proxydigest;
- allocuserpwd = &conn->allocptr.proxyuserpwd;
- userp = conn->proxyuser;
- passwdp = conn->proxypasswd;
- authp = &data->state.authproxy;
- }
- else {
- d = &data->state.digest;
- allocuserpwd = &conn->allocptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
- authp = &data->state.authhost;
- }
-
- /* not set means empty */
- if(!userp)
- userp=(char *)"";
-
- if(!passwdp)
- passwdp=(char *)"";
-
- if(!d->nonce) {
- authp->done = FALSE;
- return CURLE_OK;
- }
- authp->done = TRUE;
-
- if(!d->nc)
- d->nc = 1;
-
- if(!d->cnonce) {
- /* Generate a cnonce */
- now = Curl_tvnow();
- snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", now.tv_sec);
- if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce))
- d->cnonce = cnonce;
- else
- return CURLE_OUT_OF_MEMORY;
- }
-
- /*
- if the algorithm is "MD5" or unspecified (which then defaults to MD5):
-
- A1 = unq(username-value) ":" unq(realm-value) ":" passwd
-
- if the algorithm is "MD5-sess" then:
-
- A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
- ":" unq(nonce-value) ":" unq(cnonce-value)
- */
-
- md5this = (unsigned char *)
- aprintf("%s:%s:%s", userp, d->realm, passwdp);
- if(!md5this)
- return CURLE_OUT_OF_MEMORY;
-
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this); /* free this again */
-
- ha1 = (unsigned char *)malloc(33); /* 32 digits and 1 zero byte */
- if(!ha1)
- return CURLE_OUT_OF_MEMORY;
-
- md5_to_ascii(md5buf, ha1);
-
- if(d->algo == CURLDIGESTALGO_MD5SESS) {
- /* nonce and cnonce are OUTSIDE the hash */
- tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
- CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, (unsigned char *)tmp);
- free(tmp); /* free this again */
- md5_to_ascii(md5buf, ha1);
- }
-
- /*
- If the "qop" directive's value is "auth" or is unspecified, then A2 is:
-
- A2 = Method ":" digest-uri-value
-
- If the "qop" value is "auth-int", then A2 is:
-
- A2 = Method ":" digest-uri-value ":" H(entity-body)
-
- (The "Method" value is the HTTP request method as specified in section
- 5.1.1 of RFC 2616)
- */
-
- md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
- if(!md5this) {
- free(ha1);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if (d->qop && strequal(d->qop, "auth-int")) {
- /* We don't support auth-int at the moment. I can't see a easy way to get
- entity-body here */
- /* TODO: Append H(entity-body)*/
- }
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this); /* free this again */
- md5_to_ascii(md5buf, ha2);
-
- if (d->qop) {
- md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
- ha1,
- d->nonce,
- d->nc,
- d->cnonce,
- d->qop,
- ha2);
- }
- else {
- md5this = (unsigned char *)aprintf("%s:%s:%s",
- ha1,
- d->nonce,
- ha2);
- }
- free(ha1);
- if(!md5this)
- return CURLE_OUT_OF_MEMORY;
-
- CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
- Curl_md5it(md5buf, md5this);
- free(md5this); /* free this again */
- md5_to_ascii(md5buf, request_digest);
-
- /* for test case 64 (snooped from a Mozilla 1.3a request)
-
- Authorization: Digest username="testuser", realm="testrealm", \
- nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
- */
-
- Curl_safefree(*allocuserpwd);
-
- if (d->qop) {
- *allocuserpwd =
- aprintf( "%sAuthorization: Digest "
- "username=\"%s\", "
- "realm=\"%s\", "
- "nonce=\"%s\", "
- "uri=\"%s\", "
- "cnonce=\"%s\", "
- "nc=%08x, "
- "qop=\"%s\", "
- "response=\"%s\"",
- proxy?"Proxy-":"",
- userp,
- d->realm,
- d->nonce,
- uripath, /* this is the PATH part of the URL */
- d->cnonce,
- d->nc,
- d->qop,
- request_digest);
-
- if(strequal(d->qop, "auth"))
- d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
- which tells to the server how many times you are using the
- same nonce in the qop=auth mode. */
- }
- else {
- *allocuserpwd =
- aprintf( "%sAuthorization: Digest "
- "username=\"%s\", "
- "realm=\"%s\", "
- "nonce=\"%s\", "
- "uri=\"%s\", "
- "response=\"%s\"",
- proxy?"Proxy-":"",
- userp,
- d->realm,
- d->nonce,
- uripath, /* this is the PATH part of the URL */
- request_digest);
- }
- if(!*allocuserpwd)
- return CURLE_OUT_OF_MEMORY;
-
- /* Add optional fields */
- if(d->opaque) {
- /* append opaque */
- tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
- free(*allocuserpwd);
- *allocuserpwd = tmp;
- }
-
- if(d->algorithm) {
- /* append algorithm */
- tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
- free(*allocuserpwd);
- *allocuserpwd = tmp;
- }
-
- /* append CRLF to the userpwd header */
- tmp = (char*) realloc(*allocuserpwd, strlen(*allocuserpwd) + 3 + 1);
- if(!tmp)
- return CURLE_OUT_OF_MEMORY;
- strcat(tmp, "\r\n");
- *allocuserpwd = tmp;
-
- return CURLE_OK;
-}
-
-void Curl_digest_cleanup_one(struct digestdata *d)
-{
- if(d->nonce)
- free(d->nonce);
- d->nonce = NULL;
-
- if(d->cnonce)
- free(d->cnonce);
- d->cnonce = NULL;
-
- if(d->realm)
- free(d->realm);
- d->realm = NULL;
-
- if(d->opaque)
- free(d->opaque);
- d->opaque = NULL;
-
- if(d->qop)
- free(d->qop);
- d->qop = NULL;
-
- if(d->algorithm)
- free(d->algorithm);
- d->algorithm = NULL;
-
- d->nc = 0;
- d->algo = CURLDIGESTALGO_MD5; /* default algorithm */
- d->stale = FALSE; /* default means normal, not stale */
-}
-
-
-void Curl_digest_cleanup(struct SessionHandle *data)
-{
- Curl_digest_cleanup_one(&data->state.digest);
- Curl_digest_cleanup_one(&data->state.proxydigest);
-}
-
-#endif
diff --git a/Utilities/cmcurl/http_digest.h b/Utilities/cmcurl/http_digest.h
deleted file mode 100644
index 6cf025975..000000000
--- a/Utilities/cmcurl/http_digest.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef __HTTP_DIGEST_H
-#define __HTTP_DIGEST_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-typedef enum {
- CURLDIGEST_NONE, /* not a digest */
- CURLDIGEST_BAD, /* a digest, but one we don't like */
- CURLDIGEST_BADALGO, /* unsupported algorithm requested */
- CURLDIGEST_NOMEM,
- CURLDIGEST_FINE, /* a digest we act on */
-
- CURLDIGEST_LAST /* last entry in this enum, don't use */
-} CURLdigest;
-
-enum {
- CURLDIGESTALGO_MD5,
- CURLDIGESTALGO_MD5SESS
-};
-
-/* this is for digest header input */
-CURLdigest Curl_input_digest(struct connectdata *conn,
- bool proxy, char *header);
-
-/* this is for creating digest header output */
-CURLcode Curl_output_digest(struct connectdata *conn,
- bool proxy,
- unsigned char *request,
- unsigned char *uripath);
-void Curl_digest_cleanup_one(struct digestdata *dig);
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-void Curl_digest_cleanup(struct SessionHandle *data);
-#else
-#define Curl_digest_cleanup(x) do {} while(0)
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/http_negotiate.c b/Utilities/cmcurl/http_negotiate.c
deleted file mode 100644
index bdfeefa0a..000000000
--- a/Utilities/cmcurl/http_negotiate.c
+++ /dev/null
@@ -1,327 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-#ifdef HAVE_GSSAPI
-#ifdef HAVE_GSSMIT
-#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
-#endif
-
-#ifndef CURL_DISABLE_HTTP
- /* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "urldata.h"
-#include "sendf.h"
-#include "strequal.h"
-#include "base64.h"
-#include "http_negotiate.h"
-#include "memory.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-static int
-get_gss_name(struct connectdata *conn, gss_name_t *server)
-{
- struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
- OM_uint32 major_status, minor_status;
- gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
- char name[2048];
- const char* service;
-
- /* GSSAPI implementation by Globus (known as GSI) requires the name to be
- of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
- of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
- Change following lines if you want to use GSI */
-
- /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */
-
- if (neg_ctx->gss)
- service = "KHTTP";
- else
- service = "HTTP";
-
- token.length = strlen(service) + 1 + strlen(conn->host.name) + 1;
- if (token.length + 1 > sizeof(name))
- return EMSGSIZE;
-
- snprintf(name, sizeof(name), "%s@%s", service, conn->host.name);
-
- token.value = (void *) name;
- major_status = gss_import_name(&minor_status,
- &token,
- GSS_C_NT_HOSTBASED_SERVICE,
- server);
-
- return GSS_ERROR(major_status) ? -1 : 0;
-}
-
-static void
-log_gss_error(struct connectdata *conn, OM_uint32 error_status, char *prefix)
-{
- OM_uint32 maj_stat, min_stat;
- OM_uint32 msg_ctx = 0;
- gss_buffer_desc status_string;
- char buf[1024];
- size_t len;
-
- snprintf(buf, sizeof(buf), "%s", prefix);
- len = strlen(buf);
- do {
- maj_stat = gss_display_status (&min_stat,
- error_status,
- GSS_C_MECH_CODE,
- GSS_C_NO_OID,
- &msg_ctx,
- &status_string);
- if (sizeof(buf) > len + status_string.length + 1) {
- snprintf(buf + len, sizeof(buf) - len,
- ": %s", (char*) status_string.value);
- len += status_string.length;
- }
- gss_release_buffer(&min_stat, &status_string);
- } while (!GSS_ERROR(maj_stat) && msg_ctx != 0);
-
- infof(conn->data, "%s", buf);
-}
-
-int Curl_input_negotiate(struct connectdata *conn, char *header)
-{
- struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
- OM_uint32 major_status, minor_status, minor_status2;
- gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
- int ret;
- size_t len;
- bool gss;
- const char* protocol;
-
- while(*header && ISSPACE(*header))
- header++;
- if(checkprefix("GSS-Negotiate", header)) {
- protocol = "GSS-Negotiate";
- gss = TRUE;
- }
- else if (checkprefix("Negotiate", header)) {
- protocol = "Negotiate";
- gss = FALSE;
- }
- else
- return -1;
-
- if (neg_ctx->context) {
- if (neg_ctx->gss != gss) {
- return -1;
- }
- }
- else {
- neg_ctx->protocol = protocol;
- neg_ctx->gss = gss;
- }
-
- if (neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
- /* We finished succesfully our part of authentication, but server
- * rejected it (since we're again here). Exit with an error since we
- * can't invent anything better */
- Curl_cleanup_negotiate(conn->data);
- return -1;
- }
-
- if (neg_ctx->server_name == NULL &&
- (ret = get_gss_name(conn, &neg_ctx->server_name)))
- return ret;
-
- header += strlen(neg_ctx->protocol);
- while(*header && ISSPACE(*header))
- header++;
-
- len = strlen(header);
- if (len > 0) {
- int rawlen = Curl_base64_decode(header, (unsigned char **)&input_token.value);
- if (rawlen < 0)
- return -1;
- input_token.length = rawlen;
-
-#ifdef HAVE_SPNEGO /* Handle SPNEGO */
- if (checkprefix("Negotiate", header)) {
- ASN1_OBJECT * object = NULL;
- int rc = 1;
- unsigned char * spnegoToken = NULL;
- size_t spnegoTokenLength = 0;
- unsigned char * mechToken = NULL;
- size_t mechTokenLength = 0;
-
- spnegoToken = malloc(input_token.length);
- if (input_token.value == NULL)
- return ENOMEM;
- spnegoTokenLength = input_token.length;
-
- object = OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
- if (!parseSpnegoTargetToken(spnegoToken,
- spnegoTokenLength,
- NULL,
- NULL,
- &mechToken,
- &mechTokenLength,
- NULL,
- NULL)) {
- free(spnegoToken);
- spnegoToken = NULL;
- infof(conn->data, "Parse SPNEGO Target Token failed\n");
- }
- else {
- free(input_token.value);
- input_token.value = NULL;
- input_token.value = malloc(mechTokenLength);
- memcpy(input_token.value, mechToken,mechTokenLength);
- input_token.length = mechTokenLength;
- free(mechToken);
- mechToken = NULL;
- infof(conn->data, "Parse SPNEGO Target Token succeeded\n");
- }
- }
-#endif
- }
-
- major_status = gss_init_sec_context(&minor_status,
- GSS_C_NO_CREDENTIAL,
- &neg_ctx->context,
- neg_ctx->server_name,
- GSS_C_NO_OID,
- GSS_C_DELEG_FLAG,
- 0,
- GSS_C_NO_CHANNEL_BINDINGS,
- &input_token,
- NULL,
- &output_token,
- NULL,
- NULL);
- if (input_token.length > 0)
- gss_release_buffer(&minor_status2, &input_token);
- neg_ctx->status = major_status;
- if (GSS_ERROR(major_status)) {
- /* Curl_cleanup_negotiate(conn->data) ??? */
- log_gss_error(conn, minor_status,
- (char *)"gss_init_sec_context() failed: ");
- return -1;
- }
-
- if (output_token.length == 0) {
- return -1;
- }
-
- neg_ctx->output_token = output_token;
- /* conn->bits.close = FALSE; */
-
- return 0;
-}
-
-
-CURLcode Curl_output_negotiate(struct connectdata *conn)
-{
- struct negotiatedata *neg_ctx = &conn->data->state.negotiate;
- OM_uint32 minor_status;
- char *encoded = NULL;
- int len;
-
-#ifdef HAVE_SPNEGO /* Handle SPNEGO */
- if (checkprefix("Negotiate",neg_ctx->protocol)) {
- ASN1_OBJECT * object = NULL;
- int rc = 1;
- unsigned char * spnegoToken = NULL;
- size_t spnegoTokenLength = 0;
- unsigned char * responseToken = NULL;
- size_t responseTokenLength = 0;
-
- responseToken = malloc(neg_ctx->output_token.length);
- if ( responseToken == NULL)
- return CURLE_OUT_OF_MEMORY;
- memcpy(responseToken, neg_ctx->output_token.value,
- neg_ctx->output_token.length);
- responseTokenLength = neg_ctx->output_token.length;
-
- object=OBJ_txt2obj ("1.2.840.113554.1.2.2", 1);
- if (!makeSpnegoInitialToken (object,
- responseToken,
- responseTokenLength,
- &spnegoToken,
- &spnegoTokenLength)) {
- free(responseToken);
- responseToken = NULL;
- infof(conn->data, "Make SPNEGO Initial Token failed\n");
- }
- else {
- free(neg_ctx->output_token.value);
- responseToken = NULL;
- neg_ctx->output_token.value = malloc(spnegoTokenLength);
- memcpy(neg_ctx->output_token.value, spnegoToken,spnegoTokenLength);
- neg_ctx->output_token.length = spnegoTokenLength;
- free(spnegoToken);
- spnegoToken = NULL;
- infof(conn->data, "Make SPNEGO Initial Token succeeded\n");
- }
- }
-#endif
- len = Curl_base64_encode(conn->data,
- neg_ctx->output_token.value,
- neg_ctx->output_token.length,
- &encoded);
-
- if (len < 0)
- return CURLE_OUT_OF_MEMORY;
-
- conn->allocptr.userpwd =
- aprintf("Authorization: %s %s\r\n", neg_ctx->protocol, encoded);
- free(encoded);
- gss_release_buffer(&minor_status, &neg_ctx->output_token);
- return (conn->allocptr.userpwd == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
-}
-
-void Curl_cleanup_negotiate(struct SessionHandle *data)
-{
- OM_uint32 minor_status;
- struct negotiatedata *neg_ctx = &data->state.negotiate;
-
- if (neg_ctx->context != GSS_C_NO_CONTEXT)
- gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
-
- if (neg_ctx->output_token.length != 0)
- gss_release_buffer(&minor_status, &neg_ctx->output_token);
-
- if (neg_ctx->server_name != GSS_C_NO_NAME)
- gss_release_name(&minor_status, &neg_ctx->server_name);
-
- memset(neg_ctx, 0, sizeof(*neg_ctx));
-}
-
-
-#endif
-#endif
diff --git a/Utilities/cmcurl/http_negotiate.h b/Utilities/cmcurl/http_negotiate.h
deleted file mode 100644
index ce0d083f9..000000000
--- a/Utilities/cmcurl/http_negotiate.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __HTTP_NEGOTIATE_H
-#define __HTTP_NEGOTIATE_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifdef HAVE_GSSAPI
-
-/* this is for Negotiate header input */
-int Curl_input_negotiate(struct connectdata *conn, char *header);
-
-/* this is for creating Negotiate header output */
-CURLcode Curl_output_negotiate(struct connectdata *conn);
-
-void Curl_cleanup_negotiate(struct SessionHandle *data);
-
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/http_ntlm.c b/Utilities/cmcurl/http_ntlm.c
deleted file mode 100644
index aff1bb1b6..000000000
--- a/Utilities/cmcurl/http_ntlm.c
+++ /dev/null
@@ -1,1111 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-/* NTLM details:
-
- http://davenport.sourceforge.net/ntlm.html
- http://www.innovation.ch/java/ntlm.html
-
- Another implementation:
- http://lxr.mozilla.org/mozilla/source/security/manager/ssl/src/nsNTLMAuthModule.cpp
-
-*/
-
-#ifndef CURL_DISABLE_HTTP
-#ifdef USE_NTLM
-
-#define DEBUG_ME 0
-
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "urldata.h"
-#include "easyif.h" /* for Curl_convert_... prototypes */
-#include "sendf.h"
-#include "strequal.h"
-#include "base64.h"
-#include "http_ntlm.h"
-#include "url.h"
-#include "memory.h"
-#include "ssluse.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* "NTLMSSP" signature is always in ASCII regardless of the platform */
-#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
-
-#ifndef USE_WINDOWS_SSPI
-
-#include <openssl/des.h>
-#include <openssl/md4.h>
-#include <openssl/md5.h>
-#include <openssl/ssl.h>
-#include <openssl/rand.h>
-
-#if OPENSSL_VERSION_NUMBER < 0x00907001L
-#define DES_key_schedule des_key_schedule
-#define DES_cblock des_cblock
-#define DES_set_odd_parity des_set_odd_parity
-#define DES_set_key des_set_key
-#define DES_ecb_encrypt des_ecb_encrypt
-
-/* This is how things were done in the old days */
-#define DESKEY(x) x
-#define DESKEYARG(x) x
-#else
-/* Modern version */
-#define DESKEYARG(x) *x
-#define DESKEY(x) &x
-#endif
-
-#else
-
-#include <rpc.h>
-
-/* Handle of security.dll or secur32.dll, depending on Windows version */
-static HMODULE s_hSecDll = NULL;
-/* Pointer to SSPI dispatch table */
-static PSecurityFunctionTable s_pSecFn = NULL;
-
-#endif
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* Define this to make the type-3 message include the NT response message */
-#define USE_NTRESPONSES 1
-
-/* Define this to make the type-3 message include the NTLM2Session response
- message, requires USE_NTRESPONSES. */
-#define USE_NTLM2SESSION 1
-
-#ifndef USE_WINDOWS_SSPI
-/* this function converts from the little endian format used in the incoming
- package to whatever endian format we're using natively */
-static unsigned int readint_le(unsigned char *buf) /* must point to a
- 4 bytes buffer*/
-{
- return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
- ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
-}
-#endif
-
-#if DEBUG_ME
-# define DEBUG_OUT(x) x
-static void print_flags(FILE *handle, unsigned long flags)
-{
- if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
- if(flags & NTLMFLAG_NEGOTIATE_OEM)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
- if(flags & NTLMFLAG_REQUEST_TARGET)
- fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
- if(flags & (1<<3))
- fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
- if(flags & NTLMFLAG_NEGOTIATE_SIGN)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
- if(flags & NTLMFLAG_NEGOTIATE_SEAL)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
- if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
- if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
- if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
- if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
- if(flags & (1<<10))
- fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
- if(flags & (1<<11))
- fprintf(handle, "NTLMFLAG_UNKNOWN_11 ");
- if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
- if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
- if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
- if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
- if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
- fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
- if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
- fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
- if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
- fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
- if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
- if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
- fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
- if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
- fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
- if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
- fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
- if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
- if(flags & (1<<24))
- fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
- if(flags & (1<<25))
- fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
- if(flags & (1<<26))
- fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
- if(flags & (1<<27))
- fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
- if(flags & (1<<28))
- fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
- if(flags & NTLMFLAG_NEGOTIATE_128)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
- if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
- if(flags & NTLMFLAG_NEGOTIATE_56)
- fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
-}
-
-static void print_hex(FILE *handle, const char *buf, size_t len)
-{
- const char *p = buf;
- fprintf(stderr, "0x");
- while (len-- > 0)
- fprintf(stderr, "%02.2x", (unsigned int)*p++);
-}
-#else
-# define DEBUG_OUT(x)
-#endif
-
-/*
- (*) = A "security buffer" is a triplet consisting of two shorts and one
- long:
-
- 1. a 'short' containing the length of the buffer in bytes
- 2. a 'short' containing the allocated space for the buffer in bytes
- 3. a 'long' containing the offset to the start of the buffer from the
- beginning of the NTLM message, in bytes.
-*/
-
-
-CURLntlm Curl_input_ntlm(struct connectdata *conn,
- bool proxy, /* if proxy or not */
- char *header) /* rest of the www-authenticate:
- header */
-{
- /* point to the correct struct with this */
- struct ntlmdata *ntlm;
-#ifndef USE_WINDOWS_SSPI
- static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
-#endif
-
- ntlm = proxy?&conn->proxyntlm:&conn->ntlm;
-
- /* skip initial whitespaces */
- while(*header && ISSPACE(*header))
- header++;
-
- if(checkprefix("NTLM", header)) {
- header += strlen("NTLM");
-
- while(*header && ISSPACE(*header))
- header++;
-
- if(*header) {
- /* We got a type-2 message here:
-
- Index Description Content
- 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
- (0x4e544c4d53535000)
- 8 NTLM Message Type long (0x02000000)
- 12 Target Name security buffer(*)
- 20 Flags long
- 24 Challenge 8 bytes
- (32) Context (optional) 8 bytes (two consecutive longs)
- (40) Target Information (optional) security buffer(*)
- 32 (48) start of data block
- */
- size_t size;
- unsigned char *buffer;
- size = Curl_base64_decode(header, &buffer);
- if(!buffer)
- return CURLNTLM_BAD;
-
- ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */
-
-#ifdef USE_WINDOWS_SSPI
- ntlm->type_2 = malloc(size+1);
- if (ntlm->type_2 == NULL) {
- free(buffer);
- return CURLE_OUT_OF_MEMORY;
- }
- ntlm->n_type_2 = size;
- memcpy(ntlm->type_2, buffer, size);
-#else
- ntlm->flags = 0;
-
- if((size < 32) ||
- (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
- (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) {
- /* This was not a good enough type-2 message */
- free(buffer);
- return CURLNTLM_BAD;
- }
-
- ntlm->flags = readint_le(&buffer[20]);
- memcpy(ntlm->nonce, &buffer[24], 8);
-
- DEBUG_OUT({
- fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
- print_flags(stderr, ntlm->flags);
- fprintf(stderr, "\n nonce=");
- print_hex(stderr, (char *)ntlm->nonce, 8);
- fprintf(stderr, "\n****\n");
- fprintf(stderr, "**** Header %s\n ", header);
- });
-
- free(buffer);
-#endif
- }
- else {
- if(ntlm->state >= NTLMSTATE_TYPE1)
- return CURLNTLM_BAD;
-
- ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */
- }
- }
- return CURLNTLM_FINE;
-}
-
-#ifndef USE_WINDOWS_SSPI
-
-/*
- * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
- * key schedule ks is also set.
- */
-static void setup_des_key(unsigned char *key_56,
- DES_key_schedule DESKEYARG(ks))
-{
- DES_cblock key;
-
- key[0] = key_56[0];
- key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
- key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
- key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
- key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
- key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
- key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
- key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
-
- DES_set_odd_parity(&key);
- DES_set_key(&key, ks);
-}
-
- /*
- * takes a 21 byte array and treats it as 3 56-bit DES keys. The
- * 8 byte plaintext is encrypted with each key and the resulting 24
- * bytes are stored in the results array.
- */
-static void lm_resp(unsigned char *keys,
- unsigned char *plaintext,
- unsigned char *results)
-{
- DES_key_schedule ks;
-
- setup_des_key(keys, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
- DESKEY(ks), DES_ENCRYPT);
-
- setup_des_key(keys+7, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+8),
- DESKEY(ks), DES_ENCRYPT);
-
- setup_des_key(keys+14, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results+16),
- DESKEY(ks), DES_ENCRYPT);
-}
-
-
-/*
- * Set up lanmanager hashed password
- */
-static void mk_lm_hash(struct SessionHandle *data,
- char *password,
- unsigned char *lmbuffer /* 21 bytes */)
-{
- unsigned char pw[14];
- static const unsigned char magic[] = {
- 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
- };
- unsigned int i;
- size_t len = strlen(password);
-
- if (len > 14)
- len = 14;
-
- for (i=0; i<len; i++)
- pw[i] = (unsigned char)toupper(password[i]);
-
- for (; i<14; i++)
- pw[i] = 0;
-
-#ifdef CURL_DOES_CONVERSIONS
- /*
- * The LanManager hashed password needs to be created using the
- * password in the network encoding not the host encoding.
- */
- if(data)
- Curl_convert_to_network(data, (char *)pw, 14);
-#else
- (void)data;
-#endif
-
- {
- /* Create LanManager hashed password. */
-
- DES_key_schedule ks;
-
- setup_des_key(pw, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
- DESKEY(ks), DES_ENCRYPT);
-
- setup_des_key(pw+7, DESKEY(ks));
- DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer+8),
- DESKEY(ks), DES_ENCRYPT);
-
- memset(lmbuffer + 16, 0, 21 - 16);
- }
- }
-
-#if USE_NTRESPONSES
-static void utf8_to_unicode_le(unsigned char *dest, const char *src,
- size_t srclen)
-{
- size_t i;
- for (i=0; i<srclen; i++) {
- dest[2*i] = (unsigned char)src[i];
- dest[2*i+1] = '\0';
- }
-}
-
-/*
- * Set up nt hashed passwords
- */
-static void mk_nt_hash(struct SessionHandle *data,
- char *password,
- unsigned char *ntbuffer /* 21 bytes */)
-{
- size_t len = strlen(password);
- unsigned char *pw = malloc(len*2);
-
- utf8_to_unicode_le(pw, password, len);
-
-#ifdef CURL_DOES_CONVERSIONS
- /*
- * The NT hashed password needs to be created using the
- * password in the network encoding not the host encoding.
- */
- if(data)
- Curl_convert_to_network(data, (char *)pw, len*2);
-#else
- (void)data;
-#endif
-
- {
- /* Create NT hashed password. */
- MD4_CTX MD4;
-
- MD4_Init(&MD4);
- MD4_Update(&MD4, pw, 2*len);
- MD4_Final(ntbuffer, &MD4);
-
- memset(ntbuffer + 16, 0, 21 - 16);
- }
-
- free(pw);
-}
-#endif
-
-
-#endif
-
-#ifdef USE_WINDOWS_SSPI
-
-static void
-ntlm_sspi_cleanup(struct ntlmdata *ntlm)
-{
- if (ntlm->type_2) {
- free(ntlm->type_2);
- ntlm->type_2 = NULL;
- }
- if (ntlm->has_handles) {
- s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
- s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
- ntlm->has_handles = 0;
- }
- if (ntlm->p_identity) {
- if (ntlm->identity.User) free(ntlm->identity.User);
- if (ntlm->identity.Password) free(ntlm->identity.Password);
- if (ntlm->identity.Domain) free(ntlm->identity.Domain);
- ntlm->p_identity = NULL;
- }
-}
-
-#endif
-
-#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
-#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \
- (((x) >>16)&0xff), (((x)>>24) & 0xff)
-
-#define HOSTNAME_MAX 1024
-
-/* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm(struct connectdata *conn,
- bool proxy)
-{
- const char *domain=""; /* empty */
- char host [HOSTNAME_MAX+ 1] = ""; /* empty */
-#ifndef USE_WINDOWS_SSPI
- size_t domlen = strlen(domain);
- size_t hostlen = strlen(host);
- size_t hostoff; /* host name offset */
- size_t domoff; /* domain name offset */
-#endif
- size_t size;
- char *base64=NULL;
- unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very
- long */
-
- /* point to the address of the pointer that holds the string to sent to the
- server, which is for a plain host or for a HTTP proxy */
- char **allocuserpwd;
-
- /* point to the name and password for this */
- char *userp;
- char *passwdp;
- /* point to the correct struct with this */
- struct ntlmdata *ntlm;
- struct auth *authp;
-
- curlassert(conn);
- curlassert(conn->data);
-
- if(proxy) {
- allocuserpwd = &conn->allocptr.proxyuserpwd;
- userp = conn->proxyuser;
- passwdp = conn->proxypasswd;
- ntlm = &conn->proxyntlm;
- authp = &conn->data->state.authproxy;
- }
- else {
- allocuserpwd = &conn->allocptr.userpwd;
- userp = conn->user;
- passwdp = conn->passwd;
- ntlm = &conn->ntlm;
- authp = &conn->data->state.authhost;
- }
- authp->done = FALSE;
-
- /* not set means empty */
- if(!userp)
- userp=(char *)"";
-
- if(!passwdp)
- passwdp=(char *)"";
-
-#ifdef USE_WINDOWS_SSPI
- /* If security interface is not yet initialized try to do this */
- if (s_hSecDll == NULL) {
- /* Determine Windows version. Security functions are located in
- * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
- * contain both these DLLs (security.dll just forwards calls to
- * secur32.dll)
- */
- OSVERSIONINFO osver;
- osver.dwOSVersionInfoSize = sizeof(osver);
- GetVersionEx(&osver);
- if (osver.dwPlatformId == VER_PLATFORM_WIN32_NT
- && osver.dwMajorVersion == 4)
- s_hSecDll = LoadLibrary("security.dll");
- else
- s_hSecDll = LoadLibrary("secur32.dll");
- if (s_hSecDll != NULL) {
- INIT_SECURITY_INTERFACE pInitSecurityInterface;
- pInitSecurityInterface =
- (INIT_SECURITY_INTERFACE)GetProcAddress(s_hSecDll,
- "InitSecurityInterfaceA");
- if (pInitSecurityInterface != NULL)
- s_pSecFn = pInitSecurityInterface();
- }
- }
- if (s_pSecFn == NULL)
- return CURLE_RECV_ERROR;
-#endif
-
- switch(ntlm->state) {
- case NTLMSTATE_TYPE1:
- default: /* for the weird cases we (re)start here */
-#ifdef USE_WINDOWS_SSPI
- {
- SecBuffer buf;
- SecBufferDesc desc;
- SECURITY_STATUS status;
- ULONG attrs;
- const char *user;
- int domlen;
- TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
-
- ntlm_sspi_cleanup(ntlm);
-
- user = strchr(userp, '\\');
- if (!user)
- user = strchr(userp, '/');
-
- if (user) {
- domain = userp;
- domlen = user - userp;
- user++;
- }
- else {
- user = userp;
- domain = "";
- domlen = 0;
- }
-
- if (user && *user) {
- /* note: initialize all of this before doing the mallocs so that
- * it can be cleaned up later without leaking memory.
- */
- ntlm->p_identity = &ntlm->identity;
- memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
- if ((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL)
- return CURLE_OUT_OF_MEMORY;
- ntlm->identity.UserLength = strlen(user);
- if ((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL)
- return CURLE_OUT_OF_MEMORY;
- ntlm->identity.PasswordLength = strlen(passwdp);
- if ((ntlm->identity.Domain = malloc(domlen+1)) == NULL)
- return CURLE_OUT_OF_MEMORY;
- strncpy((char *)ntlm->identity.Domain, domain, domlen);
- ntlm->identity.Domain[domlen] = '\0';
- ntlm->identity.DomainLength = domlen;
- ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
- }
- else {
- ntlm->p_identity = NULL;
- }
-
- if (s_pSecFn->AcquireCredentialsHandle(
- NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity,
- NULL, NULL, &ntlm->handle, &tsDummy
- ) != SEC_E_OK) {
- return CURLE_OUT_OF_MEMORY;
- }
-
- desc.ulVersion = SECBUFFER_VERSION;
- desc.cBuffers = 1;
- desc.pBuffers = &buf;
- buf.cbBuffer = sizeof(ntlmbuf);
- buf.BufferType = SECBUFFER_TOKEN;
- buf.pvBuffer = ntlmbuf;
-
- status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
- (char *) host,
- ISC_REQ_CONFIDENTIALITY |
- ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONNECTION,
- 0, SECURITY_NETWORK_DREP,
- NULL, 0,
- &ntlm->c_handle, &desc,
- &attrs, &tsDummy);
-
- if (status == SEC_I_COMPLETE_AND_CONTINUE ||
- status == SEC_I_CONTINUE_NEEDED) {
- s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
- }
- else if (status != SEC_E_OK) {
- s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
- return CURLE_RECV_ERROR;
- }
-
- ntlm->has_handles = 1;
- size = buf.cbBuffer;
- }
-#else
- hostoff = 0;
- domoff = hostoff + hostlen; /* This is 0: remember that host and domain
- are empty */
-
- /* Create and send a type-1 message:
-
- Index Description Content
- 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
- (0x4e544c4d53535000)
- 8 NTLM Message Type long (0x01000000)
- 12 Flags long
- 16 Supplied Domain security buffer(*)
- 24 Supplied Workstation security buffer(*)
- 32 start of data block
-
- */
-#if USE_NTLM2SESSION
-#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
-#else
-#define NTLM2FLAG 0
-#endif
- snprintf((char *)ntlmbuf, sizeof(ntlmbuf), NTLMSSP_SIGNATURE "%c"
- "\x01%c%c%c" /* 32-bit type = 1 */
- "%c%c%c%c" /* 32-bit NTLM flag field */
- "%c%c" /* domain length */
- "%c%c" /* domain allocated space */
- "%c%c" /* domain name offset */
- "%c%c" /* 2 zeroes */
- "%c%c" /* host length */
- "%c%c" /* host allocated space */
- "%c%c" /* host name offset */
- "%c%c" /* 2 zeroes */
- "%s" /* host name */
- "%s", /* domain string */
- 0, /* trailing zero */
- 0,0,0, /* part of type-1 long */
-
- LONGQUARTET(
- NTLMFLAG_NEGOTIATE_OEM|
- NTLMFLAG_REQUEST_TARGET|
- NTLMFLAG_NEGOTIATE_NTLM_KEY|
- NTLM2FLAG|
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN
- ),
- SHORTPAIR(domlen),
- SHORTPAIR(domlen),
- SHORTPAIR(domoff),
- 0,0,
- SHORTPAIR(hostlen),
- SHORTPAIR(hostlen),
- SHORTPAIR(hostoff),
- 0,0,
- host /* this is empty */, domain /* this is empty */);
-
- /* initial packet length */
- size = 32 + hostlen + domlen;
-#endif
-
- DEBUG_OUT({
- fprintf(stderr, "**** TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
- LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM|
- NTLMFLAG_REQUEST_TARGET|
- NTLMFLAG_NEGOTIATE_NTLM_KEY|
- NTLM2FLAG|
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
- NTLMFLAG_NEGOTIATE_OEM|
- NTLMFLAG_REQUEST_TARGET|
- NTLMFLAG_NEGOTIATE_NTLM_KEY|
- NTLM2FLAG|
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
- print_flags(stderr,
- NTLMFLAG_NEGOTIATE_OEM|
- NTLMFLAG_REQUEST_TARGET|
- NTLMFLAG_NEGOTIATE_NTLM_KEY|
- NTLM2FLAG|
- NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
- fprintf(stderr, "\n****\n");
- });
-
- /* now size is the size of the base64 encoded package size */
- size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
-
- if(size >0 ) {
- Curl_safefree(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy?"Proxy-":"",
- base64);
- DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
- free(base64);
- }
- else
- return CURLE_OUT_OF_MEMORY; /* FIX TODO */
-
- break;
-
- case NTLMSTATE_TYPE2:
- /* We received the type-2 message already, create a type-3 message:
-
- Index Description Content
- 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
- (0x4e544c4d53535000)
- 8 NTLM Message Type long (0x03000000)
- 12 LM/LMv2 Response security buffer(*)
- 20 NTLM/NTLMv2 Response security buffer(*)
- 28 Domain Name security buffer(*)
- 36 User Name security buffer(*)
- 44 Workstation Name security buffer(*)
- (52) Session Key (optional) security buffer(*)
- (60) Flags (optional) long
- 52 (64) start of data block
-
- */
-
- {
-#ifdef USE_WINDOWS_SSPI
- SecBuffer type_2, type_3;
- SecBufferDesc type_2_desc, type_3_desc;
- SECURITY_STATUS status;
- ULONG attrs;
- TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */
-
- type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
- type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
- type_2_desc.pBuffers = &type_2;
- type_3_desc.pBuffers = &type_3;
-
- type_2.BufferType = SECBUFFER_TOKEN;
- type_2.pvBuffer = ntlm->type_2;
- type_2.cbBuffer = ntlm->n_type_2;
- type_3.BufferType = SECBUFFER_TOKEN;
- type_3.pvBuffer = ntlmbuf;
- type_3.cbBuffer = sizeof(ntlmbuf);
-
- status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, &ntlm->c_handle,
- (char *) host,
- ISC_REQ_CONFIDENTIALITY |
- ISC_REQ_REPLAY_DETECT |
- ISC_REQ_CONNECTION,
- 0, SECURITY_NETWORK_DREP, &type_2_desc,
- 0, &ntlm->c_handle, &type_3_desc,
- &attrs, &tsDummy);
-
- if (status != SEC_E_OK)
- return CURLE_RECV_ERROR;
-
- size = type_3.cbBuffer;
-
- ntlm_sspi_cleanup(ntlm);
-
-#else
- int lmrespoff;
- unsigned char lmresp[24]; /* fixed-size */
-#if USE_NTRESPONSES
- int ntrespoff;
- unsigned char ntresp[24]; /* fixed-size */
-#endif
- size_t useroff;
- const char *user;
- size_t userlen;
-
- user = strchr(userp, '\\');
- if(!user)
- user = strchr(userp, '/');
-
- if (user) {
- domain = userp;
- domlen = (user - domain);
- user++;
- }
- else
- user = userp;
- userlen = strlen(user);
-
- if (gethostname(host, HOSTNAME_MAX)) {
- infof(conn->data, "gethostname() failed, continuing without!");
- hostlen = 0;
- }
- else {
- /* If the workstation if configured with a full DNS name (i.e.
- * workstation.somewhere.net) gethostname() returns the fully qualified
- * name, which NTLM doesn't like.
- */
- char *dot = strchr(host, '.');
- if (dot)
- *dot = '\0';
- hostlen = strlen(host);
- }
-
-#if USE_NTLM2SESSION
- /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
- if (ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
- unsigned char ntbuffer[0x18];
- unsigned char tmp[0x18];
- unsigned char md5sum[MD5_DIGEST_LENGTH];
- MD5_CTX MD5;
- unsigned char random[8];
-
- /* Need to create 8 bytes random data */
- Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */
- RAND_bytes(random,8);
-
- /* 8 bytes random data as challenge in lmresp */
- memcpy(lmresp,random,8);
- /* Pad with zeros */
- memset(lmresp+8,0,0x10);
-
- /* Fill tmp with challenge(nonce?) + random */
- memcpy(tmp,&ntlm->nonce[0],8);
- memcpy(tmp+8,random,8);
-
- MD5_Init(&MD5);
- MD5_Update(&MD5, tmp, 16);
- MD5_Final(md5sum, &MD5);
- /* We shall only use the first 8 bytes of md5sum,
- but the des code in lm_resp only encrypt the first 8 bytes */
- mk_nt_hash(conn->data, passwdp, ntbuffer);
- lm_resp(ntbuffer, md5sum, ntresp);
-
- /* End of NTLM2 Session code */
- }
- else {
-#endif
-
-#if USE_NTRESPONSES
- unsigned char ntbuffer[0x18];
-#endif
- unsigned char lmbuffer[0x18];
-
-#if USE_NTRESPONSES
- mk_nt_hash(conn->data, passwdp, ntbuffer);
- lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
-#endif
-
- mk_lm_hash(conn->data, passwdp, lmbuffer);
- lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
- /* A safer but less compatible alternative is:
- * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
- * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
-#if USE_NTLM2SESSION
- }
-#endif
-
- lmrespoff = 64; /* size of the message header */
-#if USE_NTRESPONSES
- ntrespoff = lmrespoff + 0x18;
- domoff = ntrespoff + 0x18;
-#else
- domoff = lmrespoff + 0x18;
-#endif
- useroff = domoff + domlen;
- hostoff = useroff + userlen;
-
- /* Create the big type-3 message binary blob */
- size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf),
- NTLMSSP_SIGNATURE "%c"
- "\x03%c%c%c" /* type-3, 32 bits */
-
- "%c%c" /* LanManager length */
- "%c%c" /* LanManager allocated space */
- "%c%c" /* LanManager offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* NT-response length */
- "%c%c" /* NT-response allocated space */
- "%c%c" /* NT-response offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* domain length */
- "%c%c" /* domain allocated space */
- "%c%c" /* domain name offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* user length */
- "%c%c" /* user allocated space */
- "%c%c" /* user offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* host length */
- "%c%c" /* host allocated space */
- "%c%c" /* host offset */
- "%c%c" /* 2 zeroes */
-
- "%c%c" /* session key length (unknown purpose) */
- "%c%c" /* session key allocated space (unknown purpose) */
- "%c%c" /* session key offset (unknown purpose) */
- "%c%c" /* 2 zeroes */
-
- "%c%c%c%c" /* flags */
-
- /* domain string */
- /* user string */
- /* host string */
- /* LanManager response */
- /* NT response */
- ,
- 0, /* zero termination */
- 0,0,0, /* type-3 long, the 24 upper bits */
-
- SHORTPAIR(0x18), /* LanManager response length, twice */
- SHORTPAIR(0x18),
- SHORTPAIR(lmrespoff),
- 0x0, 0x0,
-
-#if USE_NTRESPONSES
- SHORTPAIR(0x18), /* NT-response length, twice */
- SHORTPAIR(0x18),
- SHORTPAIR(ntrespoff),
- 0x0, 0x0,
-#else
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
-#endif
- SHORTPAIR(domlen),
- SHORTPAIR(domlen),
- SHORTPAIR(domoff),
- 0x0, 0x0,
-
- SHORTPAIR(userlen),
- SHORTPAIR(userlen),
- SHORTPAIR(useroff),
- 0x0, 0x0,
-
- SHORTPAIR(hostlen),
- SHORTPAIR(hostlen),
- SHORTPAIR(hostoff),
- 0x0, 0x0,
-
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
- 0x0, 0x0,
-
- LONGQUARTET(ntlm->flags));
- DEBUG_OUT(assert(size==64));
-
- DEBUG_OUT(assert(size == lmrespoff));
- /* We append the binary hashes */
- if(size < (sizeof(ntlmbuf) - 0x18)) {
- memcpy(&ntlmbuf[size], lmresp, 0x18);
- size += 0x18;
- }
-
- DEBUG_OUT({
- fprintf(stderr, "**** TYPE3 header lmresp=");
- print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
- });
-
-#if USE_NTRESPONSES
- if(size < (sizeof(ntlmbuf) - 0x18)) {
- DEBUG_OUT(assert(size == ntrespoff));
- memcpy(&ntlmbuf[size], ntresp, 0x18);
- size += 0x18;
- }
-
- DEBUG_OUT({
- fprintf(stderr, "\n ntresp=");
- print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
- });
-
-#endif
-
- DEBUG_OUT({
- fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
- LONGQUARTET(ntlm->flags), ntlm->flags);
- print_flags(stderr, ntlm->flags);
- fprintf(stderr, "\n****\n");
- });
-
-
- /* Make sure that the domain, user and host strings fit in the target
- buffer before we copy them there. */
- if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) {
- failf(conn->data, "user + domain + host name too big");
- return CURLE_OUT_OF_MEMORY;
- }
-
- curlassert(size == domoff);
- memcpy(&ntlmbuf[size], domain, domlen);
- size += domlen;
-
- curlassert(size == useroff);
- memcpy(&ntlmbuf[size], user, userlen);
- size += userlen;
-
- curlassert(size == hostoff);
- memcpy(&ntlmbuf[size], host, hostlen);
- size += hostlen;
-
-#ifdef CURL_DOES_CONVERSIONS
- /* convert domain, user, and host to ASCII but leave the rest as-is */
- if(CURLE_OK != Curl_convert_to_network(conn->data,
- (char *)&ntlmbuf[domoff],
- size-domoff)) {
- return CURLE_CONV_FAILED;
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
-#endif
-
- /* convert the binary blob into base64 */
- size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64);
-
- if(size >0 ) {
- Curl_safefree(*allocuserpwd);
- *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
- proxy?"Proxy-":"",
- base64);
- DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
- free(base64);
- }
- else
- return CURLE_OUT_OF_MEMORY; /* FIX TODO */
-
- ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
- authp->done = TRUE;
- }
- break;
-
- case NTLMSTATE_TYPE3:
- /* connection is already authenticated,
- * don't send a header in future requests */
- if(*allocuserpwd) {
- free(*allocuserpwd);
- *allocuserpwd=NULL;
- }
- authp->done = TRUE;
- break;
- }
-
- return CURLE_OK;
-}
-
-
-void
-Curl_ntlm_cleanup(struct connectdata *conn)
-{
-#ifdef USE_WINDOWS_SSPI
- ntlm_sspi_cleanup(&conn->ntlm);
- ntlm_sspi_cleanup(&conn->proxyntlm);
- if (s_hSecDll != NULL) {
- FreeLibrary(s_hSecDll);
- s_hSecDll = NULL;
- s_pSecFn = NULL;
- }
-#else
- (void)conn;
-#endif
-}
-
-#endif /* USE_NTLM */
-#endif /* !CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/http_ntlm.h b/Utilities/cmcurl/http_ntlm.h
deleted file mode 100644
index a8de220a7..000000000
--- a/Utilities/cmcurl/http_ntlm.h
+++ /dev/null
@@ -1,146 +0,0 @@
-#ifndef __HTTP_NTLM_H
-#define __HTTP_NTLM_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-typedef enum {
- CURLNTLM_NONE, /* not a ntlm */
- CURLNTLM_BAD, /* an ntlm, but one we don't like */
- CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */
- CURLNTLM_FINE, /* an ntlm we act on */
-
- CURLNTLM_LAST /* last entry in this enum, don't use */
-} CURLntlm;
-
-/* this is for ntlm header input */
-CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, char *header);
-
-/* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
-
-void Curl_ntlm_cleanup(struct connectdata *conn);
-#ifndef USE_NTLM
-#define Curl_ntlm_cleanup(x)
-#endif
-
-
-/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
-
-#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
-/* Indicates that Unicode strings are supported for use in security buffer
- data. */
-
-#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
-/* Indicates that OEM strings are supported for use in security buffer data. */
-
-#define NTLMFLAG_REQUEST_TARGET (1<<2)
-/* Requests that the server's authentication realm be included in the Type 2
- message. */
-
-/* unknown (1<<3) */
-#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
-/* Specifies that authenticated communication between the client and server
- should carry a digital signature (message integrity). */
-
-#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
-/* Specifies that authenticated communication between the client and server
- should be encrypted (message confidentiality). */
-
-#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
-/* Indicates that the LAN Manager session key should be used for signing and
- sealing authenticated communications. */
-
-#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
-/* Indicates that NTLM authentication is being used. */
-
-/* unknown (1<<10) */
-/* unknown (1<<11) */
-
-#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
-/* Sent by the client in the Type 1 message to indicate that a desired
- authentication realm is included in the message. */
-
-#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
-/* Sent by the client in the Type 1 message to indicate that the client
- workstation's name is included in the message. */
-
-#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
-/* Sent by the server to indicate that the server and client are on the same
- machine. Implies that the client may use a pre-established local security
- context rather than responding to the challenge. */
-
-#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
-/* Indicates that authenticated communication between the client and server
- should be signed with a "dummy" signature. */
-
-#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a domain. */
-
-#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a server. */
-
-#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
-/* Sent by the server in the Type 2 message to indicate that the target
- authentication realm is a share. Presumably, this is for share-level
- authentication. Usage is unclear. */
-
-#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
-/* Indicates that the NTLM2 signing and sealing scheme should be used for
- protecting authenticated communications. */
-
-#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
-/* unknown purpose */
-
-#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
-/* Sent by the server in the Type 2 message to indicate that it is including a
- Target Information block in the message. */
-
-/* unknown (1<24) */
-/* unknown (1<25) */
-/* unknown (1<26) */
-/* unknown (1<27) */
-/* unknown (1<28) */
-
-#define NTLMFLAG_NEGOTIATE_128 (1<<29)
-/* Indicates that 128-bit encryption is supported. */
-
-#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
-/* unknown purpose */
-
-#define NTLMFLAG_NEGOTIATE_56 (1<<31)
-/* Indicates that 56-bit encryption is supported. */
-#endif
diff --git a/Utilities/cmcurl/if2ip.c b/Utilities/cmcurl/if2ip.c
deleted file mode 100644
index b4a98c662..000000000
--- a/Utilities/cmcurl/if2ip.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "if2ip.h"
-
-/*
- * This test can probably be simplified to #if defined(SIOCGIFADDR) and
- * moved after the following includes.
- */
-#if !defined(WIN32) && !defined(__BEOS__) && !defined(__CYGWIN__) && \
- !defined(__riscos__) && !defined(__INTERIX) && !defined(NETWARE) && \
- !defined(_AMIGASF) && !defined(__minix)
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-
-#ifdef HAVE_SYS_TIME_H
-/* This must be before net/if.h for AIX 3.2 to enjoy life */
-#include <sys/time.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKIO_H
-#include <sys/sockio.h>
-#endif
-
-#ifdef VMS
-#include <inet.h>
-#endif
-
-#include "inet_ntop.h"
-#include "memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define SYS_ERROR -1
-
-char *Curl_if2ip(const char *interface, char *buf, int buf_size)
-{
- int dummy;
- char *ip=NULL;
-
- if(!interface)
- return NULL;
-
- dummy = socket(AF_INET, SOCK_STREAM, 0);
- if (SYS_ERROR == dummy) {
- return NULL;
- }
- else {
- struct ifreq req;
- size_t len = strlen(interface);
- memset(&req, 0, sizeof(req));
- if(len >= sizeof(req.ifr_name))
- return NULL; /* this can't be a fine interface name */
- memcpy(req.ifr_name, interface, len+1);
- req.ifr_addr.sa_family = AF_INET;
-#ifdef IOCTL_3_ARGS
- if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req)) {
-#else
- if (SYS_ERROR == ioctl(dummy, SIOCGIFADDR, &req, sizeof(req))) {
-#endif
- sclose(dummy);
- return NULL;
- }
- else {
- struct in_addr in;
-
- struct sockaddr_in *s = (struct sockaddr_in *)&req.ifr_dstaddr;
- memcpy(&in, &s->sin_addr, sizeof(in));
- ip = (char *) Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
- }
- sclose(dummy);
- }
- return ip;
-}
-
-/* -- end of if2ip() -- */
-#else
-char *Curl_if2ip(const char *interf, char *buf, int buf_size)
-{
- (void) interf;
- (void) buf;
- (void) buf_size;
- return NULL;
-}
-#endif
diff --git a/Utilities/cmcurl/if2ip.h b/Utilities/cmcurl/if2ip.h
deleted file mode 100644
index 4e86e2b27..000000000
--- a/Utilities/cmcurl/if2ip.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef __IF2IP_H
-#define __IF2IP_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#include "setup.h"
-
-extern char *Curl_if2ip(const char *interf, char *buf, int buf_size);
-
-#ifdef __INTERIX
-#include <sys/socket.h>
-
-/* Nedelcho Stanev's work-around for SFU 3.0 */
-struct ifreq {
-#define IFNAMSIZ 16
-#define IFHWADDRLEN 6
- union {
- char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
- } ifr_ifrn;
-
- union {
- struct sockaddr ifru_addr;
- struct sockaddr ifru_broadaddr;
- struct sockaddr ifru_netmask;
- struct sockaddr ifru_hwaddr;
- short ifru_flags;
- int ifru_metric;
- int ifru_mtu;
- } ifr_ifru;
-};
-
-/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
- C code. */
-#define ifr_dstaddr ifr_addr
-
-#define ifr_name ifr_ifrn.ifrn_name /* interface name */
-#define ifr_addr ifr_ifru.ifru_addr /* address */
-#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
-#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
-#define ifr_flags ifr_ifru.ifru_flags /* flags */
-#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
-#define ifr_metric ifr_ifru.ifru_metric /* metric */
-#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
-
-#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
-#endif /* interix */
-
-#endif
diff --git a/Utilities/cmcurl/include/curl/curl.h b/Utilities/cmcurl/include/curl/curl.h
new file mode 100644
index 000000000..395521202
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/curl.h
@@ -0,0 +1,2555 @@
+#ifndef __CURL_CURL_H
+#define __CURL_CURL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * If you have libcurl problems, all docs and details are found here:
+ * https://curl.haxx.se/libcurl/
+ *
+ * curl-library mailing list subscription and unsubscription web interface:
+ * https://cool.haxx.se/mailman/listinfo/curl-library/
+ */
+
+#ifdef CURL_NO_OLDIES
+#define CURL_STRICTER
+#endif
+
+#include "curlver.h" /* libcurl version defines */
+#include "system.h" /* determine things run-time */
+#include "cmcurl/include/curl/curlbuild.h" /* libcurl build definitions */
+#include "curlrules.h" /* libcurl rules enforcement */
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && \
+ !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
+/* Needed for __FreeBSD_version symbol definition */
+#include <osreldate.h>
+#endif
+
+/* The include stuff here below is mainly for time_t! */
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
+ defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+ included, since they can't co-exist without problems */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+ libc5-based Linux systems. Only include it on systems that are known to
+ require it! */
+#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
+ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
+ defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
+ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+#include <sys/select.h>
+#endif
+
+#if !defined(WIN32) && !defined(_WIN32_WCE)
+#include <sys/socket.h>
+#endif
+
+#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#include <sys/time.h>
+#endif
+
+#if defined __BEOS__ || defined __HAIKU__
+#include <support/SupportDefs.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_easy CURL;
+typedef struct Curl_share CURLSH;
+#else
+typedef void CURL;
+typedef void CURLSH;
+#endif
+
+/*
+ * libcurl external API function linkage decorations.
+ */
+
+#ifdef CURL_STATICLIB
+# define CURL_EXTERN
+#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
+# if defined(BUILDING_LIBCURL)
+# define CURL_EXTERN __declspec(dllexport)
+# else
+# define CURL_EXTERN __declspec(dllimport)
+# endif
+#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
+# define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+# define CURL_EXTERN
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#if defined(WIN32) && !defined(__LWIP_OPT_H__) && !defined(LWIP_HDR_OPT_H)
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
+#endif
+#define curl_socket_typedef
+#endif /* curl_socket_typedef */
+
+struct curl_httppost {
+ struct curl_httppost *next; /* next entry in the list */
+ char *name; /* pointer to allocated name */
+ long namelength; /* length of name length */
+ char *contents; /* pointer to allocated data contents */
+ long contentslength; /* length of contents field, see also
+ CURL_HTTPPOST_LARGE */
+ char *buffer; /* pointer to allocated buffer contents */
+ long bufferlength; /* length of buffer field */
+ char *contenttype; /* Content-Type */
+ struct curl_slist *contentheader; /* list of extra headers for this form */
+ struct curl_httppost *more; /* if one field name has more than one
+ file, this link should link to following
+ files */
+ long flags; /* as defined below */
+
+/* specified content is a file name */
+#define CURL_HTTPPOST_FILENAME (1<<0)
+/* specified content is a file name */
+#define CURL_HTTPPOST_READFILE (1<<1)
+/* name is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRNAME (1<<2)
+/* contents is only stored pointer do not free in formfree */
+#define CURL_HTTPPOST_PTRCONTENTS (1<<3)
+/* upload file from buffer */
+#define CURL_HTTPPOST_BUFFER (1<<4)
+/* upload file from pointer contents */
+#define CURL_HTTPPOST_PTRBUFFER (1<<5)
+/* upload file contents by using the regular read callback to get the data and
+ pass the given pointer as custom pointer */
+#define CURL_HTTPPOST_CALLBACK (1<<6)
+/* use size in 'contentlen', added in 7.46.0 */
+#define CURL_HTTPPOST_LARGE (1<<7)
+
+ char *showfilename; /* The file name to show. If not set, the
+ actual file name will be used (if this
+ is a file part) */
+ void *userp; /* custom pointer used for
+ HTTPPOST_CALLBACK posts */
+ curl_off_t contentlen; /* alternative length of contents
+ field. Used if CURL_HTTPPOST_LARGE is
+ set. Added in 7.46.0 */
+};
+
+/* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered
+ deprecated but was the only choice up until 7.31.0 */
+typedef int (*curl_progress_callback)(void *clientp,
+ double dltotal,
+ double dlnow,
+ double ultotal,
+ double ulnow);
+
+/* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in
+ 7.32.0, it avoids floating point and provides more detailed information. */
+typedef int (*curl_xferinfo_callback)(void *clientp,
+ curl_off_t dltotal,
+ curl_off_t dlnow,
+ curl_off_t ultotal,
+ curl_off_t ulnow);
+
+#ifndef CURL_MAX_READ_SIZE
+ /* The maximum receive buffer size configurable via CURLOPT_BUFFERSIZE. */
+#define CURL_MAX_READ_SIZE 524288
+#endif
+
+#ifndef CURL_MAX_WRITE_SIZE
+ /* Tests have proven that 20K is a very bad buffer size for uploads on
+ Windows, while 16K for some odd reason performed a lot better.
+ We do the ifndef check to allow this value to easier be changed at build
+ time for those who feel adventurous. The practical minimum is about
+ 400 bytes since libcurl uses a buffer of this size as a scratch area
+ (unrelated to network send operations). */
+#define CURL_MAX_WRITE_SIZE 16384
+#endif
+
+#ifndef CURL_MAX_HTTP_HEADER
+/* The only reason to have a max limit for this is to avoid the risk of a bad
+ server feeding libcurl with a never-ending header that will cause reallocs
+ infinitely */
+#define CURL_MAX_HTTP_HEADER (100*1024)
+#endif
+
+/* This is a magic return code for the write callback that, when returned,
+ will signal libcurl to pause receiving on the current transfer. */
+#define CURL_WRITEFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_write_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *outstream);
+
+
+
+/* enumeration of file types */
+typedef enum {
+ CURLFILETYPE_FILE = 0,
+ CURLFILETYPE_DIRECTORY,
+ CURLFILETYPE_SYMLINK,
+ CURLFILETYPE_DEVICE_BLOCK,
+ CURLFILETYPE_DEVICE_CHAR,
+ CURLFILETYPE_NAMEDPIPE,
+ CURLFILETYPE_SOCKET,
+ CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */
+
+ CURLFILETYPE_UNKNOWN /* should never occur */
+} curlfiletype;
+
+#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0)
+#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1)
+#define CURLFINFOFLAG_KNOWN_TIME (1<<2)
+#define CURLFINFOFLAG_KNOWN_PERM (1<<3)
+#define CURLFINFOFLAG_KNOWN_UID (1<<4)
+#define CURLFINFOFLAG_KNOWN_GID (1<<5)
+#define CURLFINFOFLAG_KNOWN_SIZE (1<<6)
+#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7)
+
+/* Content of this structure depends on information which is known and is
+ achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man
+ page for callbacks returning this structure -- some fields are mandatory,
+ some others are optional. The FLAG field has special meaning. */
+struct curl_fileinfo {
+ char *filename;
+ curlfiletype filetype;
+ time_t time;
+ unsigned int perm;
+ int uid;
+ int gid;
+ curl_off_t size;
+ long int hardlinks;
+
+ struct {
+ /* If some of these fields is not NULL, it is a pointer to b_data. */
+ char *time;
+ char *perm;
+ char *user;
+ char *group;
+ char *target; /* pointer to the target filename of a symlink */
+ } strings;
+
+ unsigned int flags;
+
+ /* used internally */
+ char *b_data;
+ size_t b_size;
+ size_t b_used;
+};
+
+/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */
+#define CURL_CHUNK_BGN_FUNC_OK 0
+#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */
+#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */
+
+/* if splitting of data transfer is enabled, this callback is called before
+ download of an individual chunk started. Note that parameter "remains" works
+ only for FTP wildcard downloading (for now), otherwise is not used */
+typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
+ void *ptr,
+ int remains);
+
+/* return codes for CURLOPT_CHUNK_END_FUNCTION */
+#define CURL_CHUNK_END_FUNC_OK 0
+#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */
+
+/* If splitting of data transfer is enabled this callback is called after
+ download of an individual chunk finished.
+ Note! After this callback was set then it have to be called FOR ALL chunks.
+ Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
+ This is the reason why we don't need "transfer_info" parameter in this
+ callback and we are not interested in "remains" parameter too. */
+typedef long (*curl_chunk_end_callback)(void *ptr);
+
+/* return codes for FNMATCHFUNCTION */
+#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */
+#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */
+#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */
+
+/* callback type for wildcard downloading pattern matching. If the
+ string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
+typedef int (*curl_fnmatch_callback)(void *ptr,
+ const char *pattern,
+ const char *string);
+
+/* These are the return codes for the seek callbacks */
+#define CURL_SEEKFUNC_OK 0
+#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+ libcurl might try other means instead */
+typedef int (*curl_seek_callback)(void *instream,
+ curl_off_t offset,
+ int origin); /* 'whence' */
+
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to pause sending data on the current transfer. */
+#define CURL_READFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_read_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *instream);
+
+typedef enum {
+ CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
+ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
+ CURLSOCKTYPE_LAST /* never use */
+} curlsocktype;
+
+/* The return code from the sockopt_callback can signal information back
+ to libcurl: */
+#define CURL_SOCKOPT_OK 0
+#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return
+ CURLE_ABORTED_BY_CALLBACK */
+#define CURL_SOCKOPT_ALREADY_CONNECTED 2
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+ curl_socket_t curlfd,
+ curlsocktype purpose);
+
+struct curl_sockaddr {
+ int family;
+ int socktype;
+ int protocol;
+ unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
+ turned really ugly and painful on the systems that
+ lack this type */
+ struct sockaddr addr;
+};
+
+typedef curl_socket_t
+(*curl_opensocket_callback)(void *clientp,
+ curlsocktype purpose,
+ struct curl_sockaddr *address);
+
+typedef int
+(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
+
+typedef enum {
+ CURLIOE_OK, /* I/O operation successful */
+ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
+ CURLIOE_FAILRESTART, /* failed to restart the read */
+ CURLIOE_LAST /* never use */
+} curlioerr;
+
+typedef enum {
+ CURLIOCMD_NOP, /* no operation */
+ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+ CURLIOCMD_LAST /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+ int cmd,
+ void *clientp);
+
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively. Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
+/* the kind of data that is passed to information_callback*/
+typedef enum {
+ CURLINFO_TEXT = 0,
+ CURLINFO_HEADER_IN, /* 1 */
+ CURLINFO_HEADER_OUT, /* 2 */
+ CURLINFO_DATA_IN, /* 3 */
+ CURLINFO_DATA_OUT, /* 4 */
+ CURLINFO_SSL_DATA_IN, /* 5 */
+ CURLINFO_SSL_DATA_OUT, /* 6 */
+ CURLINFO_END
+} curl_infotype;
+
+typedef int (*curl_debug_callback)
+ (CURL *handle, /* the handle/transfer this concerns */
+ curl_infotype type, /* what kind of data */
+ char *data, /* points to the data */
+ size_t size, /* size of the data pointed to */
+ void *userptr); /* whatever the user please */
+
+/* All possible error codes from all sorts of curl functions. Future versions
+ may return other values, stay prepared.
+
+ Always add new return codes last. Never *EVER* remove any. The return
+ codes must remain the same!
+ */
+
+typedef enum {
+ CURLE_OK = 0,
+ CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
+ CURLE_FAILED_INIT, /* 2 */
+ CURLE_URL_MALFORMAT, /* 3 */
+ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for
+ 7.17.0, reused in April 2011 for 7.21.5] */
+ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
+ CURLE_COULDNT_RESOLVE_HOST, /* 6 */
+ CURLE_COULDNT_CONNECT, /* 7 */
+ CURLE_WEIRD_SERVER_REPLY, /* 8 */
+ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server
+ due to lack of access - when login fails
+ this is not returned. */
+ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for
+ 7.15.4, reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
+ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server
+ [was obsoleted in August 2007 for 7.17.0,
+ reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
+ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
+ CURLE_FTP_CANT_GET_HOST, /* 15 */
+ CURLE_HTTP2, /* 16 - A problem in the http2 framing layer.
+ [was obsoleted in August 2007 for 7.17.0,
+ reused in July 2014 for 7.38.0] */
+ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */
+ CURLE_PARTIAL_FILE, /* 18 */
+ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
+ CURLE_OBSOLETE20, /* 20 - NOT USED */
+ CURLE_QUOTE_ERROR, /* 21 - quote command failure */
+ CURLE_HTTP_RETURNED_ERROR, /* 22 */
+ CURLE_WRITE_ERROR, /* 23 */
+ CURLE_OBSOLETE24, /* 24 - NOT USED */
+ CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */
+ CURLE_READ_ERROR, /* 26 - couldn't open/read from file */
+ CURLE_OUT_OF_MEMORY, /* 27 */
+ /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
+ instead of a memory allocation error if CURL_DOES_CONVERSIONS
+ is defined
+ */
+ CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */
+ CURLE_OBSOLETE29, /* 29 - NOT USED */
+ CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
+ CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
+ CURLE_OBSOLETE32, /* 32 - NOT USED */
+ CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
+ CURLE_HTTP_POST_ERROR, /* 34 */
+ CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
+ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
+ CURLE_FILE_COULDNT_READ_FILE, /* 37 */
+ CURLE_LDAP_CANNOT_BIND, /* 38 */
+ CURLE_LDAP_SEARCH_FAILED, /* 39 */
+ CURLE_OBSOLETE40, /* 40 - NOT USED */
+ CURLE_FUNCTION_NOT_FOUND, /* 41 - NOT USED starting with 7.53.0 */
+ CURLE_ABORTED_BY_CALLBACK, /* 42 */
+ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
+ CURLE_OBSOLETE44, /* 44 - NOT USED */
+ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */
+ CURLE_OBSOLETE46, /* 46 - NOT USED */
+ CURLE_TOO_MANY_REDIRECTS, /* 47 - catch endless re-direct loops */
+ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */
+ CURLE_TELNET_OPTION_SYNTAX, /* 49 - Malformed telnet option */
+ CURLE_OBSOLETE50, /* 50 - NOT USED */
+ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
+ wasn't verified fine */
+ CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
+ CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
+ CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as
+ default */
+ CURLE_SEND_ERROR, /* 55 - failed sending network data */
+ CURLE_RECV_ERROR, /* 56 - failure in receiving network data */
+ CURLE_OBSOLETE57, /* 57 - NOT IN USE */
+ CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
+ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
+ CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
+ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */
+ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
+ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
+ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
+ CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
+ that failed */
+ CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
+ CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
+ accepted and we failed to login */
+ CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */
+ CURLE_TFTP_PERM, /* 69 - permission problem on server */
+ CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */
+ CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */
+ CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */
+ CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */
+ CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */
+ CURLE_CONV_FAILED, /* 75 - conversion failed */
+ CURLE_CONV_REQD, /* 76 - caller must register conversion
+ callbacks using curl_easy_setopt options
+ CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+ CURLOPT_CONV_TO_NETWORK_FUNCTION, and
+ CURLOPT_CONV_FROM_UTF8_FUNCTION */
+ CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing
+ or wrong format */
+ CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */
+ CURLE_SSH, /* 79 - error from the SSH layer, somewhat
+ generic so the error message will be of
+ interest when this has happened */
+
+ CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
+ connection */
+ CURLE_AGAIN, /* 81 - socket is not ready for send/recv,
+ wait till it's ready and try again (Added
+ in 7.18.2) */
+ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
+ wrong format (Added in 7.19.0) */
+ CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
+ 7.19.0) */
+ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */
+ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */
+ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */
+ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */
+ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
+ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
+ session will be queued */
+ CURLE_SSL_PINNEDPUBKEYNOTMATCH, /* 90 - specified pinned public key did not
+ match */
+ CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */
+ CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer
+ */
+ CURL_LAST /* never use! */
+} CURLcode;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Previously obsolete error code re-used in 7.38.0 */
+#define CURLE_OBSOLETE16 CURLE_HTTP2
+
+/* Previously obsolete error codes re-used in 7.24.0 */
+#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
+#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
+
+/* compatibility with older names */
+#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
+#define CURLE_FTP_WEIRD_SERVER_REPLY CURLE_WEIRD_SERVER_REPLY
+
+/* The following were added in 7.21.5, April 2011 */
+#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
+
+/* The following were added in 7.17.1 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.17.0 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */
+#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
+#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
+#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
+#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
+#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
+#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
+#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
+#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
+#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
+#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
+#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
+#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN
+
+#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
+#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
+#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
+#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
+#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
+#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
+#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
+
+/* The following were added earlier */
+
+#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
+
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
+
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+
+/* This was the error code 50 in 7.7.3 and a few earlier versions, this
+ is no longer used by libcurl but is instead #defined here only to not
+ make programs break */
+#define CURLE_ALREADY_COMPLETE 99999
+
+/* Provide defines for really old option names */
+#define CURLOPT_FILE CURLOPT_WRITEDATA /* name changed in 7.9.7 */
+#define CURLOPT_INFILE CURLOPT_READDATA /* name changed in 7.9.7 */
+#define CURLOPT_WRITEHEADER CURLOPT_HEADERDATA
+
+/* Since long deprecated options with no code in the lib that does anything
+ with them. */
+#define CURLOPT_WRITEINFO CURLOPT_OBSOLETE40
+#define CURLOPT_CLOSEPOLICY CURLOPT_OBSOLETE72
+
+#endif /*!CURL_NO_OLDIES*/
+
+/* This prototype applies to all conversion callbacks */
+typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
+ void *ssl_ctx, /* actually an
+ OpenSSL SSL_CTX */
+ void *userptr);
+
+typedef enum {
+ CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use
+ CONNECT HTTP/1.1 */
+ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT
+ HTTP/1.0 */
+ CURLPROXY_HTTPS = 2, /* added in 7.52.0 */
+ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
+ in 7.10 */
+ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
+ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
+ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+ host name rather than the IP address. added
+ in 7.18.0 */
+} curl_proxytype; /* this enum was added in 7.10 */
+
+/*
+ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
+ *
+ * CURLAUTH_NONE - No HTTP authentication
+ * CURLAUTH_BASIC - HTTP Basic authentication (default)
+ * CURLAUTH_DIGEST - HTTP Digest authentication
+ * CURLAUTH_NEGOTIATE - HTTP Negotiate (SPNEGO) authentication
+ * CURLAUTH_GSSNEGOTIATE - Alias for CURLAUTH_NEGOTIATE (deprecated)
+ * CURLAUTH_NTLM - HTTP NTLM authentication
+ * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
+ * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_ONLY - Use together with a single other type to force no
+ * authentication or just that single type
+ * CURLAUTH_ANY - All fine types set
+ * CURLAUTH_ANYSAFE - All fine types except Basic
+ */
+
+#define CURLAUTH_NONE ((unsigned long)0)
+#define CURLAUTH_BASIC (((unsigned long)1)<<0)
+#define CURLAUTH_DIGEST (((unsigned long)1)<<1)
+#define CURLAUTH_NEGOTIATE (((unsigned long)1)<<2)
+/* Deprecated since the advent of CURLAUTH_NEGOTIATE */
+#define CURLAUTH_GSSNEGOTIATE CURLAUTH_NEGOTIATE
+#define CURLAUTH_NTLM (((unsigned long)1)<<3)
+#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
+#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
+#define CURLAUTH_ONLY (((unsigned long)1)<<31)
+#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)
+#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+
+#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */
+#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */
+#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
+#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
+#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
+#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */
+#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
+
+#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */
+#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
+#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */
+
+#define CURL_ERROR_SIZE 256
+
+enum curl_khtype {
+ CURLKHTYPE_UNKNOWN,
+ CURLKHTYPE_RSA1,
+ CURLKHTYPE_RSA,
+ CURLKHTYPE_DSS
+};
+
+struct curl_khkey {
+ const char *key; /* points to a zero-terminated string encoded with base64
+ if len is zero, otherwise to the "raw" data */
+ size_t len;
+ enum curl_khtype keytype;
+};
+
+/* this is the set of return values expected from the curl_sshkeycallback
+ callback */
+enum curl_khstat {
+ CURLKHSTAT_FINE_ADD_TO_FILE,
+ CURLKHSTAT_FINE,
+ CURLKHSTAT_REJECT, /* reject the connection, return an error */
+ CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so
+ this causes a CURLE_DEFER error but otherwise the
+ connection will be left intact etc */
+ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */
+};
+
+/* this is the set of status codes pass in to the callback */
+enum curl_khmatch {
+ CURLKHMATCH_OK, /* match */
+ CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
+ CURLKHMATCH_MISSING, /* no matching host/key found */
+ CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */
+};
+
+typedef int
+ (*curl_sshkeycallback) (CURL *easy, /* easy handle */
+ const struct curl_khkey *knownkey, /* known */
+ const struct curl_khkey *foundkey, /* found */
+ enum curl_khmatch, /* libcurl's view on the keys */
+ void *clientp); /* custom pointer passed from app */
+
+/* parameter for the CURLOPT_USE_SSL option */
+typedef enum {
+ CURLUSESSL_NONE, /* do not attempt to use SSL */
+ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */
+ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
+ CURLUSESSL_ALL, /* SSL for all communication or fail */
+ CURLUSESSL_LAST /* not an option, never use */
+} curl_usessl;
+
+/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
+
+/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
+ name of improving interoperability with older servers. Some SSL libraries
+ have introduced work-arounds for this flaw but those work-arounds sometimes
+ make the SSL communication fail. To regain functionality with those broken
+ servers, a user can this way allow the vulnerability back. */
+#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+
+/* - NO_REVOKE tells libcurl to disable certificate revocation checks for those
+ SSL backends where such behavior is present. */
+#define CURLSSLOPT_NO_REVOKE (1<<1)
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2009 */
+
+#define CURLFTPSSL_NONE CURLUSESSL_NONE
+#define CURLFTPSSL_TRY CURLUSESSL_TRY
+#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
+#define CURLFTPSSL_ALL CURLUSESSL_ALL
+#define CURLFTPSSL_LAST CURLUSESSL_LAST
+#define curl_ftpssl curl_usessl
+#endif /*!CURL_NO_OLDIES*/
+
+/* parameter for the CURLOPT_FTP_SSL_CCC option */
+typedef enum {
+ CURLFTPSSL_CCC_NONE, /* do not send CCC */
+ CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
+ CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */
+ CURLFTPSSL_CCC_LAST /* not an option, never use */
+} curl_ftpccc;
+
+/* parameter for the CURLOPT_FTPSSLAUTH option */
+typedef enum {
+ CURLFTPAUTH_DEFAULT, /* let libcurl decide */
+ CURLFTPAUTH_SSL, /* use "AUTH SSL" */
+ CURLFTPAUTH_TLS, /* use "AUTH TLS" */
+ CURLFTPAUTH_LAST /* not an option, never use */
+} curl_ftpauth;
+
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+ CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */
+ CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+ again if MKD succeeded, for SFTP this does
+ similar magic */
+ CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+ again even if MKD failed! */
+ CURLFTP_CREATE_DIR_LAST /* not an option, never use */
+} curl_ftpcreatedir;
+
+/* parameter for the CURLOPT_FTP_FILEMETHOD option */
+typedef enum {
+ CURLFTPMETHOD_DEFAULT, /* let libcurl pick */
+ CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */
+ CURLFTPMETHOD_NOCWD, /* no CWD at all */
+ CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
+ CURLFTPMETHOD_LAST /* not an option, never use */
+} curl_ftpmethod;
+
+/* bitmask defines for CURLOPT_HEADEROPT */
+#define CURLHEADER_UNIFIED 0
+#define CURLHEADER_SEPARATE (1<<0)
+
+/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+#define CURLPROTO_HTTP (1<<0)
+#define CURLPROTO_HTTPS (1<<1)
+#define CURLPROTO_FTP (1<<2)
+#define CURLPROTO_FTPS (1<<3)
+#define CURLPROTO_SCP (1<<4)
+#define CURLPROTO_SFTP (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP (1<<7)
+#define CURLPROTO_LDAPS (1<<8)
+#define CURLPROTO_DICT (1<<9)
+#define CURLPROTO_FILE (1<<10)
+#define CURLPROTO_TFTP (1<<11)
+#define CURLPROTO_IMAP (1<<12)
+#define CURLPROTO_IMAPS (1<<13)
+#define CURLPROTO_POP3 (1<<14)
+#define CURLPROTO_POP3S (1<<15)
+#define CURLPROTO_SMTP (1<<16)
+#define CURLPROTO_SMTPS (1<<17)
+#define CURLPROTO_RTSP (1<<18)
+#define CURLPROTO_RTMP (1<<19)
+#define CURLPROTO_RTMPT (1<<20)
+#define CURLPROTO_RTMPE (1<<21)
+#define CURLPROTO_RTMPTE (1<<22)
+#define CURLPROTO_RTMPS (1<<23)
+#define CURLPROTO_RTMPTS (1<<24)
+#define CURLPROTO_GOPHER (1<<25)
+#define CURLPROTO_SMB (1<<26)
+#define CURLPROTO_SMBS (1<<27)
+#define CURLPROTO_ALL (~0) /* enable everything */
+
+/* long may be 32 or 64 bits, but we should never depend on anything else
+ but 32 */
+#define CURLOPTTYPE_LONG 0
+#define CURLOPTTYPE_OBJECTPOINT 10000
+#define CURLOPTTYPE_STRINGPOINT 10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T 30000
+
+/* *STRINGPOINT is an alias for OBJECTPOINT to allow tools to extract the
+ string options from the header file */
+
+/* name is uppercase CURLOPT_<name>,
+ type is one of the defined CURLOPTTYPE_<type>
+ number is unique identifier */
+#ifdef CINIT
+#undef CINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define STRINGPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLOPT_/**/name = type + number
+#endif
+
+/*
+ * This macro-mania below setups the CURLOPT_[what] enum, to be used with
+ * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
+ * word.
+ */
+
+typedef enum {
+ /* This is the FILE * or void * the regular output should be written to. */
+ CINIT(WRITEDATA, OBJECTPOINT, 1),
+
+ /* The full URL to get/put */
+ CINIT(URL, STRINGPOINT, 2),
+
+ /* Port number to connect to, if other than default. */
+ CINIT(PORT, LONG, 3),
+
+ /* Name of proxy to use. */
+ CINIT(PROXY, STRINGPOINT, 4),
+
+ /* "user:password;options" to use when fetching. */
+ CINIT(USERPWD, STRINGPOINT, 5),
+
+ /* "user:password" to use with proxy. */
+ CINIT(PROXYUSERPWD, STRINGPOINT, 6),
+
+ /* Range to get, specified as an ASCII string. */
+ CINIT(RANGE, STRINGPOINT, 7),
+
+ /* not used */
+
+ /* Specified file stream to upload from (use as input): */
+ CINIT(READDATA, OBJECTPOINT, 9),
+
+ /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
+ * bytes big. If this is not used, error messages go to stderr instead: */
+ CINIT(ERRORBUFFER, OBJECTPOINT, 10),
+
+ /* Function that will be called to store the output (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
+
+ /* Function that will be called to read the input (instead of fread). The
+ * parameters will use fread() syntax, make sure to follow them. */
+ CINIT(READFUNCTION, FUNCTIONPOINT, 12),
+
+ /* Time-out the read operation after this amount of seconds */
+ CINIT(TIMEOUT, LONG, 13),
+
+ /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+ * how large the file being sent really is. That allows better error
+ * checking and better verifies that the upload was successful. -1 means
+ * unknown size.
+ *
+ * For large file support, there is also a _LARGE version of the key
+ * which takes an off_t type, allowing platforms with larger off_t
+ * sizes to handle larger files. See below for INFILESIZE_LARGE.
+ */
+ CINIT(INFILESIZE, LONG, 14),
+
+ /* POST static input fields. */
+ CINIT(POSTFIELDS, OBJECTPOINT, 15),
+
+ /* Set the referrer page (needed by some CGIs) */
+ CINIT(REFERER, STRINGPOINT, 16),
+
+ /* Set the FTP PORT string (interface name, named or numerical IP address)
+ Use i.e '-' to use default address. */
+ CINIT(FTPPORT, STRINGPOINT, 17),
+
+ /* Set the User-Agent string (examined by some CGIs) */
+ CINIT(USERAGENT, STRINGPOINT, 18),
+
+ /* If the download receives less than "low speed limit" bytes/second
+ * during "low speed time" seconds, the operations is aborted.
+ * You could i.e if you have a pretty high speed connection, abort if
+ * it is less than 2000 bytes/sec during 20 seconds.
+ */
+
+ /* Set the "low speed limit" */
+ CINIT(LOW_SPEED_LIMIT, LONG, 19),
+
+ /* Set the "low speed time" */
+ CINIT(LOW_SPEED_TIME, LONG, 20),
+
+ /* Set the continuation offset.
+ *
+ * Note there is also a _LARGE version of this key which uses
+ * off_t types, allowing for large file offsets on platforms which
+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
+ */
+ CINIT(RESUME_FROM, LONG, 21),
+
+ /* Set cookie in request: */
+ CINIT(COOKIE, STRINGPOINT, 22),
+
+ /* This points to a linked list of headers, struct curl_slist kind. This
+ list is also used for RTSP (in spite of its name) */
+ CINIT(HTTPHEADER, OBJECTPOINT, 23),
+
+ /* This points to a linked list of post entries, struct curl_httppost */
+ CINIT(HTTPPOST, OBJECTPOINT, 24),
+
+ /* name of the file keeping your private SSL-certificate */
+ CINIT(SSLCERT, STRINGPOINT, 25),
+
+ /* password for the SSL or SSH private key */
+ CINIT(KEYPASSWD, STRINGPOINT, 26),
+
+ /* send TYPE parameter? */
+ CINIT(CRLF, LONG, 27),
+
+ /* send linked-list of QUOTE commands */
+ CINIT(QUOTE, OBJECTPOINT, 28),
+
+ /* send FILE * or void * to store headers to, if you use a callback it
+ is simply passed to the callback unmodified */
+ CINIT(HEADERDATA, OBJECTPOINT, 29),
+
+ /* point to a file to read the initial cookies from, also enables
+ "cookie awareness" */
+ CINIT(COOKIEFILE, STRINGPOINT, 31),
+
+ /* What version to specifically try to use.
+ See CURL_SSLVERSION defines below. */
+ CINIT(SSLVERSION, LONG, 32),
+
+ /* What kind of HTTP time condition to use, see defines */
+ CINIT(TIMECONDITION, LONG, 33),
+
+ /* Time to use with the above condition. Specified in number of seconds
+ since 1 Jan 1970 */
+ CINIT(TIMEVALUE, LONG, 34),
+
+ /* 35 = OBSOLETE */
+
+ /* Custom request, for customizing the get command like
+ HTTP: DELETE, TRACE and others
+ FTP: to use a different list command
+ */
+ CINIT(CUSTOMREQUEST, STRINGPOINT, 36),
+
+ /* FILE handle to use instead of stderr */
+ CINIT(STDERR, OBJECTPOINT, 37),
+
+ /* 38 is not used */
+
+ /* send linked-list of post-transfer QUOTE commands */
+ CINIT(POSTQUOTE, OBJECTPOINT, 39),
+
+ CINIT(OBSOLETE40, OBJECTPOINT, 40), /* OBSOLETE, do not use! */
+
+ CINIT(VERBOSE, LONG, 41), /* talk a lot */
+ CINIT(HEADER, LONG, 42), /* throw the header out too */
+ CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
+ CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
+ CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 400 */
+ CINIT(UPLOAD, LONG, 46), /* this is an upload */
+ CINIT(POST, LONG, 47), /* HTTP POST method */
+ CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */
+
+ CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */
+
+ /* Specify whether to read the user+password from the .netrc or the URL.
+ * This must be one of the CURL_NETRC_* enums below. */
+ CINIT(NETRC, LONG, 51),
+
+ CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */
+
+ CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
+ CINIT(PUT, LONG, 54), /* HTTP PUT */
+
+ /* 55 = OBSOLETE */
+
+ /* DEPRECATED
+ * Function that will be called instead of the internal progress display
+ * function. This function should be defined as the curl_progress_callback
+ * prototype defines. */
+ CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56),
+
+ /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION
+ callbacks */
+ CINIT(PROGRESSDATA, OBJECTPOINT, 57),
+#define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA
+
+ /* We want the referrer field set automatically when following locations */
+ CINIT(AUTOREFERER, LONG, 58),
+
+ /* Port of the proxy, can be set in the proxy string as well with:
+ "[host]:[port]" */
+ CINIT(PROXYPORT, LONG, 59),
+
+ /* size of the POST input data, if strlen() is not good to use */
+ CINIT(POSTFIELDSIZE, LONG, 60),
+
+ /* tunnel non-http operations through a HTTP proxy */
+ CINIT(HTTPPROXYTUNNEL, LONG, 61),
+
+ /* Set the interface string to use as outgoing network interface */
+ CINIT(INTERFACE, STRINGPOINT, 62),
+
+ /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
+ * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
+ * is set but doesn't match one of these, 'private' will be used. */
+ CINIT(KRBLEVEL, STRINGPOINT, 63),
+
+ /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
+ CINIT(SSL_VERIFYPEER, LONG, 64),
+
+ /* The CApath or CAfile used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAINFO, STRINGPOINT, 65),
+
+ /* 66 = OBSOLETE */
+ /* 67 = OBSOLETE */
+
+ /* Maximum number of http redirects to follow */
+ CINIT(MAXREDIRS, LONG, 68),
+
+ /* Pass a long set to 1 to get the date of the requested document (if
+ possible)! Pass a zero to shut it off. */
+ CINIT(FILETIME, LONG, 69),
+
+ /* This points to a linked list of telnet options */
+ CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+
+ /* Max amount of cached alive connections */
+ CINIT(MAXCONNECTS, LONG, 71),
+
+ CINIT(OBSOLETE72, LONG, 72), /* OBSOLETE, do not use! */
+
+ /* 73 = OBSOLETE */
+
+ /* Set to explicitly use a new connection for the upcoming transfer.
+ Do not use this unless you're absolutely sure of this, as it makes the
+ operation slower and is less friendly for the network. */
+ CINIT(FRESH_CONNECT, LONG, 74),
+
+ /* Set to explicitly forbid the upcoming transfer's connection to be re-used
+ when done. Do not use this unless you're absolutely sure of this, as it
+ makes the operation slower and is less friendly for the network. */
+ CINIT(FORBID_REUSE, LONG, 75),
+
+ /* Set to a file name that contains random data for libcurl to use to
+ seed the random engine when doing SSL connects. */
+ CINIT(RANDOM_FILE, STRINGPOINT, 76),
+
+ /* Set to the Entropy Gathering Daemon socket pathname */
+ CINIT(EGDSOCKET, STRINGPOINT, 77),
+
+ /* Time-out connect operations after this amount of seconds, if connects are
+ OK within this time, then fine... This only aborts the connect phase. */
+ CINIT(CONNECTTIMEOUT, LONG, 78),
+
+ /* Function that will be called to store headers (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
+
+ /* Set this to force the HTTP request to get back to GET. Only really usable
+ if POST, PUT or a custom request have been used first.
+ */
+ CINIT(HTTPGET, LONG, 80),
+
+ /* Set if we should verify the Common name from the peer certificate in ssl
+ * handshake, set 1 to check existence, 2 to ensure that it matches the
+ * provided hostname. */
+ CINIT(SSL_VERIFYHOST, LONG, 81),
+
+ /* Specify which file name to write all known cookies in after completed
+ operation. Set file name to "-" (dash) to make it go to stdout. */
+ CINIT(COOKIEJAR, STRINGPOINT, 82),
+
+ /* Specify which SSL ciphers to use */
+ CINIT(SSL_CIPHER_LIST, STRINGPOINT, 83),
+
+ /* Specify which HTTP version to use! This must be set to one of the
+ CURL_HTTP_VERSION* enums set below. */
+ CINIT(HTTP_VERSION, LONG, 84),
+
+ /* Specifically switch on or off the FTP engine's use of the EPSV command. By
+ default, that one will always be attempted before the more traditional
+ PASV command. */
+ CINIT(FTP_USE_EPSV, LONG, 85),
+
+ /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
+ CINIT(SSLCERTTYPE, STRINGPOINT, 86),
+
+ /* name of the file keeping your private SSL-key */
+ CINIT(SSLKEY, STRINGPOINT, 87),
+
+ /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
+ CINIT(SSLKEYTYPE, STRINGPOINT, 88),
+
+ /* crypto engine for the SSL-sub system */
+ CINIT(SSLENGINE, STRINGPOINT, 89),
+
+ /* set the crypto engine for the SSL-sub system as default
+ the param has no meaning...
+ */
+ CINIT(SSLENGINE_DEFAULT, LONG, 90),
+
+ /* Non-zero value means to use the global dns cache */
+ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */
+
+ /* DNS cache timeout */
+ CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
+
+ /* send linked-list of pre-transfer QUOTE commands */
+ CINIT(PREQUOTE, OBJECTPOINT, 93),
+
+ /* set the debug function */
+ CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
+
+ /* set the data for the debug function */
+ CINIT(DEBUGDATA, OBJECTPOINT, 95),
+
+ /* mark this as start of a cookie session */
+ CINIT(COOKIESESSION, LONG, 96),
+
+ /* The CApath directory used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAPATH, STRINGPOINT, 97),
+
+ /* Instruct libcurl to use a smaller receive buffer */
+ CINIT(BUFFERSIZE, LONG, 98),
+
+ /* Instruct libcurl to not use any signal/alarm handlers, even when using
+ timeouts. This option is useful for multi-threaded applications.
+ See libcurl-the-guide for more background information. */
+ CINIT(NOSIGNAL, LONG, 99),
+
+ /* Provide a CURLShare for mutexing non-ts data */
+ CINIT(SHARE, OBJECTPOINT, 100),
+
+ /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
+ CURLPROXY_HTTPS, CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and
+ CURLPROXY_SOCKS5. */
+ CINIT(PROXYTYPE, LONG, 101),
+
+ /* Set the Accept-Encoding string. Use this to tell a server you would like
+ the response to be compressed. Before 7.21.6, this was known as
+ CURLOPT_ENCODING */
+ CINIT(ACCEPT_ENCODING, STRINGPOINT, 102),
+
+ /* Set pointer to private data */
+ CINIT(PRIVATE, OBJECTPOINT, 103),
+
+ /* Set aliases for HTTP 200 in the HTTP Response header */
+ CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+
+ /* Continue to send authentication (user+password) when following locations,
+ even when hostname changed. This can potentially send off the name
+ and password to whatever host the server decides. */
+ CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+ /* Specifically switch on or off the FTP engine's use of the EPRT command (
+ it also disables the LPRT attempt). By default, those ones will always be
+ attempted before the good old traditional PORT command. */
+ CINIT(FTP_USE_EPRT, LONG, 106),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_USERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(HTTPAUTH, LONG, 107),
+
+ /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
+ in second argument. The function must be matching the
+ curl_ssl_ctx_callback proto. */
+ CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+
+ /* Set the userdata for the ssl context callback function's third
+ argument */
+ CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+
+ /* FTP Option that causes missing dirs to be created on the remote server.
+ In 7.19.4 we introduced the convenience enums for this option using the
+ CURLFTP_CREATE_DIR prefix.
+ */
+ CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(PROXYAUTH, LONG, 111),
+
+ /* FTP option that changes the timeout, in seconds, associated with
+ getting a response. This is different from transfer timeout time and
+ essentially places a demand on the FTP server to acknowledge commands
+ in a timely manner. */
+ CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
+#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
+
+ /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+ tell libcurl to resolve names to those IP versions only. This only has
+ affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+ CINIT(IPRESOLVE, LONG, 113),
+
+ /* Set this option to limit the size of a file that will be downloaded from
+ an HTTP or FTP server.
+
+ Note there is also _LARGE version which adds large file support for
+ platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
+ CINIT(MAXFILESIZE, LONG, 114),
+
+ /* See the comment for INFILESIZE above, but in short, specifies
+ * the size of the file being uploaded. -1 means unknown.
+ */
+ CINIT(INFILESIZE_LARGE, OFF_T, 115),
+
+ /* Sets the continuation offset. There is also a LONG version of this;
+ * look above for RESUME_FROM.
+ */
+ CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+
+ /* Sets the maximum size of data that will be downloaded from
+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
+ */
+ CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+
+ /* Set this option to the file name of your .netrc file you want libcurl
+ to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+ a poor attempt to find the user's home directory and check for a .netrc
+ file in there. */
+ CINIT(NETRC_FILE, STRINGPOINT, 118),
+
+ /* Enable SSL/TLS for FTP, pick one of:
+ CURLUSESSL_TRY - try using SSL, proceed anyway otherwise
+ CURLUSESSL_CONTROL - SSL for the control connection or fail
+ CURLUSESSL_ALL - SSL for all communication or fail
+ */
+ CINIT(USE_SSL, LONG, 119),
+
+ /* The _LARGE version of the standard POSTFIELDSIZE option */
+ CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+
+ /* Enable/disable the TCP Nagle algorithm */
+ CINIT(TCP_NODELAY, LONG, 121),
+
+ /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 123 OBSOLETE. Gone in 7.16.0 */
+ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 127 OBSOLETE. Gone in 7.16.0 */
+ /* 128 OBSOLETE. Gone in 7.16.0 */
+
+ /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
+ can be used to change libcurl's default action which is to first try
+ "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
+ response has been received.
+
+ Available parameters are:
+ CURLFTPAUTH_DEFAULT - let libcurl decide
+ CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS
+ CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL
+ */
+ CINIT(FTPSSLAUTH, LONG, 129),
+
+ CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+ CINIT(IOCTLDATA, OBJECTPOINT, 131),
+
+ /* 132 OBSOLETE. Gone in 7.16.0 */
+ /* 133 OBSOLETE. Gone in 7.16.0 */
+
+ /* zero terminated string for pass on to the FTP server when asked for
+ "account" info */
+ CINIT(FTP_ACCOUNT, STRINGPOINT, 134),
+
+ /* feed cookie into cookie engine */
+ CINIT(COOKIELIST, STRINGPOINT, 135),
+
+ /* ignore Content-Length */
+ CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
+
+ /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+ response. Typically used for FTP-SSL purposes but is not restricted to
+ that. libcurl will then instead use the same IP address it used for the
+ control connection. */
+ CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
+ /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+ above. */
+ CINIT(FTP_FILEMETHOD, LONG, 138),
+
+ /* Local port number to bind the socket to */
+ CINIT(LOCALPORT, LONG, 139),
+
+ /* Number of ports to try, including the first one set with LOCALPORT.
+ Thus, setting it to 1 will make no additional attempts but the first.
+ */
+ CINIT(LOCALPORTRANGE, LONG, 140),
+
+ /* no transfer, set up connection and let application use the socket by
+ extracting it with CURLINFO_LASTSOCKET */
+ CINIT(CONNECT_ONLY, LONG, 141),
+
+ /* Function that will be called to convert from the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+
+ /* Function that will be called to convert to the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
+
+ /* Function that will be called to convert from UTF8
+ (instead of using the iconv calls in libcurl)
+ Note that this is used only for SSL certificate processing */
+ CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
+
+ /* if the connection proceeds too quickly then need to slow it down */
+ /* limit-rate: maximum number of bytes per second to send or receive */
+ CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
+ CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
+
+ /* Pointer to command string to send if USER/PASS fails. */
+ CINIT(FTP_ALTERNATIVE_TO_USER, STRINGPOINT, 147),
+
+ /* callback function for setting socket options */
+ CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
+ CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
+
+ /* set to 0 to disable session ID re-use for this transfer, default is
+ enabled (== 1) */
+ CINIT(SSL_SESSIONID_CACHE, LONG, 150),
+
+ /* allowed SSH authentication methods */
+ CINIT(SSH_AUTH_TYPES, LONG, 151),
+
+ /* Used by scp/sftp to do public/private key authentication */
+ CINIT(SSH_PUBLIC_KEYFILE, STRINGPOINT, 152),
+ CINIT(SSH_PRIVATE_KEYFILE, STRINGPOINT, 153),
+
+ /* Send CCC (Clear Command Channel) after authentication */
+ CINIT(FTP_SSL_CCC, LONG, 154),
+
+ /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
+ CINIT(TIMEOUT_MS, LONG, 155),
+ CINIT(CONNECTTIMEOUT_MS, LONG, 156),
+
+ /* set to zero to disable the libcurl's decoding and thus pass the raw body
+ data to the application even when it is encoded/compressed */
+ CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
+ CINIT(HTTP_CONTENT_DECODING, LONG, 158),
+
+ /* Permission used when creating new files and directories on the remote
+ server for protocols that support it, SFTP/SCP/FILE */
+ CINIT(NEW_FILE_PERMS, LONG, 159),
+ CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
+
+ /* Set the behaviour of POST when redirecting. Values must be set to one
+ of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+ CINIT(POSTREDIR, LONG, 161),
+
+ /* used by scp/sftp to verify the host's public key */
+ CINIT(SSH_HOST_PUBLIC_KEY_MD5, STRINGPOINT, 162),
+
+ /* Callback function for opening socket (instead of socket(2)). Optionally,
+ callback is able change the address or refuse to connect returning
+ CURL_SOCKET_BAD. The callback should have type
+ curl_opensocket_callback */
+ CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
+ CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
+
+ /* POST volatile input fields. */
+ CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+
+ /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
+ CINIT(PROXY_TRANSFER_MODE, LONG, 166),
+
+ /* Callback function for seeking in the input stream */
+ CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
+ CINIT(SEEKDATA, OBJECTPOINT, 168),
+
+ /* CRL file */
+ CINIT(CRLFILE, STRINGPOINT, 169),
+
+ /* Issuer certificate */
+ CINIT(ISSUERCERT, STRINGPOINT, 170),
+
+ /* (IPv6) Address scope */
+ CINIT(ADDRESS_SCOPE, LONG, 171),
+
+ /* Collect certificate chain info and allow it to get retrievable with
+ CURLINFO_CERTINFO after the transfer is complete. */
+ CINIT(CERTINFO, LONG, 172),
+
+ /* "name" and "pwd" to use when fetching. */
+ CINIT(USERNAME, STRINGPOINT, 173),
+ CINIT(PASSWORD, STRINGPOINT, 174),
+
+ /* "name" and "pwd" to use with Proxy when fetching. */
+ CINIT(PROXYUSERNAME, STRINGPOINT, 175),
+ CINIT(PROXYPASSWORD, STRINGPOINT, 176),
+
+ /* Comma separated list of hostnames defining no-proxy zones. These should
+ match both hostnames directly, and hostnames within a domain. For
+ example, local.com will match local.com and www.local.com, but NOT
+ notlocal.com or www.notlocal.com. For compatibility with other
+ implementations of this, .local.com will be considered to be the same as
+ local.com. A single * is the only valid wildcard, and effectively
+ disables the use of proxy. */
+ CINIT(NOPROXY, STRINGPOINT, 177),
+
+ /* block size for TFTP transfers */
+ CINIT(TFTP_BLKSIZE, LONG, 178),
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_SERVICE, STRINGPOINT, 179), /* DEPRECATED, do not use! */
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
+
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ CINIT(PROTOCOLS, LONG, 181),
+
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ CINIT(REDIR_PROTOCOLS, LONG, 182),
+
+ /* set the SSH knownhost file name to use */
+ CINIT(SSH_KNOWNHOSTS, STRINGPOINT, 183),
+
+ /* set the SSH host key callback, must point to a curl_sshkeycallback
+ function */
+ CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
+
+ /* set the SSH host key callback custom pointer */
+ CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
+
+ /* set the SMTP mail originator */
+ CINIT(MAIL_FROM, STRINGPOINT, 186),
+
+ /* set the list of SMTP mail receiver(s) */
+ CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+
+ /* FTP: send PRET before PASV */
+ CINIT(FTP_USE_PRET, LONG, 188),
+
+ /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+ CINIT(RTSP_REQUEST, LONG, 189),
+
+ /* The RTSP session identifier */
+ CINIT(RTSP_SESSION_ID, STRINGPOINT, 190),
+
+ /* The RTSP stream URI */
+ CINIT(RTSP_STREAM_URI, STRINGPOINT, 191),
+
+ /* The Transport: header to use in RTSP requests */
+ CINIT(RTSP_TRANSPORT, STRINGPOINT, 192),
+
+ /* Manually initialize the client RTSP CSeq for this handle */
+ CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
+
+ /* Manually initialize the server RTSP CSeq for this handle */
+ CINIT(RTSP_SERVER_CSEQ, LONG, 194),
+
+ /* The stream to pass to INTERLEAVEFUNCTION. */
+ CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
+
+ /* Let the application define a custom write method for RTP data */
+ CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
+
+ /* Turn on wildcard matching */
+ CINIT(WILDCARDMATCH, LONG, 197),
+
+ /* Directory matching callback called before downloading of an
+ individual file (chunk) started */
+ CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198),
+
+ /* Directory matching callback called after the file (chunk)
+ was downloaded, or skipped */
+ CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199),
+
+ /* Change match (fnmatch-like) callback for wildcard matching */
+ CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200),
+
+ /* Let the application define custom chunk data pointer */
+ CINIT(CHUNK_DATA, OBJECTPOINT, 201),
+
+ /* FNMATCH_FUNCTION user pointer */
+ CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
+
+ /* send linked-list of name:port:address sets */
+ CINIT(RESOLVE, OBJECTPOINT, 203),
+
+ /* Set a username for authenticated TLS */
+ CINIT(TLSAUTH_USERNAME, STRINGPOINT, 204),
+
+ /* Set a password for authenticated TLS */
+ CINIT(TLSAUTH_PASSWORD, STRINGPOINT, 205),
+
+ /* Set authentication type for authenticated TLS */
+ CINIT(TLSAUTH_TYPE, STRINGPOINT, 206),
+
+ /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
+ compressed transfer-encoded responses. Set to 0 to disable the use of TE:
+ in outgoing requests. The current default is 0, but it might change in a
+ future libcurl release.
+
+ libcurl will ask for the compressed methods it knows of, and if that
+ isn't any, it will not ask for transfer-encoding at all even if this
+ option is set to 1.
+
+ */
+ CINIT(TRANSFER_ENCODING, LONG, 207),
+
+ /* Callback function for closing socket (instead of close(2)). The callback
+ should have type curl_closesocket_callback */
+ CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208),
+ CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209),
+
+ /* allow GSSAPI credential delegation */
+ CINIT(GSSAPI_DELEGATION, LONG, 210),
+
+ /* Set the name servers to use for DNS resolution */
+ CINIT(DNS_SERVERS, STRINGPOINT, 211),
+
+ /* Time-out accept operations (currently for FTP only) after this amount
+ of milliseconds. */
+ CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
+
+ /* Set TCP keepalive */
+ CINIT(TCP_KEEPALIVE, LONG, 213),
+
+ /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+ CINIT(TCP_KEEPIDLE, LONG, 214),
+ CINIT(TCP_KEEPINTVL, LONG, 215),
+
+ /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
+ CINIT(SSL_OPTIONS, LONG, 216),
+
+ /* Set the SMTP auth originator */
+ CINIT(MAIL_AUTH, STRINGPOINT, 217),
+
+ /* Enable/disable SASL initial response */
+ CINIT(SASL_IR, LONG, 218),
+
+ /* Function that will be called instead of the internal progress display
+ * function. This function should be defined as the curl_xferinfo_callback
+ * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
+ CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
+
+ /* The XOAUTH2 bearer token */
+ CINIT(XOAUTH2_BEARER, STRINGPOINT, 220),
+
+ /* Set the interface string to use as outgoing network
+ * interface for DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_INTERFACE, STRINGPOINT, 221),
+
+ /* Set the local IPv4 address to use for outgoing DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_LOCAL_IP4, STRINGPOINT, 222),
+
+ /* Set the local IPv4 address to use for outgoing DNS requests.
+ * Only supported by the c-ares DNS backend */
+ CINIT(DNS_LOCAL_IP6, STRINGPOINT, 223),
+
+ /* Set authentication options directly */
+ CINIT(LOGIN_OPTIONS, STRINGPOINT, 224),
+
+ /* Enable/disable TLS NPN extension (http2 over ssl might fail without) */
+ CINIT(SSL_ENABLE_NPN, LONG, 225),
+
+ /* Enable/disable TLS ALPN extension (http2 over ssl might fail without) */
+ CINIT(SSL_ENABLE_ALPN, LONG, 226),
+
+ /* Time to wait for a response to a HTTP request containing an
+ * Expect: 100-continue header before sending the data anyway. */
+ CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227),
+
+ /* This points to a linked list of headers used for proxy requests only,
+ struct curl_slist kind */
+ CINIT(PROXYHEADER, OBJECTPOINT, 228),
+
+ /* Pass in a bitmask of "header options" */
+ CINIT(HEADEROPT, LONG, 229),
+
+ /* The public key in DER form used to validate the peer public key
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(PINNEDPUBLICKEY, STRINGPOINT, 230),
+
+ /* Path to Unix domain socket */
+ CINIT(UNIX_SOCKET_PATH, STRINGPOINT, 231),
+
+ /* Set if we should verify the certificate status. */
+ CINIT(SSL_VERIFYSTATUS, LONG, 232),
+
+ /* Set if we should enable TLS false start. */
+ CINIT(SSL_FALSESTART, LONG, 233),
+
+ /* Do not squash dot-dot sequences */
+ CINIT(PATH_AS_IS, LONG, 234),
+
+ /* Proxy Service Name */
+ CINIT(PROXY_SERVICE_NAME, STRINGPOINT, 235),
+
+ /* Service Name */
+ CINIT(SERVICE_NAME, STRINGPOINT, 236),
+
+ /* Wait/don't wait for pipe/mutex to clarify */
+ CINIT(PIPEWAIT, LONG, 237),
+
+ /* Set the protocol used when curl is given a URL without a protocol */
+ CINIT(DEFAULT_PROTOCOL, STRINGPOINT, 238),
+
+ /* Set stream weight, 1 - 256 (default is 16) */
+ CINIT(STREAM_WEIGHT, LONG, 239),
+
+ /* Set stream dependency on another CURL handle */
+ CINIT(STREAM_DEPENDS, OBJECTPOINT, 240),
+
+ /* Set E-xclusive stream dependency on another CURL handle */
+ CINIT(STREAM_DEPENDS_E, OBJECTPOINT, 241),
+
+ /* Do not send any tftp option requests to the server */
+ CINIT(TFTP_NO_OPTIONS, LONG, 242),
+
+ /* Linked-list of host:port:connect-to-host:connect-to-port,
+ overrides the URL's host:port (only for the network layer) */
+ CINIT(CONNECT_TO, OBJECTPOINT, 243),
+
+ /* Set TCP Fast Open */
+ CINIT(TCP_FASTOPEN, LONG, 244),
+
+ /* Continue to send data if the server responds early with an
+ * HTTP status code >= 300 */
+ CINIT(KEEP_SENDING_ON_ERROR, LONG, 245),
+
+ /* The CApath or CAfile used to validate the proxy certificate
+ this option is used only if PROXY_SSL_VERIFYPEER is true */
+ CINIT(PROXY_CAINFO, STRINGPOINT, 246),
+
+ /* The CApath directory used to validate the proxy certificate
+ this option is used only if PROXY_SSL_VERIFYPEER is true */
+ CINIT(PROXY_CAPATH, STRINGPOINT, 247),
+
+ /* Set if we should verify the proxy in ssl handshake,
+ set 1 to verify. */
+ CINIT(PROXY_SSL_VERIFYPEER, LONG, 248),
+
+ /* Set if we should verify the Common name from the proxy certificate in ssl
+ * handshake, set 1 to check existence, 2 to ensure that it matches
+ * the provided hostname. */
+ CINIT(PROXY_SSL_VERIFYHOST, LONG, 249),
+
+ /* What version to specifically try to use for proxy.
+ See CURL_SSLVERSION defines below. */
+ CINIT(PROXY_SSLVERSION, LONG, 250),
+
+ /* Set a username for authenticated TLS for proxy */
+ CINIT(PROXY_TLSAUTH_USERNAME, STRINGPOINT, 251),
+
+ /* Set a password for authenticated TLS for proxy */
+ CINIT(PROXY_TLSAUTH_PASSWORD, STRINGPOINT, 252),
+
+ /* Set authentication type for authenticated TLS for proxy */
+ CINIT(PROXY_TLSAUTH_TYPE, STRINGPOINT, 253),
+
+ /* name of the file keeping your private SSL-certificate for proxy */
+ CINIT(PROXY_SSLCERT, STRINGPOINT, 254),
+
+ /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") for
+ proxy */
+ CINIT(PROXY_SSLCERTTYPE, STRINGPOINT, 255),
+
+ /* name of the file keeping your private SSL-key for proxy */
+ CINIT(PROXY_SSLKEY, STRINGPOINT, 256),
+
+ /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") for
+ proxy */
+ CINIT(PROXY_SSLKEYTYPE, STRINGPOINT, 257),
+
+ /* password for the SSL private key for proxy */
+ CINIT(PROXY_KEYPASSWD, STRINGPOINT, 258),
+
+ /* Specify which SSL ciphers to use for proxy */
+ CINIT(PROXY_SSL_CIPHER_LIST, STRINGPOINT, 259),
+
+ /* CRL file for proxy */
+ CINIT(PROXY_CRLFILE, STRINGPOINT, 260),
+
+ /* Enable/disable specific SSL features with a bitmask for proxy, see
+ CURLSSLOPT_* */
+ CINIT(PROXY_SSL_OPTIONS, LONG, 261),
+
+ /* Name of pre proxy to use. */
+ CINIT(PRE_PROXY, STRINGPOINT, 262),
+
+ /* The public key in DER form used to validate the proxy public key
+ this option is used only if PROXY_SSL_VERIFYPEER is true */
+ CINIT(PROXY_PINNEDPUBLICKEY, STRINGPOINT, 263),
+
+ /* Path to an abstract Unix domain socket */
+ CINIT(ABSTRACT_UNIX_SOCKET, STRINGPOINT, 264),
+
+ /* Suppress proxy CONNECT response headers from user callbacks */
+ CINIT(SUPPRESS_CONNECT_HEADERS, LONG, 265),
+
+ CURLOPT_LASTENTRY /* the last unused */
+} CURLoption;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
+/* These are scheduled to disappear by 2009 */
+
+/* The following were added in 7.17.0 */
+#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_FTPAPPEND CURLOPT_APPEND
+#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
+#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
+
+/* The following were added earlier */
+
+#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+ /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+ name resolves addresses using more than one IP protocol version, this
+ option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+ versions that your system allows */
+#define CURL_IPRESOLVE_V4 1 /* resolve to IPv4 addresses */
+#define CURL_IPRESOLVE_V6 2 /* resolve to IPv6 addresses */
+
+ /* three convenient "aliases" that follow the name scheme better */
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+
+ /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
+enum {
+ CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+ like the library to choose the best possible
+ for us! */
+ CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
+ CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
+ CURL_HTTP_VERSION_2_0, /* please use HTTP 2 in the request */
+ CURL_HTTP_VERSION_2TLS, /* use version 2 for HTTPS, version 1.1 for HTTP */
+ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE, /* please use HTTP 2 without HTTP/1.1
+ Upgrade */
+
+ CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
+};
+
+/* Convenience definition simple because the name of the version is HTTP/2 and
+ not 2.0. The 2_0 version of the enum name was set while the version was
+ still planned to be 2.0 and we stick to it for compatibility. */
+#define CURL_HTTP_VERSION_2 CURL_HTTP_VERSION_2_0
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+ CURL_RTSPREQ_NONE, /* first in list */
+ CURL_RTSPREQ_OPTIONS,
+ CURL_RTSPREQ_DESCRIBE,
+ CURL_RTSPREQ_ANNOUNCE,
+ CURL_RTSPREQ_SETUP,
+ CURL_RTSPREQ_PLAY,
+ CURL_RTSPREQ_PAUSE,
+ CURL_RTSPREQ_TEARDOWN,
+ CURL_RTSPREQ_GET_PARAMETER,
+ CURL_RTSPREQ_SET_PARAMETER,
+ CURL_RTSPREQ_RECORD,
+ CURL_RTSPREQ_RECEIVE,
+ CURL_RTSPREQ_LAST /* last in list */
+};
+
+ /* These enums are for use with the CURLOPT_NETRC option. */
+enum CURL_NETRC_OPTION {
+ CURL_NETRC_IGNORED, /* The .netrc will never be read.
+ * This is the default. */
+ CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred
+ * to one in the .netrc. */
+ CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored.
+ * Unless one is set programmatically, the .netrc
+ * will be queried. */
+ CURL_NETRC_LAST
+};
+
+enum {
+ CURL_SSLVERSION_DEFAULT,
+ CURL_SSLVERSION_TLSv1, /* TLS 1.x */
+ CURL_SSLVERSION_SSLv2,
+ CURL_SSLVERSION_SSLv3,
+ CURL_SSLVERSION_TLSv1_0,
+ CURL_SSLVERSION_TLSv1_1,
+ CURL_SSLVERSION_TLSv1_2,
+ CURL_SSLVERSION_TLSv1_3,
+
+ CURL_SSLVERSION_LAST /* never use, keep last */
+};
+
+enum {
+ CURL_SSLVERSION_MAX_NONE = 0,
+ CURL_SSLVERSION_MAX_DEFAULT = (CURL_SSLVERSION_TLSv1 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_0 = (CURL_SSLVERSION_TLSv1_0 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_1 = (CURL_SSLVERSION_TLSv1_1 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_2 = (CURL_SSLVERSION_TLSv1_2 << 16),
+ CURL_SSLVERSION_MAX_TLSv1_3 = (CURL_SSLVERSION_TLSv1_3 << 16),
+
+ /* never use, keep last */
+ CURL_SSLVERSION_MAX_LAST = (CURL_SSLVERSION_LAST << 16)
+};
+
+enum CURL_TLSAUTH {
+ CURL_TLSAUTH_NONE,
+ CURL_TLSAUTH_SRP,
+ CURL_TLSAUTH_LAST /* never use, keep last */
+};
+
+/* symbols to use with CURLOPT_POSTREDIR.
+ CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+ can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+ | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL 0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
+
+typedef enum {
+ CURL_TIMECOND_NONE,
+
+ CURL_TIMECOND_IFMODSINCE,
+ CURL_TIMECOND_IFUNMODSINCE,
+ CURL_TIMECOND_LASTMOD,
+
+ CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+ libcurl, see lib/README.curlx for details
+
+ !checksrc! disable SPACEBEFOREPAREN 2
+*/
+CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
+CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+
+/* name is uppercase CURLFORM_<name> */
+#ifdef CFINIT
+#undef CFINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CFINIT(name) CURLFORM_ ## name
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define CFINIT(name) CURLFORM_/**/name
+#endif
+
+typedef enum {
+ CFINIT(NOTHING), /********* the first one is unused ************/
+
+ /* */
+ CFINIT(COPYNAME),
+ CFINIT(PTRNAME),
+ CFINIT(NAMELENGTH),
+ CFINIT(COPYCONTENTS),
+ CFINIT(PTRCONTENTS),
+ CFINIT(CONTENTSLENGTH),
+ CFINIT(FILECONTENT),
+ CFINIT(ARRAY),
+ CFINIT(OBSOLETE),
+ CFINIT(FILE),
+
+ CFINIT(BUFFER),
+ CFINIT(BUFFERPTR),
+ CFINIT(BUFFERLENGTH),
+
+ CFINIT(CONTENTTYPE),
+ CFINIT(CONTENTHEADER),
+ CFINIT(FILENAME),
+ CFINIT(END),
+ CFINIT(OBSOLETE2),
+
+ CFINIT(STREAM),
+ CFINIT(CONTENTLEN), /* added in 7.46.0, provide a curl_off_t length */
+
+ CURLFORM_LASTENTRY /* the last unused */
+} CURLformoption;
+
+#undef CFINIT /* done */
+
+/* structure to be used as parameter for CURLFORM_ARRAY */
+struct curl_forms {
+ CURLformoption option;
+ const char *value;
+};
+
+/* use this for multipart formpost building */
+/* Returns code for curl_formadd()
+ *
+ * Returns:
+ * CURL_FORMADD_OK on success
+ * CURL_FORMADD_MEMORY if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
+ * CURL_FORMADD_NULL if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
+ *
+ ***************************************************************************/
+typedef enum {
+ CURL_FORMADD_OK, /* first, no error */
+
+ CURL_FORMADD_MEMORY,
+ CURL_FORMADD_OPTION_TWICE,
+ CURL_FORMADD_NULL,
+ CURL_FORMADD_UNKNOWN_OPTION,
+ CURL_FORMADD_INCOMPLETE,
+ CURL_FORMADD_ILLEGAL_ARRAY,
+ CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+
+ CURL_FORMADD_LAST /* last */
+} CURLFORMcode;
+
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanced function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
+CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...);
+
+/*
+ * callback function for curl_formget()
+ * The void *arg pointer will be the one passed as second argument to
+ * curl_formget().
+ * The character buffer passed to it must not be freed.
+ * Should return the buffer length passed to it as the argument "len" on
+ * success.
+ */
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
+ size_t len);
+
+/*
+ * NAME curl_formget()
+ *
+ * DESCRIPTION
+ *
+ * Serialize a curl_httppost struct built with curl_formadd().
+ * Accepts a void pointer as second argument which will be passed to
+ * the curl_formget_callback function.
+ * Returns 0 on success.
+ */
+CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append);
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+CURL_EXTERN void curl_formfree(struct curl_httppost *form);
+
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
+CURL_EXTERN char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+CURL_EXTERN char *curl_version(void);
+
+/*
+ * NAME curl_easy_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
+CURL_EXTERN char *curl_easy_escape(CURL *handle,
+ const char *string,
+ int length);
+
+/* the previous version: */
+CURL_EXTERN char *curl_escape(const char *string,
+ int length);
+
+
+/*
+ * NAME curl_easy_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
+ * converted into the host encoding.
+ */
+CURL_EXTERN char *curl_easy_unescape(CURL *handle,
+ const char *string,
+ int length,
+ int *outlength);
+
+/* the previous version */
+CURL_EXTERN char *curl_unescape(const char *string,
+ int length);
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
+CURL_EXTERN void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl and before any call of other libcurl functions.
+ *
+ * This function is not thread-safe!
+ */
+CURL_EXTERN CURLcode curl_global_init(long flags);
+
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl. This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
+ * callback routines with be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURL_EXTERN CURLcode curl_global_init_mem(long flags,
+ curl_malloc_callback m,
+ curl_free_callback f,
+ curl_realloc_callback r,
+ curl_strdup_callback s,
+ curl_calloc_callback c);
+
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+CURL_EXTERN void curl_global_cleanup(void);
+
+/* linked-list structure for the CURLOPT_QUOTE option (and other) */
+struct curl_slist {
+ char *data;
+ struct curl_slist *next;
+};
+
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
+ const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
+
+/*
+ * NAME curl_getdate()
+ *
+ * DESCRIPTION
+ *
+ * Returns the time, in seconds since 1 Jan 1970 of the time string given in
+ * the first argument. The time argument in the second parameter is unused
+ * and should be set to NULL.
+ */
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
+
+/* info about the certificate chain, only for OpenSSL builds. Asked
+ for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+ int num_of_certs; /* number of certificates with information */
+ struct curl_slist **certinfo; /* for each index in this array, there's a
+ linked list with textual information in the
+ format "name: value" */
+};
+
+/* enum for the different supported SSL backends */
+typedef enum {
+ CURLSSLBACKEND_NONE = 0,
+ CURLSSLBACKEND_OPENSSL = 1,
+ CURLSSLBACKEND_GNUTLS = 2,
+ CURLSSLBACKEND_NSS = 3,
+ CURLSSLBACKEND_OBSOLETE4 = 4, /* Was QSOSSL. */
+ CURLSSLBACKEND_GSKIT = 5,
+ CURLSSLBACKEND_POLARSSL = 6,
+ CURLSSLBACKEND_CYASSL = 7,
+ CURLSSLBACKEND_SCHANNEL = 8,
+ CURLSSLBACKEND_DARWINSSL = 9,
+ CURLSSLBACKEND_AXTLS = 10,
+ CURLSSLBACKEND_MBEDTLS = 11
+} curl_sslbackend;
+
+/* aliases for library clones and renames */
+#define CURLSSLBACKEND_LIBRESSL 1
+#define CURLSSLBACKEND_BORINGSSL 1
+#define CURLSSLBACKEND_WOLFSSL 6
+
+/* Information about the SSL library used and the respective internal SSL
+ handle, which can be used to obtain further information regarding the
+ connection. Asked for with CURLINFO_TLS_SSL_PTR or CURLINFO_TLS_SESSION. */
+struct curl_tlssessioninfo {
+ curl_sslbackend backend;
+ void *internals;
+};
+
+#define CURLINFO_STRING 0x100000
+#define CURLINFO_LONG 0x200000
+#define CURLINFO_DOUBLE 0x300000
+#define CURLINFO_SLIST 0x400000
+#define CURLINFO_PTR 0x400000 /* same as SLIST */
+#define CURLINFO_SOCKET 0x500000
+#define CURLINFO_MASK 0x0fffff
+#define CURLINFO_TYPEMASK 0xf00000
+
+typedef enum {
+ CURLINFO_NONE, /* first, never use this */
+ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1,
+ CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
+ CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3,
+ CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
+ CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
+ CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
+ CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7,
+ CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8,
+ CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9,
+ CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10,
+ CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11,
+ CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
+ CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
+ CURLINFO_FILETIME = CURLINFO_LONG + 14,
+ CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
+ CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
+ CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
+ CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
+ CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
+ CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
+ CURLINFO_PRIVATE = CURLINFO_STRING + 21,
+ CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22,
+ CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23,
+ CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24,
+ CURLINFO_OS_ERRNO = CURLINFO_LONG + 25,
+ CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
+ CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
+ CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
+ CURLINFO_LASTSOCKET = CURLINFO_LONG + 29,
+ CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30,
+ CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31,
+ CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32,
+ CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
+ CURLINFO_CERTINFO = CURLINFO_PTR + 34,
+ CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35,
+ CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36,
+ CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37,
+ CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38,
+ CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39,
+ CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40,
+ CURLINFO_LOCAL_IP = CURLINFO_STRING + 41,
+ CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42,
+ CURLINFO_TLS_SESSION = CURLINFO_PTR + 43,
+ CURLINFO_ACTIVESOCKET = CURLINFO_SOCKET + 44,
+ CURLINFO_TLS_SSL_PTR = CURLINFO_PTR + 45,
+ CURLINFO_HTTP_VERSION = CURLINFO_LONG + 46,
+ CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
+ CURLINFO_PROTOCOL = CURLINFO_LONG + 48,
+ CURLINFO_SCHEME = CURLINFO_STRING + 49,
+ /* Fill in new entries below here! */
+
+ CURLINFO_LASTONE = 49
+} CURLINFO;
+
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+ CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
+typedef enum {
+ CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+ CURLCLOSEPOLICY_OLDEST,
+ CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+ CURLCLOSEPOLICY_LEAST_TRAFFIC,
+ CURLCLOSEPOLICY_SLOWEST,
+ CURLCLOSEPOLICY_CALLBACK,
+
+ CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+#define CURL_GLOBAL_NOTHING 0
+#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+#define CURL_GLOBAL_ACK_EINTR (1<<2)
+
+
+/*****************************************************************************
+ * Setup defines, protos etc for the sharing stuff.
+ */
+
+/* Different data locks for a single share */
+typedef enum {
+ CURL_LOCK_DATA_NONE = 0,
+ /* CURL_LOCK_DATA_SHARE is used internally to say that
+ * the locking is just made to change the internal state of the share
+ * itself.
+ */
+ CURL_LOCK_DATA_SHARE,
+ CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_DATA_DNS,
+ CURL_LOCK_DATA_SSL_SESSION,
+ CURL_LOCK_DATA_CONNECT,
+ CURL_LOCK_DATA_LAST
+} curl_lock_data;
+
+/* Different lock access types */
+typedef enum {
+ CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */
+ CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
+ CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
+ CURL_LOCK_ACCESS_LAST /* never use */
+} curl_lock_access;
+
+typedef void (*curl_lock_function)(CURL *handle,
+ curl_lock_data data,
+ curl_lock_access locktype,
+ void *userptr);
+typedef void (*curl_unlock_function)(CURL *handle,
+ curl_lock_data data,
+ void *userptr);
+
+
+typedef enum {
+ CURLSHE_OK, /* all is fine */
+ CURLSHE_BAD_OPTION, /* 1 */
+ CURLSHE_IN_USE, /* 2 */
+ CURLSHE_INVALID, /* 3 */
+ CURLSHE_NOMEM, /* 4 out of memory */
+ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
+ CURLSHE_LAST /* never use */
+} CURLSHcode;
+
+typedef enum {
+ CURLSHOPT_NONE, /* don't use */
+ CURLSHOPT_SHARE, /* specify a data type to share */
+ CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
+ CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
+ CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
+ CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock
+ callback functions */
+ CURLSHOPT_LAST /* never use */
+} CURLSHoption;
+
+CURL_EXTERN CURLSH *curl_share_init(void);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+ CURLVERSION_FIRST,
+ CURLVERSION_SECOND,
+ CURLVERSION_THIRD,
+ CURLVERSION_FOURTH,
+ CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+ basically all programs ever that want to get version information. It is
+ meant to be a built-in version number for what kind of struct the caller
+ expects. If the struct ever changes, we redefine the NOW to another enum
+ from above. */
+#define CURLVERSION_NOW CURLVERSION_FOURTH
+
+typedef struct {
+ CURLversion age; /* age of the returned struct */
+ const char *version; /* LIBCURL_VERSION */
+ unsigned int version_num; /* LIBCURL_VERSION_NUM */
+ const char *host; /* OS/host/cpu/machine when configured */
+ int features; /* bitmask, see defines below */
+ const char *ssl_version; /* human readable string */
+ long ssl_version_num; /* not used anymore, always 0 */
+ const char *libz_version; /* human readable string */
+ /* protocols is terminated by an entry with a NULL protoname */
+ const char * const *protocols;
+
+ /* The fields below this were added in CURLVERSION_SECOND */
+ const char *ares;
+ int ares_num;
+
+ /* This field was added in CURLVERSION_THIRD */
+ const char *libidn;
+
+ /* These field were added in CURLVERSION_FOURTH */
+
+ /* Same as '_libiconv_version' if built with HAVE_ICONV */
+ int iconv_ver_num;
+
+ const char *libssh_version; /* human readable string */
+
+} curl_version_info_data;
+
+#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4 (1<<1) /* Kerberos V4 auth is supported
+ (deprecated) */
+#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
+#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
+#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth is supported
+ (deprecated) */
+#define CURL_VERSION_DEBUG (1<<6) /* Built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS (1<<7) /* Asynchronous DNS resolves */
+#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth is supported */
+#define CURL_VERSION_LARGEFILE (1<<9) /* Supports files larger than 2GB */
+#define CURL_VERSION_IDN (1<<10) /* Internationized Domain Names are
+ supported */
+#define CURL_VERSION_SSPI (1<<11) /* Built against Windows SSPI */
+#define CURL_VERSION_CONV (1<<12) /* Character conversions supported */
+#define CURL_VERSION_CURLDEBUG (1<<13) /* Debug memory tracking supported */
+#define CURL_VERSION_TLSAUTH_SRP (1<<14) /* TLS-SRP auth is supported */
+#define CURL_VERSION_NTLM_WB (1<<15) /* NTLM delegation to winbind helper
+ is supported */
+#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
+#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */
+#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */
+#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
+#define CURL_VERSION_PSL (1<<20) /* Mozilla's Public Suffix List, used
+ for cookie domain verification */
+#define CURL_VERSION_HTTPS_PROXY (1<<21) /* HTTPS-proxy support built-in */
+
+ /*
+ * NAME curl_version_info()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
+
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
+
+/*
+ * NAME curl_easy_pause()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_pause function pauses or unpauses transfers. Select the new
+ * state by setting the bitmask, use the convenience defines below.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
+
+#define CURLPAUSE_RECV (1<<0)
+#define CURLPAUSE_RECV_CONT (0)
+
+#define CURLPAUSE_SEND (1<<2)
+#define CURLPAUSE_SEND_CONT (0)
+
+#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND)
+#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
+
+#ifdef __cplusplus
+}
+#endif
+
+/* unfortunately, the easy.h and multi.h include files need options and info
+ stuff before they can be included! */
+#include "easy.h" /* nothing in curl is fun without the easy stuff */
+#include "multi.h"
+
+/* the typechecker doesn't work in C++ (yet) */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
+ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
+#include "typecheck-gcc.h"
+#else
+#if defined(__STDC__) && (__STDC__ >= 1)
+#if 0 /* Triggers clang -Wdisabled-macro-expansion, skip for CMake. */
+/* This preprocessor magic that replaces a call with the exact same call is
+ only done to make sure application authors pass exactly three arguments
+ to these functions. */
+#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+#endif
+#endif /* __STDC__ >= 1 */
+#endif /* gcc >= 4.3 && !__cplusplus */
+
+#endif /* __CURL_CURL_H */
diff --git a/Utilities/cmcurl/include/curl/curlbuild.h.cmake b/Utilities/cmcurl/include/curl/curlbuild.h.cmake
new file mode 100644
index 000000000..c8b4f5270
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/curlbuild.h.cmake
@@ -0,0 +1,218 @@
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: https://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.in or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ */
+
+/* ================================================================ */
+/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+#error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+#error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+#error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+#error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+#error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+#error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+#error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+#error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+#error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+#error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/* EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY */
+/* ================================================================ */
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file ws2tcpip.h must be included by the external interface. */
+#cmakedefine CURL_PULL_WS2TCPIP_H
+#ifdef CURL_PULL_WS2TCPIP_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file sys/types.h must be included by the external interface. */
+#cmakedefine CURL_PULL_SYS_TYPES_H
+#ifdef CURL_PULL_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file stdint.h must be included by the external interface. */
+#cmakedefine CURL_PULL_STDINT_H
+#ifdef CURL_PULL_STDINT_H
+# include <stdint.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file inttypes.h must be included by the external interface. */
+#cmakedefine CURL_PULL_INTTYPES_H
+#ifdef CURL_PULL_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file sys/socket.h must be included by the external interface. */
+#cmakedefine CURL_PULL_SYS_SOCKET_H
+#ifdef CURL_PULL_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+/* Configure process defines this to 1 when it finds out that system */
+/* header file sys/poll.h must be included by the external interface. */
+#cmakedefine CURL_PULL_SYS_POLL_H
+#ifdef CURL_PULL_SYS_POLL_H
+# include <sys/poll.h>
+#endif
+
+/* The size of `int', as computed by sizeof. */
+@CURL_SIZEOF_INT_CODE@
+
+/* The size of `long', as computed by sizeof. */
+@CURL_SIZEOF_LONG_CODE@
+
+/* The size of `long long', as computed by sizeof. */
+@CURL_SIZEOF_LONG_LONG_CODE@
+
+/* The size of `ssize_t', as computed by sizeof. */
+@CURL_SIZEOF_SSIZE_T_CODE@
+
+#define CURL_HAVE_SOCKLEN_T @CURL_HAVE_SOCKLEN_T@
+#if CURL_HAVE_SOCKLEN_T
+/* Integral data type used for curl_socklen_t. */
+#define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+
+/* The size of `curl_socklen_t', as computed by sizeof. */
+@CURL_SIZEOF_CURL_SOCKLEN_T_CODE@
+#else
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T CURL_SIZEOF_INT
+#endif
+
+/* Data type definition of curl_socklen_t. */
+typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+
+#if CURL_SIZEOF_LONG == 8
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+#elif CURL_SIZEOF_LONG_LONG == 8
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+#else
+# define CURL_TYPEOF_CURL_OFF_T ssize_t
+# define CURL_SIZEOF_CURL_OFF_T CURL_SIZEOF_SSIZE_T
+/* TODO: need adjustment here. */
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+#endif
+
+/* Data type definition of curl_off_t. */
+typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/Utilities/cmcurl/include/curl/curlrules.h b/Utilities/cmcurl/include/curl/curlrules.h
new file mode 100644
index 000000000..0abd9f71d
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/curlrules.h
@@ -0,0 +1,239 @@
+#ifndef __CURL_CURLRULES_H
+#define __CURL_CURLRULES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* COMPILE TIME SANITY CHECKS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * All checks done in this file are intentionally placed in a public
+ * header file which is pulled by curl/curl.h when an application is
+ * being built using an already built libcurl library. Additionally
+ * this file is also included and used when building the library.
+ *
+ * If compilation fails on this file it is certainly sure that the
+ * problem is elsewhere. It could be a problem in the curlbuild.h
+ * header file, or simply that you are using different compilation
+ * settings than those used to build the library.
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * Do not deactivate any check, these are done to make sure that the
+ * library is properly built and used.
+ *
+ * You can find further help on the libcurl development mailing list:
+ * https://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * NOTE 2
+ * ------
+ *
+ * Some of the following compile time checks are based on the fact
+ * that the dimension of a constant array can not be a negative one.
+ * In this way if the compile time verification fails, the compilation
+ * will fail issuing an error. The error description wording is compiler
+ * dependent but it will be quite similar to one of the following:
+ *
+ * "negative subscript or subscript is too large"
+ * "array must have at least one element"
+ * "-1 is an illegal array size"
+ * "size of array is negative"
+ *
+ * If you are building an application which tries to use an already
+ * built libcurl library and you are getting this kind of errors on
+ * this file, it is a clear indication that there is a mismatch between
+ * how the library was built and how you are trying to use it for your
+ * application. Your already compiled or binary library provider is the
+ * only one who can give you the details you need to properly use it.
+ */
+
+/*
+ * Verify that some macros are actually defined.
+ */
+
+#ifndef CURL_SIZEOF_LONG
+# error "CURL_SIZEOF_LONG definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_SOCKLEN_T
+# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_SOCKLEN_T
+# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_OFF_T
+# error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_T
+# error "CURL_FORMAT_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_TU
+# error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_OFF_T
+# error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_T
+# error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_TU
+# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
+#endif
+
+/*
+ * Macros private to this header file.
+ */
+
+#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
+
+#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
+
+/*
+ * Verify that the size previously defined and expected for long
+ * is the same as the one reported by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_01__
+ [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_off_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_02__
+ [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
+
+/*
+ * Verify at compile time that the size of curl_off_t as reported
+ * by sizeof() is greater or equal than the one reported for long
+ * for the current compilation.
+ */
+
+typedef char
+ __curl_rule_03__
+ [CurlchkszGE(curl_off_t, long)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_socklen_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_04__
+ [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
+
+/*
+ * Verify at compile time that the size of curl_socklen_t as reported
+ * by sizeof() is greater or equal than the one reported for int for
+ * the current compilation.
+ */
+
+typedef char
+ __curl_rule_05__
+ [CurlchkszGE(curl_socklen_t, int)];
+
+/* ================================================================ */
+/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */
+/* ================================================================ */
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+ defined(__ILEC400__)
+ /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+ /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+# define __CURL_OFF_T_C_HLPR2(x) x
+# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+# ifdef CURL_ISOCPP
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+# else
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+# endif
+# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+/*
+ * Get rid of macros private to this header file.
+ */
+
+#undef CurlchkszEQ
+#undef CurlchkszGE
+
+#endif /* __CURL_CURLRULES_H */
diff --git a/Utilities/cmcurl/include/curl/curlver.h b/Utilities/cmcurl/include/curl/curlver.h
new file mode 100644
index 000000000..667b7eb13
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/curlver.h
@@ -0,0 +1,77 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+ a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the global package copyright */
+#define LIBCURL_COPYRIGHT "1996 - 2017 Daniel Stenberg, <daniel@haxx.se>."
+
+/* This is the version number of the libcurl package from which this header
+ file origins: */
+#define LIBCURL_VERSION "7.54.1"
+
+/* The numeric version number is also available "in parts" by using these
+ defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 54
+#define LIBCURL_VERSION_PATCH 1
+
+/* This is the numeric version of the libcurl version number, meant for easier
+ parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
+ always follow this syntax:
+
+ 0xXXYYZZ
+
+ Where XX, YY and ZZ are the main version, release and patch numbers in
+ hexadecimal (using 8 bits each). All three numbers are always represented
+ using two digits. 1.2 would appear as "0x010200" while version 9.11.7
+ appears as "0x090b07".
+
+ This 6-digit (24 bits) hexadecimal number does not show pre-release number,
+ and it is always a greater number in a more recent release. It makes
+ comparisons with greater than and less than work.
+
+ Note: This define is the full hex number and _does not_ use the
+ CURL_VERSION_BITS() macro since curl's own configure script greps for it
+ and needs it to contain the full number.
+*/
+#define LIBCURL_VERSION_NUM 0x073601
+
+/*
+ * This is the date and time when the full source package was created. The
+ * timestamp is not stored in git, as the timestamp is properly set in the
+ * tarballs by the maketgz script.
+ *
+ * The format of the date follows this template:
+ *
+ * "2007-11-23"
+ */
+#define LIBCURL_TIMESTAMP "[unreleased]"
+
+#define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|z)
+#define CURL_AT_LEAST_VERSION(x,y,z) \
+ (LIBCURL_VERSION_NUM >= CURL_VERSION_BITS(x, y, z))
+
+#endif /* __CURL_CURLVER_H */
diff --git a/Utilities/cmcurl/include/curl/easy.h b/Utilities/cmcurl/include/curl/easy.h
new file mode 100644
index 000000000..752c5049f
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/easy.h
@@ -0,0 +1,102 @@
+#ifndef __CURL_EASY_H
+#define __CURL_EASY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
+CURL_EXTERN void curl_easy_cleanup(CURL *curl);
+
+/*
+ * NAME curl_easy_getinfo()
+ *
+ * DESCRIPTION
+ *
+ * Request internal information from the curl session with this function. The
+ * third argument MUST be a pointer to a long, a pointer to a char * or a
+ * pointer to a double (as the documentation describes elsewhere). The data
+ * pointed to will be filled in accordingly and can be relied upon only if the
+ * function returns CURLE_OK. This function is intended to get used *AFTER* a
+ * performed transfer, all results from this function are undefined until the
+ * transfer is completed.
+ */
+CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+
+
+/*
+ * NAME curl_easy_duphandle()
+ *
+ * DESCRIPTION
+ *
+ * Creates a new curl session handle with the same options set for the handle
+ * passed in. Duplicating a handle could only be a matter of cloning data and
+ * options, internal state info and things like persistent connections cannot
+ * be transferred. It is useful in multithreaded applications when you can run
+ * curl_easy_duphandle() for each new thread to avoid a series of identical
+ * curl_easy_setopt() invokes in every thread.
+ */
+CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl);
+
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+CURL_EXTERN void curl_easy_reset(CURL *curl);
+
+/*
+ * NAME curl_easy_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
+ size_t *n);
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
+ size_t buflen, size_t *n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/include/curl/mprintf.h b/Utilities/cmcurl/include/curl/mprintf.h
new file mode 100644
index 000000000..e20f546e1
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/mprintf.h
@@ -0,0 +1,50 @@
+#ifndef __CURL_MPRINTF_H
+#define __CURL_MPRINTF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+#include "curl.h" /* for CURL_EXTERN */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
+CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
+ const char *format, ...);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
+CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
+ const char *format, va_list args);
+CURL_EXTERN char *curl_maprintf(const char *format, ...);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CURL_MPRINTF_H */
diff --git a/Utilities/cmcurl/include/curl/multi.h b/Utilities/cmcurl/include/curl/multi.h
new file mode 100644
index 000000000..f93e511be
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/multi.h
@@ -0,0 +1,439 @@
+#ifndef __CURL_MULTI_H
+#define __CURL_MULTI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/*
+ This is an "external" header file. Don't give away any internals here!
+
+ GOALS
+
+ o Enable a "pull" interface. The application that uses libcurl decides where
+ and when to ask libcurl to get/send data.
+
+ o Enable multiple simultaneous transfers in the same thread without making it
+ complicated for the application.
+
+ o Enable the application to select() on its own file descriptors and curl's
+ file descriptors simultaneous easily.
+
+*/
+
+/*
+ * This header file should not really need to include "curl.h" since curl.h
+ * itself includes this file and we expect user applications to do #include
+ * <curl/curl.h> without the need for especially including multi.h.
+ *
+ * For some reason we added this include here at one point, and rather than to
+ * break existing (wrongly written) libcurl applications, we leave it as-is
+ * but with this warning attached.
+ */
+#include "curl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(BUILDING_LIBCURL) || defined(CURL_STRICTER)
+typedef struct Curl_multi CURLM;
+#else
+typedef void CURLM;
+#endif
+
+typedef enum {
+ CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
+ curl_multi_socket*() soon */
+ CURLM_OK,
+ CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
+ CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
+ CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
+ CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
+ CURLM_BAD_SOCKET, /* the passed in socket argument did not match */
+ CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
+ CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was
+ attempted to get added - again */
+ CURLM_LAST
+} CURLMcode;
+
+/* just to make code nicer when using curl_multi_socket() you can now check
+ for CURLM_CALL_MULTI_SOCKET too in the same style it works for
+ curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
+#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
+
+/* bitmask bits for CURLMOPT_PIPELINING */
+#define CURLPIPE_NOTHING 0L
+#define CURLPIPE_HTTP1 1L
+#define CURLPIPE_MULTIPLEX 2L
+
+typedef enum {
+ CURLMSG_NONE, /* first, not used */
+ CURLMSG_DONE, /* This easy handle has completed. 'result' contains
+ the CURLcode of the transfer */
+ CURLMSG_LAST /* last, not used */
+} CURLMSG;
+
+struct CURLMsg {
+ CURLMSG msg; /* what this message means */
+ CURL *easy_handle; /* the handle it concerns */
+ union {
+ void *whatever; /* message-specific data */
+ CURLcode result; /* return code for transfer */
+ } data;
+};
+typedef struct CURLMsg CURLMsg;
+
+/* Based on poll(2) structure and values.
+ * We don't use pollfd and POLL* constants explicitly
+ * to cover platforms without poll(). */
+#define CURL_WAIT_POLLIN 0x0001
+#define CURL_WAIT_POLLPRI 0x0002
+#define CURL_WAIT_POLLOUT 0x0004
+
+struct curl_waitfd {
+ curl_socket_t fd;
+ short events;
+ short revents; /* not supported yet */
+};
+
+/*
+ * Name: curl_multi_init()
+ *
+ * Desc: inititalize multi-style curl usage
+ *
+ * Returns: a new CURLM handle to use in all 'curl_multi' functions.
+ */
+CURL_EXTERN CURLM *curl_multi_init(void);
+
+/*
+ * Name: curl_multi_add_handle()
+ *
+ * Desc: add a standard curl handle to the multi stack
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_remove_handle()
+ *
+ * Desc: removes a curl handle from the multi stack again
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_fdset()
+ *
+ * Desc: Ask curl for its fd_set sets. The app can use these to select() or
+ * poll() on. We want curl_multi_perform() called as soon as one of
+ * them are ready.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *exc_fd_set,
+ int *max_fd);
+
+/*
+ * Name: curl_multi_wait()
+ *
+ * Desc: Poll on all fds within a CURLM set as well as any
+ * additional fds passed to the function.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret);
+
+ /*
+ * Name: curl_multi_perform()
+ *
+ * Desc: When the app thinks there's data available for curl it calls this
+ * function to read/write whatever there is right now. This returns
+ * as soon as the reads and writes are done. This function does not
+ * require that there actually is data available for reading or that
+ * data can be written, it can be called just in case. It returns
+ * the number of handles that still transfer data in the second
+ * argument's integer-pointer.
+ *
+ * Returns: CURLMcode type, general multi error code. *NOTE* that this only
+ * returns errors etc regarding the whole multi stack. There might
+ * still have occurred problems on invidual transfers even when this
+ * returns OK.
+ */
+CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
+ int *running_handles);
+
+ /*
+ * Name: curl_multi_cleanup()
+ *
+ * Desc: Cleans up and removes a whole multi stack. It does not free or
+ * touch any individual easy handles in any way. We need to define
+ * in what state those handles will be if this function is called
+ * in the middle of a transfer.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+
+/*
+ * Name: curl_multi_info_read()
+ *
+ * Desc: Ask the multi handle if there's any messages/informationals from
+ * the individual transfers. Messages include informationals such as
+ * error code from the transfer or just the fact that a transfer is
+ * completed. More details on these should be written down as well.
+ *
+ * Repeated calls to this function will return a new struct each
+ * time, until a special "end of msgs" struct is returned as a signal
+ * that there is no more to get at this point.
+ *
+ * The data the returned pointer points to will not survive calling
+ * curl_multi_cleanup().
+ *
+ * The 'CURLMsg' struct is meant to be very simple and only contain
+ * very basic information. If more involved information is wanted,
+ * we will provide the particular "transfer handle" in that struct
+ * and that should/could/would be used in subsequent
+ * curl_easy_getinfo() calls (or similar). The point being that we
+ * must never expose complex structs to applications, as then we'll
+ * undoubtably get backwards compatibility problems in the future.
+ *
+ * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
+ * of structs. It also writes the number of messages left in the
+ * queue (after this read) in the integer the second argument points
+ * to.
+ */
+CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+ int *msgs_in_queue);
+
+/*
+ * Name: curl_multi_strerror()
+ *
+ * Desc: The curl_multi_strerror function may be used to turn a CURLMcode
+ * value into the equivalent human readable error string. This is
+ * useful for printing meaningful error messages.
+ *
+ * Returns: A pointer to a zero-terminated error message.
+ */
+CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
+
+/*
+ * Name: curl_multi_socket() and
+ * curl_multi_socket_all()
+ *
+ * Desc: An alternative version of curl_multi_perform() that allows the
+ * application to pass in one of the file descriptors that have been
+ * detected to have "action" on them and let libcurl perform.
+ * See man page for details.
+ */
+#define CURL_POLL_NONE 0
+#define CURL_POLL_IN 1
+#define CURL_POLL_OUT 2
+#define CURL_POLL_INOUT 3
+#define CURL_POLL_REMOVE 4
+
+#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
+
+#define CURL_CSELECT_IN 0x01
+#define CURL_CSELECT_OUT 0x02
+#define CURL_CSELECT_ERR 0x04
+
+typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
+ curl_socket_t s, /* socket */
+ int what, /* see above */
+ void *userp, /* private callback
+ pointer */
+ void *socketp); /* private socket
+ pointer */
+/*
+ * Name: curl_multi_timer_callback
+ *
+ * Desc: Called by libcurl whenever the library detects a change in the
+ * maximum number of milliseconds the app is allowed to wait before
+ * curl_multi_socket() or curl_multi_perform() must be called
+ * (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
+ long timeout_ms, /* see above */
+ void *userp); /* private callback
+ pointer */
+
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
+ curl_socket_t s,
+ int ev_bitmask,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
+ int *running_handles);
+
+#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
+/* This macro below was added in 7.16.3 to push users who recompile to use
+ the new curl_multi_socket_action() instead of the old curl_multi_socket()
+*/
+#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
+#endif
+
+/*
+ * Name: curl_multi_timeout()
+ *
+ * Desc: Returns the maximum number of milliseconds the app is allowed to
+ * wait before curl_multi_socket() or curl_multi_perform() must be
+ * called (to allow libcurl's timed events to take place).
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+ long *milliseconds);
+
+#undef CINIT /* re-using the same name as in curl.h */
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
+#endif
+
+typedef enum {
+ /* This is the socket callback function pointer */
+ CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+
+ /* This is the argument passed to the socket callback */
+ CINIT(SOCKETDATA, OBJECTPOINT, 2),
+
+ /* set to 1 to enable pipelining for this multi handle */
+ CINIT(PIPELINING, LONG, 3),
+
+ /* This is the timer callback function pointer */
+ CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+ /* This is the argument passed to the timer callback */
+ CINIT(TIMERDATA, OBJECTPOINT, 5),
+
+ /* maximum number of entries in the connection cache */
+ CINIT(MAXCONNECTS, LONG, 6),
+
+ /* maximum number of (pipelining) connections to one host */
+ CINIT(MAX_HOST_CONNECTIONS, LONG, 7),
+
+ /* maximum number of requests in a pipeline */
+ CINIT(MAX_PIPELINE_LENGTH, LONG, 8),
+
+ /* a connection with a content-length longer than this
+ will not be considered for pipelining */
+ CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9),
+
+ /* a connection with a chunk length longer than this
+ will not be considered for pipelining */
+ CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10),
+
+ /* a list of site names(+port) that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11),
+
+ /* a list of server types that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12),
+
+ /* maximum number of open connections in total */
+ CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
+
+ /* This is the server push callback function pointer */
+ CINIT(PUSHFUNCTION, FUNCTIONPOINT, 14),
+
+ /* This is the argument passed to the server push callback */
+ CINIT(PUSHDATA, OBJECTPOINT, 15),
+
+ CURLMOPT_LASTENTRY /* the last unused */
+} CURLMoption;
+
+
+/*
+ * Name: curl_multi_setopt()
+ *
+ * Desc: Sets options for the multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+ CURLMoption option, ...);
+
+
+/*
+ * Name: curl_multi_assign()
+ *
+ * Desc: This function sets an association in the multi handle between the
+ * given socket and a private pointer of the application. This is
+ * (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+ curl_socket_t sockfd, void *sockp);
+
+
+/*
+ * Name: curl_push_callback
+ *
+ * Desc: This callback gets called when a new stream is being pushed by the
+ * server. It approves or denies the new stream.
+ *
+ * Returns: CURL_PUSH_OK or CURL_PUSH_DENY.
+ */
+#define CURL_PUSH_OK 0
+#define CURL_PUSH_DENY 1
+
+struct curl_pushheaders; /* forward declaration only */
+
+CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
+ size_t num);
+CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
+ const char *name);
+
+typedef int (*curl_push_callback)(CURL *parent,
+ CURL *easy,
+ size_t num_headers,
+ struct curl_pushheaders *headers,
+ void *userp);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/Utilities/cmcurl/include/curl/stdcheaders.h b/Utilities/cmcurl/include/curl/stdcheaders.h
new file mode 100644
index 000000000..027b6f421
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/stdcheaders.h
@@ -0,0 +1,33 @@
+#ifndef __STDC_HEADERS_H
+#define __STDC_HEADERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <sys/types.h>
+
+size_t fread(void *, size_t, size_t, FILE *);
+size_t fwrite(const void *, size_t, size_t, FILE *);
+
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size_t);
+
+#endif /* __STDC_HEADERS_H */
diff --git a/Utilities/cmcurl/include/curl/system.h b/Utilities/cmcurl/include/curl/system.h
new file mode 100644
index 000000000..ed3a55c95
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/system.h
@@ -0,0 +1,484 @@
+#ifndef __CURL_SYSTEM_H
+#define __CURL_SYSTEM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This header is supposed to eventually replace curlbuild.h. This little one
+ * is still learning. During the experimental phase, this header files
+ * defines symbols using the prefixes CURLSYS_ or curlsys_. When we feel
+ * confident enough, we replace curlbuild.h with this file and rename all
+ * prefixes to CURL_ and curl_.
+ */
+
+/*
+ * Try to keep one section per platform, compiler and architecture, otherwise,
+ * if an existing section is reused for a different one and later on the
+ * original is adjusted, probably the piggybacking one can be adversely
+ * changed.
+ *
+ * In order to differentiate between platforms/compilers/architectures use
+ * only compiler built in predefined preprocessor symbols.
+ *
+ * curl_off_t
+ * ----------
+ *
+ * For any given platform/compiler curl_off_t must be typedef'ed to a 64-bit
+ * wide signed integral data type. The width of this data type must remain
+ * constant and independent of any possible large file support settings.
+ *
+ * As an exception to the above, curl_off_t shall be typedef'ed to a 32-bit
+ * wide signed integral data type if there is no 64-bit type.
+ *
+ * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
+ * only be violated if off_t is the only 64-bit data type available and the
+ * size of off_t is independent of large file support settings. Keep your
+ * build on the safe side avoiding an off_t gating. If you have a 64-bit
+ * off_t then take for sure that another 64-bit data type exists, dig deeper
+ * and you will find it.
+ *
+ */
+
+#if defined(__DJGPP__) || defined(__GO32__)
+# if defined(__DJGPP__) && (__DJGPP__ > 1)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SALFORDC__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__BORLANDC__)
+# if (__BORLANDC__ < 0x520)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T i64
+# define CURLSYS_SUFFIX_CURL_OFF_TU ui64
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__TURBOC__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__WATCOMC__)
+# if defined(__386__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T i64
+# define CURLSYS_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__POCC__)
+# if (__POCC__ < 280)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# elif defined(_MSC_VER)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T i64
+# define CURLSYS_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__LCC__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SYMBIAN32__)
+# if defined(__EABI__) /* Treat all ARM compilers equally */
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__CW32__)
+# pragma longlong on
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__VC32__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MWERKS__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(_WIN32_WCE)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T i64
+# define CURLSYS_SUFFIX_CURL_OFF_TU ui64
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MINGW32__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_WS2TCPIP_H 1
+
+#elif defined(__VMS)
+# if defined(__VAX)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__OS400__)
+# if defined(__ILEC400__)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__MVS__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURLSYS_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURLSYS_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__370__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURLSYS_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURLSYS_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(TPF)
+# define CURLSYS_SIZEOF_LONG 8
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__TINYC__) /* also known as tcc */
+
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_SYS_SOCKET_H 1
+
+/* ===================================== */
+/* KEEP MSVC THE PENULTIMATE ENTRY */
+/* ===================================== */
+
+#elif defined(_MSC_VER)
+# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T __int64
+# define CURLSYS_FORMAT_CURL_OFF_T "I64d"
+# define CURLSYS_FORMAT_CURL_OFF_TU "I64u"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T i64
+# define CURLSYS_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+
+/* ===================================== */
+/* KEEP GENERIC GCC THE LAST ENTRY */
+/* ===================================== */
+
+#elif defined(__GNUC__)
+# if !defined(__LP64__) && (defined(__ILP32__) || \
+ defined(__i386__) || defined(__ppc__) || defined(__arm__) || \
+ defined(__sparc__) || defined(__mips__) || defined(__sh__))
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long long
+# define CURLSYS_FORMAT_CURL_OFF_T "lld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "llu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T LL
+# define CURLSYS_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__LP64__) || \
+ defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__)
+# define CURLSYS_SIZEOF_LONG 8
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SIZEOF_CURL_OFF_T 8
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_PULL_SYS_TYPES_H 1
+# define CURLSYS_PULL_SYS_SOCKET_H 1
+
+#else
+/* generic "safe guess" on old 32 bit style */
+# define CURLSYS_SIZEOF_LONG 4
+# define CURLSYS_SIZEOF_CURL_SOCKLEN_T 4
+# define CURLSYS_SIZEOF_CURL_OFF_T 4
+# define CURLSYS_TYPEOF_CURL_OFF_T long
+# define CURLSYS_FORMAT_CURL_OFF_T "ld"
+# define CURLSYS_FORMAT_CURL_OFF_TU "lu"
+# define CURLSYS_SUFFIX_CURL_OFF_T L
+# define CURLSYS_SUFFIX_CURL_OFF_TU UL
+# define CURLSYS_TYPEOF_CURL_SOCKLEN_T int
+#endif
+
+/* CURLSYS_PULL_WS2TCPIP_H is defined above when inclusion of header file */
+/* ws2tcpip.h is required here to properly make type definitions below. */
+#ifdef CURLSYS_PULL_WS2TCPIP_H
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# include <winsock2.h>
+# include <ws2tcpip.h>
+#endif
+
+/* CURLSYS_PULL_SYS_TYPES_H is defined above when inclusion of header file */
+/* sys/types.h is required here to properly make type definitions below. */
+#ifdef CURLSYS_PULL_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+/* CURLSYS_PULL_SYS_SOCKET_H is defined above when inclusion of header file */
+/* sys/socket.h is required here to properly make type definitions below. */
+#ifdef CURLSYS_PULL_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+#ifdef CURLSYS_TYPEOF_CURL_SOCKLEN_T
+ typedef CURLSYS_TYPEOF_CURL_SOCKLEN_T curlsys_socklen_t;
+#endif
+
+/* Data type definition of curl_off_t. */
+
+#ifdef CURLSYS_TYPEOF_CURL_OFF_T
+ typedef CURLSYS_TYPEOF_CURL_OFF_T curlsys_off_t;
+#endif
+
+#endif /* __CURL_SYSTEM_H */
+
diff --git a/Utilities/cmcurl/include/curl/typecheck-gcc.h b/Utilities/cmcurl/include/curl/typecheck-gcc.h
new file mode 100644
index 000000000..10b5de2ab
--- /dev/null
+++ b/Utilities/cmcurl/include/curl/typecheck-gcc.h
@@ -0,0 +1,668 @@
+#ifndef __CURL_TYPECHECK_GCC_H
+#define __CURL_TYPECHECK_GCC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* wraps curl_easy_setopt() with typechecking */
+
+/* To add a new kind of warning, add an
+ * if(_curl_is_sometype_option(_curl_opt))
+ * if(!_curl_is_sometype(value))
+ * _curl_easy_setopt_err_sometype();
+ * block and define _curl_is_sometype_option, _curl_is_sometype and
+ * _curl_easy_setopt_err_sometype below
+ *
+ * NOTE: We use two nested 'if' statements here instead of the && operator, in
+ * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
+ * when compiling with -Wlogical-op.
+ *
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
+ */
+#define curl_easy_setopt(handle, option, value) \
+__extension__ ({ \
+ __typeof__(option) _curl_opt = option; \
+ if(__builtin_constant_p(_curl_opt)) { \
+ if(_curl_is_long_option(_curl_opt)) \
+ if(!_curl_is_long(value)) \
+ _curl_easy_setopt_err_long(); \
+ if(_curl_is_off_t_option(_curl_opt)) \
+ if(!_curl_is_off_t(value)) \
+ _curl_easy_setopt_err_curl_off_t(); \
+ if(_curl_is_string_option(_curl_opt)) \
+ if(!_curl_is_string(value)) \
+ _curl_easy_setopt_err_string(); \
+ if(_curl_is_write_cb_option(_curl_opt)) \
+ if(!_curl_is_write_cb(value)) \
+ _curl_easy_setopt_err_write_callback(); \
+ if((_curl_opt) == CURLOPT_READFUNCTION) \
+ if(!_curl_is_read_cb(value)) \
+ _curl_easy_setopt_err_read_cb(); \
+ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
+ if(!_curl_is_ioctl_cb(value)) \
+ _curl_easy_setopt_err_ioctl_cb(); \
+ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
+ if(!_curl_is_sockopt_cb(value)) \
+ _curl_easy_setopt_err_sockopt_cb(); \
+ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
+ if(!_curl_is_opensocket_cb(value)) \
+ _curl_easy_setopt_err_opensocket_cb(); \
+ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
+ if(!_curl_is_progress_cb(value)) \
+ _curl_easy_setopt_err_progress_cb(); \
+ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
+ if(!_curl_is_debug_cb(value)) \
+ _curl_easy_setopt_err_debug_cb(); \
+ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
+ if(!_curl_is_ssl_ctx_cb(value)) \
+ _curl_easy_setopt_err_ssl_ctx_cb(); \
+ if(_curl_is_conv_cb_option(_curl_opt)) \
+ if(!_curl_is_conv_cb(value)) \
+ _curl_easy_setopt_err_conv_cb(); \
+ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
+ if(!_curl_is_seek_cb(value)) \
+ _curl_easy_setopt_err_seek_cb(); \
+ if(_curl_is_cb_data_option(_curl_opt)) \
+ if(!_curl_is_cb_data(value)) \
+ _curl_easy_setopt_err_cb_data(); \
+ if((_curl_opt) == CURLOPT_ERRORBUFFER) \
+ if(!_curl_is_error_buffer(value)) \
+ _curl_easy_setopt_err_error_buffer(); \
+ if((_curl_opt) == CURLOPT_STDERR) \
+ if(!_curl_is_FILE(value)) \
+ _curl_easy_setopt_err_FILE(); \
+ if(_curl_is_postfields_option(_curl_opt)) \
+ if(!_curl_is_postfields(value)) \
+ _curl_easy_setopt_err_postfields(); \
+ if((_curl_opt) == CURLOPT_HTTPPOST) \
+ if(!_curl_is_arr((value), struct curl_httppost)) \
+ _curl_easy_setopt_err_curl_httpost(); \
+ if(_curl_is_slist_option(_curl_opt)) \
+ if(!_curl_is_arr((value), struct curl_slist)) \
+ _curl_easy_setopt_err_curl_slist(); \
+ if((_curl_opt) == CURLOPT_SHARE) \
+ if(!_curl_is_ptr((value), CURLSH)) \
+ _curl_easy_setopt_err_CURLSH(); \
+ } \
+ curl_easy_setopt(handle, _curl_opt, value); \
+})
+
+/* wraps curl_easy_getinfo() with typechecking */
+/* FIXME: don't allow const pointers */
+#define curl_easy_getinfo(handle, info, arg) \
+__extension__ ({ \
+ __typeof__(info) _curl_info = info; \
+ if(__builtin_constant_p(_curl_info)) { \
+ if(_curl_is_string_info(_curl_info)) \
+ if(!_curl_is_arr((arg), char *)) \
+ _curl_easy_getinfo_err_string(); \
+ if(_curl_is_long_info(_curl_info)) \
+ if(!_curl_is_arr((arg), long)) \
+ _curl_easy_getinfo_err_long(); \
+ if(_curl_is_double_info(_curl_info)) \
+ if(!_curl_is_arr((arg), double)) \
+ _curl_easy_getinfo_err_double(); \
+ if(_curl_is_slist_info(_curl_info)) \
+ if(!_curl_is_arr((arg), struct curl_slist *)) \
+ _curl_easy_getinfo_err_curl_slist(); \
+ if(_curl_is_tlssessioninfo_info(_curl_info)) \
+ if(!_curl_is_arr((arg), struct curl_tlssessioninfo *)) \
+ _curl_easy_getinfo_err_curl_tlssesssioninfo(); \
+ if(_curl_is_certinfo_info(_curl_info)) \
+ if(!_curl_is_arr((arg), struct curl_certinfo *)) \
+ _curl_easy_getinfo_err_curl_certinfo(); \
+ if(_curl_is_socket_info(_curl_info)) \
+ if(!_curl_is_arr((arg), curl_socket_t)) \
+ _curl_easy_getinfo_err_curl_socket(); \
+ } \
+ curl_easy_getinfo(handle, _curl_info, arg); \
+})
+
+/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
+ * for now just make sure that the functions are called with three
+ * arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
+/* the actual warnings, triggered by calling the _curl_easy_setopt_err*
+ * functions */
+
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
+#define _CURL_WARNING(id, message) \
+ static void __attribute__((__warning__(message))) \
+ __attribute__((__unused__)) __attribute__((__noinline__)) \
+ id(void) { __asm__(""); }
+
+_CURL_WARNING(_curl_easy_setopt_err_long,
+ "curl_easy_setopt expects a long argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
+ "curl_easy_setopt expects a curl_off_t argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_string,
+ "curl_easy_setopt expects a "
+ "string ('char *' or char[]) argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_write_callback,
+ "curl_easy_setopt expects a curl_write_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_read_cb,
+ "curl_easy_setopt expects a curl_read_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
+ "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
+ "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
+ "curl_easy_setopt expects a "
+ "curl_opensocket_callback argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
+ "curl_easy_setopt expects a curl_progress_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
+ "curl_easy_setopt expects a curl_debug_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+ "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
+ "curl_easy_setopt expects a curl_conv_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
+ "curl_easy_setopt expects a curl_seek_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_cb_data,
+ "curl_easy_setopt expects a "
+ "private data pointer as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
+ "curl_easy_setopt expects a "
+ "char buffer of CURL_ERROR_SIZE as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_FILE,
+ "curl_easy_setopt expects a 'FILE *' argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_postfields,
+ "curl_easy_setopt expects a 'void *' or 'char *' argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
+ "curl_easy_setopt expects a 'struct curl_httppost *' "
+ "argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
+ "curl_easy_setopt expects a 'struct curl_slist *' argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
+ "curl_easy_setopt expects a CURLSH* argument for this option")
+
+_CURL_WARNING(_curl_easy_getinfo_err_string,
+ "curl_easy_getinfo expects a pointer to 'char *' for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_long,
+ "curl_easy_getinfo expects a pointer to long for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_double,
+ "curl_easy_getinfo expects a pointer to double for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
+ "curl_easy_getinfo expects a pointer to 'struct curl_slist *' for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_tlssesssioninfo,
+ "curl_easy_getinfo expects a pointer to "
+ "'struct curl_tlssessioninfo *' for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_certinfo,
+ "curl_easy_getinfo expects a pointer to "
+ "'struct curl_certinfo *' for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_socket,
+ "curl_easy_getinfo expects a pointer to curl_socket_t for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
+
+/* To add a new option to one of the groups, just add
+ * (option) == CURLOPT_SOMETHING
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * have to do anything
+ */
+
+/* evaluates to true if option takes a long argument */
+#define _curl_is_long_option(option) \
+ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
+
+#define _curl_is_off_t_option(option) \
+ ((option) > CURLOPTTYPE_OFF_T)
+
+/* evaluates to true if option takes a char* argument */
+#define _curl_is_string_option(option) \
+ ((option) == CURLOPT_ABSTRACT_UNIX_SOCKET || \
+ (option) == CURLOPT_ACCEPT_ENCODING || \
+ (option) == CURLOPT_CAINFO || \
+ (option) == CURLOPT_CAPATH || \
+ (option) == CURLOPT_COOKIE || \
+ (option) == CURLOPT_COOKIEFILE || \
+ (option) == CURLOPT_COOKIEJAR || \
+ (option) == CURLOPT_COOKIELIST || \
+ (option) == CURLOPT_CRLFILE || \
+ (option) == CURLOPT_CUSTOMREQUEST || \
+ (option) == CURLOPT_DEFAULT_PROTOCOL || \
+ (option) == CURLOPT_DNS_INTERFACE || \
+ (option) == CURLOPT_DNS_LOCAL_IP4 || \
+ (option) == CURLOPT_DNS_LOCAL_IP6 || \
+ (option) == CURLOPT_DNS_SERVERS || \
+ (option) == CURLOPT_EGDSOCKET || \
+ (option) == CURLOPT_FTPPORT || \
+ (option) == CURLOPT_FTP_ACCOUNT || \
+ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
+ (option) == CURLOPT_INTERFACE || \
+ (option) == CURLOPT_ISSUERCERT || \
+ (option) == CURLOPT_KEYPASSWD || \
+ (option) == CURLOPT_KRBLEVEL || \
+ (option) == CURLOPT_LOGIN_OPTIONS || \
+ (option) == CURLOPT_MAIL_AUTH || \
+ (option) == CURLOPT_MAIL_FROM || \
+ (option) == CURLOPT_NETRC_FILE || \
+ (option) == CURLOPT_NOPROXY || \
+ (option) == CURLOPT_PASSWORD || \
+ (option) == CURLOPT_PINNEDPUBLICKEY || \
+ (option) == CURLOPT_PRE_PROXY || \
+ (option) == CURLOPT_PROXY || \
+ (option) == CURLOPT_PROXYPASSWORD || \
+ (option) == CURLOPT_PROXYUSERNAME || \
+ (option) == CURLOPT_PROXYUSERPWD || \
+ (option) == CURLOPT_PROXY_CAINFO || \
+ (option) == CURLOPT_PROXY_CAPATH || \
+ (option) == CURLOPT_PROXY_CRLFILE || \
+ (option) == CURLOPT_PROXY_KEYPASSWD || \
+ (option) == CURLOPT_PROXY_PINNEDPUBLICKEY || \
+ (option) == CURLOPT_PROXY_SERVICE_NAME || \
+ (option) == CURLOPT_PROXY_SSLCERT || \
+ (option) == CURLOPT_PROXY_SSLCERTTYPE || \
+ (option) == CURLOPT_PROXY_SSLKEY || \
+ (option) == CURLOPT_PROXY_SSLKEYTYPE || \
+ (option) == CURLOPT_PROXY_SSL_CIPHER_LIST || \
+ (option) == CURLOPT_PROXY_TLSAUTH_PASSWORD || \
+ (option) == CURLOPT_PROXY_TLSAUTH_USERNAME || \
+ (option) == CURLOPT_PROXY_TLSAUTH_TYPE || \
+ (option) == CURLOPT_RANDOM_FILE || \
+ (option) == CURLOPT_RANGE || \
+ (option) == CURLOPT_REFERER || \
+ (option) == CURLOPT_RTSP_SESSION_ID || \
+ (option) == CURLOPT_RTSP_STREAM_URI || \
+ (option) == CURLOPT_RTSP_TRANSPORT || \
+ (option) == CURLOPT_SERVICE_NAME || \
+ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
+ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
+ (option) == CURLOPT_SSH_KNOWNHOSTS || \
+ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
+ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
+ (option) == CURLOPT_SSLCERT || \
+ (option) == CURLOPT_SSLCERTTYPE || \
+ (option) == CURLOPT_SSLENGINE || \
+ (option) == CURLOPT_SSLKEY || \
+ (option) == CURLOPT_SSLKEYTYPE || \
+ (option) == CURLOPT_SSL_CIPHER_LIST || \
+ (option) == CURLOPT_TLSAUTH_PASSWORD || \
+ (option) == CURLOPT_TLSAUTH_TYPE || \
+ (option) == CURLOPT_TLSAUTH_USERNAME || \
+ (option) == CURLOPT_UNIX_SOCKET_PATH || \
+ (option) == CURLOPT_URL || \
+ (option) == CURLOPT_USERAGENT || \
+ (option) == CURLOPT_USERNAME || \
+ (option) == CURLOPT_USERPWD || \
+ (option) == CURLOPT_XOAUTH2_BEARER || \
+ 0)
+
+/* evaluates to true if option takes a curl_write_callback argument */
+#define _curl_is_write_cb_option(option) \
+ ((option) == CURLOPT_HEADERFUNCTION || \
+ (option) == CURLOPT_WRITEFUNCTION)
+
+/* evaluates to true if option takes a curl_conv_callback argument */
+#define _curl_is_conv_cb_option(option) \
+ ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
+
+/* evaluates to true if option takes a data argument to pass to a callback */
+#define _curl_is_cb_data_option(option) \
+ ((option) == CURLOPT_CHUNK_DATA || \
+ (option) == CURLOPT_CLOSESOCKETDATA || \
+ (option) == CURLOPT_DEBUGDATA || \
+ (option) == CURLOPT_FNMATCH_DATA || \
+ (option) == CURLOPT_HEADERDATA || \
+ (option) == CURLOPT_INTERLEAVEDATA || \
+ (option) == CURLOPT_IOCTLDATA || \
+ (option) == CURLOPT_OPENSOCKETDATA || \
+ (option) == CURLOPT_PRIVATE || \
+ (option) == CURLOPT_PROGRESSDATA || \
+ (option) == CURLOPT_READDATA || \
+ (option) == CURLOPT_SEEKDATA || \
+ (option) == CURLOPT_SOCKOPTDATA || \
+ (option) == CURLOPT_SSH_KEYDATA || \
+ (option) == CURLOPT_SSL_CTX_DATA || \
+ (option) == CURLOPT_WRITEDATA || \
+ 0)
+
+/* evaluates to true if option takes a POST data argument (void* or char*) */
+#define _curl_is_postfields_option(option) \
+ ((option) == CURLOPT_POSTFIELDS || \
+ (option) == CURLOPT_COPYPOSTFIELDS || \
+ 0)
+
+/* evaluates to true if option takes a struct curl_slist * argument */
+#define _curl_is_slist_option(option) \
+ ((option) == CURLOPT_HTTP200ALIASES || \
+ (option) == CURLOPT_HTTPHEADER || \
+ (option) == CURLOPT_MAIL_RCPT || \
+ (option) == CURLOPT_POSTQUOTE || \
+ (option) == CURLOPT_PREQUOTE || \
+ (option) == CURLOPT_PROXYHEADER || \
+ (option) == CURLOPT_QUOTE || \
+ (option) == CURLOPT_RESOLVE || \
+ (option) == CURLOPT_TELNETOPTIONS || \
+ 0)
+
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define _curl_is_string_info(info) \
+ (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define _curl_is_long_info(info) \
+ (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define _curl_is_double_info(info) \
+ (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* true if info expects a pointer to struct curl_slist * argument */
+#define _curl_is_slist_info(info) \
+ (((info) == CURLINFO_SSL_ENGINES) || ((info) == CURLINFO_COOKIELIST))
+
+/* true if info expects a pointer to struct curl_tlssessioninfo * argument */
+#define _curl_is_tlssessioninfo_info(info) \
+ (((info) == CURLINFO_TLS_SSL_PTR) || ((info) == CURLINFO_TLS_SESSION))
+
+/* true if info expects a pointer to struct curl_certinfo * argument */
+#define _curl_is_certinfo_info(info) ((info) == CURLINFO_CERTINFO)
+
+/* true if info expects a pointer to struct curl_socket_t argument */
+#define _curl_is_socket_info(info) \
+ (CURLINFO_SOCKET < (info))
+
+
+/* typecheck helpers -- check whether given expression has requested type*/
+
+/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
+ */
+
+/* XXX: should evaluate to true iff expr is a pointer */
+#define _curl_is_any_ptr(expr) \
+ (sizeof(expr) == sizeof(void *))
+
+/* evaluates to true if expr is NULL */
+/* XXX: must not evaluate expr, so this check is not accurate */
+#define _curl_is_NULL(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
+
+/* evaluates to true if expr is type*, const type* or NULL */
+#define _curl_is_ptr(expr, type) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), type *) || \
+ __builtin_types_compatible_p(__typeof__(expr), const type *))
+
+/* evaluates to true if expr is one of type[], type*, NULL or const type* */
+#define _curl_is_arr(expr, type) \
+ (_curl_is_ptr((expr), type) || \
+ __builtin_types_compatible_p(__typeof__(expr), type []))
+
+/* evaluates to true if expr is a string */
+#define _curl_is_string(expr) \
+ (_curl_is_arr((expr), char) || \
+ _curl_is_arr((expr), signed char) || \
+ _curl_is_arr((expr), unsigned char))
+
+/* evaluates to true if expr is a long (no matter the signedness)
+ * XXX: for now, int is also accepted (and therefore short and char, which
+ * are promoted to int when passed to a variadic function) */
+#define _curl_is_long(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), long) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed long) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \
+ __builtin_types_compatible_p(__typeof__(expr), int) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed int) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \
+ __builtin_types_compatible_p(__typeof__(expr), short) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed short) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \
+ __builtin_types_compatible_p(__typeof__(expr), char) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed char) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+
+/* evaluates to true if expr is of type curl_off_t */
+#define _curl_is_off_t(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
+
+/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
+/* XXX: also check size of an char[] array? */
+#define _curl_is_error_buffer(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), char *) || \
+ __builtin_types_compatible_p(__typeof__(expr), char[]))
+
+/* evaluates to true if expr is of type (const) void* or (const) FILE* */
+#if 0
+#define _curl_is_cb_data(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_ptr((expr), FILE))
+#else /* be less strict */
+#define _curl_is_cb_data(expr) \
+ _curl_is_any_ptr(expr)
+#endif
+
+/* evaluates to true if expr is of type FILE* */
+#define _curl_is_FILE(expr) \
+ (_curl_is_NULL(expr) || \
+ (__builtin_types_compatible_p(__typeof__(expr), FILE *)))
+
+/* evaluates to true if expr can be passed as POST data (void* or char*) */
+#define _curl_is_postfields(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_arr((expr), char))
+
+/* FIXME: the whole callback checking is messy...
+ * The idea is to tolerate char vs. void and const vs. not const
+ * pointers in arguments at least
+ */
+/* helper: __builtin_types_compatible_p distinguishes between functions and
+ * function pointers, hide it */
+#define _curl_callback_compatible(func, type) \
+ (__builtin_types_compatible_p(__typeof__(func), type) || \
+ __builtin_types_compatible_p(__typeof__(func) *, type))
+
+/* evaluates to true if expr is of type curl_read_callback or "similar" */
+#define _curl_is_read_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), __typeof__(fread) *) || \
+ _curl_callback_compatible((expr), curl_read_callback) || \
+ _curl_callback_compatible((expr), _curl_read_callback1) || \
+ _curl_callback_compatible((expr), _curl_read_callback2) || \
+ _curl_callback_compatible((expr), _curl_read_callback3) || \
+ _curl_callback_compatible((expr), _curl_read_callback4) || \
+ _curl_callback_compatible((expr), _curl_read_callback5) || \
+ _curl_callback_compatible((expr), _curl_read_callback6))
+typedef size_t (*_curl_read_callback1)(char *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback2)(char *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback3)(char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_read_callback4)(void *, size_t, size_t, void *);
+typedef size_t (*_curl_read_callback5)(void *, size_t, size_t, const void *);
+typedef size_t (*_curl_read_callback6)(void *, size_t, size_t, FILE *);
+
+/* evaluates to true if expr is of type curl_write_callback or "similar" */
+#define _curl_is_write_cb(expr) \
+ (_curl_is_read_cb(expr) || \
+ _curl_callback_compatible((expr), __typeof__(fwrite) *) || \
+ _curl_callback_compatible((expr), curl_write_callback) || \
+ _curl_callback_compatible((expr), _curl_write_callback1) || \
+ _curl_callback_compatible((expr), _curl_write_callback2) || \
+ _curl_callback_compatible((expr), _curl_write_callback3) || \
+ _curl_callback_compatible((expr), _curl_write_callback4) || \
+ _curl_callback_compatible((expr), _curl_write_callback5) || \
+ _curl_callback_compatible((expr), _curl_write_callback6))
+typedef size_t (*_curl_write_callback1)(const char *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback2)(const char *, size_t, size_t,
+ const void *);
+typedef size_t (*_curl_write_callback3)(const char *, size_t, size_t, FILE *);
+typedef size_t (*_curl_write_callback4)(const void *, size_t, size_t, void *);
+typedef size_t (*_curl_write_callback5)(const void *, size_t, size_t,
+ const void *);
+typedef size_t (*_curl_write_callback6)(const void *, size_t, size_t, FILE *);
+
+/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
+#define _curl_is_ioctl_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_ioctl_callback) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback1) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback2) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback3) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (*_curl_ioctl_callback1)(CURL *, int, void *);
+typedef curlioerr (*_curl_ioctl_callback2)(CURL *, int, const void *);
+typedef curlioerr (*_curl_ioctl_callback3)(CURL *, curliocmd, void *);
+typedef curlioerr (*_curl_ioctl_callback4)(CURL *, curliocmd, const void *);
+
+/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
+#define _curl_is_sockopt_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_sockopt_callback) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback1) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback2))
+typedef int (*_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (*_curl_sockopt_callback2)(const void *, curl_socket_t,
+ curlsocktype);
+
+/* evaluates to true if expr is of type curl_opensocket_callback or
+ "similar" */
+#define _curl_is_opensocket_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_opensocket_callback) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback1) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback2) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback3) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (*_curl_opensocket_callback1)
+ (void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback2)
+ (void *, curlsocktype, const struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback3)
+ (const void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (*_curl_opensocket_callback4)
+ (const void *, curlsocktype, const struct curl_sockaddr *);
+
+/* evaluates to true if expr is of type curl_progress_callback or "similar" */
+#define _curl_is_progress_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_progress_callback) || \
+ _curl_callback_compatible((expr), _curl_progress_callback1) || \
+ _curl_callback_compatible((expr), _curl_progress_callback2))
+typedef int (*_curl_progress_callback1)(void *,
+ double, double, double, double);
+typedef int (*_curl_progress_callback2)(const void *,
+ double, double, double, double);
+
+/* evaluates to true if expr is of type curl_debug_callback or "similar" */
+#define _curl_is_debug_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_debug_callback) || \
+ _curl_callback_compatible((expr), _curl_debug_callback1) || \
+ _curl_callback_compatible((expr), _curl_debug_callback2) || \
+ _curl_callback_compatible((expr), _curl_debug_callback3) || \
+ _curl_callback_compatible((expr), _curl_debug_callback4) || \
+ _curl_callback_compatible((expr), _curl_debug_callback5) || \
+ _curl_callback_compatible((expr), _curl_debug_callback6) || \
+ _curl_callback_compatible((expr), _curl_debug_callback7) || \
+ _curl_callback_compatible((expr), _curl_debug_callback8))
+typedef int (*_curl_debug_callback1) (CURL *,
+ curl_infotype, char *, size_t, void *);
+typedef int (*_curl_debug_callback2) (CURL *,
+ curl_infotype, char *, size_t, const void *);
+typedef int (*_curl_debug_callback3) (CURL *,
+ curl_infotype, const char *, size_t, void *);
+typedef int (*_curl_debug_callback4) (CURL *,
+ curl_infotype, const char *, size_t, const void *);
+typedef int (*_curl_debug_callback5) (CURL *,
+ curl_infotype, unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback6) (CURL *,
+ curl_infotype, unsigned char *, size_t, const void *);
+typedef int (*_curl_debug_callback7) (CURL *,
+ curl_infotype, const unsigned char *, size_t, void *);
+typedef int (*_curl_debug_callback8) (CURL *,
+ curl_infotype, const unsigned char *, size_t, const void *);
+
+/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
+/* this is getting even messier... */
+#define _curl_is_ssl_ctx_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_ssl_ctx_callback) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (*_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
+ const void *);
+#ifdef HEADER_SSL_H
+/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
+ * this will of course break if we're included before OpenSSL headers...
+ */
+typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
+ const void *);
+#else
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
+#endif
+
+/* evaluates to true if expr is of type curl_conv_callback or "similar" */
+#define _curl_is_conv_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_conv_callback) || \
+ _curl_callback_compatible((expr), _curl_conv_callback1) || \
+ _curl_callback_compatible((expr), _curl_conv_callback2) || \
+ _curl_callback_compatible((expr), _curl_conv_callback3) || \
+ _curl_callback_compatible((expr), _curl_conv_callback4))
+typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
+typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
+typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
+typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
+
+/* evaluates to true if expr is of type curl_seek_callback or "similar" */
+#define _curl_is_seek_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ _curl_callback_compatible((expr), curl_seek_callback) || \
+ _curl_callback_compatible((expr), _curl_seek_callback1) || \
+ _curl_callback_compatible((expr), _curl_seek_callback2))
+typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
+typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
+
+
+#endif /* __CURL_TYPECHECK_GCC_H */
diff --git a/Utilities/cmcurl/inet_ntoa_r.h b/Utilities/cmcurl/inet_ntoa_r.h
deleted file mode 100644
index c6c9bd895..000000000
--- a/Utilities/cmcurl/inet_ntoa_r.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __INET_NTOA_R_H
-#define __INET_NTOA_R_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifdef HAVE_INET_NTOA_R_2_ARGS
-/*
- * uClibc 0.9.26 (at least) doesn't define this prototype. The buffer
- * must be at least 16 characters long.
- */
-char *inet_ntoa_r(const struct in_addr in, char buffer[]);
-
-#else
-/*
- * My solaris 5.6 system running gcc 2.8.1 does *not* have this prototype
- * in any system include file! Isn't that weird?
- */
-char *inet_ntoa_r(const struct in_addr in, char *buffer, int buflen);
-
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/inet_ntop.c b/Utilities/cmcurl/inet_ntop.c
deleted file mode 100644
index 9381963f5..000000000
--- a/Utilities/cmcurl/inet_ntop.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (C) 1996-2001 Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * Original code by Paul Vixie. "curlified" by Gisle Vanem.
- */
-
-#include "setup.h"
-
-#ifndef HAVE_INET_NTOP
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#include <string.h>
-#include <errno.h>
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "inet_ntop.h"
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-/* this platform has a inet_ntoa_r() function, but no proto declared anywhere
- so we include our own proto to make compilers happy */
-#include "inet_ntoa_r.h"
-#endif
-
-#define IN6ADDRSZ 16
-#define INADDRSZ 4
-#define INT16SZ 2
-
-#ifdef USE_WINSOCK
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-#define SET_ERRNO(e) WSASetLastError(errno = (e))
-#else
-#define SET_ERRNO(e) errno = e
-#endif
-
-/*
- * Format an IPv4 address, more or less like inet_ntoa().
- *
- * Returns `dst' (as a const)
- * Note:
- * - uses no statics
- * - takes a unsigned char* not an in_addr as input
- */
-static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
-{
-#if defined(HAVE_INET_NTOA_R_2_ARGS)
- const char *ptr;
- curlassert(size >= 16);
- ptr = inet_ntoa_r(*(struct in_addr*)src, dst);
- return (char *)memmove(dst, ptr, strlen(ptr)+1);
-
-#elif defined(HAVE_INET_NTOA_R)
- return inet_ntoa_r(*(struct in_addr*)src, dst, size);
-
-#else
- const char *addr = inet_ntoa(*(struct in_addr*)src);
-
- if (strlen(addr) >= size)
- {
- SET_ERRNO(ENOSPC);
- return (NULL);
- }
- return strcpy(dst, addr);
-#endif
-}
-
-#ifdef ENABLE_IPV6
-/*
- * Convert IPv6 binary address into presentation (printable) format.
- */
-static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
-{
- /*
- * Note that int32_t and int16_t need only be "at least" large enough
- * to contain a value of the specified size. On some systems, like
- * Crays, there is no such thing as an integer variable with 16 bits.
- * Keep this in mind if you think this function should have been coded
- * to use pointer overlays. All the world's not a VAX.
- */
- char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
- char *tp;
- struct {
- long base;
- long len;
- } best, cur;
- unsigned long words[IN6ADDRSZ / INT16SZ];
- int i;
-
- /* Preprocess:
- * Copy the input (bytewise) array into a wordwise array.
- * Find the longest run of 0x00's in src[] for :: shorthanding.
- */
- memset(words, '\0', sizeof(words));
- for (i = 0; i < IN6ADDRSZ; i++)
- words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
-
- best.base = -1;
- cur.base = -1;
- best.len = 0;
- cur.len = 0;
-
- for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
- {
- if (words[i] == 0)
- {
- if (cur.base == -1)
- cur.base = i, cur.len = 1;
- else
- cur.len++;
- }
- else if (cur.base != -1)
- {
- if (best.base == -1 || cur.len > best.len)
- best = cur;
- cur.base = -1;
- }
- }
- if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
- best = cur;
- if (best.base != -1 && best.len < 2)
- best.base = -1;
-
- /* Format the result.
- */
- tp = tmp;
- for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++)
- {
- /* Are we inside the best run of 0x00's?
- */
- if (best.base != -1 && i >= best.base && i < (best.base + best.len))
- {
- if (i == best.base)
- *tp++ = ':';
- continue;
- }
-
- /* Are we following an initial run of 0x00s or any real hex?
- */
- if (i != 0)
- *tp++ = ':';
-
- /* Is this address an encapsulated IPv4?
- */
- if (i == 6 && best.base == 0 &&
- (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
- {
- if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp)))
- {
- SET_ERRNO(ENOSPC);
- return (NULL);
- }
- tp += strlen(tp);
- break;
- }
- tp += snprintf(tp, 5, "%lx", words[i]);
- }
-
- /* Was it a trailing run of 0x00's?
- */
- if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
- *tp++ = ':';
- *tp++ = '\0';
-
- /* Check for overflow, copy, and we're done.
- */
- if ((size_t)(tp - tmp) > size)
- {
- SET_ERRNO(ENOSPC);
- return (NULL);
- }
- return strcpy (dst, tmp);
-}
-#endif /* ENABLE_IPV6 */
-
-/*
- * Convert a network format address to presentation format.
- *
- * Returns pointer to presentation format address (`buf'),
- * Returns NULL on error (see errno).
- */
-char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
-{
- switch (af) {
- case AF_INET:
- return inet_ntop4((const unsigned char*)src, buf, size);
-#ifdef ENABLE_IPV6
- case AF_INET6:
- return inet_ntop6((const unsigned char*)src, buf, size);
-#endif
- default:
- SET_ERRNO(EAFNOSUPPORT);
- return NULL;
- }
-}
-#endif /* HAVE_INET_NTOP */
diff --git a/Utilities/cmcurl/inet_ntop.h b/Utilities/cmcurl/inet_ntop.h
deleted file mode 100644
index 54d64bd19..000000000
--- a/Utilities/cmcurl/inet_ntop.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __INET_NTOP_H
-#define __INET_NTOP_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
-
-#ifdef HAVE_INET_NTOP
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#define Curl_inet_ntop(af,addr,buf,size) inet_ntop(af,addr,buf,size)
-#endif
-
-#endif /* __INET_NTOP_H */
diff --git a/Utilities/cmcurl/inet_pton.c b/Utilities/cmcurl/inet_pton.c
deleted file mode 100644
index 9b9f88b5e..000000000
--- a/Utilities/cmcurl/inet_pton.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/* This is from the BIND 4.9.4 release, modified to compile by itself */
-
-/* Copyright (c) 1996 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-#include "setup.h"
-
-#ifndef HAVE_INET_PTON
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#include <string.h>
-#include <errno.h>
-
-#include "inet_pton.h"
-
-#define IN6ADDRSZ 16
-#define INADDRSZ 4
-#define INT16SZ 2
-
-#ifdef USE_WINSOCK
-#define EAFNOSUPPORT WSAEAFNOSUPPORT
-#endif
-
-/*
- * WARNING: Don't even consider trying to compile this on a system where
- * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
- */
-
-static int inet_pton4(const char *src, unsigned char *dst);
-#ifdef ENABLE_IPV6
-static int inet_pton6(const char *src, unsigned char *dst);
-#endif
-
-/* int
- * inet_pton(af, src, dst)
- * convert from presentation format (which usually means ASCII printable)
- * to network format (which is usually some kind of binary format).
- * return:
- * 1 if the address was valid for the specified address family
- * 0 if the address wasn't valid (`dst' is untouched in this case)
- * -1 if some other error occurred (`dst' is untouched in this case, too)
- * author:
- * Paul Vixie, 1996.
- */
-int
-Curl_inet_pton(int af, const char *src, void *dst)
-{
- switch (af) {
- case AF_INET:
- return (inet_pton4(src, (unsigned char *)dst));
-#ifdef ENABLE_IPV6
-#ifndef AF_INET6
-#define AF_INET6 (AF_MAX+1) /* just to let this compile */
-#endif
- case AF_INET6:
- return (inet_pton6(src, (unsigned char *)dst));
-#endif
- default:
- errno = EAFNOSUPPORT;
- return (-1);
- }
- /* NOTREACHED */
-}
-
-/* int
- * inet_pton4(src, dst)
- * like inet_aton() but without all the hexadecimal and shorthand.
- * return:
- * 1 if `src' is a valid dotted quad, else 0.
- * notice:
- * does not touch `dst' unless it's returning 1.
- * author:
- * Paul Vixie, 1996.
- */
-static int
-inet_pton4(const char *src, unsigned char *dst)
-{
- static const char digits[] = "0123456789";
- int saw_digit, octets, ch;
- unsigned char tmp[INADDRSZ], *tp;
-
- saw_digit = 0;
- octets = 0;
- tp = tmp;
- *tp = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
-
- if ((pch = strchr(digits, ch)) != NULL) {
- unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
-
- if (val > 255)
- return (0);
- *tp = val;
- if (! saw_digit) {
- if (++octets > 4)
- return (0);
- saw_digit = 1;
- }
- } else if (ch == '.' && saw_digit) {
- if (octets == 4)
- return (0);
- *++tp = 0;
- saw_digit = 0;
- } else
- return (0);
- }
- if (octets < 4)
- return (0);
- /* bcopy(tmp, dst, INADDRSZ); */
- memcpy(dst, tmp, INADDRSZ);
- return (1);
-}
-
-#ifdef ENABLE_IPV6
-/* int
- * inet_pton6(src, dst)
- * convert presentation level address to network order binary form.
- * return:
- * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
- * notice:
- * (1) does not touch `dst' unless it's returning 1.
- * (2) :: in a full address is silently ignored.
- * credit:
- * inspired by Mark Andrews.
- * author:
- * Paul Vixie, 1996.
- */
-static int
-inet_pton6(const char *src, unsigned char *dst)
-{
- static const char xdigits_l[] = "0123456789abcdef",
- xdigits_u[] = "0123456789ABCDEF";
- unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
- const char *xdigits, *curtok;
- int ch, saw_xdigit;
- unsigned int val;
-
- memset((tp = tmp), 0, IN6ADDRSZ);
- endp = tp + IN6ADDRSZ;
- colonp = NULL;
- /* Leading :: requires some special handling. */
- if (*src == ':')
- if (*++src != ':')
- return (0);
- curtok = src;
- saw_xdigit = 0;
- val = 0;
- while ((ch = *src++) != '\0') {
- const char *pch;
-
- if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
- pch = strchr((xdigits = xdigits_u), ch);
- if (pch != NULL) {
- val <<= 4;
- val |= (pch - xdigits);
- if (val > 0xffff)
- return (0);
- saw_xdigit = 1;
- continue;
- }
- if (ch == ':') {
- curtok = src;
- if (!saw_xdigit) {
- if (colonp)
- return (0);
- colonp = tp;
- continue;
- }
- if (tp + INT16SZ > endp)
- return (0);
- *tp++ = (unsigned char) (val >> 8) & 0xff;
- *tp++ = (unsigned char) val & 0xff;
- saw_xdigit = 0;
- val = 0;
- continue;
- }
- if (ch == '.' && ((tp + INADDRSZ) <= endp) &&
- inet_pton4(curtok, tp) > 0) {
- tp += INADDRSZ;
- saw_xdigit = 0;
- break; /* '\0' was seen by inet_pton4(). */
- }
- return (0);
- }
- if (saw_xdigit) {
- if (tp + INT16SZ > endp)
- return (0);
- *tp++ = (unsigned char) (val >> 8) & 0xff;
- *tp++ = (unsigned char) val & 0xff;
- }
- if (colonp != NULL) {
- /*
- * Since some memmove()'s erroneously fail to handle
- * overlapping regions, we'll do the shift by hand.
- */
- const int n = tp - colonp;
- int i;
-
- for (i = 1; i <= n; i++) {
- endp[- i] = colonp[n - i];
- colonp[n - i] = 0;
- }
- tp = endp;
- }
- if (tp != endp)
- return (0);
- /* bcopy(tmp, dst, IN6ADDRSZ); */
- memcpy(dst, tmp, IN6ADDRSZ);
- return (1);
-}
-#endif /* ENABLE_IPV6 */
-
-#endif /* HAVE_INET_PTON */
diff --git a/Utilities/cmcurl/inet_pton.h b/Utilities/cmcurl/inet_pton.h
deleted file mode 100644
index a659a9774..000000000
--- a/Utilities/cmcurl/inet_pton.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __INET_PTON_H
-#define __INET_PTON_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-int Curl_inet_pton(int, const char *, void *);
-
-#ifdef HAVE_INET_PTON
-
-#if defined(HAVE_NO_INET_PTON_PROTO)
-int inet_pton(int af, const char *src, void *dst);
-#endif
-
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
-#endif
-
-#endif /* __INET_PTON_H */
diff --git a/Utilities/cmcurl/krb4.c b/Utilities/cmcurl/krb4.c
deleted file mode 100644
index f2b91df69..000000000
--- a/Utilities/cmcurl/krb4.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
- * use in Curl. Martin's latest changes were done 2000-09-18.
- *
- * It has since been patched away like a madman by Daniel Stenberg to make it
- * better applied to curl conditions, and to make it not use globals, pollute
- * name space and more.
- *
- * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * Copyright (c) 2004 - 2007 Daniel Stenberg
- * 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.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * $Id$
- */
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_FTP
-#ifdef HAVE_KRB4
-
-#include <stdlib.h>
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#include <string.h>
-#include <krb.h>
-#include <des.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h> /* for getpid() */
-#endif
-
-#include "urldata.h"
-#include "base64.h"
-#include "ftp.h"
-#include "sendf.h"
-#include "krb4.h"
-#include "memory.h"
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define LOCAL_ADDR (&conn->local_addr)
-#define REMOTE_ADDR conn->ip_addr->ai_addr
-#define myctladdr LOCAL_ADDR
-#define hisctladdr REMOTE_ADDR
-
-struct krb4_data {
- des_cblock key;
- des_key_schedule schedule;
- char name[ANAME_SZ];
- char instance[INST_SZ];
- char realm[REALM_SZ];
-};
-
-#ifndef HAVE_STRLCPY
-/* if it ever goes non-static, make it Curl_ prefixed! */
-static size_t
-strlcpy (char *dst, const char *src, size_t dst_sz)
-{
- size_t n;
- char *p;
-
- for (p = dst, n = 0;
- n + 1 < dst_sz && *src != '\0';
- ++p, ++src, ++n)
- *p = *src;
- *p = '\0';
- if (*src == '\0')
- return n;
- else
- return n + strlen (src);
-}
-#else
-size_t strlcpy (char *dst, const char *src, size_t dst_sz);
-#endif
-
-static int
-krb4_check_prot(void *app_data, int level)
-{
- app_data = NULL; /* prevent compiler warning */
- if(level == prot_confidential)
- return -1;
- return 0;
-}
-
-static int
-krb4_decode(void *app_data, void *buf, int len, int level,
- struct connectdata *conn)
-{
- MSG_DAT m;
- int e;
- struct krb4_data *d = app_data;
-
- if(level == prot_safe)
- e = krb_rd_safe(buf, len, &d->key,
- (struct sockaddr_in *)REMOTE_ADDR,
- (struct sockaddr_in *)LOCAL_ADDR, &m);
- else
- e = krb_rd_priv(buf, len, d->schedule, &d->key,
- (struct sockaddr_in *)REMOTE_ADDR,
- (struct sockaddr_in *)LOCAL_ADDR, &m);
- if(e) {
- struct SessionHandle *data = conn->data;
- infof(data, "krb4_decode: %s\n", krb_get_err_text(e));
- return -1;
- }
- memmove(buf, m.app_data, m.app_length);
- return m.app_length;
-}
-
-static int
-krb4_overhead(void *app_data, int level, int len)
-{
- /* no arguments are used, just init them to prevent compiler warnings */
- app_data = NULL;
- level = 0;
- len = 0;
- return 31;
-}
-
-static int
-krb4_encode(void *app_data, void *from, int length, int level, void **to,
- struct connectdata *conn)
-{
- struct krb4_data *d = app_data;
- *to = malloc(length + 31);
- if(level == prot_safe)
- return krb_mk_safe(from, *to, length, &d->key,
- (struct sockaddr_in *)LOCAL_ADDR,
- (struct sockaddr_in *)REMOTE_ADDR);
- else if(level == prot_private)
- return krb_mk_priv(from, *to, length, d->schedule, &d->key,
- (struct sockaddr_in *)LOCAL_ADDR,
- (struct sockaddr_in *)REMOTE_ADDR);
- else
- return -1;
-}
-
-static int
-mk_auth(struct krb4_data *d, KTEXT adat,
- const char *service, char *host, int checksum)
-{
- int ret;
- CREDENTIALS cred;
- char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
-
- strlcpy(sname, service, sizeof(sname));
- strlcpy(inst, krb_get_phost(host), sizeof(inst));
- strlcpy(realm, krb_realmofhost(host), sizeof(realm));
- ret = krb_mk_req(adat, sname, inst, realm, checksum);
- if(ret)
- return ret;
- strlcpy(sname, service, sizeof(sname));
- strlcpy(inst, krb_get_phost(host), sizeof(inst));
- strlcpy(realm, krb_realmofhost(host), sizeof(realm));
- ret = krb_get_cred(sname, inst, realm, &cred);
- memmove(&d->key, &cred.session, sizeof(des_cblock));
- des_key_sched(&d->key, d->schedule);
- memset(&cred, 0, sizeof(cred));
- return ret;
-}
-
-#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
-int krb_get_our_ip_for_realm(char *, struct in_addr *);
-#endif
-
-static int
-krb4_auth(void *app_data, struct connectdata *conn)
-{
- int ret;
- char *p;
- unsigned char *ptr;
- size_t len;
- KTEXT_ST adat;
- MSG_DAT msg_data;
- int checksum;
- u_int32_t cs;
- struct krb4_data *d = app_data;
- char *host = conn->host.name;
- ssize_t nread;
- int l = sizeof(conn->local_addr);
- struct SessionHandle *data = conn->data;
- CURLcode result;
-
- if(getsockname(conn->sock[FIRSTSOCKET],
- (struct sockaddr *)LOCAL_ADDR, &l) < 0)
- perror("getsockname()");
-
- checksum = getpid();
- ret = mk_auth(d, &adat, "ftp", host, checksum);
- if(ret == KDC_PR_UNKNOWN)
- ret = mk_auth(d, &adat, "rcmd", host, checksum);
- if(ret) {
- infof(data, "%s\n", krb_get_err_text(ret));
- return AUTH_CONTINUE;
- }
-
-#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
- if (krb_get_config_bool("nat_in_use")) {
- struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
- struct in_addr natAddr;
-
- if (krb_get_our_ip_for_realm(krb_realmofhost(host),
- &natAddr) != KSUCCESS
- && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
- infof(data, "Can't get address for realm %s\n",
- krb_realmofhost(host));
- else {
- if (natAddr.s_addr != localaddr->sin_addr.s_addr) {
-#ifdef HAVE_INET_NTOA_R
- char ntoa_buf[64];
- char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf));
-#else
- char *ip = (char *)inet_ntoa(natAddr);
-#endif
- infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
- localaddr->sin_addr = natAddr;
- }
- }
- }
-#endif
-
- if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) {
- Curl_failf(data, "Out of memory base64-encoding");
- return AUTH_CONTINUE;
- }
-
- result = Curl_ftpsendf(conn, "ADAT %s", p);
-
- free(p);
-
- if(result)
- return -2;
-
- if(Curl_GetFTPResponse(&nread, conn, NULL))
- return -1;
-
- if(data->state.buffer[0] != '2'){
- Curl_failf(data, "Server didn't accept auth data");
- return AUTH_ERROR;
- }
-
- p = strstr(data->state.buffer, "ADAT=");
- if(!p) {
- Curl_failf(data, "Remote host didn't send adat reply");
- return AUTH_ERROR;
- }
- p += 5;
- len = Curl_base64_decode(p, &ptr);
- if(len > sizeof(adat.dat)-1) {
- free(ptr);
- len=0;
- }
- if(!len || !ptr) {
- Curl_failf(data, "Failed to decode base64 from server");
- return AUTH_ERROR;
- }
- memcpy((char *)adat.dat, ptr, len);
- free(ptr);
- adat.length = len;
- ret = krb_rd_safe(adat.dat, adat.length, &d->key,
- (struct sockaddr_in *)hisctladdr,
- (struct sockaddr_in *)myctladdr, &msg_data);
- if(ret) {
- Curl_failf(data, "Error reading reply from server: %s",
- krb_get_err_text(ret));
- return AUTH_ERROR;
- }
- krb_get_int(msg_data.app_data, &cs, 4, 0);
- if(cs - checksum != 1) {
- Curl_failf(data, "Bad checksum returned from server");
- return AUTH_ERROR;
- }
- return AUTH_OK;
-}
-
-struct Curl_sec_client_mech Curl_krb4_client_mech = {
- "KERBEROS_V4",
- sizeof(struct krb4_data),
- NULL, /* init */
- krb4_auth,
- NULL, /* end */
- krb4_check_prot,
- krb4_overhead,
- krb4_encode,
- krb4_decode
-};
-
-CURLcode Curl_krb_kauth(struct connectdata *conn)
-{
- des_cblock key;
- des_key_schedule schedule;
- KTEXT_ST tkt, tktcopy;
- char *name;
- char *p;
- char passwd[100];
- size_t tmp;
- ssize_t nread;
- int save;
- CURLcode result;
- unsigned char *ptr;
-
- save = Curl_set_command_prot(conn, prot_private);
-
- result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);
-
- if(result)
- return result;
-
- result = Curl_GetFTPResponse(&nread, conn, NULL);
- if(result)
- return result;
-
- if(conn->data->state.buffer[0] != '3'){
- Curl_set_command_prot(conn, save);
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
-
- p = strstr(conn->data->state.buffer, "T=");
- if(!p) {
- Curl_failf(conn->data, "Bad reply from server");
- Curl_set_command_prot(conn, save);
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
-
- p += 2;
- tmp = Curl_base64_decode(p, &ptr);
- if(tmp >= sizeof(tkt.dat)) {
- free(ptr);
- tmp=0;
- }
- if(!tmp || !ptr) {
- Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
- Curl_set_command_prot(conn, save);
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
- memcpy((char *)tkt.dat, ptr, tmp);
- free(ptr);
- tkt.length = tmp;
- tktcopy.length = tkt.length;
-
- p = strstr(conn->data->state.buffer, "P=");
- if(!p) {
- Curl_failf(conn->data, "Bad reply from server");
- Curl_set_command_prot(conn, save);
- return CURLE_FTP_WEIRD_SERVER_REPLY;
- }
- name = p + 2;
- for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
- *p = 0;
-
- des_string_to_key (conn->passwd, &key);
- des_key_sched(&key, schedule);
-
- des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
- tkt.length,
- schedule, &key, DES_DECRYPT);
- if (strcmp ((char*)tktcopy.dat + 8,
- KRB_TICKET_GRANTING_TICKET) != 0) {
- afs_string_to_key(passwd,
- krb_realmofhost(conn->host.name),
- &key);
- des_key_sched(&key, schedule);
- des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
- tkt.length,
- schedule, &key, DES_DECRYPT);
- }
- memset(key, 0, sizeof(key));
- memset(schedule, 0, sizeof(schedule));
- memset(passwd, 0, sizeof(passwd));
- if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p)
- < 1) {
- failf(conn->data, "Out of memory base64-encoding.");
- Curl_set_command_prot(conn, save);
- return CURLE_OUT_OF_MEMORY;
- }
- memset (tktcopy.dat, 0, tktcopy.length);
-
- result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p);
- free(p);
- if(result)
- return result;
-
- result = Curl_GetFTPResponse(&nread, conn, NULL);
- if(result)
- return result;
- Curl_set_command_prot(conn, save);
-
- return CURLE_OK;
-}
-
-#endif /* HAVE_KRB4 */
-#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/krb4.h b/Utilities/cmcurl/krb4.h
deleted file mode 100644
index f46416e62..000000000
--- a/Utilities/cmcurl/krb4.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef __KRB4_H
-#define __KRB4_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-struct Curl_sec_client_mech {
- const char *name;
- size_t size;
- int (*init)(void *);
- int (*auth)(void *, struct connectdata *);
- void (*end)(void *);
- int (*check_prot)(void *, int);
- int (*overhead)(void *, int, int);
- int (*encode)(void *, void*, int, int, void**, struct connectdata *);
- int (*decode)(void *, void*, int, int, struct connectdata *);
-};
-
-
-#define AUTH_OK 0
-#define AUTH_CONTINUE 1
-#define AUTH_ERROR 2
-
-extern struct Curl_sec_client_mech Curl_krb4_client_mech;
-
-CURLcode Curl_krb_kauth(struct connectdata *conn);
-int Curl_sec_fflush_fd(struct connectdata *conn, int fd);
-int Curl_sec_fprintf (struct connectdata *, FILE *, const char *, ...);
-int Curl_sec_getc (struct connectdata *conn, FILE *);
-int Curl_sec_putc (struct connectdata *conn, int, FILE *);
-int Curl_sec_read (struct connectdata *conn, int, void *, int);
-int Curl_sec_read_msg (struct connectdata *conn, char *, int);
-
-int Curl_sec_vfprintf(struct connectdata *, FILE *, const char *, va_list);
-int Curl_sec_fprintf2(struct connectdata *conn, FILE *f, const char *fmt, ...);
-int Curl_sec_vfprintf2(struct connectdata *conn, FILE *, const char *, va_list);
-ssize_t Curl_sec_send(struct connectdata *conn, int, char *, int);
-int Curl_sec_write(struct connectdata *conn, int, char *, int);
-
-void Curl_sec_end (struct connectdata *);
-int Curl_sec_login (struct connectdata *);
-void Curl_sec_prot (int, char **);
-int Curl_sec_request_prot (struct connectdata *conn, const char *level);
-void Curl_sec_set_protection_level(struct connectdata *conn);
-void Curl_sec_status (void);
-
-enum protection_level Curl_set_command_prot(struct connectdata *,
- enum protection_level);
-
-
-#endif
diff --git a/Utilities/cmcurl/ldap.c b/Utilities/cmcurl/ldap.c
deleted file mode 100644
index 3e1144d4f..000000000
--- a/Utilities/cmcurl/ldap.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_LDAP
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#include <errno.h>
-
-#if defined(WIN32)
-# include <winldap.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_DLFCN_H
-# include <dlfcn.h>
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "sendf.h"
-#include "escape.h"
-#include "transfer.h"
-#include "strequal.h"
-#include "strtok.h"
-#include "ldap.h"
-#include "memory.h"
-#include "base64.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "memdebug.h"
-
-/* WLdap32.dll functions are *not* stdcall. Must call these via __cdecl
- * pointers in case libcurl was compiled as fastcall (cl -Gr). Watcom
- * uses fastcall by default.
- */
-#if !defined(WIN32) && !defined(__cdecl)
-#define __cdecl
-#endif
-
-#ifndef LDAP_SIZELIMIT_EXCEEDED
-#define LDAP_SIZELIMIT_EXCEEDED 4
-#endif
-#ifndef LDAP_VERSION2
-#define LDAP_VERSION2 2
-#endif
-#ifndef LDAP_VERSION3
-#define LDAP_VERSION3 3
-#endif
-#ifndef LDAP_OPT_PROTOCOL_VERSION
-#define LDAP_OPT_PROTOCOL_VERSION 0x0011
-#endif
-
-#define DLOPEN_MODE RTLD_LAZY /*! assume all dlopen() implementations have
- this */
-
-#if defined(RTLD_LAZY_GLOBAL) /* It turns out some systems use this: */
-# undef DLOPEN_MODE
-# define DLOPEN_MODE RTLD_LAZY_GLOBAL
-#elif defined(RTLD_GLOBAL)
-# undef DLOPEN_MODE
-# define DLOPEN_MODE (RTLD_LAZY | RTLD_GLOBAL)
-#endif
-
-#define DYNA_GET_FUNCTION(type, fnc) do { \
- (fnc) = (type)DynaGetFunction(#fnc); \
- if ((fnc) == NULL) \
- return CURLE_FUNCTION_NOT_FOUND; \
- } while (0)
-
-/*! CygWin etc. configure could set these, but we don't want it.
- * Must use WLdap32.dll code.
- */
-#if defined(WIN32)
-#undef HAVE_DLOPEN
-#undef HAVE_LIBDL
-#endif
-
-/*
- * We use this ZERO_NULL to avoid picky compiler warnings,
- * when assigning a NULL pointer to a function pointer var.
- */
-
-#define ZERO_NULL 0
-
-typedef void * (*dynafunc)(void *input);
-
-/***********************************************************************
- */
-#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) || defined(WIN32)
-static void *libldap = NULL;
-#if defined(DL_LBER_FILE)
-static void *liblber = NULL;
-#endif
-#endif
-
-struct bv {
- unsigned long bv_len;
- char *bv_val;
-};
-
-static int DynaOpen(const char **mod_name)
-{
-#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
- if (libldap == NULL) {
- /*
- * libldap.so can normally resolve its dependency on liblber.so
- * automatically, but in broken installation it does not so
- * handle it here by opening liblber.so as global.
- */
-#ifdef DL_LBER_FILE
- *mod_name = DL_LBER_FILE;
- liblber = dlopen(*mod_name, DLOPEN_MODE);
- if (!liblber)
- return 0;
-#endif
-
- /* Assume loading libldap.so will fail if loading of liblber.so failed
- */
- *mod_name = DL_LDAP_FILE;
- libldap = dlopen(*mod_name, RTLD_LAZY);
- }
- return (libldap != NULL);
-
-#elif defined(WIN32)
- *mod_name = DL_LDAP_FILE;
- if (!libldap)
- libldap = (void*)LoadLibrary(*mod_name);
- return (libldap != NULL);
-
-#else
- *mod_name = "";
- return (0);
-#endif
-}
-
-static void DynaClose(void)
-{
-#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
- if (libldap) {
- dlclose(libldap);
- libldap=NULL;
- }
-#ifdef DL_LBER_FILE
- if (liblber) {
- dlclose(liblber);
- liblber=NULL;
- }
-#endif
-#elif defined(WIN32)
- if (libldap) {
- FreeLibrary ((HMODULE)libldap);
- libldap = NULL;
- }
-#endif
-}
-
-static dynafunc DynaGetFunction(const char *name)
-{
- dynafunc func = (dynafunc)ZERO_NULL;
-
-#if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL)
- if (libldap) {
- /* This typecast magic below was brought by Joe Halpin. In ISO C, you
- * cannot typecast a data pointer to a function pointer, but that's
- * exactly what we need to do here to avoid compiler warnings on picky
- * compilers! */
- *(void**) (&func) = dlsym(libldap, name);
- }
-#elif defined(WIN32)
- if (libldap) {
- func = (dynafunc)GetProcAddress((HINSTANCE)libldap, name);
- }
-#else
- (void) name;
-#endif
- return func;
-}
-
-/***********************************************************************
- */
-typedef struct ldap_url_desc {
- struct ldap_url_desc *lud_next;
- char *lud_scheme;
- char *lud_host;
- int lud_port;
- char *lud_dn;
- char **lud_attrs;
- int lud_scope;
- char *lud_filter;
- char **lud_exts;
- int lud_crit_exts;
-} LDAPURLDesc;
-
-#ifdef WIN32
-static int _ldap_url_parse (const struct connectdata *conn,
- LDAPURLDesc **ludp);
-static void _ldap_free_urldesc (LDAPURLDesc *ludp);
-
-static void (*ldap_free_urldesc)(LDAPURLDesc *) = _ldap_free_urldesc;
-#endif
-
-#ifdef DEBUG_LDAP
- #define LDAP_TRACE(x) do { \
- _ldap_trace ("%u: ", __LINE__); \
- _ldap_trace x; \
- } while (0)
-
- static void _ldap_trace (const char *fmt, ...);
-#else
- #define LDAP_TRACE(x) ((void)0)
-#endif
-
-
-CURLcode Curl_ldap(struct connectdata *conn, bool *done)
-{
- CURLcode status = CURLE_OK;
- int rc = 0;
-#ifndef WIN32
- int (*ldap_url_parse)(char *, LDAPURLDesc **);
- void (*ldap_free_urldesc)(void *);
-#endif
- void *(__cdecl *ldap_init)(char *, int);
- int (__cdecl *ldap_simple_bind_s)(void *, char *, char *);
- int (__cdecl *ldap_unbind_s)(void *);
- int (__cdecl *ldap_search_s)(void *, char *, int, char *, char **,
- int, void **);
- void *(__cdecl *ldap_first_entry)(void *, void *);
- void *(__cdecl *ldap_next_entry)(void *, void *);
- char *(__cdecl *ldap_err2string)(int);
- char *(__cdecl *ldap_get_dn)(void *, void *);
- char *(__cdecl *ldap_first_attribute)(void *, void *, void **);
- char *(__cdecl *ldap_next_attribute)(void *, void *, void *);
- void **(__cdecl *ldap_get_values_len)(void *, void *, const char *);
- void (__cdecl *ldap_value_free_len)(void **);
- void (__cdecl *ldap_memfree)(void *);
- void (__cdecl *ber_free)(void *, int);
- int (__cdecl *ldap_set_option)(void *, int, void *);
-
- void *server;
- LDAPURLDesc *ludp = NULL;
- const char *mod_name;
- void *result;
- void *entryIterator; /*! type should be 'LDAPMessage *' */
- int num = 0;
- struct SessionHandle *data=conn->data;
- int ldap_proto;
- char *val_b64;
- size_t val_b64_sz;
-
- *done = TRUE; /* unconditionally */
- infof(data, "LDAP local: %s\n", data->change.url);
-
- if (!DynaOpen(&mod_name)) {
- failf(data, "The %s LDAP library/libraries couldn't be opened", mod_name);
- return CURLE_LIBRARY_NOT_FOUND;
- }
-
- /* The types are needed because ANSI C distinguishes between
- * pointer-to-object (data) and pointer-to-function.
- */
- DYNA_GET_FUNCTION(void *(__cdecl *)(char *, int), ldap_init);
- DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *),
- ldap_simple_bind_s);
- DYNA_GET_FUNCTION(int (__cdecl *)(void *), ldap_unbind_s);
-#ifndef WIN32
- DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse);
- DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc);
-#endif
- DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, int, char *, char **, int,
- void **), ldap_search_s);
- DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_first_entry);
- DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_next_entry);
- DYNA_GET_FUNCTION(char *(__cdecl *)(int), ldap_err2string);
- DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *), ldap_get_dn);
- DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **),
- ldap_first_attribute);
- DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *),
- ldap_next_attribute);
- DYNA_GET_FUNCTION(void **(__cdecl *)(void *, void *, const char *),
- ldap_get_values_len);
- DYNA_GET_FUNCTION(void (__cdecl *)(void **), ldap_value_free_len);
- DYNA_GET_FUNCTION(void (__cdecl *)(void *), ldap_memfree);
- DYNA_GET_FUNCTION(void (__cdecl *)(void *, int), ber_free);
- DYNA_GET_FUNCTION(int (__cdecl *)(void *, int, void *), ldap_set_option);
-
- server = (*ldap_init)(conn->host.name, (int)conn->port);
- if (server == NULL) {
- failf(data, "LDAP local: Cannot connect to %s:%d",
- conn->host.name, conn->port);
- status = CURLE_COULDNT_CONNECT;
- goto quit;
- }
-
- ldap_proto = LDAP_VERSION3;
- (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
- rc = (*ldap_simple_bind_s)(server,
- conn->bits.user_passwd ? conn->user : NULL,
- conn->bits.user_passwd ? conn->passwd : NULL);
- if (rc != 0) {
- ldap_proto = LDAP_VERSION2;
- (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
- rc = (*ldap_simple_bind_s)(server,
- conn->bits.user_passwd ? conn->user : NULL,
- conn->bits.user_passwd ? conn->passwd : NULL);
- }
- if (rc != 0) {
- failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
- status = CURLE_LDAP_CANNOT_BIND;
- goto quit;
- }
-
-#ifdef WIN32
- rc = _ldap_url_parse(conn, &ludp);
-#else
- rc = (*ldap_url_parse)(data->change.url, &ludp);
-#endif
-
- if (rc != 0) {
- failf(data, "LDAP local: %s", (*ldap_err2string)(rc));
- status = CURLE_LDAP_INVALID_URL;
- goto quit;
- }
-
- rc = (*ldap_search_s)(server, ludp->lud_dn, ludp->lud_scope,
- ludp->lud_filter, ludp->lud_attrs, 0, &result);
-
- if (rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
- failf(data, "LDAP remote: %s", (*ldap_err2string)(rc));
- status = CURLE_LDAP_SEARCH_FAILED;
- goto quit;
- }
-
- for(num = 0, entryIterator = (*ldap_first_entry)(server, result);
- entryIterator;
- entryIterator = (*ldap_next_entry)(server, entryIterator), num++)
- {
- void *ber = NULL; /*! is really 'BerElement **' */
- void *attribute; /*! suspicious that this isn't 'const' */
- char *dn = (*ldap_get_dn)(server, entryIterator);
- int i;
-
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
-
- for (attribute = (*ldap_first_attribute)(server, entryIterator, &ber);
- attribute;
- attribute = (*ldap_next_attribute)(server, entryIterator, ber))
- {
- struct bv **vals = (struct bv **)
- (*ldap_get_values_len)(server, entryIterator, attribute);
-
- if (vals != NULL)
- {
- for (i = 0; (vals[i] != NULL); i++)
- {
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0);
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
- if ((strlen(attribute) > 7) &&
- (strcmp(";binary",
- (char *)attribute +
- (strlen((char *)attribute) - 7)) == 0)) {
- /* Binary attribute, encode to base64. */
- val_b64_sz = Curl_base64_encode(conn->data,
- vals[i]->bv_val,
- vals[i]->bv_len,
- &val_b64);
- if (val_b64_sz > 0) {
- Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
- free(val_b64);
- }
- } else
- Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
- vals[i]->bv_len);
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
- }
-
- /* Free memory used to store values */
- (*ldap_value_free_len)((void **)vals);
- }
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
-
- (*ldap_memfree)(attribute);
- }
- (*ldap_memfree)(dn);
- if (ber)
- (*ber_free)(ber, 0);
- }
-
-quit:
- LDAP_TRACE (("Received %d entries\n", num));
- if (rc == LDAP_SIZELIMIT_EXCEEDED)
- infof(data, "There are more than %d entries\n", num);
- if (ludp)
- (*ldap_free_urldesc)(ludp);
- if (server)
- (*ldap_unbind_s)(server);
-
- DynaClose();
-
- /* no data to transfer */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- conn->bits.close = TRUE;
-
- return status;
-}
-
-#ifdef DEBUG_LDAP
-static void _ldap_trace (const char *fmt, ...)
-{
- static int do_trace = -1;
- va_list args;
-
- if (do_trace == -1) {
- const char *env = getenv("CURL_TRACE");
- do_trace = (env && atoi(env) > 0);
- }
- if (!do_trace)
- return;
-
- va_start (args, fmt);
- vfprintf (stderr, fmt, args);
- va_end (args);
-}
-#endif
-
-#ifdef WIN32
-/*
- * Return scope-value for a scope-string.
- */
-static int str2scope (const char *p)
-{
- if (!stricmp(p, "one"))
- return LDAP_SCOPE_ONELEVEL;
- if (!stricmp(p, "onetree"))
- return LDAP_SCOPE_ONELEVEL;
- if (!stricmp(p, "base"))
- return LDAP_SCOPE_BASE;
- if (!stricmp(p, "sub"))
- return LDAP_SCOPE_SUBTREE;
- if (!stricmp( p, "subtree"))
- return LDAP_SCOPE_SUBTREE;
- return (-1);
-}
-
-/*
- * Split 'str' into strings separated by commas.
- * Note: res[] points into 'str'.
- */
-static char **split_str (char *str)
-{
- char **res, *lasts, *s;
- int i;
-
- for (i = 2, s = strchr(str,','); s; i++)
- s = strchr(++s,',');
-
- res = calloc(i, sizeof(char*));
- if (!res)
- return NULL;
-
- for (i = 0, s = strtok_r(str, ",", &lasts); s;
- s = strtok_r(NULL, ",", &lasts), i++)
- res[i] = s;
- return res;
-}
-
-/*
- * Unescape the LDAP-URL components
- */
-static bool unescape_elements (void *data, LDAPURLDesc *ludp)
-{
- int i;
-
- if (ludp->lud_filter) {
- ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL);
- if (!ludp->lud_filter)
- return (FALSE);
- }
-
- for (i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
- ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL);
- if (!ludp->lud_attrs[i])
- return (FALSE);
- }
-
- for (i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) {
- ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL);
- if (!ludp->lud_exts[i])
- return (FALSE);
- }
-
- if (ludp->lud_dn) {
- char *dn = ludp->lud_dn;
- char *new_dn = curl_easy_unescape(data, dn, 0, NULL);
-
- free(dn);
- ludp->lud_dn = new_dn;
- if (!new_dn)
- return (FALSE);
- }
- return (TRUE);
-}
-
-/*
- * Break apart the pieces of an LDAP URL.
- * Syntax:
- * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
- *
- * <hostname> already known from 'conn->host.name'.
- * <port> already known from 'conn->remote_port'.
- * extract the rest from 'conn->data->reqdata.path+1'. All fields are optional.
- * e.g.
- * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
- * yields ludp->lud_dn = "".
- *
- * Ref. http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm#2831915
- */
-static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
-{
- char *p, *q;
- int i;
-
- if (!conn->data ||
- !conn->data->reqdata.path ||
- conn->data->reqdata.path[0] != '/' ||
- !checkprefix(conn->protostr, conn->data->change.url))
- return LDAP_INVALID_SYNTAX;
-
- ludp->lud_scope = LDAP_SCOPE_BASE;
- ludp->lud_port = conn->remote_port;
- ludp->lud_host = conn->host.name;
-
- /* parse DN (Distinguished Name).
- */
- ludp->lud_dn = strdup(conn->data->reqdata.path+1);
- if (!ludp->lud_dn)
- return LDAP_NO_MEMORY;
-
- p = strchr(ludp->lud_dn, '?');
- LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) :
- strlen(ludp->lud_dn), ludp->lud_dn));
-
- if (!p)
- goto success;
-
- *p++ = '\0';
-
- /* parse attributes. skip "??".
- */
- q = strchr(p, '?');
- if (q)
- *q++ = '\0';
-
- if (*p && *p != '?') {
- ludp->lud_attrs = split_str(p);
- if (!ludp->lud_attrs)
- return LDAP_NO_MEMORY;
-
- for (i = 0; ludp->lud_attrs[i]; i++)
- LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i]));
- }
-
- p = q;
- if (!p)
- goto success;
-
- /* parse scope. skip "??"
- */
- q = strchr(p, '?');
- if (q)
- *q++ = '\0';
-
- if (*p && *p != '?') {
- ludp->lud_scope = str2scope(p);
- if (ludp->lud_scope == -1)
- return LDAP_INVALID_SYNTAX;
- LDAP_TRACE (("scope %d\n", ludp->lud_scope));
- }
-
- p = q;
- if (!p)
- goto success;
-
- /* parse filter
- */
- q = strchr(p, '?');
- if (q)
- *q++ = '\0';
- if (!*p)
- return LDAP_INVALID_SYNTAX;
-
- ludp->lud_filter = p;
- LDAP_TRACE (("filter '%s'\n", ludp->lud_filter));
-
- p = q;
- if (!p)
- goto success;
-
- /* parse extensions
- */
- ludp->lud_exts = split_str(p);
- if (!ludp->lud_exts)
- return LDAP_NO_MEMORY;
-
- for (i = 0; ludp->lud_exts[i]; i++)
- LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i]));
-
-success:
- if (!unescape_elements(conn->data, ludp))
- return LDAP_NO_MEMORY;
- return LDAP_SUCCESS;
-}
-
-static int _ldap_url_parse (const struct connectdata *conn,
- LDAPURLDesc **ludpp)
-{
- LDAPURLDesc *ludp = calloc(sizeof(*ludp), 1);
- int rc;
-
- *ludpp = NULL;
- if (!ludp)
- return LDAP_NO_MEMORY;
-
- rc = _ldap_url_parse2 (conn, ludp);
- if (rc != LDAP_SUCCESS) {
- _ldap_free_urldesc(ludp);
- ludp = NULL;
- }
- *ludpp = ludp;
- return (rc);
-}
-
-static void _ldap_free_urldesc (LDAPURLDesc *ludp)
-{
- int i;
-
- if (!ludp)
- return;
-
- if (ludp->lud_dn)
- free(ludp->lud_dn);
-
- if (ludp->lud_filter)
- free(ludp->lud_filter);
-
- if (ludp->lud_attrs) {
- for (i = 0; ludp->lud_attrs[i]; i++)
- free(ludp->lud_attrs[i]);
- free(ludp->lud_attrs);
- }
-
- if (ludp->lud_exts) {
- for (i = 0; ludp->lud_exts[i]; i++)
- free(ludp->lud_exts[i]);
- free(ludp->lud_exts);
- }
- free (ludp);
-}
-#endif /* WIN32 */
-#endif /* CURL_DISABLE_LDAP */
diff --git a/Utilities/cmcurl/ldap.h b/Utilities/cmcurl/ldap.h
deleted file mode 100644
index b2d4f3973..000000000
--- a/Utilities/cmcurl/ldap.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __LDAP_H
-#define __LDAP_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_LDAP
-CURLcode Curl_ldap(struct connectdata *conn, bool *done);
-#endif
-#endif /* __LDAP_H */
diff --git a/Utilities/cmcurl/lib/CMakeLists.txt b/Utilities/cmcurl/lib/CMakeLists.txt
new file mode 100644
index 000000000..76dd6c63c
--- /dev/null
+++ b/Utilities/cmcurl/lib/CMakeLists.txt
@@ -0,0 +1,134 @@
+set(LIB_NAME cmcurl)
+
+configure_file(${CURL_SOURCE_DIR}/include/curl/curlbuild.h.cmake
+ ${CURL_BINARY_DIR}/include/curl/curlbuild.h)
+configure_file(curl_config.h.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
+
+transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake)
+
+list(APPEND HHEADERS
+ ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
+ ${CURL_BINARY_DIR}/include/curl/curlbuild.h
+ )
+
+if(MSVC AND NOT CURL_STATICLIB)
+ list(APPEND CSOURCES libcurl.rc)
+endif()
+
+# SET(CSOURCES
+# # memdebug.c -not used
+# # nwlib.c - Not used
+# # strtok.c - specify later
+# # strtoofft.c - specify later
+# )
+
+# # if we have Kerberos 4, right now this is never on
+# #OPTION(CURL_KRB4 "Use Kerberos 4" OFF)
+# IF(CURL_KRB4)
+# SET(CSOURCES ${CSOURCES}
+# krb4.c
+# security.c
+# )
+# ENDIF(CURL_KRB4)
+
+# #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
+# MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
+# IF(CURL_MALLOC_DEBUG)
+# SET(CSOURCES ${CSOURCES}
+# memdebug.c
+# )
+# ENDIF(CURL_MALLOC_DEBUG)
+
+# # only build compat strtoofft if we need to
+# IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
+# SET(CSOURCES ${CSOURCES}
+# strtoofft.c
+# )
+# ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
+
+
+# The rest of the build
+
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../include)
+include_directories(${CMAKE_CURRENT_BINARY_DIR}/..)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+if(USE_ARES)
+ include_directories(${CARES_INCLUDE_DIR})
+endif()
+
+if(CURL_STATICLIB)
+ # Static lib
+ set(CURL_USER_DEFINED_DYNAMIC_OR_STATIC STATIC)
+else()
+ # DLL / so dynamic lib
+ set(CURL_USER_DEFINED_DYNAMIC_OR_STATIC SHARED)
+endif()
+
+# For windows we want to install OPENSSL_LIBRARIES dlls
+# and also copy them into the build tree so that testing
+# can find them.
+if(CMAKE_USE_OPENSSL AND OPENSSL_FOUND AND WIN32)
+ find_file(CMAKE_EAY_DLL NAME libeay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
+ find_file(CMAKE_SSL_DLL NAME ssleay32.dll HINTS ${OPENSSL_INCLUDE_DIR}/..)
+ mark_as_advanced(CMAKE_EAY_DLL CMAKE_SSL_DLL)
+ if(CMAKE_SSL_DLL AND CMAKE_EAY_DLL)
+ set(CMAKE_CURL_SSL_DLLS ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll
+ ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll)
+ add_custom_command(OUTPUT
+ ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll
+ DEPENDS ${CMAKE_EAY_DLL}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_EAY_DLL}
+ ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/libeay32.dll)
+ add_custom_command(OUTPUT
+ ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll
+ DEPENDS ${CMAKE_SSL_DLL}
+ COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_SSL_DLL}
+ ${CMake_BIN_DIR}/${CMAKE_CFG_INTDIR}/ssleay32.dll)
+ install(PROGRAMS ${CMAKE_EAY_DLL} ${CMAKE_SSL_DLL} DESTINATION bin)
+ endif()
+endif()
+
+add_library(
+ ${LIB_NAME}
+ ${CURL_USER_DEFINED_DYNAMIC_OR_STATIC}
+ ${HHEADERS} ${CSOURCES}
+ ${CMAKE_CURL_SSL_DLLS}
+ )
+
+target_link_libraries(${LIB_NAME} ${CURL_LIBS})
+
+if(0) # This code not needed for building within CMake.
+if(WIN32)
+ add_definitions( -D_USRDLL )
+endif()
+endif()
+
+set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL)
+
+if(0) # This code not needed for building within CMake.
+if(HIDES_CURL_PRIVATE_SYMBOLS)
+ set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
+ set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
+endif()
+
+# Remove the "lib" prefix since the library is already named "libcurl".
+set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
+set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
+
+if(WIN32)
+ if(NOT CURL_STATICLIB)
+ # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
+ set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+ endif()
+endif()
+
+install(TARGETS ${LIB_NAME}
+ ARCHIVE DESTINATION lib
+ LIBRARY DESTINATION lib
+ RUNTIME DESTINATION bin)
+endif()
diff --git a/Utilities/cmcurl/lib/Makefile.inc b/Utilities/cmcurl/lib/Makefile.inc
new file mode 100644
index 000000000..19f58000a
--- /dev/null
+++ b/Utilities/cmcurl/lib/Makefile.inc
@@ -0,0 +1,80 @@
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
+
+LIB_VAUTH_CFILES = vauth/vauth.c vauth/cleartext.c vauth/cram.c \
+ vauth/digest.c vauth/digest_sspi.c vauth/krb5_gssapi.c \
+ vauth/krb5_sspi.c vauth/ntlm.c vauth/ntlm_sspi.c vauth/oauth2.c \
+ vauth/spnego_gssapi.c vauth/spnego_sspi.c
+
+LIB_VAUTH_HFILES = vauth/vauth.h vauth/digest.h vauth/ntlm.h
+
+LIB_VTLS_CFILES = vtls/openssl.c vtls/gtls.c vtls/vtls.c vtls/nss.c \
+ vtls/polarssl.c vtls/polarssl_threadlock.c vtls/axtls.c \
+ vtls/cyassl.c vtls/schannel.c vtls/darwinssl.c vtls/gskit.c \
+ vtls/mbedtls.c
+
+LIB_VTLS_HFILES = vtls/openssl.h vtls/vtls.h vtls/gtls.h \
+ vtls/nssg.h vtls/polarssl.h vtls/polarssl_threadlock.h vtls/axtls.h \
+ vtls/cyassl.h vtls/schannel.h vtls/darwinssl.h vtls/gskit.h \
+ vtls/mbedtls.h
+
+LIB_CFILES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
+ cookie.c http.c sendf.c ftp.c url.c dict.c if2ip.c speedcheck.c \
+ ldap.c version.c getenv.c escape.c mprintf.c telnet.c netrc.c \
+ getinfo.c transfer.c strcase.c easy.c security.c curl_fnmatch.c \
+ fileinfo.c ftplistparser.c wildcard.c krb5.c memdebug.c http_chunks.c \
+ strtok.c connect.c llist.c hash.c multi.c content_encoding.c share.c \
+ http_digest.c md4.c md5.c http_negotiate.c inet_pton.c strtoofft.c \
+ strerror.c amigaos.c hostasyn.c hostip4.c hostip6.c hostsyn.c \
+ inet_ntop.c parsedate.c select.c tftp.c splay.c strdup.c socks.c \
+ ssh.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \
+ curl_sspi.c slist.c nonblock.c curl_memrchr.c imap.c pop3.c smtp.c \
+ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c curl_rtmp.c \
+ openldap.c curl_gethostname.c gopher.c idn_win32.c \
+ http_proxy.c non-ascii.c asyn-ares.c asyn-thread.c curl_gssapi.c \
+ http_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c curl_sasl.c rand.c \
+ curl_multibyte.c hostcheck.c conncache.c pipeline.c dotdot.c \
+ x509asn1.c http2.c smb.c curl_endian.c curl_des.c system_win32.c
+
+LIB_HFILES = arpa_telnet.h netrc.h file.h timeval.h hostip.h progress.h \
+ formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h if2ip.h \
+ speedcheck.h urldata.h curl_ldap.h escape.h telnet.h getinfo.h \
+ strcase.h curl_sec.h memdebug.h http_chunks.h curl_fnmatch.h \
+ wildcard.h fileinfo.h ftplistparser.h strtok.h connect.h llist.h \
+ hash.h content_encoding.h share.h curl_md4.h curl_md5.h http_digest.h \
+ http_negotiate.h inet_pton.h amigaos.h strtoofft.h strerror.h \
+ inet_ntop.h curlx.h curl_memory.h curl_setup.h transfer.h select.h \
+ easyif.h multiif.h parsedate.h tftp.h sockaddr.h splay.h strdup.h \
+ socks.h ssh.h curl_base64.h curl_addrinfo.h curl_sspi.h \
+ slist.h nonblock.h curl_memrchr.h imap.h pop3.h smtp.h pingpong.h \
+ rtsp.h curl_threads.h warnless.h curl_hmac.h curl_rtmp.h \
+ curl_gethostname.h gopher.h http_proxy.h non-ascii.h asyn.h \
+ http_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h \
+ curl_sasl.h curl_multibyte.h hostcheck.h conncache.h \
+ curl_setup_once.h multihandle.h setup-vms.h pipeline.h dotdot.h \
+ x509asn1.h http2.h sigpipe.h smb.h curl_endian.h curl_des.h \
+ curl_printf.h system_win32.h rand.h
+
+LIB_RCFILES = libcurl.rc
+
+CSOURCES = $(LIB_CFILES) $(LIB_VAUTH_CFILES) $(LIB_VTLS_CFILES)
+HHEADERS = $(LIB_HFILES) $(LIB_VAUTH_HFILES) $(LIB_VTLS_HFILES)
diff --git a/Utilities/cmcurl/lib/amigaos.c b/Utilities/cmcurl/lib/amigaos.c
new file mode 100644
index 000000000..4f55b30e7
--- /dev/null
+++ b/Utilities/cmcurl/lib/amigaos.c
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(__AMIGA__) && !defined(__ixemul__)
+
+#include <amitcp/socketbasetags.h>
+
+#include "amigaos.h"
+
+struct Library *SocketBase = NULL;
+extern int errno, h_errno;
+
+#ifdef __libnix__
+#include <stabs.h>
+void __request(const char *msg);
+#else
+# define __request(msg) Printf(msg "\n\a")
+#endif
+
+void Curl_amiga_cleanup()
+{
+ if(SocketBase) {
+ CloseLibrary(SocketBase);
+ SocketBase = NULL;
+ }
+}
+
+bool Curl_amiga_init()
+{
+ if(!SocketBase)
+ SocketBase = OpenLibrary("bsdsocket.library", 4);
+
+ if(!SocketBase) {
+ __request("No TCP/IP Stack running!");
+ return FALSE;
+ }
+
+ if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
+ SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "curl",
+ TAG_DONE)) {
+ __request("SocketBaseTags ERROR");
+ return FALSE;
+ }
+
+#ifndef __libnix__
+ atexit(Curl_amiga_cleanup);
+#endif
+
+ return TRUE;
+}
+
+#ifdef __libnix__
+ADD2EXIT(Curl_amiga_cleanup, -50);
+#endif
+
+#endif /* __AMIGA__ && ! __ixemul__ */
diff --git a/Utilities/cmcurl/lib/amigaos.h b/Utilities/cmcurl/lib/amigaos.h
new file mode 100644
index 000000000..02bee1610
--- /dev/null
+++ b/Utilities/cmcurl/lib/amigaos.h
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_AMIGAOS_H
+#define HEADER_CURL_AMIGAOS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(__AMIGA__) && !defined(__ixemul__)
+
+bool Curl_amiga_init();
+void Curl_amiga_cleanup();
+
+#else
+
+#define Curl_amiga_init() 1
+#define Curl_amiga_cleanup() Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_AMIGAOS_H */
+
diff --git a/Utilities/cmcurl/lib/arpa_telnet.h b/Utilities/cmcurl/lib/arpa_telnet.h
new file mode 100644
index 000000000..ec238729d
--- /dev/null
+++ b/Utilities/cmcurl/lib/arpa_telnet.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_ARPA_TELNET_H
+#define HEADER_CURL_ARPA_TELNET_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+/*
+ * Telnet option defines. Add more here if in need.
+ */
+#define CURL_TELOPT_BINARY 0 /* binary 8bit data */
+#define CURL_TELOPT_ECHO 1 /* just echo! */
+#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */
+#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */
+#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */
+#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */
+#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
+
+#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
+#define CURL_NEW_ENV_VAR 0
+#define CURL_NEW_ENV_VALUE 1
+
+/*
+ * The telnet options represented as strings
+ */
+static const char * const telnetoptions[]=
+{
+ "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD",
+ "NAME", "STATUS", "TIMING MARK", "RCTE",
+ "NAOL", "NAOP", "NAOCRD", "NAOHTS",
+ "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD",
+ "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
+ "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION",
+ "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING",
+ "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS",
+ "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
+ "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
+};
+
+#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
+
+#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
+#define CURL_TELOPT(x) telnetoptions[x]
+
+#define CURL_NTELOPTS 40
+
+/*
+ * First some defines
+ */
+#define CURL_xEOF 236 /* End Of File */
+#define CURL_SE 240 /* Sub negotiation End */
+#define CURL_NOP 241 /* No OPeration */
+#define CURL_DM 242 /* Data Mark */
+#define CURL_GA 249 /* Go Ahead, reverse the line */
+#define CURL_SB 250 /* SuBnegotiation */
+#define CURL_WILL 251 /* Our side WILL use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_DO 253 /* DO use this option! */
+#define CURL_DONT 254 /* DON'T use this option! */
+#define CURL_IAC 255 /* Interpret As Command */
+
+/*
+ * Then those numbers represented as strings:
+ */
+static const char * const telnetcmds[]=
+{
+ "EOF", "SUSP", "ABORT", "EOR", "SE",
+ "NOP", "DMARK", "BRK", "IP", "AO",
+ "AYT", "EC", "EL", "GA", "SB",
+ "WILL", "WONT", "DO", "DONT", "IAC"
+};
+
+#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
+#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
+
+#define CURL_TELQUAL_IS 0
+#define CURL_TELQUAL_SEND 1
+#define CURL_TELQUAL_INFO 2
+#define CURL_TELQUAL_NAME 3
+
+#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
+ ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
+
+#endif /* CURL_DISABLE_TELNET */
+
+#endif /* HEADER_CURL_ARPA_TELNET_H */
diff --git a/Utilities/cmcurl/lib/asyn-ares.c b/Utilities/cmcurl/lib/asyn-ares.c
new file mode 100644
index 000000000..11a914f82
--- /dev/null
+++ b/Utilities/cmcurl/lib/asyn-ares.c
@@ -0,0 +1,700 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "progress.h"
+
+# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+# define CARES_STATICLIB
+# endif
+# include <ares.h>
+# include <ares_version.h> /* really old c-ares didn't include this by
+ itself */
+
+#if ARES_VERSION >= 0x010500
+/* c-ares 1.5.0 or later, the callback proto is modified */
+#define HAVE_CARES_CALLBACK_TIMEOUTS 1
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+struct ResolverResults {
+ int num_pending; /* number of ares_gethostbyname() requests */
+ Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
+ int last_status;
+};
+
+/*
+ * Curl_resolver_global_init() - the generic low-level asynchronous name
+ * resolve API. Called from curl_global_init() to initialize global resolver
+ * environment. Initializes ares library.
+ */
+int Curl_resolver_global_init(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+ if(ares_library_init(ARES_LIB_INIT_ALL)) {
+ return CURLE_FAILED_INIT;
+ }
+#endif
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ *
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Deinitializes ares library.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
+ ares_library_cleanup();
+#endif
+}
+
+/*
+ * Curl_resolver_init()
+ *
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Fills the passed pointer by the initialized ares_channel.
+ */
+CURLcode Curl_resolver_init(void **resolver)
+{
+ int status = ares_init((ares_channel*)resolver);
+ if(status != ARES_SUCCESS) {
+ if(status == ARES_ENOMEM)
+ return CURLE_OUT_OF_MEMORY;
+ else
+ return CURLE_FAILED_INIT;
+ }
+ return CURLE_OK;
+ /* make sure that all other returns from this function should destroy the
+ ares channel before returning error! */
+}
+
+/*
+ * Curl_resolver_cleanup()
+ *
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Destroys the ares channel.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+ ares_destroy((ares_channel)resolver);
+}
+
+/*
+ * Curl_resolver_duphandle()
+ *
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure). Duplicates the
+ * 'from' ares channel and passes the resulting channel to the 'to' pointer.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+ /* Clone the ares channel for the new handle */
+ if(ARES_SUCCESS != ares_dup((ares_channel*)to, (ares_channel)from))
+ return CURLE_FAILED_INIT;
+ return CURLE_OK;
+}
+
+static void destroy_async_data(struct Curl_async *async);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+ if(conn->data && conn->data->state.resolver)
+ ares_cancel((ares_channel)conn->data->state.resolver);
+ destroy_async_data(&conn->async);
+}
+
+/*
+ * destroy_async_data() cleans up async resolver data.
+ */
+static void destroy_async_data(struct Curl_async *async)
+{
+ free(async->hostname);
+
+ if(async->os_specific) {
+ struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
+ if(res) {
+ if(res->temp_ai) {
+ Curl_freeaddrinfo(res->temp_ai);
+ res->temp_ai = NULL;
+ }
+ free(res);
+ }
+ async->os_specific = NULL;
+ }
+
+ async->hostname = NULL;
+}
+
+/*
+ * Curl_resolver_getsock() is called when someone from the outside world
+ * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
+ * with ares. The caller must make sure that this function is only called when
+ * we have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_resolver_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+
+{
+ struct timeval maxtime;
+ struct timeval timebuf;
+ struct timeval *timeout;
+ long milli;
+ int max = ares_getsock((ares_channel)conn->data->state.resolver,
+ (ares_socket_t *)socks, numsocks);
+
+ maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+ maxtime.tv_usec = 0;
+
+ timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
+ &timebuf);
+ milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
+ if(milli == 0)
+ milli += 10;
+ Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME);
+
+ return max;
+}
+
+/*
+ * waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on
+ */
+
+static int waitperform(struct connectdata *conn, int timeout_ms)
+{
+ struct Curl_easy *data = conn->data;
+ int nfds;
+ int bitmask;
+ ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+ struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+ int i;
+ int num = 0;
+
+ bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
+ ARES_GETSOCK_MAXNUM);
+
+ for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+ pfd[i].events = 0;
+ pfd[i].revents = 0;
+ if(ARES_GETSOCK_READABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLRDNORM|POLLIN;
+ }
+ if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLWRNORM|POLLOUT;
+ }
+ if(pfd[i].events != 0)
+ num++;
+ else
+ break;
+ }
+
+ if(num)
+ nfds = Curl_poll(pfd, num, timeout_ms);
+ else
+ nfds = 0;
+
+ if(!nfds)
+ /* Call ares_process() unconditonally here, even if we simply timed out
+ above, as otherwise the ares name resolve won't timeout! */
+ ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
+ ARES_SOCKET_BAD);
+ else {
+ /* move through the descriptors and ask for processing on them */
+ for(i=0; i < num; i++)
+ ares_process_fd((ares_channel)data->state.resolver,
+ pfd[i].revents & (POLLRDNORM|POLLIN)?
+ pfd[i].fd:ARES_SOCKET_BAD,
+ pfd[i].revents & (POLLWRNORM|POLLOUT)?
+ pfd[i].fd:ARES_SOCKET_BAD);
+ }
+ return nfds;
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns)
+{
+ struct Curl_easy *data = conn->data;
+ struct ResolverResults *res = (struct ResolverResults *)
+ conn->async.os_specific;
+ CURLcode result = CURLE_OK;
+
+ *dns = NULL;
+
+ waitperform(conn, 0);
+
+ if(res && !res->num_pending) {
+ (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+ /* temp_ai ownership is moved to the connection, so we need not free-up
+ them */
+ res->temp_ai = NULL;
+ if(!conn->async.dns) {
+ failf(data, "Could not resolve: %s (%s)",
+ conn->async.hostname, ares_strerror(conn->async.status));
+ result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+ CURLE_COULDNT_RESOLVE_HOST;
+ }
+ else
+ *dns = conn->async.dns;
+
+ destroy_async_data(&conn->async);
+ }
+
+ return result;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ long timeout;
+ struct timeval now = Curl_tvnow();
+ struct Curl_dns_entry *temp_entry;
+
+ if(entry)
+ *entry = NULL; /* clear on entry */
+
+ timeout = Curl_timeleft(data, &now, TRUE);
+ if(timeout < 0) {
+ /* already expired! */
+ connclose(conn, "Timed out before name resolve started");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ if(!timeout)
+ timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
+
+ /* Wait for the name resolve query to complete. */
+ while(!result) {
+ struct timeval *tvp, tv, store;
+ int itimeout;
+ int timeout_ms;
+
+ itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
+
+ store.tv_sec = itimeout/1000;
+ store.tv_usec = (itimeout%1000)*1000;
+
+ tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
+
+ /* use the timeout period ares returned to us above if less than one
+ second is left, otherwise just use 1000ms to make sure the progress
+ callback gets called frequent enough */
+ if(!tvp->tv_sec)
+ timeout_ms = (int)(tvp->tv_usec/1000);
+ else
+ timeout_ms = 1000;
+
+ waitperform(conn, timeout_ms);
+ result = Curl_resolver_is_resolved(conn, &temp_entry);
+
+ if(result || conn->async.done)
+ break;
+
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else {
+ struct timeval now2 = Curl_tvnow();
+ time_t timediff = Curl_tvdiff(now2, now); /* spent time */
+ if(timediff <= 0)
+ timeout -= 1; /* always deduct at least 1 */
+ else if(timediff > timeout)
+ timeout = -1;
+ else
+ timeout -= (long)timediff;
+ now = now2; /* for next loop */
+ }
+ if(timeout < 0)
+ result = CURLE_OPERATION_TIMEDOUT;
+ }
+ if(result)
+ /* failure, so we cancel the ares operation */
+ ares_cancel((ares_channel)data->state.resolver);
+
+ /* Operation complete, if the lookup was successful we now have the entry
+ in the cache. */
+ if(entry)
+ *entry = conn->async.dns;
+
+ if(result)
+ /* close the connection, since we can't return failure here without
+ cleaning up this connection properly.
+ TODO: remove this action from here, it is not a name resolver decision.
+ */
+ connclose(conn, "c-ares resolve failed");
+
+ return result;
+}
+
+/* Connects results to the list */
+static void compound_results(struct ResolverResults *res,
+ Curl_addrinfo *ai)
+{
+ Curl_addrinfo *ai_tail;
+ if(!ai)
+ return;
+ ai_tail = ai;
+
+ while(ai_tail->ai_next)
+ ai_tail = ai_tail->ai_next;
+
+ /* Add the new results to the list of old results. */
+ ai_tail->ai_next = res->temp_ai;
+ res->temp_ai = ai;
+}
+
+/*
+ * ares_query_completed_cb() is the callback that ares will call when
+ * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
+ * when using ares, is completed either successfully or with failure.
+ */
+static void query_completed_cb(void *arg, /* (struct connectdata *) */
+ int status,
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+ int timeouts,
+#endif
+ struct hostent *hostent)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ struct ResolverResults *res;
+
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+ (void)timeouts; /* ignored */
+#endif
+
+ if(ARES_EDESTRUCTION == status)
+ /* when this ares handle is getting destroyed, the 'arg' pointer may not
+ be valid so only defer it when we know the 'status' says its fine! */
+ return;
+
+ res = (struct ResolverResults *)conn->async.os_specific;
+ res->num_pending--;
+
+ if(CURL_ASYNC_SUCCESS == status) {
+ Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+ if(ai) {
+ compound_results(res, ai);
+ }
+ }
+ /* A successful result overwrites any previous error */
+ if(res->last_status != ARES_SUCCESS)
+ res->last_status = status;
+}
+
+/*
+ * Curl_resolver_getaddrinfo() - when using ares
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ char *bufp;
+ struct Curl_easy *data = conn->data;
+ struct in_addr in;
+ int family = PF_INET;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+ *waitp = 0; /* default to synchronous response */
+
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+ }
+
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ /* Otherwise, check if this is an IPv6 address string */
+ if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
+ /* This must be an IPv6 address literal. */
+ return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+
+ switch(conn->ip_version) {
+ default:
+#if ARES_VERSION >= 0x010601
+ family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
+ c-ares versions this just falls through and defaults
+ to PF_INET */
+ break;
+#endif
+ case CURL_IPRESOLVE_V4:
+ family = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ family = PF_INET6;
+ break;
+ }
+#endif /* CURLRES_IPV6 */
+
+ bufp = strdup(hostname);
+ if(bufp) {
+ struct ResolverResults *res = NULL;
+ free(conn->async.hostname);
+ conn->async.hostname = bufp;
+ conn->async.port = port;
+ conn->async.done = FALSE; /* not done */
+ conn->async.status = 0; /* clear */
+ conn->async.dns = NULL; /* clear */
+ res = calloc(sizeof(struct ResolverResults), 1);
+ if(!res) {
+ free(conn->async.hostname);
+ conn->async.hostname = NULL;
+ return NULL;
+ }
+ conn->async.os_specific = res;
+
+ /* initial status - failed */
+ res->last_status = ARES_ENOTFOUND;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ if(family == PF_UNSPEC) {
+ if(Curl_ipv6works()) {
+ res->num_pending = 2;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET, query_completed_cb, conn);
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET6, query_completed_cb, conn);
+ }
+ else {
+ res->num_pending = 1;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET, query_completed_cb, conn);
+ }
+ }
+ else
+#endif /* CURLRES_IPV6 */
+ {
+ res->num_pending = 1;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
+ query_completed_cb, conn);
+ }
+
+ *waitp = 1; /* expect asynchronous response */
+ }
+ return NULL; /* no struct yet */
+}
+
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+ char *servers)
+{
+ CURLcode result = CURLE_NOT_BUILT_IN;
+ int ares_result;
+
+ /* If server is NULL or empty, this would purge all DNS servers
+ * from ares library, which will cause any and all queries to fail.
+ * So, just return OK if none are configured and don't actually make
+ * any changes to c-ares. This lets c-ares use it's defaults, which
+ * it gets from the OS (for instance from /etc/resolv.conf on Linux).
+ */
+ if(!(servers && servers[0]))
+ return CURLE_OK;
+
+#if (ARES_VERSION >= 0x010704)
+ ares_result = ares_set_servers_csv(data->state.resolver, servers);
+ switch(ares_result) {
+ case ARES_SUCCESS:
+ result = CURLE_OK;
+ break;
+ case ARES_ENOMEM:
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ case ARES_ENOTINITIALIZED:
+ case ARES_ENODATA:
+ case ARES_EBADSTR:
+ default:
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ break;
+ }
+#else /* too old c-ares version! */
+ (void)data;
+ (void)(ares_result);
+#endif
+ return result;
+}
+
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+ const char *interf)
+{
+#if (ARES_VERSION >= 0x010704)
+ if(!interf)
+ interf = "";
+
+ ares_set_local_dev((ares_channel)data->state.resolver, interf);
+
+ return CURLE_OK;
+#else /* c-ares version too old! */
+ (void)data;
+ (void)interf;
+ return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+ const char *local_ip4)
+{
+#if (ARES_VERSION >= 0x010704)
+ struct in_addr a4;
+
+ if((!local_ip4) || (local_ip4[0] == 0)) {
+ a4.s_addr = 0; /* disabled: do not bind to a specific address */
+ }
+ else {
+ if(Curl_inet_pton(AF_INET, local_ip4, &a4) != 1) {
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+
+ ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
+
+ return CURLE_OK;
+#else /* c-ares version too old! */
+ (void)data;
+ (void)local_ip4;
+ return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+ const char *local_ip6)
+{
+#if (ARES_VERSION >= 0x010704) && defined(ENABLE_IPV6)
+ unsigned char a6[INET6_ADDRSTRLEN];
+
+ if((!local_ip6) || (local_ip6[0] == 0)) {
+ /* disabled: do not bind to a specific address */
+ memset(a6, 0, sizeof(a6));
+ }
+ else {
+ if(Curl_inet_pton(AF_INET6, local_ip6, a6) != 1) {
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+
+ ares_set_local_ip6((ares_channel)data->state.resolver, a6);
+
+ return CURLE_OK;
+#else /* c-ares version too old! */
+ (void)data;
+ (void)local_ip6;
+ return CURLE_NOT_BUILT_IN;
+#endif
+}
+#endif /* CURLRES_ARES */
diff --git a/Utilities/cmcurl/lib/asyn-thread.c b/Utilities/cmcurl/lib/asyn-thread.c
new file mode 100644
index 000000000..65fa6c5be
--- /dev/null
+++ b/Utilities/cmcurl/lib/asyn-thread.c
@@ -0,0 +1,707 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/***********************************************************************
+ * Only for threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#ifdef HAVE_GETADDRINFO
+# define RESOLVER_ENOMEM EAI_MEMORY
+#else
+# define RESOLVER_ENOMEM ENOMEM
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "inet_ntop.h"
+#include "curl_threads.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_resolver_global_init()
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Does nothing here.
+ */
+int Curl_resolver_global_init(void)
+{
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Does nothing here.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+}
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Does nothing here.
+ */
+CURLcode Curl_resolver_init(void **resolver)
+{
+ (void)resolver;
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Does nothing here.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+ (void)resolver;
+}
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
+ * environment ('resolver' member of the UrlState structure). Does nothing
+ * here.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+ (void)to;
+ (void)from;
+ return CURLE_OK;
+}
+
+static void destroy_async_data(struct Curl_async *);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+ destroy_async_data(&conn->async);
+}
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct connectdata *conn,
+ const char *hostname, int port,
+ const struct addrinfo *hints);
+
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+ curl_mutex_t * mtx;
+ int done;
+
+ char *hostname; /* hostname to resolve, Curl_async.hostname
+ duplicate */
+ int port;
+ int sock_error;
+ Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints;
+#endif
+ struct thread_data *td; /* for thread-self cleanup */
+};
+
+struct thread_data {
+ curl_thread_t thread_hnd;
+ unsigned int poll_interval;
+ time_t interval_end;
+ struct thread_sync_data tsd;
+};
+
+static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
+{
+ return &(((struct thread_data *)conn->async.os_specific)->tsd);
+}
+
+#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data * tsd)
+{
+ if(tsd->mtx) {
+ Curl_mutex_destroy(tsd->mtx);
+ free(tsd->mtx);
+ }
+
+ free(tsd->hostname);
+
+ if(tsd->res)
+ Curl_freeaddrinfo(tsd->res);
+
+ memset(tsd, 0, sizeof(*tsd));
+}
+
+/* Initialize resolver thread synchronization data */
+static
+int init_thread_sync_data(struct thread_data * td,
+ const char *hostname,
+ int port,
+ const struct addrinfo *hints)
+{
+ struct thread_sync_data *tsd = &td->tsd;
+
+ memset(tsd, 0, sizeof(*tsd));
+
+ tsd->td = td;
+ tsd->port = port;
+#ifdef HAVE_GETADDRINFO
+ DEBUGASSERT(hints);
+ tsd->hints = *hints;
+#else
+ (void) hints;
+#endif
+
+ tsd->mtx = malloc(sizeof(curl_mutex_t));
+ if(tsd->mtx == NULL)
+ goto err_exit;
+
+ Curl_mutex_init(tsd->mtx);
+
+ tsd->sock_error = CURL_ASYNC_SUCCESS;
+
+ /* Copying hostname string because original can be destroyed by parent
+ * thread during gethostbyname execution.
+ */
+ tsd->hostname = strdup(hostname);
+ if(!tsd->hostname)
+ goto err_exit;
+
+ return 1;
+
+ err_exit:
+ /* Memory allocation failed */
+ destroy_thread_sync_data(tsd);
+ return 0;
+}
+
+static int getaddrinfo_complete(struct connectdata *conn)
+{
+ struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+ int rc;
+
+ rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+ /* The tsd->res structure has been copied to async.dns and perhaps the DNS
+ cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+ */
+ tsd->res = NULL;
+
+ return rc;
+}
+
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
+{
+ struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
+ struct thread_data *td = tsd->td;
+ char service[12];
+ int rc;
+
+ snprintf(service, sizeof(service), "%d", tsd->port);
+
+ rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
+
+ if(rc != 0) {
+ tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
+ if(tsd->sock_error == 0)
+ tsd->sock_error = RESOLVER_ENOMEM;
+ }
+ else {
+ Curl_addrinfo_set_port(tsd->res, tsd->port);
+ }
+
+ Curl_mutex_acquire(tsd->mtx);
+ if(tsd->done) {
+ /* too late, gotta clean up the mess */
+ Curl_mutex_release(tsd->mtx);
+ destroy_thread_sync_data(tsd);
+ free(td);
+ }
+ else {
+ tsd->done = 1;
+ Curl_mutex_release(tsd->mtx);
+ }
+
+ return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
+{
+ struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+ struct thread_data *td = tsd->td;
+
+ tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
+
+ if(!tsd->res) {
+ tsd->sock_error = SOCKERRNO;
+ if(tsd->sock_error == 0)
+ tsd->sock_error = RESOLVER_ENOMEM;
+ }
+
+ Curl_mutex_acquire(tsd->mtx);
+ if(tsd->done) {
+ /* too late, gotta clean up the mess */
+ Curl_mutex_release(tsd->mtx);
+ destroy_thread_sync_data(tsd);
+ free(td);
+ }
+ else {
+ tsd->done = 1;
+ Curl_mutex_release(tsd->mtx);
+ }
+
+ return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * destroy_async_data() cleans up async resolver data and thread handle.
+ */
+static void destroy_async_data(struct Curl_async *async)
+{
+ if(async->os_specific) {
+ struct thread_data *td = (struct thread_data*) async->os_specific;
+ int done;
+
+ /*
+ * if the thread is still blocking in the resolve syscall, detach it and
+ * let the thread do the cleanup...
+ */
+ Curl_mutex_acquire(td->tsd.mtx);
+ done = td->tsd.done;
+ td->tsd.done = 1;
+ Curl_mutex_release(td->tsd.mtx);
+
+ if(!done) {
+ Curl_thread_destroy(td->thread_hnd);
+ }
+ else {
+ if(td->thread_hnd != curl_thread_t_null)
+ Curl_thread_join(&td->thread_hnd);
+
+ destroy_thread_sync_data(&td->tsd);
+
+ free(async->os_specific);
+ }
+ }
+ async->os_specific = NULL;
+
+ free(async->hostname);
+ async->hostname = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread(struct connectdata *conn,
+ const char *hostname, int port,
+ const struct addrinfo *hints)
+{
+ struct thread_data *td = calloc(1, sizeof(struct thread_data));
+ int err = RESOLVER_ENOMEM;
+
+ conn->async.os_specific = (void *)td;
+ if(!td)
+ goto err_exit;
+
+ conn->async.port = port;
+ conn->async.done = FALSE;
+ conn->async.status = 0;
+ conn->async.dns = NULL;
+ td->thread_hnd = curl_thread_t_null;
+
+ if(!init_thread_sync_data(td, hostname, port, hints))
+ goto err_exit;
+
+ free(conn->async.hostname);
+ conn->async.hostname = strdup(hostname);
+ if(!conn->async.hostname)
+ goto err_exit;
+
+#ifdef HAVE_GETADDRINFO
+ td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+#else
+ td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+#endif
+
+ if(!td->thread_hnd) {
+#ifndef _WIN32_WCE
+ err = errno;
+#endif
+ goto err_exit;
+ }
+
+ return TRUE;
+
+ err_exit:
+ destroy_async_data(&conn->async);
+
+ SET_ERRNO(err);
+
+ return FALSE;
+}
+
+/*
+ * resolver_error() calls failf() with the appropriate message after a resolve
+ * error
+ */
+
+static CURLcode resolver_error(struct connectdata *conn)
+{
+ const char *host_or_proxy;
+ CURLcode result;
+
+ if(conn->bits.httpproxy) {
+ host_or_proxy = "proxy";
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ }
+ else {
+ host_or_proxy = "host";
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
+ conn->async.hostname);
+
+ return result;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ CURLcode result = CURLE_OK;
+
+ DEBUGASSERT(conn && td);
+
+ /* wait for the thread to resolve the name */
+ if(Curl_thread_join(&td->thread_hnd))
+ result = getaddrinfo_complete(conn);
+ else
+ DEBUGASSERT(0);
+
+ conn->async.done = TRUE;
+
+ if(entry)
+ *entry = conn->async.dns;
+
+ if(!conn->async.dns)
+ /* a name was not resolved, report error */
+ result = resolver_error(conn);
+
+ destroy_async_data(&conn->async);
+
+ if(!conn->async.dns)
+ connclose(conn, "asynch resolve failed");
+
+ return result;
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ struct Curl_easy *data = conn->data;
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ int done = 0;
+
+ *entry = NULL;
+
+ if(!td) {
+ DEBUGASSERT(td);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ Curl_mutex_acquire(td->tsd.mtx);
+ done = td->tsd.done;
+ Curl_mutex_release(td->tsd.mtx);
+
+ if(done) {
+ getaddrinfo_complete(conn);
+
+ if(!conn->async.dns) {
+ CURLcode result = resolver_error(conn);
+ destroy_async_data(&conn->async);
+ return result;
+ }
+ destroy_async_data(&conn->async);
+ *entry = conn->async.dns;
+ }
+ else {
+ /* poll for name lookup done with exponential backoff up to 250ms */
+ time_t elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+ if(elapsed < 0)
+ elapsed = 0;
+
+ if(td->poll_interval == 0)
+ /* Start at 1ms poll interval */
+ td->poll_interval = 1;
+ else if(elapsed >= td->interval_end)
+ /* Back-off exponentially if last interval expired */
+ td->poll_interval *= 2;
+
+ if(td->poll_interval > 250)
+ td->poll_interval = 250;
+
+ td->interval_end = elapsed + td->poll_interval;
+ Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
+ }
+
+ return CURLE_OK;
+}
+
+int Curl_resolver_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return 0;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo() - for platforms without getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct in_addr in;
+
+ *waitp = 0; /* default to synchronous response */
+
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+ /* fire up a new resolver thread! */
+ if(init_resolve_thread(conn, hostname, port, NULL)) {
+ *waitp = 1; /* expect asynchronous response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ return Curl_ipv4_resolve_r(hostname, port);
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_resolver_getaddrinfo() - for getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints;
+ struct in_addr in;
+ Curl_addrinfo *res;
+ int error;
+ char sbuf[12];
+ int pf = PF_INET;
+#ifdef CURLRES_IPV6
+ struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+ *waitp = 0; /* default to synchronous response */
+
+#ifndef USE_RESOLVE_ON_IPS
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#ifdef CURLRES_IPV6
+ /* check if this is an IPv6 address string */
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
+ /* This is an IPv6 address literal */
+ return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+#endif /* CURLRES_IPV6 */
+#endif /* !USE_RESOLVE_ON_IPS */
+
+#ifdef CURLRES_IPV6
+ /*
+ * Check if a limited name resolve has been requested.
+ */
+ switch(conn->ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+
+ if((pf != PF_INET) && !Curl_ipv6works())
+ /* The stack seems to be a non-IPv6 one */
+ pf = PF_INET;
+#endif /* CURLRES_IPV6 */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = conn->socktype;
+
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+
+ /* fire up a new resolver thread! */
+ if(init_resolve_thread(conn, hostname, port, &hints)) {
+ *waitp = 1; /* expect asynchronous response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
+ hostname, Curl_strerror(conn, ERRNO));
+
+ error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
+ if(error) {
+ infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n",
+ hostname, port, Curl_strerror(conn, SOCKERRNO));
+ return NULL;
+ }
+ else {
+ Curl_addrinfo_set_port(res, port);
+ }
+
+ return res;
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+ char *servers)
+{
+ (void)data;
+ (void)servers;
+ return CURLE_NOT_BUILT_IN;
+
+}
+
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+ const char *interf)
+{
+ (void)data;
+ (void)interf;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+ const char *local_ip4)
+{
+ (void)data;
+ (void)local_ip4;
+ return CURLE_NOT_BUILT_IN;
+}
+
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+ const char *local_ip6)
+{
+ (void)data;
+ (void)local_ip6;
+ return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* CURLRES_THREADED */
diff --git a/Utilities/cmcurl/lib/asyn.h b/Utilities/cmcurl/lib/asyn.h
new file mode 100644
index 000000000..3adc3664a
--- /dev/null
+++ b/Utilities/cmcurl/lib/asyn.h
@@ -0,0 +1,168 @@
+#ifndef HEADER_CURL_ASYN_H
+#define HEADER_CURL_ASYN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "curl_addrinfo.h"
+
+struct addrinfo;
+struct hostent;
+struct Curl_easy;
+struct connectdata;
+struct Curl_dns_entry;
+
+/*
+ * This header defines all functions in the internal asynch resolver interface.
+ * All asynch resolvers need to provide these functions.
+ * asyn-ares.c and asyn-thread.c are the current implementations of asynch
+ * resolver backends.
+ */
+
+/*
+ * Curl_resolver_global_init()
+ *
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Returning anything else than CURLE_OK fails curl_global_init().
+ */
+int Curl_resolver_global_init(void);
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ */
+void Curl_resolver_global_cleanup(void);
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Should fill the passed pointer by the initialized handler.
+ * Returning anything else than CURLE_OK fails curl_easy_init() with the
+ * correspondent code.
+ */
+CURLcode Curl_resolver_init(void **resolver);
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Should destroy the handler and free all resources connected to
+ * it.
+ */
+void Curl_resolver_cleanup(void *resolver);
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure). Should
+ * duplicate the 'from' handle and pass the resulting handle to the 'to'
+ * pointer. Returning anything else than CURLE_OK causes failed
+ * curl_easy_duphandle() call.
+ */
+int Curl_resolver_duphandle(void **to, void *from);
+
+/*
+ * Curl_resolver_cancel().
+ *
+ * It is called from inside other functions to cancel currently performing
+ * resolver request. Should also free any temporary resources allocated to
+ * perform a request.
+ */
+void Curl_resolver_cancel(struct connectdata *conn);
+
+/* Curl_resolver_getsock()
+ *
+ * This function is called from the multi_getsock() function. 'sock' is a
+ * pointer to an array to hold the file descriptors, with 'numsock' being the
+ * size of that array (in number of entries). This function is supposed to
+ * return bitmask indicating what file descriptors (referring to array indexes
+ * in the 'sock' array) to wait for, read/write.
+ */
+int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock,
+ int numsocks);
+
+/*
+ * Curl_resolver_is_resolved()
+ *
+ * Called repeatedly to check if a previous name resolve request has
+ * completed. It should also make sure to time-out if the operation seems to
+ * take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns);
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_resolver_getaddrinfo() - when using this resolver
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ *
+ * Each resolver backend must of course make sure to return data in the
+ * correct format to comply with this.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
+
+#ifndef CURLRES_ASYNCH
+/* convert these functions if an asynch resolver isn't used */
+#define Curl_resolver_cancel(x) Curl_nop_stmt
+#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_getsock(x,y,z) 0
+#define Curl_resolver_duphandle(x,y) CURLE_OK
+#define Curl_resolver_init(x) CURLE_OK
+#define Curl_resolver_global_init() CURLE_OK
+#define Curl_resolver_global_cleanup() Curl_nop_stmt
+#define Curl_resolver_cleanup(x) Curl_nop_stmt
+#endif
+
+#ifdef CURLRES_ASYNCH
+#define Curl_resolver_asynch() 1
+#else
+#define Curl_resolver_asynch() 0
+#endif
+
+
+/********** end of generic resolver interface functions *****************/
+#endif /* HEADER_CURL_ASYN_H */
diff --git a/Utilities/cmcurl/lib/base64.c b/Utilities/cmcurl/lib/base64.c
new file mode 100644
index 000000000..204a2273d
--- /dev/null
+++ b/Utilities/cmcurl/lib/base64.c
@@ -0,0 +1,320 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Base64 encoding/decoding */
+
+#include "curl_setup.h"
+#include "urldata.h" /* for the Curl_easy definition */
+#include "warnless.h"
+#include "curl_base64.h"
+#include "non-ascii.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ---- Base64 Encoding/Decoding Table --- */
+static const char base64[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/* The Base 64 encoding with an URL and filename safe alphabet, RFC 4648
+ section 5 */
+static const char base64url[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+static size_t decodeQuantum(unsigned char *dest, const char *src)
+{
+ size_t padding = 0;
+ const char *s, *p;
+ unsigned long i, x = 0;
+
+ for(i = 0, s = src; i < 4; i++, s++) {
+ unsigned long v = 0;
+
+ if(*s == '=') {
+ x = (x << 6);
+ padding++;
+ }
+ else {
+ p = base64;
+
+ while(*p && (*p != *s)) {
+ v++;
+ p++;
+ }
+
+ if(*p == *s)
+ x = (x << 6) + v;
+ else
+ return 0;
+ }
+ }
+
+ if(padding < 1)
+ dest[2] = curlx_ultouc(x & 0xFFUL);
+
+ x >>= 8;
+ if(padding < 2)
+ dest[1] = curlx_ultouc(x & 0xFFUL);
+
+ x >>= 8;
+ dest[0] = curlx_ultouc(x & 0xFFUL);
+
+ return 3 - padding;
+}
+
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 NUL-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded
+ * data. Size of decoded data is returned in variable pointed by outlen.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When decoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen)
+{
+ size_t srclen = 0;
+ size_t length = 0;
+ size_t padding = 0;
+ size_t i;
+ size_t numQuantums;
+ size_t rawlen = 0;
+ unsigned char *pos;
+ unsigned char *newstr;
+
+ *outptr = NULL;
+ *outlen = 0;
+ srclen = strlen(src);
+
+ /* Check the length of the input string is valid */
+ if(!srclen || srclen % 4)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* Find the position of any = padding characters */
+ while((src[length] != '=') && src[length])
+ length++;
+
+ /* A maximum of two = padding characters is allowed */
+ if(src[length] == '=') {
+ padding++;
+ if(src[length + 1] == '=')
+ padding++;
+ }
+
+ /* Check the = padding characters weren't part way through the input */
+ if(length + padding != srclen)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* Calculate the number of quantums */
+ numQuantums = srclen / 4;
+
+ /* Calculate the size of the decoded string */
+ rawlen = (numQuantums * 3) - padding;
+
+ /* Allocate our buffer including room for a zero terminator */
+ newstr = malloc(rawlen + 1);
+ if(!newstr)
+ return CURLE_OUT_OF_MEMORY;
+
+ pos = newstr;
+
+ /* Decode the quantums */
+ for(i = 0; i < numQuantums; i++) {
+ size_t result = decodeQuantum(pos, src);
+ if(!result) {
+ free(newstr);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ pos += result;
+ src += 4;
+ }
+
+ /* Zero terminate */
+ *pos = '\0';
+
+ /* Return the decoded data */
+ *outptr = newstr;
+ *outlen = rawlen;
+
+ return CURLE_OK;
+}
+
+static CURLcode base64_encode(const char *table64,
+ struct Curl_easy *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+ unsigned char ibuf[3];
+ unsigned char obuf[4];
+ int i;
+ int inputparts;
+ char *output;
+ char *base64data;
+ char *convbuf = NULL;
+
+ const char *indata = inputbuff;
+
+ *outptr = NULL;
+ *outlen = 0;
+
+ if(!insize)
+ insize = strlen(indata);
+
+#if SIZEOF_SIZE_T == 4
+ if(insize > UINT_MAX/4)
+ return CURLE_OUT_OF_MEMORY;
+#endif
+
+ base64data = output = malloc(insize * 4 / 3 + 4);
+ if(!output)
+ return CURLE_OUT_OF_MEMORY;
+
+ /*
+ * The base64 data needs to be created using the network encoding
+ * not the host encoding. And we can't change the actual input
+ * so we copy it to a buffer, translate it, and use that instead.
+ */
+ result = Curl_convert_clone(data, indata, insize, &convbuf);
+ if(result) {
+ free(output);
+ return result;
+ }
+
+ if(convbuf)
+ indata = (char *)convbuf;
+
+ while(insize > 0) {
+ for(i = inputparts = 0; i < 3; i++) {
+ if(insize > 0) {
+ inputparts++;
+ ibuf[i] = (unsigned char) *indata;
+ indata++;
+ insize--;
+ }
+ else
+ ibuf[i] = 0;
+ }
+
+ obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
+ obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
+ ((ibuf[1] & 0xF0) >> 4));
+ obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
+ ((ibuf[2] & 0xC0) >> 6));
+ obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
+
+ switch(inputparts) {
+ case 1: /* only one byte read */
+ snprintf(output, 5, "%c%c==",
+ table64[obuf[0]],
+ table64[obuf[1]]);
+ break;
+
+ case 2: /* two bytes read */
+ snprintf(output, 5, "%c%c%c=",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]]);
+ break;
+
+ default:
+ snprintf(output, 5, "%c%c%c%c",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]],
+ table64[obuf[3]]);
+ break;
+ }
+ output += 4;
+ }
+
+ /* Zero terminate */
+ *output = '\0';
+
+ /* Return the pointer to the new data (allocated memory) */
+ *outptr = base64data;
+
+ free(convbuf);
+
+ /* Return the length of the new data */
+ *outlen = strlen(base64data);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_base64_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When encoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_encode(struct Curl_easy *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ return base64_encode(base64, data, inputbuff, insize, outptr, outlen);
+}
+
+/*
+ * Curl_base64url_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When encoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64url_encode(struct Curl_easy *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ return base64_encode(base64url, data, inputbuff, insize, outptr, outlen);
+}
diff --git a/Utilities/cmcurl/lib/conncache.c b/Utilities/cmcurl/lib/conncache.c
new file mode 100644
index 000000000..c79d22764
--- /dev/null
+++ b/Utilities/cmcurl/lib/conncache.c
@@ -0,0 +1,360 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "conncache.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static void conn_llist_dtor(void *user, void *element)
+{
+ struct connectdata *data = element;
+ (void)user;
+
+ data->bundle = NULL;
+}
+
+static CURLcode bundle_create(struct Curl_easy *data,
+ struct connectbundle **cb_ptr)
+{
+ (void)data;
+ DEBUGASSERT(*cb_ptr == NULL);
+ *cb_ptr = malloc(sizeof(struct connectbundle));
+ if(!*cb_ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ (*cb_ptr)->num_connections = 0;
+ (*cb_ptr)->multiuse = BUNDLE_UNKNOWN;
+
+ Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor);
+ return CURLE_OK;
+}
+
+static void bundle_destroy(struct connectbundle *cb_ptr)
+{
+ if(!cb_ptr)
+ return;
+
+ Curl_llist_destroy(&cb_ptr->conn_list, NULL);
+
+ free(cb_ptr);
+}
+
+/* Add a connection to a bundle */
+static CURLcode bundle_add_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn)
+{
+ Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn,
+ &conn->bundle_node);
+ conn->bundle = cb_ptr;
+ cb_ptr->num_connections++;
+ return CURLE_OK;
+}
+
+/* Remove a connection from a bundle */
+static int bundle_remove_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+
+ curr = cb_ptr->conn_list.head;
+ while(curr) {
+ if(curr->ptr == conn) {
+ Curl_llist_remove(&cb_ptr->conn_list, curr, NULL);
+ cb_ptr->num_connections--;
+ conn->bundle = NULL;
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
+ }
+ return 0;
+}
+
+static void free_bundle_hash_entry(void *freethis)
+{
+ struct connectbundle *b = (struct connectbundle *) freethis;
+
+ bundle_destroy(b);
+}
+
+int Curl_conncache_init(struct conncache *connc, int size)
+{
+ return Curl_hash_init(&connc->hash, size, Curl_hash_str,
+ Curl_str_key_compare, free_bundle_hash_entry);
+}
+
+void Curl_conncache_destroy(struct conncache *connc)
+{
+ if(connc)
+ Curl_hash_destroy(&connc->hash);
+}
+
+/* creates a key to find a bundle for this connection */
+static void hashkey(struct connectdata *conn, char *buf,
+ size_t len) /* something like 128 is fine */
+{
+ const char *hostname;
+
+ if(conn->bits.socksproxy)
+ hostname = conn->socks_proxy.host.name;
+ else if(conn->bits.httpproxy)
+ hostname = conn->http_proxy.host.name;
+ else if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+
+ DEBUGASSERT(len > 32);
+
+ /* put the number first so that the hostname gets cut off if too long */
+ snprintf(buf, len, "%ld%s", conn->port, hostname);
+}
+
+/* Look up the bundle with all the connections to the same host this
+ connectdata struct is setup to use. */
+struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+ struct conncache *connc)
+{
+ struct connectbundle *bundle = NULL;
+ if(connc) {
+ char key[128];
+ hashkey(conn, key, sizeof(key));
+ bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
+ }
+
+ return bundle;
+}
+
+static bool conncache_add_bundle(struct conncache *connc,
+ char *key,
+ struct connectbundle *bundle)
+{
+ void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle);
+
+ return p?TRUE:FALSE;
+}
+
+static void conncache_remove_bundle(struct conncache *connc,
+ struct connectbundle *bundle)
+{
+ struct curl_hash_iterator iter;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ Curl_hash_start_iterate(&connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ if(he->ptr == bundle) {
+ /* The bundle is destroyed by the hash destructor function,
+ free_bundle_hash_entry() */
+ Curl_hash_delete(&connc->hash, he->key, he->key_len);
+ return;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+}
+
+CURLcode Curl_conncache_add_conn(struct conncache *connc,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ struct connectbundle *bundle;
+ struct connectbundle *new_bundle = NULL;
+ struct Curl_easy *data = conn->data;
+
+ bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
+ if(!bundle) {
+ int rc;
+ char key[128];
+
+ result = bundle_create(data, &new_bundle);
+ if(result)
+ return result;
+
+ hashkey(conn, key, sizeof(key));
+ rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
+
+ if(!rc) {
+ bundle_destroy(new_bundle);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ bundle = new_bundle;
+ }
+
+ result = bundle_add_conn(bundle, conn);
+ if(result) {
+ if(new_bundle)
+ conncache_remove_bundle(data->state.conn_cache, new_bundle);
+ return result;
+ }
+
+ conn->connection_id = connc->next_connection_id++;
+ connc->num_connections++;
+
+ DEBUGF(infof(conn->data, "Added connection %ld. "
+ "The cache now contains %" CURL_FORMAT_CURL_OFF_TU " members\n",
+ conn->connection_id, (curl_off_t) connc->num_connections));
+
+ return CURLE_OK;
+}
+
+void Curl_conncache_remove_conn(struct conncache *connc,
+ struct connectdata *conn)
+{
+ struct connectbundle *bundle = conn->bundle;
+
+ /* The bundle pointer can be NULL, since this function can be called
+ due to a failed connection attempt, before being added to a bundle */
+ if(bundle) {
+ bundle_remove_conn(bundle, conn);
+ if(bundle->num_connections == 0) {
+ conncache_remove_bundle(connc, bundle);
+ }
+
+ if(connc) {
+ connc->num_connections--;
+
+ DEBUGF(infof(conn->data, "The cache now contains %"
+ CURL_FORMAT_CURL_OFF_TU " members\n",
+ (curl_off_t) connc->num_connections));
+ }
+ }
+}
+
+/* This function iterates the entire connection cache and calls the
+ function func() with the connection pointer as the first argument
+ and the supplied 'param' argument as the other,
+
+ Return 0 from func() to continue the loop, return 1 to abort it.
+ */
+void Curl_conncache_foreach(struct conncache *connc,
+ void *param,
+ int (*func)(struct connectdata *conn, void *param))
+{
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ Curl_hash_start_iterate(&connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectbundle *bundle;
+
+ bundle = he->ptr;
+ he = Curl_hash_next_element(&iter);
+
+ curr = bundle->conn_list.head;
+ while(curr) {
+ /* Yes, we need to update curr before calling func(), because func()
+ might decide to remove the connection */
+ struct connectdata *conn = curr->ptr;
+ curr = curr->next;
+
+ if(1 == func(conn, param))
+ return;
+ }
+ }
+}
+
+/* Return the first connection found in the cache. Used when closing all
+ connections */
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc)
+{
+ struct curl_hash_iterator iter;
+ struct curl_hash_element *he;
+ struct connectbundle *bundle;
+
+ Curl_hash_start_iterate(&connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct curl_llist_element *curr;
+ bundle = he->ptr;
+
+ curr = bundle->conn_list.head;
+ if(curr) {
+ return curr->ptr;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+
+ return NULL;
+}
+
+
+#if 0
+/* Useful for debugging the connection cache */
+void Curl_conncache_print(struct conncache *connc)
+{
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ fprintf(stderr, "=Bundle cache=\n");
+
+ Curl_hash_start_iterate(connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectbundle *bundle;
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ fprintf(stderr, "%s -", he->key);
+ curr = bundle->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+
+ fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
+ curr = curr->next;
+ }
+ fprintf(stderr, "\n");
+
+ he = Curl_hash_next_element(&iter);
+ }
+}
+#endif
diff --git a/Utilities/cmcurl/lib/conncache.h b/Utilities/cmcurl/lib/conncache.h
new file mode 100644
index 000000000..f976cfdb4
--- /dev/null
+++ b/Utilities/cmcurl/lib/conncache.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_CONNCACHE_H
+#define HEADER_CURL_CONNCACHE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+struct conncache {
+ struct curl_hash hash;
+ size_t num_connections;
+ long next_connection_id;
+ struct timeval last_cleanup;
+};
+
+#define BUNDLE_NO_MULTIUSE -1
+#define BUNDLE_UNKNOWN 0 /* initial value */
+#define BUNDLE_PIPELINING 1
+#define BUNDLE_MULTIPLEX 2
+
+struct connectbundle {
+ int multiuse; /* supports multi-use */
+ size_t num_connections; /* Number of connections in the bundle */
+ struct curl_llist conn_list; /* The connectdata members of the bundle */
+};
+
+int Curl_conncache_init(struct conncache *, int size);
+
+void Curl_conncache_destroy(struct conncache *connc);
+
+/* return the correct bundle, to a host or a proxy */
+struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+ struct conncache *connc);
+
+CURLcode Curl_conncache_add_conn(struct conncache *connc,
+ struct connectdata *conn);
+
+void Curl_conncache_remove_conn(struct conncache *connc,
+ struct connectdata *conn);
+
+void Curl_conncache_foreach(struct conncache *connc,
+ void *param,
+ int (*func)(struct connectdata *conn,
+ void *param));
+
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc);
+
+void Curl_conncache_print(struct conncache *connc);
+
+#endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/Utilities/cmcurl/lib/connect.c b/Utilities/cmcurl/lib/connect.c
new file mode 100644
index 000000000..d4fd52b99
--- /dev/null
+++ b/Utilities/cmcurl/lib/connect.c
@@ -0,0 +1,1418 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h> /* for TCP_NODELAY */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "connect.h"
+#include "select.h"
+#include "url.h" /* for Curl_safefree() */
+#include "multiif.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
+#include "progress.h"
+#include "warnless.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "system_win32.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef __SYMBIAN32__
+/* This isn't actually supported under Symbian OS */
+#undef SO_NOSIGPIPE
+#endif
+
+static bool verifyconnect(curl_socket_t sockfd, int *error);
+
+#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
+/* DragonFlyBSD and Windows use millisecond units */
+#define KEEPALIVE_FACTOR(x) (x *= 1000)
+#else
+#define KEEPALIVE_FACTOR(x)
+#endif
+
+#if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
+#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
+
+struct tcp_keepalive {
+ u_long onoff;
+ u_long keepalivetime;
+ u_long keepaliveinterval;
+};
+#endif
+
+static void
+tcpkeepalive(struct Curl_easy *data,
+ curl_socket_t sockfd)
+{
+ int optval = data->set.tcp_keepalive?1:0;
+
+ /* only set IDLE and INTVL if setting KEEPALIVE is successful */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
+ }
+ else {
+#if defined(SIO_KEEPALIVE_VALS)
+ struct tcp_keepalive vals;
+ DWORD dummy;
+ vals.onoff = 1;
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ vals.keepalivetime = optval;
+ optval = curlx_sltosi(data->set.tcp_keepintvl);
+ KEEPALIVE_FACTOR(optval);
+ vals.keepaliveinterval = optval;
+ if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
+ NULL, 0, &dummy, NULL, NULL) != 0) {
+ infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
+ (int)sockfd, WSAGetLastError());
+ }
+#else
+#ifdef TCP_KEEPIDLE
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
+ }
+#endif
+#ifdef TCP_KEEPINTVL
+ optval = curlx_sltosi(data->set.tcp_keepintvl);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
+ }
+#endif
+#ifdef TCP_KEEPALIVE
+ /* Mac OS X style */
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
+ }
+#endif
+#endif
+ }
+}
+
+static CURLcode
+singleipconnect(struct connectdata *conn,
+ const Curl_addrinfo *ai, /* start connecting to this */
+ curl_socket_t *sock);
+
+/*
+ * Curl_timeleft() returns the amount of milliseconds left allowed for the
+ * transfer/connection. If the value is negative, the timeout time has already
+ * elapsed.
+ *
+ * The start time is stored in progress.t_startsingle - as set with
+ * Curl_pgrsTime(..., TIMER_STARTSINGLE);
+ *
+ * If 'nowp' is non-NULL, it points to the current time.
+ * 'duringconnect' is FALSE if not during a connect, as then of course the
+ * connect timeout is not taken into account!
+ *
+ * @unittest: 1303
+ */
+time_t Curl_timeleft(struct Curl_easy *data,
+ struct timeval *nowp,
+ bool duringconnect)
+{
+ int timeout_set = 0;
+ time_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+ struct timeval now;
+
+ /* if a timeout is set, use the most restrictive one */
+
+ if(data->set.timeout > 0)
+ timeout_set |= 1;
+ if(duringconnect && (data->set.connecttimeout > 0))
+ timeout_set |= 2;
+
+ switch(timeout_set) {
+ case 1:
+ timeout_ms = data->set.timeout;
+ break;
+ case 2:
+ timeout_ms = data->set.connecttimeout;
+ break;
+ case 3:
+ if(data->set.timeout < data->set.connecttimeout)
+ timeout_ms = data->set.timeout;
+ else
+ timeout_ms = data->set.connecttimeout;
+ break;
+ default:
+ /* use the default */
+ if(!duringconnect)
+ /* if we're not during connect, there's no default timeout so if we're
+ at zero we better just return zero and not make it a negative number
+ by the math below */
+ return 0;
+ break;
+ }
+
+ if(!nowp) {
+ now = Curl_tvnow();
+ nowp = &now;
+ }
+
+ /* subtract elapsed time */
+ if(duringconnect)
+ /* since this most recent connect started */
+ timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+ else
+ /* since the entire operation started */
+ timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+
+ return timeout_ms;
+}
+
+static CURLcode bindlocal(struct connectdata *conn,
+ curl_socket_t sockfd, int af, unsigned int scope)
+{
+ struct Curl_easy *data = conn->data;
+
+ struct Curl_sockaddr_storage sa;
+ struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
+ curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
+ struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
+#endif
+
+ struct Curl_dns_entry *h=NULL;
+ unsigned short port = data->set.localport; /* use this port number, 0 for
+ "random" */
+ /* how many port numbers to try to bind to, increasing one at a time */
+ int portnum = data->set.localportrange;
+ const char *dev = data->set.str[STRING_DEVICE];
+ int error;
+
+ /*************************************************************
+ * Select device to bind socket to
+ *************************************************************/
+ if(!dev && !port)
+ /* no local kind of binding was requested */
+ return CURLE_OK;
+
+ memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
+
+ if(dev && (strlen(dev)<255) ) {
+ char myhost[256] = "";
+ int done = 0; /* -1 for error, 1 for address found */
+ bool is_interface = FALSE;
+ bool is_host = FALSE;
+ static const char *if_prefix = "if!";
+ static const char *host_prefix = "host!";
+
+ if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
+ dev += strlen(if_prefix);
+ is_interface = TRUE;
+ }
+ else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
+ dev += strlen(host_prefix);
+ is_host = TRUE;
+ }
+
+ /* interface */
+ if(!is_host) {
+ switch(Curl_if2ip(af, scope, conn->scope_id, dev,
+ myhost, sizeof(myhost))) {
+ case IF2IP_NOT_FOUND:
+ if(is_interface) {
+ /* Do not fall back to treating it as a host name */
+ failf(data, "Couldn't bind to interface '%s'", dev);
+ return CURLE_INTERFACE_FAILED;
+ }
+ break;
+ case IF2IP_AF_NOT_SUPPORTED:
+ /* Signal the caller to try another address family if available */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ case IF2IP_FOUND:
+ is_interface = TRUE;
+ /*
+ * We now have the numerical IP address in the 'myhost' buffer
+ */
+ infof(data, "Local Interface %s is ip %s using address family %i\n",
+ dev, myhost, af);
+ done = 1;
+
+#ifdef SO_BINDTODEVICE
+ /* I am not sure any other OSs than Linux that provide this feature,
+ * and at the least I cannot test. --Ben
+ *
+ * This feature allows one to tightly bind the local socket to a
+ * particular interface. This will force even requests to other
+ * local interfaces to go out the external interface.
+ *
+ *
+ * Only bind to the interface when specified as interface, not just
+ * as a hostname or ip address.
+ */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ dev, (curl_socklen_t)strlen(dev)+1) != 0) {
+ error = SOCKERRNO;
+ infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
+ " will do regular bind\n",
+ dev, error, Curl_strerror(conn, error));
+ /* This is typically "errno 1, error: Operation not permitted" if
+ you're not running as root or another suitable privileged
+ user */
+ }
+#endif
+ break;
+ }
+ }
+ if(!is_interface) {
+ /*
+ * This was not an interface, resolve the name as a host name
+ * or IP number
+ *
+ * Temporarily force name resolution to use only the address type
+ * of the connection. The resolve functions should really be changed
+ * to take a type parameter instead.
+ */
+ long ipver = conn->ip_version;
+ int rc;
+
+ if(af == AF_INET)
+ conn->ip_version = CURL_IPRESOLVE_V4;
+#ifdef ENABLE_IPV6
+ else if(af == AF_INET6)
+ conn->ip_version = CURL_IPRESOLVE_V6;
+#endif
+
+ rc = Curl_resolv(conn, dev, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_resolver_wait_resolv(conn, &h);
+ conn->ip_version = ipver;
+
+ if(h) {
+ /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+ Curl_printable_address(h->addr, myhost, sizeof(myhost));
+ infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
+ dev, af, myhost, h->addr->ai_family);
+ Curl_resolv_unlock(data, h);
+ done = 1;
+ }
+ else {
+ /*
+ * provided dev was no interface (or interfaces are not supported
+ * e.g. solaris) no ip address and no domain we fail here
+ */
+ done = -1;
+ }
+ }
+
+ if(done > 0) {
+#ifdef ENABLE_IPV6
+ /* IPv6 address */
+ if(af == AF_INET6) {
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ char *scope_ptr = strchr(myhost, '%');
+ if(scope_ptr)
+ *(scope_ptr++) = 0;
+#endif
+ if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
+ si6->sin6_family = AF_INET6;
+ si6->sin6_port = htons(port);
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ if(scope_ptr)
+ /* The "myhost" string either comes from Curl_if2ip or from
+ Curl_printable_address. The latter returns only numeric scope
+ IDs and the former returns none at all. So the scope ID, if
+ present, is known to be numeric */
+ si6->sin6_scope_id = atoi(scope_ptr);
+#endif
+ }
+ sizeof_sa = sizeof(struct sockaddr_in6);
+ }
+ else
+#endif
+ /* IPv4 address */
+ if((af == AF_INET) &&
+ (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+ si4->sin_family = AF_INET;
+ si4->sin_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in);
+ }
+ }
+
+ if(done < 1) {
+ failf(data, "Couldn't bind to '%s'", dev);
+ return CURLE_INTERFACE_FAILED;
+ }
+ }
+ else {
+ /* no device was given, prepare sa to match af's needs */
+#ifdef ENABLE_IPV6
+ if(af == AF_INET6) {
+ si6->sin6_family = AF_INET6;
+ si6->sin6_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in6);
+ }
+ else
+#endif
+ if(af == AF_INET) {
+ si4->sin_family = AF_INET;
+ si4->sin_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in);
+ }
+ }
+
+ for(;;) {
+ if(bind(sockfd, sock, sizeof_sa) >= 0) {
+ /* we succeeded to bind */
+ struct Curl_sockaddr_storage add;
+ curl_socklen_t size = sizeof(add);
+ memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
+ if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "getsockname() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return CURLE_INTERFACE_FAILED;
+ }
+ infof(data, "Local port: %hu\n", port);
+ conn->bits.bound = TRUE;
+ return CURLE_OK;
+ }
+
+ if(--portnum > 0) {
+ infof(data, "Bind to local port %hu failed, trying next\n", port);
+ port++; /* try next port */
+ /* We re-use/clobber the port variable here below */
+ if(sock->sa_family == AF_INET)
+ si4->sin_port = ntohs(port);
+#ifdef ENABLE_IPV6
+ else
+ si6->sin6_port = ntohs(port);
+#endif
+ }
+ else
+ break;
+ }
+
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "bind failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+
+ return CURLE_INTERFACE_FAILED;
+}
+
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
+{
+ bool rc = TRUE;
+#ifdef SO_ERROR
+ int err = 0;
+ curl_socklen_t errSize = sizeof(err);
+
+#ifdef WIN32
+ /*
+ * In October 2003 we effectively nullified this function on Windows due to
+ * problems with it using all CPU in multi-threaded cases.
+ *
+ * In May 2004, we bring it back to offer more info back on connect failures.
+ * Gisle Vanem could reproduce the former problems with this function, but
+ * could avoid them by adding this SleepEx() call below:
+ *
+ * "I don't have Rational Quantify, but the hint from his post was
+ * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+ * just Sleep(0) would be enough?) would release whatever
+ * mutex/critical-section the ntdll call is waiting on.
+ *
+ * Someone got to verify this on Win-NT 4.0, 2000."
+ */
+
+#ifdef _WIN32_WCE
+ Sleep(0);
+#else
+ SleepEx(0, FALSE);
+#endif
+
+#endif
+
+ if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
+ err = SOCKERRNO;
+#ifdef _WIN32_WCE
+ /* Old WinCE versions don't support SO_ERROR */
+ if(WSAENOPROTOOPT == err) {
+ SET_SOCKERRNO(0);
+ err = 0;
+ }
+#endif
+#ifdef __minix
+ /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
+ if(EBADIOCTL == err) {
+ SET_SOCKERRNO(0);
+ err = 0;
+ }
+#endif
+ if((0 == err) || (EISCONN == err))
+ /* we are connected, awesome! */
+ rc = TRUE;
+ else
+ /* This wasn't a successful connect */
+ rc = FALSE;
+ if(error)
+ *error = err;
+#else
+ (void)sockfd;
+ if(error)
+ *error = SOCKERRNO;
+#endif
+ return rc;
+}
+
+/* Used within the multi interface. Try next IP address, return TRUE if no
+ more address exists or error */
+static CURLcode trynextip(struct connectdata *conn,
+ int sockindex,
+ int tempindex)
+{
+ const int other = tempindex ^ 1;
+ CURLcode result = CURLE_COULDNT_CONNECT;
+
+ /* First clean up after the failed socket.
+ Don't close it yet to ensure that the next IP's socket gets a different
+ file descriptor, which can prevent bugs when the curl_multi_socket_action
+ interface is used with certain select() replacements such as kqueue. */
+ curl_socket_t fd_to_close = conn->tempsock[tempindex];
+ conn->tempsock[tempindex] = CURL_SOCKET_BAD;
+
+ if(sockindex == FIRSTSOCKET) {
+ Curl_addrinfo *ai = NULL;
+ int family = AF_UNSPEC;
+
+ if(conn->tempaddr[tempindex]) {
+ /* find next address in the same protocol family */
+ family = conn->tempaddr[tempindex]->ai_family;
+ ai = conn->tempaddr[tempindex]->ai_next;
+ }
+#ifdef ENABLE_IPV6
+ else if(conn->tempaddr[0]) {
+ /* happy eyeballs - try the other protocol family */
+ int firstfamily = conn->tempaddr[0]->ai_family;
+ family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
+ ai = conn->tempaddr[0]->ai_next;
+ }
+#endif
+
+ while(ai) {
+ if(conn->tempaddr[other]) {
+ /* we can safely skip addresses of the other protocol family */
+ while(ai && ai->ai_family != family)
+ ai = ai->ai_next;
+ }
+
+ if(ai) {
+ result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
+ if(result == CURLE_COULDNT_CONNECT) {
+ ai = ai->ai_next;
+ continue;
+ }
+
+ conn->tempaddr[tempindex] = ai;
+ }
+ break;
+ }
+ }
+
+ if(fd_to_close != CURL_SOCKET_BAD)
+ Curl_closesocket(conn, fd_to_close);
+
+ return result;
+}
+
+/* Copies connection info into the session handle to make it available
+ when the session handle is no longer associated with a connection. */
+void Curl_persistconninfo(struct connectdata *conn)
+{
+ memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+ memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
+ conn->data->info.conn_scheme = conn->handler->scheme;
+ conn->data->info.conn_protocol = conn->handler->protocol;
+ conn->data->info.conn_primary_port = conn->primary_port;
+ conn->data->info.conn_local_port = conn->local_port;
+}
+
+/* retrieves ip address and port from a sockaddr structure */
+static bool getaddressinfo(struct sockaddr *sa, char *addr,
+ long *port)
+{
+ unsigned short us_port;
+ struct sockaddr_in *si = NULL;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *si6 = NULL;
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+ struct sockaddr_un *su = NULL;
+#endif
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ si = (struct sockaddr_in *)(void *) sa;
+ if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
+ addr, MAX_IPADR_LEN)) {
+ us_port = ntohs(si->sin_port);
+ *port = us_port;
+ return TRUE;
+ }
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ si6 = (struct sockaddr_in6 *)(void *) sa;
+ if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
+ addr, MAX_IPADR_LEN)) {
+ us_port = ntohs(si6->sin6_port);
+ *port = us_port;
+ return TRUE;
+ }
+ break;
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+ case AF_UNIX:
+ su = (struct sockaddr_un*)sa;
+ snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+ *port = 0;
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+ addr[0] = '\0';
+ *port = 0;
+
+ return FALSE;
+}
+
+/* retrieves the start/end point information of a socket of an established
+ connection */
+void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
+{
+ curl_socklen_t len;
+ struct Curl_sockaddr_storage ssrem;
+ struct Curl_sockaddr_storage ssloc;
+ struct Curl_easy *data = conn->data;
+
+ if(conn->socktype == SOCK_DGRAM)
+ /* there's no connection! */
+ return;
+
+ if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
+ int error;
+
+ len = sizeof(struct Curl_sockaddr_storage);
+ if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
+ error = SOCKERRNO;
+ failf(data, "getpeername() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ len = sizeof(struct Curl_sockaddr_storage);
+ memset(&ssloc, 0, sizeof(ssloc));
+ if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
+ error = SOCKERRNO;
+ failf(data, "getsockname() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ if(!getaddressinfo((struct sockaddr*)&ssrem,
+ conn->primary_ip, &conn->primary_port)) {
+ error = ERRNO;
+ failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+ memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
+
+ if(!getaddressinfo((struct sockaddr*)&ssloc,
+ conn->local_ip, &conn->local_port)) {
+ error = ERRNO;
+ failf(data, "ssloc inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ }
+
+ /* persist connection info in session handle */
+ Curl_persistconninfo(conn);
+}
+
+/*
+ * Curl_is_connected() checks if the socket has connected.
+ */
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+ int sockindex,
+ bool *connected)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_OK;
+ time_t allow;
+ int error = 0;
+ struct timeval now;
+ int rc;
+ int i;
+
+ DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
+
+ *connected = FALSE; /* a very negative world view is best */
+
+ if(conn->bits.tcpconnect[sockindex]) {
+ /* we are connected already! */
+ *connected = TRUE;
+ return CURLE_OK;
+ }
+
+ now = Curl_tvnow();
+
+ /* figure out how long time we have left to connect */
+ allow = Curl_timeleft(data, &now, TRUE);
+
+ if(allow < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ for(i=0; i<2; i++) {
+ const int other = i ^ 1;
+ if(conn->tempsock[i] == CURL_SOCKET_BAD)
+ continue;
+
+#ifdef mpeix
+ /* Call this function once now, and ignore the results. We do this to
+ "clear" the error state on the socket so that we can later read it
+ reliably. This is reported necessary on the MPE/iX operating system. */
+ (void)verifyconnect(conn->tempsock[i], NULL);
+#endif
+
+ /* check socket for connect */
+ rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
+
+ if(rc == 0) { /* no connection yet */
+ error = 0;
+ if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+ infof(data, "After %ldms connect time, move on!\n",
+ conn->timeoutms_per_addr);
+ error = ETIMEDOUT;
+ }
+
+ /* should we try another protocol family? */
+ if(i == 0 && conn->tempaddr[1] == NULL &&
+ curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
+ trynextip(conn, sockindex, 1);
+ }
+ }
+ else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
+ if(verifyconnect(conn->tempsock[i], &error)) {
+ /* we are connected with TCP, awesome! */
+
+ /* use this socket from now on */
+ conn->sock[sockindex] = conn->tempsock[i];
+ conn->ip_addr = conn->tempaddr[i];
+ conn->tempsock[i] = CURL_SOCKET_BAD;
+
+ /* close the other socket, if open */
+ if(conn->tempsock[other] != CURL_SOCKET_BAD) {
+ Curl_closesocket(conn, conn->tempsock[other]);
+ conn->tempsock[other] = CURL_SOCKET_BAD;
+ }
+
+ /* see if we need to do any proxy magic first once we connected */
+ result = Curl_connected_proxy(conn, sockindex);
+ if(result)
+ return result;
+
+ conn->bits.tcpconnect[sockindex] = TRUE;
+
+ *connected = TRUE;
+ if(sockindex == FIRSTSOCKET)
+ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+ Curl_updateconninfo(conn, conn->sock[sockindex]);
+ Curl_verboseconnect(conn);
+
+ return CURLE_OK;
+ }
+ infof(data, "Connection failed\n");
+ }
+ else if(rc & CURL_CSELECT_ERR)
+ (void)verifyconnect(conn->tempsock[i], &error);
+
+ /*
+ * The connection failed here, we should attempt to connect to the "next
+ * address" for the given host. But first remember the latest error.
+ */
+ if(error) {
+ data->state.os_errno = error;
+ SET_SOCKERRNO(error);
+ if(conn->tempaddr[i]) {
+ CURLcode status;
+ char ipaddress[MAX_IPADR_LEN];
+ Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
+ infof(data, "connect to %s port %ld failed: %s\n",
+ ipaddress, conn->port, Curl_strerror(conn, error));
+
+ conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
+ allow : allow / 2;
+
+ status = trynextip(conn, sockindex, i);
+ if(status != CURLE_COULDNT_CONNECT
+ || conn->tempsock[other] == CURL_SOCKET_BAD)
+ /* the last attempt failed and no other sockets remain open */
+ result = status;
+ }
+ }
+ }
+
+ if(result) {
+ /* no more addresses to try */
+
+ const char *hostname;
+
+ /* if the first address family runs out of addresses to try before
+ the happy eyeball timeout, go ahead and try the next family now */
+ if(conn->tempaddr[1] == NULL) {
+ result = trynextip(conn, sockindex, 1);
+ if(!result)
+ return result;
+ }
+
+ if(conn->bits.socksproxy)
+ hostname = conn->socks_proxy.host.name;
+ else if(conn->bits.httpproxy)
+ hostname = conn->http_proxy.host.name;
+ else if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+
+ failf(data, "Failed to connect to %s port %ld: %s",
+ hostname, conn->port, Curl_strerror(conn, error));
+ }
+
+ return result;
+}
+
+void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
+{
+#if defined(TCP_NODELAY)
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ struct Curl_easy *data = conn->data;
+#endif
+ curl_socklen_t onoff = (curl_socklen_t) 1;
+ int level = IPPROTO_TCP;
+
+#if 0
+ /* The use of getprotobyname() is disabled since it isn't thread-safe on
+ numerous systems. On these getprotobyname_r() should be used instead, but
+ that exists in at least one 4 arg version and one 5 arg version, and
+ since the proto number rarely changes anyway we now just use the hard
+ coded number. The "proper" fix would need a configure check for the
+ correct function much in the same style the gethostbyname_r versions are
+ detected. */
+ struct protoent *pe = getprotobyname("tcp");
+ if(pe)
+ level = pe->p_proto;
+#endif
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) conn;
+#endif
+
+ if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
+ sizeof(onoff)) < 0)
+ infof(data, "Could not set TCP_NODELAY: %s\n",
+ Curl_strerror(conn, SOCKERRNO));
+ else
+ infof(data, "TCP_NODELAY set\n");
+#else
+ (void)conn;
+ (void)sockfd;
+#endif
+}
+
+#ifdef SO_NOSIGPIPE
+/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+ sending data to a dead peer (instead of relying on the 4th argument to send
+ being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
+ systems? */
+static void nosigpipe(struct connectdata *conn,
+ curl_socket_t sockfd)
+{
+ struct Curl_easy *data= conn->data;
+ int onoff = 1;
+ if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
+ sizeof(onoff)) < 0)
+ infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+ Curl_strerror(conn, SOCKERRNO));
+}
+#else
+#define nosigpipe(x,y) Curl_nop_stmt
+#endif
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+ experience slow performance when you copy data to a TCP server.
+
+ https://support.microsoft.com/kb/823764
+
+ Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+ Buffer Size
+
+ The problem described in this knowledge-base is applied only to pre-Vista
+ Windows. Following function trying to detect OS version and skips
+ SO_SNDBUF adjustment for Windows Vista and above.
+*/
+#define DETECT_OS_NONE 0
+#define DETECT_OS_PREVISTA 1
+#define DETECT_OS_VISTA_OR_LATER 2
+
+void Curl_sndbufset(curl_socket_t sockfd)
+{
+ int val = CURL_MAX_WRITE_SIZE + 32;
+ int curval = 0;
+ int curlen = sizeof(curval);
+
+ static int detectOsState = DETECT_OS_NONE;
+
+ if(detectOsState == DETECT_OS_NONE) {
+ if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL))
+ detectOsState = DETECT_OS_VISTA_OR_LATER;
+ else
+ detectOsState = DETECT_OS_PREVISTA;
+ }
+
+ if(detectOsState == DETECT_OS_VISTA_OR_LATER)
+ return;
+
+ if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
+ if(curval > val)
+ return;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
+}
+#endif
+
+/*
+ * singleipconnect()
+ *
+ * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
+ * CURL_SOCKET_BAD. Other errors will however return proper errors.
+ *
+ * singleipconnect() connects to the given IP only, and it may return without
+ * having connected.
+ */
+static CURLcode singleipconnect(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ curl_socket_t *sockp)
+{
+ struct Curl_sockaddr_ex addr;
+ int rc = -1;
+ int error = 0;
+ bool isconnected = FALSE;
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sockfd;
+ CURLcode result;
+ char ipaddress[MAX_IPADR_LEN];
+ long port;
+ bool is_tcp;
+
+ *sockp = CURL_SOCKET_BAD;
+
+ result = Curl_socket(conn, ai, &addr, &sockfd);
+ if(result)
+ /* Failed to create the socket, but still return OK since we signal the
+ lack of socket as well. This allows the parent function to keep looping
+ over alternative addresses/socket families etc. */
+ return CURLE_OK;
+
+ /* store remote address and port used in this connection attempt */
+ if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
+ ipaddress, &port)) {
+ /* malformed address or bug in inet_ntop, try next address */
+ error = ERRNO;
+ failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ Curl_closesocket(conn, sockfd);
+ return CURLE_OK;
+ }
+ infof(data, " Trying %s...\n", ipaddress);
+
+#ifdef ENABLE_IPV6
+ is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
+ addr.socktype == SOCK_STREAM;
+#else
+ is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
+#endif
+ if(is_tcp && data->set.tcp_nodelay)
+ Curl_tcpnodelay(conn, sockfd);
+
+ nosigpipe(conn, sockfd);
+
+ Curl_sndbufset(sockfd);
+
+ if(is_tcp && data->set.tcp_keepalive)
+ tcpkeepalive(data, sockfd);
+
+ if(data->set.fsockopt) {
+ /* activate callback for setting socket options */
+ error = data->set.fsockopt(data->set.sockopt_client,
+ sockfd,
+ CURLSOCKTYPE_IPCXN);
+
+ if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
+ isconnected = TRUE;
+ else if(error) {
+ Curl_closesocket(conn, sockfd); /* close the socket and bail out */
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+
+ /* possibly bind the local end to an IP, interface or port */
+ if(addr.family == AF_INET
+#ifdef ENABLE_IPV6
+ || addr.family == AF_INET6
+#endif
+ ) {
+ result = bindlocal(conn, sockfd, addr.family,
+ Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
+ if(result) {
+ Curl_closesocket(conn, sockfd); /* close socket and bail out */
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ /* The address family is not supported on this interface.
+ We can continue trying addresses */
+ return CURLE_COULDNT_CONNECT;
+ }
+ return result;
+ }
+ }
+
+ /* set socket non-blocking */
+ (void)curlx_nonblock(sockfd, TRUE);
+
+ conn->connecttime = Curl_tvnow();
+ if(conn->num_addr > 1)
+ Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
+
+ /* Connect TCP sockets, bind UDP */
+ if(!isconnected && (conn->socktype == SOCK_STREAM)) {
+ if(conn->bits.tcp_fastopen) {
+#if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
+ sa_endpoints_t endpoints;
+ endpoints.sae_srcif = 0;
+ endpoints.sae_srcaddr = NULL;
+ endpoints.sae_srcaddrlen = 0;
+ endpoints.sae_dstaddr = &addr.sa_addr;
+ endpoints.sae_dstaddrlen = addr.addrlen;
+
+ rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
+ CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
+ NULL, 0, NULL, NULL);
+#elif defined(MSG_FASTOPEN) /* Linux */
+ if(conn->given->flags & PROTOPT_SSL)
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+ else
+ rc = 0; /* Do nothing */
+#endif
+ }
+ else {
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+ }
+
+ if(-1 == rc)
+ error = SOCKERRNO;
+ }
+ else {
+ *sockp = sockfd;
+ return CURLE_OK;
+ }
+
+#ifdef ENABLE_IPV6
+ conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
+#endif
+
+ if(-1 == rc) {
+ switch(error) {
+ case EINPROGRESS:
+ case EWOULDBLOCK:
+#if defined(EAGAIN)
+#if (EAGAIN) != (EWOULDBLOCK)
+ /* On some platforms EAGAIN and EWOULDBLOCK are the
+ * same value, and on others they are different, hence
+ * the odd #if
+ */
+ case EAGAIN:
+#endif
+#endif
+ result = CURLE_OK;
+ break;
+
+ default:
+ /* unknown error, fallthrough and try another address! */
+ infof(data, "Immediate connect fail for %s: %s\n",
+ ipaddress, Curl_strerror(conn, error));
+ data->state.os_errno = error;
+
+ /* connect failed */
+ Curl_closesocket(conn, sockfd);
+ result = CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ if(!result)
+ *sockp = sockfd;
+
+ return result;
+}
+
+/*
+ * TCP connect to the given host with timeout, proxy or remote doesn't matter.
+ * There might be more than one IP address to try out. Fill in the passed
+ * pointer with the connected socket.
+ */
+
+CURLcode Curl_connecthost(struct connectdata *conn, /* context */
+ const struct Curl_dns_entry *remotehost)
+{
+ struct Curl_easy *data = conn->data;
+ struct timeval before = Curl_tvnow();
+ CURLcode result = CURLE_COULDNT_CONNECT;
+
+ time_t timeout_ms = Curl_timeleft(data, &before, TRUE);
+
+ if(timeout_ms < 0) {
+ /* a precaution, no need to continue if time already is up */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ conn->num_addr = Curl_num_addresses(remotehost->addr);
+ conn->tempaddr[0] = remotehost->addr;
+ conn->tempaddr[1] = NULL;
+ conn->tempsock[0] = CURL_SOCKET_BAD;
+ conn->tempsock[1] = CURL_SOCKET_BAD;
+ Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS);
+
+ /* Max time for the next connection attempt */
+ conn->timeoutms_per_addr =
+ conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
+
+ /* start connecting to first IP */
+ while(conn->tempaddr[0]) {
+ result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
+ if(!result)
+ break;
+ conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
+ }
+
+ if(conn->tempsock[0] == CURL_SOCKET_BAD) {
+ if(!result)
+ result = CURLE_COULDNT_CONNECT;
+ return result;
+ }
+
+ data->info.numconnects++; /* to track the number of connections made */
+
+ return CURLE_OK;
+}
+
+struct connfind {
+ struct connectdata *tofind;
+ bool found;
+};
+
+static int conn_is_conn(struct connectdata *conn, void *param)
+{
+ struct connfind *f = (struct connfind *)param;
+ if(conn == f->tofind) {
+ f->found = TRUE;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given Curl_easy.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
+ struct connectdata **connp)
+{
+ curl_socket_t sockfd;
+
+ DEBUGASSERT(data);
+
+ /* this works for an easy handle:
+ * - that has been used for curl_easy_perform()
+ * - that is associated with a multi handle, and whose connection
+ * was detached with CURLOPT_CONNECT_ONLY
+ */
+ if(data->state.lastconnect && (data->multi_easy || data->multi)) {
+ struct connectdata *c = data->state.lastconnect;
+ struct connfind find;
+ find.tofind = data->state.lastconnect;
+ find.found = FALSE;
+
+ Curl_conncache_foreach(data->multi_easy?
+ &data->multi_easy->conn_cache:
+ &data->multi->conn_cache, &find, conn_is_conn);
+
+ if(!find.found) {
+ data->state.lastconnect = NULL;
+ return CURL_SOCKET_BAD;
+ }
+
+ if(connp)
+ /* only store this if the caller cares for it */
+ *connp = c;
+ sockfd = c->sock[FIRSTSOCKET];
+ }
+ else
+ return CURL_SOCKET_BAD;
+
+ return sockfd;
+}
+
+/*
+ * Check if a connection seems to be alive.
+ */
+bool Curl_connalive(struct connectdata *conn)
+{
+ /* First determine if ssl */
+ if(conn->ssl[FIRSTSOCKET].use) {
+ /* use the SSL context */
+ if(!Curl_ssl_check_cxn(conn))
+ return false; /* FIN received */
+ }
+/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
+#ifdef MSG_PEEK
+ else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
+ return false;
+ else {
+ /* use the socket */
+ char buf;
+ if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+ (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
+ return false; /* FIN received */
+ }
+ }
+#endif
+ return true;
+}
+
+/*
+ * Close a socket.
+ *
+ * 'conn' can be NULL, beware!
+ */
+int Curl_closesocket(struct connectdata *conn,
+ curl_socket_t sock)
+{
+ if(conn && conn->fclosesocket) {
+ if((sock == conn->sock[SECONDARYSOCKET]) &&
+ conn->sock_accepted[SECONDARYSOCKET])
+ /* if this socket matches the second socket, and that was created with
+ accept, then we MUST NOT call the callback but clear the accepted
+ status */
+ conn->sock_accepted[SECONDARYSOCKET] = FALSE;
+ else {
+ Curl_multi_closed(conn, sock);
+ return conn->fclosesocket(conn->closesocket_client, sock);
+ }
+ }
+
+ if(conn)
+ /* tell the multi-socket code about this */
+ Curl_multi_closed(conn, sock);
+
+ sclose(sock);
+
+ return 0;
+}
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * 'addr' should be a pointer to the correct struct to get data back, or NULL.
+ * 'sockfd' must be a pointer to a socket descriptor.
+ *
+ * If the open socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ struct Curl_sockaddr_ex *addr,
+ curl_socket_t *sockfd)
+{
+ struct Curl_easy *data = conn->data;
+ struct Curl_sockaddr_ex dummy;
+
+ if(!addr)
+ /* if the caller doesn't want info back, use a local temp copy */
+ addr = &dummy;
+
+ /*
+ * The Curl_sockaddr_ex structure is basically libcurl's external API
+ * curl_sockaddr structure with enough space available to directly hold
+ * any protocol-specific address structures. The variable declared here
+ * will be used to pass / receive data to/from the fopensocket callback
+ * if this has been set, before that, it is initialized from parameters.
+ */
+
+ addr->family = ai->ai_family;
+ addr->socktype = conn->socktype;
+ addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
+ addr->addrlen = ai->ai_addrlen;
+
+ if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
+ addr->addrlen = sizeof(struct Curl_sockaddr_storage);
+ memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
+
+ if(data->set.fopensocket)
+ /*
+ * If the opensocket callback is set, all the destination address
+ * information is passed to the callback. Depending on this information the
+ * callback may opt to abort the connection, this is indicated returning
+ * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
+ * the callback returns a valid socket the destination address information
+ * might have been changed and this 'new' address will actually be used
+ * here to connect.
+ */
+ *sockfd = data->set.fopensocket(data->set.opensocket_client,
+ CURLSOCKTYPE_IPCXN,
+ (struct curl_sockaddr *)addr);
+ else
+ /* opensocket callback not set, so simply create the socket now */
+ *sockfd = socket(addr->family, addr->socktype, addr->protocol);
+
+ if(*sockfd == CURL_SOCKET_BAD)
+ /* no socket, no connection */
+ return CURLE_COULDNT_CONNECT;
+
+#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if(conn->scope_id && (addr->family == AF_INET6)) {
+ struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
+ sa6->sin6_scope_id = conn->scope_id;
+ }
+#endif
+
+ return CURLE_OK;
+
+}
+
+/*
+ * Curl_conncontrol() marks streams or connection for closure.
+ */
+void Curl_conncontrol(struct connectdata *conn,
+ int ctrl /* see defines in header */
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ , const char *reason
+#endif
+ )
+{
+ /* close if a connection, or a stream that isn't multiplexed */
+ bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
+ ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
+ if((ctrl == CONNCTRL_STREAM) &&
+ (conn->handler->flags & PROTOPT_STREAM))
+ DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
+ else if(closeit != conn->bits.close) {
+ DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
+ closeit?"closure":"keep alive", reason));
+ conn->bits.close = closeit; /* the only place in the source code that
+ should assign this bit */
+ }
+}
+
+/* Data received can be cached at various levels, so check them all here. */
+bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
+{
+ int readable;
+
+ if(Curl_ssl_data_pending(conn, sockindex) ||
+ Curl_recv_has_postponed_data(conn, sockindex))
+ return true;
+
+ readable = SOCKET_READABLE(conn->sock[sockindex], 0);
+ return (readable > 0 && (readable & CURL_CSELECT_IN));
+}
diff --git a/Utilities/cmcurl/lib/connect.h b/Utilities/cmcurl/lib/connect.h
new file mode 100644
index 000000000..44bdb1051
--- /dev/null
+++ b/Utilities/cmcurl/lib/connect.h
@@ -0,0 +1,147 @@
+#ifndef HEADER_CURL_CONNECT_H
+#define HEADER_CURL_CONNECT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "sockaddr.h"
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+ int sockindex,
+ bool *connected);
+
+CURLcode Curl_connecthost(struct connectdata *conn,
+ const struct Curl_dns_entry *host);
+
+/* generic function that returns how much time there's left to run, according
+ to the timeouts set */
+time_t Curl_timeleft(struct Curl_easy *data,
+ struct timeval *nowp,
+ bool duringconnect);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+#define HAPPY_EYEBALLS_TIMEOUT 200 /* milliseconds to wait between
+ IPv4/IPv6 connection attempts */
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given Curl_easy.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
+ struct connectdata **connp);
+
+/*
+ * Check if a connection seems to be alive.
+ */
+bool Curl_connalive(struct connectdata *conn);
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+ experience slow performance when you copy data to a TCP server.
+
+ https://support.microsoft.com/kb/823764
+
+ Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+ Buffer Size
+
+*/
+void Curl_sndbufset(curl_socket_t sockfd);
+#else
+#define Curl_sndbufset(y) Curl_nop_stmt
+#endif
+
+void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
+void Curl_persistconninfo(struct connectdata *conn);
+int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
+
+/*
+ * The Curl_sockaddr_ex structure is basically libcurl's external API
+ * curl_sockaddr structure with enough space available to directly hold any
+ * protocol-specific address structures. The variable declared here will be
+ * used to pass / receive data to/from the fopensocket callback if this has
+ * been set, before that, it is initialized from parameters.
+ */
+struct Curl_sockaddr_ex {
+ int family;
+ int socktype;
+ int protocol;
+ unsigned int addrlen;
+ union {
+ struct sockaddr addr;
+ struct Curl_sockaddr_storage buff;
+ } _sa_ex_u;
+};
+#define sa_addr _sa_ex_u.addr
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
+ * socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ struct Curl_sockaddr_ex *addr,
+ curl_socket_t *sockfd);
+
+void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd);
+
+/*
+ * Curl_conncontrol() marks the end of a connection/stream. The 'closeit'
+ * argument specifies if it is the end of a connection or a stream.
+ *
+ * For stream-based protocols (such as HTTP/2), a stream close will not cause
+ * a connection close. Other protocols will close the connection for both
+ * cases.
+ *
+ * It sets the bit.close bit to TRUE (with an explanation for debug builds),
+ * when the connection will close.
+ */
+
+#define CONNCTRL_KEEP 0 /* undo a marked closure */
+#define CONNCTRL_CONNECTION 1
+#define CONNCTRL_STREAM 2
+
+void Curl_conncontrol(struct connectdata *conn,
+ int closeit
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ , const char *reason
+#endif
+ );
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM, y)
+#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION, y)
+#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP, y)
+#else /* if !DEBUGBUILD || CURL_DISABLE_VERBOSE_STRINGS */
+#define streamclose(x,y) Curl_conncontrol(x, CONNCTRL_STREAM)
+#define connclose(x,y) Curl_conncontrol(x, CONNCTRL_CONNECTION)
+#define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP)
+#endif
+
+bool Curl_conn_data_pending(struct connectdata *conn, int sockindex);
+
+#endif /* HEADER_CURL_CONNECT_H */
diff --git a/Utilities/cmcurl/lib/content_encoding.c b/Utilities/cmcurl/lib/content_encoding.c
new file mode 100644
index 000000000..652ed9764
--- /dev/null
+++ b/Utilities/cmcurl/lib/content_encoding.c
@@ -0,0 +1,431 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIBZ
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "content_encoding.h"
+#include "strdup.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
+ (doing so will reduce code size slightly). */
+#define OLD_ZLIB_SUPPORT 1
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
+
+#define GZIP_MAGIC_0 0x1f
+#define GZIP_MAGIC_1 0x8b
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+static voidpf
+zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
+{
+ (void) opaque;
+ /* not a typo, keep it calloc() */
+ return (voidpf) calloc(items, size);
+}
+
+static void
+zfree_cb(voidpf opaque, voidpf ptr)
+{
+ (void) opaque;
+ free(ptr);
+}
+
+static CURLcode
+process_zlib_error(struct connectdata *conn, z_stream *z)
+{
+ struct Curl_easy *data = conn->data;
+ if(z->msg)
+ failf(data, "Error while processing content unencoding: %s",
+ z->msg);
+ else
+ failf(data, "Error while processing content unencoding: "
+ "Unknown failure within decompression software.");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode
+exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
+{
+ inflateEnd(z);
+ *zlib_init = ZLIB_UNINIT;
+ return result;
+}
+
+static CURLcode
+inflate_stream(struct connectdata *conn,
+ struct SingleRequest *k)
+{
+ int allow_restart = 1;
+ z_stream *z = &k->z; /* zlib state structure */
+ uInt nread = z->avail_in;
+ Bytef *orig_in = z->next_in;
+ int status; /* zlib status */
+ CURLcode result = CURLE_OK; /* Curl_client_write status */
+ char *decomp; /* Put the decompressed data here. */
+
+ /* Dynamically allocate a buffer for decompression because it's uncommonly
+ large to hold on the stack */
+ decomp = malloc(DSIZ);
+ if(decomp == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+
+ /* because the buffer size is fixed, iteratively decompress and transfer to
+ the client via client_write. */
+ for(;;) {
+ /* (re)set buffer for decompressed output for every iteration */
+ z->next_out = (Bytef *)decomp;
+ z->avail_out = DSIZ;
+
+ status = inflate(z, Z_SYNC_FLUSH);
+ if(status == Z_OK || status == Z_STREAM_END) {
+ allow_restart = 0;
+ if((DSIZ - z->avail_out) && (!k->ignorebody)) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
+ DSIZ - z->avail_out);
+ /* if !CURLE_OK, clean up, return */
+ if(result) {
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, result);
+ }
+ }
+
+ /* Done? clean up, return */
+ if(status == Z_STREAM_END) {
+ free(decomp);
+ if(inflateEnd(z) == Z_OK)
+ return exit_zlib(z, &k->zlib_init, result);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ /* Done with these bytes, exit */
+
+ /* status is always Z_OK at this point! */
+ if(z->avail_in == 0) {
+ free(decomp);
+ return result;
+ }
+ }
+ else if(allow_restart && status == Z_DATA_ERROR) {
+ /* some servers seem to not generate zlib headers, so this is an attempt
+ to fix and continue anyway */
+
+ (void) inflateEnd(z); /* don't care about the return code */
+ if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+ z->next_in = orig_in;
+ z->avail_in = nread;
+ allow_restart = 0;
+ continue;
+ }
+ else { /* Error; exit loop, handle below */
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+ }
+ /* Will never get here */
+}
+
+CURLcode
+Curl_unencode_deflate_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread)
+{
+ z_stream *z = &k->z; /* zlib state structure */
+
+ /* Initialize zlib? */
+ if(k->zlib_init == ZLIB_UNINIT) {
+ memset(z, 0, sizeof(z_stream));
+ z->zalloc = (alloc_func)zalloc_cb;
+ z->zfree = (free_func)zfree_cb;
+
+ if(inflateInit(z) != Z_OK)
+ return process_zlib_error(conn, z);
+ k->zlib_init = ZLIB_INIT;
+ }
+
+ /* Set the compressed input when this function is called */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+
+ /* Now uncompress the data */
+ return inflate_stream(conn, k);
+}
+
+#ifdef OLD_ZLIB_SUPPORT
+/* Skip over the gzip header */
+static enum {
+ GZIP_OK,
+ GZIP_BAD,
+ GZIP_UNDERFLOW
+} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
+{
+ int method, flags;
+ const ssize_t totallen = len;
+
+ /* The shortest header is 10 bytes */
+ if(len < 10)
+ return GZIP_UNDERFLOW;
+
+ if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
+ return GZIP_BAD;
+
+ method = data[2];
+ flags = data[3];
+
+ if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ /* Can't handle this compression method or unknown flag */
+ return GZIP_BAD;
+ }
+
+ /* Skip over time, xflags, OS code and all previous bytes */
+ len -= 10;
+ data += 10;
+
+ if(flags & EXTRA_FIELD) {
+ ssize_t extra_len;
+
+ if(len < 2)
+ return GZIP_UNDERFLOW;
+
+ extra_len = (data[1] << 8) | data[0];
+
+ if(len < (extra_len+2))
+ return GZIP_UNDERFLOW;
+
+ len -= (extra_len + 2);
+ data += (extra_len + 2);
+ }
+
+ if(flags & ORIG_NAME) {
+ /* Skip over NUL-terminated file name */
+ while(len && *data) {
+ --len;
+ ++data;
+ }
+ if(!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ ++data;
+ }
+
+ if(flags & COMMENT) {
+ /* Skip over NUL-terminated comment */
+ while(len && *data) {
+ --len;
+ ++data;
+ }
+ if(!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ }
+
+ if(flags & HEAD_CRC) {
+ if(len < 2)
+ return GZIP_UNDERFLOW;
+
+ len -= 2;
+ }
+
+ *headerlen = totallen - len;
+ return GZIP_OK;
+}
+#endif
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread)
+{
+ z_stream *z = &k->z; /* zlib state structure */
+
+ /* Initialize zlib? */
+ if(k->zlib_init == ZLIB_UNINIT) {
+ memset(z, 0, sizeof(z_stream));
+ z->zalloc = (alloc_func)zalloc_cb;
+ z->zfree = (free_func)zfree_cb;
+
+ if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+ /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+ if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+ }
+ else {
+ /* we must parse the gzip header ourselves */
+ if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ k->zlib_init = ZLIB_INIT; /* Initial call state */
+ }
+ }
+
+ if(k->zlib_init == ZLIB_INIT_GZIP) {
+ /* Let zlib handle the gzip decompression entirely */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+ /* Now uncompress the data */
+ return inflate_stream(conn, k);
+ }
+
+#ifndef OLD_ZLIB_SUPPORT
+ /* Support for old zlib versions is compiled away and we are running with
+ an old version, so return an error. */
+ return exit_zlib(z, &k->zlib_init, CURLE_WRITE_ERROR);
+
+#else
+ /* This next mess is to get around the potential case where there isn't
+ * enough data passed in to skip over the gzip header. If that happens, we
+ * malloc a block and copy what we have then wait for the next call. If
+ * there still isn't enough (this is definitely a worst-case scenario), we
+ * make the block bigger, copy the next part in and keep waiting.
+ *
+ * This is only required with zlib versions < 1.2.0.4 as newer versions
+ * can handle the gzip header themselves.
+ */
+
+ switch(k->zlib_init) {
+ /* Skip over gzip header? */
+ case ZLIB_INIT:
+ {
+ /* Initial call state */
+ ssize_t hlen;
+
+ switch(check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+ case GZIP_OK:
+ z->next_in = (Bytef *)k->str + hlen;
+ z->avail_in = (uInt)(nread - hlen);
+ k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We need more data so we can find the end of the gzip header. It's
+ * possible that the memory block we malloc here will never be freed if
+ * the transfer abruptly aborts after this point. Since it's unlikely
+ * that circumstances will be right for this code path to be followed in
+ * the first place, and it's even more unlikely for a transfer to fail
+ * immediately afterwards, it should seldom be a problem.
+ */
+ z->avail_in = (uInt)nread;
+ z->next_in = malloc(z->avail_in);
+ if(z->next_in == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ memcpy(z->next_in, k->str, z->avail_in);
+ k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
+ /* We don't have any data to inflate yet */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ }
+ break;
+
+ case ZLIB_GZIP_HEADER:
+ {
+ /* Need more gzip header data state */
+ ssize_t hlen;
+ z->avail_in += (uInt)nread;
+ z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
+ if(z->next_in == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ /* Append the new block of data to the previous one */
+ memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+
+ switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+ case GZIP_OK:
+ /* This is the zlib stream data */
+ free(z->next_in);
+ /* Don't point into the malloced block since we just freed it */
+ z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
+ z->avail_in = (uInt)(z->avail_in - hlen);
+ k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We still don't have any data to inflate! */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ free(z->next_in);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ }
+ break;
+
+ case ZLIB_GZIP_INFLATING:
+ default:
+ /* Inflating stream state */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+ break;
+ }
+
+ if(z->avail_in == 0) {
+ /* We don't have any data to inflate; wait until next time */
+ return CURLE_OK;
+ }
+
+ /* We've parsed the header, now uncompress the data */
+ return inflate_stream(conn, k);
+#endif
+}
+
+void Curl_unencode_cleanup(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ struct SingleRequest *k = &data->req;
+ z_stream *z = &k->z;
+ if(k->zlib_init != ZLIB_UNINIT)
+ (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
+}
+
+#endif /* HAVE_LIBZ */
diff --git a/Utilities/cmcurl/lib/content_encoding.h b/Utilities/cmcurl/lib/content_encoding.h
new file mode 100644
index 000000000..3fadd2899
--- /dev/null
+++ b/Utilities/cmcurl/lib/content_encoding.h
@@ -0,0 +1,48 @@
+#ifndef HEADER_CURL_CONTENT_ENCODING_H
+#define HEADER_CURL_CONTENT_ENCODING_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * Comma-separated list all supported Content-Encodings ('identity' is implied)
+ */
+#ifdef HAVE_LIBZ
+#define ALL_CONTENT_ENCODINGS "deflate, gzip"
+/* force a cleanup */
+void Curl_unencode_cleanup(struct connectdata *conn);
+#else
+#define ALL_CONTENT_ENCODINGS "identity"
+#define Curl_unencode_cleanup(x) Curl_nop_stmt
+#endif
+
+CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
+ struct SingleRequest *req,
+ ssize_t nread);
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread);
+
+
+#endif /* HEADER_CURL_CONTENT_ENCODING_H */
diff --git a/Utilities/cmcurl/lib/cookie.c b/Utilities/cmcurl/lib/cookie.c
new file mode 100644
index 000000000..6b678aeb8
--- /dev/null
+++ b/Utilities/cmcurl/lib/cookie.c
@@ -0,0 +1,1449 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/***
+
+
+RECEIVING COOKIE INFORMATION
+============================
+
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ const char *file, struct CookieInfo *inc, bool newsession);
+
+ Inits a cookie struct to store data in a local file. This is always
+ called before any cookies are set.
+
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
+ struct CookieInfo *c, bool httpheader, char *lineptr,
+ const char *domain, const char *path);
+
+ The 'lineptr' parameter is a full "Set-cookie:" line as
+ received from a server.
+
+ The function need to replace previously stored lines that this new
+ line superceeds.
+
+ It may remove lines that are expired.
+
+ It should return an indication of success/error.
+
+
+SENDING COOKIE INFORMATION
+==========================
+
+struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
+ char *host, char *path, bool secure);
+
+ For a given host and path, return a linked list of cookies that
+ the client should send to the server if used now. The secure
+ boolean informs the cookie if a secure connection is achieved or
+ not.
+
+ It shall only return cookies that haven't expired.
+
+
+Example set of cookies:
+
+ Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
+ Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/ftgw; secure
+ Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie:
+ Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
+ 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
+****/
+
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+
+#ifdef USE_LIBPSL
+# include <libpsl.h>
+#endif
+
+#include "urldata.h"
+#include "cookie.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "slist.h"
+#include "share.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "curl_memrchr.h"
+#include "inet_pton.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static void freecookie(struct Cookie *co)
+{
+ free(co->expirestr);
+ free(co->domain);
+ free(co->path);
+ free(co->spath);
+ free(co->name);
+ free(co->value);
+ free(co->maxage);
+ free(co->version);
+ free(co);
+}
+
+static bool tailmatch(const char *cooke_domain, const char *hostname)
+{
+ size_t cookie_domain_len = strlen(cooke_domain);
+ size_t hostname_len = strlen(hostname);
+
+ if(hostname_len < cookie_domain_len)
+ return FALSE;
+
+ if(!strcasecompare(cooke_domain, hostname+hostname_len-cookie_domain_len))
+ return FALSE;
+
+ /* A lead char of cookie_domain is not '.'.
+ RFC6265 4.1.2.3. The Domain Attribute says:
+ For example, if the value of the Domain attribute is
+ "example.com", the user agent will include the cookie in the Cookie
+ header when making HTTP requests to example.com, www.example.com, and
+ www.corp.example.com.
+ */
+ if(hostname_len == cookie_domain_len)
+ return TRUE;
+ if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
+ return TRUE;
+ return FALSE;
+}
+
+/*
+ * matching cookie path and url path
+ * RFC6265 5.1.4 Paths and Path-Match
+ */
+static bool pathmatch(const char *cookie_path, const char *request_uri)
+{
+ size_t cookie_path_len;
+ size_t uri_path_len;
+ char *uri_path = NULL;
+ char *pos;
+ bool ret = FALSE;
+
+ /* cookie_path must not have last '/' separator. ex: /sample */
+ cookie_path_len = strlen(cookie_path);
+ if(1 == cookie_path_len) {
+ /* cookie_path must be '/' */
+ return TRUE;
+ }
+
+ uri_path = strdup(request_uri);
+ if(!uri_path)
+ return FALSE;
+ pos = strchr(uri_path, '?');
+ if(pos)
+ *pos = 0x0;
+
+ /* #-fragments are already cut off! */
+ if(0 == strlen(uri_path) || uri_path[0] != '/') {
+ free(uri_path);
+ uri_path = strdup("/");
+ if(!uri_path)
+ return FALSE;
+ }
+
+ /* here, RFC6265 5.1.4 says
+ 4. Output the characters of the uri-path from the first character up
+ to, but not including, the right-most %x2F ("/").
+ but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
+ without redirect.
+ Ignore this algorithm because /hoge is uri path for this case
+ (uri path is not /).
+ */
+
+ uri_path_len = strlen(uri_path);
+
+ if(uri_path_len < cookie_path_len) {
+ ret = FALSE;
+ goto pathmatched;
+ }
+
+ /* not using checkprefix() because matching should be case-sensitive */
+ if(strncmp(cookie_path, uri_path, cookie_path_len)) {
+ ret = FALSE;
+ goto pathmatched;
+ }
+
+ /* The cookie-path and the uri-path are identical. */
+ if(cookie_path_len == uri_path_len) {
+ ret = TRUE;
+ goto pathmatched;
+ }
+
+ /* here, cookie_path_len < url_path_len */
+ if(uri_path[cookie_path_len] == '/') {
+ ret = TRUE;
+ goto pathmatched;
+ }
+
+ ret = FALSE;
+
+pathmatched:
+ free(uri_path);
+ return ret;
+}
+
+/*
+ * cookie path sanitize
+ */
+static char *sanitize_cookie_path(const char *cookie_path)
+{
+ size_t len;
+ char *new_path = strdup(cookie_path);
+ if(!new_path)
+ return NULL;
+
+ /* some stupid site sends path attribute with '"'. */
+ len = strlen(new_path);
+ if(new_path[0] == '\"') {
+ memmove((void *)new_path, (const void *)(new_path + 1), len);
+ len--;
+ }
+ if(len && (new_path[len - 1] == '\"')) {
+ new_path[len - 1] = 0x0;
+ len--;
+ }
+
+ /* RFC6265 5.2.4 The Path Attribute */
+ if(new_path[0] != '/') {
+ /* Let cookie-path be the default-path. */
+ free(new_path);
+ new_path = strdup("/");
+ return new_path;
+ }
+
+ /* convert /hoge/ to /hoge */
+ if(len && new_path[len - 1] == '/') {
+ new_path[len - 1] = 0x0;
+ }
+
+ return new_path;
+}
+
+/*
+ * Load cookies from all given cookie files (CURLOPT_COOKIEFILE).
+ *
+ * NOTE: OOM or cookie parsing failures are ignored.
+ */
+void Curl_cookie_loadfiles(struct Curl_easy *data)
+{
+ struct curl_slist *list = data->change.cookielist;
+ if(list) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ while(list) {
+ struct CookieInfo *newcookies = Curl_cookie_init(data,
+ list->data,
+ data->cookies,
+ data->set.cookiesession);
+ if(!newcookies)
+ /* Failure may be due to OOM or a bad cookie; both are ignored
+ * but only the first should be
+ */
+ infof(data, "ignoring failed cookie_init for %s\n", list->data);
+ else
+ data->cookies = newcookies;
+ list = list->next;
+ }
+ curl_slist_free_all(data->change.cookielist); /* clean up list */
+ data->change.cookielist = NULL; /* don't do this again! */
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+}
+
+/*
+ * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
+ * that will be freed before the allocated string is stored there.
+ *
+ * It is meant to easily replace strdup()
+ */
+static void strstore(char **str, const char *newstr)
+{
+ free(*str);
+ *str = strdup(newstr);
+}
+
+/*
+ * remove_expired() removes expired cookies.
+ */
+static void remove_expired(struct CookieInfo *cookies)
+{
+ struct Cookie *co, *nx, *pv;
+ curl_off_t now = (curl_off_t)time(NULL);
+
+ co = cookies->cookies;
+ pv = NULL;
+ while(co) {
+ nx = co->next;
+ if(co->expires && co->expires < now) {
+ if(co == cookies->cookies) {
+ cookies->cookies = co->next;
+ }
+ else {
+ pv->next = co->next;
+ }
+ cookies->numcookies--;
+ freecookie(co);
+ }
+ else {
+ pv = co;
+ }
+ co = nx;
+ }
+}
+
+/*
+ * Return true if the given string is an IP(v4|v6) address.
+ */
+static bool isip(const char *domain)
+{
+ struct in_addr addr;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr6;
+#endif
+
+ if(Curl_inet_pton(AF_INET, domain, &addr)
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, domain, &addr6)
+#endif
+ ) {
+ /* domain name given as IP address */
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/****************************************************************************
+ *
+ * Curl_cookie_add()
+ *
+ * Add a single cookie line to the cookie keeping object.
+ *
+ * Be aware that sometimes we get an IP-only host name, and that might also be
+ * a numerical IPv6 address.
+ *
+ * Returns NULL on out of memory or invalid cookie. This is suboptimal,
+ * as they should be treated separately.
+ ***************************************************************************/
+
+struct Cookie *
+Curl_cookie_add(struct Curl_easy *data,
+ /* The 'data' pointer here may be NULL at times, and thus
+ must only be used very carefully for things that can deal
+ with data being NULL. Such as infof() and similar */
+
+ struct CookieInfo *c,
+ bool httpheader, /* TRUE if HTTP header-style line */
+ char *lineptr, /* first character of the line */
+ const char *domain, /* default domain */
+ const char *path) /* full path used when this cookie is set,
+ used to get default path for the cookie
+ unless set */
+{
+ struct Cookie *clist;
+ char name[MAX_NAME];
+ struct Cookie *co;
+ struct Cookie *lastc=NULL;
+ time_t now = time(NULL);
+ bool replace_old = FALSE;
+ bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
+
+#ifdef USE_LIBPSL
+ const psl_ctx_t *psl;
+#endif
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)data;
+#endif
+
+ /* First, alloc and init a new struct for it */
+ co = calloc(1, sizeof(struct Cookie));
+ if(!co)
+ return NULL; /* bail out if we're this low on memory */
+
+ if(httpheader) {
+ /* This line was read off a HTTP-header */
+ const char *ptr;
+ const char *semiptr;
+ char *what;
+
+ what = malloc(MAX_COOKIE_LINE);
+ if(!what) {
+ free(co);
+ return NULL;
+ }
+
+ semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+
+ ptr = lineptr;
+ do {
+ /* we have a <what>=<this> pair or a stand-alone word here */
+ name[0]=what[0]=0; /* init the buffers */
+ if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
+ MAX_COOKIE_LINE_TXT "[^;\r\n]",
+ name, what)) {
+ /* Use strstore() below to properly deal with received cookie
+ headers that have the same string property set more than once,
+ and then we use the last one. */
+ const char *whatptr;
+ bool done = FALSE;
+ bool sep;
+ size_t len=strlen(what);
+ size_t nlen = strlen(name);
+ const char *endofn = &ptr[ nlen ];
+
+ /* name ends with a '=' ? */
+ sep = (*endofn == '=')?TRUE:FALSE;
+
+ if(nlen) {
+ endofn--; /* move to the last character */
+ if(ISBLANK(*endofn)) {
+ /* skip trailing spaces in name */
+ while(*endofn && ISBLANK(*endofn) && nlen) {
+ endofn--;
+ nlen--;
+ }
+ name[nlen]=0; /* new end of name */
+ }
+ }
+
+ /* Strip off trailing whitespace from the 'what' */
+ while(len && ISBLANK(what[len-1])) {
+ what[len-1]=0;
+ len--;
+ }
+
+ /* Skip leading whitespace from the 'what' */
+ whatptr=what;
+ while(*whatptr && ISBLANK(*whatptr))
+ whatptr++;
+
+ if(!co->name && sep) {
+ /* The very first name/value pair is the actual cookie name */
+ co->name = strdup(name);
+ co->value = strdup(whatptr);
+ if(!co->name || !co->value) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ else if(!len) {
+ /* this was a "<name>=" with no content, and we must allow
+ 'secure' and 'httponly' specified this weirdly */
+ done = TRUE;
+ if(strcasecompare("secure", name))
+ co->secure = TRUE;
+ else if(strcasecompare("httponly", name))
+ co->httponly = TRUE;
+ else if(sep)
+ /* there was a '=' so we're not done parsing this field */
+ done = FALSE;
+ }
+ if(done)
+ ;
+ else if(strcasecompare("path", name)) {
+ strstore(&co->path, whatptr);
+ if(!co->path) {
+ badcookie = TRUE; /* out of memory bad */
+ break;
+ }
+ co->spath = sanitize_cookie_path(co->path);
+ if(!co->spath) {
+ badcookie = TRUE; /* out of memory bad */
+ break;
+ }
+ }
+ else if(strcasecompare("domain", name)) {
+ bool is_ip;
+
+ /* Now, we make sure that our host is within the given domain,
+ or the given domain is not valid and thus cannot be set. */
+
+ if('.' == whatptr[0])
+ whatptr++; /* ignore preceding dot */
+
+#ifndef USE_LIBPSL
+ /*
+ * Without PSL we don't know when the incoming cookie is set on a
+ * TLD or otherwise "protected" suffix. To reduce risk, we require a
+ * dot OR the exact host name being "localhost".
+ */
+ {
+ const char *dotp;
+ /* check for more dots */
+ dotp = strchr(whatptr, '.');
+ if(!dotp && !strcasecompare("localhost", whatptr))
+ domain=":";
+ }
+#endif
+
+ is_ip = isip(domain ? domain : whatptr);
+
+ if(!domain
+ || (is_ip && !strcmp(whatptr, domain))
+ || (!is_ip && tailmatch(whatptr, domain))) {
+ strstore(&co->domain, whatptr);
+ if(!co->domain) {
+ badcookie = TRUE;
+ break;
+ }
+ if(!is_ip)
+ co->tailmatch=TRUE; /* we always do that if the domain name was
+ given */
+ }
+ else {
+ /* we did not get a tailmatch and then the attempted set domain
+ is not a domain to which the current host belongs. Mark as
+ bad. */
+ badcookie=TRUE;
+ infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+ whatptr);
+ }
+ }
+ else if(strcasecompare("version", name)) {
+ strstore(&co->version, whatptr);
+ if(!co->version) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ else if(strcasecompare("max-age", name)) {
+ /* Defined in RFC2109:
+
+ Optional. The Max-Age attribute defines the lifetime of the
+ cookie, in seconds. The delta-seconds value is a decimal non-
+ negative integer. After delta-seconds seconds elapse, the
+ client should discard the cookie. A value of zero means the
+ cookie should be discarded immediately.
+
+ */
+ strstore(&co->maxage, whatptr);
+ if(!co->maxage) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ else if(strcasecompare("expires", name)) {
+ strstore(&co->expirestr, whatptr);
+ if(!co->expirestr) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ /*
+ else this is the second (or more) name we don't know
+ about! */
+ }
+ else {
+ /* this is an "illegal" <what>=<this> pair */
+ }
+
+ if(!semiptr || !*semiptr) {
+ /* we already know there are no more cookies */
+ semiptr = NULL;
+ continue;
+ }
+
+ ptr=semiptr+1;
+ while(*ptr && ISBLANK(*ptr))
+ ptr++;
+ semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+
+ if(!semiptr && *ptr)
+ /* There are no more semicolons, but there's a final name=value pair
+ coming up */
+ semiptr=strchr(ptr, '\0');
+ } while(semiptr);
+
+ if(co->maxage) {
+ co->expires =
+ curlx_strtoofft((*co->maxage=='\"')?
+ &co->maxage[1]:&co->maxage[0], NULL, 10);
+ if(CURL_OFF_T_MAX - now < co->expires)
+ /* avoid overflow */
+ co->expires = CURL_OFF_T_MAX;
+ else
+ co->expires += now;
+ }
+ else if(co->expirestr) {
+ /* Note that if the date couldn't get parsed for whatever reason,
+ the cookie will be treated as a session cookie */
+ co->expires = curl_getdate(co->expirestr, NULL);
+
+ /* Session cookies have expires set to 0 so if we get that back
+ from the date parser let's add a second to make it a
+ non-session cookie */
+ if(co->expires == 0)
+ co->expires = 1;
+ else if(co->expires < 0)
+ co->expires = 0;
+ }
+
+ if(!badcookie && !co->domain) {
+ if(domain) {
+ /* no domain was given in the header line, set the default */
+ co->domain=strdup(domain);
+ if(!co->domain)
+ badcookie = TRUE;
+ }
+ }
+
+ if(!badcookie && !co->path && path) {
+ /* No path was given in the header line, set the default.
+ Note that the passed-in path to this function MAY have a '?' and
+ following part that MUST not be stored as part of the path. */
+ char *queryp = strchr(path, '?');
+
+ /* queryp is where the interesting part of the path ends, so now we
+ want to the find the last */
+ char *endslash;
+ if(!queryp)
+ endslash = strrchr(path, '/');
+ else
+ endslash = memrchr(path, '/', (size_t)(queryp - path));
+ if(endslash) {
+ size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
+ co->path=malloc(pathlen+1); /* one extra for the zero byte */
+ if(co->path) {
+ memcpy(co->path, path, pathlen);
+ co->path[pathlen]=0; /* zero terminate */
+ co->spath = sanitize_cookie_path(co->path);
+ if(!co->spath)
+ badcookie = TRUE; /* out of memory bad */
+ }
+ else
+ badcookie = TRUE;
+ }
+ }
+
+ free(what);
+
+ if(badcookie || !co->name) {
+ /* we didn't get a cookie name or a bad one,
+ this is an illegal line, bail out */
+ freecookie(co);
+ return NULL;
+ }
+
+ }
+ else {
+ /* This line is NOT a HTTP header style line, we do offer support for
+ reading the odd netscape cookies-file format here */
+ char *ptr;
+ char *firstptr;
+ char *tok_buf=NULL;
+ int fields;
+
+ /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
+ marked with httpOnly after the domain name are not accessible
+ from javascripts, but since curl does not operate at javascript
+ level, we include them anyway. In Firefox's cookie files, these
+ lines are preceded with #HttpOnly_ and then everything is
+ as usual, so we skip 10 characters of the line..
+ */
+ if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
+ lineptr += 10;
+ co->httponly = TRUE;
+ }
+
+ if(lineptr[0]=='#') {
+ /* don't even try the comments */
+ free(co);
+ return NULL;
+ }
+ /* strip off the possible end-of-line characters */
+ ptr=strchr(lineptr, '\r');
+ if(ptr)
+ *ptr=0; /* clear it */
+ ptr=strchr(lineptr, '\n');
+ if(ptr)
+ *ptr=0; /* clear it */
+
+ firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
+
+ /* Now loop through the fields and init the struct we already have
+ allocated */
+ for(ptr=firstptr, fields=0; ptr && !badcookie;
+ ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
+ switch(fields) {
+ case 0:
+ if(ptr[0]=='.') /* skip preceding dots */
+ ptr++;
+ co->domain = strdup(ptr);
+ if(!co->domain)
+ badcookie = TRUE;
+ break;
+ case 1:
+ /* This field got its explanation on the 23rd of May 2001 by
+ Andrés García:
+
+ flag: A TRUE/FALSE value indicating if all machines within a given
+ domain can access the variable. This value is set automatically by
+ the browser, depending on the value you set for the domain.
+
+ As far as I can see, it is set to true when the cookie says
+ .domain.com and to false when the domain is complete www.domain.com
+ */
+ co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
+ break;
+ case 2:
+ /* It turns out, that sometimes the file format allows the path
+ field to remain not filled in, we try to detect this and work
+ around it! Andrés García made us aware of this... */
+ if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+ /* only if the path doesn't look like a boolean option! */
+ co->path = strdup(ptr);
+ if(!co->path)
+ badcookie = TRUE;
+ else {
+ co->spath = sanitize_cookie_path(co->path);
+ if(!co->spath) {
+ badcookie = TRUE; /* out of memory bad */
+ }
+ }
+ break;
+ }
+ /* this doesn't look like a path, make one up! */
+ co->path = strdup("/");
+ if(!co->path)
+ badcookie = TRUE;
+ co->spath = strdup("/");
+ if(!co->spath)
+ badcookie = TRUE;
+ fields++; /* add a field and fall down to secure */
+ /* FALLTHROUGH */
+ case 3:
+ co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
+ break;
+ case 4:
+ co->expires = curlx_strtoofft(ptr, NULL, 10);
+ break;
+ case 5:
+ co->name = strdup(ptr);
+ if(!co->name)
+ badcookie = TRUE;
+ break;
+ case 6:
+ co->value = strdup(ptr);
+ if(!co->value)
+ badcookie = TRUE;
+ break;
+ }
+ }
+ if(6 == fields) {
+ /* we got a cookie with blank contents, fix it */
+ co->value = strdup("");
+ if(!co->value)
+ badcookie = TRUE;
+ else
+ fields++;
+ }
+
+ if(!badcookie && (7 != fields))
+ /* we did not find the sufficient number of fields */
+ badcookie = TRUE;
+
+ if(badcookie) {
+ freecookie(co);
+ return NULL;
+ }
+
+ }
+
+ if(!c->running && /* read from a file */
+ c->newsession && /* clean session cookies */
+ !co->expires) { /* this is a session cookie since it doesn't expire! */
+ freecookie(co);
+ return NULL;
+ }
+
+ co->livecookie = c->running;
+
+ /* now, we have parsed the incoming line, we must now check if this
+ superceeds an already existing cookie, which it may if the previous have
+ the same domain and path as this */
+
+ /* at first, remove expired cookies */
+ remove_expired(c);
+
+#ifdef USE_LIBPSL
+ /* Check if the domain is a Public Suffix and if yes, ignore the cookie.
+ This needs a libpsl compiled with builtin data. */
+ if(domain && co->domain && !isip(co->domain)) {
+ psl = psl_builtin();
+ if(psl && !psl_is_cookie_domain_acceptable(psl, domain, co->domain)) {
+ infof(data,
+ "cookie '%s' dropped, domain '%s' must not set cookies for '%s'\n",
+ co->name, domain, co->domain);
+ freecookie(co);
+ return NULL;
+ }
+ }
+#endif
+
+ clist = c->cookies;
+ replace_old = FALSE;
+ while(clist) {
+ if(strcasecompare(clist->name, co->name)) {
+ /* the names are identical */
+
+ if(clist->domain && co->domain) {
+ if(strcasecompare(clist->domain, co->domain) &&
+ (clist->tailmatch == co->tailmatch))
+ /* The domains are identical */
+ replace_old=TRUE;
+ }
+ else if(!clist->domain && !co->domain)
+ replace_old = TRUE;
+
+ if(replace_old) {
+ /* the domains were identical */
+
+ if(clist->spath && co->spath) {
+ if(strcasecompare(clist->spath, co->spath)) {
+ replace_old = TRUE;
+ }
+ else
+ replace_old = FALSE;
+ }
+ else if(!clist->spath && !co->spath)
+ replace_old = TRUE;
+ else
+ replace_old = FALSE;
+
+ }
+
+ if(replace_old && !co->livecookie && clist->livecookie) {
+ /* Both cookies matched fine, except that the already present
+ cookie is "live", which means it was set from a header, while
+ the new one isn't "live" and thus only read from a file. We let
+ live cookies stay alive */
+
+ /* Free the newcomer and get out of here! */
+ freecookie(co);
+ return NULL;
+ }
+
+ if(replace_old) {
+ co->next = clist->next; /* get the next-pointer first */
+
+ /* then free all the old pointers */
+ free(clist->name);
+ free(clist->value);
+ free(clist->domain);
+ free(clist->path);
+ free(clist->spath);
+ free(clist->expirestr);
+ free(clist->version);
+ free(clist->maxage);
+
+ *clist = *co; /* then store all the new data */
+
+ free(co); /* free the newly alloced memory */
+ co = clist; /* point to the previous struct instead */
+
+ /* We have replaced a cookie, now skip the rest of the list but
+ make sure the 'lastc' pointer is properly set */
+ do {
+ lastc = clist;
+ clist = clist->next;
+ } while(clist);
+ break;
+ }
+ }
+ lastc = clist;
+ clist = clist->next;
+ }
+
+ if(c->running)
+ /* Only show this when NOT reading the cookies from a file */
+ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
+ "expire %" CURL_FORMAT_CURL_OFF_T "\n",
+ replace_old?"Replaced":"Added", co->name, co->value,
+ co->domain, co->path, co->expires);
+
+ if(!replace_old) {
+ /* then make the last item point on this new one */
+ if(lastc)
+ lastc->next = co;
+ else
+ c->cookies = co;
+ c->numcookies++; /* one more cookie in the jar */
+ }
+
+ return co;
+}
+
+/*
+ * get_line() makes sure to only return complete whole lines that fit in 'len'
+ * bytes and end with a newline.
+ */
+static char *get_line(char *buf, int len, FILE *input)
+{
+ bool partial = FALSE;
+ while(1) {
+ char *b = fgets(buf, len, input);
+ if(b) {
+ size_t rlen = strlen(b);
+ if(rlen && (b[rlen-1] == '\n')) {
+ if(partial) {
+ partial = FALSE;
+ continue;
+ }
+ return b;
+ }
+ /* read a partial, discard the next piece that ends with newline */
+ partial = TRUE;
+ }
+ else
+ break;
+ }
+ return NULL;
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_init()
+ *
+ * Inits a cookie struct to read data from a local file. This is always
+ * called before any cookies are set. File may be NULL.
+ *
+ * If 'newsession' is TRUE, discard all "session cookies" on read from file.
+ *
+ * Returns NULL on out of memory. Invalid cookies are ignored.
+ ****************************************************************************/
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ const char *file,
+ struct CookieInfo *inc,
+ bool newsession)
+{
+ struct CookieInfo *c;
+ FILE *fp = NULL;
+ bool fromfile=TRUE;
+ char *line = NULL;
+
+ if(NULL == inc) {
+ /* we didn't get a struct, create one */
+ c = calloc(1, sizeof(struct CookieInfo));
+ if(!c)
+ return NULL; /* failed to get memory */
+ c->filename = strdup(file?file:"none"); /* copy the name just in case */
+ if(!c->filename)
+ goto fail; /* failed to get memory */
+ }
+ else {
+ /* we got an already existing one, use that */
+ c = inc;
+ }
+ c->running = FALSE; /* this is not running, this is init */
+
+ if(file && !strcmp(file, "-")) {
+ fp = stdin;
+ fromfile=FALSE;
+ }
+ else if(file && !*file) {
+ /* points to a "" string */
+ fp = NULL;
+ }
+ else
+ fp = file?fopen(file, FOPEN_READTEXT):NULL;
+
+ c->newsession = newsession; /* new session? */
+
+ if(fp) {
+ char *lineptr;
+ bool headerline;
+
+ line = malloc(MAX_COOKIE_LINE);
+ if(!line)
+ goto fail;
+ while(get_line(line, MAX_COOKIE_LINE, fp)) {
+ if(checkprefix("Set-Cookie:", line)) {
+ /* This is a cookie line, get it! */
+ lineptr=&line[11];
+ headerline=TRUE;
+ }
+ else {
+ lineptr=line;
+ headerline=FALSE;
+ }
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+
+ Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
+ }
+ free(line); /* free the line buffer */
+
+ if(fromfile)
+ fclose(fp);
+ }
+
+ c->running = TRUE; /* now, we're running */
+
+ return c;
+
+fail:
+ free(line);
+ if(!inc)
+ /* Only clean up if we allocated it here, as the original could still be in
+ * use by a share handle */
+ Curl_cookie_cleanup(c);
+ if(fromfile && fp)
+ fclose(fp);
+ return NULL; /* out of memory */
+}
+
+/* sort this so that the longest path gets before the shorter path */
+static int cookie_sort(const void *p1, const void *p2)
+{
+ struct Cookie *c1 = *(struct Cookie **)p1;
+ struct Cookie *c2 = *(struct Cookie **)p2;
+ size_t l1, l2;
+
+ /* 1 - compare cookie path lengths */
+ l1 = c1->path ? strlen(c1->path) : 0;
+ l2 = c2->path ? strlen(c2->path) : 0;
+
+ if(l1 != l2)
+ return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+
+ /* 2 - compare cookie domain lengths */
+ l1 = c1->domain ? strlen(c1->domain) : 0;
+ l2 = c2->domain ? strlen(c2->domain) : 0;
+
+ if(l1 != l2)
+ return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+
+ /* 3 - compare cookie names */
+ if(c1->name && c2->name)
+ return strcmp(c1->name, c2->name);
+
+ /* sorry, can't be more deterministic */
+ return 0;
+}
+
+#define CLONE(field) \
+ do { \
+ if(src->field) { \
+ d->field = strdup(src->field); \
+ if(!d->field) \
+ goto fail; \
+ } \
+ } while(0)
+
+static struct Cookie *dup_cookie(struct Cookie *src)
+{
+ struct Cookie *d = calloc(sizeof(struct Cookie), 1);
+ if(d) {
+ CLONE(expirestr);
+ CLONE(domain);
+ CLONE(path);
+ CLONE(spath);
+ CLONE(name);
+ CLONE(value);
+ CLONE(maxage);
+ CLONE(version);
+ d->expires = src->expires;
+ d->tailmatch = src->tailmatch;
+ d->secure = src->secure;
+ d->livecookie = src->livecookie;
+ d->httponly = src->httponly;
+ }
+ return d;
+
+ fail:
+ freecookie(d);
+ return NULL;
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_getlist()
+ *
+ * For a given host and path, return a linked list of cookies that the
+ * client should send to the server if used now. The secure boolean informs
+ * the cookie if a secure connection is achieved or not.
+ *
+ * It shall only return cookies that haven't expired.
+ *
+ ****************************************************************************/
+
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
+ const char *host, const char *path,
+ bool secure)
+{
+ struct Cookie *newco;
+ struct Cookie *co;
+ time_t now = time(NULL);
+ struct Cookie *mainco=NULL;
+ size_t matches = 0;
+ bool is_ip;
+
+ if(!c || !c->cookies)
+ return NULL; /* no cookie struct or no cookies in the struct */
+
+ /* at first, remove expired cookies */
+ remove_expired(c);
+
+ /* check if host is an IP(v4|v6) address */
+ is_ip = isip(host);
+
+ co = c->cookies;
+
+ while(co) {
+ /* only process this cookie if it is not expired or had no expire
+ date AND that if the cookie requires we're secure we must only
+ continue if we are! */
+ if((!co->expires || (co->expires > now)) &&
+ (co->secure?secure:TRUE)) {
+
+ /* now check if the domain is correct */
+ if(!co->domain ||
+ (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
+ ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
+ /* the right part of the host matches the domain stuff in the
+ cookie data */
+
+ /* now check the left part of the path with the cookies path
+ requirement */
+ if(!co->spath || pathmatch(co->spath, path) ) {
+
+ /* and now, we know this is a match and we should create an
+ entry for the return-linked-list */
+
+ newco = dup_cookie(co);
+ if(newco) {
+ /* then modify our next */
+ newco->next = mainco;
+
+ /* point the main to us */
+ mainco = newco;
+
+ matches++;
+ }
+ else {
+ fail:
+ /* failure, clear up the allocated chain and return NULL */
+ Curl_cookie_freelist(mainco);
+ return NULL;
+ }
+ }
+ }
+ }
+ co = co->next;
+ }
+
+ if(matches) {
+ /* Now we need to make sure that if there is a name appearing more than
+ once, the longest specified path version comes first. To make this
+ the swiftest way, we just sort them all based on path length. */
+ struct Cookie **array;
+ size_t i;
+
+ /* alloc an array and store all cookie pointers */
+ array = malloc(sizeof(struct Cookie *) * matches);
+ if(!array)
+ goto fail;
+
+ co = mainco;
+
+ for(i=0; co; co = co->next)
+ array[i++] = co;
+
+ /* now sort the cookie pointers in path length order */
+ qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
+
+ /* remake the linked list order according to the new order */
+
+ mainco = array[0]; /* start here */
+ for(i=0; i<matches-1; i++)
+ array[i]->next = array[i+1];
+ array[matches-1]->next = NULL; /* terminate the list */
+
+ free(array); /* remove the temporary data again */
+ }
+
+ return mainco; /* return the new list */
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearall()
+ *
+ * Clear all existing cookies and reset the counter.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+ if(cookies) {
+ Curl_cookie_freelist(cookies->cookies);
+ cookies->cookies = NULL;
+ cookies->numcookies = 0;
+ }
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_freelist()
+ *
+ * Free a list of cookies previously returned by Curl_cookie_getlist();
+ *
+ ****************************************************************************/
+
+void Curl_cookie_freelist(struct Cookie *co)
+{
+ struct Cookie *next;
+ while(co) {
+ next = co->next;
+ freecookie(co);
+ co = next;
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearsess()
+ *
+ * Free all session cookies in the cookies list.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearsess(struct CookieInfo *cookies)
+{
+ struct Cookie *first, *curr, *next, *prev = NULL;
+
+ if(!cookies || !cookies->cookies)
+ return;
+
+ first = curr = prev = cookies->cookies;
+
+ for(; curr; curr = next) {
+ next = curr->next;
+ if(!curr->expires) {
+ if(first == curr)
+ first = next;
+
+ if(prev == curr)
+ prev = next;
+ else
+ prev->next = next;
+
+ freecookie(curr);
+ cookies->numcookies--;
+ }
+ else
+ prev = curr;
+ }
+
+ cookies->cookies = first;
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_cleanup()
+ *
+ * Free a "cookie object" previous created with Curl_cookie_init().
+ *
+ ****************************************************************************/
+void Curl_cookie_cleanup(struct CookieInfo *c)
+{
+ if(c) {
+ free(c->filename);
+ Curl_cookie_freelist(c->cookies);
+ free(c); /* free the base struct as well */
+ }
+}
+
+/* get_netscape_format()
+ *
+ * Formats a string for Netscape output file, w/o a newline at the end.
+ *
+ * Function returns a char * to a formatted line. Has to be free()d
+*/
+static char *get_netscape_format(const struct Cookie *co)
+{
+ return aprintf(
+ "%s" /* httponly preamble */
+ "%s%s\t" /* domain */
+ "%s\t" /* tailmatch */
+ "%s\t" /* path */
+ "%s\t" /* secure */
+ "%" CURL_FORMAT_CURL_OFF_T "\t" /* expires */
+ "%s\t" /* name */
+ "%s", /* value */
+ co->httponly?"#HttpOnly_":"",
+ /* Make sure all domains are prefixed with a dot if they allow
+ tailmatching. This is Mozilla-style. */
+ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+ co->domain?co->domain:"unknown",
+ co->tailmatch?"TRUE":"FALSE",
+ co->path?co->path:"/",
+ co->secure?"TRUE":"FALSE",
+ co->expires,
+ co->name,
+ co->value?co->value:"");
+}
+
+/*
+ * cookie_output()
+ *
+ * Writes all internally known cookies to the specified file. Specify
+ * "-" as file name to write to stdout.
+ *
+ * The function returns non-zero on write failure.
+ */
+static int cookie_output(struct CookieInfo *c, const char *dumphere)
+{
+ struct Cookie *co;
+ FILE *out;
+ bool use_stdout=FALSE;
+ char *format_ptr;
+
+ if((NULL == c) || (0 == c->numcookies))
+ /* If there are no known cookies, we don't write or even create any
+ destination file */
+ return 0;
+
+ /* at first, remove expired cookies */
+ remove_expired(c);
+
+ if(!strcmp("-", dumphere)) {
+ /* use stdout */
+ out = stdout;
+ use_stdout=TRUE;
+ }
+ else {
+ out = fopen(dumphere, FOPEN_WRITETEXT);
+ if(!out)
+ return 1; /* failure */
+ }
+
+ fputs("# Netscape HTTP Cookie File\n"
+ "# https://curl.haxx.se/docs/http-cookies.html\n"
+ "# This file was generated by libcurl! Edit at your own risk.\n\n",
+ out);
+
+ for(co = c->cookies; co; co = co->next) {
+ if(!co->domain)
+ continue;
+ format_ptr = get_netscape_format(co);
+ if(format_ptr == NULL) {
+ fprintf(out, "#\n# Fatal libcurl error\n");
+ if(!use_stdout)
+ fclose(out);
+ return 1;
+ }
+ fprintf(out, "%s\n", format_ptr);
+ free(format_ptr);
+ }
+
+ if(!use_stdout)
+ fclose(out);
+
+ return 0;
+}
+
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
+{
+ struct curl_slist *list = NULL;
+ struct curl_slist *beg;
+ struct Cookie *c;
+ char *line;
+
+ if((data->cookies == NULL) ||
+ (data->cookies->numcookies == 0))
+ return NULL;
+
+ for(c = data->cookies->cookies; c; c = c->next) {
+ if(!c->domain)
+ continue;
+ line = get_netscape_format(c);
+ if(!line) {
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ beg = Curl_slist_append_nodup(list, line);
+ if(!beg) {
+ free(line);
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ list = beg;
+ }
+
+ return list;
+}
+
+void Curl_flush_cookies(struct Curl_easy *data, int cleanup)
+{
+ if(data->set.str[STRING_COOKIEJAR]) {
+ if(data->change.cookielist) {
+ /* If there is a list of cookie files to read, do it first so that
+ we have all the told files read before we write the new jar.
+ Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
+ Curl_cookie_loadfiles(data);
+ }
+
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+ /* if we have a destination file for all the cookies to get dumped to */
+ if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
+ infof(data, "WARNING: failed to save cookies in %s\n",
+ data->set.str[STRING_COOKIEJAR]);
+ }
+ else {
+ if(cleanup && data->change.cookielist) {
+ /* since nothing is written, we can just free the list of cookie file
+ names */
+ curl_slist_free_all(data->change.cookielist); /* clean up list */
+ data->change.cookielist = NULL;
+ }
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ }
+
+ if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
+ Curl_cookie_cleanup(data->cookies);
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
diff --git a/Utilities/cmcurl/lib/cookie.h b/Utilities/cmcurl/lib/cookie.h
new file mode 100644
index 000000000..a9a45785c
--- /dev/null
+++ b/Utilities/cmcurl/lib/cookie.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_COOKIE_H
+#define HEADER_CURL_COOKIE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+struct Cookie {
+ struct Cookie *next; /* next in the chain */
+ char *name; /* <this> = value */
+ char *value; /* name = <this> */
+ char *path; /* path = <this> which is in Set-Cookie: */
+ char *spath; /* sanitized cookie path */
+ char *domain; /* domain = <this> */
+ curl_off_t expires; /* expires = <this> */
+ char *expirestr; /* the plain text version */
+ bool tailmatch; /* weather we do tail-matchning of the domain name */
+
+ /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
+ char *version; /* Version = <value> */
+ char *maxage; /* Max-Age = <value> */
+
+ bool secure; /* whether the 'secure' keyword was used */
+ bool livecookie; /* updated from a server, not a stored file */
+ bool httponly; /* true if the httponly directive is present */
+};
+
+struct CookieInfo {
+ /* linked list of cookies we know of */
+ struct Cookie *cookies;
+
+ char *filename; /* file we read from/write to */
+ bool running; /* state info, for cookie adding information */
+ long numcookies; /* number of cookies in the "jar" */
+ bool newsession; /* new session, discard session cookies on load */
+};
+
+/* This is the maximum line length we accept for a cookie line. RFC 2109
+ section 6.3 says:
+
+ "at least 4096 bytes per cookie (as measured by the size of the characters
+ that comprise the cookie non-terminal in the syntax description of the
+ Set-Cookie header)"
+
+*/
+#define MAX_COOKIE_LINE 5000
+#define MAX_COOKIE_LINE_TXT "4999"
+
+/* This is the maximum length of a cookie name we deal with: */
+#define MAX_NAME 1024
+#define MAX_NAME_TXT "1023"
+
+struct Curl_easy;
+/*
+ * Add a cookie to the internal list of cookies. The domain and path arguments
+ * are only used if the header boolean is TRUE.
+ */
+
+struct Cookie *Curl_cookie_add(struct Curl_easy *data,
+ struct CookieInfo *, bool header, char *lineptr,
+ const char *domain, const char *path);
+
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
+ const char *, bool);
+void Curl_cookie_freelist(struct Cookie *cookies);
+void Curl_cookie_clearall(struct CookieInfo *cookies);
+void Curl_cookie_clearsess(struct CookieInfo *cookies);
+
+#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
+#define Curl_cookie_list(x) NULL
+#define Curl_cookie_loadfiles(x) Curl_nop_stmt
+#define Curl_cookie_init(x,y,z,w) NULL
+#define Curl_cookie_cleanup(x) Curl_nop_stmt
+#define Curl_flush_cookies(x,y) Curl_nop_stmt
+#else
+void Curl_flush_cookies(struct Curl_easy *data, int cleanup);
+void Curl_cookie_cleanup(struct CookieInfo *);
+struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
+ const char *, struct CookieInfo *, bool);
+struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
+void Curl_cookie_loadfiles(struct Curl_easy *data);
+#endif
+
+#endif /* HEADER_CURL_COOKIE_H */
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.c b/Utilities/cmcurl/lib/curl_addrinfo.c
new file mode 100644
index 000000000..1adf3198a
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_addrinfo.c
@@ -0,0 +1,616 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_SYS_UN_H
+# include <sys/un.h>
+#endif
+
+#ifdef __VMS
+# include <in.h>
+# include <inet.h>
+#endif
+
+#if defined(NETWARE) && defined(__NOVELL_LIBC__)
+# undef in_addr_t
+# define in_addr_t unsigned long
+#endif
+
+#include <stddef.h>
+
+#include "curl_addrinfo.h"
+#include "inet_pton.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_freeaddrinfo()
+ *
+ * This is used to free a linked list of Curl_addrinfo structs along
+ * with all its associated allocated storage. This function should be
+ * called once for each successful call to Curl_getaddrinfo_ex() or to
+ * any function call which actually allocates a Curl_addrinfo struct.
+ */
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+ defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
+ /* workaround icc 9.1 optimizer issue */
+# define vqualifier volatile
+#else
+# define vqualifier
+#endif
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead)
+{
+ Curl_addrinfo *vqualifier canext;
+ Curl_addrinfo *ca;
+
+ for(ca = cahead; ca != NULL; ca = canext) {
+ free(ca->ai_addr);
+ free(ca->ai_canonname);
+ canext = ca->ai_next;
+
+ free(ca);
+ }
+}
+
+
+#ifdef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo_ex()
+ *
+ * This is a wrapper function around system's getaddrinfo(), with
+ * the only difference that instead of returning a linked list of
+ * addrinfo structs this one returns a linked list of Curl_addrinfo
+ * ones. The memory allocated by this function *MUST* be free'd with
+ * Curl_freeaddrinfo(). For each successful call to this function
+ * there must be an associated call later to Curl_freeaddrinfo().
+ *
+ * There should be no single call to system's getaddrinfo() in the
+ * whole library, any such call should be 'routed' through this one.
+ */
+
+int
+Curl_getaddrinfo_ex(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ Curl_addrinfo **result)
+{
+ const struct addrinfo *ai;
+ struct addrinfo *aihead;
+ Curl_addrinfo *cafirst = NULL;
+ Curl_addrinfo *calast = NULL;
+ Curl_addrinfo *ca;
+ size_t ss_size;
+ int error;
+
+ *result = NULL; /* assume failure */
+
+ error = getaddrinfo(nodename, servname, hints, &aihead);
+ if(error)
+ return error;
+
+ /* traverse the addrinfo list */
+
+ for(ai = aihead; ai != NULL; ai = ai->ai_next) {
+
+ /* ignore elements with unsupported address family, */
+ /* settle family-specific sockaddr structure size. */
+ if(ai->ai_family == AF_INET)
+ ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+ else if(ai->ai_family == AF_INET6)
+ ss_size = sizeof(struct sockaddr_in6);
+#endif
+ else
+ continue;
+
+ /* ignore elements without required address info */
+ if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0))
+ continue;
+
+ /* ignore elements with bogus address size */
+ if((size_t)ai->ai_addrlen < ss_size)
+ continue;
+
+ ca = malloc(sizeof(Curl_addrinfo));
+ if(!ca) {
+ error = EAI_MEMORY;
+ break;
+ }
+
+ /* copy each structure member individually, member ordering, */
+ /* size, or padding might be different for each platform. */
+
+ ca->ai_flags = ai->ai_flags;
+ ca->ai_family = ai->ai_family;
+ ca->ai_socktype = ai->ai_socktype;
+ ca->ai_protocol = ai->ai_protocol;
+ ca->ai_addrlen = (curl_socklen_t)ss_size;
+ ca->ai_addr = NULL;
+ ca->ai_canonname = NULL;
+ ca->ai_next = NULL;
+
+ ca->ai_addr = malloc(ss_size);
+ if(!ca->ai_addr) {
+ error = EAI_MEMORY;
+ free(ca);
+ break;
+ }
+ memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+ if(ai->ai_canonname != NULL) {
+ ca->ai_canonname = strdup(ai->ai_canonname);
+ if(!ca->ai_canonname) {
+ error = EAI_MEMORY;
+ free(ca->ai_addr);
+ free(ca);
+ break;
+ }
+ }
+
+ /* if the return list is empty, this becomes the first element */
+ if(!cafirst)
+ cafirst = ca;
+
+ /* add this element last in the return list */
+ if(calast)
+ calast->ai_next = ca;
+ calast = ca;
+
+ }
+
+ /* destroy the addrinfo list */
+ if(aihead)
+ freeaddrinfo(aihead);
+
+ /* if we failed, also destroy the Curl_addrinfo list */
+ if(error) {
+ Curl_freeaddrinfo(cafirst);
+ cafirst = NULL;
+ }
+ else if(!cafirst) {
+#ifdef EAI_NONAME
+ /* rfc3493 conformant */
+ error = EAI_NONAME;
+#else
+ /* rfc3493 obsoleted */
+ error = EAI_NODATA;
+#endif
+#ifdef USE_WINSOCK
+ SET_SOCKERRNO(error);
+#endif
+ }
+
+ *result = cafirst;
+
+ /* This is not a CURLcode */
+ return error;
+}
+#endif /* HAVE_GETADDRINFO */
+
+
+/*
+ * Curl_he2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data of a given hostent.
+ * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
+ * stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo(). For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ *
+ * Curl_addrinfo defined in "lib/curl_addrinfo.h"
+ *
+ * struct Curl_addrinfo {
+ * int ai_flags;
+ * int ai_family;
+ * int ai_socktype;
+ * int ai_protocol;
+ * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo *
+ * char *ai_canonname;
+ * struct sockaddr *ai_addr;
+ * struct Curl_addrinfo *ai_next;
+ * };
+ * typedef struct Curl_addrinfo Curl_addrinfo;
+ *
+ * hostent defined in <netdb.h>
+ *
+ * struct hostent {
+ * char *h_name;
+ * char **h_aliases;
+ * int h_addrtype;
+ * int h_length;
+ * char **h_addr_list;
+ * };
+ *
+ * for backward compatibility:
+ *
+ * #define h_addr h_addr_list[0]
+ */
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port)
+{
+ Curl_addrinfo *ai;
+ Curl_addrinfo *prevai = NULL;
+ Curl_addrinfo *firstai = NULL;
+ struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ CURLcode result = CURLE_OK;
+ int i;
+ char *curr;
+
+ if(!he)
+ /* no input == no output! */
+ return NULL;
+
+ DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
+
+ for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
+
+ size_t ss_size;
+#ifdef ENABLE_IPV6
+ if(he->h_addrtype == AF_INET6)
+ ss_size = sizeof(struct sockaddr_in6);
+ else
+#endif
+ ss_size = sizeof(struct sockaddr_in);
+
+ ai = calloc(1, sizeof(Curl_addrinfo));
+ if(!ai) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ ai->ai_canonname = strdup(he->h_name);
+ if(!ai->ai_canonname) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai);
+ break;
+ }
+ ai->ai_addr = calloc(1, ss_size);
+ if(!ai->ai_addr) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai->ai_canonname);
+ free(ai);
+ break;
+ }
+
+ if(!firstai)
+ /* store the pointer we want to return from this function */
+ firstai = ai;
+
+ if(prevai)
+ /* make the previous entry point to this */
+ prevai->ai_next = ai;
+
+ ai->ai_family = he->h_addrtype;
+
+ /* we return all names as STREAM, so when using this address for TFTP
+ the type must be ignored and conn->socktype be used instead! */
+ ai->ai_socktype = SOCK_STREAM;
+
+ ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+ /* leave the rest of the struct filled with zero */
+
+ switch(ai->ai_family) {
+ case AF_INET:
+ addr = (void *)ai->ai_addr; /* storage area for this info */
+
+ memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
+ addr->sin_family = (unsigned short)(he->h_addrtype);
+ addr->sin_port = htons((unsigned short)port);
+ break;
+
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr6 = (void *)ai->ai_addr; /* storage area for this info */
+
+ memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
+ addr6->sin6_family = (unsigned short)(he->h_addrtype);
+ addr6->sin6_port = htons((unsigned short)port);
+ break;
+#endif
+ }
+
+ prevai = ai;
+ }
+
+ if(result) {
+ Curl_freeaddrinfo(firstai);
+ firstai = NULL;
+ }
+
+ return firstai;
+}
+
+
+struct namebuff {
+ struct hostent hostentry;
+ union {
+ struct in_addr ina4;
+#ifdef ENABLE_IPV6
+ struct in6_addr ina6;
+#endif
+ } addrentry;
+ char *h_addr_list[2];
+};
+
+
+/*
+ * Curl_ip2addr()
+ *
+ * This function takes an internet address, in binary form, as input parameter
+ * along with its address family and the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for the
+ * given address/host
+ */
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
+{
+ Curl_addrinfo *ai;
+
+#if defined(__VMS) && \
+ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size save
+#pragma pointer_size short
+#pragma message disable PTRMISMATCH
+#endif
+
+ struct hostent *h;
+ struct namebuff *buf;
+ char *addrentry;
+ char *hoststr;
+ size_t addrsize;
+
+ DEBUGASSERT(inaddr && hostname);
+
+ buf = malloc(sizeof(struct namebuff));
+ if(!buf)
+ return NULL;
+
+ hoststr = strdup(hostname);
+ if(!hoststr) {
+ free(buf);
+ return NULL;
+ }
+
+ switch(af) {
+ case AF_INET:
+ addrsize = sizeof(struct in_addr);
+ addrentry = (void *)&buf->addrentry.ina4;
+ memcpy(addrentry, inaddr, sizeof(struct in_addr));
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addrsize = sizeof(struct in6_addr);
+ addrentry = (void *)&buf->addrentry.ina6;
+ memcpy(addrentry, inaddr, sizeof(struct in6_addr));
+ break;
+#endif
+ default:
+ free(hoststr);
+ free(buf);
+ return NULL;
+ }
+
+ h = &buf->hostentry;
+ h->h_name = hoststr;
+ h->h_aliases = NULL;
+ h->h_addrtype = (short)af;
+ h->h_length = (short)addrsize;
+ h->h_addr_list = &buf->h_addr_list[0];
+ h->h_addr_list[0] = addrentry;
+ h->h_addr_list[1] = NULL; /* terminate list of entries */
+
+#if defined(__VMS) && \
+ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size restore
+#pragma message enable PTRMISMATCH
+#endif
+
+ ai = Curl_he2ai(h, port);
+
+ free(hoststr);
+ free(buf);
+
+ return ai;
+}
+
+/*
+ * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
+ * allocated Curl_addrinfo struct and returns it.
+ */
+Curl_addrinfo *Curl_str2addr(char *address, int port)
+{
+ struct in_addr in;
+ if(Curl_inet_pton(AF_INET, address, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, address, port);
+#ifdef ENABLE_IPV6
+ {
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
+ /* This is a dotted IPv6 address ::1-style */
+ return Curl_ip2addr(AF_INET6, &in6, address, port);
+ }
+#endif
+ return NULL; /* bad input format */
+}
+
+#ifdef USE_UNIX_SOCKETS
+/**
+ * Given a path to a Unix domain socket, return a newly allocated Curl_addrinfo
+ * struct initialized with this path.
+ * Set '*longpath' to TRUE if the error is a too long path.
+ */
+Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
+{
+ Curl_addrinfo *ai;
+ struct sockaddr_un *sa_un;
+ size_t path_len;
+
+ *longpath = FALSE;
+
+ ai = calloc(1, sizeof(Curl_addrinfo));
+ if(!ai)
+ return NULL;
+ ai->ai_addr = calloc(1, sizeof(struct sockaddr_un));
+ if(!ai->ai_addr) {
+ free(ai);
+ return NULL;
+ }
+
+ sa_un = (void *) ai->ai_addr;
+ sa_un->sun_family = AF_UNIX;
+
+ /* sun_path must be able to store the NUL-terminated path */
+ path_len = strlen(path) + 1;
+ if(path_len > sizeof(sa_un->sun_path)) {
+ free(ai->ai_addr);
+ free(ai);
+ *longpath = TRUE;
+ return NULL;
+ }
+
+ ai->ai_family = AF_UNIX;
+ ai->ai_socktype = SOCK_STREAM; /* assume reliable transport for HTTP */
+ ai->ai_addrlen = (curl_socklen_t)
+ ((offsetof(struct sockaddr_un, sun_path) + path_len) & 0x7FFFFFFF);
+
+ /* Abstract Unix domain socket have NULL prefix instead of suffix */
+ if(abstract)
+ memcpy(sa_un->sun_path + 1, path, path_len - 1);
+ else
+ memcpy(sa_un->sun_path, path, path_len); /* copy NUL byte */
+
+ return ai;
+}
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+/*
+ * curl_dofreeaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source)
+{
+#ifdef USE_LWIPSOCK
+ lwip_freeaddrinfo(freethis);
+#else
+ (freeaddrinfo)(freethis);
+#endif
+ curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
+ source, line, (void *)freethis);
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+/*
+ * curl_dogetaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+int
+curl_dogetaddrinfo(const char *hostname,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source)
+{
+#ifdef USE_LWIPSOCK
+ int res=lwip_getaddrinfo(hostname, service, hints, result);
+#else
+ int res=(getaddrinfo)(hostname, service, hints, result);
+#endif
+ if(0 == res)
+ /* success */
+ curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
+ source, line, (void *)*result);
+ else
+ curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
+ source, line);
+ return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
+
+#if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS)
+/*
+ * Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
+ * 10.11.5.
+ */
+void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port)
+{
+ Curl_addrinfo *ca;
+ struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ for(ca = addrinfo; ca != NULL; ca = ca->ai_next) {
+ switch(ca->ai_family) {
+ case AF_INET:
+ addr = (void *)ca->ai_addr; /* storage area for this info */
+ addr->sin_port = htons((unsigned short)port);
+ break;
+
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr6 = (void *)ca->ai_addr; /* storage area for this info */
+ addr6->sin6_port = htons((unsigned short)port);
+ break;
+#endif
+ }
+ }
+}
+#endif
diff --git a/Utilities/cmcurl/lib/curl_addrinfo.h b/Utilities/cmcurl/lib/curl_addrinfo.h
new file mode 100644
index 000000000..8f6f3d106
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_addrinfo.h
@@ -0,0 +1,110 @@
+#ifndef HEADER_CURL_ADDRINFO_H
+#define HEADER_CURL_ADDRINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+# include <in.h>
+# include <inet.h>
+# include <stdlib.h>
+#endif
+
+
+/*
+ * Curl_addrinfo is our internal struct definition that we use to allow
+ * consistent internal handling of this data. We use this even when the
+ * system provides an addrinfo structure definition. And we use this for
+ * all sorts of IPv4 and IPV6 builds.
+ */
+
+struct Curl_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct Curl_addrinfo *ai_next;
+};
+typedef struct Curl_addrinfo Curl_addrinfo;
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead);
+
+#ifdef HAVE_GETADDRINFO
+int
+Curl_getaddrinfo_ex(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ Curl_addrinfo **result);
+#endif
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port);
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
+
+Curl_addrinfo *Curl_str2addr(char *dotted, int port);
+
+#ifdef USE_UNIX_SOCKETS
+Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
+ defined(HAVE_FREEADDRINFO)
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+int
+curl_dogetaddrinfo(const char *hostname,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source);
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#ifdef USE_RESOLVE_ON_IPS
+void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port);
+#else
+#define Curl_addrinfo_set_port(x,y)
+#endif
+#endif
+
+#endif /* HEADER_CURL_ADDRINFO_H */
diff --git a/Utilities/cmcurl/lib/curl_base64.h b/Utilities/cmcurl/lib/curl_base64.h
new file mode 100644
index 000000000..7e9fc2606
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_base64.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_BASE64_H
+#define HEADER_CURL_BASE64_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_base64_encode(struct Curl_easy *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen);
+CURLcode Curl_base64url_encode(struct Curl_easy *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen);
+
+CURLcode Curl_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen);
+
+#endif /* HEADER_CURL_BASE64_H */
diff --git a/Utilities/cmcurl/lib/curl_config.h.cmake b/Utilities/cmcurl/lib/curl_config.h.cmake
new file mode 100644
index 000000000..f9d54b4bd
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_config.h.cmake
@@ -0,0 +1,1006 @@
+/* lib/curl_config.h.in. Generated somehow by cmake. */
+
+/* when building libcurl itself */
+#cmakedefine BUILDING_LIBCURL 1
+
+/* to disable cookies support */
+#cmakedefine CURL_DISABLE_COOKIES 1
+
+/* to disable cryptographic authentication */
+#cmakedefine CURL_DISABLE_CRYPTO_AUTH 1
+
+/* to disable DICT */
+#cmakedefine CURL_DISABLE_DICT 1
+
+/* to disable FILE */
+#cmakedefine CURL_DISABLE_FILE 1
+
+/* to disable FTP */
+#cmakedefine CURL_DISABLE_FTP 1
+
+/* to disable GOPHER */
+#cmakedefine CURL_DISABLE_GOPHER 1
+
+/* to disable IMAP */
+#cmakedefine CURL_DISABLE_IMAP 1
+
+/* to disable HTTP */
+#cmakedefine CURL_DISABLE_HTTP 1
+
+/* to disable LDAP */
+#cmakedefine CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#cmakedefine CURL_DISABLE_LDAPS 1
+
+/* to disable POP3 */
+#cmakedefine CURL_DISABLE_POP3 1
+
+/* to disable proxies */
+#cmakedefine CURL_DISABLE_PROXY 1
+
+/* to disable RTSP */
+#cmakedefine CURL_DISABLE_RTSP 1
+
+/* to disable RTMP */
+#cmakedefine CURL_DISABLE_RTMP 1
+
+/* to disable SMB */
+#cmakedefine CURL_DISABLE_SMB 1
+
+/* to disable SMTP */
+#cmakedefine CURL_DISABLE_SMTP 1
+
+/* to disable TELNET */
+#cmakedefine CURL_DISABLE_TELNET 1
+
+/* to disable TFTP */
+#cmakedefine CURL_DISABLE_TFTP 1
+
+/* to disable verbose strings */
+#cmakedefine CURL_DISABLE_VERBOSE_STRINGS 1
+
+/* to make a symbol visible */
+#cmakedefine CURL_EXTERN_SYMBOL ${CURL_EXTERN_SYMBOL}
+/* Ensure using CURL_EXTERN_SYMBOL is possible */
+#ifndef CURL_EXTERN_SYMBOL
+#define CURL_EXTERN_SYMBOL
+#endif
+
+/* Use Windows LDAP implementation */
+#cmakedefine USE_WIN32_LDAP 1
+
+/* when not building a shared library */
+#cmakedefine CURL_STATICLIB 1
+
+/* Set to explicitly specify we don't want to use thread-safe functions */
+#cmakedefine DISABLED_THREADSAFE 1
+
+/* your Entropy Gathering Daemon socket pathname */
+#cmakedefine EGD_SOCKET ${EGD_SOCKET}
+
+/* Define if you want to enable IPv6 support */
+#cmakedefine ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
+
+/* Define to the type of arg 1 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
+
+/* Define to the type of arg 2 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
+
+/* Define to the type of arg 7 for getnameinfo. */
+#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
+
+/* Specifies the number of arguments to getservbyport_r */
+#cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#cmakedefine GETSERVBYPORT_R_BUFSIZE ${GETSERVBYPORT_R_BUFSIZE}
+
+/* Define to 1 if you have the alarm function. */
+#cmakedefine HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#cmakedefine HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#cmakedefine HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+#cmakedefine HAVE_ARPA_TFTP_H 1
+
+/* Define to 1 if you have the <assert.h> header file. */
+#cmakedefine HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#cmakedefine HAVE_BASENAME 1
+
+/* Define to 1 if bool is an available type. */
+#cmakedefine HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+#cmakedefine HAVE_CLOCK_GETTIME_MONOTONIC 1
+
+/* Define to 1 if you have the `closesocket' function. */
+#cmakedefine HAVE_CLOSESOCKET 1
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#cmakedefine HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define to 1 if you have the <crypto.h> header file. */
+#cmakedefine HAVE_CRYPTO_H 1
+
+/* Define to 1 if you have the <des.h> header file. */
+#cmakedefine HAVE_DES_H 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#cmakedefine HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#cmakedefine HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#cmakedefine HAVE_ERR_H 1
+
+/* Define to 1 if you have the fcntl function. */
+#cmakedefine HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#cmakedefine HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#cmakedefine HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#cmakedefine HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#cmakedefine HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#cmakedefine HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#cmakedefine HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#cmakedefine HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#cmakedefine HAVE_GETEUID 1
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#cmakedefine HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#cmakedefine HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_5 1
+
+/* gethostbyaddr_r() takes 7 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_7 1
+
+/* gethostbyaddr_r() takes 8 args */
+#cmakedefine HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#cmakedefine HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+#cmakedefine HAVE_GETHOSTBYNAME_R 1
+
+/* gethostbyname_r() takes 3 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_3 1
+
+/* gethostbyname_r() takes 5 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_5 1
+
+/* gethostbyname_r() takes 6 args */
+#cmakedefine HAVE_GETHOSTBYNAME_R_6 1
+
+/* Define to 1 if you have the gethostname function. */
+#cmakedefine HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+#cmakedefine HAVE_GETIFADDRS 1
+
+/* Define to 1 if you have the getnameinfo function. */
+#cmakedefine HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+#cmakedefine HAVE_GETPASS_R 1
+
+/* Define to 1 if you have the `getppid' function. */
+#cmakedefine HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#cmakedefine HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#cmakedefine HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+#cmakedefine HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+#cmakedefine HAVE_GETSERVBYPORT_R 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#cmakedefine HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+#cmakedefine HAVE_GLIBC_STRERROR_R 1
+
+/* Define to 1 if you have a working gmtime_r function. */
+#cmakedefine HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+#cmakedefine HAVE_GSSAPI 1
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_GENERIC_H 1
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_H 1
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+#cmakedefine HAVE_GSSAPI_GSSAPI_KRB5_H 1
+
+/* if you have the GNU gssapi libraries */
+#cmakedefine HAVE_GSSGNU 1
+
+/* if you have the Heimdal gssapi libraries */
+#cmakedefine HAVE_GSSHEIMDAL 1
+
+/* if you have the MIT gssapi libraries */
+#cmakedefine HAVE_GSSMIT 1
+
+/* Define to 1 if you have the `idna_strerror' function. */
+#cmakedefine HAVE_IDNA_STRERROR 1
+
+/* Define to 1 if you have the `idn_free' function. */
+#cmakedefine HAVE_IDN_FREE 1
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+#cmakedefine HAVE_IDN_FREE_H 1
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+#cmakedefine HAVE_IFADDRS_H 1
+
+/* Define to 1 if you have the `inet_addr' function. */
+#cmakedefine HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+#cmakedefine HAVE_INET_NTOA_R 1
+
+/* inet_ntoa_r() takes 2 args */
+#cmakedefine HAVE_INET_NTOA_R_2 1
+
+/* inet_ntoa_r() takes 3 args */
+#cmakedefine HAVE_INET_NTOA_R_3 1
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+#cmakedefine HAVE_INET_NTOP 1
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+#cmakedefine HAVE_INET_PTON 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#cmakedefine HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+#cmakedefine HAVE_IOCTLSOCKET 1
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL 1
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+ */
+#cmakedefine HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+#cmakedefine HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#cmakedefine HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#cmakedefine HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+#cmakedefine HAVE_IO_H 1
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+#cmakedefine HAVE_KRB4 1
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+#cmakedefine HAVE_KRB_GET_OUR_IP_FOR_REALM 1
+
+/* Define to 1 if you have the <krb.h> header file. */
+#cmakedefine HAVE_KRB_H 1
+
+/* Define to 1 if you have the lber.h header file. */
+#cmakedefine HAVE_LBER_H 1
+
+/* Define to 1 if you have the ldapssl.h header file. */
+#cmakedefine HAVE_LDAPSSL_H 1
+
+/* Define to 1 if you have the ldap.h header file. */
+#cmakedefine HAVE_LDAP_H 1
+
+/* Use LDAPS implementation */
+#cmakedefine HAVE_LDAP_SSL 1
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+#cmakedefine HAVE_LDAP_SSL_H 1
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+#cmakedefine HAVE_LDAP_URL_PARSE 1
+
+/* Define to 1 if you have the <libgen.h> header file. */
+#cmakedefine HAVE_LIBGEN_H 1
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+#cmakedefine HAVE_LIBIDN 1
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#cmakedefine HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+#cmakedefine HAVE_LIBRESOLVE 1
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+#cmakedefine HAVE_LIBSOCKET 1
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+#cmakedefine HAVE_LIBSSH2 1
+
+/* Define to 1 if libssh2 provides `libssh2_version'. */
+#cmakedefine HAVE_LIBSSH2_VERSION 1
+
+/* Define to 1 if libssh2 provides `libssh2_init'. */
+#cmakedefine HAVE_LIBSSH2_INIT 1
+
+/* Define to 1 if libssh2 provides `libssh2_exit'. */
+#cmakedefine HAVE_LIBSSH2_EXIT 1
+
+/* Define to 1 if libssh2 provides `libssh2_scp_send64'. */
+#cmakedefine HAVE_LIBSSH2_SCP_SEND64 1
+
+/* Define to 1 if libssh2 provides `libssh2_session_handshake'. */
+#cmakedefine HAVE_LIBSSH2_SESSION_HANDSHAKE 1
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+#cmakedefine HAVE_LIBSSH2_H 1
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#cmakedefine HAVE_LIBSSL 1
+
+/* if zlib is available */
+#cmakedefine HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#cmakedefine HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#cmakedefine HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#cmakedefine HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#cmakedefine HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#cmakedefine HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#cmakedefine HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+#cmakedefine HAVE_MSG_NOSIGNAL 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#cmakedefine HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#cmakedefine HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#cmakedefine HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#cmakedefine HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+#cmakedefine HAVE_NI_WITHSCOPEID 1
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE */
+#cmakedefine HAVE_OLD_GSSMIT 1
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#cmakedefine HAVE_OPENSSL_CRYPTO_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#cmakedefine HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#cmakedefine HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#cmakedefine HAVE_OPENSSL_PEM_H 1
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+#cmakedefine HAVE_OPENSSL_PKCS12_H 1
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#cmakedefine HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#cmakedefine HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#cmakedefine HAVE_OPENSSL_X509_H 1
+
+/* Define to 1 if you have the <pem.h> header file. */
+#cmakedefine HAVE_PEM_H 1
+
+/* Define to 1 if you have the `perror' function. */
+#cmakedefine HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#cmakedefine HAVE_PIPE 1
+
+/* Define to 1 if you have a working poll function. */
+#cmakedefine HAVE_POLL 1
+
+/* If you have a fine poll */
+#cmakedefine HAVE_POLL_FINE 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#cmakedefine HAVE_POLL_H 1
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+#cmakedefine HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pthread.h> header file */
+#cmakedefine HAVE_PTHREAD_H 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#cmakedefine HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+#cmakedefine HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+#cmakedefine HAVE_RAND_SCREEN 1
+
+/* Define to 1 if you have the `RAND_status' function. */
+#cmakedefine HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the recv function. */
+#cmakedefine HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#cmakedefine HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+#cmakedefine HAVE_RSA_H 1
+
+/* Define to 1 if you have the select function. */
+#cmakedefine HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#cmakedefine HAVE_SEND 1
+
+/* Define to 1 if you have the 'fsetxattr' function. */
+#cmakedefine HAVE_FSETXATTR 1
+
+/* fsetxattr() takes 5 args */
+#cmakedefine HAVE_FSETXATTR_5 1
+
+/* fsetxattr() takes 6 args */
+#cmakedefine HAVE_FSETXATTR_6 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#cmakedefine HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#cmakedefine HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#cmakedefine HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#cmakedefine HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#cmakedefine HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+#cmakedefine HAVE_SETSOCKOPT_SO_NONBLOCK 1
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+#cmakedefine HAVE_SGTTY_H 1
+
+/* Define to 1 if you have the sigaction function. */
+#cmakedefine HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#cmakedefine HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#cmakedefine HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#cmakedefine HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+#cmakedefine HAVE_SIGSETJMP 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#cmakedefine HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+#cmakedefine HAVE_SIG_ATOMIC_T_VOLATILE 1
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#cmakedefine HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#cmakedefine HAVE_SOCKET 1
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#cmakedefine HAVE_SSL_GET_SHUTDOWN 1
+
+/* Define to 1 if you have the <ssl.h> header file. */
+#cmakedefine HAVE_SSL_H 1
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#cmakedefine HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#cmakedefine HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#cmakedefine HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcasestr function. */
+#cmakedefine HAVE_STRCASESTR 1
+
+/* Define to 1 if you have the strcmpi function. */
+#cmakedefine HAVE_STRCMPI 1
+
+/* Define to 1 if you have the strdup function. */
+#cmakedefine HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#cmakedefine HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+#cmakedefine HAVE_STRICMP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H 1
+
+/* Define to 1 if you have the strlcat function. */
+#cmakedefine HAVE_STRLCAT 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#cmakedefine HAVE_STRLCPY 1
+
+/* Define to 1 if you have the strncasecmp function. */
+#cmakedefine HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+#cmakedefine HAVE_STRNCMPI 1
+
+/* Define to 1 if you have the strnicmp function. */
+#cmakedefine HAVE_STRNICMP 1
+
+/* Define to 1 if you have the <stropts.h> header file. */
+#cmakedefine HAVE_STROPTS_H 1
+
+/* Define to 1 if you have the strstr function. */
+#cmakedefine HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#cmakedefine HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+#cmakedefine HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#cmakedefine HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#cmakedefine HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#cmakedefine HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#cmakedefine HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#cmakedefine HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+#cmakedefine HAVE_SYS_POLL_H 1
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#cmakedefine HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#cmakedefine HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#cmakedefine HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#cmakedefine HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#cmakedefine HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#cmakedefine HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#cmakedefine HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#cmakedefine HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#cmakedefine HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#cmakedefine HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#cmakedefine HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+#cmakedefine HAVE_TLD_H 1
+
+/* Define to 1 if you have the `tld_strerror' function. */
+#cmakedefine HAVE_TLD_STRERROR 1
+
+/* Define to 1 if you have the `uname' function. */
+#cmakedefine HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#cmakedefine HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#cmakedefine HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#cmakedefine HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#cmakedefine HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have the winber.h header file. */
+#cmakedefine HAVE_WINBER_H 1
+
+/* Define to 1 if you have the windows.h header file. */
+#cmakedefine HAVE_WINDOWS_H 1
+
+/* Define to 1 if you have the winldap.h header file. */
+#cmakedefine HAVE_WINLDAP_H 1
+
+/* Define to 1 if you have the winsock2.h header file. */
+#cmakedefine HAVE_WINSOCK2_H 1
+
+/* Define to 1 if you have the winsock.h header file. */
+#cmakedefine HAVE_WINSOCK_H 1
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#cmakedefine HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#cmakedefine HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+#cmakedefine HAVE_WS2TCPIP_H 1
+
+/* Define to 1 if you have the <x509.h> header file. */
+#cmakedefine HAVE_X509_H 1
+
+/* Define if you have the <process.h> header file. */
+#cmakedefine HAVE_PROCESS_H 1
+
+/* if you have the zlib.h header file */
+#cmakedefine HAVE_ZLIB_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#cmakedefine LT_OBJDIR ${LT_OBJDIR}
+
+/* If you lack a fine basename() prototype */
+#cmakedefine NEED_BASENAME_PROTO 1
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+#cmakedefine NEED_LBER_H 1
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+#cmakedefine NEED_MALLOC_H 1
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+#cmakedefine NEED_REENTRANT 1
+
+/* cpu-machine-OS */
+#cmakedefine OS ${OS}
+
+/* Name of package */
+#cmakedefine PACKAGE ${PACKAGE}
+
+/* Define to the address where bug reports for this package should be sent. */
+#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT}
+
+/* Define to the full name of this package. */
+#cmakedefine PACKAGE_NAME ${PACKAGE_NAME}
+
+/* Define to the full name and version of this package. */
+#cmakedefine PACKAGE_STRING ${PACKAGE_STRING}
+
+/* Define to the one symbol short name of this package. */
+#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME}
+
+/* Define to the version of this package. */
+#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
+
+/* a suitable file to read random data from */
+#cmakedefine RANDOM_FILE "${RANDOM_FILE}"
+
+/* Define to the type of arg 1 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG1 ${RECVFROM_TYPE_ARG1}
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG2 ${RECVFROM_TYPE_ARG2}
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG3 ${RECVFROM_TYPE_ARG3}
+
+/* Define to the type of arg 4 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG4 ${RECVFROM_TYPE_ARG4}
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG5 ${RECVFROM_TYPE_ARG5}
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG5_IS_VOID 1
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#cmakedefine RECVFROM_TYPE_ARG6 ${RECVFROM_TYPE_ARG6}
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+#cmakedefine RECVFROM_TYPE_ARG6_IS_VOID 1
+
+/* Define to the function return type for recvfrom. */
+#cmakedefine RECVFROM_TYPE_RETV ${RECVFROM_TYPE_RETV}
+
+/* Define to the type of arg 1 for recv. */
+#cmakedefine RECV_TYPE_ARG1 ${RECV_TYPE_ARG1}
+
+/* Define to the type of arg 2 for recv. */
+#cmakedefine RECV_TYPE_ARG2 ${RECV_TYPE_ARG2}
+
+/* Define to the type of arg 3 for recv. */
+#cmakedefine RECV_TYPE_ARG3 ${RECV_TYPE_ARG3}
+
+/* Define to the type of arg 4 for recv. */
+#cmakedefine RECV_TYPE_ARG4 ${RECV_TYPE_ARG4}
+
+/* Define to the function return type for recv. */
+#cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#cmakedefine RETSIGTYPE ${RETSIGTYPE}
+
+/* Define to the type qualifier of arg 5 for select. */
+#cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
+
+/* Define to the type of arg 1 for select. */
+#cmakedefine SELECT_TYPE_ARG1 ${SELECT_TYPE_ARG1}
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#cmakedefine SELECT_TYPE_ARG234 ${SELECT_TYPE_ARG234}
+
+/* Define to the type of arg 5 for select. */
+#cmakedefine SELECT_TYPE_ARG5 ${SELECT_TYPE_ARG5}
+
+/* Define to the function return type for select. */
+#cmakedefine SELECT_TYPE_RETV ${SELECT_TYPE_RETV}
+
+/* Define to the type qualifier of arg 2 for send. */
+#cmakedefine SEND_QUAL_ARG2 ${SEND_QUAL_ARG2}
+
+/* Define to the type of arg 1 for send. */
+#cmakedefine SEND_TYPE_ARG1 ${SEND_TYPE_ARG1}
+
+/* Define to the type of arg 2 for send. */
+#cmakedefine SEND_TYPE_ARG2 ${SEND_TYPE_ARG2}
+
+/* Define to the type of arg 3 for send. */
+#cmakedefine SEND_TYPE_ARG3 ${SEND_TYPE_ARG3}
+
+/* Define to the type of arg 4 for send. */
+#cmakedefine SEND_TYPE_ARG4 ${SEND_TYPE_ARG4}
+
+/* Define to the function return type for send. */
+#cmakedefine SEND_TYPE_RETV ${SEND_TYPE_RETV}
+
+/* The size of `int', as computed by sizeof. */
+@SIZEOF_INT_CODE@
+
+/* The size of `short', as computed by sizeof. */
+@SIZEOF_SHORT_CODE@
+
+/* The size of `long', as computed by sizeof. */
+@SIZEOF_LONG_CODE@
+
+/* The size of `off_t', as computed by sizeof. */
+@SIZEOF_OFF_T_CODE@
+
+/* The size of `size_t', as computed by sizeof. */
+@SIZEOF_SIZE_T_CODE@
+
+/* The size of `ssize_t', as computed by sizeof. */
+@SIZEOF_SSIZE_T_CODE@
+
+/* The size of `time_t', as computed by sizeof. */
+@SIZEOF_TIME_T_CODE@
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+#cmakedefine STRERROR_R_TYPE_ARG3 ${STRERROR_R_TYPE_ARG3}
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#cmakedefine TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+#cmakedefine USE_ARES 1
+
+/* Define if you want to enable POSIX threaded DNS lookup */
+#cmakedefine USE_THREADS_POSIX 1
+
+/* Define if you want to enable WIN32 threaded DNS lookup */
+#cmakedefine USE_THREADS_WIN32 1
+
+/* Define to disable non-blocking sockets. */
+#cmakedefine USE_BLOCKING_SOCKETS 1
+
+/* if GnuTLS is enabled */
+#cmakedefine USE_GNUTLS 1
+
+/* if PolarSSL is enabled */
+#cmakedefine USE_POLARSSL 1
+
+/* if DarwinSSL is enabled */
+#cmakedefine USE_DARWINSSL 1
+
+/* if mbedTLS is enabled */
+#cmakedefine USE_MBEDTLS 1
+
+/* if libSSH2 is in use */
+#cmakedefine USE_LIBSSH2 1
+
+/* If you want to build curl with the built-in manual */
+#cmakedefine USE_MANUAL 1
+
+/* if NSS is enabled */
+#cmakedefine USE_NSS 1
+
+/* if you want to use OpenLDAP code instead of legacy ldap implementation */
+#cmakedefine USE_OPENLDAP 1
+
+/* if OpenSSL is in use */
+#cmakedefine USE_OPENSSL 1
+
+/* to enable NGHTTP2 */
+#cmakedefine USE_NGHTTP2 1
+
+/* if Unix domain sockets are enabled */
+#cmakedefine USE_UNIX_SOCKETS
+
+/* to enable SSPI support */
+#cmakedefine USE_WINDOWS_SSPI 1
+
+/* to enable Windows SSL */
+#cmakedefine USE_SCHANNEL 1
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+#cmakedefine USE_YASSLEMUL 1
+
+/* Version number of package */
+#cmakedefine VERSION ${VERSION}
+
+/* Define to avoid automatic inclusion of winsock.h */
+#cmakedefine WIN32_LEAN_AND_MEAN 1
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
+
+/* Define for large files, on AIX-style hosts. */
+#cmakedefine _LARGE_FILES ${_LARGE_FILES}
+
+/* define this if you need it to compile thread-safe code */
+#cmakedefine _THREAD_SAFE ${_THREAD_SAFE}
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#cmakedefine const ${const}
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+#cmakedefine in_addr_t ${in_addr_t}
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+#undef inline
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#cmakedefine size_t ${size_t}
+
+/* the signed version of size_t */
+#ifndef SIZEOF_SSIZE_T
+# if SIZEOF_LONG == SIZEOF_SIZE_T
+ typedef long ssize_t;
+# elif SIZEOF_LONG_LONG == SIZEOF_SIZE_T
+ typedef long long ssize_t;
+# elif SIZEOF___INT64 == SIZEOF_SIZE_T
+ typedef __int64 ssize_t;
+# else
+ typedef int ssize_t;
+# endif
+#endif
diff --git a/Utilities/cmcurl/lib/curl_des.c b/Utilities/cmcurl/lib/curl_des.c
new file mode 100644
index 000000000..b123a00f0
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_des.c
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM) && !defined(USE_OPENSSL)
+
+#include "curl_des.h"
+
+/*
+ * Curl_des_set_odd_parity()
+ *
+ * This is used to apply odd parity to the given byte array. It is typically
+ * used by when a cryptography engines doesn't have it's own version.
+ *
+ * The function is a port of the Java based oddParity() function over at:
+ *
+ * https://davenport.sourceforge.io/ntlm.html
+ *
+ * Parameters:
+ *
+ * bytes [in/out] - The data whose parity bits are to be adjusted for
+ * odd parity.
+ * len [out] - The length of the data.
+ */
+void Curl_des_set_odd_parity(unsigned char *bytes, size_t len)
+{
+ size_t i;
+
+ for(i = 0; i < len; i++) {
+ unsigned char b = bytes[i];
+
+ bool needs_parity = (((b >> 7) ^ (b >> 6) ^ (b >> 5) ^
+ (b >> 4) ^ (b >> 3) ^ (b >> 2) ^
+ (b >> 1)) & 0x01) == 0;
+
+ if(needs_parity)
+ bytes[i] |= 0x01;
+ else
+ bytes[i] &= 0xfe;
+ }
+}
+
+#endif /* USE_NTLM && !USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/curl_des.h b/Utilities/cmcurl/lib/curl_des.h
new file mode 100644
index 000000000..129060ff7
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_des.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_DES_H
+#define HEADER_CURL_DES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2015, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM) && !defined(USE_OPENSSL)
+
+/* Applies odd parity to the given byte array */
+void Curl_des_set_odd_parity(unsigned char *bytes, size_t length);
+
+#endif /* USE_NTLM && !USE_OPENSSL */
+
+#endif /* HEADER_CURL_DES_H */
diff --git a/Utilities/cmcurl/lib/curl_endian.c b/Utilities/cmcurl/lib/curl_endian.c
new file mode 100644
index 000000000..c25db4956
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_endian.c
@@ -0,0 +1,124 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "curl_endian.h"
+
+/*
+ * Curl_read16_le()
+ *
+ * This function converts a 16-bit integer from the little endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf [in] - A pointer to a 2 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned short Curl_read16_le(const unsigned char *buf)
+{
+ return (unsigned short)(((unsigned short)buf[0]) |
+ ((unsigned short)buf[1] << 8));
+}
+
+/*
+ * Curl_read32_le()
+ *
+ * This function converts a 32-bit integer from the little endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf [in] - A pointer to a 4 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned int Curl_read32_le(const unsigned char *buf)
+{
+ return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
+ ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
+}
+
+/*
+ * Curl_read16_be()
+ *
+ * This function converts a 16-bit integer from the big endian format, as
+ * used in the incoming package to whatever endian format we're using
+ * natively.
+ *
+ * Parameters:
+ *
+ * buf [in] - A pointer to a 2 byte buffer.
+ *
+ * Returns the integer.
+ */
+unsigned short Curl_read16_be(const unsigned char *buf)
+{
+ return (unsigned short)(((unsigned short)buf[0] << 8) |
+ ((unsigned short)buf[1]));
+}
+
+/*
+ * Curl_write32_le()
+ *
+ * This function converts a 32-bit integer from the native endian format,
+ * to little endian format ready for sending down the wire.
+ *
+ * Parameters:
+ *
+ * value [in] - The 32-bit integer value.
+ * buffer [in] - A pointer to the output buffer.
+ */
+void Curl_write32_le(const int value, unsigned char *buffer)
+{
+ buffer[0] = (char)(value & 0x000000FF);
+ buffer[1] = (char)((value & 0x0000FF00) >> 8);
+ buffer[2] = (char)((value & 0x00FF0000) >> 16);
+ buffer[3] = (char)((value & 0xFF000000) >> 24);
+}
+
+#if (CURL_SIZEOF_CURL_OFF_T > 4)
+/*
+ * Curl_write64_le()
+ *
+ * This function converts a 64-bit integer from the native endian format,
+ * to little endian format ready for sending down the wire.
+ *
+ * Parameters:
+ *
+ * value [in] - The 64-bit integer value.
+ * buffer [in] - A pointer to the output buffer.
+ */
+#if defined(HAVE_LONGLONG)
+void Curl_write64_le(const long long value, unsigned char *buffer)
+#else
+void Curl_write64_le(const __int64 value, unsigned char *buffer)
+#endif
+{
+ Curl_write32_le((int)value, buffer);
+ Curl_write32_le((int)(value >> 32), buffer + 4);
+}
+#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */
diff --git a/Utilities/cmcurl/lib/curl_endian.h b/Utilities/cmcurl/lib/curl_endian.h
new file mode 100644
index 000000000..4f345a6a2
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_endian.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_ENDIAN_H
+#define HEADER_CURL_ENDIAN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Converts a 16-bit integer from little endian */
+unsigned short Curl_read16_le(const unsigned char *buf);
+
+/* Converts a 32-bit integer from little endian */
+unsigned int Curl_read32_le(const unsigned char *buf);
+
+/* Converts a 16-bit integer from big endian */
+unsigned short Curl_read16_be(const unsigned char *buf);
+
+/* Converts a 32-bit integer to little endian */
+void Curl_write32_le(const int value, unsigned char *buffer);
+
+#if (CURL_SIZEOF_CURL_OFF_T > 4)
+/* Converts a 64-bit integer to little endian */
+#if defined(HAVE_LONGLONG)
+void Curl_write64_le(const long long value, unsigned char *buffer);
+#else
+void Curl_write64_le(const __int64 value, unsigned char *buffer);
+#endif
+#endif
+
+#endif /* HEADER_CURL_ENDIAN_H */
diff --git a/Utilities/cmcurl/lib/curl_fnmatch.c b/Utilities/cmcurl/lib/curl_fnmatch.c
new file mode 100644
index 000000000..46d3ada1e
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_fnmatch.c
@@ -0,0 +1,424 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "curl_fnmatch.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
+#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
+
+#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
+
+#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
+#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
+#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
+#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
+#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
+#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
+#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
+#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
+#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
+#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
+
+typedef enum {
+ CURLFNM_LOOP_DEFAULT = 0,
+ CURLFNM_LOOP_BACKSLASH
+} loop_state;
+
+typedef enum {
+ CURLFNM_SCHS_DEFAULT = 0,
+ CURLFNM_SCHS_MAYRANGE,
+ CURLFNM_SCHS_MAYRANGE2,
+ CURLFNM_SCHS_RIGHTBR,
+ CURLFNM_SCHS_RIGHTBRLEFTBR
+} setcharset_state;
+
+typedef enum {
+ CURLFNM_PKW_INIT = 0,
+ CURLFNM_PKW_DDOT
+} parsekey_state;
+
+#define SETCHARSET_OK 1
+#define SETCHARSET_FAIL 0
+
+static int parsekeyword(unsigned char **pattern, unsigned char *charset)
+{
+ parsekey_state state = CURLFNM_PKW_INIT;
+#define KEYLEN 10
+ char keyword[KEYLEN] = { 0 };
+ int found = FALSE;
+ int i;
+ unsigned char *p = *pattern;
+ for(i = 0; !found; i++) {
+ char c = *p++;
+ if(i >= KEYLEN)
+ return SETCHARSET_FAIL;
+ switch(state) {
+ case CURLFNM_PKW_INIT:
+ if(ISALPHA(c) && ISLOWER(c))
+ keyword[i] = c;
+ else if(c == ':')
+ state = CURLFNM_PKW_DDOT;
+ else
+ return 0;
+ break;
+ case CURLFNM_PKW_DDOT:
+ if(c == ']')
+ found = TRUE;
+ else
+ return SETCHARSET_FAIL;
+ }
+ }
+#undef KEYLEN
+
+ *pattern = p; /* move caller's pattern pointer */
+ if(strcmp(keyword, "digit") == 0)
+ charset[CURLFNM_DIGIT] = 1;
+ else if(strcmp(keyword, "alnum") == 0)
+ charset[CURLFNM_ALNUM] = 1;
+ else if(strcmp(keyword, "alpha") == 0)
+ charset[CURLFNM_ALPHA] = 1;
+ else if(strcmp(keyword, "xdigit") == 0)
+ charset[CURLFNM_XDIGIT] = 1;
+ else if(strcmp(keyword, "print") == 0)
+ charset[CURLFNM_PRINT] = 1;
+ else if(strcmp(keyword, "graph") == 0)
+ charset[CURLFNM_GRAPH] = 1;
+ else if(strcmp(keyword, "space") == 0)
+ charset[CURLFNM_SPACE] = 1;
+ else if(strcmp(keyword, "blank") == 0)
+ charset[CURLFNM_BLANK] = 1;
+ else if(strcmp(keyword, "upper") == 0)
+ charset[CURLFNM_UPPER] = 1;
+ else if(strcmp(keyword, "lower") == 0)
+ charset[CURLFNM_LOWER] = 1;
+ else
+ return SETCHARSET_FAIL;
+ return SETCHARSET_OK;
+}
+
+/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
+static int setcharset(unsigned char **p, unsigned char *charset)
+{
+ setcharset_state state = CURLFNM_SCHS_DEFAULT;
+ unsigned char rangestart = 0;
+ unsigned char lastchar = 0;
+ bool something_found = FALSE;
+ unsigned char c;
+ for(;;) {
+ c = **p;
+ switch(state) {
+ case CURLFNM_SCHS_DEFAULT:
+ if(ISALNUM(c)) { /* ASCII value */
+ rangestart = c;
+ charset[c] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_MAYRANGE;
+ something_found = TRUE;
+ }
+ else if(c == ']') {
+ if(something_found)
+ return SETCHARSET_OK;
+ something_found = TRUE;
+ state = CURLFNM_SCHS_RIGHTBR;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '[') {
+ char c2 = *((*p)+1);
+ if(c2 == ':') { /* there has to be a keyword */
+ (*p) += 2;
+ if(parsekeyword(p, charset)) {
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else {
+ charset[c] = 1;
+ (*p)++;
+ }
+ something_found = TRUE;
+ }
+ else if(c == '?' || c == '*') {
+ something_found = TRUE;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '^' || c == '!') {
+ if(!something_found) {
+ if(charset[CURLFNM_NEGATE]) {
+ charset[c] = 1;
+ something_found = TRUE;
+ }
+ else
+ charset[CURLFNM_NEGATE] = 1; /* negate charset */
+ }
+ else
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT((c))) {
+ something_found = TRUE;
+ state = CURLFNM_SCHS_MAYRANGE;
+ charset[c] = 1;
+ rangestart = c;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else if(c == '\0') {
+ return SETCHARSET_FAIL;
+ }
+ else {
+ charset[c] = 1;
+ (*p)++;
+ something_found = TRUE;
+ }
+ break;
+ case CURLFNM_SCHS_MAYRANGE:
+ if(c == '-') {
+ charset[c] = 1;
+ (*p)++;
+ lastchar = '-';
+ state = CURLFNM_SCHS_MAYRANGE2;
+ }
+ else if(c == '[') {
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else if(ISALNUM(c)) {
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT(c)) {
+ charset[c] = 1;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else
+ return SETCHARSET_FAIL;
+ break;
+ case CURLFNM_SCHS_MAYRANGE2:
+ if(c == '\\') {
+ c = *(++(*p));
+ if(!ISPRINT(c))
+ return SETCHARSET_FAIL;
+ }
+ if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT(c)) {
+ charset[c] = 1;
+ state = CURLFNM_SCHS_DEFAULT;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ if(c >= rangestart) {
+ if((ISLOWER(c) && ISLOWER(rangestart)) ||
+ (ISDIGIT(c) && ISDIGIT(rangestart)) ||
+ (ISUPPER(c) && ISUPPER(rangestart))) {
+ charset[lastchar] = 0;
+ rangestart++;
+ while(rangestart++ <= c)
+ charset[rangestart-1] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ break;
+ case CURLFNM_SCHS_RIGHTBR:
+ if(c == '[') {
+ state = CURLFNM_SCHS_RIGHTBRLEFTBR;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else if(c == '\0') {
+ return SETCHARSET_FAIL;
+ }
+ else if(ISPRINT(c)) {
+ charset[c] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
+ * nonsense warning 'statement not reached' at end of the fnc when
+ * compiling on Solaris */
+ goto fail;
+ break;
+ case CURLFNM_SCHS_RIGHTBRLEFTBR:
+ if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else {
+ state = CURLFNM_SCHS_DEFAULT;
+ charset[c] = 1;
+ (*p)++;
+ }
+ break;
+ }
+ }
+fail:
+ return SETCHARSET_FAIL;
+}
+
+static int loop(const unsigned char *pattern, const unsigned char *string)
+{
+ loop_state state = CURLFNM_LOOP_DEFAULT;
+ unsigned char *p = (unsigned char *)pattern;
+ unsigned char *s = (unsigned char *)string;
+ unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
+ int rc = 0;
+
+ for(;;) {
+ switch(state) {
+ case CURLFNM_LOOP_DEFAULT:
+ if(*p == '*') {
+ while(*(p+1) == '*') /* eliminate multiple stars */
+ p++;
+ if(*s == '\0' && *(p+1) == '\0')
+ return CURL_FNMATCH_MATCH;
+ rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
+ if(rc == CURL_FNMATCH_MATCH)
+ return CURL_FNMATCH_MATCH;
+ if(*s) /* let the star eat up one character */
+ s++;
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else if(*p == '?') {
+ if(ISPRINT(*s)) {
+ s++;
+ p++;
+ }
+ else if(*s == '\0')
+ return CURL_FNMATCH_NOMATCH;
+ else
+ return CURL_FNMATCH_FAIL; /* cannot deal with other character */
+ }
+ else if(*p == '\0') {
+ if(*s == '\0')
+ return CURL_FNMATCH_MATCH;
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else if(*p == '\\') {
+ state = CURLFNM_LOOP_BACKSLASH;
+ p++;
+ }
+ else if(*p == '[') {
+ unsigned char *pp = p+1; /* cannot handle with pointer to register */
+ if(setcharset(&pp, charset)) {
+ int found = FALSE;
+ if(charset[(unsigned int)*s])
+ found = TRUE;
+ else if(charset[CURLFNM_ALNUM])
+ found = ISALNUM(*s);
+ else if(charset[CURLFNM_ALPHA])
+ found = ISALPHA(*s);
+ else if(charset[CURLFNM_DIGIT])
+ found = ISDIGIT(*s);
+ else if(charset[CURLFNM_XDIGIT])
+ found = ISXDIGIT(*s);
+ else if(charset[CURLFNM_PRINT])
+ found = ISPRINT(*s);
+ else if(charset[CURLFNM_SPACE])
+ found = ISSPACE(*s);
+ else if(charset[CURLFNM_UPPER])
+ found = ISUPPER(*s);
+ else if(charset[CURLFNM_LOWER])
+ found = ISLOWER(*s);
+ else if(charset[CURLFNM_BLANK])
+ found = ISBLANK(*s);
+ else if(charset[CURLFNM_GRAPH])
+ found = ISGRAPH(*s);
+
+ if(charset[CURLFNM_NEGATE])
+ found = !found;
+
+ if(found) {
+ p = pp+1;
+ s++;
+ memset(charset, 0, CURLFNM_CHSET_SIZE);
+ }
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else
+ return CURL_FNMATCH_FAIL;
+ }
+ else {
+ if(*p++ != *s++)
+ return CURL_FNMATCH_NOMATCH;
+ }
+ break;
+ case CURLFNM_LOOP_BACKSLASH:
+ if(ISPRINT(*p)) {
+ if(*p++ == *s++)
+ state = CURLFNM_LOOP_DEFAULT;
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else
+ return CURL_FNMATCH_FAIL;
+ break;
+ }
+ }
+}
+
+/*
+ * @unittest: 1307
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
+{
+ (void)ptr; /* the argument is specified by the curl_fnmatch_callback
+ prototype, but not used by Curl_fnmatch() */
+ if(!pattern || !string) {
+ return CURL_FNMATCH_FAIL;
+ }
+ return loop((unsigned char *)pattern, (unsigned char *)string);
+}
diff --git a/Utilities/cmcurl/lib/curl_fnmatch.h b/Utilities/cmcurl/lib/curl_fnmatch.h
new file mode 100644
index 000000000..69ffe392f
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_fnmatch.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_FNMATCH_H
+#define HEADER_CURL_FNMATCH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#define CURL_FNMATCH_MATCH 0
+#define CURL_FNMATCH_NOMATCH 1
+#define CURL_FNMATCH_FAIL 2
+
+/* default pattern matching function
+ * =================================
+ * Implemented with recursive backtracking, if you want to use Curl_fnmatch,
+ * please note that there is not implemented UTF/UNICODE support.
+ *
+ * Implemented features:
+ * '?' notation, does not match UTF characters
+ * '*' can also work with UTF string
+ * [a-zA-Z0-9] enumeration support
+ *
+ * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space
+ * and upper (use as "[[:alnum:]]")
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string);
+
+#endif /* HEADER_CURL_FNMATCH_H */
diff --git a/Utilities/cmcurl/lib/curl_gethostname.c b/Utilities/cmcurl/lib/curl_gethostname.c
new file mode 100644
index 000000000..8337c72e8
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_gethostname.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "curl_gethostname.h"
+
+/*
+ * Curl_gethostname() is a wrapper around gethostname() which allows
+ * overriding the host name that the function would normally return.
+ * This capability is used by the test suite to verify exact matching
+ * of NTLM authentication, which exercises libcurl's MD4 and DES code
+ * as well as by the SMTP module when a hostname is not provided.
+ *
+ * For libcurl debug enabled builds host name overriding takes place
+ * when environment variable CURL_GETHOSTNAME is set, using the value
+ * held by the variable to override returned host name.
+ *
+ * Note: The function always returns the un-qualified hostname rather
+ * than being provider dependent.
+ *
+ * For libcurl shared library release builds the test suite preloads
+ * another shared library named libhostname using the LD_PRELOAD
+ * mechanism which intercepts, and might override, the gethostname()
+ * function call. In this case a given platform must support the
+ * LD_PRELOAD mechanism and additionally have environment variable
+ * CURL_GETHOSTNAME set in order to override the returned host name.
+ *
+ * For libcurl static library release builds no overriding takes place.
+ */
+
+int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen)
+{
+#ifndef HAVE_GETHOSTNAME
+
+ /* Allow compilation and return failure when unavailable */
+ (void) name;
+ (void) namelen;
+ return -1;
+
+#else
+ int err;
+ char *dot;
+
+#ifdef DEBUGBUILD
+
+ /* Override host name when environment variable CURL_GETHOSTNAME is set */
+ const char *force_hostname = getenv("CURL_GETHOSTNAME");
+ if(force_hostname) {
+ strncpy(name, force_hostname, namelen);
+ err = 0;
+ }
+ else {
+ name[0] = '\0';
+ err = gethostname(name, namelen);
+ }
+
+#else /* DEBUGBUILD */
+
+ /* The call to system's gethostname() might get intercepted by the
+ libhostname library when libcurl is built as a non-debug shared
+ library when running the test suite. */
+ name[0] = '\0';
+ err = gethostname(name, namelen);
+
+#endif
+
+ name[namelen - 1] = '\0';
+
+ if(err)
+ return err;
+
+ /* Truncate domain, leave only machine name */
+ dot = strchr(name, '.');
+ if(dot)
+ *dot = '\0';
+
+ return 0;
+#endif
+
+}
diff --git a/Utilities/cmcurl/lib/curl_gethostname.h b/Utilities/cmcurl/lib/curl_gethostname.h
new file mode 100644
index 000000000..07517c535
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_gethostname.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_GETHOSTNAME_H
+#define HEADER_CURL_GETHOSTNAME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Hostname buffer size */
+#define HOSTNAME_MAX 1024
+
+/* This returns the local machine's un-qualified hostname */
+int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen);
+
+#endif /* HEADER_CURL_GETHOSTNAME_H */
diff --git a/Utilities/cmcurl/lib/curl_gssapi.c b/Utilities/cmcurl/lib/curl_gssapi.c
new file mode 100644
index 000000000..83f3fa0c4
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_gssapi.c
@@ -0,0 +1,131 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_GSSAPI
+
+#include "curl_gssapi.h"
+#include "sendf.h"
+
+static char spnego_oid_bytes[] = "\x2b\x06\x01\x05\x05\x02";
+gss_OID_desc Curl_spnego_mech_oid = { 6, &spnego_oid_bytes };
+static char krb5_oid_bytes[] = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02";
+gss_OID_desc Curl_krb5_mech_oid = { 9, &krb5_oid_bytes };
+
+OM_uint32 Curl_gss_init_sec_context(
+ struct Curl_easy *data,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_buffer_t output_token,
+ const bool mutual_auth,
+ OM_uint32 *ret_flags)
+{
+ OM_uint32 req_flags = GSS_C_REPLAY_FLAG;
+
+ if(mutual_auth)
+ req_flags |= GSS_C_MUTUAL_FLAG;
+
+ if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) {
+#ifdef GSS_C_DELEG_POLICY_FLAG
+ req_flags |= GSS_C_DELEG_POLICY_FLAG;
+#else
+ infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
+ "compiled in\n");
+#endif
+ }
+
+ if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
+ req_flags |= GSS_C_DELEG_FLAG;
+
+ return gss_init_sec_context(minor_status,
+ GSS_C_NO_CREDENTIAL, /* cred_handle */
+ context,
+ target_name,
+ mech_type,
+ req_flags,
+ 0, /* time_req */
+ input_chan_bindings,
+ input_token,
+ NULL, /* actual_mech_type */
+ output_token,
+ ret_flags,
+ NULL /* time_rec */);
+}
+
+#define GSS_LOG_BUFFER_LEN 1024
+static size_t display_gss_error(OM_uint32 status, int type,
+ char *buf, size_t len) {
+ OM_uint32 maj_stat;
+ OM_uint32 min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+
+ do {
+ maj_stat = gss_display_status(&min_stat,
+ status,
+ type,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &status_string);
+ if(GSS_LOG_BUFFER_LEN > len + status_string.length + 3) {
+ len += snprintf(buf + len, GSS_LOG_BUFFER_LEN - len,
+ "%.*s. ", (int)status_string.length,
+ (char *)status_string.value);
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ } while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
+
+ return len;
+}
+
+/*
+ * Curl_gss_log_error()
+ *
+ * This is used to log a GSS-API error status.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * prefix [in] - The prefix of the log message.
+ * major [in] - The major status code.
+ * minor [in] - The minor status code.
+ */
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+ OM_uint32 major, OM_uint32 minor)
+{
+ char buf[GSS_LOG_BUFFER_LEN];
+ size_t len = 0;
+
+ if(major != GSS_S_FAILURE)
+ len = display_gss_error(major, GSS_C_GSS_CODE, buf, len);
+
+ display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
+
+ infof(data, "%s%s\n", prefix, buf);
+}
+
+#endif /* HAVE_GSSAPI */
diff --git a/Utilities/cmcurl/lib/curl_gssapi.h b/Utilities/cmcurl/lib/curl_gssapi.h
new file mode 100644
index 000000000..9700a2817
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_gssapi.h
@@ -0,0 +1,75 @@
+#ifndef HEADER_CURL_GSSAPI_H
+#define HEADER_CURL_GSSAPI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2011 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_GSSGNU
+# include <gss.h>
+#elif defined HAVE_GSSMIT
+ /* MIT style */
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_generic.h>
+# include <gssapi/gssapi_krb5.h>
+#else
+ /* Heimdal-style */
+# include <gssapi.h>
+#endif
+
+extern gss_OID_desc Curl_spnego_mech_oid;
+extern gss_OID_desc Curl_krb5_mech_oid;
+
+/* Common method for using GSS-API */
+OM_uint32 Curl_gss_init_sec_context(
+ struct Curl_easy *data,
+ OM_uint32 *minor_status,
+ gss_ctx_id_t *context,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_buffer_t output_token,
+ const bool mutual_auth,
+ OM_uint32 *ret_flags);
+
+/* Helper to log a GSS-API error status */
+void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
+ OM_uint32 major, OM_uint32 minor);
+
+/* Provide some definitions missing in old headers */
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#define NCOMPAT 1
+#endif
+
+/* Define our privacy and integrity protection values */
+#define GSSAUTH_P_NONE 1
+#define GSSAUTH_P_INTEGRITY 2
+#define GSSAUTH_P_PRIVACY 4
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* HEADER_CURL_GSSAPI_H */
diff --git a/Utilities/cmcurl/lib/curl_hmac.h b/Utilities/cmcurl/lib/curl_hmac.h
new file mode 100644
index 000000000..756dc9e4c
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_hmac.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_HMAC_H
+#define HEADER_CURL_HMAC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+typedef void (* HMAC_hinit_func)(void *context);
+typedef void (* HMAC_hupdate_func)(void *context,
+ const unsigned char *data,
+ unsigned int len);
+typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context);
+
+
+/* Per-hash function HMAC parameters. */
+
+typedef struct {
+ HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */
+ HMAC_hupdate_func hmac_hupdate; /* Update context with data. */
+ HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */
+ unsigned int hmac_ctxtsize; /* Context structure size. */
+ unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */
+ unsigned int hmac_resultlen; /* Result length (bytes). */
+} HMAC_params;
+
+
+/* HMAC computation context. */
+
+typedef struct {
+ const HMAC_params *hmac_hash; /* Hash function definition. */
+ void *hmac_hashctxt1; /* Hash function context 1. */
+ void *hmac_hashctxt2; /* Hash function context 2. */
+} HMAC_context;
+
+
+/* Prototypes. */
+
+HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams,
+ const unsigned char *key,
+ unsigned int keylen);
+int Curl_HMAC_update(HMAC_context *context,
+ const unsigned char *data,
+ unsigned int len);
+int Curl_HMAC_final(HMAC_context *context, unsigned char *result);
+
+#endif
+
+#endif /* HEADER_CURL_HMAC_H */
diff --git a/Utilities/cmcurl/lib/curl_ldap.h b/Utilities/cmcurl/lib/curl_ldap.h
new file mode 100644
index 000000000..27d03810f
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_ldap.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_LDAP_H
+#define HEADER_CURL_LDAP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_LDAP
+extern const struct Curl_handler Curl_handler_ldap;
+
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+extern const struct Curl_handler Curl_handler_ldaps;
+#endif
+
+#endif
+#endif /* HEADER_CURL_LDAP_H */
+
diff --git a/Utilities/cmcurl/lib/curl_md4.h b/Utilities/cmcurl/lib/curl_md4.h
new file mode 100644
index 000000000..e0690416d
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_md4.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_MD4_H
+#define HEADER_CURL_MD4_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
+ (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
+
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len);
+
+#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) ||
+ (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */
+
+#endif /* HEADER_CURL_MD4_H */
diff --git a/Utilities/cmcurl/lib/curl_md5.h b/Utilities/cmcurl/lib/curl_md5.h
new file mode 100644
index 000000000..5f70c9634
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_md5.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_MD5_H
+#define HEADER_CURL_MD5_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+#include "curl_hmac.h"
+
+#define MD5_DIGEST_LEN 16
+
+typedef void (* Curl_MD5_init_func)(void *context);
+typedef void (* Curl_MD5_update_func)(void *context,
+ const unsigned char *data,
+ unsigned int len);
+typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context);
+
+typedef struct {
+ Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
+ Curl_MD5_update_func md5_update_func; /* Update context with data */
+ Curl_MD5_final_func md5_final_func; /* Get final result procedure */
+ unsigned int md5_ctxtsize; /* Context structure size */
+ unsigned int md5_resultlen; /* Result length (bytes) */
+} MD5_params;
+
+typedef struct {
+ const MD5_params *md5_hash; /* Hash function definition */
+ void *md5_hashctx; /* Hash function context */
+} MD5_context;
+
+extern const MD5_params Curl_DIGEST_MD5[1];
+extern const HMAC_params Curl_HMAC_MD5[1];
+
+void Curl_md5it(unsigned char *output,
+ const unsigned char *input);
+
+MD5_context * Curl_MD5_init(const MD5_params *md5params);
+int Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len);
+int Curl_MD5_final(MD5_context *context, unsigned char *result);
+
+#endif
+
+#endif /* HEADER_CURL_MD5_H */
diff --git a/Utilities/cmcurl/lib/curl_memory.h b/Utilities/cmcurl/lib/curl_memory.h
new file mode 100644
index 000000000..fccf46879
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_memory.h
@@ -0,0 +1,156 @@
+#ifndef HEADER_CURL_MEMORY_H
+#define HEADER_CURL_MEMORY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Nasty internal details ahead...
+ *
+ * File curl_memory.h must be included by _all_ *.c source files
+ * that use memory related functions strdup, malloc, calloc, realloc
+ * or free, and given source file is used to build libcurl library.
+ * It should be included immediately before memdebug.h as the last files
+ * included to avoid undesired interaction with other memory function
+ * headers in dependent libraries.
+ *
+ * There is nearly no exception to above rule. All libcurl source
+ * files in 'lib' subdirectory as well as those living deep inside
+ * 'packages' subdirectories and linked together in order to build
+ * libcurl library shall follow it.
+ *
+ * File lib/strdup.c is an exception, given that it provides a strdup
+ * clone implementation while using malloc. Extra care needed inside
+ * this one. TODO: revisit this paragraph and related code.
+ *
+ * The need for curl_memory.h inclusion is due to libcurl's feature
+ * of allowing library user to provide memory replacement functions,
+ * memory callbacks, at runtime with curl_global_init_mem()
+ *
+ * Any *.c source file used to build libcurl library that does not
+ * include curl_memory.h and uses any memory function of the five
+ * mentioned above will compile without any indication, but it will
+ * trigger weird memory related issues at runtime.
+ *
+ * OTOH some source files from 'lib' subdirectory may additionally be
+ * used directly as source code when using some curlx_ functions by
+ * third party programs that don't even use libcurl at all. When using
+ * these source files in this way it is necessary these are compiled
+ * with CURLX_NO_MEMORY_CALLBACKS defined, in order to ensure that no
+ * attempt of calling libcurl's memory callbacks is done from code
+ * which can not use this machinery.
+ *
+ * Notice that libcurl's 'memory tracking' system works chaining into
+ * the memory callback machinery. This implies that when compiling
+ * 'lib' source files with CURLX_NO_MEMORY_CALLBACKS defined this file
+ * disengages usage of libcurl's 'memory tracking' system, defining
+ * MEMDEBUG_NODEFINES and overriding CURLDEBUG purpose.
+ *
+ * CURLX_NO_MEMORY_CALLBACKS takes precedence over CURLDEBUG. This is
+ * done in order to allow building a 'memory tracking' enabled libcurl
+ * and at the same time allow building programs which do not use it.
+ *
+ * Programs and libraries in 'tests' subdirectories have specific
+ * purposes and needs, and as such each one will use whatever fits
+ * best, depending additionally whether it links with libcurl or not.
+ *
+ * Caveat emptor. Proper curlx_* separation is a work in progress
+ * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may
+ * still be required. IOW don't use them yet, there are sharp edges.
+ */
+
+#ifdef HEADER_CURL_MEMDEBUG_H
+#error "Header memdebug.h shall not be included before curl_memory.h"
+#endif
+
+#ifndef CURLX_NO_MEMORY_CALLBACKS
+
+#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */
+/*
+ * The following memory function replacement typedef's are COPIED from
+ * curl/curl.h and MUST match the originals. We copy them to avoid having to
+ * include curl/curl.h here. We avoid that include since it includes stdio.h
+ * and other headers that may get messed up with defines done here.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+#define CURL_DID_MEMORY_FUNC_TYPEDEFS
+#endif
+
+extern curl_malloc_callback Curl_cmalloc;
+extern curl_free_callback Curl_cfree;
+extern curl_realloc_callback Curl_crealloc;
+extern curl_strdup_callback Curl_cstrdup;
+extern curl_calloc_callback Curl_ccalloc;
+#if defined(WIN32) && defined(UNICODE)
+extern curl_wcsdup_callback Curl_cwcsdup;
+#endif
+
+#ifndef CURLDEBUG
+
+/*
+ * libcurl's 'memory tracking' system defines strdup, malloc, calloc,
+ * realloc and free, along with others, in memdebug.h in a different
+ * way although still using memory callbacks forward declared above.
+ * When using the 'memory tracking' system (CURLDEBUG defined) we do
+ * not define here the five memory functions given that definitions
+ * from memdebug.h are the ones that shall be used.
+ */
+
+#undef strdup
+#define strdup(ptr) Curl_cstrdup(ptr)
+#undef malloc
+#define malloc(size) Curl_cmalloc(size)
+#undef calloc
+#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
+#undef realloc
+#define realloc(ptr,size) Curl_crealloc(ptr, size)
+#undef free
+#define free(ptr) Curl_cfree(ptr)
+
+#ifdef WIN32
+# ifdef UNICODE
+# undef wcsdup
+# define wcsdup(ptr) Curl_cwcsdup(ptr)
+# undef _wcsdup
+# define _wcsdup(ptr) Curl_cwcsdup(ptr)
+# undef _tcsdup
+# define _tcsdup(ptr) Curl_cwcsdup(ptr)
+# else
+# undef _tcsdup
+# define _tcsdup(ptr) Curl_cstrdup(ptr)
+# endif
+#endif
+
+#endif /* CURLDEBUG */
+
+#else /* CURLX_NO_MEMORY_CALLBACKS */
+
+#ifndef MEMDEBUG_NODEFINES
+#define MEMDEBUG_NODEFINES
+#endif
+
+#endif /* CURLX_NO_MEMORY_CALLBACKS */
+
+#endif /* HEADER_CURL_MEMORY_H */
diff --git a/Utilities/cmcurl/lib/curl_memrchr.c b/Utilities/cmcurl/lib/curl_memrchr.c
new file mode 100644
index 000000000..c521497b2
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_memrchr.c
@@ -0,0 +1,61 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "curl_memrchr.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_MEMRCHR
+
+/*
+ * Curl_memrchr()
+ *
+ * Our memrchr() function clone for systems which lack this function. The
+ * memrchr() function is like the memchr() function, except that it searches
+ * backwards from the end of the n bytes pointed to by s instead of forward
+ * from the beginning.
+ */
+
+void *
+Curl_memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *p = s;
+ const unsigned char *q = s;
+
+ p += n - 1;
+
+ while(p >= q) {
+ if(*p == (unsigned char)c)
+ return (void *)p;
+ p--;
+ }
+
+ return NULL;
+}
+
+#endif /* HAVE_MEMRCHR */
diff --git a/Utilities/cmcurl/lib/curl_memrchr.h b/Utilities/cmcurl/lib/curl_memrchr.h
new file mode 100644
index 000000000..747509c45
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_memrchr.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_MEMRCHR_H
+#define HEADER_CURL_MEMRCHR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_MEMRCHR
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#else /* HAVE_MEMRCHR */
+
+void *Curl_memrchr(const void *s, int c, size_t n);
+
+#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
+
+#endif /* HAVE_MEMRCHR */
+
+#endif /* HEADER_CURL_MEMRCHR_H */
diff --git a/Utilities/cmcurl/lib/curl_multibyte.c b/Utilities/cmcurl/lib/curl_multibyte.c
new file mode 100644
index 000000000..e78bb5002
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_multibyte.c
@@ -0,0 +1,84 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \
+ defined(USE_WIN32_LDAP)) && defined(UNICODE))
+
+ /*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+#include "curl_multibyte.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8)
+{
+ wchar_t *str_w = NULL;
+
+ if(str_utf8) {
+ int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+ str_utf8, -1, NULL, 0);
+ if(str_w_len > 0) {
+ str_w = malloc(str_w_len * sizeof(wchar_t));
+ if(str_w) {
+ if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
+ str_w_len) == 0) {
+ free(str_w);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return str_w;
+}
+
+char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w)
+{
+ char *str_utf8 = NULL;
+
+ if(str_w) {
+ int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
+ 0, NULL, NULL);
+ if(str_utf8_len > 0) {
+ str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
+ if(str_utf8) {
+ if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
+ NULL, FALSE) == 0) {
+ free(str_utf8);
+ return NULL;
+ }
+ }
+ }
+ }
+
+ return str_utf8;
+}
+
+#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */
diff --git a/Utilities/cmcurl/lib/curl_multibyte.h b/Utilities/cmcurl/lib/curl_multibyte.h
new file mode 100644
index 000000000..615f5c086
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_multibyte.h
@@ -0,0 +1,92 @@
+#ifndef HEADER_CURL_MULTIBYTE_H
+#define HEADER_CURL_MULTIBYTE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \
+ defined(USE_WIN32_LDAP)) && defined(UNICODE))
+
+ /*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8);
+char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w);
+
+#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */
+
+
+#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \
+ defined(USE_WIN32_LDAP)
+
+/*
+ * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8()
+ * and Curl_unicodefree() main purpose is to minimize the number of
+ * preprocessor conditional directives needed by code using these
+ * to differentiate UNICODE from non-UNICODE builds.
+ *
+ * When building with UNICODE defined, this two macros
+ * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
+ * return a pointer to a newly allocated memory area holding result.
+ * When the result is no longer needed, allocated memory is intended
+ * to be free'ed with Curl_unicodefree().
+ *
+ * When building without UNICODE defined, this macros
+ * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
+ * return the pointer received as argument. Curl_unicodefree() does
+ * no actual free'ing of this pointer it is simply set to NULL.
+ */
+
+#ifdef UNICODE
+
+#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr))
+#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr))
+#define Curl_unicodefree(ptr) \
+ do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE
+
+typedef union {
+ unsigned short *tchar_ptr;
+ const unsigned short *const_tchar_ptr;
+ unsigned short *tbyte_ptr;
+ const unsigned short *const_tbyte_ptr;
+} xcharp_u;
+
+#else
+
+#define Curl_convert_UTF8_to_tchar(ptr) (ptr)
+#define Curl_convert_tchar_to_UTF8(ptr) (ptr)
+#define Curl_unicodefree(ptr) \
+ do {(ptr) = NULL;} WHILE_FALSE
+
+typedef union {
+ char *tchar_ptr;
+ const char *const_tchar_ptr;
+ unsigned char *tbyte_ptr;
+ const unsigned char *const_tbyte_ptr;
+} xcharp_u;
+
+#endif /* UNICODE */
+
+#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */
+
+#endif /* HEADER_CURL_MULTIBYTE_H */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.c b/Utilities/cmcurl/lib/curl_ntlm_core.c
new file mode 100644
index 000000000..aea545295
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.c
@@ -0,0 +1,794 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.io/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
+
+#ifdef USE_OPENSSL
+
+# ifdef USE_OPENSSL
+# include <openssl/des.h>
+# ifndef OPENSSL_NO_MD4
+# include <openssl/md4.h>
+# endif
+# include <openssl/md5.h>
+# include <openssl/ssl.h>
+# include <openssl/rand.h>
+# else
+# include <des.h>
+# ifndef OPENSSL_NO_MD4
+# include <md4.h>
+# endif
+# include <md5.h>
+# include <ssl.h>
+# include <rand.h>
+# endif
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+# define DES_key_schedule des_key_schedule
+# define DES_cblock des_cblock
+# define DES_set_odd_parity des_set_odd_parity
+# define DES_set_key des_set_key
+# define DES_ecb_encrypt des_ecb_encrypt
+# define DESKEY(x) x
+# define DESKEYARG(x) x
+# else
+# define DESKEYARG(x) *x
+# define DESKEY(x) &x
+# endif
+
+#elif defined(USE_GNUTLS_NETTLE)
+
+# include <nettle/des.h>
+# include <nettle/md4.h>
+
+#elif defined(USE_GNUTLS)
+
+# include <gcrypt.h>
+# define MD5_DIGEST_LENGTH 16
+# define MD4_DIGEST_LENGTH 16
+
+#elif defined(USE_MBEDTLS)
+
+# include <mbedtls/des.h>
+# include <mbedtls/md4.h>
+# if !defined(MBEDTLS_MD4_C)
+# include "curl_md4.h"
+# endif
+
+#elif defined(USE_NSS)
+
+# include <nss.h>
+# include <pk11pub.h>
+# include <hasht.h>
+# include "curl_md4.h"
+# define MD5_DIGEST_LENGTH MD5_LENGTH
+
+#elif defined(USE_DARWINSSL)
+
+# include <CommonCrypto/CommonCryptor.h>
+# include <CommonCrypto/CommonDigest.h>
+
+#elif defined(USE_OS400CRYPTO)
+# include "cipher.mih" /* mih/cipher */
+# include "curl_md4.h"
+#elif defined(USE_WIN32_CRYPTO)
+# include <wincrypt.h>
+#else
+# error "Can't compile NTLM support without a crypto library."
+#endif
+
+#include "urldata.h"
+#include "non-ascii.h"
+#include "strcase.h"
+#include "curl_ntlm_core.h"
+#include "curl_md5.h"
+#include "curl_hmac.h"
+#include "warnless.h"
+#include "curl_endian.h"
+#include "curl_des.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define NTLM_HMAC_MD5_LEN (16)
+#define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00"
+#define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4)
+
+/*
+* Turns a 56-bit key into being 64-bit wide.
+*/
+static void extend_key_56_to_64(const unsigned char *key_56, char *key)
+{
+ key[0] = key_56[0];
+ key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+ key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+ key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+ key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+ key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+ key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+ key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+}
+
+#ifdef USE_OPENSSL
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(const unsigned char *key_56,
+ DES_key_schedule DESKEYARG(ks))
+{
+ DES_cblock key;
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, (char *) &key);
+
+ /* Set the key parity to odd */
+ DES_set_odd_parity(&key);
+
+ /* Set the key */
+ DES_set_key(&key, ks);
+}
+
+#elif defined(USE_GNUTLS_NETTLE)
+
+static void setup_des_key(const unsigned char *key_56,
+ struct des_ctx *des)
+{
+ char key[8];
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+ /* Set the key */
+ des_set_key(des, (const uint8_t *) key);
+}
+
+#elif defined(USE_GNUTLS)
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+ */
+static void setup_des_key(const unsigned char *key_56,
+ gcry_cipher_hd_t *des)
+{
+ char key[8];
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+ /* Set the key */
+ gcry_cipher_setkey(*des, key, sizeof(key));
+}
+
+#elif defined(USE_MBEDTLS)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ mbedtls_des_context ctx;
+ char key[8];
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ mbedtls_des_key_set_parity((unsigned char *) key);
+
+ /* Perform the encryption */
+ mbedtls_des_init(&ctx);
+ mbedtls_des_setkey_enc(&ctx, (unsigned char *) key);
+ return mbedtls_des_crypt_ecb(&ctx, in, out) == 0;
+}
+
+#elif defined(USE_NSS)
+
+/*
+ * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using
+ * the expanded key. The caller is responsible for giving 64 bit of valid
+ * data is IN and (at least) 64 bit large buffer as OUT.
+ */
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
+ PK11SlotInfo *slot = NULL;
+ char key[8]; /* expanded 64 bit key */
+ SECItem key_item;
+ PK11SymKey *symkey = NULL;
+ SECItem *param = NULL;
+ PK11Context *ctx = NULL;
+ int out_len; /* not used, required by NSS */
+ bool rv = FALSE;
+
+ /* use internal slot for DES encryption (requires NSS to be initialized) */
+ slot = PK11_GetInternalKeySlot();
+ if(!slot)
+ return FALSE;
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+ /* Import the key */
+ key_item.data = (unsigned char *)key;
+ key_item.len = sizeof(key);
+ symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT,
+ &key_item, NULL);
+ if(!symkey)
+ goto fail;
+
+ /* Create the DES encryption context */
+ param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL);
+ if(!param)
+ goto fail;
+ ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param);
+ if(!ctx)
+ goto fail;
+
+ /* Perform the encryption */
+ if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8,
+ (unsigned char *)in, /* inbuflen */ 8)
+ && SECSuccess == PK11_Finalize(ctx))
+ rv = /* all OK */ TRUE;
+
+fail:
+ /* cleanup */
+ if(ctx)
+ PK11_DestroyContext(ctx, PR_TRUE);
+ if(symkey)
+ PK11_FreeSymKey(symkey);
+ if(param)
+ SECITEM_FreeItem(param, PR_TRUE);
+ PK11_FreeSlot(slot);
+ return rv;
+}
+
+#elif defined(USE_DARWINSSL)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ char key[8];
+ size_t out_len;
+ CCCryptorStatus err;
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
+
+ /* Perform the encryption */
+ err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
+ kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out,
+ 8 /* outbuflen */, &out_len);
+
+ return err == kCCSuccess;
+}
+
+#elif defined(USE_OS400CRYPTO)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ char key[8];
+ _CIPHER_Control_T ctl;
+
+ /* Setup the cipher control structure */
+ ctl.Func_ID = ENCRYPT_ONLY;
+ ctl.Data_Len = sizeof(key);
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, ctl.Crypto_Key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) ctl.Crypto_Key, ctl.Data_Len);
+
+ /* Perform the encryption */
+ _CIPHER((_SPCPTR *) &out, &ctl, (_SPCPTR *) &in);
+
+ return TRUE;
+}
+
+#elif defined(USE_WIN32_CRYPTO)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ HCRYPTPROV hprov;
+ HCRYPTKEY hkey;
+ struct {
+ BLOBHEADER hdr;
+ unsigned int len;
+ char key[8];
+ } blob;
+ DWORD len = 8;
+
+ /* Acquire the crypto provider */
+ if(!CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return FALSE;
+
+ /* Setup the key blob structure */
+ memset(&blob, 0, sizeof(blob));
+ blob.hdr.bType = PLAINTEXTKEYBLOB;
+ blob.hdr.bVersion = 2;
+ blob.hdr.aiKeyAlg = CALG_DES;
+ blob.len = sizeof(blob.key);
+
+ /* Expand the 56-bit key to 64-bits */
+ extend_key_56_to_64(key_56, blob.key);
+
+ /* Set the key parity to odd */
+ Curl_des_set_odd_parity((unsigned char *) blob.key, sizeof(blob.key));
+
+ /* Import the key */
+ if(!CryptImportKey(hprov, (BYTE *) &blob, sizeof(blob), 0, 0, &hkey)) {
+ CryptReleaseContext(hprov, 0);
+
+ return FALSE;
+ }
+
+ memcpy(out, in, 8);
+
+ /* Perform the encryption */
+ CryptEncrypt(hkey, 0, FALSE, 0, out, &len, len);
+
+ CryptDestroyKey(hkey);
+ CryptReleaseContext(hprov, 0);
+
+ return TRUE;
+}
+
+#endif /* defined(USE_WIN32_CRYPTO) */
+
+ /*
+ * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+ * 8 byte plaintext is encrypted with each key and the resulting 24
+ * bytes are stored in the results array.
+ */
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+ const unsigned char *plaintext,
+ unsigned char *results)
+{
+#ifdef USE_OPENSSL
+ DES_key_schedule ks;
+
+ setup_des_key(keys, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys + 7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys + 14, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
+ DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct des_ctx des;
+ setup_des_key(keys, &des);
+ des_encrypt(&des, 8, results, plaintext);
+ setup_des_key(keys + 7, &des);
+ des_encrypt(&des, 8, results + 8, plaintext);
+ setup_des_key(keys + 14, &des);
+ des_encrypt(&des, 8, results + 16, plaintext);
+#elif defined(USE_GNUTLS)
+ gcry_cipher_hd_t des;
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys, &des);
+ gcry_cipher_encrypt(des, results, 8, plaintext, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys + 7, &des);
+ gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys + 14, &des);
+ gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
+ gcry_cipher_close(des);
+#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+ encrypt_des(plaintext, results, keys);
+ encrypt_des(plaintext, results + 8, keys + 7);
+ encrypt_des(plaintext, results + 16, keys + 14);
+#endif
+}
+
+/*
+ * Set up lanmanager hashed password
+ */
+CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
+ const char *password,
+ unsigned char *lmbuffer /* 21 bytes */)
+{
+ CURLcode result;
+ unsigned char pw[14];
+ static const unsigned char magic[] = {
+ 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
+ };
+ size_t len = CURLMIN(strlen(password), 14);
+
+ Curl_strntoupper((char *)pw, password, len);
+ memset(&pw[len], 0, 14 - len);
+
+ /*
+ * The LanManager hashed password needs to be created using the
+ * password in the network encoding not the host encoding.
+ */
+ result = Curl_convert_to_network(data, (char *)pw, 14);
+ if(result)
+ return result;
+
+ {
+ /* Create LanManager hashed password. */
+
+#ifdef USE_OPENSSL
+ DES_key_schedule ks;
+
+ setup_des_key(pw, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(pw + 7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
+ DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct des_ctx des;
+ setup_des_key(pw, &des);
+ des_encrypt(&des, 8, lmbuffer, magic);
+ setup_des_key(pw + 7, &des);
+ des_encrypt(&des, 8, lmbuffer + 8, magic);
+#elif defined(USE_GNUTLS)
+ gcry_cipher_hd_t des;
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(pw, &des);
+ gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(pw + 7, &des);
+ gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
+ gcry_cipher_close(des);
+#elif defined(USE_MBEDTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) \
+ || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
+ encrypt_des(magic, lmbuffer, pw);
+ encrypt_des(magic, lmbuffer + 8, pw + 7);
+#endif
+
+ memset(lmbuffer + 16, 0, 21 - 16);
+ }
+
+ return CURLE_OK;
+}
+
+#ifdef USE_NTRESPONSES
+static void ascii_to_unicode_le(unsigned char *dest, const char *src,
+ size_t srclen)
+{
+ size_t i;
+ for(i = 0; i < srclen; i++) {
+ dest[2 * i] = (unsigned char)src[i];
+ dest[2 * i + 1] = '\0';
+ }
+}
+
+#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+
+static void ascii_uppercase_to_unicode_le(unsigned char *dest,
+ const char *src, size_t srclen)
+{
+ size_t i;
+ for(i = 0; i < srclen; i++) {
+ dest[2 * i] = (unsigned char)(Curl_raw_toupper(src[i]));
+ dest[2 * i + 1] = '\0';
+ }
+}
+
+#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
+
+/*
+ * Set up nt hashed passwords
+ * @unittest: 1600
+ */
+CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
+ const char *password,
+ unsigned char *ntbuffer /* 21 bytes */)
+{
+ size_t len = strlen(password);
+ unsigned char *pw = malloc(len * 2);
+ CURLcode result;
+ if(!pw)
+ return CURLE_OUT_OF_MEMORY;
+
+ ascii_to_unicode_le(pw, password, len);
+
+ /*
+ * The NT hashed password needs to be created using the password in the
+ * network encoding not the host encoding.
+ */
+ result = Curl_convert_to_network(data, (char *)pw, len * 2);
+ if(result)
+ return result;
+
+ {
+ /* Create NT hashed password. */
+#ifdef USE_OPENSSL
+ MD4_CTX MD4pw;
+ MD4_Init(&MD4pw);
+ MD4_Update(&MD4pw, pw, 2 * len);
+ MD4_Final(ntbuffer, &MD4pw);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct md4_ctx MD4pw;
+ md4_init(&MD4pw);
+ md4_update(&MD4pw, (unsigned int)(2 * len), pw);
+ md4_digest(&MD4pw, MD4_DIGEST_SIZE, ntbuffer);
+#elif defined(USE_GNUTLS)
+ gcry_md_hd_t MD4pw;
+ gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
+ gcry_md_write(MD4pw, pw, 2 * len);
+ memcpy(ntbuffer, gcry_md_read(MD4pw, 0), MD4_DIGEST_LENGTH);
+ gcry_md_close(MD4pw);
+#elif defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
+ (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
+ Curl_md4it(ntbuffer, pw, 2 * len);
+#elif defined(USE_MBEDTLS)
+ mbedtls_md4(pw, 2 * len, ntbuffer);
+#elif defined(USE_DARWINSSL)
+ (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
+#elif defined(USE_WIN32_CRYPTO)
+ HCRYPTPROV hprov;
+ if(CryptAcquireContext(&hprov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ HCRYPTHASH hhash;
+ if(CryptCreateHash(hprov, CALG_MD4, 0, 0, &hhash)) {
+ DWORD length = 16;
+ CryptHashData(hhash, pw, (unsigned int)len * 2, 0);
+ CryptGetHashParam(hhash, HP_HASHVAL, ntbuffer, &length, 0);
+ CryptDestroyHash(hhash);
+ }
+ CryptReleaseContext(hprov, 0);
+ }
+#endif
+
+ memset(ntbuffer + 16, 0, 21 - 16);
+ }
+
+ free(pw);
+
+ return CURLE_OK;
+}
+
+#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+
+/* This returns the HMAC MD5 digest */
+CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
+ const unsigned char *data, unsigned int datalen,
+ unsigned char *output)
+{
+ HMAC_context *ctxt = Curl_HMAC_init(Curl_HMAC_MD5, key, keylen);
+
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Update the digest with the given challenge */
+ Curl_HMAC_update(ctxt, data, datalen);
+
+ /* Finalise the digest */
+ Curl_HMAC_final(ctxt, output);
+
+ return CURLE_OK;
+}
+
+/* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
+ * (uppercase UserName + Domain) as the data
+ */
+CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
+ const char *domain, size_t domlen,
+ unsigned char *ntlmhash,
+ unsigned char *ntlmv2hash)
+{
+ /* Unicode representation */
+ size_t identity_len = (userlen + domlen) * 2;
+ unsigned char *identity = malloc(identity_len);
+ CURLcode result = CURLE_OK;
+
+ if(!identity)
+ return CURLE_OUT_OF_MEMORY;
+
+ ascii_uppercase_to_unicode_le(identity, user, userlen);
+ ascii_to_unicode_le(identity + (userlen << 1), domain, domlen);
+
+ result = Curl_hmac_md5(ntlmhash, 16, identity, curlx_uztoui(identity_len),
+ ntlmv2hash);
+
+ free(identity);
+
+ return result;
+}
+
+/*
+ * Curl_ntlm_core_mk_ntlmv2_resp()
+ *
+ * This creates the NTLMv2 response as set in the ntlm type-3 message.
+ *
+ * Parameters:
+ *
+ * ntlmv2hash [in] - The ntlmv2 hash (16 bytes)
+ * challenge_client [in] - The client nonce (8 bytes)
+ * ntlm [in] - The ntlm data struct being used to read TargetInfo
+ and Server challenge received in the type-2 message
+ * ntresp [out] - The address where a pointer to newly allocated
+ * memory holding the NTLMv2 response.
+ * ntresp_len [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
+ unsigned char *challenge_client,
+ struct ntlmdata *ntlm,
+ unsigned char **ntresp,
+ unsigned int *ntresp_len)
+{
+/* NTLMv2 response structure :
+------------------------------------------------------------------------------
+0 HMAC MD5 16 bytes
+------BLOB--------------------------------------------------------------------
+16 Signature 0x01010000
+20 Reserved long (0x00000000)
+24 Timestamp LE, 64-bit signed value representing the number of
+ tenths of a microsecond since January 1, 1601.
+32 Client Nonce 8 bytes
+40 Unknown 4 bytes
+44 Target Info N bytes (from the type-2 message)
+44+N Unknown 4 bytes
+------------------------------------------------------------------------------
+*/
+
+ unsigned int len = 0;
+ unsigned char *ptr = NULL;
+ unsigned char hmac_output[NTLM_HMAC_MD5_LEN];
+ curl_off_t tw;
+
+ CURLcode result = CURLE_OK;
+
+#if CURL_SIZEOF_CURL_OFF_T < 8
+#error "this section needs 64bit support to work"
+#endif
+
+ /* Calculate the timestamp */
+#ifdef DEBUGBUILD
+ char *force_timestamp = getenv("CURL_FORCETIME");
+ if(force_timestamp)
+ tw = CURL_OFF_T_C(11644473600) * 10000000;
+ else
+#endif
+ tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000;
+
+ /* Calculate the response len */
+ len = NTLM_HMAC_MD5_LEN + NTLMv2_BLOB_LEN;
+
+ /* Allocate the response */
+ ptr = malloc(len);
+ if(!ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(ptr, 0, len);
+
+ /* Create the BLOB structure */
+ snprintf((char *)ptr + NTLM_HMAC_MD5_LEN, NTLMv2_BLOB_LEN,
+ "%c%c%c%c" /* NTLMv2_BLOB_SIGNATURE */
+ "%c%c%c%c", /* Reserved = 0 */
+ NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
+ NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
+ 0, 0, 0, 0);
+
+ Curl_write64_le(tw, ptr + 24);
+ memcpy(ptr + 32, challenge_client, 8);
+ memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
+
+ /* Concatenate the Type 2 challenge with the BLOB and do HMAC MD5 */
+ memcpy(ptr + 8, &ntlm->nonce[0], 8);
+ result = Curl_hmac_md5(ntlmv2hash, NTLM_HMAC_MD5_LEN, ptr + 8,
+ NTLMv2_BLOB_LEN + 8, hmac_output);
+ if(result) {
+ free(ptr);
+ return result;
+ }
+
+ /* Concatenate the HMAC MD5 output with the BLOB */
+ memcpy(ptr, hmac_output, NTLM_HMAC_MD5_LEN);
+
+ /* Return the response */
+ *ntresp = ptr;
+ *ntresp_len = len;
+
+ return result;
+}
+
+/*
+ * Curl_ntlm_core_mk_lmv2_resp()
+ *
+ * This creates the LMv2 response as used in the ntlm type-3 message.
+ *
+ * Parameters:
+ *
+ * ntlmv2hash [in] - The ntlmv2 hash (16 bytes)
+ * challenge_client [in] - The client nonce (8 bytes)
+ * challenge_client [in] - The server challenge (8 bytes)
+ * lmresp [out] - The LMv2 response (24 bytes)
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
+ unsigned char *challenge_client,
+ unsigned char *challenge_server,
+ unsigned char *lmresp)
+{
+ unsigned char data[16];
+ unsigned char hmac_output[16];
+ CURLcode result = CURLE_OK;
+
+ memcpy(&data[0], challenge_server, 8);
+ memcpy(&data[8], challenge_client, 8);
+
+ result = Curl_hmac_md5(ntlmv2hash, 16, &data[0], 16, hmac_output);
+ if(result)
+ return result;
+
+ /* Concatenate the HMAC MD5 output with the client nonce */
+ memcpy(lmresp, hmac_output, 16);
+ memcpy(lmresp+16, challenge_client, 8);
+
+ return result;
+}
+
+#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
+
+#endif /* USE_NTRESPONSES */
+
+#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
+
+#endif /* USE_NTLM */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_core.h b/Utilities/cmcurl/lib/curl_ntlm_core.h
new file mode 100644
index 000000000..4a83d40bc
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_ntlm_core.h
@@ -0,0 +1,101 @@
+#ifndef HEADER_CURL_NTLM_CORE_H
+#define HEADER_CURL_NTLM_CORE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM)
+
+#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
+
+#ifdef USE_OPENSSL
+# if !defined(OPENSSL_VERSION_NUMBER) && \
+ !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H)
+# error "curl_ntlm_core.h shall not be included before OpenSSL headers."
+# endif
+#endif
+
+/* Define USE_NTRESPONSES in order to make the type-3 message include
+ * the NT response message. */
+#if !defined(USE_OPENSSL) || !defined(OPENSSL_NO_MD4)
+#define USE_NTRESPONSES
+#endif
+
+/* Define USE_NTLM2SESSION in order to make the type-3 message include the
+ NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and a
+ Crypto engine that we have curl_ssl_md5sum() for. */
+#if defined(USE_NTRESPONSES) && !defined(USE_WIN32_CRYPTO)
+#define USE_NTLM2SESSION
+#endif
+
+/* Define USE_NTLM_V2 in order to allow the type-3 message to include the
+ LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1
+ and support for 64-bit integers. */
+#if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4)
+#define USE_NTLM_V2
+#endif
+
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+ const unsigned char *plaintext,
+ unsigned char *results);
+
+CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
+ const char *password,
+ unsigned char *lmbuffer /* 21 bytes */);
+
+#ifdef USE_NTRESPONSES
+CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
+ const char *password,
+ unsigned char *ntbuffer /* 21 bytes */);
+
+#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+
+CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
+ const unsigned char *data, unsigned int datalen,
+ unsigned char *output);
+
+CURLcode Curl_ntlm_core_mk_ntlmv2_hash(const char *user, size_t userlen,
+ const char *domain, size_t domlen,
+ unsigned char *ntlmhash,
+ unsigned char *ntlmv2hash);
+
+CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
+ unsigned char *challenge_client,
+ struct ntlmdata *ntlm,
+ unsigned char **ntresp,
+ unsigned int *ntresp_len);
+
+CURLcode Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
+ unsigned char *challenge_client,
+ unsigned char *challenge_server,
+ unsigned char *lmresp);
+
+#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
+
+#endif /* USE_NTRESPONSES */
+
+#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
+
+#endif /* USE_NTLM */
+
+#endif /* HEADER_CURL_NTLM_CORE_H */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.c b/Utilities/cmcurl/lib/curl_ntlm_wb.c
new file mode 100644
index 000000000..9f5b87bc3
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.c
@@ -0,0 +1,431 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.io/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "vauth/ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "url.h"
+#include "strerror.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
+ to avoid fooling the socket leak detector */
+#if defined(HAVE_CLOSESOCKET)
+# define sclose_nolog(x) closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+# define sclose_nolog(x) CloseSocket((x))
+#else
+# define sclose_nolog(x) close((x))
+#endif
+
+void Curl_ntlm_wb_cleanup(struct connectdata *conn)
+{
+ if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
+ sclose(conn->ntlm_auth_hlpr_socket);
+ conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ }
+
+ if(conn->ntlm_auth_hlpr_pid) {
+ int i;
+ for(i = 0; i < 4; i++) {
+ pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
+ if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
+ break;
+ switch(i) {
+ case 0:
+ kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
+ break;
+ case 1:
+ /* Give the process another moment to shut down cleanly before
+ bringing down the axe */
+ Curl_wait_ms(1);
+ break;
+ case 2:
+ kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
+ break;
+ case 3:
+ break;
+ }
+ }
+ conn->ntlm_auth_hlpr_pid = 0;
+ }
+
+ free(conn->challenge_header);
+ conn->challenge_header = NULL;
+ free(conn->response_header);
+ conn->response_header = NULL;
+}
+
+static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
+{
+ curl_socket_t sockfds[2];
+ pid_t child_pid;
+ const char *username;
+ char *slash, *domain = NULL;
+ const char *ntlm_auth = NULL;
+ char *ntlm_auth_alloc = NULL;
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+ struct passwd pw, *pw_res;
+ char pwbuf[1024];
+#endif
+ int error;
+
+ /* Return if communication with ntlm_auth already set up */
+ if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
+ conn->ntlm_auth_hlpr_pid)
+ return CURLE_OK;
+
+ username = userp;
+ /* The real ntlm_auth really doesn't like being invoked with an
+ empty username. It won't make inferences for itself, and expects
+ the client to do so (mostly because it's really designed for
+ servers like squid to use for auth, and client support is an
+ afterthought for it). So try hard to provide a suitable username
+ if we don't already have one. But if we can't, provide the
+ empty one anyway. Perhaps they have an implementation of the
+ ntlm_auth helper which *doesn't* need it so we might as well try */
+ if(!username || !username[0]) {
+ username = getenv("NTLMUSER");
+ if(!username || !username[0])
+ username = getenv("LOGNAME");
+ if(!username || !username[0])
+ username = getenv("USER");
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+ if((!username || !username[0]) &&
+ !getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) &&
+ pw_res) {
+ username = pw.pw_name;
+ }
+#endif
+ if(!username || !username[0])
+ username = userp;
+ }
+ slash = strpbrk(username, "\\/");
+ if(slash) {
+ domain = strdup(username);
+ if(!domain)
+ return CURLE_OUT_OF_MEMORY;
+ slash = domain + (slash - username);
+ *slash = '\0';
+ username = username + (slash - domain) + 1;
+ }
+
+ /* For testing purposes, when DEBUGBUILD is defined and environment
+ variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
+ NTLM challenge/response which only accepts commands and output
+ strings pre-written in test case definitions */
+#ifdef DEBUGBUILD
+ ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
+ if(ntlm_auth_alloc)
+ ntlm_auth = ntlm_auth_alloc;
+ else
+#endif
+ ntlm_auth = NTLM_WB_FILE;
+
+ if(access(ntlm_auth, X_OK) != 0) {
+ error = ERRNO;
+ failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
+ ntlm_auth, error, Curl_strerror(conn, error));
+ goto done;
+ }
+
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
+ error = ERRNO;
+ failf(conn->data, "Could not open socket pair. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ goto done;
+ }
+
+ child_pid = fork();
+ if(child_pid == -1) {
+ error = ERRNO;
+ sclose(sockfds[0]);
+ sclose(sockfds[1]);
+ failf(conn->data, "Could not fork. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ goto done;
+ }
+ else if(!child_pid) {
+ /*
+ * child process
+ */
+
+ /* Don't use sclose in the child since it fools the socket leak detector */
+ sclose_nolog(sockfds[0]);
+ if(dup2(sockfds[1], STDIN_FILENO) == -1) {
+ error = ERRNO;
+ failf(conn->data, "Could not redirect child stdin. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
+ error = ERRNO;
+ failf(conn->data, "Could not redirect child stdout. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ if(domain)
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ "--domain", domain,
+ NULL);
+ else
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ NULL);
+
+ error = ERRNO;
+ sclose_nolog(sockfds[1]);
+ failf(conn->data, "Could not execl(). errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ sclose(sockfds[1]);
+ conn->ntlm_auth_hlpr_socket = sockfds[0];
+ conn->ntlm_auth_hlpr_pid = child_pid;
+ free(domain);
+ free(ntlm_auth_alloc);
+ return CURLE_OK;
+
+done:
+ free(domain);
+ free(ntlm_auth_alloc);
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+static CURLcode ntlm_wb_response(struct connectdata *conn,
+ const char *input, curlntlm state)
+{
+ char *buf = malloc(NTLM_BUFSIZE);
+ size_t len_in = strlen(input), len_out = 0;
+
+ if(!buf)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(len_in > 0) {
+ ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in);
+ if(written == -1) {
+ /* Interrupted by a signal, retry it */
+ if(errno == EINTR)
+ continue;
+ /* write failed if other errors happen */
+ goto done;
+ }
+ input += written;
+ len_in -= written;
+ }
+ /* Read one line */
+ while(1) {
+ ssize_t size;
+ char *newbuf;
+
+ size = sread(conn->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
+ if(size == -1) {
+ if(errno == EINTR)
+ continue;
+ goto done;
+ }
+ else if(size == 0)
+ goto done;
+
+ len_out += size;
+ if(buf[len_out - 1] == '\n') {
+ buf[len_out - 1] = '\0';
+ break;
+ }
+ newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE);
+ if(!newbuf)
+ return CURLE_OUT_OF_MEMORY;
+
+ buf = newbuf;
+ }
+
+ /* Samba/winbind installed but not configured */
+ if(state == NTLMSTATE_TYPE1 &&
+ len_out == 3 &&
+ buf[0] == 'P' && buf[1] == 'W')
+ goto done;
+ /* invalid response */
+ if(len_out < 4)
+ goto done;
+ if(state == NTLMSTATE_TYPE1 &&
+ (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' '))
+ goto done;
+ if(state == NTLMSTATE_TYPE2 &&
+ (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') &&
+ (buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
+ goto done;
+
+ conn->response_header = aprintf("NTLM %.*s", len_out - 4, buf + 3);
+ free(buf);
+ return CURLE_OK;
+done:
+ free(buf);
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+/*
+ * This is for creating ntlm header output by delegating challenge/response
+ * to Samba's winbind daemon helper ntlm_auth.
+ */
+CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
+ bool proxy)
+{
+ /* point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+ /* point to the name and password for this */
+ const char *userp;
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ struct auth *authp;
+
+ CURLcode res = CURLE_OK;
+ char *input;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->data);
+
+ if(proxy) {
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->http_proxy.user;
+ ntlm = &conn->proxyntlm;
+ authp = &conn->data->state.authproxy;
+ }
+ else {
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ ntlm = &conn->ntlm;
+ authp = &conn->data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp="";
+
+ switch(ntlm->state) {
+ case NTLMSTATE_TYPE1:
+ default:
+ /* Use Samba's 'winbind' daemon to support NTLM authentication,
+ * by delegating the NTLM challenge/response protocal to a helper
+ * in ntlm_auth.
+ * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
+ * https://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
+ * https://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
+ * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
+ * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
+ * filename of ntlm_auth helper.
+ * If NTLM authentication using winbind fails, go back to original
+ * request handling process.
+ */
+ /* Create communication with ntlm_auth */
+ res = ntlm_wb_init(conn, userp);
+ if(res)
+ return res;
+ res = ntlm_wb_response(conn, "YR\n", ntlm->state);
+ if(res)
+ return res;
+
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
+ proxy ? "Proxy-" : "",
+ conn->response_header);
+ DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ free(conn->response_header);
+ conn->response_header = NULL;
+ break;
+ case NTLMSTATE_TYPE2:
+ input = aprintf("TT %s\n", conn->challenge_header);
+ if(!input)
+ return CURLE_OUT_OF_MEMORY;
+ res = ntlm_wb_response(conn, input, ntlm->state);
+ free(input);
+ input = NULL;
+ if(res)
+ return res;
+
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
+ proxy ? "Proxy-" : "",
+ conn->response_header);
+ DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+ authp->done = TRUE;
+ Curl_ntlm_wb_cleanup(conn);
+ break;
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ free(*allocuserpwd);
+ *allocuserpwd=NULL;
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
diff --git a/Utilities/cmcurl/lib/curl_ntlm_wb.h b/Utilities/cmcurl/lib/curl_ntlm_wb.h
new file mode 100644
index 000000000..aba3d469c
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_ntlm_wb.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_NTLM_WB_H
+#define HEADER_CURL_NTLM_WB_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+
+/* this is for creating ntlm header output by delegating challenge/response
+ to Samba's winbind daemon helper ntlm_auth */
+CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy);
+
+void Curl_ntlm_wb_cleanup(struct connectdata *conn);
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM && NTLM_WB_ENABLED */
+
+#endif /* HEADER_CURL_NTLM_WB_H */
diff --git a/Utilities/cmcurl/lib/curl_printf.h b/Utilities/cmcurl/lib/curl_printf.h
new file mode 100644
index 000000000..49857cdb0
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_printf.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_PRINTF_H
+#define HEADER_CURL_PRINTF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This header should be included by ALL code in libcurl that uses any
+ * *rintf() functions.
+ */
+
+#include <curl/mprintf.h>
+
+# undef printf
+# undef fprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+# define snprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define vsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+
+/* We define away the sprintf functions unconditonally since we don't want
+ internal code to be using them, intentionally or by mistake!*/
+# undef sprintf
+# undef vsprintf
+# define sprintf sprintf_was_used
+# define vsprintf vsprintf_was_used
+
+#endif /* HEADER_CURL_PRINTF_H */
diff --git a/Utilities/cmcurl/lib/curl_rtmp.c b/Utilities/cmcurl/lib/curl_rtmp.c
new file mode 100644
index 000000000..87a6caf9e
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_rtmp.c
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBRTMP
+
+#include "curl_rtmp.h"
+#include "urldata.h"
+#include "nonblock.h" /* for curlx_nonblock */
+#include "progress.h" /* for Curl_pgrsSetUploadSize */
+#include "transfer.h"
+#include "warnless.h"
+#include <curl/curl.h>
+#include <librtmp/rtmp.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef _WIN32
+#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
+#define SET_RCVTIMEO(tv,s) int tv = s*1000
+#else
+#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
+#endif
+
+#define DEF_BUFTIME (2*60*60*1000) /* 2 hours */
+
+static CURLcode rtmp_setup_connection(struct connectdata *conn);
+static CURLcode rtmp_do(struct connectdata *conn, bool *done);
+static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
+static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
+static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
+
+static Curl_recv rtmp_recv;
+static Curl_send rtmp_send;
+
+/*
+ * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
+ */
+
+const struct Curl_handler Curl_handler_rtmp = {
+ "RTMP", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMP, /* defport */
+ CURLPROTO_RTMP, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpt = {
+ "RTMPT", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPT, /* defport */
+ CURLPROTO_RTMPT, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpe = {
+ "RTMPE", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMP, /* defport */
+ CURLPROTO_RTMPE, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpte = {
+ "RTMPTE", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPT, /* defport */
+ CURLPROTO_RTMPTE, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmps = {
+ "RTMPS", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPS, /* defport */
+ CURLPROTO_RTMPS, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpts = {
+ "RTMPTS", /* scheme */
+ rtmp_setup_connection, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPS, /* defport */
+ CURLPROTO_RTMPTS, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+static CURLcode rtmp_setup_connection(struct connectdata *conn)
+{
+ RTMP *r = RTMP_Alloc();
+ if(!r)
+ return CURLE_OUT_OF_MEMORY;
+
+ RTMP_Init(r);
+ RTMP_SetBufferMS(r, DEF_BUFTIME);
+ if(!RTMP_SetupURL(r, conn->data->change.url)) {
+ RTMP_Free(r);
+ return CURLE_URL_MALFORMAT;
+ }
+ conn->proto.generic = r;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
+{
+ RTMP *r = conn->proto.generic;
+ SET_RCVTIMEO(tv, 10);
+
+ r->m_sb.sb_socket = conn->sock[FIRSTSOCKET];
+
+ /* We have to know if it's a write before we send the
+ * connect request packet
+ */
+ if(conn->data->set.upload)
+ r->Link.protocol |= RTMP_FEATURE_WRITE;
+
+ /* For plain streams, use the buffer toggle trick to keep data flowing */
+ if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
+ !(r->Link.protocol & RTMP_FEATURE_HTTP))
+ r->Link.lFlags |= RTMP_LF_BUFX;
+
+ (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
+ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
+ (char *)&tv, sizeof(tv));
+
+ if(!RTMP_Connect1(r, NULL))
+ return CURLE_FAILED_INIT;
+
+ /* Clients must send a periodic BytesReceived report to the server */
+ r->m_bSendCounter = true;
+
+ *done = TRUE;
+ conn->recv[FIRSTSOCKET] = rtmp_recv;
+ conn->send[FIRSTSOCKET] = rtmp_send;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_do(struct connectdata *conn, bool *done)
+{
+ RTMP *r = conn->proto.generic;
+
+ if(!RTMP_ConnectStream(r, 0))
+ return CURLE_FAILED_INIT;
+
+ if(conn->data->set.upload) {
+ Curl_pgrsSetUploadSize(conn->data, conn->data->state.infilesize);
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ }
+ else
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ *done = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ (void)conn; /* unused */
+ (void)status; /* unused */
+ (void)premature; /* unused */
+
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ RTMP *r = conn->proto.generic;
+ (void)dead_connection;
+ if(r) {
+ conn->proto.generic = NULL;
+ RTMP_Close(r);
+ RTMP_Free(r);
+ }
+ return CURLE_OK;
+}
+
+static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
+ size_t len, CURLcode *err)
+{
+ RTMP *r = conn->proto.generic;
+ ssize_t nread;
+
+ (void)sockindex; /* unused */
+
+ nread = RTMP_Read(r, buf, curlx_uztosi(len));
+ if(nread < 0) {
+ if(r->m_read.status == RTMP_READ_COMPLETE ||
+ r->m_read.status == RTMP_READ_EOF) {
+ conn->data->req.size = conn->data->req.bytecount;
+ nread = 0;
+ }
+ else
+ *err = CURLE_RECV_ERROR;
+ }
+ return nread;
+}
+
+static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
+ const void *buf, size_t len, CURLcode *err)
+{
+ RTMP *r = conn->proto.generic;
+ ssize_t num;
+
+ (void)sockindex; /* unused */
+
+ num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
+ if(num < 0)
+ *err = CURLE_SEND_ERROR;
+
+ return num;
+}
+#endif /* USE_LIBRTMP */
diff --git a/Utilities/cmcurl/lib/curl_rtmp.h b/Utilities/cmcurl/lib/curl_rtmp.h
new file mode 100644
index 000000000..3306e2200
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_rtmp.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_RTMP_H
+#define HEADER_CURL_RTMP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifdef USE_LIBRTMP
+extern const struct Curl_handler Curl_handler_rtmp;
+extern const struct Curl_handler Curl_handler_rtmpt;
+extern const struct Curl_handler Curl_handler_rtmpe;
+extern const struct Curl_handler Curl_handler_rtmpte;
+extern const struct Curl_handler Curl_handler_rtmps;
+extern const struct Curl_handler Curl_handler_rtmpts;
+#endif
+
+#endif /* HEADER_CURL_RTMP_H */
diff --git a/Utilities/cmcurl/lib/curl_sasl.c b/Utilities/cmcurl/lib/curl_sasl.c
new file mode 100644
index 000000000..bd574b5e2
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_sasl.c
@@ -0,0 +1,626 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2617 Basic and Digest Access Authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * RFC7628 A Set of SASL Mechanisms for OAuth
+ * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "vauth/vauth.h"
+#include "vtls/vtls.h"
+#include "curl_hmac.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "non-ascii.h" /* included for Curl_convert_... prototypes */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Supported mechanisms */
+static const struct {
+ const char *name; /* Name */
+ size_t len; /* Name length */
+ unsigned int bit; /* Flag bit */
+} mechtable[] = {
+ { "LOGIN", 5, SASL_MECH_LOGIN },
+ { "PLAIN", 5, SASL_MECH_PLAIN },
+ { "CRAM-MD5", 8, SASL_MECH_CRAM_MD5 },
+ { "DIGEST-MD5", 10, SASL_MECH_DIGEST_MD5 },
+ { "GSSAPI", 6, SASL_MECH_GSSAPI },
+ { "EXTERNAL", 8, SASL_MECH_EXTERNAL },
+ { "NTLM", 4, SASL_MECH_NTLM },
+ { "XOAUTH2", 7, SASL_MECH_XOAUTH2 },
+ { "OAUTHBEARER", 11, SASL_MECH_OAUTHBEARER },
+ { ZERO_NULL, 0, 0 }
+};
+
+/*
+ * Curl_sasl_cleanup()
+ *
+ * This is used to cleanup any libraries or curl modules used by the sasl
+ * functions.
+ *
+ * Parameters:
+ *
+ * conn [in] - The connection data.
+ * authused [in] - The authentication mechanism used.
+ */
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
+{
+#if defined(USE_KERBEROS5)
+ /* Cleanup the gssapi structure */
+ if(authused == SASL_MECH_GSSAPI) {
+ Curl_auth_gssapi_cleanup(&conn->krb5);
+ }
+#endif
+
+#if defined(USE_NTLM)
+ /* Cleanup the NTLM structure */
+ if(authused == SASL_MECH_NTLM) {
+ Curl_auth_ntlm_cleanup(&conn->ntlm);
+ }
+#endif
+
+#if !defined(USE_KERBEROS5) && !defined(USE_NTLM)
+ /* Reserved for future use */
+ (void)conn;
+ (void)authused;
+#endif
+}
+
+/*
+ * Curl_sasl_decode_mech()
+ *
+ * Convert a SASL mechanism name into a token.
+ *
+ * Parameters:
+ *
+ * ptr [in] - The mechanism string.
+ * maxlen [in] - Maximum mechanism string length.
+ * len [out] - If not NULL, effective name length.
+ *
+ * Returns the SASL mechanism token or 0 if no match.
+ */
+unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
+{
+ unsigned int i;
+ char c;
+
+ for(i = 0; mechtable[i].name; i++) {
+ if(maxlen >= mechtable[i].len &&
+ !memcmp(ptr, mechtable[i].name, mechtable[i].len)) {
+ if(len)
+ *len = mechtable[i].len;
+
+ if(maxlen == mechtable[i].len)
+ return mechtable[i].bit;
+
+ c = ptr[mechtable[i].len];
+ if(!ISUPPER(c) && !ISDIGIT(c) && c != '-' && c != '_')
+ return mechtable[i].bit;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Curl_sasl_parse_url_auth_option()
+ *
+ * Parse the URL login options.
+ */
+CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
+ const char *value, size_t len)
+{
+ CURLcode result = CURLE_OK;
+ unsigned int mechbit;
+ size_t mechlen;
+
+ if(!len)
+ return CURLE_URL_MALFORMAT;
+
+ if(sasl->resetprefs) {
+ sasl->resetprefs = FALSE;
+ sasl->prefmech = SASL_AUTH_NONE;
+ }
+
+ if(!strncmp(value, "*", len))
+ sasl->prefmech = SASL_AUTH_DEFAULT;
+ else {
+ mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
+ if(mechbit && mechlen == len)
+ sasl->prefmech |= mechbit;
+ else
+ result = CURLE_URL_MALFORMAT;
+ }
+
+ return result;
+}
+
+/*
+ * Curl_sasl_init()
+ *
+ * Initializes the SASL structure.
+ */
+void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
+{
+ sasl->params = params; /* Set protocol dependent parameters */
+ sasl->state = SASL_STOP; /* Not yet running */
+ sasl->authmechs = SASL_AUTH_NONE; /* No known authentication mechanism yet */
+ sasl->prefmech = SASL_AUTH_DEFAULT; /* Prefer all mechanisms */
+ sasl->authused = SASL_AUTH_NONE; /* No the authentication mechanism used */
+ sasl->resetprefs = TRUE; /* Reset prefmech upon AUTH parsing. */
+ sasl->mutual_auth = FALSE; /* No mutual authentication (GSSAPI only) */
+ sasl->force_ir = FALSE; /* Respect external option */
+}
+
+/*
+ * state()
+ *
+ * This is the ONLY way to change SASL state!
+ */
+static void state(struct SASL *sasl, struct connectdata *conn,
+ saslstate newstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[]={
+ "STOP",
+ "PLAIN",
+ "LOGIN",
+ "LOGIN_PASSWD",
+ "EXTERNAL",
+ "CRAMMD5",
+ "DIGESTMD5",
+ "DIGESTMD5_RESP",
+ "NTLM",
+ "NTLM_TYPE2MSG",
+ "GSSAPI",
+ "GSSAPI_TOKEN",
+ "GSSAPI_NO_DATA",
+ "OAUTH2",
+ "OAUTH2_RESP",
+ "CANCEL",
+ "FINAL",
+ /* LAST */
+ };
+
+ if(sasl->state != newstate)
+ infof(conn->data, "SASL %p state change from %s to %s\n",
+ (void *)sasl, names[sasl->state], names[newstate]);
+#else
+ (void) conn;
+#endif
+
+ sasl->state = newstate;
+}
+
+/*
+ * Curl_sasl_can_authenticate()
+ *
+ * Check if we have enough auth data and capabilities to authenticate.
+ */
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
+{
+ /* Have credentials been provided? */
+ if(conn->bits.user_passwd)
+ return TRUE;
+
+ /* EXTERNAL can authenticate without a user name and/or password */
+ if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
+ return TRUE;
+
+ return FALSE;
+}
+
+/*
+ * Curl_sasl_start()
+ *
+ * Calculate the required login details for SASL authentication.
+ */
+CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+ bool force_ir, saslprogress *progress)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ unsigned int enabledmechs;
+ const char *mech = NULL;
+ char *resp = NULL;
+ size_t len = 0;
+ saslstate state1 = SASL_STOP;
+ saslstate state2 = SASL_FINAL;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#if defined(USE_KERBEROS5)
+ const char *service = data->set.str[STRING_SERVICE_NAME] ?
+ data->set.str[STRING_SERVICE_NAME] :
+ sasl->params->service;
+#endif
+
+ sasl->force_ir = force_ir; /* Latch for future use */
+ sasl->authused = 0; /* No mechanism used yet */
+ enabledmechs = sasl->authmechs & sasl->prefmech;
+ *progress = SASL_IDLE;
+
+ /* Calculate the supported authentication mechanism, by decreasing order of
+ security, as well as the initial response where appropriate */
+ if((enabledmechs & SASL_MECH_EXTERNAL) && !conn->passwd[0]) {
+ mech = SASL_MECH_STRING_EXTERNAL;
+ state1 = SASL_EXTERNAL;
+ sasl->authused = SASL_MECH_EXTERNAL;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_external_message(data, conn->user, &resp,
+ &len);
+ }
+ else if(conn->bits.user_passwd) {
+#if defined(USE_KERBEROS5)
+ if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
+ Curl_auth_user_contains_domain(conn->user)) {
+ sasl->mutual_auth = FALSE; /* TODO: Calculate mutual authentication */
+ mech = SASL_MECH_STRING_GSSAPI;
+ state1 = SASL_GSSAPI;
+ state2 = SASL_GSSAPI_TOKEN;
+ sasl->authused = SASL_MECH_GSSAPI;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_gssapi_user_message(data, conn->user,
+ conn->passwd,
+ service,
+ data->easy_conn->
+ host.name,
+ sasl->mutual_auth,
+ NULL, &conn->krb5,
+ &resp, &len);
+ }
+ else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
+ Curl_auth_is_digest_supported()) {
+ mech = SASL_MECH_STRING_DIGEST_MD5;
+ state1 = SASL_DIGESTMD5;
+ sasl->authused = SASL_MECH_DIGEST_MD5;
+ }
+ else if(enabledmechs & SASL_MECH_CRAM_MD5) {
+ mech = SASL_MECH_STRING_CRAM_MD5;
+ state1 = SASL_CRAMMD5;
+ sasl->authused = SASL_MECH_CRAM_MD5;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if((enabledmechs & SASL_MECH_NTLM) && Curl_auth_is_ntlm_supported()) {
+ mech = SASL_MECH_STRING_NTLM;
+ state1 = SASL_NTLM;
+ state2 = SASL_NTLM_TYPE2MSG;
+ sasl->authused = SASL_MECH_NTLM;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm, &resp, &len);
+ }
+ else
+#endif
+ if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) {
+ mech = SASL_MECH_STRING_OAUTHBEARER;
+ state1 = SASL_OAUTH2;
+ state2 = SASL_OAUTH2_RESP;
+ sasl->authused = SASL_MECH_OAUTHBEARER;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ hostname,
+ port,
+ conn->oauth_bearer,
+ &resp, &len);
+ }
+ else if((enabledmechs & SASL_MECH_XOAUTH2) && conn->oauth_bearer) {
+ mech = SASL_MECH_STRING_XOAUTH2;
+ state1 = SASL_OAUTH2;
+ sasl->authused = SASL_MECH_XOAUTH2;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ NULL, 0,
+ conn->oauth_bearer,
+ &resp, &len);
+ }
+ else if(enabledmechs & SASL_MECH_LOGIN) {
+ mech = SASL_MECH_STRING_LOGIN;
+ state1 = SASL_LOGIN;
+ state2 = SASL_LOGIN_PASSWD;
+ sasl->authused = SASL_MECH_LOGIN;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ }
+ else if(enabledmechs & SASL_MECH_PLAIN) {
+ mech = SASL_MECH_STRING_PLAIN;
+ state1 = SASL_PLAIN;
+ sasl->authused = SASL_MECH_PLAIN;
+
+ if(force_ir || data->set.sasl_ir)
+ result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
+ &resp, &len);
+ }
+ }
+
+ if(!result && mech) {
+ if(resp && sasl->params->maxirlen &&
+ strlen(mech) + len > sasl->params->maxirlen) {
+ free(resp);
+ resp = NULL;
+ }
+
+ result = sasl->params->sendauth(conn, mech, resp);
+ if(!result) {
+ *progress = SASL_INPROGRESS;
+ state(sasl, conn, resp ? state2 : state1);
+ }
+ }
+
+ free(resp);
+
+ return result;
+}
+
+/*
+ * Curl_sasl_continue()
+ *
+ * Continue the authentication.
+ */
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+ int code, saslprogress *progress)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ saslstate newstate = SASL_FINAL;
+ char *resp = NULL;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+ char *chlg = NULL;
+ size_t chlglen = 0;
+#endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5)
+ const char *service = data->set.str[STRING_SERVICE_NAME] ?
+ data->set.str[STRING_SERVICE_NAME] :
+ sasl->params->service;
+#endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_NTLM)
+ char *serverdata;
+#endif
+ size_t len = 0;
+
+ *progress = SASL_INPROGRESS;
+
+ if(sasl->state == SASL_FINAL) {
+ if(code != sasl->params->finalcode)
+ result = CURLE_LOGIN_DENIED;
+ *progress = SASL_DONE;
+ state(sasl, conn, SASL_STOP);
+ return result;
+ }
+
+ if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
+ code != sasl->params->contcode) {
+ *progress = SASL_DONE;
+ state(sasl, conn, SASL_STOP);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ switch(sasl->state) {
+ case SASL_STOP:
+ *progress = SASL_DONE;
+ return result;
+ case SASL_PLAIN:
+ result = Curl_auth_create_plain_message(data, conn->user, conn->passwd,
+ &resp,
+ &len);
+ break;
+ case SASL_LOGIN:
+ result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+ newstate = SASL_LOGIN_PASSWD;
+ break;
+ case SASL_LOGIN_PASSWD:
+ result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
+ break;
+ case SASL_EXTERNAL:
+ result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case SASL_CRAMMD5:
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
+ if(!result)
+ result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
+ conn->passwd, &resp, &len);
+ free(chlg);
+ break;
+ case SASL_DIGESTMD5:
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ result = Curl_auth_create_digest_md5_message(data, serverdata,
+ conn->user, conn->passwd,
+ service,
+ &resp, &len);
+ newstate = SASL_DIGESTMD5_RESP;
+ break;
+ case SASL_DIGESTMD5_RESP:
+ resp = strdup("");
+ if(!resp)
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+#endif
+
+#ifdef USE_NTLM
+ case SASL_NTLM:
+ /* Create the type-1 message */
+ result = Curl_auth_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm, &resp, &len);
+ newstate = SASL_NTLM_TYPE2MSG;
+ break;
+ case SASL_NTLM_TYPE2MSG:
+ /* Decode the type-2 message */
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
+ &conn->ntlm);
+ if(!result)
+ result = Curl_auth_create_ntlm_type3_message(data, conn->user,
+ conn->passwd, &conn->ntlm,
+ &resp, &len);
+ break;
+#endif
+
+#if defined(USE_KERBEROS5)
+ case SASL_GSSAPI:
+ result = Curl_auth_create_gssapi_user_message(data, conn->user,
+ conn->passwd,
+ service,
+ data->easy_conn->host.name,
+ sasl->mutual_auth, NULL,
+ &conn->krb5,
+ &resp, &len);
+ newstate = SASL_GSSAPI_TOKEN;
+ break;
+ case SASL_GSSAPI_TOKEN:
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ if(sasl->mutual_auth) {
+ /* Decode the user token challenge and create the optional response
+ message */
+ result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+ NULL, NULL,
+ sasl->mutual_auth,
+ serverdata, &conn->krb5,
+ &resp, &len);
+ newstate = SASL_GSSAPI_NO_DATA;
+ }
+ else
+ /* Decode the security challenge and create the response message */
+ result = Curl_auth_create_gssapi_security_message(data, serverdata,
+ &conn->krb5,
+ &resp, &len);
+ break;
+ case SASL_GSSAPI_NO_DATA:
+ sasl->params->getmessage(data->state.buffer, &serverdata);
+ /* Decode the security challenge and create the response message */
+ result = Curl_auth_create_gssapi_security_message(data, serverdata,
+ &conn->krb5,
+ &resp, &len);
+ break;
+#endif
+
+ case SASL_OAUTH2:
+ /* Create the authorisation message */
+ if(sasl->authused == SASL_MECH_OAUTHBEARER) {
+ result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ hostname,
+ port,
+ conn->oauth_bearer,
+ &resp, &len);
+
+ /* Failures maybe sent by the server as continuations for OAUTHBEARER */
+ newstate = SASL_OAUTH2_RESP;
+ }
+ else
+ result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+ NULL, 0,
+ conn->oauth_bearer,
+ &resp, &len);
+ break;
+
+ case SASL_OAUTH2_RESP:
+ /* The continuation is optional so check the response code */
+ if(code == sasl->params->finalcode) {
+ /* Final response was received so we are done */
+ *progress = SASL_DONE;
+ state(sasl, conn, SASL_STOP);
+ return result;
+ }
+ else if(code == sasl->params->contcode) {
+ /* Acknowledge the continuation by sending a 0x01 response base64
+ encoded */
+ resp = strdup("AQ==");
+ if(!resp)
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ else {
+ *progress = SASL_DONE;
+ state(sasl, conn, SASL_STOP);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ case SASL_CANCEL:
+ /* Remove the offending mechanism from the supported list */
+ sasl->authmechs ^= sasl->authused;
+
+ /* Start an alternative SASL authentication */
+ result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress);
+ newstate = sasl->state; /* Use state from Curl_sasl_start() */
+ break;
+ default:
+ failf(data, "Unsupported SASL authentication mechanism");
+ result = CURLE_UNSUPPORTED_PROTOCOL; /* Should not happen */
+ break;
+ }
+
+ switch(result) {
+ case CURLE_BAD_CONTENT_ENCODING:
+ /* Cancel dialog */
+ result = sasl->params->sendcont(conn, "*");
+ newstate = SASL_CANCEL;
+ break;
+ case CURLE_OK:
+ if(resp)
+ result = sasl->params->sendcont(conn, resp);
+ break;
+ default:
+ newstate = SASL_STOP; /* Stop on error */
+ *progress = SASL_DONE;
+ break;
+ }
+
+ free(resp);
+
+ state(sasl, conn, newstate);
+
+ return result;
+}
diff --git a/Utilities/cmcurl/lib/curl_sasl.h b/Utilities/cmcurl/lib/curl_sasl.h
new file mode 100644
index 000000000..7647a48be
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_sasl.h
@@ -0,0 +1,143 @@
+#ifndef HEADER_CURL_SASL_H
+#define HEADER_CURL_SASL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+struct Curl_easy;
+struct connectdata;
+
+/* Authentication mechanism flags */
+#define SASL_MECH_LOGIN (1 << 0)
+#define SASL_MECH_PLAIN (1 << 1)
+#define SASL_MECH_CRAM_MD5 (1 << 2)
+#define SASL_MECH_DIGEST_MD5 (1 << 3)
+#define SASL_MECH_GSSAPI (1 << 4)
+#define SASL_MECH_EXTERNAL (1 << 5)
+#define SASL_MECH_NTLM (1 << 6)
+#define SASL_MECH_XOAUTH2 (1 << 7)
+#define SASL_MECH_OAUTHBEARER (1 << 8)
+
+/* Authentication mechanism values */
+#define SASL_AUTH_NONE 0
+#define SASL_AUTH_ANY ~0U
+#define SASL_AUTH_DEFAULT (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
+
+/* Authentication mechanism strings */
+#define SASL_MECH_STRING_LOGIN "LOGIN"
+#define SASL_MECH_STRING_PLAIN "PLAIN"
+#define SASL_MECH_STRING_CRAM_MD5 "CRAM-MD5"
+#define SASL_MECH_STRING_DIGEST_MD5 "DIGEST-MD5"
+#define SASL_MECH_STRING_GSSAPI "GSSAPI"
+#define SASL_MECH_STRING_EXTERNAL "EXTERNAL"
+#define SASL_MECH_STRING_NTLM "NTLM"
+#define SASL_MECH_STRING_XOAUTH2 "XOAUTH2"
+#define SASL_MECH_STRING_OAUTHBEARER "OAUTHBEARER"
+
+/* SASL machine states */
+typedef enum {
+ SASL_STOP,
+ SASL_PLAIN,
+ SASL_LOGIN,
+ SASL_LOGIN_PASSWD,
+ SASL_EXTERNAL,
+ SASL_CRAMMD5,
+ SASL_DIGESTMD5,
+ SASL_DIGESTMD5_RESP,
+ SASL_NTLM,
+ SASL_NTLM_TYPE2MSG,
+ SASL_GSSAPI,
+ SASL_GSSAPI_TOKEN,
+ SASL_GSSAPI_NO_DATA,
+ SASL_OAUTH2,
+ SASL_OAUTH2_RESP,
+ SASL_CANCEL,
+ SASL_FINAL
+} saslstate;
+
+/* Progress indicator */
+typedef enum {
+ SASL_IDLE,
+ SASL_INPROGRESS,
+ SASL_DONE
+} saslprogress;
+
+/* Protocol dependent SASL parameters */
+struct SASLproto {
+ const char *service; /* The service name */
+ int contcode; /* Code to receive when continuation is expected */
+ int finalcode; /* Code to receive upon authentication success */
+ size_t maxirlen; /* Maximum initial response length */
+ CURLcode (*sendauth)(struct connectdata *conn,
+ const char *mech, const char *ir);
+ /* Send authentication command */
+ CURLcode (*sendcont)(struct connectdata *conn, const char *contauth);
+ /* Send authentication continuation */
+ void (*getmessage)(char *buffer, char **outptr);
+ /* Get SASL response message */
+};
+
+/* Per-connection parameters */
+struct SASL {
+ const struct SASLproto *params; /* Protocol dependent parameters */
+ saslstate state; /* Current machine state */
+ unsigned int authmechs; /* Accepted authentication mechanisms */
+ unsigned int prefmech; /* Preferred authentication mechanism */
+ unsigned int authused; /* Auth mechanism used for the connection */
+ bool resetprefs; /* For URL auth option parsing. */
+ bool mutual_auth; /* Mutual authentication enabled (GSSAPI only) */
+ bool force_ir; /* Protocol always supports initial response */
+};
+
+/* This is used to test whether the line starts with the given mechanism */
+#define sasl_mech_equal(line, wordlen, mech) \
+ (wordlen == (sizeof(mech) - 1) / sizeof(char) && \
+ !memcmp(line, mech, wordlen))
+
+/* This is used to cleanup any libraries or curl modules used by the sasl
+ functions */
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
+
+/* Convert a mechanism name to a token */
+unsigned int Curl_sasl_decode_mech(const char *ptr,
+ size_t maxlen, size_t *len);
+
+/* Parse the URL login options */
+CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
+ const char *value, size_t len);
+
+/* Initializes an SASL structure */
+void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
+
+/* Check if we have enough auth data and capabilities to authenticate */
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
+
+/* Calculate the required login details for SASL authentication */
+CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+ bool force_ir, saslprogress *progress);
+
+/* Continue an SASL authentication */
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+ int code, saslprogress *progress);
+
+#endif /* HEADER_CURL_SASL_H */
diff --git a/Utilities/cmcurl/lib/curl_sec.h b/Utilities/cmcurl/lib/curl_sec.h
new file mode 100644
index 000000000..7bdde269b
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_sec.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_SECURITY_H
+#define HEADER_CURL_SECURITY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+struct Curl_sec_client_mech {
+ const char *name;
+ size_t size;
+ int (*init)(void *);
+ int (*auth)(void *, struct connectdata *);
+ void (*end)(void *);
+ int (*check_prot)(void *, int);
+ int (*overhead)(void *, int, int);
+ int (*encode)(void *, const void *, int, int, void **);
+ int (*decode)(void *, void *, int, int, struct connectdata *);
+};
+
+#define AUTH_OK 0
+#define AUTH_CONTINUE 1
+#define AUTH_ERROR 2
+
+#ifdef HAVE_GSSAPI
+int Curl_sec_read_msg(struct connectdata *conn, char *,
+ enum protection_level);
+void Curl_sec_end(struct connectdata *);
+CURLcode Curl_sec_login(struct connectdata *);
+int Curl_sec_request_prot(struct connectdata *conn, const char *level);
+
+extern struct Curl_sec_client_mech Curl_krb5_client_mech;
+#endif
+
+#endif /* HEADER_CURL_SECURITY_H */
diff --git a/Utilities/cmcurl/lib/curl_setup.h b/Utilities/cmcurl/lib/curl_setup.h
new file mode 100644
index 000000000..a6268adf2
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_setup.h
@@ -0,0 +1,773 @@
+#ifndef HEADER_CURL_SETUP_H
+#define HEADER_CURL_SETUP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \
+ !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
+#ifdef HAVE_CONFIG_H
+
+#include "curl_config.h"
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef _WIN32_WCE
+# include "config-win32ce.h"
+#else
+# ifdef WIN32
+# include "config-win32.h"
+# endif
+#endif
+
+#if defined(macintosh) && defined(__MRC__)
+# include "config-mac.h"
+#endif
+
+#ifdef __riscos__
+# include "config-riscos.h"
+#endif
+
+#ifdef __AMIGA__
+# include "config-amigaos.h"
+#endif
+
+#ifdef __SYMBIAN32__
+# include "config-symbian.h"
+#endif
+
+#ifdef __OS400__
+# include "config-os400.h"
+#endif
+
+#ifdef TPF
+# include "config-tpf.h"
+#endif
+
+#ifdef __VXWORKS__
+# include "config-vxworks.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+#endif
+
+/* ================================================================ */
+/* Definition of preprocessor macros/symbols which modify compiler */
+/* behavior or generated code characteristics must be done here, */
+/* as appropriate, before any system header file is included. It is */
+/* also possible to have them defined in the config file included */
+/* before this point. As a result of all this we frown inclusion of */
+/* system header files in our config files, avoid this at any cost. */
+/* ================================================================ */
+
+/*
+ * AIX 4.3 and newer needs _THREAD_SAFE defined to build
+ * proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_THREAD_SAFE
+# ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+# endif
+#endif
+
+/*
+ * Tru64 needs _REENTRANT set for a few function prototypes and
+ * things to appear in the system header files. Unixware needs it
+ * to build proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_REENTRANT
+# ifndef _REENTRANT
+# define _REENTRANT
+# endif
+#endif
+
+/* Solaris needs this to get a POSIX-conformant getpwuid_r */
+#if defined(sun) || defined(__sun)
+# ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+# endif
+#endif
+
+/* ================================================================ */
+/* If you need to include a system header file for your platform, */
+/* please, do it beyond the point further indicated in this file. */
+/* ================================================================ */
+
+#include <curl/curl.h>
+
+/*
+ * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro
+ */
+
+#ifdef SIZEOF_CURL_OFF_T
+# error "SIZEOF_CURL_OFF_T shall not be defined!"
+ Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined
+#endif
+
+/*
+ * Disable other protocols when http is the only one desired.
+ */
+
+#ifdef HTTP_ONLY
+# ifndef CURL_DISABLE_TFTP
+# define CURL_DISABLE_TFTP
+# endif
+# ifndef CURL_DISABLE_FTP
+# define CURL_DISABLE_FTP
+# endif
+# ifndef CURL_DISABLE_LDAP
+# define CURL_DISABLE_LDAP
+# endif
+# ifndef CURL_DISABLE_TELNET
+# define CURL_DISABLE_TELNET
+# endif
+# ifndef CURL_DISABLE_DICT
+# define CURL_DISABLE_DICT
+# endif
+# ifndef CURL_DISABLE_FILE
+# define CURL_DISABLE_FILE
+# endif
+# ifndef CURL_DISABLE_RTSP
+# define CURL_DISABLE_RTSP
+# endif
+# ifndef CURL_DISABLE_POP3
+# define CURL_DISABLE_POP3
+# endif
+# ifndef CURL_DISABLE_IMAP
+# define CURL_DISABLE_IMAP
+# endif
+# ifndef CURL_DISABLE_SMTP
+# define CURL_DISABLE_SMTP
+# endif
+# ifndef CURL_DISABLE_RTMP
+# define CURL_DISABLE_RTMP
+# endif
+# ifndef CURL_DISABLE_GOPHER
+# define CURL_DISABLE_GOPHER
+# endif
+# ifndef CURL_DISABLE_SMB
+# define CURL_DISABLE_SMB
+# endif
+#endif
+
+/*
+ * When http is disabled rtsp is not supported.
+ */
+
+#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
+# define CURL_DISABLE_RTSP
+#endif
+
+/* ================================================================ */
+/* No system header file shall be included in this file before this */
+/* point. The only allowed ones are those included from curlbuild.h */
+/* ================================================================ */
+
+/*
+ * OS/400 setup file includes some system headers.
+ */
+
+#ifdef __OS400__
+# include "setup-os400.h"
+#endif
+
+/*
+ * VMS setup file includes some system headers.
+ */
+
+#ifdef __VMS
+# include "setup-vms.h"
+#endif
+
+/*
+ * Use getaddrinfo to resolve the IPv4 address literal. If the current network
+ * interface doesn’t support IPv4, but supports IPv6, NAT64, and DNS64,
+ * performing this task will result in a synthesized IPv6 address.
+ */
+#ifdef __APPLE__
+#define USE_RESOLVE_ON_IPS 1
+#endif
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preprocessor block only to include or exclude windows.h,
+ * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * to any other further and independent block. Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined. configure script takes
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
+ */
+
+#ifdef HAVE_WINDOWS_H
+# if defined(UNICODE) && !defined(_UNICODE)
+# define _UNICODE
+# endif
+# if defined(_UNICODE) && !defined(UNICODE)
+# define UNICODE
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+# endif
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# endif
+# endif
+# include <tchar.h>
+# ifdef UNICODE
+ typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str);
+# endif
+#endif
+
+/*
+ * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
+ * define USE_WINSOCK to 1 if we have and use WINSOCK API, else
+ * undefine USE_WINSOCK.
+ */
+
+#undef USE_WINSOCK
+
+#ifdef HAVE_WINSOCK2_H
+# define USE_WINSOCK 2
+#else
+# ifdef HAVE_WINSOCK_H
+# define USE_WINSOCK 1
+# endif
+#endif
+
+#ifdef USE_LWIPSOCK
+# include <lwip/init.h>
+# include <lwip/sockets.h>
+# include <lwip/netdb.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRICMP_H
+# include <extra/stricmp.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRDUP_H
+# include <extra/strdup.h>
+#endif
+
+#ifdef TPF
+# include <strings.h> /* for bzero, strcasecmp, and strncasecmp */
+# include <string.h> /* for strcpy and strlen */
+# include <stdlib.h> /* for rand and srand */
+# include <sys/socket.h> /* for select and ioctl*/
+# include <netdb.h> /* for in_addr_t definition */
+# include <tpf/sysapi.h> /* for tpf_process_signals */
+ /* change which select is used for libcurl */
+# define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
+#endif
+
+#ifdef __VXWORKS__
+# include <sockLib.h> /* for generic BSD socket functions */
+# include <ioLib.h> /* for basic I/O interface functions */
+#endif
+
+#ifdef __AMIGA__
+# ifndef __ixemul__
+# include <exec/types.h>
+# include <exec/execbase.h>
+# include <proto/exec.h>
+# include <proto/dos.h>
+# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0)
+# endif
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef __TANDEM /* for nsr-tandem-nsk systems */
+#include <floss.h>
+#endif
+
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
+#endif
+
+#ifdef __POCC__
+# include <sys/types.h>
+# include <unistd.h>
+# define sys_nerr EILSEQ
+#endif
+
+/*
+ * Salford-C kludge section (mostly borrowed from wxWidgets).
+ */
+#ifdef __SALFORDC__
+ #pragma suppress 353 /* Possible nested comments */
+ #pragma suppress 593 /* Define not used */
+ #pragma suppress 61 /* enum has no name */
+ #pragma suppress 106 /* unnamed, unused parameter */
+ #include <clib.h>
+#endif
+
+/* Default Windows file API selection. */
+#ifdef _WIN32
+# if defined(_MSC_VER) && (_INTEGRAL_MAX_BITS >= 64)
+# define USE_WIN32_LARGE_FILES
+# elif defined(__MINGW32__)
+# define USE_WIN32_LARGE_FILES
+# else
+# define USE_WIN32_SMALL_FILES
+# endif
+#endif
+
+/*
+ * Large file (>2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# undef lseek
+# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence)
+# undef fstat
+# define fstat(fdes,stp) _fstati64(fdes, stp)
+# undef stat
+# define stat(fname,stp) _stati64(fname, stp)
+# define struct_stat struct _stati64
+# define LSEEK_ERROR (__int64)-1
+#endif
+
+/*
+ * Small file (<2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# ifndef _WIN32_WCE
+# undef lseek
+# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
+# define fstat(fdes,stp) _fstat(fdes, stp)
+# define stat(fname,stp) _stat(fname, stp)
+# define struct_stat struct _stat
+# endif
+# define LSEEK_ERROR (long)-1
+#endif
+
+#ifndef struct_stat
+# define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+# define LSEEK_ERROR (off_t)-1
+#endif
+
+/*
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
+ */
+
+#ifndef SIZEOF_OFF_T
+# if defined(__VMS) && !defined(__VAX)
+# if defined(_LARGEFILE)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__OS400__) && defined(__ILEC400__)
+# if defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__MVS__) && defined(__IBMC__)
+# if defined(_LP64) || defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__370__) && defined(__IBMC__)
+# if defined(_LP64) || defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# endif
+# ifndef SIZEOF_OFF_T
+# define SIZEOF_OFF_T 4
+# endif
+#endif
+
+/*
+ * Arg 2 type for gethostname in case it hasn't been defined in config file.
+ */
+
+#ifndef GETHOSTNAME_TYPE_ARG2
+# ifdef USE_WINSOCK
+# define GETHOSTNAME_TYPE_ARG2 int
+# else
+# define GETHOSTNAME_TYPE_ARG2 size_t
+# endif
+#endif
+
+/* Below we define some functions. They should
+
+ 4. set the SIGALRM signal timeout
+ 5. set dir/file naming defines
+ */
+
+#ifdef WIN32
+
+# define DIR_CHAR "\\"
+# define DOT_CHAR "_"
+
+#else /* WIN32 */
+
+# ifdef MSDOS /* Watt-32 */
+
+# include <sys/ioctl.h>
+# define select(n,r,w,x,t) select_s(n,r,w,x,t)
+# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+# include <tcp.h>
+# ifdef word
+# undef word
+# endif
+# ifdef byte
+# undef byte
+# endif
+
+# endif /* MSDOS */
+
+# ifdef __minix
+ /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
+ extern char *strtok_r(char *s, const char *delim, char **last);
+ extern struct tm *gmtime_r(const time_t * const timep, struct tm *tmp);
+# endif
+
+# define DIR_CHAR "/"
+# ifndef DOT_CHAR
+# define DOT_CHAR "."
+# endif
+
+# ifdef MSDOS
+# undef DOT_CHAR
+# define DOT_CHAR "_"
+# endif
+
+# ifndef fileno /* sunos 4 have this as a macro! */
+ int fileno(FILE *stream);
+# endif
+
+#endif /* WIN32 */
+
+/*
+ * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
+ * defined in ws2tcpip.h as well as to provide IPv6 support.
+ * Does not apply if lwIP is used.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__) && !defined(USE_LWIPSOCK)
+# if !defined(HAVE_WS2TCPIP_H) || \
+ ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
+# undef HAVE_GETADDRINFO_THREADSAFE
+# undef HAVE_FREEADDRINFO
+# undef HAVE_GETADDRINFO
+# undef HAVE_GETNAMEINFO
+# undef ENABLE_IPV6
+# endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/* resolver specialty compile-time defines */
+/* CURLRES_* defines to use in the host*.c sources */
+/* ---------------------------------------------------------------- */
+
+/*
+ * lcc-win32 doesn't have _beginthreadex(), lacks threads support.
+ */
+
+#if defined(__LCC__) && defined(WIN32)
+# undef USE_THREADS_POSIX
+# undef USE_THREADS_WIN32
+#endif
+
+/*
+ * MSVC threads support requires a multi-threaded runtime library.
+ * _beginthreadex() is not available in single-threaded ones.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
+# undef USE_THREADS_POSIX
+# undef USE_THREADS_WIN32
+#endif
+
+/*
+ * Mutually exclusive CURLRES_* definitions.
+ */
+
+#ifdef USE_ARES
+# define CURLRES_ASYNCH
+# define CURLRES_ARES
+/* now undef the stock libc functions just to avoid them being used */
+# undef HAVE_GETADDRINFO
+# undef HAVE_FREEADDRINFO
+# undef HAVE_GETHOSTBYNAME
+#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+# define CURLRES_ASYNCH
+# define CURLRES_THREADED
+#else
+# define CURLRES_SYNCH
+#endif
+
+#ifdef ENABLE_IPV6
+# define CURLRES_IPV6
+#else
+# define CURLRES_IPV4
+#endif
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * When using WINSOCK, TELNET protocol requires WINSOCK2 API.
+ */
+
+#if defined(USE_WINSOCK) && (USE_WINSOCK != 2)
+# define CURL_DISABLE_TELNET 1
+#endif
+
+/*
+ * msvc 6.0 does not have struct sockaddr_storage and
+ * does not define IPPROTO_ESP in winsock2.h. But both
+ * are available if PSDK is properly installed.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
+# undef HAVE_STRUCT_SOCKADDR_STORAGE
+# endif
+#endif
+
+/*
+ * Intentionally fail to build when using msvc 6.0 without PSDK installed.
+ * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
+ * in lib/config-win32.h although absolutely discouraged and unsupported.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_))
+# if !defined(ALLOW_MSVC6_WITHOUT_PSDK)
+# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \
+ "Windows Server 2003 PSDK"
+# else
+# define CURL_DISABLE_LDAP 1
+# endif
+# endif
+#endif
+
+#ifdef NETWARE
+int netware_init(void);
+#ifndef __NOVELL_LIBC__
+#include <sys/bsdskt.h>
+#include <sys/timeval.h>
+#endif
+#endif
+
+#if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
+/* The lib and header are present */
+#define USE_LIBIDN2
+#endif
+
+#if defined(USE_LIBIDN2) && defined(USE_WIN32_IDN)
+#error "Both libidn2 and WinIDN are enabled, choose one."
+#endif
+
+#ifndef SIZEOF_TIME_T
+/* assume default size of time_t to be 32 bit */
+#define SIZEOF_TIME_T 4
+#endif
+
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+
+#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
+ defined(USE_POLARSSL) || defined(USE_AXTLS) || defined(USE_MBEDTLS) || \
+ defined(USE_CYASSL) || defined(USE_SCHANNEL) || \
+ defined(USE_DARWINSSL) || defined(USE_GSKIT)
+#define USE_SSL /* SSL support has been enabled */
+#endif
+
+/* Single point where USE_SPNEGO definition might be defined */
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
+ (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
+#define USE_SPNEGO
+#endif
+
+/* Single point where USE_KERBEROS5 definition might be defined */
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
+ (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
+#define USE_KERBEROS5
+#endif
+
+/* Single point where USE_NTLM definition might be defined */
+#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \
+ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL) || \
+ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
+ defined(USE_MBEDTLS)
+
+#define USE_NTLM
+
+# if defined(USE_MBEDTLS)
+/* Get definition of MBEDTLS_MD4_C */
+# include <mbedtls/md4.h>
+# endif
+
+#endif
+#endif
+
+/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
+#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
+#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
+#endif
+
+/*
+ * Provide a mechanism to silence picky compilers, such as gcc 4.6+.
+ * Parameters should of course normally not be unused, but for example when
+ * we have multiple implementations of the same interface it may happen.
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ >= 3) || \
+ ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
+# define UNUSED_PARAM __attribute__((__unused__))
+# define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
+#else
+# define UNUSED_PARAM /*NOTHING*/
+# define WARN_UNUSED_RESULT
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#include "curl_setup_once.h"
+#endif
+
+/*
+ * Definition of our NOP statement Object-like macro
+ */
+
+#ifndef Curl_nop_stmt
+# define Curl_nop_stmt do { } WHILE_FALSE
+#endif
+
+/*
+ * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
+ */
+
+#if defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H)
+# if defined(SOCKET) || \
+ defined(USE_WINSOCK) || \
+ defined(HAVE_WINSOCK_H) || \
+ defined(HAVE_WINSOCK2_H) || \
+ defined(HAVE_WS2TCPIP_H)
+# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
+# endif
+#endif
+
+/*
+ * Portable symbolic names for Winsock shutdown() mode flags.
+ */
+
+#ifdef USE_WINSOCK
+# define SHUT_RD 0x00
+# define SHUT_WR 0x01
+# define SHUT_RDWR 0x02
+#endif
+
+/* Define S_ISREG if not defined by system headers, f.e. MSVC */
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+/* Define S_ISDIR if not defined by system headers, f.e. MSVC */
+#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+/* In Windows the default file mode is text but an application can override it.
+Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
+*/
+#if defined(WIN32) || defined(MSDOS)
+#define FOPEN_READTEXT "rt"
+#define FOPEN_WRITETEXT "wt"
+#elif defined(__CYGWIN__)
+/* Cygwin has specific behavior we need to address when WIN32 is not defined.
+https://cygwin.com/cygwin-ug-net/using-textbinary.html
+For write we want our output to have line endings of LF and be compatible with
+other Cygwin utilities. For read we want to handle input that may have line
+endings either CRLF or LF so 't' is appropriate.
+*/
+#define FOPEN_READTEXT "rt"
+#define FOPEN_WRITETEXT "w"
+#else
+#define FOPEN_READTEXT "r"
+#define FOPEN_WRITETEXT "w"
+#endif
+
+/* WinSock destroys recv() buffer when send() failed.
+ * Enabled automatically for Windows and for Cygwin as Cygwin sockets are
+ * wrappers for WinSock sockets. https://github.com/curl/curl/issues/657
+ * Define DONT_USE_RECV_BEFORE_SEND_WORKAROUND to force disable workaround.
+ */
+#if !defined(DONT_USE_RECV_BEFORE_SEND_WORKAROUND)
+# if defined(WIN32) || defined(__CYGWIN__)
+# define USE_RECV_BEFORE_SEND_WORKAROUND
+# endif
+#else /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
+# ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+# undef USE_RECV_BEFORE_SEND_WORKAROUND
+# endif
+#endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUNDS */
+
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)
+# include <winapifamily.h>
+# if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) && \
+ !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+# define CURL_WINDOWS_APP
+# endif
+# endif
+
+#endif /* HEADER_CURL_SETUP_H */
diff --git a/Utilities/cmcurl/lib/curl_setup_once.h b/Utilities/cmcurl/lib/curl_setup_once.h
new file mode 100644
index 000000000..684187cae
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_setup_once.h
@@ -0,0 +1,551 @@
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#define HEADER_CURL_SETUP_ONCE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+
+/*
+ * Inclusion of common header files.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#endif
+
+#ifdef WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
+#include <stdbool.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef _APP32_64BIT_OFF_T
+# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
+# undef _APP32_64BIT_OFF_T
+# else
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef OLD_APP32_64BIT_OFF_T
+# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
+
+/*
+ * Definition of timeval struct for platforms that don't have it.
+ */
+
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+
+/*
+ * If we have the MSG_NOSIGNAL define, make sure we use
+ * it as the fourth argument of function send()
+ */
+
+#ifdef HAVE_MSG_NOSIGNAL
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#else
+#define SEND_4TH_ARG 0
+#endif
+
+
+#if defined(__minix)
+/* Minix doesn't support recv on TCP sockets */
+#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
+ (RECV_TYPE_ARG2)(y), \
+ (RECV_TYPE_ARG3)(z))
+
+#elif defined(HAVE_RECV)
+/*
+ * The definitions for the return type and arguments types
+ * of functions recv() and send() belong and come from the
+ * configuration file. Do not define them in any other place.
+ *
+ * HAVE_RECV is defined if you have a function named recv()
+ * which is used to read incoming data from sockets. If your
+ * function has another name then don't define HAVE_RECV.
+ *
+ * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
+ * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
+ * be defined.
+ *
+ * HAVE_SEND is defined if you have a function named send()
+ * which is used to write outgoing data on a connected socket.
+ * If yours has another name then don't define HAVE_SEND.
+ *
+ * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
+ * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
+ * SEND_TYPE_RETV must also be defined.
+ */
+
+#if !defined(RECV_TYPE_ARG1) || \
+ !defined(RECV_TYPE_ARG2) || \
+ !defined(RECV_TYPE_ARG3) || \
+ !defined(RECV_TYPE_ARG4) || \
+ !defined(RECV_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_recv
+ /* */
+#else
+#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
+ (RECV_TYPE_ARG2)(y), \
+ (RECV_TYPE_ARG3)(z), \
+ (RECV_TYPE_ARG4)(0))
+#endif
+#else /* HAVE_RECV */
+#ifndef sread
+ /* */
+ Error Missing_definition_of_macro_sread
+ /* */
+#endif
+#endif /* HAVE_RECV */
+
+
+#if defined(__minix)
+/* Minix doesn't support send on TCP sockets */
+#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
+ (SEND_TYPE_ARG2)(y), \
+ (SEND_TYPE_ARG3)(z))
+
+#elif defined(HAVE_SEND)
+#if !defined(SEND_TYPE_ARG1) || \
+ !defined(SEND_QUAL_ARG2) || \
+ !defined(SEND_TYPE_ARG2) || \
+ !defined(SEND_TYPE_ARG3) || \
+ !defined(SEND_TYPE_ARG4) || \
+ !defined(SEND_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_send
+ /* */
+#else
+#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
+ (SEND_QUAL_ARG2 SEND_TYPE_ARG2)(y), \
+ (SEND_TYPE_ARG3)(z), \
+ (SEND_TYPE_ARG4)(SEND_4TH_ARG))
+#endif
+#else /* HAVE_SEND */
+#ifndef swrite
+ /* */
+ Error Missing_definition_of_macro_swrite
+ /* */
+#endif
+#endif /* HAVE_SEND */
+
+
+#if 0
+#if defined(HAVE_RECVFROM)
+/*
+ * Currently recvfrom is only used on udp sockets.
+ */
+#if !defined(RECVFROM_TYPE_ARG1) || \
+ !defined(RECVFROM_TYPE_ARG2) || \
+ !defined(RECVFROM_TYPE_ARG3) || \
+ !defined(RECVFROM_TYPE_ARG4) || \
+ !defined(RECVFROM_TYPE_ARG5) || \
+ !defined(RECVFROM_TYPE_ARG6) || \
+ !defined(RECVFROM_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_recvfrom
+ /* */
+#else
+#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \
+ (RECVFROM_TYPE_ARG2 *)(b), \
+ (RECVFROM_TYPE_ARG3) (bl), \
+ (RECVFROM_TYPE_ARG4) (0), \
+ (RECVFROM_TYPE_ARG5 *)(f), \
+ (RECVFROM_TYPE_ARG6 *)(fl))
+#endif
+#else /* HAVE_RECVFROM */
+#ifndef sreadfrom
+ /* */
+ Error Missing_definition_of_macro_sreadfrom
+ /* */
+#endif
+#endif /* HAVE_RECVFROM */
+
+
+#ifdef RECVFROM_TYPE_ARG6_IS_VOID
+# define RECVFROM_ARG6_T int
+#else
+# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6
+#endif
+#endif /* if 0 */
+
+
+/*
+ * Function-like macro definition used to close a socket.
+ */
+
+#if defined(HAVE_CLOSESOCKET)
+# define sclose(x) closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+# define sclose(x) CloseSocket((x))
+#elif defined(HAVE_CLOSE_S)
+# define sclose(x) close_s((x))
+#elif defined(USE_LWIPSOCK)
+# define sclose(x) lwip_close((x))
+#else
+# define sclose(x) close((x))
+#endif
+
+/*
+ * Stack-independent version of fcntl() on sockets:
+ */
+#if defined(USE_LWIPSOCK)
+# define sfcntl lwip_fcntl
+#else
+# define sfcntl fcntl
+#endif
+
+/*
+ * Uppercase macro versions of ANSI/ISO is*() functions/macros which
+ * avoid negative number inputs with argument byte codes > 127.
+ */
+
+#define ISSPACE(x) (isspace((int) ((unsigned char)x)))
+#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
+#define ISALNUM(x) (isalnum((int) ((unsigned char)x)))
+#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#define ISGRAPH(x) (isgraph((int) ((unsigned char)x)))
+#define ISALPHA(x) (isalpha((int) ((unsigned char)x)))
+#define ISPRINT(x) (isprint((int) ((unsigned char)x)))
+#define ISUPPER(x) (isupper((int) ((unsigned char)x)))
+#define ISLOWER(x) (islower((int) ((unsigned char)x)))
+#define ISASCII(x) (isascii((int) ((unsigned char)x)))
+
+#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \
+ (((unsigned char)x) == '\t'))
+
+#define TOLOWER(x) (tolower((int) ((unsigned char)x)))
+
+
+/*
+ * 'bool' stuff compatible with HP-UX headers.
+ */
+
+#if defined(__hpux) && !defined(HAVE_BOOL_T)
+ typedef int bool;
+# define false 0
+# define true 1
+# define HAVE_BOOL_T
+#endif
+
+
+/*
+ * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
+ * On non-C99 platforms there's no bool, so define an enum for that.
+ * On C99 platforms 'false' and 'true' also exist. Enum uses a
+ * global namespace though, so use bool_false and bool_true.
+ */
+
+#ifndef HAVE_BOOL_T
+ typedef enum {
+ bool_false = 0,
+ bool_true = 1
+ } bool;
+
+/*
+ * Use a define to let 'true' and 'false' use those enums. There
+ * are currently no use of true and false in libcurl proper, but
+ * there are some in the examples. This will cater for any later
+ * code happening to use true and false.
+ */
+# define false bool_false
+# define true bool_true
+# define HAVE_BOOL_T
+#endif
+
+
+/*
+ * Redefine TRUE and FALSE too, to catch current use. With this
+ * change, 'bool found = 1' will give a warning on MIPSPro, but
+ * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro,
+ * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too.
+ */
+
+#ifndef TRUE
+#define TRUE true
+#endif
+#ifndef FALSE
+#define FALSE false
+#endif
+
+
+/*
+ * Macro WHILE_FALSE may be used to build single-iteration do-while loops,
+ * avoiding compiler warnings. Mostly intended for other macro definitions.
+ */
+
+#define WHILE_FALSE while(0)
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# undef WHILE_FALSE
+# if (_MSC_VER < 1500)
+# define WHILE_FALSE while(1, 0)
+# else
+# define WHILE_FALSE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+while(0) \
+__pragma(warning(pop))
+# endif
+#endif
+
+
+/*
+ * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
+ */
+
+#ifndef HAVE_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+#define HAVE_SIG_ATOMIC_T
+#endif
+
+
+/*
+ * Convenience SIG_ATOMIC_T definition
+ */
+
+#ifdef HAVE_SIG_ATOMIC_T_VOLATILE
+#define SIG_ATOMIC_T static sig_atomic_t
+#else
+#define SIG_ATOMIC_T static volatile sig_atomic_t
+#endif
+
+
+/*
+ * Default return type for signal handlers.
+ */
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+
+/*
+ * Macro used to include code only in debug builds.
+ */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x) do { } WHILE_FALSE
+#endif
+
+
+/*
+ * Macro used to include assertion code only in debug builds.
+ */
+
+#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
+#define DEBUGASSERT(x) assert(x)
+#else
+#define DEBUGASSERT(x) do { } WHILE_FALSE
+#endif
+
+
+/*
+ * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#ifdef USE_WINSOCK
+#define SOCKERRNO ((int)WSAGetLastError())
+#define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
+#else
+#define SOCKERRNO (errno)
+#define SET_SOCKERRNO(x) (errno = (x))
+#endif
+
+
+/*
+ * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#if defined(WIN32) && !defined(USE_LWIPSOCK)
+#define ERRNO ((int)GetLastError())
+#define SET_ERRNO(x) (SetLastError((DWORD)(x)))
+#else
+#define ERRNO (errno)
+#define SET_ERRNO(x) (errno = (x))
+#endif
+
+
+/*
+ * Portable error number symbolic names defined to Winsock error codes.
+ */
+
+#ifdef USE_WINSOCK
+#undef EBADF /* override definition in errno.h */
+#define EBADF WSAEBADF
+#undef EINTR /* override definition in errno.h */
+#define EINTR WSAEINTR
+#undef EINVAL /* override definition in errno.h */
+#define EINVAL WSAEINVAL
+#undef EWOULDBLOCK /* override definition in errno.h */
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef EINPROGRESS /* override definition in errno.h */
+#define EINPROGRESS WSAEINPROGRESS
+#undef EALREADY /* override definition in errno.h */
+#define EALREADY WSAEALREADY
+#undef ENOTSOCK /* override definition in errno.h */
+#define ENOTSOCK WSAENOTSOCK
+#undef EDESTADDRREQ /* override definition in errno.h */
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#undef EMSGSIZE /* override definition in errno.h */
+#define EMSGSIZE WSAEMSGSIZE
+#undef EPROTOTYPE /* override definition in errno.h */
+#define EPROTOTYPE WSAEPROTOTYPE
+#undef ENOPROTOOPT /* override definition in errno.h */
+#define ENOPROTOOPT WSAENOPROTOOPT
+#undef EPROTONOSUPPORT /* override definition in errno.h */
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#undef EOPNOTSUPP /* override definition in errno.h */
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#undef EAFNOSUPPORT /* override definition in errno.h */
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#undef EADDRINUSE /* override definition in errno.h */
+#define EADDRINUSE WSAEADDRINUSE
+#undef EADDRNOTAVAIL /* override definition in errno.h */
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#undef ENETDOWN /* override definition in errno.h */
+#define ENETDOWN WSAENETDOWN
+#undef ENETUNREACH /* override definition in errno.h */
+#define ENETUNREACH WSAENETUNREACH
+#undef ENETRESET /* override definition in errno.h */
+#define ENETRESET WSAENETRESET
+#undef ECONNABORTED /* override definition in errno.h */
+#define ECONNABORTED WSAECONNABORTED
+#undef ECONNRESET /* override definition in errno.h */
+#define ECONNRESET WSAECONNRESET
+#undef ENOBUFS /* override definition in errno.h */
+#define ENOBUFS WSAENOBUFS
+#undef EISCONN /* override definition in errno.h */
+#define EISCONN WSAEISCONN
+#undef ENOTCONN /* override definition in errno.h */
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#undef ETIMEDOUT /* override definition in errno.h */
+#define ETIMEDOUT WSAETIMEDOUT
+#undef ECONNREFUSED /* override definition in errno.h */
+#define ECONNREFUSED WSAECONNREFUSED
+#undef ELOOP /* override definition in errno.h */
+#define ELOOP WSAELOOP
+#ifndef ENAMETOOLONG /* possible previous definition in errno.h */
+#define ENAMETOOLONG WSAENAMETOOLONG
+#endif
+#define EHOSTDOWN WSAEHOSTDOWN
+#undef EHOSTUNREACH /* override definition in errno.h */
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#ifndef ENOTEMPTY /* possible previous definition in errno.h */
+#define ENOTEMPTY WSAENOTEMPTY
+#endif
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+#endif
+
+/*
+ * Macro argv_item_t hides platform details to code using it.
+ */
+
+#ifdef __VMS
+#define argv_item_t __char_ptr32
+#else
+#define argv_item_t char *
+#endif
+
+
+/*
+ * We use this ZERO_NULL to avoid picky compiler warnings,
+ * when assigning a NULL pointer to a function pointer var.
+ */
+
+#define ZERO_NULL 0
+
+
+#endif /* HEADER_CURL_SETUP_ONCE_H */
+
diff --git a/Utilities/cmcurl/lib/curl_sspi.c b/Utilities/cmcurl/lib/curl_sspi.c
new file mode 100644
index 000000000..11a7120a9
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_sspi.c
@@ -0,0 +1,235 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+#include "curl_sspi.h"
+#include "curl_multibyte.h"
+#include "system_win32.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* We use our own typedef here since some headers might lack these */
+typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
+
+/* See definition of SECURITY_ENTRYPOINT in sspi.h */
+#ifdef UNICODE
+# ifdef _WIN32_WCE
+# define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
+# else
+# define SECURITYENTRYPOINT "InitSecurityInterfaceW"
+# endif
+#else
+# define SECURITYENTRYPOINT "InitSecurityInterfaceA"
+#endif
+
+/* Handle of security.dll or secur32.dll, depending on Windows version */
+HMODULE s_hSecDll = NULL;
+
+/* Pointer to SSPI dispatch table */
+PSecurityFunctionTable s_pSecFn = NULL;
+
+/*
+ * Curl_sspi_global_init()
+ *
+ * This is used to load the Security Service Provider Interface (SSPI)
+ * dynamic link library portably across all Windows versions, without
+ * the need to directly link libcurl, nor the application using it, at
+ * build time.
+ *
+ * Once this function has been executed, Windows SSPI functions can be
+ * called through the Security Service Provider Interface dispatch table.
+ *
+ * Parameters:
+ *
+ * None.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_sspi_global_init(void)
+{
+ INITSECURITYINTERFACE_FN pInitSecurityInterface;
+
+ /* If security interface is not yet initialized try to do this */
+ if(!s_hSecDll) {
+ /* Security Service Provider Interface (SSPI) functions are located in
+ * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
+ * have both these DLLs (security.dll forwards calls to secur32.dll) */
+
+ /* Load SSPI dll into the address space of the calling process */
+ if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
+ s_hSecDll = Curl_load_library(TEXT("security.dll"));
+ else
+ s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
+ if(!s_hSecDll)
+ return CURLE_FAILED_INIT;
+
+ /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
+ pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
+ GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
+ if(!pInitSecurityInterface)
+ return CURLE_FAILED_INIT;
+
+ /* Get pointer to Security Service Provider Interface dispatch table */
+ s_pSecFn = pInitSecurityInterface();
+ if(!s_pSecFn)
+ return CURLE_FAILED_INIT;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_sspi_global_cleanup()
+ *
+ * This deinitializes the Security Service Provider Interface from libcurl.
+ *
+ * Parameters:
+ *
+ * None.
+ */
+void Curl_sspi_global_cleanup(void)
+{
+ if(s_hSecDll) {
+ FreeLibrary(s_hSecDll);
+ s_hSecDll = NULL;
+ s_pSecFn = NULL;
+ }
+}
+
+/*
+ * Curl_create_sspi_identity()
+ *
+ * This is used to populate a SSPI identity structure based on the supplied
+ * username and password.
+ *
+ * Parameters:
+ *
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * identity [in/out] - The identity structure.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
+ SEC_WINNT_AUTH_IDENTITY *identity)
+{
+ xcharp_u useranddomain;
+ xcharp_u user, dup_user;
+ xcharp_u domain, dup_domain;
+ xcharp_u passwd, dup_passwd;
+ size_t domlen = 0;
+
+ domain.const_tchar_ptr = TEXT("");
+
+ /* Initialize the identity */
+ memset(identity, 0, sizeof(*identity));
+
+ useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
+ if(!useranddomain.tchar_ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
+ if(!user.const_tchar_ptr)
+ user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
+
+ if(user.tchar_ptr) {
+ domain.tchar_ptr = useranddomain.tchar_ptr;
+ domlen = user.tchar_ptr - useranddomain.tchar_ptr;
+ user.tchar_ptr++;
+ }
+ else {
+ user.tchar_ptr = useranddomain.tchar_ptr;
+ domain.const_tchar_ptr = TEXT("");
+ domlen = 0;
+ }
+
+ /* Setup the identity's user and length */
+ dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
+ if(!dup_user.tchar_ptr) {
+ Curl_unicodefree(useranddomain.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ identity->User = dup_user.tbyte_ptr;
+ identity->UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
+ dup_user.tchar_ptr = NULL;
+
+ /* Setup the identity's domain and length */
+ dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
+ if(!dup_domain.tchar_ptr) {
+ Curl_unicodefree(useranddomain.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
+ *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
+ identity->Domain = dup_domain.tbyte_ptr;
+ identity->DomainLength = curlx_uztoul(domlen);
+ dup_domain.tchar_ptr = NULL;
+
+ Curl_unicodefree(useranddomain.tchar_ptr);
+
+ /* Setup the identity's password and length */
+ passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
+ if(!passwd.tchar_ptr)
+ return CURLE_OUT_OF_MEMORY;
+ dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
+ if(!dup_passwd.tchar_ptr) {
+ Curl_unicodefree(passwd.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ identity->Password = dup_passwd.tbyte_ptr;
+ identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
+ dup_passwd.tchar_ptr = NULL;
+
+ Curl_unicodefree(passwd.tchar_ptr);
+
+ /* Setup the identity's flags */
+ identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_sspi_free_identity()
+ *
+ * This is used to free the contents of a SSPI identifier structure.
+ *
+ * Parameters:
+ *
+ * identity [in/out] - The identity structure.
+ */
+void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity)
+{
+ if(identity) {
+ Curl_safefree(identity->User);
+ Curl_safefree(identity->Password);
+ Curl_safefree(identity->Domain);
+ }
+}
+
+#endif /* USE_WINDOWS_SSPI */
diff --git a/Utilities/cmcurl/lib/curl_sspi.h b/Utilities/cmcurl/lib/curl_sspi.h
new file mode 100644
index 000000000..2bbf9477b
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_sspi.h
@@ -0,0 +1,350 @@
+#ifndef HEADER_CURL_SSPI_H
+#define HEADER_CURL_SSPI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+/*
+ * When including the following three headers, it is mandatory to define either
+ * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code.
+ */
+
+#undef SECURITY_WIN32
+#undef SECURITY_KERNEL
+#define SECURITY_WIN32 1
+#include <security.h>
+#include <sspi.h>
+#include <rpc.h>
+
+CURLcode Curl_sspi_global_init(void);
+void Curl_sspi_global_cleanup(void);
+
+/* This is used to populate the domain in a SSPI identity structure */
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+ SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* This is used to generate an SSPI identity structure */
+CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
+ SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* This is used to free an SSPI identity structure */
+void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity);
+
+/* Forward-declaration of global variables defined in curl_sspi.c */
+extern HMODULE s_hSecDll;
+extern PSecurityFunctionTable s_pSecFn;
+
+/* Provide some definitions missing in old headers */
+#define SP_NAME_DIGEST "WDigest"
+#define SP_NAME_NTLM "NTLM"
+#define SP_NAME_NEGOTIATE "Negotiate"
+#define SP_NAME_KERBEROS "Kerberos"
+
+#ifndef ISC_REQ_USE_HTTP_STYLE
+#define ISC_REQ_USE_HTTP_STYLE 0x01000000
+#endif
+
+#ifndef ISC_RET_REPLAY_DETECT
+#define ISC_RET_REPLAY_DETECT 0x00000004
+#endif
+
+#ifndef ISC_RET_SEQUENCE_DETECT
+#define ISC_RET_SEQUENCE_DETECT 0x00000008
+#endif
+
+#ifndef ISC_RET_CONFIDENTIALITY
+#define ISC_RET_CONFIDENTIALITY 0x00000010
+#endif
+
+#ifndef ISC_RET_ALLOCATED_MEMORY
+#define ISC_RET_ALLOCATED_MEMORY 0x00000100
+#endif
+
+#ifndef ISC_RET_STREAM
+#define ISC_RET_STREAM 0x00008000
+#endif
+
+#ifndef SEC_E_INSUFFICIENT_MEMORY
+# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L)
+#endif
+#ifndef SEC_E_INVALID_HANDLE
+# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_FUNCTION
+# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L)
+#endif
+#ifndef SEC_E_TARGET_UNKNOWN
+# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L)
+#endif
+#ifndef SEC_E_INTERNAL_ERROR
+# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L)
+#endif
+#ifndef SEC_E_SECPKG_NOT_FOUND
+# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L)
+#endif
+#ifndef SEC_E_NOT_OWNER
+# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L)
+#endif
+#ifndef SEC_E_CANNOT_INSTALL
+# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L)
+#endif
+#ifndef SEC_E_INVALID_TOKEN
+# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L)
+#endif
+#ifndef SEC_E_CANNOT_PACK
+# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L)
+#endif
+#ifndef SEC_E_QOP_NOT_SUPPORTED
+# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL)
+#endif
+#ifndef SEC_E_NO_IMPERSONATION
+# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL)
+#endif
+#ifndef SEC_E_LOGON_DENIED
+# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL)
+#endif
+#ifndef SEC_E_UNKNOWN_CREDENTIALS
+# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL)
+#endif
+#ifndef SEC_E_NO_CREDENTIALS
+# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL)
+#endif
+#ifndef SEC_E_MESSAGE_ALTERED
+# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL)
+#endif
+#ifndef SEC_E_OUT_OF_SEQUENCE
+# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L)
+#endif
+#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY
+# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L)
+#endif
+#ifndef SEC_E_BAD_PKGID
+# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L)
+#endif
+#ifndef SEC_E_CONTEXT_EXPIRED
+# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L)
+#endif
+#ifndef SEC_E_INCOMPLETE_MESSAGE
+# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L)
+#endif
+#ifndef SEC_E_INCOMPLETE_CREDENTIALS
+# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L)
+#endif
+#ifndef SEC_E_BUFFER_TOO_SMALL
+# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L)
+#endif
+#ifndef SEC_E_WRONG_PRINCIPAL
+# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L)
+#endif
+#ifndef SEC_E_TIME_SKEW
+# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L)
+#endif
+#ifndef SEC_E_UNTRUSTED_ROOT
+# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L)
+#endif
+#ifndef SEC_E_ILLEGAL_MESSAGE
+# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L)
+#endif
+#ifndef SEC_E_CERT_UNKNOWN
+# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L)
+#endif
+#ifndef SEC_E_CERT_EXPIRED
+# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L)
+#endif
+#ifndef SEC_E_ENCRYPT_FAILURE
+# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L)
+#endif
+#ifndef SEC_E_DECRYPT_FAILURE
+# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L)
+#endif
+#ifndef SEC_E_ALGORITHM_MISMATCH
+# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L)
+#endif
+#ifndef SEC_E_SECURITY_QOS_FAILED
+# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L)
+#endif
+#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED
+# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L)
+#endif
+#ifndef SEC_E_NO_TGT_REPLY
+# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L)
+#endif
+#ifndef SEC_E_NO_IP_ADDRESSES
+# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L)
+#endif
+#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE
+# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L)
+#endif
+#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
+# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L)
+#endif
+#ifndef SEC_E_MAX_REFERRALS_EXCEEDED
+# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L)
+#endif
+#ifndef SEC_E_MUST_BE_KDC
+# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L)
+#endif
+#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL)
+#endif
+#ifndef SEC_E_TOO_MANY_PRINCIPALS
+# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL)
+#endif
+#ifndef SEC_E_NO_PA_DATA
+# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL)
+#endif
+#ifndef SEC_E_PKINIT_NAME_MISMATCH
+# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL)
+#endif
+#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED
+# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL)
+#endif
+#ifndef SEC_E_SHUTDOWN_IN_PROGRESS
+# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL)
+#endif
+#ifndef SEC_E_KDC_INVALID_REQUEST
+# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L)
+#endif
+#ifndef SEC_E_KDC_UNABLE_TO_REFER
+# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L)
+#endif
+#ifndef SEC_E_KDC_UNKNOWN_ETYPE
+# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_PREAUTH
+# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L)
+#endif
+#ifndef SEC_E_DELEGATION_REQUIRED
+# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L)
+#endif
+#ifndef SEC_E_BAD_BINDINGS
+# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L)
+#endif
+#ifndef SEC_E_MULTIPLE_ACCOUNTS
+# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L)
+#endif
+#ifndef SEC_E_NO_KERB_KEY
+# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L)
+#endif
+#ifndef SEC_E_CERT_WRONG_USAGE
+# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L)
+#endif
+#ifndef SEC_E_DOWNGRADE_DETECTED
+# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_REVOKED
+# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED
+# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_C
+# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L)
+#endif
+#ifndef SEC_E_PKINIT_CLIENT_FAILURE
+# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_EXPIRED
+# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L)
+#endif
+#ifndef SEC_E_NO_S4U_PROT_SUPPORT
+# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L)
+#endif
+#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE
+# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_KDC
+# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC
+# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L)
+#endif
+#ifndef SEC_E_KDC_CERT_EXPIRED
+# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL)
+#endif
+#ifndef SEC_E_KDC_CERT_REVOKED
+# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL)
+#endif
+#ifndef SEC_E_INVALID_PARAMETER
+# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
+#endif
+#ifndef SEC_E_DELEGATION_POLICY
+# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL)
+#endif
+#ifndef SEC_E_POLICY_NLTM_ONLY
+# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL)
+#endif
+
+#ifndef SEC_I_CONTINUE_NEEDED
+# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L)
+#endif
+#ifndef SEC_I_COMPLETE_NEEDED
+# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L)
+#endif
+#ifndef SEC_I_COMPLETE_AND_CONTINUE
+# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L)
+#endif
+#ifndef SEC_I_LOCAL_LOGON
+# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L)
+#endif
+#ifndef SEC_I_CONTEXT_EXPIRED
+# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L)
+#endif
+#ifndef SEC_I_INCOMPLETE_CREDENTIALS
+# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L)
+#endif
+#ifndef SEC_I_RENEGOTIATE
+# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L)
+#endif
+#ifndef SEC_I_NO_LSA_CONTEXT
+# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L)
+#endif
+#ifndef SEC_I_SIGNATURE_NEEDED
+# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
+#endif
+
+#ifndef CRYPT_E_REVOKED
+# define CRYPT_E_REVOKED ((HRESULT)0x80092010L)
+#endif
+
+#ifdef UNICODE
+# define SECFLAG_WINNT_AUTH_IDENTITY \
+ (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE
+#else
+# define SECFLAG_WINNT_AUTH_IDENTITY \
+ (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI
+#endif
+
+/*
+ * Definitions required from ntsecapi.h are directly provided below this point
+ * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
+ */
+#define KERB_WRAP_NO_ENCRYPT 0x80000001
+
+#endif /* USE_WINDOWS_SSPI */
+
+#endif /* HEADER_CURL_SSPI_H */
diff --git a/Utilities/cmcurl/lib/curl_threads.c b/Utilities/cmcurl/lib/curl_threads.c
new file mode 100644
index 000000000..a78eff5c2
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_threads.c
@@ -0,0 +1,139 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#include "curl_threads.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(USE_THREADS_POSIX)
+
+struct curl_actual_call {
+ unsigned int (*func)(void *);
+ void *arg;
+};
+
+static void *curl_thread_create_thunk(void *arg)
+{
+ struct curl_actual_call * ac = arg;
+ unsigned int (*func)(void *) = ac->func;
+ void *real_arg = ac->arg;
+
+ free(ac);
+
+ (*func)(real_arg);
+
+ return 0;
+}
+
+curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg)
+{
+ curl_thread_t t = malloc(sizeof(pthread_t));
+ struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call));
+ if(!(ac && t))
+ goto err;
+
+ ac->func = func;
+ ac->arg = arg;
+
+ if(pthread_create(t, NULL, curl_thread_create_thunk, ac) != 0)
+ goto err;
+
+ return t;
+
+err:
+ free(t);
+ free(ac);
+ return curl_thread_t_null;
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+ if(hnd != curl_thread_t_null) {
+ pthread_detach(*hnd);
+ free(hnd);
+ }
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+ int ret = (pthread_join(**hnd, NULL) == 0);
+
+ free(*hnd);
+ *hnd = curl_thread_t_null;
+
+ return ret;
+}
+
+#elif defined(USE_THREADS_WIN32)
+
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+ void *arg)
+{
+#ifdef _WIN32_WCE
+ return CreateThread(NULL, 0, func, arg, 0, NULL);
+#else
+ curl_thread_t t;
+ t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
+ if((t == 0) || (t == (curl_thread_t)-1L))
+ return curl_thread_t_null;
+ return t;
+#endif
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+ CloseHandle(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
+ (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+ int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
+#else
+ int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0);
+#endif
+
+ Curl_thread_destroy(*hnd);
+
+ *hnd = curl_thread_t_null;
+
+ return ret;
+}
+
+#endif /* USE_THREADS_* */
diff --git a/Utilities/cmcurl/lib/curl_threads.h b/Utilities/cmcurl/lib/curl_threads.h
new file mode 100644
index 000000000..9e0d14a30
--- /dev/null
+++ b/Utilities/cmcurl/lib/curl_threads.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_THREADS_H
+#define HEADER_CURL_THREADS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_THREADS_POSIX)
+# define CURL_STDCALL
+# define curl_mutex_t pthread_mutex_t
+# define curl_thread_t pthread_t *
+# define curl_thread_t_null (pthread_t *)0
+# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
+# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
+# define Curl_mutex_release(m) pthread_mutex_unlock(m)
+# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
+#elif defined(USE_THREADS_WIN32)
+# define CURL_STDCALL __stdcall
+# define curl_mutex_t CRITICAL_SECTION
+# define curl_thread_t HANDLE
+# define curl_thread_t_null (HANDLE)0
+# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
+ (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+# define Curl_mutex_init(m) InitializeCriticalSection(m)
+# else
+# define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1)
+# endif
+# define Curl_mutex_acquire(m) EnterCriticalSection(m)
+# define Curl_mutex_release(m) LeaveCriticalSection(m)
+# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+/* !checksrc! disable SPACEBEFOREPAREN 1 */
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+ void *arg);
+
+void Curl_thread_destroy(curl_thread_t hnd);
+
+int Curl_thread_join(curl_thread_t *hnd);
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* HEADER_CURL_THREADS_H */
diff --git a/Utilities/cmcurl/lib/curlx.h b/Utilities/cmcurl/lib/curlx.h
new file mode 100644
index 000000000..6168dc119
--- /dev/null
+++ b/Utilities/cmcurl/lib/curlx.h
@@ -0,0 +1,115 @@
+#ifndef HEADER_CURL_CURLX_H
+#define HEADER_CURL_CURLX_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+ functions while they still are offered publicly. They will be made library-
+ private one day */
+
+#include "strcase.h"
+/* "strcase.h" provides the strcasecompare protos */
+
+#include "strtoofft.h"
+/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
+ curl_off_t number from a given string.
+*/
+
+#include "timeval.h"
+/*
+ "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
+ don't have one and has protos for these functions:
+
+ curlx_tvnow()
+ curlx_tvdiff()
+ curlx_tvdiff_secs()
+*/
+
+#include "nonblock.h"
+/* "nonblock.h" provides curlx_nonblock() */
+
+#include "warnless.h"
+/* "warnless.h" provides functions:
+
+ curlx_ultous()
+ curlx_ultouc()
+ curlx_uztosi()
+*/
+
+/* Now setup curlx_ * names for the functions that are to become curlx_ and
+ be removed from a future libcurl official API:
+ curlx_getenv
+ curlx_mprintf (and its variations)
+ curlx_strcasecompare
+ curlx_strncasecompare
+
+*/
+
+#define curlx_getenv curl_getenv
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+ the curlx_* version instead. It makes the source code transparent and
+ easier to understand/patch. Undefine them first. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define snprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define vsprintf curlx_mvsprintf
+# define vsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
+#endif /* HEADER_CURL_CURLX_H */
+
diff --git a/Utilities/cmcurl/lib/dict.c b/Utilities/cmcurl/lib/dict.c
new file mode 100644
index 000000000..451ec389a
--- /dev/null
+++ b/Utilities/cmcurl/lib/dict.c
@@ -0,0 +1,278 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_DICT
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "dict.h"
+#include "strcase.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode dict_do(struct connectdata *conn, bool *done);
+
+/*
+ * DICT protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_dict = {
+ "DICT", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ dict_do, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_DICT, /* defport */
+ CURLPROTO_DICT, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
+{
+ char *newp = NULL;
+ char *dictp;
+ char *ptr;
+ size_t len;
+ char ch;
+ int olen=0;
+
+ CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
+ if(!newp || result)
+ return NULL;
+
+ dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
+ if(dictp) {
+ /* According to RFC2229 section 2.2, these letters need to be escaped with
+ \[letter] */
+ for(ptr = newp;
+ (ch = *ptr) != 0;
+ ptr++) {
+ if((ch <= 32) || (ch == 127) ||
+ (ch == '\'') || (ch == '\"') || (ch == '\\')) {
+ dictp[olen++] = '\\';
+ }
+ dictp[olen++] = ch;
+ }
+ dictp[olen]=0;
+ }
+ free(newp);
+ return dictp;
+}
+
+static CURLcode dict_do(struct connectdata *conn, bool *done)
+{
+ char *word;
+ char *eword;
+ char *ppath;
+ char *database = NULL;
+ char *strategy = NULL;
+ char *nthdef = NULL; /* This is not part of the protocol, but required
+ by RFC 2229 */
+ CURLcode result=CURLE_OK;
+ struct Curl_easy *data=conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+ char *path = data->state.path;
+ curl_off_t *bytecount = &data->req.bytecount;
+
+ *done = TRUE; /* unconditionally */
+
+ if(conn->bits.user_passwd) {
+ /* AUTH is missing */
+ }
+
+ if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+ strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+ strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
+
+ word = strchr(path, ':');
+ if(word) {
+ word++;
+ database = strchr(word, ':');
+ if(database) {
+ *database++ = (char)0;
+ strategy = strchr(database, ':');
+ if(strategy) {
+ *strategy++ = (char)0;
+ nthdef = strchr(strategy, ':');
+ if(nthdef) {
+ *nthdef = (char)0;
+ }
+ }
+ }
+ }
+
+ if((word == NULL) || (*word == (char)0)) {
+ infof(data, "lookup word is missing\n");
+ word=(char *)"default";
+ }
+ if((database == NULL) || (*database == (char)0)) {
+ database = (char *)"!";
+ }
+ if((strategy == NULL) || (*strategy == (char)0)) {
+ strategy = (char *)".";
+ }
+
+ eword = unescape_word(data, word);
+ if(!eword)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "MATCH "
+ "%s " /* database */
+ "%s " /* strategy */
+ "%s\r\n" /* word */
+ "QUIT\r\n",
+
+ database,
+ strategy,
+ eword
+ );
+
+ free(eword);
+
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ }
+ else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+ strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+ strncasecompare(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
+
+ word = strchr(path, ':');
+ if(word) {
+ word++;
+ database = strchr(word, ':');
+ if(database) {
+ *database++ = (char)0;
+ nthdef = strchr(database, ':');
+ if(nthdef) {
+ *nthdef = (char)0;
+ }
+ }
+ }
+
+ if((word == NULL) || (*word == (char)0)) {
+ infof(data, "lookup word is missing\n");
+ word=(char *)"default";
+ }
+ if((database == NULL) || (*database == (char)0)) {
+ database = (char *)"!";
+ }
+
+ eword = unescape_word(data, word);
+ if(!eword)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "DEFINE "
+ "%s " /* database */
+ "%s\r\n" /* word */
+ "QUIT\r\n",
+ database,
+ eword);
+
+ free(eword);
+
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ }
+ else {
+
+ ppath = strchr(path, '/');
+ if(ppath) {
+ int i;
+
+ ppath++;
+ for(i = 0; ppath[i]; i++) {
+ if(ppath[i] == ':')
+ ppath[i] = ' ';
+ }
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "%s\r\n"
+ "QUIT\r\n", ppath);
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
+ }
+ }
+
+ return CURLE_OK;
+}
+#endif /*CURL_DISABLE_DICT*/
diff --git a/Utilities/cmcurl/lib/dict.h b/Utilities/cmcurl/lib/dict.h
new file mode 100644
index 000000000..12c0f3394
--- /dev/null
+++ b/Utilities/cmcurl/lib/dict.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_DICT_H
+#define HEADER_CURL_DICT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_DICT
+extern const struct Curl_handler Curl_handler_dict;
+#endif
+
+#endif /* HEADER_CURL_DICT_H */
diff --git a/Utilities/cmcurl/lib/dotdot.c b/Utilities/cmcurl/lib/dotdot.c
new file mode 100644
index 000000000..20603bcab
--- /dev/null
+++ b/Utilities/cmcurl/lib/dotdot.c
@@ -0,0 +1,180 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "dotdot.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * "Remove Dot Segments"
+ * https://tools.ietf.org/html/rfc3986#section-5.2.4
+ */
+
+/*
+ * Curl_dedotdotify()
+ * @unittest: 1395
+ *
+ * This function gets a zero-terminated path with dot and dotdot sequences
+ * passed in and strips them off according to the rules in RFC 3986 section
+ * 5.2.4.
+ *
+ * The function handles a query part ('?' + stuff) appended but it expects
+ * that fragments ('#' + stuff) have already been cut off.
+ *
+ * RETURNS
+ *
+ * an allocated dedotdotified output string
+ */
+char *Curl_dedotdotify(const char *input)
+{
+ size_t inlen = strlen(input);
+ char *clone;
+ size_t clen = inlen; /* the length of the cloned input */
+ char *out = malloc(inlen+1);
+ char *outptr;
+ char *orgclone;
+ char *queryp;
+ if(!out)
+ return NULL; /* out of memory */
+
+ /* get a cloned copy of the input */
+ clone = strdup(input);
+ if(!clone) {
+ free(out);
+ return NULL;
+ }
+ orgclone = clone;
+ outptr = out;
+
+ if(!*clone) {
+ /* zero length string, return that */
+ free(out);
+ return clone;
+ }
+
+ /*
+ * To handle query-parts properly, we must find it and remove it during the
+ * dotdot-operation and then append it again at the end to the output
+ * string.
+ */
+ queryp = strchr(clone, '?');
+ if(queryp)
+ *queryp = 0;
+
+ do {
+
+ /* A. If the input buffer begins with a prefix of "../" or "./", then
+ remove that prefix from the input buffer; otherwise, */
+
+ if(!strncmp("./", clone, 2)) {
+ clone+=2;
+ clen-=2;
+ }
+ else if(!strncmp("../", clone, 3)) {
+ clone+=3;
+ clen-=3;
+ }
+
+ /* B. if the input buffer begins with a prefix of "/./" or "/.", where
+ "." is a complete path segment, then replace that prefix with "/" in
+ the input buffer; otherwise, */
+ else if(!strncmp("/./", clone, 3)) {
+ clone+=2;
+ clen-=2;
+ }
+ else if(!strcmp("/.", clone)) {
+ clone[1]='/';
+ clone++;
+ clen-=1;
+ }
+
+ /* C. if the input buffer begins with a prefix of "/../" or "/..", where
+ ".." is a complete path segment, then replace that prefix with "/" in
+ the input buffer and remove the last segment and its preceding "/" (if
+ any) from the output buffer; otherwise, */
+
+ else if(!strncmp("/../", clone, 4)) {
+ clone+=3;
+ clen-=3;
+ /* remove the last segment from the output buffer */
+ while(outptr > out) {
+ outptr--;
+ if(*outptr == '/')
+ break;
+ }
+ *outptr = 0; /* zero-terminate where it stops */
+ }
+ else if(!strcmp("/..", clone)) {
+ clone[2]='/';
+ clone+=2;
+ clen-=2;
+ /* remove the last segment from the output buffer */
+ while(outptr > out) {
+ outptr--;
+ if(*outptr == '/')
+ break;
+ }
+ *outptr = 0; /* zero-terminate where it stops */
+ }
+
+ /* D. if the input buffer consists only of "." or "..", then remove
+ that from the input buffer; otherwise, */
+
+ else if(!strcmp(".", clone) || !strcmp("..", clone)) {
+ *clone=0;
+ *out=0;
+ }
+
+ else {
+ /* E. move the first path segment in the input buffer to the end of
+ the output buffer, including the initial "/" character (if any) and
+ any subsequent characters up to, but not including, the next "/"
+ character or the end of the input buffer. */
+
+ do {
+ *outptr++ = *clone++;
+ clen--;
+ } while(*clone && (*clone != '/'));
+ *outptr = 0;
+ }
+
+ } while(*clone);
+
+ if(queryp) {
+ size_t qlen;
+ /* There was a query part, append that to the output. The 'clone' string
+ may now have been altered so we copy from the original input string
+ from the correct index. */
+ size_t oindex = queryp - orgclone;
+ qlen = strlen(&input[oindex]);
+ memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */
+ }
+
+ free(orgclone);
+ return out;
+}
diff --git a/Utilities/cmcurl/lib/dotdot.h b/Utilities/cmcurl/lib/dotdot.h
new file mode 100644
index 000000000..fac8e6f2a
--- /dev/null
+++ b/Utilities/cmcurl/lib/dotdot.h
@@ -0,0 +1,25 @@
+#ifndef HEADER_CURL_DOTDOT_H
+#define HEADER_CURL_DOTDOT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+char *Curl_dedotdotify(const char *input);
+#endif
diff --git a/Utilities/cmcurl/lib/easy.c b/Utilities/cmcurl/lib/easy.c
new file mode 100644
index 000000000..2b1ce9e8a
--- /dev/null
+++ b/Utilities/cmcurl/lib/easy.c
@@ -0,0 +1,1139 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/*
+ * See comment in curl_memory.h for the explanation of this sanity check.
+ */
+
+#ifdef CURLX_NO_MEMORY_CALLBACKS
+#error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined"
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "vtls/vtls.h"
+#include "url.h"
+#include "getinfo.h"
+#include "hostip.h"
+#include "share.h"
+#include "strdup.h"
+#include "progress.h"
+#include "easyif.h"
+#include "select.h"
+#include "sendf.h" /* for failf function prototype */
+#include "connect.h" /* for Curl_getconnectinfo */
+#include "slist.h"
+#include "amigaos.h"
+#include "non-ascii.h"
+#include "warnless.h"
+#include "conncache.h"
+#include "multiif.h"
+#include "sigpipe.h"
+#include "ssh.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+void Curl_version_init(void);
+
+/* win32_cleanup() is for win32 socket cleanup functionality, the opposite
+ of win32_init() */
+static void win32_cleanup(void)
+{
+#ifdef USE_WINSOCK
+ WSACleanup();
+#endif
+#ifdef USE_WINDOWS_SSPI
+ Curl_sspi_global_cleanup();
+#endif
+}
+
+/* win32_init() performs win32 socket initialization to properly setup the
+ stack to allow networking */
+static CURLcode win32_init(void)
+{
+#ifdef USE_WINSOCK
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int res;
+
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+ Error IPV6_requires_winsock2
+#endif
+
+ wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
+ res = WSAStartup(wVersionRequested, &wsaData);
+
+ if(res != 0)
+ /* Tell the user that we couldn't find a useable */
+ /* winsock.dll. */
+ return CURLE_FAILED_INIT;
+
+ /* Confirm that the Windows Sockets DLL supports what we need.*/
+ /* Note that if the DLL supports versions greater */
+ /* than wVersionRequested, it will still return */
+ /* wVersionRequested in wVersion. wHighVersion contains the */
+ /* highest supported version. */
+
+ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+ HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested) ) {
+ /* Tell the user that we couldn't find a useable */
+
+ /* winsock.dll. */
+ WSACleanup();
+ return CURLE_FAILED_INIT;
+ }
+ /* The Windows Sockets DLL is acceptable. Proceed. */
+#elif defined(USE_LWIPSOCK)
+ lwip_init();
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+ {
+ CURLcode result = Curl_sspi_global_init();
+ if(result)
+ return result;
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+/* true globals -- for curl_global_init() and curl_global_cleanup() */
+static unsigned int initialized;
+static long init_flags;
+
+/*
+ * strdup (and other memory functions) is redefined in complicated
+ * ways, but at this point it must be defined as the system-supplied strdup
+ * so the callback pointer is initialized correctly.
+ */
+#if defined(_WIN32_WCE)
+#define system_strdup _strdup
+#elif !defined(HAVE_STRDUP)
+#define system_strdup curlx_strdup
+#else
+#define system_strdup strdup
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
+#endif
+
+#ifndef __SYMBIAN32__
+/*
+ * If a memory-using function (like curl_getenv) is used before
+ * curl_global_init() is called, we need to have these pointers set already.
+ */
+curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
+curl_free_callback Curl_cfree = (curl_free_callback)free;
+curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc;
+curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup;
+curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc;
+#if defined(WIN32) && defined(UNICODE)
+curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+#endif
+#else
+/*
+ * Symbian OS doesn't support initialization to code in writable static data.
+ * Initialization will occur in the curl_global_init() call.
+ */
+curl_malloc_callback Curl_cmalloc;
+curl_free_callback Curl_cfree;
+curl_realloc_callback Curl_crealloc;
+curl_strdup_callback Curl_cstrdup;
+curl_calloc_callback Curl_ccalloc;
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+# pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#endif
+
+/**
+ * curl_global_init() globally initializes curl given a bitwise set of the
+ * different features of what to initialize.
+ */
+static CURLcode global_init(long flags, bool memoryfuncs)
+{
+ if(initialized++)
+ return CURLE_OK;
+
+ if(memoryfuncs) {
+ /* Setup the default memory functions here (again) */
+ Curl_cmalloc = (curl_malloc_callback)malloc;
+ Curl_cfree = (curl_free_callback)free;
+ Curl_crealloc = (curl_realloc_callback)realloc;
+ Curl_cstrdup = (curl_strdup_callback)system_strdup;
+ Curl_ccalloc = (curl_calloc_callback)calloc;
+#if defined(WIN32) && defined(UNICODE)
+ Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+#endif
+ }
+
+ if(flags & CURL_GLOBAL_SSL)
+ if(!Curl_ssl_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+ if(flags & CURL_GLOBAL_WIN32)
+ if(win32_init()) {
+ DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+#ifdef __AMIGA__
+ if(!Curl_amiga_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+#endif
+
+#ifdef NETWARE
+ if(netware_init()) {
+ DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
+ }
+#endif
+
+ if(Curl_resolver_global_init()) {
+ DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+ (void)Curl_ipv6works();
+
+#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
+ if(libssh2_init(0)) {
+ DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+#endif
+
+ if(flags & CURL_GLOBAL_ACK_EINTR)
+ Curl_ack_eintr = 1;
+
+ init_flags = flags;
+
+ Curl_version_init();
+
+ return CURLE_OK;
+}
+
+
+/**
+ * curl_global_init() globally initializes curl given a bitwise set of the
+ * different features of what to initialize.
+ */
+CURLcode curl_global_init(long flags)
+{
+ return global_init(flags, TRUE);
+}
+
+/*
+ * curl_global_init_mem() globally initializes curl and also registers the
+ * user provided callback routines.
+ */
+CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
+ curl_free_callback f, curl_realloc_callback r,
+ curl_strdup_callback s, curl_calloc_callback c)
+{
+ /* Invalid input, return immediately */
+ if(!m || !f || !r || !s || !c)
+ return CURLE_FAILED_INIT;
+
+ if(initialized) {
+ /* Already initialized, don't do it again, but bump the variable anyway to
+ work like curl_global_init() and require the same amount of cleanup
+ calls. */
+ initialized++;
+ return CURLE_OK;
+ }
+
+ /* set memory functions before global_init() in case it wants memory
+ functions */
+ Curl_cmalloc = m;
+ Curl_cfree = f;
+ Curl_cstrdup = s;
+ Curl_crealloc = r;
+ Curl_ccalloc = c;
+
+ /* Call the actual init function, but without setting */
+ return global_init(flags, FALSE);
+}
+
+/**
+ * curl_global_cleanup() globally cleanups curl, uses the value of
+ * "init_flags" to determine what needs to be cleaned up and what doesn't.
+ */
+void curl_global_cleanup(void)
+{
+ if(!initialized)
+ return;
+
+ if(--initialized)
+ return;
+
+ Curl_global_host_cache_dtor();
+
+ if(init_flags & CURL_GLOBAL_SSL)
+ Curl_ssl_cleanup();
+
+ Curl_resolver_global_cleanup();
+
+ if(init_flags & CURL_GLOBAL_WIN32)
+ win32_cleanup();
+
+ Curl_amiga_cleanup();
+
+#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
+ (void)libssh2_exit();
+#endif
+
+ init_flags = 0;
+}
+
+/*
+ * curl_easy_init() is the external interface to alloc, setup and init an
+ * easy handle that is returned. If anything goes wrong, NULL is returned.
+ */
+struct Curl_easy *curl_easy_init(void)
+{
+ CURLcode result;
+ struct Curl_easy *data;
+
+ /* Make sure we inited the global SSL stuff */
+ if(!initialized) {
+ result = curl_global_init(CURL_GLOBAL_DEFAULT);
+ if(result) {
+ /* something in the global init failed, return nothing */
+ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
+ return NULL;
+ }
+ }
+
+ /* We use curl_open() with undefined URL so far */
+ result = Curl_open(&data);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
+ return NULL;
+ }
+
+ return data;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(struct Curl_easy *data, CURLoption tag, ...)
+{
+ va_list arg;
+ CURLcode result;
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ va_start(arg, tag);
+
+ result = Curl_setopt(data, tag, arg);
+
+ va_end(arg);
+ return result;
+}
+
+#ifdef CURLDEBUG
+
+struct socketmonitor {
+ struct socketmonitor *next; /* the next node in the list or NULL */
+ struct pollfd socket; /* socket info of what to monitor */
+};
+
+struct events {
+ long ms; /* timeout, run the timeout function when reached */
+ bool msbump; /* set TRUE when timeout is set by callback */
+ int num_sockets; /* number of nodes in the monitor list */
+ struct socketmonitor *list; /* list of sockets to monitor */
+ int running_handles; /* store the returned number */
+};
+
+/* events_timer
+ *
+ * Callback that gets called with a new value when the timeout should be
+ * updated.
+ */
+
+static int events_timer(struct Curl_multi *multi, /* multi handle */
+ long timeout_ms, /* see above */
+ void *userp) /* private callback pointer */
+{
+ struct events *ev = userp;
+ (void)multi;
+ if(timeout_ms == -1)
+ /* timeout removed */
+ timeout_ms = 0;
+ else if(timeout_ms == 0)
+ /* timeout is already reached! */
+ timeout_ms = 1; /* trigger asap */
+
+ ev->ms = timeout_ms;
+ ev->msbump = TRUE;
+ return 0;
+}
+
+
+/* poll2cselect
+ *
+ * convert from poll() bit definitions to libcurl's CURL_CSELECT_* ones
+ */
+static int poll2cselect(int pollmask)
+{
+ int omask=0;
+ if(pollmask & POLLIN)
+ omask |= CURL_CSELECT_IN;
+ if(pollmask & POLLOUT)
+ omask |= CURL_CSELECT_OUT;
+ if(pollmask & POLLERR)
+ omask |= CURL_CSELECT_ERR;
+ return omask;
+}
+
+
+/* socketcb2poll
+ *
+ * convert from libcurl' CURL_POLL_* bit definitions to poll()'s
+ */
+static short socketcb2poll(int pollmask)
+{
+ short omask=0;
+ if(pollmask & CURL_POLL_IN)
+ omask |= POLLIN;
+ if(pollmask & CURL_POLL_OUT)
+ omask |= POLLOUT;
+ return omask;
+}
+
+/* events_socket
+ *
+ * Callback that gets called with information about socket activity to
+ * monitor.
+ */
+static int events_socket(struct Curl_easy *easy, /* easy handle */
+ curl_socket_t s, /* socket */
+ int what, /* see above */
+ void *userp, /* private callback
+ pointer */
+ void *socketp) /* private socket
+ pointer */
+{
+ struct events *ev = userp;
+ struct socketmonitor *m;
+ struct socketmonitor *prev=NULL;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) easy;
+#endif
+ (void)socketp;
+
+ m = ev->list;
+ while(m) {
+ if(m->socket.fd == s) {
+
+ if(what == CURL_POLL_REMOVE) {
+ struct socketmonitor *nxt = m->next;
+ /* remove this node from the list of monitored sockets */
+ if(prev)
+ prev->next = nxt;
+ else
+ ev->list = nxt;
+ free(m);
+ m = nxt;
+ infof(easy, "socket cb: socket %d REMOVED\n", s);
+ }
+ else {
+ /* The socket 's' is already being monitored, update the activity
+ mask. Convert from libcurl bitmask to the poll one. */
+ m->socket.events = socketcb2poll(what);
+ infof(easy, "socket cb: socket %d UPDATED as %s%s\n", s,
+ what&CURL_POLL_IN?"IN":"",
+ what&CURL_POLL_OUT?"OUT":"");
+ }
+ break;
+ }
+ prev = m;
+ m = m->next; /* move to next node */
+ }
+ if(!m) {
+ if(what == CURL_POLL_REMOVE) {
+ /* this happens a bit too often, libcurl fix perhaps? */
+ /* fprintf(stderr,
+ "%s: socket %d asked to be REMOVED but not present!\n",
+ __func__, s); */
+ }
+ else {
+ m = malloc(sizeof(struct socketmonitor));
+ if(m) {
+ m->next = ev->list;
+ m->socket.fd = s;
+ m->socket.events = socketcb2poll(what);
+ m->socket.revents = 0;
+ ev->list = m;
+ infof(easy, "socket cb: socket %d ADDED as %s%s\n", s,
+ what&CURL_POLL_IN?"IN":"",
+ what&CURL_POLL_OUT?"OUT":"");
+ }
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * events_setup()
+ *
+ * Do the multi handle setups that only event-based transfers need.
+ */
+static void events_setup(struct Curl_multi *multi, struct events *ev)
+{
+ /* timer callback */
+ curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, events_timer);
+ curl_multi_setopt(multi, CURLMOPT_TIMERDATA, ev);
+
+ /* socket callback */
+ curl_multi_setopt(multi, CURLMOPT_SOCKETFUNCTION, events_socket);
+ curl_multi_setopt(multi, CURLMOPT_SOCKETDATA, ev);
+}
+
+
+/* wait_or_timeout()
+ *
+ * waits for activity on any of the given sockets, or the timeout to trigger.
+ */
+
+static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
+{
+ bool done = FALSE;
+ CURLMcode mcode = CURLM_OK;
+ CURLcode result = CURLE_OK;
+
+ while(!done) {
+ CURLMsg *msg;
+ struct socketmonitor *m;
+ struct pollfd *f;
+ struct pollfd fds[4];
+ int numfds=0;
+ int pollrc;
+ int i;
+ struct timeval before;
+ struct timeval after;
+
+ /* populate the fds[] array */
+ for(m = ev->list, f=&fds[0]; m; m = m->next) {
+ f->fd = m->socket.fd;
+ f->events = m->socket.events;
+ f->revents = 0;
+ /* fprintf(stderr, "poll() %d check socket %d\n", numfds, f->fd); */
+ f++;
+ numfds++;
+ }
+
+ /* get the time stamp to use to figure out how long poll takes */
+ before = curlx_tvnow();
+
+ /* wait for activity or timeout */
+ pollrc = Curl_poll(fds, numfds, (int)ev->ms);
+
+ after = curlx_tvnow();
+
+ ev->msbump = FALSE; /* reset here */
+
+ if(0 == pollrc) {
+ /* timeout! */
+ ev->ms = 0;
+ /* fprintf(stderr, "call curl_multi_socket_action(TIMEOUT)\n"); */
+ mcode = curl_multi_socket_action(multi, CURL_SOCKET_TIMEOUT, 0,
+ &ev->running_handles);
+ }
+ else if(pollrc > 0) {
+ /* loop over the monitored sockets to see which ones had activity */
+ for(i = 0; i< numfds; i++) {
+ if(fds[i].revents) {
+ /* socket activity, tell libcurl */
+ int act = poll2cselect(fds[i].revents); /* convert */
+ infof(multi->easyp, "call curl_multi_socket_action(socket %d)\n",
+ fds[i].fd);
+ mcode = curl_multi_socket_action(multi, fds[i].fd, act,
+ &ev->running_handles);
+ }
+ }
+
+ if(!ev->msbump) {
+ /* If nothing updated the timeout, we decrease it by the spent time.
+ * If it was updated, it has the new timeout time stored already.
+ */
+ time_t timediff = curlx_tvdiff(after, before);
+ if(timediff > 0) {
+ if(timediff > ev->ms)
+ ev->ms = 0;
+ else
+ ev->ms -= (long)timediff;
+ }
+ }
+ }
+ else
+ return CURLE_RECV_ERROR;
+
+ if(mcode)
+ return CURLE_URL_MALFORMAT; /* TODO: return a proper error! */
+
+ /* we don't really care about the "msgs_in_queue" value returned in the
+ second argument */
+ msg = curl_multi_info_read(multi, &pollrc);
+ if(msg) {
+ result = msg->data.result;
+ done = TRUE;
+ }
+ }
+
+ return result;
+}
+
+
+/* easy_events()
+ *
+ * Runs a transfer in a blocking manner using the events-based API
+ */
+static CURLcode easy_events(struct Curl_multi *multi)
+{
+ struct events evs= {2, FALSE, 0, NULL, 0};
+
+ /* if running event-based, do some further multi inits */
+ events_setup(multi, &evs);
+
+ return wait_or_timeout(multi, &evs);
+}
+#else /* CURLDEBUG */
+/* when not built with debug, this function doesn't exist */
+#define easy_events(x) CURLE_NOT_BUILT_IN
+#endif
+
+static CURLcode easy_transfer(struct Curl_multi *multi)
+{
+ bool done = FALSE;
+ CURLMcode mcode = CURLM_OK;
+ CURLcode result = CURLE_OK;
+ struct timeval before;
+ int without_fds = 0; /* count number of consecutive returns from
+ curl_multi_wait() without any filedescriptors */
+
+ while(!done && !mcode) {
+ int still_running = 0;
+ int rc;
+
+ before = curlx_tvnow();
+ mcode = curl_multi_wait(multi, NULL, 0, 1000, &rc);
+
+ if(!mcode) {
+ if(!rc) {
+ struct timeval after = curlx_tvnow();
+
+ /* If it returns without any filedescriptor instantly, we need to
+ avoid busy-looping during periods where it has nothing particular
+ to wait for */
+ if(curlx_tvdiff(after, before) <= 10) {
+ without_fds++;
+ if(without_fds > 2) {
+ int sleep_ms = without_fds < 10 ? (1 << (without_fds - 1)) : 1000;
+ Curl_wait_ms(sleep_ms);
+ }
+ }
+ else
+ /* it wasn't "instant", restart counter */
+ without_fds = 0;
+ }
+ else
+ /* got file descriptor, restart counter */
+ without_fds = 0;
+
+ mcode = curl_multi_perform(multi, &still_running);
+ }
+
+ /* only read 'still_running' if curl_multi_perform() return OK */
+ if(!mcode && !still_running) {
+ CURLMsg *msg = curl_multi_info_read(multi, &rc);
+ if(msg) {
+ result = msg->data.result;
+ done = TRUE;
+ }
+ }
+ }
+
+ /* Make sure to return some kind of error if there was a multi problem */
+ if(mcode) {
+ result = (mcode == CURLM_OUT_OF_MEMORY) ? CURLE_OUT_OF_MEMORY :
+ /* The other multi errors should never happen, so return
+ something suitably generic */
+ CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ return result;
+}
+
+
+/*
+ * easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
+ *
+ * CONCEPT: This function creates a multi handle, adds the easy handle to it,
+ * runs curl_multi_perform() until the transfer is done, then detaches the
+ * easy handle, destroys the multi handle and returns the easy handle's return
+ * code.
+ *
+ * REALITY: it can't just create and destroy the multi handle that easily. It
+ * needs to keep it around since if this easy handle is used again by this
+ * function, the same multi handle must be re-used so that the same pools and
+ * caches can be used.
+ *
+ * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
+ * instead of curl_multi_perform() and use curl_multi_socket_action().
+ */
+static CURLcode easy_perform(struct Curl_easy *data, bool events)
+{
+ struct Curl_multi *multi;
+ CURLMcode mcode;
+ CURLcode result = CURLE_OK;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(data->multi) {
+ failf(data, "easy handle already used in multi handle");
+ return CURLE_FAILED_INIT;
+ }
+
+ if(data->multi_easy)
+ multi = data->multi_easy;
+ else {
+ /* this multi handle will only ever have a single easy handled attached
+ to it, so make it use minimal hashes */
+ multi = Curl_multi_handle(1, 3);
+ if(!multi)
+ return CURLE_OUT_OF_MEMORY;
+ data->multi_easy = multi;
+ }
+
+ /* Copy the MAXCONNECTS option to the multi handle */
+ curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
+
+ mcode = curl_multi_add_handle(multi, data);
+ if(mcode) {
+ curl_multi_cleanup(multi);
+ if(mcode == CURLM_OUT_OF_MEMORY)
+ return CURLE_OUT_OF_MEMORY;
+ return CURLE_FAILED_INIT;
+ }
+
+ sigpipe_ignore(data, &pipe_st);
+
+ /* assign this after curl_multi_add_handle() since that function checks for
+ it and rejects this handle otherwise */
+ data->multi = multi;
+
+ /* run the transfer */
+ result = events ? easy_events(multi) : easy_transfer(multi);
+
+ /* ignoring the return code isn't nice, but atm we can't really handle
+ a failure here, room for future improvement! */
+ (void)curl_multi_remove_handle(multi, data);
+
+ sigpipe_restore(&pipe_st);
+
+ /* The multi handle is kept alive, owned by the easy handle */
+ return result;
+}
+
+
+/*
+ * curl_easy_perform() is the external interface that performs a blocking
+ * transfer as previously setup.
+ */
+CURLcode curl_easy_perform(struct Curl_easy *data)
+{
+ return easy_perform(data, FALSE);
+}
+
+#ifdef CURLDEBUG
+/*
+ * curl_easy_perform_ev() is the external interface that performs a blocking
+ * transfer using the event-based API internally.
+ */
+CURLcode curl_easy_perform_ev(struct Curl_easy *data)
+{
+ return easy_perform(data, TRUE);
+}
+
+#endif
+
+/*
+ * curl_easy_cleanup() is the external interface to cleaning/freeing the given
+ * easy handle.
+ */
+void curl_easy_cleanup(struct Curl_easy *data)
+{
+ SIGPIPE_VARIABLE(pipe_st);
+
+ if(!data)
+ return;
+
+ sigpipe_ignore(data, &pipe_st);
+ Curl_close(data);
+ sigpipe_restore(&pipe_st);
+}
+
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
+#undef curl_easy_getinfo
+CURLcode curl_easy_getinfo(struct Curl_easy *data, CURLINFO info, ...)
+{
+ va_list arg;
+ void *paramp;
+ CURLcode result;
+
+ va_start(arg, info);
+ paramp = va_arg(arg, void *);
+
+ result = Curl_getinfo(data, info, paramp);
+
+ va_end(arg);
+ return result;
+}
+
+/*
+ * curl_easy_duphandle() is an external interface to allow duplication of a
+ * given input easy handle. The returned handle will be a new working handle
+ * with all options set exactly as the input source handle.
+ */
+struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
+{
+ struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy));
+ if(NULL == outcurl)
+ goto fail;
+
+ /*
+ * We setup a few buffers we need. We should probably make them
+ * get setup on-demand in the code, as that would probably decrease
+ * the likeliness of us forgetting to init a buffer here in the future.
+ */
+ outcurl->set.buffer_size = data->set.buffer_size;
+ outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1);
+ if(!outcurl->state.buffer)
+ goto fail;
+
+ outcurl->state.headerbuff = malloc(HEADERSIZE);
+ if(!outcurl->state.headerbuff)
+ goto fail;
+ outcurl->state.headersize = HEADERSIZE;
+
+ /* copy all userdefined values */
+ if(Curl_dupset(outcurl, data))
+ goto fail;
+
+ /* the connection cache is setup on demand */
+ outcurl->state.conn_cache = NULL;
+
+ outcurl->state.lastconnect = NULL;
+
+ outcurl->progress.flags = data->progress.flags;
+ outcurl->progress.callback = data->progress.callback;
+
+ if(data->cookies) {
+ /* If cookies are enabled in the parent handle, we enable them
+ in the clone as well! */
+ outcurl->cookies = Curl_cookie_init(data,
+ data->cookies->filename,
+ outcurl->cookies,
+ data->set.cookiesession);
+ if(!outcurl->cookies)
+ goto fail;
+ }
+
+ /* duplicate all values in 'change' */
+ if(data->change.cookielist) {
+ outcurl->change.cookielist =
+ Curl_slist_duplicate(data->change.cookielist);
+ if(!outcurl->change.cookielist)
+ goto fail;
+ }
+
+ if(data->change.url) {
+ outcurl->change.url = strdup(data->change.url);
+ if(!outcurl->change.url)
+ goto fail;
+ outcurl->change.url_alloc = TRUE;
+ }
+
+ if(data->change.referer) {
+ outcurl->change.referer = strdup(data->change.referer);
+ if(!outcurl->change.referer)
+ goto fail;
+ outcurl->change.referer_alloc = TRUE;
+ }
+
+ /* Clone the resolver handle, if present, for the new handle */
+ if(Curl_resolver_duphandle(&outcurl->state.resolver,
+ data->state.resolver))
+ goto fail;
+
+ Curl_convert_setup(outcurl);
+
+ Curl_initinfo(outcurl);
+
+ outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
+ /* we reach this point and thus we are OK */
+
+ return outcurl;
+
+ fail:
+
+ if(outcurl) {
+ curl_slist_free_all(outcurl->change.cookielist);
+ outcurl->change.cookielist = NULL;
+ Curl_safefree(outcurl->state.buffer);
+ Curl_safefree(outcurl->state.headerbuff);
+ Curl_safefree(outcurl->change.url);
+ Curl_safefree(outcurl->change.referer);
+ Curl_freeset(outcurl);
+ free(outcurl);
+ }
+
+ return NULL;
+}
+
+/*
+ * curl_easy_reset() is an external interface that allows an app to re-
+ * initialize a session handle to the default values.
+ */
+void curl_easy_reset(struct Curl_easy *data)
+{
+ Curl_safefree(data->state.pathbuffer);
+
+ data->state.path = NULL;
+
+ Curl_free_request_state(data);
+
+ /* zero out UserDefined data: */
+ Curl_freeset(data);
+ memset(&data->set, 0, sizeof(struct UserDefined));
+ (void)Curl_init_userdefined(&data->set);
+
+ /* zero out Progress data: */
+ memset(&data->progress, 0, sizeof(struct Progress));
+
+ /* zero out PureInfo data: */
+ Curl_initinfo(data);
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+
+ /* zero out authentication data: */
+ memset(&data->state.authhost, 0, sizeof(struct auth));
+ memset(&data->state.authproxy, 0, sizeof(struct auth));
+}
+
+/*
+ * curl_easy_pause() allows an application to pause or unpause a specific
+ * transfer and direction. This function sets the full new state for the
+ * current connection this easy handle operates on.
+ *
+ * NOTE: if you have the receiving paused and you call this function to remove
+ * the pausing, you may get your write callback called at this point.
+ *
+ * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
+ */
+CURLcode curl_easy_pause(struct Curl_easy *data, int action)
+{
+ struct SingleRequest *k = &data->req;
+ CURLcode result = CURLE_OK;
+
+ /* first switch off both pause bits */
+ int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
+
+ /* set the new desired pause bits */
+ newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
+ ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+
+ /* put it back in the keepon */
+ k->keepon = newstate;
+
+ if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempcount) {
+ /* there are buffers for sending that can be delivered as the receive
+ pausing is lifted! */
+ unsigned int i;
+ unsigned int count = data->state.tempcount;
+ struct tempbuf writebuf[3]; /* there can only be three */
+
+ /* copy the structs to allow for immediate re-pausing */
+ for(i=0; i < data->state.tempcount; i++) {
+ writebuf[i] = data->state.tempwrite[i];
+ data->state.tempwrite[i].buf = NULL;
+ }
+ data->state.tempcount = 0;
+
+ for(i=0; i < count; i++) {
+ /* even if one function returns error, this loops through and frees all
+ buffers */
+ if(!result)
+ result = Curl_client_chop_write(data->easy_conn,
+ writebuf[i].type,
+ writebuf[i].buf,
+ writebuf[i].len);
+ free(writebuf[i].buf);
+ }
+ if(result)
+ return result;
+ }
+
+ /* if there's no error and we're not pausing both directions, we want
+ to have this handle checked soon */
+ if(!result &&
+ ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) !=
+ (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) )
+ Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
+
+ return result;
+}
+
+
+static CURLcode easy_connection(struct Curl_easy *data,
+ curl_socket_t *sfd,
+ struct connectdata **connp)
+{
+ if(data == NULL)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
+ if(!data->set.connect_only) {
+ failf(data, "CONNECT_ONLY is required!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+
+ *sfd = Curl_getconnectinfo(data, connp);
+
+ if(*sfd == CURL_SOCKET_BAD) {
+ failf(data, "Failed to get recent socket");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ * Returns CURLE_OK on success, error code on error.
+ */
+CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
+ size_t *n)
+{
+ curl_socket_t sfd;
+ CURLcode result;
+ ssize_t n1;
+ struct connectdata *c;
+
+ result = easy_connection(data, &sfd, &c);
+ if(result)
+ return result;
+
+ *n = 0;
+ result = Curl_read(c, sfd, buffer, buflen, &n1);
+
+ if(result)
+ return result;
+
+ *n = (size_t)n1;
+
+ return CURLE_OK;
+}
+
+/*
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
+ size_t buflen, size_t *n)
+{
+ curl_socket_t sfd;
+ CURLcode result;
+ ssize_t n1;
+ struct connectdata *c = NULL;
+
+ result = easy_connection(data, &sfd, &c);
+ if(result)
+ return result;
+
+ *n = 0;
+ result = Curl_write(c, sfd, buffer, buflen, &n1);
+
+ if(n1 == -1)
+ return CURLE_SEND_ERROR;
+
+ /* detect EAGAIN */
+ if(!result && !n1)
+ return CURLE_AGAIN;
+
+ *n = (size_t)n1;
+
+ return result;
+}
diff --git a/Utilities/cmcurl/lib/easyif.h b/Utilities/cmcurl/lib/easyif.h
new file mode 100644
index 000000000..f6132cc70
--- /dev/null
+++ b/Utilities/cmcurl/lib/easyif.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_EASYIF_H
+#define HEADER_CURL_EASYIF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by easy.c
+ */
+#ifdef CURLDEBUG
+CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
+#endif
+
+#endif /* HEADER_CURL_EASYIF_H */
+
diff --git a/Utilities/cmcurl/lib/escape.c b/Utilities/cmcurl/lib/escape.c
new file mode 100644
index 000000000..973aeb6ea
--- /dev/null
+++ b/Utilities/cmcurl/lib/escape.c
@@ -0,0 +1,242 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred. */
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "escape.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Portable character check (remember EBCDIC). Do not use isalnum() because
+ its behavior is altered by the current locale.
+ See https://tools.ietf.org/html/rfc3986#section-2.3
+*/
+static bool Curl_isunreserved(unsigned char in)
+{
+ switch(in) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case '-': case '.': case '_': case '~':
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_escape(const char *string, int inlength)
+{
+ return curl_easy_escape(NULL, string, inlength);
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_unescape(const char *string, int length)
+{
+ return curl_easy_unescape(NULL, string, length, NULL);
+}
+
+char *curl_easy_escape(struct Curl_easy *data, const char *string,
+ int inlength)
+{
+ size_t alloc;
+ char *ns;
+ char *testing_ptr = NULL;
+ unsigned char in; /* we need to treat the characters unsigned */
+ size_t newlen;
+ size_t strindex=0;
+ size_t length;
+ CURLcode result;
+
+ if(inlength < 0)
+ return NULL;
+
+ alloc = (inlength?(size_t)inlength:strlen(string))+1;
+ newlen = alloc;
+
+ ns = malloc(alloc);
+ if(!ns)
+ return NULL;
+
+ length = alloc-1;
+ while(length--) {
+ in = *string;
+
+ if(Curl_isunreserved(in))
+ /* just copy this */
+ ns[strindex++]=in;
+ else {
+ /* encode it */
+ newlen += 2; /* the size grows with two, since this'll become a %XX */
+ if(newlen > alloc) {
+ alloc *= 2;
+ testing_ptr = Curl_saferealloc(ns, alloc);
+ if(!testing_ptr)
+ return NULL;
+ ns = testing_ptr;
+ }
+
+ result = Curl_convert_to_network(data, &in, 1);
+ if(result) {
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ free(ns);
+ return NULL;
+ }
+
+ snprintf(&ns[strindex], 4, "%%%02X", in);
+
+ strindex+=3;
+ }
+ string++;
+ }
+ ns[strindex]=0; /* terminate it */
+ return ns;
+}
+
+/*
+ * Curl_urldecode() URL decodes the given string.
+ *
+ * Optionally detects control characters (byte codes lower than 32) in the
+ * data and rejects such data.
+ *
+ * Returns a pointer to a malloced string in *ostring with length given in
+ * *olen. If length == 0, the length is assumed to be strlen(string).
+ *
+ */
+CURLcode Curl_urldecode(struct Curl_easy *data,
+ const char *string, size_t length,
+ char **ostring, size_t *olen,
+ bool reject_ctrl)
+{
+ size_t alloc = (length?length:strlen(string))+1;
+ char *ns = malloc(alloc);
+ unsigned char in;
+ size_t strindex=0;
+ unsigned long hex;
+ CURLcode result;
+
+ if(!ns)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(--alloc > 0) {
+ in = *string;
+ if(('%' == in) && (alloc > 2) &&
+ ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
+ /* this is two hexadecimal digits following a '%' */
+ char hexstr[3];
+ char *ptr;
+ hexstr[0] = string[1];
+ hexstr[1] = string[2];
+ hexstr[2] = 0;
+
+ hex = strtoul(hexstr, &ptr, 16);
+
+ in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
+
+ result = Curl_convert_from_network(data, &in, 1);
+ if(result) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(ns);
+ return result;
+ }
+
+ string+=2;
+ alloc-=2;
+ }
+
+ if(reject_ctrl && (in < 0x20)) {
+ free(ns);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ ns[strindex++] = in;
+ string++;
+ }
+ ns[strindex]=0; /* terminate it */
+
+ if(olen)
+ /* store output size */
+ *olen = strindex;
+
+ /* store output string */
+ *ostring = ns;
+
+ return CURLE_OK;
+}
+
+/*
+ * Unescapes the given URL escaped string of given length. Returns a
+ * pointer to a malloced string with length given in *olen.
+ * If length == 0, the length is assumed to be strlen(string).
+ * If olen == NULL, no output length is stored.
+ */
+char *curl_easy_unescape(struct Curl_easy *data, const char *string,
+ int length, int *olen)
+{
+ char *str = NULL;
+ if(length >= 0) {
+ size_t inputlen = length;
+ size_t outputlen;
+ CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen,
+ FALSE);
+ if(res)
+ return NULL;
+
+ if(olen) {
+ if(outputlen <= (size_t) INT_MAX)
+ *olen = curlx_uztosi(outputlen);
+ else
+ /* too large to return in an int, fail! */
+ Curl_safefree(str);
+ }
+ }
+ return str;
+}
+
+/* For operating systems/environments that use different malloc/free
+ systems for the app and for this library, we provide a free that uses
+ the library's memory system */
+void curl_free(void *p)
+{
+ free(p);
+}
diff --git a/Utilities/cmcurl/lib/escape.h b/Utilities/cmcurl/lib/escape.h
new file mode 100644
index 000000000..638666f03
--- /dev/null
+++ b/Utilities/cmcurl/lib/escape.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_ESCAPE_H
+#define HEADER_CURL_ESCAPE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred. */
+
+CURLcode Curl_urldecode(struct Curl_easy *data,
+ const char *string, size_t length,
+ char **ostring, size_t *olen,
+ bool reject_crlf);
+
+#endif /* HEADER_CURL_ESCAPE_H */
+
diff --git a/Utilities/cmcurl/lib/file.c b/Utilities/cmcurl/lib/file.c
new file mode 100644
index 000000000..c804d75e1
--- /dev/null
+++ b/Utilities/cmcurl/lib/file.c
@@ -0,0 +1,594 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FILE
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "strtoofft.h"
+#include "urldata.h"
+#include <curl/curl.h>
+#include "progress.h"
+#include "sendf.h"
+#include "escape.h"
+#include "file.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "transfer.h"
+#include "url.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \
+ defined(__SYMBIAN32__)
+#define DOS_FILESYSTEM 1
+#endif
+
+#ifdef OPEN_NEEDS_ARG3
+# define open_readonly(p,f) open((p),(f),(0))
+#else
+# define open_readonly(p,f) open((p),(f))
+#endif
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode file_do(struct connectdata *, bool *done);
+static CURLcode file_done(struct connectdata *conn,
+ CURLcode status, bool premature);
+static CURLcode file_connect(struct connectdata *conn, bool *done);
+static CURLcode file_disconnect(struct connectdata *conn,
+ bool dead_connection);
+static CURLcode file_setup_connection(struct connectdata *conn);
+
+/*
+ * FILE scheme handler.
+ */
+
+const struct Curl_handler Curl_handler_file = {
+ "FILE", /* scheme */
+ file_setup_connection, /* setup_connection */
+ file_do, /* do_it */
+ file_done, /* done */
+ ZERO_NULL, /* do_more */
+ file_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ file_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ 0, /* defport */
+ CURLPROTO_FILE, /* protocol */
+ PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+static CURLcode file_setup_connection(struct connectdata *conn)
+{
+ /* allocate the FILE specific struct */
+ conn->data->req.protop = calloc(1, sizeof(struct FILEPROTO));
+ if(!conn->data->req.protop)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+ /*
+ Check if this is a range download, and if so, set the internal variables
+ properly. This code is copied from the FTP implementation and might as
+ well be factored out.
+ */
+static CURLcode file_range(struct connectdata *conn)
+{
+ curl_off_t from, to;
+ curl_off_t totalsize=-1;
+ char *ptr;
+ char *ptr2;
+ struct Curl_easy *data = conn->data;
+
+ if(data->state.use_range && data->state.range) {
+ from=curlx_strtoofft(data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if(ptr == ptr2) {
+ /* we didn't get any digit */
+ to=-1;
+ }
+ if((-1 == to) && (from>=0)) {
+ /* X - */
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE %" CURL_FORMAT_CURL_OFF_T " to end of file\n",
+ from));
+ }
+ else if(from < 0) {
+ /* -Y */
+ data->req.maxdownload = -from;
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE the last %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ -from));
+ }
+ else {
+ /* X-Y */
+ totalsize = to-from;
+ data->req.maxdownload = totalsize+1; /* include last byte */
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE from %" CURL_FORMAT_CURL_OFF_T
+ " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ from, data->req.maxdownload));
+ }
+ DEBUGF(infof(data, "range-download from %" CURL_FORMAT_CURL_OFF_T
+ " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ from, to, data->req.maxdownload));
+ }
+ else
+ data->req.maxdownload = -1;
+ return CURLE_OK;
+}
+
+/*
+ * file_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time. We emulate a
+ * connect-then-transfer protocol and "connect" to the file here
+ */
+static CURLcode file_connect(struct connectdata *conn, bool *done)
+{
+ struct Curl_easy *data = conn->data;
+ char *real_path;
+ struct FILEPROTO *file = data->req.protop;
+ int fd;
+#ifdef DOS_FILESYSTEM
+ size_t i;
+ char *actual_path;
+#endif
+ size_t real_path_len;
+
+ CURLcode result = Curl_urldecode(data, data->state.path, 0, &real_path,
+ &real_path_len, FALSE);
+ if(result)
+ return result;
+
+#ifdef DOS_FILESYSTEM
+ /* If the first character is a slash, and there's
+ something that looks like a drive at the beginning of
+ the path, skip the slash. If we remove the initial
+ slash in all cases, paths without drive letters end up
+ relative to the current directory which isn't how
+ browsers work.
+
+ Some browsers accept | instead of : as the drive letter
+ separator, so we do too.
+
+ On other platforms, we need the slash to indicate an
+ absolute pathname. On Windows, absolute paths start
+ with a drive letter.
+ */
+ actual_path = real_path;
+ if((actual_path[0] == '/') &&
+ actual_path[1] &&
+ (actual_path[2] == ':' || actual_path[2] == '|')) {
+ actual_path[2] = ':';
+ actual_path++;
+ real_path_len--;
+ }
+
+ /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
+ for(i=0; i < real_path_len; ++i)
+ if(actual_path[i] == '/')
+ actual_path[i] = '\\';
+ else if(!actual_path[i]) { /* binary zero */
+ Curl_safefree(real_path);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
+ file->path = actual_path;
+#else
+ if(memchr(real_path, 0, real_path_len)) {
+ /* binary zeroes indicate foul play */
+ Curl_safefree(real_path);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ fd = open_readonly(real_path, O_RDONLY);
+ file->path = real_path;
+#endif
+ file->freepath = real_path; /* free this when done */
+
+ file->fd = fd;
+ if(!data->set.upload && (fd == -1)) {
+ failf(data, "Couldn't open file %s", data->state.path);
+ file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+ return CURLE_FILE_COULDNT_READ_FILE;
+ }
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+static CURLcode file_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ (void)status; /* not used */
+ (void)premature; /* not used */
+
+ if(file) {
+ Curl_safefree(file->freepath);
+ file->path = NULL;
+ if(file->fd != -1)
+ close(file->fd);
+ file->fd = -1;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode file_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ (void)dead_connection; /* not used */
+
+ if(file) {
+ Curl_safefree(file->freepath);
+ file->path = NULL;
+ if(file->fd != -1)
+ close(file->fd);
+ file->fd = -1;
+ }
+
+ return CURLE_OK;
+}
+
+#ifdef DOS_FILESYSTEM
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct connectdata *conn)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ const char *dir = strchr(file->path, DIRSEP);
+ int fd;
+ int mode;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ char *buf = data->state.buffer;
+ size_t nread;
+ size_t nwrite;
+ curl_off_t bytecount = 0;
+ struct_stat file_stat;
+ const char *buf2;
+
+ /*
+ * Since FILE: doesn't do the full init, we need to provide some extra
+ * assignments here.
+ */
+ conn->data->req.upload_fromhere = buf;
+
+ if(!dir)
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+ if(!dir[1])
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+#ifdef O_BINARY
+#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY
+#else
+#define MODE_DEFAULT O_WRONLY|O_CREAT
+#endif
+
+ if(data->state.resume_from)
+ mode = MODE_DEFAULT|O_APPEND;
+ else
+ mode = MODE_DEFAULT|O_TRUNC;
+
+ fd = open(file->path, mode, conn->data->set.new_file_perms);
+ if(fd < 0) {
+ failf(data, "Can't open %s for writing", file->path);
+ return CURLE_WRITE_ERROR;
+ }
+
+ if(-1 != data->state.infilesize)
+ /* known size of data to "upload" */
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+ /* treat the negative resume offset value as the case of "-" */
+ if(data->state.resume_from < 0) {
+ if(fstat(fd, &file_stat)) {
+ close(fd);
+ failf(data, "Can't get the size of %s", file->path);
+ return CURLE_WRITE_ERROR;
+ }
+ data->state.resume_from = (curl_off_t)file_stat.st_size;
+ }
+
+ while(!result) {
+ int readcount;
+ result = Curl_fillreadbuffer(conn, (int)data->set.buffer_size, &readcount);
+ if(result)
+ break;
+
+ if(readcount <= 0) /* fix questionable compare error. curlvms */
+ break;
+
+ nread = (size_t)readcount;
+
+ /*skip bytes before resume point*/
+ if(data->state.resume_from) {
+ if((curl_off_t)nread <= data->state.resume_from) {
+ data->state.resume_from -= nread;
+ nread = 0;
+ buf2 = buf;
+ }
+ else {
+ buf2 = buf + data->state.resume_from;
+ nread -= (size_t)data->state.resume_from;
+ data->state.resume_from = 0;
+ }
+ }
+ else
+ buf2 = buf;
+
+ /* write the data to the target */
+ nwrite = write(fd, buf2, nread);
+ if(nwrite != nread) {
+ result = CURLE_SEND_ERROR;
+ break;
+ }
+
+ bytecount += nread;
+
+ Curl_pgrsSetUploadCounter(data, bytecount);
+
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_tvnow());
+ }
+ if(!result && Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ close(fd);
+
+ return result;
+}
+
+/*
+ * file_do() is the protocol-specific function for the do-phase, separated
+ * from the connect-phase above. Other protocols merely setup the transfer in
+ * the do-phase, to have it done in the main transfer loop but since some
+ * platforms we support don't allow select()ing etc on file handles (as
+ * opposed to sockets) we instead perform the whole do-operation in this
+ * function.
+ */
+static CURLcode file_do(struct connectdata *conn, bool *done)
+{
+ /* This implementation ignores the host name in conformance with
+ RFC 1738. Only local files (reachable via the standard file system)
+ are supported. This means that files on remotely mounted directories
+ (via NFS, Samba, NT sharing) can be accessed through a file:// URL
+ */
+ CURLcode result = CURLE_OK;
+ struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
+ Windows version to have a different struct without
+ having to redefine the simple word 'stat' */
+ curl_off_t expected_size=0;
+ bool size_known;
+ bool fstated=FALSE;
+ ssize_t nread;
+ struct Curl_easy *data = conn->data;
+ char *buf = data->state.buffer;
+ curl_off_t bytecount = 0;
+ int fd;
+ struct FILEPROTO *file;
+
+ *done = TRUE; /* unconditionally */
+
+ Curl_initinfo(data);
+ Curl_pgrsStartNow(data);
+
+ if(data->set.upload)
+ return file_upload(conn);
+
+ file = conn->data->req.protop;
+
+ /* get the fd from the connection phase */
+ fd = file->fd;
+
+ /* VMS: This only works reliable for STREAMLF files */
+ if(-1 != fstat(fd, &statbuf)) {
+ /* we could stat it, then read out the size */
+ expected_size = statbuf.st_size;
+ /* and store the modification time */
+ data->info.filetime = (long)statbuf.st_mtime;
+ fstated = TRUE;
+ }
+
+ if(fstated && !data->state.range && data->set.timecondition) {
+ if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ }
+
+ /* If we have selected NOBODY and HEADER, it means that we only want file
+ information. Which for FILE can't be much more than the file size and
+ date. */
+ if(data->set.opt_no_body && data->set.include_header && fstated) {
+ time_t filetime;
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+ char header[80];
+ snprintf(header, sizeof(header),
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", expected_size);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, header, 0);
+ if(result)
+ return result;
+
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH,
+ (char *)"Accept-ranges: bytes\r\n", 0);
+ if(result)
+ return result;
+
+ filetime = (time_t)statbuf.st_mtime;
+ result = Curl_gmtime(filetime, &buffer);
+ if(result)
+ return result;
+
+ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+ snprintf(header, sizeof(header),
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+ if(!result)
+ /* set the file size to make it available post transfer */
+ Curl_pgrsSetDownloadSize(data, expected_size);
+ return result;
+ }
+
+ /* Check whether file range has been specified */
+ file_range(conn);
+
+ /* Adjust the start offset in case we want to get the N last bytes
+ * of the stream iff the filesize could be determined */
+ if(data->state.resume_from < 0) {
+ if(!fstated) {
+ failf(data, "Can't get the size of file.");
+ return CURLE_READ_ERROR;
+ }
+ data->state.resume_from += (curl_off_t)statbuf.st_size;
+ }
+
+ if(data->state.resume_from <= expected_size)
+ expected_size -= data->state.resume_from;
+ else {
+ failf(data, "failed to resume file:// transfer");
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+
+ /* A high water mark has been specified so we obey... */
+ if(data->req.maxdownload > 0)
+ expected_size = data->req.maxdownload;
+
+ if(!fstated || (expected_size == 0))
+ size_known = FALSE;
+ else
+ size_known = TRUE;
+
+ /* The following is a shortcut implementation of file reading
+ this is both more efficient than the former call to download() and
+ it avoids problems with select() and recv() on file descriptors
+ in Winsock */
+ if(fstated)
+ Curl_pgrsSetDownloadSize(data, expected_size);
+
+ if(data->state.resume_from) {
+ if(data->state.resume_from !=
+ lseek(fd, data->state.resume_from, SEEK_SET))
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+ while(!result) {
+ /* Don't fill a whole buffer if we want less than all data */
+ size_t bytestoread;
+
+ if(size_known) {
+ bytestoread = (expected_size < data->set.buffer_size) ?
+ curlx_sotouz(expected_size) : (size_t)data->set.buffer_size;
+ }
+ else
+ bytestoread = data->set.buffer_size-1;
+
+ nread = read(fd, buf, bytestoread);
+
+ if(nread > 0)
+ buf[nread] = 0;
+
+ if(nread <= 0 || (size_known && (expected_size == 0)))
+ break;
+
+ bytecount += nread;
+ if(size_known)
+ expected_size -= nread;
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
+ if(result)
+ return result;
+
+ Curl_pgrsSetDownloadCounter(data, bytecount);
+
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_tvnow());
+ }
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ return result;
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/file.h b/Utilities/cmcurl/lib/file.h
new file mode 100644
index 000000000..c12ae0e09
--- /dev/null
+++ b/Utilities/cmcurl/lib/file.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_FILE_H
+#define HEADER_CURL_FILE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * FILE unique setup
+ ***************************************************************************/
+struct FILEPROTO {
+ char *path; /* the path we operate on */
+ char *freepath; /* pointer to the allocated block we must free, this might
+ differ from the 'path' pointer */
+ int fd; /* open file descriptor to read from! */
+};
+
+#ifndef CURL_DISABLE_FILE
+extern const struct Curl_handler Curl_handler_file;
+#endif
+
+#endif /* HEADER_CURL_FILE_H */
+
diff --git a/Utilities/cmcurl/lib/fileinfo.c b/Utilities/cmcurl/lib/fileinfo.c
new file mode 100644
index 000000000..387298847
--- /dev/null
+++ b/Utilities/cmcurl/lib/fileinfo.c
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "strdup.h"
+#include "fileinfo.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct fileinfo *Curl_fileinfo_alloc(void)
+{
+ return calloc(1, sizeof(struct fileinfo));
+}
+
+void Curl_fileinfo_dtor(void *user, void *element)
+{
+ struct fileinfo *finfo = element;
+ (void) user;
+ if(!finfo)
+ return;
+
+ Curl_safefree(finfo->info.b_data);
+
+ free(finfo);
+}
diff --git a/Utilities/cmcurl/lib/fileinfo.h b/Utilities/cmcurl/lib/fileinfo.h
new file mode 100644
index 000000000..c5d0ee5b6
--- /dev/null
+++ b/Utilities/cmcurl/lib/fileinfo.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_FILEINFO_H
+#define HEADER_CURL_FILEINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+#include "llist.h"
+
+struct fileinfo {
+ struct curl_fileinfo info;
+ struct curl_llist_element list;
+};
+
+struct fileinfo *Curl_fileinfo_alloc(void);
+
+void Curl_fileinfo_dtor(void *, void *);
+
+#endif /* HEADER_CURL_FILEINFO_H */
diff --git a/Utilities/cmcurl/lib/formdata.c b/Utilities/cmcurl/lib/formdata.c
new file mode 100644
index 000000000..e48a6276c
--- /dev/null
+++ b/Utilities/cmcurl/lib/formdata.c
@@ -0,0 +1,1595 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#ifndef CURL_DISABLE_HTTP
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "urldata.h" /* for struct Curl_easy */
+#include "formdata.h"
+#include "vtls/vtls.h"
+#include "strcase.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "rand.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef HAVE_BASENAME
+static char *Curl_basename(char *path);
+#define basename(x) Curl_basename((x))
+#endif
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size);
+static CURLcode formboundary(struct Curl_easy *data, char *buffer, size_t len);
+
+/* What kind of Content-Type to use on un-specified files with unrecognized
+ extensions. */
+#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
+
+#define HTTPPOST_PTRNAME CURL_HTTPPOST_PTRNAME
+#define HTTPPOST_FILENAME CURL_HTTPPOST_FILENAME
+#define HTTPPOST_PTRCONTENTS CURL_HTTPPOST_PTRCONTENTS
+#define HTTPPOST_READFILE CURL_HTTPPOST_READFILE
+#define HTTPPOST_PTRBUFFER CURL_HTTPPOST_PTRBUFFER
+#define HTTPPOST_CALLBACK CURL_HTTPPOST_CALLBACK
+#define HTTPPOST_BUFFER CURL_HTTPPOST_BUFFER
+
+/***************************************************************************
+ *
+ * AddHttpPost()
+ *
+ * Adds a HttpPost structure to the list, if parent_post is given becomes
+ * a subpost of parent_post instead of a direct list element.
+ *
+ * Returns newly allocated HttpPost on success and NULL if malloc failed.
+ *
+ ***************************************************************************/
+static struct curl_httppost *
+AddHttpPost(char *name, size_t namelength,
+ char *value, curl_off_t contentslength,
+ char *buffer, size_t bufferlength,
+ char *contenttype,
+ long flags,
+ struct curl_slist *contentHeader,
+ char *showfilename, char *userp,
+ struct curl_httppost *parent_post,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post)
+{
+ struct curl_httppost *post;
+ post = calloc(1, sizeof(struct curl_httppost));
+ if(post) {
+ post->name = name;
+ post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
+ post->contents = value;
+ post->contentlen = contentslength;
+ post->buffer = buffer;
+ post->bufferlength = (long)bufferlength;
+ post->contenttype = contenttype;
+ post->contentheader = contentHeader;
+ post->showfilename = showfilename;
+ post->userp = userp;
+ post->flags = flags | CURL_HTTPPOST_LARGE;
+ }
+ else
+ return NULL;
+
+ if(parent_post) {
+ /* now, point our 'more' to the original 'more' */
+ post->more = parent_post->more;
+
+ /* then move the original 'more' to point to ourselves */
+ parent_post->more = post;
+ }
+ else {
+ /* make the previous point to this */
+ if(*last_post)
+ (*last_post)->next = post;
+ else
+ (*httppost) = post;
+
+ (*last_post) = post;
+ }
+ return post;
+}
+
+/***************************************************************************
+ *
+ * AddFormInfo()
+ *
+ * Adds a FormInfo structure to the list presented by parent_form_info.
+ *
+ * Returns newly allocated FormInfo on success and NULL if malloc failed/
+ * parent_form_info is NULL.
+ *
+ ***************************************************************************/
+static FormInfo * AddFormInfo(char *value,
+ char *contenttype,
+ FormInfo *parent_form_info)
+{
+ FormInfo *form_info;
+ form_info = calloc(1, sizeof(struct FormInfo));
+ if(form_info) {
+ if(value)
+ form_info->value = value;
+ if(contenttype)
+ form_info->contenttype = contenttype;
+ form_info->flags = HTTPPOST_FILENAME;
+ }
+ else
+ return NULL;
+
+ if(parent_form_info) {
+ /* now, point our 'more' to the original 'more' */
+ form_info->more = parent_form_info->more;
+
+ /* then move the original 'more' to point to ourselves */
+ parent_form_info->more = form_info;
+ }
+
+ return form_info;
+}
+
+/***************************************************************************
+ *
+ * ContentTypeForFilename()
+ *
+ * Provides content type for filename if one of the known types (else
+ * (either the prevtype or the default is returned).
+ *
+ * Returns some valid contenttype for filename.
+ *
+ ***************************************************************************/
+static const char *ContentTypeForFilename(const char *filename,
+ const char *prevtype)
+{
+ const char *contenttype = NULL;
+ unsigned int i;
+ /*
+ * No type was specified, we scan through a few well-known
+ * extensions and pick the first we match!
+ */
+ struct ContentType {
+ const char *extension;
+ const char *type;
+ };
+ static const struct ContentType ctts[]={
+ {".gif", "image/gif"},
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".txt", "text/plain"},
+ {".html", "text/html"},
+ {".xml", "application/xml"}
+ };
+
+ if(prevtype)
+ /* default to the previously set/used! */
+ contenttype = prevtype;
+ else
+ contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
+
+ if(filename) { /* in case a NULL was passed in */
+ for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+ if(strlen(filename) >= strlen(ctts[i].extension)) {
+ if(strcasecompare(filename +
+ strlen(filename) - strlen(ctts[i].extension),
+ ctts[i].extension)) {
+ contenttype = ctts[i].type;
+ break;
+ }
+ }
+ }
+ }
+ /* we have a contenttype by now */
+ return contenttype;
+}
+
+/***************************************************************************
+ *
+ * FormAdd()
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
+ *
+ * Has two principal functionalities: using files and byte arrays as
+ * post parts. Byte arrays are either copied or just the pointer is stored
+ * (as the user requests) while for files only the filename and not the
+ * content is stored.
+ *
+ * While you may have only one byte array for each name, multiple filenames
+ * are allowed (and because of this feature CURLFORM_END is needed after
+ * using CURLFORM_FILE).
+ *
+ * Examples:
+ *
+ * Simple name/value pair with copied contents:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
+ *
+ * name/value pair where only the content pointer is remembered:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
+ * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
+ *
+ * storing a filename (CONTENTTYPE is optional!):
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
+ * CURLFORM_END);
+ *
+ * storing multiple filenames:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
+ *
+ * Returns:
+ * CURL_FORMADD_OK on success
+ * CURL_FORMADD_MEMORY if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
+ * CURL_FORMADD_NULL if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
+ *
+ ***************************************************************************/
+
+static
+CURLFORMcode FormAdd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ va_list params)
+{
+ FormInfo *first_form, *current_form, *form = NULL;
+ CURLFORMcode return_value = CURL_FORMADD_OK;
+ const char *prevtype = NULL;
+ struct curl_httppost *post = NULL;
+ CURLformoption option;
+ struct curl_forms *forms = NULL;
+ char *array_value=NULL; /* value read from an array */
+
+ /* This is a state variable, that if TRUE means that we're parsing an
+ array that we got passed to us. If FALSE we're parsing the input
+ va_list arguments. */
+ bool array_state = FALSE;
+
+ /*
+ * We need to allocate the first struct to fill in.
+ */
+ first_form = calloc(1, sizeof(struct FormInfo));
+ if(!first_form)
+ return CURL_FORMADD_MEMORY;
+
+ current_form = first_form;
+
+ /*
+ * Loop through all the options set. Break if we have an error to report.
+ */
+ while(return_value == CURL_FORMADD_OK) {
+
+ /* first see if we have more parts of the array param */
+ if(array_state && forms) {
+ /* get the upcoming option from the given array */
+ option = forms->option;
+ array_value = (char *)forms->value;
+
+ forms++; /* advance this to next entry */
+ if(CURLFORM_END == option) {
+ /* end of array state */
+ array_state = FALSE;
+ continue;
+ }
+ }
+ else {
+ /* This is not array-state, get next option */
+ option = va_arg(params, CURLformoption);
+ if(CURLFORM_END == option)
+ break;
+ }
+
+ switch(option) {
+ case CURLFORM_ARRAY:
+ if(array_state)
+ /* we don't support an array from within an array */
+ return_value = CURL_FORMADD_ILLEGAL_ARRAY;
+ else {
+ forms = va_arg(params, struct curl_forms *);
+ if(forms)
+ array_state = TRUE;
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ /*
+ * Set the Name property.
+ */
+ case CURLFORM_PTRNAME:
+#ifdef CURL_DOES_CONVERSIONS
+ /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
+ * the data in all cases so that we'll have safe memory for the eventual
+ * conversion.
+ */
+#else
+ current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+#endif
+ /* FALLTHROUGH */
+ case CURLFORM_COPYNAME:
+ if(current_form->name)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *name = array_state?
+ array_value:va_arg(params, char *);
+ if(name)
+ current_form->name = name; /* store for the moment */
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ case CURLFORM_NAMELENGTH:
+ if(current_form->namelength)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->namelength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ /*
+ * Set the contents property.
+ */
+ case CURLFORM_PTRCONTENTS:
+ current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
+ case CURLFORM_COPYCONTENTS:
+ if(current_form->value)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *value =
+ array_state?array_value:va_arg(params, char *);
+ if(value)
+ current_form->value = value; /* store for the moment */
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ case CURLFORM_CONTENTSLENGTH:
+ current_form->contentslength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ case CURLFORM_CONTENTLEN:
+ current_form->flags |= CURL_HTTPPOST_LARGE;
+ current_form->contentslength =
+ array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
+ break;
+
+ /* Get contents from a given file name */
+ case CURLFORM_FILECONTENT:
+ if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ const char *filename = array_state?
+ array_value:va_arg(params, char *);
+ if(filename) {
+ current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_READFILE;
+ current_form->value_alloc = TRUE;
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ /* We upload a file */
+ case CURLFORM_FILE:
+ {
+ const char *filename = array_state?array_value:
+ va_arg(params, char *);
+
+ if(current_form->value) {
+ if(current_form->flags & HTTPPOST_FILENAME) {
+ if(filename) {
+ char *fname = strdup(filename);
+ if(!fname)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(fname, NULL, current_form);
+ if(!form) {
+ free(fname);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->value_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ else
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ }
+ else {
+ if(filename) {
+ current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_FILENAME;
+ current_form->value_alloc = TRUE;
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ }
+
+ case CURLFORM_BUFFERPTR:
+ current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
+ if(current_form->buffer)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *buffer =
+ array_state?array_value:va_arg(params, char *);
+ if(buffer) {
+ current_form->buffer = buffer; /* store for the moment */
+ current_form->value = buffer; /* make it non-NULL to be accepted
+ as fine */
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ case CURLFORM_BUFFERLENGTH:
+ if(current_form->bufferlength)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->bufferlength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ case CURLFORM_STREAM:
+ current_form->flags |= HTTPPOST_CALLBACK;
+ if(current_form->userp)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *userp =
+ array_state?array_value:va_arg(params, char *);
+ if(userp) {
+ current_form->userp = userp;
+ current_form->value = userp; /* this isn't strictly true but we
+ derive a value from this later on
+ and we need this non-NULL to be
+ accepted as a fine form part */
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ case CURLFORM_CONTENTTYPE:
+ {
+ const char *contenttype =
+ array_state?array_value:va_arg(params, char *);
+ if(current_form->contenttype) {
+ if(current_form->flags & HTTPPOST_FILENAME) {
+ if(contenttype) {
+ char *type = strdup(contenttype);
+ if(!type)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(NULL, type, current_form);
+ if(!form) {
+ free(type);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->contenttype_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ else
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ }
+ else {
+ if(contenttype) {
+ current_form->contenttype = strdup(contenttype);
+ if(!current_form->contenttype)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->contenttype_alloc = TRUE;
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ }
+ case CURLFORM_CONTENTHEADER:
+ {
+ /* this "cast increases required alignment of target type" but
+ we consider it OK anyway */
+ struct curl_slist *list = array_state?
+ (struct curl_slist *)(void *)array_value:
+ va_arg(params, struct curl_slist *);
+
+ if(current_form->contentheader)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->contentheader = list;
+
+ break;
+ }
+ case CURLFORM_FILENAME:
+ case CURLFORM_BUFFER:
+ {
+ const char *filename = array_state?array_value:
+ va_arg(params, char *);
+ if(current_form->showfilename)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ current_form->showfilename = strdup(filename);
+ if(!current_form->showfilename)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->showfilename_alloc = TRUE;
+ }
+ break;
+ }
+ default:
+ return_value = CURL_FORMADD_UNKNOWN_OPTION;
+ break;
+ }
+ }
+
+ if(CURL_FORMADD_OK != return_value) {
+ /* On error, free allocated fields for all nodes of the FormInfo linked
+ list without deallocating nodes. List nodes are deallocated later on */
+ FormInfo *ptr;
+ for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
+ if(ptr->name_alloc) {
+ Curl_safefree(ptr->name);
+ ptr->name_alloc = FALSE;
+ }
+ if(ptr->value_alloc) {
+ Curl_safefree(ptr->value);
+ ptr->value_alloc = FALSE;
+ }
+ if(ptr->contenttype_alloc) {
+ Curl_safefree(ptr->contenttype);
+ ptr->contenttype_alloc = FALSE;
+ }
+ if(ptr->showfilename_alloc) {
+ Curl_safefree(ptr->showfilename);
+ ptr->showfilename_alloc = FALSE;
+ }
+ }
+ }
+
+ if(CURL_FORMADD_OK == return_value) {
+ /* go through the list, check for completeness and if everything is
+ * alright add the HttpPost item otherwise set return_value accordingly */
+
+ post = NULL;
+ for(form = first_form;
+ form != NULL;
+ form = form->more) {
+ if(((!form->name || !form->value) && !post) ||
+ ( (form->contentslength) &&
+ (form->flags & HTTPPOST_FILENAME) ) ||
+ ( (form->flags & HTTPPOST_FILENAME) &&
+ (form->flags & HTTPPOST_PTRCONTENTS) ) ||
+
+ ( (!form->buffer) &&
+ (form->flags & HTTPPOST_BUFFER) &&
+ (form->flags & HTTPPOST_PTRBUFFER) ) ||
+
+ ( (form->flags & HTTPPOST_READFILE) &&
+ (form->flags & HTTPPOST_PTRCONTENTS) )
+ ) {
+ return_value = CURL_FORMADD_INCOMPLETE;
+ break;
+ }
+ if(((form->flags & HTTPPOST_FILENAME) ||
+ (form->flags & HTTPPOST_BUFFER)) &&
+ !form->contenttype) {
+ char *f = form->flags & HTTPPOST_BUFFER?
+ form->showfilename : form->value;
+
+ /* our contenttype is missing */
+ form->contenttype = strdup(ContentTypeForFilename(f, prevtype));
+ if(!form->contenttype) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->contenttype_alloc = TRUE;
+ }
+ if(!(form->flags & HTTPPOST_PTRNAME) &&
+ (form == first_form) ) {
+ /* Note that there's small risk that form->name is NULL here if the
+ app passed in a bad combo, so we better check for that first. */
+ if(form->name) {
+ /* copy name (without strdup; possibly contains null characters) */
+ form->name = Curl_memdup(form->name, form->namelength?
+ form->namelength:
+ strlen(form->name)+1);
+ }
+ if(!form->name) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->name_alloc = TRUE;
+ }
+ if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
+ HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
+ HTTPPOST_CALLBACK)) && form->value) {
+ /* copy value (without strdup; possibly contains null characters) */
+ size_t clen = (size_t) form->contentslength;
+ if(!clen)
+ clen = strlen(form->value)+1;
+
+ form->value = Curl_memdup(form->value, clen);
+
+ if(!form->value) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->value_alloc = TRUE;
+ }
+ post = AddHttpPost(form->name, form->namelength,
+ form->value, form->contentslength,
+ form->buffer, form->bufferlength,
+ form->contenttype, form->flags,
+ form->contentheader, form->showfilename,
+ form->userp,
+ post, httppost,
+ last_post);
+
+ if(!post) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+
+ if(form->contenttype)
+ prevtype = form->contenttype;
+ }
+ if(CURL_FORMADD_OK != return_value) {
+ /* On error, free allocated fields for nodes of the FormInfo linked
+ list which are not already owned by the httppost linked list
+ without deallocating nodes. List nodes are deallocated later on */
+ FormInfo *ptr;
+ for(ptr = form; ptr != NULL; ptr = ptr->more) {
+ if(ptr->name_alloc) {
+ Curl_safefree(ptr->name);
+ ptr->name_alloc = FALSE;
+ }
+ if(ptr->value_alloc) {
+ Curl_safefree(ptr->value);
+ ptr->value_alloc = FALSE;
+ }
+ if(ptr->contenttype_alloc) {
+ Curl_safefree(ptr->contenttype);
+ ptr->contenttype_alloc = FALSE;
+ }
+ if(ptr->showfilename_alloc) {
+ Curl_safefree(ptr->showfilename);
+ ptr->showfilename_alloc = FALSE;
+ }
+ }
+ }
+ }
+
+ /* Always deallocate FormInfo linked list nodes without touching node
+ fields given that these have either been deallocated or are owned
+ now by the httppost linked list */
+ while(first_form) {
+ FormInfo *ptr = first_form->more;
+ free(first_form);
+ first_form = ptr;
+ }
+
+ return return_value;
+}
+
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ *
+ * @unittest: 1308
+ */
+
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...)
+{
+ va_list arg;
+ CURLFORMcode result;
+ va_start(arg, last_post);
+ result = FormAdd(httppost, last_post, arg);
+ va_end(arg);
+ return result;
+}
+
+#ifdef __VMS
+#include <fabdef.h>
+/*
+ * get_vms_file_size does what it takes to get the real size of the file
+ *
+ * For fixed files, find out the size of the EOF block and adjust.
+ *
+ * For all others, have to read the entire file in, discarding the contents.
+ * Most posted text files will be small, and binary files like zlib archives
+ * and CD/DVD images should be either a STREAM_LF format or a fixed format.
+ *
+ */
+curl_off_t VmsRealFileSize(const char *name,
+ const struct_stat *stat_buf)
+{
+ char buffer[8192];
+ curl_off_t count;
+ int ret_stat;
+ FILE * file;
+
+ file = fopen(name, FOPEN_READTEXT); /* VMS */
+ if(file == NULL)
+ return 0;
+
+ count = 0;
+ ret_stat = 1;
+ while(ret_stat > 0) {
+ ret_stat = fread(buffer, 1, sizeof(buffer), file);
+ if(ret_stat != 0)
+ count += ret_stat;
+ }
+ fclose(file);
+
+ return count;
+}
+
+/*
+ *
+ * VmsSpecialSize checks to see if the stat st_size can be trusted and
+ * if not to call a routine to get the correct size.
+ *
+ */
+static curl_off_t VmsSpecialSize(const char *name,
+ const struct_stat *stat_buf)
+{
+ switch(stat_buf->st_fab_rfm) {
+ case FAB$C_VAR:
+ case FAB$C_VFC:
+ return VmsRealFileSize(name, stat_buf);
+ break;
+ default:
+ return stat_buf->st_size;
+ }
+}
+
+#endif
+
+#ifndef __VMS
+#define filesize(name, stat_data) (stat_data.st_size)
+#else
+ /* Getting the expected file size needs help on VMS */
+#define filesize(name, stat_data) VmsSpecialSize(name, &stat_data)
+#endif
+
+/*
+ * AddFormData() adds a chunk of data to the FormData linked list.
+ *
+ * size is incremented by the chunk length, unless it is NULL
+ */
+static CURLcode AddFormData(struct FormData **formp,
+ enum formtype type,
+ const void *line,
+ curl_off_t length,
+ curl_off_t *size)
+{
+ struct FormData *newform;
+ char *alloc2 = NULL;
+ CURLcode result = CURLE_OK;
+ if(length < 0 || (size && *size < 0))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ newform = malloc(sizeof(struct FormData));
+ if(!newform)
+ return CURLE_OUT_OF_MEMORY;
+ newform->next = NULL;
+
+ if(type <= FORM_CONTENT) {
+ /* we make it easier for plain strings: */
+ if(!length)
+ length = strlen((char *)line);
+#if (SIZEOF_SIZE_T < CURL_SIZEOF_CURL_OFF_T)
+ else if(length >= (curl_off_t)(size_t)-1) {
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto error;
+ }
+#endif
+ if(type != FORM_DATAMEM) {
+ newform->line = malloc((size_t)length+1);
+ if(!newform->line) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto error;
+ }
+ alloc2 = newform->line;
+ memcpy(newform->line, line, (size_t)length);
+
+ /* zero terminate for easier debugging */
+ newform->line[(size_t)length]=0;
+ }
+ else {
+ newform->line = (char *)line;
+ type = FORM_DATA; /* in all other aspects this is just FORM_DATA */
+ }
+ newform->length = (size_t)length;
+ }
+ else
+ /* For callbacks and files we don't have any actual data so we just keep a
+ pointer to whatever this points to */
+ newform->line = (char *)line;
+
+ newform->type = type;
+
+ if(size) {
+ if(type != FORM_FILE)
+ /* for static content as well as callback data we add the size given
+ as input argument */
+ *size += length;
+ else {
+ /* Since this is a file to be uploaded here, add the size of the actual
+ file */
+ if(strcmp("-", newform->line)) {
+ struct_stat file;
+ if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
+ *size += filesize(newform->line, file);
+ else {
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ goto error;
+ }
+ }
+ }
+ }
+
+ if(*formp) {
+ (*formp)->next = newform;
+ *formp = newform;
+ }
+ else
+ *formp = newform;
+
+ return CURLE_OK;
+ error:
+ if(newform)
+ free(newform);
+ if(alloc2)
+ free(alloc2);
+ return result;
+}
+
+/*
+ * AddFormDataf() adds printf()-style formatted data to the formdata chain.
+ */
+
+static CURLcode AddFormDataf(struct FormData **formp,
+ curl_off_t *size,
+ const char *fmt, ...)
+{
+ char *s;
+ CURLcode result;
+ va_list ap;
+ va_start(ap, fmt);
+ s = curl_mvaprintf(fmt, ap);
+ va_end(ap);
+
+ if(!s)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = AddFormData(formp, FORM_DATAMEM, s, 0, size);
+ if(result)
+ free(s);
+
+ return result;
+}
+
+/*
+ * Curl_formclean() is used from http.c, this cleans a built FormData linked
+ * list
+ */
+void Curl_formclean(struct FormData **form_ptr)
+{
+ struct FormData *next, *form;
+
+ form = *form_ptr;
+ if(!form)
+ return;
+
+ do {
+ next=form->next; /* the following form line */
+ if(form->type <= FORM_CONTENT)
+ free(form->line); /* free the line */
+ free(form); /* free the struct */
+ form = next;
+ } while(form); /* continue */
+
+ *form_ptr = NULL;
+}
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ *
+ * @unittest: 1308
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append)
+{
+ CURLcode result;
+ curl_off_t size;
+ struct FormData *data, *ptr;
+
+ result = Curl_getformdata(NULL, &data, form, NULL, &size);
+ if(result)
+ return (int)result;
+
+ for(ptr = data; ptr; ptr = ptr->next) {
+ if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
+ char buffer[8192];
+ size_t nread;
+ struct Form temp;
+
+ Curl_FormInit(&temp, ptr);
+
+ do {
+ nread = readfromfile(&temp, buffer, sizeof(buffer));
+ if((nread == (size_t) -1) ||
+ (nread > sizeof(buffer)) ||
+ (nread != append(arg, buffer, nread))) {
+ if(temp.fp)
+ fclose(temp.fp);
+ Curl_formclean(&data);
+ return -1;
+ }
+ } while(nread);
+ }
+ else {
+ if(ptr->length != append(arg, ptr->line, ptr->length)) {
+ Curl_formclean(&data);
+ return -1;
+ }
+ }
+ }
+ Curl_formclean(&data);
+ return 0;
+}
+
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
+void curl_formfree(struct curl_httppost *form)
+{
+ struct curl_httppost *next;
+
+ if(!form)
+ /* no form to free, just get out of this */
+ return;
+
+ do {
+ next=form->next; /* the following form line */
+
+ /* recurse to sub-contents */
+ curl_formfree(form->more);
+
+ if(!(form->flags & HTTPPOST_PTRNAME))
+ free(form->name); /* free the name */
+ if(!(form->flags &
+ (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK))
+ )
+ free(form->contents); /* free the contents */
+ free(form->contenttype); /* free the content type */
+ free(form->showfilename); /* free the faked file name */
+ free(form); /* free the struct */
+ form = next;
+ } while(form); /* continue */
+}
+
+#ifndef HAVE_BASENAME
+/*
+ (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+ Edition)
+
+ The basename() function shall take the pathname pointed to by path and
+ return a pointer to the final component of the pathname, deleting any
+ trailing '/' characters.
+
+ If the string pointed to by path consists entirely of the '/' character,
+ basename() shall return a pointer to the string "/". If the string pointed
+ to by path is exactly "//", it is implementation-defined whether '/' or "//"
+ is returned.
+
+ If path is a null pointer or points to an empty string, basename() shall
+ return a pointer to the string ".".
+
+ The basename() function may modify the string pointed to by path, and may
+ return a pointer to static storage that may then be overwritten by a
+ subsequent call to basename().
+
+ The basename() function need not be reentrant. A function that is not
+ required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+ /* Ignore all the details above for now and make a quick and simple
+ implementaion here */
+ char *s1;
+ char *s2;
+
+ s1=strrchr(path, '/');
+ s2=strrchr(path, '\\');
+
+ if(s1 && s2) {
+ path = (s1 > s2? s1 : s2)+1;
+ }
+ else if(s1)
+ path = s1 + 1;
+ else if(s2)
+ path = s2 + 1;
+
+ return path;
+}
+#endif
+
+static char *strippath(const char *fullfile)
+{
+ char *filename;
+ char *base;
+ filename = strdup(fullfile); /* duplicate since basename() may ruin the
+ buffer it works on */
+ if(!filename)
+ return NULL;
+ base = strdup(basename(filename));
+
+ free(filename); /* free temporary buffer */
+
+ return base; /* returns an allocated string or NULL ! */
+}
+
+static CURLcode formdata_add_filename(const struct curl_httppost *file,
+ struct FormData **form,
+ curl_off_t *size)
+{
+ CURLcode result = CURLE_OK;
+ char *filename = file->showfilename;
+ char *filebasename = NULL;
+ char *filename_escaped = NULL;
+
+ if(!filename) {
+ filebasename = strippath(file->contents);
+ if(!filebasename)
+ return CURLE_OUT_OF_MEMORY;
+ filename = filebasename;
+ }
+
+ if(strchr(filename, '\\') || strchr(filename, '"')) {
+ char *p0, *p1;
+
+ /* filename need be escaped */
+ filename_escaped = malloc(strlen(filename)*2+1);
+ if(!filename_escaped) {
+ free(filebasename);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ p0 = filename_escaped;
+ p1 = filename;
+ while(*p1) {
+ if(*p1 == '\\' || *p1 == '"')
+ *p0++ = '\\';
+ *p0++ = *p1++;
+ }
+ *p0 = '\0';
+ filename = filename_escaped;
+ }
+ result = AddFormDataf(form, size,
+ "; filename=\"%s\"",
+ filename);
+ free(filename_escaped);
+ free(filebasename);
+ return result;
+}
+
+/*
+ * Curl_getformdata() converts a linked list of "meta data" into a complete
+ * (possibly huge) multipart formdata. The input list is in 'post', while the
+ * output resulting linked lists gets stored in '*finalform'. *sizep will get
+ * the total size of the whole POST.
+ * A multipart/form_data content-type is built, unless a custom content-type
+ * is passed in 'custom_content_type'.
+ *
+ * This function will not do a failf() for the potential memory failures but
+ * should for all other errors it spots. Just note that this function MAY get
+ * a NULL pointer in the 'data' argument.
+ */
+
+CURLcode Curl_getformdata(struct Curl_easy *data,
+ struct FormData **finalform,
+ struct curl_httppost *post,
+ const char *custom_content_type,
+ curl_off_t *sizep)
+{
+ struct FormData *form = NULL;
+ struct FormData *firstform;
+ struct curl_httppost *file;
+ CURLcode result = CURLE_OK;
+ curl_off_t size = 0; /* support potentially ENORMOUS formposts */
+ char fileboundary[42];
+ struct curl_slist *curList;
+ char boundary[42];
+
+ *finalform = NULL; /* default form is empty */
+
+ if(!post)
+ return result; /* no input => no output! */
+
+ result = formboundary(data, boundary, sizeof(boundary));
+ if(result)
+ return result;
+
+ /* Make the first line of the output */
+ result = AddFormDataf(&form, NULL,
+ "%s; boundary=%s\r\n",
+ custom_content_type?custom_content_type:
+ "Content-Type: multipart/form-data",
+ boundary);
+
+ if(result) {
+ return result;
+ }
+ /* we DO NOT include that line in the total size of the POST, since it'll be
+ part of the header! */
+
+ firstform = form;
+
+ do {
+
+ if(size) {
+ result = AddFormDataf(&form, &size, "\r\n");
+ if(result)
+ break;
+ }
+
+ /* boundary */
+ result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
+ if(result)
+ break;
+
+ /* Maybe later this should be disabled when a custom_content_type is
+ passed, since Content-Disposition is not meaningful for all multipart
+ types.
+ */
+ result = AddFormDataf(&form, &size,
+ "Content-Disposition: form-data; name=\"");
+ if(result)
+ break;
+
+ result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
+ &size);
+ if(result)
+ break;
+
+ result = AddFormDataf(&form, &size, "\"");
+ if(result)
+ break;
+
+ if(post->more) {
+ /* If used, this is a link to more file names, we must then do
+ the magic to include several files with the same field name */
+
+ result = formboundary(data, fileboundary, sizeof(fileboundary));
+ if(result) {
+ break;
+ }
+
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: multipart/mixed;"
+ " boundary=%s\r\n",
+ fileboundary);
+ if(result)
+ break;
+ }
+
+ file = post;
+
+ do {
+
+ /* If 'showfilename' is set, that is a faked name passed on to us
+ to use to in the formpost. If that is not set, the actually used
+ local file name should be added. */
+
+ if(post->more) {
+ /* if multiple-file */
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s\r\nContent-Disposition: "
+ "attachment",
+ fileboundary);
+ if(result)
+ break;
+ result = formdata_add_filename(file, &form, &size);
+ if(result)
+ break;
+ }
+ else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
+ HTTPPOST_CALLBACK)) {
+ /* it should be noted that for the HTTPPOST_FILENAME and
+ HTTPPOST_CALLBACK cases the ->showfilename struct member is always
+ assigned at this point */
+ if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
+ result = formdata_add_filename(post, &form, &size);
+ }
+
+ if(result)
+ break;
+ }
+
+ if(file->contenttype) {
+ /* we have a specified type */
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: %s",
+ file->contenttype);
+ if(result)
+ break;
+ }
+
+ curList = file->contentheader;
+ while(curList) {
+ /* Process the additional headers specified for this form */
+ result = AddFormDataf(&form, &size, "\r\n%s", curList->data);
+ if(result)
+ break;
+ curList = curList->next;
+ }
+ if(result)
+ break;
+
+ result = AddFormDataf(&form, &size, "\r\n\r\n");
+ if(result)
+ break;
+
+ if((post->flags & HTTPPOST_FILENAME) ||
+ (post->flags & HTTPPOST_READFILE)) {
+ /* we should include the contents from the specified file */
+ FILE *fileread;
+
+ fileread = !strcmp("-", file->contents)?
+ stdin:fopen(file->contents, "rb"); /* binary read for win32 */
+
+ /*
+ * VMS: This only allows for stream files on VMS. Stream files are
+ * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
+ * every record needs to have a \n appended & 1 added to SIZE
+ */
+
+ if(fileread) {
+ if(fileread != stdin) {
+ /* close the file */
+ fclose(fileread);
+ /* add the file name only - for later reading from this */
+ result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
+ }
+ else {
+ /* When uploading from stdin, we can't know the size of the file,
+ * thus must read the full file as before. We *could* use chunked
+ * transfer-encoding, but that only works for HTTP 1.1 and we
+ * can't be sure we work with such a server.
+ */
+ size_t nread;
+ char buffer[512];
+ while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
+ result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
+ if(result || feof(fileread) || ferror(fileread))
+ break;
+ }
+ }
+ }
+ else {
+ if(data)
+ failf(data, "couldn't open file \"%s\"", file->contents);
+ *finalform = NULL;
+ result = CURLE_READ_ERROR;
+ }
+ }
+ else if(post->flags & HTTPPOST_BUFFER)
+ /* include contents of buffer */
+ result = AddFormData(&form, FORM_CONTENT, post->buffer,
+ post->bufferlength, &size);
+ else if(post->flags & HTTPPOST_CALLBACK)
+ /* the contents should be read with the callback and the size is set
+ with the contentslength */
+ result = AddFormData(&form, FORM_CALLBACK, post->userp,
+ post->flags&CURL_HTTPPOST_LARGE?
+ post->contentlen:post->contentslength, &size);
+ else
+ /* include the contents we got */
+ result = AddFormData(&form, FORM_CONTENT, post->contents,
+ post->flags&CURL_HTTPPOST_LARGE?
+ post->contentlen:post->contentslength, &size);
+ file = file->more;
+ } while(file && !result); /* for each specified file for this field */
+
+ if(result)
+ break;
+
+ if(post->more) {
+ /* this was a multiple-file inclusion, make a termination file
+ boundary: */
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s--",
+ fileboundary);
+ if(result)
+ break;
+ }
+ post = post->next;
+ } while(post); /* for each field */
+
+ /* end-boundary for everything */
+ if(!result)
+ result = AddFormDataf(&form, &size, "\r\n--%s--\r\n", boundary);
+
+ if(result) {
+ Curl_formclean(&firstform);
+ return result;
+ }
+
+ *sizep = size;
+ *finalform = firstform;
+
+ return result;
+}
+
+/*
+ * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
+ * and resets the 'sent' counter.
+ */
+int Curl_FormInit(struct Form *form, struct FormData *formdata)
+{
+ if(!formdata)
+ return 1; /* error */
+
+ form->data = formdata;
+ form->sent = 0;
+ form->fp = NULL;
+ form->fread_func = ZERO_NULL;
+
+ return 0;
+}
+
+#ifndef __VMS
+# define fopen_read fopen
+#else
+ /*
+ * vmsfopenread
+ *
+ * For upload to work as expected on VMS, different optional
+ * parameters must be added to the fopen command based on
+ * record format of the file.
+ *
+ */
+# define fopen_read vmsfopenread
+static FILE * vmsfopenread(const char *file, const char *mode)
+{
+ struct_stat statbuf;
+ int result;
+
+ result = stat(file, &statbuf);
+
+ switch(statbuf.st_fab_rfm) {
+ case FAB$C_VAR:
+ case FAB$C_VFC:
+ case FAB$C_STMCR:
+ return fopen(file, FOPEN_READTEXT); /* VMS */
+ break;
+ default:
+ return fopen(file, FOPEN_READTEXT, "rfm=stmlf", "ctx=stm");
+ }
+}
+#endif
+
+/*
+ * readfromfile()
+ *
+ * The read callback that this function may use can return a value larger than
+ * 'size' (which then this function returns) that indicates a problem and it
+ * must be properly dealt with
+ */
+static size_t readfromfile(struct Form *form, char *buffer,
+ size_t size)
+{
+ size_t nread;
+ bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
+
+ if(callback) {
+ if(form->fread_func == ZERO_NULL)
+ return 0;
+ nread = form->fread_func(buffer, 1, size, form->data->line);
+ }
+ else {
+ if(!form->fp) {
+ /* this file hasn't yet been opened */
+ form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
+ if(!form->fp)
+ return (size_t)-1; /* failure */
+ }
+ nread = fread(buffer, 1, size, form->fp);
+ }
+ if(!nread) {
+ /* this is the last chunk from the file, move on */
+ if(form->fp) {
+ fclose(form->fp);
+ form->fp = NULL;
+ }
+ form->data = form->data->next;
+ }
+
+ return nread;
+}
+
+/*
+ * Curl_FormReader() is the fread() emulation function that will be used to
+ * deliver the formdata to the transfer loop and then sent away to the peer.
+ */
+size_t Curl_FormReader(char *buffer,
+ size_t size,
+ size_t nitems,
+ FILE *mydata)
+{
+ struct Form *form;
+ size_t wantedsize;
+ size_t gotsize = 0;
+
+ form=(struct Form *)mydata;
+
+ wantedsize = size * nitems;
+
+ if(!form->data)
+ return 0; /* nothing, error, empty */
+
+ if((form->data->type == FORM_FILE) ||
+ (form->data->type == FORM_CALLBACK)) {
+ gotsize = readfromfile(form, buffer, wantedsize);
+
+ if(gotsize)
+ /* If positive or -1, return. If zero, continue! */
+ return gotsize;
+ }
+ do {
+
+ if((form->data->length - form->sent) > wantedsize - gotsize) {
+
+ memcpy(buffer + gotsize, form->data->line + form->sent,
+ wantedsize - gotsize);
+
+ form->sent += wantedsize-gotsize;
+
+ return wantedsize;
+ }
+
+ memcpy(buffer+gotsize,
+ form->data->line + form->sent,
+ (form->data->length - form->sent) );
+ gotsize += form->data->length - form->sent;
+
+ form->sent = 0;
+
+ form->data = form->data->next; /* advance */
+
+ } while(form->data && (form->data->type < FORM_CALLBACK));
+ /* If we got an empty line and we have more data, we proceed to the next
+ line immediately to avoid returning zero before we've reached the end. */
+
+ return gotsize;
+}
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len)
+{
+ char *header;
+ struct Form *form=(struct Form *)formp;
+
+ if(!form->data)
+ return NULL; /* nothing, ERROR! */
+
+ header = form->data->line;
+ *len = form->data->length;
+
+ form->data = form->data->next; /* advance */
+
+ return header;
+}
+
+/*
+ * formboundary() creates a suitable boundary string and returns an allocated
+ * one.
+ */
+static CURLcode formboundary(struct Curl_easy *data,
+ char *buffer, size_t buflen)
+{
+ /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
+ combinations */
+ if(buflen < 41)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ memset(buffer, '-', 24);
+ Curl_rand_hex(data, (unsigned char *)&buffer[24], 17);
+
+ return CURLE_OK;
+}
+
+#else /* CURL_DISABLE_HTTP */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...)
+{
+ (void)httppost;
+ (void)last_post;
+ return CURL_FORMADD_DISABLED;
+}
+
+int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append)
+{
+ (void) form;
+ (void) arg;
+ (void) append;
+ return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+ (void)form;
+ /* does nothing HTTP is disabled */
+}
+
+
+#endif /* !defined(CURL_DISABLE_HTTP) */
diff --git a/Utilities/cmcurl/lib/formdata.h b/Utilities/cmcurl/lib/formdata.h
new file mode 100644
index 000000000..69629f628
--- /dev/null
+++ b/Utilities/cmcurl/lib/formdata.h
@@ -0,0 +1,99 @@
+#ifndef HEADER_CURL_FORMDATA_H
+#define HEADER_CURL_FORMDATA_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+enum formtype {
+ FORM_DATAMEM, /* already allocated FORM_DATA memory */
+ FORM_DATA, /* form metadata (convert to network encoding if necessary) */
+ FORM_CONTENT, /* form content (never convert) */
+ FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback
+ */
+ FORM_FILE /* 'line' points to a file name we should read from
+ to create the form data (never convert) */
+};
+
+/* plain and simple linked list with lines to send */
+struct FormData {
+ struct FormData *next;
+ enum formtype type;
+ char *line;
+ size_t length;
+};
+
+struct Form {
+ struct FormData *data; /* current form line to send */
+ size_t sent; /* number of bytes of the current line that has
+ already been sent in a previous invoke */
+ FILE *fp; /* file to read from */
+ curl_read_callback fread_func; /* fread callback pointer */
+};
+
+/* used by FormAdd for temporary storage */
+typedef struct FormInfo {
+ char *name;
+ bool name_alloc;
+ size_t namelength;
+ char *value;
+ bool value_alloc;
+ curl_off_t contentslength;
+ char *contenttype;
+ bool contenttype_alloc;
+ long flags;
+ char *buffer; /* pointer to existing buffer used for file upload */
+ size_t bufferlength;
+ char *showfilename; /* The file name to show. If not set, the actual
+ file name will be used */
+ bool showfilename_alloc;
+ char *userp; /* pointer for the read callback */
+ struct curl_slist *contentheader;
+ struct FormInfo *more;
+} FormInfo;
+
+int Curl_FormInit(struct Form *form, struct FormData *formdata);
+
+CURLcode Curl_getformdata(struct Curl_easy *data,
+ struct FormData **,
+ struct curl_httppost *post,
+ const char *custom_contenttype,
+ curl_off_t *size);
+
+/* fread() emulation */
+size_t Curl_FormReader(char *buffer,
+ size_t size,
+ size_t nitems,
+ FILE *mydata);
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len);
+
+char *Curl_FormBoundary(void);
+
+void Curl_formclean(struct FormData **);
+
+CURLcode Curl_formconvert(struct Curl_easy *, struct FormData *);
+
+#endif /* HEADER_CURL_FORMDATA_H */
diff --git a/Utilities/cmcurl/lib/ftp.c b/Utilities/cmcurl/lib/ftp.c
new file mode 100644
index 000000000..783dbe124
--- /dev/null
+++ b/Utilities/cmcurl/lib/ftp.c
@@ -0,0 +1,4546 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "ftp.h"
+#include "fileinfo.h"
+#include "ftplistparser.h"
+#include "curl_sec.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "strcase.h"
+#include "speedcheck.h"
+#include "warnless.h"
+#include "http_proxy.h"
+#include "non-ascii.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
+#endif
+
+/* Local API functions */
+#ifndef DEBUGBUILD
+static void _state(struct connectdata *conn,
+ ftpstate newstate);
+#define state(x,y) _state(x,y)
+#else
+static void _state(struct connectdata *conn,
+ ftpstate newstate,
+ int lineno);
+#define state(x,y) _state(x,y,__LINE__)
+#endif
+
+static CURLcode ftp_sendquote(struct connectdata *conn,
+ struct curl_slist *quote);
+static CURLcode ftp_quit(struct connectdata *conn);
+static CURLcode ftp_parse_url_path(struct connectdata *conn);
+static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void ftp_pasv_verbose(struct connectdata *conn,
+ Curl_addrinfo *ai,
+ char *newhost, /* ascii version */
+ int port);
+#endif
+static CURLcode ftp_state_prepare_transfer(struct connectdata *conn);
+static CURLcode ftp_state_mdtm(struct connectdata *conn);
+static CURLcode ftp_state_quote(struct connectdata *conn,
+ bool init, ftpstate instate);
+static CURLcode ftp_nb_type(struct connectdata *conn,
+ bool ascii, ftpstate newstate);
+static int ftp_need_type(struct connectdata *conn,
+ bool ascii);
+static CURLcode ftp_do(struct connectdata *conn, bool *done);
+static CURLcode ftp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode ftp_connect(struct connectdata *conn, bool *done);
+static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection);
+static CURLcode ftp_do_more(struct connectdata *conn, int *completed);
+static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done);
+static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode ftp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode ftp_setup_connection(struct connectdata * conn);
+
+static CURLcode init_wc_data(struct connectdata *conn);
+static CURLcode wc_statemach(struct connectdata *conn);
+
+static void wc_data_dtor(void *ptr);
+
+static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
+
+static CURLcode ftp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *ftpcode,
+ size_t *size);
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+ bool connected);
+
+/* easy-to-use macro: */
+#define PPSENDF(x,y,z) result = Curl_pp_sendf(x,y,z); \
+ if(result) \
+ return result
+
+
+/*
+ * FTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftp = {
+ "FTP", /* scheme */
+ ftp_setup_connection, /* setup_connection */
+ ftp_do, /* do_it */
+ ftp_done, /* done */
+ ftp_do_more, /* do_more */
+ ftp_connect, /* connect_it */
+ ftp_multi_statemach, /* connecting */
+ ftp_doing, /* doing */
+ ftp_getsock, /* proto_getsock */
+ ftp_getsock, /* doing_getsock */
+ ftp_domore_getsock, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTP, /* defport */
+ CURLPROTO_FTP, /* protocol */
+ PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+#ifdef USE_SSL
+/*
+ * FTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftps = {
+ "FTPS", /* scheme */
+ ftp_setup_connection, /* setup_connection */
+ ftp_do, /* do_it */
+ ftp_done, /* done */
+ ftp_do_more, /* do_more */
+ ftp_connect, /* connect_it */
+ ftp_multi_statemach, /* connecting */
+ ftp_doing, /* doing */
+ ftp_getsock, /* proto_getsock */
+ ftp_getsock, /* doing_getsock */
+ ftp_domore_getsock, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTPS, /* defport */
+ CURLPROTO_FTPS, /* protocol */
+ PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
+ PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed FTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftp_proxy = {
+ "FTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed FTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftps_proxy = {
+ "FTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+static void close_secondarysocket(struct connectdata *conn)
+{
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+ }
+ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+ conn->tunnel_state[SECONDARYSOCKET] = TUNNEL_INIT;
+}
+
+/*
+ * NOTE: back in the old days, we added code in the FTP code that made NOBODY
+ * requests on files respond with headers passed to the client/stdout that
+ * looked like HTTP ones.
+ *
+ * This approach is not very elegant, it causes confusion and is error-prone.
+ * It is subject for removal at the next (or at least a future) soname bump.
+ * Until then you can test the effects of the removal by undefining the
+ * following define named CURL_FTP_HTTPSTYLE_HEAD.
+ */
+#define CURL_FTP_HTTPSTYLE_HEAD 1
+
+static void freedirs(struct ftp_conn *ftpc)
+{
+ int i;
+ if(ftpc->dirs) {
+ for(i=0; i < ftpc->dirdepth; i++) {
+ free(ftpc->dirs[i]);
+ ftpc->dirs[i]=NULL;
+ }
+ free(ftpc->dirs);
+ ftpc->dirs = NULL;
+ ftpc->dirdepth = 0;
+ }
+ Curl_safefree(ftpc->file);
+
+ /* no longer of any use */
+ Curl_safefree(ftpc->newhost);
+}
+
+/* Returns non-zero if the given string contains CR (\r) or LF (\n),
+ which are not allowed within RFC 959 <string>.
+ Note: The input string is in the client's encoding which might
+ not be ASCII, so escape sequences \r & \n must be used instead
+ of hex values 0x0d & 0x0a.
+*/
+static bool isBadFtpString(const char *string)
+{
+ return ((NULL != strchr(string, '\r')) ||
+ (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
+}
+
+/***********************************************************************
+ *
+ * AcceptServerConnect()
+ *
+ * After connection request is received from the server this function is
+ * called to accept the connection and close the listening socket
+ *
+ */
+static CURLcode AcceptServerConnect(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+ curl_socket_t s = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+ struct Curl_sockaddr_storage add;
+#else
+ struct sockaddr_in add;
+#endif
+ curl_socklen_t size = (curl_socklen_t) sizeof(add);
+
+ if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
+ size = sizeof(add);
+
+ s=accept(sock, (struct sockaddr *) &add, &size);
+ }
+ Curl_closesocket(conn, sock); /* close the first socket */
+
+ if(CURL_SOCKET_BAD == s) {
+ failf(data, "Error accept()ing server connect");
+ return CURLE_FTP_PORT_FAILED;
+ }
+ infof(data, "Connection accepted from server\n");
+ /* when this happens within the DO state it is important that we mark us as
+ not needing DO_MORE anymore */
+ conn->bits.do_more = FALSE;
+
+ conn->sock[SECONDARYSOCKET] = s;
+ (void)curlx_nonblock(s, TRUE); /* enable non-blocking */
+ conn->sock_accepted[SECONDARYSOCKET] = TRUE;
+
+ if(data->set.fsockopt) {
+ int error = 0;
+
+ /* activate callback for setting socket options */
+ error = data->set.fsockopt(data->set.sockopt_client,
+ s,
+ CURLSOCKTYPE_ACCEPT);
+
+ if(error) {
+ close_secondarysocket(conn);
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+
+ return CURLE_OK;
+
+}
+
+/*
+ * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
+ * waiting server to connect. If the value is negative, the timeout time has
+ * already elapsed.
+ *
+ * The start time is stored in progress.t_acceptdata - as set with
+ * Curl_pgrsTime(..., TIMER_STARTACCEPT);
+ *
+ */
+static time_t ftp_timeleft_accept(struct Curl_easy *data)
+{
+ time_t timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
+ time_t other;
+ struct timeval now;
+
+ if(data->set.accepttimeout > 0)
+ timeout_ms = data->set.accepttimeout;
+
+ now = Curl_tvnow();
+
+ /* check if the generic timeout possibly is set shorter */
+ other = Curl_timeleft(data, &now, FALSE);
+ if(other && (other < timeout_ms))
+ /* note that this also works fine for when other happens to be negative
+ due to it already having elapsed */
+ timeout_ms = other;
+ else {
+ /* subtract elapsed time */
+ timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+ }
+
+ return timeout_ms;
+}
+
+
+/***********************************************************************
+ *
+ * ReceivedServerConnect()
+ *
+ * After allowing server to connect to us from data port, this function
+ * checks both data connection for connection establishment and ctrl
+ * connection for a negative response regarding a failure in connecting
+ *
+ */
+static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
+{
+ struct Curl_easy *data = conn->data;
+ curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
+ curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ int result;
+ time_t timeout_ms;
+ ssize_t nread;
+ int ftpcode;
+
+ *received = FALSE;
+
+ timeout_ms = ftp_timeleft_accept(data);
+ infof(data, "Checking for server connect\n");
+ if(timeout_ms < 0) {
+ /* if a timeout was already reached, bail out */
+ failf(data, "Accept timeout occurred while waiting server connect");
+ return CURLE_FTP_ACCEPT_TIMEOUT;
+ }
+
+ /* First check whether there is a cached response from server */
+ if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
+ /* Data connection could not be established, let's return */
+ infof(data, "There is negative response in cache while serv connect\n");
+ Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ return CURLE_FTP_ACCEPT_FAILED;
+ }
+
+ result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+
+ /* see if the connection request is already here */
+ switch(result) {
+ case -1: /* error */
+ /* let's die here */
+ failf(data, "Error while waiting for server connect");
+ return CURLE_FTP_ACCEPT_FAILED;
+ case 0: /* Server connect is not received yet */
+ break; /* loop */
+ default:
+
+ if(result & CURL_CSELECT_IN2) {
+ infof(data, "Ready to accept data connection from server\n");
+ *received = TRUE;
+ }
+ else if(result & CURL_CSELECT_IN) {
+ infof(data, "Ctrl conn has data while waiting for data conn\n");
+ Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ if(ftpcode/100 > 3)
+ return CURLE_FTP_ACCEPT_FAILED;
+
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
+
+ break;
+ } /* switch() */
+
+ return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * InitiateTransfer()
+ *
+ * After connection from server is accepted this function is called to
+ * setup transfer parameters and initiate the data transfer.
+ *
+ */
+static CURLcode InitiateTransfer(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ CURLcode result = CURLE_OK;
+
+ if(conn->bits.ftp_use_data_ssl) {
+ /* since we only have a plaintext TCP connection here, we must now
+ * do the TLS stuff */
+ infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+ result = Curl_ssl_connect(conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+ }
+
+ if(conn->proto.ftpc.state_saved == FTP_STOR) {
+ *(ftp->bytecountp)=0;
+
+ /* When we know we're uploading a specified file, we can get the file
+ size prior to the actual upload. */
+
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+ /* set the SO_SNDBUF for the secondary socket for those who need it */
+ Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
+
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+ SECONDARYSOCKET, ftp->bytecountp);
+ }
+ else {
+ /* FTP download: */
+ Curl_setup_transfer(conn, SECONDARYSOCKET,
+ conn->proto.ftpc.retr_size_saved, FALSE,
+ ftp->bytecountp, -1, NULL); /* no upload here */
+ }
+
+ conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
+ state(conn, FTP_STOP);
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * AllowServerConnect()
+ *
+ * When we've issue the PORT command, we have told the server to connect to
+ * us. This function checks whether data connection is established if so it is
+ * accepted.
+ *
+ */
+static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
+{
+ struct Curl_easy *data = conn->data;
+ time_t timeout_ms;
+ CURLcode result = CURLE_OK;
+
+ *connected = FALSE;
+ infof(data, "Preparing for accepting server on data port\n");
+
+ /* Save the time we start accepting server connect */
+ Curl_pgrsTime(data, TIMER_STARTACCEPT);
+
+ timeout_ms = ftp_timeleft_accept(data);
+ if(timeout_ms < 0) {
+ /* if a timeout was already reached, bail out */
+ failf(data, "Accept timeout occurred while waiting server connect");
+ return CURLE_FTP_ACCEPT_TIMEOUT;
+ }
+
+ /* see if the connection request is already here */
+ result = ReceivedServerConnect(conn, connected);
+ if(result)
+ return result;
+
+ if(*connected) {
+ result = AcceptServerConnect(conn);
+ if(result)
+ return result;
+
+ result = InitiateTransfer(conn);
+ if(result)
+ return result;
+ }
+ else {
+ /* Add timeout to multi handle and break out of the loop */
+ if(!result && *connected == FALSE) {
+ Curl_expire(data, data->set.accepttimeout > 0 ?
+ data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, 0);
+ }
+ }
+
+ return result;
+}
+
+/* macro to check for a three-digit ftp status code at the start of the
+ given string */
+#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
+ ISDIGIT(line[2]))
+
+/* macro to check for the last line in an FTP server response */
+#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
+
+static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *code)
+{
+ (void)conn;
+
+ if((len > 3) && LASTLINE(line)) {
+ *code = curlx_sltosi(strtol(line, NULL, 10));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static CURLcode ftp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *ftpcode, /* return the ftp-code if done */
+ size_t *size) /* size of the response */
+{
+ struct connectdata *conn = pp->conn;
+ struct Curl_easy *data = conn->data;
+#ifdef HAVE_GSSAPI
+ char * const buf = data->state.buffer;
+#endif
+ CURLcode result = CURLE_OK;
+ int code;
+
+ result = Curl_pp_readresp(sockfd, pp, &code, size);
+
+#if defined(HAVE_GSSAPI)
+ /* handle the security-oriented responses 6xx ***/
+ /* FIXME: some errorchecking perhaps... ***/
+ switch(code) {
+ case 631:
+ code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
+ break;
+ case 632:
+ code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
+ break;
+ case 633:
+ code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
+ break;
+ default:
+ /* normal ftp stuff we pass through! */
+ break;
+ }
+#endif
+
+ /* store the latest code for later retrieval */
+ data->info.httpcode=code;
+
+ if(ftpcode)
+ *ftpcode = code;
+
+ if(421 == code) {
+ /* 421 means "Service not available, closing control connection." and FTP
+ * servers use it to signal that idle session timeout has been exceeded.
+ * If we ignored the response, it could end up hanging in some cases.
+ *
+ * This response code can come at any point so having it treated
+ * generically is a good idea.
+ */
+ infof(data, "We got a 421 - timeout!\n");
+ state(conn, FTP_STOP);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ return result;
+}
+
+/* --- parse FTP server responses --- */
+
+/*
+ * Curl_GetFTPResponse() is a BLOCKING function to read the full response
+ * from a server after a command.
+ *
+ */
+
+CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
+ struct connectdata *conn,
+ int *ftpcode) /* return the ftp-code */
+{
+ /*
+ * We cannot read just one byte per read() and then go back to select() as
+ * the OpenSSL read() doesn't grok that properly.
+ *
+ * Alas, read as much as possible, split up into lines, use the ending
+ * line in a response or continue reading. */
+
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ time_t timeout; /* timeout in milliseconds */
+ time_t interval_ms;
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ size_t nread;
+ int cache_skip=0;
+ int value_to_be_ignored=0;
+
+ if(ftpcode)
+ *ftpcode = 0; /* 0 for errors */
+ else
+ /* make the pointer point to something for the rest of this function */
+ ftpcode = &value_to_be_ignored;
+
+ *nreadp=0;
+
+ while(!*ftpcode && !result) {
+ /* check and reset timeout value every lap */
+ timeout = Curl_pp_state_timeout(pp);
+
+ if(timeout <=0) {
+ failf(data, "FTP response timeout");
+ return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+ }
+
+ interval_ms = 1000; /* use 1 second timeout intervals */
+ if(timeout < interval_ms)
+ interval_ms = timeout;
+
+ /*
+ * Since this function is blocking, we need to wait here for input on the
+ * connection and only then we call the response reading function. We do
+ * timeout at least every second to make the timeout check run.
+ *
+ * A caution here is that the ftp_readresp() function has a cache that may
+ * contain pieces of a response from the previous invoke and we need to
+ * make sure we don't just wait for input while there is unhandled data in
+ * that cache. But also, if the cache is there, we call ftp_readresp() and
+ * the cache wasn't good enough to continue we must not just busy-loop
+ * around this function.
+ *
+ */
+
+ if(pp->cache && (cache_skip < 2)) {
+ /*
+ * There's a cache left since before. We then skipping the wait for
+ * socket action, unless this is the same cache like the previous round
+ * as then the cache was deemed not enough to act on and we then need to
+ * wait for more data anyway.
+ */
+ }
+ else if(!Curl_conn_data_pending(conn, FIRSTSOCKET)) {
+ switch(SOCKET_READABLE(sockfd, interval_ms)) {
+ case -1: /* select() error, stop reading */
+ failf(data, "FTP response aborted due to select/poll error: %d",
+ SOCKERRNO);
+ return CURLE_RECV_ERROR;
+
+ case 0: /* timeout */
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ continue; /* just continue in our loop for the timeout duration */
+
+ default: /* for clarity */
+ break;
+ }
+ }
+ result = ftp_readresp(sockfd, pp, ftpcode, &nread);
+ if(result)
+ break;
+
+ if(!nread && pp->cache)
+ /* bump cache skip counter as on repeated skips we must wait for more
+ data */
+ cache_skip++;
+ else
+ /* when we got data or there is no cache left, we reset the cache skip
+ counter */
+ cache_skip=0;
+
+ *nreadp += nread;
+
+ } /* while there's buffer left and loop is requested */
+
+ pp->pending_resp = FALSE;
+
+ return result;
+}
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+static const char * const ftp_state_names[]={
+ "STOP",
+ "WAIT220",
+ "AUTH",
+ "USER",
+ "PASS",
+ "ACCT",
+ "PBSZ",
+ "PROT",
+ "CCC",
+ "PWD",
+ "SYST",
+ "NAMEFMT",
+ "QUOTE",
+ "RETR_PREQUOTE",
+ "STOR_PREQUOTE",
+ "POSTQUOTE",
+ "CWD",
+ "MKD",
+ "MDTM",
+ "TYPE",
+ "LIST_TYPE",
+ "RETR_TYPE",
+ "STOR_TYPE",
+ "SIZE",
+ "RETR_SIZE",
+ "STOR_SIZE",
+ "REST",
+ "RETR_REST",
+ "PORT",
+ "PRET",
+ "PASV",
+ "LIST",
+ "RETR",
+ "STOR",
+ "QUIT"
+};
+#endif
+
+/* This is the ONLY way to change FTP state! */
+static void _state(struct connectdata *conn,
+ ftpstate newstate
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+ )
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+#if defined(DEBUGBUILD)
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) lineno;
+#else
+ if(ftpc->state != newstate)
+ infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
+ (void *)ftpc, lineno, ftp_state_names[ftpc->state],
+ ftp_state_names[newstate]);
+#endif
+#endif
+
+ ftpc->state = newstate;
+}
+
+static CURLcode ftp_state_user(struct connectdata *conn)
+{
+ CURLcode result;
+ struct FTP *ftp = conn->data->req.protop;
+ /* send USER */
+ PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
+
+ state(conn, FTP_USER);
+ conn->data->state.ftp_trying_alternative = FALSE;
+
+ return CURLE_OK;
+}
+
+static CURLcode ftp_state_pwd(struct connectdata *conn)
+{
+ CURLcode result;
+
+ /* send PWD to discover our entry point */
+ PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
+ state(conn, FTP_PWD);
+
+ return CURLE_OK;
+}
+
+/* For the FTP "protocol connect" and "doing" phases only */
+static int ftp_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
+}
+
+/* For the FTP "DO_MORE" phase only */
+static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ /* When in DO_MORE state, we could be either waiting for us to connect to a
+ * remote site, or we could wait for that site to connect to us. Or just
+ * handle ordinary commands.
+ */
+
+ if(FTP_STOP == ftpc->state) {
+ int bits = GETSOCK_READSOCK(0);
+
+ /* if stopped and still in this state, then we're also waiting for a
+ connect on the secondary connection */
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ if(!conn->data->set.ftp_use_port) {
+ int s;
+ int i;
+ /* PORT is used to tell the server to connect to us, and during that we
+ don't do happy eyeballs, but we do if we connect to the server */
+ for(s=1, i=0; i<2; i++) {
+ if(conn->tempsock[i] != CURL_SOCKET_BAD) {
+ socks[s] = conn->tempsock[i];
+ bits |= GETSOCK_WRITESOCK(s++);
+ }
+ }
+ }
+ else {
+ socks[1] = conn->sock[SECONDARYSOCKET];
+ bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
+ }
+
+ return bits;
+ }
+ return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
+}
+
+/* This is called after the FTP_QUOTE state is passed.
+
+ ftp_state_cwd() sends the range of CWD commands to the server to change to
+ the correct directory. It may also need to send MKD commands to create
+ missing ones, if that option is enabled.
+*/
+static CURLcode ftp_state_cwd(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(ftpc->cwddone)
+ /* already done and fine */
+ result = ftp_state_mdtm(conn);
+ else {
+ ftpc->count2 = 0; /* count2 counts failed CWDs */
+
+ /* count3 is set to allow a MKD to fail once. In the case when first CWD
+ fails and then MKD fails (due to another session raced it to create the
+ dir) this then allows for a second try to CWD to it */
+ ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+
+ if(conn->bits.reuse && ftpc->entrypath) {
+ /* This is a re-used connection. Since we change directory to where the
+ transfer is taking place, we must first get back to the original dir
+ where we ended up after login: */
+ ftpc->count1 = 0; /* we count this as the first path, then we add one
+ for all upcoming ones in the ftp->dirs[] array */
+ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
+ state(conn, FTP_CWD);
+ }
+ else {
+ if(ftpc->dirdepth) {
+ ftpc->count1 = 1;
+ /* issue the first CWD, the rest is sent when the CWD responses are
+ received... */
+ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
+ state(conn, FTP_CWD);
+ }
+ else {
+ /* No CWD necessary */
+ result = ftp_state_mdtm(conn);
+ }
+ }
+ }
+ return result;
+}
+
+typedef enum {
+ EPRT,
+ PORT,
+ DONE
+} ftpport;
+
+static CURLcode ftp_state_use_port(struct connectdata *conn,
+ ftpport fcmd) /* start with this */
+
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct Curl_easy *data=conn->data;
+ curl_socket_t portsock= CURL_SOCKET_BAD;
+ char myhost[256] = "";
+
+ struct Curl_sockaddr_storage ss;
+ Curl_addrinfo *res, *ai;
+ curl_socklen_t sslen;
+ char hbuf[NI_MAXHOST];
+ struct sockaddr *sa=(struct sockaddr *)&ss;
+ struct sockaddr_in * const sa4 = (void *)sa;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 * const sa6 = (void *)sa;
+#endif
+ char tmp[1024];
+ static const char mode[][5] = { "EPRT", "PORT" };
+ int rc;
+ int error;
+ char *host = NULL;
+ char *string_ftpport = data->set.str[STRING_FTPPORT];
+ struct Curl_dns_entry *h=NULL;
+ unsigned short port_min = 0;
+ unsigned short port_max = 0;
+ unsigned short port;
+ bool possibly_non_local = TRUE;
+
+ char *addr = NULL;
+
+ /* Step 1, figure out what is requested,
+ * accepted format :
+ * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
+ */
+
+ if(data->set.str[STRING_FTPPORT] &&
+ (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
+
+#ifdef ENABLE_IPV6
+ size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET6_ADDRSTRLEN : strlen(string_ftpport);
+#else
+ size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET_ADDRSTRLEN : strlen(string_ftpport);
+#endif
+ char *ip_start = string_ftpport;
+ char *ip_end = NULL;
+ char *port_start = NULL;
+ char *port_sep = NULL;
+
+ addr = calloc(addrlen+1, 1);
+ if(!addr)
+ return CURLE_OUT_OF_MEMORY;
+
+#ifdef ENABLE_IPV6
+ if(*string_ftpport == '[') {
+ /* [ipv6]:port(-range) */
+ ip_start = string_ftpport + 1;
+ ip_end = strchr(string_ftpport, ']');
+ if(ip_end)
+ strncpy(addr, ip_start, ip_end - ip_start);
+ }
+ else
+#endif
+ if(*string_ftpport == ':') {
+ /* :port */
+ ip_end = string_ftpport;
+ }
+ else {
+ ip_end = strchr(string_ftpport, ':');
+ if(ip_end) {
+ /* either ipv6 or (ipv4|domain|interface):port(-range) */
+#ifdef ENABLE_IPV6
+ if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
+ /* ipv6 */
+ port_min = port_max = 0;
+ strcpy(addr, string_ftpport);
+ ip_end = NULL; /* this got no port ! */
+ }
+ else
+#endif
+ /* (ipv4|domain|interface):port(-range) */
+ strncpy(addr, string_ftpport, ip_end - ip_start);
+ }
+ else
+ /* ipv4|interface */
+ strcpy(addr, string_ftpport);
+ }
+
+ /* parse the port */
+ if(ip_end != NULL) {
+ port_start = strchr(ip_end, ':');
+ if(port_start) {
+ port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
+ port_sep = strchr(port_start, '-');
+ if(port_sep) {
+ port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+ }
+ else
+ port_max = port_min;
+ }
+ }
+
+ /* correct errors like:
+ * :1234-1230
+ * :-4711, in this case port_min is (unsigned)-1,
+ * therefore port_min > port_max for all cases
+ * but port_max = (unsigned)-1
+ */
+ if(port_min > port_max)
+ port_min = port_max = 0;
+
+
+ if(*addr != '\0') {
+ /* attempt to get the address of the given interface name */
+ switch(Curl_if2ip(conn->ip_addr->ai_family,
+ Curl_ipv6_scope(conn->ip_addr->ai_addr),
+ conn->scope_id, addr, hbuf, sizeof(hbuf))) {
+ case IF2IP_NOT_FOUND:
+ /* not an interface, use the given string as host name instead */
+ host = addr;
+ break;
+ case IF2IP_AF_NOT_SUPPORTED:
+ return CURLE_FTP_PORT_FAILED;
+ case IF2IP_FOUND:
+ host = hbuf; /* use the hbuf for host name */
+ }
+ }
+ else
+ /* there was only a port(-range) given, default the host */
+ host = NULL;
+ } /* data->set.ftpport */
+
+ if(!host) {
+ /* not an interface and not a host name, get default by extracting
+ the IP from the control connection */
+
+ sslen = sizeof(ss);
+ if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ free(addr);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ switch(sa->sa_family) {
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+ break;
+#endif
+ default:
+ Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+ break;
+ }
+ host = hbuf; /* use this host name */
+ possibly_non_local = FALSE; /* we know it is local now */
+ }
+
+ /* resolv ip/host to ip */
+ rc = Curl_resolv(conn, host, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_resolver_wait_resolv(conn, &h);
+ if(h) {
+ res = h->addr;
+ /* when we return from this function, we can forget about this entry
+ to we can unlock it now already */
+ Curl_resolv_unlock(data, h);
+ } /* (h) */
+ else
+ res = NULL; /* failure! */
+
+ if(res == NULL) {
+ failf(data, "failed to resolve the address provided to PORT: %s", host);
+ free(addr);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ free(addr);
+ host = NULL;
+
+ /* step 2, create a socket for the requested address */
+
+ portsock = CURL_SOCKET_BAD;
+ error = 0;
+ for(ai = res; ai; ai = ai->ai_next) {
+ result = Curl_socket(conn, ai, NULL, &portsock);
+ if(result) {
+ error = SOCKERRNO;
+ continue;
+ }
+ break;
+ }
+ if(!ai) {
+ failf(data, "socket failure: %s", Curl_strerror(conn, error));
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 3, bind to a suitable local address */
+
+ memcpy(sa, ai->ai_addr, ai->ai_addrlen);
+ sslen = ai->ai_addrlen;
+
+ for(port = port_min; port <= port_max;) {
+ if(sa->sa_family == AF_INET)
+ sa4->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+ else
+ sa6->sin6_port = htons(port);
+#endif
+ /* Try binding the given address. */
+ if(bind(portsock, sa, sslen) ) {
+ /* It failed. */
+ error = SOCKERRNO;
+ if(possibly_non_local && (error == EADDRNOTAVAIL)) {
+ /* The requested bind address is not local. Use the address used for
+ * the control connection instead and restart the port loop
+ */
+
+ infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
+ Curl_strerror(conn, error) );
+
+ sslen = sizeof(ss);
+ if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ port = port_min;
+ possibly_non_local = FALSE; /* don't try this again */
+ continue;
+ }
+ if(error != EADDRINUSE && error != EACCES) {
+ failf(data, "bind(port=%hu) failed: %s", port,
+ Curl_strerror(conn, error) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ }
+ else
+ break;
+
+ port++;
+ }
+
+ /* maybe all ports were in use already*/
+ if(port > port_max) {
+ failf(data, "bind() failed, we ran out of ports!");
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* get the name again after the bind() so that we can extract the
+ port number it uses now */
+ sslen = sizeof(ss);
+ if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 4, listen on the socket */
+
+ if(listen(portsock, 1)) {
+ failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 5, send the proper FTP command */
+
+ /* get a plain printable version of the numerical address to work with
+ below */
+ Curl_printable_address(ai, myhost, sizeof(myhost));
+
+#ifdef ENABLE_IPV6
+ if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
+ /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
+ request and enable EPRT again! */
+ conn->bits.ftp_use_eprt = TRUE;
+#endif
+
+ for(; fcmd != DONE; fcmd++) {
+
+ if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
+ /* if disabled, goto next */
+ continue;
+
+ if((PORT == fcmd) && sa->sa_family != AF_INET)
+ /* PORT is IPv4 only */
+ continue;
+
+ switch(sa->sa_family) {
+ case AF_INET:
+ port = ntohs(sa4->sin_port);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ port = ntohs(sa6->sin6_port);
+ break;
+#endif
+ default:
+ continue; /* might as well skip this */
+ }
+
+ if(EPRT == fcmd) {
+ /*
+ * Two fine examples from RFC2428;
+ *
+ * EPRT |1|132.235.1.2|6275|
+ *
+ * EPRT |2|1080::8:800:200C:417A|5282|
+ */
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
+ sa->sa_family == AF_INET?1:2,
+ myhost, port);
+ if(result) {
+ failf(data, "Failure sending EPRT command: %s",
+ curl_easy_strerror(result));
+ Curl_closesocket(conn, portsock);
+ /* don't retry using PORT */
+ ftpc->count1 = PORT;
+ /* bail out */
+ state(conn, FTP_STOP);
+ return result;
+ }
+ break;
+ }
+ if(PORT == fcmd) {
+ char *source = myhost;
+ char *dest = tmp;
+
+ /* translate x.x.x.x to x,x,x,x */
+ while(source && *source) {
+ if(*source == '.')
+ *dest=',';
+ else
+ *dest = *source;
+ dest++;
+ source++;
+ }
+ *dest = 0;
+ snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
+ if(result) {
+ failf(data, "Failure sending PORT command: %s",
+ curl_easy_strerror(result));
+ Curl_closesocket(conn, portsock);
+ /* bail out */
+ state(conn, FTP_STOP);
+ return result;
+ }
+ break;
+ }
+ }
+
+ /* store which command was sent */
+ ftpc->count1 = fcmd;
+
+ close_secondarysocket(conn);
+
+ /* we set the secondary socket variable to this for now, it is only so that
+ the cleanup function will close it in case we fail before the true
+ secondary stuff is made */
+ conn->sock[SECONDARYSOCKET] = portsock;
+
+ /* this tcpconnect assignment below is a hackish work-around to make the
+ multi interface with active FTP work - as it will not wait for a
+ (passive) connect in Curl_is_connected().
+
+ The *proper* fix is to make sure that the active connection from the
+ server is done in a non-blocking way. Currently, it is still BLOCKING.
+ */
+ conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
+
+ state(conn, FTP_PORT);
+ return result;
+}
+
+static CURLcode ftp_state_use_pasv(struct connectdata *conn)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result = CURLE_OK;
+ /*
+ Here's the excecutive summary on what to do:
+
+ PASV is RFC959, expect:
+ 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
+
+ LPSV is RFC1639, expect:
+ 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
+
+ EPSV is RFC2428, expect:
+ 229 Entering Extended Passive Mode (|||port|)
+
+ */
+
+ static const char mode[][5] = { "EPSV", "PASV" };
+ int modeoff;
+
+#ifdef PF_INET6
+ if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
+ /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
+ request and enable EPSV again! */
+ conn->bits.ftp_use_epsv = TRUE;
+#endif
+
+ modeoff = conn->bits.ftp_use_epsv?0:1;
+
+ PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
+
+ ftpc->count1 = modeoff;
+ state(conn, FTP_PASV);
+ infof(conn->data, "Connect data stream passively\n");
+
+ return result;
+}
+
+/*
+ * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc.
+ *
+ * REST is the last command in the chain of commands when a "head"-like
+ * request is made. Thus, if an actual transfer is to be made this is where we
+ * take off for real.
+ */
+static CURLcode ftp_state_prepare_transfer(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct Curl_easy *data = conn->data;
+
+ if(ftp->transfer != FTPTRANSFER_BODY) {
+ /* doesn't transfer any data */
+
+ /* still possibly do PRE QUOTE jobs */
+ state(conn, FTP_RETR_PREQUOTE);
+ result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+ }
+ else if(data->set.ftp_use_port) {
+ /* We have chosen to use the PORT (or similar) command */
+ result = ftp_state_use_port(conn, EPRT);
+ }
+ else {
+ /* We have chosen (this is default) to use the PASV (or similar) command */
+ if(data->set.ftp_use_pret) {
+ /* The user has requested that we send a PRET command
+ to prepare the server for the upcoming PASV */
+ if(!conn->proto.ftpc.file) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
+ data->set.str[STRING_CUSTOMREQUEST]?
+ data->set.str[STRING_CUSTOMREQUEST]:
+ (data->set.ftp_list_only?"NLST":"LIST"));
+ }
+ else if(data->set.upload) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
+ }
+ else {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
+ }
+ state(conn, FTP_PRET);
+ }
+ else {
+ result = ftp_state_use_pasv(conn);
+ }
+ }
+ return result;
+}
+
+static CURLcode ftp_state_rest(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+ /* if a "head"-like request is being made (on a file) */
+
+ /* Determine if server can respond to REST command and therefore
+ whether it supports range */
+ PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
+
+ state(conn, FTP_REST);
+ }
+ else
+ result = ftp_state_prepare_transfer(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_size(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+ /* if a "head"-like request is being made (on a file) */
+
+ /* we know ftpc->file is a valid pointer to a file name */
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+
+ state(conn, FTP_SIZE);
+ }
+ else
+ result = ftp_state_rest(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_list(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ /* If this output is to be machine-parsed, the NLST command might be better
+ to use, since the LIST command output is not specified or standard in any
+ way. It has turned out that the NLST list output is not the same on all
+ servers either... */
+
+ /*
+ if FTPFILE_NOCWD was specified, we are currently in
+ the user's home directory, so we should add the path
+ as argument for the LIST / NLST / or custom command.
+ Whether the server will support this, is uncertain.
+
+ The other ftp_filemethods will CWD into dir/dir/ first and
+ then just do LIST (in that case: nothing to do here)
+ */
+ char *cmd, *lstArg, *slashPos;
+
+ lstArg = NULL;
+ if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
+ data->state.path &&
+ data->state.path[0] &&
+ strchr(data->state.path, '/')) {
+
+ lstArg = strdup(data->state.path);
+ if(!lstArg)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Check if path does not end with /, as then we cut off the file part */
+ if(lstArg[strlen(lstArg) - 1] != '/') {
+
+ /* chop off the file part if format is dir/dir/file */
+ slashPos = strrchr(lstArg, '/');
+ if(slashPos)
+ *(slashPos+1) = '\0';
+ }
+ }
+
+ cmd = aprintf("%s%s%s",
+ data->set.str[STRING_CUSTOMREQUEST]?
+ data->set.str[STRING_CUSTOMREQUEST]:
+ (data->set.ftp_list_only?"NLST":"LIST"),
+ lstArg? " ": "",
+ lstArg? lstArg: "");
+
+ if(!cmd) {
+ free(lstArg);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
+
+ free(lstArg);
+ free(cmd);
+
+ if(result)
+ return result;
+
+ state(conn, FTP_LIST);
+
+ return result;
+}
+
+static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* We've sent the TYPE, now we must send the list of prequote strings */
+
+ result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+
+ return result;
+}
+
+static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* We've sent the TYPE, now we must send the list of prequote strings */
+
+ result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
+
+ return result;
+}
+
+static CURLcode ftp_state_type(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ /* If we have selected NOBODY and HEADER, it means that we only want file
+ information. Which in FTP can't be much more than the file size and
+ date. */
+ if(data->set.opt_no_body && ftpc->file &&
+ ftp_need_type(conn, data->set.prefer_ascii)) {
+ /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
+ may not support it! It is however the only way we have to get a file's
+ size! */
+
+ ftp->transfer = FTPTRANSFER_INFO;
+ /* this means no actual transfer will be made */
+
+ /* Some servers return different sizes for different modes, and thus we
+ must set the proper type before we check the size */
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
+ if(result)
+ return result;
+ }
+ else
+ result = ftp_state_size(conn);
+
+ return result;
+}
+
+/* This is called after the CWD commands have been done in the beginning of
+ the DO phase */
+static CURLcode ftp_state_mdtm(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ /* Requested time of file or time-depended transfer? */
+ if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
+
+ /* we have requested to get the modified-time of the file, this is a white
+ spot as the MDTM is not mentioned in RFC959 */
+ PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
+
+ state(conn, FTP_MDTM);
+ }
+ else
+ result = ftp_state_type(conn);
+
+ return result;
+}
+
+
+/* This is called after the TYPE and possible quote commands have been sent */
+static CURLcode ftp_state_ul_setup(struct connectdata *conn,
+ bool sizechecked)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ int seekerr = CURL_SEEKFUNC_OK;
+
+ if((data->state.resume_from && !sizechecked) ||
+ ((data->state.resume_from > 0) && sizechecked)) {
+ /* we're about to continue the uploading of a file */
+ /* 1. get already existing file's size. We use the SIZE command for this
+ which may not exist in the server! The SIZE command is not in
+ RFC959. */
+
+ /* 2. This used to set REST. But since we can do append, we
+ don't another ftp command. We just skip the source file
+ offset and then we APPEND the rest on the file instead */
+
+ /* 3. pass file-size number of bytes in the source file */
+ /* 4. lower the infilesize counter */
+ /* => transfer as usual */
+
+ if(data->state.resume_from < 0) {
+ /* Got no given size to start from, figure it out */
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+ state(conn, FTP_STOR_SIZE);
+ return result;
+ }
+
+ /* enable append */
+ data->set.ftp_append = TRUE;
+
+ /* Let's read off the proper amount of bytes from the input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ curl_off_t passed=0;
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+ data->state.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Failed to read data");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ } while(passed < data->state.resume_from);
+ }
+ /* now, decrease the size of the read */
+ if(data->state.infilesize>0) {
+ data->state.infilesize -= data->state.resume_from;
+
+ if(data->state.infilesize <= 0) {
+ infof(data, "File already completely uploaded\n");
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ /* Set ->transfer so that we won't get any error in
+ * ftp_done() because we didn't transfer anything! */
+ ftp->transfer = FTPTRANSFER_NONE;
+
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ }
+ /* we've passed, proceed as normal */
+ } /* resume_from */
+
+ PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
+ ftpc->file);
+
+ state(conn, FTP_STOR);
+
+ return result;
+}
+
+static CURLcode ftp_state_quote(struct connectdata *conn,
+ bool init,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ bool quote=FALSE;
+ struct curl_slist *item;
+
+ switch(instate) {
+ case FTP_QUOTE:
+ default:
+ item = data->set.quote;
+ break;
+ case FTP_RETR_PREQUOTE:
+ case FTP_STOR_PREQUOTE:
+ item = data->set.prequote;
+ break;
+ case FTP_POSTQUOTE:
+ item = data->set.postquote;
+ break;
+ }
+
+ /*
+ * This state uses:
+ * 'count1' to iterate over the commands to send
+ * 'count2' to store whether to allow commands to fail
+ */
+
+ if(init)
+ ftpc->count1 = 0;
+ else
+ ftpc->count1++;
+
+ if(item) {
+ int i = 0;
+
+ /* Skip count1 items in the linked list */
+ while((i< ftpc->count1) && item) {
+ item = item->next;
+ i++;
+ }
+ if(item) {
+ char *cmd = item->data;
+ if(cmd[0] == '*') {
+ cmd++;
+ ftpc->count2 = 1; /* the sent command is allowed to fail */
+ }
+ else
+ ftpc->count2 = 0; /* failure means cancel operation */
+
+ PPSENDF(&ftpc->pp, "%s", cmd);
+ state(conn, instate);
+ quote = TRUE;
+ }
+ }
+
+ if(!quote) {
+ /* No more quote to send, continue to ... */
+ switch(instate) {
+ case FTP_QUOTE:
+ default:
+ result = ftp_state_cwd(conn);
+ break;
+ case FTP_RETR_PREQUOTE:
+ if(ftp->transfer != FTPTRANSFER_BODY)
+ state(conn, FTP_STOP);
+ else {
+ if(ftpc->known_filesize != -1) {
+ Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
+ result = ftp_state_retr(conn, ftpc->known_filesize);
+ }
+ else {
+ if(data->set.ignorecl) {
+ /* This code is to support download of growing files. It prevents
+ the state machine from requesting the file size from the
+ server. With an unknown file size the download continues until
+ the server terminates it, otherwise the client stops if the
+ received byte count exceeds the reported file size. Set option
+ CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
+ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+ state(conn, FTP_RETR);
+ }
+ else {
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+ state(conn, FTP_RETR_SIZE);
+ }
+ }
+ }
+ break;
+ case FTP_STOR_PREQUOTE:
+ result = ftp_state_ul_setup(conn, FALSE);
+ break;
+ case FTP_POSTQUOTE:
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
+ problems */
+static CURLcode ftp_epsv_disable(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->bits.ipv6) {
+ /* We can't disable EPSV when doing IPv6, so this is instead a fail */
+ failf(conn->data, "Failed EPSV attempt, exiting\n");
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
+
+ infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n");
+ /* disable it for next transfer */
+ conn->bits.ftp_use_epsv = FALSE;
+ conn->data->state.errorbuf = FALSE; /* allow error message to get
+ rewritten */
+ PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV");
+ conn->proto.ftpc.count1++;
+ /* remain in/go to the FTP_PASV state */
+ state(conn, FTP_PASV);
+ return result;
+}
+
+
+static char *control_address(struct connectdata *conn)
+{
+ /* Returns the control connection IP address.
+ If a proxy tunnel is used, returns the original host name instead, because
+ the effective control connection address is the proxy address,
+ not the ftp host. */
+ if(conn->bits.tunnel_proxy || conn->bits.socksproxy)
+ return conn->host.name;
+
+ return conn->ip_addr_str;
+}
+
+static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result;
+ struct Curl_easy *data=conn->data;
+ struct Curl_dns_entry *addr=NULL;
+ int rc;
+ unsigned short connectport; /* the local port connect() should use! */
+ char *str=&data->state.buffer[4]; /* start on the first letter */
+
+ /* if we come here again, make sure the former name is cleared */
+ Curl_safefree(ftpc->newhost);
+
+ if((ftpc->count1 == 0) &&
+ (ftpcode == 229)) {
+ /* positive EPSV response */
+ char *ptr = strchr(str, '(');
+ if(ptr) {
+ unsigned int num;
+ char separator[4];
+ ptr++;
+ if(5 == sscanf(ptr, "%c%c%c%u%c",
+ &separator[0],
+ &separator[1],
+ &separator[2],
+ &num,
+ &separator[3])) {
+ const char sep1 = separator[0];
+ int i;
+
+ /* The four separators should be identical, or else this is an oddly
+ formatted reply and we bail out immediately. */
+ for(i=1; i<4; i++) {
+ if(separator[i] != sep1) {
+ ptr=NULL; /* set to NULL to signal error */
+ break;
+ }
+ }
+ if(num > 0xffff) {
+ failf(data, "Illegal port number in EPSV reply");
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+ if(ptr) {
+ ftpc->newport = (unsigned short)(num & 0xffff);
+ ftpc->newhost = strdup(control_address(conn));
+ if(!ftpc->newhost)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ ptr=NULL;
+ }
+ if(!ptr) {
+ failf(data, "Weirdly formatted EPSV reply");
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+ }
+ else if((ftpc->count1 == 1) &&
+ (ftpcode == 227)) {
+ /* positive PASV response */
+ int ip[4];
+ int port[2];
+
+ /*
+ * Scan for a sequence of six comma-separated numbers and use them as
+ * IP+port indicators.
+ *
+ * Found reply-strings include:
+ * "227 Entering Passive Mode (127,0,0,1,4,51)"
+ * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+ * "227 Entering passive mode. 127,0,0,1,4,51"
+ */
+ while(*str) {
+ if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+ &ip[0], &ip[1], &ip[2], &ip[3],
+ &port[0], &port[1]))
+ break;
+ str++;
+ }
+
+ if(!*str) {
+ failf(data, "Couldn't interpret the 227-response");
+ return CURLE_FTP_WEIRD_227_FORMAT;
+ }
+
+ /* we got OK from server */
+ if(data->set.ftp_skip_ip) {
+ /* told to ignore the remotely given IP but instead use the host we used
+ for the control connection */
+ infof(data, "Skip %d.%d.%d.%d for data connection, re-use %s instead\n",
+ ip[0], ip[1], ip[2], ip[3],
+ conn->host.name);
+ ftpc->newhost = strdup(control_address(conn));
+ }
+ else
+ ftpc->newhost = aprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+
+ if(!ftpc->newhost)
+ return CURLE_OUT_OF_MEMORY;
+
+ ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
+ }
+ else if(ftpc->count1 == 0) {
+ /* EPSV failed, move on to PASV */
+ return ftp_epsv_disable(conn);
+ }
+ else {
+ failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+
+ if(conn->bits.proxy) {
+ /*
+ * This connection uses a proxy and we need to connect to the proxy again
+ * here. We don't want to rely on a former host lookup that might've
+ * expired now, instead we remake the lookup here and now!
+ */
+ const char * const host_name = conn->bits.socksproxy ?
+ conn->socks_proxy.host.name : conn->http_proxy.host.name;
+ rc = Curl_resolv(conn, host_name, (int)conn->port, &addr);
+ if(rc == CURLRESOLV_PENDING)
+ /* BLOCKING, ignores the return code but 'addr' will be NULL in
+ case of failure */
+ (void)Curl_resolver_wait_resolv(conn, &addr);
+
+ connectport =
+ (unsigned short)conn->port; /* we connect to the proxy's port */
+
+ if(!addr) {
+ failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
+ return CURLE_COULDNT_RESOLVE_PROXY;
+ }
+ }
+ else {
+ /* normal, direct, ftp connection */
+ rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, &addr);
+ if(rc == CURLRESOLV_PENDING)
+ /* BLOCKING */
+ (void)Curl_resolver_wait_resolv(conn, &addr);
+
+ connectport = ftpc->newport; /* we connect to the remote port */
+
+ if(!addr) {
+ failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
+ return CURLE_FTP_CANT_GET_HOST;
+ }
+ }
+
+ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+ result = Curl_connecthost(conn, addr);
+
+ if(result) {
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
+ if(ftpc->count1 == 0 && ftpcode == 229)
+ return ftp_epsv_disable(conn);
+
+ return result;
+ }
+
+
+ /*
+ * When this is used from the multi interface, this might've returned with
+ * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
+ * connect to connect.
+ */
+
+ if(data->set.verbose)
+ /* this just dumps information about this second connection */
+ ftp_pasv_verbose(conn, addr->addr, ftpc->newhost, connectport);
+
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+ Curl_safefree(conn->secondaryhostname);
+ conn->secondary_port = ftpc->newport;
+ conn->secondaryhostname = strdup(ftpc->newhost);
+ if(!conn->secondaryhostname)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->bits.do_more = TRUE;
+ state(conn, FTP_STOP); /* this phase is completed */
+
+ return result;
+}
+
+static CURLcode ftp_state_port_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ ftpport fcmd = (ftpport)ftpc->count1;
+ CURLcode result = CURLE_OK;
+
+ /* The FTP spec tells a positive response should have code 200.
+ Be more permissive here to tolerate deviant servers. */
+ if(ftpcode / 100 != 2) {
+ /* the command failed */
+
+ if(EPRT == fcmd) {
+ infof(data, "disabling EPRT usage\n");
+ conn->bits.ftp_use_eprt = FALSE;
+ }
+ fcmd++;
+
+ if(fcmd == DONE) {
+ failf(data, "Failed to do PORT");
+ result = CURLE_FTP_PORT_FAILED;
+ }
+ else
+ /* try next */
+ result = ftp_state_use_port(conn, fcmd);
+ }
+ else {
+ infof(data, "Connect data stream actively\n");
+ state(conn, FTP_STOP); /* end of DO phase */
+ result = ftp_dophase_done(conn, FALSE);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data=conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ switch(ftpcode) {
+ case 213:
+ {
+ /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
+ last .sss part is optional and means fractions of a second */
+ int year, month, day, hour, minute, second;
+ if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
+ &year, &month, &day, &hour, &minute, &second)) {
+ /* we have a time, reformat it */
+ char timebuf[24];
+ time_t secs=time(NULL);
+
+ snprintf(timebuf, sizeof(timebuf),
+ "%04d%02d%02d %02d:%02d:%02d GMT",
+ year, month, day, hour, minute, second);
+ /* now, convert this into a time() value: */
+ data->info.filetime = (long)curl_getdate(timebuf, &secs);
+ }
+
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ /* If we asked for a time of the file and we actually got one as well,
+ we "emulate" a HTTP-style header in our output. */
+
+ if(data->set.opt_no_body &&
+ ftpc->file &&
+ data->set.get_filetime &&
+ (data->info.filetime>=0) ) {
+ char headerbuf[128];
+ time_t filetime = (time_t)data->info.filetime;
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+
+ result = Curl_gmtime(filetime, &buffer);
+ if(result)
+ return result;
+
+ /* format: "Tue, 15 Nov 1994 12:45:26" */
+ snprintf(headerbuf, sizeof(headerbuf),
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, headerbuf, 0);
+ if(result)
+ return result;
+ } /* end of a ridiculous amount of conditionals */
+#endif
+ }
+ break;
+ default:
+ infof(data, "unsupported MDTM reply format\n");
+ break;
+ case 550: /* "No such file or directory" */
+ failf(data, "Given file does not exist");
+ result = CURLE_FTP_COULDNT_RETR_FILE;
+ break;
+ }
+
+ if(data->set.timecondition) {
+ if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ if(data->info.filetime <= data->set.timevalue) {
+ infof(data, "The requested document is not new enough\n");
+ ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ data->info.timecond = TRUE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ if(data->info.filetime > data->set.timevalue) {
+ infof(data, "The requested document is not old enough\n");
+ ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ data->info.timecond = TRUE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ break;
+ } /* switch */
+ }
+ else {
+ infof(data, "Skipping time comparison\n");
+ }
+ }
+
+ if(!result)
+ result = ftp_state_type(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_type_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data=conn->data;
+
+ if(ftpcode/100 != 2) {
+ /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
+ successful 'TYPE I'. While that is not as RFC959 says, it is still a
+ positive response code and we allow that. */
+ failf(data, "Couldn't set desired mode");
+ return CURLE_FTP_COULDNT_SET_TYPE;
+ }
+ if(ftpcode != 200)
+ infof(data, "Got a %03d response code instead of the assumed 200\n",
+ ftpcode);
+
+ if(instate == FTP_TYPE)
+ result = ftp_state_size(conn);
+ else if(instate == FTP_LIST_TYPE)
+ result = ftp_state_list(conn);
+ else if(instate == FTP_RETR_TYPE)
+ result = ftp_state_retr_prequote(conn);
+ else if(instate == FTP_STOR_TYPE)
+ result = ftp_state_stor_prequote(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_retr(struct connectdata *conn,
+ curl_off_t filesize)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data=conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ ftp->downloadsize = filesize;
+
+ if(data->state.resume_from) {
+ /* We always (attempt to) get the size of downloads, so it is done before
+ this even when not doing resumes. */
+ if(filesize == -1) {
+ infof(data, "ftp server doesn't support SIZE\n");
+ /* We couldn't get the size and therefore we can't know if there really
+ is a part of the file left to get, although the server will just
+ close the connection when we start the connection so it won't cause
+ us any harm, just not make us exit as nicely. */
+ }
+ else {
+ /* We got a file size report, so we check that there actually is a
+ part of the file left to get, or else we go home. */
+ if(data->state.resume_from< 0) {
+ /* We're supposed to download the last abs(from) bytes */
+ if(filesize < -data->state.resume_from) {
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+ data->state.resume_from, filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* convert to size to download */
+ ftp->downloadsize = -data->state.resume_from;
+ /* download from where? */
+ data->state.resume_from = filesize - ftp->downloadsize;
+ }
+ else {
+ if(filesize < data->state.resume_from) {
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+ data->state.resume_from, filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* Now store the number of bytes we are expected to download */
+ ftp->downloadsize = filesize-data->state.resume_from;
+ }
+ }
+
+ if(ftp->downloadsize == 0) {
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ infof(data, "File already completely downloaded\n");
+
+ /* Set ->transfer so that we won't get any error in ftp_done()
+ * because we didn't transfer the any file */
+ ftp->transfer = FTPTRANSFER_NONE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+
+ /* Set resume file transfer offset */
+ infof(data, "Instructs server to resume from offset %"
+ CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
+
+ PPSENDF(&ftpc->pp, "REST %" CURL_FORMAT_CURL_OFF_T,
+ data->state.resume_from);
+
+ state(conn, FTP_RETR_REST);
+ }
+ else {
+ /* no resume */
+ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+ state(conn, FTP_RETR);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_size_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data=conn->data;
+ curl_off_t filesize;
+ char *buf = data->state.buffer;
+
+ /* get the size from the ascii string: */
+ filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
+
+ if(instate == FTP_SIZE) {
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ if(-1 != filesize) {
+ char clbuf[128];
+ snprintf(clbuf, sizeof(clbuf),
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, clbuf, 0);
+ if(result)
+ return result;
+ }
+#endif
+ Curl_pgrsSetDownloadSize(data, filesize);
+ result = ftp_state_rest(conn);
+ }
+ else if(instate == FTP_RETR_SIZE) {
+ Curl_pgrsSetDownloadSize(data, filesize);
+ result = ftp_state_retr(conn, filesize);
+ }
+ else if(instate == FTP_STOR_SIZE) {
+ data->state.resume_from = filesize;
+ result = ftp_state_ul_setup(conn, TRUE);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_rest_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ switch(instate) {
+ case FTP_REST:
+ default:
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ if(ftpcode == 350) {
+ char buffer[24]= { "Accept-ranges: bytes\r\n" };
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
+ if(result)
+ return result;
+ }
+#endif
+ result = ftp_state_prepare_transfer(conn);
+ break;
+
+ case FTP_RETR_REST:
+ if(ftpcode != 350) {
+ failf(conn->data, "Couldn't use REST");
+ result = CURLE_FTP_COULDNT_USE_REST;
+ }
+ else {
+ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+ state(conn, FTP_RETR);
+ }
+ break;
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_stor_resp(struct connectdata *conn,
+ int ftpcode, ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ if(ftpcode>=400) {
+ failf(data, "Failed FTP upload: %0d", ftpcode);
+ state(conn, FTP_STOP);
+ /* oops, we never close the sockets! */
+ return CURLE_UPLOAD_FAILED;
+ }
+
+ conn->proto.ftpc.state_saved = instate;
+
+ /* PORT means we are now awaiting the server to connect to us. */
+ if(data->set.ftp_use_port) {
+ bool connected;
+
+ state(conn, FTP_STOP); /* no longer in STOR state */
+
+ result = AllowServerConnect(conn, &connected);
+ if(result)
+ return result;
+
+ if(!connected) {
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ infof(data, "Data conn was not available immediately\n");
+ ftpc->wait_data_conn = TRUE;
+ }
+
+ return CURLE_OK;
+ }
+ return InitiateTransfer(conn);
+}
+
+/* for LIST and RETR responses */
+static CURLcode ftp_state_get_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+
+ if((ftpcode == 150) || (ftpcode == 125)) {
+
+ /*
+ A;
+ 150 Opening BINARY mode data connection for /etc/passwd (2241
+ bytes). (ok, the file is being transferred)
+
+ B:
+ 150 Opening ASCII mode data connection for /bin/ls
+
+ C:
+ 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
+
+ D:
+ 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
+
+ E:
+ 125 Data connection already open; Transfer starting. */
+
+ curl_off_t size=-1; /* default unknown size */
+
+
+ /*
+ * It appears that there are FTP-servers that return size 0 for files when
+ * SIZE is used on the file while being in BINARY mode. To work around
+ * that (stupid) behavior, we attempt to parse the RETR response even if
+ * the SIZE returned size zero.
+ *
+ * Debugging help from Salvatore Sorrentino on February 26, 2003.
+ */
+
+ if((instate != FTP_LIST) &&
+ !data->set.prefer_ascii &&
+ (ftp->downloadsize < 1)) {
+ /*
+ * It seems directory listings either don't show the size or very
+ * often uses size 0 anyway. ASCII transfers may very well turn out
+ * that the transferred amount of data is not the same as this line
+ * tells, why using this number in those cases only confuses us.
+ *
+ * Example D above makes this parsing a little tricky */
+ char *bytes;
+ char *buf = data->state.buffer;
+ bytes=strstr(buf, " bytes");
+ if(bytes--) {
+ long in=(long)(bytes-buf);
+ /* this is a hint there is size information in there! ;-) */
+ while(--in) {
+ /* scan for the left parenthesis and break there */
+ if('(' == *bytes)
+ break;
+ /* skip only digits */
+ if(!ISDIGIT(*bytes)) {
+ bytes=NULL;
+ break;
+ }
+ /* one more estep backwards */
+ bytes--;
+ }
+ /* if we have nothing but digits: */
+ if(bytes++) {
+ /* get the number! */
+ size = curlx_strtoofft(bytes, NULL, 0);
+ }
+ }
+ }
+ else if(ftp->downloadsize > -1)
+ size = ftp->downloadsize;
+
+ if(size > data->req.maxdownload && data->req.maxdownload > 0)
+ size = data->req.size = data->req.maxdownload;
+ else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+ size = -1; /* kludge for servers that understate ASCII mode file size */
+
+ infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
+ data->req.maxdownload);
+
+ if(instate != FTP_LIST)
+ infof(data, "Getting file with size: %" CURL_FORMAT_CURL_OFF_T "\n",
+ size);
+
+ /* FTP download: */
+ conn->proto.ftpc.state_saved = instate;
+ conn->proto.ftpc.retr_size_saved = size;
+
+ if(data->set.ftp_use_port) {
+ bool connected;
+
+ result = AllowServerConnect(conn, &connected);
+ if(result)
+ return result;
+
+ if(!connected) {
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ infof(data, "Data conn was not available immediately\n");
+ state(conn, FTP_STOP);
+ ftpc->wait_data_conn = TRUE;
+ }
+ }
+ else
+ return InitiateTransfer(conn);
+ }
+ else {
+ if((instate == FTP_LIST) && (ftpcode == 450)) {
+ /* simply no matching files in the dir listing */
+ ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+ state(conn, FTP_STOP); /* this phase is over */
+ }
+ else {
+ failf(data, "RETR response: %03d", ftpcode);
+ return instate == FTP_RETR && ftpcode == 550?
+ CURLE_REMOTE_FILE_NOT_FOUND:
+ CURLE_FTP_COULDNT_RETR_FILE;
+ }
+ }
+
+ return result;
+}
+
+/* after USER, PASS and ACCT */
+static CURLcode ftp_state_loggedin(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->ssl[FIRSTSOCKET].use) {
+ /* PBSZ = PROTECTION BUFFER SIZE.
+
+ The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
+
+ Specifically, the PROT command MUST be preceded by a PBSZ
+ command and a PBSZ command MUST be preceded by a successful
+ security data exchange (the TLS negotiation in this case)
+
+ ... (and on page 8):
+
+ Thus the PBSZ command must still be issued, but must have a
+ parameter of '0' to indicate that no buffering is taking place
+ and the data connection should not be encapsulated.
+ */
+ PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
+ state(conn, FTP_PBSZ);
+ }
+ else {
+ result = ftp_state_pwd(conn);
+ }
+ return result;
+}
+
+/* for USER and PASS responses */
+static CURLcode ftp_state_user_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ (void)instate; /* no use for this yet */
+
+ /* some need password anyway, and others just return 2xx ignored */
+ if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
+ /* 331 Password required for ...
+ (the server requires to send the user's password too) */
+ PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
+ state(conn, FTP_PASS);
+ }
+ else if(ftpcode/100 == 2) {
+ /* 230 User ... logged in.
+ (the user logged in with or without password) */
+ result = ftp_state_loggedin(conn);
+ }
+ else if(ftpcode == 332) {
+ if(data->set.str[STRING_FTP_ACCOUNT]) {
+ PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
+ state(conn, FTP_ACCT);
+ }
+ else {
+ failf(data, "ACCT requested but none available");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+ else {
+ /* All other response codes, like:
+
+ 530 User ... access denied
+ (the server denies to log the specified user) */
+
+ if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
+ !conn->data->state.ftp_trying_alternative) {
+ /* Ok, USER failed. Let's try the supplied command. */
+ PPSENDF(&conn->proto.ftpc.pp, "%s",
+ conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+ conn->data->state.ftp_trying_alternative = TRUE;
+ state(conn, FTP_USER);
+ result = CURLE_OK;
+ }
+ else {
+ failf(data, "Access denied: %03d", ftpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+ return result;
+}
+
+/* for ACCT response */
+static CURLcode ftp_state_acct_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ if(ftpcode != 230) {
+ failf(data, "ACCT rejected by server: %03d", ftpcode);
+ result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
+ }
+ else
+ result = ftp_state_loggedin(conn);
+
+ return result;
+}
+
+
+static CURLcode ftp_statemach_act(struct connectdata *conn)
+{
+ CURLcode result;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ struct Curl_easy *data=conn->data;
+ int ftpcode;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ static const char ftpauth[][4] = { "SSL", "TLS" };
+ size_t nread = 0;
+
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ result = ftp_readresp(sock, pp, &ftpcode, &nread);
+ if(result)
+ return result;
+
+ if(ftpcode) {
+ /* we have now received a full FTP server response */
+ switch(ftpc->state) {
+ case FTP_WAIT220:
+ if(ftpcode == 230)
+ /* 230 User logged in - already! */
+ return ftp_state_user_resp(conn, ftpcode, ftpc->state);
+ else if(ftpcode != 220) {
+ failf(data, "Got a %03d ftp-server response when 220 was expected",
+ ftpcode);
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
+
+ /* We have received a 220 response fine, now we proceed. */
+#ifdef HAVE_GSSAPI
+ if(data->set.krb) {
+ /* If not anonymous login, try a secure login. Note that this
+ procedure is still BLOCKING. */
+
+ Curl_sec_request_prot(conn, "private");
+ /* We set private first as default, in case the line below fails to
+ set a valid level */
+ Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
+
+ if(Curl_sec_login(conn))
+ infof(data, "Logging in with password in cleartext!\n");
+ else
+ infof(data, "Authentication successful\n");
+ }
+#endif
+
+ if(data->set.use_ssl &&
+ (!conn->ssl[FIRSTSOCKET].use ||
+ (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
+ !conn->proxy_ssl[FIRSTSOCKET].use))) {
+ /* We don't have a SSL/TLS connection yet, but FTPS is
+ requested. Try a FTPS connection now */
+
+ ftpc->count3=0;
+ switch(data->set.ftpsslauth) {
+ case CURLFTPAUTH_DEFAULT:
+ case CURLFTPAUTH_SSL:
+ ftpc->count2 = 1; /* add one to get next */
+ ftpc->count1 = 0;
+ break;
+ case CURLFTPAUTH_TLS:
+ ftpc->count2 = -1; /* subtract one to get next */
+ ftpc->count1 = 1;
+ break;
+ default:
+ failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
+ (int)data->set.ftpsslauth);
+ return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
+ }
+ PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+ state(conn, FTP_AUTH);
+ }
+ else {
+ result = ftp_state_user(conn);
+ if(result)
+ return result;
+ }
+
+ break;
+
+ case FTP_AUTH:
+ /* we have gotten the response to a previous AUTH command */
+
+ /* RFC2228 (page 5) says:
+ *
+ * If the server is willing to accept the named security mechanism,
+ * and does not require any security data, it must respond with
+ * reply code 234/334.
+ */
+
+ if((ftpcode == 234) || (ftpcode == 334)) {
+ /* Curl_ssl_connect is BLOCKING */
+ result = Curl_ssl_connect(conn, FIRSTSOCKET);
+ if(!result) {
+ conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */
+ result = ftp_state_user(conn);
+ }
+ }
+ else if(ftpc->count3 < 1) {
+ ftpc->count3++;
+ ftpc->count1 += ftpc->count2; /* get next attempt */
+ result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+ /* remain in this same state */
+ }
+ else {
+ if(data->set.use_ssl > CURLUSESSL_TRY)
+ /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
+ result = CURLE_USE_SSL_FAILED;
+ else
+ /* ignore the failure and continue */
+ result = ftp_state_user(conn);
+ }
+
+ if(result)
+ return result;
+ break;
+
+ case FTP_USER:
+ case FTP_PASS:
+ result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_ACCT:
+ result = ftp_state_acct_resp(conn, ftpcode);
+ break;
+
+ case FTP_PBSZ:
+ PPSENDF(&ftpc->pp, "PROT %c",
+ data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
+ state(conn, FTP_PROT);
+
+ break;
+
+ case FTP_PROT:
+ if(ftpcode/100 == 2)
+ /* We have enabled SSL for the data connection! */
+ conn->bits.ftp_use_data_ssl =
+ (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
+ /* FTP servers typically responds with 500 if they decide to reject
+ our 'P' request */
+ else if(data->set.use_ssl > CURLUSESSL_CONTROL)
+ /* we failed and bails out */
+ return CURLE_USE_SSL_FAILED;
+
+ if(data->set.ftp_ccc) {
+ /* CCC - Clear Command Channel
+ */
+ PPSENDF(&ftpc->pp, "%s", "CCC");
+ state(conn, FTP_CCC);
+ }
+ else {
+ result = ftp_state_pwd(conn);
+ if(result)
+ return result;
+ }
+ break;
+
+ case FTP_CCC:
+ if(ftpcode < 500) {
+ /* First shut down the SSL layer (note: this call will block) */
+ result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
+
+ if(result) {
+ failf(conn->data, "Failed to clear the command channel (CCC)");
+ return result;
+ }
+ }
+
+ /* Then continue as normal */
+ result = ftp_state_pwd(conn);
+ if(result)
+ return result;
+ break;
+
+ case FTP_PWD:
+ if(ftpcode == 257) {
+ char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ const size_t buf_size = data->set.buffer_size;
+ char *dir;
+ char *store;
+
+ dir = malloc(nread + 1);
+ if(!dir)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Reply format is like
+ 257<space>[rubbish]"<directory-name>"<space><commentary> and the
+ RFC959 says
+
+ The directory name can contain any character; embedded
+ double-quotes should be escaped by double-quotes (the
+ "quote-doubling" convention).
+ */
+
+ /* scan for the first double-quote for non-standard responses */
+ while(ptr < &data->state.buffer[buf_size]
+ && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
+ ptr++;
+
+ if('\"' == *ptr) {
+ /* it started good */
+ ptr++;
+ for(store = dir; *ptr;) {
+ if('\"' == *ptr) {
+ if('\"' == ptr[1]) {
+ /* "quote-doubling" */
+ *store = ptr[1];
+ ptr++;
+ }
+ else {
+ /* end of path */
+ *store = '\0'; /* zero terminate */
+ break; /* get out of this loop */
+ }
+ }
+ else
+ *store = *ptr;
+ store++;
+ ptr++;
+ }
+
+ /* If the path name does not look like an absolute path (i.e.: it
+ does not start with a '/'), we probably need some server-dependent
+ adjustments. For example, this is the case when connecting to
+ an OS400 FTP server: this server supports two name syntaxes,
+ the default one being incompatible with standard paths. In
+ addition, this server switches automatically to the regular path
+ syntax when one is encountered in a command: this results in
+ having an entrypath in the wrong syntax when later used in CWD.
+ The method used here is to check the server OS: we do it only
+ if the path name looks strange to minimize overhead on other
+ systems. */
+
+ if(!ftpc->server_os && dir[0] != '/') {
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
+ if(result) {
+ free(dir);
+ return result;
+ }
+ Curl_safefree(ftpc->entrypath);
+ ftpc->entrypath = dir; /* remember this */
+ infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ /* also save it where getinfo can access it: */
+ data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+ state(conn, FTP_SYST);
+ break;
+ }
+
+ Curl_safefree(ftpc->entrypath);
+ ftpc->entrypath = dir; /* remember this */
+ infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ /* also save it where getinfo can access it: */
+ data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+ }
+ else {
+ /* couldn't get the path */
+ free(dir);
+ infof(data, "Failed to figure out path\n");
+ }
+ }
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_SYST:
+ if(ftpcode == 215) {
+ char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ char *os;
+ char *store;
+
+ os = malloc(nread + 1);
+ if(!os)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Reply format is like
+ 215<space><OS-name><space><commentary>
+ */
+ while(*ptr == ' ')
+ ptr++;
+ for(store = os; *ptr && *ptr != ' ';)
+ *store++ = *ptr++;
+ *store = '\0'; /* zero terminate */
+
+ /* Check for special servers here. */
+
+ if(strcasecompare(os, "OS/400")) {
+ /* Force OS400 name format 1. */
+ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
+ if(result) {
+ free(os);
+ return result;
+ }
+ /* remember target server OS */
+ Curl_safefree(ftpc->server_os);
+ ftpc->server_os = os;
+ state(conn, FTP_NAMEFMT);
+ break;
+ }
+ /* Nothing special for the target server. */
+ /* remember target server OS */
+ Curl_safefree(ftpc->server_os);
+ ftpc->server_os = os;
+ }
+ else {
+ /* Cannot identify server OS. Continue anyway and cross fingers. */
+ }
+
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_NAMEFMT:
+ if(ftpcode == 250) {
+ /* Name format change successful: reload initial path. */
+ ftp_state_pwd(conn);
+ break;
+ }
+
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_QUOTE:
+ case FTP_POSTQUOTE:
+ case FTP_RETR_PREQUOTE:
+ case FTP_STOR_PREQUOTE:
+ if((ftpcode >= 400) && !ftpc->count2) {
+ /* failure response code, and not allowed to fail */
+ failf(conn->data, "QUOT command failed with %03d", ftpcode);
+ return CURLE_QUOTE_ERROR;
+ }
+ result = ftp_state_quote(conn, FALSE, ftpc->state);
+ if(result)
+ return result;
+
+ break;
+
+ case FTP_CWD:
+ if(ftpcode/100 != 2) {
+ /* failure to CWD there */
+ if(conn->data->set.ftp_create_missing_dirs &&
+ ftpc->count1 && !ftpc->count2) {
+ /* try making it */
+ ftpc->count2++; /* counter to prevent CWD-MKD loops */
+ PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
+ state(conn, FTP_MKD);
+ }
+ else {
+ /* return failure */
+ failf(data, "Server denied you to change to the given directory");
+ ftpc->cwdfail = TRUE; /* don't remember this path as we failed
+ to enter it */
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ }
+ else {
+ /* success */
+ ftpc->count2=0;
+ if(++ftpc->count1 <= ftpc->dirdepth) {
+ /* send next CWD */
+ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+ }
+ else {
+ result = ftp_state_mdtm(conn);
+ if(result)
+ return result;
+ }
+ }
+ break;
+
+ case FTP_MKD:
+ if((ftpcode/100 != 2) && !ftpc->count3--) {
+ /* failure to MKD the dir */
+ failf(data, "Failed to MKD dir: %03d", ftpcode);
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ state(conn, FTP_CWD);
+ /* send CWD */
+ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+ break;
+
+ case FTP_MDTM:
+ result = ftp_state_mdtm_resp(conn, ftpcode);
+ break;
+
+ case FTP_TYPE:
+ case FTP_LIST_TYPE:
+ case FTP_RETR_TYPE:
+ case FTP_STOR_TYPE:
+ result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_SIZE:
+ case FTP_RETR_SIZE:
+ case FTP_STOR_SIZE:
+ result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_REST:
+ case FTP_RETR_REST:
+ result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_PRET:
+ if(ftpcode != 200) {
+ /* there only is this one standard OK return code. */
+ failf(data, "PRET command not accepted: %03d", ftpcode);
+ return CURLE_FTP_PRET_FAILED;
+ }
+ result = ftp_state_use_pasv(conn);
+ break;
+
+ case FTP_PASV:
+ result = ftp_state_pasv_resp(conn, ftpcode);
+ break;
+
+ case FTP_PORT:
+ result = ftp_state_port_resp(conn, ftpcode);
+ break;
+
+ case FTP_LIST:
+ case FTP_RETR:
+ result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_STOR:
+ result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, FTP_STOP);
+ break;
+ }
+ } /* if(ftpcode) */
+
+ return result;
+}
+
+
+/* called repeatedly until done from multi.c */
+static CURLcode ftp_multi_statemach(struct connectdata *conn,
+ bool *done)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
+
+ /* Check for the state outside of the Curl_socket_check() return code checks
+ since at times we are in fact already in this state when this function
+ gets called. */
+ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode ftp_block_statemach(struct connectdata *conn)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ CURLcode result = CURLE_OK;
+
+ while(ftpc->state != FTP_STOP) {
+ result = Curl_pp_statemach(pp, TRUE);
+ if(result)
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * ftp_connect() should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ *
+ */
+static CURLcode ftp_connect(struct connectdata *conn,
+ bool *done) /* see description above */
+{
+ CURLcode result;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections on ftp */
+ connkeep(conn, "FTP default");
+
+ pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+ pp->statemach_act = ftp_statemach_act;
+ pp->endofresp = ftp_endofresp;
+ pp->conn = conn;
+
+ if(conn->handler->flags & PROTOPT_SSL) {
+ /* BLOCKING */
+ result = Curl_ssl_connect(conn, FIRSTSOCKET);
+ if(result)
+ return result;
+ }
+
+ Curl_pp_init(pp); /* init the generic pingpong data */
+
+ /* When we connect, we start in the state where we await the 220
+ response */
+ state(conn, FTP_WAIT220);
+
+ result = ftp_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ struct Curl_easy *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ ssize_t nread;
+ int ftpcode;
+ CURLcode result = CURLE_OK;
+ char *path = NULL;
+ const char *path_to_use = data->state.path;
+
+ if(!ftp)
+ return CURLE_OK;
+
+ switch(status) {
+ case CURLE_BAD_DOWNLOAD_RESUME:
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ case CURLE_FTP_PORT_FAILED:
+ case CURLE_FTP_ACCEPT_FAILED:
+ case CURLE_FTP_ACCEPT_TIMEOUT:
+ case CURLE_FTP_COULDNT_SET_TYPE:
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ case CURLE_PARTIAL_FILE:
+ case CURLE_UPLOAD_FAILED:
+ case CURLE_REMOTE_ACCESS_DENIED:
+ case CURLE_FILESIZE_EXCEEDED:
+ case CURLE_REMOTE_FILE_NOT_FOUND:
+ case CURLE_WRITE_ERROR:
+ /* the connection stays alive fine even though this happened */
+ /* fall-through */
+ case CURLE_OK: /* doesn't affect the control connection's status */
+ if(!premature)
+ break;
+
+ /* until we cope better with prematurely ended requests, let them
+ * fallback as if in complete failure */
+ /* FALLTHROUGH */
+ default: /* by default, an error means the control connection is
+ wedged and should not be used anymore */
+ ftpc->ctl_valid = FALSE;
+ ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
+ current path, as this connection is going */
+ connclose(conn, "FTP ended with bad error code");
+ result = status; /* use the already set error code */
+ break;
+ }
+
+ /* now store a copy of the directory we are in */
+ free(ftpc->prevpath);
+
+ if(data->set.wildcardmatch) {
+ if(data->set.chunk_end && ftpc->file) {
+ data->set.chunk_end(data->wildcard.customptr);
+ }
+ ftpc->known_filesize = -1;
+ }
+
+ if(!result)
+ /* get the "raw" path */
+ result = Curl_urldecode(data, path_to_use, 0, &path, NULL, FALSE);
+ if(result) {
+ /* We can limp along anyway (and should try to since we may already be in
+ * the error path) */
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ connclose(conn, "FTP: out of memory!"); /* mark for connection closure */
+ ftpc->prevpath = NULL; /* no path remembering */
+ }
+ else {
+ size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
+ size_t dlen = strlen(path)-flen;
+ if(!ftpc->cwdfail) {
+ if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
+ ftpc->prevpath = path;
+ if(flen)
+ /* if 'path' is not the whole string */
+ ftpc->prevpath[dlen]=0; /* terminate */
+ }
+ else {
+ /* we never changed dir */
+ ftpc->prevpath=strdup("");
+ free(path);
+ }
+ if(ftpc->prevpath)
+ infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
+ }
+ else {
+ ftpc->prevpath = NULL; /* no path */
+ free(path);
+ }
+ }
+ /* free the dir tree and file parts */
+ freedirs(ftpc);
+
+ /* shut down the socket to inform the server we're done */
+
+#ifdef _WIN32_WCE
+ shutdown(conn->sock[SECONDARYSOCKET], 2); /* SD_BOTH */
+#endif
+
+ if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+ if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
+ /* partial download completed */
+ result = Curl_pp_sendf(pp, "%s", "ABOR");
+ if(result) {
+ failf(data, "Failure sending ABOR command: %s",
+ curl_easy_strerror(result));
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ connclose(conn, "ABOR command failed"); /* connection closure */
+ }
+ }
+
+ if(conn->ssl[SECONDARYSOCKET].use) {
+ /* The secondary socket is using SSL so we must close down that part
+ first before we close the socket for real */
+ Curl_ssl_close(conn, SECONDARYSOCKET);
+
+ /* Note that we keep "use" set to TRUE since that (next) connection is
+ still requested to use SSL */
+ }
+ close_secondarysocket(conn);
+ }
+
+ if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+ pp->pending_resp && !premature) {
+ /*
+ * Let's see what the server says about the transfer we just performed,
+ * but lower the timeout as sometimes this connection has died while the
+ * data has been transferred. This happens when doing through NATs etc that
+ * abandon old silent connections.
+ */
+ long old_time = pp->response_time;
+
+ pp->response_time = 60*1000; /* give it only a minute for now */
+ pp->response = Curl_tvnow(); /* timeout relative now */
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ pp->response_time = old_time; /* set this back to previous value */
+
+ if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
+ failf(data, "control connection looks dead");
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
+ }
+
+ if(result)
+ return result;
+
+ if(ftpc->dont_check && data->req.maxdownload > 0) {
+ /* we have just sent ABOR and there is no reliable way to check if it was
+ * successful or not; we have to close the connection now */
+ infof(data, "partial download completed, closing connection\n");
+ connclose(conn, "Partial download with no ability to check");
+ return result;
+ }
+
+ if(!ftpc->dont_check) {
+ /* 226 Transfer complete, 250 Requested file action okay, completed. */
+ if((ftpcode != 226) && (ftpcode != 250)) {
+ failf(data, "server did not report OK, got %d", ftpcode);
+ result = CURLE_PARTIAL_FILE;
+ }
+ }
+ }
+
+ if(result || premature)
+ /* the response code from the transfer showed an error already so no
+ use checking further */
+ ;
+ else if(data->set.upload) {
+ if((-1 != data->state.infilesize) &&
+ (data->state.infilesize != *ftp->bytecountp) &&
+ !data->set.crlf &&
+ (ftp->transfer == FTPTRANSFER_BODY)) {
+ failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
+ " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
+ *ftp->bytecountp, data->state.infilesize);
+ result = CURLE_PARTIAL_FILE;
+ }
+ }
+ else {
+ if((-1 != data->req.size) &&
+ (data->req.size != *ftp->bytecountp) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
+ * we'll check to see if the discrepancy can be explained by the number
+ * of CRLFs we've changed to LFs.
+ */
+ ((data->req.size + data->state.crlf_conversions) !=
+ *ftp->bytecountp) &&
+#endif /* CURL_DO_LINEEND_CONV */
+ (data->req.maxdownload != *ftp->bytecountp)) {
+ failf(data, "Received only partial file: %" CURL_FORMAT_CURL_OFF_T
+ " bytes", *ftp->bytecountp);
+ result = CURLE_PARTIAL_FILE;
+ }
+ else if(!ftpc->dont_check &&
+ !*ftp->bytecountp &&
+ (data->req.size>0)) {
+ failf(data, "No data was received!");
+ result = CURLE_FTP_COULDNT_RETR_FILE;
+ }
+ }
+
+ /* clear these for next connection */
+ ftp->transfer = FTPTRANSFER_BODY;
+ ftpc->dont_check = FALSE;
+
+ /* Send any post-transfer QUOTE strings? */
+ if(!status && !result && !premature && data->set.postquote)
+ result = ftp_sendquote(conn, data->set.postquote);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_sendquote()
+ *
+ * Where a 'quote' means a list of custom commands to send to the server.
+ * The quote list is passed as an argument.
+ *
+ * BLOCKING
+ */
+
+static
+CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
+{
+ struct curl_slist *item;
+ ssize_t nread;
+ int ftpcode;
+ CURLcode result;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ item = quote;
+ while(item) {
+ if(item->data) {
+ char *cmd = item->data;
+ bool acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal FTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ acceptfail = TRUE;
+ }
+
+ PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
+
+ pp->response = Curl_tvnow(); /* timeout relative now */
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if(result)
+ return result;
+
+ if(!acceptfail && (ftpcode >= 400)) {
+ failf(conn->data, "QUOT string not accepted: %s", cmd);
+ return CURLE_QUOTE_ERROR;
+ }
+ }
+
+ item = item->next;
+ }
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_need_type()
+ *
+ * Returns TRUE if we in the current situation should send TYPE
+ */
+static int ftp_need_type(struct connectdata *conn,
+ bool ascii_wanted)
+{
+ return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
+}
+
+/***********************************************************************
+ *
+ * ftp_nb_type()
+ *
+ * Set TYPE. We only deal with ASCII or BINARY so this function
+ * sets one of them.
+ * If the transfer type is not sent, simulate on OK response in newstate
+ */
+static CURLcode ftp_nb_type(struct connectdata *conn,
+ bool ascii, ftpstate newstate)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result;
+ char want = (char)(ascii?'A':'I');
+
+ if(ftpc->transfertype == want) {
+ state(conn, newstate);
+ return ftp_state_type_resp(conn, 200, newstate);
+ }
+
+ PPSENDF(&ftpc->pp, "TYPE %c", want);
+ state(conn, newstate);
+
+ /* keep track of our current transfer type */
+ ftpc->transfertype = want;
+ return CURLE_OK;
+}
+
+/***************************************************************************
+ *
+ * ftp_pasv_verbose()
+ *
+ * This function only outputs some informationals about this second connection
+ * when we've issued a PASV command before and thus we have connected to a
+ * possibly new IP address.
+ *
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void
+ftp_pasv_verbose(struct connectdata *conn,
+ Curl_addrinfo *ai,
+ char *newhost, /* ascii version */
+ int port)
+{
+ char buf[256];
+ Curl_printable_address(ai, buf, sizeof(buf));
+ infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+}
+#endif
+
+/*
+ Check if this is a range download, and if so, set the internal variables
+ properly.
+ */
+
+static CURLcode ftp_range(struct connectdata *conn)
+{
+ curl_off_t from, to;
+ char *ptr;
+ char *ptr2;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(data->state.use_range && data->state.range) {
+ from=curlx_strtoofft(data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if(ptr == ptr2) {
+ /* we didn't get any digit */
+ to=-1;
+ }
+ if((-1 == to) && (from>=0)) {
+ /* X - */
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE %" CURL_FORMAT_CURL_OFF_T
+ " to end of file\n", from));
+ }
+ else if(from < 0) {
+ /* -Y */
+ data->req.maxdownload = -from;
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE the last %" CURL_FORMAT_CURL_OFF_T
+ " bytes\n", -from));
+ }
+ else {
+ /* X-Y */
+ data->req.maxdownload = (to-from)+1; /* include last byte */
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE from %" CURL_FORMAT_CURL_OFF_T
+ " getting %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ from, data->req.maxdownload));
+ }
+ DEBUGF(infof(conn->data, "range-download from %" CURL_FORMAT_CURL_OFF_T
+ " to %" CURL_FORMAT_CURL_OFF_T ", totally %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ from, to, data->req.maxdownload));
+ ftpc->dont_check = TRUE; /* don't check for successful transfer */
+ }
+ else
+ data->req.maxdownload = -1;
+ return CURLE_OK;
+}
+
+
+/*
+ * ftp_do_more()
+ *
+ * This function shall be called when the second FTP (data) connection is
+ * connected.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back
+ * (which basically is only for when PASV is being sent to retry a failed
+ * EPSV).
+ */
+
+static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
+{
+ struct Curl_easy *data=conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ bool complete = FALSE;
+
+ /* the ftp struct is inited in ftp_connect() */
+ struct FTP *ftp = data->req.protop;
+
+ /* if the second connection isn't done yet, wait for it */
+ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
+ if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
+ /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
+ aren't used so we blank their arguments. TODO: make this nicer */
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
+
+ return result;
+ }
+
+ result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
+
+ /* Ready to do more? */
+ if(connected) {
+ DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
+ }
+ else {
+ if(result && (ftpc->count1 == 0)) {
+ *completep = -1; /* go back to DOING please */
+ /* this is a EPSV connect failing, try PASV instead */
+ return ftp_epsv_disable(conn);
+ }
+ return result;
+ }
+ }
+
+ result = Curl_proxy_connect(conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+
+ if(CONNECT_SECONDARYSOCKET_PROXY_SSL())
+ return result;
+
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
+ conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE)
+ return result;
+
+
+ if(ftpc->state) {
+ /* already in a state so skip the initial commands.
+ They are only done to kickstart the do_more state */
+ result = ftp_multi_statemach(conn, &complete);
+
+ *completep = (int)complete;
+
+ /* if we got an error or if we don't wait for a data connection return
+ immediately */
+ if(result || (ftpc->wait_data_conn != TRUE))
+ return result;
+
+ if(ftpc->wait_data_conn)
+ /* if we reach the end of the FTP state machine here, *complete will be
+ TRUE but so is ftpc->wait_data_conn, which says we need to wait for
+ the data connection and therefore we're not actually complete */
+ *completep = 0;
+ }
+
+ if(ftp->transfer <= FTPTRANSFER_INFO) {
+ /* a transfer is about to take place, or if not a file name was given
+ so we'll do a SIZE on it later and then we need the right TYPE first */
+
+ if(ftpc->wait_data_conn == TRUE) {
+ bool serv_conned;
+
+ result = ReceivedServerConnect(conn, &serv_conned);
+ if(result)
+ return result; /* Failed to accept data connection */
+
+ if(serv_conned) {
+ /* It looks data connection is established */
+ result = AcceptServerConnect(conn);
+ ftpc->wait_data_conn = FALSE;
+ if(!result)
+ result = InitiateTransfer(conn);
+
+ if(result)
+ return result;
+
+ *completep = 1; /* this state is now complete when the server has
+ connected back to us */
+ }
+ }
+ else if(data->set.upload) {
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+ if(result)
+ return result;
+
+ result = ftp_multi_statemach(conn, &complete);
+ if(ftpc->wait_data_conn)
+ /* if we reach the end of the FTP state machine here, *complete will be
+ TRUE but so is ftpc->wait_data_conn, which says we need to wait for
+ the data connection and therefore we're not actually complete */
+ *completep = 0;
+ else
+ *completep = (int)complete;
+ }
+ else {
+ /* download */
+ ftp->downloadsize = -1; /* unknown as of yet */
+
+ result = ftp_range(conn);
+ if(result)
+ ;
+ else if(data->set.ftp_list_only || !ftpc->file) {
+ /* The specified path ends with a slash, and therefore we think this
+ is a directory that is requested, use LIST. But before that we
+ need to set ASCII transfer mode. */
+
+ /* But only if a body transfer was requested. */
+ if(ftp->transfer == FTPTRANSFER_BODY) {
+ result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
+ if(result)
+ return result;
+ }
+ /* otherwise just fall through */
+ }
+ else {
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
+ if(result)
+ return result;
+ }
+
+ result = ftp_multi_statemach(conn, &complete);
+ *completep = (int)complete;
+ }
+ return result;
+ }
+
+ if(!result && (ftp->transfer != FTPTRANSFER_BODY))
+ /* no data to transfer. FIX: it feels like a kludge to have this here
+ too! */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ if(!ftpc->wait_data_conn) {
+ /* no waiting for the data connection so this is now complete */
+ *completep = 1;
+ DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
+ }
+
+ return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_perform()
+ *
+ * This is the actual DO function for FTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode ftp_perform(struct connectdata *conn,
+ bool *connected, /* connect status after PASV / PORT */
+ bool *dophase_done)
+{
+ /* this is FTP and no proxy */
+ CURLcode result=CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* requested no body means no transfer... */
+ struct FTP *ftp = conn->data->req.protop;
+ ftp->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
+ if(result)
+ return result;
+
+ /* run the state-machine */
+ result = ftp_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[SECONDARYSOCKET];
+
+ infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete1\n"));
+ }
+
+ return result;
+}
+
+static void wc_data_dtor(void *ptr)
+{
+ struct ftp_wc_tmpdata *tmp = ptr;
+ if(tmp)
+ Curl_ftp_parselist_data_free(&tmp->parser);
+ free(tmp);
+}
+
+static CURLcode init_wc_data(struct connectdata *conn)
+{
+ char *last_slash;
+ char *path = conn->data->state.path;
+ struct WildcardData *wildcard = &(conn->data->wildcard);
+ CURLcode result = CURLE_OK;
+ struct ftp_wc_tmpdata *ftp_tmp;
+
+ last_slash = strrchr(conn->data->state.path, '/');
+ if(last_slash) {
+ last_slash++;
+ if(last_slash[0] == '\0') {
+ wildcard->state = CURLWC_CLEAN;
+ result = ftp_parse_url_path(conn);
+ return result;
+ }
+ wildcard->pattern = strdup(last_slash);
+ if(!wildcard->pattern)
+ return CURLE_OUT_OF_MEMORY;
+ last_slash[0] = '\0'; /* cut file from path */
+ }
+ else { /* there is only 'wildcard pattern' or nothing */
+ if(path[0]) {
+ wildcard->pattern = strdup(path);
+ if(!wildcard->pattern)
+ return CURLE_OUT_OF_MEMORY;
+ path[0] = '\0';
+ }
+ else { /* only list */
+ wildcard->state = CURLWC_CLEAN;
+ result = ftp_parse_url_path(conn);
+ return result;
+ }
+ }
+
+ /* program continues only if URL is not ending with slash, allocate needed
+ resources for wildcard transfer */
+
+ /* allocate ftp protocol specific temporary wildcard data */
+ ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
+ if(!ftp_tmp) {
+ Curl_safefree(wildcard->pattern);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* INITIALIZE parselist structure */
+ ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
+ if(!ftp_tmp->parser) {
+ Curl_safefree(wildcard->pattern);
+ free(ftp_tmp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
+ wildcard->tmp_dtor = wc_data_dtor;
+
+ /* wildcard does not support NOCWD option (assert it?) */
+ if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
+ conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
+
+ /* try to parse ftp url */
+ result = ftp_parse_url_path(conn);
+ if(result) {
+ Curl_safefree(wildcard->pattern);
+ wildcard->tmp_dtor(wildcard->tmp);
+ wildcard->tmp_dtor = ZERO_NULL;
+ wildcard->tmp = NULL;
+ return result;
+ }
+
+ wildcard->path = strdup(conn->data->state.path);
+ if(!wildcard->path) {
+ Curl_safefree(wildcard->pattern);
+ wildcard->tmp_dtor(wildcard->tmp);
+ wildcard->tmp_dtor = ZERO_NULL;
+ wildcard->tmp = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* backup old write_function */
+ ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
+ /* parsing write function */
+ conn->data->set.fwrite_func = Curl_ftp_parselist;
+ /* backup old file descriptor */
+ ftp_tmp->backup.file_descriptor = conn->data->set.out;
+ /* let the writefunc callback know what curl pointer is working with */
+ conn->data->set.out = conn;
+
+ infof(conn->data, "Wildcard - Parsing started\n");
+ return CURLE_OK;
+}
+
+/* This is called recursively */
+static CURLcode wc_statemach(struct connectdata *conn)
+{
+ struct WildcardData * const wildcard = &(conn->data->wildcard);
+ CURLcode result = CURLE_OK;
+
+ switch(wildcard->state) {
+ case CURLWC_INIT:
+ result = init_wc_data(conn);
+ if(wildcard->state == CURLWC_CLEAN)
+ /* only listing! */
+ break;
+ wildcard->state = result ? CURLWC_ERROR : CURLWC_MATCHING;
+ break;
+
+ case CURLWC_MATCHING: {
+ /* In this state is LIST response successfully parsed, so lets restore
+ previous WRITEFUNCTION callback and WRITEDATA pointer */
+ struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
+ conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
+ conn->data->set.out = ftp_tmp->backup.file_descriptor;
+ ftp_tmp->backup.write_function = ZERO_NULL;
+ ftp_tmp->backup.file_descriptor = NULL;
+ wildcard->state = CURLWC_DOWNLOADING;
+
+ if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
+ /* error found in LIST parsing */
+ wildcard->state = CURLWC_CLEAN;
+ return wc_statemach(conn);
+ }
+ if(wildcard->filelist.size == 0) {
+ /* no corresponding file */
+ wildcard->state = CURLWC_CLEAN;
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+ }
+ return wc_statemach(conn);
+ }
+
+ case CURLWC_DOWNLOADING: {
+ /* filelist has at least one file, lets get first one */
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct curl_fileinfo *finfo = wildcard->filelist.head->ptr;
+
+ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+ if(!tmp_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* switch default "state.pathbuffer" and tmp_path, good to see
+ ftp_parse_url_path function to understand this trick */
+ Curl_safefree(conn->data->state.pathbuffer);
+ conn->data->state.pathbuffer = tmp_path;
+ conn->data->state.path = tmp_path;
+
+ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
+ if(conn->data->set.chunk_bgn) {
+ long userresponse = conn->data->set.chunk_bgn(
+ finfo, wildcard->customptr, (int)wildcard->filelist.size);
+ switch(userresponse) {
+ case CURL_CHUNK_BGN_FUNC_SKIP:
+ infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
+ finfo->filename);
+ wildcard->state = CURLWC_SKIP;
+ return wc_statemach(conn);
+ case CURL_CHUNK_BGN_FUNC_FAIL:
+ return CURLE_CHUNK_FAILED;
+ }
+ }
+
+ if(finfo->filetype != CURLFILETYPE_FILE) {
+ wildcard->state = CURLWC_SKIP;
+ return wc_statemach(conn);
+ }
+
+ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+ ftpc->known_filesize = finfo->size;
+
+ result = ftp_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* we don't need the Curl_fileinfo of first file anymore */
+ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+
+ if(wildcard->filelist.size == 0) { /* remains only one file to down. */
+ wildcard->state = CURLWC_CLEAN;
+ /* after that will be ftp_do called once again and no transfer
+ will be done because of CURLWC_CLEAN state */
+ return CURLE_OK;
+ }
+ } break;
+
+ case CURLWC_SKIP: {
+ if(conn->data->set.chunk_end)
+ conn->data->set.chunk_end(conn->data->wildcard.customptr);
+ Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
+ wildcard->state = (wildcard->filelist.size == 0) ?
+ CURLWC_CLEAN : CURLWC_DOWNLOADING;
+ return wc_statemach(conn);
+ }
+
+ case CURLWC_CLEAN: {
+ struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
+ result = CURLE_OK;
+ if(ftp_tmp)
+ result = Curl_ftp_parselist_geterror(ftp_tmp->parser);
+
+ wildcard->state = result ? CURLWC_ERROR : CURLWC_DONE;
+ } break;
+
+ case CURLWC_DONE:
+ case CURLWC_ERROR:
+ case CURLWC_CLEAR:
+ break;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (ftp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode ftp_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ *done = FALSE; /* default to false */
+ ftpc->wait_data_conn = FALSE; /* default to no such wait */
+
+ if(conn->data->set.wildcardmatch) {
+ result = wc_statemach(conn);
+ if(conn->data->wildcard.state == CURLWC_SKIP ||
+ conn->data->wildcard.state == CURLWC_DONE) {
+ /* do not call ftp_regular_transfer */
+ return CURLE_OK;
+ }
+ if(result) /* error, loop or skipping the file */
+ return result;
+ }
+ else { /* no wildcard FSM needed */
+ result = ftp_parse_url_path(conn);
+ if(result)
+ return result;
+ }
+
+ result = ftp_regular_transfer(conn, done);
+
+ return result;
+}
+
+
+CURLcode Curl_ftpsend(struct connectdata *conn, const char *cmd)
+{
+ ssize_t bytes_written;
+#define SBUF_SIZE 1024
+ char s[SBUF_SIZE];
+ size_t write_len;
+ char *sptr=s;
+ CURLcode result = CURLE_OK;
+#ifdef HAVE_GSSAPI
+ enum protection_level data_sec = conn->data_prot;
+#endif
+
+ write_len = strlen(cmd);
+ if(write_len > (sizeof(s) -3))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
+ write_len +=2;
+
+ bytes_written=0;
+
+ result = Curl_convert_to_network(conn->data, s, write_len);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+ for(;;) {
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CMD;
+#endif
+ result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+ &bytes_written);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+ conn->data_prot = data_sec;
+#endif
+
+ if(result)
+ break;
+
+ if(conn->data->set.verbose)
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+ sptr, (size_t)bytes_written, conn);
+
+ if(bytes_written != (ssize_t)write_len) {
+ write_len -= bytes_written;
+ sptr += bytes_written;
+ }
+ else
+ break;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_quit()
+ *
+ * This should be called before calling sclose() on an ftp control connection
+ * (not data connections). We should then wait for the response from the
+ * server before returning. The calling code should then try to close the
+ * connection.
+ *
+ */
+static CURLcode ftp_quit(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->proto.ftpc.ctl_valid) {
+ result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT");
+ if(result) {
+ failf(conn->data, "Failure sending QUIT command: %s",
+ curl_easy_strerror(result));
+ conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
+ connclose(conn, "QUIT command failed"); /* mark for connection closure */
+ state(conn, FTP_STOP);
+ return result;
+ }
+
+ state(conn, FTP_QUIT);
+
+ result = ftp_block_statemach(conn);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_disconnect()
+ *
+ * Disconnect from an FTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct ftp_conn *ftpc= &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to.
+
+ ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+ will try to send the QUIT command, otherwise it will just return.
+ */
+ if(dead_connection)
+ ftpc->ctl_valid = FALSE;
+
+ /* The FTP session may or may not have been allocated/setup at this point! */
+ (void)ftp_quit(conn); /* ignore errors on the QUIT */
+
+ if(ftpc->entrypath) {
+ struct Curl_easy *data = conn->data;
+ if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
+ data->state.most_recent_ftp_entrypath = NULL;
+ }
+ free(ftpc->entrypath);
+ ftpc->entrypath = NULL;
+ }
+
+ freedirs(ftpc);
+ free(ftpc->prevpath);
+ ftpc->prevpath = NULL;
+ free(ftpc->server_os);
+ ftpc->server_os = NULL;
+
+ Curl_pp_disconnect(pp);
+
+#ifdef HAVE_GSSAPI
+ Curl_sec_end(conn);
+#endif
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static
+CURLcode ftp_parse_url_path(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ /* the ftp struct is already inited in ftp_connect() */
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ const char *slash_pos; /* position of the first '/' char in curpos */
+ const char *path_to_use = data->state.path;
+ const char *cur_pos;
+ const char *filename = NULL;
+
+ cur_pos = path_to_use; /* current position in path. point at the begin of
+ next path component */
+
+ ftpc->ctl_valid = FALSE;
+ ftpc->cwdfail = FALSE;
+
+ switch(data->set.ftp_filemethod) {
+ case FTPFILE_NOCWD:
+ /* fastest, but less standard-compliant */
+
+ /*
+ The best time to check whether the path is a file or directory is right
+ here. so:
+
+ the first condition in the if() right here, is there just in case
+ someone decides to set path to NULL one day
+ */
+ if(path_to_use[0] &&
+ (path_to_use[strlen(path_to_use) - 1] != '/') )
+ filename = path_to_use; /* this is a full file path */
+ /*
+ else {
+ ftpc->file is not used anywhere other than for operations on a file.
+ In other words, never for directory operations.
+ So we can safely leave filename as NULL here and use it as a
+ argument in dir/file decisions.
+ }
+ */
+ break;
+
+ case FTPFILE_SINGLECWD:
+ /* get the last slash */
+ if(!path_to_use[0]) {
+ /* no dir, no file */
+ ftpc->dirdepth = 0;
+ break;
+ }
+ slash_pos=strrchr(cur_pos, '/');
+ if(slash_pos || !*cur_pos) {
+ size_t dirlen = slash_pos-cur_pos;
+ CURLcode result;
+
+ ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0]));
+ if(!ftpc->dirs)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(!dirlen)
+ dirlen++;
+
+ result = Curl_urldecode(conn->data, slash_pos ? cur_pos : "/",
+ slash_pos ? dirlen : 1,
+ &ftpc->dirs[0], NULL,
+ FALSE);
+ if(result) {
+ freedirs(ftpc);
+ return result;
+ }
+ ftpc->dirdepth = 1; /* we consider it to be a single dir */
+ filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
+ }
+ else
+ filename = cur_pos; /* this is a file name only */
+ break;
+
+ default: /* allow pretty much anything */
+ case FTPFILE_MULTICWD:
+ ftpc->dirdepth = 0;
+ ftpc->diralloc = 5; /* default dir depth to allocate */
+ ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
+ if(!ftpc->dirs)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* we have a special case for listing the root dir only */
+ if(!strcmp(path_to_use, "/")) {
+ cur_pos++; /* make it point to the zero byte */
+ ftpc->dirs[0] = strdup("/");
+ ftpc->dirdepth++;
+ }
+ else {
+ /* parse the URL path into separate path components */
+ while((slash_pos = strchr(cur_pos, '/')) != NULL) {
+ /* 1 or 0 pointer offset to indicate absolute directory */
+ ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
+ (ftpc->dirdepth == 0))?1:0;
+
+ /* seek out the next path component */
+ if(slash_pos-cur_pos) {
+ /* we skip empty path components, like "x//y" since the FTP command
+ CWD requires a parameter and a non-existent parameter a) doesn't
+ work on many servers and b) has no effect on the others. */
+ size_t len = slash_pos - cur_pos + absolute_dir;
+ CURLcode result =
+ Curl_urldecode(conn->data, cur_pos - absolute_dir, len,
+ &ftpc->dirs[ftpc->dirdepth], NULL,
+ TRUE);
+ if(result) {
+ freedirs(ftpc);
+ return result;
+ }
+ }
+ else {
+ cur_pos = slash_pos + 1; /* jump to the rest of the string */
+ if(!ftpc->dirdepth) {
+ /* path starts with a slash, add that as a directory */
+ ftpc->dirs[ftpc->dirdepth] = strdup("/");
+ if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */
+ failf(data, "no memory");
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ continue;
+ }
+
+ cur_pos = slash_pos + 1; /* jump to the rest of the string */
+ if(++ftpc->dirdepth >= ftpc->diralloc) {
+ /* enlarge array */
+ char **bigger;
+ ftpc->diralloc *= 2; /* double the size each time */
+ bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
+ if(!bigger) {
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ftpc->dirs = bigger;
+ }
+ }
+ }
+ filename = cur_pos; /* the rest is the file name */
+ break;
+ } /* switch */
+
+ if(filename && *filename) {
+ CURLcode result =
+ Curl_urldecode(conn->data, filename, 0, &ftpc->file, NULL, TRUE);
+
+ if(result) {
+ freedirs(ftpc);
+ return result;
+ }
+ }
+ else
+ ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
+ pointer */
+
+ if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+ /* We need a file name when uploading. Return error! */
+ failf(data, "Uploading to a URL without a file name!");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ ftpc->cwddone = FALSE; /* default to not done */
+
+ if(ftpc->prevpath) {
+ /* prevpath is "raw" so we convert the input path before we compare the
+ strings */
+ size_t dlen;
+ char *path;
+ CURLcode result =
+ Curl_urldecode(conn->data, data->state.path, 0, &path, &dlen, FALSE);
+ if(result) {
+ freedirs(ftpc);
+ return result;
+ }
+
+ dlen -= ftpc->file?strlen(ftpc->file):0;
+ if((dlen == strlen(ftpc->prevpath)) &&
+ !strncmp(path, ftpc->prevpath, dlen)) {
+ infof(data, "Request has same path as previous transfer\n");
+ ftpc->cwddone = TRUE;
+ }
+ free(path);
+ }
+
+ return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+ bool connected)
+{
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(connected) {
+ int completed;
+ CURLcode result = ftp_do_more(conn, &completed);
+
+ if(result) {
+ close_secondarysocket(conn);
+ return result;
+ }
+ }
+
+ if(ftp->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ else if(!connected)
+ /* since we didn't connect now, we want do_more to get called */
+ conn->bits.do_more = TRUE;
+
+ ftpc->ctl_valid = TRUE; /* seems good */
+
+ return CURLE_OK;
+}
+
+/* called from multi.c while DOing */
+static CURLcode ftp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = ftp_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = ftp_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete2\n"));
+ }
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * ftp_done() function without finding any major problem.
+ */
+static
+CURLcode ftp_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result=CURLE_OK;
+ bool connected=FALSE;
+ struct Curl_easy *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ data->req.size = -1; /* make sure this is unknown at this point */
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, -1);
+ Curl_pgrsSetDownloadSize(data, -1);
+
+ ftpc->ctl_valid = TRUE; /* starts good */
+
+ result = ftp_perform(conn,
+ &connected, /* have we connected after PASV/PORT */
+ dophase_done); /* all commands in the DO-phase done? */
+
+ if(!result) {
+
+ if(!*dophase_done)
+ /* the DO phase has not completed yet */
+ return CURLE_OK;
+
+ result = ftp_dophase_done(conn, connected);
+
+ if(result)
+ return result;
+ }
+ else
+ freedirs(ftpc);
+
+ return result;
+}
+
+static CURLcode ftp_setup_connection(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ char *type;
+ char command;
+ struct FTP *ftp;
+
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel ftp operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_ftp)
+ conn->handler = &Curl_handler_ftp_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_ftps_proxy;
+#else
+ failf(data, "FTPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+ /* set it up as a HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+#else
+ failf(data, "FTP over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ conn->data->req.protop = ftp = malloc(sizeof(struct FTP));
+ if(NULL == ftp)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->state.path++; /* don't include the initial slash */
+ data->state.slash_removed = TRUE; /* we've skipped the slash */
+
+ /* FTP URLs support an extension like ";type=<typecode>" that
+ * we'll try to get now! */
+ type = strstr(data->state.path, ";type=");
+
+ if(!type)
+ type = strstr(conn->host.rawalloc, ";type=");
+
+ if(type) {
+ *type = 0; /* it was in the middle of the hostname */
+ command = Curl_raw_toupper(type[6]);
+ conn->bits.type_set = TRUE;
+
+ switch(command) {
+ case 'A': /* ASCII mode */
+ data->set.prefer_ascii = TRUE;
+ break;
+
+ case 'D': /* directory mode */
+ data->set.ftp_list_only = TRUE;
+ break;
+
+ case 'I': /* binary mode */
+ default:
+ /* switch off ASCII */
+ data->set.prefer_ascii = FALSE;
+ break;
+ }
+ }
+
+ /* get some initial data into the ftp struct */
+ ftp->bytecountp = &conn->data->req.bytecount;
+ ftp->transfer = FTPTRANSFER_BODY;
+ ftp->downloadsize = 0;
+
+ /* No need to duplicate user+password, the connectdata struct won't change
+ during a session, but we re-init them here since on subsequent inits
+ since the conn struct may have changed or been replaced.
+ */
+ ftp->user = conn->user;
+ ftp->passwd = conn->passwd;
+ if(isBadFtpString(ftp->user))
+ return CURLE_URL_MALFORMAT;
+ if(isBadFtpString(ftp->passwd))
+ return CURLE_URL_MALFORMAT;
+
+ conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/lib/ftp.h b/Utilities/cmcurl/lib/ftp.h
new file mode 100644
index 000000000..3bbf26206
--- /dev/null
+++ b/Utilities/cmcurl/lib/ftp.h
@@ -0,0 +1,159 @@
+#ifndef HEADER_CURL_FTP_H
+#define HEADER_CURL_FTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+
+#ifndef CURL_DISABLE_FTP
+extern const struct Curl_handler Curl_handler_ftp;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_ftps;
+#endif
+
+CURLcode Curl_ftpsend(struct connectdata *, const char *cmd);
+CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+ int *ftpcode);
+#endif /* CURL_DISABLE_FTP */
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+typedef enum {
+ FTP_STOP, /* do nothing state, stops the state machine */
+ FTP_WAIT220, /* waiting for the initial 220 response immediately after
+ a connect */
+ FTP_AUTH,
+ FTP_USER,
+ FTP_PASS,
+ FTP_ACCT,
+ FTP_PBSZ,
+ FTP_PROT,
+ FTP_CCC,
+ FTP_PWD,
+ FTP_SYST,
+ FTP_NAMEFMT,
+ FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
+ FTP_RETR_PREQUOTE,
+ FTP_STOR_PREQUOTE,
+ FTP_POSTQUOTE,
+ FTP_CWD, /* change dir */
+ FTP_MKD, /* if the dir didn't exist */
+ FTP_MDTM, /* to figure out the datestamp */
+ FTP_TYPE, /* to set type when doing a head-like request */
+ FTP_LIST_TYPE, /* set type when about to do a dir list */
+ FTP_RETR_TYPE, /* set type when about to RETR a file */
+ FTP_STOR_TYPE, /* set type when about to STOR a file */
+ FTP_SIZE, /* get the remote file's size for head-like request */
+ FTP_RETR_SIZE, /* get the remote file's size for RETR */
+ FTP_STOR_SIZE, /* get the size for STOR */
+ FTP_REST, /* when used to check if the server supports it in head-like */
+ FTP_RETR_REST, /* when asking for "resume" in for RETR */
+ FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
+ FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
+ FTP_PASV, /* generic state for PASV and EPSV, check count1 */
+ FTP_LIST, /* generic state for LIST, NLST or a custom list command */
+ FTP_RETR,
+ FTP_STOR, /* generic state for STOR and APPE */
+ FTP_QUIT,
+ FTP_LAST /* never used */
+} ftpstate;
+
+struct ftp_parselist_data; /* defined later in ftplistparser.c */
+
+struct ftp_wc_tmpdata {
+ struct ftp_parselist_data *parser;
+
+ struct {
+ curl_write_callback write_function;
+ FILE *file_descriptor;
+ } backup;
+};
+
+typedef enum {
+ FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */
+ FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */
+ FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the
+ file */
+} curl_ftpfile;
+
+/* This FTP struct is used in the Curl_easy. All FTP data that is
+ connection-oriented must be in FTP_conn to properly deal with the fact that
+ perhaps the Curl_easy is changed between the times the connection is
+ used. */
+struct FTP {
+ curl_off_t *bytecountp;
+ char *user; /* user name string */
+ char *passwd; /* password string */
+
+ /* transfer a file/body or not, done as a typedefed enum just to make
+ debuggers display the full symbol and not just the numerical value */
+ curl_pp_transfer transfer;
+ curl_off_t downloadsize;
+};
+
+
+/* ftp_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct ftp_conn {
+ struct pingpong pp;
+ char *entrypath; /* the PWD reply when we logged on */
+ char **dirs; /* realloc()ed array for path components */
+ int dirdepth; /* number of entries used in the 'dirs' array */
+ int diralloc; /* number of entries allocated for the 'dirs' array */
+ char *file; /* decoded file */
+ bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
+ file size and 226/250 status check. It should still
+ read the line, just ignore the result. */
+ bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If
+ the connection has timed out or been closed, this
+ should be FALSE when it gets to Curl_ftp_quit() */
+ bool cwddone; /* if it has been determined that the proper CWD combo
+ already has been done */
+ bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent
+ caching the current directory */
+ bool wait_data_conn; /* this is set TRUE if data connection is waited */
+ char *prevpath; /* conn->path from the previous transfer */
+ char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
+ and others (A/I or zero) */
+ int count1; /* general purpose counter for the state machine */
+ int count2; /* general purpose counter for the state machine */
+ int count3; /* general purpose counter for the state machine */
+ ftpstate state; /* always use ftp.c:state() to change state! */
+ ftpstate state_saved; /* transfer type saved to be reloaded after
+ data connection is established */
+ curl_off_t retr_size_saved; /* Size of retrieved file saved */
+ char *server_os; /* The target server operating system. */
+ curl_off_t known_filesize; /* file size is different from -1, if wildcard
+ LIST parsing was done and wc_statemach set
+ it */
+ /* newhost is the (allocated) IP addr or host name to connect the data
+ connection to */
+ char *newhost; /* this is the pair to connect the DATA... */
+ unsigned short newport; /* connection to */
+
+};
+
+#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */
+
+#endif /* HEADER_CURL_FTP_H */
diff --git a/Utilities/cmcurl/lib/ftplistparser.c b/Utilities/cmcurl/lib/ftplistparser.c
new file mode 100644
index 000000000..2acce31d8
--- /dev/null
+++ b/Utilities/cmcurl/lib/ftplistparser.c
@@ -0,0 +1,1024 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/**
+ * Now implemented:
+ *
+ * 1) Unix version 1
+ * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
+ * 2) Unix version 2
+ * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
+ * 3) Unix version 3
+ * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
+ * 4) Unix symlink
+ * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
+ * 5) DOS style
+ * 01-29-97 11:32PM <DIR> prog
+ */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "fileinfo.h"
+#include "llist.h"
+#include "strtoofft.h"
+#include "ftp.h"
+#include "ftplistparser.h"
+#include "curl_fnmatch.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* allocs buffer which will contain one line of LIST command response */
+#define FTP_BUFFER_ALLOCSIZE 160
+
+typedef enum {
+ PL_UNIX_TOTALSIZE = 0,
+ PL_UNIX_FILETYPE,
+ PL_UNIX_PERMISSION,
+ PL_UNIX_HLINKS,
+ PL_UNIX_USER,
+ PL_UNIX_GROUP,
+ PL_UNIX_SIZE,
+ PL_UNIX_TIME,
+ PL_UNIX_FILENAME,
+ PL_UNIX_SYMLINK
+} pl_unix_mainstate;
+
+typedef union {
+ enum {
+ PL_UNIX_TOTALSIZE_INIT = 0,
+ PL_UNIX_TOTALSIZE_READING
+ } total_dirsize;
+
+ enum {
+ PL_UNIX_HLINKS_PRESPACE = 0,
+ PL_UNIX_HLINKS_NUMBER
+ } hlinks;
+
+ enum {
+ PL_UNIX_USER_PRESPACE = 0,
+ PL_UNIX_USER_PARSING
+ } user;
+
+ enum {
+ PL_UNIX_GROUP_PRESPACE = 0,
+ PL_UNIX_GROUP_NAME
+ } group;
+
+ enum {
+ PL_UNIX_SIZE_PRESPACE = 0,
+ PL_UNIX_SIZE_NUMBER
+ } size;
+
+ enum {
+ PL_UNIX_TIME_PREPART1 = 0,
+ PL_UNIX_TIME_PART1,
+ PL_UNIX_TIME_PREPART2,
+ PL_UNIX_TIME_PART2,
+ PL_UNIX_TIME_PREPART3,
+ PL_UNIX_TIME_PART3
+ } time;
+
+ enum {
+ PL_UNIX_FILENAME_PRESPACE = 0,
+ PL_UNIX_FILENAME_NAME,
+ PL_UNIX_FILENAME_WINDOWSEOL
+ } filename;
+
+ enum {
+ PL_UNIX_SYMLINK_PRESPACE = 0,
+ PL_UNIX_SYMLINK_NAME,
+ PL_UNIX_SYMLINK_PRETARGET1,
+ PL_UNIX_SYMLINK_PRETARGET2,
+ PL_UNIX_SYMLINK_PRETARGET3,
+ PL_UNIX_SYMLINK_PRETARGET4,
+ PL_UNIX_SYMLINK_TARGET,
+ PL_UNIX_SYMLINK_WINDOWSEOL
+ } symlink;
+} pl_unix_substate;
+
+typedef enum {
+ PL_WINNT_DATE = 0,
+ PL_WINNT_TIME,
+ PL_WINNT_DIRORSIZE,
+ PL_WINNT_FILENAME
+} pl_winNT_mainstate;
+
+typedef union {
+ enum {
+ PL_WINNT_TIME_PRESPACE = 0,
+ PL_WINNT_TIME_TIME
+ } time;
+ enum {
+ PL_WINNT_DIRORSIZE_PRESPACE = 0,
+ PL_WINNT_DIRORSIZE_CONTENT
+ } dirorsize;
+ enum {
+ PL_WINNT_FILENAME_PRESPACE = 0,
+ PL_WINNT_FILENAME_CONTENT,
+ PL_WINNT_FILENAME_WINEOL
+ } filename;
+} pl_winNT_substate;
+
+/* This struct is used in wildcard downloading - for parsing LIST response */
+struct ftp_parselist_data {
+ enum {
+ OS_TYPE_UNKNOWN = 0,
+ OS_TYPE_UNIX,
+ OS_TYPE_WIN_NT
+ } os_type;
+
+ union {
+ struct {
+ pl_unix_mainstate main;
+ pl_unix_substate sub;
+ } UNIX;
+
+ struct {
+ pl_winNT_mainstate main;
+ pl_winNT_substate sub;
+ } NT;
+ } state;
+
+ CURLcode error;
+ struct fileinfo *file_data;
+ unsigned int item_length;
+ size_t item_offset;
+ struct {
+ size_t filename;
+ size_t user;
+ size_t group;
+ size_t time;
+ size_t perm;
+ size_t symlink_target;
+ } offsets;
+};
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
+{
+ return calloc(1, sizeof(struct ftp_parselist_data));
+}
+
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
+{
+ free(*pl_data);
+ *pl_data = NULL;
+}
+
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
+{
+ return pl_data->error;
+}
+
+
+#define FTP_LP_MALFORMATED_PERM 0x01000000
+
+static int ftp_pl_get_permission(const char *str)
+{
+ int permissions = 0;
+ /* USER */
+ if(str[0] == 'r')
+ permissions |= 1 << 8;
+ else if(str[0] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[1] == 'w')
+ permissions |= 1 << 7;
+ else if(str[1] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+
+ if(str[2] == 'x')
+ permissions |= 1 << 6;
+ else if(str[2] == 's') {
+ permissions |= 1 << 6;
+ permissions |= 1 << 11;
+ }
+ else if(str[2] == 'S')
+ permissions |= 1 << 11;
+ else if(str[2] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ /* GROUP */
+ if(str[3] == 'r')
+ permissions |= 1 << 5;
+ else if(str[3] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[4] == 'w')
+ permissions |= 1 << 4;
+ else if(str[4] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[5] == 'x')
+ permissions |= 1 << 3;
+ else if(str[5] == 's') {
+ permissions |= 1 << 3;
+ permissions |= 1 << 10;
+ }
+ else if(str[5] == 'S')
+ permissions |= 1 << 10;
+ else if(str[5] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ /* others */
+ if(str[6] == 'r')
+ permissions |= 1 << 2;
+ else if(str[6] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[7] == 'w')
+ permissions |= 1 << 1;
+ else if(str[7] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[8] == 'x')
+ permissions |= 1;
+ else if(str[8] == 't') {
+ permissions |= 1;
+ permissions |= 1 << 9;
+ }
+ else if(str[8] == 'T')
+ permissions |= 1 << 9;
+ else if(str[8] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+
+ return permissions;
+}
+
+static void PL_ERROR(struct connectdata *conn, CURLcode err)
+{
+ struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ if(parser->file_data)
+ Curl_fileinfo_dtor(NULL, parser->file_data);
+ parser->file_data = NULL;
+ parser->error = err;
+}
+
+static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
+ struct fileinfo *infop)
+{
+ curl_fnmatch_callback compare;
+ struct WildcardData *wc = &conn->data->wildcard;
+ struct ftp_wc_tmpdata *tmpdata = wc->tmp;
+ struct curl_llist *llist = &wc->filelist;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ bool add = TRUE;
+ struct curl_fileinfo *finfo = &infop->info;
+
+ /* move finfo pointers to b_data */
+ char *str = finfo->b_data;
+ finfo->filename = str + parser->offsets.filename;
+ finfo->strings.group = parser->offsets.group ?
+ str + parser->offsets.group : NULL;
+ finfo->strings.perm = parser->offsets.perm ?
+ str + parser->offsets.perm : NULL;
+ finfo->strings.target = parser->offsets.symlink_target ?
+ str + parser->offsets.symlink_target : NULL;
+ finfo->strings.time = str + parser->offsets.time;
+ finfo->strings.user = parser->offsets.user ?
+ str + parser->offsets.user : NULL;
+
+ /* get correct fnmatch callback */
+ compare = conn->data->set.fnmatch;
+ if(!compare)
+ compare = Curl_fnmatch;
+
+ /* filter pattern-corresponding filenames */
+ if(compare(conn->data->set.fnmatch_data, wc->pattern,
+ finfo->filename) == 0) {
+ /* discard symlink which is containing multiple " -> " */
+ if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
+ (strstr(finfo->strings.target, " -> "))) {
+ add = FALSE;
+ }
+ }
+ else {
+ add = FALSE;
+ }
+
+ if(add) {
+ Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
+ }
+ else {
+ Curl_fileinfo_dtor(NULL, finfo);
+ }
+
+ tmpdata->parser->file_data = NULL;
+ return CURLE_OK;
+}
+
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+ void *connptr)
+{
+ size_t bufflen = size*nmemb;
+ struct connectdata *conn = (struct connectdata *)connptr;
+ struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ struct fileinfo *infop;
+ struct curl_fileinfo *finfo;
+ unsigned long i = 0;
+ CURLcode result;
+
+ if(parser->error) { /* error in previous call */
+ /* scenario:
+ * 1. call => OK..
+ * 2. call => OUT_OF_MEMORY (or other error)
+ * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
+ * in wc_statemach()
+ */
+ return bufflen;
+ }
+
+ if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
+ /* considering info about FILE response format */
+ parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
+ OS_TYPE_WIN_NT : OS_TYPE_UNIX;
+ }
+
+ while(i < bufflen) { /* FSM */
+
+ char c = buffer[i];
+ if(!parser->file_data) { /* tmp file data is not allocated yet */
+ parser->file_data = Curl_fileinfo_alloc();
+ if(!parser->file_data) {
+ parser->error = CURLE_OUT_OF_MEMORY;
+ return bufflen;
+ }
+ parser->file_data->info.b_data = malloc(FTP_BUFFER_ALLOCSIZE);
+ if(!parser->file_data->info.b_data) {
+ PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
+ return bufflen;
+ }
+ parser->file_data->info.b_size = FTP_BUFFER_ALLOCSIZE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+
+ infop = parser->file_data;
+ finfo = &infop->info;
+ finfo->b_data[finfo->b_used++] = c;
+
+ if(finfo->b_used >= finfo->b_size - 1) {
+ /* if it is important, extend buffer space for file data */
+ char *tmp = realloc(finfo->b_data,
+ finfo->b_size + FTP_BUFFER_ALLOCSIZE);
+ if(tmp) {
+ finfo->b_size += FTP_BUFFER_ALLOCSIZE;
+ finfo->b_data = tmp;
+ }
+ else {
+ Curl_fileinfo_dtor(NULL, parser->file_data);
+ parser->file_data = NULL;
+ parser->error = CURLE_OUT_OF_MEMORY;
+ PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
+ return bufflen;
+ }
+ }
+
+ switch(parser->os_type) {
+ case OS_TYPE_UNIX:
+ switch(parser->state.UNIX.main) {
+ case PL_UNIX_TOTALSIZE:
+ switch(parser->state.UNIX.sub.total_dirsize) {
+ case PL_UNIX_TOTALSIZE_INIT:
+ if(c == 't') {
+ parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
+ parser->item_length++;
+ }
+ else {
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ /* start FSM again not considering size of directory */
+ finfo->b_used = 0;
+ i--;
+ }
+ break;
+ case PL_UNIX_TOTALSIZE_READING:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->item_length--;
+ finfo->b_used--;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_length - 1] = 0;
+ if(strncmp("total ", finfo->b_data, 6) == 0) {
+ char *endptr = finfo->b_data+6;
+ /* here we can deal with directory size, pass the leading white
+ spaces and then the digits */
+ while(ISSPACE(*endptr))
+ endptr++;
+ while(ISDIGIT(*endptr))
+ endptr++;
+ if(*endptr != 0) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ finfo->b_used = 0;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_FILETYPE:
+ switch(c) {
+ case '-':
+ finfo->filetype = CURLFILETYPE_FILE;
+ break;
+ case 'd':
+ finfo->filetype = CURLFILETYPE_DIRECTORY;
+ break;
+ case 'l':
+ finfo->filetype = CURLFILETYPE_SYMLINK;
+ break;
+ case 'p':
+ finfo->filetype = CURLFILETYPE_NAMEDPIPE;
+ break;
+ case 's':
+ finfo->filetype = CURLFILETYPE_SOCKET;
+ break;
+ case 'c':
+ finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
+ break;
+ case 'b':
+ finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
+ break;
+ case 'D':
+ finfo->filetype = CURLFILETYPE_DOOR;
+ break;
+ default:
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_PERMISSION;
+ parser->item_length = 0;
+ parser->item_offset = 1;
+ break;
+ case PL_UNIX_PERMISSION:
+ parser->item_length++;
+ if(parser->item_length <= 9) {
+ if(!strchr("rwx-tTsS", c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else if(parser->item_length == 10) {
+ unsigned int perm;
+ if(c != ' ') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ finfo->b_data[10] = 0; /* terminate permissions */
+ perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
+ if(perm & FTP_LP_MALFORMATED_PERM) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_PERM;
+ parser->file_data->info.perm = perm;
+ parser->offsets.perm = parser->item_offset;
+
+ parser->item_length = 0;
+ parser->state.UNIX.main = PL_UNIX_HLINKS;
+ parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
+ }
+ break;
+ case PL_UNIX_HLINKS:
+ switch(parser->state.UNIX.sub.hlinks) {
+ case PL_UNIX_HLINKS_PRESPACE:
+ if(c != ' ') {
+ if(c >= '0' && c <= '9') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_HLINKS_NUMBER:
+ parser->item_length ++;
+ if(c == ' ') {
+ char *p;
+ long int hlinks;
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
+ if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
+ parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
+ parser->file_data->info.hardlinks = hlinks;
+ }
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ parser->state.UNIX.main = PL_UNIX_USER;
+ parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
+ }
+ else if(c < '0' || c > '9') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_USER:
+ switch(parser->state.UNIX.sub.user) {
+ case PL_UNIX_USER_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
+ }
+ break;
+ case PL_UNIX_USER_PARSING:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.user = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_GROUP;
+ parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_GROUP:
+ switch(parser->state.UNIX.sub.group) {
+ case PL_UNIX_GROUP_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
+ }
+ break;
+ case PL_UNIX_GROUP_NAME:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.group = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_SIZE;
+ parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_SIZE:
+ switch(parser->state.UNIX.sub.size) {
+ case PL_UNIX_SIZE_PRESPACE:
+ if(c != ' ') {
+ if(c >= '0' && c <= '9') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_SIZE_NUMBER:
+ parser->item_length++;
+ if(c == ' ') {
+ char *p;
+ curl_off_t fsize;
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
+ if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+ fsize != CURL_OFF_T_MIN) {
+ parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+ parser->file_data->info.size = fsize;
+ }
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ parser->state.UNIX.main = PL_UNIX_TIME;
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
+ }
+ else if(!ISDIGIT(c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_TIME:
+ switch(parser->state.UNIX.sub.time) {
+ case PL_UNIX_TIME_PREPART1:
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->item_offset = finfo->b_used -1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART1:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
+ }
+ else if(!ISALNUM(c) && c != '.') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_TIME_PREPART2:
+ parser->item_length++;
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART2:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
+ }
+ else if(!ISALNUM(c) && c != '.') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_TIME_PREPART3:
+ parser->item_length++;
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART3:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
+ parser->offsets.time = parser->item_offset;
+ /*
+ if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
+ }
+ */
+ if(finfo->filetype == CURLFILETYPE_SYMLINK) {
+ parser->state.UNIX.main = PL_UNIX_SYMLINK;
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
+ }
+ else {
+ parser->state.UNIX.main = PL_UNIX_FILENAME;
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
+ }
+ }
+ else if(!ISALNUM(c) && c != '.' && c != ':') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_FILENAME:
+ switch(parser->state.UNIX.sub.filename) {
+ case PL_UNIX_FILENAME_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
+ }
+ break;
+ case PL_UNIX_FILENAME_NAME:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_FILENAME_WINDOWSEOL:
+ if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_SYMLINK:
+ switch(parser->state.UNIX.sub.symlink) {
+ case PL_UNIX_SYMLINK_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_NAME:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET1:
+ parser->item_length++;
+ if(c == '-') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET2:
+ parser->item_length++;
+ if(c == '>') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET3:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
+ /* now place where is symlink following */
+ finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET4:
+ if(c != '\r' && c != '\n') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_SYMLINK_TARGET:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.symlink_target = parser->item_offset;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ }
+ break;
+ case PL_UNIX_SYMLINK_WINDOWSEOL:
+ if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.symlink_target = parser->item_offset;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case OS_TYPE_WIN_NT:
+ switch(parser->state.NT.main) {
+ case PL_WINNT_DATE:
+ parser->item_length++;
+ if(parser->item_length < 9) {
+ if(!strchr("0123456789-", c)) { /* only simple control */
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else if(parser->item_length == 9) {
+ if(c == ' ') {
+ parser->state.NT.main = PL_WINNT_TIME;
+ parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_WINNT_TIME:
+ parser->item_length++;
+ switch(parser->state.NT.sub.time) {
+ case PL_WINNT_TIME_PRESPACE:
+ if(!ISSPACE(c)) {
+ parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
+ }
+ break;
+ case PL_WINNT_TIME_TIME:
+ if(c == ' ') {
+ parser->offsets.time = parser->item_offset;
+ finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
+ parser->state.NT.main = PL_WINNT_DIRORSIZE;
+ parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
+ parser->item_length = 0;
+ }
+ else if(!strchr("APM0123456789:", c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_WINNT_DIRORSIZE:
+ switch(parser->state.NT.sub.dirorsize) {
+ case PL_WINNT_DIRORSIZE_PRESPACE:
+ if(c == ' ') {
+
+ }
+ else {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
+ }
+ break;
+ case PL_WINNT_DIRORSIZE_CONTENT:
+ parser->item_length ++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
+ finfo->filetype = CURLFILETYPE_DIRECTORY;
+ finfo->size = 0;
+ }
+ else {
+ char *endptr;
+ finfo->size = curlx_strtoofft(finfo->b_data +
+ parser->item_offset,
+ &endptr, 10);
+ if(!*endptr) {
+ if(finfo->size == CURL_OFF_T_MAX ||
+ finfo->size == CURL_OFF_T_MIN) {
+ if(errno == ERANGE) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ /* correct file type */
+ parser->file_data->info.filetype = CURLFILETYPE_FILE;
+ }
+
+ parser->file_data->info.flags |= CURLFINFOFLAG_KNOWN_SIZE;
+ parser->item_length = 0;
+ parser->state.NT.main = PL_WINNT_FILENAME;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ break;
+ }
+ break;
+ case PL_WINNT_FILENAME:
+ switch(parser->state.NT.sub.filename) {
+ case PL_WINNT_FILENAME_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used -1;
+ parser->item_length = 1;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
+ }
+ break;
+ case PL_WINNT_FILENAME_CONTENT:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
+ finfo->b_data[finfo->b_used - 1] = 0;
+ }
+ else if(c == '\n') {
+ parser->offsets.filename = parser->item_offset;
+ finfo->b_data[finfo->b_used - 1] = 0;
+ parser->offsets.filename = parser->item_offset;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ parser->state.NT.main = PL_WINNT_DATE;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ break;
+ case PL_WINNT_FILENAME_WINEOL:
+ if(c == '\n') {
+ parser->offsets.filename = parser->item_offset;
+ result = ftp_pl_insert_finfo(conn, infop);
+ if(result) {
+ PL_ERROR(conn, result);
+ return bufflen;
+ }
+ parser->state.NT.main = PL_WINNT_DATE;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ return bufflen + 1;
+ }
+
+ i++;
+ }
+
+ return bufflen;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/lib/ftplistparser.h b/Utilities/cmcurl/lib/ftplistparser.h
new file mode 100644
index 000000000..8128887c0
--- /dev/null
+++ b/Utilities/cmcurl/lib/ftplistparser.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_FTPLISTPARSER_H
+#define HEADER_CURL_FTPLISTPARSER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+/* WRITEFUNCTION callback for parsing LIST responses */
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+ void *connptr);
+
+struct ftp_parselist_data; /* defined inside ftplibparser.c */
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data);
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void);
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
+
+#endif /* CURL_DISABLE_FTP */
+#endif /* HEADER_CURL_FTPLISTPARSER_H */
diff --git a/Utilities/cmcurl/lib/getenv.c b/Utilities/cmcurl/lib/getenv.c
new file mode 100644
index 000000000..89d181de3
--- /dev/null
+++ b/Utilities/cmcurl/lib/getenv.c
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+static
+char *GetEnv(const char *variable)
+{
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+ (void)variable;
+ return NULL;
+#else
+#ifdef WIN32
+ char env[MAX_PATH]; /* MAX_PATH is from windef.h */
+ char *temp = getenv(variable);
+ env[0] = '\0';
+ if(temp != NULL)
+ ExpandEnvironmentStringsA(temp, env, sizeof(env));
+ return (env[0] != '\0')?strdup(env):NULL;
+#else
+ char *env = getenv(variable);
+ return (env && env[0])?strdup(env):NULL;
+#endif
+#endif
+}
+
+char *curl_getenv(const char *v)
+{
+ return GetEnv(v);
+}
diff --git a/Utilities/cmcurl/lib/getinfo.c b/Utilities/cmcurl/lib/getinfo.c
new file mode 100644
index 000000000..a1ce5058e
--- /dev/null
+++ b/Utilities/cmcurl/lib/getinfo.c
@@ -0,0 +1,442 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "getinfo.h"
+
+#include "vtls/vtls.h"
+#include "connect.h" /* Curl_getconnectinfo() */
+#include "progress.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Initialize statistical and informational data.
+ *
+ * This function is called in curl_easy_reset, curl_easy_duphandle and at the
+ * beginning of a perform session. It must reset the session-info variables,
+ * in particular all variables in struct PureInfo.
+ */
+CURLcode Curl_initinfo(struct Curl_easy *data)
+{
+ struct Progress *pro = &data->progress;
+ struct PureInfo *info = &data->info;
+
+ pro->t_nslookup = 0;
+ pro->t_connect = 0;
+ pro->t_appconnect = 0;
+ pro->t_pretransfer = 0;
+ pro->t_starttransfer = 0;
+ pro->timespent = 0;
+ pro->t_redirect = 0;
+
+ info->httpcode = 0;
+ info->httpproxycode = 0;
+ info->httpversion = 0;
+ info->filetime = -1; /* -1 is an illegal time and thus means unknown */
+ info->timecond = FALSE;
+
+ info->header_size = 0;
+ info->request_size = 0;
+ info->proxyauthavail = 0;
+ info->httpauthavail = 0;
+ info->numconnects = 0;
+
+ free(info->contenttype);
+ info->contenttype = NULL;
+
+ free(info->wouldredirect);
+ info->wouldredirect = NULL;
+
+ info->conn_primary_ip[0] = '\0';
+ info->conn_local_ip[0] = '\0';
+ info->conn_primary_port = 0;
+ info->conn_local_port = 0;
+
+ info->conn_scheme = 0;
+ info->conn_protocol = 0;
+
+#ifdef USE_SSL
+ Curl_ssl_free_certinfo(data);
+#endif
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
+ const char **param_charp)
+{
+ switch(info) {
+ case CURLINFO_EFFECTIVE_URL:
+ *param_charp = data->change.url?data->change.url:(char *)"";
+ break;
+ case CURLINFO_CONTENT_TYPE:
+ *param_charp = data->info.contenttype;
+ break;
+ case CURLINFO_PRIVATE:
+ *param_charp = (char *) data->set.private_data;
+ break;
+ case CURLINFO_FTP_ENTRY_PATH:
+ /* Return the entrypath string from the most recent connection.
+ This pointer was copied from the connectdata structure by FTP.
+ The actual string may be free()ed by subsequent libcurl calls so
+ it must be copied to a safer area before the next libcurl call.
+ Callers must never free it themselves. */
+ *param_charp = data->state.most_recent_ftp_entrypath;
+ break;
+ case CURLINFO_REDIRECT_URL:
+ /* Return the URL this request would have been redirected to if that
+ option had been enabled! */
+ *param_charp = data->info.wouldredirect;
+ break;
+ case CURLINFO_PRIMARY_IP:
+ /* Return the ip address of the most recent (primary) connection */
+ *param_charp = data->info.conn_primary_ip;
+ break;
+ case CURLINFO_LOCAL_IP:
+ /* Return the source/local ip address of the most recent (primary)
+ connection */
+ *param_charp = data->info.conn_local_ip;
+ break;
+ case CURLINFO_RTSP_SESSION_ID:
+ *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+ break;
+ case CURLINFO_SCHEME:
+ *param_charp = data->info.conn_scheme;
+ break;
+
+ default:
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
+ long *param_longp)
+{
+ curl_socket_t sockfd;
+
+ union {
+ unsigned long *to_ulong;
+ long *to_long;
+ } lptr;
+
+ switch(info) {
+ case CURLINFO_RESPONSE_CODE:
+ *param_longp = data->info.httpcode;
+ break;
+ case CURLINFO_HTTP_CONNECTCODE:
+ *param_longp = data->info.httpproxycode;
+ break;
+ case CURLINFO_FILETIME:
+ *param_longp = data->info.filetime;
+ break;
+ case CURLINFO_HEADER_SIZE:
+ *param_longp = data->info.header_size;
+ break;
+ case CURLINFO_REQUEST_SIZE:
+ *param_longp = data->info.request_size;
+ break;
+ case CURLINFO_SSL_VERIFYRESULT:
+ *param_longp = data->set.ssl.certverifyresult;
+ break;
+ case CURLINFO_PROXY_SSL_VERIFYRESULT:
+ *param_longp = data->set.proxy_ssl.certverifyresult;
+ break;
+ case CURLINFO_REDIRECT_COUNT:
+ *param_longp = data->set.followlocation;
+ break;
+ case CURLINFO_HTTPAUTH_AVAIL:
+ lptr.to_long = param_longp;
+ *lptr.to_ulong = data->info.httpauthavail;
+ break;
+ case CURLINFO_PROXYAUTH_AVAIL:
+ lptr.to_long = param_longp;
+ *lptr.to_ulong = data->info.proxyauthavail;
+ break;
+ case CURLINFO_OS_ERRNO:
+ *param_longp = data->state.os_errno;
+ break;
+ case CURLINFO_NUM_CONNECTS:
+ *param_longp = data->info.numconnects;
+ break;
+ case CURLINFO_LASTSOCKET:
+ sockfd = Curl_getconnectinfo(data, NULL);
+
+ /* note: this is not a good conversion for systems with 64 bit sockets and
+ 32 bit longs */
+ if(sockfd != CURL_SOCKET_BAD)
+ *param_longp = (long)sockfd;
+ else
+ /* this interface is documented to return -1 in case of badness, which
+ may not be the same as the CURL_SOCKET_BAD value */
+ *param_longp = -1;
+ break;
+ case CURLINFO_PRIMARY_PORT:
+ /* Return the (remote) port of the most recent (primary) connection */
+ *param_longp = data->info.conn_primary_port;
+ break;
+ case CURLINFO_LOCAL_PORT:
+ /* Return the local port of the most recent (primary) connection */
+ *param_longp = data->info.conn_local_port;
+ break;
+ case CURLINFO_CONDITION_UNMET:
+ /* return if the condition prevented the document to get transferred */
+ *param_longp = data->info.timecond ? 1L : 0L;
+ break;
+ case CURLINFO_RTSP_CLIENT_CSEQ:
+ *param_longp = data->state.rtsp_next_client_CSeq;
+ break;
+ case CURLINFO_RTSP_SERVER_CSEQ:
+ *param_longp = data->state.rtsp_next_server_CSeq;
+ break;
+ case CURLINFO_RTSP_CSEQ_RECV:
+ *param_longp = data->state.rtsp_CSeq_recv;
+ break;
+ case CURLINFO_HTTP_VERSION:
+ switch(data->info.httpversion) {
+ case 10:
+ *param_longp = CURL_HTTP_VERSION_1_0;
+ break;
+ case 11:
+ *param_longp = CURL_HTTP_VERSION_1_1;
+ break;
+ case 20:
+ *param_longp = CURL_HTTP_VERSION_2_0;
+ break;
+ default:
+ *param_longp = CURL_HTTP_VERSION_NONE;
+ break;
+ }
+ break;
+ case CURLINFO_PROTOCOL:
+ *param_longp = data->info.conn_protocol;
+ break;
+
+ default:
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
+ double *param_doublep)
+{
+ switch(info) {
+ case CURLINFO_TOTAL_TIME:
+ *param_doublep = data->progress.timespent;
+ break;
+ case CURLINFO_NAMELOOKUP_TIME:
+ *param_doublep = data->progress.t_nslookup;
+ break;
+ case CURLINFO_CONNECT_TIME:
+ *param_doublep = data->progress.t_connect;
+ break;
+ case CURLINFO_APPCONNECT_TIME:
+ *param_doublep = data->progress.t_appconnect;
+ break;
+ case CURLINFO_PRETRANSFER_TIME:
+ *param_doublep = data->progress.t_pretransfer;
+ break;
+ case CURLINFO_STARTTRANSFER_TIME:
+ *param_doublep = data->progress.t_starttransfer;
+ break;
+ case CURLINFO_SIZE_UPLOAD:
+ *param_doublep = (double)data->progress.uploaded;
+ break;
+ case CURLINFO_SIZE_DOWNLOAD:
+ *param_doublep = (double)data->progress.downloaded;
+ break;
+ case CURLINFO_SPEED_DOWNLOAD:
+ *param_doublep = (double)data->progress.dlspeed;
+ break;
+ case CURLINFO_SPEED_UPLOAD:
+ *param_doublep = (double)data->progress.ulspeed;
+ break;
+ case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
+ *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+ (double)data->progress.size_dl:-1;
+ break;
+ case CURLINFO_CONTENT_LENGTH_UPLOAD:
+ *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+ (double)data->progress.size_ul:-1;
+ break;
+ case CURLINFO_REDIRECT_TIME:
+ *param_doublep = data->progress.t_redirect;
+ break;
+
+ default:
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
+ struct curl_slist **param_slistp)
+{
+ union {
+ struct curl_certinfo *to_certinfo;
+ struct curl_slist *to_slist;
+ } ptr;
+
+ switch(info) {
+ case CURLINFO_SSL_ENGINES:
+ *param_slistp = Curl_ssl_engines_list(data);
+ break;
+ case CURLINFO_COOKIELIST:
+ *param_slistp = Curl_cookie_list(data);
+ break;
+ case CURLINFO_CERTINFO:
+ /* Return the a pointer to the certinfo struct. Not really an slist
+ pointer but we can pretend it is here */
+ ptr.to_certinfo = &data->info.certs;
+ *param_slistp = ptr.to_slist;
+ break;
+ case CURLINFO_TLS_SESSION:
+ case CURLINFO_TLS_SSL_PTR:
+ {
+ struct curl_tlssessioninfo **tsip = (struct curl_tlssessioninfo **)
+ param_slistp;
+ struct curl_tlssessioninfo *tsi = &data->tsi;
+ struct connectdata *conn = data->easy_conn;
+
+ *tsip = tsi;
+ tsi->backend = Curl_ssl_backend();
+ tsi->internals = NULL;
+
+ if(conn && tsi->backend != CURLSSLBACKEND_NONE) {
+ unsigned int i;
+ for(i = 0; i < (sizeof(conn->ssl) / sizeof(conn->ssl[0])); ++i) {
+ if(conn->ssl[i].use) {
+#if defined(USE_AXTLS)
+ tsi->internals = (void *)conn->ssl[i].ssl;
+#elif defined(USE_CYASSL)
+ tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_DARWINSSL)
+ tsi->internals = (void *)conn->ssl[i].ssl_ctx;
+#elif defined(USE_GNUTLS)
+ tsi->internals = (void *)conn->ssl[i].session;
+#elif defined(USE_GSKIT)
+ tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_MBEDTLS)
+ tsi->internals = (void *)&conn->ssl[i].ssl;
+#elif defined(USE_NSS)
+ tsi->internals = (void *)conn->ssl[i].handle;
+#elif defined(USE_OPENSSL)
+ /* Legacy: CURLINFO_TLS_SESSION must return an SSL_CTX pointer. */
+ tsi->internals = ((info == CURLINFO_TLS_SESSION) ?
+ (void *)conn->ssl[i].ctx :
+ (void *)conn->ssl[i].handle);
+#elif defined(USE_POLARSSL)
+ tsi->internals = (void *)&conn->ssl[i].ssl;
+#elif defined(USE_SCHANNEL)
+ tsi->internals = (void *)&conn->ssl[i].ctxt->ctxt_handle;
+#elif defined(USE_SSL)
+#error "SSL backend specific information missing for CURLINFO_TLS_SSL_PTR"
+#endif
+ break;
+ }
+ }
+ }
+ }
+ break;
+ default:
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_socket(struct Curl_easy *data, CURLINFO info,
+ curl_socket_t *param_socketp)
+{
+ switch(info) {
+ case CURLINFO_ACTIVESOCKET:
+ *param_socketp = Curl_getconnectinfo(data, NULL);
+ break;
+ default:
+ return CURLE_UNKNOWN_OPTION;
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...)
+{
+ va_list arg;
+ long *param_longp = NULL;
+ double *param_doublep = NULL;
+ const char **param_charp = NULL;
+ struct curl_slist **param_slistp = NULL;
+ curl_socket_t *param_socketp = NULL;
+ int type;
+ CURLcode result = CURLE_UNKNOWN_OPTION;
+
+ if(!data)
+ return result;
+
+ va_start(arg, info);
+
+ type = CURLINFO_TYPEMASK & (int)info;
+ switch(type) {
+ case CURLINFO_STRING:
+ param_charp = va_arg(arg, const char **);
+ if(param_charp)
+ result = getinfo_char(data, info, param_charp);
+ break;
+ case CURLINFO_LONG:
+ param_longp = va_arg(arg, long *);
+ if(param_longp)
+ result = getinfo_long(data, info, param_longp);
+ break;
+ case CURLINFO_DOUBLE:
+ param_doublep = va_arg(arg, double *);
+ if(param_doublep)
+ result = getinfo_double(data, info, param_doublep);
+ break;
+ case CURLINFO_SLIST:
+ param_slistp = va_arg(arg, struct curl_slist **);
+ if(param_slistp)
+ result = getinfo_slist(data, info, param_slistp);
+ break;
+ case CURLINFO_SOCKET:
+ param_socketp = va_arg(arg, curl_socket_t *);
+ if(param_socketp)
+ result = getinfo_socket(data, info, param_socketp);
+ break;
+ default:
+ break;
+ }
+
+ va_end(arg);
+
+ return result;
+}
diff --git a/Utilities/cmcurl/lib/getinfo.h b/Utilities/cmcurl/lib/getinfo.h
new file mode 100644
index 000000000..aecf717f7
--- /dev/null
+++ b/Utilities/cmcurl/lib/getinfo.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_GETINFO_H
+#define HEADER_CURL_GETINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+CURLcode Curl_getinfo(struct Curl_easy *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct Curl_easy *data);
+
+#endif /* HEADER_CURL_GETINFO_H */
diff --git a/Utilities/cmcurl/lib/gopher.c b/Utilities/cmcurl/lib/gopher.c
new file mode 100644
index 000000000..e6d274648
--- /dev/null
+++ b/Utilities/cmcurl/lib/gopher.c
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_GOPHER
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "gopher.h"
+#include "select.h"
+#include "url.h"
+#include "escape.h"
+#include "warnless.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode gopher_do(struct connectdata *conn, bool *done);
+
+/*
+ * Gopher protocol handler.
+ * This is also a nice simple template to build off for simple
+ * connect-command-download protocols.
+ */
+
+const struct Curl_handler Curl_handler_gopher = {
+ "GOPHER", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ gopher_do, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_GOPHER, /* defport */
+ CURLPROTO_GOPHER, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+static CURLcode gopher_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result=CURLE_OK;
+ struct Curl_easy *data=conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+ curl_off_t *bytecount = &data->req.bytecount;
+ char *path = data->state.path;
+ char *sel = NULL;
+ char *sel_org = NULL;
+ ssize_t amount, k;
+ size_t len;
+
+ *done = TRUE; /* unconditionally */
+
+ /* Create selector. Degenerate cases: / and /1 => convert to "" */
+ if(strlen(path) <= 2) {
+ sel = (char *)"";
+ len = (int)strlen(sel);
+ }
+ else {
+ char *newp;
+ size_t j, i;
+
+ /* Otherwise, drop / and the first character (i.e., item type) ... */
+ newp = path;
+ newp+=2;
+
+ /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
+ j = strlen(newp);
+ for(i=0; i<j; i++)
+ if(newp[i] == '?')
+ newp[i] = '\x09';
+
+ /* ... and finally unescape */
+ result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
+ if(result)
+ return result;
+ sel_org = sel;
+ }
+
+ /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
+ sent, which could be sizeable with long selectors. */
+ k = curlx_uztosz(len);
+
+ for(;;) {
+ result = Curl_write(conn, sockfd, sel, k, &amount);
+ if(!result) { /* Which may not have written it all! */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
+ if(result)
+ break;
+
+ k -= amount;
+ sel += amount;
+ if(k < 1)
+ break; /* but it did write it all */
+ }
+ else
+ break;
+
+ /* Don't busyloop. The entire loop thing is a work-around as it causes a
+ BLOCKING behavior which is a NO-NO. This function should rather be
+ split up in a do and a doing piece where the pieces that aren't
+ possible to send now will be sent in the doing function repeatedly
+ until the entire request is sent.
+
+ Wait a while for the socket to be writable. Note that this doesn't
+ acknowledge the timeout.
+ */
+ if(SOCKET_WRITABLE(sockfd, 100) < 0) {
+ result = CURLE_SEND_ERROR;
+ break;
+ }
+ }
+
+ free(sel_org);
+
+ if(!result)
+ /* We can use Curl_sendf to send the terminal \r\n relatively safely and
+ save allocing another string/doing another _write loop. */
+ result = Curl_sendf(sockfd, conn, "\r\n");
+ if(result) {
+ failf(data, "Failed sending Gopher request");
+ return result;
+ }
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+ if(result)
+ return result;
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ return CURLE_OK;
+}
+#endif /*CURL_DISABLE_GOPHER*/
diff --git a/Utilities/cmcurl/lib/gopher.h b/Utilities/cmcurl/lib/gopher.h
new file mode 100644
index 000000000..501c990a8
--- /dev/null
+++ b/Utilities/cmcurl/lib/gopher.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_GOPHER_H
+#define HEADER_CURL_GOPHER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_GOPHER
+extern const struct Curl_handler Curl_handler_gopher;
+#endif
+
+#endif /* HEADER_CURL_GOPHER_H */
diff --git a/Utilities/cmcurl/lib/hash.c b/Utilities/cmcurl/lib/hash.c
new file mode 100644
index 000000000..6afeaa12c
--- /dev/null
+++ b/Utilities/cmcurl/lib/hash.c
@@ -0,0 +1,354 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "hash.h"
+#include "llist.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void
+hash_element_dtor(void *user, void *element)
+{
+ struct curl_hash *h = (struct curl_hash *) user;
+ struct curl_hash_element *e = (struct curl_hash_element *) element;
+
+ if(e->ptr) {
+ h->dtor(e->ptr);
+ e->ptr = NULL;
+ }
+
+ e->key_len = 0;
+
+ free(e);
+}
+
+/* Initializes a hash structure.
+ * Return 1 on error, 0 is fine.
+ *
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+int
+Curl_hash_init(struct curl_hash *h,
+ int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor)
+{
+ int i;
+
+ if(!slots || !hfunc || !comparator ||!dtor) {
+ return 1; /* failure */
+ }
+
+ h->hash_func = hfunc;
+ h->comp_func = comparator;
+ h->dtor = dtor;
+ h->size = 0;
+ h->slots = slots;
+
+ h->table = malloc(slots * sizeof(struct curl_llist));
+ if(h->table) {
+ for(i = 0; i < slots; ++i)
+ Curl_llist_init(&h->table[i], (curl_llist_dtor) hash_element_dtor);
+ return 0; /* fine */
+ }
+ h->slots = 0;
+ return 1; /* failure */
+}
+
+static struct curl_hash_element *
+mk_hash_element(const void *key, size_t key_len, const void *p)
+{
+ /* allocate the struct plus memory after it to store the key */
+ struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element) +
+ key_len);
+ if(he) {
+ /* copy the key */
+ memcpy(he->key, key, key_len);
+ he->key_len = key_len;
+ he->ptr = (void *) p;
+ }
+ return he;
+}
+
+#define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
+
+/* Insert the data in the hash. If there already was a match in the hash,
+ * that data is replaced.
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void *
+Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
+{
+ struct curl_hash_element *he;
+ struct curl_llist_element *le;
+ struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+ for(le = l->head; le; le = le->next) {
+ he = (struct curl_hash_element *) le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ Curl_llist_remove(l, le, (void *)h);
+ --h->size;
+ break;
+ }
+ }
+
+ he = mk_hash_element(key, key_len, p);
+ if(he) {
+ Curl_llist_insert_next(l, l->tail, he, &he->list);
+ ++h->size;
+ return p; /* return the new entry */
+ }
+
+ return NULL; /* failure */
+}
+
+/* Remove the identified hash entry.
+ * Returns non-zero on failure.
+ *
+ * @unittest: 1603
+ */
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
+{
+ struct curl_llist_element *le;
+ struct curl_hash_element *he;
+ struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+ for(le = l->head; le; le = le->next) {
+ he = le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ Curl_llist_remove(l, le, (void *) h);
+ --h->size;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* Retrieves a hash element.
+ *
+ * @unittest: 1603
+ */
+void *
+Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
+{
+ struct curl_llist_element *le;
+ struct curl_hash_element *he;
+ struct curl_llist *l;
+
+ if(h) {
+ l = FETCH_LIST(h, key, key_len);
+ for(le = l->head; le; le = le->next) {
+ he = le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ return he->ptr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
+void
+Curl_hash_apply(curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr))
+{
+ struct curl_llist_element *le;
+ int i;
+
+ for(i = 0; i < h->slots; ++i) {
+ for(le = (h->table[i])->head;
+ le;
+ le = le->next) {
+ curl_hash_element *el = le->ptr;
+ cb(user, el->ptr);
+ }
+ }
+}
+#endif
+
+/* Destroys all the entries in the given hash and resets its attributes,
+ * prepping the given hash for [static|dynamic] deallocation.
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void
+Curl_hash_destroy(struct curl_hash *h)
+{
+ int i;
+
+ for(i = 0; i < h->slots; ++i) {
+ Curl_llist_destroy(&h->table[i], (void *) h);
+ }
+
+ Curl_safefree(h->table);
+ h->size = 0;
+ h->slots = 0;
+}
+
+/* Removes all the entries in the given hash.
+ *
+ * @unittest: 1602
+ */
+void
+Curl_hash_clean(struct curl_hash *h)
+{
+ Curl_hash_clean_with_criterium(h, NULL, NULL);
+}
+
+/* Cleans all entries that pass the comp function criteria. */
+void
+Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+ int (*comp)(void *, void *))
+{
+ struct curl_llist_element *le;
+ struct curl_llist_element *lnext;
+ struct curl_llist *list;
+ int i;
+
+ if(!h)
+ return;
+
+ for(i = 0; i < h->slots; ++i) {
+ list = &h->table[i];
+ le = list->head; /* get first list entry */
+ while(le) {
+ struct curl_hash_element *he = le->ptr;
+ lnext = le->next;
+ /* ask the callback function if we shall remove this entry or not */
+ if(comp == NULL || comp(user, he->ptr)) {
+ Curl_llist_remove(list, le, (void *) h);
+ --h->size; /* one less entry in the hash now */
+ }
+ le = lnext;
+ }
+ }
+}
+
+size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
+{
+ const char *key_str = (const char *) key;
+ const char *end = key_str + key_length;
+ unsigned long h = 5381;
+
+ while(key_str < end) {
+ h += h << 5;
+ h ^= (unsigned long) *key_str++;
+ }
+
+ return (h % slots_num);
+}
+
+size_t Curl_str_key_compare(void *k1, size_t key1_len,
+ void *k2, size_t key2_len)
+{
+ if((key1_len == key2_len) && !memcmp(k1, k2, key1_len))
+ return 1;
+
+ return 0;
+}
+
+void Curl_hash_start_iterate(struct curl_hash *hash,
+ struct curl_hash_iterator *iter)
+{
+ iter->hash = hash;
+ iter->slot_index = 0;
+ iter->current_element = NULL;
+}
+
+struct curl_hash_element *
+Curl_hash_next_element(struct curl_hash_iterator *iter)
+{
+ int i;
+ struct curl_hash *h = iter->hash;
+
+ /* Get the next element in the current list, if any */
+ if(iter->current_element)
+ iter->current_element = iter->current_element->next;
+
+ /* If we have reached the end of the list, find the next one */
+ if(!iter->current_element) {
+ for(i = iter->slot_index;i < h->slots;i++) {
+ if(h->table[i].head) {
+ iter->current_element = h->table[i].head;
+ iter->slot_index = i+1;
+ break;
+ }
+ }
+ }
+
+ if(iter->current_element) {
+ struct curl_hash_element *he = iter->current_element->ptr;
+ return he;
+ }
+ iter->current_element = NULL;
+ return NULL;
+}
+
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct curl_hash *h,
+ void (*func)(void *))
+{
+ struct curl_hash_iterator iter;
+ struct curl_hash_element *he;
+ int last_index = -1;
+
+ if(!h)
+ return;
+
+ fprintf(stderr, "=Hash dump=\n");
+
+ Curl_hash_start_iterate(h, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ if(iter.slot_index != last_index) {
+ fprintf(stderr, "index %d:", iter.slot_index);
+ if(last_index >= 0) {
+ fprintf(stderr, "\n");
+ }
+ last_index = iter.slot_index;
+ }
+
+ if(func)
+ func(he->ptr);
+ else
+ fprintf(stderr, " [%p]", (void *)he->ptr);
+
+ he = Curl_hash_next_element(&iter);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
diff --git a/Utilities/cmcurl/lib/hash.h b/Utilities/cmcurl/lib/hash.h
new file mode 100644
index 000000000..90a25d1ca
--- /dev/null
+++ b/Utilities/cmcurl/lib/hash.h
@@ -0,0 +1,100 @@
+#ifndef HEADER_CURL_HASH_H
+#define HEADER_CURL_HASH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <stddef.h>
+
+#include "llist.h"
+
+/* Hash function prototype */
+typedef size_t (*hash_function) (void *key,
+ size_t key_length,
+ size_t slots_num);
+
+/*
+ Comparator function prototype. Compares two keys.
+*/
+typedef size_t (*comp_function) (void *key1,
+ size_t key1_len,
+ void *key2,
+ size_t key2_len);
+
+typedef void (*curl_hash_dtor)(void *);
+
+struct curl_hash {
+ struct curl_llist *table;
+
+ /* Hash function to be used for this hash table */
+ hash_function hash_func;
+
+ /* Comparator function to compare keys */
+ comp_function comp_func;
+ curl_hash_dtor dtor;
+ int slots;
+ size_t size;
+};
+
+struct curl_hash_element {
+ struct curl_llist_element list;
+ void *ptr;
+ size_t key_len;
+ char key[1]; /* allocated memory following the struct */
+};
+
+struct curl_hash_iterator {
+ struct curl_hash *hash;
+ int slot_index;
+ struct curl_llist_element *current_element;
+};
+
+int Curl_hash_init(struct curl_hash *h,
+ int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor);
+
+void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p);
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len);
+void *Curl_hash_pick(struct curl_hash *, void *key, size_t key_len);
+void Curl_hash_apply(struct curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr));
+int Curl_hash_count(struct curl_hash *h);
+void Curl_hash_destroy(struct curl_hash *h);
+void Curl_hash_clean(struct curl_hash *h);
+void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+ int (*comp)(void *, void *));
+size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num);
+size_t Curl_str_key_compare(void *k1, size_t key1_len, void *k2,
+ size_t key2_len);
+void Curl_hash_start_iterate(struct curl_hash *hash,
+ struct curl_hash_iterator *iter);
+struct curl_hash_element *
+Curl_hash_next_element(struct curl_hash_iterator *iter);
+
+void Curl_hash_print(struct curl_hash *h,
+ void (*func)(void *));
+
+
+#endif /* HEADER_CURL_HASH_H */
diff --git a/Utilities/cmcurl/lib/hmac.c b/Utilities/cmcurl/lib/hmac.c
new file mode 100644
index 000000000..dae95054b
--- /dev/null
+++ b/Utilities/cmcurl/lib/hmac.c
@@ -0,0 +1,132 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2104 Keyed-Hashing for Message Authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include <curl/curl.h>
+
+#include "curl_hmac.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Generic HMAC algorithm.
+ *
+ * This module computes HMAC digests based on any hash function. Parameters
+ * and computing procedures are set-up dynamically at HMAC computation
+ * context initialisation.
+ */
+
+static const unsigned char hmac_ipad = 0x36;
+static const unsigned char hmac_opad = 0x5C;
+
+
+
+HMAC_context *
+Curl_HMAC_init(const HMAC_params * hashparams,
+ const unsigned char *key,
+ unsigned int keylen)
+{
+ size_t i;
+ HMAC_context *ctxt;
+ unsigned char *hkey;
+ unsigned char b;
+
+ /* Create HMAC context. */
+ i = sizeof *ctxt + 2 * hashparams->hmac_ctxtsize +
+ hashparams->hmac_resultlen;
+ ctxt = malloc(i);
+
+ if(!ctxt)
+ return ctxt;
+
+ ctxt->hmac_hash = hashparams;
+ ctxt->hmac_hashctxt1 = (void *) (ctxt + 1);
+ ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 +
+ hashparams->hmac_ctxtsize);
+
+ /* If the key is too long, replace it by its hash digest. */
+ if(keylen > hashparams->hmac_maxkeylen) {
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen);
+ hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize;
+ (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1);
+ key = hkey;
+ keylen = hashparams->hmac_resultlen;
+ }
+
+ /* Prime the two hash contexts with the modified key. */
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2);
+
+ for(i = 0; i < keylen; i++) {
+ b = (unsigned char)(*key ^ hmac_ipad);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1);
+ b = (unsigned char)(*key++ ^ hmac_opad);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1);
+ }
+
+ for(; i < hashparams->hmac_maxkeylen; i++) {
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1);
+ }
+
+ /* Done, return pointer to HMAC context. */
+ return ctxt;
+}
+
+int Curl_HMAC_update(HMAC_context * ctxt,
+ const unsigned char *data,
+ unsigned int len)
+{
+ /* Update first hash calculation. */
+ (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len);
+ return 0;
+}
+
+
+int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result)
+{
+ const HMAC_params * hashparams = ctxt->hmac_hash;
+
+ /* Do not get result if called with a null parameter: only release
+ storage. */
+
+ if(!result)
+ result = (unsigned char *) ctxt->hmac_hashctxt2 +
+ ctxt->hmac_hash->hmac_ctxtsize;
+
+ (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2,
+ result, hashparams->hmac_resultlen);
+ (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2);
+ free((char *) ctxt);
+ return 0;
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/hostasyn.c b/Utilities/cmcurl/lib/hostasyn.c
new file mode 100644
index 000000000..28bdf7a48
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostasyn.c
@@ -0,0 +1,153 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
+/*
+ * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
+ * or getaddrinfo_thread() when we got the name resolved (or not!).
+ *
+ * If the status argument is CURL_ASYNC_SUCCESS, this function takes
+ * ownership of the Curl_addrinfo passed, storing the resolved data
+ * in the DNS cache.
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+ int status,
+ struct Curl_addrinfo *ai)
+{
+ struct Curl_dns_entry *dns = NULL;
+ CURLcode result = CURLE_OK;
+
+ conn->async.status = status;
+
+ if(CURL_ASYNC_SUCCESS == status) {
+ if(ai) {
+ struct Curl_easy *data = conn->data;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns = Curl_cache_addr(data, ai,
+ conn->async.hostname,
+ conn->async.port);
+ if(!dns) {
+ /* failed to store, cleanup and return error */
+ Curl_freeaddrinfo(ai);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+ }
+ else {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ conn->async.dns = dns;
+
+ /* Set async.done TRUE last in this function since it may be used multi-
+ threaded and once this is TRUE the other thread may read fields from the
+ async struct */
+ conn->async.done = TRUE;
+
+ /* IPv4: The input hostent struct will be freed by ares when we return from
+ this function */
+ return result;
+}
+
+/* Call this function after Curl_connect() has returned async=TRUE and
+ then a successful name resolve has been received.
+
+ Note: this function disconnects and frees the conn data in case of
+ resolve failure */
+CURLcode Curl_async_resolved(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result;
+
+ if(conn->async.dns) {
+ conn->dns_entry = conn->async.dns;
+ conn->async.dns = NULL;
+ }
+
+ result = Curl_setup_conn(conn, protocol_done);
+
+ if(result)
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(conn, FALSE); /* close the connection */
+
+ return result;
+}
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+}
+
+#endif /* CURLRES_ASYNCH */
diff --git a/Utilities/cmcurl/lib/hostcheck.c b/Utilities/cmcurl/lib/hostcheck.c
new file mode 100644
index 000000000..156091ca8
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostcheck.c
@@ -0,0 +1,150 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_OPENSSL) \
+ || defined(USE_AXTLS) \
+ || defined(USE_GSKIT) \
+ || (defined(USE_SCHANNEL) && defined(_WIN32_WCE))
+/* these backends use functions from this file */
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "hostcheck.h"
+#include "strcase.h"
+#include "inet_pton.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ * "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * https://tools.ietf.org/html/rfc6125#section-6.4.3
+ *
+ * In addition: ignore trailing dots in the host names and wildcards, so that
+ * the names are used normalized. This is what the browsers do.
+ *
+ * Do not allow wildcard matching on IP numbers. There are apparently
+ * certificates being used with an IP address in the CN field, thus making no
+ * apparent distinction between a name and an IP. We need to detect the use of
+ * an IP address and not wildcard match on such names.
+ *
+ * NOTE: hostmatch() gets called with copied buffers so that it can modify the
+ * contents at will.
+ */
+
+static int hostmatch(char *hostname, char *pattern)
+{
+ const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
+ int wildcard_enabled;
+ size_t prefixlen, suffixlen;
+ struct in_addr ignored;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 si6;
+#endif
+
+ /* normalize pattern and hostname by stripping off trailing dots */
+ size_t len = strlen(hostname);
+ if(hostname[len-1]=='.')
+ hostname[len-1]=0;
+ len = strlen(pattern);
+ if(pattern[len-1]=='.')
+ pattern[len-1]=0;
+
+ pattern_wildcard = strchr(pattern, '*');
+ if(pattern_wildcard == NULL)
+ return strcasecompare(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ /* detect IP address as hostname and fail the match if so */
+ if(Curl_inet_pton(AF_INET, hostname, &ignored) > 0)
+ return CURL_HOST_NOMATCH;
+#ifdef ENABLE_IPV6
+ if(Curl_inet_pton(AF_INET6, hostname, &si6.sin6_addr) > 0)
+ return CURL_HOST_NOMATCH;
+#endif
+
+ /* We require at least 2 dots in pattern to avoid too wide wildcard
+ match. */
+ wildcard_enabled = 1;
+ pattern_label_end = strchr(pattern, '.');
+ if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+ pattern_wildcard > pattern_label_end ||
+ strncasecompare(pattern, "xn--", 4)) {
+ wildcard_enabled = 0;
+ }
+ if(!wildcard_enabled)
+ return strcasecompare(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ hostname_label_end = strchr(hostname, '.');
+ if(hostname_label_end == NULL ||
+ !strcasecompare(pattern_label_end, hostname_label_end))
+ return CURL_HOST_NOMATCH;
+
+ /* The wildcard must match at least one character, so the left-most
+ label of the hostname is at least as large as the left-most label
+ of the pattern. */
+ if(hostname_label_end - hostname < pattern_label_end - pattern)
+ return CURL_HOST_NOMATCH;
+
+ prefixlen = pattern_wildcard - pattern;
+ suffixlen = pattern_label_end - (pattern_wildcard+1);
+ return strncasecompare(pattern, hostname, prefixlen) &&
+ strncasecompare(pattern_wildcard+1, hostname_label_end - suffixlen,
+ suffixlen) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+}
+
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
+{
+ char *matchp;
+ char *hostp;
+ int res = 0;
+ if(!match_pattern || !*match_pattern ||
+ !hostname || !*hostname) /* sanity check */
+ ;
+ else {
+ matchp = strdup(match_pattern);
+ if(matchp) {
+ hostp = strdup(hostname);
+ if(hostp) {
+ if(hostmatch(hostp, matchp) == CURL_HOST_MATCH)
+ res= 1;
+ free(hostp);
+ }
+ free(matchp);
+ }
+ }
+
+ return res;
+}
+
+#endif /* OPENSSL, AXTLS, GSKIT or schannel+wince */
diff --git a/Utilities/cmcurl/lib/hostcheck.h b/Utilities/cmcurl/lib/hostcheck.h
new file mode 100644
index 000000000..86e3b96a9
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostcheck.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_HOSTCHECK_H
+#define HEADER_CURL_HOSTCHECK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#define CURL_HOST_NOMATCH 0
+#define CURL_HOST_MATCH 1
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
+
+#endif /* HEADER_CURL_HOSTCHECK_H */
+
diff --git a/Utilities/cmcurl/lib/hostip.c b/Utilities/cmcurl/lib/hostip.c
new file mode 100644
index 000000000..619ec84b5
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostip.c
@@ -0,0 +1,884 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_ntop.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(CURLRES_SYNCH) && \
+ defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
+/* alarm-based timeouts can only be used with all the dependencies satisfied */
+#define USE_ALARM_TIMEOUT
+#endif
+
+/*
+ * hostip.c explained
+ * ==================
+ *
+ * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ * source file are these:
+ *
+ * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * defined.
+ *
+ * CURLRES_ARES - is defined if libcurl is built to use c-ares for
+ * asynchronous name resolves. This can be Windows or *nix.
+ *
+ * CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ * Windows, and then the name resolve will be done in a new thread, and the
+ * supported API will be the same as for ares-builds.
+ *
+ * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ * defined.
+ *
+ * The host*.c sources files are split up like this:
+ *
+ * hostip.c - method-independent resolver functions and utility functions
+ * hostasyn.c - functions for asynchronous name resolves
+ * hostsyn.c - functions for synchronous name resolves
+ * hostip4.c - IPv4 specific functions
+ * hostip6.c - IPv6 specific functions
+ *
+ * The two asynchronous name resolver backends are implemented in:
+ * asyn-ares.c - functions for ares-using name resolves
+ * asyn-thread.c - functions for threaded name resolves
+
+ * The hostip.h is the united header file for all this. It defines the
+ * CURLRES_* defines based on the config*.h and curl_setup.h defines.
+ */
+
+/* These two symbols are for the global DNS cache */
+static struct curl_hash hostname_cache;
+static int host_cache_initialized;
+
+static void freednsentry(void *freethis);
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void)
+{
+ int rc = 0;
+ if(!host_cache_initialized) {
+ rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
+ Curl_str_key_compare, freednsentry);
+ if(!rc)
+ host_cache_initialized = 1;
+ }
+ return rc?NULL:&hostname_cache;
+}
+
+/*
+ * Destroy and cleanup the global DNS cache
+ */
+void Curl_global_host_cache_dtor(void)
+{
+ if(host_cache_initialized) {
+ Curl_hash_destroy(&hostname_cache);
+ host_cache_initialized = 0;
+ }
+}
+
+/*
+ * Return # of addresses in a Curl_addrinfo struct
+ */
+int Curl_num_addresses(const Curl_addrinfo *addr)
+{
+ int i = 0;
+ while(addr) {
+ addr = addr->ai_next;
+ i++;
+ }
+ return i;
+}
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ai' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ *
+ * If the conversion fails, it returns NULL.
+ */
+const char *
+Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
+{
+ const struct sockaddr_in *sa4;
+ const struct in_addr *ipaddr4;
+#ifdef ENABLE_IPV6
+ const struct sockaddr_in6 *sa6;
+ const struct in6_addr *ipaddr6;
+#endif
+
+ switch(ai->ai_family) {
+ case AF_INET:
+ sa4 = (const void *)ai->ai_addr;
+ ipaddr4 = &sa4->sin_addr;
+ return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
+ bufsize);
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ sa6 = (const void *)ai->ai_addr;
+ ipaddr6 = &sa6->sin6_addr;
+ return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
+ bufsize);
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Return a hostcache id string for the provided host + port, to be used by
+ * the DNS caching.
+ */
+static char *
+create_hostcache_id(const char *name, int port)
+{
+ /* create and return the new allocated entry */
+ char *id = aprintf("%s:%d", name, port);
+ char *ptr = id;
+ if(ptr) {
+ /* lower case the name part */
+ while(*ptr && (*ptr != ':')) {
+ *ptr = (char)TOLOWER(*ptr);
+ ptr++;
+ }
+ }
+ return id;
+}
+
+struct hostcache_prune_data {
+ long cache_timeout;
+ time_t now;
+};
+
+/*
+ * This function is set as a callback to be called for every entry in the DNS
+ * cache when we want to prune old unused entries.
+ *
+ * Returning non-zero means remove the entry, return 0 to keep it in the
+ * cache.
+ */
+static int
+hostcache_timestamp_remove(void *datap, void *hc)
+{
+ struct hostcache_prune_data *data =
+ (struct hostcache_prune_data *) datap;
+ struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+
+ return (0 != c->timestamp)
+ && (data->now - c->timestamp >= data->cache_timeout);
+}
+
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ */
+static void
+hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
+{
+ struct hostcache_prune_data user;
+
+ user.cache_timeout = cache_timeout;
+ user.now = now;
+
+ Curl_hash_clean_with_criterium(hostcache,
+ (void *) &user,
+ hostcache_timestamp_remove);
+}
+
+/*
+ * Library-wide function for pruning the DNS cache. This function takes and
+ * returns the appropriate locks.
+ */
+void Curl_hostcache_prune(struct Curl_easy *data)
+{
+ time_t now;
+
+ if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
+ /* cache forever means never prune, and NULL hostcache means
+ we can't do it */
+ return;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ time(&now);
+
+ /* Remove outdated and unused entries from the hostcache */
+ hostcache_prune(data->dns.hostcache,
+ data->set.dns_cache_timeout,
+ now);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+#ifdef HAVE_SIGSETJMP
+/* Beware this is a global and unique instance. This is used to store the
+ return address that we can jump back to from inside a signal handler. This
+ is not thread-safe stuff. */
+sigjmp_buf curl_jmpenv;
+#endif
+
+/* lookup address, returns entry if found and not stale */
+static struct Curl_dns_entry *
+fetch_addr(struct connectdata *conn,
+ const char *hostname,
+ int port)
+{
+ char *entry_id = NULL;
+ struct Curl_dns_entry *dns = NULL;
+ size_t entry_len;
+ struct Curl_easy *data = conn->data;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return dns;
+
+ entry_len = strlen(entry_id);
+
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+
+ if(dns && (data->set.dns_cache_timeout != -1)) {
+ /* See whether the returned entry is stale. Done before we release lock */
+ struct hostcache_prune_data user;
+
+ time(&user.now);
+ user.cache_timeout = data->set.dns_cache_timeout;
+
+ if(hostcache_timestamp_remove(&user, dns)) {
+ infof(data, "Hostname in DNS cache was stale, zapped\n");
+ dns = NULL; /* the memory deallocation is being handled by the hash */
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+ }
+ }
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ return dns;
+}
+
+/*
+ * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
+ *
+ * Curl_resolv() checks initially and multi_runsingle() checks each time
+ * it discovers the handle in the state WAITRESOLVE whether the hostname
+ * has already been resolved and the address has already been stored in
+ * the DNS cache. This short circuits waiting for a lot of pending
+ * lookups for the same hostname requested by different handles.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+struct Curl_dns_entry *
+Curl_fetch_addr(struct connectdata *conn,
+ const char *hostname,
+ int port)
+{
+ struct Curl_easy *data = conn->data;
+ struct Curl_dns_entry *dns = NULL;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns = fetch_addr(conn, hostname, port);
+
+ if(dns)
+ dns->inuse++; /* we use it! */
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ return dns;
+}
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * When calling Curl_resolv() has resulted in a response with a returned
+ * address, we call this function to store the information in the dns
+ * cache etc
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct Curl_easy *data,
+ Curl_addrinfo *addr,
+ const char *hostname,
+ int port)
+{
+ char *entry_id;
+ size_t entry_len;
+ struct Curl_dns_entry *dns;
+ struct Curl_dns_entry *dns2;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return NULL;
+ entry_len = strlen(entry_id);
+
+ /* Create a new cache entry */
+ dns = calloc(1, sizeof(struct Curl_dns_entry));
+ if(!dns) {
+ free(entry_id);
+ return NULL;
+ }
+
+ dns->inuse = 1; /* the cache has the first reference */
+ dns->addr = addr; /* this is the address(es) */
+ time(&dns->timestamp);
+ if(dns->timestamp == 0)
+ dns->timestamp = 1; /* zero indicates CURLOPT_RESOLVE entry */
+
+ /* Store the resolved data in our DNS cache. */
+ dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+ (void *)dns);
+ if(!dns2) {
+ free(dns);
+ free(entry_id);
+ return NULL;
+ }
+
+ dns = dns2;
+ dns->inuse++; /* mark entry as in-use */
+
+ /* free the allocated entry_id */
+ free(entry_id);
+
+ return dns;
+}
+
+/*
+ * Curl_resolv() is the main name resolve function within libcurl. It resolves
+ * a name and returns a pointer to the entry in the 'entry' argument (if one
+ * is provided). This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * In debug mode, we specifically test for an interface name "LocalHost"
+ * and resolve "localhost" instead as a means to permit test cases
+ * to connect to a local test server with any host name.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_ERROR (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ struct Curl_dns_entry **entry)
+{
+ struct Curl_dns_entry *dns = NULL;
+ struct Curl_easy *data = conn->data;
+ CURLcode result;
+ int rc = CURLRESOLV_ERROR; /* default to failure */
+
+ *entry = NULL;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns = fetch_addr(conn, hostname, port);
+
+ if(dns) {
+ infof(data, "Hostname %s was found in DNS cache\n", hostname);
+ dns->inuse++; /* we use it! */
+ rc = CURLRESOLV_RESOLVED;
+ }
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns) {
+ /* The entry was not in the cache. Resolve it to IP address */
+
+ Curl_addrinfo *addr;
+ int respwait;
+
+ /* Check what IP specifics the app has requested and if we can provide it.
+ * If not, bail out. */
+ if(!Curl_ipvalid(conn))
+ return CURLRESOLV_ERROR;
+
+ /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
+ non-zero value indicating that we need to wait for the response to the
+ resolve call */
+ addr = Curl_getaddrinfo(conn,
+#ifdef DEBUGBUILD
+ (data->set.str[STRING_DEVICE]
+ && !strcmp(data->set.str[STRING_DEVICE],
+ "LocalHost"))?"localhost":
+#endif
+ hostname, port, &respwait);
+
+ if(!addr) {
+ if(respwait) {
+ /* the response to our resolve call will come asynchronously at
+ a later time, good or bad */
+ /* First, check that we haven't received the info by now */
+ result = Curl_resolver_is_resolved(conn, &dns);
+ if(result) /* error detected */
+ return CURLRESOLV_ERROR;
+ if(dns)
+ rc = CURLRESOLV_RESOLVED; /* pointer provided */
+ else
+ rc = CURLRESOLV_PENDING; /* no info yet */
+ }
+ }
+ else {
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* we got a response, store it in the cache */
+ dns = Curl_cache_addr(data, addr, hostname, port);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns)
+ /* returned failure, bail out nicely */
+ Curl_freeaddrinfo(addr);
+ else
+ rc = CURLRESOLV_RESOLVED;
+ }
+ }
+
+ *entry = dns;
+
+ return rc;
+}
+
+#ifdef USE_ALARM_TIMEOUT
+/*
+ * This signal handler jumps back into the main libcurl code and continues
+ * execution. This effectively causes the remainder of the application to run
+ * within a signal handler which is nonportable and could lead to problems.
+ */
+static
+RETSIGTYPE alarmfunc(int sig)
+{
+ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
+ (void)sig;
+ siglongjmp(curl_jmpenv, 1);
+}
+#endif /* USE_ALARM_TIMEOUT */
+
+/*
+ * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
+ * timeout. This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * If built with a synchronous resolver and use of signals is not
+ * disabled by the application, then a nonzero timeout will cause a
+ * timeout after the specified number of milliseconds. Otherwise, timeout
+ * is ignored.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
+ * CURLRESOLV_ERROR (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv_timeout(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ struct Curl_dns_entry **entry,
+ time_t timeoutms)
+{
+#ifdef USE_ALARM_TIMEOUT
+#ifdef HAVE_SIGACTION
+ struct sigaction keep_sigact; /* store the old struct here */
+ volatile bool keep_copysig = FALSE; /* whether old sigact has been saved */
+ struct sigaction sigact;
+#else
+#ifdef HAVE_SIGNAL
+ void (*keep_sigact)(int); /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+ volatile long timeout;
+ volatile unsigned int prev_alarm = 0;
+ struct Curl_easy *data = conn->data;
+#endif /* USE_ALARM_TIMEOUT */
+ int rc;
+
+ *entry = NULL;
+
+ if(timeoutms < 0)
+ /* got an already expired timeout */
+ return CURLRESOLV_TIMEDOUT;
+
+#ifdef USE_ALARM_TIMEOUT
+ if(data->set.no_signal)
+ /* Ignore the timeout when signals are disabled */
+ timeout = 0;
+ else
+ timeout = (timeoutms > LONG_MAX) ? LONG_MAX : (long)timeoutms;
+
+ if(!timeout)
+ /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
+ return Curl_resolv(conn, hostname, port, entry);
+
+ if(timeout < 1000) {
+ /* The alarm() function only provides integer second resolution, so if
+ we want to wait less than one second we must bail out already now. */
+ failf(data,
+ "remaining timeout of %ld too small to resolve via SIGALRM method",
+ timeout);
+ return CURLRESOLV_TIMEDOUT;
+ }
+ /* This allows us to time-out from the name resolver, as the timeout
+ will generate a signal and we will siglongjmp() from that here.
+ This technique has problems (see alarmfunc).
+ This should be the last thing we do before calling Curl_resolv(),
+ as otherwise we'd have to worry about variables that get modified
+ before we invoke Curl_resolv() (and thus use "volatile"). */
+ if(sigsetjmp(curl_jmpenv, 1)) {
+ /* this is coming from a siglongjmp() after an alarm signal */
+ failf(data, "name lookup timed out");
+ rc = CURLRESOLV_ERROR;
+ goto clean_up;
+ }
+ else {
+ /*************************************************************
+ * Set signal handler to catch SIGALRM
+ * Store the old value to be able to set it back later!
+ *************************************************************/
+#ifdef HAVE_SIGACTION
+ sigaction(SIGALRM, NULL, &sigact);
+ keep_sigact = sigact;
+ keep_copysig = TRUE; /* yes, we have a copy */
+ sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+ /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+ sigact.sa_flags &= ~SA_RESTART;
+#endif
+ /* now set the new struct */
+ sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+ /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+ keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+ /* alarm() makes a signal get sent when the timeout fires off, and that
+ will abort system calls */
+ prev_alarm = alarm(curlx_sltoui(timeout/1000L));
+ }
+
+#else
+#ifndef CURLRES_ASYNCH
+ if(timeoutms)
+ infof(conn->data, "timeout on name lookup is not supported\n");
+#else
+ (void)timeoutms; /* timeoutms not used with an async resolver */
+#endif
+#endif /* USE_ALARM_TIMEOUT */
+
+ /* Perform the actual name resolution. This might be interrupted by an
+ * alarm if it takes too long.
+ */
+ rc = Curl_resolv(conn, hostname, port, entry);
+
+#ifdef USE_ALARM_TIMEOUT
+clean_up:
+
+ if(!prev_alarm)
+ /* deactivate a possibly active alarm before uninstalling the handler */
+ alarm(0);
+
+#ifdef HAVE_SIGACTION
+ if(keep_copysig) {
+ /* we got a struct as it looked before, now put that one back nice
+ and clean */
+ sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
+ }
+#else
+#ifdef HAVE_SIGNAL
+ /* restore the previous SIGALRM handler */
+ signal(SIGALRM, keep_sigact);
+#endif
+#endif /* HAVE_SIGACTION */
+
+ /* switch back the alarm() to either zero or to what it was before minus
+ the time we spent until now! */
+ if(prev_alarm) {
+ /* there was an alarm() set before us, now put it back */
+ unsigned long elapsed_secs = (unsigned long) (Curl_tvdiff(Curl_tvnow(),
+ conn->created) / 1000);
+
+ /* the alarm period is counted in even number of seconds */
+ unsigned long alarm_set = prev_alarm - elapsed_secs;
+
+ if(!alarm_set ||
+ ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+ /* if the alarm time-left reached zero or turned "negative" (counted
+ with unsigned values), we should fire off a SIGALRM here, but we
+ won't, and zero would be to switch it off so we never set it to
+ less than 1! */
+ alarm(1);
+ rc = CURLRESOLV_TIMEDOUT;
+ failf(data, "Previous alarm fired off!");
+ }
+ else
+ alarm((unsigned int)alarm_set);
+ }
+#endif /* USE_ALARM_TIMEOUT */
+
+ return rc;
+}
+
+/*
+ * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been
+ * made, the struct may be destroyed due to pruning. It is important that only
+ * one unlock is made for each Curl_resolv() call.
+ *
+ * May be called with 'data' == NULL for global cache.
+ */
+void Curl_resolv_unlock(struct Curl_easy *data, struct Curl_dns_entry *dns)
+{
+ if(data && data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ freednsentry(dns);
+
+ if(data && data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * File-internal: release cache dns entry reference, free if inuse drops to 0
+ */
+static void freednsentry(void *freethis)
+{
+ struct Curl_dns_entry *dns = (struct Curl_dns_entry *) freethis;
+ DEBUGASSERT(dns && (dns->inuse>0));
+
+ dns->inuse--;
+ if(dns->inuse == 0) {
+ Curl_freeaddrinfo(dns->addr);
+ free(dns);
+ }
+}
+
+/*
+ * Curl_mk_dnscache() inits a new DNS cache and returns success/failure.
+ */
+int Curl_mk_dnscache(struct curl_hash *hash)
+{
+ return Curl_hash_init(hash, 7, Curl_hash_str, Curl_str_key_compare,
+ freednsentry);
+}
+
+/*
+ * Curl_hostcache_clean()
+ *
+ * This _can_ be called with 'data' == NULL but then of course no locking
+ * can be done!
+ */
+
+void Curl_hostcache_clean(struct Curl_easy *data,
+ struct curl_hash *hash)
+{
+ if(data && data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ Curl_hash_clean(hash);
+
+ if(data && data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+
+CURLcode Curl_loadhostpairs(struct Curl_easy *data)
+{
+ struct curl_slist *hostp;
+ char hostname[256];
+ char address[256];
+ int port;
+
+ for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
+ if(!hostp->data)
+ continue;
+ if(hostp->data[0] == '-') {
+ char *entry_id;
+ size_t entry_len;
+
+ if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
+ infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'!\n",
+ hostp->data);
+ continue;
+ }
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ entry_len = strlen(entry_id);
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* delete entry, ignore if it didn't exist */
+ Curl_hash_delete(data->dns.hostcache, entry_id, entry_len+1);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+ }
+ else {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *addr;
+ char *entry_id;
+ size_t entry_len;
+
+ if(3 != sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
+ address)) {
+ infof(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!\n",
+ hostp->data);
+ continue;
+ }
+
+ addr = Curl_str2addr(address, port);
+ if(!addr) {
+ infof(data, "Address in '%s' found illegal!\n", hostp->data);
+ continue;
+ }
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id) {
+ Curl_freeaddrinfo(addr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ entry_len = strlen(entry_id);
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ if(!dns) {
+ /* if not in the cache already, put this host in the cache */
+ dns = Curl_cache_addr(data, addr, hostname, port);
+ if(dns) {
+ dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
+ /* release the returned reference; the cache itself will keep the
+ * entry alive: */
+ dns->inuse--;
+ }
+ }
+ else
+ /* this is a duplicate, free it again */
+ Curl_freeaddrinfo(addr);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns) {
+ Curl_freeaddrinfo(addr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ infof(data, "Added %s:%d:%s to DNS cache\n",
+ hostname, port, address);
+ }
+ }
+ data->change.resolve = NULL; /* dealt with now */
+
+ return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/lib/hostip.h b/Utilities/cmcurl/lib/hostip.h
new file mode 100644
index 000000000..298eeeee3
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostip.h
@@ -0,0 +1,250 @@
+#ifndef HEADER_CURL_HOSTIP_H
+#define HEADER_CURL_HOSTIP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "hash.h"
+#include "curl_addrinfo.h"
+#include "asyn.h"
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_HOSTENT_SIZE 9000
+
+#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
+ many seconds for a name resolve */
+
+#define CURL_ASYNC_SUCCESS CURLE_OK
+
+struct addrinfo;
+struct hostent;
+struct Curl_easy;
+struct connectdata;
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void);
+void Curl_global_host_cache_dtor(void);
+
+struct Curl_dns_entry {
+ Curl_addrinfo *addr;
+ /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
+ time_t timestamp;
+ /* use-counter, use Curl_resolv_unlock to release reference */
+ long inuse;
+};
+
+/*
+ * Curl_resolv() returns an entry with the info for the specified host
+ * and port.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+/* return codes */
+#define CURLRESOLV_TIMEDOUT -2
+#define CURLRESOLV_ERROR -1
+#define CURLRESOLV_RESOLVED 0
+#define CURLRESOLV_PENDING 1
+int Curl_resolv(struct connectdata *conn, const char *hostname,
+ int port, struct Curl_dns_entry **dnsentry);
+int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
+ int port, struct Curl_dns_entry **dnsentry,
+ time_t timeoutms);
+
+#ifdef CURLRES_IPV6
+/*
+ * Curl_ipv6works() returns TRUE if IPv6 seems to work.
+ */
+bool Curl_ipv6works(void);
+#else
+#define Curl_ipv6works() FALSE
+#endif
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn);
+
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
+
+
+/* unlock a previously resolved dns entry */
+void Curl_resolv_unlock(struct Curl_easy *data,
+ struct Curl_dns_entry *dns);
+
+/* for debugging purposes only: */
+void Curl_scan_cache_used(void *user, void *ptr);
+
+/* init a new dns cache and return success */
+int Curl_mk_dnscache(struct curl_hash *hash);
+
+/* prune old entries from the DNS cache */
+void Curl_hostcache_prune(struct Curl_easy *data);
+
+/* Return # of addresses in a Curl_addrinfo struct */
+int Curl_num_addresses(const Curl_addrinfo *addr);
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+ GETNAMEINFO_TYPE_ARG2 salen,
+ char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+ char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+ GETNAMEINFO_TYPE_ARG7 flags,
+ int line, const char *source);
+#endif
+
+/* IPv4 threadsafe resolve function used for synch and asynch builds */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
+
+CURLcode Curl_async_resolved(struct connectdata *conn,
+ bool *protocol_connect);
+
+#ifndef CURLRES_ASYNCH
+#define Curl_async_resolved(x,y) CURLE_OK
+#endif
+
+/*
+ * Curl_addrinfo_callback() is used when we build with any asynch specialty.
+ * Handles end of async request processing. Inserts ai into hostcache when
+ * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
+ * request completed whether successful or failed.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+ int status,
+ Curl_addrinfo *ai);
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+ char *buf, size_t bufsize);
+
+/*
+ * Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+struct Curl_dns_entry *
+Curl_fetch_addr(struct connectdata *conn,
+ const char *hostname,
+ int port);
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr,
+ const char *hostname, int port);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
+#endif
+
+#ifdef HAVE_SIGSETJMP
+/* Forward-declaration of variable defined in hostip.c. Beware this
+ * is a global and unique instance. This is used to store the return
+ * address that we can jump back to from inside a signal handler.
+ * This is not thread-safe stuff.
+ */
+extern sigjmp_buf curl_jmpenv;
+#endif
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers);
+
+/*
+ * Function provided by the resolver backend to set
+ * outgoing interface to use for DNS requests
+ */
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+ const char *interf);
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv4 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+ const char *local_ip4);
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv6 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+ const char *local_ip6);
+
+/*
+ * Clean off entries from the cache
+ */
+void Curl_hostcache_clean(struct Curl_easy *data, struct curl_hash *hash);
+
+/*
+ * Destroy the hostcache of this handle.
+ */
+void Curl_hostcache_destroy(struct Curl_easy *data);
+
+/*
+ * Populate the cache with specified entries from CURLOPT_RESOLVE.
+ */
+CURLcode Curl_loadhostpairs(struct Curl_easy *data);
+
+#endif /* HEADER_CURL_HOSTIP_H */
diff --git a/Utilities/cmcurl/lib/hostip4.c b/Utilities/cmcurl/lib/hostip4.c
new file mode 100644
index 000000000..e459328ac
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostip4.c
@@ -0,0 +1,307 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for plain IPv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain IPv4 code coming up */
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn)
+{
+ if(conn->ip_version == CURL_IPRESOLVE_V6)
+ /* An IPv6 address was requested and we can't get/use one */
+ return FALSE;
+
+ return TRUE; /* OK, proceed */
+}
+
+#ifdef CURLRES_SYNCH
+
+/*
+ * Curl_getaddrinfo() - the IPv4 synchronous version.
+ *
+ * The original code to this function was from the Dancer source code, written
+ * by Bjorn Reese, it has since been patched and modified considerably.
+ *
+ * gethostbyname_r() is the thread-safe version of the gethostbyname()
+ * function. When we build for plain IPv4, we attempt to use this
+ * function. There are _three_ different gethostbyname_r() versions, and we
+ * detect which one this platform supports in the configure script and set up
+ * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
+ * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
+ * flavours have thread-safe versions of the plain gethostbyname() etc.
+ *
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ Curl_addrinfo *ai = NULL;
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)conn;
+#endif
+
+ *waitp = 0; /* synchronous response only */
+
+ ai = Curl_ipv4_resolve_r(hostname, port);
+ if(!ai)
+ infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+
+ return ai;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV4 */
+
+#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES)
+
+/*
+ * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
+ *
+ * This is used for both synchronous and asynchronous resolver builds,
+ * implying that only threadsafe code and function calls may be used.
+ *
+ */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+ int port)
+{
+#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
+ int res;
+#endif
+ Curl_addrinfo *ai = NULL;
+ struct hostent *h = NULL;
+ struct in_addr in;
+ struct hostent *buf = NULL;
+
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#if defined(HAVE_GETADDRINFO_THREADSAFE)
+ else {
+ struct addrinfo hints;
+ char sbuf[12];
+ char *sbufptr = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if(port) {
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+ sbufptr = sbuf;
+ }
+
+ (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
+
+#elif defined(HAVE_GETHOSTBYNAME_R)
+ /*
+ * gethostbyname_r() is the preferred resolve function for many platforms.
+ * Since there are three different versions of it, the following code is
+ * somewhat #ifdef-ridden.
+ */
+ else {
+ int h_errnop;
+
+ buf = calloc(1, CURL_HOSTENT_SIZE);
+ if(!buf)
+ return NULL; /* major failure */
+ /*
+ * The clearing of the buffer is a workaround for a gethostbyname_r bug in
+ * qnx nto and it is also _required_ for some of these functions on some
+ * platforms.
+ */
+
+#if defined(HAVE_GETHOSTBYNAME_R_5)
+ /* Solaris, IRIX and more */
+ h = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h_errnop);
+
+ /* If the buffer is too small, it returns NULL and sets errno to
+ * ERANGE. The errno is thread safe if this is compiled with
+ * -D_REENTRANT as then the 'errno' variable is a macro defined to get
+ * used properly for threads.
+ */
+
+ if(h) {
+ ;
+ }
+ else
+#elif defined(HAVE_GETHOSTBYNAME_R_6)
+ /* Linux */
+
+ (void)gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h, /* DIFFERENCE */
+ &h_errnop);
+ /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
+ * sudden this function returns EAGAIN if the given buffer size is too
+ * small. Previous versions are known to return ERANGE for the same
+ * problem.
+ *
+ * This wouldn't be such a big problem if older versions wouldn't
+ * sometimes return EAGAIN on a common failure case. Alas, we can't
+ * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
+ * glibc.
+ *
+ * For now, we do that and thus we may call the function repeatedly and
+ * fail for older glibc versions that return EAGAIN, until we run out of
+ * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
+ *
+ * If anyone has a better fix, please tell us!
+ *
+ * -------------------------------------------------------------------
+ *
+ * On October 23rd 2003, Dan C dug up more details on the mysteries of
+ * gethostbyname_r() in glibc:
+ *
+ * In glibc 2.2.5 the interface is different (this has also been
+ * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+ * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
+ * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+ *
+ * In this "buggy" version, the return code is -1 on error and 'errno'
+ * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
+ * thread-safe variable.
+ */
+
+ if(!h) /* failure */
+#elif defined(HAVE_GETHOSTBYNAME_R_3)
+ /* AIX, Digital Unix/Tru64, HPUX 10, more? */
+
+ /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+ * the plain fact that it does not return unique full buffers on each
+ * call, but instead several of the pointers in the hostent structs will
+ * point to the same actual data! This have the unfortunate down-side that
+ * our caching system breaks down horribly. Luckily for us though, AIX 4.3
+ * and more recent versions have a "completely thread-safe"[*] libc where
+ * all the data is stored in thread-specific memory areas making calls to
+ * the plain old gethostbyname() work fine even for multi-threaded
+ * programs.
+ *
+ * This AIX 4.3 or later detection is all made in the configure script.
+ *
+ * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
+ *
+ * [*] = much later we've found out that it isn't at all "completely
+ * thread-safe", but at least the gethostbyname() function is.
+ */
+
+ if(CURL_HOSTENT_SIZE >=
+ (sizeof(struct hostent)+sizeof(struct hostent_data))) {
+
+ /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
+ * that should work! September 20: Richard Prescott worked on the buffer
+ * size dilemma.
+ */
+
+ res = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (struct hostent_data *)((char *)buf +
+ sizeof(struct hostent)));
+ h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
+ }
+ else
+ res = -1; /* failure, too smallish buffer size */
+
+ if(!res) { /* success */
+
+ h = buf; /* result expected in h */
+
+ /* This is the worst kind of the different gethostbyname_r() interfaces.
+ * Since we don't know how big buffer this particular lookup required,
+ * we can't realloc down the huge alloc without doing closer analysis of
+ * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
+ * name lookup. Fixing this would require an extra malloc() and then
+ * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
+ * memory area to the actually used amount.
+ */
+ }
+ else
+#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
+ {
+ h = NULL; /* set return code to NULL */
+ free(buf);
+ }
+#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+ /*
+ * Here is code for platforms that don't have a thread safe
+ * getaddrinfo() nor gethostbyname_r() function or for which
+ * gethostbyname() is the preferred one.
+ */
+ else {
+ h = gethostbyname((void *)hostname);
+#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+ }
+
+ if(h) {
+ ai = Curl_he2ai(h, port);
+
+ if(buf) /* used a *_r() function */
+ free(buf);
+ }
+
+ return ai;
+}
+#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */
diff --git a/Utilities/cmcurl/lib/hostip6.c b/Utilities/cmcurl/lib/hostip6.c
new file mode 100644
index 000000000..4ebfc2dcf
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostip6.c
@@ -0,0 +1,234 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for IPv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+/* These are strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+/*
+ * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
+ * (ignoring the fact c-ares doesn't return 'serv').
+ */
+
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+ GETNAMEINFO_TYPE_ARG2 salen,
+ char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+ char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+ GETNAMEINFO_TYPE_ARG7 flags,
+ int line, const char *source)
+{
+ int res = (getnameinfo)(sa, salen,
+ host, hostlen,
+ serv, servlen,
+ flags);
+ if(0 == res)
+ /* success */
+ curl_memlog("GETNAME %s:%d getnameinfo()\n",
+ source, line);
+ else
+ curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
+ source, line, res);
+ return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
+
+/*
+ * Curl_ipv6works() returns TRUE if IPv6 seems to work.
+ */
+bool Curl_ipv6works(void)
+{
+ /* the nature of most system is that IPv6 status doesn't come and go
+ during a program's lifetime so we only probe the first time and then we
+ have the info kept for fast re-use */
+ static int ipv6_works = -1;
+ if(-1 == ipv6_works) {
+ /* probe to see if we have a working IPv6 stack */
+ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if(s == CURL_SOCKET_BAD)
+ /* an IPv6 address was requested but we can't get/use one */
+ ipv6_works = 0;
+ else {
+ ipv6_works = 1;
+ Curl_closesocket(NULL, s);
+ }
+ }
+ return (ipv6_works>0)?TRUE:FALSE;
+}
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn)
+{
+ if(conn->ip_version == CURL_IPRESOLVE_V6)
+ return Curl_ipv6works();
+
+ return TRUE;
+}
+
+#if defined(CURLRES_SYNCH)
+
+#ifdef DEBUG_ADDRINFO
+static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
+{
+ printf("dump_addrinfo:\n");
+ for(; ai; ai = ai->ai_next) {
+ char buf[INET6_ADDRSTRLEN];
+
+ printf(" fam %2d, CNAME %s, ",
+ ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+ if(Curl_printable_address(ai, buf, sizeof(buf)))
+ printf("%s\n", buf);
+ else
+ printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
+ }
+}
+#else
+#define dump_addrinfo(x,y) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_getaddrinfo() when built IPv6-enabled (non-threading and
+ * non-ares version).
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'addrinfo' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints;
+ Curl_addrinfo *res;
+ int error;
+ char sbuf[12];
+ char *sbufptr = NULL;
+#ifndef USE_RESOLVE_ON_IPS
+ char addrbuf[128];
+#endif
+ int pf;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ struct Curl_easy *data = conn->data;
+#endif
+
+ *waitp = 0; /* synchronous response only */
+
+ /* Check if a limited name resolve has been requested */
+ switch(conn->ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+
+ if((pf != PF_INET) && !Curl_ipv6works())
+ /* The stack seems to be a non-IPv6 one */
+ pf = PF_INET;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = conn->socktype;
+
+#ifndef USE_RESOLVE_ON_IPS
+ /*
+ * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from
+ * an IPv4 address on iOS and Mac OS X.
+ */
+ if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
+ (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
+ /* the given address is numerical only, prevent a reverse lookup */
+ hints.ai_flags = AI_NUMERICHOST;
+ }
+#endif
+
+ if(port) {
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+ sbufptr=sbuf;
+ }
+
+ error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
+ if(error) {
+ infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+ return NULL;
+ }
+
+ if(port) {
+ Curl_addrinfo_set_port(res, port);
+ }
+
+ dump_addrinfo(conn, res);
+
+ return res;
+}
+#endif /* CURLRES_SYNCH */
+
+#endif /* CURLRES_IPV6 */
diff --git a/Utilities/cmcurl/lib/hostsyn.c b/Utilities/cmcurl/lib/hostsyn.c
new file mode 100644
index 000000000..1a95263c6
--- /dev/null
+++ b/Utilities/cmcurl/lib/hostsyn.c
@@ -0,0 +1,107 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+CURLcode Curl_set_dns_servers(struct Curl_easy *data,
+ char *servers)
+{
+ (void)data;
+ (void)servers;
+ return CURLE_NOT_BUILT_IN;
+
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * outgoing interface to use for DNS requests
+ */
+CURLcode Curl_set_dns_interface(struct Curl_easy *data,
+ const char *interf)
+{
+ (void)data;
+ (void)interf;
+ return CURLE_NOT_BUILT_IN;
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv4 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
+ const char *local_ip4)
+{
+ (void)data;
+ (void)local_ip4;
+ return CURLE_NOT_BUILT_IN;
+}
+
+/*
+ * Function provided by the resolver backend to set
+ * local IPv6 address to use as source address for DNS requests
+ */
+CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
+ const char *local_ip6)
+{
+ (void)data;
+ (void)local_ip6;
+ return CURLE_NOT_BUILT_IN;
+}
+
+#endif /* truly sync */
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
new file mode 100644
index 000000000..21574e21d
--- /dev/null
+++ b/Utilities/cmcurl/lib/http.c
@@ -0,0 +1,3784 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "formdata.h"
+#include "progress.h"
+#include "curl_base64.h"
+#include "cookie.h"
+#include "vauth/vauth.h"
+#include "vtls/vtls.h"
+#include "http_digest.h"
+#include "http_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "http_negotiate.h"
+#include "url.h"
+#include "share.h"
+#include "hostip.h"
+#include "http.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "strcase.h"
+#include "content_encoding.h"
+#include "http_proxy.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "conncache.h"
+#include "pipeline.h"
+#include "http2.h"
+#include "connect.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static int http_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+static int http_should_fail(struct connectdata *conn);
+
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done);
+static int https_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+#else
+#define https_connecting(x,y) CURLE_COULDNT_CONNECT
+#endif
+
+/*
+ * HTTP handler interface.
+ */
+const struct Curl_handler Curl_handler_http = {
+ "HTTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_CREDSPERREQUEST /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTPS handler interface.
+ */
+const struct Curl_handler Curl_handler_https = {
+ "HTTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ https_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ https_getsock, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTPS, /* defport */
+ CURLPROTO_HTTPS, /* protocol */
+ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
+};
+#endif
+
+CURLcode Curl_http_setup_conn(struct connectdata *conn)
+{
+ /* allocate the HTTP-specific struct for the Curl_easy, only to survive
+ during this request */
+ struct HTTP *http;
+ DEBUGASSERT(conn->data->req.protop == NULL);
+
+ http = calloc(1, sizeof(struct HTTP));
+ if(!http)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->data->req.protop = http;
+
+ Curl_http2_setup_conn(conn);
+ Curl_http2_setup_req(conn->data);
+
+ return CURLE_OK;
+}
+
+/*
+ * checkheaders() checks the linked list of custom HTTP headers for a
+ * particular header (prefix).
+ *
+ * Returns a pointer to the first matching header or NULL if none matched.
+ */
+char *Curl_checkheaders(const struct connectdata *conn,
+ const char *thisheader)
+{
+ struct curl_slist *head;
+ size_t thislen = strlen(thisheader);
+ struct Curl_easy *data = conn->data;
+
+ for(head = data->set.headers;head; head=head->next) {
+ if(strncasecompare(head->data, thisheader, thislen))
+ return head->data;
+ }
+
+ return NULL;
+}
+
+/*
+ * checkProxyHeaders() checks the linked list of custom proxy headers
+ * if proxy headers are not available, then it will lookup into http header
+ * link list
+ *
+ * It takes a connectdata struct as input instead of the Curl_easy simply
+ * to know if this is a proxy request or not, as it then might check a
+ * different header list.
+ */
+char *Curl_checkProxyheaders(const struct connectdata *conn,
+ const char *thisheader)
+{
+ struct curl_slist *head;
+ size_t thislen = strlen(thisheader);
+ struct Curl_easy *data = conn->data;
+
+ for(head = (conn->bits.proxy && data->set.sep_headers) ?
+ data->set.proxyheaders : data->set.headers;
+ head; head=head->next) {
+ if(strncasecompare(head->data, thisheader, thislen))
+ return head->data;
+ }
+
+ return NULL;
+}
+
+/*
+ * Strip off leading and trailing whitespace from the value in the
+ * given HTTP header line and return a strdupped copy. Returns NULL in
+ * case of allocation failure. Returns an empty string if the header value
+ * consists entirely of whitespace.
+ */
+char *Curl_copy_header_value(const char *header)
+{
+ const char *start;
+ const char *end;
+ char *value;
+ size_t len;
+
+ DEBUGASSERT(header);
+
+ /* Find the end of the header name */
+ while(*header && (*header != ':'))
+ ++header;
+
+ if(*header)
+ /* Skip over colon */
+ ++header;
+
+ /* Find the first non-space letter */
+ start = header;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* data is in the host encoding so
+ use '\r' and '\n' instead of 0x0d and 0x0a */
+ end = strchr(start, '\r');
+ if(!end)
+ end = strchr(start, '\n');
+ if(!end)
+ end = strchr(start, '\0');
+ if(!end)
+ return NULL;
+
+ /* skip all trailing space letters */
+ while((end > start) && ISSPACE(*end))
+ end--;
+
+ /* get length of the type */
+ len = end - start + 1;
+
+ value = malloc(len + 1);
+ if(!value)
+ return NULL;
+
+ memcpy(value, start, len);
+ value[len] = 0; /* zero terminate */
+
+ return value;
+}
+
+/*
+ * http_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
+{
+ size_t size = 0;
+ char *authorization = NULL;
+ struct Curl_easy *data = conn->data;
+ char **userp;
+ const char *user;
+ const char *pwd;
+ CURLcode result;
+ char *out;
+
+ if(proxy) {
+ userp = &conn->allocptr.proxyuserpwd;
+ user = conn->http_proxy.user;
+ pwd = conn->http_proxy.passwd;
+ }
+ else {
+ userp = &conn->allocptr.userpwd;
+ user = conn->user;
+ pwd = conn->passwd;
+ }
+
+ out = aprintf("%s:%s", user, pwd);
+ if(!out)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_base64_encode(data, out, strlen(out), &authorization, &size);
+ if(result)
+ goto fail;
+
+ if(!authorization) {
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ goto fail;
+ }
+
+ free(*userp);
+ *userp = aprintf("%sAuthorization: Basic %s\r\n",
+ proxy ? "Proxy-" : "",
+ authorization);
+ free(authorization);
+ if(!*userp) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto fail;
+ }
+
+ fail:
+ free(out);
+ return result;
+}
+
+/* pickoneauth() selects the most favourable authentication method from the
+ * ones available and the ones we want.
+ *
+ * return TRUE if one was picked
+ */
+static bool pickoneauth(struct auth *pick)
+{
+ bool picked;
+ /* only deal with authentication we want */
+ unsigned long avail = pick->avail & pick->want;
+ picked = TRUE;
+
+ /* The order of these checks is highly relevant, as this will be the order
+ of preference in case of the existence of multiple accepted types. */
+ if(avail & CURLAUTH_NEGOTIATE)
+ pick->picked = CURLAUTH_NEGOTIATE;
+ else if(avail & CURLAUTH_DIGEST)
+ pick->picked = CURLAUTH_DIGEST;
+ else if(avail & CURLAUTH_NTLM)
+ pick->picked = CURLAUTH_NTLM;
+ else if(avail & CURLAUTH_NTLM_WB)
+ pick->picked = CURLAUTH_NTLM_WB;
+ else if(avail & CURLAUTH_BASIC)
+ pick->picked = CURLAUTH_BASIC;
+ else {
+ pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
+ picked = FALSE;
+ }
+ pick->avail = CURLAUTH_NONE; /* clear it here */
+
+ return picked;
+}
+
+/*
+ * Curl_http_perhapsrewind()
+ *
+ * If we are doing POST or PUT {
+ * If we have more data to send {
+ * If we are doing NTLM {
+ * Keep sending since we must not disconnect
+ * }
+ * else {
+ * If there is more than just a little data left to send, close
+ * the current connection by force.
+ * }
+ * }
+ * If we have sent any data {
+ * If we don't have track of all the data {
+ * call app to tell it to rewind
+ * }
+ * else {
+ * rewind internally so that the operation can restart fine
+ * }
+ * }
+ * }
+ */
+static CURLcode http_perhapsrewind(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ struct HTTP *http = data->req.protop;
+ curl_off_t bytessent;
+ curl_off_t expectsend = -1; /* default is unknown */
+
+ if(!http)
+ /* If this is still NULL, we have not reach very far and we can safely
+ skip this rewinding stuff */
+ return CURLE_OK;
+
+ switch(data->set.httpreq) {
+ case HTTPREQ_GET:
+ case HTTPREQ_HEAD:
+ return CURLE_OK;
+ default:
+ break;
+ }
+
+ bytessent = http->writebytecount;
+
+ if(conn->bits.authneg) {
+ /* This is a state where we are known to be negotiating and we don't send
+ any data then. */
+ expectsend = 0;
+ }
+ else if(!conn->bits.protoconnstart) {
+ /* HTTP CONNECT in progress: there is no body */
+ expectsend = 0;
+ }
+ else {
+ /* figure out how much data we are expected to send */
+ switch(data->set.httpreq) {
+ case HTTPREQ_POST:
+ if(data->state.infilesize != -1)
+ expectsend = data->state.infilesize;
+ break;
+ case HTTPREQ_PUT:
+ if(data->state.infilesize != -1)
+ expectsend = data->state.infilesize;
+ break;
+ case HTTPREQ_POST_FORM:
+ expectsend = http->postsize;
+ break;
+ default:
+ break;
+ }
+ }
+
+ conn->bits.rewindaftersend = FALSE; /* default */
+
+ if((expectsend == -1) || (expectsend > bytessent)) {
+#if defined(USE_NTLM)
+ /* There is still data left to send */
+ if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM) ||
+ (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+ if(((expectsend - bytessent) < 2000) ||
+ (conn->ntlm.state != NTLMSTATE_NONE) ||
+ (conn->proxyntlm.state != NTLMSTATE_NONE)) {
+ /* The NTLM-negotiation has started *OR* there is just a little (<2K)
+ data left to send, keep on sending. */
+
+ /* rewind data when completely done sending! */
+ if(!conn->bits.authneg) {
+ conn->bits.rewindaftersend = TRUE;
+ infof(data, "Rewind stream after send\n");
+ }
+
+ return CURLE_OK;
+ }
+
+ if(conn->bits.close)
+ /* this is already marked to get closed */
+ return CURLE_OK;
+
+ infof(data, "NTLM send, close instead of sending %"
+ CURL_FORMAT_CURL_OFF_T " bytes\n",
+ (curl_off_t)(expectsend - bytessent));
+ }
+#endif
+
+ /* This is not NTLM or many bytes left to send: close */
+ streamclose(conn, "Mid-auth HTTP and much data left to send");
+ data->req.size = 0; /* don't download any more than 0 bytes */
+
+ /* There still is data left to send, but this connection is marked for
+ closure so we can safely do the rewind right now */
+ }
+
+ if(bytessent)
+ /* we rewind now at once since if we already sent something */
+ return Curl_readrewind(conn);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_http_auth_act() gets called when all HTTP headers have been received
+ * and it checks what authentication methods that are available and decides
+ * which one (if any) to use. It will set 'newurl' if an auth method was
+ * picked.
+ */
+
+CURLcode Curl_http_auth_act(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ bool pickhost = FALSE;
+ bool pickproxy = FALSE;
+ CURLcode result = CURLE_OK;
+
+ if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
+ /* this is a transient response code, ignore */
+ return CURLE_OK;
+
+ if(data->state.authproblem)
+ return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+ if(conn->bits.user_passwd &&
+ ((data->req.httpcode == 401) ||
+ (conn->bits.authneg && data->req.httpcode < 300))) {
+ pickhost = pickoneauth(&data->state.authhost);
+ if(!pickhost)
+ data->state.authproblem = TRUE;
+ }
+ if(conn->bits.proxy_user_passwd &&
+ ((data->req.httpcode == 407) ||
+ (conn->bits.authneg && data->req.httpcode < 300))) {
+ pickproxy = pickoneauth(&data->state.authproxy);
+ if(!pickproxy)
+ data->state.authproblem = TRUE;
+ }
+
+ if(pickhost || pickproxy) {
+ /* In case this is GSS auth, the newurl field is already allocated so
+ we must make sure to free it before allocating a new one. As figured
+ out in bug #2284386 */
+ Curl_safefree(data->req.newurl);
+ data->req.newurl = strdup(data->change.url); /* clone URL */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD) &&
+ !conn->bits.rewindaftersend) {
+ result = http_perhapsrewind(conn);
+ if(result)
+ return result;
+ }
+ }
+ else if((data->req.httpcode < 300) &&
+ (!data->state.authhost.done) &&
+ conn->bits.authneg) {
+ /* no (known) authentication available,
+ authentication is not "done" yet and
+ no authentication seems to be required and
+ we didn't try HEAD or GET */
+ if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD)) {
+ data->req.newurl = strdup(data->change.url); /* clone URL */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authhost.done = TRUE;
+ }
+ }
+ if(http_should_fail(conn)) {
+ failf(data, "The requested URL returned error: %d",
+ data->req.httpcode);
+ result = CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ return result;
+}
+
+/*
+ * Output the correct authentication header depending on the auth type
+ * and whether or not it is to a proxy.
+ */
+static CURLcode
+output_auth_headers(struct connectdata *conn,
+ struct auth *authstatus,
+ const char *request,
+ const char *path,
+ bool proxy)
+{
+ const char *auth = NULL;
+ CURLcode result = CURLE_OK;
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_SPNEGO)
+ struct Curl_easy *data = conn->data;
+#endif
+#ifdef USE_SPNEGO
+ struct negotiatedata *negdata = proxy ?
+ &data->state.proxyneg : &data->state.negotiate;
+#endif
+
+#ifdef CURL_DISABLE_CRYPTO_AUTH
+ (void)request;
+ (void)path;
+#endif
+
+#ifdef USE_SPNEGO
+ negdata->state = GSS_AUTHNONE;
+ if((authstatus->picked == CURLAUTH_NEGOTIATE) &&
+ negdata->context && !GSS_ERROR(negdata->status)) {
+ auth = "Negotiate";
+ result = Curl_output_negotiate(conn, proxy);
+ if(result)
+ return result;
+ authstatus->done = TRUE;
+ negdata->state = GSS_AUTHSENT;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if(authstatus->picked == CURLAUTH_NTLM) {
+ auth = "NTLM";
+ result = Curl_output_ntlm(conn, proxy);
+ if(result)
+ return result;
+ }
+ else
+#endif
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ if(authstatus->picked == CURLAUTH_NTLM_WB) {
+ auth="NTLM_WB";
+ result = Curl_output_ntlm_wb(conn, proxy);
+ if(result)
+ return result;
+ }
+ else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(authstatus->picked == CURLAUTH_DIGEST) {
+ auth = "Digest";
+ result = Curl_output_digest(conn,
+ proxy,
+ (const unsigned char *)request,
+ (const unsigned char *)path);
+ if(result)
+ return result;
+ }
+ else
+#endif
+ if(authstatus->picked == CURLAUTH_BASIC) {
+ /* Basic */
+ if((proxy && conn->bits.proxy_user_passwd &&
+ !Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
+ (!proxy && conn->bits.user_passwd &&
+ !Curl_checkheaders(conn, "Authorization:"))) {
+ auth = "Basic";
+ result = http_output_basic(conn, proxy);
+ if(result)
+ return result;
+ }
+
+ /* NOTE: this function should set 'done' TRUE, as the other auth
+ functions work that way */
+ authstatus->done = TRUE;
+ }
+
+ if(auth) {
+ infof(data, "%s auth using %s with user '%s'\n",
+ proxy ? "Proxy" : "Server", auth,
+ proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") :
+ (conn->user ? conn->user : ""));
+ authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
+ }
+ else
+ authstatus->multipass = FALSE;
+
+ return CURLE_OK;
+}
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ const char *request,
+ const char *path,
+ bool proxytunnel) /* TRUE if this is the request setting
+ up the proxy tunnel */
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct auth *authhost;
+ struct auth *authproxy;
+
+ DEBUGASSERT(data);
+
+ authhost = &data->state.authhost;
+ authproxy = &data->state.authproxy;
+
+ if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+ conn->bits.user_passwd)
+ /* continue please */;
+ else {
+ authhost->done = TRUE;
+ authproxy->done = TRUE;
+ return CURLE_OK; /* no authentication with no user or password */
+ }
+
+ if(authhost->want && !authhost->picked)
+ /* The app has selected one or more methods, but none has been picked
+ so far by a server round-trip. Then we set the picked one to the
+ want one, and if this is one single bit it'll be used instantly. */
+ authhost->picked = authhost->want;
+
+ if(authproxy->want && !authproxy->picked)
+ /* The app has selected one or more methods, but none has been picked so
+ far by a proxy round-trip. Then we set the picked one to the want one,
+ and if this is one single bit it'll be used instantly. */
+ authproxy->picked = authproxy->want;
+
+#ifndef CURL_DISABLE_PROXY
+ /* Send proxy authentication header if needed */
+ if(conn->bits.httpproxy &&
+ (conn->bits.tunnel_proxy == proxytunnel)) {
+ result = output_auth_headers(conn, authproxy, request, path, TRUE);
+ if(result)
+ return result;
+ }
+ else
+#else
+ (void)proxytunnel;
+#endif /* CURL_DISABLE_PROXY */
+ /* we have no proxy so let's pretend we're done authenticating
+ with it */
+ authproxy->done = TRUE;
+
+ /* To prevent the user+password to get sent to other than the original
+ host due to a location-follow, we do some weirdo checks here */
+ if(!data->state.this_is_a_follow ||
+ conn->bits.netrc ||
+ !data->state.first_host ||
+ data->set.http_disable_hostname_check_before_authentication ||
+ strcasecompare(data->state.first_host, conn->host.name)) {
+ result = output_auth_headers(conn, authhost, request, path, FALSE);
+ }
+ else
+ authhost->done = TRUE;
+
+ return result;
+}
+
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
+
+CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
+ const char *auth) /* the first non-space */
+{
+ /*
+ * This resource requires authentication
+ */
+ struct Curl_easy *data = conn->data;
+
+#ifdef USE_SPNEGO
+ struct negotiatedata *negdata = proxy?
+ &data->state.proxyneg:&data->state.negotiate;
+#endif
+ unsigned long *availp;
+ struct auth *authp;
+
+ if(proxy) {
+ availp = &data->info.proxyauthavail;
+ authp = &data->state.authproxy;
+ }
+ else {
+ availp = &data->info.httpauthavail;
+ authp = &data->state.authhost;
+ }
+
+ /*
+ * Here we check if we want the specific single authentication (using ==) and
+ * if we do, we initiate usage of it.
+ *
+ * If the provided authentication is wanted as one out of several accepted
+ * types (using &), we OR this authentication type to the authavail
+ * variable.
+ *
+ * Note:
+ *
+ * ->picked is first set to the 'want' value (one or more bits) before the
+ * request is sent, and then it is again set _after_ all response 401/407
+ * headers have been received but then only to a single preferred method
+ * (bit).
+ */
+
+ while(*auth) {
+#ifdef USE_SPNEGO
+ if(checkprefix("Negotiate", auth)) {
+ if((authp->avail & CURLAUTH_NEGOTIATE) ||
+ Curl_auth_is_spnego_supported()) {
+ *availp |= CURLAUTH_NEGOTIATE;
+ authp->avail |= CURLAUTH_NEGOTIATE;
+
+ if(authp->picked == CURLAUTH_NEGOTIATE) {
+ if(negdata->state == GSS_AUTHSENT ||
+ negdata->state == GSS_AUTHNONE) {
+ CURLcode result = Curl_input_negotiate(conn, proxy, auth);
+ if(!result) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->change.url);
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authproblem = FALSE;
+ /* we received a GSS auth token and we dealt with it fine */
+ negdata->state = GSS_AUTHRECV;
+ }
+ else
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ /* NTLM support requires the SSL crypto libs */
+ if(checkprefix("NTLM", auth)) {
+ if((authp->avail & CURLAUTH_NTLM) ||
+ (authp->avail & CURLAUTH_NTLM_WB) ||
+ Curl_auth_is_ntlm_supported()) {
+ *availp |= CURLAUTH_NTLM;
+ authp->avail |= CURLAUTH_NTLM;
+
+ if(authp->picked == CURLAUTH_NTLM ||
+ authp->picked == CURLAUTH_NTLM_WB) {
+ /* NTLM authentication is picked and activated */
+ CURLcode result = Curl_input_ntlm(conn, proxy, auth);
+ if(!result) {
+ data->state.authproblem = FALSE;
+#ifdef NTLM_WB_ENABLED
+ if(authp->picked == CURLAUTH_NTLM_WB) {
+ *availp &= ~CURLAUTH_NTLM;
+ authp->avail &= ~CURLAUTH_NTLM;
+ *availp |= CURLAUTH_NTLM_WB;
+ authp->avail |= CURLAUTH_NTLM_WB;
+
+ /* Get the challenge-message which will be passed to
+ * ntlm_auth for generating the type 3 message later */
+ while(*auth && ISSPACE(*auth))
+ auth++;
+ if(checkprefix("NTLM", auth)) {
+ auth += strlen("NTLM");
+ while(*auth && ISSPACE(*auth))
+ auth++;
+ if(*auth) {
+ conn->challenge_header = strdup(auth);
+ if(!conn->challenge_header)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ }
+#endif
+ }
+ else {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ }
+ else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(checkprefix("Digest", auth)) {
+ if((authp->avail & CURLAUTH_DIGEST) != 0)
+ infof(data, "Ignoring duplicate digest auth header.\n");
+ else if(Curl_auth_is_digest_supported()) {
+ CURLcode result;
+
+ *availp |= CURLAUTH_DIGEST;
+ authp->avail |= CURLAUTH_DIGEST;
+
+ /* We call this function on input Digest headers even if Digest
+ * authentication isn't activated yet, as we need to store the
+ * incoming data from this header in case we are going to use
+ * Digest */
+ result = Curl_input_digest(conn, proxy, auth);
+ if(result) {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+ if(checkprefix("Basic", auth)) {
+ *availp |= CURLAUTH_BASIC;
+ authp->avail |= CURLAUTH_BASIC;
+ if(authp->picked == CURLAUTH_BASIC) {
+ /* We asked for Basic authentication but got a 40X back
+ anyway, which basically means our name+password isn't
+ valid. */
+ authp->avail = CURLAUTH_NONE;
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+
+ /* there may be multiple methods on one line, so keep reading */
+ while(*auth && *auth != ',') /* read up to the next comma */
+ auth++;
+ if(*auth == ',') /* if we're on a comma, skip it */
+ auth++;
+ while(*auth && ISSPACE(*auth))
+ auth++;
+ }
+
+ return CURLE_OK;
+}
+
+/**
+ * http_should_fail() determines whether an HTTP response has gotten us
+ * into an error state or not.
+ *
+ * @param conn all information about the current connection
+ *
+ * @retval 0 communications should continue
+ *
+ * @retval 1 communications should not continue
+ */
+static int http_should_fail(struct connectdata *conn)
+{
+ struct Curl_easy *data;
+ int httpcode;
+
+ DEBUGASSERT(conn);
+ data = conn->data;
+ DEBUGASSERT(data);
+
+ httpcode = data->req.httpcode;
+
+ /*
+ ** If we haven't been asked to fail on error,
+ ** don't fail.
+ */
+ if(!data->set.http_fail_on_error)
+ return 0;
+
+ /*
+ ** Any code < 400 is never terminal.
+ */
+ if(httpcode < 400)
+ return 0;
+
+ /*
+ ** Any code >= 400 that's not 401 or 407 is always
+ ** a terminal error
+ */
+ if((httpcode != 401) && (httpcode != 407))
+ return 1;
+
+ /*
+ ** All we have left to deal with is 401 and 407
+ */
+ DEBUGASSERT((httpcode == 401) || (httpcode == 407));
+
+ /*
+ ** Examine the current authentication state to see if this
+ ** is an error. The idea is for this function to get
+ ** called after processing all the headers in a response
+ ** message. So, if we've been to asked to authenticate a
+ ** particular stage, and we've done it, we're OK. But, if
+ ** we're already completely authenticated, it's not OK to
+ ** get another 401 or 407.
+ **
+ ** It is possible for authentication to go stale such that
+ ** the client needs to reauthenticate. Once that info is
+ ** available, use it here.
+ */
+
+ /*
+ ** Either we're not authenticating, or we're supposed to
+ ** be authenticating something else. This is an error.
+ */
+ if((httpcode == 401) && !conn->bits.user_passwd)
+ return TRUE;
+ if((httpcode == 407) && !conn->bits.proxy_user_passwd)
+ return TRUE;
+
+ return data->state.authproblem;
+}
+
+/*
+ * readmoredata() is a "fread() emulation" to provide POST and/or request
+ * data. It is used when a huge POST is to be made and the entire chunk wasn't
+ * sent in the first send(). This function will then be called from the
+ * transfer.c loop when more data is to be sent to the peer.
+ *
+ * Returns the amount of bytes it filled the buffer with.
+ */
+static size_t readmoredata(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userp)
+{
+ struct connectdata *conn = (struct connectdata *)userp;
+ struct HTTP *http = conn->data->req.protop;
+ size_t fullsize = size * nitems;
+
+ if(!http->postsize)
+ /* nothing to return */
+ return 0;
+
+ /* make sure that a HTTP request is never sent away chunked! */
+ conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
+
+ if(http->postsize <= (curl_off_t)fullsize) {
+ memcpy(buffer, http->postdata, (size_t)http->postsize);
+ fullsize = (size_t)http->postsize;
+
+ if(http->backup.postsize) {
+ /* move backup data into focus and continue on that */
+ http->postdata = http->backup.postdata;
+ http->postsize = http->backup.postsize;
+ conn->data->state.fread_func = http->backup.fread_func;
+ conn->data->state.in = http->backup.fread_in;
+
+ http->sending++; /* move one step up */
+
+ http->backup.postsize=0;
+ }
+ else
+ http->postsize = 0;
+
+ return fullsize;
+ }
+
+ memcpy(buffer, http->postdata, fullsize);
+ http->postdata += fullsize;
+ http->postsize -= fullsize;
+
+ return fullsize;
+}
+
+/* ------------------------------------------------------------------------- */
+/* add_buffer functions */
+
+/*
+ * Curl_add_buffer_init() sets up and returns a fine buffer struct
+ */
+Curl_send_buffer *Curl_add_buffer_init(void)
+{
+ return calloc(1, sizeof(Curl_send_buffer));
+}
+
+/*
+ * Curl_add_buffer_free() frees all associated resources.
+ */
+void Curl_add_buffer_free(Curl_send_buffer *buff)
+{
+ if(buff) /* deal with NULL input */
+ free(buff->buffer);
+ free(buff);
+}
+
+/*
+ * Curl_add_buffer_send() sends a header buffer and frees all associated
+ * memory. Body data may be appended to the header data if desired.
+ *
+ * Returns CURLcode
+ */
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+ struct connectdata *conn,
+
+ /* add the number of sent bytes to this
+ counter */
+ long *bytes_written,
+
+ /* how much of the buffer contains body data */
+ size_t included_body_bytes,
+ int socketindex)
+
+{
+ ssize_t amount;
+ CURLcode result;
+ char *ptr;
+ size_t size;
+ struct HTTP *http = conn->data->req.protop;
+ size_t sendsize;
+ curl_socket_t sockfd;
+ size_t headersize;
+
+ DEBUGASSERT(socketindex <= SECONDARYSOCKET);
+
+ sockfd = conn->sock[socketindex];
+
+ /* The looping below is required since we use non-blocking sockets, but due
+ to the circumstances we will just loop and try again and again etc */
+
+ ptr = in->buffer;
+ size = in->size_used;
+
+ headersize = size - included_body_bytes; /* the initial part that isn't body
+ is header */
+
+ DEBUGASSERT(size > included_body_bytes);
+
+ result = Curl_convert_to_network(conn->data, ptr, headersize);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result) {
+ /* conversion failed, free memory and return to the caller */
+ Curl_add_buffer_free(in);
+ return result;
+ }
+
+ if((conn->handler->flags & PROTOPT_SSL ||
+ conn->http_proxy.proxytype == CURLPROXY_HTTPS)
+ && conn->httpversion != 20) {
+ /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
+ when we speak HTTPS, as if only a fraction of it is sent now, this data
+ needs to fit into the normal read-callback buffer later on and that
+ buffer is using this size.
+ */
+
+ sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE);
+
+ /* OpenSSL is very picky and we must send the SAME buffer pointer to the
+ library when we attempt to re-send this buffer. Sending the same data
+ is not enough, we must use the exact same address. For this reason, we
+ must copy the data to the uploadbuffer first, since that is the buffer
+ we will be using if this send is retried later.
+ */
+ memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
+ ptr = conn->data->state.uploadbuffer;
+ }
+ else
+ sendsize = size;
+
+ result = Curl_write(conn, sockfd, ptr, sendsize, &amount);
+
+ if(!result) {
+ /*
+ * Note that we may not send the entire chunk at once, and we have a set
+ * number of data bytes at the end of the big buffer (out of which we may
+ * only send away a part).
+ */
+ /* how much of the header that was sent */
+ size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
+ size_t bodylen = amount - headlen;
+
+ if(conn->data->set.verbose) {
+ /* this data _may_ contain binary stuff */
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
+ if(bodylen) {
+ /* there was body data sent beyond the initial header part, pass that
+ on to the debug callback too */
+ Curl_debug(conn->data, CURLINFO_DATA_OUT,
+ ptr+headlen, bodylen, conn);
+ }
+ }
+
+ /* 'amount' can never be a very large value here so typecasting it so a
+ signed 31 bit value should not cause problems even if ssize_t is
+ 64bit */
+ *bytes_written += (long)amount;
+
+ if(http) {
+ /* if we sent a piece of the body here, up the byte counter for it
+ accordingly */
+ http->writebytecount += bodylen;
+
+ if((size_t)amount != size) {
+ /* The whole request could not be sent in one system call. We must
+ queue it up and send it later when we get the chance. We must not
+ loop here and wait until it might work again. */
+
+ size -= amount;
+
+ ptr = in->buffer + amount;
+
+ /* backup the currently set pointers */
+ http->backup.fread_func = conn->data->state.fread_func;
+ http->backup.fread_in = conn->data->state.in;
+ http->backup.postdata = http->postdata;
+ http->backup.postsize = http->postsize;
+
+ /* set the new pointers for the request-sending */
+ conn->data->state.fread_func = (curl_read_callback)readmoredata;
+ conn->data->state.in = (void *)conn;
+ http->postdata = ptr;
+ http->postsize = (curl_off_t)size;
+
+ http->send_buffer = in;
+ http->sending = HTTPSEND_REQUEST;
+
+ return CURLE_OK;
+ }
+ http->sending = HTTPSEND_BODY;
+ /* the full buffer was sent, clean up and return */
+ }
+ else {
+ if((size_t)amount != size)
+ /* We have no continue-send mechanism now, fail. This can only happen
+ when this function is used from the CONNECT sending function. We
+ currently (stupidly) assume that the whole request is always sent
+ away in the first single chunk.
+
+ This needs FIXing.
+ */
+ return CURLE_SEND_ERROR;
+ Curl_pipeline_leave_write(conn);
+ }
+ }
+ Curl_add_buffer_free(in);
+
+ return result;
+}
+
+
+/*
+ * add_bufferf() add the formatted input to the buffer.
+ */
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
+{
+ char *s;
+ va_list ap;
+ va_start(ap, fmt);
+ s = vaprintf(fmt, ap); /* this allocs a new string to append */
+ va_end(ap);
+
+ if(s) {
+ CURLcode result = Curl_add_buffer(in, s, strlen(s));
+ free(s);
+ return result;
+ }
+ /* If we failed, we cleanup the whole buffer and return error */
+ free(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * add_buffer() appends a memory chunk to the existing buffer
+ */
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
+{
+ char *new_rb;
+ size_t new_size;
+
+ if(~size < in->size_used) {
+ /* If resulting used size of send buffer would wrap size_t, cleanup
+ the whole buffer and return error. Otherwise the required buffer
+ size will fit into a single allocatable memory chunk */
+ Curl_safefree(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!in->buffer ||
+ ((in->size_used + size) > (in->size_max - 1))) {
+
+ /* If current buffer size isn't enough to hold the result, use a
+ buffer size that doubles the required size. If this new size
+ would wrap size_t, then just use the largest possible one */
+
+ if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) ||
+ (~(size * 2) < (in->size_used * 2)))
+ new_size = (size_t)-1;
+ else
+ new_size = (in->size_used+size) * 2;
+
+ if(in->buffer)
+ /* we have a buffer, enlarge the existing one */
+ new_rb = Curl_saferealloc(in->buffer, new_size);
+ else
+ /* create a new buffer */
+ new_rb = malloc(new_size);
+
+ if(!new_rb) {
+ /* If we failed, we cleanup the whole buffer and return error */
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ in->buffer = new_rb;
+ in->size_max = new_size;
+ }
+ memcpy(&in->buffer[in->size_used], inptr, size);
+
+ in->size_used += size;
+
+ return CURLE_OK;
+}
+
+/* end of the add_buffer functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/*
+ * Curl_compareheader()
+ *
+ * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
+ * Pass headers WITH the colon.
+ */
+bool
+Curl_compareheader(const char *headerline, /* line to check */
+ const char *header, /* header keyword _with_ colon */
+ const char *content) /* content string to find */
+{
+ /* RFC2616, section 4.2 says: "Each header field consists of a name followed
+ * by a colon (":") and the field value. Field names are case-insensitive.
+ * The field value MAY be preceded by any amount of LWS, though a single SP
+ * is preferred." */
+
+ size_t hlen = strlen(header);
+ size_t clen;
+ size_t len;
+ const char *start;
+ const char *end;
+
+ if(!strncasecompare(headerline, header, hlen))
+ return FALSE; /* doesn't start with header */
+
+ /* pass the header */
+ start = &headerline[hlen];
+
+ /* pass all white spaces */
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* find the end of the header line */
+ end = strchr(start, '\r'); /* lines end with CRLF */
+ if(!end) {
+ /* in case there's a non-standard compliant line here */
+ end = strchr(start, '\n');
+
+ if(!end)
+ /* hm, there's no line ending here, use the zero byte! */
+ end = strchr(start, '\0');
+ }
+
+ len = end-start; /* length of the content part of the input line */
+ clen = strlen(content); /* length of the word to find */
+
+ /* find the content string in the rest of the line */
+ for(;len>=clen;len--, start++) {
+ if(strncasecompare(start, content, clen))
+ return TRUE; /* match! */
+ }
+
+ return FALSE; /* no match */
+}
+
+/*
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
+ */
+CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+
+ /* We default to persistent connections. We set this already in this connect
+ function to make the re-use checks properly be able to check this bit. */
+ connkeep(conn, "HTTP default");
+
+ /* the CONNECT procedure might not have been completed */
+ result = Curl_proxy_connect(conn, FIRSTSOCKET);
+ if(result)
+ return result;
+
+ if(conn->bits.proxy_connect_closed)
+ /* this is not an error, just part of the connection negotiation */
+ return CURLE_OK;
+
+ if(CONNECT_FIRSTSOCKET_PROXY_SSL())
+ return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */
+
+ if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ /* nothing else to do except wait right now - we're not done here. */
+ return CURLE_OK;
+
+ if(conn->given->protocol & CURLPROTO_HTTPS) {
+ /* perform SSL initialization */
+ result = https_connecting(conn, done);
+ if(result)
+ return result;
+ }
+ else
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+ interface and then we're always _sending_ a request and thus we wait for
+ the single socket to become writable only */
+static int http_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ /* write mode */
+ (void)numsocks; /* unused, we trust it to be at least 1 */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+}
+
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+ DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL));
+
+ /* perform SSL initialization for this socket */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
+ if(result)
+ connclose(conn, "Failed HTTPS connection");
+
+ return result;
+}
+
+static int https_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn->handler->flags & PROTOPT_SSL)
+ return Curl_ssl_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+#endif /* USE_SSL */
+
+/*
+ * Curl_http_done() gets called after a single HTTP request has been
+ * performed.
+ */
+
+CURLcode Curl_http_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct Curl_easy *data = conn->data;
+ struct HTTP *http = data->req.protop;
+
+ /* Clear multipass flag. If authentication isn't done yet, then it will get
+ * a chance to be set back to true when we output the next auth header */
+ data->state.authhost.multipass = FALSE;
+ data->state.authproxy.multipass = FALSE;
+
+ Curl_unencode_cleanup(conn);
+
+#ifdef USE_SPNEGO
+ if(data->state.proxyneg.state == GSS_AUTHSENT ||
+ data->state.negotiate.state == GSS_AUTHSENT) {
+ /* add forbid re-use if http-code != 401/407 as a WA only needed for
+ * 401/407 that signal auth failure (empty) otherwise state will be RECV
+ * with current code.
+ * Do not close CONNECT_ONLY connections. */
+ if((data->req.httpcode != 401) && (data->req.httpcode != 407) &&
+ !data->set.connect_only)
+ streamclose(conn, "Negotiate transfer completed");
+ Curl_cleanup_negotiate(data);
+ }
+#endif
+
+ /* set the proper values (possibly modified on POST) */
+ conn->seek_func = data->set.seek_func; /* restore */
+ conn->seek_client = data->set.seek_client; /* restore */
+
+ if(!http)
+ return CURLE_OK;
+
+ if(http->send_buffer) {
+ Curl_add_buffer_free(http->send_buffer);
+ http->send_buffer = NULL; /* clear the pointer */
+ }
+
+ Curl_http2_done(conn, premature);
+
+ if(HTTPREQ_POST_FORM == data->set.httpreq) {
+ data->req.bytecount = http->readbytecount + http->writebytecount;
+
+ Curl_formclean(&http->sendit); /* Now free that whole lot */
+ if(http->form.fp) {
+ /* a file being uploaded was left opened, close it! */
+ fclose(http->form.fp);
+ http->form.fp = NULL;
+ }
+ }
+ else if(HTTPREQ_PUT == data->set.httpreq)
+ data->req.bytecount = http->readbytecount + http->writebytecount;
+
+ if(status)
+ return status;
+
+ if(!premature && /* this check is pointless when DONE is called before the
+ entire operation is complete */
+ !conn->bits.retry &&
+ !data->set.connect_only &&
+ (http->readbytecount +
+ data->req.headerbytecount -
+ data->req.deductheadercount) <= 0) {
+ /* If this connection isn't simply closed to be retried, AND nothing was
+ read from the HTTP server (that counts), this can't be right so we
+ return an error here */
+ failf(data, "Empty reply from server");
+ return CURLE_GOT_NOTHING;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Determine if we should use HTTP 1.1 (OR BETTER) for this request. Reasons
+ * to avoid it include:
+ *
+ * - if the user specifically requested HTTP 1.0
+ * - if the server we are connected to only supports 1.0
+ * - if any server previously contacted to handle this request only supports
+ * 1.0.
+ */
+static bool use_http_1_1plus(const struct Curl_easy *data,
+ const struct connectdata *conn)
+{
+ if((data->state.httpversion == 10) || (conn->httpversion == 10))
+ return FALSE;
+ if((data->set.httpversion == CURL_HTTP_VERSION_1_0) &&
+ (conn->httpversion <= 10))
+ return FALSE;
+ return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) ||
+ (data->set.httpversion >= CURL_HTTP_VERSION_1_1));
+}
+
+static const char *get_http_string(const struct Curl_easy *data,
+ const struct connectdata *conn)
+{
+#ifdef USE_NGHTTP2
+ if(conn->proto.httpc.h2)
+ return "2";
+#endif
+
+ if(use_http_1_1plus(data, conn))
+ return "1.1";
+
+ return "1.0";
+}
+
+/* check and possibly add an Expect: header */
+static CURLcode expect100(struct Curl_easy *data,
+ struct connectdata *conn,
+ Curl_send_buffer *req_buffer)
+{
+ CURLcode result = CURLE_OK;
+ const char *ptr;
+ data->state.expect100header = FALSE; /* default to false unless it is set
+ to TRUE below */
+ if(use_http_1_1plus(data, conn) &&
+ (conn->httpversion != 20)) {
+ /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
+ Expect: 100-continue to the headers which actually speeds up post
+ operations (as there is one packet coming back from the web server) */
+ ptr = Curl_checkheaders(conn, "Expect:");
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, "Expect:", "100-continue");
+ }
+ else {
+ result = Curl_add_bufferf(req_buffer,
+ "Expect: 100-continue\r\n");
+ if(!result)
+ data->state.expect100header = TRUE;
+ }
+ }
+
+ return result;
+}
+
+enum proxy_use {
+ HEADER_SERVER, /* direct to server */
+ HEADER_PROXY, /* regular request to proxy */
+ HEADER_CONNECT /* sending CONNECT to a proxy */
+};
+
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+ bool is_connect,
+ Curl_send_buffer *req_buffer)
+{
+ char *ptr;
+ struct curl_slist *h[2];
+ struct curl_slist *headers;
+ int numlists=1; /* by default */
+ struct Curl_easy *data = conn->data;
+ int i;
+
+ enum proxy_use proxy;
+
+ if(is_connect)
+ proxy = HEADER_CONNECT;
+ else
+ proxy = conn->bits.httpproxy && !conn->bits.tunnel_proxy?
+ HEADER_PROXY:HEADER_SERVER;
+
+ switch(proxy) {
+ case HEADER_SERVER:
+ h[0] = data->set.headers;
+ break;
+ case HEADER_PROXY:
+ h[0] = data->set.headers;
+ if(data->set.sep_headers) {
+ h[1] = data->set.proxyheaders;
+ numlists++;
+ }
+ break;
+ case HEADER_CONNECT:
+ if(data->set.sep_headers)
+ h[0] = data->set.proxyheaders;
+ else
+ h[0] = data->set.headers;
+ break;
+ }
+
+ /* loop through one or two lists */
+ for(i=0; i < numlists; i++) {
+ headers = h[i];
+
+ while(headers) {
+ ptr = strchr(headers->data, ':');
+ if(ptr) {
+ /* we require a colon for this to be a true header */
+
+ ptr++; /* pass the colon */
+ while(*ptr && ISSPACE(*ptr))
+ ptr++;
+
+ if(*ptr) {
+ /* only send this if the contents was non-blank */
+
+ if(conn->allocptr.host &&
+ /* a Host: header was sent already, don't pass on any custom Host:
+ header as that will produce *two* in the same request! */
+ checkprefix("Host:", headers->data))
+ ;
+ else if(data->set.httpreq == HTTPREQ_POST_FORM &&
+ /* this header (extended by formdata.c) is sent later */
+ checkprefix("Content-Type:", headers->data))
+ ;
+ else if(conn->bits.authneg &&
+ /* while doing auth neg, don't allow the custom length since
+ we will force length zero then */
+ checkprefix("Content-Length", headers->data))
+ ;
+ else if(conn->allocptr.te &&
+ /* when asking for Transfer-Encoding, don't pass on a custom
+ Connection: */
+ checkprefix("Connection", headers->data))
+ ;
+ else if((conn->httpversion == 20) &&
+ checkprefix("Transfer-Encoding:", headers->data))
+ /* HTTP/2 doesn't support chunked requests */
+ ;
+ else {
+ CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n",
+ headers->data);
+ if(result)
+ return result;
+ }
+ }
+ }
+ else {
+ ptr = strchr(headers->data, ';');
+ if(ptr) {
+
+ ptr++; /* pass the semicolon */
+ while(*ptr && ISSPACE(*ptr))
+ ptr++;
+
+ if(*ptr) {
+ /* this may be used for something else in the future */
+ }
+ else {
+ if(*(--ptr) == ';') {
+ CURLcode result;
+
+ /* send no-value custom header if terminated by semicolon */
+ *ptr = ':';
+ result = Curl_add_bufferf(req_buffer, "%s\r\n",
+ headers->data);
+ if(result)
+ return result;
+ }
+ }
+ }
+ }
+ headers = headers->next;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+ Curl_send_buffer *req_buffer)
+{
+ const struct tm *tm;
+ struct tm keeptime;
+ CURLcode result;
+ char datestr[80];
+ const char *condp;
+
+ if(data->set.timecondition == CURL_TIMECOND_NONE)
+ /* no condition was asked for */
+ return CURLE_OK;
+
+ result = Curl_gmtime(data->set.timevalue, &keeptime);
+ if(result) {
+ failf(data, "Invalid TIMEVALUE");
+ return result;
+ }
+ tm = &keeptime;
+
+ switch(data->set.timecondition) {
+ default:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ case CURL_TIMECOND_IFMODSINCE:
+ condp = "If-Modified-Since";
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ condp = "If-Unmodified-Since";
+ break;
+ case CURL_TIMECOND_LASTMOD:
+ condp = "Last-Modified";
+ break;
+ }
+
+ /* The If-Modified-Since header family should have their times set in
+ * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
+ * represented in Greenwich Mean Time (GMT), without exception. For the
+ * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
+ * Time)." (see page 20 of RFC2616).
+ */
+
+ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+ snprintf(datestr, sizeof(datestr),
+ "%s: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ condp,
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+
+ result = Curl_add_buffer(req_buffer, datestr, strlen(datestr));
+
+ return result;
+}
+
+/*
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct connectdata *conn, bool *done)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_OK;
+ struct HTTP *http;
+ const char *ppath = data->state.path;
+ bool paste_ftp_userpwd = FALSE;
+ char ftp_typecode[sizeof("/;type=?")] = "";
+ const char *host = conn->host.name;
+ const char *te = ""; /* transfer-encoding */
+ const char *ptr;
+ const char *request;
+ Curl_HttpReq httpreq = data->set.httpreq;
+#if !defined(CURL_DISABLE_COOKIES)
+ char *addcookies = NULL;
+#endif
+ curl_off_t included_body = 0;
+ const char *httpstring;
+ Curl_send_buffer *req_buffer;
+ curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
+ int seekerr = CURL_SEEKFUNC_OK;
+
+ /* Always consider the DO phase done after this function call, even if there
+ may be parts of the request that is not yet sent, since we can deal with
+ the rest of the request in the PERFORM phase. */
+ *done = TRUE;
+
+ if(conn->httpversion < 20) { /* unless the connection is re-used and already
+ http2 */
+ switch(conn->negnpn) {
+ case CURL_HTTP_VERSION_2:
+ conn->httpversion = 20; /* we know we're on HTTP/2 now */
+
+ result = Curl_http2_switched(conn, NULL, 0);
+ if(result)
+ return result;
+ break;
+ case CURL_HTTP_VERSION_1_1:
+ /* continue with HTTP/1.1 when explicitly requested */
+ break;
+ default:
+ /* Check if user wants to use HTTP/2 with clear TCP*/
+#ifdef USE_NGHTTP2
+ if(conn->data->set.httpversion ==
+ CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+ DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
+ conn->httpversion = 20;
+
+ result = Curl_http2_switched(conn, NULL, 0);
+ if(result)
+ return result;
+ }
+#endif
+ break;
+ }
+ }
+ else {
+ /* prepare for a http2 request */
+ result = Curl_http2_setup(conn);
+ if(result)
+ return result;
+ }
+
+ http = data->req.protop;
+
+ if(!data->state.this_is_a_follow) {
+ /* Free to avoid leaking memory on multiple requests*/
+ free(data->state.first_host);
+
+ data->state.first_host = strdup(conn->host.name);
+ if(!data->state.first_host)
+ return CURLE_OUT_OF_MEMORY;
+
+ data->state.first_remote_port = conn->remote_port;
+ }
+ http->writebytecount = http->readbytecount = 0;
+
+ if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) &&
+ data->set.upload) {
+ httpreq = HTTPREQ_PUT;
+ }
+
+ /* Now set the 'request' pointer to the proper request string */
+ if(data->set.str[STRING_CUSTOMREQUEST])
+ request = data->set.str[STRING_CUSTOMREQUEST];
+ else {
+ if(data->set.opt_no_body)
+ request = "HEAD";
+ else {
+ DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+ switch(httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ request = "POST";
+ break;
+ case HTTPREQ_PUT:
+ request = "PUT";
+ break;
+ default: /* this should never happen */
+ case HTTPREQ_GET:
+ request = "GET";
+ break;
+ case HTTPREQ_HEAD:
+ request = "HEAD";
+ break;
+ }
+ }
+ }
+
+ /* The User-Agent string might have been allocated in url.c already, because
+ it might have been used in the proxy connect, but if we have got a header
+ with the user-agent string specified, we erase the previously made string
+ here. */
+ if(Curl_checkheaders(conn, "User-Agent:")) {
+ free(conn->allocptr.uagent);
+ conn->allocptr.uagent=NULL;
+ }
+
+ /* setup the authentication headers */
+ result = Curl_http_output_auth(conn, request, ppath, FALSE);
+ if(result)
+ return result;
+
+ if((data->state.authhost.multipass || data->state.authproxy.multipass) &&
+ (httpreq != HTTPREQ_GET) &&
+ (httpreq != HTTPREQ_HEAD)) {
+ /* Auth is required and we are not authenticated yet. Make a PUT or POST
+ with content-length zero as a "probe". */
+ conn->bits.authneg = TRUE;
+ }
+ else
+ conn->bits.authneg = FALSE;
+
+ Curl_safefree(conn->allocptr.ref);
+ if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) {
+ conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ if(!conn->allocptr.ref)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else
+ conn->allocptr.ref = NULL;
+
+#if !defined(CURL_DISABLE_COOKIES)
+ if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:"))
+ addcookies = data->set.str[STRING_COOKIE];
+#endif
+
+ if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
+ data->set.str[STRING_ENCODING]) {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding =
+ aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+ if(!conn->allocptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding = NULL;
+ }
+
+#ifdef HAVE_LIBZ
+ /* we only consider transfer-encoding magic if libz support is built-in */
+
+ if(!Curl_checkheaders(conn, "TE:") &&
+ data->set.http_transfer_encoding) {
+ /* When we are to insert a TE: header in the request, we must also insert
+ TE in a Connection: header, so we need to merge the custom provided
+ Connection: header and prevent the original to get sent. Note that if
+ the user has inserted his/hers own TE: header we don't do this magic
+ but then assume that the user will handle it all! */
+ char *cptr = Curl_checkheaders(conn, "Connection:");
+#define TE_HEADER "TE: gzip\r\n"
+
+ Curl_safefree(conn->allocptr.te);
+
+ /* Create the (updated) Connection: header */
+ conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr):
+ strdup("Connection: TE\r\n" TE_HEADER);
+
+ if(!conn->allocptr.te)
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif
+
+ ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
+ if(ptr) {
+ /* Some kind of TE is requested, check if 'chunked' is chosen */
+ data->req.upload_chunky =
+ Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+ }
+ else {
+ if((conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ data->set.upload &&
+ (data->state.infilesize == -1)) {
+ if(conn->bits.authneg)
+ /* don't enable chunked during auth neg */
+ ;
+ else if(use_http_1_1plus(data, conn)) {
+ /* HTTP, upload, unknown file size and not HTTP 1.0 */
+ data->req.upload_chunky = TRUE;
+ }
+ else {
+ failf(data, "Chunky upload is not supported by HTTP 1.0");
+ return CURLE_UPLOAD_FAILED;
+ }
+ }
+ else {
+ /* else, no chunky upload */
+ data->req.upload_chunky = FALSE;
+ }
+
+ if(data->req.upload_chunky)
+ te = "Transfer-Encoding: chunked\r\n";
+ }
+
+ Curl_safefree(conn->allocptr.host);
+
+ ptr = Curl_checkheaders(conn, "Host:");
+ if(ptr && (!data->state.this_is_a_follow ||
+ strcasecompare(data->state.first_host, conn->host.name))) {
+#if !defined(CURL_DISABLE_COOKIES)
+ /* If we have a given custom Host: header, we extract the host name in
+ order to possibly use it for cookie reasons later on. We only allow the
+ custom Host: header if this is NOT a redirect, as setting Host: in the
+ redirected request is being out on thin ice. Except if the host name
+ is the same as the first one! */
+ char *cookiehost = Curl_copy_header_value(ptr);
+ if(!cookiehost)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*cookiehost)
+ /* ignore empty data */
+ free(cookiehost);
+ else {
+ /* If the host begins with '[', we start searching for the port after
+ the bracket has been closed */
+ int startsearch = 0;
+ if(*cookiehost == '[') {
+ char *closingbracket;
+ /* since the 'cookiehost' is an allocated memory area that will be
+ freed later we cannot simply increment the pointer */
+ memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
+ closingbracket = strchr(cookiehost, ']');
+ if(closingbracket)
+ *closingbracket = 0;
+ }
+ else {
+ char *colon = strchr(cookiehost + startsearch, ':');
+ if(colon)
+ *colon = 0; /* The host must not include an embedded port number */
+ }
+ Curl_safefree(conn->allocptr.cookiehost);
+ conn->allocptr.cookiehost = cookiehost;
+ }
+#endif
+
+ if(strcmp("Host:", ptr)) {
+ conn->allocptr.host = aprintf("%s\r\n", ptr);
+ if(!conn->allocptr.host)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else
+ /* when clearing the header */
+ conn->allocptr.host = NULL;
+ }
+ else {
+ /* When building Host: headers, we must put the host name within
+ [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+
+ if(((conn->given->protocol&CURLPROTO_HTTPS) &&
+ (conn->remote_port == PORT_HTTPS)) ||
+ ((conn->given->protocol&CURLPROTO_HTTP) &&
+ (conn->remote_port == PORT_HTTP)) )
+ /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
+ the port number in the host string */
+ conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
+ conn->bits.ipv6_ip?"[":"",
+ host,
+ conn->bits.ipv6_ip?"]":"");
+ else
+ conn->allocptr.host = aprintf("Host: %s%s%s:%hu\r\n",
+ conn->bits.ipv6_ip?"[":"",
+ host,
+ conn->bits.ipv6_ip?"]":"",
+ conn->remote_port);
+
+ if(!conn->allocptr.host)
+ /* without Host: we can't make a nice request */
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+ /* Using a proxy but does not tunnel through it */
+
+ /* The path sent to the proxy is in fact the entire URL. But if the remote
+ host is a IDN-name, we must make sure that the request we produce only
+ uses the encoded host name! */
+ if(conn->host.dispname != conn->host.name) {
+ char *url = data->change.url;
+ ptr = strstr(url, conn->host.dispname);
+ if(ptr) {
+ /* This is where the display name starts in the URL, now replace this
+ part with the encoded name. TODO: This method of replacing the host
+ name is rather crude as I believe there's a slight risk that the
+ user has entered a user name or password that contain the host name
+ string. */
+ size_t currlen = strlen(conn->host.dispname);
+ size_t newlen = strlen(conn->host.name);
+ size_t urllen = strlen(url);
+
+ char *newurl;
+
+ newurl = malloc(urllen + newlen - currlen + 1);
+ if(newurl) {
+ /* copy the part before the host name */
+ memcpy(newurl, url, ptr - url);
+ /* append the new host name instead of the old */
+ memcpy(newurl + (ptr - url), conn->host.name, newlen);
+ /* append the piece after the host name */
+ memcpy(newurl + newlen + (ptr - url),
+ ptr + currlen, /* copy the trailing zero byte too */
+ urllen - (ptr-url) - currlen + 1);
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
+ }
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ ppath = data->change.url;
+ if(checkprefix("ftp://", ppath)) {
+ if(data->set.proxy_transfer_mode) {
+ /* when doing ftp, append ;type=<a|i> if not present */
+ char *type = strstr(ppath, ";type=");
+ if(type && type[6] && type[7] == 0) {
+ switch(Curl_raw_toupper(type[6])) {
+ case 'A':
+ case 'D':
+ case 'I':
+ break;
+ default:
+ type = NULL;
+ }
+ }
+ if(!type) {
+ char *p = ftp_typecode;
+ /* avoid sending invalid URLs like ftp://example.com;type=i if the
+ * user specified ftp://example.com without the slash */
+ if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
+ *p++ = '/';
+ }
+ snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
+ data->set.prefer_ascii ? 'a' : 'i');
+ }
+ }
+ if(conn->bits.user_passwd && !conn->bits.userpwd_in_url)
+ paste_ftp_userpwd = TRUE;
+ }
+ }
+#endif /* CURL_DISABLE_PROXY */
+
+ if(HTTPREQ_POST_FORM == httpreq) {
+ /* we must build the whole post sequence first, so that we have a size of
+ the whole transfer before we start to send it */
+ result = Curl_getformdata(data, &http->sendit, data->set.httppost,
+ Curl_checkheaders(conn, "Content-Type:"),
+ &http->postsize);
+ if(result)
+ return result;
+ }
+
+ http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n";
+
+ if(( (HTTPREQ_POST == httpreq) ||
+ (HTTPREQ_POST_FORM == httpreq) ||
+ (HTTPREQ_PUT == httpreq) ) &&
+ data->state.resume_from) {
+ /**********************************************************************
+ * Resuming upload in HTTP means that we PUT or POST and that we have
+ * got a resume_from value set. The resume value has already created
+ * a Range: header that will be passed along. We need to "fast forward"
+ * the file the given number of bytes and decrease the assume upload
+ * file size before we continue this venture in the dark lands of HTTP.
+ *********************************************************************/
+
+ if(data->state.resume_from < 0) {
+ /*
+ * This is meant to get the size of the present remote-file by itself.
+ * We don't support this now. Bail out!
+ */
+ data->state.resume_from = 0;
+ }
+
+ if(data->state.resume_from && !data->state.this_is_a_follow) {
+ /* do we still game? */
+
+ /* Now, let's read off the proper amount of bytes from the
+ input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ curl_off_t passed=0;
+
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_READ_ERROR;
+ }
+ /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->state.fread_func(data->state.buffer, 1, readthisamountnow,
+ data->state.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Could only read %" CURL_FORMAT_CURL_OFF_T
+ " bytes from the input", passed);
+ return CURLE_READ_ERROR;
+ }
+ } while(passed < data->state.resume_from);
+ }
+
+ /* now, decrease the size of the read */
+ if(data->state.infilesize>0) {
+ data->state.infilesize -= data->state.resume_from;
+
+ if(data->state.infilesize <= 0) {
+ failf(data, "File already completely uploaded");
+ return CURLE_PARTIAL_FILE;
+ }
+ }
+ /* we've passed, proceed as normal */
+ }
+ }
+ if(data->state.use_range) {
+ /*
+ * A range is selected. We use different headers whether we're downloading
+ * or uploading and we always let customized headers override our internal
+ * ones if any such are specified.
+ */
+ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
+ !Curl_checkheaders(conn, "Range:")) {
+ /* if a line like this was already allocated, free the previous one */
+ free(conn->allocptr.rangeline);
+ conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
+ data->state.range);
+ }
+ else if((httpreq != HTTPREQ_GET) &&
+ !Curl_checkheaders(conn, "Content-Range:")) {
+
+ /* if a line like this was already allocated, free the previous one */
+ free(conn->allocptr.rangeline);
+
+ if(data->set.set_resume_from < 0) {
+ /* Upload resume was asked for, but we don't know the size of the
+ remote part so we tell the server (and act accordingly) that we
+ upload the whole file (again) */
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.infilesize - 1, data->state.infilesize);
+
+ }
+ else if(data->state.resume_from) {
+ /* This is because "resume" was selected */
+ curl_off_t total_expected_size=
+ data->state.resume_from + data->state.infilesize;
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
+ "/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.range, total_expected_size-1,
+ total_expected_size);
+ }
+ else {
+ /* Range was selected and then we just pass the incoming range and
+ append total size */
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
+ data->state.range, data->state.infilesize);
+ }
+ if(!conn->allocptr.rangeline)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ httpstring = get_http_string(data, conn);
+
+ /* initialize a dynamic send-buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* add the main request stuff */
+ /* GET/HEAD/POST/PUT */
+ result = Curl_add_bufferf(req_buffer, "%s ", request);
+ if(result)
+ return result;
+
+ /* url */
+ if(paste_ftp_userpwd)
+ result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
+ conn->user, conn->passwd,
+ ppath + sizeof("ftp://") - 1);
+ else
+ result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
+ if(result)
+ return result;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "%s" /* ftp typecode (;type=x) */
+ " HTTP/%s\r\n" /* HTTP version */
+ "%s" /* host */
+ "%s" /* proxyuserpwd */
+ "%s" /* userpwd */
+ "%s" /* range */
+ "%s" /* user agent */
+ "%s" /* accept */
+ "%s" /* TE: */
+ "%s" /* accept-encoding */
+ "%s" /* referer */
+ "%s" /* Proxy-Connection */
+ "%s",/* transfer-encoding */
+
+ ftp_typecode,
+ httpstring,
+ (conn->allocptr.host?conn->allocptr.host:""),
+ conn->allocptr.proxyuserpwd?
+ conn->allocptr.proxyuserpwd:"",
+ conn->allocptr.userpwd?conn->allocptr.userpwd:"",
+ (data->state.use_range && conn->allocptr.rangeline)?
+ conn->allocptr.rangeline:"",
+ (data->set.str[STRING_USERAGENT] &&
+ *data->set.str[STRING_USERAGENT] &&
+ conn->allocptr.uagent)?
+ conn->allocptr.uagent:"",
+ http->p_accept?http->p_accept:"",
+ conn->allocptr.te?conn->allocptr.te:"",
+ (data->set.str[STRING_ENCODING] &&
+ *data->set.str[STRING_ENCODING] &&
+ conn->allocptr.accept_encoding)?
+ conn->allocptr.accept_encoding:"",
+ (data->change.referer && conn->allocptr.ref)?
+ conn->allocptr.ref:"" /* Referer: <data> */,
+ (conn->bits.httpproxy &&
+ !conn->bits.tunnel_proxy &&
+ !Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
+ "Proxy-Connection: Keep-Alive\r\n":"",
+ te
+ );
+
+ /* clear userpwd and proxyuserpwd to avoid re-using old credentials
+ * from re-used connections */
+ Curl_safefree(conn->allocptr.userpwd);
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+
+ if(result)
+ return result;
+
+ if(!(conn->handler->flags&PROTOPT_SSL) &&
+ conn->httpversion != 20 &&
+ (data->set.httpversion == CURL_HTTP_VERSION_2)) {
+ /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
+ over SSL */
+ result = Curl_http2_request_upgrade(req_buffer, conn);
+ if(result)
+ return result;
+ }
+
+#if !defined(CURL_DISABLE_COOKIES)
+ if(data->cookies || addcookies) {
+ struct Cookie *co=NULL; /* no cookies from start */
+ int count=0;
+
+ if(data->cookies) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ co = Curl_cookie_getlist(data->cookies,
+ conn->allocptr.cookiehost?
+ conn->allocptr.cookiehost:host,
+ data->state.path,
+ (conn->handler->protocol&CURLPROTO_HTTPS)?
+ TRUE:FALSE);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ if(co) {
+ struct Cookie *store=co;
+ /* now loop through all cookies that matched */
+ while(co) {
+ if(co->value) {
+ if(0 == count) {
+ result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ if(result)
+ break;
+ }
+ result = Curl_add_bufferf(req_buffer,
+ "%s%s=%s", count?"; ":"",
+ co->name, co->value);
+ if(result)
+ break;
+ count++;
+ }
+ co = co->next; /* next cookie please */
+ }
+ Curl_cookie_freelist(store);
+ }
+ if(addcookies && !result) {
+ if(!count)
+ result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ if(!result) {
+ result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"",
+ addcookies);
+ count++;
+ }
+ }
+ if(count && !result)
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+
+ if(result)
+ return result;
+ }
+#endif
+
+ result = Curl_add_timecondition(data, req_buffer);
+ if(result)
+ return result;
+
+ result = Curl_add_custom_headers(conn, FALSE, req_buffer);
+ if(result)
+ return result;
+
+ http->postdata = NULL; /* nothing to post at this point */
+ Curl_pgrsSetUploadSize(data, -1); /* upload size is unknown atm */
+
+ /* If 'authdone' is FALSE, we must not set the write socket index to the
+ Curl_transfer() call below, as we're not ready to actually upload any
+ data yet. */
+
+ switch(httpreq) {
+
+ case HTTPREQ_POST_FORM:
+ if(!http->sendit || conn->bits.authneg) {
+ /* nothing to post! */
+ result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+ if(result)
+ return result;
+
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ -1, NULL);
+ break;
+ }
+
+ if(Curl_FormInit(&http->form, http->sendit)) {
+ failf(data, "Internal HTTP POST error!");
+ return CURLE_HTTP_POST_ERROR;
+ }
+
+ /* Get the currently set callback function pointer and store that in the
+ form struct since we might want the actual user-provided callback later
+ on. The data->set.fread_func pointer itself will be changed for the
+ multipart case to the function that returns a multipart formatted
+ stream. */
+ http->form.fread_func = data->state.fread_func;
+
+ /* Set the read function to read from the generated form data */
+ data->state.fread_func = (curl_read_callback)Curl_FormReader;
+ data->state.in = &http->form;
+
+ http->sending = HTTPSEND_BODY;
+
+ if(!data->req.upload_chunky &&
+ !Curl_checkheaders(conn, "Content-Length:")) {
+ /* only add Content-Length if not uploading chunked */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", http->postsize);
+ if(result)
+ return result;
+ }
+
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+
+ {
+
+ /* Get Content-Type: line from Curl_formpostheader.
+ */
+ char *contentType;
+ size_t linelength=0;
+ contentType = Curl_formpostheader((void *)&http->form,
+ &linelength);
+ if(!contentType) {
+ failf(data, "Could not get Content-Type header line!");
+ return CURLE_HTTP_POST_ERROR;
+ }
+
+ result = Curl_add_buffer(req_buffer, contentType, linelength);
+ if(result)
+ return result;
+ }
+
+ /* make the request end in a true CRLF */
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ /* set upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ /* fire away the whole request to the server */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, FIRSTSOCKET,
+ &http->writebytecount);
+
+ if(result) {
+ Curl_formclean(&http->sendit); /* free that whole lot */
+ return result;
+ }
+
+ /* convert the form data */
+ result = Curl_convert_form(data, http->sendit);
+ if(result) {
+ Curl_formclean(&http->sendit); /* free that whole lot */
+ return result;
+ }
+
+ break;
+
+ case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+ if(conn->bits.authneg)
+ postsize = 0;
+ else
+ postsize = data->state.infilesize;
+
+ if((postsize != -1) && !data->req.upload_chunky &&
+ (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
+ /* only add Content-Length if not uploading chunked */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", postsize);
+ if(result)
+ return result;
+ }
+
+ if(postsize != 0) {
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+ }
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+ if(result)
+ return result;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, postsize);
+
+ /* this sends the buffer and frees all the buffer resources */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending PUT request");
+ else
+ /* prepare for transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, postsize?FIRSTSOCKET:-1,
+ postsize?&http->writebytecount:NULL);
+ if(result)
+ return result;
+ break;
+
+ case HTTPREQ_POST:
+ /* this is the simple POST, using x-www-form-urlencoded style */
+
+ if(conn->bits.authneg)
+ postsize = 0;
+ else
+ /* the size of the post body */
+ postsize = data->state.infilesize;
+
+ /* We only set Content-Length and allow a custom Content-Length if
+ we don't upload data chunked, as RFC2616 forbids us to set both
+ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+ if((postsize != -1) && !data->req.upload_chunky &&
+ (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) {
+ /* we allow replacing this header if not during auth negotiation,
+ although it isn't very wise to actually set your own */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", postsize);
+ if(result)
+ return result;
+ }
+
+ if(!Curl_checkheaders(conn, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: application/"
+ "x-www-form-urlencoded\r\n");
+ if(result)
+ return result;
+ }
+
+ /* For really small posts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ ptr = Curl_checkheaders(conn, "Expect:");
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, "Expect:", "100-continue");
+ }
+ else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) {
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+ }
+ else
+ data->state.expect100header = FALSE;
+
+ if(data->set.postfields) {
+
+ /* In HTTP2, we send request body in DATA frame regardless of
+ its size. */
+ if(conn->httpversion != 20 &&
+ !data->state.expect100header &&
+ (postsize < MAX_INITIAL_POST_SIZE)) {
+ /* if we don't use expect: 100 AND
+ postsize is less than MAX_INITIAL_POST_SIZE
+
+ then append the post data to the HTTP request header. This limit
+ is no magic limit but only set to prevent really huge POSTs to
+ get the data duplicated with malloc() and family. */
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+
+ if(!data->req.upload_chunky) {
+ /* We're not sending it 'chunked', append it to the request
+ already now to reduce the number if send() calls */
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ included_body = postsize;
+ }
+ else {
+ if(postsize) {
+ /* Append the POST data chunky-style */
+ result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+ if(!result) {
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(!result)
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ included_body = postsize + 2;
+ }
+ }
+ if(!result)
+ result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
+ /* 0 CR LF CR LF */
+ included_body += 5;
+ }
+ if(result)
+ return result;
+ /* Make sure the progress information is accurate */
+ Curl_pgrsSetUploadSize(data, postsize);
+ }
+ else {
+ /* A huge POST coming up, do data separate from the request */
+ http->postsize = postsize;
+ http->postdata = data->set.postfields;
+
+ http->sending = HTTPSEND_BODY;
+
+ data->state.fread_func = (curl_read_callback)readmoredata;
+ data->state.in = (void *)conn;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+ }
+ }
+ else {
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ /* Chunky upload is selected and we're negotiating auth still, send
+ end-of-data only */
+ result = Curl_add_buffer(req_buffer,
+ "\x30\x0d\x0a\x0d\x0a", 5);
+ /* 0 CR LF CR LF */
+ if(result)
+ return result;
+ }
+
+ else if(data->state.infilesize) {
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
+
+ /* set the pointer to mark that we will send the post body using the
+ read callback, but only if we're not in authenticate
+ negotiation */
+ if(!conn->bits.authneg) {
+ http->postdata = (char *)&http->postdata;
+ http->postsize = postsize;
+ }
+ }
+ }
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
+ (size_t)included_body, FIRSTSOCKET);
+
+ if(result)
+ failf(data, "Failed sending HTTP POST request");
+ else
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, http->postdata?FIRSTSOCKET:-1,
+ http->postdata?&http->writebytecount:NULL);
+ break;
+
+ default:
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+
+ if(result)
+ failf(data, "Failed sending HTTP request");
+ else
+ /* HTTP GET/HEAD download: */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ http->postdata?FIRSTSOCKET:-1,
+ http->postdata?&http->writebytecount:NULL);
+ }
+ if(result)
+ return result;
+
+ if(http->writebytecount) {
+ /* if a request-body has been sent off, we make sure this progress is noted
+ properly */
+ Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ if(http->writebytecount >= postsize) {
+ /* already sent the entire request body, mark the "upload" as
+ complete */
+ infof(data, "upload completely sent off: %" CURL_FORMAT_CURL_OFF_T
+ " out of %" CURL_FORMAT_CURL_OFF_T " bytes\n",
+ http->writebytecount, postsize);
+ data->req.upload_done = TRUE;
+ data->req.keepon &= ~KEEP_SEND; /* we're done writing */
+ data->req.exp100 = EXP100_SEND_DATA; /* already sent */
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ }
+ }
+
+ if((conn->httpversion == 20) && data->req.upload_chunky)
+ /* upload_chunky was set above to set up the request in a chunky fashion,
+ but is disabled here again to avoid that the chunked encoded version is
+ actually used when sending the request body over h2 */
+ data->req.upload_chunky = FALSE;
+ return result;
+}
+
+/*
+ * checkhttpprefix()
+ *
+ * Returns TRUE if member of the list matches prefix of string
+ */
+static bool
+checkhttpprefix(struct Curl_easy *data,
+ const char *s)
+{
+ struct curl_slist *head = data->set.http200aliases;
+ bool rc = FALSE;
+#ifdef CURL_DOES_CONVERSIONS
+ /* convert from the network encoding using a scratch area */
+ char *scratch = strdup(s);
+ if(NULL == scratch) {
+ failf(data, "Failed to allocate memory for conversion!");
+ return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+ }
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(scratch);
+ return FALSE; /* can't return CURLE_foobar so return FALSE */
+ }
+ s = scratch;
+#endif /* CURL_DOES_CONVERSIONS */
+
+ while(head) {
+ if(checkprefix(head->data, s)) {
+ rc = TRUE;
+ break;
+ }
+ head = head->next;
+ }
+
+ if(!rc && (checkprefix("HTTP/", s)))
+ rc = TRUE;
+
+#ifdef CURL_DOES_CONVERSIONS
+ free(scratch);
+#endif /* CURL_DOES_CONVERSIONS */
+ return rc;
+}
+
+#ifndef CURL_DISABLE_RTSP
+static bool
+checkrtspprefix(struct Curl_easy *data,
+ const char *s)
+{
+
+#ifdef CURL_DOES_CONVERSIONS
+ /* convert from the network encoding using a scratch area */
+ char *scratch = strdup(s);
+ if(NULL == scratch) {
+ failf(data, "Failed to allocate memory for conversion!");
+ return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+ }
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(scratch);
+ return FALSE; /* can't return CURLE_foobar so return FALSE */
+ }
+ s = scratch;
+#else
+ (void)data; /* unused */
+#endif /* CURL_DOES_CONVERSIONS */
+ if(checkprefix("RTSP/", s))
+ return TRUE;
+ return FALSE;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static bool
+checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
+ const char *s)
+{
+#ifndef CURL_DISABLE_RTSP
+ if(conn->handler->protocol & CURLPROTO_RTSP)
+ return checkrtspprefix(data, s);
+#else
+ (void)conn;
+#endif /* CURL_DISABLE_RTSP */
+
+ return checkhttpprefix(data, s);
+}
+
+/*
+ * header_append() copies a chunk of data to the end of the already received
+ * header. We make sure that the full string fit in the allocated header
+ * buffer, or else we enlarge it.
+ */
+static CURLcode header_append(struct Curl_easy *data,
+ struct SingleRequest *k,
+ size_t length)
+{
+ if(k->hbuflen + length >= data->state.headersize) {
+ /* We enlarge the header buffer as it is too small */
+ char *newbuff;
+ size_t hbufp_index;
+ size_t newsize;
+
+ if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) {
+ /* The reason to have a max limit for this is to avoid the risk of a bad
+ server feeding libcurl with a never-ending header that will cause
+ reallocs infinitely */
+ failf(data, "Avoided giant realloc for header (max is %d)!",
+ CURL_MAX_HTTP_HEADER);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
+ hbufp_index = k->hbufp - data->state.headerbuff;
+ newbuff = realloc(data->state.headerbuff, newsize);
+ if(!newbuff) {
+ failf(data, "Failed to alloc memory for big header!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->state.headersize=newsize;
+ data->state.headerbuff = newbuff;
+ k->hbufp = data->state.headerbuff + hbufp_index;
+ }
+ memcpy(k->hbufp, k->str_start, length);
+ k->hbufp += length;
+ k->hbuflen += length;
+ *k->hbufp = 0;
+
+ return CURLE_OK;
+}
+
+static void print_http_error(struct Curl_easy *data)
+{
+ struct SingleRequest *k = &data->req;
+ char *beg = k->p;
+
+ /* make sure that data->req.p points to the HTTP status line */
+ if(!strncmp(beg, "HTTP", 4)) {
+
+ /* skip to HTTP status code */
+ beg = strchr(beg, ' ');
+ if(beg && *++beg) {
+
+ /* find trailing CR */
+ char end_char = '\r';
+ char *end = strchr(beg, end_char);
+ if(!end) {
+ /* try to find LF (workaround for non-compliant HTTP servers) */
+ end_char = '\n';
+ end = strchr(beg, end_char);
+ }
+
+ if(end) {
+ /* temporarily replace CR or LF by NUL and print the error message */
+ *end = '\0';
+ failf(data, "The requested URL returned error: %s", beg);
+
+ /* restore the previously replaced CR or LF */
+ *end = end_char;
+ return;
+ }
+ }
+ }
+
+ /* fall-back to printing the HTTP status code only */
+ failf(data, "The requested URL returned error: %d", k->httpcode);
+}
+
+/*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *stop_reading)
+{
+ CURLcode result;
+ struct SingleRequest *k = &data->req;
+
+ /* header line within buffer loop */
+ do {
+ size_t rest_length;
+ size_t full_length;
+ int writetype;
+
+ /* str_start is start of line within buf */
+ k->str_start = k->str;
+
+ /* data is in network encoding so use 0x0a instead of '\n' */
+ k->end_ptr = memchr(k->str_start, 0x0a, *nread);
+
+ if(!k->end_ptr) {
+ /* Not a complete header line within buffer, append the data to
+ the end of the headerbuff. */
+ result = header_append(data, k, *nread);
+ if(result)
+ return result;
+
+ if(!k->headerline && (k->hbuflen>5)) {
+ /* make a first check that this looks like a protocol header */
+ if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
+ /* this is not the beginning of a protocol first header line */
+ k->header = FALSE;
+ k->badheader = HEADER_ALLBAD;
+ break;
+ }
+ }
+
+ break; /* read more and try again */
+ }
+
+ /* decrease the size of the remaining (supposed) header line */
+ rest_length = (k->end_ptr - k->str)+1;
+ *nread -= (ssize_t)rest_length;
+
+ k->str = k->end_ptr + 1; /* move past new line */
+
+ full_length = k->str - k->str_start;
+
+ result = header_append(data, k, full_length);
+ if(result)
+ return result;
+
+ k->end_ptr = k->hbufp;
+ k->p = data->state.headerbuff;
+
+ /****
+ * We now have a FULL header line that p points to
+ *****/
+
+ if(!k->headerline) {
+ /* the first read header */
+ if((k->hbuflen>5) &&
+ !checkprotoprefix(data, conn, data->state.headerbuff)) {
+ /* this is not the beginning of a protocol first header line */
+ k->header = FALSE;
+ if(*nread)
+ /* since there's more, this is a partial bad header */
+ k->badheader = HEADER_PARTHEADER;
+ else {
+ /* this was all we read so it's all a bad header */
+ k->badheader = HEADER_ALLBAD;
+ *nread = (ssize_t)rest_length;
+ }
+ break;
+ }
+ }
+
+ /* headers are in network encoding so
+ use 0x0a and 0x0d instead of '\n' and '\r' */
+ if((0x0a == *k->p) || (0x0d == *k->p)) {
+ size_t headerlen;
+ /* Zero-length header line means end of headers! */
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(0x0d == *k->p) {
+ *k->p = '\r'; /* replace with CR in host encoding */
+ k->p++; /* pass the CR byte */
+ }
+ if(0x0a == *k->p) {
+ *k->p = '\n'; /* replace with LF in host encoding */
+ k->p++; /* pass the LF byte */
+ }
+#else
+ if('\r' == *k->p)
+ k->p++; /* pass the \r byte */
+ if('\n' == *k->p)
+ k->p++; /* pass the \n byte */
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(100 <= k->httpcode && 199 >= k->httpcode) {
+ /* "A user agent MAY ignore unexpected 1xx status responses." */
+ switch(k->httpcode) {
+ case 100:
+ /*
+ * We have made a HTTP PUT or POST and this is 1.1-lingo
+ * that tells us that the server is OK with this and ready
+ * to receive the data.
+ * However, we'll get more headers now so we must get
+ * back into the header-parsing state!
+ */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
+ /* if we did wait for this do enable write now! */
+ if(k->exp100 > EXP100_SEND_DATA) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ }
+ break;
+ case 101:
+ /* Switching Protocols */
+ if(k->upgr101 == UPGR101_REQUESTED) {
+ /* Switching to HTTP/2 */
+ infof(data, "Received 101\n");
+ k->upgr101 = UPGR101_RECEIVED;
+
+ /* we'll get more headers (HTTP/2 response) */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
+ /* switch to http2 now. The bytes after response headers
+ are also processed here, otherwise they are lost. */
+ result = Curl_http2_switched(conn, k->str, *nread);
+ if(result)
+ return result;
+ *nread = 0;
+ }
+ else {
+ /* Switching to another protocol (e.g. WebSocket) */
+ k->header = FALSE; /* no more header to parse! */
+ }
+ break;
+ default:
+ /* the status code 1xx indicates a provisional response, so
+ we'll get another set of headers */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+ break;
+ }
+ }
+ else {
+ k->header = FALSE; /* no more header to parse! */
+
+ if((k->size == -1) && !k->chunk && !conn->bits.close &&
+ (conn->httpversion == 11) &&
+ !(conn->handler->protocol & CURLPROTO_RTSP) &&
+ data->set.httpreq != HTTPREQ_HEAD) {
+ /* On HTTP 1.1, when connection is not to get closed, but no
+ Content-Length nor Content-Encoding chunked have been
+ received, according to RFC2616 section 4.4 point 5, we
+ assume that the server will close the connection to
+ signal the end of the document. */
+ infof(data, "no chunk, no close, no size. Assume close to "
+ "signal end\n");
+ streamclose(conn, "HTTP: No end-of-message indicator");
+ }
+ }
+
+ /* At this point we have some idea about the fate of the connection.
+ If we are closing the connection it may result auth failure. */
+#if defined(USE_NTLM)
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->ntlm.state == NTLMSTATE_TYPE2)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) {
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+ data->state.authproblem = TRUE;
+ }
+#endif
+
+ /*
+ * When all the headers have been parsed, see if we should give
+ * up and return an error.
+ */
+ if(http_should_fail(conn)) {
+ failf(data, "The requested URL returned error: %d",
+ k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ /* now, only output this if the header AND body are requested:
+ */
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ headerlen = k->p - data->state.headerbuff;
+
+ result = Curl_client_write(conn, writetype,
+ data->state.headerbuff,
+ headerlen);
+ if(result)
+ return result;
+
+ data->info.header_size += (long)headerlen;
+ data->req.headerbytecount += (long)headerlen;
+
+ data->req.deductheadercount =
+ (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
+
+ /* Curl_http_auth_act() checks what authentication methods
+ * that are available and decides which one (if any) to
+ * use. It will set 'newurl' if an auth method was picked. */
+ result = Curl_http_auth_act(conn);
+
+ if(result)
+ return result;
+
+ if(k->httpcode >= 300) {
+ if((!conn->bits.authneg) && !conn->bits.close &&
+ !conn->bits.rewindaftersend) {
+ /*
+ * General treatment of errors when about to send data. Including :
+ * "417 Expectation Failed", while waiting for 100-continue.
+ *
+ * The check for close above is done simply because of something
+ * else has already deemed the connection to get closed then
+ * something else should've considered the big picture and we
+ * avoid this check.
+ *
+ * rewindaftersend indicates that something has told libcurl to
+ * continue sending even if it gets discarded
+ */
+
+ switch(data->set.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ /* We got an error response. If this happened before the whole
+ * request body has been sent we stop sending and mark the
+ * connection for closure after we've read the entire response.
+ */
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ if(!k->upload_done) {
+ if(data->set.http_keep_sending_on_error) {
+ infof(data, "HTTP error before end of send, keep sending\n");
+ if(k->exp100 > EXP100_SEND_DATA) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ }
+ }
+ else {
+ infof(data, "HTTP error before end of send, stop sending\n");
+ streamclose(conn, "Stop sending data before everything sent");
+ k->upload_done = TRUE;
+ k->keepon &= ~KEEP_SEND; /* don't send */
+ if(data->state.expect100header)
+ k->exp100 = EXP100_FAILED;
+ }
+ }
+ break;
+
+ default: /* default label present to avoid compiler warnings */
+ break;
+ }
+ }
+
+ if(conn->bits.rewindaftersend) {
+ /* We rewind after a complete send, so thus we continue
+ sending now */
+ infof(data, "Keep sending data to get tossed away!\n");
+ k->keepon |= KEEP_SEND;
+ }
+ }
+
+ if(!k->header) {
+ /*
+ * really end-of-headers.
+ *
+ * If we requested a "no body", this is a good time to get
+ * out and return home.
+ */
+ if(data->set.opt_no_body)
+ *stop_reading = TRUE;
+#ifndef CURL_DISABLE_RTSP
+ else if((conn->handler->protocol & CURLPROTO_RTSP) &&
+ (data->set.rtspreq == RTSPREQ_DESCRIBE) &&
+ (k->size <= -1))
+ /* Respect section 4.4 of rfc2326: If the Content-Length header is
+ absent, a length 0 must be assumed. It will prevent libcurl from
+ hanging on DESCRIBE request that got refused for whatever
+ reason */
+ *stop_reading = TRUE;
+#endif
+ else {
+ /* If we know the expected size of this document, we set the
+ maximum download size to the size of the expected
+ document or else, we won't know when to stop reading!
+
+ Note that we set the download maximum even if we read a
+ "Connection: close" header, to make sure that
+ "Content-Length: 0" still prevents us from attempting to
+ read the (missing) response-body.
+ */
+ /* According to RFC2616 section 4.4, we MUST ignore
+ Content-Length: headers if we are now receiving data
+ using chunked Transfer-Encoding.
+ */
+ if(k->chunk)
+ k->maxdownload = k->size = -1;
+ }
+ if(-1 != k->size) {
+ /* We do this operation even if no_body is true, since this
+ data might be retrieved later with curl_easy_getinfo()
+ and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
+
+ Curl_pgrsSetDownloadSize(data, k->size);
+ k->maxdownload = k->size;
+ }
+
+ /* If max download size is *zero* (nothing) we already have
+ nothing and can safely return ok now! But for HTTP/2, we'd
+ like to call http2_handle_stream_close to properly close a
+ stream. In order to do this, we keep reading until we
+ close the stream. */
+ if(0 == k->maxdownload
+#if defined(USE_NGHTTP2)
+ && !((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ conn->httpversion == 20)
+#endif
+ )
+ *stop_reading = TRUE;
+
+ if(*stop_reading) {
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
+ }
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ k->str_start, headerlen, conn);
+ break; /* exit header line loop */
+ }
+
+ /* We continue reading headers, so reset the line-based
+ header parsing variables hbufp && hbuflen */
+ k->hbufp = data->state.headerbuff;
+ k->hbuflen = 0;
+ continue;
+ }
+
+ /*
+ * Checks for special headers coming up.
+ */
+
+ if(!k->headerline++) {
+ /* This is the first header, it MUST be the error code line
+ or else we consider this to be the body right away! */
+ int httpversion_major;
+ int rtspversion_major;
+ int nc = 0;
+#ifdef CURL_DOES_CONVERSIONS
+#define HEADER1 scratch
+#define SCRATCHSIZE 21
+ CURLcode res;
+ char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
+ /* We can't really convert this yet because we
+ don't know if it's the 1st header line or the body.
+ So we do a partial conversion into a scratch area,
+ leaving the data at k->p as-is.
+ */
+ strncpy(&scratch[0], k->p, SCRATCHSIZE);
+ scratch[SCRATCHSIZE] = 0; /* null terminate */
+ res = Curl_convert_from_network(data,
+ &scratch[0],
+ SCRATCHSIZE);
+ if(res)
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ return res;
+#else
+#define HEADER1 k->p /* no conversion needed, just use k->p */
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ /*
+ * https://tools.ietf.org/html/rfc7230#section-3.1.2
+ *
+ * The response code is always a three-digit number in HTTP as the spec
+ * says. We try to allow any number here, but we cannot make
+ * guarantees on future behaviors since it isn't within the protocol.
+ */
+ nc = sscanf(HEADER1,
+ " HTTP/%d.%d %d",
+ &httpversion_major,
+ &conn->httpversion,
+ &k->httpcode);
+
+ if(nc == 1 && httpversion_major == 2 &&
+ 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) {
+ conn->httpversion = 0;
+ nc = 3;
+ }
+
+ if(nc==3) {
+ conn->httpversion += 10 * httpversion_major;
+
+ if(k->upgr101 == UPGR101_RECEIVED) {
+ /* supposedly upgraded to http2 now */
+ if(conn->httpversion != 20)
+ infof(data, "Lying server, not serving HTTP/2\n");
+ }
+ }
+ else {
+ /* this is the real world, not a Nirvana
+ NCSA 1.5.x returns this crap when asked for HTTP/1.1
+ */
+ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
+ conn->httpversion = 10;
+
+ /* If user has set option HTTP200ALIASES,
+ compare header line against list of aliases
+ */
+ if(!nc) {
+ if(checkhttpprefix(data, k->p)) {
+ nc = 1;
+ k->httpcode = 200;
+ conn->httpversion = 10;
+ }
+ }
+ }
+ }
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ nc = sscanf(HEADER1,
+ " RTSP/%d.%d %3d",
+ &rtspversion_major,
+ &conn->rtspversion,
+ &k->httpcode);
+ if(nc==3) {
+ conn->rtspversion += 10 * rtspversion_major;
+ conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
+ }
+ else {
+ /* TODO: do we care about the other cases here? */
+ nc = 0;
+ }
+ }
+
+ if(nc) {
+ data->info.httpcode = k->httpcode;
+
+ data->info.httpversion = conn->httpversion;
+ if(!data->state.httpversion ||
+ data->state.httpversion > conn->httpversion)
+ /* store the lowest server version we encounter */
+ data->state.httpversion = conn->httpversion;
+
+ /*
+ * This code executes as part of processing the header. As a
+ * result, it's not totally clear how to interpret the
+ * response code yet as that depends on what other headers may
+ * be present. 401 and 407 may be errors, but may be OK
+ * depending on how authentication is working. Other codes
+ * are definitely errors, so give up here.
+ */
+ if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
+ ((k->httpcode != 401) || !conn->bits.user_passwd) &&
+ ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
+
+ if(data->state.resume_from &&
+ (data->set.httpreq==HTTPREQ_GET) &&
+ (k->httpcode == 416)) {
+ /* "Requested Range Not Satisfiable", just proceed and
+ pretend this is no error */
+ }
+ else {
+ /* serious error, go home! */
+ print_http_error(data);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+ }
+
+ if(conn->httpversion == 10) {
+ /* Default action for HTTP/1.0 must be to close, unless
+ we get one of those fancy headers that tell us the
+ server keeps it open for us! */
+ infof(data, "HTTP 1.0, assume close after body\n");
+ connclose(conn, "HTTP/1.0 close after body");
+ }
+ else if(conn->httpversion == 20 ||
+ (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
+ DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
+
+ /* HTTP/2 cannot blacklist multiplexing since it is a core
+ functionality of the protocol */
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+ }
+ else if(conn->httpversion >= 11 &&
+ !conn->bits.close) {
+ /* If HTTP version is >= 1.1 and connection is persistent
+ server supports pipelining. */
+ DEBUGF(infof(data,
+ "HTTP 1.1 or later with persistent connection, "
+ "pipelining supported\n"));
+ /* Activate pipelining if needed */
+ if(conn->bundle) {
+ if(!Curl_pipeline_site_blacklisted(data, conn))
+ conn->bundle->multiuse = BUNDLE_PIPELINING;
+ }
+ }
+
+ switch(k->httpcode) {
+ case 204:
+ /* (quote from RFC2616, section 10.2.5): The server has
+ * fulfilled the request but does not need to return an
+ * entity-body ... The 204 response MUST NOT include a
+ * message-body, and thus is always terminated by the first
+ * empty line after the header fields. */
+ /* FALLTHROUGH */
+ case 304:
+ /* (quote from RFC2616, section 10.3.5): The 304 response
+ * MUST NOT contain a message-body, and thus is always
+ * terminated by the first empty line after the header
+ * fields. */
+ if(data->set.timecondition)
+ data->info.timecond = TRUE;
+ k->size=0;
+ k->maxdownload=0;
+ k->ignorecl = TRUE; /* ignore Content-Length headers */
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+ else {
+ k->header = FALSE; /* this is not a header line */
+ break;
+ }
+ }
+
+ result = Curl_convert_from_network(data, k->p, strlen(k->p));
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+ /* Check for Content-Length: header lines to get size */
+ if(!k->ignorecl && !data->set.ignorecl &&
+ checkprefix("Content-Length:", k->p)) {
+ curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
+ if(data->set.max_filesize &&
+ contentlength > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ if(contentlength >= 0) {
+ k->size = contentlength;
+ k->maxdownload = k->size;
+ /* we set the progress download size already at this point
+ just to make it easier for apps/callbacks to extract this
+ info as soon as possible */
+ Curl_pgrsSetDownloadSize(data, k->size);
+ }
+ else {
+ /* Negative Content-Length is really odd, and we know it
+ happens for example when older Apache servers send large
+ files */
+ streamclose(conn, "negative content-length");
+ infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T
+ ", closing after transfer\n", contentlength);
+ }
+ }
+ /* check for Content-Type: header lines to get the MIME-type */
+ else if(checkprefix("Content-Type:", k->p)) {
+ char *contenttype = Curl_copy_header_value(k->p);
+ if(!contenttype)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*contenttype)
+ /* ignore empty data */
+ free(contenttype);
+ else {
+ Curl_safefree(data->info.contenttype);
+ data->info.contenttype = contenttype;
+ }
+ }
+ else if(checkprefix("Server:", k->p)) {
+ if(conn->httpversion < 20) {
+ /* only do this for non-h2 servers */
+ char *server_name = Curl_copy_header_value(k->p);
+
+ /* Turn off pipelining if the server version is blacklisted */
+ if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) {
+ if(Curl_pipeline_server_blacklisted(data, server_name))
+ conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
+ }
+ free(server_name);
+ }
+ }
+ else if((conn->httpversion == 10) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(k->p,
+ "Proxy-Connection:", "keep-alive")) {
+ /*
+ * When a HTTP/1.0 reply comes when using a proxy, the
+ * 'Proxy-Connection: keep-alive' line tells us the
+ * connection will be kept alive for our pleasure.
+ * Default action for 1.0 is to close.
+ */
+ connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
+ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+ }
+ else if((conn->httpversion == 11) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(k->p,
+ "Proxy-Connection:", "close")) {
+ /*
+ * We get a HTTP/1.1 response from a proxy and it says it'll
+ * close down after this transfer.
+ */
+ connclose(conn, "Proxy-Connection: asked to close after done");
+ infof(data, "HTTP/1.1 proxy connection set close!\n");
+ }
+ else if((conn->httpversion == 10) &&
+ Curl_compareheader(k->p, "Connection:", "keep-alive")) {
+ /*
+ * A HTTP/1.0 reply with the 'Connection: keep-alive' line
+ * tells us the connection will be kept alive for our
+ * pleasure. Default action for 1.0 is to close.
+ *
+ * [RFC2068, section 19.7.1] */
+ connkeep(conn, "Connection keep-alive");
+ infof(data, "HTTP/1.0 connection set to keep alive!\n");
+ }
+ else if(Curl_compareheader(k->p, "Connection:", "close")) {
+ /*
+ * [RFC 2616, section 8.1.2.1]
+ * "Connection: close" is HTTP/1.1 language and means that
+ * the connection will close when this request has been
+ * served.
+ */
+ streamclose(conn, "Connection: close used");
+ }
+ else if(checkprefix("Transfer-Encoding:", k->p)) {
+ /* One or more encodings. We check for chunked and/or a compression
+ algorithm. */
+ /*
+ * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+ * means that the server will send a series of "chunks". Each
+ * chunk starts with line with info (including size of the
+ * coming block) (terminated with CRLF), then a block of data
+ * with the previously mentioned size. There can be any amount
+ * of chunks, and a chunk-data set to zero signals the
+ * end-of-chunks. */
+
+ char *start;
+
+ /* Find the first non-space letter */
+ start = k->p + 18;
+
+ for(;;) {
+ /* skip whitespaces and commas */
+ while(*start && (ISSPACE(*start) || (*start == ',')))
+ start++;
+
+ if(checkprefix("chunked", start)) {
+ k->chunk = TRUE; /* chunks coming our way */
+
+ /* init our chunky engine */
+ Curl_httpchunk_init(conn);
+
+ start += 7;
+ }
+
+ if(k->auto_decoding)
+ /* TODO: we only support the first mentioned compression for now */
+ break;
+
+ if(checkprefix("identity", start)) {
+ k->auto_decoding = IDENTITY;
+ start += 8;
+ }
+ else if(checkprefix("deflate", start)) {
+ k->auto_decoding = DEFLATE;
+ start += 7;
+ }
+ else if(checkprefix("gzip", start)) {
+ k->auto_decoding = GZIP;
+ start += 4;
+ }
+ else if(checkprefix("x-gzip", start)) {
+ k->auto_decoding = GZIP;
+ start += 6;
+ }
+ else
+ /* unknown! */
+ break;
+
+ }
+
+ }
+ else if(checkprefix("Content-Encoding:", k->p) &&
+ data->set.str[STRING_ENCODING]) {
+ /*
+ * Process Content-Encoding. Look for the values: identity,
+ * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+ * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+ * 2616). zlib cannot handle compress. However, errors are
+ * handled further down when the response body is processed
+ */
+ char *start;
+
+ /* Find the first non-space letter */
+ start = k->p + 17;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* Record the content-encoding for later use */
+ if(checkprefix("identity", start))
+ k->auto_decoding = IDENTITY;
+ else if(checkprefix("deflate", start))
+ k->auto_decoding = DEFLATE;
+ else if(checkprefix("gzip", start)
+ || checkprefix("x-gzip", start))
+ k->auto_decoding = GZIP;
+ }
+ else if(checkprefix("Content-Range:", k->p)) {
+ /* Content-Range: bytes [num]-
+ Content-Range: bytes: [num]-
+ Content-Range: [num]-
+ Content-Range: [asterisk]/[total]
+
+ The second format was added since Sun's webserver
+ JavaWebServer/1.1.1 obviously sends the header this way!
+ The third added since some servers use that!
+ The forth means the requested range was unsatisfied.
+ */
+
+ char *ptr = k->p + 14;
+
+ /* Move forward until first digit or asterisk */
+ while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
+ ptr++;
+
+ /* if it truly stopped on a digit */
+ if(ISDIGIT(*ptr)) {
+ k->offset = curlx_strtoofft(ptr, NULL, 10);
+
+ if(data->state.resume_from == k->offset)
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
+ }
+ else
+ data->state.resume_from = 0; /* get everything */
+ }
+#if !defined(CURL_DISABLE_COOKIES)
+ else if(data->cookies &&
+ checkprefix("Set-Cookie:", k->p)) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_add(data,
+ data->cookies, TRUE, k->p+11,
+ /* If there is a custom-set Host: name, use it
+ here, or else use real peer host name. */
+ conn->allocptr.cookiehost?
+ conn->allocptr.cookiehost:conn->host.name,
+ data->state.path);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+#endif
+ else if(checkprefix("Last-Modified:", k->p) &&
+ (data->set.timecondition || data->set.get_filetime) ) {
+ time_t secs=time(NULL);
+ k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
+ &secs);
+ if(data->set.get_filetime)
+ data->info.filetime = (long)k->timeofdoc;
+ }
+ else if((checkprefix("WWW-Authenticate:", k->p) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", k->p) &&
+ (407 == k->httpcode))) {
+
+ bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+ char *auth = Curl_copy_header_value(k->p);
+ if(!auth)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_http_input_auth(conn, proxy, auth);
+
+ free(auth);
+
+ if(result)
+ return result;
+ }
+ else if((k->httpcode >= 300 && k->httpcode < 400) &&
+ checkprefix("Location:", k->p) &&
+ !data->req.location) {
+ /* this is the URL that the server advises us to use instead */
+ char *location = Curl_copy_header_value(k->p);
+ if(!location)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*location)
+ /* ignore empty data */
+ free(location);
+ else {
+ data->req.location = location;
+
+ if(data->set.http_follow_location) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->req.location); /* clone */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* some cases of POST and PUT etc needs to rewind the data
+ stream at this point */
+ result = http_perhapsrewind(conn);
+ if(result)
+ return result;
+ }
+ }
+ }
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ result = Curl_rtsp_parseheader(conn, k->p);
+ if(result)
+ return result;
+ }
+
+ /*
+ * End of header-checks. Write them to the client.
+ */
+
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ k->p, (size_t)k->hbuflen, conn);
+
+ result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
+ if(result)
+ return result;
+
+ data->info.header_size += (long)k->hbuflen;
+ data->req.headerbytecount += (long)k->hbuflen;
+
+ /* reset hbufp pointer && hbuflen */
+ k->hbufp = data->state.headerbuff;
+ k->hbuflen = 0;
+ }
+ while(*k->str); /* header line within buffer */
+
+ /* We might have reached the end of the header part here, but
+ there might be a non-header part left in the end of the read
+ buffer. */
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/lib/http.h b/Utilities/cmcurl/lib/http.h
new file mode 100644
index 000000000..7ce4bd9a0
--- /dev/null
+++ b/Utilities/cmcurl/lib/http.h
@@ -0,0 +1,258 @@
+#ifndef HEADER_CURL_HTTP_H
+#define HEADER_CURL_HTTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifdef USE_NGHTTP2
+#include <nghttp2/nghttp2.h>
+#endif
+
+extern const struct Curl_handler Curl_handler_http;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_https;
+#endif
+
+/* Header specific functions */
+bool Curl_compareheader(const char *headerline, /* line to check */
+ const char *header, /* header keyword _with_ colon */
+ const char *content); /* content string to find */
+
+char *Curl_checkheaders(const struct connectdata *conn,
+ const char *thisheader);
+char *Curl_copy_header_value(const char *header);
+
+char *Curl_checkProxyheaders(const struct connectdata *conn,
+ const char *thisheader);
+/* ------------------------------------------------------------------------- */
+/*
+ * The add_buffer series of functions are used to build one large memory chunk
+ * from repeated function invokes. Used so that the entire HTTP request can
+ * be sent in one go.
+ */
+struct Curl_send_buffer {
+ char *buffer;
+ size_t size_max;
+ size_t size_used;
+};
+typedef struct Curl_send_buffer Curl_send_buffer;
+
+Curl_send_buffer *Curl_add_buffer_init(void);
+void Curl_add_buffer_free(Curl_send_buffer *buff);
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+ struct connectdata *conn,
+ long *bytes_written,
+ size_t included_body_bytes,
+ int socketindex);
+
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+ Curl_send_buffer *buf);
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+ bool is_connect,
+ Curl_send_buffer *req_buffer);
+
+/* protocol-specific functions set up to be called by the main engine */
+CURLcode Curl_http(struct connectdata *conn, bool *done);
+CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
+CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_http_setup_conn(struct connectdata *conn);
+
+/* The following functions are defined in http_chunks.c */
+void Curl_httpchunk_init(struct connectdata *conn);
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
+ ssize_t length, ssize_t *wrote);
+
+/* These functions are in http.c */
+void Curl_http_auth_stage(struct Curl_easy *data, int stage);
+CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
+ const char *auth);
+CURLcode Curl_http_auth_act(struct connectdata *conn);
+CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
+
+/* If only the PICKNONE bit is set, there has been a round-trip and we
+ selected to use no auth at all. Ie, we actively select no auth, as opposed
+ to not having one selected. The other CURLAUTH_* defines are present in the
+ public curl/curl.h header. */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+
+/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
+ data get included in the initial data chunk sent to the server. If the
+ data is larger than this, it will automatically get split up in multiple
+ system calls.
+
+ This value used to be fairly big (100K), but we must take into account that
+ if the server rejects the POST due for authentication reasons, this data
+ will always be uncondtionally sent and thus it may not be larger than can
+ always be afforded to send twice.
+
+ It must not be greater than 64K to work on VMS.
+*/
+#ifndef MAX_INITIAL_POST_SIZE
+#define MAX_INITIAL_POST_SIZE (64*1024)
+#endif
+
+#ifndef TINY_INITIAL_POST_SIZE
+#define TINY_INITIAL_POST_SIZE 1024
+#endif
+
+#endif /* CURL_DISABLE_HTTP */
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+ struct FormData *sendit;
+ curl_off_t postsize; /* off_t to handle large file sizes */
+ const char *postdata;
+
+ const char *p_pragma; /* Pragma: string */
+ const char *p_accept; /* Accept: string */
+ curl_off_t readbytecount;
+ curl_off_t writebytecount;
+
+ /* For FORM posting */
+ struct Form form;
+
+ struct back {
+ curl_read_callback fread_func; /* backup storage for fread pointer */
+ void *fread_in; /* backup storage for fread_in pointer */
+ const char *postdata;
+ curl_off_t postsize;
+ } backup;
+
+ enum {
+ HTTPSEND_NADA, /* init */
+ HTTPSEND_REQUEST, /* sending a request */
+ HTTPSEND_BODY, /* sending body */
+ HTTPSEND_LAST /* never use this */
+ } sending;
+
+ void *send_buffer; /* used if the request couldn't be sent in one chunk,
+ points to an allocated send_buffer struct */
+
+#ifdef USE_NGHTTP2
+ /*********** for HTTP/2 we store stream-local data here *************/
+ int32_t stream_id; /* stream we are interested in */
+
+ bool bodystarted;
+ /* We store non-final and final response headers here, per-stream */
+ Curl_send_buffer *header_recvbuf;
+ size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into
+ upper layer */
+ Curl_send_buffer *trailer_recvbuf;
+ int status_code; /* HTTP status code */
+ const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
+ size_t pauselen; /* the number of bytes left in data */
+ bool closed; /* TRUE on HTTP2 stream close */
+ bool close_handled; /* TRUE if stream closure is handled by libcurl */
+ uint32_t error_code; /* HTTP/2 error code */
+
+ char *mem; /* points to a buffer in memory to store received data */
+ size_t len; /* size of the buffer 'mem' points to */
+ size_t memlen; /* size of data copied to mem */
+
+ const uint8_t *upload_mem; /* points to a buffer to read from */
+ size_t upload_len; /* size of the buffer 'upload_mem' points to */
+ curl_off_t upload_left; /* number of bytes left to upload */
+
+ char **push_headers; /* allocated array */
+ size_t push_headers_used; /* number of entries filled in */
+ size_t push_headers_alloc; /* number of entries allocated */
+#endif
+};
+
+typedef int (*sending)(void); /* Curl_send */
+typedef int (*recving)(void); /* Curl_recv */
+
+#ifdef USE_NGHTTP2
+/* h2 settings for this connection */
+struct h2settings {
+ uint32_t max_concurrent_streams;
+ bool enable_push;
+};
+#endif
+
+
+struct http_conn {
+#ifdef USE_NGHTTP2
+#define H2_BINSETTINGS_LEN 80
+ nghttp2_session *h2;
+ uint8_t binsettings[H2_BINSETTINGS_LEN];
+ size_t binlen; /* length of the binsettings data */
+ sending send_underlying; /* underlying send Curl_send callback */
+ recving recv_underlying; /* underlying recv Curl_recv callback */
+ char *inbuf; /* buffer to receive data from underlying socket */
+ size_t inbuflen; /* number of bytes filled in inbuf */
+ size_t nread_inbuf; /* number of bytes read from in inbuf */
+ /* We need separate buffer for transmission and reception because we
+ may call nghttp2_session_send() after the
+ nghttp2_session_mem_recv() but mem buffer is still not full. In
+ this case, we wrongly sends the content of mem buffer if we share
+ them for both cases. */
+ int32_t pause_stream_id; /* stream ID which paused
+ nghttp2_session_mem_recv */
+ size_t drain_total; /* sum of all stream's UrlState.drain */
+
+ /* this is a hash of all individual streams (Curl_easy structs) */
+ struct h2settings settings;
+
+ /* list of settings that will be sent */
+ nghttp2_settings_entry local_settings[3];
+ size_t local_settings_num;
+#else
+ int unused; /* prevent a compiler warning */
+#endif
+};
+
+CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *stop_reading);
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ const char *request,
+ const char *path,
+ bool proxytunnel); /* TRUE if this is the request setting
+ up the proxy tunnel */
+
+#endif /* HEADER_CURL_HTTP_H */
+
diff --git a/Utilities/cmcurl/lib/http2.c b/Utilities/cmcurl/lib/http2.c
new file mode 100644
index 000000000..f8e23c517
--- /dev/null
+++ b/Utilities/cmcurl/lib/http2.c
@@ -0,0 +1,2236 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NGHTTP2
+#include <nghttp2/nghttp2.h>
+#include "urldata.h"
+#include "http2.h"
+#include "http.h"
+#include "sendf.h"
+#include "curl_base64.h"
+#include "strcase.h"
+#include "multiif.h"
+#include "conncache.h"
+#include "url.h"
+#include "connect.h"
+#include "strtoofft.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MIN(x,y) ((x)<(y)?(x):(y))
+
+#if (NGHTTP2_VERSION_NUM < 0x010000)
+#error too old nghttp2 version, upgrade!
+#endif
+
+#if (NGHTTP2_VERSION_NUM > 0x010800)
+#define NGHTTP2_HAS_HTTP2_STRERROR 1
+#endif
+
+#if (NGHTTP2_VERSION_NUM >= 0x010900)
+/* nghttp2_session_callbacks_set_error_callback is present in nghttp2 1.9.0 or
+ later */
+#define NGHTTP2_HAS_ERROR_CALLBACK 1
+#else
+#define nghttp2_session_callbacks_set_error_callback(x,y)
+#endif
+
+#if (NGHTTP2_VERSION_NUM >= 0x010c00)
+#define NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE 1
+#endif
+
+#define HTTP2_HUGE_WINDOW_SIZE (1 << 30)
+
+/*
+ * Curl_http2_init_state() is called when the easy handle is created and
+ * allows for HTTP/2 specific init of state.
+ */
+void Curl_http2_init_state(struct UrlState *state)
+{
+ state->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
+}
+
+/*
+ * Curl_http2_init_userset() is called when the easy handle is created and
+ * allows for HTTP/2 specific user-set fields.
+ */
+void Curl_http2_init_userset(struct UserDefined *set)
+{
+ set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
+}
+
+static int http2_perform_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to
+ numsocks
+ number of
+ sockets */
+ int numsocks)
+{
+ const struct http_conn *c = &conn->proto.httpc;
+ int bitmap = GETSOCK_BLANK;
+ (void)numsocks;
+
+ /* TODO We should check underlying socket state if it is SSL socket
+ because of renegotiation. */
+ sock[0] = conn->sock[FIRSTSOCKET];
+
+ /* in a HTTP/2 connection we can basically always get a frame so we should
+ always be ready for one */
+ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+ if(nghttp2_session_want_write(c->h2))
+ bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+ return bitmap;
+}
+
+static int http2_getsock(struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks
+ number of sockets */
+ int numsocks)
+{
+ return http2_perform_getsock(conn, sock, numsocks);
+}
+
+/*
+ * http2_stream_free() free HTTP2 stream related data
+ */
+static void http2_stream_free(struct HTTP *http)
+{
+ if(http) {
+ Curl_add_buffer_free(http->header_recvbuf);
+ http->header_recvbuf = NULL; /* clear the pointer */
+ Curl_add_buffer_free(http->trailer_recvbuf);
+ http->trailer_recvbuf = NULL; /* clear the pointer */
+ for(; http->push_headers_used > 0; --http->push_headers_used) {
+ free(http->push_headers[http->push_headers_used - 1]);
+ }
+ free(http->push_headers);
+ http->push_headers = NULL;
+ }
+}
+
+static CURLcode http2_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ struct http_conn *c = &conn->proto.httpc;
+ (void)dead_connection;
+
+ DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
+
+ nghttp2_session_del(c->h2);
+ Curl_safefree(c->inbuf);
+ http2_stream_free(conn->data->req.protop);
+
+ DEBUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
+
+ return CURLE_OK;
+}
+
+/* called from Curl_http_setup_conn */
+void Curl_http2_setup_req(struct Curl_easy *data)
+{
+ struct HTTP *http = data->req.protop;
+
+ http->nread_header_recvbuf = 0;
+ http->bodystarted = FALSE;
+ http->status_code = -1;
+ http->pausedata = NULL;
+ http->pauselen = 0;
+ http->error_code = NGHTTP2_NO_ERROR;
+ http->closed = FALSE;
+ http->close_handled = FALSE;
+ http->mem = data->state.buffer;
+ http->len = data->set.buffer_size;
+ http->memlen = 0;
+}
+
+/* called from Curl_http_setup_conn */
+void Curl_http2_setup_conn(struct connectdata *conn)
+{
+ conn->proto.httpc.settings.max_concurrent_streams =
+ DEFAULT_MAX_CONCURRENT_STREAMS;
+}
+
+/*
+ * HTTP2 handler interface. This isn't added to the general list of protocols
+ * but will be used at run-time when the protocol is dynamically switched from
+ * HTTP to HTTP2.
+ */
+static const struct Curl_handler Curl_handler_http2 = {
+ "HTTP", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ http2_getsock, /* proto_getsock */
+ http2_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ http2_perform_getsock, /* perform_getsock */
+ http2_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_STREAM /* flags */
+};
+
+static const struct Curl_handler Curl_handler_http2_ssl = {
+ "HTTPS", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ http2_getsock, /* proto_getsock */
+ http2_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ http2_perform_getsock, /* perform_getsock */
+ http2_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTP, /* defport */
+ CURLPROTO_HTTPS, /* protocol */
+ PROTOPT_SSL | PROTOPT_STREAM /* flags */
+};
+
+/*
+ * Store nghttp2 version info in this buffer, Prefix with a space. Return
+ * total length written.
+ */
+int Curl_http2_ver(char *p, size_t len)
+{
+ nghttp2_info *h2 = nghttp2_version(0);
+ return snprintf(p, len, " nghttp2/%s", h2->version_str);
+}
+
+/* HTTP/2 error code to name based on the Error Code Registry.
+https://tools.ietf.org/html/rfc7540#page-77
+nghttp2_error_code enums are identical.
+*/
+const char *Curl_http2_strerror(uint32_t err)
+{
+#ifndef NGHTTP2_HAS_HTTP2_STRERROR
+ const char *str[] = {
+ "NO_ERROR", /* 0x0 */
+ "PROTOCOL_ERROR", /* 0x1 */
+ "INTERNAL_ERROR", /* 0x2 */
+ "FLOW_CONTROL_ERROR", /* 0x3 */
+ "SETTINGS_TIMEOUT", /* 0x4 */
+ "STREAM_CLOSED", /* 0x5 */
+ "FRAME_SIZE_ERROR", /* 0x6 */
+ "REFUSED_STREAM", /* 0x7 */
+ "CANCEL", /* 0x8 */
+ "COMPRESSION_ERROR", /* 0x9 */
+ "CONNECT_ERROR", /* 0xA */
+ "ENHANCE_YOUR_CALM", /* 0xB */
+ "INADEQUATE_SECURITY", /* 0xC */
+ "HTTP_1_1_REQUIRED" /* 0xD */
+ };
+ return (err < sizeof str / sizeof str[0]) ? str[err] : "unknown";
+#else
+ return nghttp2_http2_strerror(err);
+#endif
+}
+
+/*
+ * The implementation of nghttp2_send_callback type. Here we write |data| with
+ * size |length| to the network and return the number of bytes actually
+ * written. See the documentation of nghttp2_send_callback for the details.
+ */
+static ssize_t send_callback(nghttp2_session *h2,
+ const uint8_t *data, size_t length, int flags,
+ void *userp)
+{
+ struct connectdata *conn = (struct connectdata *)userp;
+ struct http_conn *c = &conn->proto.httpc;
+ ssize_t written;
+ CURLcode result = CURLE_OK;
+
+ (void)h2;
+ (void)flags;
+
+ written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
+ data, length, &result);
+
+ if(result == CURLE_AGAIN) {
+ return NGHTTP2_ERR_WOULDBLOCK;
+ }
+
+ if(written == -1) {
+ failf(conn->data, "Failed sending HTTP2 data");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ if(!written)
+ return NGHTTP2_ERR_WOULDBLOCK;
+
+ return written;
+}
+
+
+/* We pass a pointer to this struct in the push callback, but the contents of
+ the struct are hidden from the user. */
+struct curl_pushheaders {
+ struct Curl_easy *data;
+ const nghttp2_push_promise *frame;
+};
+
+/*
+ * push header access function. Only to be used from within the push callback
+ */
+char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
+{
+ /* Verify that we got a good easy handle in the push header struct, mostly to
+ detect rubbish input fast(er). */
+ if(!h || !GOOD_EASY_HANDLE(h->data))
+ return NULL;
+ else {
+ struct HTTP *stream = h->data->req.protop;
+ if(num < stream->push_headers_used)
+ return stream->push_headers[num];
+ }
+ return NULL;
+}
+
+/*
+ * push header access function. Only to be used from within the push callback
+ */
+char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
+{
+ /* Verify that we got a good easy handle in the push header struct,
+ mostly to detect rubbish input fast(er). Also empty header name
+ is just a rubbish too. We have to allow ":" at the beginning of
+ the header, but header == ":" must be rejected. If we have ':' in
+ the middle of header, it could be matched in middle of the value,
+ this is because we do prefix match.*/
+ if(!h || !GOOD_EASY_HANDLE(h->data) || !header || !header[0] ||
+ !strcmp(header, ":") || strchr(header + 1, ':'))
+ return NULL;
+ else {
+ struct HTTP *stream = h->data->req.protop;
+ size_t len = strlen(header);
+ size_t i;
+ for(i=0; i<stream->push_headers_used; i++) {
+ if(!strncmp(header, stream->push_headers[i], len)) {
+ /* sub-match, make sure that it is followed by a colon */
+ if(stream->push_headers[i][len] != ':')
+ continue;
+ return &stream->push_headers[i][len+1];
+ }
+ }
+ }
+ return NULL;
+}
+
+static struct Curl_easy *duphandle(struct Curl_easy *data)
+{
+ struct Curl_easy *second = curl_easy_duphandle(data);
+ if(second) {
+ /* setup the request struct */
+ struct HTTP *http = calloc(1, sizeof(struct HTTP));
+ if(!http) {
+ (void)Curl_close(second);
+ second = NULL;
+ }
+ else {
+ second->req.protop = http;
+ http->header_recvbuf = Curl_add_buffer_init();
+ if(!http->header_recvbuf) {
+ free(http);
+ (void)Curl_close(second);
+ second = NULL;
+ }
+ else {
+ Curl_http2_setup_req(second);
+ second->state.stream_weight = data->state.stream_weight;
+ }
+ }
+ }
+ return second;
+}
+
+
+static int push_promise(struct Curl_easy *data,
+ struct connectdata *conn,
+ const nghttp2_push_promise *frame)
+{
+ int rv;
+ DEBUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
+ frame->promised_stream_id));
+ if(data->multi->push_cb) {
+ struct HTTP *stream;
+ struct HTTP *newstream;
+ struct curl_pushheaders heads;
+ CURLMcode rc;
+ struct http_conn *httpc;
+ size_t i;
+ /* clone the parent */
+ struct Curl_easy *newhandle = duphandle(data);
+ if(!newhandle) {
+ infof(data, "failed to duplicate handle\n");
+ rv = 1; /* FAIL HARD */
+ goto fail;
+ }
+
+ heads.data = data;
+ heads.frame = frame;
+ /* ask the application */
+ DEBUGF(infof(data, "Got PUSH_PROMISE, ask application!\n"));
+
+ stream = data->req.protop;
+ if(!stream) {
+ failf(data, "Internal NULL stream!\n");
+ (void)Curl_close(newhandle);
+ rv = 1;
+ goto fail;
+ }
+
+ rv = data->multi->push_cb(data, newhandle,
+ stream->push_headers_used, &heads,
+ data->multi->push_userp);
+
+ /* free the headers again */
+ for(i=0; i<stream->push_headers_used; i++)
+ free(stream->push_headers[i]);
+ free(stream->push_headers);
+ stream->push_headers = NULL;
+ stream->push_headers_used = 0;
+
+ if(rv) {
+ /* denied, kill off the new handle again */
+ http2_stream_free(newhandle->req.protop);
+ (void)Curl_close(newhandle);
+ goto fail;
+ }
+
+ newstream = newhandle->req.protop;
+ newstream->stream_id = frame->promised_stream_id;
+ newhandle->req.maxdownload = -1;
+ newhandle->req.size = -1;
+
+ /* approved, add to the multi handle and immediately switch to PERFORM
+ state with the given connection !*/
+ rc = Curl_multi_add_perform(data->multi, newhandle, conn);
+ if(rc) {
+ infof(data, "failed to add handle to multi\n");
+ http2_stream_free(newhandle->req.protop);
+ Curl_close(newhandle);
+ rv = 1;
+ goto fail;
+ }
+
+ httpc = &conn->proto.httpc;
+ nghttp2_session_set_stream_user_data(httpc->h2,
+ frame->promised_stream_id, newhandle);
+ }
+ else {
+ DEBUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
+ rv = 1;
+ }
+ fail:
+ return rv;
+}
+
+static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
+ void *userp)
+{
+ struct connectdata *conn = (struct connectdata *)userp;
+ struct http_conn *httpc = &conn->proto.httpc;
+ struct Curl_easy *data_s = NULL;
+ struct HTTP *stream = NULL;
+ static int lastStream = -1;
+ int rv;
+ size_t left, ncopy;
+ int32_t stream_id = frame->hd.stream_id;
+
+ if(!stream_id) {
+ /* stream ID zero is for connection-oriented stuff */
+ if(frame->hd.type == NGHTTP2_SETTINGS) {
+ uint32_t max_conn = httpc->settings.max_concurrent_streams;
+ DEBUGF(infof(conn->data, "Got SETTINGS\n"));
+ httpc->settings.max_concurrent_streams =
+ nghttp2_session_get_remote_settings(
+ session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
+ httpc->settings.enable_push =
+ nghttp2_session_get_remote_settings(
+ session, NGHTTP2_SETTINGS_ENABLE_PUSH);
+ DEBUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
+ httpc->settings.max_concurrent_streams));
+ DEBUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
+ httpc->settings.enable_push?"TRUE":"false"));
+ if(max_conn != httpc->settings.max_concurrent_streams) {
+ /* only signal change if the value actually changed */
+ infof(conn->data,
+ "Connection state changed (MAX_CONCURRENT_STREAMS updated)!\n");
+ Curl_multi_connchanged(conn->data->multi);
+ }
+ }
+ return 0;
+ }
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(lastStream != stream_id) {
+ lastStream = stream_id;
+ }
+ if(!data_s) {
+ DEBUGF(infof(conn->data,
+ "No Curl_easy associated with stream: %x\n",
+ stream_id));
+ return 0;
+ }
+
+ stream = data_s->req.protop;
+ if(!stream) {
+ DEBUGF(infof(conn->data, "No proto pointer for stream: %x\n",
+ stream_id));
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ DEBUGF(infof(data_s, "on_frame_recv() header %x stream %x\n",
+ frame->hd.type, stream_id));
+
+ switch(frame->hd.type) {
+ case NGHTTP2_DATA:
+ /* If body started on this stream, then receiving DATA is illegal. */
+ if(!stream->bodystarted) {
+ rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
+ stream_id, NGHTTP2_PROTOCOL_ERROR);
+
+ if(nghttp2_is_fatal(rv)) {
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ }
+ break;
+ case NGHTTP2_HEADERS:
+ if(stream->bodystarted) {
+ /* Only valid HEADERS after body started is trailer HEADERS. We
+ buffer them in on_header callback. */
+ break;
+ }
+
+ /* nghttp2 guarantees that :status is received, and we store it to
+ stream->status_code */
+ DEBUGASSERT(stream->status_code != -1);
+
+ /* Only final status code signals the end of header */
+ if(stream->status_code / 100 != 1) {
+ stream->bodystarted = TRUE;
+ stream->status_code = -1;
+ }
+
+ Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
+
+ left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
+ ncopy = MIN(stream->len, left);
+
+ memcpy(&stream->mem[stream->memlen],
+ stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
+ ncopy);
+ stream->nread_header_recvbuf += ncopy;
+
+ DEBUGF(infof(data_s, "Store %zu bytes headers from stream %u at %p\n",
+ ncopy, stream_id, stream->mem));
+
+ stream->len -= ncopy;
+ stream->memlen += ncopy;
+
+ data_s->state.drain++;
+ httpc->drain_total++;
+ {
+ /* get the pointer from userp again since it was re-assigned above */
+ struct connectdata *conn_s = (struct connectdata *)userp;
+
+ /* if we receive data for another handle, wake that up */
+ if(conn_s->data != data_s)
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+ }
+ break;
+ case NGHTTP2_PUSH_PROMISE:
+ rv = push_promise(data_s, conn, &frame->push_promise);
+ if(rv) { /* deny! */
+ rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
+ frame->push_promise.promised_stream_id,
+ NGHTTP2_CANCEL);
+ if(nghttp2_is_fatal(rv)) {
+ return rv;
+ }
+ }
+ break;
+ default:
+ DEBUGF(infof(conn->data, "Got frame type %x for stream %u!\n",
+ frame->hd.type, stream_id));
+ break;
+ }
+ return 0;
+}
+
+static int on_invalid_frame_recv(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ int lib_error_code, void *userp)
+{
+ struct Curl_easy *data_s = NULL;
+ (void)userp;
+#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void)lib_error_code;
+#endif
+
+ data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if(data_s) {
+ DEBUGF(infof(data_s,
+ "on_invalid_frame_recv() was called, error=%d:%s\n",
+ lib_error_code, nghttp2_strerror(lib_error_code)));
+ }
+ return 0;
+}
+
+static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
+ int32_t stream_id,
+ const uint8_t *data, size_t len, void *userp)
+{
+ struct HTTP *stream;
+ struct Curl_easy *data_s;
+ size_t nread;
+ struct connectdata *conn = (struct connectdata *)userp;
+ (void)session;
+ (void)flags;
+ (void)data;
+
+ DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+
+ /* get the stream from the hash based on Stream ID */
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(!data_s)
+ /* Receiving a Stream ID not in the hash should not happen, this is an
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ stream = data_s->req.protop;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ nread = MIN(stream->len, len);
+ memcpy(&stream->mem[stream->memlen], data, nread);
+
+ stream->len -= nread;
+ stream->memlen += nread;
+
+ data_s->state.drain++;
+ conn->proto.httpc.drain_total++;
+
+ /* if we receive data for another handle, wake that up */
+ if(conn->data != data_s)
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+
+ DEBUGF(infof(data_s, "%zu data received for stream %u "
+ "(%zu left in buffer %p, total %zu)\n",
+ nread, stream_id,
+ stream->len, stream->mem,
+ stream->memlen));
+
+ if(nread < len) {
+ stream->pausedata = data + nread;
+ stream->pauselen = len - nread;
+ DEBUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
+ ", stream %u\n",
+ len - nread, stream_id));
+ data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+
+ return NGHTTP2_ERR_PAUSE;
+ }
+
+ /* pause execution of nghttp2 if we received data for another handle
+ in order to process them first. */
+ if(conn->data != data_s) {
+ data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+
+ return NGHTTP2_ERR_PAUSE;
+ }
+
+ return 0;
+}
+
+static int before_frame_send(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ void *userp)
+{
+ struct Curl_easy *data_s;
+ (void)userp;
+
+ data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if(data_s) {
+ DEBUGF(infof(data_s, "before_frame_send() was called\n"));
+ }
+
+ return 0;
+}
+static int on_frame_send(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ void *userp)
+{
+ struct Curl_easy *data_s;
+ (void)userp;
+
+ data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if(data_s) {
+ DEBUGF(infof(data_s, "on_frame_send() was called, length = %zd\n",
+ frame->hd.length));
+ }
+ return 0;
+}
+static int on_frame_not_send(nghttp2_session *session,
+ const nghttp2_frame *frame,
+ int lib_error_code, void *userp)
+{
+ struct Curl_easy *data_s;
+ (void)userp;
+#if !defined(DEBUGBUILD) || defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void)lib_error_code;
+#endif
+
+ data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if(data_s) {
+ DEBUGF(infof(data_s,
+ "on_frame_not_send() was called, lib_error_code = %d\n",
+ lib_error_code));
+ }
+ return 0;
+}
+static int on_stream_close(nghttp2_session *session, int32_t stream_id,
+ uint32_t error_code, void *userp)
+{
+ struct Curl_easy *data_s;
+ struct HTTP *stream;
+ struct connectdata *conn = (struct connectdata *)userp;
+ (void)session;
+ (void)stream_id;
+
+ if(stream_id) {
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(!data_s) {
+ /* We could get stream ID not in the hash. For example, if we
+ decided to reject stream (e.g., PUSH_PROMISE). */
+ return 0;
+ }
+ DEBUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
+ Curl_http2_strerror(error_code), error_code, stream_id));
+ stream = data_s->req.protop;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ stream->error_code = error_code;
+ stream->closed = TRUE;
+ data_s->state.drain++;
+ conn->proto.httpc.drain_total++;
+
+ /* remove the entry from the hash as the stream is now gone */
+ nghttp2_session_set_stream_user_data(session, stream_id, 0);
+ DEBUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
+ }
+ return 0;
+}
+
+static int on_begin_headers(nghttp2_session *session,
+ const nghttp2_frame *frame, void *userp)
+{
+ struct HTTP *stream;
+ struct Curl_easy *data_s = NULL;
+ (void)userp;
+
+ data_s = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
+ if(!data_s) {
+ return 0;
+ }
+
+ DEBUGF(infof(data_s, "on_begin_headers() was called\n"));
+
+ if(frame->hd.type != NGHTTP2_HEADERS) {
+ return 0;
+ }
+
+ stream = data_s->req.protop;
+ if(!stream || !stream->bodystarted) {
+ return 0;
+ }
+
+ /* This is trailer HEADERS started. Allocate buffer for them. */
+ DEBUGF(infof(data_s, "trailer field started\n"));
+
+ DEBUGASSERT(stream->trailer_recvbuf == NULL);
+
+ stream->trailer_recvbuf = Curl_add_buffer_init();
+ if(!stream->trailer_recvbuf) {
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+
+ return 0;
+}
+
+/* Decode HTTP status code. Returns -1 if no valid status code was
+ decoded. */
+static int decode_status_code(const uint8_t *value, size_t len)
+{
+ int i;
+ int res;
+
+ if(len != 3) {
+ return -1;
+ }
+
+ res = 0;
+
+ for(i = 0; i < 3; ++i) {
+ char c = value[i];
+
+ if(c < '0' || c > '9') {
+ return -1;
+ }
+
+ res *= 10;
+ res += c - '0';
+ }
+
+ return res;
+}
+
+/* frame->hd.type is either NGHTTP2_HEADERS or NGHTTP2_PUSH_PROMISE */
+static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
+ const uint8_t *name, size_t namelen,
+ const uint8_t *value, size_t valuelen,
+ uint8_t flags,
+ void *userp)
+{
+ struct HTTP *stream;
+ struct Curl_easy *data_s;
+ int32_t stream_id = frame->hd.stream_id;
+ struct connectdata *conn = (struct connectdata *)userp;
+ (void)flags;
+
+ DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
+
+ /* get the stream from the hash based on Stream ID */
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(!data_s)
+ /* Receiving a Stream ID not in the hash should not happen, this is an
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ stream = data_s->req.protop;
+ if(!stream) {
+ failf(data_s, "Internal NULL stream! 5\n");
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+
+ /* Store received PUSH_PROMISE headers to be used when the subsequent
+ PUSH_PROMISE callback comes */
+ if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
+ char *h;
+
+ if(!stream->push_headers) {
+ stream->push_headers_alloc = 10;
+ stream->push_headers = malloc(stream->push_headers_alloc *
+ sizeof(char *));
+ stream->push_headers_used = 0;
+ }
+ else if(stream->push_headers_used ==
+ stream->push_headers_alloc) {
+ char **headp;
+ stream->push_headers_alloc *= 2;
+ headp = Curl_saferealloc(stream->push_headers,
+ stream->push_headers_alloc * sizeof(char *));
+ if(!headp) {
+ stream->push_headers = NULL;
+ return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
+ }
+ stream->push_headers = headp;
+ }
+ h = aprintf("%s:%s", name, value);
+ if(h)
+ stream->push_headers[stream->push_headers_used++] = h;
+ return 0;
+ }
+
+ if(stream->bodystarted) {
+ /* This is trailer fields. */
+ /* 3 is for ":" and "\r\n". */
+ uint32_t n = (uint32_t)(namelen + valuelen + 3);
+
+ DEBUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
+ value));
+
+ Curl_add_buffer(stream->trailer_recvbuf, &n, sizeof(n));
+ Curl_add_buffer(stream->trailer_recvbuf, name, namelen);
+ Curl_add_buffer(stream->trailer_recvbuf, ": ", 2);
+ Curl_add_buffer(stream->trailer_recvbuf, value, valuelen);
+ Curl_add_buffer(stream->trailer_recvbuf, "\r\n\0", 3);
+
+ return 0;
+ }
+
+ if(namelen == sizeof(":status") - 1 &&
+ memcmp(":status", name, namelen) == 0) {
+ /* nghttp2 guarantees :status is received first and only once, and
+ value is 3 digits status code, and decode_status_code always
+ succeeds. */
+ stream->status_code = decode_status_code(value, valuelen);
+ DEBUGASSERT(stream->status_code != -1);
+
+ Curl_add_buffer(stream->header_recvbuf, "HTTP/2 ", 7);
+ Curl_add_buffer(stream->header_recvbuf, value, valuelen);
+ /* the space character after the status code is mandatory */
+ Curl_add_buffer(stream->header_recvbuf, " \r\n", 3);
+ /* if we receive data for another handle, wake that up */
+ if(conn->data != data_s)
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+
+ DEBUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
+ stream->status_code, data_s));
+ return 0;
+ }
+
+ /* nghttp2 guarantees that namelen > 0, and :status was already
+ received, and this is not pseudo-header field . */
+ /* convert to a HTTP1-style header */
+ Curl_add_buffer(stream->header_recvbuf, name, namelen);
+ Curl_add_buffer(stream->header_recvbuf, ": ", 2);
+ Curl_add_buffer(stream->header_recvbuf, value, valuelen);
+ Curl_add_buffer(stream->header_recvbuf, "\r\n", 2);
+ /* if we receive data for another handle, wake that up */
+ if(conn->data != data_s)
+ Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+
+ DEBUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
+ value));
+
+ return 0; /* 0 is successful */
+}
+
+static ssize_t data_source_read_callback(nghttp2_session *session,
+ int32_t stream_id,
+ uint8_t *buf, size_t length,
+ uint32_t *data_flags,
+ nghttp2_data_source *source,
+ void *userp)
+{
+ struct Curl_easy *data_s;
+ struct HTTP *stream = NULL;
+ size_t nread;
+ (void)source;
+ (void)userp;
+
+ if(stream_id) {
+ /* get the stream from the hash based on Stream ID, stream ID zero is for
+ connection-oriented stuff */
+ data_s = nghttp2_session_get_stream_user_data(session, stream_id);
+ if(!data_s)
+ /* Receiving a Stream ID not in the hash should not happen, this is an
+ internal error more than anything else! */
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+
+ stream = data_s->req.protop;
+ if(!stream)
+ return NGHTTP2_ERR_CALLBACK_FAILURE;
+ }
+ else
+ return NGHTTP2_ERR_INVALID_ARGUMENT;
+
+ nread = MIN(stream->upload_len, length);
+ if(nread > 0) {
+ memcpy(buf, stream->upload_mem, nread);
+ stream->upload_mem += nread;
+ stream->upload_len -= nread;
+ if(data_s->state.infilesize != -1)
+ stream->upload_left -= nread;
+ }
+
+ if(stream->upload_left == 0)
+ *data_flags = NGHTTP2_DATA_FLAG_EOF;
+ else if(nread == 0)
+ return NGHTTP2_ERR_DEFERRED;
+
+ DEBUGF(infof(data_s, "data_source_read_callback: "
+ "returns %zu bytes stream %u\n",
+ nread, stream_id));
+
+ return nread;
+}
+
+#define H2_BUFSIZE 32768
+
+#ifdef NGHTTP2_HAS_ERROR_CALLBACK
+static int error_callback(nghttp2_session *session,
+ const char *msg,
+ size_t len,
+ void *userp)
+{
+ struct connectdata *conn = (struct connectdata *)userp;
+ (void)session;
+ infof(conn->data, "http2 error: %.*s\n", len, msg);
+ return 0;
+}
+#endif
+
+static void populate_settings(struct connectdata *conn,
+ struct http_conn *httpc)
+{
+ nghttp2_settings_entry *iv = httpc->local_settings;
+
+ iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
+ iv[0].value = 100;
+
+ iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
+ iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
+
+ iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
+ iv[2].value = conn->data->multi->push_cb != NULL;
+
+ httpc->local_settings_num = 3;
+}
+
+void Curl_http2_done(struct connectdata *conn, bool premature)
+{
+ struct Curl_easy *data = conn->data;
+ struct HTTP *http = data->req.protop;
+ struct http_conn *httpc = &conn->proto.httpc;
+
+ if(http->header_recvbuf) {
+ DEBUGF(infof(data, "free header_recvbuf!!\n"));
+ Curl_add_buffer_free(http->header_recvbuf);
+ http->header_recvbuf = NULL; /* clear the pointer */
+ Curl_add_buffer_free(http->trailer_recvbuf);
+ http->trailer_recvbuf = NULL; /* clear the pointer */
+ if(http->push_headers) {
+ /* if they weren't used and then freed before */
+ for(; http->push_headers_used > 0; --http->push_headers_used) {
+ free(http->push_headers[http->push_headers_used - 1]);
+ }
+ free(http->push_headers);
+ http->push_headers = NULL;
+ }
+ }
+
+ if(premature) {
+ /* RST_STREAM */
+ nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE, http->stream_id,
+ NGHTTP2_STREAM_CLOSED);
+ if(http->stream_id == httpc->pause_stream_id) {
+ infof(data, "stopped the pause stream!\n");
+ httpc->pause_stream_id = 0;
+ }
+ }
+ if(http->stream_id) {
+ nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
+ http->stream_id = 0;
+ }
+}
+
+/*
+ * Initialize nghttp2 for a Curl connection
+ */
+CURLcode Curl_http2_init(struct connectdata *conn)
+{
+ if(!conn->proto.httpc.h2) {
+ int rc;
+ nghttp2_session_callbacks *callbacks;
+
+ conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
+ if(conn->proto.httpc.inbuf == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ rc = nghttp2_session_callbacks_new(&callbacks);
+
+ if(rc) {
+ failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
+ return CURLE_OUT_OF_MEMORY; /* most likely at least */
+ }
+
+ /* nghttp2_send_callback */
+ nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
+ /* nghttp2_on_frame_recv_callback */
+ nghttp2_session_callbacks_set_on_frame_recv_callback
+ (callbacks, on_frame_recv);
+ /* nghttp2_on_invalid_frame_recv_callback */
+ nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
+ (callbacks, on_invalid_frame_recv);
+ /* nghttp2_on_data_chunk_recv_callback */
+ nghttp2_session_callbacks_set_on_data_chunk_recv_callback
+ (callbacks, on_data_chunk_recv);
+ /* nghttp2_before_frame_send_callback */
+ nghttp2_session_callbacks_set_before_frame_send_callback
+ (callbacks, before_frame_send);
+ /* nghttp2_on_frame_send_callback */
+ nghttp2_session_callbacks_set_on_frame_send_callback
+ (callbacks, on_frame_send);
+ /* nghttp2_on_frame_not_send_callback */
+ nghttp2_session_callbacks_set_on_frame_not_send_callback
+ (callbacks, on_frame_not_send);
+ /* nghttp2_on_stream_close_callback */
+ nghttp2_session_callbacks_set_on_stream_close_callback
+ (callbacks, on_stream_close);
+ /* nghttp2_on_begin_headers_callback */
+ nghttp2_session_callbacks_set_on_begin_headers_callback
+ (callbacks, on_begin_headers);
+ /* nghttp2_on_header_callback */
+ nghttp2_session_callbacks_set_on_header_callback(callbacks, on_header);
+
+ nghttp2_session_callbacks_set_error_callback(callbacks, error_callback);
+
+ /* The nghttp2 session is not yet setup, do it */
+ rc = nghttp2_session_client_new(&conn->proto.httpc.h2, callbacks, conn);
+
+ nghttp2_session_callbacks_del(callbacks);
+
+ if(rc) {
+ failf(conn->data, "Couldn't initialize nghttp2!");
+ return CURLE_OUT_OF_MEMORY; /* most likely at least */
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
+ * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
+ */
+CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ ssize_t binlen;
+ char *base64;
+ size_t blen;
+ struct SingleRequest *k = &conn->data->req;
+ uint8_t *binsettings = conn->proto.httpc.binsettings;
+ struct http_conn *httpc = &conn->proto.httpc;
+
+ populate_settings(conn, httpc);
+
+ /* this returns number of bytes it wrote */
+ binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
+ httpc->local_settings,
+ httpc->local_settings_num);
+ if(!binlen) {
+ failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
+ return CURLE_FAILED_INIT;
+ }
+ conn->proto.httpc.binlen = binlen;
+
+ result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
+ &base64, &blen);
+ if(result)
+ return result;
+
+ result = Curl_add_bufferf(req,
+ "Connection: Upgrade, HTTP2-Settings\r\n"
+ "Upgrade: %s\r\n"
+ "HTTP2-Settings: %s\r\n",
+ NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
+ free(base64);
+
+ k->upgr101 = UPGR101_REQUESTED;
+
+ return result;
+}
+
+/*
+ * Returns nonzero if current HTTP/2 session should be closed.
+ */
+static int should_close_session(struct http_conn *httpc)
+{
+ return httpc->drain_total == 0 && !nghttp2_session_want_read(httpc->h2) &&
+ !nghttp2_session_want_write(httpc->h2);
+}
+
+static int h2_session_send(struct Curl_easy *data,
+ nghttp2_session *h2);
+
+/*
+ * h2_process_pending_input() processes pending input left in
+ * httpc->inbuf. Then, call h2_session_send() to send pending data.
+ * This function returns 0 if it succeeds, or -1 and error code will
+ * be assigned to *err.
+ */
+static int h2_process_pending_input(struct Curl_easy *data,
+ struct http_conn *httpc,
+ CURLcode *err)
+{
+ ssize_t nread;
+ char *inbuf;
+ ssize_t rv;
+
+ nread = httpc->inbuflen - httpc->nread_inbuf;
+ inbuf = httpc->inbuf + httpc->nread_inbuf;
+
+ rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
+ if(rv < 0) {
+ failf(data,
+ "h2_process_pending_input: nghttp2_session_mem_recv() returned "
+ "%d:%s\n", rv, nghttp2_strerror((int)rv));
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ if(nread == rv) {
+ DEBUGF(infof(data,
+ "h2_process_pending_input: All data in connection buffer "
+ "processed\n"));
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+ }
+ else {
+ httpc->nread_inbuf += rv;
+ DEBUGF(infof(data,
+ "h2_process_pending_input: %zu bytes left in connection "
+ "buffer\n",
+ httpc->inbuflen - httpc->nread_inbuf));
+ }
+
+ rv = h2_session_send(data, httpc->h2);
+ if(rv != 0) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(data,
+ "h2_process_pending_input: nothing to do in this session\n"));
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Called from transfer.c:done_sending when we stop uploading.
+ */
+CURLcode Curl_http2_done_sending(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ if((conn->handler == &Curl_handler_http2_ssl) ||
+ (conn->handler == &Curl_handler_http2)) {
+ /* make sure this is only attempted for HTTP/2 transfers */
+
+ struct HTTP *stream = conn->data->req.protop;
+
+ if(stream->upload_left) {
+ /* If the stream still thinks there's data left to upload. */
+ struct http_conn *httpc = &conn->proto.httpc;
+ nghttp2_session *h2 = httpc->h2;
+
+ stream->upload_left = 0; /* DONE! */
+
+ /* resume sending here to trigger the callback to get called again so
+ that it can signal EOF to nghttp2 */
+ (void)nghttp2_session_resume_data(h2, stream->stream_id);
+
+ (void)h2_process_pending_input(conn->data, httpc, &result);
+ }
+ }
+ return result;
+}
+
+
+static ssize_t http2_handle_stream_close(struct connectdata *conn,
+ struct Curl_easy *data,
+ struct HTTP *stream, CURLcode *err)
+{
+ char *trailer_pos, *trailer_end;
+ CURLcode result;
+ struct http_conn *httpc = &conn->proto.httpc;
+
+ if(httpc->pause_stream_id == stream->stream_id) {
+ httpc->pause_stream_id = 0;
+ }
+
+ DEBUGASSERT(httpc->drain_total >= data->state.drain);
+ httpc->drain_total -= data->state.drain;
+ data->state.drain = 0;
+
+ if(httpc->pause_stream_id == 0) {
+ if(h2_process_pending_input(data, httpc, err) != 0) {
+ return -1;
+ }
+ }
+
+ DEBUGASSERT(data->state.drain == 0);
+
+ /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
+ stream->closed = FALSE;
+ if(stream->error_code != NGHTTP2_NO_ERROR) {
+ failf(data, "HTTP/2 stream %u was not closed cleanly: %s (err %d)",
+ stream->stream_id, Curl_http2_strerror(stream->error_code),
+ stream->error_code);
+ *err = CURLE_HTTP2_STREAM;
+ return -1;
+ }
+
+ if(!stream->bodystarted) {
+ failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
+ " all response header fields, teated as error",
+ stream->stream_id);
+ *err = CURLE_HTTP2_STREAM;
+ return -1;
+ }
+
+ if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
+ trailer_pos = stream->trailer_recvbuf->buffer;
+ trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
+
+ for(; trailer_pos < trailer_end;) {
+ uint32_t n;
+ memcpy(&n, trailer_pos, sizeof(n));
+ trailer_pos += sizeof(n);
+
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
+ if(result) {
+ *err = result;
+ return -1;
+ }
+
+ trailer_pos += n + 1;
+ }
+ }
+
+ stream->close_handled = TRUE;
+
+ DEBUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
+ return 0;
+}
+
+/*
+ * h2_pri_spec() fills in the pri_spec struct, used by nghttp2 to send weight
+ * and dependency to the peer. It also stores the updated values in the state
+ * struct.
+ */
+
+static void h2_pri_spec(struct Curl_easy *data,
+ nghttp2_priority_spec *pri_spec)
+{
+ struct HTTP *depstream = (data->set.stream_depends_on?
+ data->set.stream_depends_on->req.protop:NULL);
+ int32_t depstream_id = depstream? depstream->stream_id:0;
+ nghttp2_priority_spec_init(pri_spec, depstream_id, data->set.stream_weight,
+ data->set.stream_depends_e);
+ data->state.stream_weight = data->set.stream_weight;
+ data->state.stream_depends_e = data->set.stream_depends_e;
+ data->state.stream_depends_on = data->set.stream_depends_on;
+}
+
+/*
+ * h2_session_send() checks if there's been an update in the priority /
+ * dependency settings and if so it submits a PRIORITY frame with the updated
+ * info.
+ */
+static int h2_session_send(struct Curl_easy *data,
+ nghttp2_session *h2)
+{
+ struct HTTP *stream = data->req.protop;
+ if((data->set.stream_weight != data->state.stream_weight) ||
+ (data->set.stream_depends_e != data->state.stream_depends_e) ||
+ (data->set.stream_depends_on != data->state.stream_depends_on) ) {
+ /* send new weight and/or dependency */
+ nghttp2_priority_spec pri_spec;
+ int rv;
+
+ h2_pri_spec(data, &pri_spec);
+
+ DEBUGF(infof(data, "Queuing PRIORITY on stream %u (easy %p)\n",
+ stream->stream_id, data));
+ rv = nghttp2_submit_priority(h2, NGHTTP2_FLAG_NONE, stream->stream_id,
+ &pri_spec);
+ if(rv)
+ return rv;
+ }
+
+ return nghttp2_session_send(h2);
+}
+
+static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ CURLcode result = CURLE_OK;
+ ssize_t rv;
+ ssize_t nread;
+ struct http_conn *httpc = &conn->proto.httpc;
+ struct Curl_easy *data = conn->data;
+ struct HTTP *stream = data->req.protop;
+
+ (void)sockindex; /* we always do HTTP2 on sockindex 0 */
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(data,
+ "http2_recv: nothing to do in this session\n"));
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+
+ /* Nullify here because we call nghttp2_session_send() and they
+ might refer to the old buffer. */
+ stream->upload_mem = NULL;
+ stream->upload_len = 0;
+
+ /*
+ * At this point 'stream' is just in the Curl_easy the connection
+ * identifies as its owner at this time.
+ */
+
+ if(stream->bodystarted &&
+ stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
+ /* If there is body data pending for this stream to return, do that */
+ size_t left =
+ stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
+ size_t ncopy = MIN(len, left);
+ memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
+ ncopy);
+ stream->nread_header_recvbuf += ncopy;
+
+ DEBUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
+ (int)ncopy));
+ return ncopy;
+ }
+
+ DEBUGF(infof(data, "http2_recv: easy %p (stream %u)\n",
+ data, stream->stream_id));
+
+ if((data->state.drain) && stream->memlen) {
+ DEBUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)\n",
+ stream->memlen, stream->stream_id,
+ stream->mem, mem));
+ if(mem != stream->mem) {
+ /* if we didn't get the same buffer this time, we must move the data to
+ the beginning */
+ memmove(mem, stream->mem, stream->memlen);
+ stream->len = len - stream->memlen;
+ stream->mem = mem;
+ }
+ if(httpc->pause_stream_id == stream->stream_id && !stream->pausedata) {
+ /* We have paused nghttp2, but we have no pause data (see
+ on_data_chunk_recv). */
+ httpc->pause_stream_id = 0;
+ if(h2_process_pending_input(data, httpc, &result) != 0) {
+ *err = result;
+ return -1;
+ }
+ }
+ }
+ else if(stream->pausedata) {
+ DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
+ nread = MIN(len, stream->pauselen);
+ memcpy(mem, stream->pausedata, nread);
+
+ stream->pausedata += nread;
+ stream->pauselen -= nread;
+
+ infof(data, "%zu data bytes written\n", nread);
+ if(stream->pauselen == 0) {
+ DEBUGF(infof(data, "Unpaused by stream %u\n", stream->stream_id));
+ DEBUGASSERT(httpc->pause_stream_id == stream->stream_id);
+ httpc->pause_stream_id = 0;
+
+ stream->pausedata = NULL;
+ stream->pauselen = 0;
+
+ /* When NGHTTP2_ERR_PAUSE is returned from
+ data_source_read_callback, we might not process DATA frame
+ fully. Calling nghttp2_session_mem_recv() again will
+ continue to process DATA frame, but if there is no incoming
+ frames, then we have to call it again with 0-length data.
+ Without this, on_stream_close callback will not be called,
+ and stream could be hanged. */
+ if(h2_process_pending_input(data, httpc, &result) != 0) {
+ *err = result;
+ return -1;
+ }
+ }
+ DEBUGF(infof(data, "http2_recv: returns unpaused %zd bytes on stream %u\n",
+ nread, stream->stream_id));
+ return nread;
+ }
+ else if(httpc->pause_stream_id) {
+ /* If a stream paused nghttp2_session_mem_recv previously, and has
+ not processed all data, it still refers to the buffer in
+ nghttp2_session. If we call nghttp2_session_mem_recv(), we may
+ overwrite that buffer. To avoid that situation, just return
+ here with CURLE_AGAIN. This could be busy loop since data in
+ socket is not read. But it seems that usually streams are
+ notified with its drain property, and socket is read again
+ quickly. */
+ DEBUGF(infof(data, "stream %x is paused, pause id: %x\n",
+ stream->stream_id, httpc->pause_stream_id));
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+ else {
+ char *inbuf;
+ /* remember where to store incoming data for this stream and how big the
+ buffer is */
+ stream->mem = mem;
+ stream->len = len;
+ stream->memlen = 0;
+
+ if(httpc->inbuflen == 0) {
+ nread = ((Curl_recv *)httpc->recv_underlying)(
+ conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
+
+ if(nread == -1) {
+ if(result != CURLE_AGAIN)
+ failf(data, "Failed receiving HTTP2 data");
+ else if(stream->closed)
+ /* received when the stream was already closed! */
+ return http2_handle_stream_close(conn, data, stream, err);
+
+ *err = result;
+ return -1;
+ }
+
+ if(nread == 0) {
+ failf(data, "Unexpected EOF");
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ DEBUGF(infof(data, "nread=%zd\n", nread));
+
+ httpc->inbuflen = nread;
+ inbuf = httpc->inbuf;
+ }
+ else {
+ nread = httpc->inbuflen - httpc->nread_inbuf;
+ inbuf = httpc->inbuf + httpc->nread_inbuf;
+
+ DEBUGF(infof(data, "Use data left in connection buffer, nread=%zd\n",
+ nread));
+ }
+ rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
+
+ if(nghttp2_is_fatal((int)rv)) {
+ failf(data, "nghttp2_session_mem_recv() returned %d:%s\n",
+ rv, nghttp2_strerror((int)rv));
+ *err = CURLE_RECV_ERROR;
+ return 0;
+ }
+ DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", rv));
+ if(nread == rv) {
+ DEBUGF(infof(data, "All data in connection buffer processed\n"));
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+ }
+ else {
+ httpc->nread_inbuf += rv;
+ DEBUGF(infof(data, "%zu bytes left in connection buffer\n",
+ httpc->inbuflen - httpc->nread_inbuf));
+ }
+ /* Always send pending frames in nghttp2 session, because
+ nghttp2_session_mem_recv() may queue new frame */
+ rv = h2_session_send(data, httpc->h2);
+ if(rv != 0) {
+ *err = CURLE_SEND_ERROR;
+ return 0;
+ }
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(data, "http2_recv: nothing to do in this session\n"));
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+ }
+ if(stream->memlen) {
+ ssize_t retlen = stream->memlen;
+ DEBUGF(infof(data, "http2_recv: returns %zd for stream %u\n",
+ retlen, stream->stream_id));
+ stream->memlen = 0;
+
+ if(httpc->pause_stream_id == stream->stream_id) {
+ /* data for this stream is returned now, but this stream caused a pause
+ already so we need it called again asap */
+ DEBUGF(infof(data, "Data returned for PAUSED stream %u\n",
+ stream->stream_id));
+ }
+ else if(!stream->closed) {
+ DEBUGASSERT(httpc->drain_total >= data->state.drain);
+ httpc->drain_total -= data->state.drain;
+ data->state.drain = 0; /* this stream is hereby drained */
+ }
+
+ return retlen;
+ }
+ /* If stream is closed, return 0 to signal the http routine to close
+ the connection */
+ if(stream->closed) {
+ return http2_handle_stream_close(conn, data, stream, err);
+ }
+ *err = CURLE_AGAIN;
+ DEBUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
+ stream->stream_id));
+ return -1;
+}
+
+/* Index where :authority header field will appear in request header
+ field list. */
+#define AUTHORITY_DST_IDX 3
+
+#define HEADER_OVERFLOW(x) \
+ (x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
+
+/*
+ * Check header memory for the token "trailers".
+ * Parse the tokens as separated by comma and surrounded by whitespace.
+ * Returns TRUE if found or FALSE if not.
+ */
+static bool contains_trailers(const char *p, size_t len)
+{
+ const char *end = p + len;
+ for(;;) {
+ for(; p != end && (*p == ' ' || *p == '\t'); ++p)
+ ;
+ if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
+ return FALSE;
+ if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
+ p += sizeof("trailers") - 1;
+ for(; p != end && (*p == ' ' || *p == '\t'); ++p)
+ ;
+ if(p == end || *p == ',')
+ return TRUE;
+ }
+ /* skip to next token */
+ for(; p != end && *p != ','; ++p)
+ ;
+ if(p == end)
+ return FALSE;
+ ++p;
+ }
+}
+
+typedef enum {
+ /* Send header to server */
+ HEADERINST_FORWARD,
+ /* Don't send header to server */
+ HEADERINST_IGNORE,
+ /* Discard header, and replace it with "te: trailers" */
+ HEADERINST_TE_TRAILERS
+} header_instruction;
+
+/* Decides how to treat given header field. */
+static header_instruction inspect_header(const char *name, size_t namelen,
+ const char *value, size_t valuelen) {
+ switch(namelen) {
+ case 2:
+ if(!strncasecompare("te", name, namelen))
+ return HEADERINST_FORWARD;
+
+ return contains_trailers(value, valuelen) ?
+ HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
+ case 7:
+ return strncasecompare("upgrade", name, namelen) ?
+ HEADERINST_IGNORE : HEADERINST_FORWARD;
+ case 10:
+ return (strncasecompare("connection", name, namelen) ||
+ strncasecompare("keep-alive", name, namelen)) ?
+ HEADERINST_IGNORE : HEADERINST_FORWARD;
+ case 16:
+ return strncasecompare("proxy-connection", name, namelen) ?
+ HEADERINST_IGNORE : HEADERINST_FORWARD;
+ case 17:
+ return strncasecompare("transfer-encoding", name, namelen) ?
+ HEADERINST_IGNORE : HEADERINST_FORWARD;
+ default:
+ return HEADERINST_FORWARD;
+ }
+}
+
+static ssize_t http2_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ /*
+ * BIG TODO: Currently, we send request in this function, but this
+ * function is also used to send request body. It would be nice to
+ * add dedicated function for request.
+ */
+ int rv;
+ struct http_conn *httpc = &conn->proto.httpc;
+ struct HTTP *stream = conn->data->req.protop;
+ nghttp2_nv *nva = NULL;
+ size_t nheader;
+ size_t i;
+ size_t authority_idx;
+ char *hdbuf = (char *)mem;
+ char *end, *line_end;
+ nghttp2_data_provider data_prd;
+ int32_t stream_id;
+ nghttp2_session *h2 = httpc->h2;
+ nghttp2_priority_spec pri_spec;
+
+ (void)sockindex;
+
+ DEBUGF(infof(conn->data, "http2_send len=%zu\n", len));
+
+ if(stream->stream_id != -1) {
+ if(stream->close_handled) {
+ infof(conn->data, "stream %d closed\n", stream->stream_id);
+ *err = CURLE_HTTP2_STREAM;
+ return -1;
+ }
+ else if(stream->closed) {
+ return http2_handle_stream_close(conn, conn->data, stream, err);
+ }
+ /* If stream_id != -1, we have dispatched request HEADERS, and now
+ are going to send or sending request body in DATA frame */
+ stream->upload_mem = mem;
+ stream->upload_len = len;
+ nghttp2_session_resume_data(h2, stream->stream_id);
+ rv = h2_session_send(conn->data, h2);
+ if(nghttp2_is_fatal(rv)) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+ len -= stream->upload_len;
+
+ /* Nullify here because we call nghttp2_session_send() and they
+ might refer to the old buffer. */
+ stream->upload_mem = NULL;
+ stream->upload_len = 0;
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+
+ if(stream->upload_left) {
+ /* we are sure that we have more data to send here. Calling the
+ following API will make nghttp2_session_want_write() return
+ nonzero if remote window allows it, which then libcurl checks
+ socket is writable or not. See http2_perform_getsock(). */
+ nghttp2_session_resume_data(h2, stream->stream_id);
+ }
+
+ DEBUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
+ stream->stream_id));
+ return len;
+ }
+
+ /* Calculate number of headers contained in [mem, mem + len) */
+ /* Here, we assume the curl http code generate *correct* HTTP header
+ field block */
+ nheader = 0;
+ for(i = 1; i < len; ++i) {
+ if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
+ ++nheader;
+ ++i;
+ }
+ }
+ if(nheader < 2)
+ goto fail;
+
+ /* We counted additional 2 \r\n in the first and last line. We need 3
+ new headers: :method, :path and :scheme. Therefore we need one
+ more space. */
+ nheader += 1;
+ nva = malloc(sizeof(nghttp2_nv) * nheader);
+ if(nva == NULL) {
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+
+ /* Extract :method, :path from request line */
+ line_end = strstr(hdbuf, "\r\n");
+
+ /* Method does not contain spaces */
+ end = memchr(hdbuf, ' ', line_end - hdbuf);
+ if(!end || end == hdbuf)
+ goto fail;
+ nva[0].name = (unsigned char *)":method";
+ nva[0].namelen = strlen((char *)nva[0].name);
+ nva[0].value = (unsigned char *)hdbuf;
+ nva[0].valuelen = (size_t)(end - hdbuf);
+ nva[0].flags = NGHTTP2_NV_FLAG_NONE;
+ if(HEADER_OVERFLOW(nva[0])) {
+ failf(conn->data, "Failed sending HTTP request: Header overflow");
+ goto fail;
+ }
+
+ hdbuf = end + 1;
+
+ /* Path may contain spaces so scan backwards */
+ end = NULL;
+ for(i = (size_t)(line_end - hdbuf); i; --i) {
+ if(hdbuf[i - 1] == ' ') {
+ end = &hdbuf[i - 1];
+ break;
+ }
+ }
+ if(!end || end == hdbuf)
+ goto fail;
+ nva[1].name = (unsigned char *)":path";
+ nva[1].namelen = strlen((char *)nva[1].name);
+ nva[1].value = (unsigned char *)hdbuf;
+ nva[1].valuelen = (size_t)(end - hdbuf);
+ nva[1].flags = NGHTTP2_NV_FLAG_NONE;
+ if(HEADER_OVERFLOW(nva[1])) {
+ failf(conn->data, "Failed sending HTTP request: Header overflow");
+ goto fail;
+ }
+
+ hdbuf = end + 1;
+
+ end = line_end;
+ nva[2].name = (unsigned char *)":scheme";
+ nva[2].namelen = strlen((char *)nva[2].name);
+ if(conn->handler->flags & PROTOPT_SSL)
+ nva[2].value = (unsigned char *)"https";
+ else
+ nva[2].value = (unsigned char *)"http";
+ nva[2].valuelen = strlen((char *)nva[2].value);
+ nva[2].flags = NGHTTP2_NV_FLAG_NONE;
+ if(HEADER_OVERFLOW(nva[2])) {
+ failf(conn->data, "Failed sending HTTP request: Header overflow");
+ goto fail;
+ }
+
+ authority_idx = 0;
+ i = 3;
+ while(i < nheader) {
+ size_t hlen;
+
+ hdbuf = line_end + 2;
+
+ line_end = strstr(hdbuf, "\r\n");
+ if(line_end == hdbuf)
+ goto fail;
+
+ /* header continuation lines are not supported */
+ if(*hdbuf == ' ' || *hdbuf == '\t')
+ goto fail;
+
+ for(end = hdbuf; end < line_end && *end != ':'; ++end)
+ ;
+ if(end == hdbuf || end == line_end)
+ goto fail;
+ hlen = end - hdbuf;
+
+ if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
+ authority_idx = i;
+ nva[i].name = (unsigned char *)":authority";
+ nva[i].namelen = strlen((char *)nva[i].name);
+ }
+ else {
+ nva[i].name = (unsigned char *)hdbuf;
+ nva[i].namelen = (size_t)(end - hdbuf);
+ }
+ hdbuf = end + 1;
+ while(*hdbuf == ' ' || *hdbuf == '\t')
+ ++hdbuf;
+ end = line_end;
+
+ switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
+ end - hdbuf)) {
+ case HEADERINST_IGNORE:
+ /* skip header fields prohibited by HTTP/2 specification. */
+ --nheader;
+ continue;
+ case HEADERINST_TE_TRAILERS:
+ nva[i].value = (uint8_t*)"trailers";
+ nva[i].valuelen = sizeof("trailers") - 1;
+ break;
+ default:
+ nva[i].value = (unsigned char *)hdbuf;
+ nva[i].valuelen = (size_t)(end - hdbuf);
+ }
+
+ nva[i].flags = NGHTTP2_NV_FLAG_NONE;
+ if(HEADER_OVERFLOW(nva[i])) {
+ failf(conn->data, "Failed sending HTTP request: Header overflow");
+ goto fail;
+ }
+ ++i;
+ }
+
+ /* :authority must come before non-pseudo header fields */
+ if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
+ nghttp2_nv authority = nva[authority_idx];
+ for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
+ nva[i] = nva[i - 1];
+ }
+ nva[i] = authority;
+ }
+
+ /* Warn stream may be rejected if cumulative length of headers is too large.
+ It appears nghttp2 will not send a header frame larger than 64KB. */
+#define MAX_ACC 60000 /* <64KB to account for some overhead */
+ {
+ size_t acc = 0;
+
+ for(i = 0; i < nheader; ++i) {
+ acc += nva[i].namelen + nva[i].valuelen;
+
+ DEBUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
+ nva[i].namelen, nva[i].name,
+ nva[i].valuelen, nva[i].value));
+ }
+
+ if(acc > MAX_ACC) {
+ infof(conn->data, "http2_send: Warning: The cumulative length of all "
+ "headers exceeds %zu bytes and that could cause the "
+ "stream to be rejected.\n", MAX_ACC);
+ }
+ }
+
+ h2_pri_spec(conn->data, &pri_spec);
+
+ switch(conn->data->set.httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ case HTTPREQ_PUT:
+ if(conn->data->state.infilesize != -1)
+ stream->upload_left = conn->data->state.infilesize;
+ else
+ /* data sending without specifying the data amount up front */
+ stream->upload_left = -1; /* unknown, but not zero */
+
+ data_prd.read_callback = data_source_read_callback;
+ data_prd.source.ptr = NULL;
+ stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
+ &data_prd, conn->data);
+ break;
+ default:
+ stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
+ NULL, conn->data);
+ }
+
+ Curl_safefree(nva);
+
+ if(stream_id < 0) {
+ DEBUGF(infof(conn->data, "http2_send() send error\n"));
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
+ stream_id, conn->data);
+ stream->stream_id = stream_id;
+
+ /* this does not call h2_session_send() since there can not have been any
+ * priority upodate since the nghttp2_submit_request() call above */
+ rv = nghttp2_session_send(h2);
+
+ if(rv != 0) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+ *err = CURLE_HTTP2;
+ return -1;
+ }
+
+ if(stream->stream_id != -1) {
+ /* If whole HEADERS frame was sent off to the underlying socket,
+ the nghttp2 library calls data_source_read_callback. But only
+ it found that no data available, so it deferred the DATA
+ transmission. Which means that nghttp2_session_want_write()
+ returns 0 on http2_perform_getsock(), which results that no
+ writable socket check is performed. To workaround this, we
+ issue nghttp2_session_resume_data() here to bring back DATA
+ transmission from deferred state. */
+ nghttp2_session_resume_data(h2, stream->stream_id);
+ }
+
+ return len;
+
+fail:
+ free(nva);
+ *err = CURLE_SEND_ERROR;
+ return -1;
+}
+
+CURLcode Curl_http2_setup(struct connectdata *conn)
+{
+ CURLcode result;
+ struct http_conn *httpc = &conn->proto.httpc;
+ struct HTTP *stream = conn->data->req.protop;
+
+ stream->stream_id = -1;
+
+ if(!stream->header_recvbuf)
+ stream->header_recvbuf = Curl_add_buffer_init();
+
+ if((conn->handler == &Curl_handler_http2_ssl) ||
+ (conn->handler == &Curl_handler_http2))
+ return CURLE_OK; /* already done */
+
+ if(conn->handler->flags & PROTOPT_SSL)
+ conn->handler = &Curl_handler_http2_ssl;
+ else
+ conn->handler = &Curl_handler_http2;
+
+ result = Curl_http2_init(conn);
+ if(result)
+ return result;
+
+ infof(conn->data, "Using HTTP2, server supports multi-use\n");
+ stream->upload_left = 0;
+ stream->upload_mem = NULL;
+ stream->upload_len = 0;
+
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+
+ httpc->pause_stream_id = 0;
+ httpc->drain_total = 0;
+
+ conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
+ conn->httpversion = 20;
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+
+ infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
+ Curl_multi_connchanged(conn->data->multi);
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_http2_switched(struct connectdata *conn,
+ const char *mem, size_t nread)
+{
+ CURLcode result;
+ struct http_conn *httpc = &conn->proto.httpc;
+ int rv;
+ ssize_t nproc;
+ struct Curl_easy *data = conn->data;
+ struct HTTP *stream = conn->data->req.protop;
+
+ result = Curl_http2_setup(conn);
+ if(result)
+ return result;
+
+ httpc->recv_underlying = (recving)conn->recv[FIRSTSOCKET];
+ httpc->send_underlying = (sending)conn->send[FIRSTSOCKET];
+ conn->recv[FIRSTSOCKET] = http2_recv;
+ conn->send[FIRSTSOCKET] = http2_send;
+
+ if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
+ /* stream 1 is opened implicitly on upgrade */
+ stream->stream_id = 1;
+ /* queue SETTINGS frame (again) */
+ rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
+ httpc->binlen, NULL);
+ if(rv != 0) {
+ failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+
+ nghttp2_session_set_stream_user_data(httpc->h2,
+ stream->stream_id,
+ conn->data);
+ }
+ else {
+ populate_settings(conn, httpc);
+
+ /* stream ID is unknown at this point */
+ stream->stream_id = -1;
+ rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
+ httpc->local_settings,
+ httpc->local_settings_num);
+ if(rv != 0) {
+ failf(data, "nghttp2_submit_settings() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+ }
+
+#ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
+ rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
+ HTTP2_HUGE_WINDOW_SIZE);
+ if(rv != 0) {
+ failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+#endif
+
+ /* we are going to copy mem to httpc->inbuf. This is required since
+ mem is part of buffer pointed by stream->mem, and callbacks
+ called by nghttp2_session_mem_recv() will write stream specific
+ data into stream->mem, overwriting data already there. */
+ if(H2_BUFSIZE < nread) {
+ failf(data, "connection buffer size is too small to store data following "
+ "HTTP Upgrade response header: buflen=%zu, datalen=%zu",
+ H2_BUFSIZE, nread);
+ return CURLE_HTTP2;
+ }
+
+ infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
+ " after upgrade: len=%zu\n",
+ nread);
+
+ if(nread)
+ memcpy(httpc->inbuf, mem, nread);
+ httpc->inbuflen = nread;
+
+ nproc = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)httpc->inbuf,
+ httpc->inbuflen);
+
+ if(nghttp2_is_fatal((int)nproc)) {
+ failf(data, "nghttp2_session_mem_recv() failed: %s(%d)",
+ nghttp2_strerror((int)nproc), (int)nproc);
+ return CURLE_HTTP2;
+ }
+
+ DEBUGF(infof(data, "nghttp2_session_mem_recv() returns %zd\n", nproc));
+
+ if((ssize_t)nread == nproc) {
+ httpc->inbuflen = 0;
+ httpc->nread_inbuf = 0;
+ }
+ else {
+ httpc->nread_inbuf += nproc;
+ }
+
+ /* Try to send some frames since we may read SETTINGS already. */
+ rv = h2_session_send(data, httpc->h2);
+
+ if(rv != 0) {
+ failf(data, "nghttp2_session_send() failed: %s(%d)",
+ nghttp2_strerror(rv), rv);
+ return CURLE_HTTP2;
+ }
+
+ if(should_close_session(httpc)) {
+ DEBUGF(infof(data,
+ "nghttp2_session_send(): nothing to do in this session\n"));
+ return CURLE_HTTP2;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
+ bool exclusive)
+{
+ if(parent) {
+ struct Curl_http2_dep **tail;
+ struct Curl_http2_dep *dep = calloc(1, sizeof(struct Curl_http2_dep));
+ dep->data = child;
+
+ if(parent->set.stream_dependents && exclusive) {
+ struct Curl_http2_dep *node = parent->set.stream_dependents;
+ while(node) {
+ node->data->set.stream_depends_on = child;
+ node = node->next;
+ }
+
+ tail = &child->set.stream_dependents;
+ while(*tail)
+ tail = &(*tail)->next;
+
+ DEBUGASSERT(!*tail);
+ *tail = parent->set.stream_dependents;
+ parent->set.stream_dependents = 0;
+ }
+
+ tail = &parent->set.stream_dependents;
+ while(*tail) {
+ (*tail)->data->set.stream_depends_e = FALSE;
+ tail = &(*tail)->next;
+ }
+
+ DEBUGASSERT(!*tail);
+ *tail = dep;
+ }
+
+ child->set.stream_depends_on = parent;
+ child->set.stream_depends_e = exclusive;
+}
+
+void Curl_http2_remove_child(struct Curl_easy *parent, struct Curl_easy *child)
+{
+ struct Curl_http2_dep *last = 0;
+ struct Curl_http2_dep *data = parent->set.stream_dependents;
+ DEBUGASSERT(child->set.stream_depends_on == parent);
+
+ while(data && data->data != child) {
+ last = data;
+ data = data->next;
+ }
+
+ DEBUGASSERT(data);
+
+ if(data) {
+ if(last) {
+ last->next = data->next;
+ }
+ else {
+ parent->set.stream_dependents = data->next;
+ }
+ free(data);
+ }
+
+ child->set.stream_depends_on = 0;
+ child->set.stream_depends_e = FALSE;
+}
+
+void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
+{
+ while(data->set.stream_dependents) {
+ struct Curl_easy *tmp = data->set.stream_dependents->data;
+ Curl_http2_remove_child(data, tmp);
+ if(data->set.stream_depends_on)
+ Curl_http2_add_child(data->set.stream_depends_on, tmp, FALSE);
+ }
+
+ if(data->set.stream_depends_on)
+ Curl_http2_remove_child(data->set.stream_depends_on, data);
+}
+
+#else /* !USE_NGHTTP2 */
+
+/* Satisfy external references even if http2 is not compiled in. */
+
+#define CURL_DISABLE_TYPECHECK
+#include <curl/curl.h>
+
+char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
+{
+ (void) h;
+ (void) num;
+ return NULL;
+}
+
+char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header)
+{
+ (void) h;
+ (void) header;
+ return NULL;
+}
+
+#endif /* USE_NGHTTP2 */
diff --git a/Utilities/cmcurl/lib/http2.h b/Utilities/cmcurl/lib/http2.h
new file mode 100644
index 000000000..f405b3aeb
--- /dev/null
+++ b/Utilities/cmcurl/lib/http2.h
@@ -0,0 +1,79 @@
+#ifndef HEADER_CURL_HTTP2_H
+#define HEADER_CURL_HTTP2_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NGHTTP2
+#include "http.h"
+
+/* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
+ from the peer */
+#define DEFAULT_MAX_CONCURRENT_STREAMS 13
+
+/*
+ * Store nghttp2 version info in this buffer, Prefix with a space. Return
+ * total length written.
+ */
+int Curl_http2_ver(char *p, size_t len);
+
+const char *Curl_http2_strerror(uint32_t err);
+
+CURLcode Curl_http2_init(struct connectdata *conn);
+void Curl_http2_init_state(struct UrlState *state);
+void Curl_http2_init_userset(struct UserDefined *set);
+CURLcode Curl_http2_send_request(struct connectdata *conn);
+CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
+ struct connectdata *conn);
+CURLcode Curl_http2_setup(struct connectdata *conn);
+CURLcode Curl_http2_switched(struct connectdata *conn,
+ const char *data, size_t nread);
+/* called from Curl_http_setup_conn */
+void Curl_http2_setup_conn(struct connectdata *conn);
+void Curl_http2_setup_req(struct Curl_easy *data);
+void Curl_http2_done(struct connectdata *conn, bool premature);
+CURLcode Curl_http2_done_sending(struct connectdata *conn);
+void Curl_http2_add_child(struct Curl_easy *parent, struct Curl_easy *child,
+ bool exclusive);
+void Curl_http2_remove_child(struct Curl_easy *parent,
+ struct Curl_easy *child);
+void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
+#else /* USE_NGHTTP2 */
+#define Curl_http2_init(x) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_send_request(x) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_setup_conn(x)
+#define Curl_http2_setup_req(x)
+#define Curl_http2_init_state(x)
+#define Curl_http2_init_userset(x)
+#define Curl_http2_done(x,y)
+#define Curl_http2_done_sending(x)
+#define Curl_http2_add_child(x, y, z)
+#define Curl_http2_remove_child(x, y)
+#define Curl_http2_cleanup_dependencies(x)
+#endif
+
+#endif /* HEADER_CURL_HTTP2_H */
+
diff --git a/Utilities/cmcurl/lib/http_chunks.c b/Utilities/cmcurl/lib/http_chunks.c
new file mode 100644
index 000000000..1bdf6974c
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_chunks.c
@@ -0,0 +1,381 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h" /* it includes http_chunks.h */
+#include "sendf.h" /* for the client write stuff */
+
+#include "content_encoding.h"
+#include "http.h"
+#include "non-ascii.h" /* for Curl_convert_to_network prototype */
+#include "strtoofft.h"
+#include "warnless.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Chunk format (simplified):
+ *
+ * <HEX SIZE>[ chunk extension ] CRLF
+ * <DATA> CRLF
+ *
+ * Highlights from RFC2616 section 3.6 say:
+
+ The chunked encoding modifies the body of a message in order to
+ transfer it as a series of chunks, each with its own size indicator,
+ followed by an OPTIONAL trailer containing entity-header fields. This
+ allows dynamically produced content to be transferred along with the
+ information necessary for the recipient to verify that it has
+ received the full message.
+
+ Chunked-Body = *chunk
+ last-chunk
+ trailer
+ CRLF
+
+ chunk = chunk-size [ chunk-extension ] CRLF
+ chunk-data CRLF
+ chunk-size = 1*HEX
+ last-chunk = 1*("0") [ chunk-extension ] CRLF
+
+ chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ chunk-ext-name = token
+ chunk-ext-val = token | quoted-string
+ chunk-data = chunk-size(OCTET)
+ trailer = *(entity-header CRLF)
+
+ The chunk-size field is a string of hex digits indicating the size of
+ the chunk. The chunked encoding is ended by any chunk whose size is
+ zero, followed by the trailer, which is terminated by an empty line.
+
+ */
+
+/* Check for an ASCII hex digit.
+ We avoid the use of isxdigit to accommodate non-ASCII hosts. */
+static bool Curl_isxdigit(char digit)
+{
+ return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
+ || (digit >= 0x41 && digit <= 0x46) /* A-F */
+ || (digit >= 0x61 && digit <= 0x66) /* a-f */) ? TRUE : FALSE;
+}
+
+void Curl_httpchunk_init(struct connectdata *conn)
+{
+ struct Curl_chunker *chunk = &conn->chunk;
+ chunk->hexindex=0; /* start at 0 */
+ chunk->dataleft=0; /* no data left yet! */
+ chunk->state = CHUNK_HEX; /* we get hex first! */
+}
+
+/*
+ * chunk_read() returns a OK for normal operations, or a positive return code
+ * for errors. STOP means this sequence of chunks is complete. The 'wrote'
+ * argument is set to tell the caller how many bytes we actually passed to the
+ * client (for byte-counting and whatever).
+ *
+ * The states and the state-machine is further explained in the header file.
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
+ */
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+ char *datap,
+ ssize_t datalen,
+ ssize_t *wrotep)
+{
+ CURLcode result=CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct Curl_chunker *ch = &conn->chunk;
+ struct SingleRequest *k = &data->req;
+ size_t piece;
+ curl_off_t length = (curl_off_t)datalen;
+ size_t *wrote = (size_t *)wrotep;
+
+ *wrote = 0; /* nothing's written yet */
+
+ /* the original data is written to the client, but we go on with the
+ chunk read process, to properly calculate the content length*/
+ if(data->set.http_te_skip && !k->ignorebody) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+ }
+
+ while(length) {
+ switch(ch->state) {
+ case CHUNK_HEX:
+ if(Curl_isxdigit(*datap)) {
+ if(ch->hexindex < MAXNUM_SIZE) {
+ ch->hexbuffer[ch->hexindex] = *datap;
+ datap++;
+ length--;
+ ch->hexindex++;
+ }
+ else {
+ return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
+ }
+ }
+ else {
+ char *endptr;
+ if(0 == ch->hexindex)
+ /* This is illegal data, we received junk where we expected
+ a hexadecimal digit. */
+ return CHUNKE_ILLEGAL_HEX;
+
+ /* length and datap are unmodified */
+ ch->hexbuffer[ch->hexindex]=0;
+
+ /* convert to host encoding before calling strtoul */
+ result = Curl_convert_from_network(conn->data, ch->hexbuffer,
+ ch->hexindex);
+ if(result) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad hex character */
+ return CHUNKE_ILLEGAL_HEX;
+ }
+
+ ch->datasize=curlx_strtoofft(ch->hexbuffer, &endptr, 16);
+ if((ch->datasize == CURL_OFF_T_MAX) && (errno == ERANGE))
+ /* overflow is an error */
+ return CHUNKE_ILLEGAL_HEX;
+ ch->state = CHUNK_LF; /* now wait for the CRLF */
+ }
+ break;
+
+ case CHUNK_LF:
+ /* waiting for the LF after a chunk size */
+ if(*datap == 0x0a) {
+ /* we're now expecting data to come, unless size was zero! */
+ if(0 == ch->datasize) {
+ ch->state = CHUNK_TRAILER; /* now check for trailers */
+ conn->trlPos=0;
+ }
+ else
+ ch->state = CHUNK_DATA;
+ }
+
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_DATA:
+ /* We expect 'datasize' of data. We have 'length' right now, it can be
+ more or less than 'datasize'. Get the smallest piece.
+ */
+ piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
+
+ /* Write the data portion available */
+#ifdef HAVE_LIBZ
+ switch(conn->data->set.http_ce_skip?
+ IDENTITY : data->req.auto_decoding) {
+ case IDENTITY:
+#endif
+ if(!k->ignorebody) {
+ if(!data->set.http_te_skip)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
+ piece);
+ else
+ result = CURLE_OK;
+ }
+#ifdef HAVE_LIBZ
+ break;
+
+ case DEFLATE:
+ /* update data->req.keep.str to point to the chunk data. */
+ data->req.str = datap;
+ result = Curl_unencode_deflate_write(conn, &data->req,
+ (ssize_t)piece);
+ break;
+
+ case GZIP:
+ /* update data->req.keep.str to point to the chunk data. */
+ data->req.str = datap;
+ result = Curl_unencode_gzip_write(conn, &data->req,
+ (ssize_t)piece);
+ break;
+
+ default:
+ failf(conn->data,
+ "Unrecognized content encoding type. "
+ "libcurl understands `identity', `deflate' and `gzip' "
+ "content encodings.");
+ return CHUNKE_BAD_ENCODING;
+ }
+#endif
+
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+
+ *wrote += piece;
+
+ ch->datasize -= piece; /* decrease amount left to expect */
+ datap += piece; /* move read pointer forward */
+ length -= piece; /* decrease space left in this round */
+
+ if(0 == ch->datasize)
+ /* end of data this round, we now expect a trailing CRLF */
+ ch->state = CHUNK_POSTLF;
+ break;
+
+ case CHUNK_POSTLF:
+ if(*datap == 0x0a) {
+ /* The last one before we go back to hex state and start all over. */
+ Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */
+ }
+ else if(*datap != 0x0d)
+ return CHUNKE_BAD_CHUNK;
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_TRAILER:
+ if((*datap == 0x0d) || (*datap == 0x0a)) {
+ /* this is the end of a trailer, but if the trailer was zero bytes
+ there was no trailer and we move on */
+
+ if(conn->trlPos) {
+ /* we allocate trailer with 3 bytes extra room to fit this */
+ conn->trailer[conn->trlPos++]=0x0d;
+ conn->trailer[conn->trlPos++]=0x0a;
+ conn->trailer[conn->trlPos]=0;
+
+ /* Convert to host encoding before calling Curl_client_write */
+ result = Curl_convert_from_network(conn->data, conn->trailer,
+ conn->trlPos);
+ if(result)
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad chunk */
+ return CHUNKE_BAD_CHUNK;
+
+ if(!data->set.http_te_skip) {
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ conn->trailer, conn->trlPos);
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+ }
+ conn->trlPos=0;
+ ch->state = CHUNK_TRAILER_CR;
+ if(*datap == 0x0a)
+ /* already on the LF */
+ break;
+ }
+ else {
+ /* no trailer, we're on the final CRLF pair */
+ ch->state = CHUNK_TRAILER_POSTCR;
+ break; /* don't advance the pointer */
+ }
+ }
+ else {
+ /* conn->trailer is assumed to be freed in url.c on a
+ connection basis */
+ if(conn->trlPos >= conn->trlMax) {
+ /* we always allocate three extra bytes, just because when the full
+ header has been received we append CRLF\0 */
+ char *ptr;
+ if(conn->trlMax) {
+ conn->trlMax *= 2;
+ ptr = realloc(conn->trailer, conn->trlMax + 3);
+ }
+ else {
+ conn->trlMax=128;
+ ptr = malloc(conn->trlMax + 3);
+ }
+ if(!ptr)
+ return CHUNKE_OUT_OF_MEMORY;
+ conn->trailer = ptr;
+ }
+ conn->trailer[conn->trlPos++]=*datap;
+ }
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_TRAILER_CR:
+ if(*datap == 0x0a) {
+ ch->state = CHUNK_TRAILER_POSTCR;
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ break;
+
+ case CHUNK_TRAILER_POSTCR:
+ /* We enter this state when a CR should arrive so we expect to
+ have to first pass a CR before we wait for LF */
+ if((*datap != 0x0d) && (*datap != 0x0a)) {
+ /* not a CR then it must be another header in the trailer */
+ ch->state = CHUNK_TRAILER;
+ break;
+ }
+ if(*datap == 0x0d) {
+ /* skip if CR */
+ datap++;
+ length--;
+ }
+ /* now wait for the final LF */
+ ch->state = CHUNK_STOP;
+ break;
+
+ case CHUNK_STOP:
+ if(*datap == 0x0a) {
+ length--;
+
+ /* Record the length of any data left in the end of the buffer
+ even if there's no more chunks to read */
+ ch->dataleft = curlx_sotouz(length);
+
+ return CHUNKE_STOP; /* return stop */
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ }
+ }
+ return CHUNKE_OK;
+}
+
+const char *Curl_chunked_strerror(CHUNKcode code)
+{
+ switch(code) {
+ default:
+ return "OK";
+ case CHUNKE_TOO_LONG_HEX:
+ return "Too long hexadecimal number";
+ case CHUNKE_ILLEGAL_HEX:
+ return "Illegal or missing hexadecimal sequence";
+ case CHUNKE_BAD_CHUNK:
+ return "Malformed encoding found";
+ case CHUNKE_WRITE_ERROR:
+ return "Write error";
+ case CHUNKE_BAD_ENCODING:
+ return "Bad content-encoding found";
+ case CHUNKE_OUT_OF_MEMORY:
+ return "Out of memory";
+ }
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/Utilities/cmcurl/lib/http_chunks.h b/Utilities/cmcurl/lib/http_chunks.h
new file mode 100644
index 000000000..3a8b4ddf3
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_chunks.h
@@ -0,0 +1,91 @@
+#ifndef HEADER_CURL_HTTP_CHUNKS_H
+#define HEADER_CURL_HTTP_CHUNKS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
+ * to convert it, we "only" support 2^32 bytes chunk data.
+ */
+#define MAXNUM_SIZE 16
+
+typedef enum {
+ /* await and buffer all hexadecimal digits until we get one that isn't a
+ hexadecimal digit. When done, we go CHUNK_LF */
+ CHUNK_HEX,
+
+ /* wait for LF, ignore all else */
+ CHUNK_LF,
+
+ /* We eat the amount of data specified. When done, we move on to the
+ POST_CR state. */
+ CHUNK_DATA,
+
+ /* POSTLF should get a CR and then a LF and nothing else, then move back to
+ HEX as the CRLF combination marks the end of a chunk. A missing CR is no
+ big deal. */
+ CHUNK_POSTLF,
+
+ /* Used to mark that we're out of the game. NOTE: that there's a 'dataleft'
+ field in the struct that will tell how many bytes that were not passed to
+ the client in the end of the last buffer! */
+ CHUNK_STOP,
+
+ /* At this point optional trailer headers can be found, unless the next line
+ is CRLF */
+ CHUNK_TRAILER,
+
+ /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
+ Next char must be a LF */
+ CHUNK_TRAILER_CR,
+
+ /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be
+ signalled If this is an empty trailer CHUNKE_STOP will be signalled.
+ Otherwise the trailer will be broadcasted via Curl_client_write() and the
+ next state will be CHUNK_TRAILER */
+ CHUNK_TRAILER_POSTCR
+} ChunkyState;
+
+typedef enum {
+ CHUNKE_STOP = -1,
+ CHUNKE_OK = 0,
+ CHUNKE_TOO_LONG_HEX = 1,
+ CHUNKE_ILLEGAL_HEX,
+ CHUNKE_BAD_CHUNK,
+ CHUNKE_WRITE_ERROR,
+ CHUNKE_BAD_ENCODING,
+ CHUNKE_OUT_OF_MEMORY,
+ CHUNKE_LAST
+} CHUNKcode;
+
+const char *Curl_chunked_strerror(CHUNKcode code);
+
+struct Curl_chunker {
+ char hexbuffer[ MAXNUM_SIZE + 1];
+ int hexindex;
+ ChunkyState state;
+ curl_off_t datasize;
+ size_t dataleft; /* untouched data amount at the end of the last buffer */
+};
+
+#endif /* HEADER_CURL_HTTP_CHUNKS_H */
+
diff --git a/Utilities/cmcurl/lib/http_digest.c b/Utilities/cmcurl/lib/http_digest.c
new file mode 100644
index 000000000..e2d865b0a
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_digest.c
@@ -0,0 +1,180 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include "urldata.h"
+#include "strcase.h"
+#include "vauth/vauth.h"
+#include "http_digest.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Test example headers:
+
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
+Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
+
+*/
+
+CURLcode Curl_input_digest(struct connectdata *conn,
+ bool proxy,
+ const char *header) /* rest of the *-authenticate:
+ header */
+{
+ struct Curl_easy *data = conn->data;
+
+ /* Point to the correct struct with this */
+ struct digestdata *digest;
+
+ if(proxy) {
+ digest = &data->state.proxydigest;
+ }
+ else {
+ digest = &data->state.digest;
+ }
+
+ if(!checkprefix("Digest", header))
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ header += strlen("Digest");
+ while(*header && ISSPACE(*header))
+ header++;
+
+ return Curl_auth_decode_digest_http_message(header, digest);
+}
+
+CURLcode Curl_output_digest(struct connectdata *conn,
+ bool proxy,
+ const unsigned char *request,
+ const unsigned char *uripath)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ unsigned char *path = NULL;
+ char *tmp = NULL;
+ char *response;
+ size_t len;
+ bool have_chlg;
+
+ /* Point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+
+ /* Point to the name and password for this */
+ const char *userp;
+ const char *passwdp;
+
+ /* Point to the correct struct with this */
+ struct digestdata *digest;
+ struct auth *authp;
+
+ if(proxy) {
+ digest = &data->state.proxydigest;
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->http_proxy.user;
+ passwdp = conn->http_proxy.passwd;
+ authp = &data->state.authproxy;
+ }
+ else {
+ digest = &data->state.digest;
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ authp = &data->state.authhost;
+ }
+
+ Curl_safefree(*allocuserpwd);
+
+ /* not set means empty */
+ if(!userp)
+ userp = "";
+
+ if(!passwdp)
+ passwdp = "";
+
+#if defined(USE_WINDOWS_SSPI)
+ have_chlg = digest->input_token ? TRUE : FALSE;
+#else
+ have_chlg = digest->nonce ? TRUE : FALSE;
+#endif
+
+ if(!have_chlg) {
+ authp->done = FALSE;
+ return CURLE_OK;
+ }
+
+ /* So IE browsers < v7 cut off the URI part at the query part when they
+ evaluate the MD5 and some (IIS?) servers work with them so we may need to
+ do the Digest IE-style. Note that the different ways cause different MD5
+ sums to get sent.
+
+ Apache servers can be set to do the Digest IE-style automatically using
+ the BrowserMatch feature:
+ https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
+
+ Further details on Digest implementation differences:
+ http://www.fngtps.com/2006/09/http-authentication
+ */
+
+ if(authp->iestyle) {
+ tmp = strchr((char *)uripath, '?');
+ if(tmp) {
+ size_t urilen = tmp - (char *)uripath;
+ path = (unsigned char *) aprintf("%.*s", urilen, uripath);
+ }
+ }
+ if(!tmp)
+ path = (unsigned char *) strdup((char *) uripath);
+
+ if(!path)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_auth_create_digest_http_message(data, userp, passwdp, request,
+ path, digest, &response, &len);
+ free(path);
+ if(result)
+ return result;
+
+ *allocuserpwd = aprintf("%sAuthorization: Digest %s\r\n",
+ proxy ? "Proxy-" : "",
+ response);
+ free(response);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+
+ authp->done = TRUE;
+
+ return CURLE_OK;
+}
+
+void Curl_digest_cleanup(struct Curl_easy *data)
+{
+ Curl_auth_digest_cleanup(&data->state.digest);
+ Curl_auth_digest_cleanup(&data->state.proxydigest);
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/http_digest.h b/Utilities/cmcurl/lib/http_digest.h
new file mode 100644
index 000000000..fd225c7c1
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_digest.h
@@ -0,0 +1,42 @@
+#ifndef HEADER_CURL_HTTP_DIGEST_H
+#define HEADER_CURL_HTTP_DIGEST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* this is for digest header input */
+CURLcode Curl_input_digest(struct connectdata *conn,
+ bool proxy, const char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct connectdata *conn,
+ bool proxy,
+ const unsigned char *request,
+ const unsigned char *uripath);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+void Curl_digest_cleanup(struct Curl_easy *data);
+#else
+#define Curl_digest_cleanup(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_HTTP_DIGEST_H */
diff --git a/Utilities/cmcurl/lib/http_negotiate.c b/Utilities/cmcurl/lib/http_negotiate.c
new file mode 100644
index 000000000..51375e81d
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_negotiate.c
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+
+#include "urldata.h"
+#include "sendf.h"
+#include "http_negotiate.h"
+#include "vauth/vauth.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
+ const char *header)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ size_t len;
+
+ /* Point to the username, password, service and host */
+ const char *userp;
+ const char *passwdp;
+ const char *service;
+ const char *host;
+
+ /* Point to the correct struct with this */
+ struct negotiatedata *neg_ctx;
+
+ if(proxy) {
+ userp = conn->http_proxy.user;
+ passwdp = conn->http_proxy.passwd;
+ service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+ data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+ host = conn->http_proxy.host.name;
+ neg_ctx = &data->state.proxyneg;
+ }
+ else {
+ userp = conn->user;
+ passwdp = conn->passwd;
+ service = data->set.str[STRING_SERVICE_NAME] ?
+ data->set.str[STRING_SERVICE_NAME] : "HTTP";
+ host = conn->host.name;
+ neg_ctx = &data->state.negotiate;
+ }
+
+ /* Not set means empty */
+ if(!userp)
+ userp = "";
+
+ if(!passwdp)
+ passwdp = "";
+
+ /* Obtain the input token, if any */
+ header += strlen("Negotiate");
+ while(*header && ISSPACE(*header))
+ header++;
+
+ len = strlen(header);
+ if(!len) {
+ /* Is this the first call in a new negotiation? */
+ if(neg_ctx->context) {
+ /* The server rejected our authentication and hasn't suppled any more
+ negotiation mechanisms */
+ return CURLE_LOGIN_DENIED;
+ }
+ }
+
+ /* Initilise the security context and decode our challenge */
+ result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
+ host, header, neg_ctx);
+
+ if(result)
+ Curl_auth_spnego_cleanup(neg_ctx);
+
+ return result;
+}
+
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
+{
+ struct negotiatedata *neg_ctx = proxy ? &conn->data->state.proxyneg :
+ &conn->data->state.negotiate;
+ char *base64 = NULL;
+ size_t len = 0;
+ char *userp;
+ CURLcode result;
+
+ result = Curl_auth_create_spnego_message(conn->data, neg_ctx, &base64, &len);
+ if(result)
+ return result;
+
+ userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
+ base64);
+
+ if(proxy) {
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = userp;
+ }
+ else {
+ Curl_safefree(conn->allocptr.userpwd);
+ conn->allocptr.userpwd = userp;
+ }
+
+ free(base64);
+
+ return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+void Curl_cleanup_negotiate(struct Curl_easy *data)
+{
+ Curl_auth_spnego_cleanup(&data->state.negotiate);
+ Curl_auth_spnego_cleanup(&data->state.proxyneg);
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/http_negotiate.h b/Utilities/cmcurl/lib/http_negotiate.h
new file mode 100644
index 000000000..c64e54825
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_negotiate.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_HTTP_NEGOTIATE_H
+#define HEADER_CURL_HTTP_NEGOTIATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifdef USE_SPNEGO
+
+/* this is for Negotiate header input */
+CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
+ const char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+
+void Curl_cleanup_negotiate(struct Curl_easy *data);
+
+#endif /* USE_SPNEGO */
+
+#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/Utilities/cmcurl/lib/http_ntlm.c b/Utilities/cmcurl/lib/http_ntlm.c
new file mode 100644
index 000000000..8a78bd293
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_ntlm.c
@@ -0,0 +1,238 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.io/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strcase.h"
+#include "http_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "vauth/vauth.h"
+#include "url.h"
+
+#if defined(USE_NSS)
+#include "vtls/nssg.h"
+#elif defined(USE_WINDOWS_SSPI)
+#include "curl_sspi.h"
+#endif
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+CURLcode Curl_input_ntlm(struct connectdata *conn,
+ bool proxy, /* if proxy or not */
+ const char *header) /* rest of the www-authenticate:
+ header */
+{
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ CURLcode result = CURLE_OK;
+
+ ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+
+ if(checkprefix("NTLM", header)) {
+ header += strlen("NTLM");
+
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(*header) {
+ result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm);
+ if(result)
+ return result;
+
+ ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+ }
+ else {
+ if(ntlm->state == NTLMSTATE_LAST) {
+ infof(conn->data, "NTLM auth restarted\n");
+ Curl_http_ntlm_cleanup(conn);
+ }
+ else if(ntlm->state == NTLMSTATE_TYPE3) {
+ infof(conn->data, "NTLM handshake rejected\n");
+ Curl_http_ntlm_cleanup(conn);
+ ntlm->state = NTLMSTATE_NONE;
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ else if(ntlm->state >= NTLMSTATE_TYPE1) {
+ infof(conn->data, "NTLM handshake failure (internal error)\n");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+ }
+ }
+
+ return result;
+}
+
+/*
+ * This is for creating ntlm header output
+ */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
+{
+ char *base64 = NULL;
+ size_t len = 0;
+ CURLcode result;
+
+ /* point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+
+ /* point to the name and password for this */
+ const char *userp;
+ const char *passwdp;
+
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ struct auth *authp;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->data);
+
+#ifdef USE_NSS
+ if(CURLE_OK != Curl_nss_force_init(conn->data))
+ return CURLE_OUT_OF_MEMORY;
+#endif
+
+ if(proxy) {
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->http_proxy.user;
+ passwdp = conn->http_proxy.passwd;
+ ntlm = &conn->proxyntlm;
+ authp = &conn->data->state.authproxy;
+ }
+ else {
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ ntlm = &conn->ntlm;
+ authp = &conn->data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp = "";
+
+ if(!passwdp)
+ passwdp = "";
+
+#ifdef USE_WINDOWS_SSPI
+ if(s_hSecDll == NULL) {
+ /* not thread safe and leaks - use curl_global_init() to avoid */
+ CURLcode err = Curl_sspi_global_init();
+ if(s_hSecDll == NULL)
+ return err;
+ }
+#endif
+
+ switch(ntlm->state) {
+ case NTLMSTATE_TYPE1:
+ default: /* for the weird cases we (re)start here */
+ /* Create a type-1 message */
+ result = Curl_auth_create_ntlm_type1_message(userp, passwdp, ntlm, &base64,
+ &len);
+ if(result)
+ return result;
+
+ if(base64) {
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+
+ DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ }
+ break;
+
+ case NTLMSTATE_TYPE2:
+ /* We already received the type-2 message, create a type-3 message */
+ result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp,
+ ntlm, &base64, &len);
+ if(result)
+ return result;
+
+ if(base64) {
+ free(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+
+ DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+
+ ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */
+ authp->done = TRUE;
+ }
+ break;
+
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ ntlm->state = NTLMSTATE_LAST;
+ /* fall-through */
+ case NTLMSTATE_LAST:
+ Curl_safefree(*allocuserpwd);
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_http_ntlm_cleanup(struct connectdata *conn)
+{
+ Curl_auth_ntlm_cleanup(&conn->ntlm);
+ Curl_auth_ntlm_cleanup(&conn->proxyntlm);
+
+#if defined(NTLM_WB_ENABLED)
+ Curl_ntlm_wb_cleanup(conn);
+#endif
+}
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
diff --git a/Utilities/cmcurl/lib/http_ntlm.h b/Utilities/cmcurl/lib/http_ntlm.h
new file mode 100644
index 000000000..d186bbe37
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_ntlm.h
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_NTLM_H
+#define HEADER_CURL_NTLM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+ const char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+
+void Curl_http_ntlm_cleanup(struct connectdata *conn);
+
+#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
+
+#endif /* HEADER_CURL_NTLM_H */
diff --git a/Utilities/cmcurl/lib/http_proxy.c b/Utilities/cmcurl/lib/http_proxy.c
new file mode 100644
index 000000000..9894e2e5f
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_proxy.c
@@ -0,0 +1,656 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "http_proxy.h"
+#include "sendf.h"
+#include "http.h"
+#include "url.h"
+#include "select.h"
+#include "progress.h"
+#include "non-ascii.h"
+#include "connect.h"
+#include "curlx.h"
+#include "vtls/vtls.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Perform SSL initialization for HTTPS proxy. Sets
+ * proxy_ssl_connected connection bit when complete. Can be
+ * called multiple times.
+ */
+static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
+{
+#ifdef USE_SSL
+ CURLcode result = CURLE_OK;
+ DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS);
+ if(!conn->bits.proxy_ssl_connected[sockindex]) {
+ /* perform SSL initialization for this socket */
+ result =
+ Curl_ssl_connect_nonblocking(conn, sockindex,
+ &conn->bits.proxy_ssl_connected[sockindex]);
+ if(result)
+ conn->bits.close = TRUE; /* a failed connection is marked for closure to
+ prevent (bad) re-use or similar */
+ }
+ return result;
+#else
+ (void) conn;
+ (void) sockindex;
+ return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+{
+ if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
+ const CURLcode result = https_proxy_connect(conn, sockindex);
+ if(result)
+ return result;
+ if(!conn->bits.proxy_ssl_connected[sockindex])
+ return result; /* wait for HTTPS proxy SSL initialization to complete */
+ }
+
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+#ifndef CURL_DISABLE_PROXY
+ /* for [protocol] tunneled through HTTP proxy */
+ struct HTTP http_proxy;
+ void *prot_save;
+ const char *hostname;
+ int remote_port;
+ CURLcode result;
+
+ /* BLOCKING */
+ /* We want "seamless" operations through HTTP proxy tunnel */
+
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
+ * member conn->proto.http; we want [protocol] through HTTP and we have
+ * to change the member temporarily for connecting to the HTTP
+ * proxy. After Curl_proxyCONNECT we have to set back the member to the
+ * original pointer
+ *
+ * This function might be called several times in the multi interface case
+ * if the proxy's CONNECT response is not instant.
+ */
+ prot_save = conn->data->req.protop;
+ memset(&http_proxy, 0, sizeof(http_proxy));
+ conn->data->req.protop = &http_proxy;
+ connkeep(conn, "HTTP proxy CONNECT");
+
+ /* for the secondary socket (FTP), use the "connect to host"
+ * but ignore the "connect to port" (use the secondary port)
+ */
+
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else if(sockindex == SECONDARYSOCKET)
+ hostname = conn->secondaryhostname;
+ else
+ hostname = conn->host.name;
+
+ if(sockindex == SECONDARYSOCKET)
+ remote_port = conn->secondary_port;
+ else if(conn->bits.conn_to_port)
+ remote_port = conn->conn_to_port;
+ else
+ remote_port = conn->remote_port;
+ result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
+ conn->data->req.protop = prot_save;
+ if(CURLE_OK != result)
+ return result;
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ /* no HTTP tunnel proxy, just return */
+ return CURLE_OK;
+}
+
+#define CONNECT_BUFFER_SIZE 16384
+
+static CURLcode CONNECT(struct connectdata *conn,
+ int sockindex,
+ const char *hostname,
+ int remote_port)
+{
+ int subversion=0;
+ struct Curl_easy *data=conn->data;
+ struct SingleRequest *k = &data->req;
+ CURLcode result;
+ curl_socket_t tunnelsocket = conn->sock[sockindex];
+ curl_off_t cl=0;
+ bool closeConnection = FALSE;
+ bool chunked_encoding = FALSE;
+ time_t check;
+
+#define SELECT_OK 0
+#define SELECT_ERROR 1
+#define SELECT_TIMEOUT 2
+ int error = SELECT_OK;
+
+ if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
+ return CURLE_OK; /* CONNECT is already completed */
+
+ conn->bits.proxy_connect_closed = FALSE;
+
+ do {
+ if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
+ /* BEGIN CONNECT PHASE */
+ char *host_port;
+ Curl_send_buffer *req_buffer;
+
+ infof(data, "Establish HTTP proxy tunnel to %s:%hu\n",
+ hostname, remote_port);
+
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+
+ /* initialize a dynamic send-buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ host_port = aprintf("%s:%hu", hostname, remote_port);
+ if(!host_port) {
+ Curl_add_buffer_free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
+
+ free(host_port);
+
+ if(!result) {
+ char *host = NULL;
+ const char *proxyconn="";
+ const char *useragent="";
+ const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
+ "1.0" : "1.1";
+ bool ipv6_ip = conn->bits.ipv6_ip;
+ char *hostheader;
+
+ /* the hostname may be different */
+ if(hostname != conn->host.name)
+ ipv6_ip = (strchr(hostname, ':') != NULL);
+ hostheader= /* host:port with IPv6 support */
+ aprintf("%s%s%s:%hu", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
+ remote_port);
+ if(!hostheader) {
+ Curl_add_buffer_free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!Curl_checkProxyheaders(conn, "Host:")) {
+ host = aprintf("Host: %s\r\n", hostheader);
+ if(!host) {
+ free(hostheader);
+ Curl_add_buffer_free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
+ proxyconn = "Proxy-Connection: Keep-Alive\r\n";
+
+ if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
+ data->set.str[STRING_USERAGENT])
+ useragent = conn->allocptr.uagent;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "CONNECT %s HTTP/%s\r\n"
+ "%s" /* Host: */
+ "%s" /* Proxy-Authorization */
+ "%s" /* User-Agent */
+ "%s", /* Proxy-Connection */
+ hostheader,
+ http,
+ host?host:"",
+ conn->allocptr.proxyuserpwd?
+ conn->allocptr.proxyuserpwd:"",
+ useragent,
+ proxyconn);
+
+ if(host)
+ free(host);
+ free(hostheader);
+
+ if(!result)
+ result = Curl_add_custom_headers(conn, TRUE, req_buffer);
+
+ if(!result)
+ /* CRLF terminate the request */
+ result = Curl_add_bufferf(req_buffer, "\r\n");
+
+ if(!result) {
+ /* Send the connect request to the proxy */
+ /* BLOCKING */
+ result =
+ Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, sockindex);
+ }
+ req_buffer = NULL;
+ if(result)
+ failf(data, "Failed sending CONNECT to proxy");
+ }
+
+ Curl_add_buffer_free(req_buffer);
+ if(result)
+ return result;
+
+ conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
+ } /* END CONNECT PHASE */
+
+ check = Curl_timeleft(data, NULL, TRUE);
+ if(check <= 0) {
+ failf(data, "Proxy CONNECT aborted due to timeout");
+ return CURLE_RECV_ERROR;
+ }
+
+ if(!Curl_conn_data_pending(conn, sockindex))
+ /* return so we'll be called again polling-style */
+ return CURLE_OK;
+ DEBUGF(infof(data, "Read response immediately from proxy CONNECT\n"));
+
+ /* at this point, the tunnel_connecting phase is over. */
+
+ { /* READING RESPONSE PHASE */
+ size_t nread; /* total size read */
+ int perline; /* count bytes per line */
+ int keepon=TRUE;
+ ssize_t gotbytes;
+ char *ptr;
+ char *line_start;
+
+ ptr = conn->connect_buffer;
+ line_start = ptr;
+
+ nread = 0;
+ perline = 0;
+
+ while(nread < (size_t)CONNECT_BUFFER_SIZE && keepon && !error) {
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ if(ptr >= &conn->connect_buffer[CONNECT_BUFFER_SIZE]) {
+ failf(data, "CONNECT response too large!");
+ return CURLE_RECV_ERROR;
+ }
+
+ check = Curl_timeleft(data, NULL, TRUE);
+ if(check <= 0) {
+ failf(data, "Proxy CONNECT aborted due to timeout");
+ error = SELECT_TIMEOUT; /* already too little time */
+ break;
+ }
+
+ /* Read one byte at a time to avoid a race condition. Wait at most one
+ second before looping to ensure continuous pgrsUpdates. */
+ result = Curl_read(conn, tunnelsocket, ptr, 1, &gotbytes);
+ if(result == CURLE_AGAIN) {
+ if(SOCKET_READABLE(tunnelsocket, check<1000L?check:1000) == -1) {
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted due to select/poll error");
+ break;
+ }
+ continue;
+ }
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+ else if(gotbytes <= 0) {
+ if(data->set.proxyauth && data->state.authproxy.avail) {
+ /* proxy auth was requested and there was proxy auth available,
+ then deem this as "mere" proxy disconnect */
+ conn->bits.proxy_connect_closed = TRUE;
+ infof(data, "Proxy CONNECT connection closed\n");
+ }
+ else {
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted");
+ }
+ keepon = FALSE;
+ break;
+ }
+
+ /* We got a byte of data */
+ nread++;
+
+ if(keepon > TRUE) {
+ /* This means we are currently ignoring a response-body */
+
+ nread = 0; /* make next read start over in the read buffer */
+ ptr = conn->connect_buffer;
+ if(cl) {
+ /* A Content-Length based body: simply count down the counter
+ and make sure to break out of the loop when we're done! */
+ cl--;
+ if(cl <= 0) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ else {
+ /* chunked-encoded body, so we need to do the chunked dance
+ properly to know when the end of the body is reached */
+ CHUNKcode r;
+ ssize_t tookcareof = 0;
+
+ /* now parse the chunked piece of data so that we can
+ properly tell when the stream ends */
+ r = Curl_httpchunk_read(conn, ptr, 1, &tookcareof);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE\n");
+ keepon = FALSE;
+ /* we did the full CONNECT treatment, go COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ }
+ }
+ continue;
+ }
+
+ perline++; /* amount of bytes in this line so far */
+
+ /* if this is not the end of a header line then continue */
+ if(*ptr != 0x0a) {
+ ptr++;
+ continue;
+ }
+
+ /* convert from the network encoding */
+ result = Curl_convert_from_network(data, line_start, perline);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+ /* output debug if that is requested */
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ line_start, (size_t)perline, conn);
+
+ if(!data->set.suppress_connect_headers) {
+ /* send the header to the callback */
+ int writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ result = Curl_client_write(conn, writetype, line_start, perline);
+ if(result)
+ return result;
+ }
+
+ data->info.header_size += (long)perline;
+ data->req.headerbytecount += (long)perline;
+
+ /* Newlines are CRLF, so the CR is ignored as the line isn't
+ really terminated until the LF comes. Treat a following CR
+ as end-of-headers as well.*/
+
+ if(('\r' == line_start[0]) ||
+ ('\n' == line_start[0])) {
+ /* end of response-headers from the proxy */
+ nread = 0; /* make next read start over in the read
+ buffer */
+ ptr = conn->connect_buffer;
+ if((407 == k->httpcode) && !data->state.authproblem) {
+ /* If we get a 407 response code with content length
+ when we have no auth problem, we must ignore the
+ whole response-body */
+ keepon = 2;
+
+ if(cl) {
+ infof(data, "Ignore %" CURL_FORMAT_CURL_OFF_T
+ " bytes of response-body\n", cl);
+ }
+ else if(chunked_encoding) {
+ CHUNKcode r;
+
+ infof(data, "Ignore chunked response-body\n");
+
+ /* We set ignorebody true here since the chunked
+ decoder function will acknowledge that. Pay
+ attention so that this is cleared again when this
+ function returns! */
+ k->ignorebody = TRUE;
+
+ if(line_start[1] == '\n') {
+ /* this can only be a LF if the letter at index 0
+ was a CR */
+ line_start++;
+ }
+
+ /* now parse the chunked piece of data so that we can
+ properly tell when the stream ends */
+ r = Curl_httpchunk_read(conn, line_start + 1, 1, &gotbytes);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE\n");
+ keepon = FALSE;
+ /* we did the full CONNECT treatment, go to
+ COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ }
+ }
+ else {
+ /* without content-length or chunked encoding, we
+ can't keep the connection alive since the close is
+ the end signal so we bail out at once instead */
+ keepon = FALSE;
+ }
+ }
+ else
+ keepon = FALSE;
+ /* we did the full CONNECT treatment, go to COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ continue;
+ }
+
+ line_start[perline] = 0; /* zero terminate the buffer */
+ if((checkprefix("WWW-Authenticate:", line_start) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", line_start) &&
+ (407 == k->httpcode))) {
+
+ bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
+ char *auth = Curl_copy_header_value(line_start);
+ if(!auth)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_http_input_auth(conn, proxy, auth);
+
+ free(auth);
+
+ if(result)
+ return result;
+ }
+ else if(checkprefix("Content-Length:", line_start)) {
+ if(k->httpcode/100 == 2) {
+ /* A client MUST ignore any Content-Length or Transfer-Encoding
+ header fields received in a successful response to CONNECT.
+ "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+ infof(data, "Ignoring Content-Length in CONNECT %03d response\n",
+ k->httpcode);
+ }
+ else {
+ cl = curlx_strtoofft(line_start +
+ strlen("Content-Length:"), NULL, 10);
+ }
+ }
+ else if(Curl_compareheader(line_start, "Connection:", "close"))
+ closeConnection = TRUE;
+ else if(checkprefix("Transfer-Encoding:", line_start)) {
+ if(k->httpcode/100 == 2) {
+ /* A client MUST ignore any Content-Length or Transfer-Encoding
+ header fields received in a successful response to CONNECT.
+ "Successful" described as: 2xx (Successful). RFC 7231 4.3.6 */
+ infof(data, "Ignoring Transfer-Encoding in "
+ "CONNECT %03d response\n", k->httpcode);
+ }
+ else if(Curl_compareheader(line_start,
+ "Transfer-Encoding:", "chunked")) {
+ infof(data, "CONNECT responded chunked\n");
+ chunked_encoding = TRUE;
+ /* init our chunky engine */
+ Curl_httpchunk_init(conn);
+ }
+ }
+ else if(Curl_compareheader(line_start, "Proxy-Connection:", "close"))
+ closeConnection = TRUE;
+ else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+ &subversion,
+ &k->httpcode)) {
+ /* store the HTTP code from the proxy */
+ data->info.httpproxycode = k->httpcode;
+ }
+
+ perline = 0; /* line starts over here */
+ ptr = conn->connect_buffer;
+ line_start = ptr;
+ } /* while there's buffer left and loop is requested */
+
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ if(error)
+ return CURLE_RECV_ERROR;
+
+ if(data->info.httpproxycode != 200) {
+ /* Deal with the possibly already received authenticate
+ headers. 'newurl' is set to a new URL if we must loop. */
+ result = Curl_http_auth_act(conn);
+ if(result)
+ return result;
+
+ if(conn->bits.close)
+ /* the connection has been marked for closure, most likely in the
+ Curl_http_auth_act() function and thus we can kill it at once
+ below */
+ closeConnection = TRUE;
+ }
+
+ if(closeConnection && data->req.newurl) {
+ /* Connection closed by server. Don't use it anymore */
+ Curl_closesocket(conn, conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ break;
+ }
+ } /* END READING RESPONSE PHASE */
+
+ /* If we are supposed to continue and request a new URL, which basically
+ * means the HTTP authentication is still going on so if the tunnel
+ * is complete we start over in INIT state */
+ if(data->req.newurl &&
+ (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) {
+ conn->tunnel_state[sockindex] = TUNNEL_INIT;
+ infof(data, "TUNNEL_STATE switched to: %d\n",
+ conn->tunnel_state[sockindex]);
+ }
+
+ } while(data->req.newurl);
+
+ if(200 != data->req.httpcode) {
+ if(closeConnection && data->req.newurl) {
+ conn->bits.proxy_connect_closed = TRUE;
+ infof(data, "Connect me again please\n");
+ }
+ else {
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ /* failure, close this connection to avoid re-use */
+ streamclose(conn, "proxy CONNECT failure");
+ Curl_closesocket(conn, conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
+
+ /* to back to init state */
+ conn->tunnel_state[sockindex] = TUNNEL_INIT;
+
+ if(conn->bits.proxy_connect_closed)
+ /* this is not an error, just part of the connection negotiation */
+ return CURLE_OK;
+ failf(data, "Received HTTP code %d from proxy after CONNECT",
+ data->req.httpcode);
+ return CURLE_RECV_ERROR;
+ }
+
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+
+ /* If a proxy-authorization header was used for the proxy, then we should
+ make sure that it isn't accidentally used for the document request
+ after we've connected. So let's free and clear it here. */
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = NULL;
+
+ data->state.authproxy.done = TRUE;
+
+ infof(data, "Proxy replied OK to CONNECT request\n");
+ data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
+ conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
+ document request */
+ return CURLE_OK;
+}
+
+/*
+ * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
+ * function will issue the necessary commands to get a seamless tunnel through
+ * this proxy. After that, the socket can be used just as a normal socket.
+ */
+
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+ int sockindex,
+ const char *hostname,
+ int remote_port)
+{
+ CURLcode result;
+ if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
+ if(!conn->connect_buffer) {
+ conn->connect_buffer = malloc(CONNECT_BUFFER_SIZE);
+ if(!conn->connect_buffer)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ result = CONNECT(conn, sockindex, hostname, remote_port);
+
+ if(result || (TUNNEL_COMPLETE == conn->tunnel_state[sockindex]))
+ Curl_safefree(conn->connect_buffer);
+
+ return result;
+}
+
+
+#endif /* CURL_DISABLE_PROXY */
diff --git a/Utilities/cmcurl/lib/http_proxy.h b/Utilities/cmcurl/lib/http_proxy.h
new file mode 100644
index 000000000..cbb1ab421
--- /dev/null
+++ b/Utilities/cmcurl/lib/http_proxy.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_HTTP_PROXY_H
+#define HEADER_CURL_HTTP_PROXY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+/* ftp can use this as well */
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+ int tunnelsocket,
+ const char *hostname, int remote_port);
+
+/* Default proxy timeout in milliseconds */
+#define PROXY_TIMEOUT (3600*1000)
+
+CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex);
+
+#else
+#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
+#define Curl_proxy_connect(x,y) CURLE_OK
+#endif
+
+#endif /* HEADER_CURL_HTTP_PROXY_H */
diff --git a/Utilities/cmcurl/lib/idn_win32.c b/Utilities/cmcurl/lib/idn_win32.c
new file mode 100644
index 000000000..8dc300b36
--- /dev/null
+++ b/Utilities/cmcurl/lib/idn_win32.c
@@ -0,0 +1,111 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+ /*
+ * IDN conversions using Windows kernel32 and normaliz libraries.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_WIN32_IDN
+
+#include "curl_multibyte.h"
+#include "curl_memory.h"
+#include "warnless.h"
+
+ /* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef WANT_IDN_PROTOTYPES
+# if defined(_SAL_VERSION)
+WINNORMALIZEAPI int WINAPI
+IdnToAscii(_In_ DWORD dwFlags,
+ _In_reads_(cchUnicodeChar) LPCWSTR lpUnicodeCharStr,
+ _In_ int cchUnicodeChar,
+ _Out_writes_opt_(cchASCIIChar) LPWSTR lpASCIICharStr,
+ _In_ int cchASCIIChar);
+WINNORMALIZEAPI int WINAPI
+IdnToUnicode(_In_ DWORD dwFlags,
+ _In_reads_(cchASCIIChar) LPCWSTR lpASCIICharStr,
+ _In_ int cchASCIIChar,
+ _Out_writes_opt_(cchUnicodeChar) LPWSTR lpUnicodeCharStr,
+ _In_ int cchUnicodeChar);
+# else
+WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags,
+ const WCHAR *lpUnicodeCharStr,
+ int cchUnicodeChar,
+ WCHAR *lpASCIICharStr,
+ int cchASCIIChar);
+WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
+ const WCHAR *lpASCIICharStr,
+ int cchASCIIChar,
+ WCHAR *lpUnicodeCharStr,
+ int cchUnicodeChar);
+# endif
+#endif
+
+#define IDN_MAX_LENGTH 255
+
+bool curl_win32_idn_to_ascii(const char *in, char **out);
+bool curl_win32_ascii_to_idn(const char *in, char **out);
+
+bool curl_win32_idn_to_ascii(const char *in, char **out)
+{
+ bool success = FALSE;
+
+ wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+ if(in_w) {
+ wchar_t punycode[IDN_MAX_LENGTH];
+ int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
+ free(in_w);
+ if(chars) {
+ *out = Curl_convert_wchar_to_UTF8(punycode);
+ if(*out)
+ success = TRUE;
+ }
+ }
+
+ return success;
+}
+
+bool curl_win32_ascii_to_idn(const char *in, char **out)
+{
+ bool success = FALSE;
+
+ wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+ if(in_w) {
+ size_t in_len = wcslen(in_w) + 1;
+ wchar_t unicode[IDN_MAX_LENGTH];
+ int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
+ unicode, IDN_MAX_LENGTH);
+ free(in_w);
+ if(chars) {
+ *out = Curl_convert_wchar_to_UTF8(unicode);
+ if(*out)
+ success = TRUE;
+ }
+ }
+
+ return success;
+}
+
+#endif /* USE_WIN32_IDN */
diff --git a/Utilities/cmcurl/lib/if2ip.c b/Utilities/cmcurl/lib/if2ip.c
new file mode 100644
index 000000000..4de81be60
--- /dev/null
+++ b/Utilities/cmcurl/lib/if2ip.c
@@ -0,0 +1,272 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
+#ifdef HAVE_IFADDRS_H
+# include <ifaddrs.h>
+#endif
+#ifdef HAVE_STROPTS_H
+# include <stropts.h>
+#endif
+#ifdef __VMS
+# include <inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "strcase.h"
+#include "if2ip.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ------------------------------------------------------------------ */
+
+/* Return the scope of the given address. */
+unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
+{
+#ifndef ENABLE_IPV6
+ (void) sa;
+#else
+ if(sa->sa_family == AF_INET6) {
+ const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
+ const unsigned char *b = sa6->sin6_addr.s6_addr;
+ unsigned short w = (unsigned short) ((b[0] << 8) | b[1]);
+
+ switch(w & 0xFFC0) {
+ case 0xFE80:
+ return IPV6_SCOPE_LINKLOCAL;
+ case 0xFEC0:
+ return IPV6_SCOPE_SITELOCAL;
+ case 0x0000:
+ w = b[1] | b[2] | b[3] | b[4] | b[5] | b[6] | b[7] | b[8] | b[9] |
+ b[10] | b[11] | b[12] | b[13] | b[14];
+ if(w || b[15] != 0x01)
+ break;
+ return IPV6_SCOPE_NODELOCAL;
+ default:
+ break;
+ }
+ }
+#endif
+
+ return IPV6_SCOPE_GLOBAL;
+}
+
+
+#if defined(HAVE_GETIFADDRS)
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ bool result = FALSE;
+
+ struct ifaddrs *iface, *head;
+
+ if(getifaddrs(&head) >= 0) {
+ for(iface=head; iface != NULL; iface=iface->ifa_next) {
+ if(strcasecompare(iface->ifa_name, interf)) {
+ result = TRUE;
+ break;
+ }
+ }
+ freeifaddrs(head);
+ }
+ return result;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ unsigned int remote_scope_id, const char *interf,
+ char *buf, int buf_size)
+{
+ struct ifaddrs *iface, *head;
+ if2ip_result_t res = IF2IP_NOT_FOUND;
+
+#ifndef ENABLE_IPV6
+ (void) remote_scope;
+
+#ifndef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ (void) remote_scope_id;
+#endif
+
+#endif
+
+ if(getifaddrs(&head) >= 0) {
+ for(iface = head; iface != NULL; iface=iface->ifa_next) {
+ if(iface->ifa_addr != NULL) {
+ if(iface->ifa_addr->sa_family == af) {
+ if(strcasecompare(iface->ifa_name, interf)) {
+ void *addr;
+ char *ip;
+ char scope[12] = "";
+ char ipstr[64];
+#ifdef ENABLE_IPV6
+ if(af == AF_INET6) {
+ unsigned int scopeid = 0;
+ unsigned int ifscope = Curl_ipv6_scope(iface->ifa_addr);
+
+ if(ifscope != remote_scope) {
+ /* We are interested only in interface addresses whose
+ scope matches the remote address we want to
+ connect to: global for global, link-local for
+ link-local, etc... */
+ if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
+ continue;
+ }
+
+ addr =
+ &((struct sockaddr_in6 *)(void *)iface->ifa_addr)->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ /* Include the scope of this interface as part of the address */
+ scopeid = ((struct sockaddr_in6 *)(void *)iface->ifa_addr)
+ ->sin6_scope_id;
+
+ /* If given, scope id should match. */
+ if(remote_scope_id && scopeid != remote_scope_id) {
+ if(res == IF2IP_NOT_FOUND)
+ res = IF2IP_AF_NOT_SUPPORTED;
+
+ continue;
+ }
+#endif
+ if(scopeid)
+ snprintf(scope, sizeof(scope), "%%%u", scopeid);
+ }
+ else
+#endif
+ addr =
+ &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
+ res = IF2IP_FOUND;
+ ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+ snprintf(buf, buf_size, "%s%s", ip, scope);
+ break;
+ }
+ }
+ else if((res == IF2IP_NOT_FOUND) &&
+ strcasecompare(iface->ifa_name, interf)) {
+ res = IF2IP_AF_NOT_SUPPORTED;
+ }
+ }
+ }
+
+ freeifaddrs(head);
+ }
+
+ return res;
+}
+
+#elif defined(HAVE_IOCTL_SIOCGIFADDR)
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ /* This is here just to support the old interfaces */
+ char buf[256];
+
+ return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
+ IF2IP_NOT_FOUND) ? FALSE : TRUE;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ unsigned int remote_scope_id, const char *interf,
+ char *buf, int buf_size)
+{
+ struct ifreq req;
+ struct in_addr in;
+ struct sockaddr_in *s;
+ curl_socket_t dummy;
+ size_t len;
+
+ (void)remote_scope;
+ (void)remote_scope_id;
+
+ if(!interf || (af != AF_INET))
+ return IF2IP_NOT_FOUND;
+
+ len = strlen(interf);
+ if(len >= sizeof(req.ifr_name))
+ return IF2IP_NOT_FOUND;
+
+ dummy = socket(AF_INET, SOCK_STREAM, 0);
+ if(CURL_SOCKET_BAD == dummy)
+ return IF2IP_NOT_FOUND;
+
+ memset(&req, 0, sizeof(req));
+ memcpy(req.ifr_name, interf, len+1);
+ req.ifr_addr.sa_family = AF_INET;
+
+ if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
+ sclose(dummy);
+ /* With SIOCGIFADDR, we cannot tell the difference between an interface
+ that does not exist and an interface that has no address of the
+ correct family. Assume the interface does not exist */
+ return IF2IP_NOT_FOUND;
+ }
+
+ s = (struct sockaddr_in *)(void *)&req.ifr_addr;
+ memcpy(&in, &s->sin_addr, sizeof(in));
+ Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+
+ sclose(dummy);
+ return IF2IP_FOUND;
+}
+
+#else
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ (void) interf;
+
+ return FALSE;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ unsigned int remote_scope_id, const char *interf,
+ char *buf, int buf_size)
+{
+ (void) af;
+ (void) remote_scope;
+ (void) remote_scope_id;
+ (void) interf;
+ (void) buf;
+ (void) buf_size;
+ return IF2IP_NOT_FOUND;
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/if2ip.h b/Utilities/cmcurl/lib/if2ip.h
new file mode 100644
index 000000000..f3a7ff0b2
--- /dev/null
+++ b/Utilities/cmcurl/lib/if2ip.h
@@ -0,0 +1,83 @@
+#ifndef HEADER_CURL_IF2IP_H
+#define HEADER_CURL_IF2IP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* IPv6 address scopes. */
+#define IPV6_SCOPE_GLOBAL 0 /* Global scope. */
+#define IPV6_SCOPE_LINKLOCAL 1 /* Link-local scope. */
+#define IPV6_SCOPE_SITELOCAL 2 /* Site-local scope (deprecated). */
+#define IPV6_SCOPE_NODELOCAL 3 /* Loopback. */
+
+unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
+
+bool Curl_if_is_interface_name(const char *interf);
+
+typedef enum {
+ IF2IP_NOT_FOUND = 0, /* Interface not found */
+ IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */
+ IF2IP_FOUND = 2 /* The address has been stored in "buf" */
+} if2ip_result_t;
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ unsigned int remote_scope_id, const char *interf,
+ char *buf, int buf_size);
+
+#ifdef __INTERIX
+
+/* Nedelcho Stanev's work-around for SFU 3.0 */
+struct ifreq {
+#define IFNAMSIZ 16
+#define IFHWADDRLEN 6
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_metric;
+ int ifru_mtu;
+ } ifr_ifru;
+};
+
+/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
+ C code. */
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+
+#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
+
+#endif /* __INTERIX */
+
+#endif /* HEADER_CURL_IF2IP_H */
diff --git a/Utilities/cmcurl/lib/imap.c b/Utilities/cmcurl/lib/imap.c
new file mode 100644
index 000000000..b528f77d9
--- /dev/null
+++ b/Utilities/cmcurl/lib/imap.c
@@ -0,0 +1,2132 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3501 IMAPv4 protocol
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC4959 IMAP Extension for SASL Initial Client Response
+ * RFC5092 IMAP URL Scheme
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_IMAP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "imap.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "strcase.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode imap_do(struct connectdata *conn, bool *done);
+static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode imap_connect(struct connectdata *conn, bool *done);
+static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
+static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
+static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode imap_setup_connection(struct connectdata *conn);
+static char *imap_atom(const char *str, bool escape_only);
+static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
+static CURLcode imap_parse_url_options(struct connectdata *conn);
+static CURLcode imap_parse_url_path(struct connectdata *conn);
+static CURLcode imap_parse_custom_request(struct connectdata *conn);
+static CURLcode imap_perform_authenticate(struct connectdata *conn,
+ const char *mech,
+ const char *initresp);
+static CURLcode imap_continue_authenticate(struct connectdata *conn,
+ const char *resp);
+static void imap_get_message(char *buffer, char **outptr);
+
+/*
+ * IMAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imap = {
+ "IMAP", /* scheme */
+ imap_setup_connection, /* setup_connection */
+ imap_do, /* do_it */
+ imap_done, /* done */
+ ZERO_NULL, /* do_more */
+ imap_connect, /* connect_it */
+ imap_multi_statemach, /* connecting */
+ imap_doing, /* doing */
+ imap_getsock, /* proto_getsock */
+ imap_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ imap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAP, /* defport */
+ CURLPROTO_IMAP, /* protocol */
+ PROTOPT_CLOSEACTION| /* flags */
+ PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * IMAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imaps = {
+ "IMAPS", /* scheme */
+ imap_setup_connection, /* setup_connection */
+ imap_do, /* do_it */
+ imap_done, /* done */
+ ZERO_NULL, /* do_more */
+ imap_connect, /* connect_it */
+ imap_multi_statemach, /* connecting */
+ imap_doing, /* doing */
+ imap_getsock, /* proto_getsock */
+ imap_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ imap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAPS, /* defport */
+ CURLPROTO_IMAPS, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed IMAP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imap_proxy = {
+ "IMAP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed IMAPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imaps_proxy = {
+ "IMAPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+/* SASL parameters for the imap protocol */
+static const struct SASLproto saslimap = {
+ "imap", /* The service name */
+ '+', /* Code received when continuation is expected */
+ 'O', /* Code to receive upon authentication success */
+ 0, /* Maximum initial response length (no max) */
+ imap_perform_authenticate, /* Send authentication command */
+ imap_continue_authenticate, /* Send authentication continuation */
+ imap_get_message /* Get SASL response message */
+};
+
+
+#ifdef USE_SSL
+static void imap_to_imaps(struct connectdata *conn)
+{
+ /* Change the connection handler */
+ conn->handler = &Curl_handler_imaps;
+
+ /* Set the connection's upgraded to TLS flag */
+ conn->tls_upgraded = TRUE;
+}
+#else
+#define imap_to_imaps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * imap_matchresp()
+ *
+ * Determines whether the untagged response is related to the specified
+ * command by checking if it is in format "* <command-name> ..." or
+ * "* <number> <command-name> ...".
+ *
+ * The "* " marker is assumed to have already been checked by the caller.
+ */
+static bool imap_matchresp(const char *line, size_t len, const char *cmd)
+{
+ const char *end = line + len;
+ size_t cmd_len = strlen(cmd);
+
+ /* Skip the untagged response marker */
+ line += 2;
+
+ /* Do we have a number after the marker? */
+ if(line < end && ISDIGIT(*line)) {
+ /* Skip the number */
+ do
+ line++;
+ while(line < end && ISDIGIT(*line));
+
+ /* Do we have the space character? */
+ if(line == end || *line != ' ')
+ return FALSE;
+
+ line++;
+ }
+
+ /* Does the command name match and is it followed by a space character or at
+ the end of line? */
+ if(line + cmd_len <= end && strncasecompare(line, cmd, cmd_len) &&
+ (line[cmd_len] == ' ' || line + cmd_len + 2 == end))
+ return TRUE;
+
+ return FALSE;
+}
+
+/***********************************************************************
+ *
+ * imap_endofresp()
+ *
+ * Checks whether the given string is a valid tagged, untagged or continuation
+ * response which can be processed by the response handler.
+ */
+static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct IMAP *imap = conn->data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *id = imapc->resptag;
+ size_t id_len = strlen(id);
+
+ /* Do we have a tagged command response? */
+ if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
+ line += id_len + 1;
+ len -= id_len + 1;
+
+ if(len >= 2 && !memcmp(line, "OK", 2))
+ *resp = 'O';
+ else if(len >= 2 && !memcmp(line, "NO", 2))
+ *resp = 'N';
+ else if(len >= 3 && !memcmp(line, "BAD", 3))
+ *resp = 'B';
+ else {
+ failf(conn->data, "Bad tagged response");
+ *resp = -1;
+ }
+
+ return TRUE;
+ }
+
+ /* Do we have an untagged command response? */
+ if(len >= 2 && !memcmp("* ", line, 2)) {
+ switch(imapc->state) {
+ /* States which are interested in untagged responses */
+ case IMAP_CAPABILITY:
+ if(!imap_matchresp(line, len, "CAPABILITY"))
+ return FALSE;
+ break;
+
+ case IMAP_LIST:
+ if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
+ (imap->custom && !imap_matchresp(line, len, imap->custom) &&
+ (strcmp(imap->custom, "STORE") ||
+ !imap_matchresp(line, len, "FETCH")) &&
+ strcmp(imap->custom, "SELECT") &&
+ strcmp(imap->custom, "EXAMINE") &&
+ strcmp(imap->custom, "SEARCH") &&
+ strcmp(imap->custom, "EXPUNGE") &&
+ strcmp(imap->custom, "LSUB") &&
+ strcmp(imap->custom, "UID") &&
+ strcmp(imap->custom, "NOOP")))
+ return FALSE;
+ break;
+
+ case IMAP_SELECT:
+ /* SELECT is special in that its untagged responses do not have a
+ common prefix so accept anything! */
+ break;
+
+ case IMAP_FETCH:
+ if(!imap_matchresp(line, len, "FETCH"))
+ return FALSE;
+ break;
+
+ case IMAP_SEARCH:
+ if(!imap_matchresp(line, len, "SEARCH"))
+ return FALSE;
+ break;
+
+ /* Ignore other untagged responses */
+ default:
+ return FALSE;
+ }
+
+ *resp = '*';
+ return TRUE;
+ }
+
+ /* Do we have a continuation response? This should be a + symbol followed by
+ a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
+ APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
+ some e-mail servers ignore this and only send a single + instead. */
+ if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
+ (len >= 2 && !memcmp("+ ", line, 2)))) {
+ switch(imapc->state) {
+ /* States which are interested in continuation responses */
+ case IMAP_AUTHENTICATE:
+ case IMAP_APPEND:
+ *resp = '+';
+ break;
+
+ default:
+ failf(conn->data, "Unexpected continuation response");
+ *resp = -1;
+ break;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * imap_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static void imap_get_message(char *buffer, char **outptr)
+{
+ size_t len = 0;
+ char *message = NULL;
+
+ /* Find the start of the message */
+ for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
+ ;
+
+ /* Find the end of the message */
+ for(len = strlen(message); len--;)
+ if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+ message[len] != '\t')
+ break;
+
+ /* Terminate the message */
+ if(++len) {
+ message[len] = '\0';
+ }
+
+ *outptr = message;
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change IMAP state!
+ */
+static void state(struct connectdata *conn, imapstate newstate)
+{
+ struct imap_conn *imapc = &conn->proto.imapc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[]={
+ "STOP",
+ "SERVERGREET",
+ "CAPABILITY",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTHENTICATE",
+ "LOGIN",
+ "LIST",
+ "SELECT",
+ "FETCH",
+ "FETCH_FINAL",
+ "APPEND",
+ "APPEND_FINAL",
+ "SEARCH",
+ "LOGOUT",
+ /* LAST */
+ };
+
+ if(imapc->state != newstate)
+ infof(conn->data, "IMAP %p state change from %s to %s\n",
+ (void *)imapc, names[imapc->state], names[newstate]);
+#endif
+
+ imapc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_capability()
+ *
+ * Sends the CAPABILITY command in order to obtain a list of server side
+ * supported capabilities.
+ */
+static CURLcode imap_perform_capability(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ imapc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
+ imapc->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
+ imapc->tls_supported = FALSE; /* Clear the TLS capability */
+
+ /* Send the CAPABILITY command */
+ result = imap_sendf(conn, "CAPABILITY");
+
+ if(!result)
+ state(conn, IMAP_CAPABILITY);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_starttls()
+ *
+ * Sends the STARTTLS command to start the upgrade to TLS.
+ */
+static CURLcode imap_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STARTTLS command */
+ result = imap_sendf(conn, "STARTTLS");
+
+ if(!result)
+ state(conn, IMAP_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
+
+ if(!result) {
+ if(imapc->state != IMAP_UPGRADETLS)
+ state(conn, IMAP_UPGRADETLS);
+
+ if(imapc->ssldone) {
+ imap_to_imaps(conn);
+ result = imap_perform_capability(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_login()
+ *
+ * Sends a clear text LOGIN command to authenticate with.
+ */
+static CURLcode imap_perform_login(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ char *user;
+ char *passwd;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, IMAP_STOP);
+
+ return result;
+ }
+
+ /* Make sure the username and password are in the correct atom format */
+ user = imap_atom(conn->user, false);
+ passwd = imap_atom(conn->passwd, false);
+
+ /* Send the LOGIN command */
+ result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
+ passwd ? passwd : "");
+
+ free(user);
+ free(passwd);
+
+ if(!result)
+ state(conn, IMAP_LOGIN);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_authenticate()
+ *
+ * Sends an AUTHENTICATE command allowing the client to login with the given
+ * SASL authentication mechanism.
+ */
+static CURLcode imap_perform_authenticate(struct connectdata *conn,
+ const char *mech,
+ const char *initresp)
+{
+ CURLcode result = CURLE_OK;
+
+ if(initresp) {
+ /* Send the AUTHENTICATE command with the initial response */
+ result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
+ }
+ else {
+ /* Send the AUTHENTICATE command */
+ result = imap_sendf(conn, "AUTHENTICATE %s", mech);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_continue_authenticate()
+ *
+ * Sends SASL continuation data or cancellation.
+ */
+static CURLcode imap_continue_authenticate(struct connectdata *conn,
+ const char *resp)
+{
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ return Curl_pp_sendf(&imapc->pp, "%s", resp);
+}
+
+/***********************************************************************
+ *
+ * imap_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism, falling back to clear text should a common
+ * mechanism not be available between the client and server.
+ */
+static CURLcode imap_perform_authentication(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ saslprogress progress;
+
+ /* Check we have enough data to authenticate with and end the
+ connect phase if we don't */
+ if(!Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
+ state(conn, IMAP_STOP);
+ return result;
+ }
+
+ /* Calculate the SASL login details */
+ result = Curl_sasl_start(&imapc->sasl, conn, imapc->ir_supported, &progress);
+
+ if(!result) {
+ if(progress == SASL_INPROGRESS)
+ state(conn, IMAP_AUTHENTICATE);
+ else if(!imapc->login_disabled && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
+ /* Perform clear text authentication */
+ result = imap_perform_login(conn);
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_list()
+ *
+ * Sends a LIST command or an alternative custom request.
+ */
+static CURLcode imap_perform_list(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ char *mailbox;
+
+ if(imap->custom)
+ /* Send the custom request */
+ result = imap_sendf(conn, "%s%s", imap->custom,
+ imap->custom_params ? imap->custom_params : "");
+ else {
+ /* Make sure the mailbox is in the correct atom format if necessary */
+ mailbox = imap->mailbox ? imap_atom(imap->mailbox, true) : strdup("");
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the LIST command */
+ result = imap_sendf(conn, "LIST \"%s\" *", mailbox);
+
+ free(mailbox);
+ }
+
+ if(!result)
+ state(conn, IMAP_LIST);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_select()
+ *
+ * Sends a SELECT command to ask the server to change the selected mailbox.
+ */
+static CURLcode imap_perform_select(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ char *mailbox;
+
+ /* Invalidate old information as we are switching mailboxes */
+ Curl_safefree(imapc->mailbox);
+ Curl_safefree(imapc->mailbox_uidvalidity);
+
+ /* Check we have a mailbox */
+ if(!imap->mailbox) {
+ failf(conn->data, "Cannot SELECT without a mailbox.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Make sure the mailbox is in the correct atom format */
+ mailbox = imap_atom(imap->mailbox, false);
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the SELECT command */
+ result = imap_sendf(conn, "SELECT %s", mailbox);
+
+ free(mailbox);
+
+ if(!result)
+ state(conn, IMAP_SELECT);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_fetch()
+ *
+ * Sends a FETCH command to initiate the download of a message.
+ */
+static CURLcode imap_perform_fetch(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct IMAP *imap = conn->data->req.protop;
+
+ /* Check we have a UID */
+ if(!imap->uid) {
+ failf(conn->data, "Cannot FETCH without a UID.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Send the FETCH command */
+ if(imap->partial)
+ result = imap_sendf(conn, "FETCH %s BODY[%s]<%s>",
+ imap->uid,
+ imap->section ? imap->section : "",
+ imap->partial);
+ else
+ result = imap_sendf(conn, "FETCH %s BODY[%s]",
+ imap->uid,
+ imap->section ? imap->section : "");
+
+ if(!result)
+ state(conn, IMAP_FETCH);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_append()
+ *
+ * Sends an APPEND command to initiate the upload of a message.
+ */
+static CURLcode imap_perform_append(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct IMAP *imap = conn->data->req.protop;
+ char *mailbox;
+
+ /* Check we have a mailbox */
+ if(!imap->mailbox) {
+ failf(conn->data, "Cannot APPEND without a mailbox.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Check we know the size of the upload */
+ if(conn->data->state.infilesize < 0) {
+ failf(conn->data, "Cannot APPEND with unknown input file size\n");
+ return CURLE_UPLOAD_FAILED;
+ }
+
+ /* Make sure the mailbox is in the correct atom format */
+ mailbox = imap_atom(imap->mailbox, false);
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the APPEND command */
+ result = imap_sendf(conn, "APPEND %s (\\Seen) {%" CURL_FORMAT_CURL_OFF_T "}",
+ mailbox, conn->data->state.infilesize);
+
+ free(mailbox);
+
+ if(!result)
+ state(conn, IMAP_APPEND);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_search()
+ *
+ * Sends a SEARCH command.
+ */
+static CURLcode imap_perform_search(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct IMAP *imap = conn->data->req.protop;
+
+ /* Check we have a query string */
+ if(!imap->query) {
+ failf(conn->data, "Cannot SEARCH without a query string.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Send the SEARCH command */
+ result = imap_sendf(conn, "SEARCH %s", imap->query);
+
+ if(!result)
+ state(conn, IMAP_SEARCH);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_logout()
+ *
+ * Performs the logout action prior to sclose() being called.
+ */
+static CURLcode imap_perform_logout(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the LOGOUT command */
+ result = imap_sendf(conn, "LOGOUT");
+
+ if(!result)
+ state(conn, IMAP_LOGOUT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Got unexpected imap-server response");
+ result = CURLE_WEIRD_SERVER_REPLY;
+ }
+ else
+ result = imap_perform_capability(conn);
+
+ return result;
+}
+
+/* For CAPABILITY responses */
+static CURLcode imap_state_capability_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *line = data->state.buffer;
+ size_t wordlen;
+
+ (void)instate; /* no use for this yet */
+
+ /* Do we have a untagged response? */
+ if(imapcode == '*') {
+ line += 2;
+
+ /* Loop through the data line */
+ for(;;) {
+ while(*line &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ }
+
+ if(!*line)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Does the server support the STARTTLS capability? */
+ if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
+ imapc->tls_supported = TRUE;
+
+ /* Has the server explicitly disabled clear text authentication? */
+ else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
+ imapc->login_disabled = TRUE;
+
+ /* Does the server support the SASL-IR capability? */
+ else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
+ imapc->ir_supported = TRUE;
+
+ /* Do we have a SASL based authentication mechanism? */
+ else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
+ size_t llen;
+ unsigned int mechbit;
+
+ line += 5;
+ wordlen -= 5;
+
+ /* Test the word for a matching authentication mechanism */
+ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+ if(mechbit && llen == wordlen)
+ imapc->sasl.authmechs |= mechbit;
+ }
+
+ line += wordlen;
+ }
+ }
+ else if(imapcode == 'O') {
+ if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(imapc->tls_supported)
+ /* Switch to TLS connection now */
+ result = imap_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = imap_perform_authentication(conn);
+ else {
+ failf(data, "STARTTLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = imap_perform_authentication(conn);
+ }
+ else
+ result = imap_perform_authentication(conn);
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode imap_state_starttls_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = imap_perform_authentication(conn);
+ }
+ else
+ result = imap_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode imap_state_auth_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ saslprogress progress;
+
+ (void)instate; /* no use for this yet */
+
+ result = Curl_sasl_continue(&imapc->sasl, conn, imapcode, &progress);
+ if(!result)
+ switch(progress) {
+ case SASL_DONE:
+ state(conn, IMAP_STOP); /* Authenticated */
+ break;
+ case SASL_IDLE: /* No mechanism left after cancellation */
+ if((!imapc->login_disabled) && (imapc->preftype & IMAP_TYPE_CLEARTEXT))
+ /* Perform clear text authentication */
+ result = imap_perform_login(conn);
+ else {
+ failf(data, "Authentication cancelled");
+ result = CURLE_LOGIN_DENIED;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/* For LOGIN responses */
+static CURLcode imap_state_login_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Access denied. %c", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For LIST and SEARCH responses */
+static CURLcode imap_state_listsearch_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ char *line = conn->data->state.buffer;
+ size_t len = strlen(line);
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode == '*') {
+ /* Temporarily add the LF character back and send as body to the client */
+ line[len] = '\n';
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
+ else if(imapcode != 'O')
+ result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
+ else
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For SELECT responses */
+static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = conn->data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *line = data->state.buffer;
+ char tmp[20];
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode == '*') {
+ /* See if this is an UIDVALIDITY response */
+ if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) {
+ Curl_safefree(imapc->mailbox_uidvalidity);
+ imapc->mailbox_uidvalidity = strdup(tmp);
+ }
+ }
+ else if(imapcode == 'O') {
+ /* Check if the UIDVALIDITY has been specified and matches */
+ if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
+ strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+ failf(conn->data, "Mailbox UIDVALIDITY has changed");
+ result = CURLE_REMOTE_FILE_NOT_FOUND;
+ }
+ else {
+ /* Note the currently opened mailbox on this connection */
+ imapc->mailbox = strdup(imap->mailbox);
+
+ if(imap->custom)
+ result = imap_perform_list(conn);
+ else if(imap->query)
+ result = imap_perform_search(conn);
+ else
+ result = imap_perform_fetch(conn);
+ }
+ }
+ else {
+ failf(data, "Select failed");
+ result = CURLE_LOGIN_DENIED;
+ }
+
+ return result;
+}
+
+/* For the (first line of the) FETCH responses */
+static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+ const char *ptr = data->state.buffer;
+ bool parsed = FALSE;
+ curl_off_t size = 0;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '*') {
+ Curl_pgrsSetDownloadSize(data, -1);
+ state(conn, IMAP_STOP);
+ return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */
+ }
+
+ /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
+ the continuation data contained within the curly brackets */
+ while(*ptr && (*ptr != '{'))
+ ptr++;
+
+ if(*ptr == '{') {
+ char *endptr;
+ size = curlx_strtoofft(ptr + 1, &endptr, 10);
+ if(endptr - ptr > 1 && endptr[0] == '}' &&
+ endptr[1] == '\r' && endptr[2] == '\0')
+ parsed = TRUE;
+ }
+
+ if(parsed) {
+ infof(data, "Found %" CURL_FORMAT_CURL_OFF_TU " bytes to download\n",
+ size);
+ Curl_pgrsSetDownloadSize(data, size);
+
+ if(pp->cache) {
+ /* At this point there is a bunch of data in the header "cache" that is
+ actually body content, send it as body and then skip it. Do note
+ that there may even be additional "headers" after the body. */
+ size_t chunk = pp->cache_size;
+
+ if(chunk > (size_t)size)
+ /* The conversion from curl_off_t to size_t is always fine here */
+ chunk = (size_t)size;
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
+ if(result)
+ return result;
+
+ data->req.bytecount += chunk;
+
+ infof(data, "Written %" CURL_FORMAT_CURL_OFF_TU
+ " bytes, %" CURL_FORMAT_CURL_OFF_TU
+ " bytes are left for transfer\n", (curl_off_t)chunk,
+ size - chunk);
+
+ /* Have we used the entire cache or just part of it?*/
+ if(pp->cache_size > chunk) {
+ /* Only part of it so shrink the cache to fit the trailing data */
+ memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
+ pp->cache_size -= chunk;
+ }
+ else {
+ /* Free the cache */
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
+ }
+ }
+
+ if(data->req.bytecount == size)
+ /* The entire data is already transferred! */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ else {
+ /* IMAP download */
+ data->req.maxdownload = size;
+ Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL);
+ }
+ }
+ else {
+ /* We don't know how to parse this line */
+ failf(pp->conn->data, "Failed to parse FETCH response.");
+ result = CURLE_WEIRD_SERVER_REPLY;
+ }
+
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For final FETCH responses performed after the download */
+static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != 'O')
+ result = CURLE_WEIRD_SERVER_REPLY;
+ else
+ /* End of DONE phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For APPEND responses */
+static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != '+') {
+ result = CURLE_UPLOAD_FAILED;
+ }
+ else {
+ /* Set the progress upload size */
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+ /* IMAP upload */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+ }
+
+ return result;
+}
+
+/* For final APPEND responses performed after the upload */
+static CURLcode imap_state_append_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != 'O')
+ result = CURLE_UPLOAD_FAILED;
+ else
+ /* End of DONE phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+static CURLcode imap_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int imapcode;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
+ if(imapc->state == IMAP_UPGRADETLS)
+ return imap_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ do {
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
+ if(result)
+ return result;
+
+ /* Was there an error parsing the response line? */
+ if(imapcode == -1)
+ return CURLE_WEIRD_SERVER_REPLY;
+
+ if(!imapcode)
+ break;
+
+ /* We have now received a full IMAP server response */
+ switch(imapc->state) {
+ case IMAP_SERVERGREET:
+ result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_CAPABILITY:
+ result = imap_state_capability_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_STARTTLS:
+ result = imap_state_starttls_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE:
+ result = imap_state_auth_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LOGIN:
+ result = imap_state_login_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LIST:
+ result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_SELECT:
+ result = imap_state_select_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_FETCH:
+ result = imap_state_fetch_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_FETCH_FINAL:
+ result = imap_state_fetch_final_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_APPEND:
+ result = imap_state_append_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_APPEND_FINAL:
+ result = imap_state_append_final_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_SEARCH:
+ result = imap_state_listsearch_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LOGOUT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, IMAP_STOP);
+ break;
+ }
+ } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
+ if(result || !imapc->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&imapc->pp, FALSE);
+ *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode imap_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ while(imapc->state != IMAP_STOP && !result)
+ result = Curl_pp_statemach(&imapc->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the struct IMAP for the current Curl_easy if
+ required */
+static CURLcode imap_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap;
+
+ imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
+ if(!imap)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the IMAP "protocol connect" and "doing" phases only */
+static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * imap_connect()
+ *
+ * This function should do everything that is to be considered a part of the
+ * connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode imap_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in IMAP */
+ connkeep(conn, "IMAP default");
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = imap_statemach_act;
+ pp->endofresp = imap_endofresp;
+ pp->conn = conn;
+
+ /* Set the default preferred authentication type and mechanism */
+ imapc->preftype = IMAP_TYPE_ANY;
+ Curl_sasl_init(&imapc->sasl, &saslimap);
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = imap_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, IMAP_SERVERGREET);
+
+ /* Start off with an response id of '*' */
+ strcpy(imapc->resptag, "*");
+
+ result = imap_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+
+ (void)premature;
+
+ if(!imap)
+ return CURLE_OK;
+
+ if(status) {
+ connclose(conn, "IMAP done with bad status"); /* marked for closure */
+ result = status; /* use the already set error code */
+ }
+ else if(!data->set.connect_only && !imap->custom &&
+ (imap->uid || data->set.upload)) {
+ /* Handle responses after FETCH or APPEND transfer has finished */
+ if(!data->set.upload)
+ state(conn, IMAP_FETCH_FINAL);
+ else {
+ /* End the APPEND command first by sending an empty line */
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
+ if(!result)
+ state(conn, IMAP_APPEND_FINAL);
+ }
+
+ /* Run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the imap_multi_statemach function but we have no general support for
+ non-blocking DONE operations!
+ */
+ if(!result)
+ result = imap_block_statemach(conn);
+ }
+
+ /* Cleanup our per-request based variables */
+ Curl_safefree(imap->mailbox);
+ Curl_safefree(imap->uidvalidity);
+ Curl_safefree(imap->uid);
+ Curl_safefree(imap->section);
+ Curl_safefree(imap->partial);
+ Curl_safefree(imap->query);
+ Curl_safefree(imap->custom);
+ Curl_safefree(imap->custom_params);
+
+ /* Clear the transfer mode for the next request */
+ imap->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform()
+ *
+ * This is the actual DO function for IMAP. Fetch or append a message, or do
+ * other things according to the options previously setup.
+ */
+static CURLcode imap_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is IMAP and no proxy */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ bool selected = FALSE;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ imap->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
+ has already been selected on this connection */
+ if(imap->mailbox && imapc->mailbox &&
+ !strcmp(imap->mailbox, imapc->mailbox) &&
+ (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
+ !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+ selected = TRUE;
+
+ /* Start the first command in the DO phase */
+ if(conn->data->set.upload)
+ /* APPEND can be executed directly */
+ result = imap_perform_append(conn);
+ else if(imap->custom && (selected || !imap->mailbox))
+ /* Custom command using the same mailbox or no mailbox */
+ result = imap_perform_list(conn);
+ else if(!imap->custom && selected && imap->uid)
+ /* FETCH from the same mailbox */
+ result = imap_perform_fetch(conn);
+ else if(!imap->custom && selected && imap->query)
+ /* SEARCH the current mailbox */
+ result = imap_perform_search(conn);
+ else if(imap->mailbox && !selected &&
+ (imap->custom || imap->uid || imap->query))
+ /* SELECT the mailbox */
+ result = imap_perform_select(conn);
+ else
+ /* LIST */
+ result = imap_perform_list(conn);
+
+ if(result)
+ return result;
+
+ /* Run the state-machine */
+ result = imap_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (imap_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode imap_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ /* Parse the URL path */
+ result = imap_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Parse the custom request */
+ result = imap_parse_custom_request(conn);
+ if(result)
+ return result;
+
+ result = imap_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_disconnect()
+ *
+ * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The IMAP session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
+ if(!imap_perform_logout(conn))
+ (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&imapc->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, imapc->sasl.authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(imapc->mailbox);
+ Curl_safefree(imapc->mailbox_uidvalidity);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
+{
+ struct IMAP *imap = conn->data->req.protop;
+
+ (void)connected;
+
+ if(imap->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = imap_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = imap_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode imap_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct Curl_easy *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, -1);
+ Curl_pgrsSetDownloadSize(data, -1);
+
+ /* Carry out the perform */
+ result = imap_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = imap_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode imap_setup_connection(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+
+ /* Initialise the IMAP layer */
+ CURLcode result = imap_init(conn);
+ if(result)
+ return result;
+
+ /* Clear the TLS upgraded flag */
+ conn->tls_upgraded = FALSE;
+
+ /* Set up the proxy if necessary */
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel IMAP operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_imap)
+ conn->handler = &Curl_handler_imap_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_imaps_proxy;
+#else
+ failf(data, "IMAPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* set it up as an HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+#else
+ failf(data, "IMAP over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_sendf()
+ *
+ * Sends the formatted string as an IMAP command to the server.
+ *
+ * Designed to never block.
+ */
+static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ char *taggedfmt;
+ va_list ap;
+
+ DEBUGASSERT(fmt);
+
+ /* Calculate the next command ID wrapping at 3 digits */
+ imapc->cmdid = (imapc->cmdid + 1) % 1000;
+
+ /* Calculate the tag based on the connection ID and command ID */
+ snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
+ 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
+
+ /* Prefix the format with the tag */
+ taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
+ if(!taggedfmt)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the data with the tag */
+ va_start(ap, fmt);
+ result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
+ va_end(ap);
+
+ free(taggedfmt);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_atom()
+ *
+ * Checks the input string for characters that need escaping and returns an
+ * atom ready for sending to the server.
+ *
+ * The returned string needs to be freed.
+ *
+ */
+static char *imap_atom(const char *str, bool escape_only)
+{
+ /* !checksrc! disable PARENBRACE 1 */
+ const char atom_specials[] = "(){ %*]";
+ const char *p1;
+ char *p2;
+ size_t backsp_count = 0;
+ size_t quote_count = 0;
+ bool others_exists = FALSE;
+ size_t newlen = 0;
+ char *newstr = NULL;
+
+ if(!str)
+ return NULL;
+
+ /* Look for "atom-specials", counting the backslash and quote characters as
+ these will need escapping */
+ p1 = str;
+ while(*p1) {
+ if(*p1 == '\\')
+ backsp_count++;
+ else if(*p1 == '"')
+ quote_count++;
+ else if(!escape_only) {
+ const char *p3 = atom_specials;
+
+ while(*p3 && !others_exists) {
+ if(*p1 == *p3)
+ others_exists = TRUE;
+
+ p3++;
+ }
+ }
+
+ p1++;
+ }
+
+ /* Does the input contain any "atom-special" characters? */
+ if(!backsp_count && !quote_count && !others_exists)
+ return strdup(str);
+
+ /* Calculate the new string length */
+ newlen = strlen(str) + backsp_count + quote_count + (others_exists ? 2 : 0);
+
+ /* Allocate the new string */
+ newstr = (char *) malloc((newlen + 1) * sizeof(char));
+ if(!newstr)
+ return NULL;
+
+ /* Surround the string in quotes if necessary */
+ p2 = newstr;
+ if(others_exists) {
+ newstr[0] = '"';
+ newstr[newlen - 1] = '"';
+ p2++;
+ }
+
+ /* Copy the string, escaping backslash and quote characters along the way */
+ p1 = str;
+ while(*p1) {
+ if(*p1 == '\\' || *p1 == '"') {
+ *p2 = '\\';
+ p2++;
+ }
+
+ *p2 = *p1;
+
+ p1++;
+ p2++;
+ }
+
+ /* Terminate the string */
+ newstr[newlen] = '\0';
+
+ return newstr;
+}
+
+/***********************************************************************
+ *
+ * imap_is_bchar()
+ *
+ * Portable test of whether the specified char is a "bchar" as defined in the
+ * grammar of RFC-5092.
+ */
+static bool imap_is_bchar(char ch)
+{
+ switch(ch) {
+ /* bchar */
+ case ':': case '@': case '/':
+ /* bchar -> achar */
+ case '&': case '=':
+ /* bchar -> achar -> uchar -> unreserved */
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ case '-': case '.': case '_': case '~':
+ /* bchar -> achar -> uchar -> sub-delims-sh */
+ case '!': case '$': case '\'': case '(': case ')': case '*':
+ case '+': case ',':
+ /* bchar -> achar -> uchar -> pct-encoded */
+ case '%': /* HEXDIG chars are already included above */
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode imap_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *ptr = conn->options;
+
+ imapc->sasl.resetprefs = TRUE;
+
+ while(!result && ptr && *ptr) {
+ const char *key = ptr;
+ const char *value;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ value = ptr + 1;
+
+ while(*ptr && *ptr != ';')
+ ptr++;
+
+ if(strncasecompare(key, "AUTH=", 5))
+ result = Curl_sasl_parse_url_auth_option(&imapc->sasl,
+ value, ptr - value);
+ else
+ result = CURLE_URL_MALFORMAT;
+
+ if(*ptr == ';')
+ ptr++;
+ }
+
+ switch(imapc->sasl.prefmech) {
+ case SASL_AUTH_NONE:
+ imapc->preftype = IMAP_TYPE_NONE;
+ break;
+ case SASL_AUTH_DEFAULT:
+ imapc->preftype = IMAP_TYPE_ANY;
+ break;
+ default:
+ imapc->preftype = IMAP_TYPE_SASL;
+ break;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static CURLcode imap_parse_url_path(struct connectdata *conn)
+{
+ /* The imap struct is already initialised in imap_connect() */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ const char *begin = data->state.path;
+ const char *ptr = begin;
+
+ /* See how much of the URL is a valid path and decode it */
+ while(imap_is_bchar(*ptr))
+ ptr++;
+
+ if(ptr != begin) {
+ /* Remove the trailing slash if present */
+ const char *end = ptr;
+ if(end > begin && end[-1] == '/')
+ end--;
+
+ result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
+ TRUE);
+ if(result)
+ return result;
+ }
+ else
+ imap->mailbox = NULL;
+
+ /* There can be any number of parameters in the form ";NAME=VALUE" */
+ while(*ptr == ';') {
+ char *name;
+ char *value;
+ size_t valuelen;
+
+ /* Find the length of the name parameter */
+ begin = ++ptr;
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ if(!*ptr)
+ return CURLE_URL_MALFORMAT;
+
+ /* Decode the name parameter */
+ result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE);
+ if(result)
+ return result;
+
+ /* Find the length of the value parameter */
+ begin = ++ptr;
+ while(imap_is_bchar(*ptr))
+ ptr++;
+
+ /* Decode the value parameter */
+ result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE);
+ if(result) {
+ free(name);
+ return result;
+ }
+
+ DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value));
+
+ /* Process the known hierarchical parameters (UIDVALIDITY, UID, SECTION and
+ PARTIAL) stripping of the trailing slash character if it is present.
+
+ Note: Unknown parameters trigger a URL_MALFORMAT error. */
+ if(strcasecompare(name, "UIDVALIDITY") && !imap->uidvalidity) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->uidvalidity = value;
+ value = NULL;
+ }
+ else if(strcasecompare(name, "UID") && !imap->uid) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->uid = value;
+ value = NULL;
+ }
+ else if(strcasecompare(name, "SECTION") && !imap->section) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->section = value;
+ value = NULL;
+ }
+ else if(strcasecompare(name, "PARTIAL") && !imap->partial) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->partial = value;
+ value = NULL;
+ }
+ else {
+ free(name);
+ free(value);
+
+ return CURLE_URL_MALFORMAT;
+ }
+
+ free(name);
+ free(value);
+ }
+
+ /* Does the URL contain a query parameter? Only valid when we have a mailbox
+ and no UID as per RFC-5092 */
+ if(imap->mailbox && !imap->uid && *ptr == '?') {
+ /* Find the length of the query parameter */
+ begin = ++ptr;
+ while(imap_is_bchar(*ptr))
+ ptr++;
+
+ /* Decode the query parameter */
+ result = Curl_urldecode(data, begin, ptr - begin, &imap->query, NULL,
+ TRUE);
+ if(result)
+ return result;
+ }
+
+ /* Any extra stuff at the end of the URL is an error */
+ if(*ptr)
+ return CURLE_URL_MALFORMAT;
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode imap_parse_custom_request(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ if(custom) {
+ /* URL decode the custom request */
+ result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE);
+
+ /* Extract the parameters if specified */
+ if(!result) {
+ const char *params = imap->custom;
+
+ while(*params && *params != ' ')
+ params++;
+
+ if(*params) {
+ imap->custom_params = strdup(params);
+ imap->custom[params - imap->custom] = '\0';
+
+ if(!imap->custom_params)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ }
+
+ return result;
+}
+
+#endif /* CURL_DISABLE_IMAP */
diff --git a/Utilities/cmcurl/lib/imap.h b/Utilities/cmcurl/lib/imap.h
new file mode 100644
index 000000000..5e0e228f5
--- /dev/null
+++ b/Utilities/cmcurl/lib/imap.h
@@ -0,0 +1,96 @@
+#ifndef HEADER_CURL_IMAP_H
+#define HEADER_CURL_IMAP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * IMAP unique setup
+ ***************************************************************************/
+typedef enum {
+ IMAP_STOP, /* do nothing state, stops the state machine */
+ IMAP_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ IMAP_CAPABILITY,
+ IMAP_STARTTLS,
+ IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ IMAP_AUTHENTICATE,
+ IMAP_LOGIN,
+ IMAP_LIST,
+ IMAP_SELECT,
+ IMAP_FETCH,
+ IMAP_FETCH_FINAL,
+ IMAP_APPEND,
+ IMAP_APPEND_FINAL,
+ IMAP_SEARCH,
+ IMAP_LOGOUT,
+ IMAP_LAST /* never used */
+} imapstate;
+
+/* This IMAP struct is used in the Curl_easy. All IMAP data that is
+ connection-oriented must be in imap_conn to properly deal with the fact that
+ perhaps the Curl_easy is changed between the times the connection is
+ used. */
+struct IMAP {
+ curl_pp_transfer transfer;
+ char *mailbox; /* Mailbox to select */
+ char *uidvalidity; /* UIDVALIDITY to check in select */
+ char *uid; /* Message UID to fetch */
+ char *section; /* Message SECTION to fetch */
+ char *partial; /* Message PARTIAL to fetch */
+ char *query; /* Query to search for */
+ char *custom; /* Custom request */
+ char *custom_params; /* Parameters for the custom request */
+};
+
+/* imap_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct imap_conn {
+ struct pingpong pp;
+ imapstate state; /* Always use imap.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ struct SASL sasl; /* SASL-related parameters */
+ unsigned int preftype; /* Preferred authentication type */
+ int cmdid; /* Last used command ID */
+ char resptag[5]; /* Response tag to wait for */
+ bool tls_supported; /* StartTLS capability supported by server */
+ bool login_disabled; /* LOGIN command disabled by server */
+ bool ir_supported; /* Initial response supported by server */
+ char *mailbox; /* The last selected mailbox */
+ char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */
+};
+
+extern const struct Curl_handler Curl_handler_imap;
+extern const struct Curl_handler Curl_handler_imaps;
+
+/* Authentication type flags */
+#define IMAP_TYPE_CLEARTEXT (1 << 0)
+#define IMAP_TYPE_SASL (1 << 1)
+
+/* Authentication type values */
+#define IMAP_TYPE_NONE 0
+#define IMAP_TYPE_ANY ~0U
+
+#endif /* HEADER_CURL_IMAP_H */
diff --git a/Utilities/cmcurl/lib/inet_ntop.c b/Utilities/cmcurl/lib/inet_ntop.c
new file mode 100644
index 000000000..9afbdbb32
--- /dev/null
+++ b/Utilities/cmcurl/lib/inet_ntop.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Original code by Paul Vixie. "curlified" by Gisle Vanem.
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "curl_printf.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/*
+ * Format an IPv4 address, more or less like inet_ntoa().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ * - uses no statics
+ * - takes a unsigned char* not an in_addr as input
+ */
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
+{
+ char tmp[sizeof "255.255.255.255"];
+ size_t len;
+
+ DEBUGASSERT(size >= 16);
+
+ tmp[0] = '\0';
+ (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+ ((int)((unsigned char)src[0])) & 0xff,
+ ((int)((unsigned char)src[1])) & 0xff,
+ ((int)((unsigned char)src[2])) & 0xff,
+ ((int)((unsigned char)src[3])) & 0xff);
+
+ len = strlen(tmp);
+ if(len == 0 || len >= size) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return dst;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ char *tp;
+ struct {
+ long base;
+ long len;
+ } best, cur;
+ unsigned long words[IN6ADDRSZ / INT16SZ];
+ int i;
+
+ /* Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof(words));
+ for(i = 0; i < IN6ADDRSZ; i++)
+ words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
+
+ best.base = -1;
+ cur.base = -1;
+ best.len = 0;
+ cur.len = 0;
+
+ for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ if(words[i] == 0) {
+ if(cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ }
+ else if(cur.base != -1) {
+ if(best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
+ best = cur;
+ if(best.base != -1 && best.len < 2)
+ best.base = -1;
+ /* Format the result. */
+ tp = tmp;
+ for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
+ if(i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+
+ /* Are we following an initial run of 0x00s or any real hex?
+ */
+ if(i != 0)
+ *tp++ = ':';
+
+ /* Is this address an encapsulated IPv4?
+ */
+ if(i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += snprintf(tp, 5, "%lx", words[i]);
+ }
+
+ /* Was it a trailing run of 0x00's?
+ */
+ if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /* Check for overflow, copy, and we're done.
+ */
+ if((size_t)(tp - tmp) > size) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return dst;
+}
+#endif /* ENABLE_IPV6 */
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`buf').
+ * Returns NULL on error and errno set with the specific
+ * error, EAFNOSUPPORT or ENOSPC.
+ *
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this function sets when returning NULL, not SOCKERRNO.
+ */
+char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+ switch(af) {
+ case AF_INET:
+ return inet_ntop4((const unsigned char *)src, buf, size);
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ return inet_ntop6((const unsigned char *)src, buf, size);
+#endif
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return NULL;
+ }
+}
+#endif /* HAVE_INET_NTOP */
diff --git a/Utilities/cmcurl/lib/inet_ntop.h b/Utilities/cmcurl/lib/inet_ntop.h
new file mode 100644
index 000000000..9f4461271
--- /dev/null
+++ b/Utilities/cmcurl/lib/inet_ntop.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_INET_NTOP_H
+#define HEADER_CURL_INET_NTOP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+
+#ifdef HAVE_INET_NTOP
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_ntop(af,addr,buf,size) \
+ inet_ntop(af, addr, buf, (curl_socklen_t)size)
+#endif
+
+#endif /* HEADER_CURL_INET_NTOP_H */
+
diff --git a/Utilities/cmcurl/lib/inet_pton.c b/Utilities/cmcurl/lib/inet_pton.c
new file mode 100644
index 000000000..475f44abc
--- /dev/null
+++ b/Utilities/cmcurl/lib/inet_pton.c
@@ -0,0 +1,236 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef ENABLE_IPV6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * notice:
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this function sets when returning (-1), not SOCKERRNO.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+ switch(af) {
+ case AF_INET:
+ return (inet_pton4(src, (unsigned char *)dst));
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ return (inet_pton6(src, (unsigned char *)dst));
+#endif
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ tp = tmp;
+ *tp = 0;
+ while((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if(pch) {
+ unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
+
+ if(saw_digit && *tp == 0)
+ return (0);
+ if(val > 255)
+ return (0);
+ *tp = (unsigned char)val;
+ if(! saw_digit) {
+ if(++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ }
+ else if(ch == '.' && saw_digit) {
+ if(octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ }
+ else
+ return (0);
+ }
+ if(octets < 4)
+ return (0);
+ memcpy(dst, tmp, INADDRSZ);
+ return (1);
+}
+
+#ifdef ENABLE_IPV6
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ size_t val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if(*src == ':')
+ if(*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr((xdigits = xdigits_l), ch);
+ if(!pch)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if(pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if(++saw_xdigit > 4)
+ return (0);
+ continue;
+ }
+ if(ch == ':') {
+ curtok = src;
+ if(!saw_xdigit) {
+ if(colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if(tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if(ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if(saw_xdigit) {
+ if(tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) ((val >> 8) & 0xff);
+ *tp++ = (unsigned char) (val & 0xff);
+ }
+ if(colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const ssize_t n = tp - colonp;
+ ssize_t i;
+
+ if(tp == endp)
+ return (0);
+ for(i = 1; i <= n; i++) {
+ *(endp - i) = *(colonp + n - i);
+ *(colonp + n - i) = 0;
+ }
+ tp = endp;
+ }
+ if(tp != endp)
+ return (0);
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+#endif /* ENABLE_IPV6 */
+
+#endif /* HAVE_INET_PTON */
diff --git a/Utilities/cmcurl/lib/inet_pton.h b/Utilities/cmcurl/lib/inet_pton.h
new file mode 100644
index 000000000..9188d9598
--- /dev/null
+++ b/Utilities/cmcurl/lib/inet_pton.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_INET_PTON_H
+#define HEADER_CURL_INET_PTON_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+int Curl_inet_pton(int, const char *, void *);
+
+#ifdef HAVE_INET_PTON
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#endif
+
+#endif /* HEADER_CURL_INET_PTON_H */
+
diff --git a/Utilities/cmcurl/lib/krb5.c b/Utilities/cmcurl/lib/krb5.c
new file mode 100644
index 000000000..69a35979a
--- /dev/null
+++ b/Utilities/cmcurl/lib/krb5.c
@@ -0,0 +1,342 @@
+/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2016 Daniel Stenberg
+ * 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.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_FTP)
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "curl_gssapi.h"
+#include "sendf.h"
+#include "curl_sec.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static int
+krb5_init(void *app_data)
+{
+ gss_ctx_id_t *context = app_data;
+ /* Make sure our context is initialized for krb5_end. */
+ *context = GSS_C_NO_CONTEXT;
+ return 0;
+}
+
+static int
+krb5_check_prot(void *app_data, int level)
+{
+ (void)app_data; /* unused */
+ if(level == PROT_CONFIDENTIAL)
+ return -1;
+ return 0;
+}
+
+static int
+krb5_decode(void *app_data, void *buf, int len,
+ int level UNUSED_PARAM,
+ struct connectdata *conn UNUSED_PARAM)
+{
+ gss_ctx_id_t *context = app_data;
+ OM_uint32 maj, min;
+ gss_buffer_desc enc, dec;
+
+ (void)level;
+ (void)conn;
+
+ enc.value = buf;
+ enc.length = len;
+ maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
+ if(maj != GSS_S_COMPLETE) {
+ if(len >= 4)
+ strcpy(buf, "599 ");
+ return -1;
+ }
+
+ memcpy(buf, dec.value, dec.length);
+ len = curlx_uztosi(dec.length);
+ gss_release_buffer(&min, &dec);
+
+ return len;
+}
+
+static int
+krb5_overhead(void *app_data, int level, int len)
+{
+ /* no arguments are used */
+ (void)app_data;
+ (void)level;
+ (void)len;
+ return 0;
+}
+
+static int
+krb5_encode(void *app_data, const void *from, int length, int level, void **to)
+{
+ gss_ctx_id_t *context = app_data;
+ gss_buffer_desc dec, enc;
+ OM_uint32 maj, min;
+ int state;
+ int len;
+
+ /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
+ * libraries modify the input buffer in gss_seal()
+ */
+ dec.value = (void *)from;
+ dec.length = length;
+ maj = gss_seal(&min, *context,
+ level == PROT_PRIVATE,
+ GSS_C_QOP_DEFAULT,
+ &dec, &state, &enc);
+
+ if(maj != GSS_S_COMPLETE)
+ return -1;
+
+ /* malloc a new buffer, in case gss_release_buffer doesn't work as
+ expected */
+ *to = malloc(enc.length);
+ if(!*to)
+ return -1;
+ memcpy(*to, enc.value, enc.length);
+ len = curlx_uztosi(enc.length);
+ gss_release_buffer(&min, &enc);
+ return len;
+}
+
+static int
+krb5_auth(void *app_data, struct connectdata *conn)
+{
+ int ret = AUTH_OK;
+ char *p;
+ const char *host = conn->host.name;
+ ssize_t nread;
+ curl_socklen_t l = sizeof(conn->local_addr);
+ struct Curl_easy *data = conn->data;
+ CURLcode result;
+ const char *service = data->set.str[STRING_SERVICE_NAME] ?
+ data->set.str[STRING_SERVICE_NAME] :
+ "ftp";
+ const char *srv_host = "host";
+ gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
+ OM_uint32 maj, min;
+ gss_name_t gssname;
+ gss_ctx_id_t *context = app_data;
+ struct gss_channel_bindings_struct chan;
+ size_t base64_sz = 0;
+ struct sockaddr_in **remote_addr =
+ (struct sockaddr_in **)&conn->ip_addr->ai_addr;
+ char *stringp;
+
+ if(getsockname(conn->sock[FIRSTSOCKET],
+ (struct sockaddr *)&conn->local_addr, &l) < 0)
+ perror("getsockname()");
+
+ chan.initiator_addrtype = GSS_C_AF_INET;
+ chan.initiator_address.length = l - 4;
+ chan.initiator_address.value = &conn->local_addr.sin_addr.s_addr;
+ chan.acceptor_addrtype = GSS_C_AF_INET;
+ chan.acceptor_address.length = l - 4;
+ chan.acceptor_address.value = &(*remote_addr)->sin_addr.s_addr;
+ chan.application_data.length = 0;
+ chan.application_data.value = NULL;
+
+ /* this loop will execute twice (once for service, once for host) */
+ for(;;) {
+ /* this really shouldn't be repeated here, but can't help it */
+ if(service == srv_host) {
+ result = Curl_ftpsend(conn, "AUTH GSSAPI");
+ if(result)
+ return -2;
+
+ if(Curl_GetFTPResponse(&nread, conn, NULL))
+ return -1;
+
+ if(data->state.buffer[0] != '3')
+ return -1;
+ }
+
+ stringp = aprintf("%s@%s", service, host);
+ if(!stringp)
+ return -2;
+
+ input_buffer.value = stringp;
+ input_buffer.length = strlen(stringp);
+ maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE,
+ &gssname);
+ free(stringp);
+ if(maj != GSS_S_COMPLETE) {
+ gss_release_name(&min, &gssname);
+ if(service == srv_host) {
+ Curl_failf(data, "Error importing service name %s@%s", service, host);
+ return AUTH_ERROR;
+ }
+ service = srv_host;
+ continue;
+ }
+ /* We pass NULL as |output_name_type| to avoid a leak. */
+ gss_display_name(&min, gssname, &output_buffer, NULL);
+ Curl_infof(data, "Trying against %s\n", output_buffer.value);
+ gssresp = GSS_C_NO_BUFFER;
+ *context = GSS_C_NO_CONTEXT;
+
+ do {
+ /* Release the buffer at each iteration to avoid leaking: the first time
+ we are releasing the memory from gss_display_name. The last item is
+ taken care by a final gss_release_buffer. */
+ gss_release_buffer(&min, &output_buffer);
+ ret = AUTH_OK;
+ maj = Curl_gss_init_sec_context(data,
+ &min,
+ context,
+ gssname,
+ &Curl_krb5_mech_oid,
+ &chan,
+ gssresp,
+ &output_buffer,
+ TRUE,
+ NULL);
+
+ if(gssresp) {
+ free(_gssresp.value);
+ gssresp = NULL;
+ }
+
+ if(GSS_ERROR(maj)) {
+ Curl_infof(data, "Error creating security context\n");
+ ret = AUTH_ERROR;
+ break;
+ }
+
+ if(output_buffer.length != 0) {
+ char *cmd;
+
+ result = Curl_base64_encode(data, (char *)output_buffer.value,
+ output_buffer.length, &p, &base64_sz);
+ if(result) {
+ Curl_infof(data, "base64-encoding: %s\n",
+ curl_easy_strerror(result));
+ ret = AUTH_ERROR;
+ break;
+ }
+
+ cmd = aprintf("ADAT %s", p);
+ if(cmd)
+ result = Curl_ftpsend(conn, cmd);
+ else
+ result = CURLE_OUT_OF_MEMORY;
+
+ free(p);
+
+ if(result) {
+ ret = -2;
+ break;
+ }
+
+ if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+ ret = -1;
+ break;
+ }
+
+ if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
+ Curl_infof(data, "Server didn't accept auth data\n");
+ ret = AUTH_ERROR;
+ break;
+ }
+
+ p = data->state.buffer + 4;
+ p = strstr(p, "ADAT=");
+ if(p) {
+ result = Curl_base64_decode(p + 5,
+ (unsigned char **)&_gssresp.value,
+ &_gssresp.length);
+ if(result) {
+ Curl_failf(data, "base64-decoding: %s",
+ curl_easy_strerror(result));
+ ret = AUTH_CONTINUE;
+ break;
+ }
+ }
+
+ gssresp = &_gssresp;
+ }
+ } while(maj == GSS_S_CONTINUE_NEEDED);
+
+ gss_release_name(&min, &gssname);
+ gss_release_buffer(&min, &output_buffer);
+
+ if(gssresp)
+ free(_gssresp.value);
+
+ if(ret == AUTH_OK || service == srv_host)
+ return ret;
+
+ service = srv_host;
+ }
+ return ret;
+}
+
+static void krb5_end(void *app_data)
+{
+ OM_uint32 min;
+ gss_ctx_id_t *context = app_data;
+ if(*context != GSS_C_NO_CONTEXT) {
+#ifdef DEBUGBUILD
+ OM_uint32 maj =
+#endif
+ gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
+ DEBUGASSERT(maj == GSS_S_COMPLETE);
+ }
+}
+
+struct Curl_sec_client_mech Curl_krb5_client_mech = {
+ "GSSAPI",
+ sizeof(gss_ctx_id_t),
+ krb5_init,
+ krb5_auth,
+ krb5_end,
+ krb5_check_prot,
+ krb5_overhead,
+ krb5_encode,
+ krb5_decode
+};
+
+#endif /* HAVE_GSSAPI && !CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/lib/ldap.c b/Utilities/cmcurl/lib/ldap.c
new file mode 100644
index 000000000..79e84d94e
--- /dev/null
+++ b/Utilities/cmcurl/lib/ldap.c
@@ -0,0 +1,1084 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */
+# include <winldap.h>
+# ifndef LDAP_VENDOR_NAME
+# error Your Platform SDK is NOT sufficient for LDAP support! \
+ Update your Platform SDK, or disable LDAP support!
+# else
+# include <winber.h>
+# endif
+#else
+# define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */
+# ifdef HAVE_LBER_H
+# include <lber.h>
+# endif
+# include <ldap.h>
+# if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
+# include <ldap_ssl.h>
+# endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
+#endif
+
+/* These are macros in both <wincrypt.h> (in above <winldap.h>) and typedefs
+ * in BoringSSL's <openssl/x509.h>
+ */
+#ifdef HAVE_BORINGSSL
+# undef X509_NAME
+# undef X509_CERT_PAIR
+# undef X509_EXTENSIONS
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "transfer.h"
+#include "strcase.h"
+#include "strtok.h"
+#include "curl_ldap.h"
+#include "curl_multibyte.h"
+#include "curl_base64.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/* Use our own implementation. */
+
+typedef struct {
+ char *lud_host;
+ int lud_port;
+#if defined(USE_WIN32_LDAP)
+ TCHAR *lud_dn;
+ TCHAR **lud_attrs;
+#else
+ char *lud_dn;
+ char **lud_attrs;
+#endif
+ int lud_scope;
+#if defined(USE_WIN32_LDAP)
+ TCHAR *lud_filter;
+#else
+ char *lud_filter;
+#endif
+ char **lud_exts;
+ size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the
+ "real" struct so can only be used in code
+ without HAVE_LDAP_URL_PARSE defined */
+} CURL_LDAPURLDesc;
+
+#undef LDAPURLDesc
+#define LDAPURLDesc CURL_LDAPURLDesc
+
+static int _ldap_url_parse(const struct connectdata *conn,
+ LDAPURLDesc **ludp);
+static void _ldap_free_urldesc(LDAPURLDesc *ludp);
+
+#undef ldap_free_urldesc
+#define ldap_free_urldesc _ldap_free_urldesc
+#endif
+
+#ifdef DEBUG_LDAP
+ #define LDAP_TRACE(x) do { \
+ _ldap_trace("%u: ", __LINE__); \
+ _ldap_trace x; \
+ } WHILE_FALSE
+
+ static void _ldap_trace(const char *fmt, ...);
+#else
+ #define LDAP_TRACE(x) Curl_nop_stmt
+#endif
+
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+ "LDAP", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_ldap, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAP, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef HAVE_LDAP_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+ "LDAPS", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_ldap, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAPS, /* defport */
+ CURLPROTO_LDAPS, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#endif
+
+#if defined(USE_WIN32_LDAP)
+
+#if defined(USE_WINDOWS_SSPI)
+static int ldap_win_bind_auth(LDAP *server, const char *user,
+ const char *passwd, unsigned long authflags)
+{
+ ULONG method = 0;
+ SEC_WINNT_AUTH_IDENTITY cred = { 0, };
+ int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+
+#if defined(USE_SPNEGO)
+ if(authflags & CURLAUTH_NEGOTIATE) {
+ method = LDAP_AUTH_NEGOTIATE;
+ }
+ else
+#endif
+#if defined(USE_NTLM)
+ if(authflags & CURLAUTH_NTLM) {
+ method = LDAP_AUTH_NTLM;
+ }
+ else
+#endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+ if(authflags & CURLAUTH_DIGEST) {
+ method = LDAP_AUTH_DIGEST;
+ }
+ else
+#endif
+ {
+ /* required anyway if one of upper preprocessor definitions enabled */
+ }
+
+ if(method && user && passwd) {
+ rc = Curl_create_sspi_identity(user, passwd, &cred);
+ if(!rc) {
+ rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
+ Curl_sspi_free_identity(&cred);
+ }
+ }
+ else {
+ /* proceed with current user credentials */
+ method = LDAP_AUTH_NEGOTIATE;
+ rc = ldap_bind_s(server, NULL, NULL, method);
+ }
+ return rc;
+}
+#endif /* #if defined(USE_WINDOWS_SSPI) */
+
+static int ldap_win_bind(struct connectdata *conn, LDAP *server,
+ const char *user, const char *passwd)
+{
+ int rc = LDAP_INVALID_CREDENTIALS;
+ ULONG method = LDAP_AUTH_SIMPLE;
+
+ PTCHAR inuser = NULL;
+ PTCHAR inpass = NULL;
+
+ if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
+ inuser = Curl_convert_UTF8_to_tchar((char *) user);
+ inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
+
+ rc = ldap_bind_s(server, inuser, inpass, method);
+
+ Curl_unicodefree(inuser);
+ Curl_unicodefree(inpass);
+ }
+#if defined(USE_WINDOWS_SSPI)
+ else {
+ rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
+ }
+#endif
+
+ return rc;
+}
+#endif /* #if defined(USE_WIN32_LDAP) */
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ int rc = 0;
+ LDAP *server = NULL;
+ LDAPURLDesc *ludp = NULL;
+ LDAPMessage *ldapmsg = NULL;
+ LDAPMessage *entryIterator;
+ int num = 0;
+ struct Curl_easy *data=conn->data;
+ int ldap_proto = LDAP_VERSION3;
+ int ldap_ssl = 0;
+ char *val_b64 = NULL;
+ size_t val_b64_sz = 0;
+ curl_off_t dlsize = 0;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
+#endif
+#if defined(USE_WIN32_LDAP)
+ TCHAR *host = NULL;
+#else
+ char *host = NULL;
+#endif
+ char *user = NULL;
+ char *passwd = NULL;
+
+ *done = TRUE; /* unconditionally */
+ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
+ LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
+ infof(data, "LDAP local: %s\n", data->change.url);
+
+#ifdef HAVE_LDAP_URL_PARSE
+ rc = ldap_url_parse(data->change.url, &ludp);
+#else
+ rc = _ldap_url_parse(conn, &ludp);
+#endif
+ if(rc != 0) {
+ failf(data, "LDAP local: %s", ldap_err2string(rc));
+ result = CURLE_LDAP_INVALID_URL;
+ goto quit;
+ }
+
+ /* Get the URL scheme (either ldap or ldaps) */
+ if(conn->given->flags & PROTOPT_SSL)
+ ldap_ssl = 1;
+ infof(data, "LDAP local: trying to establish %s connection\n",
+ ldap_ssl ? "encrypted" : "cleartext");
+
+#if defined(USE_WIN32_LDAP)
+ host = Curl_convert_UTF8_to_tchar(conn->host.name);
+ if(!host) {
+ result = CURLE_OUT_OF_MEMORY;
+
+ goto quit;
+ }
+#else
+ host = conn->host.name;
+#endif
+
+ if(conn->bits.user_passwd) {
+ user = conn->user;
+ passwd = conn->passwd;
+ }
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
+#endif
+ ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+
+ if(ldap_ssl) {
+#ifdef HAVE_LDAP_SSL
+#ifdef USE_WIN32_LDAP
+ /* Win32 LDAP SDK doesn't support insecure mode without CA! */
+ server = ldap_sslinit(host, (int)conn->port, 1);
+ ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
+#else
+ int ldap_option;
+ char *ldap_ca = conn->ssl_config.CAfile;
+#if defined(CURL_HAS_NOVELL_LDAPSDK)
+ rc = ldapssl_client_init(NULL, NULL);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ if(conn->ssl_config.verifypeer) {
+ /* Novell SDK supports DER or BASE64 files. */
+ int cert_type = LDAPSSL_CERT_FILETYPE_B64;
+ if((data->set.ssl.cert_type) &&
+ (strcasecompare(data->set.ssl.cert_type, "DER")))
+ cert_type = LDAPSSL_CERT_FILETYPE_DER;
+ if(!ldap_ca) {
+ failf(data, "LDAP local: ERROR %s CA cert not set!",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ infof(data, "LDAP local: using %s CA cert '%s'\n",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_ca);
+ rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting %s CA cert: %s",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ ldap_option = LDAPSSL_VERIFY_SERVER;
+ }
+ else
+ ldap_option = LDAPSSL_VERIFY_NONE;
+ rc = ldapssl_set_verify_mode(ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ server = ldapssl_init(host, (int)conn->port, 1);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.dispname, conn->port);
+ result = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+#elif defined(LDAP_OPT_X_TLS)
+ if(conn->ssl_config.verifypeer) {
+ /* OpenLDAP SDK supports BASE64 files. */
+ if((data->set.ssl.cert_type) &&
+ (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
+ failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ if(!ldap_ca) {
+ failf(data, "LDAP local: ERROR PEM CA cert not set!");
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ ldap_option = LDAP_OPT_X_TLS_DEMAND;
+ }
+ else
+ ldap_option = LDAP_OPT_X_TLS_NEVER;
+
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ server = ldap_init(host, (int)conn->port);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.dispname, conn->port);
+ result = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+ ldap_option = LDAP_OPT_X_TLS_HARD;
+ rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+/*
+ rc = ldap_start_tls_s(server, NULL, NULL);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
+ ldap_err2string(rc));
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+*/
+#else
+ /* we should probably never come up to here since configure
+ should check in first place if we can support LDAP SSL/TLS */
+ failf(data, "LDAP local: SSL/TLS not supported with this version "
+ "of the OpenLDAP toolkit\n");
+ result = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+#endif
+#endif
+#endif /* CURL_LDAP_USE_SSL */
+ }
+ else {
+ server = ldap_init(host, (int)conn->port);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.dispname, conn->port);
+ result = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+ }
+#ifdef USE_WIN32_LDAP
+ ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+#endif
+
+#ifdef USE_WIN32_LDAP
+ rc = ldap_win_bind(conn, server, user, passwd);
+#else
+ rc = ldap_simple_bind_s(server, user, passwd);
+#endif
+ if(!ldap_ssl && rc != 0) {
+ ldap_proto = LDAP_VERSION2;
+ ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+#ifdef USE_WIN32_LDAP
+ rc = ldap_win_bind(conn, server, user, passwd);
+#else
+ rc = ldap_simple_bind_s(server, user, passwd);
+#endif
+ }
+ if(rc != 0) {
+ failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
+ result = CURLE_LDAP_CANNOT_BIND;
+ goto quit;
+ }
+
+ rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
+
+ if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+ failf(data, "LDAP remote: %s", ldap_err2string(rc));
+ result = CURLE_LDAP_SEARCH_FAILED;
+ goto quit;
+ }
+
+ for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
+ entryIterator;
+ entryIterator = ldap_next_entry(server, entryIterator), num++) {
+ BerElement *ber = NULL;
+#if defined(USE_WIN32_LDAP)
+ TCHAR *attribute;
+#else
+ char *attribute; /*! suspicious that this isn't 'const' */
+#endif
+ int i;
+
+ /* Get the DN and write it to the client */
+ {
+ char *name;
+ size_t name_len;
+#if defined(USE_WIN32_LDAP)
+ TCHAR *dn = ldap_get_dn(server, entryIterator);
+ name = Curl_convert_tchar_to_UTF8(dn);
+ if(!name) {
+ ldap_memfree(dn);
+
+ result = CURLE_OUT_OF_MEMORY;
+
+ goto quit;
+ }
+#else
+ char *dn = name = ldap_get_dn(server, entryIterator);
+#endif
+ name_len = strlen(name);
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ if(result) {
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(name);
+#endif
+ ldap_memfree(dn);
+
+ goto quit;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
+ name_len);
+ if(result) {
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(name);
+#endif
+ ldap_memfree(dn);
+
+ goto quit;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ if(result) {
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(name);
+#endif
+ ldap_memfree(dn);
+
+ goto quit;
+ }
+
+ dlsize += name_len + 5;
+
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(name);
+#endif
+ ldap_memfree(dn);
+ }
+
+ /* Get the attributes and write them to the client */
+ for(attribute = ldap_first_attribute(server, entryIterator, &ber);
+ attribute;
+ attribute = ldap_next_attribute(server, entryIterator, ber)) {
+ BerValue **vals;
+ size_t attr_len;
+#if defined(USE_WIN32_LDAP)
+ char *attr = Curl_convert_tchar_to_UTF8(attribute);
+ if(!attr) {
+ if(ber)
+ ber_free(ber, 0);
+
+ result = CURLE_OUT_OF_MEMORY;
+
+ goto quit;
+ }
+#else
+ char *attr = attribute;
+#endif
+ attr_len = strlen(attr);
+
+ vals = ldap_get_values_len(server, entryIterator, attribute);
+ if(vals != NULL) {
+ for(i = 0; (vals[i] != NULL); i++) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *) attr, attr_len);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ dlsize += attr_len + 3;
+
+ if((attr_len > 7) &&
+ (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
+ /* Binary attribute, encode to base64. */
+ result = Curl_base64_encode(data,
+ vals[i]->bv_val,
+ vals[i]->bv_len,
+ &val_b64,
+ &val_b64_sz);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ if(val_b64_sz > 0) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+ val_b64_sz);
+ free(val_b64);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ dlsize += val_b64_sz;
+ }
+ }
+ else {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+ vals[i]->bv_len);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ dlsize += vals[i]->bv_len;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ if(result) {
+ ldap_value_free_len(vals);
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+ if(ber)
+ ber_free(ber, 0);
+
+ goto quit;
+ }
+
+ dlsize++;
+ }
+
+ /* Free memory used to store values */
+ ldap_value_free_len(vals);
+ }
+
+ /* Free the attribute as we are done with it */
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(attr);
+#endif
+ ldap_memfree(attribute);
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ if(result)
+ goto quit;
+ dlsize++;
+ Curl_pgrsSetDownloadCounter(data, dlsize);
+ }
+
+ if(ber)
+ ber_free(ber, 0);
+ }
+
+quit:
+ if(ldapmsg) {
+ ldap_msgfree(ldapmsg);
+ LDAP_TRACE(("Received %d entries\n", num));
+ }
+ if(rc == LDAP_SIZELIMIT_EXCEEDED)
+ infof(data, "There are more than %d entries\n", num);
+ if(ludp)
+ ldap_free_urldesc(ludp);
+ if(server)
+ ldap_unbind_s(server);
+#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
+ if(ldap_ssl)
+ ldapssl_client_deinit();
+#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
+
+#if defined(USE_WIN32_LDAP)
+ Curl_unicodefree(host);
+#endif
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ connclose(conn, "LDAP connection always disable re-use");
+
+ return result;
+}
+
+#ifdef DEBUG_LDAP
+static void _ldap_trace(const char *fmt, ...)
+{
+ static int do_trace = -1;
+ va_list args;
+
+ if(do_trace == -1) {
+ const char *env = getenv("CURL_TRACE");
+ do_trace = (env && strtol(env, NULL, 10) > 0);
+ }
+ if(!do_trace)
+ return;
+
+ va_start(args, fmt);
+ vfprintf(stderr, fmt, args);
+ va_end(args);
+}
+#endif
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/*
+ * Return scope-value for a scope-string.
+ */
+static int str2scope(const char *p)
+{
+ if(strcasecompare(p, "one"))
+ return LDAP_SCOPE_ONELEVEL;
+ if(strcasecompare(p, "onetree"))
+ return LDAP_SCOPE_ONELEVEL;
+ if(strcasecompare(p, "base"))
+ return LDAP_SCOPE_BASE;
+ if(strcasecompare(p, "sub"))
+ return LDAP_SCOPE_SUBTREE;
+ if(strcasecompare(p, "subtree"))
+ return LDAP_SCOPE_SUBTREE;
+ return (-1);
+}
+
+/*
+ * Split 'str' into strings separated by commas.
+ * Note: out[] points into 'str'.
+ */
+static bool split_str(char *str, char ***out, size_t *count)
+{
+ char **res;
+ char *lasts;
+ char *s;
+ size_t i;
+ size_t items = 1;
+
+ s = strchr(str, ',');
+ while(s) {
+ items++;
+ s = strchr(++s, ',');
+ }
+
+ res = calloc(items, sizeof(char *));
+ if(!res)
+ return FALSE;
+
+ for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
+ s = strtok_r(NULL, ",", &lasts), i++)
+ res[i] = s;
+
+ *out = res;
+ *count = items;
+
+ return TRUE;
+}
+
+/*
+ * Break apart the pieces of an LDAP URL.
+ * Syntax:
+ * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
+ *
+ * <hostname> already known from 'conn->host.name'.
+ * <port> already known from 'conn->remote_port'.
+ * extract the rest from 'conn->data->state.path+1'. All fields are optional.
+ * e.g.
+ * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
+ * yields ludp->lud_dn = "".
+ *
+ * Defined in RFC4516 section 2.
+ */
+static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+ int rc = LDAP_SUCCESS;
+ char *path;
+ char *p;
+ char *q;
+ size_t i;
+
+ if(!conn->data ||
+ !conn->data->state.path ||
+ conn->data->state.path[0] != '/' ||
+ !checkprefix("LDAP", conn->data->change.url))
+ return LDAP_INVALID_SYNTAX;
+
+ ludp->lud_scope = LDAP_SCOPE_BASE;
+ ludp->lud_port = conn->remote_port;
+ ludp->lud_host = conn->host.name;
+
+ /* Duplicate the path */
+ p = path = strdup(conn->data->state.path + 1);
+ if(!path)
+ return LDAP_NO_MEMORY;
+
+ /* Parse the DN (Distinguished Name) */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p) {
+ char *dn = p;
+ char *unescaped;
+ CURLcode result;
+
+ LDAP_TRACE(("DN '%s'\n", dn));
+
+ /* Unescape the DN */
+ result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE);
+ if(result) {
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+
+#if defined(USE_WIN32_LDAP)
+ /* Convert the unescaped string to a tchar */
+ ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);
+
+ /* Free the unescaped string as we are done with it */
+ Curl_unicodefree(unescaped);
+
+ if(!ludp->lud_dn) {
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+#else
+ ludp->lud_dn = unescaped;
+#endif
+ }
+
+ p = q;
+ if(!p)
+ goto quit;
+
+ /* Parse the attributes. skip "??" */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p) {
+ char **attributes;
+ size_t count = 0;
+
+ /* Split the string into an array of attributes */
+ if(!split_str(p, &attributes, &count)) {
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+
+ /* Allocate our array (+1 for the NULL entry) */
+#if defined(USE_WIN32_LDAP)
+ ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
+#else
+ ludp->lud_attrs = calloc(count + 1, sizeof(char *));
+#endif
+ if(!ludp->lud_attrs) {
+ free(attributes);
+
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+
+ for(i = 0; i < count; i++) {
+ char *unescaped;
+ CURLcode result;
+
+ LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i]));
+
+ /* Unescape the attribute */
+ result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
+ FALSE);
+ if(result) {
+ free(attributes);
+
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+
+#if defined(USE_WIN32_LDAP)
+ /* Convert the unescaped string to a tchar */
+ ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);
+
+ /* Free the unescaped string as we are done with it */
+ Curl_unicodefree(unescaped);
+
+ if(!ludp->lud_attrs[i]) {
+ free(attributes);
+
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+#else
+ ludp->lud_attrs[i] = unescaped;
+#endif
+
+ ludp->lud_attrs_dups++;
+ }
+
+ free(attributes);
+ }
+
+ p = q;
+ if(!p)
+ goto quit;
+
+ /* Parse the scope. skip "??" */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p) {
+ ludp->lud_scope = str2scope(p);
+ if(ludp->lud_scope == -1) {
+ rc = LDAP_INVALID_SYNTAX;
+
+ goto quit;
+ }
+ LDAP_TRACE(("scope %d\n", ludp->lud_scope));
+ }
+
+ p = q;
+ if(!p)
+ goto quit;
+
+ /* Parse the filter */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p) {
+ char *filter = p;
+ char *unescaped;
+ CURLcode result;
+
+ LDAP_TRACE(("filter '%s'\n", filter));
+
+ /* Unescape the filter */
+ result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE);
+ if(result) {
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+
+#if defined(USE_WIN32_LDAP)
+ /* Convert the unescaped string to a tchar */
+ ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);
+
+ /* Free the unescaped string as we are done with it */
+ Curl_unicodefree(unescaped);
+
+ if(!ludp->lud_filter) {
+ rc = LDAP_NO_MEMORY;
+
+ goto quit;
+ }
+#else
+ ludp->lud_filter = unescaped;
+#endif
+ }
+
+ p = q;
+ if(p && !*p) {
+ rc = LDAP_INVALID_SYNTAX;
+
+ goto quit;
+ }
+
+quit:
+ free(path);
+
+ return rc;
+}
+
+static int _ldap_url_parse(const struct connectdata *conn,
+ LDAPURLDesc **ludpp)
+{
+ LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
+ int rc;
+
+ *ludpp = NULL;
+ if(!ludp)
+ return LDAP_NO_MEMORY;
+
+ rc = _ldap_url_parse2(conn, ludp);
+ if(rc != LDAP_SUCCESS) {
+ _ldap_free_urldesc(ludp);
+ ludp = NULL;
+ }
+ *ludpp = ludp;
+ return (rc);
+}
+
+static void _ldap_free_urldesc(LDAPURLDesc *ludp)
+{
+ size_t i;
+
+ if(!ludp)
+ return;
+
+ free(ludp->lud_dn);
+ free(ludp->lud_filter);
+
+ if(ludp->lud_attrs) {
+ for(i = 0; i < ludp->lud_attrs_dups; i++)
+ free(ludp->lud_attrs[i]);
+ free(ludp->lud_attrs);
+ }
+
+ free(ludp);
+}
+#endif /* !HAVE_LDAP_URL_PARSE */
+#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */
diff --git a/Utilities/cmcurl/lib/libcurl.rc b/Utilities/cmcurl/lib/libcurl.rc
new file mode 100644
index 000000000..3316fba19
--- /dev/null
+++ b/Utilities/cmcurl/lib/libcurl.rc
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include <winver.h>
+#include "../include/curl/curlver.h"
+
+LANGUAGE 0x09,0x01
+
+#define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RC_VERSION
+ PRODUCTVERSION RC_VERSION
+ FILEFLAGSMASK 0x3fL
+#if defined(DEBUGBUILD) || defined(_DEBUG)
+ FILEFLAGS 1
+#else
+ FILEFLAGS 0
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "The curl library, https://curl.haxx.se/\0"
+ VALUE "FileDescription", "libcurl Shared Library\0"
+ VALUE "FileVersion", LIBCURL_VERSION "\0"
+ VALUE "InternalName", "libcurl\0"
+ VALUE "OriginalFilename", "libcurl.dll\0"
+ VALUE "ProductName", "The curl library\0"
+ VALUE "ProductVersion", LIBCURL_VERSION "\0"
+ VALUE "LegalCopyright", "\xa9 " LIBCURL_COPYRIGHT "\0" /* a9: Copyright symbol */
+ VALUE "License", "https://curl.haxx.se/docs/copyright.html\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Utilities/cmcurl/lib/llist.c b/Utilities/cmcurl/lib/llist.c
new file mode 100644
index 000000000..4bb0a51b8
--- /dev/null
+++ b/Utilities/cmcurl/lib/llist.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "llist.h"
+#include "curl_memory.h"
+
+/* this must be the last include file */
+#include "memdebug.h"
+
+/*
+ * @unittest: 1300
+ */
+void
+Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
+{
+ l->size = 0;
+ l->dtor = dtor;
+ l->head = NULL;
+ l->tail = NULL;
+}
+
+/*
+ * Curl_llist_insert_next()
+ *
+ * Inserts a new list element after the given one 'e'. If the given existing
+ * entry is NULL and the list already has elements, the new one will be
+ * inserted first in the list.
+ *
+ * The 'ne' argument should be a pointer into the object to store.
+ *
+ * @unittest: 1300
+ */
+void
+Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
+ const void *p,
+ struct curl_llist_element *ne)
+{
+ ne->ptr = (void *) p;
+ if(list->size == 0) {
+ list->head = ne;
+ list->head->prev = NULL;
+ list->head->next = NULL;
+ list->tail = ne;
+ }
+ else {
+ /* if 'e' is NULL here, we insert the new element first in the list */
+ ne->next = e?e->next:list->head;
+ ne->prev = e;
+ if(!e) {
+ list->head->prev = ne;
+ list->head = ne;
+ }
+ else if(e->next) {
+ e->next->prev = ne;
+ }
+ else {
+ list->tail = ne;
+ }
+ if(e)
+ e->next = ne;
+ }
+
+ ++list->size;
+}
+
+/*
+ * @unittest: 1300
+ */
+void
+Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
+ void *user)
+{
+ void *ptr;
+ if(e == NULL || list->size == 0)
+ return;
+
+ if(e == list->head) {
+ list->head = e->next;
+
+ if(list->head == NULL)
+ list->tail = NULL;
+ else
+ e->next->prev = NULL;
+ }
+ else {
+ e->prev->next = e->next;
+ if(!e->next)
+ list->tail = e->prev;
+ else
+ e->next->prev = e->prev;
+ }
+
+ ptr = e->ptr;
+
+ e->ptr = NULL;
+ e->prev = NULL;
+ e->next = NULL;
+
+ --list->size;
+
+ /* call the dtor() last for when it actually frees the 'e' memory itself */
+ if(list->dtor)
+ list->dtor(user, ptr);
+}
+
+void
+Curl_llist_destroy(struct curl_llist *list, void *user)
+{
+ if(list) {
+ while(list->size > 0)
+ Curl_llist_remove(list, list->tail, user);
+ }
+}
+
+size_t
+Curl_llist_count(struct curl_llist *list)
+{
+ return list->size;
+}
+
+/*
+ * @unittest: 1300
+ */
+void Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e,
+ struct curl_llist *to_list,
+ struct curl_llist_element *to_e)
+{
+ /* Remove element from list */
+ if(e == NULL || list->size == 0)
+ return;
+
+ if(e == list->head) {
+ list->head = e->next;
+
+ if(list->head == NULL)
+ list->tail = NULL;
+ else
+ e->next->prev = NULL;
+ }
+ else {
+ e->prev->next = e->next;
+ if(!e->next)
+ list->tail = e->prev;
+ else
+ e->next->prev = e->prev;
+ }
+
+ --list->size;
+
+ /* Add element to to_list after to_e */
+ if(to_list->size == 0) {
+ to_list->head = e;
+ to_list->head->prev = NULL;
+ to_list->head->next = NULL;
+ to_list->tail = e;
+ }
+ else {
+ e->next = to_e->next;
+ e->prev = to_e;
+ if(to_e->next) {
+ to_e->next->prev = e;
+ }
+ else {
+ to_list->tail = e;
+ }
+ to_e->next = e;
+ }
+
+ ++to_list->size;
+}
diff --git a/Utilities/cmcurl/lib/llist.h b/Utilities/cmcurl/lib/llist.h
new file mode 100644
index 000000000..6b644b99c
--- /dev/null
+++ b/Utilities/cmcurl/lib/llist.h
@@ -0,0 +1,54 @@
+#ifndef HEADER_CURL_LLIST_H
+#define HEADER_CURL_LLIST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <stddef.h>
+
+typedef void (*curl_llist_dtor)(void *, void *);
+
+struct curl_llist_element {
+ void *ptr;
+ struct curl_llist_element *prev;
+ struct curl_llist_element *next;
+};
+
+struct curl_llist {
+ struct curl_llist_element *head;
+ struct curl_llist_element *tail;
+ curl_llist_dtor dtor;
+ size_t size;
+};
+
+void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
+void Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
+ const void *, struct curl_llist_element *node);
+void Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
+ void *);
+size_t Curl_llist_count(struct curl_llist *);
+void Curl_llist_destroy(struct curl_llist *, void *);
+void Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
+ struct curl_llist *, struct curl_llist_element *);
+
+#endif /* HEADER_CURL_LLIST_H */
+
diff --git a/Utilities/cmcurl/lib/md4.c b/Utilities/cmcurl/lib/md4.c
new file mode 100644
index 000000000..2bb7dcc25
--- /dev/null
+++ b/Utilities/cmcurl/lib/md4.c
@@ -0,0 +1,307 @@
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD4 Message-Digest Algorithm (RFC 1320).
+ *
+ * Homepage:
+ http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain. In case
+ * this attempt to disclaim copyright and place the software in the public
+ * domain is deemed null and void, then the software is Copyright (c) 2001
+ * Alexander Peslyak and it is hereby released to the general public under the
+ * following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include "curl_setup.h"
+
+/* The NSS, OS/400 and sometimes mbed TLS crypto libraries do not provide the
+ * MD4 hash algorithm, so we have a local implementation of it */
+#if defined(USE_NSS) || defined(USE_OS400CRYPTO) || \
+ (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C))
+
+#include "curl_md4.h"
+#include "warnless.h"
+
+#ifndef HAVE_OPENSSL
+
+#include <string.h>
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD4_u32plus;
+
+typedef struct {
+ MD4_u32plus lo, hi;
+ MD4_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ MD4_u32plus block[16];
+} MD4_CTX;
+
+static void MD4_Init(MD4_CTX *ctx);
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
+
+/*
+ * The basic MD4 functions.
+ *
+ * F and G are optimized compared to their RFC 1320 definitions, with the
+ * optimization for F borrowed from Colin Plumb's MD5 implementation.
+ */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/*
+ * The MD4 transformation for all three rounds.
+ */
+#define STEP(f, a, b, c, d, x, s) \
+ (a) += f((b), (c), (d)) + (x); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s))));
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization. Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+ (*(MD4_u32plus *)(void *)&ptr[(n) * 4])
+#define GET(n) \
+ SET(n)
+#else
+#define SET(n) \
+ (ctx->block[(n)] = \
+ (MD4_u32plus)ptr[(n) * 4] | \
+ ((MD4_u32plus)ptr[(n) * 4 + 1] << 8) | \
+ ((MD4_u32plus)ptr[(n) * 4 + 2] << 16) | \
+ ((MD4_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+ (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters. There are no alignment requirements.
+ */
+static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+ const unsigned char *ptr;
+ MD4_u32plus a, b, c, d;
+ MD4_u32plus saved_a, saved_b, saved_c, saved_d;
+
+ ptr = (const unsigned char *)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+/* Round 1 */
+ STEP(F, a, b, c, d, SET(0), 3)
+ STEP(F, d, a, b, c, SET(1), 7)
+ STEP(F, c, d, a, b, SET(2), 11)
+ STEP(F, b, c, d, a, SET(3), 19)
+ STEP(F, a, b, c, d, SET(4), 3)
+ STEP(F, d, a, b, c, SET(5), 7)
+ STEP(F, c, d, a, b, SET(6), 11)
+ STEP(F, b, c, d, a, SET(7), 19)
+ STEP(F, a, b, c, d, SET(8), 3)
+ STEP(F, d, a, b, c, SET(9), 7)
+ STEP(F, c, d, a, b, SET(10), 11)
+ STEP(F, b, c, d, a, SET(11), 19)
+ STEP(F, a, b, c, d, SET(12), 3)
+ STEP(F, d, a, b, c, SET(13), 7)
+ STEP(F, c, d, a, b, SET(14), 11)
+ STEP(F, b, c, d, a, SET(15), 19)
+
+/* Round 2 */
+ STEP(G, a, b, c, d, GET(0) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(4) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(8) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(12) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(1) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(5) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(9) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(13) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(2) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(6) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(10) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(14) + 0x5a827999, 13)
+ STEP(G, a, b, c, d, GET(3) + 0x5a827999, 3)
+ STEP(G, d, a, b, c, GET(7) + 0x5a827999, 5)
+ STEP(G, c, d, a, b, GET(11) + 0x5a827999, 9)
+ STEP(G, b, c, d, a, GET(15) + 0x5a827999, 13)
+
+/* Round 3 */
+ STEP(H, a, b, c, d, GET(0) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(8) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(4) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(12) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(2) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(10) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(6) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(14) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(1) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(9) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(5) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(13) + 0x6ed9eba1, 15)
+ STEP(H, a, b, c, d, GET(3) + 0x6ed9eba1, 3)
+ STEP(H, d, a, b, c, GET(11) + 0x6ed9eba1, 9)
+ STEP(H, c, d, a, b, GET(7) + 0x6ed9eba1, 11)
+ STEP(H, b, c, d, a, GET(15) + 0x6ed9eba1, 15)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while(size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
+}
+
+static void MD4_Init(MD4_CTX *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
+}
+
+static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
+{
+ MD4_u32plus saved_lo;
+ unsigned long used, available;
+
+ saved_lo = ctx->lo;
+ ctx->lo = (saved_lo + size) & 0x1fffffff;
+ if(ctx->lo < saved_lo)
+ ctx->hi++;
+ ctx->hi += (MD4_u32plus)size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if(used) {
+ available = 64 - used;
+
+ if(size < available) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, available);
+ data = (const unsigned char *)data + available;
+ size -= available;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if(size >= 64) {
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
+{
+ unsigned long used, available;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ available = 64 - used;
+
+ if(available < 8) {
+ memset(&ctx->buffer[used], 0, available);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ available = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, available - 8);
+
+ ctx->lo <<= 3;
+ ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
+ ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
+ ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
+ ctx->buffer[59] = curlx_ultouc((ctx->lo >> 24)&0xff);
+ ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
+ ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
+ ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
+ ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
+
+ body(ctx, ctx->buffer, 64);
+
+ result[0] = curlx_ultouc((ctx->a)&0xff);
+ result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
+ result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
+ result[3] = curlx_ultouc(ctx->a >> 24);
+ result[4] = curlx_ultouc((ctx->b)&0xff);
+ result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
+ result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
+ result[7] = curlx_ultouc(ctx->b >> 24);
+ result[8] = curlx_ultouc((ctx->c)&0xff);
+ result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
+ result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
+ result[11] = curlx_ultouc(ctx->c >> 24);
+ result[12] = curlx_ultouc((ctx->d)&0xff);
+ result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
+ result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
+ result[15] = curlx_ultouc(ctx->d >> 24);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif
+
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len)
+{
+ MD4_CTX ctx;
+ MD4_Init(&ctx);
+ MD4_Update(&ctx, input, curlx_uztoui(len));
+ MD4_Final(output, &ctx);
+}
+#endif /* defined(USE_NSS) || defined(USE_OS400CRYPTO) ||
+ (defined(USE_MBEDTLS) && !defined(MBEDTLS_MD4_C)) */
diff --git a/Utilities/cmcurl/lib/md5.c b/Utilities/cmcurl/lib/md5.c
new file mode 100644
index 000000000..80301a141
--- /dev/null
+++ b/Utilities/cmcurl/lib/md5.c
@@ -0,0 +1,563 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include <curl/curl.h>
+
+#include "curl_md5.h"
+#include "curl_hmac.h"
+#include "warnless.h"
+
+#if defined(USE_GNUTLS_NETTLE)
+
+#include <nettle/md5.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef struct md5_ctx MD5_CTX;
+
+static void MD5_Init(MD5_CTX * ctx)
+{
+ md5_init(ctx);
+}
+
+static void MD5_Update(MD5_CTX * ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ md5_update(ctx, inputLen, input);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+{
+ md5_digest(ctx, 16, digest);
+}
+
+#elif defined(USE_GNUTLS)
+
+#include <gcrypt.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef gcry_md_hd_t MD5_CTX;
+
+static void MD5_Init(MD5_CTX * ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_MD5, 0);
+}
+
+static void MD5_Update(MD5_CTX * ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ gcry_md_write(*ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, 0), 16);
+ gcry_md_close(*ctx);
+}
+
+#elif defined(USE_OPENSSL)
+/* When OpenSSL is available we use the MD5-function from OpenSSL */
+#include <openssl/md5.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+
+/* For Apple operating systems: CommonCrypto has the functions we need.
+ These functions are available on Tiger and later, as well as iOS 2.0
+ and later. If you're building for an older cat, well, sorry.
+
+ Declaring the functions as static like this seems to be a bit more
+ reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
+# include <CommonCrypto/CommonDigest.h>
+# define MD5_CTX CC_MD5_CTX
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void MD5_Init(MD5_CTX *ctx)
+{
+ CC_MD5_Init(ctx);
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CC_MD5_Update(ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ CC_MD5_Final(digest, ctx);
+}
+
+#elif defined(_WIN32) && !defined(CURL_WINDOWS_APP)
+
+#include <wincrypt.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef struct {
+ HCRYPTPROV hCryptProv;
+ HCRYPTHASH hHash;
+} MD5_CTX;
+
+static void MD5_Init(MD5_CTX *ctx)
+{
+ if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
+ }
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ unsigned long length = 0;
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+ if(length == 16)
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
+ if(ctx->hHash)
+ CryptDestroyHash(ctx->hHash);
+ if(ctx->hCryptProv)
+ CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+#elif defined(USE_AXTLS)
+#include <axTLS/config.h>
+#include <axTLS/os_int.h>
+#include <axTLS/crypto.h>
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+#else
+/* When no other crypto library is available we use this code segment */
+/*
+ * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
+ * MD5 Message-Digest Algorithm (RFC 1321).
+ *
+ * Homepage:
+ http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
+ *
+ * Author:
+ * Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
+ *
+ * This software was written by Alexander Peslyak in 2001. No copyright is
+ * claimed, and the software is hereby placed in the public domain.
+ * In case this attempt to disclaim copyright and place the software in the
+ * public domain is deemed null and void, then the software is
+ * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
+ * general public under the following terms:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted.
+ *
+ * There's ABSOLUTELY NO WARRANTY, express or implied.
+ *
+ * (This is a heavily cut-down "BSD license".)
+ *
+ * This differs from Colin Plumb's older public domain implementation in that
+ * no exactly 32-bit integer data type is required (any 32-bit or wider
+ * unsigned integer data type will do), there's no compile-time endianness
+ * configuration, and the function prototypes match OpenSSL's. No code from
+ * Colin Plumb's implementation has been reused; this comment merely compares
+ * the properties of the two independent implementations.
+ *
+ * The primary goals of this implementation are portability and ease of use.
+ * It is meant to be fast, but not as fast as possible. Some known
+ * optimizations are not included to reduce source code size and avoid
+ * compile-time configuration.
+ */
+
+#include <string.h>
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Any 32-bit or wider unsigned integer data type will do */
+typedef unsigned int MD5_u32plus;
+
+typedef struct {
+ MD5_u32plus lo, hi;
+ MD5_u32plus a, b, c, d;
+ unsigned char buffer[64];
+ MD5_u32plus block[16];
+} MD5_CTX;
+
+static void MD5_Init(MD5_CTX *ctx);
+static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
+static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+
+/*
+ * The basic MD5 functions.
+ *
+ * F and G are optimized compared to their RFC 1321 definitions for
+ * architectures that lack an AND-NOT instruction, just like in Colin Plumb's
+ * implementation.
+ */
+#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
+#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
+#define H(x, y, z) (((x) ^ (y)) ^ (z))
+#define H2(x, y, z) ((x) ^ ((y) ^ (z)))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+/*
+ * The MD5 transformation for all four rounds.
+ */
+#define STEP(f, a, b, c, d, x, t, s) \
+ (a) += f((b), (c), (d)) + (x) + (t); \
+ (a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
+ (a) += (b);
+
+/*
+ * SET reads 4 input bytes in little-endian byte order and stores them
+ * in a properly aligned word in host byte order.
+ *
+ * The check for little-endian architectures that tolerate unaligned
+ * memory accesses is just an optimization. Nothing will break if it
+ * doesn't work.
+ */
+#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
+#define SET(n) \
+ (*(MD5_u32plus *)(void *)&ptr[(n) * 4])
+#define GET(n) \
+ SET(n)
+#else
+#define SET(n) \
+ (ctx->block[(n)] = \
+ (MD5_u32plus)ptr[(n) * 4] | \
+ ((MD5_u32plus)ptr[(n) * 4 + 1] << 8) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 2] << 16) | \
+ ((MD5_u32plus)ptr[(n) * 4 + 3] << 24))
+#define GET(n) \
+ (ctx->block[(n)])
+#endif
+
+/*
+ * This processes one or more 64-byte data blocks, but does NOT update
+ * the bit counters. There are no alignment requirements.
+ */
+static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+ const unsigned char *ptr;
+ MD5_u32plus a, b, c, d;
+ MD5_u32plus saved_a, saved_b, saved_c, saved_d;
+
+ ptr = (const unsigned char *)data;
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ do {
+ saved_a = a;
+ saved_b = b;
+ saved_c = c;
+ saved_d = d;
+
+/* Round 1 */
+ STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
+ STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
+ STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
+ STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
+ STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
+ STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
+ STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
+ STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
+ STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
+ STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
+ STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
+ STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
+ STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
+ STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
+ STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
+ STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
+
+/* Round 2 */
+ STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
+ STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
+ STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
+ STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
+ STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
+ STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
+ STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
+ STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
+ STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
+ STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
+ STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
+ STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
+ STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
+ STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
+ STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
+ STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
+
+/* Round 3 */
+ STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
+ STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11)
+ STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
+ STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23)
+ STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
+ STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11)
+ STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
+ STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23)
+ STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
+ STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11)
+ STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
+ STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23)
+ STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
+ STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11)
+ STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
+ STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23)
+
+/* Round 4 */
+ STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
+ STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
+ STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
+ STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
+ STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
+ STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
+ STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
+ STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
+ STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
+ STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
+ STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
+ STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
+ STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
+ STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
+ STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
+ STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
+
+ a += saved_a;
+ b += saved_b;
+ c += saved_c;
+ d += saved_d;
+
+ ptr += 64;
+ } while(size -= 64);
+
+ ctx->a = a;
+ ctx->b = b;
+ ctx->c = c;
+ ctx->d = d;
+
+ return ptr;
+}
+
+static void MD5_Init(MD5_CTX *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+
+ ctx->lo = 0;
+ ctx->hi = 0;
+}
+
+static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
+{
+ MD5_u32plus saved_lo;
+ unsigned long used, available;
+
+ saved_lo = ctx->lo;
+ ctx->lo = (saved_lo + size) & 0x1fffffff;
+ if(ctx->lo < saved_lo)
+ ctx->hi++;
+ ctx->hi += (MD5_u32plus)size >> 29;
+
+ used = saved_lo & 0x3f;
+
+ if(used) {
+ available = 64 - used;
+
+ if(size < available) {
+ memcpy(&ctx->buffer[used], data, size);
+ return;
+ }
+
+ memcpy(&ctx->buffer[used], data, available);
+ data = (const unsigned char *)data + available;
+ size -= available;
+ body(ctx, ctx->buffer, 64);
+ }
+
+ if(size >= 64) {
+ data = body(ctx, data, size & ~(unsigned long)0x3f);
+ size &= 0x3f;
+ }
+
+ memcpy(ctx->buffer, data, size);
+}
+
+static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
+{
+ unsigned long used, available;
+
+ used = ctx->lo & 0x3f;
+
+ ctx->buffer[used++] = 0x80;
+
+ available = 64 - used;
+
+ if(available < 8) {
+ memset(&ctx->buffer[used], 0, available);
+ body(ctx, ctx->buffer, 64);
+ used = 0;
+ available = 64;
+ }
+
+ memset(&ctx->buffer[used], 0, available - 8);
+
+ ctx->lo <<= 3;
+ ctx->buffer[56] = curlx_ultouc((ctx->lo)&0xff);
+ ctx->buffer[57] = curlx_ultouc((ctx->lo >> 8)&0xff);
+ ctx->buffer[58] = curlx_ultouc((ctx->lo >> 16)&0xff);
+ ctx->buffer[59] = curlx_ultouc(ctx->lo >> 24);
+ ctx->buffer[60] = curlx_ultouc((ctx->hi)&0xff);
+ ctx->buffer[61] = curlx_ultouc((ctx->hi >> 8)&0xff);
+ ctx->buffer[62] = curlx_ultouc((ctx->hi >> 16)&0xff);
+ ctx->buffer[63] = curlx_ultouc(ctx->hi >> 24);
+
+ body(ctx, ctx->buffer, 64);
+
+ result[0] = curlx_ultouc((ctx->a)&0xff);
+ result[1] = curlx_ultouc((ctx->a >> 8)&0xff);
+ result[2] = curlx_ultouc((ctx->a >> 16)&0xff);
+ result[3] = curlx_ultouc(ctx->a >> 24);
+ result[4] = curlx_ultouc((ctx->b)&0xff);
+ result[5] = curlx_ultouc((ctx->b >> 8)&0xff);
+ result[6] = curlx_ultouc((ctx->b >> 16)&0xff);
+ result[7] = curlx_ultouc(ctx->b >> 24);
+ result[8] = curlx_ultouc((ctx->c)&0xff);
+ result[9] = curlx_ultouc((ctx->c >> 8)&0xff);
+ result[10] = curlx_ultouc((ctx->c >> 16)&0xff);
+ result[11] = curlx_ultouc(ctx->c >> 24);
+ result[12] = curlx_ultouc((ctx->d)&0xff);
+ result[13] = curlx_ultouc((ctx->d >> 8)&0xff);
+ result[14] = curlx_ultouc((ctx->d >> 16)&0xff);
+ result[15] = curlx_ultouc(ctx->d >> 24);
+
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+#endif /* CRYPTO LIBS */
+
+const HMAC_params Curl_HMAC_MD5[] = {
+ {
+ (HMAC_hinit_func) MD5_Init, /* Hash initialization function. */
+ (HMAC_hupdate_func) MD5_Update, /* Hash update function. */
+ (HMAC_hfinal_func) MD5_Final, /* Hash computation end function. */
+ sizeof(MD5_CTX), /* Size of hash context structure. */
+ 64, /* Maximum key length. */
+ 16 /* Result size. */
+ }
+};
+
+const MD5_params Curl_DIGEST_MD5[] = {
+ {
+ (Curl_MD5_init_func) MD5_Init, /* Digest initialization function */
+ (Curl_MD5_update_func) MD5_Update, /* Digest update function */
+ (Curl_MD5_final_func) MD5_Final, /* Digest computation end function */
+ sizeof(MD5_CTX), /* Size of digest context struct */
+ 16 /* Result size */
+ }
+};
+
+/*
+ * @unittest: 1601
+ */
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+ const unsigned char *input)
+{
+ MD5_CTX ctx;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
+ MD5_Final(outbuffer, &ctx);
+}
+
+MD5_context *Curl_MD5_init(const MD5_params *md5params)
+{
+ MD5_context *ctxt;
+
+ /* Create MD5 context */
+ ctxt = malloc(sizeof *ctxt);
+
+ if(!ctxt)
+ return ctxt;
+
+ ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
+
+ if(!ctxt->md5_hashctx) {
+ free(ctxt);
+ return NULL;
+ }
+
+ ctxt->md5_hash = md5params;
+
+ (*md5params->md5_init_func)(ctxt->md5_hashctx);
+
+ return ctxt;
+}
+
+int Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len)
+{
+ (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
+
+ return 0;
+}
+
+int Curl_MD5_final(MD5_context *context, unsigned char *result)
+{
+ (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
+
+ free(context->md5_hashctx);
+ free(context);
+
+ return 0;
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/memdebug.c b/Utilities/cmcurl/lib/memdebug.c
new file mode 100644
index 000000000..2b8808ab0
--- /dev/null
+++ b/Utilities/cmcurl/lib/memdebug.c
@@ -0,0 +1,484 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURLDEBUG
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Until 2011-08-17 libcurl's Memory Tracking feature also performed
+ * automatic malloc and free filling operations using 0xA5 and 0x13
+ * values. Our own preinitialization of dynamically allocated memory
+ * might be useful when not using third party memory debuggers, but
+ * on the other hand this would fool memory debuggers into thinking
+ * that all dynamically allocated memory is properly initialized.
+ *
+ * As a default setting, libcurl's Memory Tracking feature no longer
+ * performs preinitialization of dynamically allocated memory on its
+ * own. If you know what you are doing, and really want to retain old
+ * behavior, you can achieve this compiling with preprocessor symbols
+ * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate
+ * values.
+ */
+
+#ifdef CURL_MT_MALLOC_FILL
+# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff)
+# error "invalid CURL_MT_MALLOC_FILL or out of range"
+# endif
+#endif
+
+#ifdef CURL_MT_FREE_FILL
+# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff)
+# error "invalid CURL_MT_FREE_FILL or out of range"
+# endif
+#endif
+
+#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL)
+# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL)
+# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL"
+# endif
+#endif
+
+#ifdef CURL_MT_MALLOC_FILL
+# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len))
+#else
+# define mt_malloc_fill(buf,len) Curl_nop_stmt
+#endif
+
+#ifdef CURL_MT_FREE_FILL
+# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len))
+#else
+# define mt_free_fill(buf,len) Curl_nop_stmt
+#endif
+
+struct memdebug {
+ size_t size;
+ union {
+ curl_off_t o;
+ double d;
+ void *p;
+ } mem[1];
+ /* I'm hoping this is the thing with the strictest alignment
+ * requirements. That also means we waste some space :-( */
+};
+
+/*
+ * Note that these debug functions are very simple and they are meant to
+ * remain so. For advanced analysis, record a log file and write perl scripts
+ * to analyze them!
+ *
+ * Don't use these with multithreaded test programs!
+ */
+
+#define logfile curl_debuglogfile
+FILE *curl_debuglogfile = NULL;
+static bool memlimit = FALSE; /* enable memory limit */
+static long memsize = 0; /* set number of mallocs allowed */
+
+/* this sets the log file name */
+void curl_memdebug(const char *logname)
+{
+ if(!logfile) {
+ if(logname && *logname)
+ logfile = fopen(logname, FOPEN_WRITETEXT);
+ else
+ logfile = stderr;
+#ifdef MEMDEBUG_LOG_SYNC
+ /* Flush the log file after every line so the log isn't lost in a crash */
+ setbuf(logfile, (char *)NULL);
+#endif
+ }
+}
+
+/* This function sets the number of malloc() calls that should return
+ successfully! */
+void curl_memlimit(long limit)
+{
+ if(!memlimit) {
+ memlimit = TRUE;
+ memsize = limit;
+ }
+}
+
+/* returns TRUE if this isn't allowed! */
+static bool countcheck(const char *func, int line, const char *source)
+{
+ /* if source is NULL, then the call is made internally and this check
+ should not be made */
+ if(memlimit && source) {
+ if(!memsize) {
+ if(source) {
+ /* log to file */
+ curl_memlog("LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ /* log to stderr also */
+ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ fflush(logfile); /* because it might crash now */
+ }
+ SET_ERRNO(ENOMEM);
+ return TRUE; /* RETURN ERROR! */
+ }
+ else
+ memsize--; /* countdown */
+
+
+ }
+
+ return FALSE; /* allow this */
+}
+
+void *curl_domalloc(size_t wantedsize, int line, const char *source)
+{
+ struct memdebug *mem;
+ size_t size;
+
+ DEBUGASSERT(wantedsize != 0);
+
+ if(countcheck("malloc", line, source))
+ return NULL;
+
+ /* alloc at least 64 bytes */
+ size = sizeof(struct memdebug)+wantedsize;
+
+ mem = (Curl_cmalloc)(size);
+ if(mem) {
+ /* fill memory with junk */
+ mt_malloc_fill(mem->mem, wantedsize);
+ mem->size = wantedsize;
+ }
+
+ if(source)
+ curl_memlog("MEM %s:%d malloc(%zu) = %p\n",
+ source, line, wantedsize,
+ mem ? (void *)mem->mem : (void *)0);
+
+ return (mem ? mem->mem : NULL);
+}
+
+void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
+ int line, const char *source)
+{
+ struct memdebug *mem;
+ size_t size, user_size;
+
+ DEBUGASSERT(wanted_elements != 0);
+ DEBUGASSERT(wanted_size != 0);
+
+ if(countcheck("calloc", line, source))
+ return NULL;
+
+ /* alloc at least 64 bytes */
+ user_size = wanted_size * wanted_elements;
+ size = sizeof(struct memdebug) + user_size;
+
+ mem = (Curl_ccalloc)(1, size);
+ if(mem)
+ mem->size = user_size;
+
+ if(source)
+ curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
+ source, line, wanted_elements, wanted_size,
+ mem ? (void *)mem->mem : (void *)0);
+
+ return (mem ? mem->mem : NULL);
+}
+
+char *curl_dostrdup(const char *str, int line, const char *source)
+{
+ char *mem;
+ size_t len;
+
+ DEBUGASSERT(str != NULL);
+
+ if(countcheck("strdup", line, source))
+ return NULL;
+
+ len=strlen(str)+1;
+
+ mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+ if(mem)
+ memcpy(mem, str, len);
+
+ if(source)
+ curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
+ source, line, (const void *)str, len, (const void *)mem);
+
+ return mem;
+}
+
+#if defined(WIN32) && defined(UNICODE)
+wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
+{
+ wchar_t *mem;
+ size_t wsiz, bsiz;
+
+ DEBUGASSERT(str != NULL);
+
+ if(countcheck("wcsdup", line, source))
+ return NULL;
+
+ wsiz = wcslen(str) + 1;
+ bsiz = wsiz * sizeof(wchar_t);
+
+ mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
+ if(mem)
+ memcpy(mem, str, bsiz);
+
+ if(source)
+ curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
+ source, line, (void *)str, bsiz, (void *)mem);
+
+ return mem;
+}
+#endif
+
+/* We provide a realloc() that accepts a NULL as pointer, which then
+ performs a malloc(). In order to work with ares. */
+void *curl_dorealloc(void *ptr, size_t wantedsize,
+ int line, const char *source)
+{
+ struct memdebug *mem=NULL;
+
+ size_t size = sizeof(struct memdebug)+wantedsize;
+
+ DEBUGASSERT(wantedsize != 0);
+
+ if(countcheck("realloc", line, source))
+ return NULL;
+
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:1684)
+ /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+ if(ptr)
+ mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+
+ mem = (Curl_crealloc)(mem, size);
+ if(source)
+ curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
+ source, line, (void *)ptr, wantedsize,
+ mem ? (void *)mem->mem : (void *)0);
+
+ if(mem) {
+ mem->size = wantedsize;
+ return mem->mem;
+ }
+
+ return NULL;
+}
+
+void curl_dofree(void *ptr, int line, const char *source)
+{
+ struct memdebug *mem;
+
+ if(ptr) {
+
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:1684)
+ /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+ mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+
+ /* destroy */
+ mt_free_fill(mem->mem, mem->size);
+
+ /* free for real */
+ (Curl_cfree)(mem);
+ }
+
+ if(source)
+ curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
+}
+
+curl_socket_t curl_socket(int domain, int type, int protocol,
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socket() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socket() = %ld\n" :
+ "FD %s:%d socket() = %zd\n";
+
+ curl_socket_t sockfd = socket(domain, type, protocol);
+
+ if(source && (sockfd != CURL_SOCKET_BAD))
+ curl_memlog(fmt, source, line, sockfd);
+
+ return sockfd;
+}
+
+#ifdef HAVE_SOCKETPAIR
+int curl_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socketpair() = %d %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socketpair() = %ld %ld\n" :
+ "FD %s:%d socketpair() = %zd %zd\n";
+
+ int res = socketpair(domain, type, protocol, socket_vector);
+
+ if(source && (0 == res))
+ curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
+
+ return res;
+}
+#endif
+
+curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d accept() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d accept() = %ld\n" :
+ "FD %s:%d accept() = %zd\n";
+
+ struct sockaddr *addr = (struct sockaddr *)saddr;
+ curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
+
+ curl_socket_t sockfd = accept(s, addr, addrlen);
+
+ if(source && (sockfd != CURL_SOCKET_BAD))
+ curl_memlog(fmt, source, line, sockfd);
+
+ return sockfd;
+}
+
+/* separate function to allow libcurl to mark a "faked" close */
+void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d sclose(%d)\n":
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d sclose(%ld)\n":
+ "FD %s:%d sclose(%zd)\n";
+
+ if(source)
+ curl_memlog(fmt, source, line, sockfd);
+}
+
+/* this is our own defined way to close sockets on *ALL* platforms */
+int curl_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+ int res=sclose(sockfd);
+ curl_mark_sclose(sockfd, line, source);
+ return res;
+}
+
+FILE *curl_fopen(const char *file, const char *mode,
+ int line, const char *source)
+{
+ FILE *res=fopen(file, mode);
+
+ if(source)
+ curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+ source, line, file, mode, (void *)res);
+
+ return res;
+}
+
+#ifdef HAVE_FDOPEN
+FILE *curl_fdopen(int filedes, const char *mode,
+ int line, const char *source)
+{
+ FILE *res=fdopen(filedes, mode);
+
+ if(source)
+ curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
+ source, line, filedes, mode, (void *)res);
+
+ return res;
+}
+#endif
+
+int curl_fclose(FILE *file, int line, const char *source)
+{
+ int res;
+
+ DEBUGASSERT(file != NULL);
+
+ res=fclose(file);
+
+ if(source)
+ curl_memlog("FILE %s:%d fclose(%p)\n",
+ source, line, (void *)file);
+
+ return res;
+}
+
+#define LOGLINE_BUFSIZE 1024
+
+/* this does the writing to the memory tracking log file */
+void curl_memlog(const char *format, ...)
+{
+ char *buf;
+ int nchars;
+ va_list ap;
+
+ if(!logfile)
+ return;
+
+ buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
+ if(!buf)
+ return;
+
+ va_start(ap, format);
+ nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+ va_end(ap);
+
+ if(nchars > LOGLINE_BUFSIZE - 1)
+ nchars = LOGLINE_BUFSIZE - 1;
+
+ if(nchars > 0)
+ fwrite(buf, 1, (size_t)nchars, logfile);
+
+ (Curl_cfree)(buf);
+}
+
+#endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/lib/memdebug.h b/Utilities/cmcurl/lib/memdebug.h
new file mode 100644
index 000000000..835dab38c
--- /dev/null
+++ b/Utilities/cmcurl/lib/memdebug.h
@@ -0,0 +1,173 @@
+#ifndef HEADER_CURL_MEMDEBUG_H
+#define HEADER_CURL_MEMDEBUG_H
+#ifdef CURLDEBUG
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#define CURL_MT_LOGFNAME_BUFSIZE 512
+
+#define logfile curl_debuglogfile
+
+extern FILE *logfile;
+
+/* memory functions */
+CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
+CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line,
+ const char *source);
+CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line,
+ const char *source);
+CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
+CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
+#if defined(WIN32) && defined(UNICODE)
+CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line,
+ const char *source);
+#endif
+
+CURL_EXTERN void curl_memdebug(const char *logname);
+CURL_EXTERN void curl_memlimit(long limit);
+CURL_EXTERN void curl_memlog(const char *format, ...);
+
+/* file descriptor manipulators */
+CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol,
+ int line, const char *source);
+CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd,
+ int line, const char *source);
+CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
+ int line, const char *source);
+CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
+ int line, const char *source);
+#ifdef HAVE_SOCKETPAIR
+CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line, const char *source);
+#endif
+
+/* FILE functions */
+CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
+ const char *source);
+#ifdef HAVE_FDOPEN
+CURL_EXTERN FILE *curl_fdopen(int filedes, const char *mode, int line,
+ const char *source);
+#endif
+CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
+
+#ifndef MEMDEBUG_NODEFINES
+
+/* Set this symbol on the command-line, recompile all lib-sources */
+#undef strdup
+#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
+#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
+#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
+
+#ifdef WIN32
+# ifdef UNICODE
+# undef wcsdup
+# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# undef _wcsdup
+# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# undef _tcsdup
+# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# else
+# undef _tcsdup
+# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+# endif
+#endif
+
+#undef socket
+#define socket(domain,type,protocol)\
+ curl_socket(domain, type, protocol, __LINE__, __FILE__)
+#undef accept /* for those with accept as a macro */
+#define accept(sock,addr,len)\
+ curl_accept(sock, addr, len, __LINE__, __FILE__)
+#ifdef HAVE_SOCKETPAIR
+#define socketpair(domain,type,protocol,socket_vector)\
+ curl_socketpair(domain, type, protocol, socket_vector, __LINE__, __FILE__)
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#if defined(getaddrinfo) && defined(__osf__)
+/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
+ our macro as for other platforms. Instead, we redefine the new name they
+ define getaddrinfo to become! */
+#define ogetaddrinfo(host,serv,hint,res) \
+ curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#else
+#undef getaddrinfo
+#define getaddrinfo(host,serv,hint,res) \
+ curl_dogetaddrinfo(host, serv, hint, res, __LINE__, __FILE__)
+#endif
+#endif /* HAVE_GETADDRINFO */
+
+#ifdef HAVE_GETNAMEINFO
+#undef getnameinfo
+#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
+ curl_dogetnameinfo(sa, salen, host, hostlen, serv, servlen, flags, \
+ __LINE__, __FILE__)
+#endif /* HAVE_GETNAMEINFO */
+
+#ifdef HAVE_FREEADDRINFO
+#undef freeaddrinfo
+#define freeaddrinfo(data) \
+ curl_dofreeaddrinfo(data, __LINE__, __FILE__)
+#endif /* HAVE_FREEADDRINFO */
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+
+#define fake_sclose(sockfd) curl_mark_sclose(sockfd,__LINE__,__FILE__)
+
+#undef fopen
+#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
+#undef fdopen
+#define fdopen(file,mode) curl_fdopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
+
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* CURLDEBUG */
+
+/*
+** Following section applies even when CURLDEBUG is not defined.
+*/
+
+#ifndef fake_sclose
+#define fake_sclose(x) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_safefree defined as a macro to allow MemoryTracking feature
+ * to log free() calls at same location where Curl_safefree is used.
+ * This macro also assigns NULL to given pointer when free'd.
+ */
+
+#define Curl_safefree(ptr) \
+ do { free((ptr)); (ptr) = NULL;} WHILE_FALSE
+
+#endif /* HEADER_CURL_MEMDEBUG_H */
diff --git a/Utilities/cmcurl/lib/mprintf.c b/Utilities/cmcurl/lib/mprintf.c
new file mode 100644
index 000000000..eb7ee0c6b
--- /dev/null
+++ b/Utilities/cmcurl/lib/mprintf.c
@@ -0,0 +1,1177 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1999 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ *
+ * Purpose:
+ * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
+ * 1.0. A full blooded printf() clone with full support for <num>$
+ * everywhere (parameters, widths and precisions) including variabled
+ * sized parameters (like doubles, long longs, long doubles and even
+ * void * in 64-bit architectures).
+ *
+ * Current restrictions:
+ * - Max 128 parameters
+ * - No 'long double' support.
+ *
+ * If you ever want truly portable and good *printf() clones, the project that
+ * took on from here is named 'Trio' and you find more details on the trio web
+ * page at https://daniel.haxx.se/projects/trio/
+ */
+
+#include "curl_setup.h"
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * If SIZEOF_SIZE_T has not been defined, default to the size of long.
+ */
+
+#ifndef SIZEOF_SIZE_T
+# define SIZEOF_SIZE_T CURL_SIZEOF_LONG
+#endif
+
+#ifdef HAVE_LONGLONG
+# define LONG_LONG_TYPE long long
+# define HAVE_LONG_LONG_TYPE
+#else
+# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define LONG_LONG_TYPE __int64
+# define HAVE_LONG_LONG_TYPE
+# else
+# undef LONG_LONG_TYPE
+# undef HAVE_LONG_LONG_TYPE
+# endif
+#endif
+
+/*
+ * Non-ANSI integer extensions
+ */
+
+#if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
+ (defined(__WATCOMC__) && defined(__386__)) || \
+ (defined(__POCC__) && defined(_MSC_VER)) || \
+ (defined(_WIN32_WCE)) || \
+ (defined(__MINGW32__)) || \
+ (defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64))
+# define MP_HAVE_INT_EXTENSIONS
+#endif
+
+/*
+ * Max integer data types that mprintf.c is capable
+ */
+
+#ifdef HAVE_LONG_LONG_TYPE
+# define mp_intmax_t LONG_LONG_TYPE
+# define mp_uintmax_t unsigned LONG_LONG_TYPE
+#else
+# define mp_intmax_t long
+# define mp_uintmax_t unsigned long
+#endif
+
+#define BUFFSIZE 326 /* buffer for long-to-str and float-to-str calcs, should
+ fit negative DBL_MAX (317 letters) */
+#define MAX_PARAMETERS 128 /* lame static limit */
+
+#ifdef __AMIGA__
+# undef FORMAT_INT
+#endif
+
+/* Lower-case digits. */
+static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+/* Upper-case digits. */
+static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+#define OUTCHAR(x) \
+ do{ \
+ if(stream((unsigned char)(x), (FILE *)data) != -1) \
+ done++; \
+ else \
+ return done; /* return immediately on failure */ \
+ } WHILE_FALSE
+
+/* Data type to read from the arglist */
+typedef enum {
+ FORMAT_UNKNOWN = 0,
+ FORMAT_STRING,
+ FORMAT_PTR,
+ FORMAT_INT,
+ FORMAT_INTPTR,
+ FORMAT_LONG,
+ FORMAT_LONGLONG,
+ FORMAT_DOUBLE,
+ FORMAT_LONGDOUBLE,
+ FORMAT_WIDTH /* For internal use */
+} FormatType;
+
+/* conversion and display flags */
+enum {
+ FLAGS_NEW = 0,
+ FLAGS_SPACE = 1<<0,
+ FLAGS_SHOWSIGN = 1<<1,
+ FLAGS_LEFT = 1<<2,
+ FLAGS_ALT = 1<<3,
+ FLAGS_SHORT = 1<<4,
+ FLAGS_LONG = 1<<5,
+ FLAGS_LONGLONG = 1<<6,
+ FLAGS_LONGDOUBLE = 1<<7,
+ FLAGS_PAD_NIL = 1<<8,
+ FLAGS_UNSIGNED = 1<<9,
+ FLAGS_OCTAL = 1<<10,
+ FLAGS_HEX = 1<<11,
+ FLAGS_UPPER = 1<<12,
+ FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
+ FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
+ FLAGS_PREC = 1<<15, /* precision was specified */
+ FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
+ FLAGS_CHAR = 1<<17, /* %c story */
+ FLAGS_FLOATE = 1<<18, /* %e or %E */
+ FLAGS_FLOATG = 1<<19 /* %g or %G */
+};
+
+typedef struct {
+ FormatType type;
+ int flags;
+ long width; /* width OR width parameter number */
+ long precision; /* precision OR precision parameter number */
+ union {
+ char *str;
+ void *ptr;
+ union {
+ mp_intmax_t as_signed;
+ mp_uintmax_t as_unsigned;
+ } num;
+ double dnum;
+ } data;
+} va_stack_t;
+
+struct nsprintf {
+ char *buffer;
+ size_t length;
+ size_t max;
+};
+
+struct asprintf {
+ char *buffer; /* allocated buffer */
+ size_t len; /* length of string */
+ size_t alloc; /* length of alloc */
+ int fail; /* (!= 0) if an alloc has failed and thus
+ the output is not the complete data */
+};
+
+static long dprintf_DollarString(char *input, char **end)
+{
+ int number=0;
+ while(ISDIGIT(*input)) {
+ number *= 10;
+ number += *input-'0';
+ input++;
+ }
+ if(number && ('$'==*input++)) {
+ *end = input;
+ return number;
+ }
+ return 0;
+}
+
+static bool dprintf_IsQualifierNoDollar(const char *fmt)
+{
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ if(!strncmp(fmt, "I32", 3) || !strncmp(fmt, "I64", 3)) {
+ return TRUE;
+ }
+#endif
+
+ switch(*fmt) {
+ case '-': case '+': case ' ': case '#': case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'h': case 'l': case 'L': case 'z': case 'q':
+ case '*': case 'O':
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ case 'I':
+#endif
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+/******************************************************************
+ *
+ * Pass 1:
+ * Create an index with the type of each parameter entry and its
+ * value (may vary in size)
+ *
+ * Returns zero on success.
+ *
+ ******************************************************************/
+
+static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
+ va_list arglist)
+{
+ char *fmt = (char *)format;
+ int param_num = 0;
+ long this_param;
+ long width;
+ long precision;
+ int flags;
+ long max_param=0;
+ long i;
+
+ while(*fmt) {
+ if(*fmt++ == '%') {
+ if(*fmt == '%') {
+ fmt++;
+ continue; /* while */
+ }
+
+ flags = FLAGS_NEW;
+
+ /* Handle the positional case (N$) */
+
+ param_num++;
+
+ this_param = dprintf_DollarString(fmt, &fmt);
+ if(0 == this_param)
+ /* we got no positional, get the next counter */
+ this_param = param_num;
+
+ if(this_param > max_param)
+ max_param = this_param;
+
+ /*
+ * The parameter with number 'i' should be used. Next, we need
+ * to get SIZE and TYPE of the parameter. Add the information
+ * to our array.
+ */
+
+ width = 0;
+ precision = 0;
+
+ /* Handle the flags */
+
+ while(dprintf_IsQualifierNoDollar(fmt)) {
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ if(!strncmp(fmt, "I32", 3)) {
+ flags |= FLAGS_LONG;
+ fmt += 3;
+ }
+ else if(!strncmp(fmt, "I64", 3)) {
+ flags |= FLAGS_LONGLONG;
+ fmt += 3;
+ }
+ else
+#endif
+
+ switch(*fmt++) {
+ case ' ':
+ flags |= FLAGS_SPACE;
+ break;
+ case '+':
+ flags |= FLAGS_SHOWSIGN;
+ break;
+ case '-':
+ flags |= FLAGS_LEFT;
+ flags &= ~FLAGS_PAD_NIL;
+ break;
+ case '#':
+ flags |= FLAGS_ALT;
+ break;
+ case '.':
+ if('*' == *fmt) {
+ /* The precision is picked from a specified parameter */
+
+ flags |= FLAGS_PRECPARAM;
+ fmt++;
+ param_num++;
+
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ precision = i;
+ else
+ precision = param_num;
+
+ if(precision > max_param)
+ max_param = precision;
+ }
+ else {
+ flags |= FLAGS_PREC;
+ precision = strtol(fmt, &fmt, 10);
+ }
+ break;
+ case 'h':
+ flags |= FLAGS_SHORT;
+ break;
+#if defined(MP_HAVE_INT_EXTENSIONS)
+ case 'I':
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+#endif
+ case 'l':
+ if(flags & FLAGS_LONG)
+ flags |= FLAGS_LONGLONG;
+ else
+ flags |= FLAGS_LONG;
+ break;
+ case 'L':
+ flags |= FLAGS_LONGDOUBLE;
+ break;
+ case 'q':
+ flags |= FLAGS_LONGLONG;
+ break;
+ case 'z':
+ /* the code below generates a warning if -Wunreachable-code is
+ used */
+#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+ case 'O':
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+ case '0':
+ if(!(flags & FLAGS_LEFT))
+ flags |= FLAGS_PAD_NIL;
+ /* FALLTHROUGH */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ flags |= FLAGS_WIDTH;
+ width = strtol(fmt-1, &fmt, 10);
+ break;
+ case '*': /* Special case */
+ flags |= FLAGS_WIDTHPARAM;
+ param_num++;
+
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ width = i;
+ else
+ width = param_num;
+ if(width > max_param)
+ max_param=width;
+ break;
+ default:
+ break;
+ }
+ } /* switch */
+
+ /* Handle the specifier */
+
+ i = this_param - 1;
+
+ if((i < 0) || (i >= MAX_PARAMETERS))
+ /* out of allowed range */
+ return 1;
+
+ switch (*fmt) {
+ case 'S':
+ flags |= FLAGS_ALT;
+ /* FALLTHROUGH */
+ case 's':
+ vto[i].type = FORMAT_STRING;
+ break;
+ case 'n':
+ vto[i].type = FORMAT_INTPTR;
+ break;
+ case 'p':
+ vto[i].type = FORMAT_PTR;
+ break;
+ case 'd': case 'i':
+ vto[i].type = FORMAT_INT;
+ break;
+ case 'u':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_UNSIGNED;
+ break;
+ case 'o':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_OCTAL;
+ break;
+ case 'x':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_HEX|FLAGS_UNSIGNED;
+ break;
+ case 'X':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
+ break;
+ case 'c':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_CHAR;
+ break;
+ case 'f':
+ vto[i].type = FORMAT_DOUBLE;
+ break;
+ case 'e':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATE;
+ break;
+ case 'E':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATE|FLAGS_UPPER;
+ break;
+ case 'g':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATG;
+ break;
+ case 'G':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATG|FLAGS_UPPER;
+ break;
+ default:
+ vto[i].type = FORMAT_UNKNOWN;
+ break;
+ } /* switch */
+
+ vto[i].flags = flags;
+ vto[i].width = width;
+ vto[i].precision = precision;
+
+ if(flags & FLAGS_WIDTHPARAM) {
+ /* we have the width specified from a parameter, so we make that
+ parameter's info setup properly */
+ long k = width - 1;
+ vto[i].width = k;
+ vto[k].type = FORMAT_WIDTH;
+ vto[k].flags = FLAGS_NEW;
+ /* can't use width or precision of width! */
+ vto[k].width = 0;
+ vto[k].precision = 0;
+ }
+ if(flags & FLAGS_PRECPARAM) {
+ /* we have the precision specified from a parameter, so we make that
+ parameter's info setup properly */
+ long k = precision - 1;
+ vto[i].precision = k;
+ vto[k].type = FORMAT_WIDTH;
+ vto[k].flags = FLAGS_NEW;
+ /* can't use width or precision of width! */
+ vto[k].width = 0;
+ vto[k].precision = 0;
+ }
+ *endpos++ = fmt + 1; /* end of this sequence */
+ }
+ }
+
+ /* Read the arg list parameters into our data list */
+ for(i=0; i<max_param; i++) {
+ /* Width/precision arguments must be read before the main argument
+ they are attached to */
+ if(vto[i].flags & FLAGS_WIDTHPARAM) {
+ vto[vto[i].width].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+ if(vto[i].flags & FLAGS_PRECPARAM) {
+ vto[vto[i].precision].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+
+ switch(vto[i].type) {
+ case FORMAT_STRING:
+ vto[i].data.str = va_arg(arglist, char *);
+ break;
+
+ case FORMAT_INTPTR:
+ case FORMAT_UNKNOWN:
+ case FORMAT_PTR:
+ vto[i].data.ptr = va_arg(arglist, void *);
+ break;
+
+ case FORMAT_INT:
+#ifdef HAVE_LONG_LONG_TYPE
+ if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+ else if(vto[i].flags & FLAGS_LONGLONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, mp_intmax_t);
+ else
+#endif
+ {
+ if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned long);
+ else if(vto[i].flags & FLAGS_LONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, long);
+ else if(vto[i].flags & FLAGS_UNSIGNED)
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned int);
+ else
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+ break;
+
+ case FORMAT_DOUBLE:
+ vto[i].data.dnum = va_arg(arglist, double);
+ break;
+
+ case FORMAT_WIDTH:
+ /* Argument has been read. Silently convert it into an integer
+ * for later use
+ */
+ vto[i].type = FORMAT_INT;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+
+}
+
+static int dprintf_formatf(
+ void *data, /* untouched by format(), just sent to the stream() function in
+ the second argument */
+ /* function pointer called for each output character */
+ int (*stream)(int, FILE *),
+ const char *format, /* %-formatted string */
+ va_list ap_save) /* list of parameters */
+{
+ /* Base-36 digits for numbers. */
+ const char *digits = lower_digits;
+
+ /* Pointer into the format string. */
+ char *f;
+
+ /* Number of characters written. */
+ int done = 0;
+
+ long param; /* current parameter to read */
+ long param_num=0; /* parameter counter */
+
+ va_stack_t vto[MAX_PARAMETERS];
+ char *endpos[MAX_PARAMETERS];
+ char **end;
+
+ char work[BUFFSIZE];
+
+ va_stack_t *p;
+
+ /* 'workend' points to the final buffer byte position, but with an extra
+ byte as margin to avoid the (false?) warning Coverity gives us
+ otherwise */
+ char *workend = &work[sizeof(work) - 2];
+
+ /* Do the actual %-code parsing */
+ if(dprintf_Pass1(format, vto, endpos, ap_save))
+ return -1;
+
+ end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
+ created for us */
+
+ f = (char *)format;
+ while(*f != '\0') {
+ /* Format spec modifiers. */
+ int is_alt;
+
+ /* Width of a field. */
+ long width;
+
+ /* Precision of a field. */
+ long prec;
+
+ /* Decimal integer is negative. */
+ int is_neg;
+
+ /* Base of a number to be written. */
+ unsigned long base;
+
+ /* Integral values to be written. */
+ mp_uintmax_t num;
+
+ /* Used to convert negative in positive. */
+ mp_intmax_t signed_num;
+
+ char *w;
+
+ if(*f != '%') {
+ /* This isn't a format spec, so write everything out until the next one
+ OR end of string is reached. */
+ do {
+ OUTCHAR(*f);
+ } while(*++f && ('%' != *f));
+ continue;
+ }
+
+ ++f;
+
+ /* Check for "%%". Note that although the ANSI standard lists
+ '%' as a conversion specifier, it says "The complete format
+ specification shall be `%%'," so we can avoid all the width
+ and precision processing. */
+ if(*f == '%') {
+ ++f;
+ OUTCHAR('%');
+ continue;
+ }
+
+ /* If this is a positional parameter, the position must follow immediately
+ after the %, thus create a %<num>$ sequence */
+ param=dprintf_DollarString(f, &f);
+
+ if(!param)
+ param = param_num;
+ else
+ --param;
+
+ param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
+ third %s will pick the 3rd argument */
+
+ p = &vto[param];
+
+ /* pick up the specified width */
+ if(p->flags & FLAGS_WIDTHPARAM) {
+ width = (long)vto[p->width].data.num.as_signed;
+ param_num++; /* since the width is extracted from a parameter, we
+ must skip that to get to the next one properly */
+ if(width < 0) {
+ /* "A negative field width is taken as a '-' flag followed by a
+ positive field width." */
+ width = -width;
+ p->flags |= FLAGS_LEFT;
+ p->flags &= ~FLAGS_PAD_NIL;
+ }
+ }
+ else
+ width = p->width;
+
+ /* pick up the specified precision */
+ if(p->flags & FLAGS_PRECPARAM) {
+ prec = (long)vto[p->precision].data.num.as_signed;
+ param_num++; /* since the precision is extracted from a parameter, we
+ must skip that to get to the next one properly */
+ if(prec < 0)
+ /* "A negative precision is taken as if the precision were
+ omitted." */
+ prec = -1;
+ }
+ else if(p->flags & FLAGS_PREC)
+ prec = p->precision;
+ else
+ prec = -1;
+
+ is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
+
+ switch(p->type) {
+ case FORMAT_INT:
+ num = p->data.num.as_unsigned;
+ if(p->flags & FLAGS_CHAR) {
+ /* Character. */
+ if(!(p->flags & FLAGS_LEFT))
+ while(--width > 0)
+ OUTCHAR(' ');
+ OUTCHAR((char) num);
+ if(p->flags & FLAGS_LEFT)
+ while(--width > 0)
+ OUTCHAR(' ');
+ break;
+ }
+ if(p->flags & FLAGS_OCTAL) {
+ /* Octal unsigned integer. */
+ base = 8;
+ goto unsigned_number;
+ }
+ else if(p->flags & FLAGS_HEX) {
+ /* Hexadecimal unsigned integer. */
+
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ base = 16;
+ goto unsigned_number;
+ }
+ else if(p->flags & FLAGS_UNSIGNED) {
+ /* Decimal unsigned integer. */
+ base = 10;
+ goto unsigned_number;
+ }
+
+ /* Decimal integer. */
+ base = 10;
+
+ is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
+ if(is_neg) {
+ /* signed_num might fail to hold absolute negative minimum by 1 */
+ signed_num = p->data.num.as_signed + (mp_intmax_t)1;
+ signed_num = -signed_num;
+ num = (mp_uintmax_t)signed_num;
+ num += (mp_uintmax_t)1;
+ }
+
+ goto number;
+
+ unsigned_number:
+ /* Unsigned number of base BASE. */
+ is_neg = 0;
+
+ number:
+ /* Number of base BASE. */
+
+ /* Supply a default precision if none was given. */
+ if(prec == -1)
+ prec = 1;
+
+ /* Put the number in WORK. */
+ w = workend;
+ while(num > 0) {
+ *w-- = digits[num % base];
+ num /= base;
+ }
+ width -= (long)(workend - w);
+ prec -= (long)(workend - w);
+
+ if(is_alt && base == 8 && prec <= 0) {
+ *w-- = '0';
+ --width;
+ }
+
+ if(prec > 0) {
+ width -= prec;
+ while(prec-- > 0)
+ *w-- = '0';
+ }
+
+ if(is_alt && base == 16)
+ width -= 2;
+
+ if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
+ --width;
+
+ if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ if(is_neg)
+ OUTCHAR('-');
+ else if(p->flags & FLAGS_SHOWSIGN)
+ OUTCHAR('+');
+ else if(p->flags & FLAGS_SPACE)
+ OUTCHAR(' ');
+
+ if(is_alt && base == 16) {
+ OUTCHAR('0');
+ if(p->flags & FLAGS_UPPER)
+ OUTCHAR('X');
+ else
+ OUTCHAR('x');
+ }
+
+ if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
+ while(width-- > 0)
+ OUTCHAR('0');
+
+ /* Write the number. */
+ while(++w <= workend) {
+ OUTCHAR(*w);
+ }
+
+ if(p->flags & FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+ break;
+
+ case FORMAT_STRING:
+ /* String. */
+ {
+ static const char null[] = "(nil)";
+ const char *str;
+ size_t len;
+
+ str = (char *) p->data.str;
+ if(str == NULL) {
+ /* Write null[] if there's space. */
+ if(prec == -1 || prec >= (long) sizeof(null) - 1) {
+ str = null;
+ len = sizeof(null) - 1;
+ /* Disable quotes around (nil) */
+ p->flags &= (~FLAGS_ALT);
+ }
+ else {
+ str = "";
+ len = 0;
+ }
+ }
+ else if(prec != -1)
+ len = (size_t)prec;
+ else
+ len = strlen(str);
+
+ width -= (len > LONG_MAX) ? LONG_MAX : (long)len;
+
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
+
+ if(!(p->flags&FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ while((len-- > 0) && *str)
+ OUTCHAR(*str++);
+ if(p->flags&FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
+ }
+ break;
+
+ case FORMAT_PTR:
+ /* Generic pointer. */
+ {
+ void *ptr;
+ ptr = (void *) p->data.ptr;
+ if(ptr != NULL) {
+ /* If the pointer is not NULL, write it as a %#x spec. */
+ base = 16;
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ is_alt = 1;
+ num = (size_t) ptr;
+ is_neg = 0;
+ goto number;
+ }
+ else {
+ /* Write "(nil)" for a nil pointer. */
+ static const char strnil[] = "(nil)";
+ const char *point;
+
+ width -= (long)(sizeof(strnil) - 1);
+ if(p->flags & FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+ for(point = strnil; *point != '\0'; ++point)
+ OUTCHAR(*point);
+ if(! (p->flags & FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
+ }
+ }
+ break;
+
+ case FORMAT_DOUBLE:
+ {
+ char formatbuf[32]="%";
+ char *fptr = &formatbuf[1];
+ size_t left = sizeof(formatbuf)-strlen(formatbuf);
+ int len;
+
+ width = -1;
+ if(p->flags & FLAGS_WIDTH)
+ width = p->width;
+ else if(p->flags & FLAGS_WIDTHPARAM)
+ width = (long)vto[p->width].data.num.as_signed;
+
+ prec = -1;
+ if(p->flags & FLAGS_PREC)
+ prec = p->precision;
+ else if(p->flags & FLAGS_PRECPARAM)
+ prec = (long)vto[p->precision].data.num.as_signed;
+
+ if(p->flags & FLAGS_LEFT)
+ *fptr++ = '-';
+ if(p->flags & FLAGS_SHOWSIGN)
+ *fptr++ = '+';
+ if(p->flags & FLAGS_SPACE)
+ *fptr++ = ' ';
+ if(p->flags & FLAGS_ALT)
+ *fptr++ = '#';
+
+ *fptr = 0;
+
+ if(width >= 0) {
+ if(width >= (long)sizeof(work))
+ width = sizeof(work)-1;
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, "%ld", width);
+ fptr += len;
+ left -= len;
+ }
+ if(prec >= 0) {
+ /* for each digit in the integer part, we can have one less
+ precision */
+ size_t maxprec = sizeof(work) - 2;
+ double val = p->data.dnum;
+ while(val >= 10.0) {
+ val /= 10;
+ maxprec--;
+ }
+
+ if(prec > (long)maxprec)
+ prec = (long)maxprec-1;
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, ".%ld", prec);
+ fptr += len;
+ }
+ if(p->flags & FLAGS_LONG)
+ *fptr++ = 'l';
+
+ if(p->flags & FLAGS_FLOATE)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
+ else if(p->flags & FLAGS_FLOATG)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
+ else
+ *fptr++ = 'f';
+
+ *fptr = 0; /* and a final zero termination */
+
+ /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
+ output characters */
+ (sprintf)(work, formatbuf, p->data.dnum);
+ DEBUGASSERT(strlen(work) <= sizeof(work));
+ for(fptr=work; *fptr; fptr++)
+ OUTCHAR(*fptr);
+ }
+ break;
+
+ case FORMAT_INTPTR:
+ /* Answer the count of characters written. */
+#ifdef HAVE_LONG_LONG_TYPE
+ if(p->flags & FLAGS_LONGLONG)
+ *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
+ else
+#endif
+ if(p->flags & FLAGS_LONG)
+ *(long *) p->data.ptr = (long)done;
+ else if(!(p->flags & FLAGS_SHORT))
+ *(int *) p->data.ptr = (int)done;
+ else
+ *(short *) p->data.ptr = (short)done;
+ break;
+
+ default:
+ break;
+ }
+ f = *end++; /* goto end of %-code */
+
+ }
+ return done;
+}
+
+/* fputc() look-alike */
+static int addbyter(int output, FILE *data)
+{
+ struct nsprintf *infop=(struct nsprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
+ if(infop->length < infop->max) {
+ /* only do this if we haven't reached max length yet */
+ infop->buffer[0] = outc; /* store */
+ infop->buffer++; /* increase pointer */
+ infop->length++; /* we are now one byte larger */
+ return outc; /* fputc() returns like this on success */
+ }
+ return -1;
+}
+
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
+ va_list ap_save)
+{
+ int retcode;
+ struct nsprintf info;
+
+ info.buffer = buffer;
+ info.length = 0;
+ info.max = maxlength;
+
+ retcode = dprintf_formatf(&info, addbyter, format, ap_save);
+ if((retcode != -1) && info.max) {
+ /* we terminate this with a zero byte */
+ if(info.max == info.length)
+ /* we're at maximum, scrap the last letter */
+ info.buffer[-1] = 0;
+ else
+ info.buffer[0] = 0;
+ }
+ return retcode;
+}
+
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+ retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+/* fputc() look-alike */
+static int alloc_addbyter(int output, FILE *data)
+{
+ struct asprintf *infop=(struct asprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
+ if(!infop->buffer) {
+ infop->buffer = malloc(32);
+ if(!infop->buffer) {
+ infop->fail = 1;
+ return -1; /* fail */
+ }
+ infop->alloc = 32;
+ infop->len =0;
+ }
+ else if(infop->len+1 >= infop->alloc) {
+ char *newptr = NULL;
+ size_t newsize = infop->alloc*2;
+
+ /* detect wrap-around or other overflow problems */
+ if(newsize > infop->alloc)
+ newptr = realloc(infop->buffer, newsize);
+
+ if(!newptr) {
+ infop->fail = 1;
+ return -1; /* fail */
+ }
+ infop->buffer = newptr;
+ infop->alloc = newsize;
+ }
+
+ infop->buffer[ infop->len ] = outc;
+
+ infop->len++;
+
+ return outc; /* fputc() returns like this on success */
+}
+
+char *curl_maprintf(const char *format, ...)
+{
+ va_list ap_save; /* argument pointer */
+ int retcode;
+ struct asprintf info;
+
+ info.buffer = NULL;
+ info.len = 0;
+ info.alloc = 0;
+ info.fail = 0;
+
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ va_end(ap_save);
+ if((-1 == retcode) || info.fail) {
+ if(info.alloc)
+ free(info.buffer);
+ return NULL;
+ }
+ if(info.alloc) {
+ info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ return strdup("");
+}
+
+char *curl_mvaprintf(const char *format, va_list ap_save)
+{
+ int retcode;
+ struct asprintf info;
+
+ info.buffer = NULL;
+ info.len = 0;
+ info.alloc = 0;
+ info.fail = 0;
+
+ retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ if((-1 == retcode) || info.fail) {
+ if(info.alloc)
+ free(info.buffer);
+ return NULL;
+ }
+
+ if(info.alloc) {
+ info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ return strdup("");
+}
+
+static int storebuffer(int output, FILE *data)
+{
+ char **buffer = (char **)data;
+ unsigned char outc = (unsigned char)output;
+ **buffer = outc;
+ (*buffer)++;
+ return outc; /* act like fputc() ! */
+}
+
+int curl_msprintf(char *buffer, const char *format, ...)
+{
+ va_list ap_save; /* argument pointer */
+ int retcode;
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+ va_end(ap_save);
+ *buffer=0; /* we terminate this with a zero byte */
+ return retcode;
+}
+
+int curl_mprintf(const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+
+ retcode = dprintf_formatf(stdout, fputc, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+int curl_mfprintf(FILE *whereto, const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(whereto, fputc, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
+{
+ int retcode;
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+ *buffer=0; /* we terminate this with a zero byte */
+ return retcode;
+}
+
+int curl_mvprintf(const char *format, va_list ap_save)
+{
+ return dprintf_formatf(stdout, fputc, format, ap_save);
+}
+
+int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
+{
+ return dprintf_formatf(whereto, fputc, format, ap_save);
+}
diff --git a/Utilities/cmcurl/lib/multi.c b/Utilities/cmcurl/lib/multi.c
new file mode 100644
index 000000000..c3a0d122c
--- /dev/null
+++ b/Utilities/cmcurl/lib/multi.c
@@ -0,0 +1,3131 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "transfer.h"
+#include "url.h"
+#include "connect.h"
+#include "progress.h"
+#include "easyif.h"
+#include "share.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "timeval.h"
+#include "http.h"
+#include "select.h"
+#include "warnless.h"
+#include "speedcheck.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "pipeline.h"
+#include "sigpipe.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
+ to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
+ CURL handle takes 45-50 K memory, therefore this 3K are not significant.
+*/
+#ifndef CURL_SOCKET_HASH_TABLE_SIZE
+#define CURL_SOCKET_HASH_TABLE_SIZE 911
+#endif
+
+#define CURL_CONNECTION_HASH_SIZE 97
+
+#define CURL_MULTI_HANDLE 0x000bab1e
+
+#define GOOD_MULTI_HANDLE(x) \
+ ((x) && (x)->type == CURL_MULTI_HANDLE)
+
+static void singlesocket(struct Curl_multi *multi,
+ struct Curl_easy *data);
+static int update_timer(struct Curl_multi *multi);
+
+static CURLMcode add_next_timeout(struct timeval now,
+ struct Curl_multi *multi,
+ struct Curl_easy *d);
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms);
+
+#ifdef DEBUGBUILD
+static const char * const statename[]={
+ "INIT",
+ "CONNECT_PEND",
+ "CONNECT",
+ "WAITRESOLVE",
+ "WAITCONNECT",
+ "WAITPROXYCONNECT",
+ "SENDPROTOCONNECT",
+ "PROTOCONNECT",
+ "WAITDO",
+ "DO",
+ "DOING",
+ "DO_MORE",
+ "DO_DONE",
+ "WAITPERFORM",
+ "PERFORM",
+ "TOOFAST",
+ "DONE",
+ "COMPLETED",
+ "MSGSENT",
+};
+#endif
+
+/* function pointer called once when switching TO a state */
+typedef void (*init_multistate_func)(struct Curl_easy *data);
+
+/* always use this function to change state, to make debugging easier */
+static void mstate(struct Curl_easy *data, CURLMstate state
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+)
+{
+ CURLMstate oldstate = data->mstate;
+ static const init_multistate_func finit[CURLM_STATE_LAST] = {
+ NULL,
+ NULL,
+ Curl_init_CONNECT, /* CONNECT */
+ /* the rest is NULL too */
+ };
+
+#if defined(DEBUGBUILD) && defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) lineno;
+#endif
+
+ if(oldstate == state)
+ /* don't bother when the new state is the same as the old state */
+ return;
+
+ data->mstate = state;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ long connection_id = -5000;
+
+ if(data->easy_conn)
+ connection_id = data->easy_conn->connection_id;
+
+ infof(data,
+ "STATE: %s => %s handle %p; line %d (connection #%ld)\n",
+ statename[oldstate], statename[data->mstate],
+ (void *)data, lineno, connection_id);
+ }
+#endif
+
+ if(state == CURLM_STATE_COMPLETED)
+ /* changing to COMPLETED means there's one less easy handle 'alive' */
+ data->multi->num_alive--;
+
+ /* if this state has an init-function, run it */
+ if(finit[state])
+ finit[state](data);
+}
+
+#ifndef DEBUGBUILD
+#define multistate(x,y) mstate(x,y)
+#else
+#define multistate(x,y) mstate(x,y, __LINE__)
+#endif
+
+/*
+ * We add one of these structs to the sockhash for a particular socket
+ */
+
+struct Curl_sh_entry {
+ struct Curl_easy *easy;
+ int action; /* what action READ/WRITE this socket waits for */
+ curl_socket_t socket; /* mainly to ease debugging */
+ void *socketp; /* settable by users with curl_multi_assign() */
+};
+/* bits for 'action' having no bits means this socket is not expecting any
+ action */
+#define SH_READ 1
+#define SH_WRITE 2
+
+/* look up a given socket in the socket hash, skip invalid sockets */
+static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
+ curl_socket_t s)
+{
+ if(s != CURL_SOCKET_BAD)
+ /* only look for proper sockets */
+ return Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+ return NULL;
+}
+
+/* make sure this socket is present in the hash for this handle */
+static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
+ curl_socket_t s,
+ struct Curl_easy *data)
+{
+ struct Curl_sh_entry *there = sh_getentry(sh, s);
+ struct Curl_sh_entry *check;
+
+ if(there)
+ /* it is present, return fine */
+ return there;
+
+ /* not present, add it */
+ check = calloc(1, sizeof(struct Curl_sh_entry));
+ if(!check)
+ return NULL; /* major failure */
+
+ check->easy = data;
+ check->socket = s;
+
+ /* make/add new hash entry */
+ if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
+ free(check);
+ return NULL; /* major failure */
+ }
+
+ return check; /* things are good in sockhash land */
+}
+
+
+/* delete the given socket + handle from the hash */
+static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
+{
+ /* We remove the hash entry. This will end up in a call to
+ sh_freeentry(). */
+ Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
+}
+
+/*
+ * free a sockhash entry
+ */
+static void sh_freeentry(void *freethis)
+{
+ struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
+
+ free(p);
+}
+
+static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
+{
+ (void) k1_len; (void) k2_len;
+
+ return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2));
+}
+
+static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
+{
+ curl_socket_t fd = *((curl_socket_t *) key);
+ (void) key_length;
+
+ return (fd % slots_num);
+}
+
+/*
+ * sh_init() creates a new socket hash and returns the handle for it.
+ *
+ * Quote from README.multi_socket:
+ *
+ * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
+ * is somewhat of a bottle neck. Its current implementation may be a bit too
+ * limiting. It simply has a fixed-size array, and on each entry in the array
+ * it has a linked list with entries. So the hash only checks which list to
+ * scan through. The code I had used so for used a list with merely 7 slots
+ * (as that is what the DNS hash uses) but with 7000 connections that would
+ * make an average of 1000 nodes in each list to run through. I upped that to
+ * 97 slots (I believe a prime is suitable) and noticed a significant speed
+ * increase. I need to reconsider the hash implementation or use a rather
+ * large default value like this. At 9000 connections I was still below 10us
+ * per call."
+ *
+ */
+static int sh_init(struct curl_hash *hash, int hashsize)
+{
+ return Curl_hash_init(hash, hashsize, hash_fd, fd_key_compare,
+ sh_freeentry);
+}
+
+/*
+ * multi_addmsg()
+ *
+ * Called when a transfer is completed. Adds the given msg pointer to
+ * the list kept in the multi handle.
+ */
+static CURLMcode multi_addmsg(struct Curl_multi *multi,
+ struct Curl_message *msg)
+{
+ Curl_llist_insert_next(&multi->msglist, multi->msglist.tail, msg,
+ &msg->list);
+ return CURLM_OK;
+}
+
+/*
+ * multi_freeamsg()
+ *
+ * Callback used by the llist system when a single list entry is destroyed.
+ */
+static void multi_freeamsg(void *a, void *b)
+{
+ (void)a;
+ (void)b;
+}
+
+struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
+ int chashsize) /* connection hash */
+{
+ struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
+
+ if(!multi)
+ return NULL;
+
+ multi->type = CURL_MULTI_HANDLE;
+
+ if(Curl_mk_dnscache(&multi->hostcache))
+ goto error;
+
+ if(sh_init(&multi->sockhash, hashsize))
+ goto error;
+
+ if(Curl_conncache_init(&multi->conn_cache, chashsize))
+ goto error;
+
+ Curl_llist_init(&multi->msglist, multi_freeamsg);
+ Curl_llist_init(&multi->pending, multi_freeamsg);
+
+ /* allocate a new easy handle to use when closing cached connections */
+ multi->closure_handle = curl_easy_init();
+ if(!multi->closure_handle)
+ goto error;
+
+ multi->closure_handle->multi = multi;
+ multi->closure_handle->state.conn_cache = &multi->conn_cache;
+
+ multi->max_pipeline_length = 5;
+
+ /* -1 means it not set by user, use the default value */
+ multi->maxconnects = -1;
+ return multi;
+
+ error:
+
+ Curl_hash_destroy(&multi->sockhash);
+ Curl_hash_destroy(&multi->hostcache);
+ Curl_conncache_destroy(&multi->conn_cache);
+ Curl_close(multi->closure_handle);
+ multi->closure_handle = NULL;
+ Curl_llist_destroy(&multi->msglist, NULL);
+ Curl_llist_destroy(&multi->pending, NULL);
+
+ free(multi);
+ return NULL;
+}
+
+struct Curl_multi *curl_multi_init(void)
+{
+ return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
+ CURL_CONNECTION_HASH_SIZE);
+}
+
+CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* Verify that we got a somewhat good easy handle too */
+ if(!GOOD_EASY_HANDLE(data))
+ return CURLM_BAD_EASY_HANDLE;
+
+ /* Prevent users from adding same easy handle more than once and prevent
+ adding to more than one multi stack */
+ if(data->multi)
+ return CURLM_ADDED_ALREADY;
+
+ /* Initialize timeout list for this handle */
+ Curl_llist_init(&data->state.timeoutlist, NULL);
+
+ /*
+ * No failure allowed in this function beyond this point. And no
+ * modification of easy nor multi handle allowed before this except for
+ * potential multi's connection cache growing which won't be undone in this
+ * function no matter what.
+ */
+
+ /* set the easy handle */
+ multistate(data, CURLM_STATE_INIT);
+
+ if((data->set.global_dns_cache) &&
+ (data->dns.hostcachetype != HCACHE_GLOBAL)) {
+ /* global dns cache was requested but still isn't */
+ struct curl_hash *global = Curl_global_host_cache_init();
+ if(global) {
+ /* only do this if the global cache init works */
+ data->dns.hostcache = global;
+ data->dns.hostcachetype = HCACHE_GLOBAL;
+ }
+ }
+ /* for multi interface connections, we share DNS cache automatically if the
+ easy handle's one is currently not set. */
+ else if(!data->dns.hostcache ||
+ (data->dns.hostcachetype == HCACHE_NONE)) {
+ data->dns.hostcache = &multi->hostcache;
+ data->dns.hostcachetype = HCACHE_MULTI;
+ }
+
+ /* Point to the multi's connection cache */
+ data->state.conn_cache = &multi->conn_cache;
+
+ /* This adds the new entry at the 'end' of the doubly-linked circular
+ list of Curl_easy structs to try and maintain a FIFO queue so
+ the pipelined requests are in order. */
+
+ /* We add this new entry last in the list. */
+
+ data->next = NULL; /* end of the line */
+ if(multi->easyp) {
+ struct Curl_easy *last = multi->easylp;
+ last->next = data;
+ data->prev = last;
+ multi->easylp = data; /* the new last node */
+ }
+ else {
+ /* first node, make prev NULL! */
+ data->prev = NULL;
+ multi->easylp = multi->easyp = data; /* both first and last */
+ }
+
+ /* make the Curl_easy refer back to this multi handle */
+ data->multi = multi;
+
+ /* Set the timeout for this handle to expire really soon so that it will
+ be taken care of even when this handle is added in the midst of operation
+ when only the curl_multi_socket() API is used. During that flow, only
+ sockets that time-out or have actions will be dealt with. Since this
+ handle has no action yet, we make sure it times out to get things to
+ happen. */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+ /* increase the node-counter */
+ multi->num_easy++;
+
+ /* increase the alive-counter */
+ multi->num_alive++;
+
+ /* A somewhat crude work-around for a little glitch in update_timer() that
+ happens if the lastcall time is set to the same time when the handle is
+ removed as when the next handle is added, as then the check in
+ update_timer() that prevents calling the application multiple times with
+ the same timer infor will not trigger and then the new handle's timeout
+ will not be notified to the app.
+
+ The work-around is thus simply to clear the 'lastcall' variable to force
+ update_timer() to always trigger a callback to the app when a new easy
+ handle is added */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
+ /* The closure handle only ever has default timeouts set. To improve the
+ state somewhat we clone the timeouts from each added handle so that the
+ closure handle always has the same timeouts as the most recently added
+ easy handle. */
+ multi->closure_handle->set.timeout = data->set.timeout;
+ multi->closure_handle->set.server_response_timeout =
+ data->set.server_response_timeout;
+
+ update_timer(multi);
+ return CURLM_OK;
+}
+
+#if 0
+/* Debug-function, used like this:
+ *
+ * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
+ *
+ * Enable the hash print function first by editing hash.c
+ */
+static void debug_print_sock_hash(void *p)
+{
+ struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
+
+ fprintf(stderr, " [easy %p/magic %x/socket %d]",
+ (void *)sh->data, sh->data->magic, (int)sh->socket);
+}
+#endif
+
+/* Mark the connection as 'idle', or close it if the cache is full.
+ Returns TRUE if the connection is kept, or FALSE if it was closed. */
+static bool
+ConnectionDone(struct Curl_easy *data, struct connectdata *conn)
+{
+ /* data->multi->maxconnects can be negative, deal with it. */
+ size_t maxconnects =
+ (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
+ data->multi->maxconnects;
+ struct connectdata *conn_candidate = NULL;
+
+ /* Mark the current connection as 'unused' */
+ conn->inuse = FALSE;
+
+ if(maxconnects > 0 &&
+ data->state.conn_cache->num_connections > maxconnects) {
+ infof(data, "Connection cache is full, closing the oldest one.\n");
+
+ conn_candidate = Curl_oldest_idle_connection(data);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly */
+ conn_candidate->data = data;
+
+ /* the winner gets the honour of being disconnected */
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ }
+
+ return (conn_candidate == conn) ? FALSE : TRUE;
+}
+
+static CURLcode multi_done(struct connectdata **connp,
+ CURLcode status, /* an error if this is called
+ after an error was detected */
+ bool premature)
+{
+ CURLcode result;
+ struct connectdata *conn;
+ struct Curl_easy *data;
+ unsigned int i;
+
+ DEBUGASSERT(*connp);
+
+ conn = *connp;
+ data = conn->data;
+
+ DEBUGF(infof(data, "multi_done\n"));
+
+ if(data->state.done)
+ /* Stop if multi_done() has already been called */
+ return CURLE_OK;
+
+ Curl_getoff_all_pipelines(data, conn);
+
+ /* Cleanup possible redirect junk */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ free(data->req.location);
+ data->req.location = NULL;
+
+ switch(status) {
+ case CURLE_ABORTED_BY_CALLBACK:
+ case CURLE_READ_ERROR:
+ case CURLE_WRITE_ERROR:
+ /* When we're aborted due to a callback return code it basically have to
+ be counted as premature as there is trouble ahead if we don't. We have
+ many callbacks and protocols work differently, we could potentially do
+ this more fine-grained in the future. */
+ premature = TRUE;
+ default:
+ break;
+ }
+
+ /* this calls the protocol-specific function pointer previously set */
+ if(conn->handler->done)
+ result = conn->handler->done(conn, status, premature);
+ else
+ result = status;
+
+ if(CURLE_ABORTED_BY_CALLBACK != result) {
+ /* avoid this if we already aborted by callback to avoid this calling
+ another callback */
+ CURLcode rc = Curl_pgrsDone(conn);
+ if(!result && rc)
+ result = CURLE_ABORTED_BY_CALLBACK;
+ }
+
+ if(conn->send_pipe.size + conn->recv_pipe.size != 0 &&
+ !data->set.reuse_forbid &&
+ !conn->bits.close) {
+ /* Stop if pipeline is not empty and we do not have to close
+ connection. */
+ data->easy_conn = NULL;
+ DEBUGF(infof(data, "Connection still in use, no more multi_done now!\n"));
+ return CURLE_OK;
+ }
+
+ data->state.done = TRUE; /* called just now! */
+ Curl_resolver_cancel(conn);
+
+ if(conn->dns_entry) {
+ Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+ conn->dns_entry = NULL;
+ }
+
+ /* if the transfer was completed in a paused state there can be buffered
+ data left to free */
+ for(i=0; i < data->state.tempcount; i++) {
+ free(data->state.tempwrite[i].buf);
+ }
+ data->state.tempcount = 0;
+
+ /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+ forced us to close this connection. This is ignored for requests taking
+ place in a NTLM authentication handshake
+
+ if conn->bits.close is TRUE, it means that the connection should be
+ closed in spite of all our efforts to be nice, due to protocol
+ restrictions in our or the server's end
+
+ if premature is TRUE, it means this connection was said to be DONE before
+ the entire request operation is complete and thus we can't know in what
+ state it is for re-using, so we're forced to close it. In a perfect world
+ we can add code that keep track of if we really must close it here or not,
+ but currently we have no such detail knowledge.
+ */
+
+ if((data->set.reuse_forbid
+#if defined(USE_NTLM)
+ && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
+ conn->proxyntlm.state == NTLMSTATE_TYPE2)
+#endif
+ ) || conn->bits.close || premature) {
+ CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
+
+ /* If we had an error already, make sure we return that one. But
+ if we got a new error, return that. */
+ if(!result && res2)
+ result = res2;
+ }
+ else {
+ /* the connection is no longer in use */
+ if(ConnectionDone(data, conn)) {
+ /* remember the most recently used connection */
+ data->state.lastconnect = conn;
+
+ infof(data, "Connection #%ld to host %s left intact\n",
+ conn->connection_id,
+ conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
+ conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+ conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+ conn->host.dispname);
+ }
+ else
+ data->state.lastconnect = NULL;
+ }
+
+ *connp = NULL; /* to make the caller of this function better detect that
+ this was either closed or handed over to the connection
+ cache here, and therefore cannot be used from this point on
+ */
+ Curl_free_request_state(data);
+
+ return result;
+}
+
+CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ struct Curl_easy *easy = data;
+ bool premature;
+ bool easy_owns_conn;
+ struct curl_llist_element *e;
+
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* Verify that we got a somewhat good easy handle too */
+ if(!GOOD_EASY_HANDLE(data))
+ return CURLM_BAD_EASY_HANDLE;
+
+ /* Prevent users from trying to remove same easy handle more than once */
+ if(!data->multi)
+ return CURLM_OK; /* it is already removed so let's say it is fine! */
+
+ premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
+ easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
+ TRUE : FALSE;
+
+ /* If the 'state' is not INIT or COMPLETED, we might need to do something
+ nice to put the easy_handle in a good known state when this returns. */
+ if(premature) {
+ /* this handle is "alive" so we need to count down the total number of
+ alive connections when this is removed */
+ multi->num_alive--;
+
+ /* When this handle gets removed, other handles may be able to get the
+ connection */
+ Curl_multi_process_pending_handles(multi);
+ }
+
+ if(data->easy_conn &&
+ data->mstate > CURLM_STATE_DO &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ /* Set connection owner so that the DONE function closes it. We can
+ safely do this here since connection is killed. */
+ data->easy_conn->data = easy;
+ /* If the handle is in a pipeline and has started sending off its
+ request but not received its response yet, we need to close
+ connection. */
+ streamclose(data->easy_conn, "Removed with partial response");
+ easy_owns_conn = TRUE;
+ }
+
+ /* The timer must be shut down before data->multi is set to NULL,
+ else the timenode will remain in the splay tree after
+ curl_easy_cleanup is called. */
+ Curl_expire_clear(data);
+
+ if(data->dns.hostcachetype == HCACHE_MULTI) {
+ /* stop using the multi handle's DNS cache */
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+ if(data->easy_conn) {
+
+ /* we must call multi_done() here (if we still own the connection) so that
+ we don't leave a half-baked one around */
+ if(easy_owns_conn) {
+
+ /* multi_done() clears the conn->data field to lose the association
+ between the easy handle and the connection
+
+ Note that this ignores the return code simply because there's
+ nothing really useful to do with it anyway! */
+ (void)multi_done(&data->easy_conn, data->result, premature);
+ }
+ else
+ /* Clear connection pipelines, if multi_done above was not called */
+ Curl_getoff_all_pipelines(data, data->easy_conn);
+ }
+
+ Curl_wildcard_dtor(&data->wildcard);
+
+ /* destroy the timeout list that is held in the easy handle, do this *after*
+ multi_done() as that may actually call Curl_expire that uses this */
+ Curl_llist_destroy(&data->state.timeoutlist, NULL);
+
+ /* as this was using a shared connection cache we clear the pointer to that
+ since we're not part of that multi handle anymore */
+ data->state.conn_cache = NULL;
+
+ /* change state without using multistate(), only to make singlesocket() do
+ what we want */
+ data->mstate = CURLM_STATE_COMPLETED;
+ singlesocket(multi, easy); /* to let the application know what sockets that
+ vanish with this handle */
+
+ /* Remove the association between the connection and the handle */
+ if(data->easy_conn) {
+ data->easy_conn->data = NULL;
+ data->easy_conn = NULL;
+ }
+
+ data->multi = NULL; /* clear the association to this multi handle */
+
+ /* make sure there's no pending message in the queue sent from this easy
+ handle */
+
+ for(e = multi->msglist.head; e; e = e->next) {
+ struct Curl_message *msg = e->ptr;
+
+ if(msg->extmsg.easy_handle == easy) {
+ Curl_llist_remove(&multi->msglist, e, NULL);
+ /* there can only be one from this specific handle */
+ break;
+ }
+ }
+
+ /* make the previous node point to our next */
+ if(data->prev)
+ data->prev->next = data->next;
+ else
+ multi->easyp = data->next; /* point to first node */
+
+ /* make our next point to our previous node */
+ if(data->next)
+ data->next->prev = data->prev;
+ else
+ multi->easylp = data->prev; /* point to last node */
+
+ /* NOTE NOTE NOTE
+ We do not touch the easy handle here! */
+ multi->num_easy--; /* one less to care about now */
+
+ update_timer(multi);
+ return CURLM_OK;
+}
+
+/* Return TRUE if the application asked for a certain set of pipelining */
+bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
+{
+ return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
+}
+
+void Curl_multi_handlePipeBreak(struct Curl_easy *data)
+{
+ data->easy_conn = NULL;
+}
+
+static int waitconnect_getsock(struct connectdata *conn,
+ curl_socket_t *sock,
+ int numsocks)
+{
+ int i;
+ int s=0;
+ int rc=0;
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+#ifdef USE_SSL
+ if(CONNECT_FIRSTSOCKET_PROXY_SSL())
+ return Curl_ssl_getsock(conn, sock, numsocks);
+#endif
+
+ for(i=0; i<2; i++) {
+ if(conn->tempsock[i] != CURL_SOCKET_BAD) {
+ sock[s] = conn->tempsock[i];
+ rc |= GETSOCK_WRITESOCK(s++);
+ }
+ }
+
+ return rc;
+}
+
+static int waitproxyconnect_getsock(struct connectdata *conn,
+ curl_socket_t *sock,
+ int numsocks)
+{
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ sock[0] = conn->sock[FIRSTSOCKET];
+
+ /* when we've sent a CONNECT to a proxy, we should rather wait for the
+ socket to become readable to be able to get the response headers */
+ if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ return GETSOCK_READSOCK(0);
+
+ return GETSOCK_WRITESOCK(0);
+}
+
+static int domore_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn && conn->handler->domore_getsock)
+ return conn->handler->domore_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+/* returns bitmapped flags for this handle and its sockets */
+static int multi_getsock(struct Curl_easy *data,
+ curl_socket_t *socks, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+ /* If the pipe broke, or if there's no connection left for this easy handle,
+ then we MUST bail out now with no bitmask set. The no connection case can
+ happen when this is called from curl_multi_remove_handle() =>
+ singlesocket() => multi_getsock().
+ */
+ if(data->state.pipe_broke || !data->easy_conn)
+ return 0;
+
+ if(data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ /* Set up ownership correctly */
+ data->easy_conn->data = data;
+ }
+
+ switch(data->mstate) {
+ default:
+#if 0 /* switch back on these cases to get the compiler to check for all enums
+ to be present */
+ case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
+ case CURLM_STATE_COMPLETED:
+ case CURLM_STATE_MSGSENT:
+ case CURLM_STATE_INIT:
+ case CURLM_STATE_CONNECT:
+ case CURLM_STATE_WAITDO:
+ case CURLM_STATE_DONE:
+ case CURLM_STATE_LAST:
+ /* this will get called with CURLM_STATE_COMPLETED when a handle is
+ removed */
+#endif
+ return 0;
+
+ case CURLM_STATE_WAITRESOLVE:
+ return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_PROTOCONNECT:
+ case CURLM_STATE_SENDPROTOCONNECT:
+ return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO:
+ case CURLM_STATE_DOING:
+ return Curl_doing_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_WAITPROXYCONNECT:
+ return waitproxyconnect_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_WAITCONNECT:
+ return waitconnect_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO_MORE:
+ return domore_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
+ to waiting for the same as the *PERFORM
+ states */
+ case CURLM_STATE_PERFORM:
+ case CURLM_STATE_WAITPERFORM:
+ return Curl_single_getsock(data->easy_conn, socks, numsocks);
+ }
+
+}
+
+CURLMcode curl_multi_fdset(struct Curl_multi *multi,
+ fd_set *read_fd_set, fd_set *write_fd_set,
+ fd_set *exc_fd_set, int *max_fd)
+{
+ /* Scan through all the easy handles to get the file descriptors set.
+ Some easy handles may not have connected to the remote host yet,
+ and then we must make sure that is done. */
+ struct Curl_easy *data;
+ int this_max_fd=-1;
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+ int i;
+ (void)exc_fd_set; /* not used */
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ FD_SET(sockbunch[i], read_fd_set);
+ s = sockbunch[i];
+ }
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ FD_SET(sockbunch[i], write_fd_set);
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD)
+ /* this socket is unused, break out of loop */
+ break;
+ if((int)s > this_max_fd)
+ this_max_fd = (int)s;
+ }
+
+ data = data->next; /* check next handle */
+ }
+
+ *max_fd = this_max_fd;
+
+ return CURLM_OK;
+}
+
+#define NUM_POLLS_ON_STACK 10
+
+CURLMcode curl_multi_wait(struct Curl_multi *multi,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret)
+{
+ struct Curl_easy *data;
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+ unsigned int i;
+ unsigned int nfds = 0;
+ unsigned int curlfds;
+ struct pollfd *ufds = NULL;
+ bool ufds_malloc = FALSE;
+ long timeout_internal;
+ int retcode = 0;
+ struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* If the internally desired timeout is actually shorter than requested from
+ the outside, then use the shorter time! But only if the internal timer
+ is actually larger than -1! */
+ (void)multi_timeout(multi, &timeout_internal);
+ if((timeout_internal >= 0) && (timeout_internal < (long)timeout_ms))
+ timeout_ms = (int)timeout_internal;
+
+ /* Count up how many fds we have from the multi handle */
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if(bitmap & GETSOCK_READSOCK(i)) {
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(bitmap & GETSOCK_WRITESOCK(i)) {
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD) {
+ break;
+ }
+ }
+
+ data = data->next; /* check next handle */
+ }
+
+ curlfds = nfds; /* number of internal file descriptors */
+ nfds += extra_nfds; /* add the externally provided ones */
+
+ if(nfds) {
+ if(nfds > NUM_POLLS_ON_STACK) {
+ ufds = malloc(nfds * sizeof(struct pollfd));
+ if(!ufds)
+ return CURLM_OUT_OF_MEMORY;
+ ufds_malloc = TRUE;
+ }
+ else
+ ufds = &a_few_on_stack[0];
+ }
+ nfds = 0;
+
+ /* only do the second loop if we found descriptors in the first stage run
+ above */
+
+ if(curlfds) {
+ /* Add the curl handles to our pollfds first */
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if(bitmap & GETSOCK_READSOCK(i)) {
+ ufds[nfds].fd = sockbunch[i];
+ ufds[nfds].events = POLLIN;
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(bitmap & GETSOCK_WRITESOCK(i)) {
+ ufds[nfds].fd = sockbunch[i];
+ ufds[nfds].events = POLLOUT;
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD) {
+ break;
+ }
+ }
+
+ data = data->next; /* check next handle */
+ }
+ }
+
+ /* Add external file descriptions from poll-like struct curl_waitfd */
+ for(i = 0; i < extra_nfds; i++) {
+ ufds[nfds].fd = extra_fds[i].fd;
+ ufds[nfds].events = 0;
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
+ ufds[nfds].events |= POLLIN;
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+ ufds[nfds].events |= POLLPRI;
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT)
+ ufds[nfds].events |= POLLOUT;
+ ++nfds;
+ }
+
+ if(nfds) {
+ int pollrc;
+ /* wait... */
+ pollrc = Curl_poll(ufds, nfds, timeout_ms);
+ DEBUGF(infof(data, "Curl_poll(%d ds, %d ms) == %d\n",
+ nfds, timeout_ms, pollrc));
+
+ if(pollrc > 0) {
+ retcode = pollrc;
+ /* copy revents results from the poll to the curl_multi_wait poll
+ struct, the bit values of the actual underlying poll() implementation
+ may not be the same as the ones in the public libcurl API! */
+ for(i = 0; i < extra_nfds; i++) {
+ unsigned short mask = 0;
+ unsigned r = ufds[curlfds + i].revents;
+
+ if(r & POLLIN)
+ mask |= CURL_WAIT_POLLIN;
+ if(r & POLLOUT)
+ mask |= CURL_WAIT_POLLOUT;
+ if(r & POLLPRI)
+ mask |= CURL_WAIT_POLLPRI;
+
+ extra_fds[i].revents = mask;
+ }
+ }
+ }
+
+ if(ufds_malloc)
+ free(ufds);
+ if(ret)
+ *ret = retcode;
+ return CURLM_OK;
+}
+
+/*
+ * Curl_multi_connchanged() is called to tell that there is a connection in
+ * this multi handle that has changed state (pipelining become possible, the
+ * number of allowed streams changed or similar), and a subsequent use of this
+ * multi handle should move CONNECT_PEND handles back to CONNECT to have them
+ * retry.
+ */
+void Curl_multi_connchanged(struct Curl_multi *multi)
+{
+ multi->recheckstate = TRUE;
+}
+
+/*
+ * multi_ischanged() is called
+ *
+ * Returns TRUE/FALSE whether the state is changed to trigger a CONNECT_PEND
+ * => CONNECT action.
+ *
+ * Set 'clear' to TRUE to have it also clear the state variable.
+ */
+static bool multi_ischanged(struct Curl_multi *multi, bool clear)
+{
+ bool retval = multi->recheckstate;
+ if(clear)
+ multi->recheckstate = FALSE;
+ return retval;
+}
+
+CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ CURLMcode rc;
+
+ rc = curl_multi_add_handle(multi, data);
+ if(!rc) {
+ struct SingleRequest *k = &data->req;
+
+ /* pass in NULL for 'conn' here since we don't want to init the
+ connection, only this transfer */
+ Curl_init_do(data, NULL);
+
+ /* take this handle to the perform state right away */
+ multistate(data, CURLM_STATE_PERFORM);
+ data->easy_conn = conn;
+ k->keepon |= KEEP_RECV; /* setup to receive! */
+ }
+ return rc;
+}
+
+static CURLcode multi_reconnect_request(struct connectdata **connp)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn = *connp;
+ struct Curl_easy *data = conn->data;
+
+ /* This was a re-use of a connection and we got a write error in the
+ * DO-phase. Then we DISCONNECT this connection and have another attempt to
+ * CONNECT and then DO again! The retry cannot possibly find another
+ * connection to re-use, since we only keep one possible connection for
+ * each. */
+
+ infof(data, "Re-used connection seems dead, get a new one\n");
+
+ connclose(conn, "Reconnect dead connection"); /* enforce close */
+ result = multi_done(&conn, result, FALSE); /* we are so done with this */
+
+ /* conn may no longer be a good pointer, clear it to avoid mistakes by
+ parent functions */
+ *connp = NULL;
+
+ /*
+ * We need to check for CURLE_SEND_ERROR here as well. This could happen
+ * when the request failed on a FTP connection and thus multi_done() itself
+ * tried to use the connection (again).
+ */
+ if(!result || (CURLE_SEND_ERROR == result)) {
+ bool async;
+ bool protocol_done = TRUE;
+
+ /* Now, redo the connect and get a new connection */
+ result = Curl_connect(data, connp, &async, &protocol_done);
+ if(!result) {
+ /* We have connected or sent away a name resolve query fine */
+
+ conn = *connp; /* setup conn to again point to something nice */
+ if(async) {
+ /* Now, if async is TRUE here, we need to wait for the name
+ to resolve */
+ result = Curl_resolver_wait_resolv(conn, NULL);
+ if(result)
+ return result;
+
+ /* Resolved, continue with the connection */
+ result = Curl_async_resolved(conn, &protocol_done);
+ if(result)
+ return result;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ * do_complete is called when the DO actions are complete.
+ *
+ * We init chunking and trailer bits to their default values here immediately
+ * before receiving any header data for the current request in the pipeline.
+ */
+static void do_complete(struct connectdata *conn)
+{
+ conn->data->req.chunk=FALSE;
+ conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
+ conn->sockfd:conn->writesockfd)+1;
+ Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
+}
+
+static CURLcode multi_do(struct connectdata **connp, bool *done)
+{
+ CURLcode result=CURLE_OK;
+ struct connectdata *conn = *connp;
+ struct Curl_easy *data = conn->data;
+
+ if(conn->handler->do_it) {
+ /* generic protocol-specific function pointer set in curl_connect() */
+ result = conn->handler->do_it(conn, done);
+
+ /* This was formerly done in transfer.c, but we better do it here */
+ if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
+ /*
+ * If the connection is using an easy handle, call reconnect
+ * to re-establish the connection. Otherwise, let the multi logic
+ * figure out how to re-establish the connection.
+ */
+ if(!data->multi) {
+ result = multi_reconnect_request(connp);
+
+ if(!result) {
+ /* ... finally back to actually retry the DO phase */
+ conn = *connp; /* re-assign conn since multi_reconnect_request
+ creates a new connection */
+ result = conn->handler->do_it(conn, done);
+ }
+ }
+ else
+ return result;
+ }
+
+ if(!result && *done)
+ /* do_complete must be called after the protocol-specific DO function */
+ do_complete(conn);
+ }
+ return result;
+}
+
+/*
+ * multi_do_more() is called during the DO_MORE multi state. It is basically a
+ * second stage DO state which (wrongly) was introduced to support FTP's
+ * second connection.
+ *
+ * TODO: A future libcurl should be able to work away this state.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
+ * DOING state there's more work to do!
+ */
+
+static CURLcode multi_do_more(struct connectdata *conn, int *complete)
+{
+ CURLcode result=CURLE_OK;
+
+ *complete = 0;
+
+ if(conn->handler->do_more)
+ result = conn->handler->do_more(conn, complete);
+
+ if(!result && (*complete == 1))
+ /* do_complete must be called after the protocol-specific DO function */
+ do_complete(conn);
+
+ return result;
+}
+
+static CURLMcode multi_runsingle(struct Curl_multi *multi,
+ struct timeval now,
+ struct Curl_easy *data)
+{
+ struct Curl_message *msg = NULL;
+ bool connected;
+ bool async;
+ bool protocol_connect = FALSE;
+ bool dophase_done = FALSE;
+ bool done = FALSE;
+ CURLMcode rc;
+ CURLcode result = CURLE_OK;
+ struct SingleRequest *k;
+ time_t timeout_ms;
+ time_t recv_timeout_ms;
+ time_t send_timeout_ms;
+ int control;
+
+ if(!GOOD_EASY_HANDLE(data))
+ return CURLM_BAD_EASY_HANDLE;
+
+ do {
+ /* A "stream" here is a logical stream if the protocol can handle that
+ (HTTP/2), or the full connection for older protocols */
+ bool stream_error = FALSE;
+ rc = CURLM_OK;
+
+ /* Handle the case when the pipe breaks, i.e., the connection
+ we're using gets cleaned up and we're left with nothing. */
+ if(data->state.pipe_broke) {
+ infof(data, "Pipe broke: handle %p, url = %s\n",
+ (void *)data, data->state.path);
+
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ /* Head back to the CONNECT state */
+ multistate(data, CURLM_STATE_CONNECT);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ result = CURLE_OK;
+ }
+
+ data->state.pipe_broke = FALSE;
+ data->easy_conn = NULL;
+ continue;
+ }
+
+ if(!data->easy_conn &&
+ data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_DONE) {
+ /* In all these states, the code will blindly access 'data->easy_conn'
+ so this is precaution that it isn't NULL. And it silences static
+ analyzers. */
+ failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
+ return CURLM_INTERNAL_ERROR;
+ }
+
+ if(multi_ischanged(multi, TRUE)) {
+ DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
+ Curl_multi_process_pending_handles(multi);
+ }
+
+ if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_COMPLETED)
+ /* Make sure we set the connection's current owner */
+ data->easy_conn->data = data;
+
+ if(data->easy_conn &&
+ (data->mstate >= CURLM_STATE_CONNECT) &&
+ (data->mstate < CURLM_STATE_COMPLETED)) {
+ /* we need to wait for the connect state as only then is the start time
+ stored, but we must not check already completed handles */
+
+ timeout_ms = Curl_timeleft(data, &now,
+ (data->mstate <= CURLM_STATE_WAITDO)?
+ TRUE:FALSE);
+
+ if(timeout_ms < 0) {
+ /* Handle timed out */
+ if(data->mstate == CURLM_STATE_WAITRESOLVE)
+ failf(data, "Resolving timed out after %ld milliseconds",
+ Curl_tvdiff(now, data->progress.t_startsingle));
+ else if(data->mstate == CURLM_STATE_WAITCONNECT)
+ failf(data, "Connection timed out after %ld milliseconds",
+ Curl_tvdiff(now, data->progress.t_startsingle));
+ else {
+ k = &data->req;
+ if(k->size != -1) {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_tvdiff(now, data->progress.t_startsingle),
+ k->bytecount, k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_tvdiff(now, data->progress.t_startsingle),
+ k->bytecount);
+ }
+ }
+
+ /* Force connection closed if the connection has indeed been used */
+ if(data->mstate > CURLM_STATE_DO) {
+ streamclose(data->easy_conn, "Disconnected with pending data");
+ stream_error = TRUE;
+ }
+ result = CURLE_OPERATION_TIMEDOUT;
+ (void)multi_done(&data->easy_conn, result, TRUE);
+ /* Skip the statemachine and go directly to error handling section. */
+ goto statemachine_end;
+ }
+ }
+
+ switch(data->mstate) {
+ case CURLM_STATE_INIT:
+ /* init this transfer. */
+ result=Curl_pretransfer(data);
+
+ if(!result) {
+ /* after init, go CONNECT */
+ multistate(data, CURLM_STATE_CONNECT);
+ Curl_pgrsTime(data, TIMER_STARTOP);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_CONNECT_PEND:
+ /* We will stay here until there is a connection available. Then
+ we try again in the CURLM_STATE_CONNECT state. */
+ break;
+
+ case CURLM_STATE_CONNECT:
+ /* Connect. We want to get a connection identifier filled in. */
+ Curl_pgrsTime(data, TIMER_STARTSINGLE);
+ result = Curl_connect(data, &data->easy_conn,
+ &async, &protocol_connect);
+ if(CURLE_NO_CONNECTION_AVAILABLE == result) {
+ /* There was no connection available. We will go to the pending
+ state and wait for an available connection. */
+ multistate(data, CURLM_STATE_CONNECT_PEND);
+
+ /* add this handle to the list of connect-pending handles */
+ Curl_llist_insert_next(&multi->pending, multi->pending.tail, data,
+ &data->connect_queue);
+ result = CURLE_OK;
+ break;
+ }
+
+ if(!result) {
+ /* Add this handle to the send or pend pipeline */
+ result = Curl_add_handle_to_pipeline(data, data->easy_conn);
+ if(result)
+ stream_error = TRUE;
+ else {
+ if(async)
+ /* We're now waiting for an asynchronous name lookup */
+ multistate(data, CURLM_STATE_WAITRESOLVE);
+ else {
+ /* after the connect has been sent off, go WAITCONNECT unless the
+ protocol connect is already done and we can go directly to
+ WAITDO or DO! */
+ rc = CURLM_CALL_MULTI_PERFORM;
+
+ if(protocol_connect)
+ multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ else {
+#ifndef CURL_DISABLE_HTTP
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
+#endif
+ multistate(data, CURLM_STATE_WAITCONNECT);
+ }
+ }
+ }
+ }
+ break;
+
+ case CURLM_STATE_WAITRESOLVE:
+ /* awaiting an asynch name resolve to complete */
+ {
+ struct Curl_dns_entry *dns = NULL;
+ struct connectdata *conn = data->easy_conn;
+ const char *hostname;
+
+ if(conn->bits.httpproxy)
+ hostname = conn->http_proxy.host.name;
+ else if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
+ else
+ hostname = conn->host.name;
+
+ /* check if we have the name resolved by now */
+ dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+
+ if(dns) {
+#ifdef CURLRES_ASYNCH
+ conn->async.dns = dns;
+ conn->async.done = TRUE;
+#endif
+ result = CURLE_OK;
+ infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
+ }
+
+ if(!dns)
+ result = Curl_resolver_is_resolved(data->easy_conn, &dns);
+
+ /* Update sockets here, because the socket(s) may have been
+ closed and the application thus needs to be told, even if it
+ is likely that the same socket(s) will again be used further
+ down. If the name has not yet been resolved, it is likely
+ that new sockets have been opened in an attempt to contact
+ another resolver. */
+ singlesocket(multi, data);
+
+ if(dns) {
+ /* Perform the next step in the connection phase, and then move on
+ to the WAITCONNECT state */
+ result = Curl_async_resolved(data->easy_conn, &protocol_connect);
+
+ if(result)
+ /* if Curl_async_resolved() returns failure, the connection struct
+ is already freed and gone */
+ data->easy_conn = NULL; /* no more connection */
+ else {
+ /* call again please so that we get the next socket setup */
+ rc = CURLM_CALL_MULTI_PERFORM;
+ if(protocol_connect)
+ multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ else {
+#ifndef CURL_DISABLE_HTTP
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
+#endif
+ multistate(data, CURLM_STATE_WAITCONNECT);
+ }
+ }
+ }
+
+ if(result) {
+ /* failure detected */
+ stream_error = TRUE;
+ break;
+ }
+ }
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLM_STATE_WAITPROXYCONNECT:
+ /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
+ result = Curl_http_connect(data->easy_conn, &protocol_connect);
+
+ if(data->easy_conn->bits.proxy_connect_closed) {
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* connect back to proxy again */
+ result = CURLE_OK;
+ multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multistate(data, CURLM_STATE_CONNECT);
+ }
+ else if(!result) {
+ if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
+ data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
+ (data->easy_conn->tunnel_state[FIRSTSOCKET] != TUNNEL_CONNECT)) {
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* initiate protocol connect phase */
+ multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ }
+ }
+ break;
+#endif
+
+ case CURLM_STATE_WAITCONNECT:
+ /* awaiting a completion of an asynch TCP connect */
+ result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected);
+ if(connected && !result) {
+#ifndef CURL_DISABLE_HTTP
+ if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
+ !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
+ (data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)) {
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ break;
+ }
+#endif
+ rc = CURLM_CALL_MULTI_PERFORM;
+ multistate(data, data->easy_conn->bits.tunnel_proxy?
+ CURLM_STATE_WAITPROXYCONNECT:
+ CURLM_STATE_SENDPROTOCONNECT);
+ }
+ else if(result) {
+ /* failure detected */
+ /* Just break, the cleaning up is handled all in one place */
+ stream_error = TRUE;
+ break;
+ }
+ break;
+
+ case CURLM_STATE_SENDPROTOCONNECT:
+ result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
+ if(!protocol_connect)
+ /* switch to waiting state */
+ multistate(data, CURLM_STATE_PROTOCONNECT);
+ else if(!result) {
+ /* protocol connect has completed, go WAITDO or DO */
+ multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ else if(result) {
+ /* failure detected */
+ Curl_posttransfer(data);
+ multi_done(&data->easy_conn, result, TRUE);
+ stream_error = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_PROTOCONNECT:
+ /* protocol-specific connect phase */
+ result = Curl_protocol_connecting(data->easy_conn, &protocol_connect);
+ if(!result && protocol_connect) {
+ /* after the connect has completed, go WAITDO or DO */
+ multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ else if(result) {
+ /* failure detected */
+ Curl_posttransfer(data);
+ multi_done(&data->easy_conn, result, TRUE);
+ stream_error = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_WAITDO:
+ /* Wait for our turn to DO when we're pipelining requests */
+ if(Curl_pipeline_checkget_write(data, data->easy_conn)) {
+ /* Grabbed the channel */
+ multistate(data, CURLM_STATE_DO);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_DO:
+ if(data->set.connect_only) {
+ /* keep connection open for application to use the socket */
+ connkeep(data->easy_conn, "CONNECT_ONLY");
+ multistate(data, CURLM_STATE_DONE);
+ result = CURLE_OK;
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ else {
+ /* Perform the protocol's DO action */
+ result = multi_do(&data->easy_conn, &dophase_done);
+
+ /* When multi_do() returns failure, data->easy_conn might be NULL! */
+
+ if(!result) {
+ if(!dophase_done) {
+ /* some steps needed for wildcard matching */
+ if(data->set.wildcardmatch) {
+ struct WildcardData *wc = &data->wildcard;
+ if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
+ /* skip some states if it is important */
+ multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multistate(data, CURLM_STATE_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ break;
+ }
+ }
+ /* DO was not completed in one function call, we must continue
+ DOING... */
+ multistate(data, CURLM_STATE_DOING);
+ rc = CURLM_OK;
+ }
+
+ /* after DO, go DO_DONE... or DO_MORE */
+ else if(data->easy_conn->bits.do_more) {
+ /* we're supposed to do more, but we need to sit down, relax
+ and wait a little while first */
+ multistate(data, CURLM_STATE_DO_MORE);
+ rc = CURLM_OK;
+ }
+ else {
+ /* we're done with the DO, now DO_DONE */
+ multistate(data, CURLM_STATE_DO_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ else if((CURLE_SEND_ERROR == result) &&
+ data->easy_conn->bits.reuse) {
+ /*
+ * In this situation, a connection that we were trying to use
+ * may have unexpectedly died. If possible, send the connection
+ * back to the CONNECT phase so we can try again.
+ */
+ char *newurl = NULL;
+ followtype follow=FOLLOW_NONE;
+ CURLcode drc;
+ bool retry = FALSE;
+
+ drc = Curl_retry_request(data->easy_conn, &newurl);
+ if(drc) {
+ /* a failure here pretty much implies an out of memory */
+ result = drc;
+ stream_error = TRUE;
+ }
+ else
+ retry = (newurl)?TRUE:FALSE;
+
+ Curl_posttransfer(data);
+ drc = multi_done(&data->easy_conn, result, FALSE);
+
+ /* When set to retry the connection, we must to go back to
+ * the CONNECT state */
+ if(retry) {
+ if(!drc || (drc == CURLE_SEND_ERROR)) {
+ follow = FOLLOW_RETRY;
+ drc = Curl_follow(data, newurl, follow);
+ if(!drc) {
+ multistate(data, CURLM_STATE_CONNECT);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ result = CURLE_OK;
+ }
+ else {
+ /* Follow failed */
+ result = drc;
+ }
+ }
+ else {
+ /* done didn't return OK or SEND_ERROR */
+ result = drc;
+ }
+ }
+ else {
+ /* Have error handler disconnect conn if we can't retry */
+ stream_error = TRUE;
+ }
+ free(newurl);
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ if(data->easy_conn)
+ multi_done(&data->easy_conn, result, FALSE);
+ stream_error = TRUE;
+ }
+ }
+ break;
+
+ case CURLM_STATE_DOING:
+ /* we continue DOING until the DO phase is complete */
+ result = Curl_protocol_doing(data->easy_conn,
+ &dophase_done);
+ if(!result) {
+ if(dophase_done) {
+ /* after DO, go DO_DONE or DO_MORE */
+ multistate(data, data->easy_conn->bits.do_more?
+ CURLM_STATE_DO_MORE:
+ CURLM_STATE_DO_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ } /* dophase_done */
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ multi_done(&data->easy_conn, result, FALSE);
+ stream_error = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_DO_MORE:
+ /*
+ * When we are connected, DO MORE and then go DO_DONE
+ */
+ result = multi_do_more(data->easy_conn, &control);
+
+ /* No need to remove this handle from the send pipeline here since that
+ is done in multi_done() */
+ if(!result) {
+ if(control) {
+ /* if positive, advance to DO_DONE
+ if negative, go back to DOING */
+ multistate(data, control==1?
+ CURLM_STATE_DO_DONE:
+ CURLM_STATE_DOING);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ else
+ /* stay in DO_MORE */
+ rc = CURLM_OK;
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ multi_done(&data->easy_conn, result, FALSE);
+ stream_error = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_DO_DONE:
+ /* Move ourselves from the send to recv pipeline */
+ Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ /* Only perform the transfer if there's a good socket to work with.
+ Having both BAD is a signal to skip immediately to DONE */
+ if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
+ (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
+ multistate(data, CURLM_STATE_WAITPERFORM);
+ else
+ multistate(data, CURLM_STATE_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ break;
+
+ case CURLM_STATE_WAITPERFORM:
+ /* Wait for our turn to PERFORM */
+ if(Curl_pipeline_checkget_read(data, data->easy_conn)) {
+ /* Grabbed the channel */
+ multistate(data, CURLM_STATE_PERFORM);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
+ /* if both rates are within spec, resume transfer */
+ if(Curl_pgrsUpdate(data->easy_conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, now);
+
+ if(!result) {
+ send_timeout_ms = 0;
+ if(data->set.max_send_speed > 0)
+ send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
+ data->set.max_send_speed,
+ data->progress.ul_limit_start,
+ now);
+
+ recv_timeout_ms = 0;
+ if(data->set.max_recv_speed > 0)
+ recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
+ data->set.max_recv_speed,
+ data->progress.dl_limit_start,
+ now);
+
+ if(send_timeout_ms <= 0 && recv_timeout_ms <= 0)
+ multistate(data, CURLM_STATE_PERFORM);
+ else if(send_timeout_ms >= recv_timeout_ms)
+ Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+ else
+ Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+ }
+ break;
+
+ case CURLM_STATE_PERFORM:
+ {
+ char *newurl = NULL;
+ bool retry = FALSE;
+ bool comeback = FALSE;
+
+ /* check if over send speed */
+ send_timeout_ms = 0;
+ if(data->set.max_send_speed > 0)
+ send_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
+ data->set.max_send_speed,
+ data->progress.ul_limit_start,
+ now);
+
+ /* check if over recv speed */
+ recv_timeout_ms = 0;
+ if(data->set.max_recv_speed > 0)
+ recv_timeout_ms = Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
+ data->set.max_recv_speed,
+ data->progress.dl_limit_start,
+ now);
+
+ if(send_timeout_ms > 0 || recv_timeout_ms > 0) {
+ multistate(data, CURLM_STATE_TOOFAST);
+ if(send_timeout_ms >= recv_timeout_ms)
+ Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST);
+ else
+ Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST);
+ break;
+ }
+
+ /* read/write data if it is ready to do so */
+ result = Curl_readwrite(data->easy_conn, data, &done, &comeback);
+
+ k = &data->req;
+
+ if(!(k->keepon & KEEP_RECV))
+ /* We're done receiving */
+ Curl_pipeline_leave_read(data->easy_conn);
+
+ if(!(k->keepon & KEEP_SEND))
+ /* We're done sending */
+ Curl_pipeline_leave_write(data->easy_conn);
+
+ if(done || (result == CURLE_RECV_ERROR)) {
+ /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
+ * condition and the server closed the re-used connection exactly when
+ * we wanted to use it, so figure out if that is indeed the case.
+ */
+ CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
+ if(!ret)
+ retry = (newurl)?TRUE:FALSE;
+
+ if(retry) {
+ /* if we are to retry, set the result to OK and consider the
+ request as done */
+ result = CURLE_OK;
+ done = TRUE;
+ }
+ }
+
+ if(result) {
+ /*
+ * The transfer phase returned error, we mark the connection to get
+ * closed to prevent being re-used. This is because we can't possibly
+ * know if the connection is in a good shape or not now. Unless it is
+ * a protocol which uses two "channels" like FTP, as then the error
+ * happened in the data connection.
+ */
+
+ if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) &&
+ result != CURLE_HTTP2_STREAM)
+ streamclose(data->easy_conn, "Transfer returned error");
+
+ Curl_posttransfer(data);
+ multi_done(&data->easy_conn, result, TRUE);
+ }
+ else if(done) {
+ followtype follow=FOLLOW_NONE;
+
+ /* call this even if the readwrite function returned error */
+ Curl_posttransfer(data);
+
+ /* we're no longer receiving */
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+
+ /* expire the new receiving pipeline head */
+ if(data->easy_conn->recv_pipe.head)
+ Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
+
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ /* When we follow redirects or is set to retry the connection, we must
+ to go back to the CONNECT state */
+ if(data->req.newurl || retry) {
+ if(!retry) {
+ /* if the URL is a follow-location and not just a retried request
+ then figure out the URL here */
+ free(newurl);
+ newurl = data->req.newurl;
+ data->req.newurl = NULL;
+ follow = FOLLOW_REDIR;
+ }
+ else
+ follow = FOLLOW_RETRY;
+ result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ if(!result) {
+ result = Curl_follow(data, newurl, follow);
+ if(!result) {
+ multistate(data, CURLM_STATE_CONNECT);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ }
+ else {
+ /* after the transfer is done, go DONE */
+
+ /* but first check to see if we got a location info even though we're
+ not following redirects */
+ if(data->req.location) {
+ free(newurl);
+ newurl = data->req.location;
+ data->req.location = NULL;
+ result = Curl_follow(data, newurl, FOLLOW_FAKE);
+ if(result)
+ stream_error = TRUE;
+ }
+
+ multistate(data, CURLM_STATE_DONE);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ else if(comeback)
+ rc = CURLM_CALL_MULTI_PERFORM;
+
+ free(newurl);
+ break;
+ }
+
+ case CURLM_STATE_DONE:
+ /* this state is highly transient, so run another loop after this */
+ rc = CURLM_CALL_MULTI_PERFORM;
+
+ if(data->easy_conn) {
+ CURLcode res;
+
+ /* Remove ourselves from the receive pipeline, if we are there. */
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ /* post-transfer command */
+ res = multi_done(&data->easy_conn, result, FALSE);
+
+ /* allow a previously set error code take precedence */
+ if(!result)
+ result = res;
+
+ /*
+ * If there are other handles on the pipeline, multi_done won't set
+ * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
+ * access free'd data, if the connection is free'd and the handle
+ * removed before we perform the processing in CURLM_STATE_COMPLETED
+ */
+ if(data->easy_conn)
+ data->easy_conn = NULL;
+ }
+
+ if(data->set.wildcardmatch) {
+ if(data->wildcard.state != CURLWC_DONE) {
+ /* if a wildcard is set and we are not ending -> lets start again
+ with CURLM_STATE_INIT */
+ multistate(data, CURLM_STATE_INIT);
+ break;
+ }
+ }
+
+ /* after we have DONE what we're supposed to do, go COMPLETED, and
+ it doesn't matter what the multi_done() returned! */
+ multistate(data, CURLM_STATE_COMPLETED);
+ break;
+
+ case CURLM_STATE_COMPLETED:
+ /* this is a completed transfer, it is likely to still be connected */
+
+ /* This node should be delinked from the list now and we should post
+ an information message that we are complete. */
+
+ /* Important: reset the conn pointer so that we don't point to memory
+ that could be freed anytime */
+ data->easy_conn = NULL;
+
+ Curl_expire_clear(data); /* stop all timers */
+ break;
+
+ case CURLM_STATE_MSGSENT:
+ data->result = result;
+ return CURLM_OK; /* do nothing */
+
+ default:
+ return CURLM_INTERNAL_ERROR;
+ }
+ statemachine_end:
+
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(result) {
+ /*
+ * If an error was returned, and we aren't in completed state now,
+ * then we go to completed and consider this transfer aborted.
+ */
+
+ /* NOTE: no attempt to disconnect connections must be made
+ in the case blocks above - cleanup happens only here */
+
+ data->state.pipe_broke = FALSE;
+
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ if(data->easy_conn) {
+ /* if this has a connection, unsubscribe from the pipelines */
+ Curl_pipeline_leave_write(data->easy_conn);
+ Curl_pipeline_leave_read(data->easy_conn);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe);
+ Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+
+ if(stream_error) {
+ /* Don't attempt to send data over a connection that timed out */
+ bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
+ /* disconnect properly */
+ Curl_disconnect(data->easy_conn, dead_connection);
+
+ /* This is where we make sure that the easy_conn pointer is reset.
+ We don't have to do this in every case block above where a
+ failure is detected */
+ data->easy_conn = NULL;
+ }
+ }
+ else if(data->mstate == CURLM_STATE_CONNECT) {
+ /* Curl_connect() failed */
+ (void)Curl_posttransfer(data);
+ }
+
+ multistate(data, CURLM_STATE_COMPLETED);
+ }
+ /* if there's still a connection to use, call the progress function */
+ else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
+ /* aborted due to progress callback return code must close the
+ connection */
+ result = CURLE_ABORTED_BY_CALLBACK;
+ streamclose(data->easy_conn, "Aborted by callback");
+
+ /* if not yet in DONE state, go there, otherwise COMPLETED */
+ multistate(data, (data->mstate < CURLM_STATE_DONE)?
+ CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
+ rc = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+
+ if(CURLM_STATE_COMPLETED == data->mstate) {
+ /* now fill in the Curl_message with this info */
+ msg = &data->msg;
+
+ msg->extmsg.msg = CURLMSG_DONE;
+ msg->extmsg.easy_handle = data;
+ msg->extmsg.data.result = result;
+
+ rc = multi_addmsg(multi, msg);
+
+ multistate(data, CURLM_STATE_MSGSENT);
+ }
+ } while((rc == CURLM_CALL_MULTI_PERFORM) || multi_ischanged(multi, FALSE));
+
+ data->result = result;
+
+
+ return rc;
+}
+
+
+CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
+{
+ struct Curl_easy *data;
+ CURLMcode returncode=CURLM_OK;
+ struct Curl_tree *t;
+ struct timeval now = Curl_tvnow();
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ data=multi->easyp;
+ while(data) {
+ CURLMcode result;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ sigpipe_ignore(data, &pipe_st);
+ result = multi_runsingle(multi, now, data);
+ sigpipe_restore(&pipe_st);
+
+ if(result)
+ returncode = result;
+
+ data = data->next; /* operate on next handle */
+ }
+
+ /*
+ * Simply remove all expired timers from the splay since handles are dealt
+ * with unconditionally by this function and curl_multi_timeout() requires
+ * that already passed/handled expire times are removed from the splay.
+ *
+ * It is important that the 'now' value is set at the entry of this function
+ * and not for the current time as it may have ticked a little while since
+ * then and then we risk this loop to remove timers that actually have not
+ * been handled!
+ */
+ do {
+ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+ if(t)
+ /* the removed may have another timeout in queue */
+ (void)add_next_timeout(now, multi, t->payload);
+
+ } while(t);
+
+ *running_handles = multi->num_alive;
+
+ if(CURLM_OK >= returncode)
+ update_timer(multi);
+
+ return returncode;
+}
+
+static void close_all_connections(struct Curl_multi *multi)
+{
+ struct connectdata *conn;
+
+ conn = Curl_conncache_find_first_connection(&multi->conn_cache);
+ while(conn) {
+ SIGPIPE_VARIABLE(pipe_st);
+ conn->data = multi->closure_handle;
+
+ sigpipe_ignore(conn->data, &pipe_st);
+ conn->data->easy_conn = NULL; /* clear the easy handle's connection
+ pointer */
+ /* This will remove the connection from the cache */
+ connclose(conn, "kill all");
+ (void)Curl_disconnect(conn, FALSE);
+ sigpipe_restore(&pipe_st);
+
+ conn = Curl_conncache_find_first_connection(&multi->conn_cache);
+ }
+}
+
+CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
+{
+ struct Curl_easy *data;
+ struct Curl_easy *nextdata;
+
+ if(GOOD_MULTI_HANDLE(multi)) {
+ bool restore_pipe = FALSE;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ multi->type = 0; /* not good anymore */
+
+ /* Close all the connections in the connection cache */
+ close_all_connections(multi);
+
+ if(multi->closure_handle) {
+ sigpipe_ignore(multi->closure_handle, &pipe_st);
+ restore_pipe = TRUE;
+
+ multi->closure_handle->dns.hostcache = &multi->hostcache;
+ Curl_hostcache_clean(multi->closure_handle,
+ multi->closure_handle->dns.hostcache);
+
+ Curl_close(multi->closure_handle);
+ }
+
+ Curl_hash_destroy(&multi->sockhash);
+ Curl_conncache_destroy(&multi->conn_cache);
+ Curl_llist_destroy(&multi->msglist, NULL);
+ Curl_llist_destroy(&multi->pending, NULL);
+
+ /* remove all easy handles */
+ data = multi->easyp;
+ while(data) {
+ nextdata=data->next;
+ if(data->dns.hostcachetype == HCACHE_MULTI) {
+ /* clear out the usage of the shared DNS cache */
+ Curl_hostcache_clean(data, data->dns.hostcache);
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+ /* Clear the pointer to the connection cache */
+ data->state.conn_cache = NULL;
+ data->multi = NULL; /* clear the association */
+
+ data = nextdata;
+ }
+
+ Curl_hash_destroy(&multi->hostcache);
+
+ /* Free the blacklists by setting them to NULL */
+ Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
+ Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
+
+ free(multi);
+ if(restore_pipe)
+ sigpipe_restore(&pipe_st);
+
+ return CURLM_OK;
+ }
+ return CURLM_BAD_HANDLE;
+}
+
+/*
+ * curl_multi_info_read()
+ *
+ * This function is the primary way for a multi/multi_socket application to
+ * figure out if a transfer has ended. We MUST make this function as fast as
+ * possible as it will be polled frequently and we MUST NOT scan any lists in
+ * here to figure out things. We must scale fine to thousands of handles and
+ * beyond. The current design is fully O(1).
+ */
+
+CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
+{
+ struct Curl_message *msg;
+
+ *msgs_in_queue = 0; /* default to none */
+
+ if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) {
+ /* there is one or more messages in the list */
+ struct curl_llist_element *e;
+
+ /* extract the head of the list to return */
+ e = multi->msglist.head;
+
+ msg = e->ptr;
+
+ /* remove the extracted entry */
+ Curl_llist_remove(&multi->msglist, e, NULL);
+
+ *msgs_in_queue = curlx_uztosi(Curl_llist_count(&multi->msglist));
+
+ return &msg->extmsg;
+ }
+ return NULL;
+}
+
+/*
+ * singlesocket() checks what sockets we deal with and their "action state"
+ * and if we have a different state in any of those sockets from last time we
+ * call the callback accordingly.
+ */
+static void singlesocket(struct Curl_multi *multi,
+ struct Curl_easy *data)
+{
+ curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+ int i;
+ struct Curl_sh_entry *entry;
+ curl_socket_t s;
+ int num;
+ unsigned int curraction;
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+ socks[i] = CURL_SOCKET_BAD;
+
+ /* Fill in the 'current' struct with the state as it is now: what sockets to
+ supervise and for what actions */
+ curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
+
+ /* We have 0 .. N sockets already and we get to know about the 0 .. M
+ sockets we should have from now on. Detect the differences, remove no
+ longer supervised ones and add new ones */
+
+ /* walk over the sockets we got right now */
+ for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
+ (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
+ i++) {
+ int action = CURL_POLL_NONE;
+
+ s = socks[i];
+
+ /* get it from the hash */
+ entry = sh_getentry(&multi->sockhash, s);
+
+ if(curraction & GETSOCK_READSOCK(i))
+ action |= CURL_POLL_IN;
+ if(curraction & GETSOCK_WRITESOCK(i))
+ action |= CURL_POLL_OUT;
+
+ if(entry) {
+ /* yeps, already present so check if it has the same action set */
+ if(entry->action == action)
+ /* same, continue */
+ continue;
+ }
+ else {
+ /* this is a socket we didn't have before, add it! */
+ entry = sh_addentry(&multi->sockhash, s, data);
+ if(!entry)
+ /* fatal */
+ return;
+ }
+
+ /* we know (entry != NULL) at this point, see the logic above */
+ if(multi->socket_cb)
+ multi->socket_cb(data,
+ s,
+ action,
+ multi->socket_userp,
+ entry->socketp);
+
+ entry->action = action; /* store the current action state */
+ }
+
+ num = i; /* number of sockets */
+
+ /* when we've walked over all the sockets we should have right now, we must
+ make sure to detect sockets that are removed */
+ for(i=0; i< data->numsocks; i++) {
+ int j;
+ s = data->sockets[i];
+ for(j=0; j<num; j++) {
+ if(s == socks[j]) {
+ /* this is still supervised */
+ s = CURL_SOCKET_BAD;
+ break;
+ }
+ }
+
+ entry = sh_getentry(&multi->sockhash, s);
+ if(entry) {
+ /* this socket has been removed. Tell the app to remove it */
+ bool remove_sock_from_hash = TRUE;
+
+ /* check if the socket to be removed serves a connection which has
+ other easy-s in a pipeline. In this case the socket should not be
+ removed. */
+ struct connectdata *easy_conn = data->easy_conn;
+ if(easy_conn) {
+ if(easy_conn->recv_pipe.size > 1) {
+ /* the handle should not be removed from the pipe yet */
+ remove_sock_from_hash = FALSE;
+
+ /* Update the sockhash entry to instead point to the next in line
+ for the recv_pipe, or the first (in case this particular easy
+ isn't already) */
+ if(entry->easy == data) {
+ if(Curl_recvpipe_head(data, easy_conn))
+ entry->easy = easy_conn->recv_pipe.head->next->ptr;
+ else
+ entry->easy = easy_conn->recv_pipe.head->ptr;
+ }
+ }
+ if(easy_conn->send_pipe.size > 1) {
+ /* the handle should not be removed from the pipe yet */
+ remove_sock_from_hash = FALSE;
+
+ /* Update the sockhash entry to instead point to the next in line
+ for the send_pipe, or the first (in case this particular easy
+ isn't already) */
+ if(entry->easy == data) {
+ if(Curl_sendpipe_head(data, easy_conn))
+ entry->easy = easy_conn->send_pipe.head->next->ptr;
+ else
+ entry->easy = easy_conn->send_pipe.head->ptr;
+ }
+ }
+ /* Don't worry about overwriting recv_pipe head with send_pipe_head,
+ when action will be asked on the socket (see multi_socket()), the
+ head of the correct pipe will be taken according to the
+ action. */
+ }
+
+ if(remove_sock_from_hash) {
+ /* in this case 'entry' is always non-NULL */
+ if(multi->socket_cb)
+ multi->socket_cb(data,
+ s,
+ CURL_POLL_REMOVE,
+ multi->socket_userp,
+ entry->socketp);
+ sh_delentry(&multi->sockhash, s);
+ }
+ } /* if sockhash entry existed */
+ } /* for loop over numsocks */
+
+ memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
+ data->numsocks = num;
+}
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using is about to be closed. This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
+{
+ struct Curl_multi *multi = conn->data->multi;
+ if(multi) {
+ /* this is set if this connection is part of a handle that is added to
+ a multi handle, and only then this is necessary */
+ struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+ if(entry) {
+ if(multi->socket_cb)
+ multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
+ multi->socket_userp,
+ entry->socketp);
+
+ /* now remove it from the socket hash */
+ sh_delentry(&multi->sockhash, s);
+ }
+ }
+}
+
+/*
+ * add_next_timeout()
+ *
+ * Each Curl_easy has a list of timeouts. The add_next_timeout() is called
+ * when it has just been removed from the splay tree because the timeout has
+ * expired. This function is then to advance in the list to pick the next
+ * timeout to use (skip the already expired ones) and add this node back to
+ * the splay tree again.
+ *
+ * The splay tree only has each sessionhandle as a single node and the nearest
+ * timeout is used to sort it on.
+ */
+static CURLMcode add_next_timeout(struct timeval now,
+ struct Curl_multi *multi,
+ struct Curl_easy *d)
+{
+ struct timeval *tv = &d->state.expiretime;
+ struct curl_llist *list = &d->state.timeoutlist;
+ struct curl_llist_element *e;
+ struct time_node *node = NULL;
+
+ /* move over the timeout list for this specific handle and remove all
+ timeouts that are now passed tense and store the next pending
+ timeout in *tv */
+ for(e = list->head; e;) {
+ struct curl_llist_element *n = e->next;
+ time_t diff;
+ node = (struct time_node *)e->ptr;
+ diff = curlx_tvdiff(node->time, now);
+ if(diff <= 0)
+ /* remove outdated entry */
+ Curl_llist_remove(list, e, NULL);
+ else
+ /* the list is sorted so get out on the first mismatch */
+ break;
+ e = n;
+ }
+ e = list->head;
+ if(!e) {
+ /* clear the expire times within the handles that we remove from the
+ splay tree */
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+ }
+ else {
+ /* copy the first entry to 'tv' */
+ memcpy(tv, &node->time, sizeof(*tv));
+
+ /* remove first entry from list */
+ Curl_llist_remove(list, e, NULL);
+
+ /* insert this node again into the splay */
+ multi->timetree = Curl_splayinsert(*tv, multi->timetree,
+ &d->state.timenode);
+ }
+ return CURLM_OK;
+}
+
+static CURLMcode multi_socket(struct Curl_multi *multi,
+ bool checkall,
+ curl_socket_t s,
+ int ev_bitmask,
+ int *running_handles)
+{
+ CURLMcode result = CURLM_OK;
+ struct Curl_easy *data = NULL;
+ struct Curl_tree *t;
+ struct timeval now = Curl_tvnow();
+
+ if(checkall) {
+ /* *perform() deals with running_handles on its own */
+ result = curl_multi_perform(multi, running_handles);
+
+ /* walk through each easy handle and do the socket state change magic
+ and callbacks */
+ if(result != CURLM_BAD_HANDLE) {
+ data=multi->easyp;
+ while(data) {
+ singlesocket(multi, data);
+ data = data->next;
+ }
+ }
+
+ /* or should we fall-through and do the timer-based stuff? */
+ return result;
+ }
+ if(s != CURL_SOCKET_TIMEOUT) {
+
+ struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+ if(!entry)
+ /* Unmatched socket, we can't act on it but we ignore this fact. In
+ real-world tests it has been proved that libevent can in fact give
+ the application actions even though the socket was just previously
+ asked to get removed, so thus we better survive stray socket actions
+ and just move on. */
+ ;
+ else {
+ SIGPIPE_VARIABLE(pipe_st);
+
+ data = entry->easy;
+
+ if(data->magic != CURLEASY_MAGIC_NUMBER)
+ /* bad bad bad bad bad bad bad */
+ return CURLM_INTERNAL_ERROR;
+
+ /* If the pipeline is enabled, take the handle which is in the head of
+ the pipeline. If we should write into the socket, take the send_pipe
+ head. If we should read from the socket, take the recv_pipe head. */
+ if(data->easy_conn) {
+ if((ev_bitmask & CURL_POLL_OUT) &&
+ data->easy_conn->send_pipe.head)
+ data = data->easy_conn->send_pipe.head->ptr;
+ else if((ev_bitmask & CURL_POLL_IN) &&
+ data->easy_conn->recv_pipe.head)
+ data = data->easy_conn->recv_pipe.head->ptr;
+ }
+
+ if(data->easy_conn &&
+ !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they're not locked */
+ data->easy_conn->cselect_bits = ev_bitmask;
+
+ sigpipe_ignore(data, &pipe_st);
+ result = multi_runsingle(multi, now, data);
+ sigpipe_restore(&pipe_st);
+
+ if(data->easy_conn &&
+ !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
+ /* clear the bitmask only if not locked */
+ data->easy_conn->cselect_bits = 0;
+
+ if(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data);
+
+ /* Now we fall-through and do the timer-based stuff, since we don't want
+ to force the user to have to deal with timeouts as long as at least
+ one connection in fact has traffic. */
+
+ data = NULL; /* set data to NULL again to avoid calling
+ multi_runsingle() in case there's no need to */
+ now = Curl_tvnow(); /* get a newer time since the multi_runsingle() loop
+ may have taken some time */
+ }
+ }
+ else {
+ /* Asked to run due to time-out. Clear the 'lastcall' variable to force
+ update_timer() to trigger a callback to the app again even if the same
+ timeout is still the one to run after this call. That handles the case
+ when the application asks libcurl to run the timeout prematurely. */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+ }
+
+ /*
+ * The loop following here will go on as long as there are expire-times left
+ * to process in the splay and 'data' will be re-assigned for every expired
+ * handle we deal with.
+ */
+ do {
+ /* the first loop lap 'data' can be NULL */
+ if(data) {
+ SIGPIPE_VARIABLE(pipe_st);
+
+ sigpipe_ignore(data, &pipe_st);
+ result = multi_runsingle(multi, now, data);
+ sigpipe_restore(&pipe_st);
+
+ if(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data);
+ }
+
+ /* Check if there's one (more) expired timer to deal with! This function
+ extracts a matching node if there is one */
+
+ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+ if(t) {
+ data = t->payload; /* assign this for next loop */
+ (void)add_next_timeout(now, multi, t->payload);
+ }
+
+ } while(t);
+
+ *running_handles = multi->num_alive;
+ return result;
+}
+
+#undef curl_multi_setopt
+CURLMcode curl_multi_setopt(struct Curl_multi *multi,
+ CURLMoption option, ...)
+{
+ CURLMcode res = CURLM_OK;
+ va_list param;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ va_start(param, option);
+
+ switch(option) {
+ case CURLMOPT_SOCKETFUNCTION:
+ multi->socket_cb = va_arg(param, curl_socket_callback);
+ break;
+ case CURLMOPT_SOCKETDATA:
+ multi->socket_userp = va_arg(param, void *);
+ break;
+ case CURLMOPT_PUSHFUNCTION:
+ multi->push_cb = va_arg(param, curl_push_callback);
+ break;
+ case CURLMOPT_PUSHDATA:
+ multi->push_userp = va_arg(param, void *);
+ break;
+ case CURLMOPT_PIPELINING:
+ multi->pipelining = va_arg(param, long);
+ break;
+ case CURLMOPT_TIMERFUNCTION:
+ multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+ break;
+ case CURLMOPT_TIMERDATA:
+ multi->timer_userp = va_arg(param, void *);
+ break;
+ case CURLMOPT_MAXCONNECTS:
+ multi->maxconnects = va_arg(param, long);
+ break;
+ case CURLMOPT_MAX_HOST_CONNECTIONS:
+ multi->max_host_connections = va_arg(param, long);
+ break;
+ case CURLMOPT_MAX_PIPELINE_LENGTH:
+ multi->max_pipeline_length = va_arg(param, long);
+ break;
+ case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
+ multi->content_length_penalty_size = va_arg(param, long);
+ break;
+ case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
+ multi->chunk_length_penalty_size = va_arg(param, long);
+ break;
+ case CURLMOPT_PIPELINING_SITE_BL:
+ res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
+ &multi->pipelining_site_bl);
+ break;
+ case CURLMOPT_PIPELINING_SERVER_BL:
+ res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
+ &multi->pipelining_server_bl);
+ break;
+ case CURLMOPT_MAX_TOTAL_CONNECTIONS:
+ multi->max_total_connections = va_arg(param, long);
+ break;
+ default:
+ res = CURLM_UNKNOWN_OPTION;
+ break;
+ }
+ va_end(param);
+ return res;
+}
+
+/* we define curl_multi_socket() in the public multi.h header */
+#undef curl_multi_socket
+
+CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
+ int *running_handles)
+{
+ CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles);
+ if(CURLM_OK >= result)
+ update_timer(multi);
+ return result;
+}
+
+CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
+ int ev_bitmask, int *running_handles)
+{
+ CURLMcode result = multi_socket(multi, FALSE, s,
+ ev_bitmask, running_handles);
+ if(CURLM_OK >= result)
+ update_timer(multi);
+ return result;
+}
+
+CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
+
+{
+ CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0,
+ running_handles);
+ if(CURLM_OK >= result)
+ update_timer(multi);
+ return result;
+}
+
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms)
+{
+ static struct timeval tv_zero = {0, 0};
+
+ if(multi->timetree) {
+ /* we have a tree of expire times */
+ struct timeval now = Curl_tvnow();
+
+ /* splay the lowest to the bottom */
+ multi->timetree = Curl_splay(tv_zero, multi->timetree);
+
+ if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
+ /* some time left before expiration */
+ *timeout_ms = (long)curlx_tvdiff(multi->timetree->key, now);
+ if(!*timeout_ms)
+ /*
+ * Since we only provide millisecond resolution on the returned value
+ * and the diff might be less than one millisecond here, we don't
+ * return zero as that may cause short bursts of busyloops on fast
+ * processors while the diff is still present but less than one
+ * millisecond! instead we return 1 until the time is ripe.
+ */
+ *timeout_ms=1;
+ }
+ else
+ /* 0 means immediately */
+ *timeout_ms = 0;
+ }
+ else
+ *timeout_ms = -1;
+
+ return CURLM_OK;
+}
+
+CURLMcode curl_multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms)
+{
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+static int update_timer(struct Curl_multi *multi)
+{
+ long timeout_ms;
+
+ if(!multi->timer_cb)
+ return 0;
+ if(multi_timeout(multi, &timeout_ms)) {
+ return -1;
+ }
+ if(timeout_ms < 0) {
+ static const struct timeval none={0, 0};
+ if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
+ multi->timer_lastcall = none;
+ /* there's no timeout now but there was one previously, tell the app to
+ disable it */
+ return multi->timer_cb(multi, -1, multi->timer_userp);
+ }
+ return 0;
+ }
+
+ /* When multi_timeout() is done, multi->timetree points to the node with the
+ * timeout we got the (relative) time-out time for. We can thus easily check
+ * if this is the same (fixed) time as we got in a previous call and then
+ * avoid calling the callback again. */
+ if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
+ return 0;
+
+ multi->timer_lastcall = multi->timetree->key;
+
+ return multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+}
+
+/*
+ * multi_deltimeout()
+ *
+ * Remove a given timestamp from the list of timeouts.
+ */
+static void
+multi_deltimeout(struct Curl_easy *data, expire_id eid)
+{
+ struct curl_llist_element *e;
+ struct curl_llist *timeoutlist = &data->state.timeoutlist;
+ /* find and remove the specific node from the list */
+ for(e = timeoutlist->head; e; e = e->next) {
+ struct time_node *n = (struct time_node *)e->ptr;
+ if(n->eid == eid) {
+ Curl_llist_remove(timeoutlist, e, NULL);
+ return;
+ }
+ }
+}
+
+/*
+ * multi_addtimeout()
+ *
+ * Add a timestamp to the list of timeouts. Keep the list sorted so that head
+ * of list is always the timeout nearest in time.
+ *
+ */
+static CURLMcode
+multi_addtimeout(struct Curl_easy *data,
+ struct timeval *stamp,
+ expire_id eid)
+{
+ struct curl_llist_element *e;
+ struct time_node *node;
+ struct curl_llist_element *prev = NULL;
+ size_t n;
+ struct curl_llist *timeoutlist = &data->state.timeoutlist;
+
+ node = &data->state.expires[eid];
+
+ /* copy the timestamp and id */
+ memcpy(&node->time, stamp, sizeof(*stamp));
+ node->eid = eid; /* also marks it as in use */
+
+ n = Curl_llist_count(timeoutlist);
+ if(n) {
+ /* find the correct spot in the list */
+ for(e = timeoutlist->head; e; e = e->next) {
+ struct time_node *check = (struct time_node *)e->ptr;
+ time_t diff = curlx_tvdiff(check->time, node->time);
+ if(diff > 0)
+ break;
+ prev = e;
+ }
+
+ }
+ /* else
+ this is the first timeout on the list */
+
+ Curl_llist_insert_next(timeoutlist, prev, node, &node->list);
+ return CURLM_OK;
+}
+
+/*
+ * Curl_expire()
+ *
+ * given a number of milliseconds from now to use to set the 'act before
+ * this'-time for the transfer, to be extracted by curl_multi_timeout()
+ *
+ * The timeout will be added to a queue of timeouts if it defines a moment in
+ * time that is later than the current head of queue.
+ *
+ * Expire replaces a former timeout using the same id if already set.
+ */
+void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
+{
+ struct Curl_multi *multi = data->multi;
+ struct timeval *nowp = &data->state.expiretime;
+ int rc;
+ struct timeval set;
+
+ /* this is only interesting while there is still an associated multi struct
+ remaining! */
+ if(!multi)
+ return;
+
+ DEBUGASSERT(id < EXPIRE_LAST);
+
+ set = Curl_tvnow();
+ set.tv_sec += (long)(milli/1000);
+ set.tv_usec += (long)(milli%1000)*1000;
+
+ if(set.tv_usec >= 1000000) {
+ set.tv_sec++;
+ set.tv_usec -= 1000000;
+ }
+
+ if(nowp->tv_sec || nowp->tv_usec) {
+ /* This means that the struct is added as a node in the splay tree.
+ Compare if the new time is earlier, and only remove-old/add-new if it
+ is. */
+ time_t diff = curlx_tvdiff(set, *nowp);
+
+ /* remove the previous timer first, if there */
+ multi_deltimeout(data, id);
+
+ if(diff > 0) {
+ /* the new expire time was later so just add it to the queue
+ and get out */
+ multi_addtimeout(data, &set, id);
+ return;
+ }
+
+ /* the new time is newer than the presently set one, so add the current
+ to the queue and update the head */
+ multi_addtimeout(data, nowp, id);
+
+ /* Since this is an updated time, we must remove the previous entry from
+ the splay tree first and then re-add the new value */
+ rc = Curl_splayremovebyaddr(multi->timetree,
+ &data->state.timenode,
+ &multi->timetree);
+ if(rc)
+ infof(data, "Internal error removing splay node = %d\n", rc);
+ }
+
+ *nowp = set;
+ data->state.timenode.payload = data;
+ multi->timetree = Curl_splayinsert(*nowp, multi->timetree,
+ &data->state.timenode);
+}
+
+/*
+ * Curl_expire_done()
+ *
+ * Removes the expire timer. Marks it as done.
+ *
+ */
+void Curl_expire_done(struct Curl_easy *data, expire_id id)
+{
+ /* remove the timer, if there */
+ multi_deltimeout(data, id);
+}
+
+/*
+ * Curl_expire_clear()
+ *
+ * Clear ALL timeout values for this handle.
+ */
+void Curl_expire_clear(struct Curl_easy *data)
+{
+ struct Curl_multi *multi = data->multi;
+ struct timeval *nowp = &data->state.expiretime;
+ int rc;
+
+ /* this is only interesting while there is still an associated multi struct
+ remaining! */
+ if(!multi)
+ return;
+
+ if(nowp->tv_sec || nowp->tv_usec) {
+ /* Since this is an cleared time, we must remove the previous entry from
+ the splay tree */
+ struct curl_llist *list = &data->state.timeoutlist;
+
+ rc = Curl_splayremovebyaddr(multi->timetree,
+ &data->state.timenode,
+ &multi->timetree);
+ if(rc)
+ infof(data, "Internal error clearing splay node = %d\n", rc);
+
+ /* flush the timeout list too */
+ while(list->size > 0) {
+ Curl_llist_remove(list, list->tail, NULL);
+ }
+
+#ifdef DEBUGBUILD
+ infof(data, "Expire cleared\n");
+#endif
+ nowp->tv_sec = 0;
+ nowp->tv_usec = 0;
+ }
+}
+
+
+
+
+CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
+ void *hashp)
+{
+ struct Curl_sh_entry *there = NULL;
+
+ there = sh_getentry(&multi->sockhash, s);
+
+ if(!there)
+ return CURLM_BAD_SOCKET;
+
+ there->socketp = hashp;
+
+ return CURLM_OK;
+}
+
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
+{
+ return multi ? multi->max_host_connections : 0;
+}
+
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
+{
+ return multi ? multi->max_total_connections : 0;
+}
+
+curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
+{
+ return multi ? multi->content_length_penalty_size : 0;
+}
+
+curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
+{
+ return multi ? multi->chunk_length_penalty_size : 0;
+}
+
+struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
+{
+ return &multi->pipelining_site_bl;
+}
+
+struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
+{
+ return &multi->pipelining_server_bl;
+}
+
+void Curl_multi_process_pending_handles(struct Curl_multi *multi)
+{
+ struct curl_llist_element *e = multi->pending.head;
+
+ while(e) {
+ struct Curl_easy *data = e->ptr;
+ struct curl_llist_element *next = e->next;
+
+ if(data->mstate == CURLM_STATE_CONNECT_PEND) {
+ multistate(data, CURLM_STATE_CONNECT);
+
+ /* Remove this node from the list */
+ Curl_llist_remove(&multi->pending, e, NULL);
+
+ /* Make sure that the handle will be processed soonish. */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ }
+
+ e = next; /* operate on next handle */
+ }
+}
+
+#ifdef DEBUGBUILD
+void Curl_multi_dump(struct Curl_multi *multi)
+{
+ struct Curl_easy *data;
+ int i;
+ fprintf(stderr, "* Multi status: %d handles, %d alive\n",
+ multi->num_easy, multi->num_alive);
+ for(data=multi->easyp; data; data = data->next) {
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ /* only display handles that are not completed */
+ fprintf(stderr, "handle %p, state %s, %d sockets\n",
+ (void *)data,
+ statename[data->mstate], data->numsocks);
+ for(i=0; i < data->numsocks; i++) {
+ curl_socket_t s = data->sockets[i];
+ struct Curl_sh_entry *entry = sh_getentry(&multi->sockhash, s);
+
+ fprintf(stderr, "%d ", (int)s);
+ if(!entry) {
+ fprintf(stderr, "INTERNAL CONFUSION\n");
+ continue;
+ }
+ fprintf(stderr, "[%s %s] ",
+ entry->action&CURL_POLL_IN?"RECVING":"",
+ entry->action&CURL_POLL_OUT?"SENDING":"");
+ }
+ if(data->numsocks)
+ fprintf(stderr, "\n");
+ }
+ }
+}
+#endif
diff --git a/Utilities/cmcurl/lib/multihandle.h b/Utilities/cmcurl/lib/multihandle.h
new file mode 100644
index 000000000..e6ffbf5b6
--- /dev/null
+++ b/Utilities/cmcurl/lib/multihandle.h
@@ -0,0 +1,155 @@
+#ifndef HEADER_CURL_MULTIHANDLE_H
+#define HEADER_CURL_MULTIHANDLE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "conncache.h"
+
+struct Curl_message {
+ struct curl_llist_element list;
+ /* the 'CURLMsg' is the part that is visible to the external user */
+ struct CURLMsg extmsg;
+};
+
+/* NOTE: if you add a state here, add the name to the statename[] array as
+ well!
+*/
+typedef enum {
+ CURLM_STATE_INIT, /* 0 - start in this state */
+ CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
+ CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */
+ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */
+ CURLM_STATE_WAITCONNECT, /* 4 - awaiting the TCP connect to finalize */
+ CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization
+ to complete and/or proxy CONNECT to
+ finalize */
+ CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */
+ CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect
+ phase */
+ CURLM_STATE_WAITDO, /* 8 - wait for our turn to send the request */
+ CURLM_STATE_DO, /* 9 - start send off the request (part 1) */
+ CURLM_STATE_DOING, /* 10 - sending off the request (part 1) */
+ CURLM_STATE_DO_MORE, /* 11 - send off the request (part 2) */
+ CURLM_STATE_DO_DONE, /* 12 - done sending off request */
+ CURLM_STATE_WAITPERFORM, /* 13 - wait for our turn to read the response */
+ CURLM_STATE_PERFORM, /* 14 - transfer data */
+ CURLM_STATE_TOOFAST, /* 15 - wait because limit-rate exceeded */
+ CURLM_STATE_DONE, /* 16 - post data transfer operation */
+ CURLM_STATE_COMPLETED, /* 17 - operation complete */
+ CURLM_STATE_MSGSENT, /* 18 - the operation complete message is sent */
+ CURLM_STATE_LAST /* 19 - not a true state, never use this */
+} CURLMstate;
+
+/* we support N sockets per easy handle. Set the corresponding bit to what
+ action we should wait for */
+#define MAX_SOCKSPEREASYHANDLE 5
+#define GETSOCK_READABLE (0x00ff)
+#define GETSOCK_WRITABLE (0xff00)
+
+#define CURLPIPE_ANY (CURLPIPE_HTTP1 | CURLPIPE_MULTIPLEX)
+
+/* This is the struct known as CURLM on the outside */
+struct Curl_multi {
+ /* First a simple identifier to easier detect if a user mix up
+ this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
+ long type;
+
+ /* We have a doubly-linked circular list with easy handles */
+ struct Curl_easy *easyp;
+ struct Curl_easy *easylp; /* last node */
+
+ int num_easy; /* amount of entries in the linked list above. */
+ int num_alive; /* amount of easy handles that are added but have not yet
+ reached COMPLETE state */
+
+ struct curl_llist msglist; /* a list of messages from completed transfers */
+
+ struct curl_llist pending; /* Curl_easys that are in the
+ CURLM_STATE_CONNECT_PEND state */
+
+ /* callback function and user data pointer for the *socket() API */
+ curl_socket_callback socket_cb;
+ void *socket_userp;
+
+ /* callback function and user data pointer for server push */
+ curl_push_callback push_cb;
+ void *push_userp;
+
+ /* Hostname cache */
+ struct curl_hash hostcache;
+
+ /* timetree points to the splay-tree of time nodes to figure out expire
+ times of all currently set timers */
+ struct Curl_tree *timetree;
+
+ /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
+ the pluralis form, there can be more than one easy handle waiting on the
+ same actual socket) */
+ struct curl_hash sockhash;
+
+ /* pipelining wanted bits (CURLPIPE*) */
+ long pipelining;
+
+ bool recheckstate; /* see Curl_multi_connchanged */
+
+ /* Shared connection cache (bundles)*/
+ struct conncache conn_cache;
+
+ /* This handle will be used for closing the cached connections in
+ curl_multi_cleanup() */
+ struct Curl_easy *closure_handle;
+
+ long maxconnects; /* if >0, a fixed limit of the maximum number of entries
+ we're allowed to grow the connection cache to */
+
+ long max_host_connections; /* if >0, a fixed limit of the maximum number
+ of connections per host */
+
+ long max_total_connections; /* if >0, a fixed limit of the maximum number
+ of connections in total */
+
+ long max_pipeline_length; /* if >0, maximum number of requests in a
+ pipeline */
+
+ long content_length_penalty_size; /* a connection with a
+ content-length bigger than
+ this is not considered
+ for pipelining */
+
+ long chunk_length_penalty_size; /* a connection with a chunk length
+ bigger than this is not
+ considered for pipelining */
+
+ struct curl_llist pipelining_site_bl; /* List of sites that are blacklisted
+ from pipelining */
+
+ struct curl_llist pipelining_server_bl; /* List of server types that are
+ blacklisted from pipelining */
+
+ /* timer callback and user data pointer for the *socket() API */
+ curl_multi_timer_callback timer_cb;
+ void *timer_userp;
+ struct timeval timer_lastcall; /* the fixed time for the timeout for the
+ previous callback */
+};
+
+#endif /* HEADER_CURL_MULTIHANDLE_H */
diff --git a/Utilities/cmcurl/lib/multiif.h b/Utilities/cmcurl/lib/multiif.h
new file mode 100644
index 000000000..a877571a0
--- /dev/null
+++ b/Utilities/cmcurl/lib/multiif.h
@@ -0,0 +1,99 @@
+#ifndef HEADER_CURL_MULTIIF_H
+#define HEADER_CURL_MULTIIF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by multi.c
+ */
+
+void Curl_expire(struct Curl_easy *data, time_t milli, expire_id);
+void Curl_expire_clear(struct Curl_easy *data);
+void Curl_expire_done(struct Curl_easy *data, expire_id id);
+bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
+void Curl_multi_handlePipeBreak(struct Curl_easy *data);
+
+/* Internal version of curl_multi_init() accepts size parameters for the
+ socket and connection hashes */
+struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
+
+/* the write bits start at bit 16 for the *getsock() bitmap */
+#define GETSOCK_WRITEBITSTART 16
+
+#define GETSOCK_BLANK 0 /* no bits set */
+
+/* set the bit for the given sock number to make the bitmap for writable */
+#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
+
+/* set the bit for the given sock number to make the bitmap for readable */
+#define GETSOCK_READSOCK(x) (1 << (x))
+
+#ifdef DEBUGBUILD
+ /*
+ * Curl_multi_dump is not a stable public function, this is only meant to
+ * allow easier tracking of the internal handle's state and what sockets
+ * they use. Only for research and development DEBUGBUILD enabled builds.
+ */
+void Curl_multi_dump(struct Curl_multi *multi);
+#endif
+
+void Curl_multi_process_pending_handles(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */
+curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE option */
+curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_PIPELINING_SITE_BL option */
+struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_PIPELINING_SERVER_BL option */
+struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
+
+void Curl_multi_connchanged(struct Curl_multi *multi);
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using is about to be closed. This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
+
+/*
+ * Add a handle and move it into PERFORM state at once. For pushed streams.
+ */
+CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
+ struct Curl_easy *data,
+ struct connectdata *conn);
+#endif /* HEADER_CURL_MULTIIF_H */
diff --git a/Utilities/cmcurl/lib/netrc.c b/Utilities/cmcurl/lib/netrc.c
new file mode 100644
index 000000000..996711d11
--- /dev/null
+++ b/Utilities/cmcurl/lib/netrc.c
@@ -0,0 +1,201 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include <curl/curl.h>
+#include "netrc.h"
+#include "strtok.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Get user and password from .netrc when given a machine name */
+
+enum host_lookup_state {
+ NOTHING,
+ HOSTFOUND, /* the 'machine' keyword was found */
+ HOSTVALID /* this is "our" machine! */
+};
+
+/*
+ * @unittest: 1304
+ *
+ * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
+ * in.
+ */
+int Curl_parsenetrc(const char *host,
+ char **loginp,
+ char **passwordp,
+ char *netrcfile)
+{
+ FILE *file;
+ int retcode=1;
+ int specific_login = (*loginp && **loginp != 0);
+ bool netrc_alloc = FALSE;
+ enum host_lookup_state state=NOTHING;
+
+ char state_login=0; /* Found a login keyword */
+ char state_password=0; /* Found a password keyword */
+ int state_our_login=FALSE; /* With specific_login, found *our* login name */
+
+#define NETRC DOT_CHAR "netrc"
+
+ if(!netrcfile) {
+ bool home_alloc = FALSE;
+ char *home = curl_getenv("HOME"); /* portable environment reader */
+ if(home) {
+ home_alloc = TRUE;
+#if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID)
+ }
+ else {
+ struct passwd pw, *pw_res;
+ char pwbuf[1024];
+ if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res)
+ && pw_res) {
+ home = strdup(pw.pw_dir);
+ if(!home)
+ return CURLE_OUT_OF_MEMORY;
+ home_alloc = TRUE;
+ }
+#elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+ }
+ else {
+ struct passwd *pw;
+ pw= getpwuid(geteuid());
+ if(pw) {
+ home = pw->pw_dir;
+ }
+#endif
+ }
+
+ if(!home)
+ return retcode; /* no home directory found (or possibly out of memory) */
+
+ netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
+ if(home_alloc)
+ free(home);
+ if(!netrcfile) {
+ return -1;
+ }
+ netrc_alloc = TRUE;
+ }
+
+ file = fopen(netrcfile, FOPEN_READTEXT);
+ if(netrc_alloc)
+ free(netrcfile);
+ if(file) {
+ char *tok;
+ char *tok_buf;
+ bool done=FALSE;
+ char netrcbuffer[256];
+ int netrcbuffsize = (int)sizeof(netrcbuffer);
+
+ while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
+ tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
+ while(!done && tok) {
+
+ if((*loginp && **loginp) && (*passwordp && **passwordp)) {
+ done=TRUE;
+ break;
+ }
+
+ switch(state) {
+ case NOTHING:
+ if(strcasecompare("machine", tok)) {
+ /* the next tok is the machine name, this is in itself the
+ delimiter that starts the stuff entered for this machine,
+ after this we need to search for 'login' and
+ 'password'. */
+ state=HOSTFOUND;
+ }
+ else if(strcasecompare("default", tok)) {
+ state=HOSTVALID;
+ retcode=0; /* we did find our host */
+ }
+ break;
+ case HOSTFOUND:
+ if(strcasecompare(host, tok)) {
+ /* and yes, this is our host! */
+ state=HOSTVALID;
+ retcode=0; /* we did find our host */
+ }
+ else
+ /* not our host */
+ state=NOTHING;
+ break;
+ case HOSTVALID:
+ /* we are now parsing sub-keywords concerning "our" host */
+ if(state_login) {
+ if(specific_login) {
+ state_our_login = strcasecompare(*loginp, tok);
+ }
+ else {
+ free(*loginp);
+ *loginp = strdup(tok);
+ if(!*loginp) {
+ retcode = -1; /* allocation failed */
+ goto out;
+ }
+ }
+ state_login=0;
+ }
+ else if(state_password) {
+ if(state_our_login || !specific_login) {
+ free(*passwordp);
+ *passwordp = strdup(tok);
+ if(!*passwordp) {
+ retcode = -1; /* allocation failed */
+ goto out;
+ }
+ }
+ state_password=0;
+ }
+ else if(strcasecompare("login", tok))
+ state_login=1;
+ else if(strcasecompare("password", tok))
+ state_password=1;
+ else if(strcasecompare("machine", tok)) {
+ /* ok, there's machine here go => */
+ state = HOSTFOUND;
+ state_our_login = FALSE;
+ }
+ break;
+ } /* switch (state) */
+
+ tok = strtok_r(NULL, " \t\n", &tok_buf);
+ } /* while(tok) */
+ } /* while fgets() */
+
+ out:
+ fclose(file);
+ }
+
+ return retcode;
+}
diff --git a/Utilities/cmcurl/lib/netrc.h b/Utilities/cmcurl/lib/netrc.h
new file mode 100644
index 000000000..d980166e6
--- /dev/null
+++ b/Utilities/cmcurl/lib/netrc.h
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_NETRC_H
+#define HEADER_CURL_NETRC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
+int Curl_parsenetrc(const char *host,
+ char **loginp,
+ char **passwordp,
+ char *filename);
+ /* Assume: (*passwordp)[0]=0, host[0] != 0.
+ * If (*loginp)[0] = 0, search for login and password within a machine
+ * section in the netrc.
+ * If (*loginp)[0] != 0, search for password within machine and login.
+ */
+
+#endif /* HEADER_CURL_NETRC_H */
diff --git a/Utilities/cmcurl/lib/non-ascii.c b/Utilities/cmcurl/lib/non-ascii.c
new file mode 100644
index 000000000..2f5de4c68
--- /dev/null
+++ b/Utilities/cmcurl/lib/non-ascii.c
@@ -0,0 +1,338 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#include <curl/curl.h>
+
+#include "non-ascii.h"
+#include "formdata.h"
+#include "sendf.h"
+#include "urldata.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+#ifndef CURL_ICONV_CODESET_FOR_UTF8
+#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
+#endif
+#define ICONV_ERROR (size_t)-1
+#endif /* HAVE_ICONV */
+
+/*
+ * Curl_convert_clone() returns a malloced copy of the source string (if
+ * returning CURLE_OK), with the data converted to network format.
+ */
+CURLcode Curl_convert_clone(struct Curl_easy *data,
+ const char *indata,
+ size_t insize,
+ char **outbuf)
+{
+ char *convbuf;
+ CURLcode result;
+
+ convbuf = malloc(insize);
+ if(!convbuf)
+ return CURLE_OUT_OF_MEMORY;
+
+ memcpy(convbuf, indata, insize);
+ result = Curl_convert_to_network(data, convbuf, insize);
+ if(result) {
+ free(convbuf);
+ return result;
+ }
+
+ *outbuf = convbuf; /* return the converted buffer */
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_to_network() is an internal function for performing ASCII
+ * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ */
+CURLcode Curl_convert_to_network(struct Curl_easy *data,
+ char *buffer, size_t length)
+{
+ if(data->set.convtonetwork) {
+ /* use translation callback */
+ CURLcode result = data->set.convtonetwork(buffer, length);
+ if(result) {
+ failf(data,
+ "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
+ (int)result, curl_easy_strerror(result));
+ }
+
+ return result;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->outbound_cd == (iconv_t)-1) {
+ data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(data->outbound_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->outbound_cd, (const char **)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "The Curl_convert_to_network iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_network() is an internal function for performing ASCII
+ * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ */
+CURLcode Curl_convert_from_network(struct Curl_easy *data,
+ char *buffer, size_t length)
+{
+ if(data->set.convfromnetwork) {
+ /* use translation callback */
+ CURLcode result = data->set.convfromnetwork(buffer, length);
+ if(result) {
+ failf(data,
+ "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
+ (int)result, curl_easy_strerror(result));
+ }
+
+ return result;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->inbound_cd == (iconv_t)-1) {
+ data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(data->inbound_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "Curl_convert_from_network iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_utf8() is an internal function for performing UTF-8
+ * conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
+ char *buffer, size_t length)
+{
+ if(data->set.convfromutf8) {
+ /* use translation callback */
+ CURLcode result = data->set.convfromutf8(buffer, length);
+ if(result) {
+ failf(data,
+ "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
+ (int)result, curl_easy_strerror(result));
+ }
+
+ return result;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ const char *input_ptr;
+ char *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->utf8_cd == (iconv_t)-1) {
+ data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+ if(data->utf8_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ if(output_ptr < input_ptr) {
+ /* null terminate the now shorter output string */
+ *output_ptr = 0x00;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Init conversion stuff for a Curl_easy
+ */
+void Curl_convert_init(struct Curl_easy *data)
+{
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+ /* conversion descriptors for iconv calls */
+ data->outbound_cd = (iconv_t)-1;
+ data->inbound_cd = (iconv_t)-1;
+ data->utf8_cd = (iconv_t)-1;
+#else
+ (void)data;
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+}
+
+/*
+ * Setup conversion stuff for a Curl_easy
+ */
+void Curl_convert_setup(struct Curl_easy *data)
+{
+ data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+}
+
+/*
+ * Close conversion stuff for a Curl_easy
+ */
+
+void Curl_convert_close(struct Curl_easy *data)
+{
+#ifdef HAVE_ICONV
+ /* close iconv conversion descriptors */
+ if(data->inbound_cd != (iconv_t)-1) {
+ iconv_close(data->inbound_cd);
+ }
+ if(data->outbound_cd != (iconv_t)-1) {
+ iconv_close(data->outbound_cd);
+ }
+ if(data->utf8_cd != (iconv_t)-1) {
+ iconv_close(data->utf8_cd);
+ }
+#else
+ (void)data;
+#endif /* HAVE_ICONV */
+}
+
+/*
+ * Curl_convert_form() is used from http.c, this converts any form items that
+ need to be sent in the network encoding. Returns CURLE_OK on success.
+ */
+CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form)
+{
+ CURLcode result;
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ while(form) {
+ if(form->type == FORM_DATA) {
+ result = Curl_convert_to_network(data, form->line, form->length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
+ }
+
+ form = form->next;
+ }
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */
diff --git a/Utilities/cmcurl/lib/non-ascii.h b/Utilities/cmcurl/lib/non-ascii.h
new file mode 100644
index 000000000..e27f1f41f
--- /dev/null
+++ b/Utilities/cmcurl/lib/non-ascii.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_NON_ASCII_H
+#define HEADER_CURL_NON_ASCII_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef CURL_DOES_CONVERSIONS
+
+#include "urldata.h"
+
+/*
+ * Curl_convert_clone() returns a malloced copy of the source string (if
+ * returning CURLE_OK), with the data converted to network format.
+ *
+ * If no conversion was needed *outbuf may be NULL.
+ */
+CURLcode Curl_convert_clone(struct Curl_easy *data,
+ const char *indata,
+ size_t insize,
+ char **outbuf);
+
+void Curl_convert_init(struct Curl_easy *data);
+void Curl_convert_setup(struct Curl_easy *data);
+void Curl_convert_close(struct Curl_easy *data);
+
+CURLcode Curl_convert_to_network(struct Curl_easy *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_from_network(struct Curl_easy *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_form(struct Curl_easy *data, struct FormData *form);
+#else
+#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
+#define Curl_convert_init(x) Curl_nop_stmt
+#define Curl_convert_setup(x) Curl_nop_stmt
+#define Curl_convert_close(x) Curl_nop_stmt
+#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_form(a,b) CURLE_OK
+#endif
+
+#endif /* HEADER_CURL_NON_ASCII_H */
diff --git a/Utilities/cmcurl/lib/nonblock.c b/Utilities/cmcurl/lib/nonblock.c
new file mode 100644
index 000000000..5959281e5
--- /dev/null
+++ b/Utilities/cmcurl/lib/nonblock.c
@@ -0,0 +1,90 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "nonblock.h"
+
+/*
+ * curlx_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */)
+{
+#if defined(USE_BLOCKING_SOCKETS)
+
+ return 0; /* returns success */
+
+#elif defined(HAVE_FCNTL_O_NONBLOCK)
+
+ /* most recent unix versions */
+ int flags;
+ flags = sfcntl(sockfd, F_GETFL, 0);
+ if(nonblock)
+ return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+ return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+
+#elif defined(HAVE_IOCTL_FIONBIO)
+
+ /* older unix versions */
+ int flags = nonblock ? 1 : 0;
+ return ioctl(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
+
+ /* Windows */
+ unsigned long flags = nonblock ? 1UL : 0UL;
+ return ioctlsocket(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
+
+ /* Amiga */
+ long flags = nonblock ? 1L : 0L;
+ return IoctlSocket(sockfd, FIONBIO, (char *)&flags);
+
+#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
+
+ /* BeOS */
+ long b = nonblock ? 1L : 0L;
+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+
+#else
+# error "no non-blocking method was found/used/set"
+#endif
+}
diff --git a/Utilities/cmcurl/lib/nonblock.h b/Utilities/cmcurl/lib/nonblock.h
new file mode 100644
index 000000000..98cdc25ab
--- /dev/null
+++ b/Utilities/cmcurl/lib/nonblock.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_NONBLOCK_H
+#define HEADER_CURL_NONBLOCK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h> /* for curl_socket_t */
+
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */);
+
+#endif /* HEADER_CURL_NONBLOCK_H */
+
diff --git a/Utilities/cmcurl/lib/nwlib.c b/Utilities/cmcurl/lib/nwlib.c
new file mode 100644
index 000000000..290cbe31f
--- /dev/null
+++ b/Utilities/cmcurl/lib/nwlib.c
@@ -0,0 +1,327 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef NETWARE /* Novell NetWare */
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to register as a real lib. */
+#include <library.h>
+#include <netware.h>
+#include <screen.h>
+#include <nks/thread.h>
+#include <nks/synch.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef struct
+{
+ int _errno;
+ void *twentybytes;
+} libthreaddata_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ int z;
+ void *tenbytes;
+ NXKey_t perthreadkey; /* if -1, no key obtained... */
+ NXMutex_t *lock;
+} libdata_t;
+
+int gLibId = -1;
+void *gLibHandle = (void *) NULL;
+rtag_t gAllocTag = (rtag_t) NULL;
+NXMutex_t *gLibLock = (NXMutex_t *) NULL;
+
+/* internal library function prototypes... */
+int DisposeLibraryData(void *);
+void DisposeThreadData(void *);
+int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata);
+
+
+int _NonAppStart(void *NLMHandle,
+ void *errorScreen,
+ const char *cmdLine,
+ const char *loadDirPath,
+ size_t uninitializedDataLength,
+ void *NLMFileHandle,
+ int (*readRoutineP)(int conn,
+ void *fileHandle, size_t offset,
+ size_t nbytes,
+ size_t *bytesRead,
+ void *buffer),
+ size_t customDataOffset,
+ size_t customDataSize,
+ int messageCount,
+ const char **messages)
+{
+ NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
+
+#ifndef __GNUC__
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+#endif
+
+ /*
+ * Here we process our command line, post errors (to the error screen),
+ * perform initializations and anything else we need to do before being able
+ * to accept calls into us. If we succeed, we return non-zero and the NetWare
+ * Loader will leave us up, otherwise we fail to load and get dumped.
+ */
+ gAllocTag = AllocateResourceTag(NLMHandle,
+ "<library-name> memory allocations",
+ AllocSignature);
+
+ if(!gAllocTag) {
+ OutputToScreen(errorScreen, "Unable to allocate resource tag for "
+ "library memory allocations.\n");
+ return -1;
+ }
+
+ gLibId = register_library(DisposeLibraryData);
+
+ if(gLibId < -1) {
+ OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
+ return -1;
+ }
+
+ gLibHandle = NLMHandle;
+
+ gLibLock = NXMutexAlloc(0, 0, &liblock);
+
+ if(!gLibLock) {
+ OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Here we clean up any resources we allocated. Resource tags is a big part
+ * of what we created, but NetWare doesn't ask us to free those.
+ */
+void _NonAppStop(void)
+{
+ (void) unregister_library(gLibId);
+ NXMutexFree(gLibLock);
+}
+
+/*
+ * This function cannot be the first in the file for if the file is linked
+ * first, then the check-unload function's offset will be nlmname.nlm+0
+ * which is how to tell that there isn't one. When the check function is
+ * first in the linked objects, it is ambiguous. For this reason, we will
+ * put it inside this file after the stop function.
+ *
+ * Here we check to see if it's alright to ourselves to be unloaded. If not,
+ * we return a non-zero value. Right now, there isn't any reason not to allow
+ * it.
+ */
+int _NonAppCheckUnload(void)
+{
+ return 0;
+}
+
+int GetOrSetUpData(int id, libdata_t **appData,
+ libthreaddata_t **threadData)
+{
+ int err;
+ libdata_t *app_data;
+ libthreaddata_t *thread_data;
+ NXKey_t key;
+ NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
+
+ err = 0;
+ thread_data = (libthreaddata_t *) NULL;
+
+ /*
+ * Attempt to get our data for the application calling us. This is where we
+ * store whatever application-specific information we need to carry in
+ * support of calling applications.
+ */
+ app_data = (libdata_t *) get_app_data(id);
+
+ if(!app_data) {
+ /*
+ * This application hasn't called us before; set up application AND
+ * per-thread data. Of course, just in case a thread from this same
+ * application is calling us simultaneously, we better lock our application
+ * data-creation mutex. We also need to recheck for data after we acquire
+ * the lock because WE might be that other thread that was too late to
+ * create the data and the first thread in will have created it.
+ */
+ NXLock(gLibLock);
+
+ app_data = (libdata_t *) get_app_data(id);
+ if(!app_data) {
+ app_data = malloc(sizeof(libdata_t));
+
+ if(app_data) {
+ memset(app_data, 0, sizeof(libdata_t));
+
+ app_data->tenbytes = malloc(10);
+ app_data->lock = NXMutexAlloc(0, 0, &liblock);
+
+ if(!app_data->tenbytes || !app_data->lock) {
+ if(app_data->lock)
+ NXMutexFree(app_data->lock);
+
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ if(app_data) {
+ /*
+ * Here we burn in the application data that we were trying to get
+ * by calling get_app_data(). Next time we call the first function,
+ * we'll get this data we're just now setting. We also go on here to
+ * establish the per-thread data for the calling thread, something
+ * we'll have to do on each application thread the first time
+ * it calls us.
+ */
+ err = set_app_data(gLibId, app_data);
+
+ if(err) {
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+ else {
+ /* create key for thread-specific data... */
+ err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
+
+ if(err) /* (no more keys left?) */
+ key = -1;
+
+ app_data->perthreadkey = key;
+ }
+ }
+ }
+ }
+
+ NXUnlock(gLibLock);
+ }
+
+ if(app_data) {
+ key = app_data->perthreadkey;
+
+ if(key != -1 /* couldn't create a key? no thread data */
+ && !(err = NXKeyGetValue(key, (void **) &thread_data))
+ && !thread_data) {
+ /*
+ * Allocate the per-thread data for the calling thread. Regardless of
+ * whether there was already application data or not, this may be the
+ * first call by a new thread. The fact that we allocation 20 bytes on
+ * a pointer is not very important, this just helps to demonstrate that
+ * we can have arbitrarily complex per-thread data.
+ */
+ thread_data = malloc(sizeof(libthreaddata_t));
+
+ if(thread_data) {
+ thread_data->_errno = 0;
+ thread_data->twentybytes = malloc(20);
+
+ if(!thread_data->twentybytes) {
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ err = NXKeySetValue(key, thread_data);
+ if(err) {
+ free(thread_data->twentybytes);
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ }
+ }
+ }
+ }
+
+ if(appData)
+ *appData = app_data;
+
+ if(threadData)
+ *threadData = thread_data;
+
+ return err;
+}
+
+int DisposeLibraryData(void *data)
+{
+ if(data) {
+ void *tenbytes = ((libdata_t *) data)->tenbytes;
+
+ free(tenbytes);
+ free(data);
+ }
+
+ return 0;
+}
+
+void DisposeThreadData(void *data)
+{
+ if(data) {
+ void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
+
+ free(twentybytes);
+ free(data);
+ }
+}
+
+#else /* __NOVELL_LIBC__ */
+/* For native CLib-based NLM seems we can do a bit more simple. */
+#include <nwthread.h>
+
+int main(void)
+{
+ /* initialize any globals here... */
+
+ /* do this if any global initializing was done
+ SynchronizeStart();
+ */
+ ExitThread(TSR_THREAD, 0);
+ return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#else /* NETWARE */
+
+#ifdef __POCC__
+# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */
+#endif
+
+#endif /* NETWARE */
diff --git a/Utilities/cmcurl/lib/nwos.c b/Utilities/cmcurl/lib/nwos.c
new file mode 100644
index 000000000..c6c22ccbb
--- /dev/null
+++ b/Utilities/cmcurl/lib/nwos.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef NETWARE /* Novell NetWare */
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to do nothing. */
+int netware_init(void)
+{
+ return 0;
+}
+
+#else /* __NOVELL_LIBC__ */
+
+/* For native CLib-based NLM we need to initialize the LONG namespace. */
+#include <nwnspace.h>
+#include <nwthread.h>
+#include <nwadv.h>
+/* Make the CLIB Ctx stuff link */
+#include <netdb.h>
+NETDB_DEFINE_CONTEXT
+/* Make the CLIB Inet stuff link */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+NETINET_DEFINE_CONTEXT
+
+int netware_init(void)
+{
+ int rc = 0;
+ unsigned int myHandle = GetNLMHandle();
+ /* import UnAugmentAsterisk dynamically for NW4.x compatibility */
+ void (*pUnAugmentAsterisk)(int) = (void(*)(int))
+ ImportSymbol(myHandle, "UnAugmentAsterisk");
+ /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */
+ void (*pUseAccurateCaseForPaths)(int) = (void(*)(int))
+ ImportSymbol(myHandle, "UseAccurateCaseForPaths");
+ if(pUnAugmentAsterisk)
+ pUnAugmentAsterisk(1);
+ if(pUseAccurateCaseForPaths)
+ pUseAccurateCaseForPaths(1);
+ UnimportSymbol(myHandle, "UnAugmentAsterisk");
+ UnimportSymbol(myHandle, "UseAccurateCaseForPaths");
+ /* set long name space */
+ if((SetCurrentNameSpace(4) == 255)) {
+ rc = 1;
+ }
+ if((SetTargetNameSpace(4) == 255)) {
+ rc = rc + 2;
+ }
+ return rc;
+}
+
+/* dummy function to satisfy newer prelude */
+int __init_environment(void)
+{
+ return 0;
+}
+
+/* dummy function to satisfy newer prelude */
+int __deinit_environment(void)
+{
+ return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#endif /* NETWARE */
diff --git a/Utilities/cmcurl/lib/openldap.c b/Utilities/cmcurl/lib/openldap.c
new file mode 100644
index 000000000..4b8cfb9c2
--- /dev/null
+++ b/Utilities/cmcurl/lib/openldap.c
@@ -0,0 +1,711 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
+ * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+#include <ldap.h>
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "vtls/vtls.h"
+#include "transfer.h"
+#include "curl_ldap.h"
+#include "curl_base64.h"
+#include "connect.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef _LDAP_PVT_H
+extern int ldap_pvt_url_scheme2proto(const char *);
+extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
+ LDAP **ld);
+#endif
+
+static CURLcode ldap_setup_connection(struct connectdata *conn);
+static CURLcode ldap_do(struct connectdata *conn, bool *done);
+static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
+static CURLcode ldap_connect(struct connectdata *conn, bool *done);
+static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
+static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
+
+static Curl_recv ldap_recv;
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+ "LDAP", /* scheme */
+ ldap_setup_connection, /* setup_connection */
+ ldap_do, /* do_it */
+ ldap_done, /* done */
+ ZERO_NULL, /* do_more */
+ ldap_connect, /* connect_it */
+ ldap_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ldap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAP, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+ "LDAPS", /* scheme */
+ ldap_setup_connection, /* setup_connection */
+ ldap_do, /* do_it */
+ ldap_done, /* done */
+ ZERO_NULL, /* do_more */
+ ldap_connect, /* connect_it */
+ ldap_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ldap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAPS, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#endif
+
+static const char *url_errs[] = {
+ "success",
+ "out of memory",
+ "bad parameter",
+ "unrecognized scheme",
+ "unbalanced delimiter",
+ "bad URL",
+ "bad host or port",
+ "bad or missing attributes",
+ "bad or missing scope",
+ "bad or missing filter",
+ "bad or missing extensions"
+};
+
+typedef struct ldapconninfo {
+ LDAP *ld;
+ Curl_recv *recv; /* for stacking SSL handler */
+ Curl_send *send;
+ int proto;
+ int msgid;
+ bool ssldone;
+ bool sslinst;
+ bool didbind;
+} ldapconninfo;
+
+typedef struct ldapreqinfo {
+ int msgid;
+ int nument;
+} ldapreqinfo;
+
+static CURLcode ldap_setup_connection(struct connectdata *conn)
+{
+ ldapconninfo *li;
+ LDAPURLDesc *lud;
+ struct Curl_easy *data=conn->data;
+ int rc, proto;
+ CURLcode status;
+
+ rc = ldap_url_parse(data->change.url, &lud);
+ if(rc != LDAP_URL_SUCCESS) {
+ const char *msg = "url parsing problem";
+ status = CURLE_URL_MALFORMAT;
+ if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
+ if(rc == LDAP_URL_ERR_MEM)
+ status = CURLE_OUT_OF_MEMORY;
+ msg = url_errs[rc];
+ }
+ failf(conn->data, "LDAP local: %s", msg);
+ return status;
+ }
+ proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
+ ldap_free_urldesc(lud);
+
+ li = calloc(1, sizeof(ldapconninfo));
+ if(!li)
+ return CURLE_OUT_OF_MEMORY;
+ li->proto = proto;
+ conn->proto.generic = li;
+ connkeep(conn, "OpenLDAP default");
+ /* TODO:
+ * - provide option to choose SASL Binds instead of Simple
+ */
+ return CURLE_OK;
+}
+
+#ifdef USE_SSL
+static Sockbuf_IO ldapsb_tls;
+#endif
+
+static CURLcode ldap_connect(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct Curl_easy *data = conn->data;
+ int rc, proto = LDAP_VERSION3;
+ char hosturl[1024];
+ char *ptr;
+
+ (void)done;
+
+ strcpy(hosturl, "ldap");
+ ptr = hosturl+4;
+ if(conn->handler->flags & PROTOPT_SSL)
+ *ptr++ = 's';
+ snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
+ conn->host.name, conn->remote_port);
+
+ rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
+ if(rc) {
+ failf(data, "LDAP local: Cannot connect to %s, %s",
+ hosturl, ldap_err2string(rc));
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+
+#ifdef USE_SSL
+ if(conn->handler->flags & PROTOPT_SSL) {
+ CURLcode result;
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+ if(result)
+ return result;
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct Curl_easy *data = conn->data;
+ LDAPMessage *msg = NULL;
+ struct timeval tv = {0, 1}, *tvp;
+ int rc, err;
+ char *info = NULL;
+
+#ifdef USE_SSL
+ if(conn->handler->flags & PROTOPT_SSL) {
+ /* Is the SSL handshake complete yet? */
+ if(!li->ssldone) {
+ CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+ &li->ssldone);
+ if(result || !li->ssldone)
+ return result;
+ }
+
+ /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
+ if(!li->sslinst) {
+ Sockbuf *sb;
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
+ li->sslinst = TRUE;
+ li->recv = conn->recv[FIRSTSOCKET];
+ li->send = conn->send[FIRSTSOCKET];
+ }
+ }
+#endif
+
+ tvp = &tv;
+
+retry:
+ if(!li->didbind) {
+ char *binddn;
+ struct berval passwd;
+
+ if(conn->bits.user_passwd) {
+ binddn = conn->user;
+ passwd.bv_val = conn->passwd;
+ passwd.bv_len = strlen(passwd.bv_val);
+ }
+ else {
+ binddn = NULL;
+ passwd.bv_val = NULL;
+ passwd.bv_len = 0;
+ }
+ rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
+ NULL, NULL, &li->msgid);
+ if(rc)
+ return CURLE_LDAP_CANNOT_BIND;
+ li->didbind = TRUE;
+ if(tvp)
+ return CURLE_OK;
+ }
+
+ rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
+ if(rc < 0) {
+ failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
+ return CURLE_LDAP_CANNOT_BIND;
+ }
+ if(rc == 0) {
+ /* timed out */
+ return CURLE_OK;
+ }
+
+ rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
+ if(rc) {
+ failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
+ return CURLE_LDAP_CANNOT_BIND;
+ }
+
+ /* Try to fallback to LDAPv2? */
+ if(err == LDAP_PROTOCOL_ERROR) {
+ int proto;
+ ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ if(proto == LDAP_VERSION3) {
+ if(info) {
+ ldap_memfree(info);
+ info = NULL;
+ }
+ proto = LDAP_VERSION2;
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ li->didbind = FALSE;
+ goto retry;
+ }
+ }
+
+ if(err) {
+ failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
+ info ? info : "");
+ if(info)
+ ldap_memfree(info);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ if(info)
+ ldap_memfree(info);
+ conn->recv[FIRSTSOCKET] = ldap_recv;
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ ldapconninfo *li = conn->proto.generic;
+ (void) dead_connection;
+
+ if(li) {
+ if(li->ld) {
+ ldap_unbind_ext(li->ld, NULL, NULL);
+ li->ld = NULL;
+ }
+ conn->proto.generic = NULL;
+ free(li);
+ }
+ return CURLE_OK;
+}
+
+static CURLcode ldap_do(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ ldapreqinfo *lr;
+ CURLcode status = CURLE_OK;
+ int rc = 0;
+ LDAPURLDesc *ludp = NULL;
+ int msgid;
+ struct Curl_easy *data=conn->data;
+
+ connkeep(conn, "OpenLDAP do");
+
+ infof(data, "LDAP local: %s\n", data->change.url);
+
+ rc = ldap_url_parse(data->change.url, &ludp);
+ if(rc != LDAP_URL_SUCCESS) {
+ const char *msg = "url parsing problem";
+ status = CURLE_URL_MALFORMAT;
+ if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
+ if(rc == LDAP_URL_ERR_MEM)
+ status = CURLE_OUT_OF_MEMORY;
+ msg = url_errs[rc];
+ }
+ failf(conn->data, "LDAP local: %s", msg);
+ return status;
+ }
+
+ rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0,
+ NULL, NULL, NULL, 0, &msgid);
+ ldap_free_urldesc(ludp);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
+ return CURLE_LDAP_SEARCH_FAILED;
+ }
+ lr = calloc(1, sizeof(ldapreqinfo));
+ if(!lr)
+ return CURLE_OUT_OF_MEMORY;
+ lr->msgid = msgid;
+ data->req.protop = lr;
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ *done = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+ bool premature)
+{
+ ldapreqinfo *lr = conn->data->req.protop;
+
+ (void)res;
+ (void)premature;
+
+ if(lr) {
+ /* if there was a search in progress, abandon it */
+ if(lr->msgid) {
+ ldapconninfo *li = conn->proto.generic;
+ ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
+ lr->msgid = 0;
+ }
+ conn->data->req.protop = NULL;
+ free(lr);
+ }
+
+ return CURLE_OK;
+}
+
+static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
+ size_t len, CURLcode *err)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct Curl_easy *data = conn->data;
+ ldapreqinfo *lr = data->req.protop;
+ int rc, ret;
+ LDAPMessage *msg = NULL;
+ LDAPMessage *ent;
+ BerElement *ber = NULL;
+ struct timeval tv = {0, 1};
+
+ (void)len;
+ (void)buf;
+ (void)sockindex;
+
+ rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
+ if(rc < 0) {
+ failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ *err = CURLE_AGAIN;
+ ret = -1;
+
+ /* timed out */
+ if(!msg)
+ return ret;
+
+ for(ent = ldap_first_message(li->ld, msg); ent;
+ ent = ldap_next_message(li->ld, ent)) {
+ struct berval bv, *bvals, **bvp = &bvals;
+ int binary = 0, msgtype;
+ CURLcode writeerr;
+
+ msgtype = ldap_msgtype(ent);
+ if(msgtype == LDAP_RES_SEARCH_RESULT) {
+ int code;
+ char *info = NULL;
+ rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
+ if(rc) {
+ failf(data, "LDAP local: search ldap_parse_result %s",
+ ldap_err2string(rc));
+ *err = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
+ failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
+ info ? info : "");
+ *err = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else {
+ /* successful */
+ if(code == LDAP_SIZELIMIT_EXCEEDED)
+ infof(data, "There are more than %d entries\n", lr->nument);
+ data->req.size = data->req.bytecount;
+ *err = CURLE_OK;
+ ret = 0;
+ }
+ lr->msgid = 0;
+ ldap_memfree(info);
+ break;
+ }
+ else if(msgtype != LDAP_RES_SEARCH_ENTRY)
+ continue;
+
+ lr->nument++;
+ rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
+ if(rc < 0) {
+ /* TODO: verify that this is really how this return code should be
+ handled */
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+ bv.bv_len);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+ data->req.bytecount += bv.bv_len + 5;
+
+ for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
+ rc == LDAP_SUCCESS;
+ rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) {
+ int i;
+
+ if(bv.bv_val == NULL) break;
+
+ if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
+ binary = 1;
+ else
+ binary = 0;
+
+ for(i=0; bvals[i].bv_val != NULL; i++) {
+ int binval = 0;
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+ bv.bv_len);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+ data->req.bytecount += bv.bv_len + 2;
+
+ if(!binary) {
+ /* check for leading or trailing whitespace */
+ if(ISSPACE(bvals[i].bv_val[0]) ||
+ ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
+ binval = 1;
+ else {
+ /* check for unprintable characters */
+ unsigned int j;
+ for(j=0; j<bvals[i].bv_len; j++)
+ if(!ISPRINT(bvals[i].bv_val[j])) {
+ binval = 1;
+ break;
+ }
+ }
+ }
+ if(binary || binval) {
+ char *val_b64 = NULL;
+ size_t val_b64_sz = 0;
+ /* Binary value, encode to base64. */
+ CURLcode error = Curl_base64_encode(data,
+ bvals[i].bv_val,
+ bvals[i].bv_len,
+ &val_b64,
+ &val_b64_sz);
+ if(error) {
+ ber_memfree(bvals);
+ ber_free(ber, 0);
+ ldap_msgfree(msg);
+ *err = error;
+ return -1;
+ }
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *)": ", 2);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ data->req.bytecount += 2;
+ if(val_b64_sz > 0) {
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+ val_b64_sz);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+ free(val_b64);
+ data->req.bytecount += val_b64_sz;
+ }
+ }
+ else {
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
+ bvals[i].bv_len);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ data->req.bytecount += bvals[i].bv_len + 1;
+ }
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+
+ data->req.bytecount++;
+ }
+ ber_memfree(bvals);
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+ data->req.bytecount++;
+ }
+ writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ if(writeerr) {
+ *err = writeerr;
+ return -1;
+ }
+ data->req.bytecount++;
+ ber_free(ber, 0);
+ }
+ ldap_msgfree(msg);
+ return ret;
+}
+
+#ifdef USE_SSL
+static int
+ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+ sbiod->sbiod_pvt = arg;
+ return 0;
+}
+
+static int
+ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
+{
+ sbiod->sbiod_pvt = NULL;
+ return 0;
+}
+
+/* We don't need to do anything because libcurl does it already */
+static int
+ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
+{
+ (void)sbiod;
+ return 0;
+}
+
+static int
+ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+ (void)arg;
+ if(opt == LBER_SB_OPT_DATA_READY) {
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ return Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ }
+ return 0;
+}
+
+static ber_slen_t
+ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ ldapconninfo *li = conn->proto.generic;
+ ber_slen_t ret;
+ CURLcode err = CURLE_RECV_ERROR;
+
+ ret = li->recv(conn, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ return ret;
+}
+
+static ber_slen_t
+ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ ldapconninfo *li = conn->proto.generic;
+ ber_slen_t ret;
+ CURLcode err = CURLE_SEND_ERROR;
+
+ ret = li->send(conn, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ return ret;
+}
+
+static Sockbuf_IO ldapsb_tls =
+{
+ ldapsb_tls_setup,
+ ldapsb_tls_remove,
+ ldapsb_tls_ctrl,
+ ldapsb_tls_read,
+ ldapsb_tls_write,
+ ldapsb_tls_close
+};
+#endif /* USE_SSL */
+
+#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
diff --git a/Utilities/cmcurl/lib/parsedate.c b/Utilities/cmcurl/lib/parsedate.c
new file mode 100644
index 000000000..3c783be48
--- /dev/null
+++ b/Utilities/cmcurl/lib/parsedate.c
@@ -0,0 +1,585 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+/*
+ A brief summary of the date string formats this parser groks:
+
+ RFC 2616 3.3.1
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ we support dates without week day name:
+
+ 06 Nov 1994 08:49:37 GMT
+ 06-Nov-94 08:49:37 GMT
+ Nov 6 08:49:37 1994
+
+ without the time zone:
+
+ 06 Nov 1994 08:49:37
+ 06-Nov-94 08:49:37
+
+ weird order:
+
+ 1994 Nov 6 08:49:37 (GNU date fails)
+ GMT 08:49:37 06-Nov-94 Sunday
+ 94 6 Nov 08:49:37 (GNU date fails)
+
+ time left out:
+
+ 1994 Nov 6
+ 06-Nov-94
+ Sun Nov 6 94
+
+ unusual separators:
+
+ 1994.Nov.6
+ Sun/Nov/6/94/GMT
+
+ commonly used time zone names:
+
+ Sun, 06 Nov 1994 08:49:37 CET
+ 06 Nov 1994 08:49:37 EST
+
+ time zones specified using RFC822 style:
+
+ Sun, 12 Sep 2004 15:05:58 -0700
+ Sat, 11 Sep 2004 21:32:11 +0200
+
+ compact numerical date strings:
+
+ 20040912 15:05:58 -0700
+ 20040911 +0200
+
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "strcase.h"
+#include "warnless.h"
+#include "parsedate.h"
+
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday", "Sunday" };
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+struct tzinfo {
+ char name[5];
+ int offset; /* +/- in minutes */
+};
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK - a fine conversion
+ * PARSEDATE_FAIL - failed to convert
+ * PARSEDATE_LATER - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK 0
+#define PARSEDATE_FAIL -1
+#define PARSEDATE_LATER 1
+#define PARSEDATE_SOONER 2
+
+/* Here's a bunch of frequently used time zone names. These were supported
+ by the old getdate parser. */
+#define tDAYZONE -60 /* offset for daylight savings time */
+static const struct tzinfo tz[]= {
+ {"GMT", 0}, /* Greenwich Mean */
+ {"UTC", 0}, /* Universal (Coordinated) */
+ {"WET", 0}, /* Western European */
+ {"BST", 0 tDAYZONE}, /* British Summer */
+ {"WAT", 60}, /* West Africa */
+ {"AST", 240}, /* Atlantic Standard */
+ {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */
+ {"EST", 300}, /* Eastern Standard */
+ {"EDT", 300 tDAYZONE}, /* Eastern Daylight */
+ {"CST", 360}, /* Central Standard */
+ {"CDT", 360 tDAYZONE}, /* Central Daylight */
+ {"MST", 420}, /* Mountain Standard */
+ {"MDT", 420 tDAYZONE}, /* Mountain Daylight */
+ {"PST", 480}, /* Pacific Standard */
+ {"PDT", 480 tDAYZONE}, /* Pacific Daylight */
+ {"YST", 540}, /* Yukon Standard */
+ {"YDT", 540 tDAYZONE}, /* Yukon Daylight */
+ {"HST", 600}, /* Hawaii Standard */
+ {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */
+ {"CAT", 600}, /* Central Alaska */
+ {"AHST", 600}, /* Alaska-Hawaii Standard */
+ {"NT", 660}, /* Nome */
+ {"IDLW", 720}, /* International Date Line West */
+ {"CET", -60}, /* Central European */
+ {"MET", -60}, /* Middle European */
+ {"MEWT", -60}, /* Middle European Winter */
+ {"MEST", -60 tDAYZONE}, /* Middle European Summer */
+ {"CEST", -60 tDAYZONE}, /* Central European Summer */
+ {"MESZ", -60 tDAYZONE}, /* Middle European Summer */
+ {"FWT", -60}, /* French Winter */
+ {"FST", -60 tDAYZONE}, /* French Summer */
+ {"EET", -120}, /* Eastern Europe, USSR Zone 1 */
+ {"WAST", -420}, /* West Australian Standard */
+ {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
+ {"CCT", -480}, /* China Coast, USSR Zone 7 */
+ {"JST", -540}, /* Japan Standard, USSR Zone 8 */
+ {"EAST", -600}, /* Eastern Australian Standard */
+ {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
+ {"GST", -600}, /* Guam Standard, USSR Zone 9 */
+ {"NZT", -720}, /* New Zealand */
+ {"NZST", -720}, /* New Zealand Standard */
+ {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
+ {"IDLE", -720}, /* International Date Line East */
+ /* Next up: Military timezone names. RFC822 allowed these, but (as noted in
+ RFC 1123) had their signs wrong. Here we use the correct signs to match
+ actual military usage.
+ */
+ {"A", +1 * 60}, /* Alpha */
+ {"B", +2 * 60}, /* Bravo */
+ {"C", +3 * 60}, /* Charlie */
+ {"D", +4 * 60}, /* Delta */
+ {"E", +5 * 60}, /* Echo */
+ {"F", +6 * 60}, /* Foxtrot */
+ {"G", +7 * 60}, /* Golf */
+ {"H", +8 * 60}, /* Hotel */
+ {"I", +9 * 60}, /* India */
+ /* "J", Juliet is not used as a timezone, to indicate the observer's local
+ time */
+ {"K", +10 * 60}, /* Kilo */
+ {"L", +11 * 60}, /* Lima */
+ {"M", +12 * 60}, /* Mike */
+ {"N", -1 * 60}, /* November */
+ {"O", -2 * 60}, /* Oscar */
+ {"P", -3 * 60}, /* Papa */
+ {"Q", -4 * 60}, /* Quebec */
+ {"R", -5 * 60}, /* Romeo */
+ {"S", -6 * 60}, /* Sierra */
+ {"T", -7 * 60}, /* Tango */
+ {"U", -8 * 60}, /* Uniform */
+ {"V", -9 * 60}, /* Victor */
+ {"W", -10 * 60}, /* Whiskey */
+ {"X", -11 * 60}, /* X-ray */
+ {"Y", -12 * 60}, /* Yankee */
+ {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */
+};
+
+/* returns:
+ -1 no day
+ 0 monday - 6 sunday
+*/
+
+static int checkday(const char *check, size_t len)
+{
+ int i;
+ const char * const *what;
+ bool found= FALSE;
+ if(len > 3)
+ what = &weekday[0];
+ else
+ what = &Curl_wkday[0];
+ for(i=0; i<7; i++) {
+ if(strcasecompare(check, what[0])) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?i:-1;
+}
+
+static int checkmonth(const char *check)
+{
+ int i;
+ const char * const *what;
+ bool found= FALSE;
+
+ what = &Curl_month[0];
+ for(i=0; i<12; i++) {
+ if(strcasecompare(check, what[0])) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?i:-1; /* return the offset or -1, no real offset is -1 */
+}
+
+/* return the time zone offset between GMT and the input one, in number
+ of seconds or -1 if the timezone wasn't found/legal */
+
+static int checktz(const char *check)
+{
+ unsigned int i;
+ const struct tzinfo *what;
+ bool found= FALSE;
+
+ what = tz;
+ for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+ if(strcasecompare(check, what->name)) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?what->offset*60:-1;
+}
+
+static void skip(const char **date)
+{
+ /* skip everything that aren't letters or digits */
+ while(**date && !ISALNUM(**date))
+ (*date)++;
+}
+
+enum assume {
+ DATE_MDAY,
+ DATE_YEAR,
+ DATE_TIME
+};
+
+/* this is a clone of 'struct tm' but with all fields we don't need or use
+ cut out */
+struct my_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+};
+
+/* struct tm to time since epoch in GMT time zone.
+ * This is similar to the standard mktime function but for GMT only, and
+ * doesn't suffer from the various bugs and portability problems that
+ * some systems' implementations have.
+ */
+static time_t my_timegm(struct my_tm *tm)
+{
+ static const int month_days_cumulative [12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int month, year, leap_days;
+
+ if(tm->tm_year < 70)
+ /* we don't support years before 1970 as they will cause this function
+ to return a negative value */
+ return -1;
+
+ year = tm->tm_year + 1900;
+ month = tm->tm_mon;
+ if(month < 0) {
+ year += (11 - month) / 12;
+ month = 11 - (11 - month) % 12;
+ }
+ else if(month >= 12) {
+ year -= month / 12;
+ month = month % 12;
+ }
+
+ leap_days = year - (tm->tm_mon <= 1);
+ leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
+ - (1969 / 4) + (1969 / 100) - (1969 / 400));
+
+ return ((((time_t) (year - 1970) * 365
+ + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
+ + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+}
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK - a fine conversion
+ * PARSEDATE_FAIL - failed to convert
+ * PARSEDATE_LATER - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output)
+{
+ time_t t = 0;
+ int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
+ int monnum=-1; /* month of the year number, 0-11 */
+ int mdaynum=-1; /* day of month, 1 - 31 */
+ int hournum=-1;
+ int minnum=-1;
+ int secnum=-1;
+ int yearnum=-1;
+ int tzoff=-1;
+ struct my_tm tm;
+ enum assume dignext = DATE_MDAY;
+ const char *indate = date; /* save the original pointer */
+ int part = 0; /* max 6 parts */
+
+ while(*date && (part < 6)) {
+ bool found=FALSE;
+
+ skip(&date);
+
+ if(ISALPHA(*date)) {
+ /* a name coming up */
+ char buf[32]="";
+ size_t len;
+ if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz]", buf))
+ len = strlen(buf);
+ else
+ len = 0;
+
+ if(wdaynum == -1) {
+ wdaynum = checkday(buf, len);
+ if(wdaynum != -1)
+ found = TRUE;
+ }
+ if(!found && (monnum == -1)) {
+ monnum = checkmonth(buf);
+ if(monnum != -1)
+ found = TRUE;
+ }
+
+ if(!found && (tzoff == -1)) {
+ /* this just must be a time zone string */
+ tzoff = checktz(buf);
+ if(tzoff != -1)
+ found = TRUE;
+ }
+
+ if(!found)
+ return PARSEDATE_FAIL; /* bad string */
+
+ date += len;
+ }
+ else if(ISDIGIT(*date)) {
+ /* a digit */
+ int val;
+ char *end;
+ int len=0;
+ if((secnum == -1) &&
+ (3 == sscanf(date, "%02d:%02d:%02d%n",
+ &hournum, &minnum, &secnum, &len))) {
+ /* time stamp! */
+ date += len;
+ }
+ else if((secnum == -1) &&
+ (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
+ /* time stamp without seconds */
+ date += len;
+ secnum = 0;
+ }
+ else {
+ long lval;
+ int error;
+ int old_errno;
+
+ old_errno = ERRNO;
+ SET_ERRNO(0);
+ lval = strtol(date, &end, 10);
+ error = ERRNO;
+ if(error != old_errno)
+ SET_ERRNO(old_errno);
+
+ if(error)
+ return PARSEDATE_FAIL;
+
+#if LONG_MAX != INT_MAX
+ if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
+ return PARSEDATE_FAIL;
+#endif
+
+ val = curlx_sltosi(lval);
+
+ if((tzoff == -1) &&
+ ((end - date) == 4) &&
+ (val <= 1400) &&
+ (indate< date) &&
+ ((date[-1] == '+' || date[-1] == '-'))) {
+ /* four digits and a value less than or equal to 1400 (to take into
+ account all sorts of funny time zone diffs) and it is preceded
+ with a plus or minus. This is a time zone indication. 1400 is
+ picked since +1300 is frequently used and +1400 is mentioned as
+ an edge number in the document "ISO C 200X Proposal: Timezone
+ Functions" at http://david.tribble.com/text/c0xtimezone.html If
+ anyone has a more authoritative source for the exact maximum time
+ zone offsets, please speak up! */
+ found = TRUE;
+ tzoff = (val/100 * 60 + val%100)*60;
+
+ /* the + and - prefix indicates the local time compared to GMT,
+ this we need ther reversed math to get what we want */
+ tzoff = date[-1]=='+'?-tzoff:tzoff;
+ }
+
+ if(((end - date) == 8) &&
+ (yearnum == -1) &&
+ (monnum == -1) &&
+ (mdaynum == -1)) {
+ /* 8 digits, no year, month or day yet. This is YYYYMMDD */
+ found = TRUE;
+ yearnum = val/10000;
+ monnum = (val%10000)/100-1; /* month is 0 - 11 */
+ mdaynum = val%100;
+ }
+
+ if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
+ if((val > 0) && (val<32)) {
+ mdaynum = val;
+ found = TRUE;
+ }
+ dignext = DATE_YEAR;
+ }
+
+ if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
+ yearnum = val;
+ found = TRUE;
+ if(yearnum < 1900) {
+ if(yearnum > 70)
+ yearnum += 1900;
+ else
+ yearnum += 2000;
+ }
+ if(mdaynum == -1)
+ dignext = DATE_MDAY;
+ }
+
+ if(!found)
+ return PARSEDATE_FAIL;
+
+ date = end;
+ }
+ }
+
+ part++;
+ }
+
+ if(-1 == secnum)
+ secnum = minnum = hournum = 0; /* no time, make it zero */
+
+ if((-1 == mdaynum) ||
+ (-1 == monnum) ||
+ (-1 == yearnum))
+ /* lacks vital info, fail */
+ return PARSEDATE_FAIL;
+
+#if SIZEOF_TIME_T < 5
+ /* 32 bit time_t can only hold dates to the beginning of 2038 */
+ if(yearnum > 2037) {
+ *output = 0x7fffffff;
+ return PARSEDATE_LATER;
+ }
+#endif
+
+ if(yearnum < 1970) {
+ *output = 0;
+ return PARSEDATE_SOONER;
+ }
+
+ if((mdaynum > 31) || (monnum > 11) ||
+ (hournum > 23) || (minnum > 59) || (secnum > 60))
+ return PARSEDATE_FAIL; /* clearly an illegal date */
+
+ tm.tm_sec = secnum;
+ tm.tm_min = minnum;
+ tm.tm_hour = hournum;
+ tm.tm_mday = mdaynum;
+ tm.tm_mon = monnum;
+ tm.tm_year = yearnum - 1900;
+
+ /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
+ architectures that feature 64 bit 'long'.
+
+ Some systems have 64 bit time_t and deal with years beyond 2038. However,
+ even on some of the systems with 64 bit time_t mktime() returns -1 for
+ dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+ */
+ t = my_timegm(&tm);
+
+ /* time zone adjust (cast t to int to compare to negative one) */
+ if(-1 != (int)t) {
+
+ /* Add the time zone diff between local time zone and GMT. */
+ long delta = (long)(tzoff!=-1?tzoff:0);
+
+ if((delta>0) && (t > LONG_MAX - delta)) {
+ *output = 0x7fffffff;
+ return PARSEDATE_LATER; /* time_t overflow */
+ }
+
+ t += delta;
+ }
+
+ *output = t;
+
+ return PARSEDATE_OK;
+}
+
+time_t curl_getdate(const char *p, const time_t *now)
+{
+ time_t parsed = -1;
+ int rc = parsedate(p, &parsed);
+ (void)now; /* legacy argument from the past that we ignore */
+
+ switch(rc) {
+ case PARSEDATE_OK:
+ case PARSEDATE_LATER:
+ case PARSEDATE_SOONER:
+ return parsed;
+ }
+ /* everything else is fail */
+ return -1;
+}
+
+/*
+ * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
+ * gmtime_r() or gmtime() functions anywhere else but here.
+ *
+ */
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store)
+{
+ const struct tm *tm;
+#ifdef HAVE_GMTIME_R
+ /* thread-safe version */
+ tm = (struct tm *)gmtime_r(&intime, store);
+#else
+ tm = gmtime(&intime);
+ if(tm)
+ *store = *tm; /* copy the pointed struct to the local copy */
+#endif
+
+ if(!tm)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/lib/parsedate.h b/Utilities/cmcurl/lib/parsedate.h
new file mode 100644
index 000000000..2e59eb17c
--- /dev/null
+++ b/Utilities/cmcurl/lib/parsedate.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_PARSEDATE_H
+#define HEADER_CURL_PARSEDATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+extern const char * const Curl_wkday[7];
+extern const char * const Curl_month[12];
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store);
+
+#endif /* HEADER_CURL_PARSEDATE_H */
+
diff --git a/Utilities/cmcurl/lib/pingpong.c b/Utilities/cmcurl/lib/pingpong.c
new file mode 100644
index 000000000..5ed79b718
--- /dev/null
+++ b/Utilities/cmcurl/lib/pingpong.c
@@ -0,0 +1,513 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * 'pingpong' is for generic back-and-forth support functions used by FTP,
+ * IMAP, POP3, SMTP and whatever more that likes them.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "progress.h"
+#include "speedcheck.h"
+#include "pingpong.h"
+#include "multiif.h"
+#include "non-ascii.h"
+#include "vtls/vtls.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef USE_PINGPONG
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+ triggered */
+time_t Curl_pp_state_timeout(struct pingpong *pp)
+{
+ struct connectdata *conn = pp->conn;
+ struct Curl_easy *data=conn->data;
+ time_t timeout_ms; /* in milliseconds */
+ time_t timeout2_ms; /* in milliseconds */
+ long response_time= (data->set.server_response_timeout)?
+ data->set.server_response_timeout: pp->response_time;
+
+ /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
+ remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
+ supposed to govern the response for any given server response, not for
+ the time from connect to the given server response. */
+
+ /* Without a requested timeout, we only wait 'response_time' seconds for the
+ full response to arrive before we bail out */
+ timeout_ms = response_time -
+ Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
+
+ if(data->set.timeout) {
+ /* if timeout is requested, find out how much remaining time we have */
+ timeout2_ms = data->set.timeout - /* timeout time */
+ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+
+ /* pick the lowest number */
+ timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
+ }
+
+ return timeout_ms;
+}
+
+/*
+ * Curl_pp_statemach()
+ */
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
+{
+ struct connectdata *conn = pp->conn;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int rc;
+ time_t interval_ms;
+ time_t timeout_ms = Curl_pp_state_timeout(pp);
+ struct Curl_easy *data=conn->data;
+ CURLcode result = CURLE_OK;
+
+ if(timeout_ms <=0) {
+ failf(data, "server response timeout");
+ return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+ }
+
+ if(block) {
+ interval_ms = 1000; /* use 1 second timeout intervals */
+ if(timeout_ms < interval_ms)
+ interval_ms = timeout_ms;
+ }
+ else
+ interval_ms = 0; /* immediate */
+
+ if(Curl_ssl_data_pending(conn, FIRSTSOCKET))
+ rc = 1;
+ else if(Curl_pp_moredata(pp))
+ /* We are receiving and there is data in the cache so just read it */
+ rc = 1;
+ else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET))
+ /* We are receiving and there is data ready in the SSL library */
+ rc = 1;
+ else
+ rc = Curl_socket_check(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+ CURL_SOCKET_BAD,
+ pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+ interval_ms);
+
+ if(block) {
+ /* if we didn't wait, we don't have to spend time on this now */
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_tvnow());
+
+ if(result)
+ return result;
+ }
+
+ if(rc == -1) {
+ failf(data, "select/poll error");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else if(rc)
+ result = pp->statemach_act(conn);
+
+ return result;
+}
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp)
+{
+ struct connectdata *conn = pp->conn;
+ pp->nread_resp = 0;
+ pp->linestart_resp = conn->data->state.buffer;
+ pp->pending_resp = TRUE;
+ pp->response = Curl_tvnow(); /* start response time-out now! */
+}
+
+
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+ const char *fmt,
+ va_list args)
+{
+ ssize_t bytes_written;
+ size_t write_len;
+ char *fmt_crlf;
+ char *s;
+ CURLcode result;
+ struct connectdata *conn = pp->conn;
+ struct Curl_easy *data = conn->data;
+
+#ifdef HAVE_GSSAPI
+ enum protection_level data_sec = conn->data_prot;
+#endif
+
+ DEBUGASSERT(pp->sendleft == 0);
+ DEBUGASSERT(pp->sendsize == 0);
+ DEBUGASSERT(pp->sendthis == NULL);
+
+ fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */
+ if(!fmt_crlf)
+ return CURLE_OUT_OF_MEMORY;
+
+ s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */
+ free(fmt_crlf);
+ if(!s)
+ return CURLE_OUT_OF_MEMORY;
+
+ bytes_written = 0;
+ write_len = strlen(s);
+
+ Curl_pp_init(pp);
+
+ result = Curl_convert_to_network(data, s, write_len);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result) {
+ free(s);
+ return result;
+ }
+
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CMD;
+#endif
+ result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
+ &bytes_written);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+ conn->data_prot = data_sec;
+#endif
+
+ if(result) {
+ free(s);
+ return result;
+ }
+
+ if(conn->data->set.verbose)
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+ s, (size_t)bytes_written, conn);
+
+ if(bytes_written != (ssize_t)write_len) {
+ /* the whole chunk was not sent, keep it around and adjust sizes */
+ pp->sendthis = s;
+ pp->sendsize = write_len;
+ pp->sendleft = write_len - bytes_written;
+ }
+ else {
+ free(s);
+ pp->sendthis = NULL;
+ pp->sendleft = pp->sendsize = 0;
+ pp->response = Curl_tvnow();
+ }
+
+ return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+ const char *fmt, ...)
+{
+ CURLcode result;
+ va_list ap;
+ va_start(ap, fmt);
+
+ result = Curl_pp_vsendf(pp, fmt, ap);
+
+ va_end(ap);
+
+ return result;
+}
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *code, /* return the server code if done */
+ size_t *size) /* size of the response */
+{
+ ssize_t perline; /* count bytes per line */
+ bool keepon=TRUE;
+ ssize_t gotbytes;
+ char *ptr;
+ struct connectdata *conn = pp->conn;
+ struct Curl_easy *data = conn->data;
+ char * const buf = data->state.buffer;
+ CURLcode result = CURLE_OK;
+
+ *code = 0; /* 0 for errors or not done */
+ *size = 0;
+
+ ptr=buf + pp->nread_resp;
+
+ /* number of bytes in the current line, so far */
+ perline = (ssize_t)(ptr-pp->linestart_resp);
+
+ while((pp->nread_resp < (size_t)data->set.buffer_size) &&
+ (keepon && !result)) {
+
+ if(pp->cache) {
+ /* we had data in the "cache", copy that instead of doing an actual
+ * read
+ *
+ * pp->cache_size is cast to ssize_t here. This should be safe, because
+ * it would have been populated with something of size int to begin
+ * with, even though its datatype may be larger than an int.
+ */
+ DEBUGASSERT((ptr+pp->cache_size) <= (buf+data->set.buffer_size+1));
+ memcpy(ptr, pp->cache, pp->cache_size);
+ gotbytes = (ssize_t)pp->cache_size;
+ free(pp->cache); /* free the cache */
+ pp->cache = NULL; /* clear the pointer */
+ pp->cache_size = 0; /* zero the size just in case */
+ }
+ else {
+#ifdef HAVE_GSSAPI
+ enum protection_level prot = conn->data_prot;
+ conn->data_prot = PROT_CLEAR;
+#endif
+ DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
+ (buf + data->set.buffer_size + 1));
+ result = Curl_read(conn, sockfd, ptr,
+ data->set.buffer_size - pp->nread_resp,
+ &gotbytes);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
+ conn->data_prot = prot;
+#endif
+ if(result == CURLE_AGAIN)
+ return CURLE_OK; /* return */
+
+ if(!result && (gotbytes > 0))
+ /* convert from the network encoding */
+ result = Curl_convert_from_network(data, ptr, gotbytes);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+
+ if(result)
+ /* Set outer result variable to this error. */
+ keepon = FALSE;
+ }
+
+ if(!keepon)
+ ;
+ else if(gotbytes <= 0) {
+ keepon = FALSE;
+ result = CURLE_RECV_ERROR;
+ failf(data, "response reading failed");
+ }
+ else {
+ /* we got a whole chunk of data, which can be anything from one
+ * byte to a set of lines and possible just a piece of the last
+ * line */
+ ssize_t i;
+ ssize_t clipamount = 0;
+ bool restart = FALSE;
+
+ data->req.headerbytecount += (long)gotbytes;
+
+ pp->nread_resp += gotbytes;
+ for(i = 0; i < gotbytes; ptr++, i++) {
+ perline++;
+ if(*ptr=='\n') {
+ /* a newline is CRLF in pp-talk, so the CR is ignored as
+ the line isn't really terminated until the LF comes */
+
+ /* output debug output if that is requested */
+#ifdef HAVE_GSSAPI
+ if(!conn->sec_complete)
+#endif
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ pp->linestart_resp, (size_t)perline, conn);
+
+ /*
+ * We pass all response-lines to the callback function registered
+ * for "headers". The response lines can be seen as a kind of
+ * headers.
+ */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ pp->linestart_resp, perline);
+ if(result)
+ return result;
+
+ if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
+ /* This is the end of the last line, copy the last line to the
+ start of the buffer and zero terminate, for old times sake */
+ size_t n = ptr - pp->linestart_resp;
+ memmove(buf, pp->linestart_resp, n);
+ buf[n]=0; /* zero terminate */
+ keepon=FALSE;
+ pp->linestart_resp = ptr+1; /* advance pointer */
+ i++; /* skip this before getting out */
+
+ *size = pp->nread_resp; /* size of the response */
+ pp->nread_resp = 0; /* restart */
+ break;
+ }
+ perline=0; /* line starts over here */
+ pp->linestart_resp = ptr+1;
+ }
+ }
+
+ if(!keepon && (i != gotbytes)) {
+ /* We found the end of the response lines, but we didn't parse the
+ full chunk of data we have read from the server. We therefore need
+ to store the rest of the data to be checked on the next invoke as
+ it may actually contain another end of response already! */
+ clipamount = gotbytes - i;
+ restart = TRUE;
+ DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
+ "server response left\n",
+ (int)clipamount));
+ }
+ else if(keepon) {
+
+ if((perline == gotbytes) && (gotbytes > data->set.buffer_size/2)) {
+ /* We got an excessive line without newlines and we need to deal
+ with it. We keep the first bytes of the line then we throw
+ away the rest. */
+ infof(data, "Excessive server response line length received, "
+ "%zd bytes. Stripping\n", gotbytes);
+ restart = TRUE;
+
+ /* we keep 40 bytes since all our pingpong protocols are only
+ interested in the first piece */
+ clipamount = 40;
+ }
+ else if(pp->nread_resp > (size_t)data->set.buffer_size/2) {
+ /* We got a large chunk of data and there's potentially still
+ trailing data to take care of, so we put any such part in the
+ "cache", clear the buffer to make space and restart. */
+ clipamount = perline;
+ restart = TRUE;
+ }
+ }
+ else if(i == gotbytes)
+ restart = TRUE;
+
+ if(clipamount) {
+ pp->cache_size = clipamount;
+ pp->cache = malloc(pp->cache_size);
+ if(pp->cache)
+ memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(restart) {
+ /* now reset a few variables to start over nicely from the start of
+ the big buffer */
+ pp->nread_resp = 0; /* start over from scratch in the buffer */
+ ptr = pp->linestart_resp = buf;
+ perline = 0;
+ }
+
+ } /* there was data */
+
+ } /* while there's buffer left and loop is requested */
+
+ pp->pending_resp = FALSE;
+
+ return result;
+}
+
+int Curl_pp_getsock(struct pingpong *pp,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ struct connectdata *conn = pp->conn;
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ if(pp->sendleft) {
+ /* write mode */
+ return GETSOCK_WRITESOCK(0);
+ }
+
+ /* read mode */
+ return GETSOCK_READSOCK(0);
+}
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp)
+{
+ /* we have a piece of a command still left to send */
+ struct connectdata *conn = pp->conn;
+ ssize_t written;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
+ pp->sendleft, pp->sendleft, &written);
+ if(result)
+ return result;
+
+ if(written != (ssize_t)pp->sendleft) {
+ /* only a fraction was sent */
+ pp->sendleft -= written;
+ }
+ else {
+ free(pp->sendthis);
+ pp->sendthis=NULL;
+ pp->sendleft = pp->sendsize = 0;
+ pp->response = Curl_tvnow();
+ }
+ return CURLE_OK;
+}
+
+CURLcode Curl_pp_disconnect(struct pingpong *pp)
+{
+ free(pp->cache);
+ pp->cache = NULL;
+ return CURLE_OK;
+}
+
+bool Curl_pp_moredata(struct pingpong *pp)
+{
+ return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
+ TRUE : FALSE;
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/pingpong.h b/Utilities/cmcurl/lib/pingpong.h
new file mode 100644
index 000000000..ee1a59b51
--- /dev/null
+++ b/Utilities/cmcurl/lib/pingpong.h
@@ -0,0 +1,150 @@
+#ifndef HEADER_CURL_PINGPONG_H
+#define HEADER_CURL_PINGPONG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \
+ !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP)
+#define USE_PINGPONG
+#endif
+
+/* forward-declaration, this is defined in urldata.h */
+struct connectdata;
+
+typedef enum {
+ FTPTRANSFER_BODY, /* yes do transfer a body */
+ FTPTRANSFER_INFO, /* do still go through to get info/headers */
+ FTPTRANSFER_NONE, /* don't get anything and don't get info */
+ FTPTRANSFER_LAST /* end of list marker, never used */
+} curl_pp_transfer;
+
+/*
+ * 'pingpong' is the generic struct used for protocols doing server<->client
+ * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
+ *
+ * It holds response cache and non-blocking sending data.
+ */
+struct pingpong {
+ char *cache; /* data cache between getresponse()-calls */
+ size_t cache_size; /* size of cache in bytes */
+ size_t nread_resp; /* number of bytes currently read of a server response */
+ char *linestart_resp; /* line start pointer for the server response
+ reader function */
+ bool pending_resp; /* set TRUE when a server response is pending or in
+ progress, and is cleared once the last response is
+ read */
+ char *sendthis; /* allocated pointer to a buffer that is to be sent to the
+ server */
+ size_t sendleft; /* number of bytes left to send from the sendthis buffer */
+ size_t sendsize; /* total size of the sendthis buffer */
+ struct timeval response; /* set to Curl_tvnow() when a command has been sent
+ off, used to time-out response reading */
+ long response_time; /* When no timeout is given, this is the amount of
+ milliseconds we await for a server response. */
+
+ struct connectdata *conn; /* points to the connectdata struct that this
+ belongs to */
+
+ /* Function pointers the protocols MUST implement and provide for the
+ pingpong layer to function */
+
+ CURLcode (*statemach_act)(struct connectdata *conn);
+
+ bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len,
+ int *code);
+};
+
+/*
+ * Curl_pp_statemach()
+ *
+ * called repeatedly until done. Set 'wait' to make it wait a while on the
+ * socket if there's no traffic.
+ */
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block);
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp);
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+ triggered */
+time_t Curl_pp_state_timeout(struct pingpong *pp);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+ const char *fmt, ...);
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formatted string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+ const char *fmt,
+ va_list args);
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *code, /* return the server code if done */
+ size_t *size); /* size of the response */
+
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp);
+
+/* call this when a pingpong connection is disconnected */
+CURLcode Curl_pp_disconnect(struct pingpong *pp);
+
+int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks,
+ int numsocks);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_moredata()
+ *
+ * Returns whether there are still more data in the cache and so a call
+ * to Curl_pp_readresp() will not block.
+ */
+bool Curl_pp_moredata(struct pingpong *pp);
+
+#endif /* HEADER_CURL_PINGPONG_H */
diff --git a/Utilities/cmcurl/lib/pipeline.c b/Utilities/cmcurl/lib/pipeline.c
new file mode 100644
index 000000000..b8d203745
--- /dev/null
+++ b/Utilities/cmcurl/lib/pipeline.c
@@ -0,0 +1,410 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2013 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "pipeline.h"
+#include "sendf.h"
+#include "strcase.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct site_blacklist_entry {
+ struct curl_llist_element list;
+ unsigned short port;
+ char hostname[1];
+};
+
+static void site_blacklist_llist_dtor(void *user, void *element)
+{
+ struct site_blacklist_entry *entry = element;
+ (void)user;
+ free(entry);
+}
+
+static void server_blacklist_llist_dtor(void *user, void *element)
+{
+ (void)user;
+ free(element);
+}
+
+bool Curl_pipeline_penalized(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(data) {
+ bool penalized = FALSE;
+ curl_off_t penalty_size =
+ Curl_multi_content_length_penalty_size(data->multi);
+ curl_off_t chunk_penalty_size =
+ Curl_multi_chunk_length_penalty_size(data->multi);
+ curl_off_t recv_size = -2; /* Make it easy to spot in the log */
+
+ /* Find the head of the recv pipe, if any */
+ if(conn->recv_pipe.head) {
+ struct Curl_easy *recv_handle = conn->recv_pipe.head->ptr;
+
+ recv_size = recv_handle->req.size;
+
+ if(penalty_size > 0 && recv_size > penalty_size)
+ penalized = TRUE;
+ }
+
+ if(chunk_penalty_size > 0 &&
+ (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
+ penalized = TRUE;
+
+ infof(data, "Conn: %ld (%p) Receive pipe weight: (%"
+ CURL_FORMAT_CURL_OFF_T "/%zu), penalized: %s\n",
+ conn->connection_id, (void *)conn, recv_size,
+ conn->chunk.datasize, penalized?"TRUE":"FALSE");
+ return penalized;
+ }
+ return FALSE;
+}
+
+static CURLcode addHandleToPipeline(struct Curl_easy *data,
+ struct curl_llist *pipeline)
+{
+ Curl_llist_insert_next(pipeline, pipeline->tail, data,
+ &data->pipeline_queue);
+ return CURLE_OK;
+}
+
+
+CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *sendhead = conn->send_pipe.head;
+ struct curl_llist *pipeline;
+ CURLcode result;
+
+ pipeline = &conn->send_pipe;
+
+ result = addHandleToPipeline(handle, pipeline);
+
+ if(pipeline == &conn->send_pipe && sendhead != conn->send_pipe.head) {
+ /* this is a new one as head, expire it */
+ Curl_pipeline_leave_write(conn); /* not in use yet */
+ Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
+ }
+
+#if 0 /* enable for pipeline debugging */
+ print_pipeline(conn);
+#endif
+
+ return result;
+}
+
+/* Move this transfer from the sending list to the receiving list.
+
+ Pay special attention to the new sending list "leader" as it needs to get
+ checked to update what sockets it acts on.
+
+*/
+void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+
+ curr = conn->send_pipe.head;
+ while(curr) {
+ if(curr->ptr == handle) {
+ Curl_llist_move(&conn->send_pipe, curr,
+ &conn->recv_pipe, conn->recv_pipe.tail);
+
+ if(conn->send_pipe.head) {
+ /* Since there's a new easy handle at the start of the send pipeline,
+ set its timeout value to 1ms to make it trigger instantly */
+ Curl_pipeline_leave_write(conn); /* not used now */
+#ifdef DEBUGBUILD
+ infof(conn->data, "%p is at send pipe head B!\n",
+ (void *)conn->send_pipe.head->ptr);
+#endif
+ Curl_expire(conn->send_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
+ }
+
+ /* The receiver's list is not really interesting here since either this
+ handle is now first in the list and we'll deal with it soon, or
+ another handle is already first and thus is already taken care of */
+
+ break; /* we're done! */
+ }
+ curr = curr->next;
+ }
+}
+
+bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
+ struct connectdata *conn)
+{
+ if(handle->multi) {
+ struct curl_llist *blacklist =
+ Curl_multi_pipelining_site_bl(handle->multi);
+
+ if(blacklist) {
+ struct curl_llist_element *curr;
+
+ curr = blacklist->head;
+ while(curr) {
+ struct site_blacklist_entry *site;
+
+ site = curr->ptr;
+ if(strcasecompare(site->hostname, conn->host.name) &&
+ site->port == conn->remote_port) {
+ infof(handle, "Site %s:%d is pipeline blacklisted\n",
+ conn->host.name, conn->remote_port);
+ return TRUE;
+ }
+ curr = curr->next;
+ }
+ }
+ }
+ return FALSE;
+}
+
+CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
+ struct curl_llist *list)
+{
+ /* Free the old list */
+ if(list->size)
+ Curl_llist_destroy(list, NULL);
+
+ if(sites) {
+ Curl_llist_init(list, (curl_llist_dtor) site_blacklist_llist_dtor);
+
+ /* Parse the URLs and populate the list */
+ while(*sites) {
+ char *port;
+ struct site_blacklist_entry *entry;
+
+ entry = malloc(sizeof(struct site_blacklist_entry) + strlen(*sites));
+ if(!entry) {
+ Curl_llist_destroy(list, NULL);
+ return CURLM_OUT_OF_MEMORY;
+ }
+ strcpy(entry->hostname, *sites);
+
+ port = strchr(entry->hostname, ':');
+ if(port) {
+ *port = '\0';
+ port++;
+ entry->port = (unsigned short)strtol(port, NULL, 10);
+ }
+ else {
+ /* Default port number for HTTP */
+ entry->port = 80;
+ }
+
+ Curl_llist_insert_next(list, list->tail, entry, &entry->list);
+ sites++;
+ }
+ }
+
+ return CURLM_OK;
+}
+
+bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
+ char *server_name)
+{
+ if(handle->multi && server_name) {
+ struct curl_llist *blacklist =
+ Curl_multi_pipelining_server_bl(handle->multi);
+
+ if(blacklist) {
+ struct curl_llist_element *curr;
+
+ curr = blacklist->head;
+ while(curr) {
+ char *bl_server_name;
+
+ bl_server_name = curr->ptr;
+ if(strncasecompare(bl_server_name, server_name,
+ strlen(bl_server_name))) {
+ infof(handle, "Server %s is blacklisted\n", server_name);
+ return TRUE;
+ }
+ curr = curr->next;
+ }
+ }
+
+ DEBUGF(infof(handle, "Server %s is not blacklisted\n", server_name));
+ }
+ return FALSE;
+}
+
+struct blacklist_node {
+ struct curl_llist_element list;
+ char server_name[1];
+};
+
+CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
+ struct curl_llist *list)
+{
+ /* Free the old list */
+ if(list->size)
+ Curl_llist_destroy(list, NULL);
+
+ if(servers) {
+ Curl_llist_init(list, (curl_llist_dtor) server_blacklist_llist_dtor);
+
+ /* Parse the URLs and populate the list */
+ while(*servers) {
+ struct blacklist_node *n;
+ size_t len = strlen(*servers);
+
+ n = malloc(sizeof(struct blacklist_node) + len);
+ if(!n) {
+ Curl_llist_destroy(list, NULL);
+ return CURLM_OUT_OF_MEMORY;
+ }
+ strcpy(n->server_name, *servers);
+
+ Curl_llist_insert_next(list, list->tail, n->server_name,
+ &n->list);
+ servers++;
+ }
+ }
+
+
+ return CURLM_OK;
+}
+
+static bool pipe_head(struct Curl_easy *data,
+ struct curl_llist *pipeline)
+{
+ if(pipeline) {
+ struct curl_llist_element *curr = pipeline->head;
+ if(curr)
+ return (curr->ptr == data) ? TRUE : FALSE;
+ }
+ return FALSE;
+}
+
+/* returns TRUE if the given handle is head of the recv pipe */
+bool Curl_recvpipe_head(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ return pipe_head(data, &conn->recv_pipe);
+}
+
+/* returns TRUE if the given handle is head of the send pipe */
+bool Curl_sendpipe_head(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ return pipe_head(data, &conn->send_pipe);
+}
+
+
+/*
+ * Check if the write channel is available and this handle as at the head,
+ * then grab the channel and return TRUE.
+ *
+ * If not available, return FALSE.
+ */
+
+bool Curl_pipeline_checkget_write(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(conn->bits.multiplex)
+ /* when multiplexing, we can use it at once */
+ return TRUE;
+
+ if(!conn->writechannel_inuse && Curl_sendpipe_head(data, conn)) {
+ /* Grab the channel */
+ conn->writechannel_inuse = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/*
+ * Check if the read channel is available and this handle as at the head, then
+ * grab the channel and return TRUE.
+ *
+ * If not available, return FALSE.
+ */
+
+bool Curl_pipeline_checkget_read(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ if(conn->bits.multiplex)
+ /* when multiplexing, we can use it at once */
+ return TRUE;
+
+ if(!conn->readchannel_inuse && Curl_recvpipe_head(data, conn)) {
+ /* Grab the channel */
+ conn->readchannel_inuse = TRUE;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*
+ * The current user of the pipeline write channel gives it up.
+ */
+void Curl_pipeline_leave_write(struct connectdata *conn)
+{
+ conn->writechannel_inuse = FALSE;
+}
+
+/*
+ * The current user of the pipeline read channel gives it up.
+ */
+void Curl_pipeline_leave_read(struct connectdata *conn)
+{
+ conn->readchannel_inuse = FALSE;
+}
+
+
+#if 0
+void print_pipeline(struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+ struct connectbundle *cb_ptr;
+ struct Curl_easy *data = conn->data;
+
+ cb_ptr = conn->bundle;
+
+ if(cb_ptr) {
+ curr = cb_ptr->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+ infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
+ conn->connection_id,
+ (void *)conn,
+ conn->send_pipe->size,
+ conn->recv_pipe->size);
+ curr = curr->next;
+ }
+ }
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/pipeline.h b/Utilities/cmcurl/lib/pipeline.h
new file mode 100644
index 000000000..413ba31a0
--- /dev/null
+++ b/Utilities/cmcurl/lib/pipeline.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_PIPELINE_H
+#define HEADER_CURL_PIPELINE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2013 - 2014, Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_add_handle_to_pipeline(struct Curl_easy *handle,
+ struct connectdata *conn);
+void Curl_move_handle_from_send_to_recv_pipe(struct Curl_easy *handle,
+ struct connectdata *conn);
+bool Curl_pipeline_penalized(struct Curl_easy *data,
+ struct connectdata *conn);
+
+bool Curl_pipeline_site_blacklisted(struct Curl_easy *handle,
+ struct connectdata *conn);
+
+CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
+ struct curl_llist *list_ptr);
+
+bool Curl_pipeline_server_blacklisted(struct Curl_easy *handle,
+ char *server_name);
+
+CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
+ struct curl_llist *list_ptr);
+
+bool Curl_pipeline_checkget_write(struct Curl_easy *data,
+ struct connectdata *conn);
+bool Curl_pipeline_checkget_read(struct Curl_easy *data,
+ struct connectdata *conn);
+void Curl_pipeline_leave_write(struct connectdata *conn);
+void Curl_pipeline_leave_read(struct connectdata *conn);
+bool Curl_recvpipe_head(struct Curl_easy *data,
+ struct connectdata *conn);
+bool Curl_sendpipe_head(struct Curl_easy *data,
+ struct connectdata *conn);
+
+#endif /* HEADER_CURL_PIPELINE_H */
diff --git a/Utilities/cmcurl/lib/pop3.c b/Utilities/cmcurl/lib/pop3.c
new file mode 100644
index 000000000..3feb3be83
--- /dev/null
+++ b/Utilities/cmcurl/lib/pop3.c
@@ -0,0 +1,1612 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC1734 POP3 Authentication
+ * RFC1939 POP3 protocol
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2384 POP URL Scheme
+ * RFC2449 POP3 Extension Mechanism
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC5034 POP3 SASL Authentication Mechanism
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_POP3
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "pop3.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "curl_sasl.h"
+#include "curl_md5.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode pop3_do(struct connectdata *conn, bool *done);
+static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode pop3_connect(struct connectdata *conn, bool *done);
+static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
+static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode pop3_setup_connection(struct connectdata *conn);
+static CURLcode pop3_parse_url_options(struct connectdata *conn);
+static CURLcode pop3_parse_url_path(struct connectdata *conn);
+static CURLcode pop3_parse_custom_request(struct connectdata *conn);
+static CURLcode pop3_perform_auth(struct connectdata *conn, const char *mech,
+ const char *initresp);
+static CURLcode pop3_continue_auth(struct connectdata *conn, const char *resp);
+static void pop3_get_message(char *buffer, char **outptr);
+
+/*
+ * POP3 protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3 = {
+ "POP3", /* scheme */
+ pop3_setup_connection, /* setup_connection */
+ pop3_do, /* do_it */
+ pop3_done, /* done */
+ ZERO_NULL, /* do_more */
+ pop3_connect, /* connect_it */
+ pop3_multi_statemach, /* connecting */
+ pop3_doing, /* doing */
+ pop3_getsock, /* proto_getsock */
+ pop3_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ pop3_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3, /* defport */
+ CURLPROTO_POP3, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
+ PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * POP3S protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3s = {
+ "POP3S", /* scheme */
+ pop3_setup_connection, /* setup_connection */
+ pop3_do, /* do_it */
+ pop3_done, /* done */
+ ZERO_NULL, /* do_more */
+ pop3_connect, /* connect_it */
+ pop3_multi_statemach, /* connecting */
+ pop3_doing, /* doing */
+ pop3_getsock, /* proto_getsock */
+ pop3_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ pop3_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3S, /* defport */
+ CURLPROTO_POP3S, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL
+ | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed POP3 protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3_proxy = {
+ "POP3", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed POP3S protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3s_proxy = {
+ "POP3S", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3S, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+/* SASL parameters for the pop3 protocol */
+static const struct SASLproto saslpop3 = {
+ "pop", /* The service name */
+ '*', /* Code received when continuation is expected */
+ '+', /* Code to receive upon authentication success */
+ 255 - 8, /* Maximum initial response length (no max) */
+ pop3_perform_auth, /* Send authentication command */
+ pop3_continue_auth, /* Send authentication continuation */
+ pop3_get_message /* Get SASL response message */
+};
+
+#ifdef USE_SSL
+static void pop3_to_pop3s(struct connectdata *conn)
+{
+ /* Change the connection handler */
+ conn->handler = &Curl_handler_pop3s;
+
+ /* Set the connection's upgraded to TLS flag */
+ conn->tls_upgraded = TRUE;
+}
+#else
+#define pop3_to_pop3s(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * pop3_endofresp()
+ *
+ * Checks for an ending POP3 status code at the start of the given string, but
+ * also detects the APOP timestamp from the server greeting and various
+ * capabilities from the CAPA response including the supported authentication
+ * types and allowed SASL mechanisms.
+ */
+static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ /* Do we have an error response? */
+ if(len >= 4 && !memcmp("-ERR", line, 4)) {
+ *resp = '-';
+
+ return TRUE;
+ }
+
+ /* Are we processing CAPA command responses? */
+ if(pop3c->state == POP3_CAPA) {
+ /* Do we have the terminating line? */
+ if(len >= 1 && !memcmp(line, ".", 1))
+ /* Treat the response as a success */
+ *resp = '+';
+ else
+ /* Treat the response as an untagged continuation */
+ *resp = '*';
+
+ return TRUE;
+ }
+
+ /* Do we have a success response? */
+ if(len >= 3 && !memcmp("+OK", line, 3)) {
+ *resp = '+';
+
+ return TRUE;
+ }
+
+ /* Do we have a continuation response? */
+ if(len >= 1 && !memcmp("+", line, 1)) {
+ *resp = '*';
+
+ return TRUE;
+ }
+
+ return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * pop3_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static void pop3_get_message(char *buffer, char **outptr)
+{
+ size_t len = 0;
+ char *message = NULL;
+
+ /* Find the start of the message */
+ for(message = buffer + 2; *message == ' ' || *message == '\t'; message++)
+ ;
+
+ /* Find the end of the message */
+ for(len = strlen(message); len--;)
+ if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+ message[len] != '\t')
+ break;
+
+ /* Terminate the message */
+ if(++len) {
+ message[len] = '\0';
+ }
+
+ *outptr = message;
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change POP3 state!
+ */
+static void state(struct connectdata *conn, pop3state newstate)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "STOP",
+ "SERVERGREET",
+ "CAPA",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTH",
+ "APOP",
+ "USER",
+ "PASS",
+ "COMMAND",
+ "QUIT",
+ /* LAST */
+ };
+
+ if(pop3c->state != newstate)
+ infof(conn->data, "POP3 %p state change from %s to %s\n",
+ (void *)pop3c, names[pop3c->state], names[newstate]);
+#endif
+
+ pop3c->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_capa()
+ *
+ * Sends the CAPA command in order to obtain a list of server side supported
+ * capabilities.
+ */
+static CURLcode pop3_perform_capa(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ pop3c->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanisms yet */
+ pop3c->sasl.authused = SASL_AUTH_NONE; /* Clear the auth. mechanism used */
+ pop3c->tls_supported = FALSE; /* Clear the TLS capability */
+
+ /* Send the CAPA command */
+ result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
+
+ if(!result)
+ state(conn, POP3_CAPA);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode pop3_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STLS command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
+
+ if(!result)
+ state(conn, POP3_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+
+ if(!result) {
+ if(pop3c->state != POP3_UPGRADETLS)
+ state(conn, POP3_UPGRADETLS);
+
+ if(pop3c->ssldone) {
+ pop3_to_pop3s(conn);
+ result = pop3_perform_capa(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_user()
+ *
+ * Sends a clear text USER command to authenticate with.
+ */
+static CURLcode pop3_perform_user(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, POP3_STOP);
+
+ return result;
+ }
+
+ /* Send the USER command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
+ conn->user ? conn->user : "");
+ if(!result)
+ state(conn, POP3_USER);
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/***********************************************************************
+ *
+ * pop3_perform_apop()
+ *
+ * Sends an APOP command to authenticate with.
+ */
+static CURLcode pop3_perform_apop(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ size_t i;
+ MD5_context *ctxt;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char secret[2 * MD5_DIGEST_LEN + 1];
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, POP3_STOP);
+
+ return result;
+ }
+
+ /* Create the digest */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
+ curlx_uztoui(strlen(pop3c->apoptimestamp)));
+
+ Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
+ curlx_uztoui(strlen(conn->passwd)));
+
+ /* Finalise the digest */
+ Curl_MD5_final(ctxt, digest);
+
+ /* Convert the calculated 16 octet digest into a 32 byte hex string */
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&secret[2 * i], 3, "%02x", digest[i]);
+
+ result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
+
+ if(!result)
+ state(conn, POP3_APOP);
+
+ return result;
+}
+#endif
+
+/***********************************************************************
+ *
+ * pop3_perform_auth()
+ *
+ * Sends an AUTH command allowing the client to login with the given SASL
+ * authentication mechanism.
+ */
+static CURLcode pop3_perform_auth(struct connectdata *conn,
+ const char *mech,
+ const char *initresp)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ if(initresp) { /* AUTH <mech> ...<crlf> */
+ /* Send the AUTH command with the initial response */
+ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
+ }
+ else {
+ /* Send the AUTH command */
+ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_continue_auth()
+ *
+ * Sends SASL continuation data or cancellation.
+ */
+static CURLcode pop3_continue_auth(struct connectdata *conn,
+ const char *resp)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ return Curl_pp_sendf(&pop3c->pp, "%s", resp);
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism, falling back to APOP and clear text should a
+ * common mechanism not be available between the client and server.
+ */
+static CURLcode pop3_perform_authentication(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ saslprogress progress = SASL_IDLE;
+
+ /* Check we have enough data to authenticate with and end the
+ connect phase if we don't */
+ if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
+ state(conn, POP3_STOP);
+ return result;
+ }
+
+ if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_SASL) {
+ /* Calculate the SASL login details */
+ result = Curl_sasl_start(&pop3c->sasl, conn, FALSE, &progress);
+
+ if(!result)
+ if(progress == SASL_INPROGRESS)
+ state(conn, POP3_AUTH);
+ }
+
+ if(!result && progress == SASL_IDLE) {
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
+ /* Perform APOP authentication */
+ result = pop3_perform_apop(conn);
+ else
+#endif
+ if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
+ /* Perform clear text authentication */
+ result = pop3_perform_user(conn);
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_command()
+ *
+ * Sends a POP3 based command.
+ */
+static CURLcode pop3_perform_command(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *command = NULL;
+
+ /* Calculate the default command */
+ if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
+ command = "LIST";
+
+ if(pop3->id[0] != '\0')
+ /* Message specific LIST so skip the BODY transfer */
+ pop3->transfer = FTPTRANSFER_INFO;
+ }
+ else
+ command = "RETR";
+
+ /* Send the command */
+ if(pop3->id[0] != '\0')
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command), pop3->id);
+ else
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command));
+
+ if(!result)
+ state(conn, POP3_COMMAND);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_quit()
+ *
+ * Performs the quit action prior to sclose() be called.
+ */
+static CURLcode pop3_perform_quit(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the QUIT command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
+
+ if(!result)
+ state(conn, POP3_QUIT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
+ size_t i;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Got unexpected pop3-server response");
+ result = CURLE_WEIRD_SERVER_REPLY;
+ }
+ else {
+ /* Does the server support APOP authentication? */
+ if(len >= 4 && line[len - 2] == '>') {
+ /* Look for the APOP timestamp */
+ for(i = 3; i < len - 2; ++i) {
+ if(line[i] == '<') {
+ /* Calculate the length of the timestamp */
+ size_t timestamplen = len - 1 - i;
+ if(!timestamplen)
+ break;
+
+ /* Allocate some memory for the timestamp */
+ pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
+
+ if(!pop3c->apoptimestamp)
+ break;
+
+ /* Copy the timestamp */
+ memcpy(pop3c->apoptimestamp, line + i, timestamplen);
+ pop3c->apoptimestamp[timestamplen] = '\0';
+
+ /* Store the APOP capability */
+ pop3c->authtypes |= POP3_TYPE_APOP;
+ break;
+ }
+ }
+ }
+
+ result = pop3_perform_capa(conn);
+ }
+
+ return result;
+}
+
+/* For CAPA responses */
+static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
+ size_t wordlen;
+
+ (void)instate; /* no use for this yet */
+
+ /* Do we have a untagged continuation response? */
+ if(pop3code == '*') {
+ /* Does the server support the STLS capability? */
+ if(len >= 4 && !memcmp(line, "STLS", 4))
+ pop3c->tls_supported = TRUE;
+
+ /* Does the server support clear text authentication? */
+ else if(len >= 4 && !memcmp(line, "USER", 4))
+ pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+
+ /* Does the server support SASL based authentication? */
+ else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
+ pop3c->authtypes |= POP3_TYPE_SASL;
+
+ /* Advance past the SASL keyword */
+ line += 5;
+ len -= 5;
+
+ /* Loop through the data line */
+ for(;;) {
+ size_t llen;
+ unsigned int mechbit;
+
+ while(len &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ len--;
+ }
+
+ if(!len)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Test the word for a matching authentication mechanism */
+ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+ if(mechbit && llen == wordlen)
+ pop3c->sasl.authmechs |= mechbit;
+
+ line += wordlen;
+ len -= wordlen;
+ }
+ }
+ }
+ else if(pop3code == '+') {
+ if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(pop3c->tls_supported)
+ /* Switch to TLS connection now */
+ result = pop3_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = pop3_perform_authentication(conn);
+ else {
+ failf(data, "STLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = pop3_perform_authentication(conn);
+ }
+ else {
+ /* Clear text is supported when CAPA isn't recognised */
+ pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+
+ result = pop3_perform_authentication(conn);
+ }
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = pop3_perform_authentication(conn);
+ }
+ else
+ result = pop3_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode pop3_state_auth_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ saslprogress progress;
+
+ (void)instate; /* no use for this yet */
+
+ result = Curl_sasl_continue(&pop3c->sasl, conn, pop3code, &progress);
+ if(!result)
+ switch(progress) {
+ case SASL_DONE:
+ state(conn, POP3_STOP); /* Authenticated */
+ break;
+ case SASL_IDLE: /* No mechanism left after cancellation */
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
+ /* Perform APOP authentication */
+ result = pop3_perform_apop(conn);
+ else
+#endif
+ if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_CLEARTEXT)
+ /* Perform clear text authentication */
+ result = pop3_perform_user(conn);
+ else {
+ failf(data, "Authentication cancelled");
+ result = CURLE_LOGIN_DENIED;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* For APOP responses */
+static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Authentication failed: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+#endif
+
+/* For USER responses */
+static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied. %c", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* Send the PASS command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
+ conn->passwd ? conn->passwd : "");
+ if(!result)
+ state(conn, POP3_PASS);
+
+ return result;
+}
+
+/* For PASS responses */
+static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied. %c", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+
+/* For command responses */
+static CURLcode pop3_state_command_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ state(conn, POP3_STOP);
+ return CURLE_RECV_ERROR;
+ }
+
+ /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
+ EOB string so count this is two matching bytes. This is necessary to make
+ the code detect the EOB if the only data than comes now is %2e CR LF like
+ when there is no body to return. */
+ pop3c->eob = 2;
+
+ /* But since this initial CR LF pair is not part of the actual body, we set
+ the strip counter here so that these bytes won't be delivered. */
+ pop3c->strip = 2;
+
+ if(pop3->transfer == FTPTRANSFER_BODY) {
+ /* POP3 download */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+
+ if(pp->cache) {
+ /* The header "cache" contains a bunch of data that is actually body
+ content so send it as such. Note that there may even be additional
+ "headers" after the body */
+
+ if(!data->set.opt_no_body) {
+ result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
+ if(result)
+ return result;
+ }
+
+ /* Free the cache */
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
+ }
+ }
+
+ /* End of DO phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+
+static CURLcode pop3_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int pop3code;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
+ if(pop3c->state == POP3_UPGRADETLS)
+ return pop3_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ do {
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
+ if(result)
+ return result;
+
+ if(!pop3code)
+ break;
+
+ /* We have now received a full POP3 server response */
+ switch(pop3c->state) {
+ case POP3_SERVERGREET:
+ result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_CAPA:
+ result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_STARTTLS:
+ result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH:
+ result = pop3_state_auth_resp(conn, pop3code, pop3c->state);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case POP3_APOP:
+ result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
+ break;
+#endif
+
+ case POP3_USER:
+ result = pop3_state_user_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_PASS:
+ result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_COMMAND:
+ result = pop3_state_command_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, POP3_STOP);
+ break;
+ }
+ } while(!result && pop3c->state != POP3_STOP && Curl_pp_moredata(pp));
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+ if(result || !pop3c->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&pop3c->pp, FALSE);
+ *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode pop3_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ while(pop3c->state != POP3_STOP && !result)
+ result = Curl_pp_statemach(&pop3c->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the POP3 struct for the current Curl_easy if
+ required */
+static CURLcode pop3_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3;
+
+ pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
+ if(!pop3)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the POP3 "protocol connect" and "doing" phases only */
+static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * pop3_connect()
+ *
+ * This function should do everything that is to be considered a part of the
+ * connection phase.
+ *
+ * The variable 'done' points to will be TRUE if the protocol-layer connect
+ * phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode pop3_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in POP3 */
+ connkeep(conn, "POP3 default");
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = pop3_statemach_act;
+ pp->endofresp = pop3_endofresp;
+ pp->conn = conn;
+
+ /* Set the default preferred authentication type and mechanism */
+ pop3c->preftype = POP3_TYPE_ANY;
+ Curl_sasl_init(&pop3c->sasl, &saslpop3);
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = pop3_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, POP3_SERVERGREET);
+
+ result = pop3_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+
+ (void)premature;
+
+ if(!pop3)
+ return CURLE_OK;
+
+ if(status) {
+ connclose(conn, "POP3 done with bad status");
+ result = status; /* use the already set error code */
+ }
+
+ /* Cleanup our per-request based variables */
+ Curl_safefree(pop3->id);
+ Curl_safefree(pop3->custom);
+
+ /* Clear the transfer mode for the next request */
+ pop3->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform()
+ *
+ * This is the actual DO function for POP3. Get a message/listing according to
+ * the options previously setup.
+ */
+static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is POP3 and no proxy */
+ CURLcode result = CURLE_OK;
+ struct POP3 *pop3 = conn->data->req.protop;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ pop3->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Start the first command in the DO phase */
+ result = pop3_perform_command(conn);
+ if(result)
+ return result;
+
+ /* Run the state-machine */
+ result = pop3_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (pop3_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode pop3_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ /* Parse the URL path */
+ result = pop3_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Parse the custom request */
+ result = pop3_parse_custom_request(conn);
+ if(result)
+ return result;
+
+ result = pop3_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_disconnect()
+ *
+ * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The POP3 session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
+ if(!pop3_perform_quit(conn))
+ (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&pop3c->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, pop3c->sasl.authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(pop3c->apoptimestamp);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
+{
+ (void)conn;
+ (void)connected;
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = pop3_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = pop3_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode pop3_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct Curl_easy *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, -1);
+ Curl_pgrsSetDownloadSize(data, -1);
+
+ /* Carry out the perform */
+ result = pop3_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = pop3_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode pop3_setup_connection(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+
+ /* Initialise the POP3 layer */
+ CURLcode result = pop3_init(conn);
+ if(result)
+ return result;
+
+ /* Clear the TLS upgraded flag */
+ conn->tls_upgraded = FALSE;
+
+ /* Set up the proxy if necessary */
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel POP3 operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_pop3)
+ conn->handler = &Curl_handler_pop3_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_pop3s_proxy;
+#else
+ failf(data, "POP3S not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* set it up as an HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+#else
+ failf(data, "POP3 over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode pop3_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ const char *ptr = conn->options;
+
+ pop3c->sasl.resetprefs = TRUE;
+
+ while(!result && ptr && *ptr) {
+ const char *key = ptr;
+ const char *value;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ value = ptr + 1;
+
+ while(*ptr && *ptr != ';')
+ ptr++;
+
+ if(strncasecompare(key, "AUTH=", 5)) {
+ result = Curl_sasl_parse_url_auth_option(&pop3c->sasl,
+ value, ptr - value);
+
+ if(result && strncasecompare(value, "+APOP", ptr - value)) {
+ pop3c->preftype = POP3_TYPE_APOP;
+ pop3c->sasl.prefmech = SASL_AUTH_NONE;
+ result = CURLE_OK;
+ }
+ }
+ else
+ result = CURLE_URL_MALFORMAT;
+
+ if(*ptr == ';')
+ ptr++;
+ }
+
+ if(pop3c->preftype != POP3_TYPE_APOP)
+ switch(pop3c->sasl.prefmech) {
+ case SASL_AUTH_NONE:
+ pop3c->preftype = POP3_TYPE_NONE;
+ break;
+ case SASL_AUTH_DEFAULT:
+ pop3c->preftype = POP3_TYPE_ANY;
+ break;
+ default:
+ pop3c->preftype = POP3_TYPE_SASL;
+ break;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode pop3_parse_url_path(struct connectdata *conn)
+{
+ /* The POP3 struct is already initialised in pop3_connect() */
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *path = data->state.path;
+
+ /* URL decode the path for the message ID */
+ return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode pop3_parse_custom_request(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ /* URL decode the custom request */
+ if(custom)
+ result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * Curl_pop3_write()
+ *
+ * This function scans the body after the end-of-body and writes everything
+ * until the end is found.
+ */
+CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
+{
+ /* This code could be made into a special function in the handler struct */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SingleRequest *k = &data->req;
+
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ bool strip_dot = FALSE;
+ size_t last = 0;
+ size_t i;
+
+ /* Search through the buffer looking for the end-of-body marker which is
+ 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
+ the eob so the server will have prefixed it with an extra dot which we
+ need to strip out. Additionally the marker could of course be spread out
+ over 5 different data chunks. */
+ for(i = 0; i < nread; i++) {
+ size_t prev = pop3c->eob;
+
+ switch(str[i]) {
+ case 0x0d:
+ if(pop3c->eob == 0) {
+ pop3c->eob++;
+
+ if(i) {
+ /* Write out the body part that didn't match */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+ i - last);
+
+ if(result)
+ return result;
+
+ last = i;
+ }
+ }
+ else if(pop3c->eob == 3)
+ pop3c->eob++;
+ else
+ /* If the character match wasn't at position 0 or 3 then restart the
+ pattern matching */
+ pop3c->eob = 1;
+ break;
+
+ case 0x0a:
+ if(pop3c->eob == 1 || pop3c->eob == 4)
+ pop3c->eob++;
+ else
+ /* If the character match wasn't at position 1 or 4 then start the
+ search again */
+ pop3c->eob = 0;
+ break;
+
+ case 0x2e:
+ if(pop3c->eob == 2)
+ pop3c->eob++;
+ else if(pop3c->eob == 3) {
+ /* We have an extra dot after the CRLF which we need to strip off */
+ strip_dot = TRUE;
+ pop3c->eob = 0;
+ }
+ else
+ /* If the character match wasn't at position 2 then start the search
+ again */
+ pop3c->eob = 0;
+ break;
+
+ default:
+ pop3c->eob = 0;
+ break;
+ }
+
+ /* Did we have a partial match which has subsequently failed? */
+ if(prev && prev >= pop3c->eob) {
+ /* Strip can only be non-zero for the very first mismatch after CRLF
+ and then both prev and strip are equal and nothing will be output
+ below */
+ while(prev && pop3c->strip) {
+ prev--;
+ pop3c->strip--;
+ }
+
+ if(prev) {
+ /* If the partial match was the CRLF and dot then only write the CRLF
+ as the server would have inserted the dot */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB,
+ strip_dot ? prev - 1 : prev);
+
+ if(result)
+ return result;
+
+ last = i;
+ strip_dot = FALSE;
+ }
+ }
+ }
+
+ if(pop3c->eob == POP3_EOB_LEN) {
+ /* We have a full match so the transfer is done, however we must transfer
+ the CRLF at the start of the EOB as this is considered to be part of the
+ message as per RFC-1939, sect. 3 */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
+
+ k->keepon &= ~KEEP_RECV;
+ pop3c->eob = 0;
+
+ return result;
+ }
+
+ if(pop3c->eob)
+ /* While EOB is matching nothing should be output */
+ return CURLE_OK;
+
+ if(nread - last) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+ nread - last);
+ }
+
+ return result;
+}
+
+#endif /* CURL_DISABLE_POP3 */
diff --git a/Utilities/cmcurl/lib/pop3.h b/Utilities/cmcurl/lib/pop3.h
new file mode 100644
index 000000000..a8e697cde
--- /dev/null
+++ b/Utilities/cmcurl/lib/pop3.h
@@ -0,0 +1,95 @@
+#ifndef HEADER_CURL_POP3_H
+#define HEADER_CURL_POP3_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * POP3 unique setup
+ ***************************************************************************/
+typedef enum {
+ POP3_STOP, /* do nothing state, stops the state machine */
+ POP3_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ POP3_CAPA,
+ POP3_STARTTLS,
+ POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ POP3_AUTH,
+ POP3_APOP,
+ POP3_USER,
+ POP3_PASS,
+ POP3_COMMAND,
+ POP3_QUIT,
+ POP3_LAST /* never used */
+} pop3state;
+
+/* This POP3 struct is used in the Curl_easy. All POP3 data that is
+ connection-oriented must be in pop3_conn to properly deal with the fact that
+ perhaps the Curl_easy is changed between the times the connection is
+ used. */
+struct POP3 {
+ curl_pp_transfer transfer;
+ char *id; /* Message ID */
+ char *custom; /* Custom Request */
+};
+
+/* pop3_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct pop3_conn {
+ struct pingpong pp;
+ pop3state state; /* Always use pop3.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ size_t eob; /* Number of bytes of the EOB (End Of Body) that
+ have been received so far */
+ size_t strip; /* Number of bytes from the start to ignore as
+ non-body */
+ struct SASL sasl; /* SASL-related storage */
+ unsigned int authtypes; /* Accepted authentication types */
+ unsigned int preftype; /* Preferred authentication type */
+ char *apoptimestamp; /* APOP timestamp from the server greeting */
+ bool tls_supported; /* StartTLS capability supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_pop3;
+extern const struct Curl_handler Curl_handler_pop3s;
+
+/* Authentication type flags */
+#define POP3_TYPE_CLEARTEXT (1 << 0)
+#define POP3_TYPE_APOP (1 << 1)
+#define POP3_TYPE_SASL (1 << 2)
+
+/* Authentication type values */
+#define POP3_TYPE_NONE 0
+#define POP3_TYPE_ANY ~0U
+
+/* This is the 5-bytes End-Of-Body marker for POP3 */
+#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define POP3_EOB_LEN 5
+
+/* This function scans the body after the end-of-body and writes everything
+ * until the end is found */
+CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread);
+
+#endif /* HEADER_CURL_POP3_H */
diff --git a/Utilities/cmcurl/lib/progress.c b/Utilities/cmcurl/lib/progress.c
new file mode 100644
index 000000000..cfaf4049e
--- /dev/null
+++ b/Utilities/cmcurl/lib/progress.c
@@ -0,0 +1,567 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "sendf.h"
+#include "progress.h"
+#include "curl_printf.h"
+
+/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
+ byte) */
+static void time2str(char *r, curl_off_t seconds)
+{
+ curl_off_t d, h, m, s;
+ if(seconds <= 0) {
+ strcpy(r, "--:--:--");
+ return;
+ }
+ h = seconds / CURL_OFF_T_C(3600);
+ if(h <= CURL_OFF_T_C(99)) {
+ m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
+ s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
+ snprintf(r, 9, "%2" CURL_FORMAT_CURL_OFF_T ":%02" CURL_FORMAT_CURL_OFF_T
+ ":%02" CURL_FORMAT_CURL_OFF_T, h, m, s);
+ }
+ else {
+ /* this equals to more than 99 hours, switch to a more suitable output
+ format to fit within the limits. */
+ d = seconds / CURL_OFF_T_C(86400);
+ h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
+ if(d <= CURL_OFF_T_C(999))
+ snprintf(r, 9, "%3" CURL_FORMAT_CURL_OFF_T
+ "d %02" CURL_FORMAT_CURL_OFF_T "h", d, h);
+ else
+ snprintf(r, 9, "%7" CURL_FORMAT_CURL_OFF_T "d", d);
+ }
+}
+
+/* The point of this function would be to return a string of the input data,
+ but never longer than 5 columns (+ one zero byte).
+ Add suffix k, M, G when suitable... */
+static char *max5data(curl_off_t bytes, char *max5)
+{
+#define ONE_KILOBYTE CURL_OFF_T_C(1024)
+#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
+#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
+#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
+#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
+
+ if(bytes < CURL_OFF_T_C(100000))
+ snprintf(max5, 6, "%5" CURL_FORMAT_CURL_OFF_T, bytes);
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "k", bytes/ONE_KILOBYTE);
+
+ else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
+ /* 'XX.XM' is good as long as we're less than 100 megs */
+ snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
+ (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+
+#if (CURL_SIZEOF_CURL_OFF_T > 4)
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
+ /* 'XXXXM' is good until we're at 10000MB or above */
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
+
+ else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
+ /* 10000 MB - 100 GB, we show it as XX.XG */
+ snprintf(max5, 6, "%2" CURL_FORMAT_CURL_OFF_T ".%0"
+ CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE,
+ (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
+ /* up to 10000GB, display without decimal: XXXXG */
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "G", bytes/ONE_GIGABYTE);
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
+ /* up to 10000TB, display without decimal: XXXXT */
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "T", bytes/ONE_TERABYTE);
+
+ else
+ /* up to 10000PB, display without decimal: XXXXP */
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
+
+ /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
+ can hold, but our data type is signed so 8192PB will be the maximum. */
+
+#else
+
+ else
+ snprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
+
+#endif
+
+ return max5;
+}
+
+/*
+
+ New proposed interface, 9th of February 2000:
+
+ pgrsStartNow() - sets start time
+ pgrsSetDownloadSize(x) - known expected download size
+ pgrsSetUploadSize(x) - known expected upload size
+ pgrsSetDownloadCounter() - amount of data currently downloaded
+ pgrsSetUploadCounter() - amount of data currently uploaded
+ pgrsUpdate() - show progress
+ pgrsDone() - transfer complete
+
+*/
+
+int Curl_pgrsDone(struct connectdata *conn)
+{
+ int rc;
+ struct Curl_easy *data = conn->data;
+ data->progress.lastshow=0;
+ rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
+ if(rc)
+ return rc;
+
+ if(!(data->progress.flags & PGRS_HIDE) &&
+ !data->progress.callback)
+ /* only output if we don't use a progress callback and we're not
+ * hidden */
+ fprintf(data->set.err, "\n");
+
+ data->progress.speeder_c = 0; /* reset the progress meter display */
+ return 0;
+}
+
+/* reset all times except redirect, and reset the known transfer sizes */
+void Curl_pgrsResetTimesSizes(struct Curl_easy *data)
+{
+ data->progress.t_nslookup = 0.0;
+ data->progress.t_connect = 0.0;
+ data->progress.t_pretransfer = 0.0;
+ data->progress.t_starttransfer = 0.0;
+
+ Curl_pgrsSetDownloadSize(data, -1);
+ Curl_pgrsSetUploadSize(data, -1);
+}
+
+void Curl_pgrsTime(struct Curl_easy *data, timerid timer)
+{
+ struct timeval now = Curl_tvnow();
+
+ switch(timer) {
+ default:
+ case TIMER_NONE:
+ /* mistake filter */
+ break;
+ case TIMER_STARTOP:
+ /* This is set at the start of a transfer */
+ data->progress.t_startop = now;
+ break;
+ case TIMER_STARTSINGLE:
+ /* This is set at the start of each single fetch */
+ data->progress.t_startsingle = now;
+ break;
+
+ case TIMER_STARTACCEPT:
+ data->progress.t_acceptdata = Curl_tvnow();
+ break;
+
+ case TIMER_NAMELOOKUP:
+ data->progress.t_nslookup =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_CONNECT:
+ data->progress.t_connect =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_APPCONNECT:
+ data->progress.t_appconnect =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_PRETRANSFER:
+ data->progress.t_pretransfer =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_STARTTRANSFER:
+ data->progress.t_starttransfer =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_POSTRANSFER:
+ /* this is the normal end-of-transfer thing */
+ break;
+ case TIMER_REDIRECT:
+ data->progress.t_redirect = Curl_tvdiff_secs(now, data->progress.start);
+ break;
+ }
+}
+
+void Curl_pgrsStartNow(struct Curl_easy *data)
+{
+ data->progress.speeder_c = 0; /* reset the progress meter display */
+ data->progress.start = Curl_tvnow();
+ data->progress.ul_limit_start.tv_sec = 0;
+ data->progress.ul_limit_start.tv_usec = 0;
+ data->progress.dl_limit_start.tv_sec = 0;
+ data->progress.dl_limit_start.tv_usec = 0;
+ /* clear all bits except HIDE and HEADERS_OUT */
+ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
+}
+
+/*
+ * This is used to handle speed limits, calculating how much milliseconds we
+ * need to wait until we're back under the speed limit, if needed.
+ *
+ * The way it works is by having a "starting point" (time & amount of data
+ * transferred by then) used in the speed computation, to be used instead of
+ * the start of the transfer. This starting point is regularly moved as
+ * transfer goes on, to keep getting accurate values (instead of average over
+ * the entire transfer).
+ *
+ * This function takes the current amount of data transferred, the amount at
+ * the starting point, the limit (in bytes/s), the time of the starting point
+ * and the current time.
+ *
+ * Returns -1 if no waiting is needed (not enough data transferred since
+ * starting point yet), 0 when no waiting is needed but the starting point
+ * should be reset (to current), or the number of milliseconds to wait to get
+ * back under the speed limit.
+ */
+long Curl_pgrsLimitWaitTime(curl_off_t cursize,
+ curl_off_t startsize,
+ curl_off_t limit,
+ struct timeval start,
+ struct timeval now)
+{
+ curl_off_t size = cursize - startsize;
+ time_t minimum;
+ time_t actual;
+
+ /* we don't have a starting point yet -- return 0 so it gets (re)set */
+ if(start.tv_sec == 0 && start.tv_usec == 0)
+ return 0;
+
+ /* not enough data yet */
+ if(size < limit)
+ return -1;
+
+ minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
+ actual = Curl_tvdiff(now, start);
+
+ if(actual < minimum)
+ /* this is a conversion on some systems (64bit time_t => 32bit long) */
+ return (long)(minimum - actual);
+
+ return 0;
+}
+
+void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
+{
+ struct timeval now = Curl_tvnow();
+
+ data->progress.downloaded = size;
+
+ /* download speed limit */
+ if((data->set.max_recv_speed > 0) &&
+ (Curl_pgrsLimitWaitTime(data->progress.downloaded,
+ data->progress.dl_limit_size,
+ data->set.max_recv_speed,
+ data->progress.dl_limit_start,
+ now) == 0)) {
+ data->progress.dl_limit_start = now;
+ data->progress.dl_limit_size = size;
+ }
+}
+
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size)
+{
+ struct timeval now = Curl_tvnow();
+
+ data->progress.uploaded = size;
+
+ /* upload speed limit */
+ if((data->set.max_send_speed > 0) &&
+ (Curl_pgrsLimitWaitTime(data->progress.uploaded,
+ data->progress.ul_limit_size,
+ data->set.max_send_speed,
+ data->progress.ul_limit_start,
+ now) == 0)) {
+ data->progress.ul_limit_start = now;
+ data->progress.ul_limit_size = size;
+ }
+}
+
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size)
+{
+ if(size >= 0) {
+ data->progress.size_dl = size;
+ data->progress.flags |= PGRS_DL_SIZE_KNOWN;
+ }
+ else {
+ data->progress.size_dl = 0;
+ data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
+ }
+}
+
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
+{
+ if(size >= 0) {
+ data->progress.size_ul = size;
+ data->progress.flags |= PGRS_UL_SIZE_KNOWN;
+ }
+ else {
+ data->progress.size_ul = 0;
+ data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
+ }
+}
+
+/*
+ * Curl_pgrsUpdate() returns 0 for success or the value returned by the
+ * progress callback!
+ */
+int Curl_pgrsUpdate(struct connectdata *conn)
+{
+ struct timeval now;
+ int result;
+ char max5[6][10];
+ curl_off_t dlpercen=0;
+ curl_off_t ulpercen=0;
+ curl_off_t total_percen=0;
+ curl_off_t total_transfer;
+ curl_off_t total_expected_transfer;
+ curl_off_t timespent;
+ struct Curl_easy *data = conn->data;
+ int nowindex = data->progress.speeder_c% CURR_TIME;
+ int checkindex;
+ int countindex; /* amount of seconds stored in the speeder array */
+ char time_left[10];
+ char time_total[10];
+ char time_spent[10];
+ curl_off_t ulestimate=0;
+ curl_off_t dlestimate=0;
+ curl_off_t total_estimate;
+ bool shownow=FALSE;
+
+ now = Curl_tvnow(); /* what time is it */
+
+ /* The time spent so far (from the start) */
+ data->progress.timespent = curlx_tvdiff_secs(now, data->progress.start);
+ timespent = (curl_off_t)data->progress.timespent;
+
+ /* The average download speed this far */
+ data->progress.dlspeed = (curl_off_t)
+ ((double)data->progress.downloaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
+
+ /* The average upload speed this far */
+ data->progress.ulspeed = (curl_off_t)
+ ((double)data->progress.uploaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
+
+ /* Calculations done at most once a second, unless end is reached */
+ if(data->progress.lastshow != now.tv_sec) {
+ shownow = TRUE;
+
+ data->progress.lastshow = now.tv_sec;
+
+ /* Let's do the "current speed" thing, which should use the fastest
+ of the dl/ul speeds. Store the faster speed at entry 'nowindex'. */
+ data->progress.speeder[ nowindex ] =
+ data->progress.downloaded>data->progress.uploaded?
+ data->progress.downloaded:data->progress.uploaded;
+
+ /* remember the exact time for this moment */
+ data->progress.speeder_time [ nowindex ] = now;
+
+ /* advance our speeder_c counter, which is increased every time we get
+ here and we expect it to never wrap as 2^32 is a lot of seconds! */
+ data->progress.speeder_c++;
+
+ /* figure out how many index entries of data we have stored in our speeder
+ array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
+ transfer. Imagine, after one second we have filled in two entries,
+ after two seconds we've filled in three entries etc. */
+ countindex = ((data->progress.speeder_c>=CURR_TIME)?
+ CURR_TIME:data->progress.speeder_c) - 1;
+
+ /* first of all, we don't do this if there's no counted seconds yet */
+ if(countindex) {
+ time_t span_ms;
+
+ /* Get the index position to compare with the 'nowindex' position.
+ Get the oldest entry possible. While we have less than CURR_TIME
+ entries, the first entry will remain the oldest. */
+ checkindex = (data->progress.speeder_c>=CURR_TIME)?
+ data->progress.speeder_c%CURR_TIME:0;
+
+ /* Figure out the exact time for the time span */
+ span_ms = Curl_tvdiff(now,
+ data->progress.speeder_time[checkindex]);
+ if(0 == span_ms)
+ span_ms=1; /* at least one millisecond MUST have passed */
+
+ /* Calculate the average speed the last 'span_ms' milliseconds */
+ {
+ curl_off_t amount = data->progress.speeder[nowindex]-
+ data->progress.speeder[checkindex];
+
+ if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+ /* the 'amount' value is bigger than would fit in 32 bits if
+ multiplied with 1000, so we use the double math for this */
+ data->progress.current_speed = (curl_off_t)
+ ((double)amount/((double)span_ms/1000.0));
+ else
+ /* the 'amount' value is small enough to fit within 32 bits even
+ when multiplied with 1000 */
+ data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
+ }
+ }
+ else
+ /* the first second we use the main average */
+ data->progress.current_speed =
+ (data->progress.ulspeed>data->progress.dlspeed)?
+ data->progress.ulspeed:data->progress.dlspeed;
+
+ } /* Calculations end */
+
+ if(!(data->progress.flags & PGRS_HIDE)) {
+ /* progress meter has not been shut off */
+
+ if(data->set.fxferinfo) {
+ /* There's a callback set, call that */
+ result= data->set.fxferinfo(data->set.progress_client,
+ data->progress.size_dl,
+ data->progress.downloaded,
+ data->progress.size_ul,
+ data->progress.uploaded);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+ if(data->set.fprogress) {
+ /* The older deprecated callback is set, call that */
+ result= data->set.fprogress(data->set.progress_client,
+ (double)data->progress.size_dl,
+ (double)data->progress.downloaded,
+ (double)data->progress.size_ul,
+ (double)data->progress.uploaded);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+
+ if(!shownow)
+ /* only show the internal progress meter once per second */
+ return 0;
+
+ /* If there's no external callback set, use internal code to show
+ progress */
+
+ if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
+ if(data->state.resume_from) {
+ fprintf(data->set.err,
+ "** Resuming transfer from byte position %"
+ CURL_FORMAT_CURL_OFF_T "\n", data->state.resume_from);
+ }
+ fprintf(data->set.err,
+ " %% Total %% Received %% Xferd Average Speed "
+ "Time Time Time Current\n"
+ " Dload Upload "
+ "Total Spent Left Speed\n");
+ data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
+ }
+
+ /* Figure out the estimated time of arrival for the upload */
+ if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+ (data->progress.ulspeed > CURL_OFF_T_C(0))) {
+ ulestimate = data->progress.size_ul / data->progress.ulspeed;
+
+ if(data->progress.size_ul > CURL_OFF_T_C(10000))
+ ulpercen = data->progress.uploaded /
+ (data->progress.size_ul/CURL_OFF_T_C(100));
+ else if(data->progress.size_ul > CURL_OFF_T_C(0))
+ ulpercen = (data->progress.uploaded*100) /
+ data->progress.size_ul;
+ }
+
+ /* ... and the download */
+ if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+ (data->progress.dlspeed > CURL_OFF_T_C(0))) {
+ dlestimate = data->progress.size_dl / data->progress.dlspeed;
+
+ if(data->progress.size_dl > CURL_OFF_T_C(10000))
+ dlpercen = data->progress.downloaded /
+ (data->progress.size_dl/CURL_OFF_T_C(100));
+ else if(data->progress.size_dl > CURL_OFF_T_C(0))
+ dlpercen = (data->progress.downloaded*100) /
+ data->progress.size_dl;
+ }
+
+ /* Now figure out which of them is slower and use that one for the
+ total estimate! */
+ total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
+
+ /* create the three time strings */
+ time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+ time2str(time_total, total_estimate);
+ time2str(time_spent, timespent);
+
+ /* Get the total amount of data expected to get transferred */
+ total_expected_transfer =
+ (data->progress.flags & PGRS_UL_SIZE_KNOWN?
+ data->progress.size_ul:data->progress.uploaded)+
+ (data->progress.flags & PGRS_DL_SIZE_KNOWN?
+ data->progress.size_dl:data->progress.downloaded);
+
+ /* We have transferred this much so far */
+ total_transfer = data->progress.downloaded + data->progress.uploaded;
+
+ /* Get the percentage of data transferred so far */
+ if(total_expected_transfer > CURL_OFF_T_C(10000))
+ total_percen = total_transfer /
+ (total_expected_transfer/CURL_OFF_T_C(100));
+ else if(total_expected_transfer > CURL_OFF_T_C(0))
+ total_percen = (total_transfer*100) / total_expected_transfer;
+
+ fprintf(data->set.err,
+ "\r"
+ "%3" CURL_FORMAT_CURL_OFF_T " %s "
+ "%3" CURL_FORMAT_CURL_OFF_T " %s "
+ "%3" CURL_FORMAT_CURL_OFF_T " %s %s %s %s %s %s %s",
+ total_percen, /* 3 letters */ /* total % */
+ max5data(total_expected_transfer, max5[2]), /* total size */
+ dlpercen, /* 3 letters */ /* rcvd % */
+ max5data(data->progress.downloaded, max5[0]), /* rcvd size */
+ ulpercen, /* 3 letters */ /* xfer % */
+ max5data(data->progress.uploaded, max5[1]), /* xfer size */
+ max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
+ max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
+ time_total, /* 8 letters */ /* total time */
+ time_spent, /* 8 letters */ /* time spent */
+ time_left, /* 8 letters */ /* time left */
+ max5data(data->progress.current_speed, max5[5]) /* current speed */
+ );
+
+ /* we flush the output stream to make it appear as soon as possible */
+ fflush(data->set.err);
+
+ } /* !(data->progress.flags & PGRS_HIDE) */
+
+ return 0;
+}
diff --git a/Utilities/cmcurl/lib/progress.h b/Utilities/cmcurl/lib/progress.h
new file mode 100644
index 000000000..155ff04fe
--- /dev/null
+++ b/Utilities/cmcurl/lib/progress.h
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_PROGRESS_H
+#define HEADER_CURL_PROGRESS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "timeval.h"
+
+
+typedef enum {
+ TIMER_NONE,
+ TIMER_STARTOP,
+ TIMER_STARTSINGLE,
+ TIMER_NAMELOOKUP,
+ TIMER_CONNECT,
+ TIMER_APPCONNECT,
+ TIMER_PRETRANSFER,
+ TIMER_STARTTRANSFER,
+ TIMER_POSTRANSFER,
+ TIMER_STARTACCEPT,
+ TIMER_REDIRECT,
+ TIMER_LAST /* must be last */
+} timerid;
+
+int Curl_pgrsDone(struct connectdata *);
+void Curl_pgrsStartNow(struct Curl_easy *data);
+void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
+void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
+int Curl_pgrsUpdate(struct connectdata *);
+void Curl_pgrsResetTimesSizes(struct Curl_easy *data);
+void Curl_pgrsTime(struct Curl_easy *data, timerid timer);
+long Curl_pgrsLimitWaitTime(curl_off_t cursize,
+ curl_off_t startsize,
+ curl_off_t limit,
+ struct timeval start,
+ struct timeval now);
+
+/* Don't show progress for sizes smaller than: */
+#define LEAST_SIZE_PROGRESS BUFSIZE
+
+#define PROGRESS_DOWNLOAD (1<<0)
+#define PROGRESS_UPLOAD (1<<1)
+#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD)
+
+#define PGRS_SHOW_DL (1<<0)
+#define PGRS_SHOW_UL (1<<1)
+#define PGRS_DONE_DL (1<<2)
+#define PGRS_DONE_UL (1<<3)
+#define PGRS_HIDE (1<<4)
+#define PGRS_UL_SIZE_KNOWN (1<<5)
+#define PGRS_DL_SIZE_KNOWN (1<<6)
+
+#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
+
+
+#endif /* HEADER_CURL_PROGRESS_H */
+
diff --git a/Utilities/cmcurl/lib/rand.c b/Utilities/cmcurl/lib/rand.c
new file mode 100644
index 000000000..b6f40ac0a
--- /dev/null
+++ b/Utilities/cmcurl/lib/rand.c
@@ -0,0 +1,179 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include <curl/curl.h>
+#include "vtls/vtls.h"
+#include "sendf.h"
+#include "rand.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
+{
+ unsigned int r;
+ CURLcode result = CURLE_OK;
+ static unsigned int randseed;
+ static bool seeded = FALSE;
+
+#ifdef CURLDEBUG
+ char *force_entropy = getenv("CURL_ENTROPY");
+ if(force_entropy) {
+ if(!seeded) {
+ unsigned int seed = 0;
+ size_t elen = strlen(force_entropy);
+ size_t clen = sizeof(seed);
+ size_t min = elen < clen ? elen : clen;
+ memcpy((char *)&seed, force_entropy, min);
+ randseed = ntohl(seed);
+ seeded = TRUE;
+ }
+ else
+ randseed++;
+ *rnd = randseed;
+ return CURLE_OK;
+ }
+#endif
+
+ /* data may be NULL! */
+ result = Curl_ssl_random(data, (unsigned char *)rnd, sizeof(*rnd));
+ if(result != CURLE_NOT_BUILT_IN)
+ /* only if there is no random function in the TLS backend do the non crypto
+ version, otherwise return result */
+ return result;
+
+ /* ---- non-cryptographic version following ---- */
+
+#ifdef RANDOM_FILE
+ if(!seeded) {
+ /* if there's a random file to read a seed from, use it */
+ int fd = open(RANDOM_FILE, O_RDONLY);
+ if(fd > -1) {
+ /* read random data into the randseed variable */
+ ssize_t nread = read(fd, &randseed, sizeof(randseed));
+ if(nread == sizeof(randseed))
+ seeded = TRUE;
+ close(fd);
+ }
+ }
+#endif
+
+ if(!seeded) {
+ struct timeval now = curlx_tvnow();
+ infof(data, "WARNING: Using weak random seed\n");
+ randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ seeded = TRUE;
+ }
+
+ /* Return an unsigned 32-bit pseudo-random number. */
+ r = randseed = randseed * 1103515245 + 12345;
+ *rnd = (r << 16) | ((r >> 16) & 0xFFFF);
+ return CURLE_OK;
+}
+
+/*
+ * Curl_rand() stores 'num' number of random unsigned integers in the buffer
+ * 'rndptr' points to.
+ *
+ * If libcurl is built without TLS support or with a TLS backend that lacks a
+ * proper random API (Gskit, PolarSSL or mbedTLS), this function will use
+ * "weak" random.
+ *
+ * When built *with* TLS support and a backend that offers strong random, it
+ * will return error if it cannot provide strong random values.
+ *
+ * NOTE: 'data' may be passed in as NULL when coming from external API without
+ * easy handle!
+ *
+ */
+
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num)
+{
+ CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+
+ DEBUGASSERT(num > 0);
+
+ while(num) {
+ unsigned int r;
+ size_t left = num < sizeof(unsigned int) ? num : sizeof(unsigned int);
+
+ result = randit(data, &r);
+ if(result)
+ return result;
+
+ while(left) {
+ *rnd++ = (unsigned char)(r & 0xFF);
+ r >>= 8;
+ --num;
+ --left;
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Curl_rand_hex() fills the 'rnd' buffer with a given 'num' size with random
+ * hexadecimal digits PLUS a zero terminating byte. It must be an odd number
+ * size.
+ */
+
+CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
+ size_t num)
+{
+ CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
+ const char *hex = "0123456789abcdef";
+ unsigned char buffer[128];
+ unsigned char *bufp = buffer;
+ DEBUGASSERT(num > 1);
+
+ if((num/2 >= sizeof(buffer)) || !(num&1))
+ /* make sure it fits in the local buffer and that it is an odd number! */
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ num--; /* save one for zero termination */
+
+ result = Curl_rand(data, buffer, num/2);
+ if(result)
+ return result;
+
+ while(num) {
+ *rnd++ = hex[(*bufp & 0xF0)>>4];
+ *rnd++ = hex[*bufp & 0x0F];
+ bufp++;
+ num -= 2;
+ }
+ *rnd = 0;
+
+ return result;
+}
diff --git a/Utilities/cmcurl/lib/rand.h b/Utilities/cmcurl/lib/rand.h
new file mode 100644
index 000000000..c6fae3553
--- /dev/null
+++ b/Utilities/cmcurl/lib/rand.h
@@ -0,0 +1,47 @@
+#ifndef HEADER_CURL_RAND_H
+#define HEADER_CURL_RAND_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Curl_rand() stores 'num' number of random unsigned characters in the buffer
+ * 'rnd' points to.
+ *
+ * If libcurl is built without TLS support or with a TLS backend that lacks a
+ * proper random API (Gskit, PolarSSL or mbedTLS), this function will use
+ * "weak" random.
+ *
+ * When built *with* TLS support and a backend that offers strong random, it
+ * will return error if it cannot provide strong random values.
+ *
+ * NOTE: 'data' may be passed in as NULL when coming from external API without
+ * easy handle!
+ *
+ */
+CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
+
+/* Same as above but outputs only random lowercase hex characters.
+ Does NOT terminate.*/
+CURLcode Curl_rand_hex(struct Curl_easy *data, unsigned char *rnd,
+ size_t num);
+
+#endif /* HEADER_CURL_RAND_H */
diff --git a/Utilities/cmcurl/lib/rtsp.c b/Utilities/cmcurl/lib/rtsp.c
new file mode 100644
index 000000000..1810cdafb
--- /dev/null
+++ b/Utilities/cmcurl/lib/rtsp.c
@@ -0,0 +1,815 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_RTSP
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "http.h"
+#include "url.h"
+#include "progress.h"
+#include "rtsp.h"
+#include "strcase.h"
+#include "select.h"
+#include "connect.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * TODO (general)
+ * -incoming server requests
+ * -server CSeq counter
+ * -digest authentication
+ * -connect thru proxy
+ * -pipelining?
+ */
+
+
+#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1])))
+
+#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
+ ((int)((unsigned char)((p)[3]))))
+
+/* protocol-specific functions set up to be called by the main engine */
+static CURLcode rtsp_do(struct connectdata *conn, bool *done);
+static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature);
+static CURLcode rtsp_connect(struct connectdata *conn, bool *done);
+static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead);
+
+static int rtsp_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+/*
+ * Parse and write out any available RTP data.
+ *
+ * nread: amount of data left after k->str. will be modified if RTP
+ * data is parsed and k->str is moved up
+ * readmore: whether or not the RTP parser needs more data right away
+ */
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *readmore);
+
+static CURLcode rtsp_setup_connection(struct connectdata *conn);
+
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+ interface and then we're always _sending_ a request and thus we wait for
+ the single socket to become writable only */
+static int rtsp_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ /* write mode */
+ (void)numsocks; /* unused, we trust it to be at least 1 */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
+
+
+/*
+ * RTSP handler interface.
+ */
+const struct Curl_handler Curl_handler_rtsp = {
+ "RTSP", /* scheme */
+ rtsp_setup_connection, /* setup_connection */
+ rtsp_do, /* do_it */
+ rtsp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtsp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ rtsp_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtsp_disconnect, /* disconnect */
+ rtsp_rtp_readwrite, /* readwrite */
+ PORT_RTSP, /* defport */
+ CURLPROTO_RTSP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+
+static CURLcode rtsp_setup_connection(struct connectdata *conn)
+{
+ struct RTSP *rtsp;
+
+ conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
+ if(!rtsp)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+
+/*
+ * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not
+ * want to block the application forever while receiving a stream. Therefore,
+ * we cannot assume that an RTSP socket is dead just because it is readable.
+ *
+ * Instead, if it is readable, run Curl_connalive() to peek at the socket
+ * and distinguish between closed and data.
+ */
+bool Curl_rtsp_connisdead(struct connectdata *check)
+{
+ int sval;
+ bool ret_val = TRUE;
+
+ sval = SOCKET_READABLE(check->sock[FIRSTSOCKET], 0);
+ if(sval == 0) {
+ /* timeout */
+ ret_val = FALSE;
+ }
+ else if(sval & CURL_CSELECT_ERR) {
+ /* socket is in an error state */
+ ret_val = TRUE;
+ }
+ else if(sval & CURL_CSELECT_IN) {
+ /* readable with no error. could still be closed */
+ ret_val = !Curl_connalive(check);
+ }
+
+ return ret_val;
+}
+
+static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode httpStatus;
+ struct Curl_easy *data = conn->data;
+
+ httpStatus = Curl_http_connect(conn, done);
+
+ /* Initialize the CSeq if not already done */
+ if(data->state.rtsp_next_client_CSeq == 0)
+ data->state.rtsp_next_client_CSeq = 1;
+ if(data->state.rtsp_next_server_CSeq == 0)
+ data->state.rtsp_next_server_CSeq = 1;
+
+ conn->proto.rtspc.rtp_channel = -1;
+
+ return httpStatus;
+}
+
+static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead)
+{
+ (void) dead;
+ Curl_safefree(conn->proto.rtspc.rtp_buf);
+ return CURLE_OK;
+}
+
+
+static CURLcode rtsp_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct Curl_easy *data = conn->data;
+ struct RTSP *rtsp = data->req.protop;
+ CURLcode httpStatus;
+ long CSeq_sent;
+ long CSeq_recv;
+
+ /* Bypass HTTP empty-reply checks on receive */
+ if(data->set.rtspreq == RTSPREQ_RECEIVE)
+ premature = TRUE;
+
+ httpStatus = Curl_http_done(conn, status, premature);
+
+ if(rtsp) {
+ /* Check the sequence numbers */
+ CSeq_sent = rtsp->CSeq_sent;
+ CSeq_recv = rtsp->CSeq_recv;
+ if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) {
+ failf(data,
+ "The CSeq of this request %ld did not match the response %ld",
+ CSeq_sent, CSeq_recv);
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ if(data->set.rtspreq == RTSPREQ_RECEIVE &&
+ (conn->proto.rtspc.rtp_channel == -1)) {
+ infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
+ /* TODO CPC: Server -> Client logic here */
+ }
+ }
+
+ return httpStatus;
+}
+
+static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result=CURLE_OK;
+ Curl_RtspReq rtspreq = data->set.rtspreq;
+ struct RTSP *rtsp = data->req.protop;
+ struct HTTP *http;
+ Curl_send_buffer *req_buffer;
+ curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+
+ const char *p_request = NULL;
+ const char *p_session_id = NULL;
+ const char *p_accept = NULL;
+ const char *p_accept_encoding = NULL;
+ const char *p_range = NULL;
+ const char *p_referrer = NULL;
+ const char *p_stream_uri = NULL;
+ const char *p_transport = NULL;
+ const char *p_uagent = NULL;
+ const char *p_proxyuserpwd = NULL;
+ const char *p_userpwd = NULL;
+
+ *done = TRUE;
+
+ http = &(rtsp->http_wrapper);
+ /* Assert that no one has changed the RTSP struct in an evil way */
+ DEBUGASSERT((void *)http == (void *)rtsp);
+
+ rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
+ rtsp->CSeq_recv = 0;
+
+ /* Setup the 'p_request' pointer to the proper p_request string
+ * Since all RTSP requests are included here, there is no need to
+ * support custom requests like HTTP.
+ **/
+ data->set.opt_no_body = TRUE; /* most requests don't contain a body */
+ switch(rtspreq) {
+ default:
+ failf(data, "Got invalid RTSP request");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ case RTSPREQ_OPTIONS:
+ p_request = "OPTIONS";
+ break;
+ case RTSPREQ_DESCRIBE:
+ p_request = "DESCRIBE";
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_ANNOUNCE:
+ p_request = "ANNOUNCE";
+ break;
+ case RTSPREQ_SETUP:
+ p_request = "SETUP";
+ break;
+ case RTSPREQ_PLAY:
+ p_request = "PLAY";
+ break;
+ case RTSPREQ_PAUSE:
+ p_request = "PAUSE";
+ break;
+ case RTSPREQ_TEARDOWN:
+ p_request = "TEARDOWN";
+ break;
+ case RTSPREQ_GET_PARAMETER:
+ /* GET_PARAMETER's no_body status is determined later */
+ p_request = "GET_PARAMETER";
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_SET_PARAMETER:
+ p_request = "SET_PARAMETER";
+ break;
+ case RTSPREQ_RECORD:
+ p_request = "RECORD";
+ break;
+ case RTSPREQ_RECEIVE:
+ p_request = "";
+ /* Treat interleaved RTP as body*/
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_LAST:
+ failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ if(rtspreq == RTSPREQ_RECEIVE) {
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, -1, NULL);
+
+ return result;
+ }
+
+ p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
+ if(!p_session_id &&
+ (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
+ failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
+ p_request);
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ /* TODO: proxy? */
+
+ /* Stream URI. Default to server '*' if not specified */
+ if(data->set.str[STRING_RTSP_STREAM_URI]) {
+ p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
+ }
+ else {
+ p_stream_uri = "*";
+ }
+
+ /* Transport Header for SETUP requests */
+ p_transport = Curl_checkheaders(conn, "Transport:");
+ if(rtspreq == RTSPREQ_SETUP && !p_transport) {
+ /* New Transport: setting? */
+ if(data->set.str[STRING_RTSP_TRANSPORT]) {
+ Curl_safefree(conn->allocptr.rtsp_transport);
+
+ conn->allocptr.rtsp_transport =
+ aprintf("Transport: %s\r\n",
+ data->set.str[STRING_RTSP_TRANSPORT]);
+ if(!conn->allocptr.rtsp_transport)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ failf(data,
+ "Refusing to issue an RTSP SETUP without a Transport: header.");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ p_transport = conn->allocptr.rtsp_transport;
+ }
+
+ /* Accept Headers for DESCRIBE requests */
+ if(rtspreq == RTSPREQ_DESCRIBE) {
+ /* Accept Header */
+ p_accept = Curl_checkheaders(conn, "Accept:")?
+ NULL:"Accept: application/sdp\r\n";
+
+ /* Accept-Encoding header */
+ if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
+ data->set.str[STRING_ENCODING]) {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding =
+ aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+
+ if(!conn->allocptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
+
+ p_accept_encoding = conn->allocptr.accept_encoding;
+ }
+ }
+
+ /* The User-Agent string might have been allocated in url.c already, because
+ it might have been used in the proxy connect, but if we have got a header
+ with the user-agent string specified, we erase the previously made string
+ here. */
+ if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
+ Curl_safefree(conn->allocptr.uagent);
+ conn->allocptr.uagent = NULL;
+ }
+ else if(!Curl_checkheaders(conn, "User-Agent:") &&
+ data->set.str[STRING_USERAGENT]) {
+ p_uagent = conn->allocptr.uagent;
+ }
+
+ /* setup the authentication headers */
+ result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE);
+ if(result)
+ return result;
+
+ p_proxyuserpwd = conn->allocptr.proxyuserpwd;
+ p_userpwd = conn->allocptr.userpwd;
+
+ /* Referrer */
+ Curl_safefree(conn->allocptr.ref);
+ if(data->change.referer && !Curl_checkheaders(conn, "Referer:"))
+ conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ else
+ conn->allocptr.ref = NULL;
+
+ p_referrer = conn->allocptr.ref;
+
+ /*
+ * Range Header
+ * Only applies to PLAY, PAUSE, RECORD
+ *
+ * Go ahead and use the Range stuff supplied for HTTP
+ */
+ if(data->state.use_range &&
+ (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
+
+ /* Check to see if there is a range set in the custom headers */
+ if(!Curl_checkheaders(conn, "Range:") && data->state.range) {
+ Curl_safefree(conn->allocptr.rangeline);
+ conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
+ p_range = conn->allocptr.rangeline;
+ }
+ }
+
+ /*
+ * Sanity check the custom headers
+ */
+ if(Curl_checkheaders(conn, "CSeq:")) {
+ failf(data, "CSeq cannot be set as a custom header.");
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ if(Curl_checkheaders(conn, "Session:")) {
+ failf(data, "Session ID cannot be set as a custom header.");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ /* Initialize a dynamic send buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
+ "CSeq: %ld\r\n", /* CSeq */
+ p_request, p_stream_uri, rtsp->CSeq_sent);
+ if(result)
+ return result;
+
+ /*
+ * Rather than do a normal alloc line, keep the session_id unformatted
+ * to make comparison easier
+ */
+ if(p_session_id) {
+ result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
+ if(result)
+ return result;
+ }
+
+ /*
+ * Shared HTTP-like options
+ */
+ result = Curl_add_bufferf(req_buffer,
+ "%s" /* transport */
+ "%s" /* accept */
+ "%s" /* accept-encoding */
+ "%s" /* range */
+ "%s" /* referrer */
+ "%s" /* user-agent */
+ "%s" /* proxyuserpwd */
+ "%s" /* userpwd */
+ ,
+ p_transport ? p_transport : "",
+ p_accept ? p_accept : "",
+ p_accept_encoding ? p_accept_encoding : "",
+ p_range ? p_range : "",
+ p_referrer ? p_referrer : "",
+ p_uagent ? p_uagent : "",
+ p_proxyuserpwd ? p_proxyuserpwd : "",
+ p_userpwd ? p_userpwd : "");
+
+ /*
+ * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+ * with basic and digest, it will be freed anyway by the next request
+ */
+ Curl_safefree(conn->allocptr.userpwd);
+ conn->allocptr.userpwd = NULL;
+
+ if(result)
+ return result;
+
+ if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
+ result = Curl_add_timecondition(data, req_buffer);
+ if(result)
+ return result;
+ }
+
+ result = Curl_add_custom_headers(conn, FALSE, req_buffer);
+ if(result)
+ return result;
+
+ if(rtspreq == RTSPREQ_ANNOUNCE ||
+ rtspreq == RTSPREQ_SET_PARAMETER ||
+ rtspreq == RTSPREQ_GET_PARAMETER) {
+
+ if(data->set.upload) {
+ putsize = data->state.infilesize;
+ data->set.httpreq = HTTPREQ_PUT;
+
+ }
+ else {
+ postsize = (data->state.infilesize != -1)?
+ data->state.infilesize:
+ (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
+ data->set.httpreq = HTTPREQ_POST;
+ }
+
+ if(putsize > 0 || postsize > 0) {
+ /* As stated in the http comments, it is probably not wise to
+ * actually set a custom Content-Length in the headers */
+ if(!Curl_checkheaders(conn, "Content-Length:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
+ (data->set.upload ? putsize : postsize));
+ if(result)
+ return result;
+ }
+
+ if(rtspreq == RTSPREQ_SET_PARAMETER ||
+ rtspreq == RTSPREQ_GET_PARAMETER) {
+ if(!Curl_checkheaders(conn, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: text/parameters\r\n");
+ if(result)
+ return result;
+ }
+ }
+
+ if(rtspreq == RTSPREQ_ANNOUNCE) {
+ if(!Curl_checkheaders(conn, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: application/sdp\r\n");
+ if(result)
+ return result;
+ }
+ }
+
+ data->state.expect100header = FALSE; /* RTSP posts are simple/small */
+ }
+ else if(rtspreq == RTSPREQ_GET_PARAMETER) {
+ /* Check for an empty GET_PARAMETER (heartbeat) request */
+ data->set.httpreq = HTTPREQ_HEAD;
+ data->set.opt_no_body = TRUE;
+ }
+ }
+
+ /* RTSP never allows chunked transfer */
+ data->req.forbidchunk = TRUE;
+ /* Finish the request buffer */
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ if(postsize > 0) {
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(result)
+ return result;
+ }
+
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result) {
+ failf(data, "Failed sending RTSP request");
+ return result;
+ }
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ putsize?FIRSTSOCKET:-1,
+ putsize?&http->writebytecount:NULL);
+
+ /* Increment the CSeq on success */
+ data->state.rtsp_next_client_CSeq++;
+
+ if(http->writebytecount) {
+ /* if a request-body has been sent off, we make sure this progress is
+ noted properly */
+ Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ }
+
+ return result;
+}
+
+
+static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *readmore) {
+ struct SingleRequest *k = &data->req;
+ struct rtsp_conn *rtspc = &(conn->proto.rtspc);
+
+ char *rtp; /* moving pointer to rtp data */
+ ssize_t rtp_dataleft; /* how much data left to parse in this round */
+ char *scratch;
+ CURLcode result;
+
+ if(rtspc->rtp_buf) {
+ /* There was some leftover data the last time. Merge buffers */
+ char *newptr = Curl_saferealloc(rtspc->rtp_buf,
+ rtspc->rtp_bufsize + *nread);
+ if(!newptr) {
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ rtspc->rtp_buf = newptr;
+ memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread);
+ rtspc->rtp_bufsize += *nread;
+ rtp = rtspc->rtp_buf;
+ rtp_dataleft = rtspc->rtp_bufsize;
+ }
+ else {
+ /* Just parse the request buffer directly */
+ rtp = k->str;
+ rtp_dataleft = *nread;
+ }
+
+ while((rtp_dataleft > 0) &&
+ (rtp[0] == '$')) {
+ if(rtp_dataleft > 4) {
+ int rtp_length;
+
+ /* Parse the header */
+ /* The channel identifier immediately follows and is 1 byte */
+ rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp);
+
+ /* The length is two bytes */
+ rtp_length = RTP_PKT_LENGTH(rtp);
+
+ if(rtp_dataleft < rtp_length + 4) {
+ /* Need more - incomplete payload*/
+ *readmore = TRUE;
+ break;
+ }
+ /* We have the full RTP interleaved packet
+ * Write out the header including the leading '$' */
+ DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
+ rtspc->rtp_channel, rtp_length));
+ result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
+ if(result) {
+ failf(data, "Got an error writing an RTP packet");
+ *readmore = FALSE;
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return result;
+ }
+
+ /* Move forward in the buffer */
+ rtp_dataleft -= rtp_length + 4;
+ rtp += rtp_length + 4;
+
+ if(data->set.rtspreq == RTSPREQ_RECEIVE) {
+ /* If we are in a passive receive, give control back
+ * to the app as often as we can.
+ */
+ k->keepon &= ~KEEP_RECV;
+ }
+ }
+ else {
+ /* Need more - incomplete header */
+ *readmore = TRUE;
+ break;
+ }
+ }
+
+ if(rtp_dataleft != 0 && rtp[0] == '$') {
+ DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
+ *readmore ? "(READMORE)" : ""));
+
+ /* Store the incomplete RTP packet for a "rewind" */
+ scratch = malloc(rtp_dataleft);
+ if(!scratch) {
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(scratch, rtp, rtp_dataleft);
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = scratch;
+ rtspc->rtp_bufsize = rtp_dataleft;
+
+ /* As far as the transfer is concerned, this data is consumed */
+ *nread = 0;
+ return CURLE_OK;
+ }
+ /* Fix up k->str to point just after the last RTP packet */
+ k->str += *nread - rtp_dataleft;
+
+ /* either all of the data has been read or...
+ * rtp now points at the next byte to parse
+ */
+ if(rtp_dataleft > 0)
+ DEBUGASSERT(k->str[0] == rtp[0]);
+
+ DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */
+
+ *nread = rtp_dataleft;
+
+ /* If we get here, we have finished with the leftover/merge buffer */
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+
+ return CURLE_OK;
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
+{
+ struct Curl_easy *data = conn->data;
+ size_t wrote;
+ curl_write_callback writeit;
+
+ if(len == 0) {
+ failf(data, "Cannot write a 0 size RTP packet.");
+ return CURLE_WRITE_ERROR;
+ }
+
+ writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
+ wrote = writeit(ptr, 1, len, data->set.rtp_out);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote) {
+ failf(data, "Cannot pause RTP");
+ return CURLE_WRITE_ERROR;
+ }
+
+ if(wrote != len) {
+ failf(data, "Failed writing RTP data");
+ return CURLE_WRITE_ERROR;
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
+ char *header)
+{
+ struct Curl_easy *data = conn->data;
+ long CSeq = 0;
+
+ if(checkprefix("CSeq:", header)) {
+ /* Store the received CSeq. Match is verified in rtsp_done */
+ int nc = sscanf(&header[4], ": %ld", &CSeq);
+ if(nc == 1) {
+ struct RTSP *rtsp = data->req.protop;
+ rtsp->CSeq_recv = CSeq; /* mark the request */
+ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+ }
+ else {
+ failf(data, "Unable to read the CSeq header: [%s]", header);
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ }
+ else if(checkprefix("Session:", header)) {
+ char *start;
+
+ /* Find the first non-space letter */
+ start = header + 8;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ if(!*start) {
+ failf(data, "Got a blank Session ID");
+ }
+ else if(data->set.str[STRING_RTSP_SESSION_ID]) {
+ /* If the Session ID is set, then compare */
+ if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
+ strlen(data->set.str[STRING_RTSP_SESSION_ID])) != 0) {
+ failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
+ start, data->set.str[STRING_RTSP_SESSION_ID]);
+ return CURLE_RTSP_SESSION_ERROR;
+ }
+ }
+ else {
+ /* If the Session ID is not set, and we find it in a response, then set
+ * it.
+ *
+ * Allow any non whitespace content, up to the field separator or end of
+ * line. RFC 2326 isn't 100% clear on the session ID and for example
+ * gstreamer does url-encoded session ID's not covered by the standard.
+ */
+ char *end = start;
+ while(*end && *end != ';' && !ISSPACE(*end))
+ end++;
+
+ /* Copy the id substring into a new buffer */
+ data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
+ if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
+ (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
+ }
+ }
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_RTSP */
diff --git a/Utilities/cmcurl/lib/rtsp.h b/Utilities/cmcurl/lib/rtsp.h
new file mode 100644
index 000000000..5a8d5556f
--- /dev/null
+++ b/Utilities/cmcurl/lib/rtsp.h
@@ -0,0 +1,69 @@
+#ifndef HEADER_CURL_RTSP_H
+#define HEADER_CURL_RTSP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_RTSP
+
+extern const struct Curl_handler Curl_handler_rtsp;
+
+bool Curl_rtsp_connisdead(struct connectdata *check);
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
+
+#else
+/* disabled */
+#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
+#define Curl_rtsp_connisdead(x) TRUE
+
+#endif /* CURL_DISABLE_RTSP */
+
+/*
+ * RTSP Connection data
+ *
+ * Currently, only used for tracking incomplete RTP data reads
+ */
+struct rtsp_conn {
+ char *rtp_buf;
+ ssize_t rtp_bufsize;
+ int rtp_channel;
+};
+
+/****************************************************************************
+ * RTSP unique setup
+ ***************************************************************************/
+struct RTSP {
+ /*
+ * http_wrapper MUST be the first element of this structure for the wrap
+ * logic to work. In this way, we get a cheap polymorphism because
+ * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
+ *
+ * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
+ * functions can also index into the later elements.
+ */
+ struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */
+
+ long CSeq_sent; /* CSeq of this request */
+ long CSeq_recv; /* CSeq received */
+};
+
+
+#endif /* HEADER_CURL_RTSP_H */
+
diff --git a/Utilities/cmcurl/lib/security.c b/Utilities/cmcurl/lib/security.c
new file mode 100644
index 000000000..f4a876341
--- /dev/null
+++ b/Utilities/cmcurl/lib/security.c
@@ -0,0 +1,588 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. His latest changes were done 2000-09-18.
+ *
+ * It has since been patched and modified a lot by Daniel Stenberg
+ * <daniel@haxx.se> to make it better applied to curl conditions, and to make
+ * it not use globals, pollute name space and more. This source code awaits a
+ * rewrite to work around the paragraph 2 in the BSD licenses as explained
+ * below.
+ *
+ * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ *
+ * Copyright (C) 2001 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * 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.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_memory.h"
+#include "curl_sec.h"
+#include "ftp.h"
+#include "sendf.h"
+#include "strcase.h"
+#include "warnless.h"
+#include "strdup.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static const struct {
+ enum protection_level level;
+ const char *name;
+} level_names[] = {
+ { PROT_CLEAR, "clear" },
+ { PROT_SAFE, "safe" },
+ { PROT_CONFIDENTIAL, "confidential" },
+ { PROT_PRIVATE, "private" }
+};
+
+static enum protection_level
+name_to_level(const char *name)
+{
+ int i;
+ for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
+ if(checkprefix(name, level_names[i].name))
+ return level_names[i].level;
+ return PROT_NONE;
+}
+
+/* Convert a protocol |level| to its char representation.
+ We take an int to catch programming mistakes. */
+static char level_to_char(int level)
+{
+ switch(level) {
+ case PROT_CLEAR:
+ return 'C';
+ case PROT_SAFE:
+ return 'S';
+ case PROT_CONFIDENTIAL:
+ return 'E';
+ case PROT_PRIVATE:
+ return 'P';
+ case PROT_CMD:
+ /* Fall through */
+ default:
+ /* Those 2 cases should not be reached! */
+ break;
+ }
+ DEBUGASSERT(0);
+ /* Default to the most secure alternative. */
+ return 'P';
+}
+
+/* Send an FTP command defined by |message| and the optional arguments. The
+ function returns the ftp_code. If an error occurs, -1 is returned. */
+static int ftp_send_command(struct connectdata *conn, const char *message, ...)
+{
+ int ftp_code;
+ ssize_t nread=0;
+ va_list args;
+ char print_buffer[50];
+
+ va_start(args, message);
+ vsnprintf(print_buffer, sizeof(print_buffer), message, args);
+ va_end(args);
+
+ if(Curl_ftpsend(conn, print_buffer)) {
+ ftp_code = -1;
+ }
+ else {
+ if(Curl_GetFTPResponse(&nread, conn, &ftp_code))
+ ftp_code = -1;
+ }
+
+ (void)nread; /* Unused */
+ return ftp_code;
+}
+
+/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
+ saying whether an error occurred or CURLE_OK if |len| was read. */
+static CURLcode
+socket_read(curl_socket_t fd, void *to, size_t len)
+{
+ char *to_p = to;
+ CURLcode result;
+ ssize_t nread;
+
+ while(len > 0) {
+ result = Curl_read_plain(fd, to_p, len, &nread);
+ if(!result) {
+ len -= nread;
+ to_p += nread;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(result == CURLE_AGAIN)
+ continue;
+ return result;
+ }
+ }
+ return CURLE_OK;
+}
+
+
+/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
+ CURLcode saying whether an error occurred or CURLE_OK if |len| was
+ written. */
+static CURLcode
+socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
+ size_t len)
+{
+ const char *to_p = to;
+ CURLcode result;
+ ssize_t written;
+
+ while(len > 0) {
+ result = Curl_write_plain(conn, fd, to_p, len, &written);
+ if(!result) {
+ len -= written;
+ to_p += written;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(result == CURLE_AGAIN)
+ continue;
+ return result;
+ }
+ }
+ return CURLE_OK;
+}
+
+static CURLcode read_data(struct connectdata *conn,
+ curl_socket_t fd,
+ struct krb5buffer *buf)
+{
+ int len;
+ void *tmp = NULL;
+ CURLcode result;
+
+ result = socket_read(fd, &len, sizeof(len));
+ if(result)
+ return result;
+
+ if(len) {
+ /* only realloc if there was a length */
+ len = ntohl(len);
+ tmp = Curl_saferealloc(buf->data, len);
+ }
+ if(tmp == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ buf->data = tmp;
+ result = socket_read(fd, buf->data, len);
+ if(result)
+ return result;
+ buf->size = conn->mech->decode(conn->app_data, buf->data, len,
+ conn->data_prot, conn);
+ buf->index = 0;
+ return CURLE_OK;
+}
+
+static size_t
+buffer_read(struct krb5buffer *buf, void *data, size_t len)
+{
+ if(buf->size - buf->index < len)
+ len = buf->size - buf->index;
+ memcpy(data, (char *)buf->data + buf->index, len);
+ buf->index += len;
+ return len;
+}
+
+/* Matches Curl_recv signature */
+static ssize_t sec_recv(struct connectdata *conn, int sockindex,
+ char *buffer, size_t len, CURLcode *err)
+{
+ size_t bytes_read;
+ size_t total_read = 0;
+ curl_socket_t fd = conn->sock[sockindex];
+
+ *err = CURLE_OK;
+
+ /* Handle clear text response. */
+ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+ return read(fd, buffer, len);
+
+ if(conn->in_buffer.eof_flag) {
+ conn->in_buffer.eof_flag = 0;
+ return 0;
+ }
+
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
+
+ while(len > 0) {
+ if(read_data(conn, fd, &conn->in_buffer))
+ return -1;
+ if(conn->in_buffer.size == 0) {
+ if(bytes_read > 0)
+ conn->in_buffer.eof_flag = 1;
+ return bytes_read;
+ }
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
+ }
+ /* FIXME: Check for overflow */
+ return total_read;
+}
+
+/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
+ and negociating with the server. |from| can be NULL. */
+/* FIXME: We don't check for errors nor report any! */
+static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
+ const char *from, int length)
+{
+ int bytes, htonl_bytes; /* 32-bit integers for htonl */
+ char *buffer = NULL;
+ char *cmd_buffer;
+ size_t cmd_size = 0;
+ CURLcode error;
+ enum protection_level prot_level = conn->data_prot;
+ bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+
+ DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
+
+ if(iscmd) {
+ if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+ prot_level = PROT_PRIVATE;
+ else
+ prot_level = conn->command_prot;
+ }
+ bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
+ (void **)&buffer);
+ if(!buffer || bytes <= 0)
+ return; /* error */
+
+ if(iscmd) {
+ error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
+ &cmd_buffer, &cmd_size);
+ if(error) {
+ free(buffer);
+ return; /* error */
+ }
+ if(cmd_size > 0) {
+ static const char *enc = "ENC ";
+ static const char *mic = "MIC ";
+ if(prot_level == PROT_PRIVATE)
+ socket_write(conn, fd, enc, 4);
+ else
+ socket_write(conn, fd, mic, 4);
+
+ socket_write(conn, fd, cmd_buffer, cmd_size);
+ socket_write(conn, fd, "\r\n", 2);
+ infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+ cmd_buffer);
+ free(cmd_buffer);
+ }
+ }
+ else {
+ htonl_bytes = htonl(bytes);
+ socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
+ socket_write(conn, fd, buffer, curlx_sitouz(bytes));
+ }
+ free(buffer);
+}
+
+static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
+ const char *buffer, size_t length)
+{
+ ssize_t tx = 0, len = conn->buffer_size;
+
+ len -= conn->mech->overhead(conn->app_data, conn->data_prot,
+ curlx_sztosi(len));
+ if(len <= 0)
+ len = length;
+ while(length) {
+ if(length < (size_t)len)
+ len = length;
+
+ do_sec_send(conn, fd, buffer, curlx_sztosi(len));
+ length -= len;
+ buffer += len;
+ tx += len;
+ }
+ return tx;
+}
+
+/* Matches Curl_send signature */
+static ssize_t sec_send(struct connectdata *conn, int sockindex,
+ const void *buffer, size_t len, CURLcode *err)
+{
+ curl_socket_t fd = conn->sock[sockindex];
+ *err = CURLE_OK;
+ return sec_write(conn, fd, buffer, len);
+}
+
+int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
+ enum protection_level level)
+{
+ /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
+ int */
+ int decoded_len;
+ char *buf;
+ int ret_code = 0;
+ size_t decoded_sz = 0;
+ CURLcode error;
+
+ if(!conn->mech)
+ /* not inititalized, return error */
+ return -1;
+
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+ error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+ if(error || decoded_sz == 0)
+ return -1;
+
+ if(decoded_sz > (size_t)INT_MAX) {
+ free(buf);
+ return -1;
+ }
+ decoded_len = curlx_uztosi(decoded_sz);
+
+ decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
+ level, conn);
+ if(decoded_len <= 0) {
+ free(buf);
+ return -1;
+ }
+
+ if(conn->data->set.verbose) {
+ buf[decoded_len] = '\n';
+ Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1, conn);
+ }
+
+ buf[decoded_len] = '\0';
+ if(decoded_len <= 3)
+ /* suspiciously short */
+ return 0;
+
+ if(buf[3] != '-')
+ /* safe to ignore return code */
+ (void)sscanf(buf, "%d", &ret_code);
+
+ if(buf[decoded_len - 1] == '\n')
+ buf[decoded_len - 1] = '\0';
+ /* FIXME: Is |buffer| length always greater than |decoded_len|? */
+ strcpy(buffer, buf);
+ free(buf);
+ return ret_code;
+}
+
+/* FIXME: The error code returned here is never checked. */
+static int sec_set_protection_level(struct connectdata *conn)
+{
+ int code;
+ char *pbsz;
+ static unsigned int buffer_size = 1 << 20; /* 1048576 */
+ enum protection_level level = conn->request_data_prot;
+
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+ if(!conn->sec_complete) {
+ infof(conn->data, "Trying to change the protection level after the"
+ "completion of the data exchange.\n");
+ return -1;
+ }
+
+ /* Bail out if we try to set up the same level */
+ if(conn->data_prot == level)
+ return 0;
+
+ if(level) {
+ code = ftp_send_command(conn, "PBSZ %u", buffer_size);
+ if(code < 0)
+ return -1;
+
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection's buffer size.");
+ return -1;
+ }
+ conn->buffer_size = buffer_size;
+
+ pbsz = strstr(conn->data->state.buffer, "PBSZ=");
+ if(pbsz) {
+ /* ignore return code, use default value if it fails */
+ (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
+ if(buffer_size < conn->buffer_size)
+ conn->buffer_size = buffer_size;
+ }
+ }
+
+ /* Now try to negiociate the protection level. */
+ code = ftp_send_command(conn, "PROT %c", level_to_char(level));
+
+ if(code < 0)
+ return -1;
+
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection level.");
+ return -1;
+ }
+
+ conn->data_prot = level;
+ if(level == PROT_PRIVATE)
+ conn->command_prot = level;
+
+ return 0;
+}
+
+int
+Curl_sec_request_prot(struct connectdata *conn, const char *level)
+{
+ enum protection_level l = name_to_level(level);
+ if(l == PROT_NONE)
+ return -1;
+ DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
+ conn->request_data_prot = l;
+ return 0;
+}
+
+static CURLcode choose_mech(struct connectdata *conn)
+{
+ int ret;
+ struct Curl_easy *data = conn->data;
+ void *tmp_allocation;
+ const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
+
+ tmp_allocation = realloc(conn->app_data, mech->size);
+ if(tmp_allocation == NULL) {
+ failf(data, "Failed realloc of size %u", mech->size);
+ mech = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ conn->app_data = tmp_allocation;
+
+ if(mech->init) {
+ ret = mech->init(conn->app_data);
+ if(ret) {
+ infof(data, "Failed initialization for %s. Skipping it.\n",
+ mech->name);
+ return CURLE_FAILED_INIT;
+ }
+ }
+
+ infof(data, "Trying mechanism %s...\n", mech->name);
+ ret = ftp_send_command(conn, "AUTH %s", mech->name);
+ if(ret < 0)
+ /* FIXME: This error is too generic but it is OK for now. */
+ return CURLE_COULDNT_CONNECT;
+
+ if(ret/100 != 3) {
+ switch(ret) {
+ case 504:
+ infof(data, "Mechanism %s is not supported by the server (server "
+ "returned ftp code: 504).\n", mech->name);
+ break;
+ case 534:
+ infof(data, "Mechanism %s was rejected by the server (server returned "
+ "ftp code: 534).\n", mech->name);
+ break;
+ default:
+ if(ret/100 == 5) {
+ infof(data, "server does not support the security extensions\n");
+ return CURLE_USE_SSL_FAILED;
+ }
+ break;
+ }
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Authenticate */
+ ret = mech->auth(conn->app_data, conn);
+
+ if(ret != AUTH_CONTINUE) {
+ if(ret != AUTH_OK) {
+ /* Mechanism has dumped the error to stderr, don't error here. */
+ return -1;
+ }
+ DEBUGASSERT(ret == AUTH_OK);
+
+ conn->mech = mech;
+ conn->sec_complete = 1;
+ conn->recv[FIRSTSOCKET] = sec_recv;
+ conn->send[FIRSTSOCKET] = sec_send;
+ conn->recv[SECONDARYSOCKET] = sec_recv;
+ conn->send[SECONDARYSOCKET] = sec_send;
+ conn->command_prot = PROT_SAFE;
+ /* Set the requested protection level */
+ /* BLOCKING */
+ (void)sec_set_protection_level(conn);
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_sec_login(struct connectdata *conn)
+{
+ return choose_mech(conn);
+}
+
+
+void
+Curl_sec_end(struct connectdata *conn)
+{
+ if(conn->mech != NULL && conn->mech->end)
+ conn->mech->end(conn->app_data);
+ free(conn->app_data);
+ conn->app_data = NULL;
+ if(conn->in_buffer.data) {
+ free(conn->in_buffer.data);
+ conn->in_buffer.data = NULL;
+ conn->in_buffer.size = 0;
+ conn->in_buffer.index = 0;
+ /* FIXME: Is this really needed? */
+ conn->in_buffer.eof_flag = 0;
+ }
+ conn->sec_complete = 0;
+ conn->data_prot = PROT_CLEAR;
+ conn->mech = NULL;
+}
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/lib/select.c b/Utilities/cmcurl/lib/select.c
new file mode 100644
index 000000000..443007227
--- /dev/null
+++ b/Utilities/cmcurl/lib/select.c
@@ -0,0 +1,583 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
+#error "We can't compile without select() or poll() support."
+#endif
+
+#if defined(__BEOS__)
+/* BeOS has FD_SET defined in socket.h */
+#include <socket.h>
+#endif
+
+#ifdef MSDOS
+#include <dos.h> /* delay() */
+#endif
+
+#ifdef __VXWORKS__
+#include <strings.h> /* bzero() in FD_SET */
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "connect.h"
+#include "select.h"
+#include "warnless.h"
+
+/* Convenience local macros */
+#define ELAPSED_MS() (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
+
+int Curl_ack_eintr = 0;
+#define ERROR_NOT_EINTR(error) (Curl_ack_eintr || error != EINTR)
+
+/*
+ * Internal function used for waiting a specific amount of ms
+ * in Curl_socket_check() and Curl_poll() when no file descriptor
+ * is provided to wait on, just being used to delay execution.
+ * WinSock select() and poll() timeout mechanisms need a valid
+ * socket descriptor in a not null file descriptor set to work.
+ * Waiting indefinitely with this function is not allowed, a
+ * zero or negative timeout value will return immediately.
+ * Timeout resolution, accuracy, as well as maximum supported
+ * value is system dependent, neither factor is a citical issue
+ * for the intended use of this function in the library.
+ *
+ * Return values:
+ * -1 = system call error, invalid timeout value, or interrupted
+ * 0 = specified timeout has elapsed
+ */
+int Curl_wait_ms(int timeout_ms)
+{
+#if !defined(MSDOS) && !defined(USE_WINSOCK)
+#ifndef HAVE_POLL_FINE
+ struct timeval pending_tv;
+#endif
+ struct timeval initial_tv;
+ int pending_ms;
+ int error;
+#endif
+ int r = 0;
+
+ if(!timeout_ms)
+ return 0;
+ if(timeout_ms < 0) {
+ SET_SOCKERRNO(EINVAL);
+ return -1;
+ }
+#if defined(MSDOS)
+ delay(timeout_ms);
+#elif defined(USE_WINSOCK)
+ Sleep(timeout_ms);
+#else
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+ do {
+#if defined(HAVE_POLL_FINE)
+ r = poll(NULL, 0, pending_ms);
+#else
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ r = select(0, NULL, NULL, NULL, &pending_tv);
+#endif /* HAVE_POLL_FINE */
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && ERROR_NOT_EINTR(error))
+ break;
+ pending_ms = timeout_ms - ELAPSED_MS();
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ } while(r == -1);
+#endif /* USE_WINSOCK */
+ if(r)
+ r = -1;
+ return r;
+}
+
+/*
+ * Wait for read or write events on a set of file descriptors. It uses poll()
+ * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
+ * otherwise select() is used. An error is returned if select() is being used
+ * and a file descriptor is too large for FD_SETSIZE.
+ *
+ * A negative timeout value makes this function wait indefinitely,
+ * unless no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ * -1 = system call error or fd >= FD_SETSIZE
+ * 0 = timeout
+ * [bitmask] = action as described below
+ *
+ * CURL_CSELECT_IN - first socket is readable
+ * CURL_CSELECT_IN2 - second socket is readable
+ * CURL_CSELECT_OUT - write socket is writable
+ * CURL_CSELECT_ERR - an error condition occurred
+ */
+int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
+ curl_socket_t readfd1,
+ curl_socket_t writefd, /* socket to write to */
+ time_t timeout_ms) /* milliseconds to wait */
+{
+#ifdef HAVE_POLL_FINE
+ struct pollfd pfd[3];
+ int num;
+#else
+ struct timeval pending_tv;
+ struct timeval *ptimeout;
+ fd_set fds_read;
+ fd_set fds_write;
+ fd_set fds_err;
+ curl_socket_t maxfd;
+#endif
+ struct timeval initial_tv = {0, 0};
+ int pending_ms = 0;
+ int error;
+ int r;
+ int ret;
+
+#if SIZEOF_TIME_T != SIZEOF_INT
+ /* wrap-around precaution */
+ if(timeout_ms >= INT_MAX)
+ timeout_ms = INT_MAX;
+#endif
+
+ if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
+ (writefd == CURL_SOCKET_BAD)) {
+ /* no sockets, just wait */
+ r = Curl_wait_ms((int)timeout_ms);
+ return r;
+ }
+
+ /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ time in this function does not need to be measured. This happens
+ when function is called with a zero timeout or a negative timeout
+ value indicating a blocking call should be performed. */
+
+ if(timeout_ms > 0) {
+ pending_ms = (int)timeout_ms;
+ initial_tv = curlx_tvnow();
+ }
+
+#ifdef HAVE_POLL_FINE
+
+ num = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ pfd[num].fd = readfd0;
+ pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+ pfd[num].revents = 0;
+ num++;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ pfd[num].fd = readfd1;
+ pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+ pfd[num].revents = 0;
+ num++;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ pfd[num].fd = writefd;
+ pfd[num].events = POLLWRNORM|POLLOUT;
+ pfd[num].revents = 0;
+ num++;
+ }
+
+ do {
+ if(timeout_ms < 0)
+ pending_ms = -1;
+ else if(!timeout_ms)
+ pending_ms = 0;
+ r = poll(pfd, num, pending_ms);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && ERROR_NOT_EINTR(error))
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = (int)(timeout_ms - ELAPSED_MS());
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ ret = 0;
+ num = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+ ret |= CURL_CSELECT_IN;
+ if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ num++;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+ ret |= CURL_CSELECT_IN2;
+ if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ num++;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLWRNORM|POLLOUT))
+ ret |= CURL_CSELECT_OUT;
+ if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ }
+
+ return ret;
+
+#else /* HAVE_POLL_FINE */
+
+ FD_ZERO(&fds_err);
+ maxfd = (curl_socket_t)-1;
+
+ FD_ZERO(&fds_read);
+ if(readfd0 != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(readfd0);
+ FD_SET(readfd0, &fds_read);
+ FD_SET(readfd0, &fds_err);
+ maxfd = readfd0;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(readfd1);
+ FD_SET(readfd1, &fds_read);
+ FD_SET(readfd1, &fds_err);
+ if(readfd1 > maxfd)
+ maxfd = readfd1;
+ }
+
+ FD_ZERO(&fds_write);
+ if(writefd != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(writefd);
+ FD_SET(writefd, &fds_write);
+ FD_SET(writefd, &fds_err);
+ if(writefd > maxfd)
+ maxfd = writefd;
+ }
+
+ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+ do {
+ if(timeout_ms > 0) {
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ }
+ else if(!timeout_ms) {
+ pending_tv.tv_sec = 0;
+ pending_tv.tv_usec = 0;
+ }
+
+ /* WinSock select() must not be called with an fd_set that contains zero
+ fd flags, or it will return WSAEINVAL. But, it also can't be called
+ with no fd_sets at all! From the documentation:
+
+ Any two of the parameters, readfds, writefds, or exceptfds, can be
+ given as null. At least one must be non-null, and any non-null
+ descriptor set must contain at least one handle to a socket.
+
+ We know that we have at least one bit set in at least two fd_sets in
+ this case, but we may have no bits set in either fds_read or fd_write,
+ so check for that and handle it. Luckily, with WinSock, we can _also_
+ ask how many bits are set on an fd_set.
+
+ It is unclear why WinSock doesn't just handle this for us instead of
+ calling this an error.
+
+ Note also that WinSock ignores the first argument, so we don't worry
+ about the fact that maxfd is computed incorrectly with WinSock (since
+ curl_socket_t is unsigned in such cases and thus -1 is the largest
+ value).
+ */
+#ifdef USE_WINSOCK
+ r = select((int)maxfd + 1,
+ fds_read.fd_count ? &fds_read : NULL,
+ fds_write.fd_count ? &fds_write : NULL,
+ &fds_err, ptimeout);
+#else
+ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+#endif
+
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && ERROR_NOT_EINTR(error))
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = (int)(timeout_ms - ELAPSED_MS());
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ ret = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ if(FD_ISSET(readfd0, &fds_read))
+ ret |= CURL_CSELECT_IN;
+ if(FD_ISSET(readfd0, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ if(FD_ISSET(readfd1, &fds_read))
+ ret |= CURL_CSELECT_IN2;
+ if(FD_ISSET(readfd1, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ if(FD_ISSET(writefd, &fds_write))
+ ret |= CURL_CSELECT_OUT;
+ if(FD_ISSET(writefd, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+
+ return ret;
+
+#endif /* HAVE_POLL_FINE */
+
+}
+
+/*
+ * This is a wrapper around poll(). If poll() does not exist, then
+ * select() is used instead. An error is returned if select() is
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unless no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ * -1 = system call error or fd >= FD_SETSIZE
+ * 0 = timeout
+ * N = number of structures with non zero revent fields
+ */
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
+{
+#ifndef HAVE_POLL_FINE
+ struct timeval pending_tv;
+ struct timeval *ptimeout;
+ fd_set fds_read;
+ fd_set fds_write;
+ fd_set fds_err;
+ curl_socket_t maxfd;
+#endif
+ struct timeval initial_tv = {0, 0};
+ bool fds_none = TRUE;
+ unsigned int i;
+ int pending_ms = 0;
+ int error;
+ int r;
+
+ if(ufds) {
+ for(i = 0; i < nfds; i++) {
+ if(ufds[i].fd != CURL_SOCKET_BAD) {
+ fds_none = FALSE;
+ break;
+ }
+ }
+ }
+ if(fds_none) {
+ r = Curl_wait_ms(timeout_ms);
+ return r;
+ }
+
+ /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ time in this function does not need to be measured. This happens
+ when function is called with a zero timeout or a negative timeout
+ value indicating a blocking call should be performed. */
+
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+ }
+
+#ifdef HAVE_POLL_FINE
+
+ do {
+ if(timeout_ms < 0)
+ pending_ms = -1;
+ else if(!timeout_ms)
+ pending_ms = 0;
+ r = poll(ufds, nfds, pending_ms);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && ERROR_NOT_EINTR(error))
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = (int)(timeout_ms - ELAPSED_MS());
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ for(i = 0; i < nfds; i++) {
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ if(ufds[i].revents & POLLHUP)
+ ufds[i].revents |= POLLIN;
+ if(ufds[i].revents & POLLERR)
+ ufds[i].revents |= (POLLIN|POLLOUT);
+ }
+
+#else /* HAVE_POLL_FINE */
+
+ FD_ZERO(&fds_read);
+ FD_ZERO(&fds_write);
+ FD_ZERO(&fds_err);
+ maxfd = (curl_socket_t)-1;
+
+ for(i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ VERIFY_SOCK(ufds[i].fd);
+ if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
+ POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
+ if(ufds[i].fd > maxfd)
+ maxfd = ufds[i].fd;
+ if(ufds[i].events & (POLLRDNORM|POLLIN))
+ FD_SET(ufds[i].fd, &fds_read);
+ if(ufds[i].events & (POLLWRNORM|POLLOUT))
+ FD_SET(ufds[i].fd, &fds_write);
+ if(ufds[i].events & (POLLRDBAND|POLLPRI))
+ FD_SET(ufds[i].fd, &fds_err);
+ }
+ }
+
+#ifdef USE_WINSOCK
+ /* WinSock select() can't handle zero events. See the comment about this in
+ Curl_check_socket(). */
+ if(fds_read.fd_count == 0 && fds_write.fd_count == 0
+ && fds_err.fd_count == 0) {
+ r = Curl_wait_ms(timeout_ms);
+ return r;
+ }
+#endif
+
+ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+ do {
+ if(timeout_ms > 0) {
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ }
+ else if(!timeout_ms) {
+ pending_tv.tv_sec = 0;
+ pending_tv.tv_usec = 0;
+ }
+
+#ifdef USE_WINSOCK
+ r = select((int)maxfd + 1,
+ /* WinSock select() can't handle fd_sets with zero bits set, so
+ don't give it such arguments. See the comment about this in
+ Curl_check_socket().
+ */
+ fds_read.fd_count ? &fds_read : NULL,
+ fds_write.fd_count ? &fds_write : NULL,
+ fds_err.fd_count ? &fds_err : NULL, ptimeout);
+#else
+ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+#endif
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && ERROR_NOT_EINTR(error))
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms - ELAPSED_MS();
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ r = 0;
+ for(i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ if(FD_ISSET(ufds[i].fd, &fds_read))
+ ufds[i].revents |= POLLIN;
+ if(FD_ISSET(ufds[i].fd, &fds_write))
+ ufds[i].revents |= POLLOUT;
+ if(FD_ISSET(ufds[i].fd, &fds_err))
+ ufds[i].revents |= POLLPRI;
+ if(ufds[i].revents != 0)
+ r++;
+ }
+
+#endif /* HAVE_POLL_FINE */
+
+ return r;
+}
+
+#ifdef TPF
+/*
+ * This is a replacement for select() on the TPF platform.
+ * It is used whenever libcurl calls select().
+ * The call below to tpf_process_signals() is required because
+ * TPF's select calls are not signal interruptible.
+ *
+ * Return values are the same as select's.
+ */
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+ fd_set* excepts, struct timeval* tv)
+{
+ int rc;
+
+ rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
+ tpf_process_signals();
+ return rc;
+}
+#endif /* TPF */
diff --git a/Utilities/cmcurl/lib/select.h b/Utilities/cmcurl/lib/select.h
new file mode 100644
index 000000000..4ed5dd2f8
--- /dev/null
+++ b/Utilities/cmcurl/lib/select.h
@@ -0,0 +1,115 @@
+#ifndef HEADER_CURL_SELECT_H
+#define HEADER_CURL_SELECT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#elif defined(HAVE_SYS_POLL_H)
+#include <sys/poll.h>
+#endif
+
+/*
+ * Definition of pollfd struct and constants for platforms lacking them.
+ */
+
+#if !defined(HAVE_STRUCT_POLLFD) && \
+ !defined(HAVE_SYS_POLL_H) && \
+ !defined(HAVE_POLL_H)
+
+#define POLLIN 0x01
+#define POLLPRI 0x02
+#define POLLOUT 0x04
+#define POLLERR 0x08
+#define POLLHUP 0x10
+#define POLLNVAL 0x20
+
+struct pollfd
+{
+ curl_socket_t fd;
+ short events;
+ short revents;
+};
+
+#endif
+
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+#ifndef POLLRDBAND
+#define POLLRDBAND POLLPRI
+#endif
+
+/* there are three CSELECT defines that are defined in the public header that
+ are exposed to users, but this *IN2 bit is only ever used internally and
+ therefore defined here */
+#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1)
+
+int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
+ curl_socket_t writefd,
+ time_t timeout_ms);
+
+#define SOCKET_READABLE(x,z) \
+ Curl_socket_check(x, CURL_SOCKET_BAD, CURL_SOCKET_BAD, z)
+#define SOCKET_WRITABLE(x,z) \
+ Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z)
+
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
+
+/* On non-DOS and non-Winsock platforms, when Curl_ack_eintr is set,
+ * EINTR condition is honored and function might exit early without
+ * awaiting full timeout. Otherwise EINTR will be ignored and full
+ * timeout will elapse. */
+extern int Curl_ack_eintr;
+
+int Curl_wait_ms(int timeout_ms);
+
+#ifdef TPF
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+ fd_set* excepts, struct timeval* tv);
+#endif
+
+/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which
+ unfortunately makes it impossible for us to easily check if they're valid
+*/
+#if defined(USE_WINSOCK) || defined(TPF)
+#define VALID_SOCK(x) 1
+#define VERIFY_SOCK(x) Curl_nop_stmt
+#else
+#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
+#define VERIFY_SOCK(x) do { \
+ if(!VALID_SOCK(x)) { \
+ SET_SOCKERRNO(EINVAL); \
+ return -1; \
+ } \
+} WHILE_FALSE
+#endif
+
+#endif /* HEADER_CURL_SELECT_H */
+
diff --git a/Utilities/cmcurl/lib/sendf.c b/Utilities/cmcurl/lib/sendf.c
new file mode 100644
index 000000000..595c36177
--- /dev/null
+++ b/Utilities/cmcurl/lib/sendf.c
@@ -0,0 +1,855 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "vtls/vtls.h"
+#include "ssh.h"
+#include "multiif.h"
+#include "non-ascii.h"
+#include "strerror.h"
+#include "select.h"
+#include "strdup.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef CURL_DO_LINEEND_CONV
+/*
+ * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
+ * (\n), with special processing for CRLF sequences that are split between two
+ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
+ * size of the data is returned.
+ */
+static size_t convert_lineends(struct Curl_easy *data,
+ char *startPtr, size_t size)
+{
+ char *inPtr, *outPtr;
+
+ /* sanity check */
+ if((startPtr == NULL) || (size < 1)) {
+ return size;
+ }
+
+ if(data->state.prev_block_had_trailing_cr) {
+ /* The previous block of incoming data
+ had a trailing CR, which was turned into a LF. */
+ if(*startPtr == '\n') {
+ /* This block of incoming data starts with the
+ previous block's LF so get rid of it */
+ memmove(startPtr, startPtr+1, size-1);
+ size--;
+ /* and it wasn't a bare CR but a CRLF conversion instead */
+ data->state.crlf_conversions++;
+ }
+ data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
+ }
+
+ /* find 1st CR, if any */
+ inPtr = outPtr = memchr(startPtr, '\r', size);
+ if(inPtr) {
+ /* at least one CR, now look for CRLF */
+ while(inPtr < (startPtr+size-1)) {
+ /* note that it's size-1, so we'll never look past the last byte */
+ if(memcmp(inPtr, "\r\n", 2) == 0) {
+ /* CRLF found, bump past the CR and copy the NL */
+ inPtr++;
+ *outPtr = *inPtr;
+ /* keep track of how many CRLFs we converted */
+ data->state.crlf_conversions++;
+ }
+ else {
+ if(*inPtr == '\r') {
+ /* lone CR, move LF instead */
+ *outPtr = '\n';
+ }
+ else {
+ /* not a CRLF nor a CR, just copy whatever it is */
+ *outPtr = *inPtr;
+ }
+ }
+ outPtr++;
+ inPtr++;
+ } /* end of while loop */
+
+ if(inPtr < startPtr+size) {
+ /* handle last byte */
+ if(*inPtr == '\r') {
+ /* deal with a CR at the end of the buffer */
+ *outPtr = '\n'; /* copy a NL instead */
+ /* note that a CRLF might be split across two blocks */
+ data->state.prev_block_had_trailing_cr = TRUE;
+ }
+ else {
+ /* copy last byte */
+ *outPtr = *inPtr;
+ }
+ outPtr++;
+ }
+ if(outPtr < startPtr+size)
+ /* tidy up by null terminating the now shorter data */
+ *outPtr = '\0';
+
+ return (outPtr - startPtr);
+ }
+ return size;
+}
+#endif /* CURL_DO_LINEEND_CONV */
+
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
+{
+ struct postponed_data * const psnd = &(conn->postponed[sockindex]);
+ return psnd->buffer && psnd->allocated_size &&
+ psnd->recv_size > psnd->recv_processed;
+}
+
+static void pre_receive_plain(struct connectdata *conn, int num)
+{
+ const curl_socket_t sockfd = conn->sock[num];
+ struct postponed_data * const psnd = &(conn->postponed[num]);
+ size_t bytestorecv = psnd->allocated_size - psnd->recv_size;
+ /* WinSock will destroy unread received data if send() is
+ failed.
+ To avoid lossage of received data, recv() must be
+ performed before every send() if any incoming data is
+ available. However, skip this, if buffer is already full. */
+ if((conn->handler->protocol&PROTO_FAMILY_HTTP) != 0 &&
+ conn->recv[num] == Curl_recv_plain &&
+ (!psnd->buffer || bytestorecv)) {
+ const int readymask = Curl_socket_check(sockfd, CURL_SOCKET_BAD,
+ CURL_SOCKET_BAD, 0);
+ if(readymask != -1 && (readymask & CURL_CSELECT_IN) != 0) {
+ /* Have some incoming data */
+ if(!psnd->buffer) {
+ /* Use buffer double default size for intermediate buffer */
+ psnd->allocated_size = 2 * conn->data->set.buffer_size;
+ psnd->buffer = malloc(psnd->allocated_size);
+ psnd->recv_size = 0;
+ psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+ psnd->bindsock = sockfd; /* Used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+ bytestorecv = psnd->allocated_size;
+ }
+ if(psnd->buffer) {
+ ssize_t recvedbytes;
+ DEBUGASSERT(psnd->bindsock == sockfd);
+ recvedbytes = sread(sockfd, psnd->buffer + psnd->recv_size,
+ bytestorecv);
+ if(recvedbytes > 0)
+ psnd->recv_size += recvedbytes;
+ }
+ else
+ psnd->allocated_size = 0;
+ }
+ }
+}
+
+static ssize_t get_pre_recved(struct connectdata *conn, int num, char *buf,
+ size_t len)
+{
+ struct postponed_data * const psnd = &(conn->postponed[num]);
+ size_t copysize;
+ if(!psnd->buffer)
+ return 0;
+
+ DEBUGASSERT(psnd->allocated_size > 0);
+ DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
+ DEBUGASSERT(psnd->recv_processed <= psnd->recv_size);
+ /* Check and process data that already received and storied in internal
+ intermediate buffer */
+ if(psnd->recv_size > psnd->recv_processed) {
+ DEBUGASSERT(psnd->bindsock == conn->sock[num]);
+ copysize = CURLMIN(len, psnd->recv_size - psnd->recv_processed);
+ memcpy(buf, psnd->buffer + psnd->recv_processed, copysize);
+ psnd->recv_processed += copysize;
+ }
+ else
+ copysize = 0; /* buffer was allocated, but nothing was received */
+
+ /* Free intermediate buffer if it has no unprocessed data */
+ if(psnd->recv_processed == psnd->recv_size) {
+ free(psnd->buffer);
+ psnd->buffer = NULL;
+ psnd->allocated_size = 0;
+ psnd->recv_size = 0;
+ psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+ psnd->bindsock = CURL_SOCKET_BAD;
+#endif /* DEBUGBUILD */
+ }
+ return (ssize_t)copysize;
+}
+#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+/* Use "do-nothing" macros instead of functions when workaround not used */
+bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
+{
+ (void)conn;
+ (void)sockindex;
+ return false;
+}
+#define pre_receive_plain(c,n) do {} WHILE_FALSE
+#define get_pre_recved(c,n,b,l) 0
+#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+
+/* Curl_infof() is for info message along the way */
+
+void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
+{
+ if(data && data->set.verbose) {
+ va_list ap;
+ size_t len;
+ char print_buffer[2048 + 1];
+ va_start(ap, fmt);
+ vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ va_end(ap);
+ len = strlen(print_buffer);
+ Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
+ }
+}
+
+/* Curl_failf() is for messages stating why we failed.
+ * The message SHALL NOT include any LF or CR.
+ */
+
+void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
+{
+ va_list ap;
+ size_t len;
+ char error[CURL_ERROR_SIZE + 2];
+ va_start(ap, fmt);
+
+ vsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
+ len = strlen(error);
+
+ if(data->set.errorbuffer && !data->state.errorbuf) {
+ strcpy(data->set.errorbuffer, error);
+ data->state.errorbuf = TRUE; /* wrote error string */
+ }
+ if(data->set.verbose) {
+ error[len] = '\n';
+ error[++len] = '\0';
+ Curl_debug(data, CURLINFO_TEXT, error, len, NULL);
+ }
+
+ va_end(ap);
+}
+
+/* Curl_sendf() sends formatted data to the server */
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
+ const char *fmt, ...)
+{
+ struct Curl_easy *data = conn->data;
+ ssize_t bytes_written;
+ size_t write_len;
+ CURLcode result = CURLE_OK;
+ char *s;
+ char *sptr;
+ va_list ap;
+ va_start(ap, fmt);
+ s = vaprintf(fmt, ap); /* returns an allocated string */
+ va_end(ap);
+ if(!s)
+ return CURLE_OUT_OF_MEMORY; /* failure */
+
+ bytes_written=0;
+ write_len = strlen(s);
+ sptr = s;
+
+ for(;;) {
+ /* Write the buffer to the socket */
+ result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
+
+ if(result)
+ break;
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
+
+ if((size_t)bytes_written != write_len) {
+ /* if not all was written at once, we must advance the pointer, decrease
+ the size left and try again! */
+ write_len -= bytes_written;
+ sptr += bytes_written;
+ }
+ else
+ break;
+ }
+
+ free(s); /* free the output string */
+
+ return result;
+}
+
+/*
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
+ *
+ * If the write would block (CURLE_AGAIN), we return CURLE_OK and
+ * (*written == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem,
+ size_t len,
+ ssize_t *written)
+{
+ ssize_t bytes_written;
+ CURLcode result = CURLE_OK;
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ bytes_written = conn->send[num](conn, num, mem, len, &result);
+
+ *written = bytes_written;
+ if(bytes_written >= 0)
+ /* we completely ignore the curlcode value when subzero is not returned */
+ return CURLE_OK;
+
+ /* handle CURLE_AGAIN or a send failure */
+ switch(result) {
+ case CURLE_AGAIN:
+ *written = 0;
+ return CURLE_OK;
+
+ case CURLE_OK:
+ /* general send failure */
+ return CURLE_SEND_ERROR;
+
+ default:
+ /* we got a specific curlcode, forward it */
+ return result;
+ }
+}
+
+ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ const void *mem, size_t len, CURLcode *code)
+{
+ curl_socket_t sockfd = conn->sock[num];
+ ssize_t bytes_written;
+ /* WinSock will destroy unread received data if send() is
+ failed.
+ To avoid lossage of received data, recv() must be
+ performed before every send() if any incoming data is
+ available. */
+ pre_receive_plain(conn, num);
+
+#ifdef MSG_FASTOPEN /* Linux */
+ if(conn->bits.tcp_fastopen) {
+ bytes_written = sendto(sockfd, mem, len, MSG_FASTOPEN,
+ conn->ip_addr->ai_addr, conn->ip_addr->ai_addrlen);
+ conn->bits.tcp_fastopen = FALSE;
+ }
+ else
+#endif
+ bytes_written = swrite(sockfd, mem, len);
+
+ *code = CURLE_OK;
+ if(-1 == bytes_written) {
+ int err = SOCKERRNO;
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefor
+ treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err) ||
+ (EINPROGRESS == err)
+#endif
+ ) {
+ /* this is just a case of EWOULDBLOCK */
+ bytes_written=0;
+ *code = CURLE_AGAIN;
+ }
+ else {
+ failf(conn->data, "Send failure: %s",
+ Curl_strerror(conn, err));
+ conn->data->state.os_errno = err;
+ *code = CURLE_SEND_ERROR;
+ }
+ }
+ return bytes_written;
+}
+
+/*
+ * Curl_write_plain() is an internal write function that sends data to the
+ * server using plain sockets only. Otherwise meant to have the exact same
+ * proto as Curl_write()
+ */
+CURLcode Curl_write_plain(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem,
+ size_t len,
+ ssize_t *written)
+{
+ ssize_t bytes_written;
+ CURLcode result;
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ bytes_written = Curl_send_plain(conn, num, mem, len, &result);
+
+ *written = bytes_written;
+
+ return result;
+}
+
+ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ size_t len, CURLcode *code)
+{
+ curl_socket_t sockfd = conn->sock[num];
+ ssize_t nread;
+ /* Check and return data that already received and storied in internal
+ intermediate buffer */
+ nread = get_pre_recved(conn, num, buf, len);
+ if(nread > 0) {
+ *code = CURLE_OK;
+ return nread;
+ }
+
+ nread = sread(sockfd, buf, len);
+
+ *code = CURLE_OK;
+ if(-1 == nread) {
+ int err = SOCKERRNO;
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefor
+ treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+ ) {
+ /* this is just a case of EWOULDBLOCK */
+ *code = CURLE_AGAIN;
+ }
+ else {
+ failf(conn->data, "Recv failure: %s",
+ Curl_strerror(conn, err));
+ conn->data->state.os_errno = err;
+ *code = CURLE_RECV_ERROR;
+ }
+ }
+ return nread;
+}
+
+static CURLcode pausewrite(struct Curl_easy *data,
+ int type, /* what type of data */
+ const char *ptr,
+ size_t len)
+{
+ /* signalled to pause sending on this connection, but since we have data
+ we want to send we need to dup it to save a copy for when the sending
+ is again enabled */
+ struct SingleRequest *k = &data->req;
+ struct UrlState *s = &data->state;
+ char *dupl;
+ unsigned int i;
+ bool newtype = TRUE;
+
+ if(s->tempcount) {
+ for(i=0; i< s->tempcount; i++) {
+ if(s->tempwrite[i].type == type) {
+ /* data for this type exists */
+ newtype = FALSE;
+ break;
+ }
+ }
+ DEBUGASSERT(i < 3);
+ }
+ else
+ i = 0;
+
+ if(!newtype) {
+ /* append new data to old data */
+
+ /* figure out the new size of the data to save */
+ size_t newlen = len + s->tempwrite[i].len;
+ /* allocate the new memory area */
+ char *newptr = realloc(s->tempwrite[i].buf, newlen);
+ if(!newptr)
+ return CURLE_OUT_OF_MEMORY;
+ /* copy the new data to the end of the new area */
+ memcpy(newptr + s->tempwrite[i].len, ptr, len);
+
+ /* update the pointer and the size */
+ s->tempwrite[i].buf = newptr;
+ s->tempwrite[i].len = newlen;
+ }
+ else {
+ dupl = Curl_memdup(ptr, len);
+ if(!dupl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* store this information in the state struct for later use */
+ s->tempwrite[i].buf = dupl;
+ s->tempwrite[i].len = len;
+ s->tempwrite[i].type = type;
+
+ if(newtype)
+ s->tempcount++;
+ }
+
+ /* mark the connection as RECV paused */
+ k->keepon |= KEEP_RECV_PAUSE;
+
+ DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n",
+ len, type));
+
+ return CURLE_OK;
+}
+
+
+/* Curl_client_chop_write() writes chunks of data not larger than
+ * CURL_MAX_WRITE_SIZE via client write callback(s) and
+ * takes care of pause requests from the callbacks.
+ */
+CURLcode Curl_client_chop_write(struct connectdata *conn,
+ int type,
+ char *ptr,
+ size_t len)
+{
+ struct Curl_easy *data = conn->data;
+ curl_write_callback writeheader = NULL;
+ curl_write_callback writebody = NULL;
+
+ if(!len)
+ return CURLE_OK;
+
+ /* If reading is paused, append this data to the already held data for this
+ type. */
+ if(data->req.keepon & KEEP_RECV_PAUSE)
+ return pausewrite(data, type, ptr, len);
+
+ /* Determine the callback(s) to use. */
+ if(type & CLIENTWRITE_BODY)
+ writebody = data->set.fwrite_func;
+ if((type & CLIENTWRITE_HEADER) &&
+ (data->set.fwrite_header || data->set.writeheader)) {
+ /*
+ * Write headers to the same callback or to the especially setup
+ * header callback function (added after version 7.7.1).
+ */
+ writeheader =
+ data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
+ }
+
+ /* Chop data, write chunks. */
+ while(len) {
+ size_t chunklen = len <= CURL_MAX_WRITE_SIZE? len: CURL_MAX_WRITE_SIZE;
+
+ if(writebody) {
+ size_t wrote = writebody(ptr, 1, chunklen, data->set.out);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote) {
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ /* Protocols that work without network cannot be paused. This is
+ actually only FILE:// just now, and it can't pause since the
+ transfer isn't done using the "normal" procedure. */
+ failf(data, "Write callback asked for PAUSE when not supported!");
+ return CURLE_WRITE_ERROR;
+ }
+ return pausewrite(data, type, ptr, len);
+ }
+ if(wrote != chunklen) {
+ failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen);
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ if(writeheader) {
+ size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote)
+ /* here we pass in the HEADER bit only since if this was body as well
+ then it was passed already and clearly that didn't trigger the
+ pause, so this is saved for later with the HEADER bit only */
+ return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
+
+ if(wrote != chunklen) {
+ failf(data, "Failed writing header");
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ ptr += chunklen;
+ len -= chunklen;
+ }
+
+ return CURLE_OK;
+}
+
+
+/* Curl_client_write() sends data to the write callback(s)
+
+ The bit pattern defines to what "streams" to write to. Body and/or header.
+ The defines are in sendf.h of course.
+
+ If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
+ local character encoding. This is a problem and should be changed in
+ the future to leave the original data alone.
+ */
+CURLcode Curl_client_write(struct connectdata *conn,
+ int type,
+ char *ptr,
+ size_t len)
+{
+ struct Curl_easy *data = conn->data;
+
+ if(0 == len)
+ len = strlen(ptr);
+
+ DEBUGASSERT(type <= 3);
+
+ /* FTP data may need conversion. */
+ if((type & CLIENTWRITE_BODY) &&
+ (conn->handler->protocol & PROTO_FAMILY_FTP) &&
+ conn->proto.ftpc.transfertype == 'A') {
+ /* convert from the network encoding */
+ CURLcode result = Curl_convert_from_network(data, ptr, len);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+#ifdef CURL_DO_LINEEND_CONV
+ /* convert end-of-line markers */
+ len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
+ }
+
+ return Curl_client_chop_write(conn, type, ptr, len);
+}
+
+CURLcode Curl_read_plain(curl_socket_t sockfd,
+ char *buf,
+ size_t bytesfromsocket,
+ ssize_t *n)
+{
+ ssize_t nread = sread(sockfd, buf, bytesfromsocket);
+
+ if(-1 == nread) {
+ int err = SOCKERRNO;
+ int return_error;
+#ifdef USE_WINSOCK
+ return_error = WSAEWOULDBLOCK == err;
+#else
+ return_error = EWOULDBLOCK == err || EAGAIN == err || EINTR == err;
+#endif
+ if(return_error)
+ return CURLE_AGAIN;
+ return CURLE_RECV_ERROR;
+ }
+
+ /* we only return number of bytes read when we return OK */
+ *n = nread;
+ return CURLE_OK;
+}
+
+/*
+ * Internal read-from-socket function. This is meant to deal with plain
+ * sockets, SSL sockets and kerberos sockets.
+ *
+ * Returns a regular CURLcode value.
+ */
+CURLcode Curl_read(struct connectdata *conn, /* connection data */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ size_t sizerequested, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
+{
+ CURLcode result = CURLE_RECV_ERROR;
+ ssize_t nread = 0;
+ size_t bytesfromsocket = 0;
+ char *buffertofill = NULL;
+ struct Curl_easy *data = conn->data;
+
+ /* if HTTP/1 pipelining is both wanted and possible */
+ bool pipelining = Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
+ (conn->bundle->multiuse == BUNDLE_PIPELINING);
+
+ /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+ If it is the second socket, we set num to 1. Otherwise to 0. This lets
+ us use the correct ssl handle. */
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ *n=0; /* reset amount to zero */
+
+ /* If session can pipeline, check connection buffer */
+ if(pipelining) {
+ size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
+ sizerequested);
+
+ /* Copy from our master buffer first if we have some unread data there*/
+ if(bytestocopy > 0) {
+ memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
+ conn->read_pos += bytestocopy;
+ conn->bits.stream_was_rewound = FALSE;
+
+ *n = (ssize_t)bytestocopy;
+ return CURLE_OK;
+ }
+ /* If we come here, it means that there is no data to read from the buffer,
+ * so we read from the socket */
+ bytesfromsocket = CURLMIN(sizerequested, MASTERBUF_SIZE);
+ buffertofill = conn->master_buffer;
+ }
+ else {
+ bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
+ buffertofill = buf;
+ }
+
+ nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
+ if(nread < 0)
+ return result;
+
+ if(pipelining) {
+ memcpy(buf, conn->master_buffer, nread);
+ conn->buf_len = nread;
+ conn->read_pos = nread;
+ }
+
+ *n += nread;
+
+ return CURLE_OK;
+}
+
+/* return 0 on success */
+static int showit(struct Curl_easy *data, curl_infotype type,
+ char *ptr, size_t size)
+{
+ static const char s_infotype[CURLINFO_END][3] = {
+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+ int rc = 0;
+
+#ifdef CURL_DOES_CONVERSIONS
+ char *buf = NULL;
+ size_t conv_size = 0;
+
+ switch(type) {
+ case CURLINFO_HEADER_OUT:
+ buf = Curl_memdup(ptr, size);
+ if(!buf)
+ return 1;
+ conv_size = size;
+
+ /* Special processing is needed for this block if it
+ * contains both headers and data (separated by CRLFCRLF).
+ * We want to convert just the headers, leaving the data as-is.
+ */
+ if(size > 4) {
+ size_t i;
+ for(i = 0; i < size-4; i++) {
+ if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
+ /* convert everything through this CRLFCRLF but no further */
+ conv_size = i + 4;
+ break;
+ }
+ }
+ }
+
+ Curl_convert_from_network(data, buf, conv_size);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* we might as well continue even if it fails... */
+ ptr = buf; /* switch pointer to use my buffer instead */
+ break;
+ default:
+ /* leave everything else as-is */
+ break;
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(data->set.fdebug)
+ rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
+ else {
+ switch(type) {
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_HEADER_IN:
+ fwrite(s_infotype[type], 2, 1, data->set.err);
+ fwrite(ptr, size, 1, data->set.err);
+#ifdef CURL_DOES_CONVERSIONS
+ if(size != conv_size) {
+ /* we had untranslated data so we need an explicit newline */
+ fwrite("\n", 1, 1, data->set.err);
+ }
+#endif
+ break;
+ default: /* nada */
+ break;
+ }
+ }
+#ifdef CURL_DOES_CONVERSIONS
+ free(buf);
+#endif
+ return rc;
+}
+
+int Curl_debug(struct Curl_easy *data, curl_infotype type,
+ char *ptr, size_t size,
+ struct connectdata *conn)
+{
+ int rc;
+ if(data->set.printhost && conn && conn->host.dispname) {
+ char buffer[160];
+ const char *t=NULL;
+ const char *w="Data";
+ switch(type) {
+ case CURLINFO_HEADER_IN:
+ w = "Header";
+ /* FALLTHROUGH */
+ case CURLINFO_DATA_IN:
+ t = "from";
+ break;
+ case CURLINFO_HEADER_OUT:
+ w = "Header";
+ /* FALLTHROUGH */
+ case CURLINFO_DATA_OUT:
+ t = "to";
+ break;
+ default:
+ break;
+ }
+
+ if(t) {
+ snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
+ conn->host.dispname);
+ rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
+ if(rc)
+ return rc;
+ }
+ }
+ rc = showit(data, type, ptr, size);
+ return rc;
+}
diff --git a/Utilities/cmcurl/lib/sendf.h b/Utilities/cmcurl/lib/sendf.h
new file mode 100644
index 000000000..fbe4f99c8
--- /dev/null
+++ b/Utilities/cmcurl/lib/sendf.h
@@ -0,0 +1,94 @@
+#ifndef HEADER_CURL_SENDF_H
+#define HEADER_CURL_SENDF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
+ const char *fmt, ...);
+void Curl_infof(struct Curl_easy *, const char *fmt, ...);
+void Curl_failf(struct Curl_easy *, const char *fmt, ...);
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+
+#if defined(HAVE_VARIADIC_MACROS_C99)
+#define infof(...) Curl_nop_stmt
+#elif defined(HAVE_VARIADIC_MACROS_GCC)
+#define infof(x...) Curl_nop_stmt
+#else
+#define infof (void)
+#endif
+
+#else /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define infof Curl_infof
+
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define failf Curl_failf
+
+#define CLIENTWRITE_BODY (1<<0)
+#define CLIENTWRITE_HEADER (1<<1)
+#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
+
+CURLcode Curl_client_chop_write(struct connectdata *conn, int type, char *ptr,
+ size_t len) WARN_UNUSED_RESULT;
+CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
+ size_t len) WARN_UNUSED_RESULT;
+
+bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex);
+
+/* internal read-function, does plain socket only */
+CURLcode Curl_read_plain(curl_socket_t sockfd,
+ char *buf,
+ size_t bytesfromsocket,
+ ssize_t *n);
+
+ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ size_t len, CURLcode *code);
+ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ const void *mem, size_t len, CURLcode *code);
+
+/* internal read-function, does plain socket, SSL and krb4 */
+CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd,
+ char *buf, size_t buffersize,
+ ssize_t *n);
+/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem, size_t len,
+ ssize_t *written);
+
+/* internal write-function, does plain sockets ONLY */
+CURLcode Curl_write_plain(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem, size_t len,
+ ssize_t *written);
+
+/* the function used to output verbose information */
+int Curl_debug(struct Curl_easy *handle, curl_infotype type,
+ char *data, size_t size,
+ struct connectdata *conn);
+
+
+#endif /* HEADER_CURL_SENDF_H */
diff --git a/Utilities/cmcurl/lib/setup-os400.h b/Utilities/cmcurl/lib/setup-os400.h
new file mode 100644
index 000000000..a3c2a7bdc
--- /dev/null
+++ b/Utilities/cmcurl/lib/setup-os400.h
@@ -0,0 +1,223 @@
+#ifndef HEADER_CURL_SETUP_OS400_H
+#define HEADER_CURL_SETUP_OS400_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+
+/* OS/400 netdb.h does not define NI_MAXHOST. */
+#define NI_MAXHOST 1025
+
+/* OS/400 netdb.h does not define NI_MAXSERV. */
+#define NI_MAXSERV 32
+
+/* No OS/400 header file defines u_int32_t. */
+typedef unsigned long u_int32_t;
+
+
+/* System API wrapper prototypes & definitions to support ASCII parameters. */
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <gskssl.h>
+#include <qsoasync.h>
+#include <gssapi.h>
+
+extern int Curl_getaddrinfo_a(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+#define getaddrinfo Curl_getaddrinfo_a
+
+
+extern int Curl_getnameinfo_a(const struct sockaddr *sa,
+ curl_socklen_t salen,
+ char *nodename, curl_socklen_t nodenamelen,
+ char *servname, curl_socklen_t servnamelen,
+ int flags);
+#define getnameinfo Curl_getnameinfo_a
+
+
+/* GSKit wrappers. */
+
+extern int Curl_gsk_environment_open(gsk_handle * my_env_handle);
+#define gsk_environment_open Curl_gsk_environment_open
+
+extern int Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
+ gsk_handle * my_session_handle);
+#define gsk_secure_soc_open Curl_gsk_secure_soc_open
+
+extern int Curl_gsk_environment_close(gsk_handle * my_env_handle);
+#define gsk_environment_close Curl_gsk_environment_close
+
+extern int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle);
+#define gsk_secure_soc_close Curl_gsk_secure_soc_close
+
+extern int Curl_gsk_environment_init(gsk_handle my_env_handle);
+#define gsk_environment_init Curl_gsk_environment_init
+
+extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle);
+#define gsk_secure_soc_init Curl_gsk_secure_soc_init
+
+extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle,
+ GSK_BUF_ID bufID,
+ const char *buffer,
+ int bufSize);
+#define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a
+
+extern int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle,
+ GSK_ENUM_ID enumID,
+ GSK_ENUM_VALUE enumValue);
+#define gsk_attribute_set_enum Curl_gsk_attribute_set_enum
+
+extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
+ GSK_NUM_ID numID,
+ int numValue);
+#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value
+
+extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
+ GSK_CALLBACK_ID callBackID,
+ void *callBackAreaPtr);
+#define gsk_attribute_set_callback Curl_gsk_attribute_set_callback
+
+extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle,
+ GSK_BUF_ID bufID,
+ const char **buffer,
+ int *bufSize);
+#define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a
+
+extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle,
+ GSK_ENUM_ID enumID,
+ GSK_ENUM_VALUE *enumValue);
+#define gsk_attribute_get_enum Curl_gsk_attribute_get_enum
+
+extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
+ GSK_NUM_ID numID,
+ int *numValue);
+#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value
+
+extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
+ GSK_CERT_ID certID,
+ const gsk_cert_data_elem **certDataElem,
+ int *certDataElementCount);
+#define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info
+
+extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle,
+ GSK_MISC_ID miscID);
+#define gsk_secure_soc_misc Curl_gsk_secure_soc_misc
+
+extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle,
+ char *readBuffer,
+ int readBufSize, int *amtRead);
+#define gsk_secure_soc_read Curl_gsk_secure_soc_read
+
+extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle,
+ char *writeBuffer,
+ int writeBufSize, int *amtWritten);
+#define gsk_secure_soc_write Curl_gsk_secure_soc_write
+
+extern const char * Curl_gsk_strerror_a(int gsk_return_value);
+#define gsk_strerror Curl_gsk_strerror_a
+
+extern int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
+ int IOCompletionPort,
+ Qso_OverlappedIO_t * communicationsArea);
+#define gsk_secure_soc_startInit Curl_gsk_secure_soc_startInit
+
+
+/* GSSAPI wrappers. */
+
+extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,
+ gss_buffer_t in_name,
+ gss_OID in_name_type,
+ gss_name_t * out_name);
+#define gss_import_name Curl_gss_import_name_a
+
+
+extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status,
+ OM_uint32 status_value,
+ int status_type, gss_OID mech_type,
+ gss_msg_ctx_t * message_context,
+ gss_buffer_t status_string);
+#define gss_display_status Curl_gss_display_status_a
+
+
+extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status,
+ gss_cred_id_t cred_handle,
+ gss_ctx_id_t * context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ gss_flags_t req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t
+ input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ gss_flags_t * ret_flags,
+ OM_uint32 * time_rec);
+#define gss_init_sec_context Curl_gss_init_sec_context_a
+
+
+extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ gss_buffer_t output_token);
+#define gss_delete_sec_context Curl_gss_delete_sec_context_a
+
+
+/* LDAP wrappers. */
+
+#define BerValue struct berval
+
+#define ldap_url_parse ldap_url_parse_utf8
+#define ldap_init Curl_ldap_init_a
+#define ldap_simple_bind_s Curl_ldap_simple_bind_s_a
+#define ldap_search_s Curl_ldap_search_s_a
+#define ldap_get_values_len Curl_ldap_get_values_len_a
+#define ldap_err2string Curl_ldap_err2string_a
+#define ldap_get_dn Curl_ldap_get_dn_a
+#define ldap_first_attribute Curl_ldap_first_attribute_a
+#define ldap_next_attribute Curl_ldap_next_attribute_a
+
+/* Some socket functions must be wrapped to process textual addresses
+ like AF_UNIX. */
+
+extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen);
+extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen);
+extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
+ struct sockaddr * dstaddr, int addrlen);
+extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
+ struct sockaddr *fromaddr, int *addrlen);
+
+#define connect Curl_os400_connect
+#define bind Curl_os400_bind
+#define sendto Curl_os400_sendto
+#define recvfrom Curl_os400_recvfrom
+
+#ifdef HAVE_LIBZ
+#define zlibVersion Curl_os400_zlibVersion
+#define inflateInit_ Curl_os400_inflateInit_
+#define inflateInit2_ Curl_os400_inflateInit2_
+#define inflate Curl_os400_inflate
+#define inflateEnd Curl_os400_inflateEnd
+#endif
+
+#endif /* HEADER_CURL_SETUP_OS400_H */
diff --git a/Utilities/cmcurl/lib/setup-vms.h b/Utilities/cmcurl/lib/setup-vms.h
new file mode 100644
index 000000000..6c454aee6
--- /dev/null
+++ b/Utilities/cmcurl/lib/setup-vms.h
@@ -0,0 +1,443 @@
+#ifndef HEADER_CURL_SETUP_VMS_H
+#define HEADER_CURL_SETUP_VMS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* */
+/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */
+/* getenv(), getpwuid() and provide is_vms_shell() */
+/* Also need upper case symbols for system services, and */
+/* OpenSSL, and some Kerberos image */
+
+#ifdef __DECC
+#pragma message save
+#pragma message disable dollarid
+#endif
+
+/* Hide the stuff we are overriding */
+#define getenv decc_getenv
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE != 64
+# define getpwuid decc_getpwuid
+# endif
+#endif
+#include <stdlib.h>
+char *decc$getenv(const char *__name);
+#include <pwd.h>
+
+#include <string.h>
+#include <unixlib.h>
+
+#undef getenv
+#undef getpwuid
+#define getenv vms_getenv
+#define getpwuid vms_getpwuid
+
+/* VAX needs these in upper case when compiling exact case */
+#define sys$assign SYS$ASSIGN
+#define sys$dassgn SYS$DASSGN
+#define sys$qiow SYS$QIOW
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+# pragma __pointer_size __save
+# endif
+#endif
+
+#if __USE_LONG_GID_T
+# define decc_getpwuid DECC$__LONG_GID_GETPWUID
+#else
+# if __INITIAL_POINTER_SIZE
+# define decc_getpwuid decc$__32_getpwuid
+# else
+# define decc_getpwuid decc$getpwuid
+# endif
+#endif
+
+ struct passwd * decc_getpwuid(uid_t uid);
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE == 32
+/* Translate the path, but only if the path is a VMS file specification */
+/* The translation is usually only needed for older versions of VMS */
+static char *vms_translate_path(const char *path)
+{
+ char *unix_path;
+ char *test_str;
+
+ /* See if the result is in VMS format, if not, we are done */
+ /* Assume that this is a PATH, not just some data */
+ test_str = strpbrk(path, ":[<^");
+ if(test_str == NULL) {
+ return (char *)path;
+ }
+
+ unix_path = decc$translate_vms(path);
+
+ if((int)unix_path <= 0) {
+ /* We can not translate it, so return the original string */
+ return (char *)path;
+ }
+}
+# else
+ /* VMS translate path is actually not needed on the current 64 bit */
+ /* VMS platforms, so instead of figuring out the pointer settings */
+ /* Change it to a noop */
+# define vms_translate_path(__path) __path
+# endif
+#endif
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+# pragma __pointer_size __restore
+# endif
+#endif
+
+static char *vms_getenv(const char *envvar)
+{
+ char *result;
+ char *vms_path;
+
+ /* first use the DECC getenv() function */
+ result = decc$getenv(envvar);
+ if(result == NULL) {
+ return result;
+ }
+
+ vms_path = result;
+ result = vms_translate_path(vms_path);
+
+ /* note that if you backport this to use VAX C RTL, that the VAX C RTL */
+ /* may do a malloc(2048) for each call to getenv(), so you will need */
+ /* to add a free(vms_path) */
+ /* Do not do a free() for DEC C RTL builds, which should be used for */
+ /* VMS 5.5-2 and later, even if using GCC */
+
+ return result;
+}
+
+
+static struct passwd vms_passwd_cache;
+
+static struct passwd * vms_getpwuid(uid_t uid)
+{
+ struct passwd * my_passwd;
+
+/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+ __char_ptr32 unix_path;
+# else
+ char *unix_path;
+# endif
+#else
+ char *unix_path;
+#endif
+
+ my_passwd = decc_getpwuid(uid);
+ if(my_passwd == NULL) {
+ return my_passwd;
+ }
+
+ unix_path = vms_translate_path(my_passwd->pw_dir);
+
+ if((long)unix_path <= 0) {
+ /* We can not translate it, so return the original string */
+ return my_passwd;
+ }
+
+ /* If no changes needed just return it */
+ if(unix_path == my_passwd->pw_dir) {
+ return my_passwd;
+ }
+
+ /* Need to copy the structure returned */
+ /* Since curl is only using pw_dir, no need to fix up */
+ /* the pw_shell when running under Bash */
+ vms_passwd_cache.pw_name = my_passwd->pw_name;
+ vms_passwd_cache.pw_uid = my_passwd->pw_uid;
+ vms_passwd_cache.pw_gid = my_passwd->pw_uid;
+ vms_passwd_cache.pw_dir = unix_path;
+ vms_passwd_cache.pw_shell = my_passwd->pw_shell;
+
+ return &vms_passwd_cache;
+}
+
+#ifdef __DECC
+#pragma message restore
+#endif
+
+/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */
+/* VMS libraries should have universal symbols in exact and uppercase */
+
+#define ASN1_INTEGER_get ASN1_INTEGER_GET
+#define ASN1_STRING_data ASN1_STRING_DATA
+#define ASN1_STRING_length ASN1_STRING_LENGTH
+#define ASN1_STRING_print ASN1_STRING_PRINT
+#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8
+#define ASN1_STRING_type ASN1_STRING_TYPE
+#define BIO_ctrl BIO_CTRL
+#define BIO_free BIO_FREE
+#define BIO_new BIO_NEW
+#define BIO_s_mem BIO_S_MEM
+#define BN_bn2bin BN_BN2BIN
+#define BN_num_bits BN_NUM_BITS
+#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA
+#define CRYPTO_free CRYPTO_FREE
+#define CRYPTO_malloc CRYPTO_MALLOC
+#define CONF_modules_load_file CONF_MODULES_LOAD_FILE
+#ifdef __VAX
+# ifdef VMS_OLD_SSL
+ /* Ancient OpenSSL on VAX/VMS missing this constant */
+# define CONF_MFLAGS_IGNORE_MISSING_FILE 0x10
+# undef CONF_modules_load_file
+ static int CONF_modules_load_file(const char *filename,
+ const char *appname,
+ unsigned long flags) {
+ return 1;
+ }
+# endif
+#endif
+#define DES_ecb_encrypt DES_ECB_ENCRYPT
+#define DES_set_key DES_SET_KEY
+#define DES_set_odd_parity DES_SET_ODD_PARITY
+#define ENGINE_ctrl ENGINE_CTRL
+#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD
+#define ENGINE_finish ENGINE_FINISH
+#define ENGINE_free ENGINE_FREE
+#define ENGINE_get_first ENGINE_GET_FIRST
+#define ENGINE_get_id ENGINE_GET_ID
+#define ENGINE_get_next ENGINE_GET_NEXT
+#define ENGINE_init ENGINE_INIT
+#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES
+#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY
+#define ENGINE_set_default ENGINE_SET_DEFAULT
+#define ERR_clear_error ERR_CLEAR_ERROR
+#define ERR_error_string ERR_ERROR_STRING
+#define ERR_error_string_n ERR_ERROR_STRING_N
+#define ERR_free_strings ERR_FREE_STRINGS
+#define ERR_get_error ERR_GET_ERROR
+#define ERR_peek_error ERR_PEEK_ERROR
+#define ERR_remove_state ERR_REMOVE_STATE
+#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS
+#define EVP_PKEY_free EVP_PKEY_FREE
+#define EVP_cleanup EVP_CLEANUP
+#define GENERAL_NAMES_free GENERAL_NAMES_FREE
+#define i2d_X509_PUBKEY I2D_X509_PUBKEY
+#define MD4_Final MD4_FINAL
+#define MD4_Init MD4_INIT
+#define MD4_Update MD4_UPDATE
+#define MD5_Final MD5_FINAL
+#define MD5_Init MD5_INIT
+#define MD5_Update MD5_UPDATE
+#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF
+#ifndef __VAX
+#define OPENSSL_load_builtin_modules OPENSSL_LOAD_BUILTIN_MODULES
+#endif
+#define PEM_read_X509 PEM_READ_X509
+#define PEM_write_bio_X509 PEM_WRITE_BIO_X509
+#define PKCS12_PBE_add PKCS12_PBE_ADD
+#define PKCS12_free PKCS12_FREE
+#define PKCS12_parse PKCS12_PARSE
+#define RAND_add RAND_ADD
+#define RAND_bytes RAND_BYTES
+#define RAND_egd RAND_EGD
+#define RAND_file_name RAND_FILE_NAME
+#define RAND_load_file RAND_LOAD_FILE
+#define RAND_status RAND_STATUS
+#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME
+#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA
+#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL
+#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY
+#define SSL_CTX_ctrl SSL_CTX_CTRL
+#define SSL_CTX_free SSL_CTX_FREE
+#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE
+#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS
+#define SSL_CTX_new SSL_CTX_NEW
+#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST
+#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD
+#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB
+#define SSL_CTX_set_msg_callback SSL_CTX_SET_MSG_CALLBACK
+#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY
+#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY
+#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE
+#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE
+#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE
+#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE
+#define SSL_SESSION_free SSL_SESSION_FREE
+#define SSL_connect SSL_CONNECT
+#define SSL_free SSL_FREE
+#define SSL_get1_session SSL_GET1_SESSION
+#define SSL_get_certificate SSL_GET_CERTIFICATE
+#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER
+#define SSL_get_error SSL_GET_ERROR
+#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN
+#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE
+#define SSL_get_privatekey SSL_GET_PRIVATEKEY
+#define SSL_get_session SSL_GET_SESSION
+#define SSL_get_shutdown SSL_GET_SHUTDOWN
+#define SSL_get_verify_result SSL_GET_VERIFY_RESULT
+#define SSL_library_init SSL_LIBRARY_INIT
+#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS
+#define SSL_new SSL_NEW
+#define SSL_peek SSL_PEEK
+#define SSL_pending SSL_PENDING
+#define SSL_read SSL_READ
+#define SSL_set_connect_state SSL_SET_CONNECT_STATE
+#define SSL_set_fd SSL_SET_FD
+#define SSL_set_session SSL_SET_SESSION
+#define SSL_shutdown SSL_SHUTDOWN
+#define SSL_version SSL_VERSION
+#define SSL_write SSL_WRITE
+#define SSLeay SSLEAY
+#define SSLv23_client_method SSLV23_CLIENT_METHOD
+#define SSLv3_client_method SSLV3_CLIENT_METHOD
+#define TLSv1_client_method TLSV1_CLIENT_METHOD
+#define UI_create_method UI_CREATE_METHOD
+#define UI_destroy_method UI_DESTROY_METHOD
+#define UI_get0_user_data UI_GET0_USER_DATA
+#define UI_get_input_flags UI_GET_INPUT_FLAGS
+#define UI_get_string_type UI_GET_STRING_TYPE
+#define UI_create_method UI_CREATE_METHOD
+#define UI_destroy_method UI_DESTROY_METHOD
+#define UI_method_get_closer UI_METHOD_GET_CLOSER
+#define UI_method_get_opener UI_METHOD_GET_OPENER
+#define UI_method_get_reader UI_METHOD_GET_READER
+#define UI_method_get_writer UI_METHOD_GET_WRITER
+#define UI_method_set_closer UI_METHOD_SET_CLOSER
+#define UI_method_set_opener UI_METHOD_SET_OPENER
+#define UI_method_set_reader UI_METHOD_SET_READER
+#define UI_method_set_writer UI_METHOD_SET_WRITER
+#define UI_OpenSSL UI_OPENSSL
+#define UI_set_result UI_SET_RESULT
+#define X509V3_EXT_print X509V3_EXT_PRINT
+#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL
+#define X509_EXTENSION_get_data X509_EXTENSION_GET_DATA
+#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT
+#define X509_LOOKUP_file X509_LOOKUP_FILE
+#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA
+#define X509_NAME_get_entry X509_NAME_GET_ENTRY
+#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID
+#define X509_NAME_print_ex X509_NAME_PRINT_EX
+#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT
+#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP
+#define X509_STORE_set_flags X509_STORE_SET_FLAGS
+#define X509_check_issued X509_CHECK_ISSUED
+#define X509_free X509_FREE
+#define X509_get_ext_d2i X509_GET_EXT_D2I
+#define X509_get_issuer_name X509_GET_ISSUER_NAME
+#define X509_get_pubkey X509_GET_PUBKEY
+#define X509_get_serialNumber X509_GET_SERIALNUMBER
+#define X509_get_subject_name X509_GET_SUBJECT_NAME
+#define X509_load_crl_file X509_LOAD_CRL_FILE
+#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING
+#define d2i_PKCS12_fp D2I_PKCS12_FP
+#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT
+#define sk_num SK_NUM
+#define sk_pop SK_POP
+#define sk_pop_free SK_POP_FREE
+#define sk_value SK_VALUE
+#ifdef __VAX
+#define OPENSSL_NO_SHA256
+#endif
+#define SHA256_Final SHA256_FINAL
+#define SHA256_Init SHA256_INIT
+#define SHA256_Update SHA256_UPDATE
+
+#define USE_UPPERCASE_GSSAPI 1
+#define gss_seal GSS_SEAL
+#define gss_unseal GSS_UNSEAL
+
+#define USE_UPPERCASE_KRBAPI 1
+
+/* AI_NUMERICHOST needed for IP V6 support in Curl */
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#ifndef AI_NUMERICHOST
+#ifdef ENABLE_IPV6
+#undef ENABLE_IPV6
+#endif
+#endif
+#endif
+
+/* VAX symbols are always in uppercase */
+#ifdef __VAX
+#define inflate INFLATE
+#define inflateEnd INFLATEEND
+#define inflateInit2_ INFLATEINIT2_
+#define inflateInit_ INFLATEINIT_
+#define zlibVersion ZLIBVERSION
+#endif
+
+/* Older VAX OpenSSL port defines these as Macros */
+/* Need to include the headers first and then redefine */
+/* that way a newer port will also work if some one has one */
+#ifdef __VAX
+
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+# define des_set_odd_parity DES_SET_ODD_PARITY
+# define des_set_key DES_SET_KEY
+# define des_ecb_encrypt DES_ECB_ENCRYPT
+
+# endif
+# include <openssl/evp.h>
+# ifndef OpenSSL_add_all_algorithms
+# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS
+ void OPENSSL_ADD_ALL_ALGORITHMS(void);
+# endif
+
+ /* Curl defines these to lower case and VAX needs them in upper case */
+ /* So we need static routines */
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+
+# undef des_set_odd_parity
+# undef DES_set_odd_parity
+# undef des_set_key
+# undef DES_set_key
+# undef des_ecb_encrypt
+# undef DES_ecb_encrypt
+
+ static void des_set_odd_parity(des_cblock *key) {
+ DES_SET_ODD_PARITY(key);
+ }
+
+ static int des_set_key(const_des_cblock *key,
+ des_key_schedule schedule) {
+ return DES_SET_KEY(key, schedule);
+ }
+
+ static void des_ecb_encrypt(const_des_cblock *input,
+ des_cblock *output,
+ des_key_schedule ks, int enc) {
+ DES_ECB_ENCRYPT(input, output, ks, enc);
+ }
+#endif
+/* Need this to stop a macro redefinition error */
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+# ifdef X509_STORE_set_flags
+# undef X509_STORE_set_flags
+# define X509_STORE_set_flags(x,y) Curl_nop_stmt
+# endif
+#endif
+#endif
+
+#endif /* HEADER_CURL_SETUP_VMS_H */
diff --git a/Utilities/cmcurl/lib/share.c b/Utilities/cmcurl/lib/share.c
new file mode 100644
index 000000000..5b3957fcf
--- /dev/null
+++ b/Utilities/cmcurl/lib/share.c
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "share.h"
+#include "vtls/vtls.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct Curl_share *
+curl_share_init(void)
+{
+ struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
+ if(share) {
+ share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+
+ if(Curl_mk_dnscache(&share->hostcache)) {
+ free(share);
+ return NULL;
+ }
+ }
+
+ return share;
+}
+
+#undef curl_share_setopt
+CURLSHcode
+curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
+{
+ va_list param;
+ int type;
+ curl_lock_function lockfunc;
+ curl_unlock_function unlockfunc;
+ void *ptr;
+ CURLSHcode res = CURLSHE_OK;
+
+ if(share->dirty)
+ /* don't allow setting options while one or more handles are already
+ using this share */
+ return CURLSHE_IN_USE;
+
+ va_start(param, option);
+
+ switch(option) {
+ case CURLSHOPT_SHARE:
+ /* this is a type this share will share */
+ type = va_arg(param, int);
+ share->specifier |= (1<<type);
+ switch(type) {
+ case CURL_LOCK_DATA_DNS:
+ break;
+
+ case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(!share->cookies) {
+ share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE);
+ if(!share->cookies)
+ res = CURLSHE_NOMEM;
+ }
+#else /* CURL_DISABLE_HTTP */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+ if(!share->sslsession) {
+ share->max_ssl_sessions = 8;
+ share->sslsession = calloc(share->max_ssl_sessions,
+ sizeof(struct curl_ssl_session));
+ share->sessionage = 0;
+ if(!share->sslsession)
+ res = CURLSHE_NOMEM;
+ }
+#else
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ }
+ break;
+
+ case CURLSHOPT_UNSHARE:
+ /* this is a type this share will no longer share */
+ type = va_arg(param, int);
+ share->specifier &= ~(1<<type);
+ switch(type) {
+ case CURL_LOCK_DATA_DNS:
+ break;
+
+ case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(share->cookies) {
+ Curl_cookie_cleanup(share->cookies);
+ share->cookies = NULL;
+ }
+#else /* CURL_DISABLE_HTTP */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+ Curl_safefree(share->sslsession);
+#else
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_CONNECT:
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ break;
+ }
+ break;
+
+ case CURLSHOPT_LOCKFUNC:
+ lockfunc = va_arg(param, curl_lock_function);
+ share->lockfunc = lockfunc;
+ break;
+
+ case CURLSHOPT_UNLOCKFUNC:
+ unlockfunc = va_arg(param, curl_unlock_function);
+ share->unlockfunc = unlockfunc;
+ break;
+
+ case CURLSHOPT_USERDATA:
+ ptr = va_arg(param, void *);
+ share->clientdata = ptr;
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ break;
+ }
+
+ va_end(param);
+
+ return res;
+}
+
+CURLSHcode
+curl_share_cleanup(struct Curl_share *share)
+{
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->lockfunc)
+ share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
+ share->clientdata);
+
+ if(share->dirty) {
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ return CURLSHE_IN_USE;
+ }
+
+ Curl_hash_destroy(&share->hostcache);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ Curl_cookie_cleanup(share->cookies);
+#endif
+
+#ifdef USE_SSL
+ if(share->sslsession) {
+ size_t i;
+ for(i = 0; i < share->max_ssl_sessions; i++)
+ Curl_ssl_kill_session(&(share->sslsession[i]));
+ free(share->sslsession);
+ }
+#endif
+
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ free(share);
+
+ return CURLSHE_OK;
+}
+
+
+CURLSHcode
+Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
+ curl_lock_access accesstype)
+{
+ struct Curl_share *share = data->share;
+
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->lockfunc) /* only call this if set! */
+ share->lockfunc(data, type, accesstype, share->clientdata);
+ }
+ /* else if we don't share this, pretend successful lock */
+
+ return CURLSHE_OK;
+}
+
+CURLSHcode
+Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
+{
+ struct Curl_share *share = data->share;
+
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->unlockfunc) /* only call this if set! */
+ share->unlockfunc (data, type, share->clientdata);
+ }
+
+ return CURLSHE_OK;
+}
diff --git a/Utilities/cmcurl/lib/share.h b/Utilities/cmcurl/lib/share.h
new file mode 100644
index 000000000..c039a16cb
--- /dev/null
+++ b/Utilities/cmcurl/lib/share.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SHARE_H
+#define HEADER_CURL_SHARE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include <curl/curl.h>
+#include "cookie.h"
+#include "urldata.h"
+
+/* SalfordC says "A structure member may not be volatile". Hence:
+ */
+#ifdef __SALFORDC__
+#define CURL_VOLATILE
+#else
+#define CURL_VOLATILE volatile
+#endif
+
+/* this struct is libcurl-private, don't export details */
+struct Curl_share {
+ unsigned int specifier;
+ CURL_VOLATILE unsigned int dirty;
+
+ curl_lock_function lockfunc;
+ curl_unlock_function unlockfunc;
+ void *clientdata;
+
+ struct curl_hash hostcache;
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ struct CookieInfo *cookies;
+#endif
+
+ struct curl_ssl_session *sslsession;
+ size_t max_ssl_sessions;
+ long sessionage;
+};
+
+CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,
+ curl_lock_access);
+CURLSHcode Curl_share_unlock(struct Curl_easy *, curl_lock_data);
+
+#endif /* HEADER_CURL_SHARE_H */
diff --git a/Utilities/cmcurl/lib/sigpipe.h b/Utilities/cmcurl/lib/sigpipe.h
new file mode 100644
index 000000000..800f9d3b4
--- /dev/null
+++ b/Utilities/cmcurl/lib/sigpipe.h
@@ -0,0 +1,78 @@
+#ifndef HEADER_CURL_SIGPIPE_H
+#define HEADER_CURL_SIGPIPE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL)
+#include <signal.h>
+
+struct sigpipe_ignore {
+ struct sigaction old_pipe_act;
+ bool no_signal;
+};
+
+#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
+
+/*
+ * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
+ * internals, and then sigpipe_restore() will restore the situation when we
+ * return from libcurl again.
+ */
+static void sigpipe_ignore(struct Curl_easy *data,
+ struct sigpipe_ignore *ig)
+{
+ /* get a local copy of no_signal because the Curl_easy might not be
+ around when we restore */
+ ig->no_signal = data->set.no_signal;
+ if(!data->set.no_signal) {
+ struct sigaction action;
+ /* first, extract the existing situation */
+ memset(&ig->old_pipe_act, 0, sizeof(struct sigaction));
+ sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
+ action = ig->old_pipe_act;
+ /* ignore this signal */
+ action.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &action, NULL);
+ }
+}
+
+/*
+ * sigpipe_restore() puts back the outside world's opinion of signal handler
+ * and SIGPIPE handling. It MUST only be called after a corresponding
+ * sigpipe_ignore() was used.
+ */
+static void sigpipe_restore(struct sigpipe_ignore *ig)
+{
+ if(!ig->no_signal)
+ /* restore the outside state */
+ sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
+}
+
+#else
+/* for systems without sigaction */
+#define sigpipe_ignore(x,y) Curl_nop_stmt
+#define sigpipe_restore(x) Curl_nop_stmt
+#define SIGPIPE_VARIABLE(x)
+#endif
+
+#endif /* HEADER_CURL_SIGPIPE_H */
diff --git a/Utilities/cmcurl/lib/slist.c b/Utilities/cmcurl/lib/slist.c
new file mode 100644
index 000000000..e5adc0e71
--- /dev/null
+++ b/Utilities/cmcurl/lib/slist.c
@@ -0,0 +1,145 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "slist.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* returns last node in linked list */
+static struct curl_slist *slist_get_last(struct curl_slist *list)
+{
+ struct curl_slist *item;
+
+ /* if caller passed us a NULL, return now */
+ if(!list)
+ return NULL;
+
+ /* loop through to find the last item */
+ item = list;
+ while(item->next) {
+ item = item->next;
+ }
+ return item;
+}
+
+/*
+ * Curl_slist_append_nodup() appends a string to the linked list. Rather than
+ * copying the string in dynamic storage, it takes its ownership. The string
+ * should have been malloc()ated. Curl_slist_append_nodup always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function.
+ * If an error occurs, NULL is returned and the string argument is NOT
+ * released.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data)
+{
+ struct curl_slist *last;
+ struct curl_slist *new_item;
+
+ DEBUGASSERT(data);
+
+ new_item = malloc(sizeof(struct curl_slist));
+ if(!new_item)
+ return NULL;
+
+ new_item->next = NULL;
+ new_item->data = data;
+
+ /* if this is the first item, then new_item *is* the list */
+ if(!list)
+ return new_item;
+
+ last = slist_get_last(list);
+ last->next = new_item;
+ return list;
+}
+
+/*
+ * curl_slist_append() appends a string to the linked list. It always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function. If you find this
+ * bothersome, then simply create a separate _init function and call it
+ * appropriately from within the program.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *list,
+ const char *data)
+{
+ char *dupdata = strdup(data);
+
+ if(!dupdata)
+ return NULL;
+
+ list = Curl_slist_append_nodup(list, dupdata);
+ if(!list)
+ free(dupdata);
+
+ return list;
+}
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist)
+{
+ struct curl_slist *outlist = NULL;
+ struct curl_slist *tmp;
+
+ while(inlist) {
+ tmp = curl_slist_append(outlist, inlist->data);
+
+ if(!tmp) {
+ curl_slist_free_all(outlist);
+ return NULL;
+ }
+
+ outlist = tmp;
+ inlist = inlist->next;
+ }
+ return outlist;
+}
+
+/* be nice and clean up resources */
+void curl_slist_free_all(struct curl_slist *list)
+{
+ struct curl_slist *next;
+ struct curl_slist *item;
+
+ if(!list)
+ return;
+
+ item = list;
+ do {
+ next = item->next;
+ Curl_safefree(item->data);
+ free(item);
+ item = next;
+ } while(next);
+}
+
diff --git a/Utilities/cmcurl/lib/slist.h b/Utilities/cmcurl/lib/slist.h
new file mode 100644
index 000000000..b3f498c35
--- /dev/null
+++ b/Utilities/cmcurl/lib/slist.h
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_SLIST_H
+#define HEADER_CURL_SLIST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist);
+
+/*
+ * Curl_slist_append_nodup() takes ownership of the given string and appends
+ * it to the list.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
+ char *data);
+
+#endif /* HEADER_CURL_SLIST_H */
+
diff --git a/Utilities/cmcurl/lib/smb.c b/Utilities/cmcurl/lib/smb.c
new file mode 100644
index 000000000..5b1ffa9b7
--- /dev/null
+++ b/Utilities/cmcurl/lib/smb.c
@@ -0,0 +1,982 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
+ * Copyright (C) 2016-2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
+ (CURL_SIZEOF_CURL_OFF_T > 4)
+
+#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
+
+#define BUILDING_CURL_SMB_C
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#ifdef CURL_WINDOWS_APP
+#define getpid GetCurrentProcessId
+#else
+#define getpid _getpid
+#endif
+#endif
+
+#include "smb.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "connect.h"
+#include "progress.h"
+#include "transfer.h"
+#include "vtls/vtls.h"
+#include "curl_ntlm_core.h"
+#include "escape.h"
+#include "curl_endian.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode smb_setup_connection(struct connectdata *conn);
+static CURLcode smb_connect(struct connectdata *conn, bool *done);
+static CURLcode smb_connection_state(struct connectdata *conn, bool *done);
+static CURLcode smb_request_state(struct connectdata *conn, bool *done);
+static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode smb_disconnect(struct connectdata *conn, bool dead);
+static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode smb_parse_url_path(struct connectdata *conn);
+
+/*
+ * SMB handler interface
+ */
+const struct Curl_handler Curl_handler_smb = {
+ "SMB", /* scheme */
+ smb_setup_connection, /* setup_connection */
+ ZERO_NULL, /* do_it */
+ smb_done, /* done */
+ ZERO_NULL, /* do_more */
+ smb_connect, /* connect_it */
+ smb_connection_state, /* connecting */
+ smb_request_state, /* doing */
+ smb_getsock, /* proto_getsock */
+ smb_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smb_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMB, /* defport */
+ CURLPROTO_SMB, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * SMBS handler interface
+ */
+const struct Curl_handler Curl_handler_smbs = {
+ "SMBS", /* scheme */
+ smb_setup_connection, /* setup_connection */
+ ZERO_NULL, /* do_it */
+ smb_done, /* done */
+ ZERO_NULL, /* do_more */
+ smb_connect, /* connect_it */
+ smb_connection_state, /* connecting */
+ smb_request_state, /* doing */
+ smb_getsock, /* proto_getsock */
+ smb_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smb_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMBS, /* defport */
+ CURLPROTO_SMBS, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#endif
+
+#define MAX_PAYLOAD_SIZE 0x8000
+#define MAX_MESSAGE_SIZE (MAX_PAYLOAD_SIZE + 0x1000)
+#define CLIENTNAME "curl"
+#define SERVICENAME "?????"
+
+/* Append a string to an SMB message */
+#define MSGCAT(str) \
+ strcpy(p, (str)); \
+ p += strlen(str);
+
+/* Append a null-terminated string to an SMB message */
+#define MSGCATNULL(str) \
+ strcpy(p, (str)); \
+ p += strlen(str) + 1;
+
+/* SMB is mostly little endian */
+#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
+ defined(__OS400__)
+static unsigned short smb_swap16(unsigned short x)
+{
+ return (unsigned short) ((x << 8) | ((x >> 8) & 0xff));
+}
+
+static unsigned int smb_swap32(unsigned int x)
+{
+ return (x << 24) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) |
+ ((x >> 24) & 0xff);
+}
+
+#ifdef HAVE_LONGLONG
+static unsigned long long smb_swap64(unsigned long long x)
+{
+ return ((unsigned long long) smb_swap32((unsigned int) x) << 32) |
+ smb_swap32((unsigned int) (x >> 32));
+}
+#else
+static unsigned __int64 smb_swap64(unsigned __int64 x)
+{
+ return ((unsigned __int64) smb_swap32((unsigned int) x) << 32) |
+ smb_swap32((unsigned int) (x >> 32));
+}
+#endif
+#else
+# define smb_swap16(x) (x)
+# define smb_swap32(x) (x)
+# define smb_swap64(x) (x)
+#endif
+
+/* SMB request state */
+enum smb_req_state {
+ SMB_REQUESTING,
+ SMB_TREE_CONNECT,
+ SMB_OPEN,
+ SMB_DOWNLOAD,
+ SMB_UPLOAD,
+ SMB_CLOSE,
+ SMB_TREE_DISCONNECT,
+ SMB_DONE
+};
+
+/* SMB request data */
+struct smb_request {
+ enum smb_req_state state;
+ char *share;
+ char *path;
+ unsigned short tid; /* Even if we connect to the same tree as another */
+ unsigned short fid; /* request, the tid will be different */
+ CURLcode result;
+};
+
+static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
+{
+ struct smb_conn *smb = &conn->proto.smbc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* For debug purposes */
+ static const char * const names[] = {
+ "SMB_NOT_CONNECTED",
+ "SMB_CONNECTING",
+ "SMB_NEGOTIATE",
+ "SMB_SETUP",
+ "SMB_CONNECTED",
+ /* LAST */
+ };
+
+ if(smb->state != newstate)
+ infof(conn->data, "SMB conn %p state change from %s to %s\n",
+ (void *)smb, names[smb->state], names[newstate]);
+#endif
+
+ smb->state = newstate;
+}
+
+static void request_state(struct connectdata *conn,
+ enum smb_req_state newstate)
+{
+ struct smb_request *req = conn->data->req.protop;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* For debug purposes */
+ static const char * const names[] = {
+ "SMB_REQUESTING",
+ "SMB_TREE_CONNECT",
+ "SMB_OPEN",
+ "SMB_DOWNLOAD",
+ "SMB_UPLOAD",
+ "SMB_CLOSE",
+ "SMB_TREE_DISCONNECT",
+ "SMB_DONE",
+ /* LAST */
+ };
+
+ if(req->state != newstate)
+ infof(conn->data, "SMB request %p state change from %s to %s\n",
+ (void *)req, names[req->state], names[newstate]);
+#endif
+
+ req->state = newstate;
+}
+
+static CURLcode smb_setup_connection(struct connectdata *conn)
+{
+ struct smb_request *req;
+
+ /* Initialize the request state */
+ conn->data->req.protop = req = calloc(1, sizeof(struct smb_request));
+ if(!req)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Parse the URL path */
+ return smb_parse_url_path(conn);
+}
+
+static CURLcode smb_connect(struct connectdata *conn, bool *done)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ char *slash;
+
+ (void) done;
+
+ /* Check we have a username and password to authenticate with */
+ if(!conn->bits.user_passwd)
+ return CURLE_LOGIN_DENIED;
+
+ /* Initialize the connection state */
+ memset(smbc, 0, sizeof(*smbc));
+ smbc->state = SMB_CONNECTING;
+ smbc->recv_buf = malloc(MAX_MESSAGE_SIZE);
+ if(!smbc->recv_buf)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Multiple requests are allowed with this connection */
+ connkeep(conn, "SMB default");
+
+ /* Parse the username, domain, and password */
+ slash = strchr(conn->user, '/');
+ if(!slash)
+ slash = strchr(conn->user, '\\');
+
+ if(slash) {
+ smbc->user = slash + 1;
+ smbc->domain = strdup(conn->user);
+ if(!smbc->domain)
+ return CURLE_OUT_OF_MEMORY;
+ smbc->domain[slash - conn->user] = 0;
+ }
+ else {
+ smbc->user = conn->user;
+ smbc->domain = strdup(conn->host.name);
+ if(!smbc->domain)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ char *buf = smbc->recv_buf;
+ ssize_t bytes_read;
+ size_t nbt_size;
+ size_t msg_size;
+ size_t len = MAX_MESSAGE_SIZE - smbc->got;
+ CURLcode result;
+
+ result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
+ if(result)
+ return result;
+
+ if(!bytes_read)
+ return CURLE_OK;
+
+ smbc->got += bytes_read;
+
+ /* Check for a 32-bit nbt header */
+ if(smbc->got < sizeof(unsigned int))
+ return CURLE_OK;
+
+ nbt_size = Curl_read16_be((const unsigned char *)
+ (buf + sizeof(unsigned short))) +
+ sizeof(unsigned int);
+ if(smbc->got < nbt_size)
+ return CURLE_OK;
+
+ msg_size = sizeof(struct smb_header);
+ if(nbt_size >= msg_size + 1) {
+ /* Add the word count */
+ msg_size += 1 + ((unsigned char) buf[msg_size]) * sizeof(unsigned short);
+ if(nbt_size >= msg_size + sizeof(unsigned short)) {
+ /* Add the byte count */
+ msg_size += sizeof(unsigned short) +
+ Curl_read16_le((const unsigned char *)&buf[msg_size]);
+ if(nbt_size < msg_size)
+ return CURLE_READ_ERROR;
+ }
+ }
+
+ *msg = buf;
+
+ return CURLE_OK;
+}
+
+static void smb_pop_message(struct connectdata *conn)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+
+ smbc->got = 0;
+}
+
+static void smb_format_message(struct connectdata *conn, struct smb_header *h,
+ unsigned char cmd, size_t len)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ struct smb_request *req = conn->data->req.protop;
+ unsigned int pid;
+
+ memset(h, 0, sizeof(*h));
+ h->nbt_length = htons((unsigned short) (sizeof(*h) - sizeof(unsigned int) +
+ len));
+ memcpy((char *)h->magic, "\xffSMB", 4);
+ h->command = cmd;
+ h->flags = SMB_FLAGS_CANONICAL_PATHNAMES | SMB_FLAGS_CASELESS_PATHNAMES;
+ h->flags2 = smb_swap16(SMB_FLAGS2_IS_LONG_NAME | SMB_FLAGS2_KNOWS_LONG_NAME);
+ h->uid = smb_swap16(smbc->uid);
+ h->tid = smb_swap16(req->tid);
+ pid = getpid();
+ h->pid_high = smb_swap16((unsigned short)(pid >> 16));
+ h->pid = smb_swap16((unsigned short) pid);
+}
+
+static CURLcode smb_send(struct connectdata *conn, ssize_t len,
+ size_t upload_size)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ ssize_t bytes_written;
+ CURLcode result;
+
+ result = Curl_write(conn, FIRSTSOCKET, conn->data->state.uploadbuffer,
+ len, &bytes_written);
+ if(result)
+ return result;
+
+ if(bytes_written != len) {
+ smbc->send_size = len;
+ smbc->sent = bytes_written;
+ }
+
+ smbc->upload_size = upload_size;
+
+ return CURLE_OK;
+}
+
+static CURLcode smb_flush(struct connectdata *conn)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ ssize_t bytes_written;
+ ssize_t len = smbc->send_size - smbc->sent;
+ CURLcode result;
+
+ if(!smbc->send_size)
+ return CURLE_OK;
+
+ result = Curl_write(conn, FIRSTSOCKET,
+ conn->data->state.uploadbuffer + smbc->sent,
+ len, &bytes_written);
+ if(result)
+ return result;
+
+ if(bytes_written != len)
+ smbc->sent += bytes_written;
+ else
+ smbc->send_size = 0;
+
+ return CURLE_OK;
+}
+
+static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd,
+ const void *msg, size_t msg_len)
+{
+ smb_format_message(conn, (struct smb_header *)conn->data->state.uploadbuffer,
+ cmd, msg_len);
+ memcpy(conn->data->state.uploadbuffer + sizeof(struct smb_header),
+ msg, msg_len);
+
+ return smb_send(conn, sizeof(struct smb_header) + msg_len, 0);
+}
+
+static CURLcode smb_send_negotiate(struct connectdata *conn)
+{
+ const char *msg = "\x00\x0c\x00\x02NT LM 0.12";
+
+ return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15);
+}
+
+static CURLcode smb_send_setup(struct connectdata *conn)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ struct smb_setup msg;
+ char *p = msg.bytes;
+ unsigned char lm_hash[21];
+ unsigned char lm[24];
+ unsigned char nt_hash[21];
+ unsigned char nt[24];
+
+ size_t byte_count = sizeof(lm) + sizeof(nt);
+ byte_count += strlen(smbc->user) + strlen(smbc->domain);
+ byte_count += strlen(OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */
+ if(byte_count > sizeof(msg.bytes))
+ return CURLE_FILESIZE_EXCEEDED;
+
+ Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash);
+ Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
+#ifdef USE_NTRESPONSES
+ Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash);
+ Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
+#else
+ memset(nt, 0, sizeof(nt));
+#endif
+
+ memset(&msg, 0, sizeof(msg));
+ msg.word_count = SMB_WC_SETUP_ANDX;
+ msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+ msg.max_buffer_size = smb_swap16(MAX_MESSAGE_SIZE);
+ msg.max_mpx_count = smb_swap16(1);
+ msg.vc_number = smb_swap16(1);
+ msg.session_key = smb_swap32(smbc->session_key);
+ msg.capabilities = smb_swap32(SMB_CAP_LARGE_FILES);
+ msg.lengths[0] = smb_swap16(sizeof(lm));
+ msg.lengths[1] = smb_swap16(sizeof(nt));
+ memcpy(p, lm, sizeof(lm));
+ p += sizeof(lm);
+ memcpy(p, nt, sizeof(nt));
+ p += sizeof(nt);
+ MSGCATNULL(smbc->user);
+ MSGCATNULL(smbc->domain);
+ MSGCATNULL(OS);
+ MSGCATNULL(CLIENTNAME);
+ byte_count = p - msg.bytes;
+ msg.byte_count = smb_swap16((unsigned short)byte_count);
+
+ return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg,
+ sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_tree_connect(struct connectdata *conn)
+{
+ struct smb_request *req = conn->data->req.protop;
+ struct smb_tree_connect msg;
+ char *p = msg.bytes;
+
+ size_t byte_count = strlen(conn->host.name) + strlen(req->share);
+ byte_count += strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */
+ if(byte_count > sizeof(msg.bytes))
+ return CURLE_FILESIZE_EXCEEDED;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.word_count = SMB_WC_TREE_CONNECT_ANDX;
+ msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+ msg.pw_len = 0;
+ MSGCAT("\\\\");
+ MSGCAT(conn->host.name);
+ MSGCAT("\\");
+ MSGCATNULL(req->share);
+ MSGCATNULL(SERVICENAME); /* Match any type of service */
+ byte_count = p - msg.bytes;
+ msg.byte_count = smb_swap16((unsigned short)byte_count);
+
+ return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg,
+ sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_open(struct connectdata *conn)
+{
+ struct smb_request *req = conn->data->req.protop;
+ struct smb_nt_create msg;
+ size_t byte_count;
+
+ if((strlen(req->path) + 1) > sizeof(msg.bytes))
+ return CURLE_FILESIZE_EXCEEDED;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.word_count = SMB_WC_NT_CREATE_ANDX;
+ msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+ byte_count = strlen(req->path);
+ msg.name_length = smb_swap16((unsigned short)byte_count);
+ msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL);
+ if(conn->data->set.upload) {
+ msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE);
+ msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF);
+ }
+ else {
+ msg.access = smb_swap32(SMB_GENERIC_READ);
+ msg.create_disposition = smb_swap32(SMB_FILE_OPEN);
+ }
+ msg.byte_count = smb_swap16((unsigned short) ++byte_count);
+ strcpy(msg.bytes, req->path);
+
+ return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg,
+ sizeof(msg) - sizeof(msg.bytes) + byte_count);
+}
+
+static CURLcode smb_send_close(struct connectdata *conn)
+{
+ struct smb_request *req = conn->data->req.protop;
+ struct smb_close msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.word_count = SMB_WC_CLOSE;
+ msg.fid = smb_swap16(req->fid);
+
+ return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
+{
+ struct smb_tree_disconnect msg;
+
+ memset(&msg, 0, sizeof(msg));
+
+ return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_read(struct connectdata *conn)
+{
+ struct smb_request *req = conn->data->req.protop;
+ curl_off_t offset = conn->data->req.offset;
+ struct smb_read msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.word_count = SMB_WC_READ_ANDX;
+ msg.andx.command = SMB_COM_NO_ANDX_COMMAND;
+ msg.fid = smb_swap16(req->fid);
+ msg.offset = smb_swap32((unsigned int) offset);
+ msg.offset_high = smb_swap32((unsigned int) (offset >> 32));
+ msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
+ msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
+
+ return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg));
+}
+
+static CURLcode smb_send_write(struct connectdata *conn)
+{
+ struct smb_write *msg = (struct smb_write *)conn->data->state.uploadbuffer;
+ struct smb_request *req = conn->data->req.protop;
+ curl_off_t offset = conn->data->req.offset;
+
+ curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
+ if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
+ upload_size = MAX_PAYLOAD_SIZE - 1;
+
+ memset(msg, 0, sizeof(*msg));
+ msg->word_count = SMB_WC_WRITE_ANDX;
+ msg->andx.command = SMB_COM_NO_ANDX_COMMAND;
+ msg->fid = smb_swap16(req->fid);
+ msg->offset = smb_swap32((unsigned int) offset);
+ msg->offset_high = smb_swap32((unsigned int) (offset >> 32));
+ msg->data_length = smb_swap16((unsigned short) upload_size);
+ msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int));
+ msg->byte_count = smb_swap16((unsigned short) (upload_size + 1));
+
+ smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX,
+ sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size);
+
+ return smb_send(conn, sizeof(*msg), (size_t) upload_size);
+}
+
+static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ CURLcode result;
+
+ /* Check if there is data in the transfer buffer */
+ if(!smbc->send_size && smbc->upload_size) {
+ int nread = smbc->upload_size > UPLOAD_BUFSIZE ? UPLOAD_BUFSIZE :
+ (int) smbc->upload_size;
+ conn->data->req.upload_fromhere = conn->data->state.uploadbuffer;
+ result = Curl_fillreadbuffer(conn, nread, &nread);
+ if(result && result != CURLE_AGAIN)
+ return result;
+ if(!nread)
+ return CURLE_OK;
+
+ smbc->upload_size -= nread;
+ smbc->send_size = nread;
+ smbc->sent = 0;
+ }
+
+ /* Check if there is data to send */
+ if(smbc->send_size) {
+ result = smb_flush(conn);
+ if(result)
+ return result;
+ }
+
+ /* Check if there is still data to be sent */
+ if(smbc->send_size || smbc->upload_size)
+ return CURLE_AGAIN;
+
+ return smb_recv_message(conn, msg);
+}
+
+static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ struct smb_negotiate_response *nrsp;
+ struct smb_header *h;
+ CURLcode result;
+ void *msg = NULL;
+
+ if(smbc->state == SMB_CONNECTING) {
+#ifdef USE_SSL
+ if((conn->handler->flags & PROTOPT_SSL)) {
+ bool ssl_done;
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
+ if(result && result != CURLE_AGAIN)
+ return result;
+ if(!ssl_done)
+ return CURLE_OK;
+ }
+#endif
+
+ result = smb_send_negotiate(conn);
+ if(result) {
+ connclose(conn, "SMB: failed to send negotiate message");
+ return result;
+ }
+
+ conn_state(conn, SMB_NEGOTIATE);
+ }
+
+ /* Send the previous message and check for a response */
+ result = smb_send_and_recv(conn, &msg);
+ if(result && result != CURLE_AGAIN) {
+ connclose(conn, "SMB: failed to communicate");
+ return result;
+ }
+
+ if(!msg)
+ return CURLE_OK;
+
+ h = msg;
+
+ switch(smbc->state) {
+ case SMB_NEGOTIATE:
+ if(h->status || smbc->got < sizeof(*nrsp) + sizeof(smbc->challenge) - 1) {
+ connclose(conn, "SMB: negotiation failed");
+ return CURLE_COULDNT_CONNECT;
+ }
+ nrsp = msg;
+ memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge));
+ smbc->session_key = smb_swap32(nrsp->session_key);
+ result = smb_send_setup(conn);
+ if(result) {
+ connclose(conn, "SMB: failed to send setup message");
+ return result;
+ }
+ conn_state(conn, SMB_SETUP);
+ break;
+
+ case SMB_SETUP:
+ if(h->status) {
+ connclose(conn, "SMB: authentication failed");
+ return CURLE_LOGIN_DENIED;
+ }
+ smbc->uid = smb_swap16(h->uid);
+ conn_state(conn, SMB_CONNECTED);
+ *done = true;
+ break;
+
+ default:
+ smb_pop_message(conn);
+ return CURLE_OK; /* ignore */
+ }
+
+ smb_pop_message(conn);
+
+ return CURLE_OK;
+}
+
+static CURLcode smb_request_state(struct connectdata *conn, bool *done)
+{
+ struct smb_request *req = conn->data->req.protop;
+ struct smb_header *h;
+ struct smb_conn *smbc = &conn->proto.smbc;
+ enum smb_req_state next_state = SMB_DONE;
+ unsigned short len;
+ unsigned short off;
+ CURLcode result;
+ void *msg = NULL;
+
+ /* Start the request */
+ if(req->state == SMB_REQUESTING) {
+ result = smb_send_tree_connect(conn);
+ if(result) {
+ connclose(conn, "SMB: failed to send tree connect message");
+ return result;
+ }
+
+ request_state(conn, SMB_TREE_CONNECT);
+ }
+
+ /* Send the previous message and check for a response */
+ result = smb_send_and_recv(conn, &msg);
+ if(result && result != CURLE_AGAIN) {
+ connclose(conn, "SMB: failed to communicate");
+ return result;
+ }
+
+ if(!msg)
+ return CURLE_OK;
+
+ h = msg;
+
+ switch(req->state) {
+ case SMB_TREE_CONNECT:
+ if(h->status) {
+ req->result = CURLE_REMOTE_FILE_NOT_FOUND;
+ if(h->status == smb_swap32(SMB_ERR_NOACCESS))
+ req->result = CURLE_REMOTE_ACCESS_DENIED;
+ break;
+ }
+ req->tid = smb_swap16(h->tid);
+ next_state = SMB_OPEN;
+ break;
+
+ case SMB_OPEN:
+ if(h->status || smbc->got < sizeof(struct smb_nt_create_response)) {
+ req->result = CURLE_REMOTE_FILE_NOT_FOUND;
+ next_state = SMB_TREE_DISCONNECT;
+ break;
+ }
+ req->fid = smb_swap16(((struct smb_nt_create_response *)msg)->fid);
+ conn->data->req.offset = 0;
+ if(conn->data->set.upload) {
+ conn->data->req.size = conn->data->state.infilesize;
+ Curl_pgrsSetUploadSize(conn->data, conn->data->req.size);
+ next_state = SMB_UPLOAD;
+ }
+ else {
+ conn->data->req.size =
+ smb_swap64(((struct smb_nt_create_response *)msg)->end_of_file);
+ Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
+ next_state = SMB_DOWNLOAD;
+ }
+ break;
+
+ case SMB_DOWNLOAD:
+ if(h->status || smbc->got < sizeof(struct smb_header) + 14) {
+ req->result = CURLE_RECV_ERROR;
+ next_state = SMB_CLOSE;
+ break;
+ }
+ len = Curl_read16_le(((const unsigned char *) msg) +
+ sizeof(struct smb_header) + 11);
+ off = Curl_read16_le(((const unsigned char *) msg) +
+ sizeof(struct smb_header) + 13);
+ if(len > 0) {
+ if(off + sizeof(unsigned int) + len > smbc->got) {
+ failf(conn->data, "Invalid input packet");
+ result = CURLE_RECV_ERROR;
+ }
+ else
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *)msg + off + sizeof(unsigned int),
+ len);
+ if(result) {
+ req->result = result;
+ next_state = SMB_CLOSE;
+ break;
+ }
+ }
+ conn->data->req.bytecount += len;
+ conn->data->req.offset += len;
+ Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount);
+ next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
+ break;
+
+ case SMB_UPLOAD:
+ if(h->status || smbc->got < sizeof(struct smb_header) + 6) {
+ req->result = CURLE_UPLOAD_FAILED;
+ next_state = SMB_CLOSE;
+ break;
+ }
+ len = Curl_read16_le(((const unsigned char *) msg) +
+ sizeof(struct smb_header) + 5);
+ conn->data->req.bytecount += len;
+ conn->data->req.offset += len;
+ Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount);
+ if(conn->data->req.bytecount >= conn->data->req.size)
+ next_state = SMB_CLOSE;
+ else
+ next_state = SMB_UPLOAD;
+ break;
+
+ case SMB_CLOSE:
+ /* We don't care if the close failed, proceed to tree disconnect anyway */
+ next_state = SMB_TREE_DISCONNECT;
+ break;
+
+ case SMB_TREE_DISCONNECT:
+ next_state = SMB_DONE;
+ break;
+
+ default:
+ smb_pop_message(conn);
+ return CURLE_OK; /* ignore */
+ }
+
+ smb_pop_message(conn);
+
+ switch(next_state) {
+ case SMB_OPEN:
+ result = smb_send_open(conn);
+ break;
+
+ case SMB_DOWNLOAD:
+ result = smb_send_read(conn);
+ break;
+
+ case SMB_UPLOAD:
+ result = smb_send_write(conn);
+ break;
+
+ case SMB_CLOSE:
+ result = smb_send_close(conn);
+ break;
+
+ case SMB_TREE_DISCONNECT:
+ result = smb_send_tree_disconnect(conn);
+ break;
+
+ case SMB_DONE:
+ result = req->result;
+ *done = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if(result) {
+ connclose(conn, "SMB: failed to send message");
+ return result;
+ }
+
+ request_state(conn, next_state);
+
+ return CURLE_OK;
+}
+
+static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ struct smb_request *req = conn->data->req.protop;
+
+ (void) premature;
+
+ Curl_safefree(req->share);
+ Curl_safefree(conn->data->req.protop);
+
+ return status;
+}
+
+static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+ struct smb_request *req = conn->data->req.protop;
+
+ (void) dead;
+
+ Curl_safefree(smbc->domain);
+ Curl_safefree(smbc->recv_buf);
+
+ /* smb_done is not always called, so cleanup the request */
+ if(req) {
+ Curl_safefree(req->share);
+ }
+
+ return CURLE_OK;
+}
+
+static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ struct smb_conn *smbc = &conn->proto.smbc;
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ if(smbc->send_size || smbc->upload_size)
+ return GETSOCK_WRITESOCK(0);
+
+ return GETSOCK_READSOCK(0);
+}
+
+static CURLcode smb_parse_url_path(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct smb_request *req = data->req.protop;
+ char *path;
+ char *slash;
+
+ /* URL decode the path */
+ result = Curl_urldecode(data, data->state.path, 0, &path, NULL, TRUE);
+ if(result)
+ return result;
+
+ /* Parse the path for the share */
+ req->share = strdup((*path == '/' || *path == '\\') ? path + 1 : path);
+ if(!req->share) {
+ free(path);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ slash = strchr(req->share, '/');
+ if(!slash)
+ slash = strchr(req->share, '\\');
+
+ /* The share must be present */
+ if(!slash) {
+ free(path);
+
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Parse the path for the file path converting any forward slashes into
+ backslashes */
+ *slash++ = 0;
+ req->path = slash;
+ for(; *slash; slash++) {
+ if(*slash == '/')
+ *slash = '\\';
+ }
+
+ free(path);
+
+ return CURLE_OK;
+}
+
+#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
+
+#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */
diff --git a/Utilities/cmcurl/lib/smb.h b/Utilities/cmcurl/lib/smb.h
new file mode 100644
index 000000000..1a4f66e5a
--- /dev/null
+++ b/Utilities/cmcurl/lib/smb.h
@@ -0,0 +1,271 @@
+#ifndef HEADER_CURL_SMB_H
+#define HEADER_CURL_SMB_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+enum smb_conn_state {
+ SMB_NOT_CONNECTED = 0,
+ SMB_CONNECTING,
+ SMB_NEGOTIATE,
+ SMB_SETUP,
+ SMB_CONNECTED
+};
+
+struct smb_conn {
+ enum smb_conn_state state;
+ char *user;
+ char *domain;
+ unsigned char challenge[8];
+ unsigned int session_key;
+ unsigned short uid;
+ char *recv_buf;
+ size_t upload_size;
+ size_t send_size;
+ size_t sent;
+ size_t got;
+};
+
+/*
+ * Definitions for SMB protocol data structures
+ */
+#ifdef BUILDING_CURL_SMB_C
+
+#if defined(_MSC_VER) || defined(__ILEC400__)
+# define PACK
+# pragma pack(push)
+# pragma pack(1)
+#elif defined(__GNUC__)
+# define PACK __attribute__((packed))
+#else
+# define PACK
+#endif
+
+#define SMB_COM_CLOSE 0x04
+#define SMB_COM_READ_ANDX 0x2e
+#define SMB_COM_WRITE_ANDX 0x2f
+#define SMB_COM_TREE_DISCONNECT 0x71
+#define SMB_COM_NEGOTIATE 0x72
+#define SMB_COM_SETUP_ANDX 0x73
+#define SMB_COM_TREE_CONNECT_ANDX 0x75
+#define SMB_COM_NT_CREATE_ANDX 0xa2
+#define SMB_COM_NO_ANDX_COMMAND 0xff
+
+#define SMB_WC_CLOSE 0x03
+#define SMB_WC_READ_ANDX 0x0c
+#define SMB_WC_WRITE_ANDX 0x0e
+#define SMB_WC_SETUP_ANDX 0x0d
+#define SMB_WC_TREE_CONNECT_ANDX 0x04
+#define SMB_WC_NT_CREATE_ANDX 0x18
+
+#define SMB_FLAGS_CANONICAL_PATHNAMES 0x10
+#define SMB_FLAGS_CASELESS_PATHNAMES 0x08
+#define SMB_FLAGS2_UNICODE_STRINGS 0x8000
+#define SMB_FLAGS2_IS_LONG_NAME 0x0040
+#define SMB_FLAGS2_KNOWS_LONG_NAME 0x0001
+
+#define SMB_CAP_LARGE_FILES 0x08
+#define SMB_GENERIC_WRITE 0x40000000
+#define SMB_GENERIC_READ 0x80000000
+#define SMB_FILE_SHARE_ALL 0x07
+#define SMB_FILE_OPEN 0x01
+#define SMB_FILE_OVERWRITE_IF 0x05
+
+#define SMB_ERR_NOACCESS 0x00050001
+
+struct smb_header {
+ unsigned char nbt_type;
+ unsigned char nbt_flags;
+ unsigned short nbt_length;
+ unsigned char magic[4];
+ unsigned char command;
+ unsigned int status;
+ unsigned char flags;
+ unsigned short flags2;
+ unsigned short pid_high;
+ unsigned char signature[8];
+ unsigned short pad;
+ unsigned short tid;
+ unsigned short pid;
+ unsigned short uid;
+ unsigned short mid;
+} PACK;
+
+struct smb_negotiate_response {
+ struct smb_header h;
+ unsigned char word_count;
+ unsigned short dialect_index;
+ unsigned char security_mode;
+ unsigned short max_mpx_count;
+ unsigned short max_number_vcs;
+ unsigned int max_buffer_size;
+ unsigned int max_raw_size;
+ unsigned int session_key;
+ unsigned int capabilities;
+ unsigned int system_time_low;
+ unsigned int system_time_high;
+ unsigned short server_time_zone;
+ unsigned char encryption_key_length;
+ unsigned short byte_count;
+ char bytes[1];
+} PACK;
+
+struct andx {
+ unsigned char command;
+ unsigned char pad;
+ unsigned short offset;
+} PACK;
+
+struct smb_setup {
+ unsigned char word_count;
+ struct andx andx;
+ unsigned short max_buffer_size;
+ unsigned short max_mpx_count;
+ unsigned short vc_number;
+ unsigned int session_key;
+ unsigned short lengths[2];
+ unsigned int pad;
+ unsigned int capabilities;
+ unsigned short byte_count;
+ char bytes[1024];
+} PACK;
+
+struct smb_tree_connect {
+ unsigned char word_count;
+ struct andx andx;
+ unsigned short flags;
+ unsigned short pw_len;
+ unsigned short byte_count;
+ char bytes[1024];
+} PACK;
+
+struct smb_nt_create {
+ unsigned char word_count;
+ struct andx andx;
+ unsigned char pad;
+ unsigned short name_length;
+ unsigned int flags;
+ unsigned int root_fid;
+ unsigned int access;
+#ifdef HAVE_LONGLONG
+ unsigned long long allocation_size;
+#else
+ unsigned __int64 allocation_size;
+#endif
+ unsigned int ext_file_attributes;
+ unsigned int share_access;
+ unsigned int create_disposition;
+ unsigned int create_options;
+ unsigned int impersonation_level;
+ unsigned char security_flags;
+ unsigned short byte_count;
+ char bytes[1024];
+} PACK;
+
+struct smb_nt_create_response {
+ struct smb_header h;
+ unsigned char word_count;
+ struct andx andx;
+ unsigned char op_lock_level;
+ unsigned short fid;
+ unsigned int create_disposition;
+#ifdef HAVE_LONGLONG
+ unsigned long long create_time;
+ unsigned long long last_access_time;
+ unsigned long long last_write_time;
+ unsigned long long last_change_time;
+#else
+ unsigned __int64 create_time;
+ unsigned __int64 last_access_time;
+ unsigned __int64 last_write_time;
+ unsigned __int64 last_change_time;
+#endif
+ unsigned int ext_file_attributes;
+#ifdef HAVE_LONGLONG
+ unsigned long long allocation_size;
+ unsigned long long end_of_file;
+#else
+ unsigned __int64 allocation_size;
+ unsigned __int64 end_of_file;
+#endif
+} PACK;
+
+struct smb_read {
+ unsigned char word_count;
+ struct andx andx;
+ unsigned short fid;
+ unsigned int offset;
+ unsigned short max_bytes;
+ unsigned short min_bytes;
+ unsigned int timeout;
+ unsigned short remaining;
+ unsigned int offset_high;
+ unsigned short byte_count;
+} PACK;
+
+struct smb_write {
+ struct smb_header h;
+ unsigned char word_count;
+ struct andx andx;
+ unsigned short fid;
+ unsigned int offset;
+ unsigned int timeout;
+ unsigned short write_mode;
+ unsigned short remaining;
+ unsigned short pad;
+ unsigned short data_length;
+ unsigned short data_offset;
+ unsigned int offset_high;
+ unsigned short byte_count;
+ unsigned char pad2;
+} PACK;
+
+struct smb_close {
+ unsigned char word_count;
+ unsigned short fid;
+ unsigned int last_mtime;
+ unsigned short byte_count;
+} PACK;
+
+struct smb_tree_disconnect {
+ unsigned char word_count;
+ unsigned short byte_count;
+} PACK;
+
+#if defined(_MSC_VER) || defined(__ILEC400__)
+# pragma pack(pop)
+#endif
+
+#endif /* BUILDING_CURL_SMB_C */
+
+#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
+ (CURL_SIZEOF_CURL_OFF_T > 4)
+
+#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
+
+extern const struct Curl_handler Curl_handler_smb;
+extern const struct Curl_handler Curl_handler_smbs;
+
+#endif /* !USE_WINDOWS_SSPI || USE_WIN32_CRYPTO */
+
+#endif /* CURL_DISABLE_SMB && USE_NTLM && CURL_SIZEOF_CURL_OFF_T > 4 */
+
+#endif /* HEADER_CURL_SMB_H */
diff --git a/Utilities/cmcurl/lib/smtp.c b/Utilities/cmcurl/lib/smtp.c
new file mode 100644
index 000000000..fe064cb2f
--- /dev/null
+++ b/Utilities/cmcurl/lib/smtp.c
@@ -0,0 +1,1673 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC1870 SMTP Service Extension for Message Size
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3207 SMTP over TLS
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ * RFC4954 SMTP Authentication
+ * RFC5321 SMTP protocol
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * Draft SMTP URL Interface <draft-earhart-url-smtp-00.txt>
+ * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_SMTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "smtp.h"
+#include "strtoofft.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "curl_gethostname.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local API functions */
+static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode smtp_do(struct connectdata *conn, bool *done);
+static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode smtp_connect(struct connectdata *conn, bool *done);
+static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
+static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
+static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode smtp_setup_connection(struct connectdata *conn);
+static CURLcode smtp_parse_url_options(struct connectdata *conn);
+static CURLcode smtp_parse_url_path(struct connectdata *conn);
+static CURLcode smtp_parse_custom_request(struct connectdata *conn);
+static CURLcode smtp_perform_auth(struct connectdata *conn, const char *mech,
+ const char *initresp);
+static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp);
+static void smtp_get_message(char *buffer, char **outptr);
+
+/*
+ * SMTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtp = {
+ "SMTP", /* scheme */
+ smtp_setup_connection, /* setup_connection */
+ smtp_do, /* do_it */
+ smtp_done, /* done */
+ ZERO_NULL, /* do_more */
+ smtp_connect, /* connect_it */
+ smtp_multi_statemach, /* connecting */
+ smtp_doing, /* doing */
+ smtp_getsock, /* proto_getsock */
+ smtp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smtp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTP, /* defport */
+ CURLPROTO_SMTP, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY | /* flags */
+ PROTOPT_URLOPTIONS
+};
+
+#ifdef USE_SSL
+/*
+ * SMTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtps = {
+ "SMTPS", /* scheme */
+ smtp_setup_connection, /* setup_connection */
+ smtp_do, /* do_it */
+ smtp_done, /* done */
+ ZERO_NULL, /* do_more */
+ smtp_connect, /* connect_it */
+ smtp_multi_statemach, /* connecting */
+ smtp_doing, /* doing */
+ smtp_getsock, /* proto_getsock */
+ smtp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smtp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTPS, /* defport */
+ CURLPROTO_SMTPS, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL
+ | PROTOPT_NOURLQUERY | PROTOPT_URLOPTIONS /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed SMTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtp_proxy = {
+ "SMTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed SMTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtps_proxy = {
+ "SMTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+/* SASL parameters for the smtp protocol */
+static const struct SASLproto saslsmtp = {
+ "smtp", /* The service name */
+ 334, /* Code received when continuation is expected */
+ 235, /* Code to receive upon authentication success */
+ 512 - 8, /* Maximum initial response length (no max) */
+ smtp_perform_auth, /* Send authentication command */
+ smtp_continue_auth, /* Send authentication continuation */
+ smtp_get_message /* Get SASL response message */
+};
+
+#ifdef USE_SSL
+static void smtp_to_smtps(struct connectdata *conn)
+{
+ /* Change the connection handler */
+ conn->handler = &Curl_handler_smtps;
+
+ /* Set the connection's upgraded to TLS flag */
+ conn->tls_upgraded = TRUE;
+}
+#else
+#define smtp_to_smtps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * smtp_endofresp()
+ *
+ * Checks for an ending SMTP status code at the start of the given string, but
+ * also detects various capabilities from the EHLO response including the
+ * supported authentication mechanisms.
+ */
+static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ bool result = FALSE;
+
+ /* Nothing for us */
+ if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
+ return FALSE;
+
+ /* Do we have a command response? This should be the response code followed
+ by a space and optionally some text as per RFC-5321 and as outlined in
+ Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
+ only send the response code instead as per Section 4.2. */
+ if(line[3] == ' ' || len == 5) {
+ result = TRUE;
+ *resp = curlx_sltosi(strtol(line, NULL, 10));
+
+ /* Make sure real server never sends internal value */
+ if(*resp == 1)
+ *resp = 0;
+ }
+ /* Do we have a multiline (continuation) response? */
+ else if(line[3] == '-' &&
+ (smtpc->state == SMTP_EHLO || smtpc->state == SMTP_COMMAND)) {
+ result = TRUE;
+ *resp = 1; /* Internal response code */
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_get_message()
+ *
+ * Gets the authentication message from the response buffer.
+ */
+static void smtp_get_message(char *buffer, char **outptr)
+{
+ size_t len = 0;
+ char *message = NULL;
+
+ /* Find the start of the message */
+ for(message = buffer + 4; *message == ' ' || *message == '\t'; message++)
+ ;
+
+ /* Find the end of the message */
+ for(len = strlen(message); len--;)
+ if(message[len] != '\r' && message[len] != '\n' && message[len] != ' ' &&
+ message[len] != '\t')
+ break;
+
+ /* Terminate the message */
+ if(++len) {
+ message[len] = '\0';
+ }
+
+ *outptr = message;
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change SMTP state!
+ */
+static void state(struct connectdata *conn, smtpstate newstate)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "STOP",
+ "SERVERGREET",
+ "EHLO",
+ "HELO",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTH",
+ "COMMAND",
+ "MAIL",
+ "RCPT",
+ "DATA",
+ "POSTDATA",
+ "QUIT",
+ /* LAST */
+ };
+
+ if(smtpc->state != newstate)
+ infof(conn->data, "SMTP %p state change from %s to %s\n",
+ (void *)smtpc, names[smtpc->state], names[newstate]);
+#endif
+
+ smtpc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_ehlo()
+ *
+ * Sends the EHLO command to not only initialise communication with the ESMTP
+ * server but to also obtain a list of server side supported capabilities.
+ */
+static CURLcode smtp_perform_ehlo(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ smtpc->sasl.authmechs = SASL_AUTH_NONE; /* No known auth. mechanism yet */
+ smtpc->sasl.authused = SASL_AUTH_NONE; /* Clear the authentication mechanism
+ used for esmtp connections */
+ smtpc->tls_supported = FALSE; /* Clear the TLS capability */
+ smtpc->auth_supported = FALSE; /* Clear the AUTH capability */
+
+ /* Send the EHLO command */
+ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
+
+ if(!result)
+ state(conn, SMTP_EHLO);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_helo()
+ *
+ * Sends the HELO command to initialise communication with the SMTP server.
+ */
+static CURLcode smtp_perform_helo(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ smtpc->sasl.authused = SASL_AUTH_NONE; /* No authentication mechanism used
+ in smtp connections */
+
+ /* Send the HELO command */
+ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
+
+ if(!result)
+ state(conn, SMTP_HELO);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode smtp_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STARTTLS command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
+
+ if(!result)
+ state(conn, SMTP_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
+
+ if(!result) {
+ if(smtpc->state != SMTP_UPGRADETLS)
+ state(conn, SMTP_UPGRADETLS);
+
+ if(smtpc->ssldone) {
+ smtp_to_smtps(conn);
+ result = smtp_perform_ehlo(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_auth()
+ *
+ * Sends an AUTH command allowing the client to login with the given SASL
+ * authentication mechanism.
+ */
+static CURLcode smtp_perform_auth(struct connectdata *conn,
+ const char *mech,
+ const char *initresp)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ if(initresp) { /* AUTH <mech> ...<crlf> */
+ /* Send the AUTH command with the initial response */
+ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
+ }
+ else {
+ /* Send the AUTH command */
+ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_continue_auth()
+ *
+ * Sends SASL continuation data or cancellation.
+ */
+static CURLcode smtp_continue_auth(struct connectdata *conn, const char *resp)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ return Curl_pp_sendf(&smtpc->pp, "%s", resp);
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_authentication()
+ *
+ * Initiates the authentication sequence, with the appropriate SASL
+ * authentication mechanism.
+ */
+static CURLcode smtp_perform_authentication(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ saslprogress progress;
+
+ /* Check we have enough data to authenticate with, and the
+ server supports authentiation, and end the connect phase if not */
+ if(!smtpc->auth_supported ||
+ !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
+ state(conn, SMTP_STOP);
+ return result;
+ }
+
+ /* Calculate the SASL login details */
+ result = Curl_sasl_start(&smtpc->sasl, conn, FALSE, &progress);
+
+ if(!result) {
+ if(progress == SASL_INPROGRESS)
+ state(conn, SMTP_AUTH);
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_command()
+ *
+ * Sends a SMTP based command.
+ */
+static CURLcode smtp_perform_command(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ /* Send the command */
+ if(smtp->rcpt)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s %s",
+ smtp->custom && smtp->custom[0] != '\0' ?
+ smtp->custom : "VRFY",
+ smtp->rcpt->data);
+ else
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s",
+ smtp->custom && smtp->custom[0] != '\0' ?
+ smtp->custom : "HELP");
+
+ if(!result)
+ state(conn, SMTP_COMMAND);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_mail()
+ *
+ * Sends an MAIL command to initiate the upload of a message.
+ */
+static CURLcode smtp_perform_mail(struct connectdata *conn)
+{
+ char *from = NULL;
+ char *auth = NULL;
+ char *size = NULL;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ /* Calculate the FROM parameter */
+ if(!data->set.str[STRING_MAIL_FROM])
+ /* Null reverse-path, RFC-5321, sect. 3.6.3 */
+ from = strdup("<>");
+ else if(data->set.str[STRING_MAIL_FROM][0] == '<')
+ from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
+ else
+ from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
+
+ if(!from)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Calculate the optional AUTH parameter */
+ if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.sasl.authused) {
+ if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
+ auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
+ else
+ /* Empty AUTH, RFC-2554, sect. 5 */
+ auth = strdup("<>");
+
+ if(!auth) {
+ free(from);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Calculate the optional SIZE parameter */
+ if(conn->proto.smtpc.size_supported && conn->data->state.infilesize > 0) {
+ size = aprintf("%" CURL_FORMAT_CURL_OFF_T, data->state.infilesize);
+
+ if(!size) {
+ free(from);
+ free(auth);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Send the MAIL command */
+ if(!auth && !size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s", from);
+ else if(auth && !size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s AUTH=%s", from, auth);
+ else if(auth && size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
+ else
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s SIZE=%s", from, size);
+
+ free(from);
+ free(auth);
+ free(size);
+
+ if(!result)
+ state(conn, SMTP_MAIL);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_rcpt_to()
+ *
+ * Sends a RCPT TO command for a given recipient as part of the message upload
+ * process.
+ */
+static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ /* Send the RCPT TO command */
+ if(smtp->rcpt->data[0] == '<')
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
+ smtp->rcpt->data);
+ else
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
+ smtp->rcpt->data);
+ if(!result)
+ state(conn, SMTP_RCPT);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_quit()
+ *
+ * Performs the quit action prior to sclose() being called.
+ */
+static CURLcode smtp_perform_quit(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the QUIT command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
+
+ if(!result)
+ state(conn, SMTP_QUIT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "Got unexpected smtp-server response: %d", smtpcode);
+ result = CURLE_WEIRD_SERVER_REPLY;
+ }
+ else
+ result = smtp_perform_ehlo(conn);
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 220) {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied, code %d", smtpcode);
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = smtp_perform_authentication(conn);
+ }
+ else
+ result = smtp_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For EHLO responses */
+static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *line = data->state.buffer;
+ size_t len = strlen(line);
+ size_t wordlen;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2 && smtpcode != 1) {
+ if(data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use)
+ result = smtp_perform_helo(conn);
+ else {
+ failf(data, "Remote access denied: %d", smtpcode);
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ }
+ }
+ else {
+ line += 4;
+ len -= 4;
+
+ /* Does the server support the STARTTLS capability? */
+ if(len >= 8 && !memcmp(line, "STARTTLS", 8))
+ smtpc->tls_supported = TRUE;
+
+ /* Does the server support the SIZE capability? */
+ else if(len >= 4 && !memcmp(line, "SIZE", 4))
+ smtpc->size_supported = TRUE;
+
+ /* Does the server support authentication? */
+ else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
+ smtpc->auth_supported = TRUE;
+
+ /* Advance past the AUTH keyword */
+ line += 5;
+ len -= 5;
+
+ /* Loop through the data line */
+ for(;;) {
+ size_t llen;
+ unsigned int mechbit;
+
+ while(len &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ len--;
+ }
+
+ if(!len)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Test the word for a matching authentication mechanism */
+ mechbit = Curl_sasl_decode_mech(line, wordlen, &llen);
+ if(mechbit && llen == wordlen)
+ smtpc->sasl.authmechs |= mechbit;
+
+ line += wordlen;
+ len -= wordlen;
+ }
+ }
+
+ if(smtpcode != 1) {
+ if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(smtpc->tls_supported)
+ /* Switch to TLS connection now */
+ result = smtp_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = smtp_perform_authentication(conn);
+ else {
+ failf(data, "STARTTLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = smtp_perform_authentication(conn);
+ }
+ }
+
+ return result;
+}
+
+/* For HELO responses */
+static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "Remote access denied: %d", smtpcode);
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, SMTP_STOP);
+
+ return result;
+}
+
+/* For SASL authentication responses */
+static CURLcode smtp_state_auth_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ saslprogress progress;
+
+ (void)instate; /* no use for this yet */
+
+ result = Curl_sasl_continue(&smtpc->sasl, conn, smtpcode, &progress);
+ if(!result)
+ switch(progress) {
+ case SASL_DONE:
+ state(conn, SMTP_STOP); /* Authenticated */
+ break;
+ case SASL_IDLE: /* No mechanism left after cancellation */
+ failf(data, "Authentication cancelled");
+ result = CURLE_LOGIN_DENIED;
+ break;
+ default:
+ break;
+ }
+
+ return result;
+}
+
+/* For command responses */
+static CURLcode smtp_state_command_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+ char *line = data->state.buffer;
+ size_t len = strlen(line);
+
+ (void)instate; /* no use for this yet */
+
+ if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
+ (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
+ failf(data, "Command failed: %d", smtpcode);
+ result = CURLE_RECV_ERROR;
+ }
+ else {
+ /* Temporarily add the LF character back and send as body to the client */
+ if(!data->set.opt_no_body) {
+ line[len] = '\n';
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
+
+ if(smtpcode != 1) {
+ if(smtp->rcpt) {
+ smtp->rcpt = smtp->rcpt->next;
+
+ if(smtp->rcpt) {
+ /* Send the next command */
+ result = smtp_perform_command(conn);
+ }
+ else
+ /* End of DO phase */
+ state(conn, SMTP_STOP);
+ }
+ else
+ /* End of DO phase */
+ state(conn, SMTP_STOP);
+ }
+ }
+
+ return result;
+}
+
+/* For MAIL responses */
+static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "MAIL failed: %d", smtpcode);
+ result = CURLE_SEND_ERROR;
+ }
+ else
+ /* Start the RCPT TO command */
+ result = smtp_perform_rcpt_to(conn);
+
+ return result;
+}
+
+/* For RCPT responses */
+static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "RCPT failed: %d", smtpcode);
+ result = CURLE_SEND_ERROR;
+ }
+ else {
+ smtp->rcpt = smtp->rcpt->next;
+
+ if(smtp->rcpt)
+ /* Send the next RCPT TO command */
+ result = smtp_perform_rcpt_to(conn);
+ else {
+ /* Send the DATA command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
+
+ if(!result)
+ state(conn, SMTP_DATA);
+ }
+ }
+
+ return result;
+}
+
+/* For DATA response */
+static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 354) {
+ failf(data, "DATA failed: %d", smtpcode);
+ result = CURLE_SEND_ERROR;
+ }
+ else {
+ /* Set the progress upload size */
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+
+ /* SMTP upload */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* End of DO phase */
+ state(conn, SMTP_STOP);
+ }
+
+ return result;
+}
+
+/* For POSTDATA responses, which are received after the entire DATA
+ part has been sent to the server */
+static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 250)
+ result = CURLE_RECV_ERROR;
+
+ /* End of DONE phase */
+ state(conn, SMTP_STOP);
+
+ return result;
+}
+
+static CURLcode smtp_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ struct Curl_easy *data = conn->data;
+ int smtpcode;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct pingpong *pp = &smtpc->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
+ if(smtpc->state == SMTP_UPGRADETLS)
+ return smtp_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ do {
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
+ if(result)
+ return result;
+
+ /* Store the latest response for later retrieval if necessary */
+ if(smtpc->state != SMTP_QUIT && smtpcode != 1)
+ data->info.httpcode = smtpcode;
+
+ if(!smtpcode)
+ break;
+
+ /* We have now received a full SMTP server response */
+ switch(smtpc->state) {
+ case SMTP_SERVERGREET:
+ result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_EHLO:
+ result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_HELO:
+ result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_STARTTLS:
+ result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH:
+ result = smtp_state_auth_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_COMMAND:
+ result = smtp_state_command_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_MAIL:
+ result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_RCPT:
+ result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_DATA:
+ result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_POSTDATA:
+ result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, SMTP_STOP);
+ break;
+ }
+ } while(!result && smtpc->state != SMTP_STOP && Curl_pp_moredata(pp));
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
+ if(result || !smtpc->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&smtpc->pp, FALSE);
+ *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode smtp_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ while(smtpc->state != SMTP_STOP && !result)
+ result = Curl_pp_statemach(&smtpc->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the SMTP struct for the current Curl_easy if
+ required */
+static CURLcode smtp_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp;
+
+ smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
+ if(!smtp)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the SMTP "protocol connect" and "doing" phases only */
+static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * smtp_connect()
+ *
+ * This function should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable pointed to by 'done' will be TRUE if the protocol-layer
+ * connect phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode smtp_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct pingpong *pp = &smtpc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in SMTP */
+ connkeep(conn, "SMTP default");
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = smtp_statemach_act;
+ pp->endofresp = smtp_endofresp;
+ pp->conn = conn;
+
+ /* Initialize the SASL storage */
+ Curl_sasl_init(&smtpc->sasl, &saslsmtp);
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = smtp_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Parse the URL path */
+ result = smtp_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, SMTP_SERVERGREET);
+
+ result = smtp_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+ struct pingpong *pp = &conn->proto.smtpc.pp;
+ char *eob;
+ ssize_t len;
+ ssize_t bytes_written;
+
+ (void)premature;
+
+ if(!smtp || !pp->conn)
+ return CURLE_OK;
+
+ if(status) {
+ connclose(conn, "SMTP done with bad status"); /* marked for closure */
+ result = status; /* use the already set error code */
+ }
+ else if(!data->set.connect_only && data->set.upload && data->set.mail_rcpt) {
+ /* Calculate the EOB taking into account any terminating CRLF from the
+ previous line of the email or the CRLF of the DATA command when there
+ is "no mail data". RFC-5321, sect. 4.1.1.4.
+
+ Note: As some SSL backends, such as OpenSSL, will cause Curl_write() to
+ fail when using a different pointer following a previous write, that
+ returned CURLE_AGAIN, we duplicate the EOB now rather than when the
+ bytes written doesn't equal len. */
+ if(smtp->trailing_crlf || !conn->data->state.infilesize) {
+ eob = strdup(SMTP_EOB + 2);
+ len = SMTP_EOB_LEN - 2;
+ }
+ else {
+ eob = strdup(SMTP_EOB);
+ len = SMTP_EOB_LEN;
+ }
+
+ if(!eob)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the end of block data */
+ result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
+ if(result) {
+ free(eob);
+ return result;
+ }
+
+ if(bytes_written != len) {
+ /* The whole chunk was not sent so keep it around and adjust the
+ pingpong structure accordingly */
+ pp->sendthis = eob;
+ pp->sendsize = len;
+ pp->sendleft = len - bytes_written;
+ }
+ else {
+ /* Successfully sent so adjust the response timeout relative to now */
+ pp->response = Curl_tvnow();
+
+ free(eob);
+ }
+
+ state(conn, SMTP_POSTDATA);
+
+ /* Run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the smtp_multi_statemach function but we have no general support for
+ non-blocking DONE operations!
+ */
+ result = smtp_block_statemach(conn);
+ }
+
+ /* Cleanup our per-request based variables */
+ Curl_safefree(smtp->custom);
+
+ /* Clear the transfer mode for the next request */
+ smtp->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform()
+ *
+ * This is the actual DO function for SMTP. Transfer a mail, send a command
+ * or get some data according to the options previously setup.
+ */
+static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is SMTP and no proxy */
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ smtp->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Store the first recipient (or NULL if not specified) */
+ smtp->rcpt = data->set.mail_rcpt;
+
+ /* Start the first command in the DO phase */
+ if(data->set.upload && data->set.mail_rcpt)
+ /* MAIL transfer */
+ result = smtp_perform_mail(conn);
+ else
+ /* SMTP based command (VRFY, EXPN, NOOP, RSET or HELP) */
+ result = smtp_perform_command(conn);
+
+ if(result)
+ return result;
+
+ /* Run the state-machine */
+ result = smtp_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (smtp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode smtp_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ /* Parse the custom request */
+ result = smtp_parse_custom_request(conn);
+ if(result)
+ return result;
+
+ result = smtp_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_disconnect()
+ *
+ * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The SMTP session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
+ if(!smtp_perform_quit(conn))
+ (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&smtpc->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, smtpc->sasl.authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(smtpc->domain);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
+{
+ struct SMTP *smtp = conn->data->req.protop;
+
+ (void)connected;
+
+ if(smtp->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = smtp_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = smtp_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode smtp_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct Curl_easy *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, -1);
+ Curl_pgrsSetDownloadSize(data, -1);
+
+ /* Carry out the perform */
+ result = smtp_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = smtp_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode smtp_setup_connection(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result;
+
+ /* Clear the TLS upgraded flag */
+ conn->tls_upgraded = FALSE;
+
+ /* Set up the proxy if necessary */
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel SMTP operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_smtp)
+ conn->handler = &Curl_handler_smtp_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_smtps_proxy;
+#else
+ failf(data, "SMTPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+ /* set it up as a HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+
+#else
+ failf(data, "SMTP over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* Initialise the SMTP layer */
+ result = smtp_init(conn);
+ if(result)
+ return result;
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode smtp_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *ptr = conn->options;
+
+ smtpc->sasl.resetprefs = TRUE;
+
+ while(!result && ptr && *ptr) {
+ const char *key = ptr;
+ const char *value;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ value = ptr + 1;
+
+ while(*ptr && *ptr != ';')
+ ptr++;
+
+ if(strncasecompare(key, "AUTH=", 5))
+ result = Curl_sasl_parse_url_auth_option(&smtpc->sasl,
+ value, ptr - value);
+ else
+ result = CURLE_URL_MALFORMAT;
+
+ if(*ptr == ';')
+ ptr++;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode smtp_parse_url_path(struct connectdata *conn)
+{
+ /* The SMTP struct is already initialised in smtp_connect() */
+ struct Curl_easy *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *path = data->state.path;
+ char localhost[HOSTNAME_MAX + 1];
+
+ /* Calculate the path if necessary */
+ if(!*path) {
+ if(!Curl_gethostname(localhost, sizeof(localhost)))
+ path = localhost;
+ else
+ path = "localhost";
+ }
+
+ /* URL decode the path and use it as the domain in our EHLO */
+ return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode smtp_parse_custom_request(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ /* URL decode the custom request */
+ if(custom)
+ result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
+
+ return result;
+}
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread)
+{
+ /* When sending a SMTP payload we must detect CRLF. sequences making sure
+ they are sent as CRLF.. instead, as a . on the beginning of a line will
+ be deleted by the server when not part of an EOB terminator and a
+ genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
+ data by the server
+ */
+ ssize_t i;
+ ssize_t si;
+ struct Curl_easy *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+ char *scratch = data->state.scratch;
+ char *newscratch = NULL;
+ char *oldscratch = NULL;
+ size_t eob_sent;
+
+ /* Do we need to allocate a scratch buffer? */
+ if(!scratch || data->set.crlf) {
+ oldscratch = scratch;
+
+ scratch = newscratch = malloc(2 * data->set.buffer_size);
+ if(!newscratch) {
+ failf(data, "Failed to alloc scratch buffer!");
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Have we already sent part of the EOB? */
+ eob_sent = smtp->eob;
+
+ /* This loop can be improved by some kind of Boyer-Moore style of
+ approach but that is saved for later... */
+ for(i = 0, si = 0; i < nread; i++) {
+ if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
+ smtp->eob++;
+
+ /* Is the EOB potentially the terminating CRLF? */
+ if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
+ smtp->trailing_crlf = TRUE;
+ else
+ smtp->trailing_crlf = FALSE;
+ }
+ else if(smtp->eob) {
+ /* A previous substring matched so output that first */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
+
+ /* Then compare the first byte */
+ if(SMTP_EOB[0] == data->req.upload_fromhere[i])
+ smtp->eob = 1;
+ else
+ smtp->eob = 0;
+
+ eob_sent = 0;
+
+ /* Reset the trailing CRLF flag as there was more data */
+ smtp->trailing_crlf = FALSE;
+ }
+
+ /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
+ if(SMTP_EOB_FIND_LEN == smtp->eob) {
+ /* Copy the replacement data to the target buffer */
+ memcpy(&scratch[si], &SMTP_EOB_REPL[eob_sent],
+ SMTP_EOB_REPL_LEN - eob_sent);
+ si += SMTP_EOB_REPL_LEN - eob_sent;
+ smtp->eob = 0;
+ eob_sent = 0;
+ }
+ else if(!smtp->eob)
+ scratch[si++] = data->req.upload_fromhere[i];
+ }
+
+ if(smtp->eob - eob_sent) {
+ /* A substring matched before processing ended so output that now */
+ memcpy(&scratch[si], &SMTP_EOB[eob_sent], smtp->eob - eob_sent);
+ si += smtp->eob - eob_sent;
+ }
+
+ /* Only use the new buffer if we replaced something */
+ if(si != nread) {
+ /* Upload from the new (replaced) buffer instead */
+ data->req.upload_fromhere = scratch;
+
+ /* Save the buffer so it can be freed later */
+ data->state.scratch = scratch;
+
+ /* Free the old scratch buffer */
+ free(oldscratch);
+
+ /* Set the new amount too */
+ data->req.upload_present = si;
+ }
+ else
+ free(newscratch);
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_SMTP */
diff --git a/Utilities/cmcurl/lib/smtp.h b/Utilities/cmcurl/lib/smtp.h
new file mode 100644
index 000000000..b67340a40
--- /dev/null
+++ b/Utilities/cmcurl/lib/smtp.h
@@ -0,0 +1,91 @@
+#ifndef HEADER_CURL_SMTP_H
+#define HEADER_CURL_SMTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "pingpong.h"
+#include "curl_sasl.h"
+
+/****************************************************************************
+ * SMTP unique setup
+ ***************************************************************************/
+typedef enum {
+ SMTP_STOP, /* do nothing state, stops the state machine */
+ SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ SMTP_EHLO,
+ SMTP_HELO,
+ SMTP_STARTTLS,
+ SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ SMTP_AUTH,
+ SMTP_COMMAND, /* VRFY, EXPN, NOOP, RSET and HELP */
+ SMTP_MAIL, /* MAIL FROM */
+ SMTP_RCPT, /* RCPT TO */
+ SMTP_DATA,
+ SMTP_POSTDATA,
+ SMTP_QUIT,
+ SMTP_LAST /* never used */
+} smtpstate;
+
+/* This SMTP struct is used in the Curl_easy. All SMTP data that is
+ connection-oriented must be in smtp_conn to properly deal with the fact that
+ perhaps the Curl_easy is changed between the times the connection is
+ used. */
+struct SMTP {
+ curl_pp_transfer transfer;
+ char *custom; /* Custom Request */
+ struct curl_slist *rcpt; /* Recipient list */
+ size_t eob; /* Number of bytes of the EOB (End Of Body) that
+ have been received so far */
+ bool trailing_crlf; /* Specifies if the tailing CRLF is present */
+};
+
+/* smtp_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct smtp_conn {
+ struct pingpong pp;
+ smtpstate state; /* Always use smtp.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ char *domain; /* Client address/name to send in the EHLO */
+ struct SASL sasl; /* SASL-related storage */
+ bool tls_supported; /* StartTLS capability supported by server */
+ bool size_supported; /* If server supports SIZE extension according to
+ RFC 1870 */
+ bool auth_supported; /* AUTH capability supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_smtp;
+extern const struct Curl_handler Curl_handler_smtps;
+
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define SMTP_EOB_LEN 5
+#define SMTP_EOB_FIND_LEN 3
+
+/* if found in data, replace it with this string instead */
+#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
+#define SMTP_EOB_REPL_LEN 4
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread);
+
+#endif /* HEADER_CURL_SMTP_H */
diff --git a/Utilities/cmcurl/lib/sockaddr.h b/Utilities/cmcurl/lib/sockaddr.h
new file mode 100644
index 000000000..95ba4c3c9
--- /dev/null
+++ b/Utilities/cmcurl/lib/sockaddr.h
@@ -0,0 +1,43 @@
+#ifndef HEADER_CURL_SOCKADDR_H
+#define HEADER_CURL_SOCKADDR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+struct Curl_sockaddr_storage {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 sa_in6;
+#endif
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ struct sockaddr_storage sa_stor;
+#else
+ char cbuf[256]; /* this should be big enough to fit a lot */
+#endif
+ } buffer;
+};
+
+#endif /* HEADER_CURL_SOCKADDR_H */
+
diff --git a/Utilities/cmcurl/lib/socks.c b/Utilities/cmcurl/lib/socks.c
new file mode 100644
index 000000000..97a44b296
--- /dev/null
+++ b/Utilities/cmcurl/lib/socks.c
@@ -0,0 +1,782 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_PROXY)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn, /* connection data */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ ssize_t buffersize, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
+{
+ ssize_t nread;
+ ssize_t allread = 0;
+ int result;
+ time_t timeleft;
+ *n = 0;
+ for(;;) {
+ timeleft = Curl_timeleft(conn->data, NULL, TRUE);
+ if(timeleft < 0) {
+ /* we already got the timeout */
+ result = CURLE_OPERATION_TIMEDOUT;
+ break;
+ }
+ if(SOCKET_READABLE(sockfd, timeleft) <= 0) {
+ result = ~CURLE_OK;
+ break;
+ }
+ result = Curl_read_plain(sockfd, buf, buffersize, &nread);
+ if(CURLE_AGAIN == result)
+ continue;
+ if(result)
+ break;
+
+ if(buffersize == nread) {
+ allread += nread;
+ *n = allread;
+ result = CURLE_OK;
+ break;
+ }
+ if(!nread) {
+ result = ~CURLE_OK;
+ break;
+ }
+
+ buffersize -= nread;
+ buf += nread;
+ allread += nread;
+ }
+ return result;
+}
+
+/*
+* This function logs in to a SOCKS4 proxy and sends the specifics to the final
+* destination server.
+*
+* Reference :
+* http://socks.permeo.com/protocol/socks4.protocol
+*
+* Note :
+* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
+* Nonsupport "Identification Protocol (RFC1413)"
+*/
+CURLcode Curl_SOCKS4(const char *proxy_name,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn)
+{
+ const bool protocol4a =
+ (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
+#define SOCKS4REQLEN 262
+ unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
+ id */
+ int result;
+ CURLcode code;
+ curl_socket_t sock = conn->sock[sockindex];
+ struct Curl_easy *data = conn->data;
+
+ if(Curl_timeleft(data, NULL, TRUE) < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(conn->bits.httpproxy)
+ infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
+ protocol4a ? "a" : "", hostname, remote_port);
+
+ (void)curlx_nonblock(sock, FALSE);
+
+ infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
+
+ /*
+ * Compose socks4 request
+ *
+ * Request format
+ *
+ * +----+----+----+----+----+----+----+----+----+----+....+----+
+ * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
+ * +----+----+----+----+----+----+----+----+----+----+....+----+
+ * # of bytes: 1 1 2 4 variable 1
+ */
+
+ socksreq[0] = 4; /* version (SOCKS4) */
+ socksreq[1] = 1; /* connect */
+ socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
+ socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
+
+ /* DNS resolve only for SOCKS4, not SOCKS4a */
+ if(!protocol4a) {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *hp=NULL;
+ int rc;
+
+ rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+ if(rc == CURLRESOLV_ERROR)
+ return CURLE_COULDNT_RESOLVE_PROXY;
+
+ if(rc == CURLRESOLV_PENDING)
+ /* ignores the return code, but 'dns' remains NULL on failure */
+ (void)Curl_resolver_wait_resolv(conn, &dns);
+
+ /*
+ * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
+ * returns a Curl_addrinfo pointer that may not always look the same.
+ */
+ if(dns)
+ hp=dns->addr;
+ if(hp) {
+ char buf[64];
+ Curl_printable_address(hp, buf, sizeof(buf));
+
+ if(hp->ai_family == AF_INET) {
+ struct sockaddr_in *saddr_in;
+
+ saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
+ socksreq[4] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[0];
+ socksreq[5] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[1];
+ socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2];
+ socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3];
+
+ infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)\n", buf);
+ }
+ else {
+ hp = NULL; /* fail! */
+
+ failf(data, "SOCKS4 connection to %s not supported\n", buf);
+ }
+
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+ }
+ if(!hp) {
+ failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
+ hostname);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ }
+
+ /*
+ * This is currently not supporting "Identification Protocol (RFC1413)".
+ */
+ socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
+ if(proxy_name) {
+ size_t plen = strlen(proxy_name);
+ if(plen >= sizeof(socksreq) - 8) {
+ failf(data, "Too long SOCKS proxy name, can't use!\n");
+ return CURLE_COULDNT_CONNECT;
+ }
+ /* copy the proxy name WITH trailing zero */
+ memcpy(socksreq + 8, proxy_name, plen+1);
+ }
+
+ /*
+ * Make connection
+ */
+ {
+ ssize_t actualread;
+ ssize_t written;
+ ssize_t hostnamelen = 0;
+ int packetsize = 9 +
+ (int)strlen((char *)socksreq + 8); /* size including NUL */
+
+ /* If SOCKS4a, set special invalid IP address 0.0.0.x */
+ if(protocol4a) {
+ socksreq[4] = 0;
+ socksreq[5] = 0;
+ socksreq[6] = 0;
+ socksreq[7] = 1;
+ /* If still enough room in buffer, also append hostname */
+ hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
+ if(packetsize + hostnamelen <= SOCKS4REQLEN)
+ strcpy((char *)socksreq + packetsize, hostname);
+ else
+ hostnamelen = 0; /* Flag: hostname did not fit in buffer */
+ }
+
+ /* Send request */
+ code = Curl_write_plain(conn, sock, (char *)socksreq,
+ packetsize + hostnamelen,
+ &written);
+ if(code || (written != packetsize + hostnamelen)) {
+ failf(data, "Failed to send SOCKS4 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(protocol4a && hostnamelen == 0) {
+ /* SOCKS4a with very long hostname - send that name separately */
+ hostnamelen = (ssize_t)strlen(hostname) + 1;
+ code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
+ &written);
+ if(code || (written != hostnamelen)) {
+ failf(data, "Failed to send SOCKS4 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ packetsize = 8; /* receive data size */
+
+ /* Receive response */
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
+ &actualread);
+ if(result || (actualread != packetsize)) {
+ failf(data, "Failed to receive SOCKS4 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /*
+ * Response format
+ *
+ * +----+----+----+----+----+----+----+----+
+ * | VN | CD | DSTPORT | DSTIP |
+ * +----+----+----+----+----+----+----+----+
+ * # of bytes: 1 1 2 4
+ *
+ * VN is the version of the reply code and should be 0. CD is the result
+ * code with one of the following values:
+ *
+ * 90: request granted
+ * 91: request rejected or failed
+ * 92: request rejected because SOCKS server cannot connect to
+ * identd on the client
+ * 93: request rejected because the client program and identd
+ * report different user-ids
+ */
+
+ /* wrong version ? */
+ if(socksreq[0] != 0) {
+ failf(data,
+ "SOCKS4 reply has wrong version, version should be 4.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Result */
+ switch(socksreq[1]) {
+ case 90:
+ infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
+ break;
+ case 91:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected or failed.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (unsigned char)socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ case 92:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected because SOCKS server cannot connect to "
+ "identd on the client.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (unsigned char)socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ case 93:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected because the client program and identd "
+ "report different user-ids.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (unsigned char)socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ default:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", Unknown.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (((unsigned char)socksreq[8] << 8) | (unsigned char)socksreq[9]),
+ (unsigned char)socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ (void)curlx_nonblock(sock, TRUE);
+
+ return CURLE_OK; /* Proxy was successful! */
+}
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the final
+ * destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn)
+{
+ /*
+ According to the RFC1928, section "6. Replies". This is what a SOCK5
+ replies:
+
+ +----+-----+-------+------+----------+----------+
+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+ +----+-----+-------+------+----------+----------+
+ | 1 | 1 | X'00' | 1 | Variable | 2 |
+ +----+-----+-------+------+----------+----------+
+
+ Where:
+
+ o VER protocol version: X'05'
+ o REP Reply field:
+ o X'00' succeeded
+ */
+
+ unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ CURLcode code;
+ curl_socket_t sock = conn->sock[sockindex];
+ struct Curl_easy *data = conn->data;
+ time_t timeout;
+ bool socks5_resolve_local =
+ (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
+ const size_t hostname_len = strlen(hostname);
+ ssize_t len = 0;
+
+ if(conn->bits.httpproxy)
+ infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+ hostname, remote_port);
+
+ /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
+ if(!socks5_resolve_local && hostname_len > 255) {
+ infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
+ "length > 255 [actual len=%zu]\n", hostname_len);
+ socks5_resolve_local = TRUE;
+ }
+
+ /* get timeout */
+ timeout = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ (void)curlx_nonblock(sock, TRUE);
+
+ /* wait until socket gets connected */
+ result = SOCKET_WRITABLE(sock, timeout);
+
+ if(-1 == result) {
+ failf(conn->data, "SOCKS5: no connection here");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(0 == result) {
+ failf(conn->data, "SOCKS5: connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(result & CURL_CSELECT_ERR) {
+ failf(conn->data, "SOCKS5: error occurred during connection");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ socksreq[0] = 5; /* version */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
+ socksreq[2] = 0; /* no authentication */
+ socksreq[3] = 1; /* GSS-API */
+ socksreq[4] = 2; /* username/password */
+#else
+ socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
+ socksreq[2] = 0; /* no authentication */
+ socksreq[3] = 2; /* username/password */
+#endif
+
+ (void)curlx_nonblock(sock, FALSE);
+
+ infof(data, "SOCKS5 communication to %s:%d\n", hostname, remote_port);
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+ &written);
+ if(code || (written != (2 + (int)socksreq[1]))) {
+ failf(data, "Unable to send initial SOCKS5 request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ (void)curlx_nonblock(sock, TRUE);
+
+ result = SOCKET_READABLE(sock, timeout);
+
+ if(-1 == result) {
+ failf(conn->data, "SOCKS5 nothing to read");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(0 == result) {
+ failf(conn->data, "SOCKS5 read timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(result & CURL_CSELECT_ERR) {
+ failf(conn->data, "SOCKS5 read error occurred");
+ return CURLE_RECV_ERROR;
+ }
+
+ (void)curlx_nonblock(sock, FALSE);
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ if(result || (actualread != 2)) {
+ failf(data, "Unable to receive initial SOCKS5 response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[0] != 5) {
+ failf(data, "Received invalid version in initial SOCKS5 response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(socksreq[1] == 0) {
+ /* Nothing to do, no authentication needed */
+ ;
+ }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ else if(socksreq[1] == 1) {
+ code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
+ if(code) {
+ failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+#endif
+ else if(socksreq[1] == 2) {
+ /* Needs user name and password */
+ size_t proxy_name_len, proxy_password_len;
+ if(proxy_name && proxy_password) {
+ proxy_name_len = strlen(proxy_name);
+ proxy_password_len = strlen(proxy_password);
+ }
+ else {
+ proxy_name_len = 0;
+ proxy_password_len = 0;
+ }
+
+ /* username/password request looks like
+ * +----+------+----------+------+----------+
+ * |VER | ULEN | UNAME | PLEN | PASSWD |
+ * +----+------+----------+------+----------+
+ * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+ * +----+------+----------+------+----------+
+ */
+ len = 0;
+ socksreq[len++] = 1; /* username/pw subnegotiation version */
+ socksreq[len++] = (unsigned char) proxy_name_len;
+ if(proxy_name && proxy_name_len)
+ memcpy(socksreq + len, proxy_name, proxy_name_len);
+ len += proxy_name_len;
+ socksreq[len++] = (unsigned char) proxy_password_len;
+ if(proxy_password && proxy_password_len)
+ memcpy(socksreq + len, proxy_password, proxy_password_len);
+ len += proxy_password_len;
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
+ if(code || (len != written)) {
+ failf(data, "Failed to send SOCKS5 sub-negotiation request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ if(result || (actualread != 2)) {
+ failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] != 0) { /* status */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Everything is good so far, user was authenticated! */
+ }
+ else {
+ /* error */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(socksreq[1] == 255) {
+#else
+ if(socksreq[1] == 1) {
+ failf(data,
+ "SOCKS5 GSSAPI per-message authentication is not supported.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(socksreq[1] == 255) {
+#endif
+ if(!proxy_name || !*proxy_name) {
+ failf(data,
+ "No authentication method was acceptable. (It is quite likely"
+ " that the SOCKS5 server wanted a username/password, since none"
+ " was supplied to the server on this connection.)");
+ }
+ else {
+ failf(data, "No authentication method was acceptable.");
+ }
+ return CURLE_COULDNT_CONNECT;
+ }
+ else {
+ failf(data,
+ "Undocumented SOCKS5 mode attempted to be used by server.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ /* Authentication is complete, now specify destination to the proxy */
+ len = 0;
+ socksreq[len++] = 5; /* version (SOCKS5) */
+ socksreq[len++] = 1; /* connect */
+ socksreq[len++] = 0; /* must be zero */
+
+ if(!socks5_resolve_local) {
+ socksreq[len++] = 3; /* ATYP: domain name = 3 */
+ socksreq[len++] = (char) hostname_len; /* address length */
+ memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */
+ len += hostname_len;
+ }
+ else {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *hp = NULL;
+ int rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+ if(rc == CURLRESOLV_ERROR)
+ return CURLE_COULDNT_RESOLVE_HOST;
+
+ if(rc == CURLRESOLV_PENDING) {
+ /* this requires that we're in "wait for resolve" state */
+ code = Curl_resolver_wait_resolv(conn, &dns);
+ if(code)
+ return code;
+ }
+
+ /*
+ * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
+ * returns a Curl_addrinfo pointer that may not always look the same.
+ */
+ if(dns)
+ hp=dns->addr;
+ if(hp) {
+ int i;
+ char buf[64];
+ Curl_printable_address(hp, buf, sizeof(buf));
+
+ if(hp->ai_family == AF_INET) {
+ struct sockaddr_in *saddr_in;
+ socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
+
+ saddr_in = (struct sockaddr_in *)(void *)hp->ai_addr;
+ for(i = 0; i < 4; i++) {
+ socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i];
+ }
+
+ infof(data, "SOCKS5 connect to IPv4 %s (locally resolved)\n", buf);
+ }
+#ifdef ENABLE_IPV6
+ else if(hp->ai_family == AF_INET6) {
+ struct sockaddr_in6 *saddr_in6;
+ socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
+
+ saddr_in6 = (struct sockaddr_in6 *)(void *)hp->ai_addr;
+ for(i = 0; i < 16; i++) {
+ socksreq[len++] =
+ ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i];
+ }
+
+ infof(data, "SOCKS5 connect to IPv6 %s (locally resolved)\n", buf);
+ }
+#endif
+ else {
+ hp = NULL; /* fail! */
+
+ failf(data, "SOCKS5 connection to %s not supported\n", buf);
+ }
+
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+ }
+ if(!hp) {
+ failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+ hostname);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ }
+
+ socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
+ socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(conn->socks5_gssapi_enctype) {
+ failf(data, "SOCKS5 GSS-API protection not yet implemented.");
+ }
+ else
+#endif
+ code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
+
+ if(code || (len != written)) {
+ failf(data, "Failed to send SOCKS5 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ len = 10; /* minimum packet size is 10 */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(conn->socks5_gssapi_enctype) {
+ failf(data, "SOCKS5 GSS-API protection not yet implemented.");
+ }
+ else
+#endif
+ result = Curl_blockread_all(conn, sock, (char *)socksreq,
+ len, &actualread);
+
+ if(result || (len != actualread)) {
+ failf(data, "Failed to receive SOCKS5 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[0] != 5) { /* version */
+ failf(data,
+ "SOCKS5 reply has wrong version, version should be 5.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
+ 1928, so the reply packet should be read until the end to avoid errors at
+ subsequent protocol level.
+
+ +----+-----+-------+------+----------+----------+
+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+ +----+-----+-------+------+----------+----------+
+ | 1 | 1 | X'00' | 1 | Variable | 2 |
+ +----+-----+-------+------+----------+----------+
+
+ ATYP:
+ o IP v4 address: X'01', BND.ADDR = 4 byte
+ o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
+ o IP v6 address: X'04', BND.ADDR = 16 byte
+ */
+
+ /* Calculate real packet size */
+ if(socksreq[3] == 3) {
+ /* domain name */
+ int addrlen = (int) socksreq[4];
+ len = 5 + addrlen + 2;
+ }
+ else if(socksreq[3] == 4) {
+ /* IPv6 */
+ len = 4 + 16 + 2;
+ }
+
+ /* At this point we already read first 10 bytes */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(!conn->socks5_gssapi_enctype) {
+ /* decrypt_gssapi_blockread already read the whole packet */
+#endif
+ if(len > 10) {
+ result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
+ len - 10, &actualread);
+ if(result || ((len - 10) != actualread)) {
+ failf(data, "Failed to receive SOCKS5 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ }
+#endif
+
+ if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+ if(socksreq[3] == 1) {
+ failf(data,
+ "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (((unsigned char)socksreq[8] << 8) |
+ (unsigned char)socksreq[9]),
+ (unsigned char)socksreq[1]);
+ }
+ else if(socksreq[3] == 3) {
+ unsigned char port_upper = (unsigned char)socksreq[len - 2];
+ socksreq[len - 2] = 0;
+ failf(data,
+ "Can't complete SOCKS5 connection to %s:%d. (%d)",
+ (char *)&socksreq[5],
+ ((port_upper << 8) |
+ (unsigned char)socksreq[len - 1]),
+ (unsigned char)socksreq[1]);
+ socksreq[len - 2] = port_upper;
+ }
+ else if(socksreq[3] == 4) {
+ failf(data,
+ "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (unsigned char)socksreq[8], (unsigned char)socksreq[9],
+ (unsigned char)socksreq[10], (unsigned char)socksreq[11],
+ (unsigned char)socksreq[12], (unsigned char)socksreq[13],
+ (unsigned char)socksreq[14], (unsigned char)socksreq[15],
+ (unsigned char)socksreq[16], (unsigned char)socksreq[17],
+ (unsigned char)socksreq[18], (unsigned char)socksreq[19],
+ (((unsigned char)socksreq[20] << 8) |
+ (unsigned char)socksreq[21]),
+ (unsigned char)socksreq[1]);
+ }
+ return CURLE_COULDNT_CONNECT;
+ }
+ infof(data, "SOCKS5 request granted.\n");
+
+ (void)curlx_nonblock(sock, TRUE);
+ return CURLE_OK; /* Proxy was successful! */
+}
+
+#endif /* CURL_DISABLE_PROXY */
+
diff --git a/Utilities/cmcurl/lib/socks.h b/Utilities/cmcurl/lib/socks.h
new file mode 100644
index 000000000..348707e74
--- /dev/null
+++ b/Utilities/cmcurl/lib/socks.h
@@ -0,0 +1,76 @@
+#ifndef HEADER_CURL_SOCKS_H
+#define HEADER_CURL_SOCKS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef CURL_DISABLE_PROXY
+#define Curl_SOCKS4(a,b,c,d,e) CURLE_NOT_BUILT_IN
+#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN
+#else
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn,
+ curl_socket_t sockfd,
+ char *buf,
+ ssize_t buffersize,
+ ssize_t *n);
+
+/*
+ * This function logs in to a SOCKS4(a) proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS4(const char *proxy_name,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn);
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+/*
+ * This function handles the SOCKS5 GSS-API negotiation and initialisation
+ */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn);
+#endif
+
+#endif /* CURL_DISABLE_PROXY */
+
+#endif /* HEADER_CURL_SOCKS_H */
+
diff --git a/Utilities/cmcurl/lib/socks_gssapi.c b/Utilities/cmcurl/lib/socks_gssapi.c
new file mode 100644
index 000000000..54d063504
--- /dev/null
+++ b/Utilities/cmcurl/lib/socks_gssapi.c
@@ -0,0 +1,526 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && !defined(CURL_DISABLE_PROXY)
+
+#include "curl_gssapi.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
+
+/*
+ * Helper GSS-API error functions.
+ */
+static int check_gss_err(struct Curl_easy *data,
+ OM_uint32 major_status,
+ OM_uint32 minor_status,
+ const char *function)
+{
+ if(GSS_ERROR(major_status)) {
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ char buf[1024];
+ size_t len;
+
+ len = 0;
+ msg_ctx = 0;
+ while(!msg_ctx) {
+ /* convert major status code (GSS-API error) to text */
+ maj_stat = gss_display_status(&min_stat, major_status,
+ GSS_C_GSS_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if(maj_stat == GSS_S_COMPLETE) {
+ if(sizeof(buf) > len + status_string.length + 1) {
+ strcpy(buf+len, (char *) status_string.value);
+ len += status_string.length;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ if(sizeof(buf) > len + 3) {
+ strcpy(buf+len, ".\n");
+ len += 2;
+ }
+ msg_ctx = 0;
+ while(!msg_ctx) {
+ /* convert minor status code (underlying routine error) to text */
+ maj_stat = gss_display_status(&min_stat, minor_status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if(maj_stat == GSS_S_COMPLETE) {
+ if(sizeof(buf) > len + status_string.length)
+ strcpy(buf+len, (char *) status_string.value);
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ failf(data, "GSS-API error: %s failed:\n%s", function, buf);
+ return 1;
+ }
+
+ return 0;
+}
+
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sock = conn->sock[sockindex];
+ CURLcode code;
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ OM_uint32 gss_major_status, gss_minor_status, gss_status;
+ OM_uint32 gss_ret_flags;
+ int gss_conf_state, gss_enc;
+ gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
+ gss_name_t server = GSS_C_NO_NAME;
+ gss_name_t gss_client_name = GSS_C_NO_NAME;
+ unsigned short us_length;
+ char *user=NULL;
+ unsigned char socksreq[4]; /* room for GSS-API exchange header only */
+ const char *serviceptr = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+ data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
+ const size_t serviceptr_length = strlen(serviceptr);
+
+ /* GSS-API request looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ /* prepare service name */
+ if(strchr(serviceptr, '/')) {
+ service.length = serviceptr_length;
+ service.value = malloc(service.length);
+ if(!service.value)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(service.value, serviceptr, service.length);
+
+ gss_major_status = gss_import_name(&gss_minor_status, &service,
+ (gss_OID) GSS_C_NULL_OID, &server);
+ }
+ else {
+ service.value = malloc(serviceptr_length +
+ strlen(conn->socks_proxy.host.name)+2);
+ if(!service.value)
+ return CURLE_OUT_OF_MEMORY;
+ service.length = serviceptr_length + strlen(conn->socks_proxy.host.name)+1;
+ snprintf(service.value, service.length+1, "%s@%s",
+ serviceptr, conn->socks_proxy.host.name);
+
+ gss_major_status = gss_import_name(&gss_minor_status, &service,
+ GSS_C_NT_HOSTBASED_SERVICE, &server);
+ }
+
+ gss_release_buffer(&gss_status, &service); /* clear allocated memory */
+
+ if(check_gss_err(data, gss_major_status,
+ gss_minor_status, "gss_import_name()")) {
+ failf(data, "Failed to create service name.");
+ gss_release_name(&gss_status, &server);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* As long as we need to keep sending some context info, and there's no */
+ /* errors, keep sending it... */
+ for(;;) {
+ gss_major_status = Curl_gss_init_sec_context(data,
+ &gss_minor_status,
+ &gss_context,
+ server,
+ &Curl_krb5_mech_oid,
+ NULL,
+ gss_token,
+ &gss_send_token,
+ TRUE,
+ &gss_ret_flags);
+
+ if(gss_token != GSS_C_NO_BUFFER)
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ if(check_gss_err(data, gss_major_status,
+ gss_minor_status, "gss_init_sec_context")) {
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to initial GSS-API token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(gss_send_token.length != 0) {
+ socksreq[0] = 1; /* GSS-API subnegotiation version */
+ socksreq[1] = 1; /* authentication message type */
+ us_length = htons((short)gss_send_token.length);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if(code || (4 != written)) {
+ failf(data, "Failed to send GSS-API authentication request.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
+ gss_send_token.length, &written);
+
+ if(code || ((ssize_t)gss_send_token.length != written)) {
+ failf(data, "Failed to send GSS-API authentication token.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ }
+
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;
+
+ /* analyse response */
+
+ /* GSS-API response looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result || (actualread != 4)) {
+ failf(data, "Failed to receive GSS-API authentication response.");
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 1) { /* status / messgae type */
+ failf(data, "Invalid GSS-API authentication response type (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ gss_recv_token.length=us_length;
+ gss_recv_token.value=malloc(us_length);
+ if(!gss_recv_token.value) {
+ failf(data,
+ "Could not allocate memory for GSS-API authentication "
+ "response token.");
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
+
+ if(result || (actualread != us_length)) {
+ failf(data, "Failed to receive GSS-API authentication token.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ gss_token = &gss_recv_token;
+ }
+
+ gss_release_name(&gss_status, &server);
+
+ /* Everything is good so far, user was authenticated! */
+ gss_major_status = gss_inquire_context(&gss_minor_status, gss_context,
+ &gss_client_name, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if(check_gss_err(data, gss_major_status,
+ gss_minor_status, "gss_inquire_context")) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
+ &gss_send_token, NULL);
+ if(check_gss_err(data, gss_major_status,
+ gss_minor_status, "gss_display_name")) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ user=malloc(gss_send_token.length+1);
+ if(!user) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(user, gss_send_token.value, gss_send_token.length);
+ user[gss_send_token.length] = '\0';
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
+ free(user);
+ user=NULL;
+
+ /* Do encryption */
+ socksreq[0] = 1; /* GSS-API subnegotiation version */
+ socksreq[1] = 2; /* encryption message type */
+
+ gss_enc = 0; /* no data protection */
+ /* do confidentiality protection if supported */
+ if(gss_ret_flags & GSS_C_CONF_FLAG)
+ gss_enc = 2;
+ /* else do integrity protection */
+ else if(gss_ret_flags & GSS_C_INTEG_FLAG)
+ gss_enc = 1;
+
+ infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+ (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+ /* force for the moment to no data protection */
+ gss_enc = 0;
+ /*
+ * Sending the encryption type in clear seems wrong. It should be
+ * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+ * The NEC reference implementations on which this is based is
+ * therefore at fault
+ *
+ * +------+------+------+.......................+
+ * + ver | mtyp | len | token |
+ * +------+------+------+.......................+
+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+ * +------+------+------+.......................+
+ *
+ * Where:
+ *
+ * - "ver" is the protocol version number, here 1 to represent the
+ * first version of the SOCKS/GSS-API protocol
+ *
+ * - "mtyp" is the message type, here 2 to represent a protection
+ * -level negotiation message
+ *
+ * - "len" is the length of the "token" field in octets
+ *
+ * - "token" is the GSS-API encapsulated protection level
+ *
+ * The token is produced by encapsulating an octet containing the
+ * required protection level using gss_seal()/gss_wrap() with conf_req
+ * set to FALSE. The token is verified using gss_unseal()/
+ * gss_unwrap().
+ *
+ */
+ if(data->set.socks5_gssapi_nec) {
+ us_length = htons((short)1);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+ }
+ else {
+ gss_send_token.length = 1;
+ gss_send_token.value = malloc(1);
+ if(!gss_send_token.value) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(gss_send_token.value, &gss_enc, 1);
+
+ gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
+ GSS_C_QOP_DEFAULT, &gss_send_token,
+ &gss_conf_state, &gss_w_token);
+
+ if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_wrap")) {
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to wrap GSS-API encryption value into token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_send_token);
+
+ us_length = htons((short)gss_w_token.length);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if(code || (4 != written)) {
+ failf(data, "Failed to send GSS-API encryption request.");
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(data->set.socks5_gssapi_nec) {
+ memcpy(socksreq, &gss_enc, 1);
+ code = Curl_write_plain(conn, sock, socksreq, 1, &written);
+ if(code || ( 1 != written)) {
+ failf(data, "Failed to send GSS-API encryption type.");
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+ else {
+ code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
+ gss_w_token.length, &written);
+ if(code || ((ssize_t)gss_w_token.length != written)) {
+ failf(data, "Failed to send GSS-API encryption type.");
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_w_token);
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result || (actualread != 4)) {
+ failf(data, "Failed to receive GSS-API encryption response.");
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 2) { /* status / messgae type */
+ failf(data, "Invalid GSS-API encryption response type (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ gss_recv_token.length= us_length;
+ gss_recv_token.value=malloc(gss_recv_token.length);
+ if(!gss_recv_token.value) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
+
+ if(result || (actualread != us_length)) {
+ failf(data, "Failed to receive GSS-API encryptrion type.");
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(!data->set.socks5_gssapi_nec) {
+ gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
+ &gss_recv_token, &gss_w_token,
+ 0, GSS_C_QOP_DEFAULT);
+
+ if(check_gss_err(data, gss_major_status, gss_minor_status, "gss_unwrap")) {
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to unwrap GSS-API encryption value into token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_recv_token);
+
+ if(gss_w_token.length != 1) {
+ failf(data, "Invalid GSS-API encryption response length (%d).",
+ gss_w_token.length);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq, gss_w_token.value, gss_w_token.length);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ }
+ else {
+ if(gss_recv_token.length != 1) {
+ failf(data, "Invalid GSS-API encryption response length (%d).",
+ gss_recv_token.length);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq, gss_recv_token.value, gss_recv_token.length);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ }
+
+ infof(data, "SOCKS5 access with%s protection granted.\n",
+ (socksreq[0]==0)?"out GSS-API data":
+ ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+
+ conn->socks5_gssapi_enctype = socksreq[0];
+ if(socksreq[0] == 0)
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+
+ return CURLE_OK;
+}
+
+#endif /* HAVE_GSSAPI && !CURL_DISABLE_PROXY */
diff --git a/Utilities/cmcurl/lib/socks_sspi.c b/Utilities/cmcurl/lib/socks_sspi.c
new file mode 100644
index 000000000..edc73ad2e
--- /dev/null
+++ b/Utilities/cmcurl/lib/socks_sspi.c
@@ -0,0 +1,605 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY)
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "strerror.h"
+#include "timeval.h"
+#include "socks.h"
+#include "curl_sspi.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Helper sspi error functions.
+ */
+static int check_sspi_err(struct connectdata *conn,
+ SECURITY_STATUS status,
+ const char *function)
+{
+ if(status != SEC_E_OK &&
+ status != SEC_I_COMPLETE_AND_CONTINUE &&
+ status != SEC_I_COMPLETE_NEEDED &&
+ status != SEC_I_CONTINUE_NEEDED) {
+ failf(conn->data, "SSPI error: %s failed: %s", function,
+ Curl_sspi_strerror(conn, status));
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the SSPI-using version of this function */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sock = conn->sock[sockindex];
+ CURLcode code;
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ /* Needs GSS-API authentication */
+ SECURITY_STATUS status;
+ unsigned long sspi_ret_flags = 0;
+ unsigned char gss_enc;
+ SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
+ SecBufferDesc input_desc, output_desc, wrap_desc;
+ SecPkgContext_Sizes sspi_sizes;
+ CredHandle cred_handle;
+ CtxtHandle sspi_context;
+ PCtxtHandle context_handle = NULL;
+ SecPkgCredentials_Names names;
+ TimeStamp expiry;
+ char *service_name = NULL;
+ unsigned short us_length;
+ unsigned long qop;
+ unsigned char socksreq[4]; /* room for GSS-API exchange header only */
+ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+ data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd";
+ const size_t service_length = strlen(service);
+
+ /* GSS-API request looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ /* prepare service name */
+ if(strchr(service, '/')) {
+ service_name = strdup(service);
+ if(!service_name)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ service_name = malloc(service_length +
+ strlen(conn->socks_proxy.host.name) + 2);
+ if(!service_name)
+ return CURLE_OUT_OF_MEMORY;
+ snprintf(service_name, service_length +
+ strlen(conn->socks_proxy.host.name)+2, "%s/%s",
+ service, conn->socks_proxy.host.name);
+ }
+
+ input_desc.cBuffers = 1;
+ input_desc.pBuffers = &sspi_recv_token;
+ input_desc.ulVersion = SECBUFFER_VERSION;
+
+ sspi_recv_token.BufferType = SECBUFFER_TOKEN;
+ sspi_recv_token.cbBuffer = 0;
+ sspi_recv_token.pvBuffer = NULL;
+
+ output_desc.cBuffers = 1;
+ output_desc.pBuffers = &sspi_send_token;
+ output_desc.ulVersion = SECBUFFER_VERSION;
+
+ sspi_send_token.BufferType = SECBUFFER_TOKEN;
+ sspi_send_token.cbBuffer = 0;
+ sspi_send_token.pvBuffer = NULL;
+
+ wrap_desc.cBuffers = 3;
+ wrap_desc.pBuffers = sspi_w_token;
+ wrap_desc.ulVersion = SECBUFFER_VERSION;
+
+ cred_handle.dwLower = 0;
+ cred_handle.dwUpper = 0;
+
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT("Kerberos"),
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred_handle,
+ &expiry);
+
+ if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) {
+ failf(data, "Failed to acquire credentials.");
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* As long as we need to keep sending some context info, and there's no */
+ /* errors, keep sending it... */
+ for(;;) {
+ TCHAR *sname;
+
+ sname = Curl_convert_UTF8_to_tchar(service_name);
+ if(!sname)
+ return CURLE_OUT_OF_MEMORY;
+
+ status = s_pSecFn->InitializeSecurityContext(&cred_handle,
+ context_handle,
+ sname,
+ ISC_REQ_MUTUAL_AUTH |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_REPLAY_DETECT,
+ 0,
+ SECURITY_NATIVE_DREP,
+ &input_desc,
+ 0,
+ &sspi_context,
+ &output_desc,
+ &sspi_ret_flags,
+ &expiry);
+
+ Curl_unicodefree(sname);
+
+ if(sspi_recv_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ sspi_recv_token.pvBuffer = NULL;
+ sspi_recv_token.cbBuffer = 0;
+ }
+
+ if(check_sspi_err(conn, status, "InitializeSecurityContext")) {
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ if(sspi_recv_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ failf(data, "Failed to initialise security context.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(sspi_send_token.cbBuffer != 0) {
+ socksreq[0] = 1; /* GSS-API subnegotiation version */
+ socksreq[1] = 1; /* authentication message type */
+ us_length = htons((short)sspi_send_token.cbBuffer);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if(code || (4 != written)) {
+ failf(data, "Failed to send SSPI authentication request.");
+ free(service_name);
+ if(sspi_send_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ if(sspi_recv_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+ sspi_send_token.cbBuffer, &written);
+ if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
+ failf(data, "Failed to send SSPI authentication token.");
+ free(service_name);
+ if(sspi_send_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ if(sspi_recv_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ }
+
+ if(sspi_send_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ sspi_send_token.pvBuffer = NULL;
+ }
+ sspi_send_token.cbBuffer = 0;
+
+ if(sspi_recv_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ sspi_recv_token.pvBuffer = NULL;
+ }
+ sspi_recv_token.cbBuffer = 0;
+
+ if(status != SEC_I_CONTINUE_NEEDED)
+ break;
+
+ /* analyse response */
+
+ /* GSS-API response looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result || (actualread != 4)) {
+ failf(data, "Failed to receive SSPI authentication response.");
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 1) { /* status / messgae type */
+ failf(data, "Invalid SSPI authentication response type (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ sspi_recv_token.cbBuffer = us_length;
+ sspi_recv_token.pvBuffer = malloc(us_length);
+
+ if(!sspi_recv_token.pvBuffer) {
+ free(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
+ sspi_recv_token.cbBuffer, &actualread);
+
+ if(result || (actualread != us_length)) {
+ failf(data, "Failed to receive SSPI authentication token.");
+ free(service_name);
+ if(sspi_recv_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ context_handle = &sspi_context;
+ }
+
+ free(service_name);
+
+ /* Everything is good so far, user was authenticated! */
+ status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
+ SECPKG_CRED_ATTR_NAMES,
+ &names);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ if(check_sspi_err(conn, status, "QueryCredentialAttributes")) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",
+ names.sUserName);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
+
+ /* Do encryption */
+ socksreq[0] = 1; /* GSS-API subnegotiation version */
+ socksreq[1] = 2; /* encryption message type */
+
+ gss_enc = 0; /* no data protection */
+ /* do confidentiality protection if supported */
+ if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
+ gss_enc = 2;
+ /* else do integrity protection */
+ else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
+ gss_enc = 1;
+
+ infof(data, "SOCKS5 server supports GSS-API %s data protection.\n",
+ (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
+ /* force to no data protection, avoid encryption/decryption for now */
+ gss_enc = 0;
+ /*
+ * Sending the encryption type in clear seems wrong. It should be
+ * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+ * The NEC reference implementations on which this is based is
+ * therefore at fault
+ *
+ * +------+------+------+.......................+
+ * + ver | mtyp | len | token |
+ * +------+------+------+.......................+
+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+ * +------+------+------+.......................+
+ *
+ * Where:
+ *
+ * - "ver" is the protocol version number, here 1 to represent the
+ * first version of the SOCKS/GSS-API protocol
+ *
+ * - "mtyp" is the message type, here 2 to represent a protection
+ * -level negotiation message
+ *
+ * - "len" is the length of the "token" field in octets
+ *
+ * - "token" is the GSS-API encapsulated protection level
+ *
+ * The token is produced by encapsulating an octet containing the
+ * required protection level using gss_seal()/gss_wrap() with conf_req
+ * set to FALSE. The token is verified using gss_unseal()/
+ * gss_unwrap().
+ *
+ */
+
+ if(data->set.socks5_gssapi_nec) {
+ us_length = htons((short)1);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+ }
+ else {
+ status = s_pSecFn->QueryContextAttributes(&sspi_context,
+ SECPKG_ATTR_SIZES,
+ &sspi_sizes);
+ if(check_sspi_err(conn, status, "QueryContextAttributes")) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
+ sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
+ sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
+
+ if(!sspi_w_token[0].pvBuffer) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ sspi_w_token[1].cbBuffer = 1;
+ sspi_w_token[1].pvBuffer = malloc(1);
+ if(!sspi_w_token[1].pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1);
+ sspi_w_token[2].BufferType = SECBUFFER_PADDING;
+ sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
+ sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
+ if(!sspi_w_token[2].pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ status = s_pSecFn->EncryptMessage(&sspi_context,
+ KERB_WRAP_NO_ENCRYPT,
+ &wrap_desc,
+ 0);
+ if(check_sspi_err(conn, status, "EncryptMessage")) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
+ + sspi_w_token[1].cbBuffer
+ + sspi_w_token[2].cbBuffer;
+ sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
+ if(!sspi_send_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
+ sspi_w_token[0].cbBuffer);
+ memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
+ sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+ memcpy((PUCHAR) sspi_send_token.pvBuffer
+ +sspi_w_token[0].cbBuffer
+ +sspi_w_token[1].cbBuffer,
+ sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
+
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ sspi_w_token[0].pvBuffer = NULL;
+ sspi_w_token[0].cbBuffer = 0;
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ sspi_w_token[1].pvBuffer = NULL;
+ sspi_w_token[1].cbBuffer = 0;
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ sspi_w_token[2].pvBuffer = NULL;
+ sspi_w_token[2].cbBuffer = 0;
+
+ us_length = htons((short)sspi_send_token.cbBuffer);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if(code || (4 != written)) {
+ failf(data, "Failed to send SSPI encryption request.");
+ if(sspi_send_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(data->set.socks5_gssapi_nec) {
+ memcpy(socksreq, &gss_enc, 1);
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
+ if(code || (1 != written)) {
+ failf(data, "Failed to send SSPI encryption type.");
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+ else {
+ code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+ sspi_send_token.cbBuffer, &written);
+ if(code || (sspi_send_token.cbBuffer != (size_t)written)) {
+ failf(data, "Failed to send SSPI encryption type.");
+ if(sspi_send_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(sspi_send_token.pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ }
+
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result || (actualread != 4)) {
+ failf(data, "Failed to receive SSPI encryption response.");
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 2) { /* status / message type */
+ failf(data, "Invalid SSPI encryption response type (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ sspi_w_token[0].cbBuffer = us_length;
+ sspi_w_token[0].pvBuffer = malloc(us_length);
+ if(!sspi_w_token[0].pvBuffer) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
+ sspi_w_token[0].cbBuffer, &actualread);
+
+ if(result || (actualread != us_length)) {
+ failf(data, "Failed to receive SSPI encryption type.");
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+
+ if(!data->set.socks5_gssapi_nec) {
+ wrap_desc.cBuffers = 2;
+ sspi_w_token[0].BufferType = SECBUFFER_STREAM;
+ sspi_w_token[1].BufferType = SECBUFFER_DATA;
+ sspi_w_token[1].cbBuffer = 0;
+ sspi_w_token[1].pvBuffer = NULL;
+
+ status = s_pSecFn->DecryptMessage(&sspi_context,
+ &wrap_desc,
+ 0,
+ &qop);
+
+ if(check_sspi_err(conn, status, "DecryptMessage")) {
+ if(sspi_w_token[0].pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ if(sspi_w_token[1].pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(sspi_w_token[1].cbBuffer != 1) {
+ failf(data, "Invalid SSPI encryption response length (%lu).",
+ (unsigned long)sspi_w_token[1].cbBuffer);
+ if(sspi_w_token[0].pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ if(sspi_w_token[1].pvBuffer)
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ }
+ else {
+ if(sspi_w_token[0].cbBuffer != 1) {
+ failf(data, "Invalid SSPI encryption response length (%lu).",
+ (unsigned long)sspi_w_token[0].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ }
+
+ infof(data, "SOCKS5 access with%s protection granted.\n",
+ (socksreq[0]==0)?"out GSS-API data":
+ ((socksreq[0]==1)?" GSS-API integrity":" GSS-API confidentiality"));
+
+ /* For later use if encryption is required
+ conn->socks5_gssapi_enctype = socksreq[0];
+ if(socksreq[0] != 0)
+ conn->socks5_sspi_context = sspi_context;
+ else {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ conn->socks5_sspi_context = sspi_context;
+ }
+ */
+ return CURLE_OK;
+}
+#endif
diff --git a/Utilities/cmcurl/lib/speedcheck.c b/Utilities/cmcurl/lib/speedcheck.c
new file mode 100644
index 000000000..8addedde5
--- /dev/null
+++ b/Utilities/cmcurl/lib/speedcheck.c
@@ -0,0 +1,73 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "speedcheck.h"
+
+void Curl_speedinit(struct Curl_easy *data)
+{
+ memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
+}
+
+/*
+ * @unittest: 1606
+ */
+CURLcode Curl_speedcheck(struct Curl_easy *data,
+ struct timeval now)
+{
+ if((data->progress.current_speed >= 0) && data->set.low_speed_time) {
+ if(data->progress.current_speed < data->set.low_speed_limit) {
+ if(!data->state.keeps_speed.tv_sec)
+ /* under the limit at this very moment */
+ data->state.keeps_speed = now;
+ else {
+ /* how long has it been under the limit */
+ time_t howlong = Curl_tvdiff(now, data->state.keeps_speed);
+
+ if(howlong >= data->set.low_speed_time * 1000) {
+ /* too long */
+ failf(data,
+ "Operation too slow. "
+ "Less than %ld bytes/sec transferred the last %ld seconds",
+ data->set.low_speed_limit,
+ data->set.low_speed_time);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ }
+ else
+ /* faster right now */
+ data->state.keeps_speed.tv_sec = 0;
+ }
+
+ if(data->set.low_speed_limit)
+ /* if low speed limit is enabled, set the expire timer to make this
+ connection's speed get checked again in a second */
+ Curl_expire(data, 1000, EXPIRE_SPEEDCHECK);
+
+ return CURLE_OK;
+}
diff --git a/Utilities/cmcurl/lib/speedcheck.h b/Utilities/cmcurl/lib/speedcheck.h
new file mode 100644
index 000000000..7dbe3d6d7
--- /dev/null
+++ b/Utilities/cmcurl/lib/speedcheck.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_SPEEDCHECK_H
+#define HEADER_CURL_SPEEDCHECK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "timeval.h"
+
+void Curl_speedinit(struct Curl_easy *data);
+CURLcode Curl_speedcheck(struct Curl_easy *data,
+ struct timeval now);
+
+#endif /* HEADER_CURL_SPEEDCHECK_H */
diff --git a/Utilities/cmcurl/lib/splay.c b/Utilities/cmcurl/lib/splay.c
new file mode 100644
index 000000000..1b301f95d
--- /dev/null
+++ b/Utilities/cmcurl/lib/splay.c
@@ -0,0 +1,274 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "splay.h"
+
+/*
+ * This macro compares two node keys i and j and returns:
+ *
+ * negative value: when i is smaller than j
+ * zero : when i is equal to j
+ * positive when : when i is larger than j
+ */
+#define compare(i,j) Curl_splaycomparekeys((i),(j))
+
+/*
+ * Splay using the key i (which may or may not be in the tree.) The starting
+ * root is t.
+ */
+struct Curl_tree *Curl_splay(struct timeval i,
+ struct Curl_tree *t)
+{
+ struct Curl_tree N, *l, *r, *y;
+ long comp;
+
+ if(t == NULL)
+ return t;
+ N.smaller = N.larger = NULL;
+ l = r = &N;
+
+ for(;;) {
+ comp = compare(i, t->key);
+ if(comp < 0) {
+ if(t->smaller == NULL)
+ break;
+ if(compare(i, t->smaller->key) < 0) {
+ y = t->smaller; /* rotate smaller */
+ t->smaller = y->larger;
+ y->larger = t;
+ t = y;
+ if(t->smaller == NULL)
+ break;
+ }
+ r->smaller = t; /* link smaller */
+ r = t;
+ t = t->smaller;
+ }
+ else if(comp > 0) {
+ if(t->larger == NULL)
+ break;
+ if(compare(i, t->larger->key) > 0) {
+ y = t->larger; /* rotate larger */
+ t->larger = y->smaller;
+ y->smaller = t;
+ t = y;
+ if(t->larger == NULL)
+ break;
+ }
+ l->larger = t; /* link larger */
+ l = t;
+ t = t->larger;
+ }
+ else
+ break;
+ }
+
+ l->larger = t->smaller; /* assemble */
+ r->smaller = t->larger;
+ t->smaller = N.larger;
+ t->larger = N.smaller;
+
+ return t;
+}
+
+/* Insert key i into the tree t. Return a pointer to the resulting tree or
+ * NULL if something went wrong.
+ *
+ * @unittest: 1309
+ */
+struct Curl_tree *Curl_splayinsert(struct timeval i,
+ struct Curl_tree *t,
+ struct Curl_tree *node)
+{
+ static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
+
+ if(node == NULL)
+ return t;
+
+ if(t != NULL) {
+ t = Curl_splay(i, t);
+ if(compare(i, t->key)==0) {
+ /* There already exists a node in the tree with the very same key. Build
+ a doubly-linked circular list of nodes. We add the new 'node' struct
+ to the end of this list. */
+
+ node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED
+ to quickly identify this node as a subnode */
+ node->samen = t;
+ node->samep = t->samep;
+ t->samep->samen = node;
+ t->samep = node;
+
+ return t; /* the root node always stays the same */
+ }
+ }
+
+ if(t == NULL) {
+ node->smaller = node->larger = NULL;
+ }
+ else if(compare(i, t->key) < 0) {
+ node->smaller = t->smaller;
+ node->larger = t;
+ t->smaller = NULL;
+
+ }
+ else {
+ node->larger = t->larger;
+ node->smaller = t;
+ t->larger = NULL;
+ }
+ node->key = i;
+
+ /* no identical nodes (yet), we are the only one in the list of nodes */
+ node->samen = node;
+ node->samep = node;
+ return node;
+}
+
+/* Finds and deletes the best-fit node from the tree. Return a pointer to the
+ resulting tree. best-fit means the smallest node if it is not larger than
+ the key */
+struct Curl_tree *Curl_splaygetbest(struct timeval i,
+ struct Curl_tree *t,
+ struct Curl_tree **removed)
+{
+ static struct timeval tv_zero = {0, 0};
+ struct Curl_tree *x;
+
+ if(!t) {
+ *removed = NULL; /* none removed since there was no root */
+ return NULL;
+ }
+
+ /* find smallest */
+ t = Curl_splay(tv_zero, t);
+ if(compare(i, t->key) < 0) {
+ /* even the smallest is too big */
+ *removed = NULL;
+ return t;
+ }
+
+ /* FIRST! Check if there is a list with identical keys */
+ x = t->samen;
+ if(x != t) {
+ /* there is, pick one from the list */
+
+ /* 'x' is the new root node */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+ x->samep = t->samep;
+ t->samep->samen = x;
+
+ *removed = t;
+ return x; /* new root */
+ }
+
+ /* we splayed the tree to the smallest element, there is no smaller */
+ x = t->larger;
+ *removed = t;
+
+ return x;
+}
+
+
+/* Deletes the very node we point out from the tree if it's there. Stores a
+ * pointer to the new resulting tree in 'newroot'.
+ *
+ * Returns zero on success and non-zero on errors! TODO: document error codes.
+ * When returning error, it does not touch the 'newroot' pointer.
+ *
+ * NOTE: when the last node of the tree is removed, there's no tree left so
+ * 'newroot' will be made to point to NULL.
+ *
+ * @unittest: 1309
+ */
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+ struct Curl_tree *removenode,
+ struct Curl_tree **newroot)
+{
+ static const struct timeval KEY_NOTUSED = {-1, -1}; /* will *NEVER* appear */
+ struct Curl_tree *x;
+
+ if(!t || !removenode)
+ return 1;
+
+ if(compare(KEY_NOTUSED, removenode->key) == 0) {
+ /* Key set to NOTUSED means it is a subnode within a 'same' linked list
+ and thus we can unlink it easily. */
+ if(removenode->samen == removenode)
+ /* A non-subnode should never be set to KEY_NOTUSED */
+ return 3;
+
+ removenode->samep->samen = removenode->samen;
+ removenode->samen->samep = removenode->samep;
+
+ /* Ensures that double-remove gets caught. */
+ removenode->samen = removenode;
+
+ *newroot = t; /* return the same root */
+ return 0;
+ }
+
+ t = Curl_splay(removenode->key, t);
+
+ /* First make sure that we got the same root node as the one we want
+ to remove, as otherwise we might be trying to remove a node that
+ isn't actually in the tree.
+
+ We cannot just compare the keys here as a double remove in quick
+ succession of a node with key != KEY_NOTUSED && same != NULL
+ could return the same key but a different node. */
+ if(t != removenode)
+ return 2;
+
+ /* Check if there is a list with identical sizes, as then we're trying to
+ remove the root node of a list of nodes with identical keys. */
+ x = t->samen;
+ if(x != t) {
+ /* 'x' is the new root node, we just make it use the root node's
+ smaller/larger links */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+ x->samep = t->samep;
+ t->samep->samen = x;
+ }
+ else {
+ /* Remove the root node */
+ if(t->smaller == NULL)
+ x = t->larger;
+ else {
+ x = Curl_splay(removenode->key, t->smaller);
+ x->larger = t->larger;
+ }
+ }
+
+ *newroot = x; /* store new root pointer */
+
+ return 0;
+}
+
diff --git a/Utilities/cmcurl/lib/splay.h b/Utilities/cmcurl/lib/splay.h
new file mode 100644
index 000000000..da81894d1
--- /dev/null
+++ b/Utilities/cmcurl/lib/splay.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_SPLAY_H
+#define HEADER_CURL_SPLAY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+struct Curl_tree {
+ struct Curl_tree *smaller; /* smaller node */
+ struct Curl_tree *larger; /* larger node */
+ struct Curl_tree *samen; /* points to the next node with identical key */
+ struct Curl_tree *samep; /* points to the prev node with identical key */
+ struct timeval key; /* this node's "sort" key */
+ void *payload; /* data the splay code doesn't care about */
+};
+
+struct Curl_tree *Curl_splay(struct timeval i,
+ struct Curl_tree *t);
+
+struct Curl_tree *Curl_splayinsert(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree *newnode);
+
+#if 0
+struct Curl_tree *Curl_splayremove(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree **removed);
+#endif
+
+struct Curl_tree *Curl_splaygetbest(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree **removed);
+
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+ struct Curl_tree *removenode,
+ struct Curl_tree **newroot);
+
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \
+ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \
+ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
+ ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0))))
+
+#ifdef DEBUGBUILD
+void Curl_splayprint(struct Curl_tree * t, int d, char output);
+#else
+#define Curl_splayprint(x,y,z) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_SPLAY_H */
diff --git a/Utilities/cmcurl/lib/ssh.c b/Utilities/cmcurl/lib/ssh.c
new file mode 100644
index 000000000..00aeca978
--- /dev/null
+++ b/Utilities/cmcurl/lib/ssh.c
@@ -0,0 +1,3447 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* #define CURL_LIBSSH2_DEBUG */
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBSSH2
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ssh.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "vtls/vtls.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "select.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifdef WIN32
+# undef PATH_MAX
+# define PATH_MAX MAX_PATH
+# ifndef R_OK
+# define R_OK 4
+# endif
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* just an extra precaution since there are systems that
+ have their definition hidden well */
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010206
+/* libssh2_sftp_statvfs and friends were added in 1.2.6 */
+#define HAS_STATVFS_SUPPORT 1
+#endif
+
+#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s))
+
+#define sftp_libssh2_realpath(s,p,t,m) \
+ libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
+ (t), (m), LIBSSH2_SFTP_REALPATH)
+
+
+/* Local functions: */
+static const char *sftp_libssh2_strerror(int err);
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
+static LIBSSH2_FREE_FUNC(my_libssh2_free);
+
+static CURLcode get_pathname(const char **cpp, char **path);
+
+static CURLcode ssh_connect(struct connectdata *conn, bool *done);
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode ssh_do(struct connectdata *conn, bool *done);
+
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+ char *homedir, /* when SFTP is used */
+ char **path);
+
+static CURLcode scp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode scp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection);
+
+static CURLcode sftp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode sftp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
+static
+CURLcode sftp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done);
+
+static int ssh_getsock(struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks);
+
+static int ssh_perform_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks
+ number of sockets */
+ int numsocks);
+
+static CURLcode ssh_setup_connection(struct connectdata *conn);
+
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+ "SCP", /* scheme */
+ ssh_setup_connection, /* setup_connection */
+ ssh_do, /* do_it */
+ scp_done, /* done */
+ ZERO_NULL, /* do_more */
+ ssh_connect, /* connect_it */
+ ssh_multi_statemach, /* connecting */
+ scp_doing, /* doing */
+ ssh_getsock, /* proto_getsock */
+ ssh_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ssh_perform_getsock, /* perform_getsock */
+ scp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SSH, /* defport */
+ CURLPROTO_SCP, /* protocol */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+ "SFTP", /* scheme */
+ ssh_setup_connection, /* setup_connection */
+ ssh_do, /* do_it */
+ sftp_done, /* done */
+ ZERO_NULL, /* do_more */
+ ssh_connect, /* connect_it */
+ ssh_multi_statemach, /* connecting */
+ sftp_doing, /* doing */
+ ssh_getsock, /* proto_getsock */
+ ssh_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ssh_perform_getsock, /* perform_getsock */
+ sftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SSH, /* defport */
+ CURLPROTO_SFTP, /* protocol */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+static void
+kbd_callback(const char *name, int name_len, const char *instruction,
+ int instruction_len, int num_prompts,
+ const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+ LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+ void **abstract)
+{
+ struct connectdata *conn = (struct connectdata *)*abstract;
+
+#ifdef CURL_LIBSSH2_DEBUG
+ fprintf(stderr, "name=%s\n", name);
+ fprintf(stderr, "name_len=%d\n", name_len);
+ fprintf(stderr, "instruction=%s\n", instruction);
+ fprintf(stderr, "instruction_len=%d\n", instruction_len);
+ fprintf(stderr, "num_prompts=%d\n", num_prompts);
+#else
+ (void)name;
+ (void)name_len;
+ (void)instruction;
+ (void)instruction_len;
+#endif /* CURL_LIBSSH2_DEBUG */
+ if(num_prompts == 1) {
+ responses[0].text = strdup(conn->passwd);
+ responses[0].length = curlx_uztoui(strlen(conn->passwd));
+ }
+ (void)prompts;
+ (void)abstract;
+} /* kbd_callback */
+
+static CURLcode sftp_libssh2_error_to_CURLE(int err)
+{
+ switch(err) {
+ case LIBSSH2_FX_OK:
+ return CURLE_OK;
+
+ case LIBSSH2_FX_NO_SUCH_FILE:
+ case LIBSSH2_FX_NO_SUCH_PATH:
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+
+ case LIBSSH2_FX_PERMISSION_DENIED:
+ case LIBSSH2_FX_WRITE_PROTECT:
+ case LIBSSH2_FX_LOCK_CONFlICT:
+ return CURLE_REMOTE_ACCESS_DENIED;
+
+ case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+ case LIBSSH2_FX_QUOTA_EXCEEDED:
+ return CURLE_REMOTE_DISK_FULL;
+
+ case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+ return CURLE_REMOTE_FILE_EXISTS;
+
+ case LIBSSH2_FX_DIR_NOT_EMPTY:
+ return CURLE_QUOTE_ERROR;
+
+ default:
+ break;
+ }
+
+ return CURLE_SSH;
+}
+
+static CURLcode libssh2_session_error_to_CURLE(int err)
+{
+ switch(err) {
+ /* Ordered by order of appearance in libssh2.h */
+ case LIBSSH2_ERROR_NONE:
+ return CURLE_OK;
+
+ case LIBSSH2_ERROR_SOCKET_NONE:
+ return CURLE_COULDNT_CONNECT;
+
+ case LIBSSH2_ERROR_ALLOC:
+ return CURLE_OUT_OF_MEMORY;
+
+ case LIBSSH2_ERROR_SOCKET_SEND:
+ return CURLE_SEND_ERROR;
+
+ case LIBSSH2_ERROR_HOSTKEY_INIT:
+ case LIBSSH2_ERROR_HOSTKEY_SIGN:
+ case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
+ case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ case LIBSSH2_ERROR_PASSWORD_EXPIRED:
+ return CURLE_LOGIN_DENIED;
+
+ case LIBSSH2_ERROR_SOCKET_TIMEOUT:
+ case LIBSSH2_ERROR_TIMEOUT:
+ return CURLE_OPERATION_TIMEDOUT;
+
+ case LIBSSH2_ERROR_EAGAIN:
+ return CURLE_AGAIN;
+ }
+
+ /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
+ error code, and possibly add a few new SSH-related one. We must however
+ not return or even depend on libssh2 errors in the public libcurl API */
+
+ return CURLE_SSH;
+}
+
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
+{
+ (void)abstract; /* arg not used */
+ return malloc(count);
+}
+
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
+{
+ (void)abstract; /* arg not used */
+ return realloc(ptr, count);
+}
+
+static LIBSSH2_FREE_FUNC(my_libssh2_free)
+{
+ (void)abstract; /* arg not used */
+ if(ptr) /* ssh2 agent sometimes call free with null ptr */
+ free(ptr);
+}
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct connectdata *conn, sshstate nowstate)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "SSH_STOP",
+ "SSH_INIT",
+ "SSH_S_STARTUP",
+ "SSH_HOSTKEY",
+ "SSH_AUTHLIST",
+ "SSH_AUTH_PKEY_INIT",
+ "SSH_AUTH_PKEY",
+ "SSH_AUTH_PASS_INIT",
+ "SSH_AUTH_PASS",
+ "SSH_AUTH_AGENT_INIT",
+ "SSH_AUTH_AGENT_LIST",
+ "SSH_AUTH_AGENT",
+ "SSH_AUTH_HOST_INIT",
+ "SSH_AUTH_HOST",
+ "SSH_AUTH_KEY_INIT",
+ "SSH_AUTH_KEY",
+ "SSH_AUTH_DONE",
+ "SSH_SFTP_INIT",
+ "SSH_SFTP_REALPATH",
+ "SSH_SFTP_QUOTE_INIT",
+ "SSH_SFTP_POSTQUOTE_INIT",
+ "SSH_SFTP_QUOTE",
+ "SSH_SFTP_NEXT_QUOTE",
+ "SSH_SFTP_QUOTE_STAT",
+ "SSH_SFTP_QUOTE_SETSTAT",
+ "SSH_SFTP_QUOTE_SYMLINK",
+ "SSH_SFTP_QUOTE_MKDIR",
+ "SSH_SFTP_QUOTE_RENAME",
+ "SSH_SFTP_QUOTE_RMDIR",
+ "SSH_SFTP_QUOTE_UNLINK",
+ "SSH_SFTP_QUOTE_STATVFS",
+ "SSH_SFTP_GETINFO",
+ "SSH_SFTP_FILETIME",
+ "SSH_SFTP_TRANS_INIT",
+ "SSH_SFTP_UPLOAD_INIT",
+ "SSH_SFTP_CREATE_DIRS_INIT",
+ "SSH_SFTP_CREATE_DIRS",
+ "SSH_SFTP_CREATE_DIRS_MKDIR",
+ "SSH_SFTP_READDIR_INIT",
+ "SSH_SFTP_READDIR",
+ "SSH_SFTP_READDIR_LINK",
+ "SSH_SFTP_READDIR_BOTTOM",
+ "SSH_SFTP_READDIR_DONE",
+ "SSH_SFTP_DOWNLOAD_INIT",
+ "SSH_SFTP_DOWNLOAD_STAT",
+ "SSH_SFTP_CLOSE",
+ "SSH_SFTP_SHUTDOWN",
+ "SSH_SCP_TRANS_INIT",
+ "SSH_SCP_UPLOAD_INIT",
+ "SSH_SCP_DOWNLOAD_INIT",
+ "SSH_SCP_DONE",
+ "SSH_SCP_SEND_EOF",
+ "SSH_SCP_WAIT_EOF",
+ "SSH_SCP_WAIT_CLOSE",
+ "SSH_SCP_CHANNEL_FREE",
+ "SSH_SESSION_DISCONNECT",
+ "SSH_SESSION_FREE",
+ "QUIT"
+ };
+
+ if(sshc->state != nowstate) {
+ infof(conn->data, "SFTP %p state change from %s to %s\n",
+ (void *)sshc, names[sshc->state], names[nowstate]);
+ }
+#endif
+
+ sshc->state = nowstate;
+}
+
+/* figure out the path to work with in this particular request */
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+ char *homedir, /* when SFTP is used */
+ char **path) /* returns the allocated
+ real path to work with */
+{
+ struct Curl_easy *data = conn->data;
+ char *real_path = NULL;
+ char *working_path;
+ size_t working_path_len;
+ CURLcode result =
+ Curl_urldecode(data, data->state.path, 0, &working_path,
+ &working_path_len, FALSE);
+ if(result)
+ return result;
+
+ /* Check for /~/, indicating relative to the user's home directory */
+ if(conn->handler->protocol & CURLPROTO_SCP) {
+ real_path = malloc(working_path_len+1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
+ /* It is referenced to the home directory, so strip the leading '/~/' */
+ memcpy(real_path, working_path+3, 4 + working_path_len-3);
+ else
+ memcpy(real_path, working_path, 1 + working_path_len);
+ }
+ else if(conn->handler->protocol & CURLPROTO_SFTP) {
+ if((working_path_len > 1) && (working_path[1] == '~')) {
+ size_t homelen = strlen(homedir);
+ real_path = malloc(homelen + working_path_len + 1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* It is referenced to the home directory, so strip the
+ leading '/' */
+ memcpy(real_path, homedir, homelen);
+ real_path[homelen] = '/';
+ real_path[homelen+1] = '\0';
+ if(working_path_len > 3) {
+ memcpy(real_path+homelen+1, working_path + 3,
+ 1 + working_path_len -3);
+ }
+ }
+ else {
+ real_path = malloc(working_path_len+1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(real_path, working_path, 1+working_path_len);
+ }
+ }
+
+ free(working_path);
+
+ /* store the pointer for the caller to receive */
+ *path = real_path;
+
+ return CURLE_OK;
+}
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+static int sshkeycallback(struct Curl_easy *easy,
+ const struct curl_khkey *knownkey, /* known */
+ const struct curl_khkey *foundkey, /* found */
+ enum curl_khmatch match,
+ void *clientp)
+{
+ (void)easy;
+ (void)knownkey;
+ (void)foundkey;
+ (void)clientp;
+
+ /* we only allow perfect matches, and we reject everything else */
+ return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
+}
+#endif
+
+/*
+ * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
+ * with 32bit size_t.
+ */
+#ifdef HAVE_LIBSSH2_SFTP_SEEK64
+#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
+#else
+#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
+#endif
+
+/*
+ * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
+ * architectures so we check of the necessary function is present.
+ */
+#ifndef HAVE_LIBSSH2_SCP_SEND64
+#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
+#else
+#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
+ (libssh2_uint64_t)d, 0, 0)
+#endif
+
+/*
+ * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
+ */
+#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
+#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
+#endif
+
+static CURLcode ssh_knownhost(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ struct Curl_easy *data = conn->data;
+
+ if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ /* we're asked to verify the host against a file */
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ int rc;
+ int keytype;
+ size_t keylen;
+ const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+ &keylen, &keytype);
+ int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
+ int keybit = 0;
+
+ if(remotekey) {
+ /*
+ * A subject to figure out is what host name we need to pass in here.
+ * What host name does OpenSSH store in its file if an IDN name is
+ * used?
+ */
+ struct libssh2_knownhost *host;
+ enum curl_khmatch keymatch;
+ curl_sshkeycallback func =
+ data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
+ struct curl_khkey knownkey;
+ struct curl_khkey *knownkeyp = NULL;
+ struct curl_khkey foundkey;
+
+ keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_CHECKP
+ keycheck = libssh2_knownhost_checkp(sshc->kh,
+ conn->host.name,
+ (conn->remote_port != PORT_SSH)?
+ conn->remote_port:-1,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit,
+ &host);
+#else
+ keycheck = libssh2_knownhost_check(sshc->kh,
+ conn->host.name,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit,
+ &host);
+#endif
+
+ infof(data, "SSH host check: %d, key: %s\n", keycheck,
+ (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+ host->key:"<none>");
+
+ /* setup 'knownkey' */
+ if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+ knownkey.key = host->key;
+ knownkey.len = 0;
+ knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+ knownkeyp = &knownkey;
+ }
+
+ /* setup 'foundkey' */
+ foundkey.key = remotekey;
+ foundkey.len = keylen;
+ foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+
+ /*
+ * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+ * curl_khmatch enum are ever modified, we need to introduce a
+ * translation table here!
+ */
+ keymatch = (enum curl_khmatch)keycheck;
+
+ /* Ask the callback how to behave */
+ rc = func(data, knownkeyp, /* from the knownhosts file */
+ &foundkey, /* from the remote host */
+ keymatch, data->set.ssh_keyfunc_userp);
+ }
+ else
+ /* no remotekey means failure! */
+ rc = CURLKHSTAT_REJECT;
+
+ switch(rc) {
+ default: /* unknown return codes will equal reject */
+ /* FALLTHROUGH */
+ case CURLKHSTAT_REJECT:
+ state(conn, SSH_SESSION_FREE);
+ /* FALLTHROUGH */
+ case CURLKHSTAT_DEFER:
+ /* DEFER means bail out but keep the SSH_HOSTKEY state */
+ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ break;
+ case CURLKHSTAT_FINE:
+ case CURLKHSTAT_FINE_ADD_TO_FILE:
+ /* proceed */
+ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+ /* the found host+key didn't match but has been told to be fine
+ anyway so we add it in memory */
+ int addrc = libssh2_knownhost_add(sshc->kh,
+ conn->host.name, NULL,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit, NULL);
+ if(addrc)
+ infof(data, "Warning adding the known host %s failed!\n",
+ conn->host.name);
+ else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+ /* now we write the entire in-memory list of known hosts to the
+ known_hosts file */
+ int wrc =
+ libssh2_knownhost_writefile(sshc->kh,
+ data->set.str[STRING_SSH_KNOWNHOSTS],
+ LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+ if(wrc) {
+ infof(data, "Warning, writing %s failed!\n",
+ data->set.str[STRING_SSH_KNOWNHOSTS]);
+ }
+ }
+ }
+ break;
+ }
+ }
+#else /* HAVE_LIBSSH2_KNOWNHOST_API */
+ (void)conn;
+#endif
+ return result;
+}
+
+static CURLcode ssh_check_fingerprint(struct connectdata *conn)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ struct Curl_easy *data = conn->data;
+ const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
+ char md5buffer[33];
+ int i;
+
+ const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
+
+ if(fingerprint) {
+ /* The fingerprint points to static storage (!), don't free() it. */
+ for(i = 0; i < 16; i++)
+ snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+ infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+ }
+
+ /* Before we authenticate we check the hostkey's MD5 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if(pubkey_md5 && strlen(pubkey_md5) == 32) {
+ if(!fingerprint || !strcasecompare(md5buffer, pubkey_md5)) {
+ if(fingerprint)
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+ else
+ failf(data,
+ "Denied establishing ssh session: md5 fingerprint not available");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+ infof(data, "MD5 checksum match!\n");
+ /* as we already matched, we skip the check for known hosts */
+ return CURLE_OK;
+ }
+ return ssh_knownhost(conn);
+}
+
+/*
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end. The data the pointer 'block' points
+ * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+
+static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct SSHPROTO *sftp_scp = data->req.protop;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ char *new_readdir_line;
+ int rc = LIBSSH2_ERROR_NONE;
+ int err;
+ int seekerr = CURL_SEEKFUNC_OK;
+ *block = 0; /* we're not blocking by default */
+
+ do {
+
+ switch(sshc->state) {
+ case SSH_INIT:
+ sshc->secondCreateDirs = 0;
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_OK;
+
+ /* Set libssh2 to non-blocking, since everything internally is
+ non-blocking */
+ libssh2_session_set_blocking(sshc->ssh_session, 0);
+
+ state(conn, SSH_S_STARTUP);
+ /* fall-through */
+
+ case SSH_S_STARTUP:
+ rc = libssh2_session_startup(sshc->ssh_session, (int)sock);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc) {
+ failf(data, "Failure establishing ssh session");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+
+ state(conn, SSH_HOSTKEY);
+
+ /* fall-through */
+ case SSH_HOSTKEY:
+ /*
+ * Before we authenticate we should check the hostkey's fingerprint
+ * against our known hosts. How that is handled (reading from file,
+ * whatever) is up to us.
+ */
+ result = ssh_check_fingerprint(conn);
+ if(!result)
+ state(conn, SSH_AUTHLIST);
+ /* ssh_check_fingerprint sets state appropriately on error */
+ break;
+
+ case SSH_AUTHLIST:
+ /*
+ * Figure out authentication methods
+ * NB: As soon as we have provided a username to an openssh server we
+ * must never change it later. Thus, always specify the correct username
+ * here, even though the libssh2 docs kind of indicate that it should be
+ * possible to get a 'generic' list (not user-specific) of authentication
+ * methods, presumably with a blank username. That won't work in my
+ * experience.
+ * So always specify it here.
+ */
+ sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(strlen(conn->user)));
+
+ if(!sshc->authlist) {
+ if(libssh2_userauth_authenticated(sshc->ssh_session)) {
+ sshc->authed = TRUE;
+ infof(data, "SSH user accepted with no authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ break;
+ }
+ err = libssh2_session_last_errno(sshc->ssh_session);
+ if(err == LIBSSH2_ERROR_EAGAIN)
+ rc = LIBSSH2_ERROR_EAGAIN;
+ else {
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(err);
+ }
+ break;
+ }
+ infof(data, "SSH authentication methods available: %s\n",
+ sshc->authlist);
+
+ state(conn, SSH_AUTH_PKEY_INIT);
+ break;
+
+ case SSH_AUTH_PKEY_INIT:
+ /*
+ * Check the supported auth types in the order I feel is most secure
+ * with the requested type of authentication
+ */
+ sshc->authed = FALSE;
+
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+ (strstr(sshc->authlist, "publickey") != NULL)) {
+ char *home = NULL;
+ bool out_of_memory = FALSE;
+
+ sshc->rsa_pub = sshc->rsa = NULL;
+
+ /* To ponder about: should really the lib be messing about with the
+ HOME environment variable etc? */
+ home = curl_getenv("HOME");
+
+ if(data->set.str[STRING_SSH_PRIVATE_KEY])
+ sshc->rsa = strdup(data->set.str[STRING_SSH_PRIVATE_KEY]);
+ else {
+ /* If no private key file is specified, try some common paths. */
+ if(home) {
+ /* Try ~/.ssh first. */
+ sshc->rsa = aprintf("%s/.ssh/id_rsa", home);
+ if(!sshc->rsa)
+ out_of_memory = TRUE;
+ else if(access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+ if(!sshc->rsa)
+ out_of_memory = TRUE;
+ else if(access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ }
+ }
+ }
+ if(!out_of_memory && !sshc->rsa) {
+ /* Nothing found; try the current dir. */
+ sshc->rsa = strdup("id_rsa");
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ sshc->rsa = strdup("id_dsa");
+ if(sshc->rsa && access(sshc->rsa, R_OK) != 0) {
+ Curl_safefree(sshc->rsa);
+ /* Out of guesses. Set to the empty string to avoid
+ * surprising info messages. */
+ sshc->rsa = strdup("");
+ }
+ }
+ }
+ }
+
+ /*
+ * Unless the user explicitly specifies a public key file, let
+ * libssh2 extract the public key from the private key file.
+ * This is done by simply passing sshc->rsa_pub = NULL.
+ */
+ if(data->set.str[STRING_SSH_PUBLIC_KEY]
+ /* treat empty string the same way as NULL */
+ && data->set.str[STRING_SSH_PUBLIC_KEY][0]) {
+ sshc->rsa_pub = strdup(data->set.str[STRING_SSH_PUBLIC_KEY]);
+ if(!sshc->rsa_pub)
+ out_of_memory = TRUE;
+ }
+
+ if(out_of_memory || sshc->rsa == NULL) {
+ free(home);
+ Curl_safefree(sshc->rsa);
+ Curl_safefree(sshc->rsa_pub);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ sshc->passphrase = data->set.ssl.key_passwd;
+ if(!sshc->passphrase)
+ sshc->passphrase = "";
+
+ free(home);
+
+ if(sshc->rsa_pub)
+ infof(data, "Using SSH public key file '%s'\n", sshc->rsa_pub);
+ infof(data, "Using SSH private key file '%s'\n", sshc->rsa);
+
+ state(conn, SSH_AUTH_PKEY);
+ }
+ else {
+ state(conn, SSH_AUTH_PASS_INIT);
+ }
+ break;
+
+ case SSH_AUTH_PKEY:
+ /* The function below checks if the files exists, no need to stat() here.
+ */
+ rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(
+ strlen(conn->user)),
+ sshc->rsa_pub,
+ sshc->rsa, sshc->passphrase);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+
+ if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized SSH public key authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ char *err_msg;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "SSH public key authentication failed: %s\n", err_msg);
+ state(conn, SSH_AUTH_PASS_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+ break;
+
+ case SSH_AUTH_PASS_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+ (strstr(sshc->authlist, "password") != NULL)) {
+ state(conn, SSH_AUTH_PASS);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+ break;
+
+ case SSH_AUTH_PASS:
+ rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
+ curlx_uztoui(strlen(conn->user)),
+ conn->passwd,
+ curlx_uztoui(strlen(conn->passwd)),
+ NULL);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized password authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+ break;
+
+ case SSH_AUTH_HOST_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+ (strstr(sshc->authlist, "hostbased") != NULL)) {
+ state(conn, SSH_AUTH_HOST);
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT_INIT);
+ }
+ break;
+
+ case SSH_AUTH_HOST:
+ state(conn, SSH_AUTH_AGENT_INIT);
+ break;
+
+ case SSH_AUTH_AGENT_INIT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
+ && (strstr(sshc->authlist, "publickey") != NULL)) {
+
+ /* Connect to the ssh-agent */
+ /* The agent could be shared by a curl thread i believe
+ but nothing obvious as keys can be added/removed at any time */
+ if(!sshc->ssh_agent) {
+ sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
+ if(!sshc->ssh_agent) {
+ infof(data, "Could not create agent object\n");
+
+ state(conn, SSH_AUTH_KEY_INIT);
+ break;
+ }
+ }
+
+ rc = libssh2_agent_connect(sshc->ssh_agent);
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+ if(rc < 0) {
+ infof(data, "Failure connecting to agent\n");
+ state(conn, SSH_AUTH_KEY_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT_LIST);
+ }
+ }
+ else
+#endif /* HAVE_LIBSSH2_AGENT_API */
+ state(conn, SSH_AUTH_KEY_INIT);
+ break;
+
+ case SSH_AUTH_AGENT_LIST:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ rc = libssh2_agent_list_identities(sshc->ssh_agent);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+ if(rc < 0) {
+ infof(data, "Failure requesting identities to agent\n");
+ state(conn, SSH_AUTH_KEY_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT);
+ sshc->sshagent_prev_identity = NULL;
+ }
+#endif
+ break;
+
+ case SSH_AUTH_AGENT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ /* as prev_identity evolves only after an identity user auth finished we
+ can safely request it again as long as EAGAIN is returned here or by
+ libssh2_agent_userauth */
+ rc = libssh2_agent_get_identity(sshc->ssh_agent,
+ &sshc->sshagent_identity,
+ sshc->sshagent_prev_identity);
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+
+ if(rc == 0) {
+ rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
+ sshc->sshagent_identity);
+
+ if(rc < 0) {
+ if(rc != LIBSSH2_ERROR_EAGAIN)
+ /* tried and failed? go to next identity */
+ sshc->sshagent_prev_identity = sshc->sshagent_identity;
+ else
+ break;
+ }
+ }
+
+ if(rc < 0)
+ infof(data, "Failure requesting identities to agent\n");
+ else if(rc == 1)
+ infof(data, "No identity would match\n");
+
+ if(rc == LIBSSH2_ERROR_NONE) {
+ sshc->authed = TRUE;
+ infof(data, "Agent based authentication successful\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ state(conn, SSH_AUTH_KEY_INIT);
+ rc = 0; /* clear rc and continue */
+ }
+#endif
+ break;
+
+ case SSH_AUTH_KEY_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+ && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+ state(conn, SSH_AUTH_KEY);
+ }
+ else {
+ state(conn, SSH_AUTH_DONE);
+ }
+ break;
+
+ case SSH_AUTH_KEY:
+ /* Authentication failed. Continue with keyboard-interactive now. */
+ rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(
+ strlen(conn->user)),
+ &kbd_callback);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized keyboard interactive authentication\n");
+ }
+ state(conn, SSH_AUTH_DONE);
+ break;
+
+ case SSH_AUTH_DONE:
+ if(!sshc->authed) {
+ failf(data, "Authentication failure");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_LOGIN_DENIED;
+ break;
+ }
+
+ /*
+ * At this point we have an authenticated ssh session.
+ */
+ infof(data, "Authentication complete\n");
+
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+
+ conn->sockfd = sock;
+ conn->writesockfd = CURL_SOCKET_BAD;
+
+ if(conn->handler->protocol == CURLPROTO_SFTP) {
+ state(conn, SSH_SFTP_INIT);
+ break;
+ }
+ infof(data, "SSH CONNECT phase done\n");
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_INIT:
+ /*
+ * Start the libssh2 sftp session
+ */
+ sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+ if(!sshc->sftp_session) {
+ char *err_msg;
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ failf(data, "Failure initializing sftp session: %s", err_msg);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+ state(conn, SSH_SFTP_REALPATH);
+ break;
+
+ case SSH_SFTP_REALPATH:
+ {
+ char tempHome[PATH_MAX];
+
+ /*
+ * Get the "home" directory
+ */
+ rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
+ tempHome, PATH_MAX-1);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc > 0) {
+ /* It seems that this string is not always NULL terminated */
+ tempHome[rc] = '\0';
+ sshc->homedir = strdup(tempHome);
+ if(!sshc->homedir) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
+ }
+ else {
+ /* Return the error type */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ if(err)
+ result = sftp_libssh2_error_to_CURLE(err);
+ else
+ /* in this case, the error wasn't in the SFTP level but for example
+ a time-out or similar */
+ result = CURLE_SSH;
+ sshc->actualcode = result;
+ DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
+ err, (int)result));
+ state(conn, SSH_STOP);
+ break;
+ }
+ }
+ /* This is the last step in the SFTP connect phase. Do note that while
+ we get the homedir here, we get the "workingpath" in the DO action
+ since the homedir will remain the same between request but the
+ working path will not. */
+ DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_QUOTE_INIT:
+
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ if(data->set.quote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.quote;
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ state(conn, SSH_SFTP_GETINFO);
+ }
+ break;
+
+ case SSH_SFTP_POSTQUOTE_INIT:
+ if(data->set.postquote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.postquote;
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SFTP_QUOTE:
+ /* Send any quote commands */
+ {
+ const char *cp;
+
+ /*
+ * Support some of the "FTP" commands
+ */
+ char *cmd = sshc->quote_item->data;
+ sshc->acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal SFTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ sshc->acceptfail = TRUE;
+ }
+
+ if(strcasecompare("pwd", cmd)) {
+ /* output debug output if that is requested */
+ char *tmp = aprintf("257 \"%s\" is current directory.\n",
+ sftp_scp->path);
+ if(!tmp) {
+ result = CURLE_OUT_OF_MEMORY;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ break;
+ }
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
+ Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+ }
+ /* this sends an FTP-like "header" to the header callback so that the
+ current directory can be read very similar to how it is read when
+ using ordinary FTP. */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+ free(tmp);
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ }
+ else
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+ }
+ if(cmd) {
+ /*
+ * the arguments following the command must be separated from the
+ * command with a space so we can check for it unconditionally
+ */
+ cp = strchr(cmd, ' ');
+ if(cp == NULL) {
+ failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+
+ /*
+ * also, every command takes at least one argument so we get that
+ * first argument right now
+ */
+ result = get_pathname(&cp, &sshc->quote_path1);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error: Bad first parameter");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+
+ /*
+ * SFTP is a binary protocol, so we don't send text commands
+ * to the server. Instead, we scan for commands used by
+ * OpenSSH's sftp program and call the appropriate libssh2
+ * functions.
+ */
+ if(strncasecompare(cmd, "chgrp ", 6) ||
+ strncasecompare(cmd, "chmod ", 6) ||
+ strncasecompare(cmd, "chown ", 6) ) {
+ /* attribute change */
+
+ /* sshc->quote_path1 contains the mode to set */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in chgrp/chmod/chown: "
+ "Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ state(conn, SSH_SFTP_QUOTE_STAT);
+ break;
+ }
+ if(strncasecompare(cmd, "ln ", 3) ||
+ strncasecompare(cmd, "symlink ", 8)) {
+ /* symbolic linking */
+ /* sshc->quote_path1 is the source */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data,
+ "Syntax error in ln/symlink: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_SYMLINK);
+ break;
+ }
+ else if(strncasecompare(cmd, "mkdir ", 6)) {
+ /* create dir */
+ state(conn, SSH_SFTP_QUOTE_MKDIR);
+ break;
+ }
+ else if(strncasecompare(cmd, "rename ", 7)) {
+ /* rename file */
+ /* first param is the source path */
+ /* second param is the dest. path */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in rename: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_RENAME);
+ break;
+ }
+ else if(strncasecompare(cmd, "rmdir ", 6)) {
+ /* delete dir */
+ state(conn, SSH_SFTP_QUOTE_RMDIR);
+ break;
+ }
+ else if(strncasecompare(cmd, "rm ", 3)) {
+ state(conn, SSH_SFTP_QUOTE_UNLINK);
+ break;
+ }
+#ifdef HAS_STATVFS_SUPPORT
+ else if(strncasecompare(cmd, "statvfs ", 8)) {
+ state(conn, SSH_SFTP_QUOTE_STATVFS);
+ break;
+ }
+#endif
+
+ failf(data, "Unknown SFTP command");
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ if(!sshc->quote_item) {
+ state(conn, SSH_SFTP_GETINFO);
+ }
+ break;
+
+ case SSH_SFTP_NEXT_QUOTE:
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+
+ sshc->quote_item = sshc->quote_item->next;
+
+ if(sshc->quote_item) {
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ if(sshc->nextstate != SSH_NO_STATE) {
+ state(conn, sshc->nextstate);
+ sshc->nextstate = SSH_NO_STATE;
+ }
+ else {
+ state(conn, SSH_SFTP_GETINFO);
+ }
+ }
+ break;
+
+ case SSH_SFTP_QUOTE_STAT:
+ {
+ char *cmd = sshc->quote_item->data;
+ sshc->acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal SFTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ sshc->acceptfail = TRUE;
+ }
+
+ if(!strncasecompare(cmd, "chmod", 5)) {
+ /* Since chown and chgrp only set owner OR group but libssh2 wants to
+ * set them both at once, we need to obtain the current ownership
+ * first. This takes an extra protocol round trip.
+ */
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_STAT,
+ &sshc->quote_attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) { /* get those attributes */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Attempt to get SFTP stats failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+
+ /* Now set the new attributes... */
+ if(strncasecompare(cmd, "chgrp", 5)) {
+ sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+ !sshc->acceptfail) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chgrp gid not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ else if(strncasecompare(cmd, "chmod", 5)) {
+ sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+ /* permissions are octal */
+ if(sshc->quote_attrs.permissions == 0 &&
+ !ISDIGIT(sshc->quote_path1[0])) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chmod permissions not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ else if(strncasecompare(cmd, "chown", 5)) {
+ sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+ !sshc->acceptfail) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chown uid not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+
+ /* Now send the completed structure... */
+ state(conn, SSH_SFTP_QUOTE_SETSTAT);
+ break;
+ }
+
+ case SSH_SFTP_QUOTE_SETSTAT:
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_SETSTAT,
+ &sshc->quote_attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Attempt to set SFTP stats failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_SYMLINK:
+ rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_SYMLINK);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "symlink command failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_MKDIR:
+ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ data->set.new_directory_perms);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_RENAME:
+ rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_RENAME_OVERWRITE |
+ LIBSSH2_SFTP_RENAME_ATOMIC |
+ LIBSSH2_SFTP_RENAME_NATIVE);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_RMDIR:
+ rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)));
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_UNLINK:
+ rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)));
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+#ifdef HAS_STATVFS_SUPPORT
+ case SSH_SFTP_QUOTE_STATVFS:
+ {
+ LIBSSH2_SFTP_STATVFS statvfs;
+ rc = libssh2_sftp_statvfs(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ &statvfs);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ else if(rc == 0) {
+ char *tmp = aprintf("statvfs:\n"
+ "f_bsize: %llu\n" "f_frsize: %llu\n"
+ "f_blocks: %llu\n" "f_bfree: %llu\n"
+ "f_bavail: %llu\n" "f_files: %llu\n"
+ "f_ffree: %llu\n" "f_favail: %llu\n"
+ "f_fsid: %llu\n" "f_flag: %llu\n"
+ "f_namemax: %llu\n",
+ statvfs.f_bsize, statvfs.f_frsize,
+ statvfs.f_blocks, statvfs.f_bfree,
+ statvfs.f_bavail, statvfs.f_files,
+ statvfs.f_ffree, statvfs.f_favail,
+ statvfs.f_fsid, statvfs.f_flag,
+ statvfs.f_namemax);
+ if(!tmp) {
+ result = CURLE_OUT_OF_MEMORY;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ break;
+ }
+
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+ free(tmp);
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ }
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+ }
+#endif
+ case SSH_SFTP_GETINFO:
+ {
+ if(data->set.get_filetime) {
+ state(conn, SSH_SFTP_FILETIME);
+ }
+ else {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ break;
+ }
+
+ case SSH_SFTP_FILETIME:
+ {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_SFTP_STAT, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc == 0) {
+ data->info.filetime = (long)attrs.mtime;
+ }
+
+ state(conn, SSH_SFTP_TRANS_INIT);
+ break;
+ }
+
+ case SSH_SFTP_TRANS_INIT:
+ if(data->set.upload)
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ else {
+ if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+ state(conn, SSH_SFTP_READDIR_INIT);
+ else
+ state(conn, SSH_SFTP_DOWNLOAD_INIT);
+ }
+ break;
+
+ case SSH_SFTP_UPLOAD_INIT:
+ {
+ unsigned long flags;
+ /*
+ * NOTE!!! libssh2 requires that the destination path is a full path
+ * that includes the destination file and name OR ends in a "/"
+ * If this is not done the destination file will be named the
+ * same name as the last directory in the path.
+ */
+
+ if(data->state.resume_from != 0) {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+ if(data->state.resume_from < 0) {
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_SFTP_STAT, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc) {
+ data->state.resume_from = 0;
+ }
+ else {
+ curl_off_t size = attrs.filesize;
+ if(size < 0) {
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ data->state.resume_from = attrs.filesize;
+ }
+ }
+ }
+
+ if(data->set.ftp_append)
+ /* Try to open for append, but create if nonexisting */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+ else if(data->state.resume_from > 0)
+ /* If we have restart position then open for append */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+ else
+ /* Clear file before writing (normal behaviour) */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+
+ sshc->sftp_handle =
+ libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ flags, data->set.new_file_perms,
+ LIBSSH2_SFTP_OPENFILE);
+
+ if(!sshc->sftp_handle) {
+ rc = libssh2_session_last_errno(sshc->ssh_session);
+
+ if(LIBSSH2_ERROR_EAGAIN == rc)
+ break;
+
+ if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+ /* only when there was an SFTP protocol error can we extract
+ the sftp error! */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ else
+ err = -1; /* not an sftp error at all */
+
+ if(sshc->secondCreateDirs) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = err>= LIBSSH2_FX_OK?
+ sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ failf(data, "Creating the dir/file failed: %s",
+ sftp_libssh2_strerror(err));
+ break;
+ }
+ if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
+ (err == LIBSSH2_FX_FAILURE) ||
+ (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+ (data->set.ftp_create_missing_dirs &&
+ (strlen(sftp_scp->path) > 1))) {
+ /* try to create the path remotely */
+ rc = 0; /* clear rc and continue */
+ sshc->secondCreateDirs = 1;
+ state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+ break;
+ }
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = err>= LIBSSH2_FX_OK?
+ sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ if(!sshc->actualcode) {
+ /* Sometimes, for some reason libssh2_sftp_last_error() returns
+ zero even though libssh2_sftp_open() failed previously! We need
+ to work around that! */
+ sshc->actualcode = CURLE_SSH;
+ err=-1;
+ }
+ failf(data, "Upload failed: %s (%d/%d)",
+ err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
+ err, rc);
+ break;
+ }
+
+ /* If we have a restart point then we need to seek to the correct
+ position. */
+ if(data->state.resume_from > 0) {
+ /* Let's read off the proper amount of bytes from the input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ curl_off_t passed=0;
+
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > data->set.buffer_size) ?
+ (size_t)data->set.buffer_size :
+ curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->state.fread_func(data->state.buffer, 1,
+ readthisamountnow, data->state.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Failed to read data");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ } while(passed < data->state.resume_from);
+ }
+
+ /* now, decrease the size of the read */
+ if(data->state.infilesize > 0) {
+ data->state.infilesize -= data->state.resume_from;
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ }
+
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
+ if(data->state.infilesize > 0) {
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ }
+ /* upload data */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
+
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ /* store this original bitmask setup to use later on if we can't
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
+
+ /* we want to use the _sending_ function even when the socket turns
+ out readable as the underlying libssh2 sftp send function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_OUT;
+
+ /* since we don't really wait for anything at this point, we want the
+ state machine to move on as soon as possible so we set a very short
+ timeout here */
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+
+ state(conn, SSH_STOP);
+ }
+ break;
+ }
+
+ case SSH_SFTP_CREATE_DIRS_INIT:
+ if(strlen(sftp_scp->path) > 1) {
+ sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
+ state(conn, SSH_SFTP_CREATE_DIRS);
+ }
+ else {
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ }
+ break;
+
+ case SSH_SFTP_CREATE_DIRS:
+ sshc->slash_pos = strchr(sshc->slash_pos, '/');
+ if(sshc->slash_pos) {
+ *sshc->slash_pos = 0;
+
+ infof(data, "Creating directory '%s'\n", sftp_scp->path);
+ state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+ break;
+ }
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ break;
+
+ case SSH_SFTP_CREATE_DIRS_MKDIR:
+ /* 'mode' - parameter is preliminary - default to 0644 */
+ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ data->set.new_directory_perms);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ *sshc->slash_pos = '/';
+ ++sshc->slash_pos;
+ if(rc < 0) {
+ /*
+ * Abort if failure wasn't that the dir already exists or the
+ * permission was denied (creation might succeed further down the
+ * path) - retry on unspecific FAILURE also
+ */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+ (err != LIBSSH2_FX_FAILURE) &&
+ (err != LIBSSH2_FX_PERMISSION_DENIED)) {
+ result = sftp_libssh2_error_to_CURLE(err);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ rc = 0; /* clear rc and continue */
+ }
+ state(conn, SSH_SFTP_CREATE_DIRS);
+ break;
+
+ case SSH_SFTP_READDIR_INIT:
+ Curl_pgrsSetDownloadSize(data, -1);
+ if(data->set.opt_no_body) {
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ /*
+ * This is a directory that we are trying to get, so produce a directory
+ * listing
+ */
+ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
+ sftp_scp->path,
+ curlx_uztoui(
+ strlen(sftp_scp->path)),
+ 0, 0, LIBSSH2_SFTP_OPENDIR);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ failf(data, "Could not open directory for reading: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ sshc->readdir_filename = malloc(PATH_MAX+1);
+ if(!sshc->readdir_filename) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ sshc->readdir_longentry = malloc(PATH_MAX+1);
+ if(!sshc->readdir_longentry) {
+ Curl_safefree(sshc->readdir_filename);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR);
+ break;
+
+ case SSH_SFTP_READDIR:
+ sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+ sshc->readdir_filename,
+ PATH_MAX,
+ sshc->readdir_longentry,
+ PATH_MAX,
+ &sshc->readdir_attrs);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ if(sshc->readdir_len > 0) {
+ sshc->readdir_filename[sshc->readdir_len] = '\0';
+
+ if(data->set.ftp_list_only) {
+ char *tmpLine;
+
+ tmpLine = aprintf("%s\n", sshc->readdir_filename);
+ if(tmpLine == NULL) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ tmpLine, sshc->readdir_len+1);
+ free(tmpLine);
+
+ if(result) {
+ state(conn, SSH_STOP);
+ break;
+ }
+ /* since this counts what we send to the client, we include the
+ newline in this counter */
+ data->req.bytecount += sshc->readdir_len+1;
+
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
+ sshc->readdir_len, conn);
+ }
+ }
+ else {
+ sshc->readdir_currLen = (int)strlen(sshc->readdir_longentry);
+ sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
+ sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
+ if(!sshc->readdir_line) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ memcpy(sshc->readdir_line, sshc->readdir_longentry,
+ sshc->readdir_currLen);
+ if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+ ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+ LIBSSH2_SFTP_S_IFLNK)) {
+ sshc->readdir_linkPath = malloc(PATH_MAX + 1);
+ if(sshc->readdir_linkPath == NULL) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+ sshc->readdir_filename);
+ state(conn, SSH_SFTP_READDIR_LINK);
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
+ break;
+ }
+ }
+ else if(sshc->readdir_len == 0) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_READDIR_DONE);
+ break;
+ }
+ else if(sshc->readdir_len <= 0) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ failf(data, "Could not open remote file for reading: %s :: %d",
+ sftp_libssh2_strerror(err),
+ libssh2_session_last_errno(sshc->ssh_session));
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ break;
+ }
+ break;
+
+ case SSH_SFTP_READDIR_LINK:
+ sshc->readdir_len =
+ libssh2_sftp_symlink_ex(sshc->sftp_session,
+ sshc->readdir_linkPath,
+ curlx_uztoui(strlen(sshc->readdir_linkPath)),
+ sshc->readdir_filename,
+ PATH_MAX, LIBSSH2_SFTP_READLINK);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ Curl_safefree(sshc->readdir_linkPath);
+
+ /* get room for the filename and extra output */
+ sshc->readdir_totalLen += 4 + sshc->readdir_len;
+ new_readdir_line = Curl_saferealloc(sshc->readdir_line,
+ sshc->readdir_totalLen);
+ if(!new_readdir_line) {
+ sshc->readdir_line = NULL;
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ sshc->readdir_line = new_readdir_line;
+
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen,
+ " -> %s",
+ sshc->readdir_filename);
+
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
+ break;
+
+ case SSH_SFTP_READDIR_BOTTOM:
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen, "\n");
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ sshc->readdir_line,
+ sshc->readdir_currLen);
+
+ if(!result) {
+
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+ sshc->readdir_currLen, conn);
+ }
+ data->req.bytecount += sshc->readdir_currLen;
+ }
+ Curl_safefree(sshc->readdir_line);
+ if(result) {
+ state(conn, SSH_STOP);
+ }
+ else
+ state(conn, SSH_SFTP_READDIR);
+ break;
+
+ case SSH_SFTP_READDIR_DONE:
+ if(libssh2_sftp_closedir(sshc->sftp_handle) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ sshc->sftp_handle = NULL;
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_DOWNLOAD_INIT:
+ /*
+ * Work on getting the specified file
+ */
+ sshc->sftp_handle =
+ libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_FXF_READ, data->set.new_file_perms,
+ LIBSSH2_SFTP_OPENFILE);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ failf(data, "Could not open remote file for reading: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ state(conn, SSH_SFTP_DOWNLOAD_STAT);
+ break;
+
+ case SSH_SFTP_DOWNLOAD_STAT:
+ {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_SFTP_STAT, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc ||
+ !(attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) ||
+ (attrs.filesize == 0)) {
+ /*
+ * libssh2_sftp_open() didn't return an error, so maybe the server
+ * just doesn't support stat()
+ * OR the server doesn't return a file size with a stat()
+ * OR file size is 0
+ */
+ data->req.size = -1;
+ data->req.maxdownload = -1;
+ Curl_pgrsSetDownloadSize(data, -1);
+ }
+ else {
+ curl_off_t size = attrs.filesize;
+
+ if(size < 0) {
+ failf(data, "Bad file size (%" CURL_FORMAT_CURL_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ if(conn->data->state.use_range) {
+ curl_off_t from, to;
+ char *ptr;
+ char *ptr2;
+
+ from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if((ptr == ptr2) /* no "to" value given */
+ || (to >= size)) {
+ to = size - 1;
+ }
+ if(from < 0) {
+ /* from is relative to end of file */
+ from += size;
+ }
+ if(from > size) {
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")", from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ if(from > to) {
+ from = to;
+ size = 0;
+ }
+ else {
+ size = to - from + 1;
+ }
+
+ SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+ }
+ data->req.size = size;
+ data->req.maxdownload = size;
+ Curl_pgrsSetDownloadSize(data, size);
+ }
+
+ /* We can resume if we can seek to the resume position */
+ if(data->state.resume_from) {
+ if(data->state.resume_from < 0) {
+ /* We're supposed to download the last abs(from) bytes */
+ if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+ failf(data, "Offset (%"
+ CURL_FORMAT_CURL_OFF_T ") was beyond file size (%"
+ CURL_FORMAT_CURL_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* download from where? */
+ data->state.resume_from += attrs.filesize;
+ }
+ else {
+ if((curl_off_t)attrs.filesize < data->state.resume_from) {
+ failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
+ ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ }
+ /* Does a completed file need to be seeked and started or closed ? */
+ /* Now store the number of bytes we are expected to download */
+ data->req.size = attrs.filesize - data->state.resume_from;
+ data->req.maxdownload = attrs.filesize - data->state.resume_from;
+ Curl_pgrsSetDownloadSize(data,
+ attrs.filesize - data->state.resume_from);
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
+ }
+
+ /* Setup the actual download */
+ if(data->req.size == 0) {
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ infof(data, "File already completely downloaded\n");
+ state(conn, SSH_STOP);
+ break;
+ }
+ Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
+ FALSE, NULL, -1, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
+
+ /* we want to use the _receiving_ function even when the socket turns
+ out writableable as the underlying libssh2 recv function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_IN;
+
+ if(result) {
+ /* this should never occur; the close state should be entered
+ at the time the error occurs */
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SFTP_CLOSE:
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
+ }
+ if(sftp_scp)
+ Curl_safefree(sftp_scp->path);
+
+ DEBUGF(infof(data, "SFTP DONE done\n"));
+
+ /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
+ After nextstate is executed, the control should come back to
+ SSH_SFTP_CLOSE to pass the correct result back */
+ if(sshc->nextstate != SSH_NO_STATE &&
+ sshc->nextstate != SSH_SFTP_CLOSE) {
+ state(conn, sshc->nextstate);
+ sshc->nextstate = SSH_SFTP_CLOSE;
+ }
+ else {
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ }
+ break;
+
+ case SSH_SFTP_SHUTDOWN:
+ /* during times we get here due to a broken transfer and then the
+ sftp_handle might not have been taken down so make sure that is done
+ before we proceed */
+
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
+ }
+ if(sshc->sftp_session) {
+ rc = libssh2_sftp_shutdown(sshc->sftp_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to stop libssh2 sftp subsystem\n");
+ }
+ sshc->sftp_session = NULL;
+ }
+
+ Curl_safefree(sshc->homedir);
+ conn->data->state.most_recent_ftp_entrypath = NULL;
+
+ state(conn, SSH_SESSION_DISCONNECT);
+ break;
+
+ case SSH_SCP_TRANS_INIT:
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ if(data->set.upload) {
+ if(data->state.infilesize < 0) {
+ failf(data, "SCP requires a known file size for upload");
+ sshc->actualcode = CURLE_UPLOAD_FAILED;
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+ }
+ state(conn, SSH_SCP_UPLOAD_INIT);
+ }
+ else {
+ state(conn, SSH_SCP_DOWNLOAD_INIT);
+ }
+ break;
+
+ case SSH_SCP_UPLOAD_INIT:
+ /*
+ * libssh2 requires that the destination path is a full path that
+ * includes the destination file and name OR ends in a "/" . If this is
+ * not done the destination file will be named the same name as the last
+ * directory in the path.
+ */
+ sshc->ssh_channel =
+ SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms,
+ data->state.infilesize);
+ if(!sshc->ssh_channel) {
+ int ssh_err;
+ char *err_msg;
+
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+
+ ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0));
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+
+ /* upload data */
+ Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+ FIRSTSOCKET, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
+
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
+ }
+ else {
+ /* store this original bitmask setup to use later on if we can't
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
+
+ /* we want to use the _sending_ function even when the socket turns
+ out readable as the underlying libssh2 scp send function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_OUT;
+
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SCP_DOWNLOAD_INIT:
+ {
+ curl_off_t bytecount;
+
+ /*
+ * We must check the remote file; if it is a directory no values will
+ * be set in sb
+ */
+
+ /*
+ * If support for >2GB files exists, use it.
+ */
+
+ /* get a fresh new channel from the ssh layer */
+#if LIBSSH2_VERSION_NUM < 0x010700
+ struct stat sb;
+ memset(&sb, 0, sizeof(struct stat));
+ sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+ sftp_scp->path, &sb);
+#else
+ libssh2_struct_stat sb;
+ memset(&sb, 0, sizeof(libssh2_struct_stat));
+ sshc->ssh_channel = libssh2_scp_recv2(sshc->ssh_session,
+ sftp_scp->path, &sb);
+#endif
+
+ if(!sshc->ssh_channel) {
+ int ssh_err;
+ char *err_msg;
+
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+
+
+ ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0));
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+
+ /* download data */
+ bytecount = (curl_off_t)sb.st_size;
+ data->req.maxdownload = (curl_off_t)sb.st_size;
+ Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
+
+ /* we want to use the _receiving_ function even when the socket turns
+ out writableable as the underlying libssh2 recv function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_IN;
+
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
+ }
+ else
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SCP_DONE:
+ if(data->set.upload)
+ state(conn, SSH_SCP_SEND_EOF);
+ else
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+
+ case SSH_SCP_SEND_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_send_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc) {
+ infof(data, "Failed to send libssh2 channel EOF\n");
+ }
+ }
+ state(conn, SSH_SCP_WAIT_EOF);
+ break;
+
+ case SSH_SCP_WAIT_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc) {
+ infof(data, "Failed to get channel EOF: %d\n", rc);
+ }
+ }
+ state(conn, SSH_SCP_WAIT_CLOSE);
+ break;
+
+ case SSH_SCP_WAIT_CLOSE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc) {
+ infof(data, "Channel failed to close: %d\n", rc);
+ }
+ }
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+
+ case SSH_SCP_CHANNEL_FREE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
+ }
+ DEBUGF(infof(data, "SCP DONE phase complete\n"));
+#if 0 /* PREV */
+ state(conn, SSH_SESSION_DISCONNECT);
+#endif
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ break;
+
+ case SSH_SESSION_DISCONNECT:
+ /* during weird times when we've been prematurely aborted, the channel
+ is still alive when we reach this state and we MUST kill the channel
+ properly first */
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
+ }
+
+ if(sshc->ssh_session) {
+ rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to disconnect libssh2 session\n");
+ }
+ }
+
+ Curl_safefree(sshc->homedir);
+ conn->data->state.most_recent_ftp_entrypath = NULL;
+
+ state(conn, SSH_SESSION_FREE);
+ break;
+
+ case SSH_SESSION_FREE:
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ if(sshc->kh) {
+ libssh2_knownhost_free(sshc->kh);
+ sshc->kh = NULL;
+ }
+#endif
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+ if(sshc->ssh_agent) {
+ rc = libssh2_agent_disconnect(sshc->ssh_agent);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to disconnect from libssh2 agent\n");
+ }
+ libssh2_agent_free(sshc->ssh_agent);
+ sshc->ssh_agent = NULL;
+
+ /* NB: there is no need to free identities, they are part of internal
+ agent stuff */
+ sshc->sshagent_identity = NULL;
+ sshc->sshagent_prev_identity = NULL;
+ }
+#endif
+
+ if(sshc->ssh_session) {
+ rc = libssh2_session_free(sshc->ssh_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ if(rc < 0) {
+ infof(data, "Failed to free libssh2 session\n");
+ }
+ sshc->ssh_session = NULL;
+ }
+
+ /* worst-case scenario cleanup */
+
+ DEBUGASSERT(sshc->ssh_session == NULL);
+ DEBUGASSERT(sshc->ssh_channel == NULL);
+ DEBUGASSERT(sshc->sftp_session == NULL);
+ DEBUGASSERT(sshc->sftp_handle == NULL);
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ DEBUGASSERT(sshc->kh == NULL);
+#endif
+#ifdef HAVE_LIBSSH2_AGENT_API
+ DEBUGASSERT(sshc->ssh_agent == NULL);
+#endif
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+
+ Curl_safefree(sshc->homedir);
+
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ Curl_safefree(sshc->readdir_line);
+ Curl_safefree(sshc->readdir_linkPath);
+
+ /* the code we are about to return */
+ result = sshc->actualcode;
+
+ memset(sshc, 0, sizeof(struct ssh_conn));
+
+ connclose(conn, "SSH session free");
+ sshc->state = SSH_SESSION_FREE; /* current */
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ } while(!rc && (sshc->state != SSH_STOP));
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ /* we would block, we need to wait for the socket to be ready (in the
+ right direction too)! */
+ *block = TRUE;
+ }
+
+ return result;
+}
+
+/* called by the multi interface to figure out what socket(s) to wait for and
+ for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
+static int ssh_perform_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks
+ number of sockets */
+ int numsocks)
+{
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ int bitmap = GETSOCK_BLANK;
+ (void)numsocks;
+
+ sock[0] = conn->sock[FIRSTSOCKET];
+
+ if(conn->waitfor & KEEP_RECV)
+ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+ if(conn->waitfor & KEEP_SEND)
+ bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+ return bitmap;
+#else
+ /* if we don't know the direction we can use the generic *_getsock()
+ function even for the protocol_connect and doing states */
+ return Curl_single_getsock(conn, sock, numsocks);
+#endif
+}
+
+/* Generic function called by the multi interface to figure out what socket(s)
+ to wait for and for what actions during the DOING and PROTOCONNECT states*/
+static int ssh_getsock(struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+#ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ (void)conn;
+ (void)sock;
+ (void)numsocks;
+ /* if we don't know any direction we can just play along as we used to and
+ not provide any sensible info */
+ return GETSOCK_BLANK;
+#else
+ /* if we know the direction we can use the generic *_getsock() function even
+ for the protocol_connect and doing states */
+ return ssh_perform_getsock(conn, sock, numsocks);
+#endif
+}
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+/*
+ * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
+ * function is used to figure out in what direction and stores this info so
+ * that the multi interface can take advantage of it. Make sure to call this
+ * function in all cases so that when it _doesn't_ return EAGAIN we can
+ * restore the default wait bits.
+ */
+static void ssh_block2waitfor(struct connectdata *conn, bool block)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ int dir = 0;
+ if(block) {
+ dir = libssh2_session_block_directions(sshc->ssh_session);
+ if(dir) {
+ /* translate the libssh2 define bits into our own bit defines */
+ conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
+ ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
+ }
+ }
+ if(!dir)
+ /* It didn't block or libssh2 didn't reveal in which direction, put back
+ the original set */
+ conn->waitfor = sshc->orig_waitfor;
+}
+#else
+ /* no libssh2 directional support so we simply don't know */
+#define ssh_block2waitfor(x,y) Curl_nop_stmt
+#endif
+
+/* called repeatedly until done from multi.c */
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ CURLcode result = CURLE_OK;
+ bool block; /* we store the status and use that to provide a ssh_getsock()
+ implementation */
+
+ result = ssh_statemach_act(conn, &block);
+ *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+ ssh_block2waitfor(conn, block);
+
+ return result;
+}
+
+static CURLcode ssh_block_statemach(struct connectdata *conn,
+ bool disconnect)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ while((sshc->state != SSH_STOP) && !result) {
+ bool block;
+ time_t left = 1000;
+ struct timeval now = Curl_tvnow();
+
+ result = ssh_statemach_act(conn, &block);
+ if(result)
+ break;
+
+ if(!disconnect) {
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ result = Curl_speedcheck(data, now);
+ if(result)
+ break;
+
+ left = Curl_timeleft(data, NULL, FALSE);
+ if(left < 0) {
+ failf(data, "Operation timed out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ if(!result && block) {
+ int dir = libssh2_session_block_directions(sshc->ssh_session);
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ curl_socket_t fd_read = CURL_SOCKET_BAD;
+ curl_socket_t fd_write = CURL_SOCKET_BAD;
+ if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
+ fd_read = sock;
+ if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir)
+ fd_write = sock;
+ /* wait for the socket to become ready */
+ (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
+ left>1000?1000:left); /* ignore result */
+ }
+#endif
+
+ }
+
+ return result;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode ssh_setup_connection(struct connectdata *conn)
+{
+ struct SSHPROTO *ssh;
+
+ conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+ if(!ssh)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+static Curl_recv scp_recv, sftp_recv;
+static Curl_send scp_send, sftp_send;
+
+/*
+ * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.
+ */
+static CURLcode ssh_connect(struct connectdata *conn, bool *done)
+{
+#ifdef CURL_LIBSSH2_DEBUG
+ curl_socket_t sock;
+#endif
+ struct ssh_conn *ssh;
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+
+ /* initialize per-handle data if not already */
+ if(!data->req.protop)
+ ssh_setup_connection(conn);
+
+ /* We default to persistent connections. We set this already in this connect
+ function to make the re-use checks properly be able to check this bit. */
+ connkeep(conn, "SSH default");
+
+ if(conn->handler->protocol & CURLPROTO_SCP) {
+ conn->recv[FIRSTSOCKET] = scp_recv;
+ conn->send[FIRSTSOCKET] = scp_send;
+ }
+ else {
+ conn->recv[FIRSTSOCKET] = sftp_recv;
+ conn->send[FIRSTSOCKET] = sftp_send;
+ }
+ ssh = &conn->proto.sshc;
+
+#ifdef CURL_LIBSSH2_DEBUG
+ if(conn->user) {
+ infof(data, "User: %s\n", conn->user);
+ }
+ if(conn->passwd) {
+ infof(data, "Password: %s\n", conn->passwd);
+ }
+ sock = conn->sock[FIRSTSOCKET];
+#endif /* CURL_LIBSSH2_DEBUG */
+
+ ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
+ my_libssh2_free,
+ my_libssh2_realloc, conn);
+ if(ssh->ssh_session == NULL) {
+ failf(data, "Failure initialising ssh session");
+ return CURLE_FAILED_INIT;
+ }
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ int rc;
+ ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
+ if(!ssh->kh) {
+ /* eeek. TODO: free the ssh_session! */
+ return CURLE_FAILED_INIT;
+ }
+
+ /* read all known hosts from there */
+ rc = libssh2_knownhost_readfile(ssh->kh,
+ data->set.str[STRING_SSH_KNOWNHOSTS],
+ LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+ if(rc < 0)
+ infof(data, "Failed to read known hosts from %s\n",
+ data->set.str[STRING_SSH_KNOWNHOSTS]);
+ }
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#ifdef CURL_LIBSSH2_DEBUG
+ libssh2_trace(ssh->ssh_session, ~0);
+ infof(data, "SSH socket: %d\n", (int)sock);
+#endif /* CURL_LIBSSH2_DEBUG */
+
+ state(conn, SSH_INIT);
+
+ result = ssh_multi_statemach(conn, done);
+
+ return result;
+}
+
+/*
+ ***********************************************************************
+ *
+ * scp_perform()
+ *
+ * This is the actual DO function for SCP. Get a file according to
+ * the options previously setup.
+ */
+
+static
+CURLcode scp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ state(conn, SSH_SCP_TRANS_INIT);
+
+ /* run the state-machine */
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode scp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result;
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ return result;
+}
+
+/*
+ * The DO function is generic for both protocols. There was previously two
+ * separate ones but this way means less duplicated code.
+ */
+
+static CURLcode ssh_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+ bool connected = 0;
+ struct Curl_easy *data = conn->data;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+
+ *done = FALSE; /* default to false */
+
+ data->req.size = -1; /* make sure this is unknown at this point */
+
+ sshc->actualcode = CURLE_OK; /* reset error code */
+ sshc->secondCreateDirs =0; /* reset the create dir attempt state
+ variable */
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, -1);
+ Curl_pgrsSetDownloadSize(data, -1);
+
+ if(conn->handler->protocol & CURLPROTO_SCP)
+ result = scp_perform(conn, &connected, done);
+ else
+ result = sftp_perform(conn, &connected, done);
+
+ return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+ this is still blocking is that the multi interface code has no support for
+ disconnecting operations that takes a while */
+static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ CURLcode result = CURLE_OK;
+ struct ssh_conn *ssh = &conn->proto.sshc;
+ (void) dead_connection;
+
+ if(ssh->ssh_session) {
+ /* only if there's a session still around to use! */
+
+ state(conn, SSH_SESSION_DISCONNECT);
+
+ result = ssh_block_statemach(conn, TRUE);
+ }
+
+ return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+ done functions */
+static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
+{
+ CURLcode result = CURLE_OK;
+ struct SSHPROTO *sftp_scp = conn->data->req.protop;
+
+ if(!status) {
+ /* run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the ssh_multi_statemach function but we have no general support for
+ non-blocking DONE operations!
+ */
+ result = ssh_block_statemach(conn, FALSE);
+ }
+ else
+ result = status;
+
+ if(sftp_scp)
+ Curl_safefree(sftp_scp->path);
+ if(Curl_pgrsDone(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ conn->data->req.keepon = 0; /* clear all bits */
+ return result;
+}
+
+
+static CURLcode scp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ (void)premature; /* not used */
+
+ if(!status)
+ state(conn, SSH_SCP_DONE);
+
+ return ssh_done(conn, status);
+
+}
+
+static ssize_t scp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ ssize_t nwrite;
+ (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+ /* libssh2_channel_write() returns int! */
+ nwrite = (ssize_t)
+ libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
+
+ ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
+ else if(nwrite < LIBSSH2_ERROR_NONE) {
+ *err = libssh2_session_error_to_CURLE((int)nwrite);
+ nwrite = -1;
+ }
+
+ return nwrite;
+}
+
+static ssize_t scp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ ssize_t nread;
+ (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+ /* libssh2_channel_read() returns int */
+ nread = (ssize_t)
+ libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
+
+ ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+ if(nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
+
+ return nread;
+}
+
+/*
+ * =============== SFTP ===============
+ */
+
+/*
+ ***********************************************************************
+ *
+ * sftp_perform()
+ *
+ * This is the actual DO function for SFTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode sftp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ state(conn, SSH_SFTP_QUOTE_INIT);
+
+ /* run the state-machine */
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode sftp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = ssh_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+ this is still blocking is that the multi interface code has no support for
+ disconnecting operations that takes a while */
+static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ CURLcode result = CURLE_OK;
+ (void) dead_connection;
+
+ DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+
+ if(conn->proto.sshc.ssh_session) {
+ /* only if there's a session still around to use! */
+ state(conn, SSH_SFTP_SHUTDOWN);
+ result = ssh_block_statemach(conn, TRUE);
+ }
+
+ DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+
+ return result;
+
+}
+
+static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+
+ if(!status) {
+ /* Post quote commands are executed after the SFTP_CLOSE state to avoid
+ errors that could happen due to open file handles during POSTQUOTE
+ operation */
+ if(!status && !premature && conn->data->set.postquote) {
+ sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
+ state(conn, SSH_SFTP_CLOSE);
+ }
+ else
+ state(conn, SSH_SFTP_CLOSE);
+ }
+ return ssh_done(conn, status);
+}
+
+/* return number of sent bytes */
+static ssize_t sftp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
+ but is changed to ssize_t in 0.15. These days we don't
+ support libssh2 0.15*/
+ (void)sockindex;
+
+ nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
+
+ ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
+ else if(nwrite < LIBSSH2_ERROR_NONE) {
+ *err = libssh2_session_error_to_CURLE((int)nwrite);
+ nwrite = -1;
+ }
+
+ return nwrite;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ * or <0 on error
+ */
+static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ ssize_t nread;
+ (void)sockindex;
+
+ nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
+
+ ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+
+ }
+ else if(nread < 0) {
+ *err = libssh2_session_error_to_CURLE((int)nread);
+ }
+ return nread;
+}
+
+/* The get_pathname() function is being borrowed from OpenSSH sftp.c
+ version 4.6p1. */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+static CURLcode
+get_pathname(const char **cpp, char **path)
+{
+ const char *cp = *cpp, *end;
+ char quot;
+ unsigned int i, j;
+ static const char WHITESPACE[] = " \t\r\n";
+
+ cp += strspn(cp, WHITESPACE);
+ if(!*cp) {
+ *cpp = cp;
+ *path = NULL;
+ return CURLE_QUOTE_ERROR;
+ }
+
+ *path = malloc(strlen(cp) + 1);
+ if(*path == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Check for quoted filenames */
+ if(*cp == '\"' || *cp == '\'') {
+ quot = *cp++;
+
+ /* Search for terminating quote, unescape some chars */
+ for(i = j = 0; i <= strlen(cp); i++) {
+ if(cp[i] == quot) { /* Found quote */
+ i++;
+ (*path)[j] = '\0';
+ break;
+ }
+ if(cp[i] == '\0') { /* End of string */
+ /*error("Unterminated quote");*/
+ goto fail;
+ }
+ if(cp[i] == '\\') { /* Escaped characters */
+ i++;
+ if(cp[i] != '\'' && cp[i] != '\"' &&
+ cp[i] != '\\') {
+ /*error("Bad escaped character '\\%c'",
+ cp[i]);*/
+ goto fail;
+ }
+ }
+ (*path)[j++] = cp[i];
+ }
+
+ if(j == 0) {
+ /*error("Empty quotes");*/
+ goto fail;
+ }
+ *cpp = cp + i + strspn(cp + i, WHITESPACE);
+ }
+ else {
+ /* Read to end of filename */
+ end = strpbrk(cp, WHITESPACE);
+ if(end == NULL)
+ end = strchr(cp, '\0');
+ *cpp = end + strspn(end, WHITESPACE);
+
+ memcpy(*path, cp, end - cp);
+ (*path)[end - cp] = '\0';
+ }
+ return CURLE_OK;
+
+ fail:
+ Curl_safefree(*path);
+ return CURLE_QUOTE_ERROR;
+}
+
+
+static const char *sftp_libssh2_strerror(int err)
+{
+ switch(err) {
+ case LIBSSH2_FX_NO_SUCH_FILE:
+ return "No such file or directory";
+
+ case LIBSSH2_FX_PERMISSION_DENIED:
+ return "Permission denied";
+
+ case LIBSSH2_FX_FAILURE:
+ return "Operation failed";
+
+ case LIBSSH2_FX_BAD_MESSAGE:
+ return "Bad message from SFTP server";
+
+ case LIBSSH2_FX_NO_CONNECTION:
+ return "Not connected to SFTP server";
+
+ case LIBSSH2_FX_CONNECTION_LOST:
+ return "Connection to SFTP server lost";
+
+ case LIBSSH2_FX_OP_UNSUPPORTED:
+ return "Operation not supported by SFTP server";
+
+ case LIBSSH2_FX_INVALID_HANDLE:
+ return "Invalid handle";
+
+ case LIBSSH2_FX_NO_SUCH_PATH:
+ return "No such file or directory";
+
+ case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+ return "File already exists";
+
+ case LIBSSH2_FX_WRITE_PROTECT:
+ return "File is write protected";
+
+ case LIBSSH2_FX_NO_MEDIA:
+ return "No media";
+
+ case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+ return "Disk full";
+
+ case LIBSSH2_FX_QUOTA_EXCEEDED:
+ return "User quota exceeded";
+
+ case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
+ return "Unknown principle";
+
+ case LIBSSH2_FX_LOCK_CONFlICT:
+ return "File lock conflict";
+
+ case LIBSSH2_FX_DIR_NOT_EMPTY:
+ return "Directory not empty";
+
+ case LIBSSH2_FX_NOT_A_DIRECTORY:
+ return "Not a directory";
+
+ case LIBSSH2_FX_INVALID_FILENAME:
+ return "Invalid filename";
+
+ case LIBSSH2_FX_LINK_LOOP:
+ return "Link points to itself";
+ }
+ return "Unknown error in libssh2";
+}
+
+#endif /* USE_LIBSSH2 */
diff --git a/Utilities/cmcurl/lib/ssh.h b/Utilities/cmcurl/lib/ssh.h
new file mode 100644
index 000000000..b350dcf3a
--- /dev/null
+++ b/Utilities/cmcurl/lib/ssh.h
@@ -0,0 +1,198 @@
+#ifndef HEADER_CURL_SSH_H
+#define HEADER_CURL_SSH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/****************************************************************************
+ * SSH unique setup
+ ***************************************************************************/
+typedef enum {
+ SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */
+ SSH_STOP = 0, /* do nothing state, stops the state machine */
+
+ SSH_INIT, /* First state in SSH-CONNECT */
+ SSH_S_STARTUP, /* Session startup */
+ SSH_HOSTKEY, /* verify hostkey */
+ SSH_AUTHLIST,
+ SSH_AUTH_PKEY_INIT,
+ SSH_AUTH_PKEY,
+ SSH_AUTH_PASS_INIT,
+ SSH_AUTH_PASS,
+ SSH_AUTH_AGENT_INIT, /* initialize then wait for connection to agent */
+ SSH_AUTH_AGENT_LIST, /* ask for list then wait for entire list to come */
+ SSH_AUTH_AGENT, /* attempt one key at a time */
+ SSH_AUTH_HOST_INIT,
+ SSH_AUTH_HOST,
+ SSH_AUTH_KEY_INIT,
+ SSH_AUTH_KEY,
+ SSH_AUTH_DONE,
+ SSH_SFTP_INIT,
+ SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */
+
+ SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */
+ SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */
+ SSH_SFTP_QUOTE,
+ SSH_SFTP_NEXT_QUOTE,
+ SSH_SFTP_QUOTE_STAT,
+ SSH_SFTP_QUOTE_SETSTAT,
+ SSH_SFTP_QUOTE_SYMLINK,
+ SSH_SFTP_QUOTE_MKDIR,
+ SSH_SFTP_QUOTE_RENAME,
+ SSH_SFTP_QUOTE_RMDIR,
+ SSH_SFTP_QUOTE_UNLINK,
+ SSH_SFTP_QUOTE_STATVFS,
+ SSH_SFTP_GETINFO,
+ SSH_SFTP_FILETIME,
+ SSH_SFTP_TRANS_INIT,
+ SSH_SFTP_UPLOAD_INIT,
+ SSH_SFTP_CREATE_DIRS_INIT,
+ SSH_SFTP_CREATE_DIRS,
+ SSH_SFTP_CREATE_DIRS_MKDIR,
+ SSH_SFTP_READDIR_INIT,
+ SSH_SFTP_READDIR,
+ SSH_SFTP_READDIR_LINK,
+ SSH_SFTP_READDIR_BOTTOM,
+ SSH_SFTP_READDIR_DONE,
+ SSH_SFTP_DOWNLOAD_INIT,
+ SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */
+ SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */
+ SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */
+ SSH_SCP_TRANS_INIT, /* First state in SCP-DO */
+ SSH_SCP_UPLOAD_INIT,
+ SSH_SCP_DOWNLOAD_INIT,
+ SSH_SCP_DONE,
+ SSH_SCP_SEND_EOF,
+ SSH_SCP_WAIT_EOF,
+ SSH_SCP_WAIT_CLOSE,
+ SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */
+ SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */
+ SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */
+ SSH_QUIT,
+ SSH_LAST /* never used */
+} sshstate;
+
+/* this struct is used in the HandleData struct which is part of the
+ Curl_easy, which means this is used on a per-easy handle basis.
+ Everything that is strictly related to a connection is banned from this
+ struct. */
+struct SSHPROTO {
+ char *path; /* the path we operate on */
+};
+
+/* ssh_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct ssh_conn {
+ const char *authlist; /* List of auth. methods, managed by libssh2 */
+#ifdef USE_LIBSSH2
+ const char *passphrase; /* pass-phrase to use */
+ char *rsa_pub; /* path name */
+ char *rsa; /* path name */
+ bool authed; /* the connection has been authenticated fine */
+ sshstate state; /* always use ssh.c:state() to change state! */
+ sshstate nextstate; /* the state to goto after stopping */
+ CURLcode actualcode; /* the actual error code */
+ struct curl_slist *quote_item; /* for the quote option */
+ char *quote_path1; /* two generic pointers for the QUOTE stuff */
+ char *quote_path2;
+ LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
+ bool acceptfail; /* used by the SFTP_QUOTE (continue if
+ quote command fails) */
+ char *homedir; /* when doing SFTP we figure out home dir in the
+ connect phase */
+
+ /* Here's a set of struct members used by the SFTP_READDIR state */
+ LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
+ char *readdir_filename;
+ char *readdir_longentry;
+ int readdir_len, readdir_totalLen, readdir_currLen;
+ char *readdir_line;
+ char *readdir_linkPath;
+ /* end of READDIR stuff */
+
+ int secondCreateDirs; /* counter use by the code to see if the
+ second attempt has been made to change
+ to/create a directory */
+ char *slash_pos; /* used by the SFTP_CREATE_DIRS state */
+ LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
+ LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
+ LIBSSH2_SFTP *sftp_session; /* SFTP handle */
+ LIBSSH2_SFTP_HANDLE *sftp_handle;
+ int orig_waitfor; /* default READ/WRITE bits wait for */
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+ LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */
+ struct libssh2_agent_publickey *sshagent_identity,
+ *sshagent_prev_identity;
+#endif
+
+ /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
+ header */
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ LIBSSH2_KNOWNHOSTS *kh;
+#endif
+#endif /* USE_LIBSSH2 */
+};
+
+#ifdef USE_LIBSSH2
+
+/* Feature detection based on version numbers to better work with
+ non-configure platforms */
+
+#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
+# error "SCP/SFTP protocols require libssh2 0.16 or later"
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010000
+#define HAVE_LIBSSH2_SFTP_SEEK64 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010100
+#define HAVE_LIBSSH2_VERSION 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010205
+#define HAVE_LIBSSH2_INIT 1
+#define HAVE_LIBSSH2_EXIT 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010206
+#define HAVE_LIBSSH2_KNOWNHOST_CHECKP 1
+#define HAVE_LIBSSH2_SCP_SEND64 1
+#endif
+
+#if LIBSSH2_VERSION_NUM >= 0x010208
+#define HAVE_LIBSSH2_SESSION_HANDSHAKE 1
+#endif
+
+extern const struct Curl_handler Curl_handler_scp;
+extern const struct Curl_handler Curl_handler_sftp;
+
+#endif /* USE_LIBSSH2 */
+
+#endif /* HEADER_CURL_SSH_H */
diff --git a/Utilities/cmcurl/lib/strcase.c b/Utilities/cmcurl/lib/strcase.c
new file mode 100644
index 000000000..a74a4be57
--- /dev/null
+++ b/Utilities/cmcurl/lib/strcase.c
@@ -0,0 +1,176 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "strcase.h"
+
+/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
+ its behavior is altered by the current locale. */
+char Curl_raw_toupper(char in)
+{
+#if !defined(CURL_DOES_CONVERSIONS)
+ if(in >= 'a' && in <= 'z')
+ return (char)('A' + in - 'a');
+#else
+ switch(in) {
+ case 'a':
+ return 'A';
+ case 'b':
+ return 'B';
+ case 'c':
+ return 'C';
+ case 'd':
+ return 'D';
+ case 'e':
+ return 'E';
+ case 'f':
+ return 'F';
+ case 'g':
+ return 'G';
+ case 'h':
+ return 'H';
+ case 'i':
+ return 'I';
+ case 'j':
+ return 'J';
+ case 'k':
+ return 'K';
+ case 'l':
+ return 'L';
+ case 'm':
+ return 'M';
+ case 'n':
+ return 'N';
+ case 'o':
+ return 'O';
+ case 'p':
+ return 'P';
+ case 'q':
+ return 'Q';
+ case 'r':
+ return 'R';
+ case 's':
+ return 'S';
+ case 't':
+ return 'T';
+ case 'u':
+ return 'U';
+ case 'v':
+ return 'V';
+ case 'w':
+ return 'W';
+ case 'x':
+ return 'X';
+ case 'y':
+ return 'Y';
+ case 'z':
+ return 'Z';
+ }
+#endif
+
+ return in;
+}
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * some further explanation to why this function is necessary.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ *
+ * @unittest: 1301
+ */
+
+int Curl_strcasecompare(const char *first, const char *second)
+{
+ while(*first && *second) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+ /* get out of the loop as soon as they don't match */
+ break;
+ first++;
+ second++;
+ }
+ /* we do the comparison here (possibly again), just to make sure that if the
+ loop above is skipped because one of the strings reached zero, we must not
+ return this as a successful match */
+ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
+}
+
+int Curl_safe_strcasecompare(const char *first, const char *second)
+{
+ if(first && second)
+ /* both pointers point to something then compare them */
+ return Curl_strcasecompare(first, second);
+
+ /* if both pointers are NULL then treat them as equal */
+ return (NULL == first && NULL == second);
+}
+
+/*
+ * @unittest: 1301
+ */
+int Curl_strncasecompare(const char *first, const char *second, size_t max)
+{
+ while(*first && *second && max) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
+ break;
+ }
+ max--;
+ first++;
+ second++;
+ }
+ if(0 == max)
+ return 1; /* they are equal this far */
+
+ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/* Copy an upper case version of the string from src to dest. The
+ * strings may overlap. No more than n characters of the string are copied
+ * (including any NUL) and the destination string will NOT be
+ * NUL-terminated if that limit is reached.
+ */
+void Curl_strntoupper(char *dest, const char *src, size_t n)
+{
+ if(n < 1)
+ return;
+
+ do {
+ *dest++ = Curl_raw_toupper(*src);
+ } while(*src++ && --n);
+}
+
+/* --- public functions --- */
+
+int curl_strequal(const char *first, const char *second)
+{
+ return Curl_strcasecompare(first, second);
+}
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+ return Curl_strncasecompare(first, second, max);
+}
diff --git a/Utilities/cmcurl/lib/strcase.h b/Utilities/cmcurl/lib/strcase.h
new file mode 100644
index 000000000..ea2abc8b6
--- /dev/null
+++ b/Utilities/cmcurl/lib/strcase.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_STRCASE_H
+#define HEADER_CURL_STRCASE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+/*
+ * Only "raw" case insensitive strings. This is meant to be locale independent
+ * and only compare strings we know are safe for this.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+
+#define strcasecompare(a,b) Curl_strcasecompare(a,b)
+#define strncasecompare(a,b,c) Curl_strncasecompare(a,b,c)
+
+int Curl_strcasecompare(const char *first, const char *second);
+int Curl_safe_strcasecompare(const char *first, const char *second);
+int Curl_strncasecompare(const char *first, const char *second, size_t max);
+
+char Curl_raw_toupper(char in);
+
+/* checkprefix() is a shorter version of the above, used when the first
+ argument is zero-byte terminated */
+#define checkprefix(a,b) curl_strnequal(a,b,strlen(a))
+
+void Curl_strntoupper(char *dest, const char *src, size_t n);
+char Curl_raw_toupper(char in);
+
+#endif /* HEADER_CURL_STRCASE_H */
diff --git a/Utilities/cmcurl/lib/strdup.c b/Utilities/cmcurl/lib/strdup.c
new file mode 100644
index 000000000..136b69377
--- /dev/null
+++ b/Utilities/cmcurl/lib/strdup.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "strdup.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef HAVE_STRDUP
+char *curlx_strdup(const char *str)
+{
+ size_t len;
+ char *newstr;
+
+ if(!str)
+ return (char *)NULL;
+
+ len = strlen(str);
+
+ if(len >= ((size_t)-1) / sizeof(char))
+ return (char *)NULL;
+
+ newstr = malloc((len+1)*sizeof(char));
+ if(!newstr)
+ return (char *)NULL;
+
+ memcpy(newstr, str, (len+1)*sizeof(char));
+
+ return newstr;
+
+}
+#endif
+
+/***************************************************************************
+ *
+ * Curl_memdup(source, length)
+ *
+ * Copies the 'source' data to a newly allocated buffer (that is
+ * returned). Copies 'length' bytes.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_memdup(const void *src, size_t length)
+{
+ void *buffer = malloc(length);
+ if(!buffer)
+ return NULL; /* fail */
+
+ memcpy(buffer, src, length);
+
+ return buffer;
+}
+
+/***************************************************************************
+ *
+ * Curl_saferealloc(ptr, size)
+ *
+ * Does a normal realloc(), but will free the data pointer if the realloc
+ * fails. If 'size' is zero, it will free the data and return a failure.
+ *
+ * This convenience function is provided and used to help us avoid a common
+ * mistake pattern when we could pass in a zero, catch the NULL return and end
+ * up free'ing the memory twice.
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+void *Curl_saferealloc(void *ptr, size_t size)
+{
+ void *datap = realloc(ptr, size);
+ if(size && !datap)
+ /* only free 'ptr' if size was non-zero */
+ free(ptr);
+ return datap;
+}
diff --git a/Utilities/cmcurl/lib/strdup.h b/Utilities/cmcurl/lib/strdup.h
new file mode 100644
index 000000000..ae3d5d011
--- /dev/null
+++ b/Utilities/cmcurl/lib/strdup.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_STRDUP_H
+#define HEADER_CURL_STRDUP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifndef HAVE_STRDUP
+extern char *curlx_strdup(const char *str);
+#endif
+void *Curl_memdup(const void *src, size_t buffer_length);
+void *Curl_saferealloc(void *ptr, size_t size);
+
+#endif /* HEADER_CURL_STRDUP_H */
diff --git a/Utilities/cmcurl/lib/strerror.c b/Utilities/cmcurl/lib/strerror.c
new file mode 100644
index 000000000..7e5cde47b
--- /dev/null
+++ b/Utilities/cmcurl/lib/strerror.c
@@ -0,0 +1,1072 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2004 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_STRERROR_R
+# if (!defined(HAVE_POSIX_STRERROR_R) && \
+ !defined(HAVE_GLIBC_STRERROR_R) && \
+ !defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
+# error "strerror_r MUST be either POSIX, glibc or vxworks-style"
+# endif
+#endif
+
+#include <curl/curl.h>
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#include "strerror.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(error) {
+ case CURLE_OK:
+ return "No error";
+
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ return "Unsupported protocol";
+
+ case CURLE_FAILED_INIT:
+ return "Failed initialization";
+
+ case CURLE_URL_MALFORMAT:
+ return "URL using bad/illegal format or missing URL";
+
+ case CURLE_NOT_BUILT_IN:
+ return "A requested feature, protocol or option was not found built-in in"
+ " this libcurl due to a build-time decision.";
+
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ return "Couldn't resolve proxy name";
+
+ case CURLE_COULDNT_RESOLVE_HOST:
+ return "Couldn't resolve host name";
+
+ case CURLE_COULDNT_CONNECT:
+ return "Couldn't connect to server";
+
+ case CURLE_WEIRD_SERVER_REPLY:
+ return "Weird server reply";
+
+ case CURLE_REMOTE_ACCESS_DENIED:
+ return "Access denied to remote resource";
+
+ case CURLE_FTP_ACCEPT_FAILED:
+ return "FTP: The server failed to connect to data port";
+
+ case CURLE_FTP_ACCEPT_TIMEOUT:
+ return "FTP: Accepting server connect has timed out";
+
+ case CURLE_FTP_PRET_FAILED:
+ return "FTP: The server did not accept the PRET command.";
+
+ case CURLE_FTP_WEIRD_PASS_REPLY:
+ return "FTP: unknown PASS reply";
+
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ return "FTP: unknown PASV reply";
+
+ case CURLE_FTP_WEIRD_227_FORMAT:
+ return "FTP: unknown 227 response format";
+
+ case CURLE_FTP_CANT_GET_HOST:
+ return "FTP: can't figure out the host in the PASV response";
+
+ case CURLE_HTTP2:
+ return "Error in the HTTP2 framing layer";
+
+ case CURLE_FTP_COULDNT_SET_TYPE:
+ return "FTP: couldn't set file type";
+
+ case CURLE_PARTIAL_FILE:
+ return "Transferred a partial file";
+
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ return "FTP: couldn't retrieve (RETR failed) the specified file";
+
+ case CURLE_QUOTE_ERROR:
+ return "Quote command returned error";
+
+ case CURLE_HTTP_RETURNED_ERROR:
+ return "HTTP response code said error";
+
+ case CURLE_WRITE_ERROR:
+ return "Failed writing received data to disk/application";
+
+ case CURLE_UPLOAD_FAILED:
+ return "Upload failed (at start/before it took off)";
+
+ case CURLE_READ_ERROR:
+ return "Failed to open/read local data from file/application";
+
+ case CURLE_OUT_OF_MEMORY:
+ return "Out of memory";
+
+ case CURLE_OPERATION_TIMEDOUT:
+ return "Timeout was reached";
+
+ case CURLE_FTP_PORT_FAILED:
+ return "FTP: command PORT failed";
+
+ case CURLE_FTP_COULDNT_USE_REST:
+ return "FTP: command REST failed";
+
+ case CURLE_RANGE_ERROR:
+ return "Requested range was not delivered by the server";
+
+ case CURLE_HTTP_POST_ERROR:
+ return "Internal problem setting up the POST";
+
+ case CURLE_SSL_CONNECT_ERROR:
+ return "SSL connect error";
+
+ case CURLE_BAD_DOWNLOAD_RESUME:
+ return "Couldn't resume download";
+
+ case CURLE_FILE_COULDNT_READ_FILE:
+ return "Couldn't read a file:// file";
+
+ case CURLE_LDAP_CANNOT_BIND:
+ return "LDAP: cannot bind";
+
+ case CURLE_LDAP_SEARCH_FAILED:
+ return "LDAP: search failed";
+
+ case CURLE_FUNCTION_NOT_FOUND:
+ return "A required function in the library was not found";
+
+ case CURLE_ABORTED_BY_CALLBACK:
+ return "Operation was aborted by an application callback";
+
+ case CURLE_BAD_FUNCTION_ARGUMENT:
+ return "A libcurl function was given a bad argument";
+
+ case CURLE_INTERFACE_FAILED:
+ return "Failed binding local connection end";
+
+ case CURLE_TOO_MANY_REDIRECTS :
+ return "Number of redirects hit maximum amount";
+
+ case CURLE_UNKNOWN_OPTION:
+ return "An unknown option was passed in to libcurl";
+
+ case CURLE_TELNET_OPTION_SYNTAX :
+ return "Malformed telnet option";
+
+ case CURLE_PEER_FAILED_VERIFICATION:
+ return "SSL peer certificate or SSH remote key was not OK";
+
+ case CURLE_GOT_NOTHING:
+ return "Server returned nothing (no headers, no data)";
+
+ case CURLE_SSL_ENGINE_NOTFOUND:
+ return "SSL crypto engine not found";
+
+ case CURLE_SSL_ENGINE_SETFAILED:
+ return "Can not set SSL crypto engine as default";
+
+ case CURLE_SSL_ENGINE_INITFAILED:
+ return "Failed to initialise SSL crypto engine";
+
+ case CURLE_SEND_ERROR:
+ return "Failed sending data to the peer";
+
+ case CURLE_RECV_ERROR:
+ return "Failure when receiving data from the peer";
+
+ case CURLE_SSL_CERTPROBLEM:
+ return "Problem with the local SSL certificate";
+
+ case CURLE_SSL_CIPHER:
+ return "Couldn't use specified SSL cipher";
+
+ case CURLE_SSL_CACERT:
+ return "Peer certificate cannot be authenticated with given CA "
+ "certificates";
+
+ case CURLE_SSL_CACERT_BADFILE:
+ return "Problem with the SSL CA cert (path? access rights?)";
+
+ case CURLE_BAD_CONTENT_ENCODING:
+ return "Unrecognized or bad HTTP Content or Transfer-Encoding";
+
+ case CURLE_LDAP_INVALID_URL:
+ return "Invalid LDAP URL";
+
+ case CURLE_FILESIZE_EXCEEDED:
+ return "Maximum file size exceeded";
+
+ case CURLE_USE_SSL_FAILED:
+ return "Requested SSL level failed";
+
+ case CURLE_SSL_SHUTDOWN_FAILED:
+ return "Failed to shut down the SSL connection";
+
+ case CURLE_SSL_CRL_BADFILE:
+ return "Failed to load CRL file (path? access rights?, format?)";
+
+ case CURLE_SSL_ISSUER_ERROR:
+ return "Issuer check against peer certificate failed";
+
+ case CURLE_SEND_FAIL_REWIND:
+ return "Send failed since rewinding of the data stream failed";
+
+ case CURLE_LOGIN_DENIED:
+ return "Login denied";
+
+ case CURLE_TFTP_NOTFOUND:
+ return "TFTP: File Not Found";
+
+ case CURLE_TFTP_PERM:
+ return "TFTP: Access Violation";
+
+ case CURLE_REMOTE_DISK_FULL:
+ return "Disk full or allocation exceeded";
+
+ case CURLE_TFTP_ILLEGAL:
+ return "TFTP: Illegal operation";
+
+ case CURLE_TFTP_UNKNOWNID:
+ return "TFTP: Unknown transfer ID";
+
+ case CURLE_REMOTE_FILE_EXISTS:
+ return "Remote file already exists";
+
+ case CURLE_TFTP_NOSUCHUSER:
+ return "TFTP: No such user";
+
+ case CURLE_CONV_FAILED:
+ return "Conversion failed";
+
+ case CURLE_CONV_REQD:
+ return "Caller must register CURLOPT_CONV_ callback options";
+
+ case CURLE_REMOTE_FILE_NOT_FOUND:
+ return "Remote file not found";
+
+ case CURLE_SSH:
+ return "Error in the SSH layer";
+
+ case CURLE_AGAIN:
+ return "Socket not ready for send/recv";
+
+ case CURLE_RTSP_CSEQ_ERROR:
+ return "RTSP CSeq mismatch or invalid CSeq";
+
+ case CURLE_RTSP_SESSION_ERROR:
+ return "RTSP session error";
+
+ case CURLE_FTP_BAD_FILE_LIST:
+ return "Unable to parse FTP file list";
+
+ case CURLE_CHUNK_FAILED:
+ return "Chunk callback failed";
+
+ case CURLE_NO_CONNECTION_AVAILABLE:
+ return "The max connection limit is reached";
+
+ case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
+ return "SSL public key does not match pinned public key";
+
+ case CURLE_SSL_INVALIDCERTSTATUS:
+ return "SSL server certificate status verification FAILED";
+
+ case CURLE_HTTP2_STREAM:
+ return "Stream error in the HTTP/2 framing layer";
+
+ /* error codes not used by current libcurl */
+ case CURLE_OBSOLETE20:
+ case CURLE_OBSOLETE24:
+ case CURLE_OBSOLETE29:
+ case CURLE_OBSOLETE32:
+ case CURLE_OBSOLETE40:
+ case CURLE_OBSOLETE44:
+ case CURLE_OBSOLETE46:
+ case CURLE_OBSOLETE50:
+ case CURLE_OBSOLETE57:
+ case CURL_LAST:
+ break;
+ }
+ /*
+ * By using a switch, gcc -Wall will complain about enum values
+ * which do not appear, helping keep this function up-to-date.
+ * By using gcc -Wall -Werror, you can't forget.
+ *
+ * A table would not have the same benefit. Most compilers will
+ * generate code very similar to a table in any case, so there
+ * is little performance gain from a table. And something is broken
+ * for the user's application, anyways, so does it matter how fast
+ * it _doesn't_ work?
+ *
+ * The line number for the error will be near this comment, which
+ * is why it is here, and not at the start of the switch.
+ */
+ return "Unknown error";
+#else
+ if(!error)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(error) {
+ case CURLM_CALL_MULTI_PERFORM:
+ return "Please call curl_multi_perform() soon";
+
+ case CURLM_OK:
+ return "No error";
+
+ case CURLM_BAD_HANDLE:
+ return "Invalid multi handle";
+
+ case CURLM_BAD_EASY_HANDLE:
+ return "Invalid easy handle";
+
+ case CURLM_OUT_OF_MEMORY:
+ return "Out of memory";
+
+ case CURLM_INTERNAL_ERROR:
+ return "Internal error";
+
+ case CURLM_BAD_SOCKET:
+ return "Invalid socket argument";
+
+ case CURLM_UNKNOWN_OPTION:
+ return "Unknown option";
+
+ case CURLM_ADDED_ALREADY:
+ return "The easy handle is already added to a multi handle";
+
+ case CURLM_LAST:
+ break;
+ }
+
+ return "Unknown error";
+#else
+ if(error == CURLM_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(error) {
+ case CURLSHE_OK:
+ return "No error";
+
+ case CURLSHE_BAD_OPTION:
+ return "Unknown share option";
+
+ case CURLSHE_IN_USE:
+ return "Share currently in use";
+
+ case CURLSHE_INVALID:
+ return "Invalid share handle";
+
+ case CURLSHE_NOMEM:
+ return "Out of memory";
+
+ case CURLSHE_NOT_BUILT_IN:
+ return "Feature not enabled in this library";
+
+ case CURLSHE_LAST:
+ break;
+ }
+
+ return "CURLSHcode unknown";
+#else
+ if(error == CURLSHE_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/* This function handles most / all (?) Winsock errors curl is able to produce.
+ */
+static const char *
+get_winsock_error (int err, char *buf, size_t len)
+{
+ const char *p;
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch(err) {
+ case WSAEINTR:
+ p = "Call interrupted";
+ break;
+ case WSAEBADF:
+ p = "Bad file";
+ break;
+ case WSAEACCES:
+ p = "Bad access";
+ break;
+ case WSAEFAULT:
+ p = "Bad argument";
+ break;
+ case WSAEINVAL:
+ p = "Invalid arguments";
+ break;
+ case WSAEMFILE:
+ p = "Out of file descriptors";
+ break;
+ case WSAEWOULDBLOCK:
+ p = "Call would block";
+ break;
+ case WSAEINPROGRESS:
+ case WSAEALREADY:
+ p = "Blocking call in progress";
+ break;
+ case WSAENOTSOCK:
+ p = "Descriptor is not a socket";
+ break;
+ case WSAEDESTADDRREQ:
+ p = "Need destination address";
+ break;
+ case WSAEMSGSIZE:
+ p = "Bad message size";
+ break;
+ case WSAEPROTOTYPE:
+ p = "Bad protocol";
+ break;
+ case WSAENOPROTOOPT:
+ p = "Protocol option is unsupported";
+ break;
+ case WSAEPROTONOSUPPORT:
+ p = "Protocol is unsupported";
+ break;
+ case WSAESOCKTNOSUPPORT:
+ p = "Socket is unsupported";
+ break;
+ case WSAEOPNOTSUPP:
+ p = "Operation not supported";
+ break;
+ case WSAEAFNOSUPPORT:
+ p = "Address family not supported";
+ break;
+ case WSAEPFNOSUPPORT:
+ p = "Protocol family not supported";
+ break;
+ case WSAEADDRINUSE:
+ p = "Address already in use";
+ break;
+ case WSAEADDRNOTAVAIL:
+ p = "Address not available";
+ break;
+ case WSAENETDOWN:
+ p = "Network down";
+ break;
+ case WSAENETUNREACH:
+ p = "Network unreachable";
+ break;
+ case WSAENETRESET:
+ p = "Network has been reset";
+ break;
+ case WSAECONNABORTED:
+ p = "Connection was aborted";
+ break;
+ case WSAECONNRESET:
+ p = "Connection was reset";
+ break;
+ case WSAENOBUFS:
+ p = "No buffer space";
+ break;
+ case WSAEISCONN:
+ p = "Socket is already connected";
+ break;
+ case WSAENOTCONN:
+ p = "Socket is not connected";
+ break;
+ case WSAESHUTDOWN:
+ p = "Socket has been shut down";
+ break;
+ case WSAETOOMANYREFS:
+ p = "Too many references";
+ break;
+ case WSAETIMEDOUT:
+ p = "Timed out";
+ break;
+ case WSAECONNREFUSED:
+ p = "Connection refused";
+ break;
+ case WSAELOOP:
+ p = "Loop??";
+ break;
+ case WSAENAMETOOLONG:
+ p = "Name too long";
+ break;
+ case WSAEHOSTDOWN:
+ p = "Host down";
+ break;
+ case WSAEHOSTUNREACH:
+ p = "Host unreachable";
+ break;
+ case WSAENOTEMPTY:
+ p = "Not empty";
+ break;
+ case WSAEPROCLIM:
+ p = "Process limit reached";
+ break;
+ case WSAEUSERS:
+ p = "Too many users";
+ break;
+ case WSAEDQUOT:
+ p = "Bad quota";
+ break;
+ case WSAESTALE:
+ p = "Something is stale";
+ break;
+ case WSAEREMOTE:
+ p = "Remote error";
+ break;
+#ifdef WSAEDISCON /* missing in SalfordC! */
+ case WSAEDISCON:
+ p = "Disconnected";
+ break;
+#endif
+ /* Extended Winsock errors */
+ case WSASYSNOTREADY:
+ p = "Winsock library is not ready";
+ break;
+ case WSANOTINITIALISED:
+ p = "Winsock library not initialised";
+ break;
+ case WSAVERNOTSUPPORTED:
+ p = "Winsock version not supported";
+ break;
+
+ /* getXbyY() errors (already handled in herrmsg):
+ * Authoritative Answer: Host not found */
+ case WSAHOST_NOT_FOUND:
+ p = "Host not found";
+ break;
+
+ /* Non-Authoritative: Host not found, or SERVERFAIL */
+ case WSATRY_AGAIN:
+ p = "Host not found, try again";
+ break;
+
+ /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+ case WSANO_RECOVERY:
+ p = "Unrecoverable error in call to nameserver";
+ break;
+
+ /* Valid name, no data record of requested type */
+ case WSANO_DATA:
+ p = "No data record of requested type";
+ break;
+
+ default:
+ return NULL;
+ }
+#else
+ if(!err)
+ return NULL;
+ else
+ p = "error";
+#endif
+ strncpy(buf, p, len);
+ buf [len-1] = '\0';
+ return buf;
+}
+#endif /* USE_WINSOCK */
+
+/*
+ * Our thread-safe and smart strerror() replacement.
+ *
+ * The 'err' argument passed in to this function MUST be a true errno number
+ * as reported on this system. We do no range checking on the number before
+ * we pass it to the "number-to-message" conversion function and there might
+ * be systems that don't do proper range checking in there themselves.
+ *
+ * We don't do range checking (on systems other than Windows) since there is
+ * no good reliable and portable way to do it.
+ */
+const char *Curl_strerror(struct connectdata *conn, int err)
+{
+ char *buf, *p;
+ size_t max;
+ int old_errno = ERRNO;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(err >= 0);
+
+ buf = conn->syserr_buf;
+ max = sizeof(conn->syserr_buf)-1;
+ *buf = '\0';
+
+#ifdef USE_WINSOCK
+
+#ifdef _WIN32_WCE
+ {
+ wchar_t wbuf[256];
+ wbuf[0] = L'\0';
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL);
+ wcstombs(buf, wbuf, max);
+ }
+#else
+ /* 'sys_nerr' is the maximum errno number, it is not widely portable */
+ if(err >= 0 && err < sys_nerr)
+ strncpy(buf, strerror(err), max);
+ else {
+ if(!get_winsock_error(err, buf, max) &&
+ !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ LANG_NEUTRAL, buf, (DWORD)max, NULL))
+ snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+ }
+#endif
+
+#else /* not USE_WINSOCK coming up */
+
+#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+ /*
+ * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
+ * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
+ * message string, or EINVAL if 'errnum' is not a valid error number.
+ */
+ if(0 != strerror_r(err, buf, max)) {
+ if('\0' == buf[0])
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
+ /*
+ * The glibc-style strerror_r() only *might* use the buffer we pass to
+ * the function, but it always returns the error message as a pointer,
+ * so we must copy that string unconditionally (if non-NULL).
+ */
+ {
+ char buffer[256];
+ char *msg = strerror_r(err, buffer, sizeof(buffer));
+ if(msg)
+ strncpy(buf, msg, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)
+ /*
+ * The vxworks-style strerror_r() does use the buffer we pass to the function.
+ * The buffer size should be at least NAME_MAX (256)
+ */
+ {
+ char buffer[256];
+ if(OK == strerror_r(err, buffer))
+ strncpy(buf, buffer, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#else
+ {
+ char *msg = strerror(err);
+ if(msg)
+ strncpy(buf, msg, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#endif
+
+#endif /* end of ! USE_WINSOCK */
+
+ buf[max] = '\0'; /* make sure the string is zero terminated */
+
+ /* strip trailing '\r\n' or '\n'. */
+ p = strrchr(buf, '\n');
+ if(p && (p - buf) >= 2)
+ *p = '\0';
+ p = strrchr(buf, '\r');
+ if(p && (p - buf) >= 1)
+ *p = '\0';
+
+ if(old_errno != ERRNO)
+ SET_ERRNO(old_errno);
+
+ return buf;
+}
+
+#ifdef USE_WINDOWS_SSPI
+const char *Curl_sspi_strerror (struct connectdata *conn, int err)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ char txtbuf[80];
+ char msgbuf[sizeof(conn->syserr_buf)];
+ char *p, *str, *msg = NULL;
+ bool msg_formatted = FALSE;
+ int old_errno;
+#endif
+ const char *txt;
+ char *outbuf;
+ size_t outmax;
+
+ DEBUGASSERT(conn);
+
+ outbuf = conn->syserr_buf;
+ outmax = sizeof(conn->syserr_buf)-1;
+ *outbuf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+
+ old_errno = ERRNO;
+
+ switch(err) {
+ case SEC_E_OK:
+ txt = "No error";
+ break;
+ case CRYPT_E_REVOKED:
+ txt = "CRYPT_E_REVOKED";
+ break;
+ case SEC_E_ALGORITHM_MISMATCH:
+ txt = "SEC_E_ALGORITHM_MISMATCH";
+ break;
+ case SEC_E_BAD_BINDINGS:
+ txt = "SEC_E_BAD_BINDINGS";
+ break;
+ case SEC_E_BAD_PKGID:
+ txt = "SEC_E_BAD_PKGID";
+ break;
+ case SEC_E_BUFFER_TOO_SMALL:
+ txt = "SEC_E_BUFFER_TOO_SMALL";
+ break;
+ case SEC_E_CANNOT_INSTALL:
+ txt = "SEC_E_CANNOT_INSTALL";
+ break;
+ case SEC_E_CANNOT_PACK:
+ txt = "SEC_E_CANNOT_PACK";
+ break;
+ case SEC_E_CERT_EXPIRED:
+ txt = "SEC_E_CERT_EXPIRED";
+ break;
+ case SEC_E_CERT_UNKNOWN:
+ txt = "SEC_E_CERT_UNKNOWN";
+ break;
+ case SEC_E_CERT_WRONG_USAGE:
+ txt = "SEC_E_CERT_WRONG_USAGE";
+ break;
+ case SEC_E_CONTEXT_EXPIRED:
+ txt = "SEC_E_CONTEXT_EXPIRED";
+ break;
+ case SEC_E_CROSSREALM_DELEGATION_FAILURE:
+ txt = "SEC_E_CROSSREALM_DELEGATION_FAILURE";
+ break;
+ case SEC_E_CRYPTO_SYSTEM_INVALID:
+ txt = "SEC_E_CRYPTO_SYSTEM_INVALID";
+ break;
+ case SEC_E_DECRYPT_FAILURE:
+ txt = "SEC_E_DECRYPT_FAILURE";
+ break;
+ case SEC_E_DELEGATION_POLICY:
+ txt = "SEC_E_DELEGATION_POLICY";
+ break;
+ case SEC_E_DELEGATION_REQUIRED:
+ txt = "SEC_E_DELEGATION_REQUIRED";
+ break;
+ case SEC_E_DOWNGRADE_DETECTED:
+ txt = "SEC_E_DOWNGRADE_DETECTED";
+ break;
+ case SEC_E_ENCRYPT_FAILURE:
+ txt = "SEC_E_ENCRYPT_FAILURE";
+ break;
+ case SEC_E_ILLEGAL_MESSAGE:
+ txt = "SEC_E_ILLEGAL_MESSAGE";
+ break;
+ case SEC_E_INCOMPLETE_CREDENTIALS:
+ txt = "SEC_E_INCOMPLETE_CREDENTIALS";
+ break;
+ case SEC_E_INCOMPLETE_MESSAGE:
+ txt = "SEC_E_INCOMPLETE_MESSAGE";
+ break;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ txt = "SEC_E_INSUFFICIENT_MEMORY";
+ break;
+ case SEC_E_INTERNAL_ERROR:
+ txt = "SEC_E_INTERNAL_ERROR";
+ break;
+ case SEC_E_INVALID_HANDLE:
+ txt = "SEC_E_INVALID_HANDLE";
+ break;
+ case SEC_E_INVALID_PARAMETER:
+ txt = "SEC_E_INVALID_PARAMETER";
+ break;
+ case SEC_E_INVALID_TOKEN:
+ txt = "SEC_E_INVALID_TOKEN";
+ break;
+ case SEC_E_ISSUING_CA_UNTRUSTED:
+ txt = "SEC_E_ISSUING_CA_UNTRUSTED";
+ break;
+ case SEC_E_ISSUING_CA_UNTRUSTED_KDC:
+ txt = "SEC_E_ISSUING_CA_UNTRUSTED_KDC";
+ break;
+ case SEC_E_KDC_CERT_EXPIRED:
+ txt = "SEC_E_KDC_CERT_EXPIRED";
+ break;
+ case SEC_E_KDC_CERT_REVOKED:
+ txt = "SEC_E_KDC_CERT_REVOKED";
+ break;
+ case SEC_E_KDC_INVALID_REQUEST:
+ txt = "SEC_E_KDC_INVALID_REQUEST";
+ break;
+ case SEC_E_KDC_UNABLE_TO_REFER:
+ txt = "SEC_E_KDC_UNABLE_TO_REFER";
+ break;
+ case SEC_E_KDC_UNKNOWN_ETYPE:
+ txt = "SEC_E_KDC_UNKNOWN_ETYPE";
+ break;
+ case SEC_E_LOGON_DENIED:
+ txt = "SEC_E_LOGON_DENIED";
+ break;
+ case SEC_E_MAX_REFERRALS_EXCEEDED:
+ txt = "SEC_E_MAX_REFERRALS_EXCEEDED";
+ break;
+ case SEC_E_MESSAGE_ALTERED:
+ txt = "SEC_E_MESSAGE_ALTERED";
+ break;
+ case SEC_E_MULTIPLE_ACCOUNTS:
+ txt = "SEC_E_MULTIPLE_ACCOUNTS";
+ break;
+ case SEC_E_MUST_BE_KDC:
+ txt = "SEC_E_MUST_BE_KDC";
+ break;
+ case SEC_E_NOT_OWNER:
+ txt = "SEC_E_NOT_OWNER";
+ break;
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ txt = "SEC_E_NO_AUTHENTICATING_AUTHORITY";
+ break;
+ case SEC_E_NO_CREDENTIALS:
+ txt = "SEC_E_NO_CREDENTIALS";
+ break;
+ case SEC_E_NO_IMPERSONATION:
+ txt = "SEC_E_NO_IMPERSONATION";
+ break;
+ case SEC_E_NO_IP_ADDRESSES:
+ txt = "SEC_E_NO_IP_ADDRESSES";
+ break;
+ case SEC_E_NO_KERB_KEY:
+ txt = "SEC_E_NO_KERB_KEY";
+ break;
+ case SEC_E_NO_PA_DATA:
+ txt = "SEC_E_NO_PA_DATA";
+ break;
+ case SEC_E_NO_S4U_PROT_SUPPORT:
+ txt = "SEC_E_NO_S4U_PROT_SUPPORT";
+ break;
+ case SEC_E_NO_TGT_REPLY:
+ txt = "SEC_E_NO_TGT_REPLY";
+ break;
+ case SEC_E_OUT_OF_SEQUENCE:
+ txt = "SEC_E_OUT_OF_SEQUENCE";
+ break;
+ case SEC_E_PKINIT_CLIENT_FAILURE:
+ txt = "SEC_E_PKINIT_CLIENT_FAILURE";
+ break;
+ case SEC_E_PKINIT_NAME_MISMATCH:
+ txt = "SEC_E_PKINIT_NAME_MISMATCH";
+ break;
+ case SEC_E_POLICY_NLTM_ONLY:
+ txt = "SEC_E_POLICY_NLTM_ONLY";
+ break;
+ case SEC_E_QOP_NOT_SUPPORTED:
+ txt = "SEC_E_QOP_NOT_SUPPORTED";
+ break;
+ case SEC_E_REVOCATION_OFFLINE_C:
+ txt = "SEC_E_REVOCATION_OFFLINE_C";
+ break;
+ case SEC_E_REVOCATION_OFFLINE_KDC:
+ txt = "SEC_E_REVOCATION_OFFLINE_KDC";
+ break;
+ case SEC_E_SECPKG_NOT_FOUND:
+ txt = "SEC_E_SECPKG_NOT_FOUND";
+ break;
+ case SEC_E_SECURITY_QOS_FAILED:
+ txt = "SEC_E_SECURITY_QOS_FAILED";
+ break;
+ case SEC_E_SHUTDOWN_IN_PROGRESS:
+ txt = "SEC_E_SHUTDOWN_IN_PROGRESS";
+ break;
+ case SEC_E_SMARTCARD_CERT_EXPIRED:
+ txt = "SEC_E_SMARTCARD_CERT_EXPIRED";
+ break;
+ case SEC_E_SMARTCARD_CERT_REVOKED:
+ txt = "SEC_E_SMARTCARD_CERT_REVOKED";
+ break;
+ case SEC_E_SMARTCARD_LOGON_REQUIRED:
+ txt = "SEC_E_SMARTCARD_LOGON_REQUIRED";
+ break;
+ case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED:
+ txt = "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
+ break;
+ case SEC_E_TARGET_UNKNOWN:
+ txt = "SEC_E_TARGET_UNKNOWN";
+ break;
+ case SEC_E_TIME_SKEW:
+ txt = "SEC_E_TIME_SKEW";
+ break;
+ case SEC_E_TOO_MANY_PRINCIPALS:
+ txt = "SEC_E_TOO_MANY_PRINCIPALS";
+ break;
+ case SEC_E_UNFINISHED_CONTEXT_DELETED:
+ txt = "SEC_E_UNFINISHED_CONTEXT_DELETED";
+ break;
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ txt = "SEC_E_UNKNOWN_CREDENTIALS";
+ break;
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ txt = "SEC_E_UNSUPPORTED_FUNCTION";
+ break;
+ case SEC_E_UNSUPPORTED_PREAUTH:
+ txt = "SEC_E_UNSUPPORTED_PREAUTH";
+ break;
+ case SEC_E_UNTRUSTED_ROOT:
+ txt = "SEC_E_UNTRUSTED_ROOT";
+ break;
+ case SEC_E_WRONG_CREDENTIAL_HANDLE:
+ txt = "SEC_E_WRONG_CREDENTIAL_HANDLE";
+ break;
+ case SEC_E_WRONG_PRINCIPAL:
+ txt = "SEC_E_WRONG_PRINCIPAL";
+ break;
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ txt = "SEC_I_COMPLETE_AND_CONTINUE";
+ break;
+ case SEC_I_COMPLETE_NEEDED:
+ txt = "SEC_I_COMPLETE_NEEDED";
+ break;
+ case SEC_I_CONTEXT_EXPIRED:
+ txt = "SEC_I_CONTEXT_EXPIRED";
+ break;
+ case SEC_I_CONTINUE_NEEDED:
+ txt = "SEC_I_CONTINUE_NEEDED";
+ break;
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ txt = "SEC_I_INCOMPLETE_CREDENTIALS";
+ break;
+ case SEC_I_LOCAL_LOGON:
+ txt = "SEC_I_LOCAL_LOGON";
+ break;
+ case SEC_I_NO_LSA_CONTEXT:
+ txt = "SEC_I_NO_LSA_CONTEXT";
+ break;
+ case SEC_I_RENEGOTIATE:
+ txt = "SEC_I_RENEGOTIATE";
+ break;
+ case SEC_I_SIGNATURE_NEEDED:
+ txt = "SEC_I_SIGNATURE_NEEDED";
+ break;
+ default:
+ txt = "Unknown error";
+ }
+
+ if(err == SEC_E_OK)
+ strncpy(outbuf, txt, outmax);
+ else if(err == SEC_E_ILLEGAL_MESSAGE)
+ snprintf(outbuf, outmax,
+ "SEC_E_ILLEGAL_MESSAGE (0x%08X) - This error usually occurs "
+ "when a fatal SSL/TLS alert is received (e.g. handshake failed). "
+ "More detail may be available in the Windows System event log.",
+ err);
+ else {
+ str = txtbuf;
+ snprintf(txtbuf, sizeof(txtbuf), "%s (0x%08X)", txt, err);
+ txtbuf[sizeof(txtbuf)-1] = '\0';
+
+#ifdef _WIN32_WCE
+ {
+ wchar_t wbuf[256];
+ wbuf[0] = L'\0';
+
+ if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, LANG_NEUTRAL,
+ wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
+ wcstombs(msgbuf, wbuf, sizeof(msgbuf)-1);
+ msg_formatted = TRUE;
+ }
+ }
+#else
+ if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, LANG_NEUTRAL,
+ msgbuf, sizeof(msgbuf)-1, NULL)) {
+ msg_formatted = TRUE;
+ }
+#endif
+ if(msg_formatted) {
+ msgbuf[sizeof(msgbuf)-1] = '\0';
+ /* strip trailing '\r\n' or '\n' */
+ p = strrchr(msgbuf, '\n');
+ if(p && (p - msgbuf) >= 2)
+ *p = '\0';
+ p = strrchr(msgbuf, '\r');
+ if(p && (p - msgbuf) >= 1)
+ *p = '\0';
+ msg = msgbuf;
+ }
+ if(msg)
+ snprintf(outbuf, outmax, "%s - %s", str, msg);
+ else
+ strncpy(outbuf, str, outmax);
+ }
+
+ if(old_errno != ERRNO)
+ SET_ERRNO(old_errno);
+
+#else
+
+ if(err == SEC_E_OK)
+ txt = "No error";
+ else
+ txt = "Error";
+
+ strncpy(outbuf, txt, outmax);
+
+#endif
+
+ outbuf[outmax] = '\0';
+
+ return outbuf;
+}
+#endif /* USE_WINDOWS_SSPI */
diff --git a/Utilities/cmcurl/lib/strerror.h b/Utilities/cmcurl/lib/strerror.h
new file mode 100644
index 000000000..627273eb2
--- /dev/null
+++ b/Utilities/cmcurl/lib/strerror.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_STRERROR_H
+#define HEADER_CURL_STRERROR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "urldata.h"
+
+const char *Curl_strerror (struct connectdata *conn, int err);
+
+#ifdef USE_LIBIDN2
+const char *Curl_idn_strerror (struct connectdata *conn, int err);
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+const char *Curl_sspi_strerror (struct connectdata *conn, int err);
+#endif
+
+#endif /* HEADER_CURL_STRERROR_H */
diff --git a/Utilities/cmcurl/lib/strtok.c b/Utilities/cmcurl/lib/strtok.c
new file mode 100644
index 000000000..460eb87e5
--- /dev/null
+++ b/Utilities/cmcurl/lib/strtok.c
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef HAVE_STRTOK_R
+#include <stddef.h>
+
+#include "strtok.h"
+
+char *
+Curl_strtok_r(char *ptr, const char *sep, char **end)
+{
+ if(!ptr)
+ /* we got NULL input so then we get our last position instead */
+ ptr = *end;
+
+ /* pass all letters that are including in the separator string */
+ while(*ptr && strchr(sep, *ptr))
+ ++ptr;
+
+ if(*ptr) {
+ /* so this is where the next piece of string starts */
+ char *start = ptr;
+
+ /* set the end pointer to the first byte after the start */
+ *end = start + 1;
+
+ /* scan through the string to find where it ends, it ends on a
+ null byte or a character that exists in the separator string */
+ while(**end && !strchr(sep, **end))
+ ++*end;
+
+ if(**end) {
+ /* the end is not a null byte */
+ **end = '\0'; /* zero terminate it! */
+ ++*end; /* advance the last pointer to beyond the null byte */
+ }
+
+ return start; /* return the position where the string starts */
+ }
+
+ /* we ended up on a null byte, there are no more strings to find! */
+ return NULL;
+}
+
+#endif /* this was only compiled if strtok_r wasn't present */
diff --git a/Utilities/cmcurl/lib/strtok.h b/Utilities/cmcurl/lib/strtok.h
new file mode 100644
index 000000000..90b831eb6
--- /dev/null
+++ b/Utilities/cmcurl/lib/strtok.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_STRTOK_H
+#define HEADER_CURL_STRTOK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+#include <stddef.h>
+
+#ifndef HAVE_STRTOK_R
+char *Curl_strtok_r(char *s, const char *delim, char **last);
+#define strtok_r Curl_strtok_r
+#else
+#include <string.h>
+#endif
+
+#endif /* HEADER_CURL_STRTOK_H */
diff --git a/Utilities/cmcurl/lib/strtoofft.c b/Utilities/cmcurl/lib/strtoofft.c
new file mode 100644
index 000000000..b854bf4de
--- /dev/null
+++ b/Utilities/cmcurl/lib/strtoofft.c
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "strtoofft.h"
+
+/*
+ * NOTE:
+ *
+ * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
+ * could use in case strtoll() doesn't exist... See
+ * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
+ */
+
+#ifdef NEED_CURL_STRTOLL
+
+/* Range tests can be used for alphanum decoding if characters are consecutive,
+ like in ASCII. Else an array is scanned. Determine this condition now. */
+
+#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
+
+#define NO_RANGE_TEST
+
+static const char valchars[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+#endif
+
+static int get_char(char c, int base);
+
+/**
+ * Emulated version of the strtoll function. This extracts a long long
+ * value from the given input string and returns it.
+ */
+curl_off_t
+curlx_strtoll(const char *nptr, char **endptr, int base)
+{
+ char *end;
+ int is_negative = 0;
+ int overflow;
+ int i;
+ curl_off_t value = 0;
+ curl_off_t newval;
+
+ /* Skip leading whitespace. */
+ end = (char *)nptr;
+ while(ISSPACE(end[0])) {
+ end++;
+ }
+
+ /* Handle the sign, if any. */
+ if(end[0] == '-') {
+ is_negative = 1;
+ end++;
+ }
+ else if(end[0] == '+') {
+ end++;
+ }
+ else if(end[0] == '\0') {
+ /* We had nothing but perhaps some whitespace -- there was no number. */
+ if(endptr) {
+ *endptr = end;
+ }
+ return 0;
+ }
+
+ /* Handle special beginnings, if present and allowed. */
+ if(end[0] == '0' && end[1] == 'x') {
+ if(base == 16 || base == 0) {
+ end += 2;
+ base = 16;
+ }
+ }
+ else if(end[0] == '0') {
+ if(base == 8 || base == 0) {
+ end++;
+ base = 8;
+ }
+ }
+
+ /* Matching strtol, if the base is 0 and it doesn't look like
+ * the number is octal or hex, we assume it's base 10.
+ */
+ if(base == 0) {
+ base = 10;
+ }
+
+ /* Loop handling digits. */
+ value = 0;
+ overflow = 0;
+ for(i = get_char(end[0], base);
+ i != -1;
+ end++, i = get_char(end[0], base)) {
+ newval = base * value + i;
+ if(newval < value) {
+ /* We've overflowed. */
+ overflow = 1;
+ break;
+ }
+ else
+ value = newval;
+ }
+
+ if(!overflow) {
+ if(is_negative) {
+ /* Fix the sign. */
+ value *= -1;
+ }
+ }
+ else {
+ if(is_negative)
+ value = CURL_OFF_T_MIN;
+ else
+ value = CURL_OFF_T_MAX;
+
+ SET_ERRNO(ERANGE);
+ }
+
+ if(endptr)
+ *endptr = end;
+
+ return value;
+}
+
+/**
+ * Returns the value of c in the given base, or -1 if c cannot
+ * be interpreted properly in that base (i.e., is out of range,
+ * is a null, etc.).
+ *
+ * @param c the character to interpret according to base
+ * @param base the base in which to interpret c
+ *
+ * @return the value of c in base, or -1 if c isn't in range
+ */
+static int get_char(char c, int base)
+{
+#ifndef NO_RANGE_TEST
+ int value = -1;
+ if(c <= '9' && c >= '0') {
+ value = c - '0';
+ }
+ else if(c <= 'Z' && c >= 'A') {
+ value = c - 'A' + 10;
+ }
+ else if(c <= 'z' && c >= 'a') {
+ value = c - 'a' + 10;
+ }
+#else
+ const char *cp;
+ int value;
+
+ cp = memchr(valchars, c, 10 + 26 + 26);
+
+ if(!cp)
+ return -1;
+
+ value = cp - valchars;
+
+ if(value >= 10 + 26)
+ value -= 26; /* Lowercase. */
+#endif
+
+ if(value >= base) {
+ value = -1;
+ }
+
+ return value;
+}
+#endif /* Only present if we need strtoll, but don't have it. */
diff --git a/Utilities/cmcurl/lib/strtoofft.h b/Utilities/cmcurl/lib/strtoofft.h
new file mode 100644
index 000000000..f4039f3a3
--- /dev/null
+++ b/Utilities/cmcurl/lib/strtoofft.h
@@ -0,0 +1,75 @@
+#ifndef HEADER_CURL_STRTOOFFT_H
+#define HEADER_CURL_STRTOOFFT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/*
+ * Determine which string to integral data type conversion function we use
+ * to implement string conversion to our curl_off_t integral data type.
+ *
+ * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
+ * an underlying data type which might be 'long', 'int64_t', 'long long' or
+ * '__int64' and more remotely other data types.
+ *
+ * On systems where the size of curl_off_t is greater than the size of 'long'
+ * the conversion function to use is strtoll() if it is available, otherwise,
+ * we emulate its functionality with our own clone.
+ *
+ * On systems where the size of curl_off_t is smaller or equal than the size
+ * of 'long' the conversion function to use is strtol().
+ */
+
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+# ifdef HAVE_STRTOLL
+# define curlx_strtoofft strtoll
+# else
+# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
+# if defined(_SAL_VERSION)
+ _Check_return_ _CRTIMP __int64 __cdecl _strtoi64(
+ _In_z_ const char *_String,
+ _Out_opt_ _Deref_post_z_ char **_EndPtr, _In_ int _Radix);
+# else
+ _CRTIMP __int64 __cdecl _strtoi64(const char *_String,
+ char **_EndPtr, int _Radix);
+# endif
+# define curlx_strtoofft _strtoi64
+# else
+ curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
+# define curlx_strtoofft curlx_strtoll
+# define NEED_CURL_STRTOLL 1
+# endif
+# endif
+#else
+# define curlx_strtoofft strtol
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T == 4)
+# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
+#else
+ /* assume CURL_SIZEOF_CURL_OFF_T == 8 */
+# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+#endif
+#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
+
+#endif /* HEADER_CURL_STRTOOFFT_H */
diff --git a/Utilities/cmcurl/lib/system_win32.c b/Utilities/cmcurl/lib/system_win32.c
new file mode 100644
index 000000000..cfbbf3279
--- /dev/null
+++ b/Utilities/cmcurl/lib/system_win32.c
@@ -0,0 +1,329 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(WIN32)
+
+#include <curl/curl.h>
+#include "system_win32.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+ defined(USE_WINSOCK))
+
+
+#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
+#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
+#endif
+
+#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
+#endif
+
+/* We use our own typedef here since some headers might lack these */
+typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
+
+/* See function definitions in winbase.h */
+#ifdef UNICODE
+# ifdef _WIN32_WCE
+# define LOADLIBARYEX L"LoadLibraryExW"
+# else
+# define LOADLIBARYEX "LoadLibraryExW"
+# endif
+#else
+# define LOADLIBARYEX "LoadLibraryExA"
+#endif
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+/*
+ * Curl_verify_windows_version()
+ *
+ * This is used to verify if we are running on a specific windows version.
+ *
+ * Parameters:
+ *
+ * majorVersion [in] - The major version number.
+ * minorVersion [in] - The minor version number.
+ * platform [in] - The optional platform identifier.
+ * condition [in] - The test condition used to specifier whether we are
+ * checking a version less then, equal to or greater than
+ * what is specified in the major and minor version
+ * numbers.
+ *
+ * Returns TRUE if matched; otherwise FALSE.
+ */
+bool Curl_verify_windows_version(const unsigned int majorVersion,
+ const unsigned int minorVersion,
+ const PlatformIdentifier platform,
+ const VersionCondition condition)
+{
+ bool matched = FALSE;
+
+#if defined(CURL_WINDOWS_APP)
+ /* We have no way to determine the Windows version from Windows apps,
+ so let's assume we're running on the target Windows version. */
+ const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
+ const WORD targetVersion = (WORD)_WIN32_WINNT;
+
+ switch(condition) {
+ case VERSION_LESS_THAN:
+ matched = targetVersion < fullVersion;
+ break;
+
+ case VERSION_LESS_THAN_EQUAL:
+ matched = targetVersion <= fullVersion;
+ break;
+
+ case VERSION_EQUAL:
+ matched = targetVersion == fullVersion;
+ break;
+
+ case VERSION_GREATER_THAN_EQUAL:
+ matched = targetVersion >= fullVersion;
+ break;
+
+ case VERSION_GREATER_THAN:
+ matched = targetVersion > fullVersion;
+ break;
+ }
+
+ if(matched && (platform == PLATFORM_WINDOWS)) {
+ /* we're always running on PLATFORM_WINNT */
+ matched = FALSE;
+ }
+#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
+ (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
+ OSVERSIONINFO osver;
+
+ memset(&osver, 0, sizeof(osver));
+ osver.dwOSVersionInfoSize = sizeof(osver);
+
+ /* Find out Windows version */
+ if(GetVersionEx(&osver)) {
+ /* Verify the Operating System version number */
+ switch(condition) {
+ case VERSION_LESS_THAN:
+ if(osver.dwMajorVersion < majorVersion ||
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion < minorVersion))
+ matched = TRUE;
+ break;
+
+ case VERSION_LESS_THAN_EQUAL:
+ if(osver.dwMajorVersion <= majorVersion &&
+ osver.dwMinorVersion <= minorVersion)
+ matched = TRUE;
+ break;
+
+ case VERSION_EQUAL:
+ if(osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion == minorVersion)
+ matched = TRUE;
+ break;
+
+ case VERSION_GREATER_THAN_EQUAL:
+ if(osver.dwMajorVersion >= majorVersion &&
+ osver.dwMinorVersion >= minorVersion)
+ matched = TRUE;
+ break;
+
+ case VERSION_GREATER_THAN:
+ if(osver.dwMajorVersion > majorVersion ||
+ (osver.dwMajorVersion == majorVersion &&
+ osver.dwMinorVersion > minorVersion))
+ matched = TRUE;
+ break;
+ }
+
+ /* Verify the platform identifier (if necessary) */
+ if(matched) {
+ switch(platform) {
+ case PLATFORM_WINDOWS:
+ if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
+ matched = FALSE;
+ break;
+
+ case PLATFORM_WINNT:
+ if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ matched = FALSE;
+
+ default: /* like platform == PLATFORM_DONT_CARE */
+ break;
+ }
+ }
+ }
+#else
+ ULONGLONG cm = 0;
+ OSVERSIONINFOEX osver;
+ BYTE majorCondition;
+ BYTE minorCondition;
+ BYTE spMajorCondition;
+ BYTE spMinorCondition;
+
+ switch(condition) {
+ case VERSION_LESS_THAN:
+ majorCondition = VER_LESS;
+ minorCondition = VER_LESS;
+ spMajorCondition = VER_LESS_EQUAL;
+ spMinorCondition = VER_LESS_EQUAL;
+ break;
+
+ case VERSION_LESS_THAN_EQUAL:
+ majorCondition = VER_LESS_EQUAL;
+ minorCondition = VER_LESS_EQUAL;
+ spMajorCondition = VER_LESS_EQUAL;
+ spMinorCondition = VER_LESS_EQUAL;
+ break;
+
+ case VERSION_EQUAL:
+ majorCondition = VER_EQUAL;
+ minorCondition = VER_EQUAL;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ case VERSION_GREATER_THAN_EQUAL:
+ majorCondition = VER_GREATER_EQUAL;
+ minorCondition = VER_GREATER_EQUAL;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ case VERSION_GREATER_THAN:
+ majorCondition = VER_GREATER;
+ minorCondition = VER_GREATER;
+ spMajorCondition = VER_GREATER_EQUAL;
+ spMinorCondition = VER_GREATER_EQUAL;
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ memset(&osver, 0, sizeof(osver));
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ osver.dwMajorVersion = majorVersion;
+ osver.dwMinorVersion = minorVersion;
+ if(platform == PLATFORM_WINDOWS)
+ osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+ else if(platform == PLATFORM_WINNT)
+ osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+ cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
+ cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
+ cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
+ if(platform != PLATFORM_DONT_CARE)
+ cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+
+ if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
+ cm))
+ matched = TRUE;
+#endif
+
+ return matched;
+}
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+ defined(USE_WINSOCK))
+
+/*
+ * Curl_load_library()
+ *
+ * This is used to dynamically load DLLs using the most secure method available
+ * for the version of Windows that we are running on.
+ *
+ * Parameters:
+ *
+ * filename [in] - The filename or full path of the DLL to load. If only the
+ * filename is passed then the DLL will be loaded from the
+ * Windows system directory.
+ *
+ * Returns the handle of the module on success; otherwise NULL.
+ */
+HMODULE Curl_load_library(LPCTSTR filename)
+{
+ HMODULE hModule = NULL;
+ LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
+
+ /* Get a handle to kernel32 so we can access it's functions at runtime */
+ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
+ if(!hKernel32)
+ return NULL;
+
+ /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
+ and above */
+ pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX);
+
+ /* Detect if there's already a path in the filename and load the library if
+ there is. Note: Both back slashes and forward slashes have been supported
+ since the earlier days of DOS at an API level although they are not
+ supported by command prompt */
+ if(_tcspbrk(filename, TEXT("\\/"))) {
+ /** !checksrc! disable BANNEDFUNC 1 **/
+ hModule = pLoadLibraryEx ?
+ pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+ LoadLibrary(filename);
+ }
+ /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
+ supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
+ Server 2008 R2 with this patch or natively on Windows 8 and above */
+ else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
+ /* Load the DLL from the Windows system directory */
+ hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ }
+ else {
+ /* Attempt to get the Windows system path */
+ UINT systemdirlen = GetSystemDirectory(NULL, 0);
+ if(systemdirlen) {
+ /* Allocate space for the full DLL path (Room for the null terminator
+ is included in systemdirlen) */
+ size_t filenamelen = _tcslen(filename);
+ TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
+ if(path && GetSystemDirectory(path, systemdirlen)) {
+ /* Calculate the full DLL path */
+ _tcscpy(path + _tcslen(path), TEXT("\\"));
+ _tcscpy(path + _tcslen(path), filename);
+
+ /* Load the DLL from the Windows system directory */
+ /** !checksrc! disable BANNEDFUNC 1 **/
+ hModule = pLoadLibraryEx ?
+ pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+ LoadLibrary(path);
+
+ }
+ free(path);
+ }
+ }
+
+ return hModule;
+}
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+#endif /* WIN32 */
diff --git a/Utilities/cmcurl/lib/system_win32.h b/Utilities/cmcurl/lib/system_win32.h
new file mode 100644
index 000000000..1e772856b
--- /dev/null
+++ b/Utilities/cmcurl/lib/system_win32.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SYSTEM_WIN32_H
+#define HEADER_CURL_SYSTEM_WIN32_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(WIN32)
+
+/* Version condition */
+typedef enum {
+ VERSION_LESS_THAN,
+ VERSION_LESS_THAN_EQUAL,
+ VERSION_EQUAL,
+ VERSION_GREATER_THAN_EQUAL,
+ VERSION_GREATER_THAN
+} VersionCondition;
+
+/* Platform identifier */
+typedef enum {
+ PLATFORM_DONT_CARE,
+ PLATFORM_WINDOWS,
+ PLATFORM_WINNT
+} PlatformIdentifier;
+
+/* This is used to verify if we are running on a specific windows version */
+bool Curl_verify_windows_version(const unsigned int majorVersion,
+ const unsigned int minorVersion,
+ const PlatformIdentifier platform,
+ const VersionCondition condition);
+
+#if defined(USE_WINDOWS_SSPI) || (!defined(CURL_DISABLE_TELNET) && \
+ defined(USE_WINSOCK))
+
+/* This is used to dynamically load DLLs */
+HMODULE Curl_load_library(LPCTSTR filename);
+
+#endif /* USE_WINDOWS_SSPI || (!CURL_DISABLE_TELNET && USE_WINSOCK) */
+
+#endif /* WIN32 */
+
+#endif /* HEADER_CURL_SYSTEM_WIN32_H */
diff --git a/Utilities/cmcurl/lib/telnet.c b/Utilities/cmcurl/lib/telnet.c
new file mode 100644
index 000000000..155d4b260
--- /dev/null
+++ b/Utilities/cmcurl/lib/telnet.c
@@ -0,0 +1,1698 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_TELNET
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "telnet.h"
+#include "connect.h"
+#include "progress.h"
+#include "system_win32.h"
+
+#define TELOPTS
+#define TELCMDS
+
+#include "arpa_telnet.h"
+#include "select.h"
+#include "strcase.h"
+#include "warnless.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SUBBUFSIZE 512
+
+#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
+#define CURL_SB_TERM(x) \
+ do { \
+ x->subend = x->subpointer; \
+ CURL_SB_CLEAR(x); \
+ } WHILE_FALSE
+#define CURL_SB_ACCUM(x,c) \
+ do { \
+ if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
+ *x->subpointer++ = (c); \
+ } WHILE_FALSE
+
+#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
+#define CURL_SB_LEN(x) (x->subend - x->subpointer)
+
+/* For posterity:
+#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
+#define CURL_SB_EOF(x) (x->subpointer >= x->subend) */
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define printoption(a,b,c,d) Curl_nop_stmt
+#endif
+
+#ifdef USE_WINSOCK
+typedef FARPROC WSOCK2_FUNC;
+static CURLcode check_wsock2(struct Curl_easy *data);
+#endif
+
+static
+CURLcode telrcv(struct connectdata *,
+ const unsigned char *inbuf, /* Data received from socket */
+ ssize_t count); /* Number of bytes received */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct Curl_easy *data,
+ const char *direction,
+ int cmd, int option);
+#endif
+
+static void negotiate(struct connectdata *);
+static void send_negotiation(struct connectdata *, int cmd, int option);
+static void set_local_option(struct connectdata *, int cmd, int option);
+static void set_remote_option(struct connectdata *, int cmd, int option);
+
+static void printsub(struct Curl_easy *data,
+ int direction, unsigned char *pointer,
+ size_t length);
+static void suboption(struct connectdata *);
+static void sendsuboption(struct connectdata *conn, int option);
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done);
+static CURLcode telnet_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode send_telnet_data(struct connectdata *conn,
+ char *buffer, ssize_t nread);
+
+/* For negotiation compliant to RFC 1143 */
+#define CURL_NO 0
+#define CURL_YES 1
+#define CURL_WANTYES 2
+#define CURL_WANTNO 3
+
+#define CURL_EMPTY 0
+#define CURL_OPPOSITE 1
+
+/*
+ * Telnet receiver states for fsm
+ */
+typedef enum
+{
+ CURL_TS_DATA = 0,
+ CURL_TS_IAC,
+ CURL_TS_WILL,
+ CURL_TS_WONT,
+ CURL_TS_DO,
+ CURL_TS_DONT,
+ CURL_TS_CR,
+ CURL_TS_SB, /* sub-option collection */
+ CURL_TS_SE /* looking for sub-option end */
+} TelnetReceive;
+
+struct TELNET {
+ int please_negotiate;
+ int already_negotiated;
+ int us[256];
+ int usq[256];
+ int us_preferred[256];
+ int him[256];
+ int himq[256];
+ int him_preferred[256];
+ int subnegotiation[256];
+ char subopt_ttype[32]; /* Set with suboption TTYPE */
+ char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
+ unsigned short subopt_wsx; /* Set with suboption NAWS */
+ unsigned short subopt_wsy; /* Set with suboption NAWS */
+ struct curl_slist *telnet_vars; /* Environment variables */
+
+ /* suboptions */
+ unsigned char subbuffer[SUBBUFSIZE];
+ unsigned char *subpointer, *subend; /* buffer for sub-options */
+
+ TelnetReceive telrcv_state;
+};
+
+
+/*
+ * TELNET protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_telnet = {
+ "TELNET", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ telnet_do, /* do_it */
+ telnet_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_TELNET, /* defport */
+ CURLPROTO_TELNET, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+#ifdef USE_WINSOCK
+static CURLcode
+check_wsock2(struct Curl_easy *data)
+{
+ int err;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ DEBUGASSERT(data);
+
+ /* telnet requires at least WinSock 2.0 so ask for it. */
+ wVersionRequested = MAKEWORD(2, 0);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ /* We must've called this once already, so this call */
+ /* should always succeed. But, just in case... */
+ if(err != 0) {
+ failf(data,"WSAStartup failed (%d)",err);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* We have to have a WSACleanup call for every successful */
+ /* WSAStartup call. */
+ WSACleanup();
+
+ /* Check that our version is supported */
+ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+ HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
+ /* Our version isn't supported */
+ failf(data, "insufficient winsock version to support "
+ "telnet");
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Our version is supported */
+ return CURLE_OK;
+}
+#endif
+
+static
+CURLcode init_telnet(struct connectdata *conn)
+{
+ struct TELNET *tn;
+
+ tn = calloc(1, sizeof(struct TELNET));
+ if(!tn)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->data->req.protop = tn; /* make us known */
+
+ tn->telrcv_state = CURL_TS_DATA;
+
+ /* Init suboptions */
+ CURL_SB_CLEAR(tn);
+
+ /* Set the options we want by default */
+ tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
+
+ /* To be compliant with previous releases of libcurl
+ we enable this option by default. This behaviour
+ can be changed thanks to the "BINARY" option in
+ CURLOPT_TELNETOPTIONS
+ */
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+
+ /* We must allow the server to echo what we sent
+ but it is not necessary to request the server
+ to do so (it might forces the server to close
+ the connection). Hence, we ignore ECHO in the
+ negotiate function
+ */
+ tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
+
+ /* Set the subnegotiation fields to send information
+ just after negotiation passed (do/will)
+
+ Default values are (0,0) initialized by calloc.
+ According to the RFC1013 it is valid:
+ A value equal to zero is acceptable for the width (or height),
+ and means that no character width (or height) is being sent.
+ In this case, the width (or height) that will be assumed by the
+ Telnet server is operating system specific (it will probably be
+ based upon the terminal type information that may have been sent
+ using the TERMINAL TYPE Telnet option). */
+ tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
+ return CURLE_OK;
+}
+
+static void negotiate(struct connectdata *conn)
+{
+ int i;
+ struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
+
+ for(i = 0;i < CURL_NTELOPTS;i++) {
+ if(i==CURL_TELOPT_ECHO)
+ continue;
+
+ if(tn->us_preferred[i] == CURL_YES)
+ set_local_option(conn, i, CURL_YES);
+
+ if(tn->him_preferred[i] == CURL_YES)
+ set_remote_option(conn, i, CURL_YES);
+ }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct Curl_easy *data,
+ const char *direction, int cmd, int option)
+{
+ const char *fmt;
+ const char *opt;
+
+ if(data->set.verbose) {
+ if(cmd == CURL_IAC) {
+ if(CURL_TELCMD_OK(option))
+ infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+ else
+ infof(data, "%s IAC %d\n", direction, option);
+ }
+ else {
+ fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
+ (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
+ if(fmt) {
+ if(CURL_TELOPT_OK(option))
+ opt = CURL_TELOPT(option);
+ else if(option == CURL_TELOPT_EXOPL)
+ opt = "EXOPL";
+ else
+ opt = NULL;
+
+ if(opt)
+ infof(data, "%s %s %s\n", direction, fmt, opt);
+ else
+ infof(data, "%s %s %d\n", direction, fmt, option);
+ }
+ else
+ infof(data, "%s %d %d\n", direction, cmd, option);
+ }
+ }
+}
+#endif
+
+static void send_negotiation(struct connectdata *conn, int cmd, int option)
+{
+ unsigned char buf[3];
+ ssize_t bytes_written;
+ int err;
+ struct Curl_easy *data = conn->data;
+
+ buf[0] = CURL_IAC;
+ buf[1] = (unsigned char)cmd;
+ buf[2] = (unsigned char)option;
+
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+
+ printoption(conn->data, "SENT", cmd, option);
+}
+
+static
+void set_remote_option(struct connectdata *conn, int option, int newstate)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ if(newstate == CURL_YES) {
+ switch(tn->him[option]) {
+ case CURL_NO:
+ tn->him[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_DO, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->himq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else { /* NO */
+ switch(tn->him[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->him[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->himq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static
+void rec_will(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ if(tn->him_preferred[option] == CURL_YES) {
+ tn->him[option] = CURL_YES;
+ send_negotiation(conn, CURL_DO, option);
+ }
+ else
+ send_negotiation(conn, CURL_DONT, option);
+
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Error: DONT answered by WILL */
+ tn->him[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: DONT answered by WILL */
+ tn->him[option] = CURL_YES;
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_YES;
+ break;
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+ }
+ break;
+ }
+}
+
+static
+void rec_wont(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->him[option] = CURL_NO;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
+ break;
+
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTYES;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DO, option);
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_NO;
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+}
+
+static void
+set_local_option(struct connectdata *conn, int option, int newstate)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ if(newstate == CURL_YES) {
+ switch(tn->us[option]) {
+ case CURL_NO:
+ tn->us[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_WILL, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->usq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else { /* NO */
+ switch(tn->us[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->us[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->usq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static
+void rec_do(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ if(tn->us_preferred[option] == CURL_YES) {
+ tn->us[option] = CURL_YES;
+ send_negotiation(conn, CURL_WILL, option);
+ if(tn->subnegotiation[option] == CURL_YES)
+ /* transmission of data option */
+ sendsuboption(conn, option);
+ }
+ else if(tn->subnegotiation[option] == CURL_YES) {
+ /* send information to achieve this option*/
+ tn->us[option] = CURL_YES;
+ send_negotiation(conn, CURL_WILL, option);
+ sendsuboption(conn, option);
+ }
+ else
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Error: DONT answered by WILL */
+ tn->us[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: DONT answered by WILL */
+ tn->us[option] = CURL_YES;
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_YES;
+ if(tn->subnegotiation[option] == CURL_YES) {
+ /* transmission of data option */
+ sendsuboption(conn, option);
+ }
+ break;
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+ }
+ break;
+ }
+}
+
+static
+void rec_dont(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->us[option] = CURL_NO;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
+ break;
+
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTYES;
+ tn->usq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WILL, option);
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_NO;
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+}
+
+
+static void printsub(struct Curl_easy *data,
+ int direction, /* '<' or '>' */
+ unsigned char *pointer, /* where suboption data is */
+ size_t length) /* length of suboption data */
+{
+ unsigned int i = 0;
+
+ if(data->set.verbose) {
+ if(direction) {
+ infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+ if(length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if(i != CURL_IAC || j != CURL_SE) {
+ infof(data, "(terminated by ");
+ if(CURL_TELOPT_OK(i))
+ infof(data, "%s ", CURL_TELOPT(i));
+ else if(CURL_TELCMD_OK(i))
+ infof(data, "%s ", CURL_TELCMD(i));
+ else
+ infof(data, "%u ", i);
+ if(CURL_TELOPT_OK(j))
+ infof(data, "%s", CURL_TELOPT(j));
+ else if(CURL_TELCMD_OK(j))
+ infof(data, "%s", CURL_TELCMD(j));
+ else
+ infof(data, "%d", j);
+ infof(data, ", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if(length < 1) {
+ infof(data, "(Empty suboption?)");
+ return;
+ }
+
+ if(CURL_TELOPT_OK(pointer[0])) {
+ switch(pointer[0]) {
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
+ case CURL_TELOPT_NEW_ENVIRON:
+ case CURL_TELOPT_NAWS:
+ infof(data, "%s", CURL_TELOPT(pointer[0]));
+ break;
+ default:
+ infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
+ break;
+ }
+ }
+ else
+ infof(data, "%d (unknown)", pointer[i]);
+
+ switch(pointer[0]) {
+ case CURL_TELOPT_NAWS:
+ if(length > 4)
+ infof(data, "Width: %hu ; Height: %hu", (pointer[1]<<8) | pointer[2],
+ (pointer[3]<<8) | pointer[4]);
+ break;
+ default:
+ switch(pointer[1]) {
+ case CURL_TELQUAL_IS:
+ infof(data, " IS");
+ break;
+ case CURL_TELQUAL_SEND:
+ infof(data, " SEND");
+ break;
+ case CURL_TELQUAL_INFO:
+ infof(data, " INFO/REPLY");
+ break;
+ case CURL_TELQUAL_NAME:
+ infof(data, " NAME");
+ break;
+ }
+
+ switch(pointer[0]) {
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
+ pointer[length] = 0;
+ infof(data, " \"%s\"", &pointer[2]);
+ break;
+ case CURL_TELOPT_NEW_ENVIRON:
+ if(pointer[1] == CURL_TELQUAL_IS) {
+ infof(data, " ");
+ for(i = 3;i < length;i++) {
+ switch(pointer[i]) {
+ case CURL_NEW_ENV_VAR:
+ infof(data, ", ");
+ break;
+ case CURL_NEW_ENV_VALUE:
+ infof(data, " = ");
+ break;
+ default:
+ infof(data, "%c", pointer[i]);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ for(i = 2; i < length; i++)
+ infof(data, " %.2x", pointer[i]);
+ break;
+ }
+ }
+ if(direction)
+ infof(data, "\n");
+ }
+}
+
+static CURLcode check_telnet_options(struct connectdata *conn)
+{
+ struct curl_slist *head;
+ struct curl_slist *beg;
+ char option_keyword[128] = "";
+ char option_arg[256] = "";
+ struct Curl_easy *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ CURLcode result = CURLE_OK;
+ int binary_option;
+
+ /* Add the user name as an environment variable if it
+ was given on the command line */
+ if(conn->bits.user_passwd) {
+ snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
+ beg = curl_slist_append(tn->telnet_vars, option_arg);
+ if(!beg) {
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ tn->telnet_vars = beg;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+ }
+
+ for(head = data->set.telnet_options; head; head=head->next) {
+ if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
+ option_keyword, option_arg) == 2) {
+
+ /* Terminal type */
+ if(strcasecompare(option_keyword, "TTYPE")) {
+ strncpy(tn->subopt_ttype, option_arg, 31);
+ tn->subopt_ttype[31] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+ continue;
+ }
+
+ /* Display variable */
+ if(strcasecompare(option_keyword, "XDISPLOC")) {
+ strncpy(tn->subopt_xdisploc, option_arg, 127);
+ tn->subopt_xdisploc[127] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+ continue;
+ }
+
+ /* Environment variable */
+ if(strcasecompare(option_keyword, "NEW_ENV")) {
+ beg = curl_slist_append(tn->telnet_vars, option_arg);
+ if(!beg) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ tn->telnet_vars = beg;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+ continue;
+ }
+
+ /* Window Size */
+ if(strcasecompare(option_keyword, "WS")) {
+ if(sscanf(option_arg, "%hu%*[xX]%hu",
+ &tn->subopt_wsx, &tn->subopt_wsy) == 2)
+ tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+ else {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_TELNET_OPTION_SYNTAX;
+ break;
+ }
+ continue;
+ }
+
+ /* To take care or not of the 8th bit in data exchange */
+ if(strcasecompare(option_keyword, "BINARY")) {
+ binary_option=atoi(option_arg);
+ if(binary_option!=1) {
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ }
+ continue;
+ }
+
+ failf(data, "Unknown telnet option %s", head->data);
+ result = CURLE_UNKNOWN_TELNET_OPTION;
+ break;
+ }
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_TELNET_OPTION_SYNTAX;
+ break;
+ }
+
+ if(result) {
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+ }
+
+ return result;
+}
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ */
+
+static void suboption(struct connectdata *conn)
+{
+ struct curl_slist *v;
+ unsigned char temp[2048];
+ ssize_t bytes_written;
+ size_t len;
+ size_t tmplen;
+ int err;
+ char varname[128] = "";
+ char varval[128] = "";
+ struct Curl_easy *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+ printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
+ switch(CURL_SB_GET(tn)) {
+ case CURL_TELOPT_TTYPE:
+ len = strlen(tn->subopt_ttype) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+ CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case CURL_TELOPT_XDISPLOC:
+ len = strlen(tn->subopt_xdisploc) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+ CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case CURL_TELOPT_NEW_ENVIRON:
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+ CURL_TELQUAL_IS);
+ len = 4;
+
+ for(v = tn->telnet_vars;v;v = v->next) {
+ tmplen = (strlen(v->data) + 1);
+ /* Add the variable only if it fits */
+ if(len + tmplen < (int)sizeof(temp)-6) {
+ if(sscanf(v->data, "%127[^,],%127s", varname, varval)) {
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+ CURL_NEW_ENV_VALUE, varval);
+ len += tmplen;
+ }
+ }
+ }
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%c", CURL_IAC, CURL_SE);
+ len += 2;
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ }
+ return;
+}
+
+
+/*
+ * sendsuboption()
+ *
+ * Send suboption information to the server side.
+ */
+
+static void sendsuboption(struct connectdata *conn, int option)
+{
+ ssize_t bytes_written;
+ int err;
+ unsigned short x, y;
+ unsigned char *uc1, *uc2;
+
+ struct Curl_easy *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+ switch(option) {
+ case CURL_TELOPT_NAWS:
+ /* We prepare data to be sent */
+ CURL_SB_CLEAR(tn);
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SB);
+ CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
+ /* We must deal either with litte or big endian processors */
+ /* Window size must be sent according to the 'network order' */
+ x=htons(tn->subopt_wsx);
+ y=htons(tn->subopt_wsy);
+ uc1 = (unsigned char *)&x;
+ uc2 = (unsigned char *)&y;
+ CURL_SB_ACCUM(tn, uc1[0]);
+ CURL_SB_ACCUM(tn, uc1[1]);
+ CURL_SB_ACCUM(tn, uc2[0]);
+ CURL_SB_ACCUM(tn, uc2[1]);
+
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SE);
+ CURL_SB_TERM(tn);
+ /* data suboption is now ready */
+
+ printsub(data, '>', (unsigned char *)tn->subbuffer+2,
+ CURL_SB_LEN(tn)-2);
+
+ /* we send the header of the suboption... */
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data, "Sending data failed (%d)", err);
+ }
+ /* ... then the window size with the send_telnet_data() function
+ to deal with 0xFF cases ... */
+ send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
+ /* ... and the footer */
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data, "Sending data failed (%d)", err);
+ }
+ break;
+ }
+}
+
+
+static
+CURLcode telrcv(struct connectdata *conn,
+ const unsigned char *inbuf, /* Data received from socket */
+ ssize_t count) /* Number of bytes received */
+{
+ unsigned char c;
+ CURLcode result;
+ int in = 0;
+ int startwrite=-1;
+ struct Curl_easy *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+#define startskipping() \
+ if(startwrite >= 0) { \
+ result = Curl_client_write(conn, \
+ CLIENTWRITE_BODY, \
+ (char *)&inbuf[startwrite], \
+ in-startwrite); \
+ if(result) \
+ return result; \
+ } \
+ startwrite = -1
+
+#define writebyte() \
+ if(startwrite < 0) \
+ startwrite = in
+
+#define bufferflush() startskipping()
+
+ while(count--) {
+ c = inbuf[in];
+
+ switch(tn->telrcv_state) {
+ case CURL_TS_CR:
+ tn->telrcv_state = CURL_TS_DATA;
+ if(c == '\0') {
+ startskipping();
+ break; /* Ignore \0 after CR */
+ }
+ writebyte();
+ break;
+
+ case CURL_TS_DATA:
+ if(c == CURL_IAC) {
+ tn->telrcv_state = CURL_TS_IAC;
+ startskipping();
+ break;
+ }
+ else if(c == '\r')
+ tn->telrcv_state = CURL_TS_CR;
+ writebyte();
+ break;
+
+ case CURL_TS_IAC:
+ process_iac:
+ DEBUGASSERT(startwrite < 0);
+ switch(c) {
+ case CURL_WILL:
+ tn->telrcv_state = CURL_TS_WILL;
+ break;
+ case CURL_WONT:
+ tn->telrcv_state = CURL_TS_WONT;
+ break;
+ case CURL_DO:
+ tn->telrcv_state = CURL_TS_DO;
+ break;
+ case CURL_DONT:
+ tn->telrcv_state = CURL_TS_DONT;
+ break;
+ case CURL_SB:
+ CURL_SB_CLEAR(tn);
+ tn->telrcv_state = CURL_TS_SB;
+ break;
+ case CURL_IAC:
+ tn->telrcv_state = CURL_TS_DATA;
+ writebyte();
+ break;
+ case CURL_DM:
+ case CURL_NOP:
+ case CURL_GA:
+ default:
+ tn->telrcv_state = CURL_TS_DATA;
+ printoption(data, "RCVD", CURL_IAC, c);
+ break;
+ }
+ break;
+
+ case CURL_TS_WILL:
+ printoption(data, "RCVD", CURL_WILL, c);
+ tn->please_negotiate = 1;
+ rec_will(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_WONT:
+ printoption(data, "RCVD", CURL_WONT, c);
+ tn->please_negotiate = 1;
+ rec_wont(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_DO:
+ printoption(data, "RCVD", CURL_DO, c);
+ tn->please_negotiate = 1;
+ rec_do(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_DONT:
+ printoption(data, "RCVD", CURL_DONT, c);
+ tn->please_negotiate = 1;
+ rec_dont(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_SB:
+ if(c == CURL_IAC)
+ tn->telrcv_state = CURL_TS_SE;
+ else
+ CURL_SB_ACCUM(tn, c);
+ break;
+
+ case CURL_TS_SE:
+ if(c != CURL_SE) {
+ if(c != CURL_IAC) {
+ /*
+ * This is an error. We only expect to get "IAC IAC" or "IAC SE".
+ * Several things may have happened. An IAC was not doubled, the
+ * IAC SE was left off, or another option got inserted into the
+ * suboption are all possibilities. If we assume that the IAC was
+ * not doubled, and really the IAC SE was left off, we could get
+ * into an infinite loop here. So, instead, we terminate the
+ * suboption, and process the partial suboption if we can.
+ */
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, c);
+ tn->subpointer -= 2;
+ CURL_SB_TERM(tn);
+
+ printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
+ suboption(conn); /* handle sub-option */
+ tn->telrcv_state = CURL_TS_IAC;
+ goto process_iac;
+ }
+ CURL_SB_ACCUM(tn, c);
+ tn->telrcv_state = CURL_TS_SB;
+ }
+ else
+ {
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SE);
+ tn->subpointer -= 2;
+ CURL_SB_TERM(tn);
+ suboption(conn); /* handle sub-option */
+ tn->telrcv_state = CURL_TS_DATA;
+ }
+ break;
+ }
+ ++in;
+ }
+ bufferflush();
+ return CURLE_OK;
+}
+
+/* Escape and send a telnet data block */
+static CURLcode send_telnet_data(struct connectdata *conn,
+ char *buffer, ssize_t nread)
+{
+ ssize_t escapes, i, j, outlen;
+ unsigned char *outbuf = NULL;
+ CURLcode result = CURLE_OK;
+ ssize_t bytes_written, total_written;
+
+ /* Determine size of new buffer after escaping */
+ escapes = 0;
+ for(i = 0; i < nread; i++)
+ if((unsigned char)buffer[i] == CURL_IAC)
+ escapes++;
+ outlen = nread + escapes;
+
+ if(outlen == nread)
+ outbuf = (unsigned char *)buffer;
+ else {
+ outbuf = malloc(nread + escapes + 1);
+ if(!outbuf)
+ return CURLE_OUT_OF_MEMORY;
+
+ j = 0;
+ for(i = 0; i < nread; i++) {
+ outbuf[j++] = buffer[i];
+ if((unsigned char)buffer[i] == CURL_IAC)
+ outbuf[j++] = CURL_IAC;
+ }
+ outbuf[j] = '\0';
+ }
+
+ total_written = 0;
+ while(!result && total_written < outlen) {
+ /* Make sure socket is writable to avoid EWOULDBLOCK condition */
+ struct pollfd pfd[1];
+ pfd[0].fd = conn->sock[FIRSTSOCKET];
+ pfd[0].events = POLLOUT;
+ switch(Curl_poll(pfd, 1, -1)) {
+ case -1: /* error, abort writing */
+ case 0: /* timeout (will never happen) */
+ result = CURLE_SEND_ERROR;
+ break;
+ default: /* write! */
+ bytes_written = 0;
+ result = Curl_write(conn, conn->sock[FIRSTSOCKET],
+ outbuf + total_written,
+ outlen - total_written,
+ &bytes_written);
+ total_written += bytes_written;
+ break;
+ }
+ }
+
+ /* Free malloc copy if escaped */
+ if(outbuf != (unsigned char *)buffer)
+ free(outbuf);
+
+ return result;
+}
+
+static CURLcode telnet_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ (void)status; /* unused */
+ (void)premature; /* not used */
+
+ if(!tn)
+ return CURLE_OK;
+
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+
+ Curl_safefree(conn->data->req.protop);
+
+ return CURLE_OK;
+}
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+#ifdef USE_WINSOCK
+ HMODULE wsock2;
+ WSOCK2_FUNC close_event_func;
+ WSOCK2_FUNC create_event_func;
+ WSOCK2_FUNC event_select_func;
+ WSOCK2_FUNC enum_netevents_func;
+ WSAEVENT event_handle;
+ WSANETWORKEVENTS events;
+ HANDLE stdin_handle;
+ HANDLE objs[2];
+ DWORD obj_count;
+ DWORD wait_timeout;
+ DWORD waitret;
+ DWORD readfile_read;
+ int err;
+#else
+ int interval_ms;
+ struct pollfd pfd[2];
+ int poll_cnt;
+ curl_off_t total_dl = 0;
+ curl_off_t total_ul = 0;
+#endif
+ ssize_t nread;
+ struct timeval now;
+ bool keepon = TRUE;
+ char *buf = data->state.buffer;
+ struct TELNET *tn;
+
+ *done = TRUE; /* unconditionally */
+
+ result = init_telnet(conn);
+ if(result)
+ return result;
+
+ tn = (struct TELNET *)data->req.protop;
+
+ result = check_telnet_options(conn);
+ if(result)
+ return result;
+
+#ifdef USE_WINSOCK
+ /*
+ ** This functionality only works with WinSock >= 2.0. So,
+ ** make sure we have it.
+ */
+ result = check_wsock2(data);
+ if(result)
+ return result;
+
+ /* OK, so we have WinSock 2.0. We need to dynamically */
+ /* load ws2_32.dll and get the function pointers we need. */
+ wsock2 = Curl_load_library(TEXT("WS2_32.DLL"));
+ if(wsock2 == NULL) {
+ failf(data, "failed to load WS2_32.DLL (%d)", ERRNO);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Grab a pointer to WSACreateEvent */
+ create_event_func = GetProcAddress(wsock2, "WSACreateEvent");
+ if(create_event_func == NULL) {
+ failf(data, "failed to find WSACreateEvent function (%d)", ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSACloseEvent */
+ close_event_func = GetProcAddress(wsock2, "WSACloseEvent");
+ if(close_event_func == NULL) {
+ failf(data, "failed to find WSACloseEvent function (%d)", ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEventSelect */
+ event_select_func = GetProcAddress(wsock2, "WSAEventSelect");
+ if(event_select_func == NULL) {
+ failf(data, "failed to find WSAEventSelect function (%d)", ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEnumNetworkEvents */
+ enum_netevents_func = GetProcAddress(wsock2, "WSAEnumNetworkEvents");
+ if(enum_netevents_func == NULL) {
+ failf(data, "failed to find WSAEnumNetworkEvents function (%d)", ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* We want to wait for both stdin and the socket. Since
+ ** the select() function in winsock only works on sockets
+ ** we have to use the WaitForMultipleObjects() call.
+ */
+
+ /* First, create a sockets event object */
+ event_handle = (WSAEVENT)create_event_func();
+ if(event_handle == WSA_INVALID_EVENT) {
+ failf(data, "WSACreateEvent failed (%d)", SOCKERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Tell winsock what events we want to listen to */
+ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
+ SOCKET_ERROR) {
+ close_event_func(event_handle);
+ FreeLibrary(wsock2);
+ return CURLE_OK;
+ }
+
+ /* The get the Windows file handle for stdin */
+ stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+ /* Create the list of objects to wait for */
+ objs[0] = event_handle;
+ objs[1] = stdin_handle;
+
+ /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
+ else use the old WaitForMultipleObjects() way */
+ if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
+ data->set.is_fread_set) {
+ /* Don't wait for stdin_handle, just wait for event_handle */
+ obj_count = 1;
+ /* Check stdin_handle per 100 milliseconds */
+ wait_timeout = 100;
+ }
+ else {
+ obj_count = 2;
+ wait_timeout = 1000;
+ }
+
+ /* Keep on listening and act on events */
+ while(keepon) {
+ const DWORD buf_size = (DWORD)data->set.buffer_size;
+ waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
+ switch(waitret) {
+ case WAIT_TIMEOUT:
+ {
+ for(;;) {
+ if(data->set.is_fread_set) {
+ size_t n;
+ /* read from user-supplied method */
+ n = data->state.fread_func(buf, 1, buf_size, data->state.in);
+ if(n == CURL_READFUNC_ABORT) {
+ keepon = FALSE;
+ result = CURLE_READ_ERROR;
+ break;
+ }
+
+ if(n == CURL_READFUNC_PAUSE)
+ break;
+
+ if(n == 0) /* no bytes */
+ break;
+
+ readfile_read = (DWORD)n; /* fall thru with number of bytes read */
+ }
+ else {
+ /* read from stdin */
+ if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ result = CURLE_READ_ERROR;
+ break;
+ }
+
+ if(!readfile_read)
+ break;
+
+ if(!ReadFile(stdin_handle, buf, buf_size,
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ result = CURLE_READ_ERROR;
+ break;
+ }
+ }
+
+ result = send_telnet_data(conn, buf, readfile_read);
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ }
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ {
+ if(!ReadFile(stdin_handle, buf, buf_size,
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ result = CURLE_READ_ERROR;
+ break;
+ }
+
+ result = send_telnet_data(conn, buf, readfile_read);
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ break;
+
+ case WAIT_OBJECT_0:
+
+ events.lNetworkEvents = 0;
+ if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
+ err = SOCKERRNO;
+ if(err != EINPROGRESS) {
+ infof(data, "WSAEnumNetworkEvents failed (%d)", err);
+ keepon = FALSE;
+ result = CURLE_READ_ERROR;
+ }
+ break;
+ }
+ if(events.lNetworkEvents & FD_READ) {
+ /* read data from network */
+ result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
+ /* read would've blocked. Loop again */
+ if(result == CURLE_AGAIN)
+ break;
+ /* returned not-zero, this an error */
+ else if(result) {
+ keepon = FALSE;
+ break;
+ }
+ /* returned zero but actually received 0 or less here,
+ the server closed the connection and we bail out */
+ else if(nread <= 0) {
+ keepon = FALSE;
+ break;
+ }
+
+ result = telrcv(conn, (unsigned char *) buf, nread);
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(tn->please_negotiate && !tn->already_negotiated) {
+ negotiate(conn);
+ tn->already_negotiated = 1;
+ }
+ }
+ if(events.lNetworkEvents & FD_CLOSE) {
+ keepon = FALSE;
+ }
+ break;
+
+ }
+
+ if(data->set.timeout) {
+ now = Curl_tvnow();
+ if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ failf(data, "Time-out");
+ result = CURLE_OPERATION_TIMEDOUT;
+ keepon = FALSE;
+ }
+ }
+ }
+
+ /* We called WSACreateEvent, so call WSACloseEvent */
+ if(!close_event_func(event_handle)) {
+ infof(data, "WSACloseEvent failed (%d)", SOCKERRNO);
+ }
+
+ /* "Forget" pointers into the library we're about to free */
+ create_event_func = NULL;
+ close_event_func = NULL;
+ event_select_func = NULL;
+ enum_netevents_func = NULL;
+
+ /* We called LoadLibrary, so call FreeLibrary */
+ if(!FreeLibrary(wsock2))
+ infof(data, "FreeLibrary(wsock2) failed (%d)", ERRNO);
+#else
+ pfd[0].fd = sockfd;
+ pfd[0].events = POLLIN;
+
+ if(data->set.is_fread_set) {
+ poll_cnt = 1;
+ interval_ms = 100; /* poll user-supplied read function */
+ }
+ else {
+ /* really using fread, so infile is a FILE* */
+ pfd[1].fd = fileno((FILE *)data->state.in);
+ pfd[1].events = POLLIN;
+ poll_cnt = 2;
+ interval_ms = 1 * 1000;
+ }
+
+ while(keepon) {
+ switch(Curl_poll(pfd, poll_cnt, interval_ms)) {
+ case -1: /* error, stop reading */
+ keepon = FALSE;
+ continue;
+ case 0: /* timeout */
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
+ /* fall through */
+ default: /* read! */
+ if(pfd[0].revents & POLLIN) {
+ /* read data from network */
+ result = Curl_read(conn, sockfd, buf, data->set.buffer_size, &nread);
+ /* read would've blocked. Loop again */
+ if(result == CURLE_AGAIN)
+ break;
+ /* returned not-zero, this an error */
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+ /* returned zero but actually received 0 or less here,
+ the server closed the connection and we bail out */
+ else if(nread <= 0) {
+ keepon = FALSE;
+ break;
+ }
+
+ total_dl += nread;
+ Curl_pgrsSetDownloadCounter(data, total_dl);
+ result = telrcv(conn, (unsigned char *)buf, nread);
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(tn->please_negotiate && !tn->already_negotiated) {
+ negotiate(conn);
+ tn->already_negotiated = 1;
+ }
+ }
+
+ nread = 0;
+ if(poll_cnt == 2) {
+ if(pfd[1].revents & POLLIN) { /* read from in file */
+ nread = read(pfd[1].fd, buf, data->set.buffer_size);
+ }
+ }
+ else {
+ /* read from user-supplied method */
+ nread = (int)data->state.fread_func(buf, 1, data->set.buffer_size,
+ data->state.in);
+ if(nread == CURL_READFUNC_ABORT) {
+ keepon = FALSE;
+ break;
+ }
+ if(nread == CURL_READFUNC_PAUSE)
+ break;
+ }
+
+ if(nread > 0) {
+ result = send_telnet_data(conn, buf, nread);
+ if(result) {
+ keepon = FALSE;
+ break;
+ }
+ total_ul += nread;
+ Curl_pgrsSetUploadCounter(data, total_ul);
+ }
+ else if(nread < 0)
+ keepon = FALSE;
+
+ break;
+ } /* poll switch statement */
+
+ if(data->set.timeout) {
+ now = Curl_tvnow();
+ if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ failf(data, "Time-out");
+ result = CURLE_OPERATION_TIMEDOUT;
+ keepon = FALSE;
+ }
+ }
+
+ if(Curl_pgrsUpdate(conn)) {
+ result = CURLE_ABORTED_BY_CALLBACK;
+ break;
+ }
+ }
+#endif
+ /* mark this as "no further transfer wanted" */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return result;
+}
+#endif
diff --git a/Utilities/cmcurl/lib/telnet.h b/Utilities/cmcurl/lib/telnet.h
new file mode 100644
index 000000000..419a399b7
--- /dev/null
+++ b/Utilities/cmcurl/lib/telnet.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TELNET_H
+#define HEADER_CURL_TELNET_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+extern const struct Curl_handler Curl_handler_telnet;
+#endif
+
+#endif /* HEADER_CURL_TELNET_H */
+
diff --git a/Utilities/cmcurl/lib/tftp.c b/Utilities/cmcurl/lib/tftp.c
new file mode 100644
index 000000000..b2b3efe0c
--- /dev/null
+++ b/Utilities/cmcurl/lib/tftp.c
@@ -0,0 +1,1396 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_TFTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "tftp.h"
+#include "progress.h"
+#include "connect.h"
+#include "strerror.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "strcase.h"
+#include "speedcheck.h"
+#include "select.h"
+#include "escape.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* RFC2348 allows the block size to be negotiated */
+#define TFTP_BLKSIZE_DEFAULT 512
+#define TFTP_BLKSIZE_MIN 8
+#define TFTP_BLKSIZE_MAX 65464
+#define TFTP_OPTION_BLKSIZE "blksize"
+
+/* from RFC2349: */
+#define TFTP_OPTION_TSIZE "tsize"
+#define TFTP_OPTION_INTERVAL "timeout"
+
+typedef enum {
+ TFTP_MODE_NETASCII=0,
+ TFTP_MODE_OCTET
+} tftp_mode_t;
+
+typedef enum {
+ TFTP_STATE_START=0,
+ TFTP_STATE_RX,
+ TFTP_STATE_TX,
+ TFTP_STATE_FIN
+} tftp_state_t;
+
+typedef enum {
+ TFTP_EVENT_NONE = -1,
+ TFTP_EVENT_INIT = 0,
+ TFTP_EVENT_RRQ = 1,
+ TFTP_EVENT_WRQ = 2,
+ TFTP_EVENT_DATA = 3,
+ TFTP_EVENT_ACK = 4,
+ TFTP_EVENT_ERROR = 5,
+ TFTP_EVENT_OACK = 6,
+ TFTP_EVENT_TIMEOUT
+} tftp_event_t;
+
+typedef enum {
+ TFTP_ERR_UNDEF=0,
+ TFTP_ERR_NOTFOUND,
+ TFTP_ERR_PERM,
+ TFTP_ERR_DISKFULL,
+ TFTP_ERR_ILLEGAL,
+ TFTP_ERR_UNKNOWNID,
+ TFTP_ERR_EXISTS,
+ TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */
+
+ /* The remaining error codes are internal to curl */
+ TFTP_ERR_NONE = -100,
+ TFTP_ERR_TIMEOUT,
+ TFTP_ERR_NORESPONSE
+} tftp_error_t;
+
+typedef struct tftp_packet {
+ unsigned char *data;
+} tftp_packet_t;
+
+typedef struct tftp_state_data {
+ tftp_state_t state;
+ tftp_mode_t mode;
+ tftp_error_t error;
+ tftp_event_t event;
+ struct connectdata *conn;
+ curl_socket_t sockfd;
+ int retries;
+ int retry_time;
+ int retry_max;
+ time_t start_time;
+ time_t max_time;
+ time_t rx_time;
+ unsigned short block;
+ struct Curl_sockaddr_storage local_addr;
+ struct Curl_sockaddr_storage remote_addr;
+ curl_socklen_t remote_addrlen;
+ int rbytes;
+ int sbytes;
+ int blksize;
+ int requested_blksize;
+ tftp_packet_t rpacket;
+ tftp_packet_t spacket;
+} tftp_state_data_t;
+
+
+/* Forward declarations */
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event);
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event);
+static CURLcode tftp_connect(struct connectdata *conn, bool *done);
+static CURLcode tftp_disconnect(struct connectdata *conn,
+ bool dead_connection);
+static CURLcode tftp_do(struct connectdata *conn, bool *done);
+static CURLcode tftp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode tftp_setup_connection(struct connectdata * conn);
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode tftp_translate_code(tftp_error_t error);
+
+
+/*
+ * TFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_tftp = {
+ "TFTP", /* scheme */
+ tftp_setup_connection, /* setup_connection */
+ tftp_do, /* do_it */
+ tftp_done, /* done */
+ ZERO_NULL, /* do_more */
+ tftp_connect, /* connect_it */
+ tftp_multi_statemach, /* connecting */
+ tftp_doing, /* doing */
+ tftp_getsock, /* proto_getsock */
+ tftp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ tftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_TFTP, /* defport */
+ CURLPROTO_TFTP, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+/**********************************************************
+ *
+ * tftp_set_timeouts -
+ *
+ * Set timeouts based on state machine state.
+ * Use user provided connect timeouts until DATA or ACK
+ * packet is received, then use user-provided transfer timeouts
+ *
+ *
+ **********************************************************/
+static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
+{
+ time_t maxtime, timeout;
+ time_t timeout_ms;
+ bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
+
+ time(&state->start_time);
+
+ /* Compute drop-dead time */
+ timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
+
+ if(timeout_ms < 0) {
+ /* time-out, bail out, go home */
+ failf(state->conn->data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(start) {
+
+ maxtime = (time_t)(timeout_ms + 500) / 1000;
+ state->max_time = state->start_time+maxtime;
+
+ /* Set per-block timeout to total */
+ timeout = maxtime;
+
+ /* Average restart after 5 seconds */
+ state->retry_max = (int)timeout/5;
+
+ if(state->retry_max < 1)
+ /* avoid division by zero below */
+ state->retry_max = 1;
+
+ /* Compute the re-start interval to suit the timeout */
+ state->retry_time = (int)timeout/state->retry_max;
+ if(state->retry_time<1)
+ state->retry_time=1;
+
+ }
+ else {
+ if(timeout_ms > 0)
+ maxtime = (time_t)(timeout_ms + 500) / 1000;
+ else
+ maxtime = 3600;
+
+ state->max_time = state->start_time+maxtime;
+
+ /* Set per-block timeout to total */
+ timeout = maxtime;
+
+ /* Average reposting an ACK after 5 seconds */
+ state->retry_max = (int)timeout/5;
+ }
+ /* But bound the total number */
+ if(state->retry_max<3)
+ state->retry_max=3;
+
+ if(state->retry_max>50)
+ state->retry_max=50;
+
+ /* Compute the re-ACK interval to suit the timeout */
+ state->retry_time = (int)(timeout/state->retry_max);
+ if(state->retry_time<1)
+ state->retry_time=1;
+
+ infof(state->conn->data,
+ "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
+ (int)state->state, (long)(state->max_time-state->start_time),
+ state->retry_time, state->retry_max);
+
+ /* init RX time */
+ time(&state->rx_time);
+
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_set_send_first
+ *
+ * Event handler for the START state
+ *
+ **********************************************************/
+
+static void setpacketevent(tftp_packet_t *packet, unsigned short num)
+{
+ packet->data[0] = (unsigned char)(num >> 8);
+ packet->data[1] = (unsigned char)(num & 0xff);
+}
+
+
+static void setpacketblock(tftp_packet_t *packet, unsigned short num)
+{
+ packet->data[2] = (unsigned char)(num >> 8);
+ packet->data[3] = (unsigned char)(num & 0xff);
+}
+
+static unsigned short getrpacketevent(const tftp_packet_t *packet)
+{
+ return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
+}
+
+static unsigned short getrpacketblock(const tftp_packet_t *packet)
+{
+ return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
+}
+
+static size_t Curl_strnlen(const char *string, size_t maxlen)
+{
+ const char *end = memchr(string, '\0', maxlen);
+ return end ? (size_t) (end - string) : maxlen;
+}
+
+static const char *tftp_option_get(const char *buf, size_t len,
+ const char **option, const char **value)
+{
+ size_t loc;
+
+ loc = Curl_strnlen(buf, len);
+ loc++; /* NULL term */
+
+ if(loc >= len)
+ return NULL;
+ *option = buf;
+
+ loc += Curl_strnlen(buf+loc, len-loc);
+ loc++; /* NULL term */
+
+ if(loc > len)
+ return NULL;
+ *value = &buf[strlen(*option) + 1];
+
+ return &buf[loc];
+}
+
+static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
+ const char *ptr, int len)
+{
+ const char *tmp = ptr;
+ struct Curl_easy *data = state->conn->data;
+
+ /* if OACK doesn't contain blksize option, the default (512) must be used */
+ state->blksize = TFTP_BLKSIZE_DEFAULT;
+
+ while(tmp < ptr + len) {
+ const char *option, *value;
+
+ tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
+ if(tmp == NULL) {
+ failf(data, "Malformed ACK packet, rejecting");
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ infof(data, "got option=(%s) value=(%s)\n", option, value);
+
+ if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
+ long blksize;
+
+ blksize = strtol(value, NULL, 10);
+
+ if(!blksize) {
+ failf(data, "invalid blocksize value in OACK packet");
+ return CURLE_TFTP_ILLEGAL;
+ }
+ if(blksize > TFTP_BLKSIZE_MAX) {
+ failf(data, "%s (%d)", "blksize is larger than max supported",
+ TFTP_BLKSIZE_MAX);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ else if(blksize < TFTP_BLKSIZE_MIN) {
+ failf(data, "%s (%d)", "blksize is smaller than min supported",
+ TFTP_BLKSIZE_MIN);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ else if(blksize > state->requested_blksize) {
+ /* could realloc pkt buffers here, but the spec doesn't call out
+ * support for the server requesting a bigger blksize than the client
+ * requests */
+ failf(data, "%s (%ld)",
+ "server requested blksize larger than allocated", blksize);
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ state->blksize = (int)blksize;
+ infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
+ state->blksize, "requested", state->requested_blksize);
+ }
+ else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
+ long tsize = 0;
+
+ tsize = strtol(value, NULL, 10);
+ infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
+
+ /* tsize should be ignored on upload: Who cares about the size of the
+ remote file? */
+ if(!data->set.upload) {
+ if(!tsize) {
+ failf(data, "invalid tsize -:%s:- value in OACK packet", value);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ Curl_pgrsSetDownloadSize(data, tsize);
+ }
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
+ char *buf, const char *option)
+{
+ if(( strlen(option) + csize + 1) > (size_t)state->blksize)
+ return 0;
+ strcpy(buf, option);
+ return strlen(option) + 1;
+}
+
+static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode result;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ struct Curl_easy *data = state->conn->data;
+
+ infof(data, "%s\n", "Connected for transmit");
+#endif
+ state->state = TFTP_STATE_TX;
+ result = tftp_set_timeouts(state);
+ if(result)
+ return result;
+ return tftp_tx(state, event);
+}
+
+static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode result;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ struct Curl_easy *data = state->conn->data;
+
+ infof(data, "%s\n", "Connected for receive");
+#endif
+ state->state = TFTP_STATE_RX;
+ result = tftp_set_timeouts(state);
+ if(result)
+ return result;
+ return tftp_rx(state, event);
+}
+
+static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
+{
+ size_t sbytes;
+ ssize_t senddata;
+ const char *mode = "octet";
+ char *filename;
+ char buf[64];
+ struct Curl_easy *data = state->conn->data;
+ CURLcode result = CURLE_OK;
+
+ /* Set ascii mode if -B flag was used */
+ if(data->set.prefer_ascii)
+ mode = "netascii";
+
+ switch(event) {
+
+ case TFTP_EVENT_INIT: /* Send the first packet out */
+ case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
+ /* Increment the retry counter, quit if over the limit */
+ state->retries++;
+ if(state->retries>state->retry_max) {
+ state->error = TFTP_ERR_NORESPONSE;
+ state->state = TFTP_STATE_FIN;
+ return result;
+ }
+
+ if(data->set.upload) {
+ /* If we are uploading, send an WRQ */
+ setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
+ state->conn->data->req.upload_fromhere =
+ (char *)state->spacket.data+4;
+ if(data->state.infilesize != -1)
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ }
+ else {
+ /* If we are downloading, send an RRQ */
+ setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
+ }
+ /* As RFC3617 describes the separator slash is not actually part of the
+ file name so we skip the always-present first letter of the path
+ string. */
+ result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
+ &filename, NULL, FALSE);
+ if(result)
+ return result;
+
+ snprintf((char *)state->spacket.data+2,
+ state->blksize,
+ "%s%c%s%c", filename, '\0', mode, '\0');
+ sbytes = 4 + strlen(filename) + strlen(mode);
+
+ /* optional addition of TFTP options */
+ if(!data->set.tftp_no_options) {
+ /* add tsize option */
+ if(data->set.upload && (data->state.infilesize != -1))
+ snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
+ data->state.infilesize);
+ else
+ strcpy(buf, "0"); /* the destination is large enough */
+
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_TSIZE);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf);
+ /* add blksize option */
+ snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_BLKSIZE);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf);
+
+ /* add timeout option */
+ snprintf(buf, sizeof(buf), "%d", state->retry_time);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_INTERVAL);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf);
+ }
+
+ /* the typecase for the 3rd argument is mostly for systems that do
+ not have a size_t argument, like older unixes that want an 'int' */
+ senddata = sendto(state->sockfd, (void *)state->spacket.data,
+ (SEND_TYPE_ARG3)sbytes, 0,
+ state->conn->ip_addr->ai_addr,
+ state->conn->ip_addr->ai_addrlen);
+ if(senddata != (ssize_t)sbytes) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ }
+ free(filename);
+ break;
+
+ case TFTP_EVENT_OACK:
+ if(data->set.upload) {
+ result = tftp_connect_for_tx(state, event);
+ }
+ else {
+ result = tftp_connect_for_rx(state, event);
+ }
+ break;
+
+ case TFTP_EVENT_ACK: /* Connected for transmit */
+ result = tftp_connect_for_tx(state, event);
+ break;
+
+ case TFTP_EVENT_DATA: /* Connected for receive */
+ result = tftp_connect_for_rx(state, event);
+ break;
+
+ case TFTP_EVENT_ERROR:
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(state->conn->data, "tftp_send_first: internal error");
+ break;
+ }
+
+ return result;
+}
+
+/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
+ boundary */
+#define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
+
+/**********************************************************
+ *
+ * tftp_rx
+ *
+ * Event handler for the RX state
+ *
+ **********************************************************/
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
+{
+ ssize_t sbytes;
+ int rblock;
+ struct Curl_easy *data = state->conn->data;
+
+ switch(event) {
+
+ case TFTP_EVENT_DATA:
+ /* Is this the block we expect? */
+ rblock = getrpacketblock(&state->rpacket);
+ if(NEXT_BLOCKNUM(state->block) == rblock) {
+ /* This is the expected block. Reset counters and ACK it. */
+ state->retries = 0;
+ }
+ else if(state->block == rblock) {
+ /* This is the last recently received block again. Log it and ACK it
+ again. */
+ infof(data, "Received last DATA packet block %d again.\n", rblock);
+ }
+ else {
+ /* totally unexpected, just log it */
+ infof(data,
+ "Received unexpected DATA packet block %d, expecting block %d\n",
+ rblock, NEXT_BLOCKNUM(state->block));
+ break;
+ }
+
+ /* ACK this block. */
+ state->block = (unsigned short)rblock;
+ setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+ setpacketblock(&state->spacket, state->block);
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes < 0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+
+ /* Check if completed (That is, a less than full packet is received) */
+ if(state->rbytes < (ssize_t)state->blksize+4) {
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ state->state = TFTP_STATE_RX;
+ }
+ time(&state->rx_time);
+ break;
+
+ case TFTP_EVENT_OACK:
+ /* ACK option acknowledgement so we can move on to data */
+ state->block = 0;
+ state->retries = 0;
+ setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+ setpacketblock(&state->spacket, state->block);
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes < 0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+
+ /* we're ready to RX data */
+ state->state = TFTP_STATE_RX;
+ time(&state->rx_time);
+ break;
+
+ case TFTP_EVENT_TIMEOUT:
+ /* Increment the retry count and fail if over the limit */
+ state->retries++;
+ infof(data,
+ "Timeout waiting for block %d ACK. Retries = %d\n",
+ NEXT_BLOCKNUM(state->block), state->retries);
+ if(state->retries > state->retry_max) {
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ /* Resend the previous ACK */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ }
+ break;
+
+ case TFTP_EVENT_ERROR:
+ setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+ setpacketblock(&state->spacket, state->block);
+ (void)sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(data, "%s", "tftp_rx: internal error");
+ return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
+ this */
+ }
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_tx
+ *
+ * Event handler for the TX state
+ *
+ **********************************************************/
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
+{
+ struct Curl_easy *data = state->conn->data;
+ ssize_t sbytes;
+ int rblock;
+ CURLcode result = CURLE_OK;
+ struct SingleRequest *k = &data->req;
+ int cb; /* Bytes currently read */
+
+ switch(event) {
+
+ case TFTP_EVENT_ACK:
+ case TFTP_EVENT_OACK:
+ if(event == TFTP_EVENT_ACK) {
+ /* Ack the packet */
+ rblock = getrpacketblock(&state->rpacket);
+
+ if(rblock != state->block &&
+ /* There's a bug in tftpd-hpa that causes it to send us an ack for
+ * 65535 when the block number wraps to 0. So when we're expecting
+ * 0, also accept 65535. See
+ * http://syslinux.zytor.com/archives/2010-September/015253.html
+ * */
+ !(state->block == 0 && rblock == 65535)) {
+ /* This isn't the expected block. Log it and up the retry counter */
+ infof(data, "Received ACK for block %d, expecting %d\n",
+ rblock, state->block);
+ state->retries++;
+ /* Bail out if over the maximum */
+ if(state->retries>state->retry_max) {
+ failf(data, "tftp_tx: giving up waiting for block %d ack",
+ state->block);
+ result = CURLE_SEND_ERROR;
+ }
+ else {
+ /* Re-send the data packet */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4+state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ result = CURLE_SEND_ERROR;
+ }
+ }
+
+ return result;
+ }
+ /* This is the expected packet. Reset the counters and send the next
+ block */
+ time(&state->rx_time);
+ state->block++;
+ }
+ else
+ state->block = 1; /* first data block is 1 when using OACK */
+
+ state->retries = 0;
+ setpacketevent(&state->spacket, TFTP_EVENT_DATA);
+ setpacketblock(&state->spacket, state->block);
+ if(state->block > 1 && state->sbytes < (int)state->blksize) {
+ state->state = TFTP_STATE_FIN;
+ return CURLE_OK;
+ }
+
+ /* TFTP considers data block size < 512 bytes as an end of session. So
+ * in some cases we must wait for additional data to build full (512 bytes)
+ * data block.
+ * */
+ state->sbytes = 0;
+ state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
+ do {
+ result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
+ &cb);
+ if(result)
+ return result;
+ state->sbytes += cb;
+ state->conn->data->req.upload_fromhere += cb;
+ } while(state->sbytes < state->blksize && cb != 0);
+
+ sbytes = sendto(state->sockfd, (void *) state->spacket.data,
+ 4 + state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ /* Update the progress meter */
+ k->writebytecount += state->sbytes;
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+ break;
+
+ case TFTP_EVENT_TIMEOUT:
+ /* Increment the retry counter and log the timeout */
+ state->retries++;
+ infof(data, "Timeout waiting for block %d ACK. "
+ " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
+ /* Decide if we've had enough */
+ if(state->retries > state->retry_max) {
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ /* Re-send the data packet */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4+state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ /* since this was a re-send, we remain at the still byte position */
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+ }
+ break;
+
+ case TFTP_EVENT_ERROR:
+ state->state = TFTP_STATE_FIN;
+ setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+ setpacketblock(&state->spacket, state->block);
+ (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(data, "tftp_tx: internal error, event: %i", (int)(event));
+ break;
+ }
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_translate_code
+ *
+ * Translate internal error codes to CURL error codes
+ *
+ **********************************************************/
+static CURLcode tftp_translate_code(tftp_error_t error)
+{
+ CURLcode result = CURLE_OK;
+
+ if(error != TFTP_ERR_NONE) {
+ switch(error) {
+ case TFTP_ERR_NOTFOUND:
+ result = CURLE_TFTP_NOTFOUND;
+ break;
+ case TFTP_ERR_PERM:
+ result = CURLE_TFTP_PERM;
+ break;
+ case TFTP_ERR_DISKFULL:
+ result = CURLE_REMOTE_DISK_FULL;
+ break;
+ case TFTP_ERR_UNDEF:
+ case TFTP_ERR_ILLEGAL:
+ result = CURLE_TFTP_ILLEGAL;
+ break;
+ case TFTP_ERR_UNKNOWNID:
+ result = CURLE_TFTP_UNKNOWNID;
+ break;
+ case TFTP_ERR_EXISTS:
+ result = CURLE_REMOTE_FILE_EXISTS;
+ break;
+ case TFTP_ERR_NOSUCHUSER:
+ result = CURLE_TFTP_NOSUCHUSER;
+ break;
+ case TFTP_ERR_TIMEOUT:
+ result = CURLE_OPERATION_TIMEDOUT;
+ break;
+ case TFTP_ERR_NORESPONSE:
+ result = CURLE_COULDNT_CONNECT;
+ break;
+ default:
+ result = CURLE_ABORTED_BY_CALLBACK;
+ break;
+ }
+ }
+ else
+ result = CURLE_OK;
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_machine
+ *
+ * The tftp state machine event dispatcher
+ *
+ **********************************************************/
+static CURLcode tftp_state_machine(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = state->conn->data;
+
+ switch(state->state) {
+ case TFTP_STATE_START:
+ DEBUGF(infof(data, "TFTP_STATE_START\n"));
+ result = tftp_send_first(state, event);
+ break;
+ case TFTP_STATE_RX:
+ DEBUGF(infof(data, "TFTP_STATE_RX\n"));
+ result = tftp_rx(state, event);
+ break;
+ case TFTP_STATE_TX:
+ DEBUGF(infof(data, "TFTP_STATE_TX\n"));
+ result = tftp_tx(state, event);
+ break;
+ case TFTP_STATE_FIN:
+ infof(data, "%s\n", "TFTP finished");
+ break;
+ default:
+ DEBUGF(infof(data, "STATE: %d\n", state->state));
+ failf(data, "%s", "Internal state machine error");
+ result = CURLE_TFTP_ILLEGAL;
+ break;
+ }
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_disconnect
+ *
+ * The disconnect callback
+ *
+ **********************************************************/
+static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ tftp_state_data_t *state = conn->proto.tftpc;
+ (void) dead_connection;
+
+ /* done, free dynamically allocated pkt buffers */
+ if(state) {
+ Curl_safefree(state->rpacket.data);
+ Curl_safefree(state->spacket.data);
+ free(state);
+ }
+
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_connect
+ *
+ * The connect callback
+ *
+ **********************************************************/
+static CURLcode tftp_connect(struct connectdata *conn, bool *done)
+{
+ tftp_state_data_t *state;
+ int blksize, rc;
+
+ blksize = TFTP_BLKSIZE_DEFAULT;
+
+ state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
+ if(!state)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* alloc pkt buffers based on specified blksize */
+ if(conn->data->set.tftp_blksize) {
+ blksize = (int)conn->data->set.tftp_blksize;
+ if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ if(!state->rpacket.data) {
+ state->rpacket.data = calloc(1, blksize + 2 + 2);
+
+ if(!state->rpacket.data)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!state->spacket.data) {
+ state->spacket.data = calloc(1, blksize + 2 + 2);
+
+ if(!state->spacket.data)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* we don't keep TFTP connections up basically because there's none or very
+ * little gain for UDP */
+ connclose(conn, "TFTP");
+
+ state->conn = conn;
+ state->sockfd = state->conn->sock[FIRSTSOCKET];
+ state->state = TFTP_STATE_START;
+ state->error = TFTP_ERR_NONE;
+ state->blksize = TFTP_BLKSIZE_DEFAULT;
+ state->requested_blksize = blksize;
+
+ ((struct sockaddr *)&state->local_addr)->sa_family =
+ (unsigned short)(conn->ip_addr->ai_family);
+
+ tftp_set_timeouts(state);
+
+ if(!conn->bits.bound) {
+ /* If not already bound, bind to any interface, random UDP port. If it is
+ * reused or a custom local port was desired, this has already been done!
+ *
+ * We once used the size of the local_addr struct as the third argument
+ * for bind() to better work with IPv6 or whatever size the struct could
+ * have, but we learned that at least Tru64, AIX and IRIX *requires* the
+ * size of that argument to match the exact size of a 'sockaddr_in' struct
+ * when running IPv4-only.
+ *
+ * Therefore we use the size from the address we connected to, which we
+ * assume uses the same IP version and thus hopefully this works for both
+ * IPv4 and IPv6...
+ */
+ rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
+ conn->ip_addr->ai_addrlen);
+ if(rc) {
+ failf(conn->data, "bind() failed; %s",
+ Curl_strerror(conn, SOCKERRNO));
+ return CURLE_COULDNT_CONNECT;
+ }
+ conn->bits.bound = TRUE;
+ }
+
+ Curl_pgrsStartNow(conn->data);
+
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_done
+ *
+ * The done callback
+ *
+ **********************************************************/
+static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ (void)status; /* unused */
+ (void)premature; /* not used */
+
+ if(Curl_pgrsDone(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ /* If we have encountered an error */
+ if(state)
+ result = tftp_translate_code(state->error);
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_getsock
+ *
+ * The getsock callback
+ *
+ **********************************************************/
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ return GETSOCK_READSOCK(0);
+}
+
+/**********************************************************
+ *
+ * tftp_receive_packet
+ *
+ * Called once select fires and data is ready on the socket
+ *
+ **********************************************************/
+static CURLcode tftp_receive_packet(struct connectdata *conn)
+{
+ struct Curl_sockaddr_storage fromaddr;
+ curl_socklen_t fromlen;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct SingleRequest *k = &data->req;
+
+ /* Receive the packet */
+ fromlen = sizeof(fromaddr);
+ state->rbytes = (int)recvfrom(state->sockfd,
+ (void *)state->rpacket.data,
+ state->blksize+4,
+ 0,
+ (struct sockaddr *)&fromaddr,
+ &fromlen);
+ if(state->remote_addrlen==0) {
+ memcpy(&state->remote_addr, &fromaddr, fromlen);
+ state->remote_addrlen = fromlen;
+ }
+
+ /* Sanity check packet length */
+ if(state->rbytes < 4) {
+ failf(data, "Received too short packet");
+ /* Not a timeout, but how best to handle it? */
+ state->event = TFTP_EVENT_TIMEOUT;
+ }
+ else {
+ /* The event is given by the TFTP packet time */
+ unsigned short event = getrpacketevent(&state->rpacket);
+ state->event = (tftp_event_t)event;
+
+ switch(state->event) {
+ case TFTP_EVENT_DATA:
+ /* Don't pass to the client empty or retransmitted packets */
+ if(state->rbytes > 4 &&
+ (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *)state->rpacket.data+4,
+ state->rbytes-4);
+ if(result) {
+ tftp_state_machine(state, TFTP_EVENT_ERROR);
+ return result;
+ }
+ k->bytecount += state->rbytes-4;
+ Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
+ }
+ break;
+ case TFTP_EVENT_ERROR:
+ {
+ unsigned short error = getrpacketblock(&state->rpacket);
+ state->error = (tftp_error_t)error;
+ infof(data, "%s\n", (const char *)state->rpacket.data+4);
+ break;
+ }
+ case TFTP_EVENT_ACK:
+ break;
+ case TFTP_EVENT_OACK:
+ result = tftp_parse_option_ack(state,
+ (const char *)state->rpacket.data+2,
+ state->rbytes-2);
+ if(result)
+ return result;
+ break;
+ case TFTP_EVENT_RRQ:
+ case TFTP_EVENT_WRQ:
+ default:
+ failf(data, "%s", "Internal error: Unexpected packet");
+ break;
+ }
+
+ /* Update the progress meter */
+ if(Curl_pgrsUpdate(conn)) {
+ tftp_state_machine(state, TFTP_EVENT_ERROR);
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_timeout
+ *
+ * Check if timeouts have been reached
+ *
+ **********************************************************/
+static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
+{
+ time_t current;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ if(event)
+ *event = TFTP_EVENT_NONE;
+
+ time(&current);
+ if(current > state->max_time) {
+ DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
+ (long)current, (long)state->max_time));
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ return 0;
+ }
+ if(current > state->rx_time+state->retry_time) {
+ if(event)
+ *event = TFTP_EVENT_TIMEOUT;
+ time(&state->rx_time); /* update even though we received nothing */
+ }
+
+ /* there's a typecast below here since 'time_t' may in fact be larger than
+ 'long', but we estimate that a 'long' will still be able to hold number
+ of seconds even if "only" 32 bit */
+ return (long)(state->max_time - current);
+}
+
+/**********************************************************
+ *
+ * tftp_multi_statemach
+ *
+ * Handle single RX socket event and return
+ *
+ **********************************************************/
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
+{
+ int rc;
+ tftp_event_t event;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ long timeout_ms = tftp_state_timeout(conn, &event);
+
+ *done = FALSE;
+
+ if(timeout_ms <= 0) {
+ failf(data, "TFTP response timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ if(event != TFTP_EVENT_NONE) {
+ result = tftp_state_machine(state, event);
+ if(result)
+ return result;
+ *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+ if(*done)
+ /* Tell curl we're done */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ }
+ else {
+ /* no timeouts to handle, check our socket */
+ rc = SOCKET_READABLE(state->sockfd, 0);
+
+ if(rc == -1) {
+ /* bail out */
+ int error = SOCKERRNO;
+ failf(data, "%s", Curl_strerror(conn, error));
+ state->event = TFTP_EVENT_ERROR;
+ }
+ else if(rc != 0) {
+ result = tftp_receive_packet(conn);
+ if(result)
+ return result;
+ result = tftp_state_machine(state, state->event);
+ if(result)
+ return result;
+ *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+ if(*done)
+ /* Tell curl we're done */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ }
+ /* if rc == 0, then select() timed out */
+ }
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_doing
+ *
+ * Called from multi.c while DOing
+ *
+ **********************************************************/
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result;
+ result = tftp_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ else if(!result) {
+ /* The multi code doesn't have this logic for the DOING state so we
+ provide it for TFTP since it may do the entire transfer in this
+ state. */
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(conn->data, Curl_tvnow());
+ }
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_peform
+ *
+ * Entry point for transfer from tftp_do, sarts state mach
+ *
+ **********************************************************/
+static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ *dophase_done = FALSE;
+
+ result = tftp_state_machine(state, TFTP_EVENT_INIT);
+
+ if((state->state == TFTP_STATE_FIN) || result)
+ return result;
+
+ tftp_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+
+/**********************************************************
+ *
+ * tftp_do
+ *
+ * The do callback
+ *
+ * This callback initiates the TFTP transfer
+ *
+ **********************************************************/
+
+static CURLcode tftp_do(struct connectdata *conn, bool *done)
+{
+ tftp_state_data_t *state;
+ CURLcode result;
+
+ *done = FALSE;
+
+ if(!conn->proto.tftpc) {
+ result = tftp_connect(conn, done);
+ if(result)
+ return result;
+ }
+
+ state = (tftp_state_data_t *)conn->proto.tftpc;
+ if(!state)
+ return CURLE_BAD_CALLING_ORDER;
+
+ result = tftp_perform(conn, done);
+
+ /* If tftp_perform() returned an error, use that for return code. If it
+ was OK, see if tftp_translate_code() has an error. */
+ if(!result)
+ /* If we have encountered an internal tftp error, translate it. */
+ result = tftp_translate_code(state->error);
+
+ return result;
+}
+
+static CURLcode tftp_setup_connection(struct connectdata * conn)
+{
+ struct Curl_easy *data = conn->data;
+ char *type;
+ char command;
+
+ conn->socktype = SOCK_DGRAM; /* UDP datagram based */
+
+ /* TFTP URLs support an extension like ";mode=<typecode>" that
+ * we'll try to get now! */
+ type = strstr(data->state.path, ";mode=");
+
+ if(!type)
+ type = strstr(conn->host.rawalloc, ";mode=");
+
+ if(type) {
+ *type = 0; /* it was in the middle of the hostname */
+ command = Curl_raw_toupper(type[6]);
+
+ switch(command) {
+ case 'A': /* ASCII mode */
+ case 'N': /* NETASCII mode */
+ data->set.prefer_ascii = TRUE;
+ break;
+
+ case 'O': /* octet mode */
+ case 'I': /* binary mode */
+ default:
+ /* switch off ASCII */
+ data->set.prefer_ascii = FALSE;
+ break;
+ }
+ }
+
+ return CURLE_OK;
+}
+#endif
diff --git a/Utilities/cmcurl/lib/tftp.h b/Utilities/cmcurl/lib/tftp.h
new file mode 100644
index 000000000..c2325b232
--- /dev/null
+++ b/Utilities/cmcurl/lib/tftp.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TFTP_H
+#define HEADER_CURL_TFTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TFTP
+extern const struct Curl_handler Curl_handler_tftp;
+#endif
+
+#endif /* HEADER_CURL_TFTP_H */
+
diff --git a/Utilities/cmcurl/lib/timeval.c b/Utilities/cmcurl/lib/timeval.c
new file mode 100644
index 000000000..bed44c573
--- /dev/null
+++ b/Utilities/cmcurl/lib/timeval.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "timeval.h"
+
+#if defined(WIN32) && !defined(MSDOS)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** GetTickCount() is available on _all_ Windows versions from W95 up
+ ** to nowadays. Returns milliseconds elapsed since last system boot,
+ ** increases monotonically and wraps once 49.7 days have elapsed.
+ */
+ struct timeval now;
+#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
+ (_WIN32_WINNT < _WIN32_WINNT_VISTA)
+ DWORD milliseconds = GetTickCount();
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
+#else
+ ULONGLONG milliseconds = GetTickCount64();
+ now.tv_sec = (long) (milliseconds / 1000);
+ now.tv_usec = (long) (milliseconds % 1000) * 1000;
+#endif
+
+ return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** clock_gettime() is granted to be increased monotonically when the
+ ** monotonic clock is queried. Time starting point is unspecified, it
+ ** could be the system start-up time, the Epoch, or something else,
+ ** in any case the time starting point does not change once that the
+ ** system has started up.
+ */
+ struct timeval now;
+ struct timespec tsnow;
+ if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+ now.tv_sec = tsnow.tv_sec;
+ now.tv_usec = tsnow.tv_nsec / 1000;
+ }
+ /*
+ ** Even when the configure process has truly detected monotonic clock
+ ** availability, it might happen that it is not actually available at
+ ** run-time. When this occurs simply fallback to other time source.
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ else
+ (void)gettimeofday(&now, NULL);
+#else
+ else {
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ }
+#endif
+ return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** gettimeofday() is not granted to be increased monotonically, due to
+ ** clock drifting and external source time synchronization it can jump
+ ** forward or backward in time.
+ */
+ struct timeval now;
+ (void)gettimeofday(&now, NULL);
+ return now;
+}
+
+#else
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** time() returns the value of time in seconds since the Epoch.
+ */
+ struct timeval now;
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ return now;
+}
+
+#endif
+
+/*
+ * Make sure that the first argument is the more recent time, as otherwise
+ * we'll get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds. For large diffs it
+ * returns 0x7fffffff on 32bit time_t systems.
+ */
+time_t curlx_tvdiff(struct timeval newer, struct timeval older)
+{
+#if SIZEOF_TIME_T < 8
+ /* for 32bit time_t systems, add a precaution to avoid overflow for really
+ big time differences */
+ time_t diff = newer.tv_sec-older.tv_sec;
+ if(diff >= (0x7fffffff/1000))
+ return 0x7fffffff;
+#endif
+ return (newer.tv_sec-older.tv_sec)*1000+
+ (time_t)(newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval newer, struct timeval older)
+{
+ if(newer.tv_sec != older.tv_sec)
+ return (double)(newer.tv_sec-older.tv_sec)+
+ (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+ return (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+}
diff --git a/Utilities/cmcurl/lib/timeval.h b/Utilities/cmcurl/lib/timeval.h
new file mode 100644
index 000000000..33969354d
--- /dev/null
+++ b/Utilities/cmcurl/lib/timeval.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_TIMEVAL_H
+#define HEADER_CURL_TIMEVAL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "curl_setup.h"
+
+struct timeval curlx_tvnow(void);
+
+/*
+ * Make sure that the first argument (t1) is the more recent time and t2 is
+ * the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+time_t curlx_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+/* These two defines below exist to provide the older API for library
+ internals only. */
+#define Curl_tvnow() curlx_tvnow()
+#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y)
+
+#endif /* HEADER_CURL_TIMEVAL_H */
+
diff --git a/Utilities/cmcurl/lib/transfer.c b/Utilities/cmcurl/lib/transfer.c
new file mode 100644
index 000000000..43e8f64aa
--- /dev/null
+++ b/Utilities/cmcurl/lib/transfer.c
@@ -0,0 +1,1965 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "strtoofft.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "content_encoding.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "speedcheck.h"
+#include "progress.h"
+#include "http.h"
+#include "url.h"
+#include "getinfo.h"
+#include "vtls/vtls.h"
+#include "select.h"
+#include "multiif.h"
+#include "connect.h"
+#include "non-ascii.h"
+#include "http2.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * This function will call the read callback to fill our buffer with data
+ * to upload.
+ */
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
+{
+ struct Curl_easy *data = conn->data;
+ size_t buffersize = (size_t)bytes;
+ int nread;
+#ifdef CURL_DOES_CONVERSIONS
+ bool sending_http_headers = FALSE;
+
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+ const struct HTTP *http = data->req.protop;
+
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+ Remember that so we don't re-translate them into garbage. */
+ sending_http_headers = TRUE;
+ }
+#endif
+
+ if(data->req.upload_chunky) {
+ /* if chunked Transfer-Encoding */
+ buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
+ data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
+ }
+
+ /* this function returns a size_t, so we typecast to int to prevent warnings
+ with picky compilers */
+ nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
+ buffersize, data->state.in);
+
+ if(nread == CURL_READFUNC_ABORT) {
+ failf(data, "operation aborted by callback");
+ *nreadp = 0;
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ if(nread == CURL_READFUNC_PAUSE) {
+ struct SingleRequest *k = &data->req;
+
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ /* protocols that work without network cannot be paused. This is
+ actually only FILE:// just now, and it can't pause since the transfer
+ isn't done using the "normal" procedure. */
+ failf(data, "Read callback asked for PAUSE when not supported!");
+ return CURLE_READ_ERROR;
+ }
+
+ /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+ k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+ if(data->req.upload_chunky) {
+ /* Back out the preallocation done above */
+ data->req.upload_fromhere -= (8 + 2);
+ }
+ *nreadp = 0;
+
+ return CURLE_OK; /* nothing was read */
+ }
+ else if((size_t)nread > buffersize) {
+ /* the read function returned a too large value */
+ *nreadp = 0;
+ failf(data, "read function returned funny value");
+ return CURLE_READ_ERROR;
+ }
+
+ if(!data->req.forbidchunk && data->req.upload_chunky) {
+ /* if chunked Transfer-Encoding
+ * build chunk:
+ *
+ * <HEX SIZE> CRLF
+ * <DATA> CRLF
+ */
+ /* On non-ASCII platforms the <DATA> may or may not be
+ translated based on set.prefer_ascii while the protocol
+ portion must always be translated to the network encoding.
+ To further complicate matters, line end conversion might be
+ done later on, so we need to prevent CRLFs from becoming
+ CRCRLFs if that's the case. To do this we use bare LFs
+ here, knowing they'll become CRLFs later on.
+ */
+
+ char hexbuffer[11];
+ const char *endofline_native;
+ const char *endofline_network;
+ int hexlen;
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (data->set.prefer_ascii) ||
+#endif
+ (data->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+ hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
+ "%x%s", nread, endofline_native);
+
+ /* move buffer pointer */
+ data->req.upload_fromhere -= hexlen;
+ nread += hexlen;
+
+ /* copy the prefix to the buffer, leaving out the NUL */
+ memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+ /* always append ASCII CRLF to the data */
+ memcpy(data->req.upload_fromhere + nread,
+ endofline_network,
+ strlen(endofline_network));
+
+#ifdef CURL_DOES_CONVERSIONS
+ CURLcode result;
+ int length;
+ if(data->set.prefer_ascii) {
+ /* translate the protocol and data */
+ length = nread;
+ }
+ else {
+ /* just translate the protocol portion */
+ length = strlen(hexbuffer);
+ }
+ result = Curl_convert_to_network(data, data->req.upload_fromhere, length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if((nread - hexlen) == 0)
+ /* mark this as done once this chunk is transferred */
+ data->req.upload_done = TRUE;
+
+ nread+=(int)strlen(endofline_native); /* for the added end of line */
+ }
+#ifdef CURL_DOES_CONVERSIONS
+ else if((data->set.prefer_ascii) && (!sending_http_headers)) {
+ CURLcode result;
+ result = Curl_convert_to_network(data, data->req.upload_fromhere, nread);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(result)
+ return result;
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ *nreadp = nread;
+
+ return CURLE_OK;
+}
+
+
+/*
+ * Curl_readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+CURLcode Curl_readrewind(struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+
+ conn->bits.rewindaftersend = FALSE; /* we rewind now */
+
+ /* explicitly switch off sending data on this connection now since we are
+ about to restart a new transfer and thus we want to avoid inadvertently
+ sending more data on the existing connection until the next transfer
+ starts */
+ data->req.keepon &= ~KEEP_SEND;
+
+ /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+ if(data->set.postfields ||
+ (data->set.httpreq == HTTPREQ_POST_FORM))
+ ; /* do nothing */
+ else {
+ if(data->set.seek_func) {
+ int err;
+
+ err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+ if(err) {
+ failf(data, "seek callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else if(data->set.ioctl_func) {
+ curlioerr err;
+
+ err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+ data->set.ioctl_client);
+ infof(data, "the ioctl callback returned %d\n", (int)err);
+
+ if(err) {
+ /* FIXME: convert to a human readable error message */
+ failf(data, "ioctl callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else {
+ /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+ given FILE * stream and we can actually attempt to rewind that
+ ourselves with fseek() */
+ if(data->state.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->state.in, 0, SEEK_SET))
+ /* successful rewind */
+ return CURLE_OK;
+ }
+
+ /* no callback set or failure above, makes us fail at once */
+ failf(data, "necessary data rewind wasn't possible");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ return CURLE_OK;
+}
+
+static int data_pending(const struct connectdata *conn)
+{
+ /* in the case of libssh2, we can never be really sure that we have emptied
+ its internal buffers so we MUST always try until we get EAGAIN back */
+ return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
+#if defined(USE_NGHTTP2)
+ Curl_ssl_data_pending(conn, FIRSTSOCKET) ||
+ /* For HTTP/2, we may read up everything including responde body
+ with header fields in Curl_http_readwrite_headers. If no
+ content-length is provided, curl waits for the connection
+ close, which we emulate it using conn->proto.httpc.closed =
+ TRUE. The thing is if we read everything, then http2_recv won't
+ be called and we cannot signal the HTTP/2 stream has closed. As
+ a workaround, we return nonzero here to call http2_recv. */
+ ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion == 20);
+#else
+ Curl_ssl_data_pending(conn, FIRSTSOCKET);
+#endif
+}
+
+static void read_rewind(struct connectdata *conn,
+ size_t thismuch)
+{
+ DEBUGASSERT(conn->read_pos >= thismuch);
+
+ conn->read_pos -= thismuch;
+ conn->bits.stream_was_rewound = TRUE;
+
+#ifdef DEBUGBUILD
+ {
+ char buf[512 + 1];
+ size_t show;
+
+ show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
+ if(conn->master_buffer) {
+ memcpy(buf, conn->master_buffer + conn->read_pos, show);
+ buf[show] = '\0';
+ }
+ else {
+ buf[0] = '\0';
+ }
+
+ DEBUGF(infof(conn->data,
+ "Buffer after stream rewind (read_pos = %zu): [%s]\n",
+ conn->read_pos, buf));
+ }
+#endif
+}
+
+/*
+ * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
+ * remote document with the time provided by CURLOPT_TIMEVAL
+ */
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
+{
+ if((timeofdoc == 0) || (data->set.timevalue == 0))
+ return TRUE;
+
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ if(timeofdoc <= data->set.timevalue) {
+ infof(data,
+ "The requested document is not new enough\n");
+ data->info.timecond = TRUE;
+ return FALSE;
+ }
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ if(timeofdoc >= data->set.timevalue) {
+ infof(data,
+ "The requested document is not old enough\n");
+ data->info.timecond = TRUE;
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Go ahead and do a read if we have a readable socket or if
+ * the stream was rewound (in which case we have data in a
+ * buffer)
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
+ */
+static CURLcode readwrite_data(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct SingleRequest *k,
+ int *didwhat, bool *done,
+ bool *comeback)
+{
+ CURLcode result = CURLE_OK;
+ ssize_t nread; /* number of bytes read */
+ size_t excess = 0; /* excess bytes read */
+ bool is_empty_data = FALSE;
+ bool readmore = FALSE; /* used by RTP to signal for more data */
+ int maxloops = 100;
+
+ *done = FALSE;
+ *comeback = FALSE;
+
+ /* This is where we loop until we have read everything there is to
+ read or we get a CURLE_AGAIN */
+ do {
+ size_t buffersize = data->set.buffer_size;
+ size_t bytestoread = buffersize;
+
+ if(
+#if defined(USE_NGHTTP2)
+ /* For HTTP/2, read data without caring about the content
+ length. This is safe because body in HTTP/2 is always
+ segmented thanks to its framing layer. Meanwhile, we have to
+ call Curl_read to ensure that http2_handle_stream_close is
+ called when we read all incoming bytes for a particular
+ stream. */
+ !((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ conn->httpversion == 20) &&
+#endif
+ k->size != -1 && !k->header) {
+ /* make sure we don't read "too much" if we can help it since we
+ might be pipelining and then someone else might want to read what
+ follows! */
+ curl_off_t totalleft = k->size - k->bytecount;
+ if(totalleft < (curl_off_t)bytestoread)
+ bytestoread = (size_t)totalleft;
+ }
+
+ if(bytestoread) {
+ /* receive data from the network! */
+ result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
+
+ /* read would've blocked */
+ if(CURLE_AGAIN == result)
+ break; /* get out of loop */
+
+ if(result>0)
+ return result;
+ }
+ else {
+ /* read nothing but since we wanted nothing we consider this an OK
+ situation to proceed from */
+ DEBUGF(infof(data, "readwrite_data: we're done!\n"));
+ nread = 0;
+ }
+
+ if((k->bytecount == 0) && (k->writebytecount == 0)) {
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+ if(k->exp100 > EXP100_SEND_DATA)
+ /* set time stamp to compare with when waiting for the 100 */
+ k->start100 = Curl_tvnow();
+ }
+
+ *didwhat |= KEEP_RECV;
+ /* indicates data of zero size, i.e. empty file */
+ is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
+
+ /* NUL terminate, allowing string ops to be used */
+ if(0 < nread || is_empty_data) {
+ k->buf[nread] = 0;
+ }
+ else if(0 >= nread) {
+ /* if we receive 0 or less here, the server closed the connection
+ and we bail out from this! */
+ DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
+ k->keepon &= ~KEEP_RECV;
+ break;
+ }
+
+ /* Default buffer to use when we write the buffer, it may be changed
+ in the flow below before the actual storing is done. */
+ k->str = k->buf;
+
+ if(conn->handler->readwrite) {
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+ if(readmore)
+ break;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ /* Since this is a two-state thing, we check if we are parsing
+ headers at the moment or not. */
+ if(k->header) {
+ /* we are in parse-the-header-mode */
+ bool stop_reading = FALSE;
+ result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
+ if(result)
+ return result;
+
+ if(conn->handler->readwrite &&
+ (k->maxdownload <= 0 && nread > 0)) {
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+ if(readmore)
+ break;
+ }
+
+ if(stop_reading) {
+ /* We've stopped dealing with input, get out of the do-while loop */
+
+ if(nread > 0) {
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
+ infof(data,
+ "Rewinding stream by : %zd"
+ " bytes on url %s (zero-length body)\n",
+ nread, data->state.path);
+ read_rewind(conn, (size_t)nread);
+ }
+ else {
+ infof(data,
+ "Excess found in a non pipelined read:"
+ " excess = %zd"
+ " url = %s (zero-length body)\n",
+ nread, data->state.path);
+ }
+ }
+
+ break;
+ }
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+
+ /* This is not an 'else if' since it may be a rest from the header
+ parsing, where the beginning of the buffer is headers and the end
+ is non-headers. */
+ if(k->str && !k->header && (nread > 0 || is_empty_data)) {
+
+ if(data->set.opt_no_body) {
+ /* data arrives although we want none, bail out */
+ streamclose(conn, "ignoring body");
+ *done = TRUE;
+ return CURLE_WEIRD_SERVER_REPLY;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ if(0 == k->bodywrites && !is_empty_data) {
+ /* These checks are only made the first time we are about to
+ write a piece of the body */
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+ /* HTTP-only checks */
+
+ if(data->req.newurl) {
+ if(conn->bits.close) {
+ /* Abort after the headers if "follow Location" is set
+ and we're set to close anyway. */
+ k->keepon &= ~KEEP_RECV;
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ /* We have a new url to load, but since we want to be able
+ to re-use this connection properly, we read the full
+ response in "ignore more" */
+ k->ignorebody = TRUE;
+ infof(data, "Ignoring the response-body\n");
+ }
+ if(data->state.resume_from && !k->content_range &&
+ (data->set.httpreq==HTTPREQ_GET) &&
+ !k->ignorebody) {
+
+ if(k->size == data->state.resume_from) {
+ /* The resume point is at the end of file, consider this fine
+ even if it doesn't allow resume from here. */
+ infof(data, "The entire document is already downloaded");
+ connclose(conn, "already downloaded");
+ /* Abort download */
+ k->keepon &= ~KEEP_RECV;
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ /* we wanted to resume a download, although the server doesn't
+ * seem to support this and we did this with a GET (if it
+ * wasn't a GET we did a POST or PUT resume) */
+ failf(data, "HTTP server doesn't seem to support "
+ "byte ranges. Cannot resume.");
+ return CURLE_RANGE_ERROR;
+ }
+
+ if(data->set.timecondition && !data->state.range) {
+ /* A time condition has been set AND no ranges have been
+ requested. This seems to be what chapter 13.3.4 of
+ RFC 2616 defines to be the correct action for a
+ HTTP/1.1 client */
+
+ if(!Curl_meets_timecondition(data, k->timeofdoc)) {
+ *done = TRUE;
+ /* We're simulating a http 304 from server so we return
+ what should have been returned from the server */
+ data->info.httpcode = 304;
+ infof(data, "Simulate a HTTP 304 response!\n");
+ /* we abort the transfer before it is completed == we ruin the
+ re-use ability. Close the connection */
+ connclose(conn, "Simulated 304 handling");
+ return CURLE_OK;
+ }
+ } /* we have a time condition */
+
+ } /* this is HTTP or RTSP */
+ } /* this is the first time we write a body part */
+#endif /* CURL_DISABLE_HTTP */
+
+ k->bodywrites++;
+
+ /* pass data to the debug function before it gets "dechunked" */
+ if(data->set.verbose) {
+ if(k->badheader) {
+ Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
+ (size_t)k->hbuflen, conn);
+ if(k->badheader == HEADER_PARTHEADER)
+ Curl_debug(data, CURLINFO_DATA_IN,
+ k->str, (size_t)nread, conn);
+ }
+ else
+ Curl_debug(data, CURLINFO_DATA_IN,
+ k->str, (size_t)nread, conn);
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ if(k->chunk) {
+ /*
+ * Here comes a chunked transfer flying and we need to decode this
+ * properly. While the name says read, this function both reads
+ * and writes away the data. The returned 'nread' holds the number
+ * of actual data it wrote to the client.
+ */
+
+ CHUNKcode res =
+ Curl_httpchunk_read(conn, k->str, nread, &nread);
+
+ if(CHUNKE_OK < res) {
+ if(CHUNKE_WRITE_ERROR == res) {
+ failf(data, "Failed writing data");
+ return CURLE_WRITE_ERROR;
+ }
+ failf(data, "%s in chunked-encoding", Curl_chunked_strerror(res));
+ return CURLE_RECV_ERROR;
+ }
+ if(CHUNKE_STOP == res) {
+ size_t dataleft;
+ /* we're done reading chunks! */
+ k->keepon &= ~KEEP_RECV; /* read no more */
+
+ /* There are now possibly N number of bytes at the end of the
+ str buffer that weren't written to the client.
+
+ We DO care about this data if we are pipelining.
+ Push it back to be read on the next pass. */
+
+ dataleft = conn->chunk.dataleft;
+ if(dataleft != 0) {
+ infof(conn->data, "Leftovers after chunking: %zu bytes\n",
+ dataleft);
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
+ /* only attempt the rewind if we truly are pipelining */
+ infof(conn->data, "Rewinding %zu bytes\n",dataleft);
+ read_rewind(conn, dataleft);
+ }
+ }
+ }
+ /* If it returned OK, we just keep going */
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+ /* Account for body content stored in the header buffer */
+ if(k->badheader && !k->ignorebody) {
+ DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n",
+ k->hbuflen));
+ k->bytecount += k->hbuflen;
+ }
+
+ if((-1 != k->maxdownload) &&
+ (k->bytecount + nread >= k->maxdownload)) {
+
+ excess = (size_t)(k->bytecount + nread - k->maxdownload);
+ if(excess > 0 && !k->ignorebody) {
+ if(Curl_pipeline_wanted(conn->data->multi, CURLPIPE_HTTP1)) {
+ infof(data,
+ "Rewinding stream by : %zu"
+ " bytes on url %s (size = %" CURL_FORMAT_CURL_OFF_T
+ ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T ", nread = %zd)\n",
+ excess, data->state.path,
+ k->size, k->maxdownload, k->bytecount, nread);
+ read_rewind(conn, excess);
+ }
+ else {
+ infof(data,
+ "Excess found in a non pipelined read:"
+ " excess = %zu"
+ ", size = %" CURL_FORMAT_CURL_OFF_T
+ ", maxdownload = %" CURL_FORMAT_CURL_OFF_T
+ ", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
+ excess, k->size, k->maxdownload, k->bytecount);
+ }
+ }
+
+ nread = (ssize_t) (k->maxdownload - k->bytecount);
+ if(nread < 0) /* this should be unusual */
+ nread = 0;
+
+ k->keepon &= ~KEEP_RECV; /* we're done reading */
+ }
+
+ k->bytecount += nread;
+
+ Curl_pgrsSetDownloadCounter(data, k->bytecount);
+
+ if(!k->chunk && (nread || k->badheader || is_empty_data)) {
+ /* If this is chunky transfer, it was already written */
+
+ if(k->badheader && !k->ignorebody) {
+ /* we parsed a piece of data wrongly assuming it was a header
+ and now we output it as body instead */
+
+ /* Don't let excess data pollute body writes */
+ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ data->state.headerbuff,
+ k->hbuflen);
+ else
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ data->state.headerbuff,
+ (size_t)k->maxdownload);
+
+ if(result)
+ return result;
+ }
+ if(k->badheader < HEADER_ALLBAD) {
+ /* This switch handles various content encodings. If there's an
+ error here, be sure to check over the almost identical code
+ in http_chunks.c.
+ Make sure that ALL_CONTENT_ENCODINGS contains all the
+ encodings handled here. */
+#ifdef HAVE_LIBZ
+ switch(conn->data->set.http_ce_skip ?
+ IDENTITY : k->auto_decoding) {
+ case IDENTITY:
+#endif
+ /* This is the default when the server sends no
+ Content-Encoding header. See Curl_readwrite_init; the
+ memset() call initializes k->auto_decoding to zero. */
+ if(!k->ignorebody) {
+
+#ifndef CURL_DISABLE_POP3
+ if(conn->handler->protocol&PROTO_FAMILY_POP3)
+ result = Curl_pop3_write(conn, k->str, nread);
+ else
+#endif /* CURL_DISABLE_POP3 */
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
+ nread);
+ }
+#ifdef HAVE_LIBZ
+ break;
+
+ case DEFLATE:
+ /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+ if(!k->ignorebody)
+ result = Curl_unencode_deflate_write(conn, k, nread);
+ break;
+
+ case GZIP:
+ /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+ if(!k->ignorebody)
+ result = Curl_unencode_gzip_write(conn, k, nread);
+ break;
+
+ default:
+ failf(data, "Unrecognized content encoding type. "
+ "libcurl understands `identity', `deflate' and `gzip' "
+ "content encodings.");
+ result = CURLE_BAD_CONTENT_ENCODING;
+ break;
+ }
+#endif
+ }
+ k->badheader = HEADER_NORMAL; /* taken care of now */
+
+ if(result)
+ return result;
+ }
+
+ } /* if(!header and data to read) */
+
+ if(conn->handler->readwrite &&
+ (excess > 0 && !conn->bits.stream_was_rewound)) {
+ /* Parse the excess data */
+ k->str += nread;
+ nread = (ssize_t)excess;
+
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+
+ if(readmore)
+ k->keepon |= KEEP_RECV; /* we're not done reading */
+ break;
+ }
+
+ if(is_empty_data) {
+ /* if we received nothing, the server closed the connection and we
+ are done */
+ k->keepon &= ~KEEP_RECV;
+ }
+
+ } while(data_pending(conn) && maxloops--);
+
+ if(maxloops <= 0) {
+ /* we mark it as read-again-please */
+ conn->cselect_bits = CURL_CSELECT_IN;
+ *comeback = TRUE;
+ }
+
+ if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
+ conn->bits.close) {
+ /* When we've read the entire thing and the close bit is set, the server
+ may now close the connection. If there's now any kind of sending going
+ on from our side, we need to stop that immediately. */
+ infof(data, "we are done reading and this is set to close, stop send\n");
+ k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode done_sending(struct connectdata *conn,
+ struct SingleRequest *k)
+{
+ k->keepon &= ~KEEP_SEND; /* we're done writing */
+
+ Curl_http2_done_sending(conn);
+
+ if(conn->bits.rewindaftersend) {
+ CURLcode result = Curl_readrewind(conn);
+ if(result)
+ return result;
+ }
+ return CURLE_OK;
+}
+
+
+/*
+ * Send data to upload to the server, when the socket is writable.
+ */
+static CURLcode readwrite_upload(struct Curl_easy *data,
+ struct connectdata *conn,
+ int *didwhat)
+{
+ ssize_t i, si;
+ ssize_t bytes_written;
+ CURLcode result;
+ ssize_t nread; /* number of bytes read */
+ bool sending_http_headers = FALSE;
+ struct SingleRequest *k = &data->req;
+
+ if((k->bytecount == 0) && (k->writebytecount == 0))
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+ *didwhat |= KEEP_SEND;
+
+ do {
+
+ /* only read more data if there's no upload data already
+ present in the upload buffer */
+ if(0 == k->upload_present) {
+ /* init the "upload from here" pointer */
+ k->upload_fromhere = data->state.uploadbuffer;
+
+ if(!k->upload_done) {
+ /* HTTP pollution, this should be written nicer to become more
+ protocol agnostic. */
+ int fillcount;
+ struct HTTP *http = k->protop;
+
+ if((k->exp100 == EXP100_SENDING_REQUEST) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* If this call is to send body data, we must take some action:
+ We have sent off the full HTTP 1.1 request, and we shall now
+ go into the Expect: 100 state and await such a header */
+ k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
+ k->keepon &= ~KEEP_SEND; /* disable writing */
+ k->start100 = Curl_tvnow(); /* timeout count starts now */
+ *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
+
+ /* set a timeout for the multi interface */
+ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
+ break;
+ }
+
+ if(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)) {
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+ Remember that so we don't change the line endings. */
+ sending_http_headers = TRUE;
+ else
+ sending_http_headers = FALSE;
+ }
+
+ result = Curl_fillreadbuffer(conn, UPLOAD_BUFSIZE, &fillcount);
+ if(result)
+ return result;
+
+ nread = (ssize_t)fillcount;
+ }
+ else
+ nread = 0; /* we're done uploading/reading */
+
+ if(!nread && (k->keepon & KEEP_SEND_PAUSE)) {
+ /* this is a paused transfer */
+ break;
+ }
+ if(nread<=0) {
+ result = done_sending(conn, k);
+ if(result)
+ return result;
+ break;
+ }
+
+ /* store number of bytes available for upload */
+ k->upload_present = nread;
+
+ /* convert LF to CRLF if so asked */
+ if((!sending_http_headers) && (
+#ifdef CURL_DO_LINEEND_CONV
+ /* always convert if we're FTPing in ASCII mode */
+ (data->set.prefer_ascii) ||
+#endif
+ (data->set.crlf))) {
+ /* Do we need to allocate a scratch buffer? */
+ if(!data->state.scratch) {
+ data->state.scratch = malloc(2 * data->set.buffer_size);
+ if(!data->state.scratch) {
+ failf(data, "Failed to alloc scratch buffer!");
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /*
+ * ASCII/EBCDIC Note: This is presumably a text (not binary)
+ * transfer so the data should already be in ASCII.
+ * That means the hex values for ASCII CR (0x0d) & LF (0x0a)
+ * must be used instead of the escape sequences \r & \n.
+ */
+ for(i = 0, si = 0; i < nread; i++, si++) {
+ if(k->upload_fromhere[i] == 0x0a) {
+ data->state.scratch[si++] = 0x0d;
+ data->state.scratch[si] = 0x0a;
+ if(!data->set.crlf) {
+ /* we're here only because FTP is in ASCII mode...
+ bump infilesize for the LF we just added */
+ if(data->state.infilesize != -1)
+ data->state.infilesize++;
+ }
+ }
+ else
+ data->state.scratch[si] = k->upload_fromhere[i];
+ }
+
+ if(si != nread) {
+ /* only perform the special operation if we really did replace
+ anything */
+ nread = si;
+
+ /* upload from the new (replaced) buffer instead */
+ k->upload_fromhere = data->state.scratch;
+
+ /* set the new amount too */
+ k->upload_present = nread;
+ }
+ }
+
+#ifndef CURL_DISABLE_SMTP
+ if(conn->handler->protocol & PROTO_FAMILY_SMTP) {
+ result = Curl_smtp_escape_eob(conn, nread);
+ if(result)
+ return result;
+ }
+#endif /* CURL_DISABLE_SMTP */
+ } /* if 0 == k->upload_present */
+ else {
+ /* We have a partial buffer left from a previous "round". Use
+ that instead of reading more data */
+ }
+
+ /* write to socket (send away data) */
+ result = Curl_write(conn,
+ conn->writesockfd, /* socket to send to */
+ k->upload_fromhere, /* buffer pointer */
+ k->upload_present, /* buffer size */
+ &bytes_written); /* actually sent */
+
+ if(result)
+ return result;
+
+ if(data->set.verbose)
+ /* show the data before we change the pointer upload_fromhere */
+ Curl_debug(data, CURLINFO_DATA_OUT, k->upload_fromhere,
+ (size_t)bytes_written, conn);
+
+ k->writebytecount += bytes_written;
+
+ if(k->writebytecount == data->state.infilesize) {
+ /* we have sent all data we were supposed to */
+ k->upload_done = TRUE;
+ infof(data, "We are completely uploaded and fine\n");
+ }
+
+ if(k->upload_present != bytes_written) {
+ /* we only wrote a part of the buffer (if anything), deal with it! */
+
+ /* store the amount of bytes left in the buffer to write */
+ k->upload_present -= bytes_written;
+
+ /* advance the pointer where to find the buffer when the next send
+ is to happen */
+ k->upload_fromhere += bytes_written;
+ }
+ else {
+ /* we've uploaded that buffer now */
+ k->upload_fromhere = data->state.uploadbuffer;
+ k->upload_present = 0; /* no more bytes left */
+
+ if(k->upload_done) {
+ result = done_sending(conn, k);
+ if(result)
+ return result;
+ }
+ }
+
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+
+ } WHILE_FALSE; /* just to break out from! */
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_readwrite() is the low-level function to be called when data is to
+ * be read and written to/from the connection.
+ *
+ * return '*comeback' TRUE if we didn't properly drain the socket so this
+ * function should get called again without select() or similar in between!
+ */
+CURLcode Curl_readwrite(struct connectdata *conn,
+ struct Curl_easy *data,
+ bool *done,
+ bool *comeback)
+{
+ struct SingleRequest *k = &data->req;
+ CURLcode result;
+ int didwhat=0;
+
+ curl_socket_t fd_read;
+ curl_socket_t fd_write;
+ int select_res = conn->cselect_bits;
+
+ conn->cselect_bits = 0;
+
+ /* only use the proper socket if the *_HOLD bit is not set simultaneously as
+ then we are in rate limiting state in that transfer direction */
+
+ if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
+ fd_read = conn->sockfd;
+ else
+ fd_read = CURL_SOCKET_BAD;
+
+ if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+ fd_write = conn->writesockfd;
+ else
+ fd_write = CURL_SOCKET_BAD;
+
+ if(conn->data->state.drain) {
+ select_res |= CURL_CSELECT_IN;
+ DEBUGF(infof(data, "Curl_readwrite: forcibly told to drain data\n"));
+ }
+
+ if(!select_res) /* Call for select()/poll() only, if read/write/error
+ status is not known. */
+ select_res = Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write, 0);
+
+ if(select_res == CURL_CSELECT_ERR) {
+ failf(data, "select/poll returned error");
+ return CURLE_SEND_ERROR;
+ }
+
+ /* We go ahead and do a read if we have a readable socket or if
+ the stream was rewound (in which case we have data in a
+ buffer) */
+ if((k->keepon & KEEP_RECV) &&
+ ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
+
+ result = readwrite_data(data, conn, k, &didwhat, done, comeback);
+ if(result || *done)
+ return result;
+ }
+
+ /* If we still have writing to do, we check if we have a writable socket. */
+ if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) {
+ /* write */
+
+ result = readwrite_upload(data, conn, &didwhat);
+ if(result)
+ return result;
+ }
+
+ k->now = Curl_tvnow();
+ if(didwhat) {
+ /* Update read/write counters */
+ if(k->bytecountp)
+ *k->bytecountp = k->bytecount; /* read count */
+ if(k->writebytecountp)
+ *k->writebytecountp = k->writebytecount; /* write count */
+ }
+ else {
+ /* no read no write, this is a timeout? */
+ if(k->exp100 == EXP100_AWAITING_CONTINUE) {
+ /* This should allow some time for the header to arrive, but only a
+ very short time as otherwise it'll be too much wasted time too
+ often. */
+
+ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
+
+ Therefore, when a client sends this header field to an origin server
+ (possibly via a proxy) from which it has never seen a 100 (Continue)
+ status, the client SHOULD NOT wait for an indefinite period before
+ sending the request body.
+
+ */
+
+ time_t ms = Curl_tvdiff(k->now, k->start100);
+ if(ms >= data->set.expect_100_timeout) {
+ /* we've waited long enough, continue anyway */
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ Curl_expire_done(data, EXPIRE_100_TIMEOUT);
+ infof(data, "Done waiting for 100-continue\n");
+ }
+ }
+ }
+
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, k->now);
+ if(result)
+ return result;
+
+ if(k->keepon) {
+ if(0 > Curl_timeleft(data, &k->now, FALSE)) {
+ if(k->size != -1) {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ CURL_FORMAT_CURL_OFF_T " out of %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount,
+ k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ CURL_FORMAT_CURL_OFF_T " bytes received",
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount);
+ }
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ else {
+ /*
+ * The transfer has been performed. Just make some general checks before
+ * returning.
+ */
+
+ if(!(data->set.opt_no_body) && (k->size != -1) &&
+ (k->bytecount != k->size) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs,
+ so we'll check to see if the discrepancy can be explained
+ by the number of CRLFs we've changed to LFs.
+ */
+ (k->bytecount != (k->size + data->state.crlf_conversions)) &&
+#endif /* CURL_DO_LINEEND_CONV */
+ !k->newurl) {
+ failf(data, "transfer closed with %" CURL_FORMAT_CURL_OFF_T
+ " bytes remaining to read", k->size - k->bytecount);
+ return CURLE_PARTIAL_FILE;
+ }
+ if(!(data->set.opt_no_body) && k->chunk &&
+ (conn->chunk.state != CHUNK_STOP)) {
+ /*
+ * In chunked mode, return an error if the connection is closed prior to
+ * the empty (terminating) chunk is read.
+ *
+ * The condition above used to check for
+ * conn->proto.http->chunk.datasize != 0 which is true after reading
+ * *any* chunk, not just the empty chunk.
+ *
+ */
+ failf(data, "transfer closed with outstanding read data remaining");
+ return CURLE_PARTIAL_FILE;
+ }
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+
+ /* Now update the "done" boolean we return */
+ *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
+ KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_single_getsock() gets called by the multi interface code when the app
+ * has requested to get the sockets for the current connection. This function
+ * will then be called once for every connection that the multi interface
+ * keeps track of. This function will only be called for connections that are
+ * in the proper state to have this information available.
+ */
+int Curl_single_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+ const struct Curl_easy *data = conn->data;
+ int bitmap = GETSOCK_BLANK;
+ unsigned sockindex = 0;
+
+ if(conn->handler->perform_getsock)
+ return conn->handler->perform_getsock(conn, sock, numsocks);
+
+ if(numsocks < 2)
+ /* simple check but we might need two slots */
+ return GETSOCK_BLANK;
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
+
+ DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+
+ bitmap |= GETSOCK_READSOCK(sockindex);
+ sock[sockindex] = conn->sockfd;
+ }
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
+
+ if((conn->sockfd != conn->writesockfd) ||
+ bitmap == GETSOCK_BLANK) {
+ /* only if they are not the same socket and we have a readable
+ one, we increase index */
+ if(bitmap != GETSOCK_BLANK)
+ sockindex++; /* increase index if we need two entries */
+
+ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+
+ sock[sockindex] = conn->writesockfd;
+ }
+
+ bitmap |= GETSOCK_WRITESOCK(sockindex);
+ }
+
+ return bitmap;
+}
+
+/* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
+ which means this gets called once for each subsequent redirect etc */
+void Curl_init_CONNECT(struct Curl_easy *data)
+{
+ data->state.fread_func = data->set.fread_func_set;
+ data->state.in = data->set.in_set;
+}
+
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts, and only
+ * once for one transfer no matter if it has redirects or do multi-pass
+ * authentication etc.
+ */
+CURLcode Curl_pretransfer(struct Curl_easy *data)
+{
+ CURLcode result;
+ if(!data->change.url) {
+ /* we can't do anything without URL */
+ failf(data, "No URL set!");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Init the SSL session ID cache here. We do it here since we want to do it
+ after the *_setopt() calls (that could specify the size of the cache) but
+ before any transfer takes place. */
+ result = Curl_ssl_initsessions(data, data->set.general_ssl.max_ssl_sessions);
+ if(result)
+ return result;
+
+ data->set.followlocation=0; /* reset the location-follow counter */
+ data->state.this_is_a_follow = FALSE; /* reset this */
+ data->state.errorbuf = FALSE; /* no error has occurred */
+ data->state.httpversion = 0; /* don't assume any particular server version */
+
+ data->state.authproblem = FALSE;
+ data->state.authhost.want = data->set.httpauth;
+ data->state.authproxy.want = data->set.proxyauth;
+ Curl_safefree(data->info.wouldredirect);
+ data->info.wouldredirect = NULL;
+
+ if(data->set.httpreq == HTTPREQ_PUT)
+ data->state.infilesize = data->set.filesize;
+ else {
+ data->state.infilesize = data->set.postfieldsize;
+ if(data->set.postfields && (data->state.infilesize == -1))
+ data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
+ }
+
+ /* If there is a list of cookie files to read, do it now! */
+ if(data->change.cookielist)
+ Curl_cookie_loadfiles(data);
+
+ /* If there is a list of host pairs to deal with */
+ if(data->change.resolve)
+ result = Curl_loadhostpairs(data);
+
+ if(!result) {
+ /* Allow data->set.use_port to set which port to use. This needs to be
+ * disabled for example when we follow Location: headers to URLs using
+ * different ports! */
+ data->state.allow_port = TRUE;
+
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+ /*************************************************************
+ * Tell signal handler to ignore SIGPIPE
+ *************************************************************/
+ if(!data->set.no_signal)
+ data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
+#endif
+
+ Curl_initinfo(data); /* reset session-specific information "variables" */
+ Curl_pgrsResetTimesSizes(data);
+ Curl_pgrsStartNow(data);
+
+ if(data->set.timeout)
+ Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
+
+ if(data->set.connecttimeout)
+ Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
+
+ /* In case the handle is re-used and an authentication method was picked
+ in the session we need to make sure we only use the one(s) we now
+ consider to be fine */
+ data->state.authhost.picked &= data->state.authhost.want;
+ data->state.authproxy.picked &= data->state.authproxy.want;
+
+ if(data->set.wildcardmatch) {
+ struct WildcardData *wc = &data->wildcard;
+ if(wc->state < CURLWC_INIT) {
+ result = Curl_wildcard_init(wc); /* init wildcard structures */
+ if(result)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
+CURLcode Curl_posttransfer(struct Curl_easy *data)
+{
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+ /* restore the signal handler for SIGPIPE before we get back */
+ if(!data->set.no_signal)
+ signal(SIGPIPE, data->state.prev_signal);
+#else
+ (void)data; /* unused parameter */
+#endif
+
+ return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ */
+static size_t strlen_url(const char *url)
+{
+ const unsigned char *ptr;
+ size_t newlen=0;
+ bool left=TRUE; /* left side of the ? */
+
+ for(ptr=(unsigned char *)url; *ptr; ptr++) {
+ switch(*ptr) {
+ case '?':
+ left=FALSE;
+ /* fall through */
+ default:
+ if(*ptr >= 0x80)
+ newlen += 2;
+ newlen++;
+ break;
+ case ' ':
+ if(left)
+ newlen+=3;
+ else
+ newlen++;
+ break;
+ }
+ }
+ return newlen;
+}
+
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+ * the source URL accordingly.
+ */
+static void strcpy_url(char *output, const char *url)
+{
+ /* we must add this with whitespace-replacing */
+ bool left=TRUE;
+ const unsigned char *iptr;
+ char *optr = output;
+ for(iptr = (unsigned char *)url; /* read from here */
+ *iptr; /* until zero byte */
+ iptr++) {
+ switch(*iptr) {
+ case '?':
+ left=FALSE;
+ /* fall through */
+ default:
+ if(*iptr >= 0x80) {
+ snprintf(optr, 4, "%%%02x", *iptr);
+ optr += 3;
+ }
+ else
+ *optr++=*iptr;
+ break;
+ case ' ':
+ if(left) {
+ *optr++='%'; /* add a '%' */
+ *optr++='2'; /* add a '2' */
+ *optr++='0'; /* add a '0' */
+ }
+ else
+ *optr++='+'; /* add a '+' here */
+ break;
+ }
+ }
+ *optr=0; /* zero terminate output buffer */
+
+}
+
+/*
+ * Returns true if the given URL is absolute (as opposed to relative)
+ */
+static bool is_absolute_url(const char *url)
+{
+ char prot[16]; /* URL protocol string storage */
+ char letter; /* used for a silly sscanf */
+
+ return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE;
+}
+
+/*
+ * Concatenate a relative URL to a base URL making it absolute.
+ * URL-encodes any spaces.
+ * The returned pointer must be freed by the caller unless NULL
+ * (returns NULL on out of memory).
+ */
+static char *concat_url(const char *base, const char *relurl)
+{
+ /***
+ TRY to append this new path to the old URL
+ to the right of the host part. Oh crap, this is doomed to cause
+ problems in the future...
+ */
+ char *newest;
+ char *protsep;
+ char *pathsep;
+ size_t newlen;
+
+ const char *useurl = relurl;
+ size_t urllen;
+
+ /* we must make our own copy of the URL to play with, as it may
+ point to read-only data */
+ char *url_clone=strdup(base);
+
+ if(!url_clone)
+ return NULL; /* skip out of this NOW */
+
+ /* protsep points to the start of the host name */
+ protsep=strstr(url_clone, "//");
+ if(!protsep)
+ protsep=url_clone;
+ else
+ protsep+=2; /* pass the slashes */
+
+ if('/' != relurl[0]) {
+ int level=0;
+
+ /* First we need to find out if there's a ?-letter in the URL,
+ and cut it and the right-side of that off */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep=0;
+
+ /* we have a relative path to append to the last slash if there's one
+ available, or if the new URL is just a query string (starts with a
+ '?') we append the new one at the end of the entire currently worked
+ out URL */
+ if(useurl[0] != '?') {
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep=0;
+ }
+
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep+1;
+ else
+ protsep = NULL;
+
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
+
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl+=2; /* just skip the "./" */
+
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl+=3; /* pass the "../" */
+ }
+
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep=0;
+ else {
+ *protsep=0;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* We got a new absolute path for this server */
+
+ if((relurl[0] == '/') && (relurl[1] == '/')) {
+ /* the new URL starts with //, just keep the protocol part from the
+ original one */
+ *protsep=0;
+ useurl = &relurl[2]; /* we keep the slashes from the original, so we
+ skip the new ones */
+ }
+ else {
+ /* cut off the original URL from the first slash, or deal with URLs
+ without slash */
+ pathsep = strchr(protsep, '/');
+ if(pathsep) {
+ /* When people use badly formatted URLs, such as
+ "http://www.url.com?dir=/home/daniel" we must not use the first
+ slash, if there's a ?-letter before it! */
+ char *sep = strchr(protsep, '?');
+ if(sep && (sep < pathsep))
+ pathsep = sep;
+ *pathsep=0;
+ }
+ else {
+ /* There was no slash. Now, since we might be operating on a badly
+ formatted URL, such as "http://www.url.com?id=2380" which doesn't
+ use a slash separator as it is supposed to, we need to check for a
+ ?-letter as well! */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep=0;
+ }
+ }
+ }
+
+ /* If the new part contains a space, this is a mighty stupid redirect
+ but we still make an effort to do "right". To the left of a '?'
+ letter we replace each space with %20 while it is replaced with '+'
+ on the right side of the '?' letter.
+ */
+ newlen = strlen_url(useurl);
+
+ urllen = strlen(url_clone);
+
+ newest = malloc(urllen + 1 + /* possible slash */
+ newlen + 1 /* zero byte */);
+
+ if(!newest) {
+ free(url_clone); /* don't leak this */
+ return NULL;
+ }
+
+ /* copy over the root url part */
+ memcpy(newest, url_clone, urllen);
+
+ /* check if we need to append a slash */
+ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ ;
+ else
+ newest[urllen++]='/';
+
+ /* then append the new piece on the right side */
+ strcpy_url(&newest[urllen], useurl);
+
+ free(url_clone);
+
+ return newest;
+}
+#endif /* CURL_DISABLE_HTTP */
+
+/*
+ * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ */
+CURLcode Curl_follow(struct Curl_easy *data,
+ char *newurl, /* the Location: string */
+ followtype type) /* see transfer.h */
+{
+#ifdef CURL_DISABLE_HTTP
+ (void)data;
+ (void)newurl;
+ (void)type;
+ /* Location: following will not happen when HTTP is disabled */
+ return CURLE_TOO_MANY_REDIRECTS;
+#else
+
+ /* Location: redirect */
+ bool disallowport = FALSE;
+ bool reachedmax = FALSE;
+
+ if(type == FOLLOW_REDIR) {
+ if((data->set.maxredirs != -1) &&
+ (data->set.followlocation >= data->set.maxredirs)) {
+ reachedmax = TRUE;
+ type = FOLLOW_FAKE; /* switch to fake to store the would-be-redirected
+ to URL */
+ }
+ else {
+ /* mark the next request as a followed location: */
+ data->state.this_is_a_follow = TRUE;
+
+ data->set.followlocation++; /* count location-followers */
+
+ if(data->set.http_auto_referer) {
+ /* We are asked to automatically set the previous URL as the referer
+ when we get the next URL. We pick the ->url field, which may or may
+ not be 100% correct */
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+
+ data->change.referer = strdup(data->change.url);
+ if(!data->change.referer)
+ return CURLE_OUT_OF_MEMORY;
+ data->change.referer_alloc = TRUE; /* yes, free this later */
+ }
+ }
+ }
+
+ if(!is_absolute_url(newurl)) {
+ /***
+ *DANG* this is an RFC 2068 violation. The URL is supposed
+ to be absolute and this doesn't seem to be that!
+ */
+ char *absolute = concat_url(data->change.url, newurl);
+ if(!absolute)
+ return CURLE_OUT_OF_MEMORY;
+ newurl = absolute;
+ }
+ else {
+ /* The new URL MAY contain space or high byte values, that means a mighty
+ stupid redirect URL but we still make an effort to do "right". */
+ char *newest;
+ size_t newlen = strlen_url(newurl);
+
+ /* This is an absolute URL, don't allow the custom port number */
+ disallowport = TRUE;
+
+ newest = malloc(newlen+1); /* get memory for this */
+ if(!newest)
+ return CURLE_OUT_OF_MEMORY;
+ strcpy_url(newest, newurl); /* create a space-free URL */
+ newurl = newest; /* use this instead now */
+
+ }
+
+ if(type == FOLLOW_FAKE) {
+ /* we're only figuring out the new url if we would've followed locations
+ but now we're done so we can get out! */
+ data->info.wouldredirect = newurl;
+
+ if(reachedmax) {
+ failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs);
+ return CURLE_TOO_MANY_REDIRECTS;
+ }
+ return CURLE_OK;
+ }
+
+ if(disallowport)
+ data->state.allow_port = FALSE;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
+
+ infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
+
+ /*
+ * We get here when the HTTP code is 300-399 (and 401). We need to perform
+ * differently based on exactly what return code there was.
+ *
+ * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+ * a HTTP (proxy-) authentication scheme other than Basic.
+ */
+ switch(data->info.httpcode) {
+ /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
+ Authorization: XXXX header in the HTTP request code snippet */
+ /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
+ Proxy-Authorization: XXXX header in the HTTP request code snippet */
+ /* 300 - Multiple Choices */
+ /* 306 - Not used */
+ /* 307 - Temporary Redirect */
+ default: /* for all above (and the unknown ones) */
+ /* Some codes are explicitly mentioned since I've checked RFC2616 and they
+ * seem to be OK to POST to.
+ */
+ break;
+ case 301: /* Moved Permanently */
+ /* (quote from RFC7231, section 6.4.2)
+ *
+ * Note: For historical reasons, a user agent MAY change the request
+ * method from POST to GET for the subsequent request. If this
+ * behavior is undesired, the 307 (Temporary Redirect) status code
+ * can be used instead.
+ *
+ * ----
+ *
+ * Many webservers expect this, so these servers often answers to a POST
+ * request with an error page. To be sure that libcurl gets the page that
+ * most user agents would get, libcurl has to force GET.
+ *
+ * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
+ * can be overridden with CURLOPT_POSTREDIR.
+ */
+ if((data->set.httpreq == HTTPREQ_POST
+ || data->set.httpreq == HTTPREQ_POST_FORM)
+ && !(data->set.keep_post & CURL_REDIR_POST_301)) {
+ infof(data, "Switch from POST to GET\n");
+ data->set.httpreq = HTTPREQ_GET;
+ }
+ break;
+ case 302: /* Found */
+ /* (quote from RFC7231, section 6.4.3)
+ *
+ * Note: For historical reasons, a user agent MAY change the request
+ * method from POST to GET for the subsequent request. If this
+ * behavior is undesired, the 307 (Temporary Redirect) status code
+ * can be used instead.
+ *
+ * ----
+ *
+ * Many webservers expect this, so these servers often answers to a POST
+ * request with an error page. To be sure that libcurl gets the page that
+ * most user agents would get, libcurl has to force GET.
+ *
+ * This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
+ * can be overridden with CURLOPT_POSTREDIR.
+ */
+ if((data->set.httpreq == HTTPREQ_POST
+ || data->set.httpreq == HTTPREQ_POST_FORM)
+ && !(data->set.keep_post & CURL_REDIR_POST_302)) {
+ infof(data, "Switch from POST to GET\n");
+ data->set.httpreq = HTTPREQ_GET;
+ }
+ break;
+
+ case 303: /* See Other */
+ /* Disable both types of POSTs, unless the user explicitly
+ asks for POST after POST */
+ if(data->set.httpreq != HTTPREQ_GET
+ && !(data->set.keep_post & CURL_REDIR_POST_303)) {
+ data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
+ infof(data, "Disables POST, goes with %s\n",
+ data->set.opt_no_body?"HEAD":"GET");
+ }
+ break;
+ case 304: /* Not Modified */
+ /* 304 means we did a conditional request and it was "Not modified".
+ * We shouldn't get any Location: header in this response!
+ */
+ break;
+ case 305: /* Use Proxy */
+ /* (quote from RFC2616, section 10.3.6):
+ * "The requested resource MUST be accessed through the proxy given
+ * by the Location field. The Location field gives the URI of the
+ * proxy. The recipient is expected to repeat this single request
+ * via the proxy. 305 responses MUST only be generated by origin
+ * servers."
+ */
+ break;
+ }
+ Curl_pgrsTime(data, TIMER_REDIRECT);
+ Curl_pgrsResetTimesSizes(data);
+
+ return CURLE_OK;
+#endif /* CURL_DISABLE_HTTP */
+}
+
+/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
+
+ NOTE: that the *url is malloc()ed. */
+CURLcode Curl_retry_request(struct connectdata *conn,
+ char **url)
+{
+ struct Curl_easy *data = conn->data;
+
+ *url = NULL;
+
+ /* if we're talking upload, we can't do the checks below, unless the protocol
+ is HTTP as when uploading over HTTP we will still get a response */
+ if(data->set.upload &&
+ !(conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_RTSP)))
+ return CURLE_OK;
+
+ if((data->req.bytecount + data->req.headerbytecount == 0) &&
+ conn->bits.reuse &&
+ (!data->set.opt_no_body
+ || (conn->handler->protocol & PROTO_FAMILY_HTTP)) &&
+ (data->set.rtspreq != RTSPREQ_RECEIVE)) {
+ /* We got no data, we attempted to re-use a connection. For HTTP this
+ can be a retry so we try again regardless if we expected a body.
+ For other protocols we only try again only if we expected a body.
+
+ This might happen if the connection was left alive when we were
+ done using it before, but that was closed when we wanted to read from
+ it again. Bad luck. Retry the same request on a fresh connect! */
+ infof(conn->data, "Connection died, retrying a fresh connect\n");
+ *url = strdup(conn->data->change.url);
+ if(!*url)
+ return CURLE_OUT_OF_MEMORY;
+
+ connclose(conn, "retry"); /* close this connection */
+ conn->bits.retry = TRUE; /* mark this as a connection we're about
+ to retry. Marking it this way should
+ prevent i.e HTTP transfers to return
+ error just because nothing has been
+ transferred! */
+
+
+ if(conn->handler->protocol&PROTO_FAMILY_HTTP) {
+ struct HTTP *http = data->req.protop;
+ if(http->writebytecount)
+ return Curl_readrewind(conn);
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
+ * Curl_setup_transfer() is called to setup some basic properties for the
+ * upcoming transfer.
+ */
+void
+Curl_setup_transfer(
+ struct connectdata *conn, /* connection data */
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ curl_off_t *bytecountp, /* return number of bytes read or NULL */
+ int writesockindex, /* socket index to write to, it may very well be
+ the same we read from. -1 disables */
+ curl_off_t *writecountp /* return number of bytes written or NULL */
+ )
+{
+ struct Curl_easy *data;
+ struct SingleRequest *k;
+
+ DEBUGASSERT(conn != NULL);
+
+ data = conn->data;
+ k = &data->req;
+
+ DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+
+ /* now copy all input parameters */
+ conn->sockfd = sockindex == -1 ?
+ CURL_SOCKET_BAD : conn->sock[sockindex];
+ conn->writesockfd = writesockindex == -1 ?
+ CURL_SOCKET_BAD:conn->sock[writesockindex];
+ k->getheader = getheader;
+
+ k->size = size;
+ k->bytecountp = bytecountp;
+ k->writebytecountp = writecountp;
+
+ /* The code sequence below is placed in this function just because all
+ necessary input is not always known in do_complete() as this function may
+ be called after that */
+
+ if(!k->getheader) {
+ k->header = FALSE;
+ if(size > 0)
+ Curl_pgrsSetDownloadSize(data, size);
+ }
+ /* we want header and/or body, if neither then don't do this! */
+ if(k->getheader || !data->set.opt_no_body) {
+
+ if(conn->sockfd != CURL_SOCKET_BAD)
+ k->keepon |= KEEP_RECV;
+
+ if(conn->writesockfd != CURL_SOCKET_BAD) {
+ struct HTTP *http = data->req.protop;
+ /* HTTP 1.1 magic:
+
+ Even if we require a 100-return code before uploading data, we might
+ need to write data before that since the REQUEST may not have been
+ finished sent off just yet.
+
+ Thus, we must check if the request has been sent before we set the
+ state info where we wait for the 100-return code
+ */
+ if((data->state.expect100header) &&
+ (conn->handler->protocol&PROTO_FAMILY_HTTP) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* wait with write until we either got 100-continue or a timeout */
+ k->exp100 = EXP100_AWAITING_CONTINUE;
+ k->start100 = Curl_tvnow();
+
+ /* Set a timeout for the multi interface. Add the inaccuracy margin so
+ that we don't fire slightly too early and get denied to run. */
+ Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
+ }
+ else {
+ if(data->state.expect100header)
+ /* when we've sent off the rest of the headers, we must await a
+ 100-continue but first finish sending the request */
+ k->exp100 = EXP100_SENDING_REQUEST;
+
+ /* enable the write bit when we're not waiting for continue */
+ k->keepon |= KEEP_SEND;
+ }
+ } /* if(conn->writesockfd != CURL_SOCKET_BAD) */
+ } /* if(k->getheader || !data->set.opt_no_body) */
+
+}
diff --git a/Utilities/cmcurl/lib/transfer.h b/Utilities/cmcurl/lib/transfer.h
new file mode 100644
index 000000000..518967260
--- /dev/null
+++ b/Utilities/cmcurl/lib/transfer.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_TRANSFER_H
+#define HEADER_CURL_TRANSFER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+void Curl_init_CONNECT(struct Curl_easy *data);
+
+CURLcode Curl_pretransfer(struct Curl_easy *data);
+CURLcode Curl_second_connect(struct connectdata *conn);
+CURLcode Curl_posttransfer(struct Curl_easy *data);
+
+typedef enum {
+ FOLLOW_NONE, /* not used within the function, just a placeholder to
+ allow initing to this */
+ FOLLOW_FAKE, /* only records stuff, not actually following */
+ FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
+ redirect following */
+ FOLLOW_REDIR, /* a full true redirect */
+ FOLLOW_LAST /* never used */
+} followtype;
+
+CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
+ followtype type);
+CURLcode Curl_readwrite(struct connectdata *conn,
+ struct Curl_easy *data, bool *done,
+ bool *comeback);
+int Curl_single_getsock(const struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+CURLcode Curl_readrewind(struct connectdata *conn);
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
+CURLcode Curl_retry_request(struct connectdata *conn, char **url);
+bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);
+
+/* This sets up a forthcoming transfer */
+void
+Curl_setup_transfer (struct connectdata *data,
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ curl_off_t *bytecountp, /* return number of bytes read */
+ int writesockindex, /* socket index to write to, it may
+ very well be the same we read from.
+ -1 disables */
+ curl_off_t *writecountp /* return number of bytes written */
+);
+
+#endif /* HEADER_CURL_TRANSFER_H */
+
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
new file mode 100644
index 000000000..87446dbca
--- /dev/null
+++ b/Utilities/cmcurl/lib/url.c
@@ -0,0 +1,7136 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+
+#elif defined(USE_WIN32_IDN)
+/* prototype for curl_win32_idn_to_ascii() */
+bool curl_win32_idn_to_ascii(const char *in, char **out);
+#endif /* USE_LIBIDN2 */
+
+#include "urldata.h"
+#include "netrc.h"
+
+#include "formdata.h"
+#include "vtls/vtls.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "cookie.h"
+#include "strcase.h"
+#include "strerror.h"
+#include "escape.h"
+#include "strtok.h"
+#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
+#include "select.h"
+#include "multiif.h"
+#include "easyif.h"
+#include "speedcheck.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "inet_pton.h"
+#include "getinfo.h"
+
+/* And now for the protocols */
+#include "ftp.h"
+#include "dict.h"
+#include "telnet.h"
+#include "tftp.h"
+#include "http.h"
+#include "http2.h"
+#include "file.h"
+#include "curl_ldap.h"
+#include "ssh.h"
+#include "imap.h"
+#include "url.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "http_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "socks.h"
+#include "curl_rtmp.h"
+#include "gopher.h"
+#include "http_proxy.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "pipeline.h"
+#include "dotdot.h"
+#include "strdup.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* Local static prototypes */
+static struct connectdata *
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
+ struct connectbundle *bundle);
+static void conn_free(struct connectdata *conn);
+static void free_fixed_hostname(struct hostname *host);
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
+static CURLcode parse_url_login(struct Curl_easy *data,
+ struct connectdata *conn,
+ char **userptr, char **passwdptr,
+ char **optionsptr);
+static CURLcode parse_login_details(const char *login, const size_t len,
+ char **userptr, char **passwdptr,
+ char **optionsptr);
+static unsigned int get_protocol_family(unsigned int protocol);
+
+#define READBUFFER_SIZE CURL_MAX_WRITE_SIZE
+#define READBUFFER_MAX CURL_MAX_READ_SIZE
+#define READBUFFER_MIN 1024
+
+/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
+ * more than just a few bytes to play with. Don't let it become too small or
+ * bad things will happen.
+ */
+#if READBUFFER_SIZE < READBUFFER_MIN
+# error READBUFFER_SIZE is too small
+#endif
+
+
+/*
+ * Protocol table.
+ */
+
+static const struct Curl_handler * const protocols[] = {
+
+#ifndef CURL_DISABLE_HTTP
+ &Curl_handler_http,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ &Curl_handler_https,
+#endif
+
+#ifndef CURL_DISABLE_FTP
+ &Curl_handler_ftp,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+ &Curl_handler_ftps,
+#endif
+
+#ifndef CURL_DISABLE_TELNET
+ &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_DICT
+ &Curl_handler_dict,
+#endif
+
+#ifndef CURL_DISABLE_LDAP
+ &Curl_handler_ldap,
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+ &Curl_handler_ldaps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_FILE
+ &Curl_handler_file,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+ &Curl_handler_tftp,
+#endif
+
+#ifdef USE_LIBSSH2
+ &Curl_handler_scp,
+ &Curl_handler_sftp,
+#endif
+
+#ifndef CURL_DISABLE_IMAP
+ &Curl_handler_imap,
+#ifdef USE_SSL
+ &Curl_handler_imaps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_POP3
+ &Curl_handler_pop3,
+#ifdef USE_SSL
+ &Curl_handler_pop3s,
+#endif
+#endif
+
+#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
+ (CURL_SIZEOF_CURL_OFF_T > 4) && \
+ (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO))
+ &Curl_handler_smb,
+#ifdef USE_SSL
+ &Curl_handler_smbs,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_SMTP
+ &Curl_handler_smtp,
+#ifdef USE_SSL
+ &Curl_handler_smtps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_RTSP
+ &Curl_handler_rtsp,
+#endif
+
+#ifndef CURL_DISABLE_GOPHER
+ &Curl_handler_gopher,
+#endif
+
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmp,
+ &Curl_handler_rtmpt,
+ &Curl_handler_rtmpe,
+ &Curl_handler_rtmpte,
+ &Curl_handler_rtmps,
+ &Curl_handler_rtmpts,
+#endif
+
+ (struct Curl_handler *) NULL
+};
+
+/*
+ * Dummy handler for undefined protocol schemes.
+ */
+
+static const struct Curl_handler Curl_handler_dummy = {
+ "<no protocol>", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ ZERO_NULL, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ 0, /* defport */
+ 0, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+void Curl_freeset(struct Curl_easy *data)
+{
+ /* Free all dynamic strings stored in the data->set substructure. */
+ enum dupstring i;
+ for(i=(enum dupstring)0; i < STRING_LAST; i++) {
+ Curl_safefree(data->set.str[i]);
+ }
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ data->change.referer = NULL;
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ data->change.url = NULL;
+}
+
+static CURLcode setstropt(char **charp, const char *s)
+{
+ /* Release the previous storage at `charp' and replace by a dynamic storage
+ copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+ Curl_safefree(*charp);
+
+ if(s) {
+ char *str = strdup(s);
+
+ if(!str)
+ return CURLE_OUT_OF_MEMORY;
+
+ *charp = str;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
+{
+ CURLcode result = CURLE_OK;
+ char *user = NULL;
+ char *passwd = NULL;
+
+ /* Parse the login details if specified. It not then we treat NULL as a hint
+ to clear the existing data */
+ if(option) {
+ result = parse_login_details(option, strlen(option),
+ (userp ? &user : NULL),
+ (passwdp ? &passwd : NULL),
+ NULL);
+ }
+
+ if(!result) {
+ /* Store the username part of option if required */
+ if(userp) {
+ if(!user && option && option[0] == ':') {
+ /* Allocate an empty string instead of returning NULL as user name */
+ user = strdup("");
+ if(!user)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(*userp);
+ *userp = user;
+ }
+
+ /* Store the password part of option if required */
+ if(passwdp) {
+ Curl_safefree(*passwdp);
+ *passwdp = passwd;
+ }
+ }
+
+ return result;
+}
+
+CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src)
+{
+ CURLcode result = CURLE_OK;
+ enum dupstring i;
+
+ /* Copy src->set into dst->set first, then deal with the strings
+ afterwards */
+ dst->set = src->set;
+
+ /* clear all string pointers first */
+ memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+ /* duplicate all strings */
+ for(i=(enum dupstring)0; i< STRING_LASTZEROTERMINATED; i++) {
+ result = setstropt(&dst->set.str[i], src->set.str[i]);
+ if(result)
+ return result;
+ }
+
+ /* duplicate memory areas pointed to */
+ i = STRING_COPYPOSTFIELDS;
+ if(src->set.postfieldsize && src->set.str[i]) {
+ /* postfieldsize is curl_off_t, Curl_memdup() takes a size_t ... */
+ dst->set.str[i] = Curl_memdup(src->set.str[i],
+ curlx_sotouz(src->set.postfieldsize));
+ if(!dst->set.str[i])
+ return CURLE_OUT_OF_MEMORY;
+ /* point to the new copy */
+ dst->set.postfields = dst->set.str[i];
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * This is the internal function curl_easy_cleanup() calls. This should
+ * cleanup and free all resources associated with this sessionhandle.
+ *
+ * NOTE: if we ever add something that attempts to write to a socket or
+ * similar here, we must ignore SIGPIPE first. It is currently only done
+ * when curl_easy_perform() is invoked.
+ */
+
+CURLcode Curl_close(struct Curl_easy *data)
+{
+ struct Curl_multi *m;
+
+ if(!data)
+ return CURLE_OK;
+
+ Curl_expire_clear(data); /* shut off timers */
+
+ m = data->multi;
+
+ if(m)
+ /* This handle is still part of a multi handle, take care of this first
+ and detach this handle from there. */
+ curl_multi_remove_handle(data->multi, data);
+
+ if(data->multi_easy)
+ /* when curl_easy_perform() is used, it creates its own multi handle to
+ use and this is the one */
+ curl_multi_cleanup(data->multi_easy);
+
+ /* Destroy the timeout list that is held in the easy handle. It is
+ /normally/ done by curl_multi_remove_handle() but this is "just in
+ case" */
+ Curl_llist_destroy(&data->state.timeoutlist, NULL);
+
+ data->magic = 0; /* force a clear AFTER the possibly enforced removal from
+ the multi handle, since that function uses the magic
+ field! */
+
+ if(data->state.rangestringalloc)
+ free(data->state.range);
+
+ /* Free the pathbuffer */
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+
+ /* freed here just in case DONE wasn't called */
+ Curl_free_request_state(data);
+
+ /* Close down all open SSL info and sessions */
+ Curl_ssl_close_all(data);
+ Curl_safefree(data->state.first_host);
+ Curl_safefree(data->state.scratch);
+ Curl_ssl_free_certinfo(data);
+
+ /* Cleanup possible redirect junk */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ data->change.referer = NULL;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ data->change.url = NULL;
+
+ Curl_safefree(data->state.buffer);
+ Curl_safefree(data->state.headerbuff);
+
+ Curl_flush_cookies(data, 1);
+
+ Curl_digest_cleanup(data);
+
+ Curl_safefree(data->info.contenttype);
+ Curl_safefree(data->info.wouldredirect);
+
+ /* this destroys the channel and we cannot use it anymore after this */
+ Curl_resolver_cleanup(data->state.resolver);
+
+ Curl_http2_cleanup_dependencies(data);
+ Curl_convert_close(data);
+
+ /* No longer a dirty share, if it exists */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+ data->share->dirty--;
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ }
+
+ if(data->set.wildcardmatch) {
+ /* destruct wildcard structures if it is needed */
+ struct WildcardData *wc = &data->wildcard;
+ Curl_wildcard_dtor(wc);
+ }
+
+ Curl_freeset(data);
+ free(data);
+ return CURLE_OK;
+}
+
+/*
+ * Initialize the UserDefined fields within a Curl_easy.
+ * This may be safely called on a new or existing Curl_easy.
+ */
+CURLcode Curl_init_userdefined(struct UserDefined *set)
+{
+ CURLcode result = CURLE_OK;
+
+ set->out = stdout; /* default output to stdout */
+ set->in_set = stdin; /* default input from stdin */
+ set->err = stderr; /* default stderr to stderr */
+
+ /* use fwrite as default function to store output */
+ set->fwrite_func = (curl_write_callback)fwrite;
+
+ /* use fread as default function to read input */
+ set->fread_func_set = (curl_read_callback)fread;
+ set->is_fread_set = 0;
+ set->is_fwrite_set = 0;
+
+ set->seek_func = ZERO_NULL;
+ set->seek_client = ZERO_NULL;
+
+ /* conversion callbacks for non-ASCII hosts */
+ set->convfromnetwork = ZERO_NULL;
+ set->convtonetwork = ZERO_NULL;
+ set->convfromutf8 = ZERO_NULL;
+
+ set->filesize = -1; /* we don't know the size */
+ set->postfieldsize = -1; /* unknown size */
+ set->maxredirs = -1; /* allow any amount by default */
+
+ set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+ set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
+ set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
+ set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
+ set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
+ set->ftp_filemethod = FTPFILE_MULTICWD;
+
+ set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+ /* Set the default size of the SSL session ID cache */
+ set->general_ssl.max_ssl_sessions = 5;
+
+ set->proxyport = 0;
+ set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ set->httpauth = CURLAUTH_BASIC; /* defaults to basic */
+ set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+ /* make libcurl quiet by default: */
+ set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ set->ssl.primary.verifypeer = TRUE;
+ set->ssl.primary.verifyhost = TRUE;
+#ifdef USE_TLS_SRP
+ set->ssl.authtype = CURL_TLSAUTH_NONE;
+#endif
+ set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
+ type */
+ set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by
+ default */
+ set->proxy_ssl = set->ssl;
+
+ set->new_file_perms = 0644; /* Default permissions */
+ set->new_directory_perms = 0755; /* Default permissions */
+
+ /* for the *protocols fields we don't use the CURLPROTO_ALL convenience
+ define since we internally only use the lower 16 bits for the passed
+ in bitmask to not conflict with the private bits */
+ set->allowed_protocols = CURLPROTO_ALL;
+ set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */
+ ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB |
+ CURLPROTO_SMBS);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ /*
+ * disallow unprotected protection negotiation NEC reference implementation
+ * seem not to follow rfc1961 section 4.3/4.4
+ */
+ set->socks5_gssapi_nec = FALSE;
+#endif
+
+ /* This is our preferred CA cert bundle/path since install time */
+#if defined(CURL_CA_BUNDLE)
+ result = setstropt(&set->str[STRING_SSL_CAFILE_ORIG], CURL_CA_BUNDLE);
+ if(result)
+ return result;
+
+ result = setstropt(&set->str[STRING_SSL_CAFILE_PROXY], CURL_CA_BUNDLE);
+ if(result)
+ return result;
+#endif
+#if defined(CURL_CA_PATH)
+ result = setstropt(&set->str[STRING_SSL_CAPATH_ORIG], CURL_CA_PATH);
+ if(result)
+ return result;
+
+ result = setstropt(&set->str[STRING_SSL_CAPATH_PROXY], CURL_CA_PATH);
+ if(result)
+ return result;
+#endif
+
+ set->wildcardmatch = FALSE;
+ set->chunk_bgn = ZERO_NULL;
+ set->chunk_end = ZERO_NULL;
+
+ /* tcp keepalives are disabled by default, but provide reasonable values for
+ * the interval and idle times.
+ */
+ set->tcp_keepalive = FALSE;
+ set->tcp_keepintvl = 60;
+ set->tcp_keepidle = 60;
+ set->tcp_fastopen = FALSE;
+ set->tcp_nodelay = TRUE;
+
+ set->ssl_enable_npn = TRUE;
+ set->ssl_enable_alpn = TRUE;
+
+ set->expect_100_timeout = 1000L; /* Wait for a second by default. */
+ set->sep_headers = TRUE; /* separated header lists by default */
+ set->buffer_size = READBUFFER_SIZE;
+
+ Curl_http2_init_userset(set);
+ return result;
+}
+
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
+
+CURLcode Curl_open(struct Curl_easy **curl)
+{
+ CURLcode result;
+ struct Curl_easy *data;
+
+ /* Very simple start-up: alloc the struct, init it with zeroes and return */
+ data = calloc(1, sizeof(struct Curl_easy));
+ if(!data) {
+ /* this is a very serious error */
+ DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ data->magic = CURLEASY_MAGIC_NUMBER;
+
+ result = Curl_resolver_init(&data->state.resolver);
+ if(result) {
+ DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ free(data);
+ return result;
+ }
+
+ /* We do some initial setup here, all those fields that can't be just 0 */
+
+ data->state.buffer = malloc(READBUFFER_SIZE + 1);
+ if(!data->state.buffer) {
+ DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ data->state.headerbuff = malloc(HEADERSIZE);
+ if(!data->state.headerbuff) {
+ DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ result = Curl_init_userdefined(&data->set);
+
+ data->state.headersize=HEADERSIZE;
+
+ Curl_convert_init(data);
+
+ Curl_initinfo(data);
+
+ /* most recent connection is not yet defined */
+ data->state.lastconnect = NULL;
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+ data->set.fnmatch = ZERO_NULL;
+ data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+
+ Curl_http2_init_state(&data->state);
+ }
+
+ if(result) {
+ Curl_resolver_cleanup(data->state.resolver);
+ free(data->state.buffer);
+ free(data->state.headerbuff);
+ Curl_freeset(data);
+ free(data);
+ data = NULL;
+ }
+ else
+ *curl = data;
+
+ return result;
+}
+
+#define C_SSLVERSION_VALUE(x) (x & 0xffff)
+#define C_SSLVERSION_MAX_VALUE(x) (x & 0xffff0000)
+
+CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
+ va_list param)
+{
+ char *argptr;
+ CURLcode result = CURLE_OK;
+ long arg;
+#ifndef CURL_DISABLE_HTTP
+ curl_off_t bigsize;
+#endif
+
+ switch(option) {
+ case CURLOPT_DNS_CACHE_TIMEOUT:
+ data->set.dns_cache_timeout = va_arg(param, long);
+ break;
+ case CURLOPT_DNS_USE_GLOBAL_CACHE:
+ /* remember we want this enabled */
+ arg = va_arg(param, long);
+ data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
+ break;
+ case CURLOPT_SSL_CIPHER_LIST:
+ /* set a list of cipher we want to use in the SSL connection */
+ result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSL_CIPHER_LIST:
+ /* set a list of cipher we want to use in the SSL connection for proxy */
+ result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RANDOM_FILE:
+ /*
+ * This is the path name to a file that contains random data to seed
+ * the random SSL stuff with. The file is only used for reading.
+ */
+ result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_EGDSOCKET:
+ /*
+ * The Entropy Gathering Daemon socket pathname
+ */
+ result = setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_MAXCONNECTS:
+ /*
+ * Set the absolute number of maximum simultaneous alive connection that
+ * libcurl is allowed to have.
+ */
+ data->set.maxconnects = va_arg(param, long);
+ break;
+ case CURLOPT_FORBID_REUSE:
+ /*
+ * When this transfer is done, it must not be left to be reused by a
+ * subsequent transfer but shall be closed immediately.
+ */
+ data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FRESH_CONNECT:
+ /*
+ * This transfer shall not use a previously cached connection but
+ * should be made with a fresh new connect!
+ */
+ data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_VERBOSE:
+ /*
+ * Verbose means infof() calls that give a lot of information about
+ * the connection and transfer procedures as well as internal choices.
+ */
+ data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_HEADER:
+ /*
+ * Set to include the header in the general data output stream.
+ */
+ data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_NOPROGRESS:
+ /*
+ * Shut off the internal supported progress meter
+ */
+ data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ if(data->set.hide_progress)
+ data->progress.flags |= PGRS_HIDE;
+ else
+ data->progress.flags &= ~PGRS_HIDE;
+ break;
+ case CURLOPT_NOBODY:
+ /*
+ * Do not include the body part in the output data stream.
+ */
+ data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FAILONERROR:
+ /*
+ * Don't output the >=400 error code HTML-page, but instead only
+ * return error.
+ */
+ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_KEEP_SENDING_ON_ERROR:
+ data->set.http_keep_sending_on_error = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+ case CURLOPT_UPLOAD:
+ case CURLOPT_PUT:
+ /*
+ * We want to sent data to the remote host. If this is HTTP, that equals
+ * using the PUT request.
+ */
+ data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ if(data->set.upload) {
+ /* If this is HTTP, PUT is what's needed to "upload" */
+ data->set.httpreq = HTTPREQ_PUT;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+ then this can be changed to HEAD later on) */
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+ case CURLOPT_FILETIME:
+ /*
+ * Try to get the file time of the remote document. The time will
+ * later (possibly) become available using curl_easy_getinfo().
+ */
+ data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
+ /*
+ * An FTP option that modifies an upload to create missing directories on
+ * the server.
+ */
+ switch(va_arg(param, long)) {
+ case 0:
+ data->set.ftp_create_missing_dirs = 0;
+ break;
+ case 1:
+ data->set.ftp_create_missing_dirs = 1;
+ break;
+ case 2:
+ data->set.ftp_create_missing_dirs = 2;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+ case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+ /*
+ * Option that specifies how quickly an server response must be obtained
+ * before it is considered failure. For pingpong protocols.
+ */
+ data->set.server_response_timeout = va_arg(param, long) * 1000;
+ break;
+ case CURLOPT_TFTP_NO_OPTIONS:
+ /*
+ * Option that prevents libcurl from sending TFTP option requests to the
+ * server.
+ */
+ data->set.tftp_no_options = va_arg(param, long) != 0;
+ break;
+ case CURLOPT_TFTP_BLKSIZE:
+ /*
+ * TFTP option that specifies the block size to use for data transmission.
+ */
+ data->set.tftp_blksize = va_arg(param, long);
+ break;
+ case CURLOPT_DIRLISTONLY:
+ /*
+ * An option that changes the command to one that asks for a list
+ * only, no file info details.
+ */
+ data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_APPEND:
+ /*
+ * We want to upload and append to an existing file.
+ */
+ data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_FTP_FILEMETHOD:
+ /*
+ * How do access files over FTP.
+ */
+ data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long);
+ break;
+ case CURLOPT_NETRC:
+ /*
+ * Parse the $HOME/.netrc file
+ */
+ data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
+ break;
+ case CURLOPT_NETRC_FILE:
+ /*
+ * Use this file instead of the $HOME/.netrc file
+ */
+ result = setstropt(&data->set.str[STRING_NETRC_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TRANSFERTEXT:
+ /*
+ * This option was previously named 'FTPASCII'. Renamed to work with
+ * more protocols than merely FTP.
+ *
+ * Transfer using ASCII (instead of BINARY).
+ */
+ data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_TIMECONDITION:
+ /*
+ * Set HTTP time condition. This must be one of the defines in the
+ * curl/curl.h header file.
+ */
+ data->set.timecondition = (curl_TimeCond)va_arg(param, long);
+ break;
+ case CURLOPT_TIMEVALUE:
+ /*
+ * This is the value to compare with the remote document with the
+ * method set with CURLOPT_TIMECONDITION
+ */
+ data->set.timevalue = (time_t)va_arg(param, long);
+ break;
+ case CURLOPT_SSLVERSION:
+ /*
+ * Set explicit SSL version to try to connect with, as some SSL
+ * implementations are lame.
+ */
+#ifdef USE_SSL
+ arg = va_arg(param, long);
+ data->set.ssl.primary.version = C_SSLVERSION_VALUE(arg);
+ data->set.ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+ result = CURLE_UNKNOWN_OPTION;
+#endif
+ break;
+ case CURLOPT_PROXY_SSLVERSION:
+ /*
+ * Set explicit SSL version to try to connect with for proxy, as some SSL
+ * implementations are lame.
+ */
+#ifdef USE_SSL
+ arg = va_arg(param, long);
+ data->set.proxy_ssl.primary.version = C_SSLVERSION_VALUE(arg);
+ data->set.proxy_ssl.primary.version_max = C_SSLVERSION_MAX_VALUE(arg);
+#else
+ result = CURLE_UNKNOWN_OPTION;
+#endif
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLOPT_AUTOREFERER:
+ /*
+ * Switch on automatic referer that gets set if curl follows locations.
+ */
+ data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_ACCEPT_ENCODING:
+ /*
+ * String to use at the value of Accept-Encoding header.
+ *
+ * If the encoding is set to "" we use an Accept-Encoding header that
+ * encompasses all the encodings we support.
+ * If the encoding is set to NULL we don't send an Accept-Encoding header
+ * and ignore an received Content-Encoding header.
+ *
+ */
+ argptr = va_arg(param, char *);
+ result = setstropt(&data->set.str[STRING_ENCODING],
+ (argptr && !*argptr)?
+ ALL_CONTENT_ENCODINGS: argptr);
+ break;
+
+ case CURLOPT_TRANSFER_ENCODING:
+ data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+
+ case CURLOPT_FOLLOWLOCATION:
+ /*
+ * Follow Location: header hints on a HTTP-server.
+ */
+ data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_UNRESTRICTED_AUTH:
+ /*
+ * Send authentication (user+password) when following locations, even when
+ * hostname changed.
+ */
+ data->set.http_disable_hostname_check_before_authentication =
+ (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_MAXREDIRS:
+ /*
+ * The maximum amount of hops you allow curl to follow Location:
+ * headers. This should mostly be used to detect never-ending loops.
+ */
+ data->set.maxredirs = va_arg(param, long);
+ break;
+
+ case CURLOPT_POSTREDIR:
+ {
+ /*
+ * Set the behaviour of POST when redirecting
+ * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+ * CURL_REDIR_POST_301 - POST is kept as POST after 301
+ * CURL_REDIR_POST_302 - POST is kept as POST after 302
+ * CURL_REDIR_POST_303 - POST is kept as POST after 303
+ * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
+ * other - POST is kept as POST after 301 and 302
+ */
+ arg = va_arg(param, long);
+ data->set.keep_post = arg & CURL_REDIR_POST_ALL;
+ }
+ break;
+
+ case CURLOPT_POST:
+ /* Does this option serve a purpose anymore? Yes it does, when
+ CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+ callback! */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_POST;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+
+ case CURLOPT_COPYPOSTFIELDS:
+ /*
+ * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+ * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+ * CURLOPT_COPYPOSTFIELDS and not altered later.
+ */
+ argptr = va_arg(param, char *);
+
+ if(!argptr || data->set.postfieldsize == -1)
+ result = setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+ else {
+ /*
+ * Check that requested length does not overflow the size_t type.
+ */
+
+ if((data->set.postfieldsize < 0) ||
+ ((sizeof(curl_off_t) != sizeof(size_t)) &&
+ (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ char *p;
+
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
+ /* Allocate even when size == 0. This satisfies the need of possible
+ later address compare to detect the COPYPOSTFIELDS mode, and
+ to mark that postfields is used rather than read function or
+ form data.
+ */
+ p = malloc((size_t)(data->set.postfieldsize?
+ data->set.postfieldsize:1));
+
+ if(!p)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ if(data->set.postfieldsize)
+ memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
+ data->set.str[STRING_COPYPOSTFIELDS] = p;
+ }
+ }
+ }
+
+ data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDS:
+ /*
+ * Like above, but use static data instead of copying it.
+ */
+ data->set.postfields = va_arg(param, void *);
+ /* Release old copied data. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, long);
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE_LARGE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, curl_off_t);
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_HTTPPOST:
+ /*
+ * Set to make us do HTTP POST
+ */
+ data->set.httppost = va_arg(param, struct curl_httppost *);
+ data->set.httpreq = HTTPREQ_POST_FORM;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ break;
+
+ case CURLOPT_REFERER:
+ /*
+ * String to set in the HTTP Referer: field.
+ */
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ result = setstropt(&data->set.str[STRING_SET_REFERER],
+ va_arg(param, char *));
+ data->change.referer = data->set.str[STRING_SET_REFERER];
+ break;
+
+ case CURLOPT_USERAGENT:
+ /*
+ * String to use in the HTTP User-Agent field
+ */
+ result = setstropt(&data->set.str[STRING_USERAGENT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_HTTPHEADER:
+ /*
+ * Set a list with HTTP headers to use (or replace internals with)
+ */
+ data->set.headers = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_PROXYHEADER:
+ /*
+ * Set a list with proxy headers to use (or replace internals with)
+ *
+ * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a
+ * long time we remain doing it this way until CURLOPT_PROXYHEADER is
+ * used. As soon as this option has been used, if set to anything but
+ * NULL, custom headers for proxies are only picked from this list.
+ *
+ * Set this option to NULL to restore the previous behavior.
+ */
+ data->set.proxyheaders = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_HEADEROPT:
+ /*
+ * Set header option.
+ */
+ arg = va_arg(param, long);
+ data->set.sep_headers = (arg & CURLHEADER_SEPARATE)? TRUE: FALSE;
+ break;
+
+ case CURLOPT_HTTP200ALIASES:
+ /*
+ * Set a list of aliases for HTTP 200 in response header
+ */
+ data->set.http200aliases = va_arg(param, struct curl_slist *);
+ break;
+
+#if !defined(CURL_DISABLE_COOKIES)
+ case CURLOPT_COOKIE:
+ /*
+ * Cookie string to send to the remote server in the request.
+ */
+ result = setstropt(&data->set.str[STRING_COOKIE],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_COOKIEFILE:
+ /*
+ * Set cookie file to read and parse. Can be used multiple times.
+ */
+ argptr = (char *)va_arg(param, void *);
+ if(argptr) {
+ struct curl_slist *cl;
+ /* append the cookie file name to the list of file names, and deal with
+ them later */
+ cl = curl_slist_append(data->change.cookielist, argptr);
+ if(!cl) {
+ curl_slist_free_all(data->change.cookielist);
+ data->change.cookielist = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->change.cookielist = cl; /* store the list for later use */
+ }
+ break;
+
+ case CURLOPT_COOKIEJAR:
+ /*
+ * Set cookie file name to dump all cookies to when we're done.
+ */
+ {
+ struct CookieInfo *newcookies;
+ result = setstropt(&data->set.str[STRING_COOKIEJAR],
+ va_arg(param, char *));
+
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ newcookies = Curl_cookie_init(data, NULL, data->cookies,
+ data->set.cookiesession);
+ if(!newcookies)
+ result = CURLE_OUT_OF_MEMORY;
+ data->cookies = newcookies;
+ }
+ break;
+
+ case CURLOPT_COOKIESESSION:
+ /*
+ * Set this option to TRUE to start a new "cookie session". It will
+ * prevent the forthcoming read-cookies-from-file actions to accept
+ * cookies that are marked as being session cookies, as they belong to a
+ * previous session.
+ *
+ * In the original Netscape cookie spec, "session cookies" are cookies
+ * with no expire date set. RFC2109 describes the same action if no
+ * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
+ * a 'Discard' action that can enforce the discard even for cookies that
+ * have a Max-Age.
+ *
+ * We run mostly with the original cookie spec, as hardly anyone implements
+ * anything else.
+ */
+ data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_COOKIELIST:
+ argptr = va_arg(param, char *);
+
+ if(argptr == NULL)
+ break;
+
+ if(strcasecompare(argptr, "ALL")) {
+ /* clear all cookies */
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_clearall(data->cookies);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ else if(strcasecompare(argptr, "SESS")) {
+ /* clear session cookies */
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_clearsess(data->cookies);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ else if(strcasecompare(argptr, "FLUSH")) {
+ /* flush cookies to file, takes care of the locking */
+ Curl_flush_cookies(data, 0);
+ }
+ else if(strcasecompare(argptr, "RELOAD")) {
+ /* reload cookies from file */
+ Curl_cookie_loadfiles(data);
+ break;
+ }
+ else {
+ if(!data->cookies)
+ /* if cookie engine was not running, activate it */
+ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+
+ argptr = strdup(argptr);
+ if(!argptr || !data->cookies) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(argptr);
+ }
+ else {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(checkprefix("Set-Cookie:", argptr))
+ /* HTTP Header format line */
+ Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
+
+ else
+ /* Netscape format line */
+ Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ free(argptr);
+ }
+ }
+
+ break;
+#endif /* CURL_DISABLE_COOKIES */
+
+ case CURLOPT_HTTPGET:
+ /*
+ * Set to force us do HTTP GET
+ */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_GET;
+ data->set.upload = FALSE; /* switch off upload */
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ break;
+
+ case CURLOPT_HTTP_VERSION:
+ /*
+ * This sets a requested HTTP version to be used. The value is one of
+ * the listed enums in curl/curl.h.
+ */
+ arg = va_arg(param, long);
+#ifndef USE_NGHTTP2
+ if(arg >= CURL_HTTP_VERSION_2)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ data->set.httpversion = arg;
+ break;
+
+ case CURLOPT_HTTPAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.httpauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+ auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+ GSS-API or SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.httpauth = auth;
+ }
+ break;
+
+ case CURLOPT_EXPECT_100_TIMEOUT_MS:
+ /*
+ * Time to wait for a response to a HTTP request containing an
+ * Expect: 100-continue header before sending the data anyway.
+ */
+ data->set.expect_100_timeout = va_arg(param, long);
+ break;
+
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURLOPT_CUSTOMREQUEST:
+ /*
+ * Set a custom string to use as request
+ */
+ result = setstropt(&data->set.str[STRING_CUSTOMREQUEST],
+ va_arg(param, char *));
+
+ /* we don't set
+ data->set.httpreq = HTTPREQ_CUSTOM;
+ here, we continue as if we were using the already set type
+ and this just changes the actual request keyword */
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_HTTPPROXYTUNNEL:
+ /*
+ * Tunnel operations through the proxy instead of normal proxy use
+ */
+ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+
+ case CURLOPT_PROXYPORT:
+ /*
+ * Explicitly set HTTP proxy port number.
+ */
+ data->set.proxyport = va_arg(param, long);
+ break;
+
+ case CURLOPT_PROXYAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.proxyauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_SPNEGO
+ auth &= ~CURLAUTH_NEGOTIATE; /* no Negotiate (SPNEGO) auth without
+ GSS-API or SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.proxyauth = auth;
+ }
+ break;
+
+ case CURLOPT_PROXY:
+ /*
+ * Set proxy server:port to use as proxy.
+ *
+ * If the proxy is set to "" (and CURLOPT_SOCKS_PROXY is set to "" or NULL)
+ * we explicitly say that we don't want to use a proxy
+ * (even though there might be environment variables saying so).
+ *
+ * Setting it to NULL, means no proxy but allows the environment variables
+ * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL).
+ */
+ result = setstropt(&data->set.str[STRING_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PRE_PROXY:
+ /*
+ * Set proxy server:port to use as SOCKS proxy.
+ *
+ * If the proxy is set to "" or NULL we explicitly say that we don't want
+ * to use the socks proxy.
+ */
+ result = setstropt(&data->set.str[STRING_PRE_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PROXYTYPE:
+ /*
+ * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
+ */
+ data->set.proxytype = (curl_proxytype)va_arg(param, long);
+ break;
+
+ case CURLOPT_PROXY_TRANSFER_MODE:
+ /*
+ * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
+ */
+ switch(va_arg(param, long)) {
+ case 0:
+ data->set.proxy_transfer_mode = FALSE;
+ break;
+ case 1:
+ data->set.proxy_transfer_mode = TRUE;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+#endif /* CURL_DISABLE_PROXY */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ case CURLOPT_SOCKS5_GSSAPI_NEC:
+ /*
+ * Set flag for NEC SOCK5 support
+ */
+ data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+ case CURLOPT_PROXY_SERVICE_NAME:
+ /*
+ * Set proxy authentication service name for Kerberos 5 and SPNEGO
+ */
+ result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
+ va_arg(param, char *));
+ break;
+#endif
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_SPNEGO)
+ case CURLOPT_SERVICE_NAME:
+ /*
+ * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
+ */
+ result = setstropt(&data->set.str[STRING_SERVICE_NAME],
+ va_arg(param, char *));
+ break;
+
+#endif
+
+ case CURLOPT_HEADERDATA:
+ /*
+ * Custom pointer to pass the header write callback function
+ */
+ data->set.writeheader = (void *)va_arg(param, void *);
+ break;
+ case CURLOPT_ERRORBUFFER:
+ /*
+ * Error buffer provided by the caller to get the human readable
+ * error string in.
+ */
+ data->set.errorbuffer = va_arg(param, char *);
+ break;
+ case CURLOPT_WRITEDATA:
+ /*
+ * FILE pointer to write to. Or possibly
+ * used as argument to the write callback.
+ */
+ data->set.out = va_arg(param, void *);
+ break;
+ case CURLOPT_FTPPORT:
+ /*
+ * Use FTP PORT, this also specifies which IP address to use
+ */
+ result = setstropt(&data->set.str[STRING_FTPPORT],
+ va_arg(param, char *));
+ data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPRT:
+ data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPSV:
+ data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_PRET:
+ data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_SSL_CCC:
+ data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long);
+ break;
+
+ case CURLOPT_FTP_SKIP_PASV_IP:
+ /*
+ * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+ * bypass of the IP address in PASV responses.
+ */
+ data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_READDATA:
+ /*
+ * FILE pointer to read the file to be uploaded from. Or possibly
+ * used as argument to the read callback.
+ */
+ data->set.in_set = va_arg(param, void *);
+ break;
+ case CURLOPT_INFILESIZE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ data->set.filesize = va_arg(param, long);
+ break;
+ case CURLOPT_INFILESIZE_LARGE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ data->set.filesize = va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_LOW_SPEED_LIMIT:
+ /*
+ * The low speed limit that if transfers are below this for
+ * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
+ */
+ data->set.low_speed_limit=va_arg(param, long);
+ break;
+ case CURLOPT_MAX_SEND_SPEED_LARGE:
+ /*
+ * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+ * bytes per second the transfer is throttled..
+ */
+ data->set.max_send_speed=va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_MAX_RECV_SPEED_LARGE:
+ /*
+ * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+ * second the transfer is throttled..
+ */
+ data->set.max_recv_speed=va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_LOW_SPEED_TIME:
+ /*
+ * The low speed time that if transfers are below the set
+ * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
+ */
+ data->set.low_speed_time=va_arg(param, long);
+ break;
+ case CURLOPT_URL:
+ /*
+ * The URL to fetch.
+ */
+ if(data->change.url_alloc) {
+ /* the already set URL is allocated, free it first! */
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ result = setstropt(&data->set.str[STRING_SET_URL],
+ va_arg(param, char *));
+ data->change.url = data->set.str[STRING_SET_URL];
+ break;
+ case CURLOPT_PORT:
+ /*
+ * The port number to use when getting the URL
+ */
+ data->set.use_port = va_arg(param, long);
+ break;
+ case CURLOPT_TIMEOUT:
+ /*
+ * The maximum time you allow curl to use for a single transfer
+ * operation.
+ */
+ data->set.timeout = va_arg(param, long) * 1000L;
+ break;
+
+ case CURLOPT_TIMEOUT_MS:
+ data->set.timeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT:
+ /*
+ * The maximum time you allow curl to use to connect.
+ */
+ data->set.connecttimeout = va_arg(param, long) * 1000L;
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT_MS:
+ data->set.connecttimeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_ACCEPTTIMEOUT_MS:
+ /*
+ * The maximum time you allow curl to wait for server connect
+ */
+ data->set.accepttimeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_USERPWD:
+ /*
+ * user:password to use in the operation
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_USERNAME],
+ &data->set.str[STRING_PASSWORD]);
+ break;
+
+ case CURLOPT_USERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_USERNAME],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PASSWORD],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_LOGIN_OPTIONS:
+ /*
+ * authentication options to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_OPTIONS],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_XOAUTH2_BEARER:
+ /*
+ * OAuth 2.0 bearer token to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_BEARER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_POSTQUOTE:
+ /*
+ * List of RAW FTP commands to use after a transfer
+ */
+ data->set.postquote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_PREQUOTE:
+ /*
+ * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+ */
+ data->set.prequote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_QUOTE:
+ /*
+ * List of RAW FTP commands to use before a transfer
+ */
+ data->set.quote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_RESOLVE:
+ /*
+ * List of NAME:[address] names to populate the DNS cache with
+ * Prefix the NAME with dash (-) to _remove_ the name from the cache.
+ *
+ * Names added with this API will remain in the cache until explicitly
+ * removed or the handle is cleaned up.
+ *
+ * This API can remove any name from the DNS cache, but only entries
+ * that aren't actually in use right now will be pruned immediately.
+ */
+ data->set.resolve = va_arg(param, struct curl_slist *);
+ data->change.resolve = data->set.resolve;
+ break;
+ case CURLOPT_PROGRESSFUNCTION:
+ /*
+ * Progress callback function
+ */
+ data->set.fprogress = va_arg(param, curl_progress_callback);
+ if(data->set.fprogress)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+ break;
+
+ case CURLOPT_XFERINFOFUNCTION:
+ /*
+ * Transfer info callback function
+ */
+ data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
+ if(data->set.fxferinfo)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+
+ break;
+
+ case CURLOPT_PROGRESSDATA:
+ /*
+ * Custom client data to pass to the progress callback
+ */
+ data->set.progress_client = va_arg(param, void *);
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_PROXYUSERPWD:
+ /*
+ * user:password needed to use the proxy
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_PROXYUSERNAME],
+ &data->set.str[STRING_PROXYPASSWORD]);
+ break;
+ case CURLOPT_PROXYUSERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PROXYUSERNAME],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXYPASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_NOPROXY:
+ /*
+ * proxy exception list
+ */
+ result = setstropt(&data->set.str[STRING_NOPROXY],
+ va_arg(param, char *));
+ break;
+#endif
+
+ case CURLOPT_RANGE:
+ /*
+ * What range of the file you want to transfer
+ */
+ result = setstropt(&data->set.str[STRING_SET_RANGE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_RESUME_FROM:
+ /*
+ * Resume transfer at the give file position
+ */
+ data->set.set_resume_from = va_arg(param, long);
+ break;
+ case CURLOPT_RESUME_FROM_LARGE:
+ /*
+ * Resume transfer at the give file position
+ */
+ data->set.set_resume_from = va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_DEBUGFUNCTION:
+ /*
+ * stderr write callback.
+ */
+ data->set.fdebug = va_arg(param, curl_debug_callback);
+ /*
+ * if the callback provided is NULL, it'll use the default callback
+ */
+ break;
+ case CURLOPT_DEBUGDATA:
+ /*
+ * Set to a void * that should receive all error writes. This
+ * defaults to CURLOPT_STDERR for normal operations.
+ */
+ data->set.debugdata = va_arg(param, void *);
+ break;
+ case CURLOPT_STDERR:
+ /*
+ * Set to a FILE * that should receive all error writes. This
+ * defaults to stderr for normal operations.
+ */
+ data->set.err = va_arg(param, FILE *);
+ if(!data->set.err)
+ data->set.err = stderr;
+ break;
+ case CURLOPT_HEADERFUNCTION:
+ /*
+ * Set header write callback
+ */
+ data->set.fwrite_header = va_arg(param, curl_write_callback);
+ break;
+ case CURLOPT_WRITEFUNCTION:
+ /*
+ * Set data write callback
+ */
+ data->set.fwrite_func = va_arg(param, curl_write_callback);
+ if(!data->set.fwrite_func) {
+ data->set.is_fwrite_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fwrite_func = (curl_write_callback)fwrite;
+ }
+ else
+ data->set.is_fwrite_set = 1;
+ break;
+ case CURLOPT_READFUNCTION:
+ /*
+ * Read data callback
+ */
+ data->set.fread_func_set = va_arg(param, curl_read_callback);
+ if(!data->set.fread_func_set) {
+ data->set.is_fread_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fread_func_set = (curl_read_callback)fread;
+ }
+ else
+ data->set.is_fread_set = 1;
+ break;
+ case CURLOPT_SEEKFUNCTION:
+ /*
+ * Seek callback. Might be NULL.
+ */
+ data->set.seek_func = va_arg(param, curl_seek_callback);
+ break;
+ case CURLOPT_SEEKDATA:
+ /*
+ * Seek control callback. Might be NULL.
+ */
+ data->set.seek_client = va_arg(param, void *);
+ break;
+ case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
+ /*
+ * "Convert from network encoding" callback
+ */
+ data->set.convfromnetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_TO_NETWORK_FUNCTION:
+ /*
+ * "Convert to network encoding" callback
+ */
+ data->set.convtonetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_FROM_UTF8_FUNCTION:
+ /*
+ * "Convert from UTF-8 encoding" callback
+ */
+ data->set.convfromutf8 = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_IOCTLFUNCTION:
+ /*
+ * I/O control callback. Might be NULL.
+ */
+ data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+ break;
+ case CURLOPT_IOCTLDATA:
+ /*
+ * I/O control data pointer. Might be NULL.
+ */
+ data->set.ioctl_client = va_arg(param, void *);
+ break;
+ case CURLOPT_SSLCERT:
+ /*
+ * String that holds file name of the SSL certificate to use
+ */
+ result = setstropt(&data->set.str[STRING_CERT_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLCERT:
+ /*
+ * String that holds file name of the SSL certificate to use for proxy
+ */
+ result = setstropt(&data->set.str[STRING_CERT_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLCERTTYPE:
+ /*
+ * String that holds file type of the SSL certificate to use
+ */
+ result = setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLCERTTYPE:
+ /*
+ * String that holds file type of the SSL certificate to use for proxy
+ */
+ result = setstropt(&data->set.str[STRING_CERT_TYPE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEY:
+ /*
+ * String that holds file name of the SSL key to use
+ */
+ result = setstropt(&data->set.str[STRING_KEY_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLKEY:
+ /*
+ * String that holds file name of the SSL key to use for proxy
+ */
+ result = setstropt(&data->set.str[STRING_KEY_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEYTYPE:
+ /*
+ * String that holds file type of the SSL key to use
+ */
+ result = setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_SSLKEYTYPE:
+ /*
+ * String that holds file type of the SSL key to use for proxy
+ */
+ result = setstropt(&data->set.str[STRING_KEY_TYPE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_KEYPASSWD:
+ /*
+ * String that holds the SSL or SSH private key password.
+ */
+ result = setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_KEYPASSWD:
+ /*
+ * String that holds the SSL private key password for proxy.
+ */
+ result = setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLENGINE:
+ /*
+ * String that holds the SSL crypto engine.
+ */
+ argptr = va_arg(param, char *);
+ if(argptr && argptr[0])
+ result = Curl_ssl_set_engine(data, argptr);
+ break;
+
+ case CURLOPT_SSLENGINE_DEFAULT:
+ /*
+ * flag to set engine as default.
+ */
+ result = Curl_ssl_set_engine_default(data);
+ break;
+ case CURLOPT_CRLF:
+ /*
+ * Kludgy option to enable CRLF conversions. Subject for removal.
+ */
+ data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_INTERFACE:
+ /*
+ * Set what interface or address/hostname to bind the socket to when
+ * performing an operation and thus what from-IP your connection will use.
+ */
+ result = setstropt(&data->set.str[STRING_DEVICE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_LOCALPORT:
+ /*
+ * Set what local port to bind the socket to when performing an operation.
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localport = curlx_sltous(arg);
+ break;
+ case CURLOPT_LOCALPORTRANGE:
+ /*
+ * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 65535))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.localportrange = curlx_sltosi(arg);
+ break;
+ case CURLOPT_KRBLEVEL:
+ /*
+ * A string that defines the kerberos security level.
+ */
+ result = setstropt(&data->set.str[STRING_KRB_LEVEL],
+ va_arg(param, char *));
+ data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
+ break;
+ case CURLOPT_GSSAPI_DELEGATION:
+ /*
+ * GSS-API credential delegation
+ */
+ data->set.gssapi_delegation = va_arg(param, long);
+ break;
+ case CURLOPT_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying.
+ */
+ data->set.ssl.primary.verifypeer = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+ case CURLOPT_PROXY_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying for proxy.
+ */
+ data->set.proxy_ssl.primary.verifypeer =
+ (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate
+ */
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
+ break;
+ case CURLOPT_PROXY_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate for proxy
+ */
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
+ break;
+ case CURLOPT_SSL_VERIFYSTATUS:
+ /*
+ * Enable certificate status verifying.
+ */
+ if(!Curl_ssl_cert_status_request()) {
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ }
+
+ data->set.ssl.primary.verifystatus = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ break;
+ case CURLOPT_SSL_CTX_FUNCTION:
+#ifdef have_curlssl_ssl_ctx
+ /*
+ * Set a SSL_CTX callback
+ */
+ data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_SSL_CTX_DATA:
+#ifdef have_curlssl_ssl_ctx
+ /*
+ * Set a SSL_CTX callback parameter pointer
+ */
+ data->set.ssl.fsslctxp = va_arg(param, void *);
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_SSL_FALSESTART:
+ /*
+ * Enable TLS false start.
+ */
+ if(!Curl_ssl_false_start()) {
+ result = CURLE_NOT_BUILT_IN;
+ break;
+ }
+
+ data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_CERTINFO:
+#ifdef have_curlssl_certinfo
+ data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_PINNEDPUBLICKEY:
+#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
+ /*
+ * Set pinned public key for SSL connection.
+ * Specify file name of the public key in DER format.
+ */
+ result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
+ va_arg(param, char *));
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_PROXY_PINNEDPUBLICKEY:
+#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
+ /*
+ * Set pinned public key for SSL connection.
+ * Specify file name of the public key in DER format.
+ */
+ result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY],
+ va_arg(param, char *));
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_CAINFO:
+ /*
+ * Set CA info for SSL connection. Specify file name of the CA certificate
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_CAINFO:
+ /*
+ * Set CA info SSL connection for proxy. Specify file name of the
+ * CA certificate
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_CAPATH:
+#ifdef have_curlssl_ca_path /* not supported by all backends */
+ /*
+ * Set CA path info for SSL connection. Specify directory name of the CA
+ * certificates which have been prepared using openssl c_rehash utility.
+ */
+ /* This does not work on windows. */
+ result = setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
+ va_arg(param, char *));
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_PROXY_CAPATH:
+#ifdef have_curlssl_ca_path /* not supported by all backends */
+ /*
+ * Set CA path info for SSL connection proxy. Specify directory name of the
+ * CA certificates which have been prepared using openssl c_rehash utility.
+ */
+ /* This does not work on windows. */
+ result = setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY],
+ va_arg(param, char *));
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection. Specify file name of the CRL
+ * to check certificates revocation
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection for proxy. Specify file name of the
+ * CRL to check certificates revocation
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_ISSUERCERT:
+ /*
+ * Set Issuer certificate file
+ * to check certificates issuer
+ */
+ result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TELNETOPTIONS:
+ /*
+ * Set a linked list of telnet options
+ */
+ data->set.telnet_options = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_BUFFERSIZE:
+ /*
+ * The application kindly asks for a differently sized receive buffer.
+ * If it seems reasonable, we'll use it.
+ */
+ arg = va_arg(param, long);
+
+ if(arg > READBUFFER_MAX)
+ arg = READBUFFER_MAX;
+ else if(arg < 1)
+ arg = READBUFFER_SIZE;
+ else if(arg < READBUFFER_MIN)
+ arg = READBUFFER_MIN;
+
+ /* Resize if new size */
+ if(arg != data->set.buffer_size) {
+ char *newbuff = realloc(data->state.buffer, arg + 1);
+ if(!newbuff) {
+ DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else
+ data->state.buffer = newbuff;
+ }
+ data->set.buffer_size = arg;
+
+ break;
+
+ case CURLOPT_NOSIGNAL:
+ /*
+ * The application asks not to set any signal() or alarm() handlers,
+ * even when using a timeout.
+ */
+ data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_SHARE:
+ {
+ struct Curl_share *set;
+ set = va_arg(param, struct Curl_share *);
+
+ /* disconnect from old share, if any */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(data->dns.hostcachetype == HCACHE_SHARED) {
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies == data->cookies)
+ data->cookies = NULL;
+#endif
+
+ if(data->share->sslsession == data->state.session)
+ data->state.session = NULL;
+
+ data->share->dirty--;
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ data->share = NULL;
+ }
+
+ /* use new share if it set */
+ data->share = set;
+ if(data->share) {
+
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ data->share->dirty++;
+
+ if(data->share->specifier & (1<< CURL_LOCK_DATA_DNS)) {
+ /* use shared host cache */
+ data->dns.hostcache = &data->share->hostcache;
+ data->dns.hostcachetype = HCACHE_SHARED;
+ }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies) {
+ /* use shared cookie list, first free own one if any */
+ Curl_cookie_cleanup(data->cookies);
+ /* enable cookies since we now use a share that uses cookies! */
+ data->cookies = data->share->cookies;
+ }
+#endif /* CURL_DISABLE_HTTP */
+ if(data->share->sslsession) {
+ data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+ data->state.session = data->share->sslsession;
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+ }
+ /* check for host cache not needed,
+ * it will be done by curl_easy_perform */
+ }
+ break;
+
+ case CURLOPT_PRIVATE:
+ /*
+ * Set private data pointer.
+ */
+ data->set.private_data = va_arg(param, void *);
+ break;
+
+ case CURLOPT_MAXFILESIZE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ data->set.max_filesize = va_arg(param, long);
+ break;
+
+#ifdef USE_SSL
+ case CURLOPT_USE_SSL:
+ /*
+ * Make transfers attempt to use SSL/TLS.
+ */
+ data->set.use_ssl = (curl_usessl)va_arg(param, long);
+ break;
+
+ case CURLOPT_SSL_OPTIONS:
+ arg = va_arg(param, long);
+ data->set.ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+ break;
+
+ case CURLOPT_PROXY_SSL_OPTIONS:
+ arg = va_arg(param, long);
+ data->set.proxy_ssl.enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
+ break;
+
+#endif
+ case CURLOPT_FTPSSLAUTH:
+ /*
+ * Set a specific auth for FTP-SSL transfers.
+ */
+ data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long);
+ break;
+
+ case CURLOPT_IPRESOLVE:
+ data->set.ipver = va_arg(param, long);
+ break;
+
+ case CURLOPT_MAXFILESIZE_LARGE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ data->set.max_filesize = va_arg(param, curl_off_t);
+ break;
+
+ case CURLOPT_TCP_NODELAY:
+ /*
+ * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+ * algorithm
+ */
+ data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_ACCOUNT:
+ result = setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_IGNORE_CONTENT_LENGTH:
+ data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_CONNECT_ONLY:
+ /*
+ * No data transfer, set up connection and let application use the socket
+ */
+ data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+ result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SOCKOPTFUNCTION:
+ /*
+ * socket callback function: called after socket() but before connect()
+ */
+ data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+ break;
+
+ case CURLOPT_SOCKOPTDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.sockopt_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_OPENSOCKETFUNCTION:
+ /*
+ * open/create socket callback function: called instead of socket(),
+ * before connect()
+ */
+ data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+ break;
+
+ case CURLOPT_OPENSOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.opensocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_CLOSESOCKETFUNCTION:
+ /*
+ * close socket callback function: called instead of close()
+ * when shutting down a connection
+ */
+ data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
+ break;
+
+ case CURLOPT_CLOSESOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.closesocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_SSL_SESSIONID_CACHE:
+ data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
+ data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
+ break;
+
+#ifdef USE_LIBSSH2
+ /* we only include SSH options if explicitly built to support SSH */
+ case CURLOPT_SSH_AUTH_TYPES:
+ data->set.ssh_auth_types = va_arg(param, long);
+ break;
+
+ case CURLOPT_SSH_PUBLIC_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+ */
+ result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_PRIVATE_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa file
+ */
+ result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+ /*
+ * Option to allow for the MD5 of the host public key to be checked
+ * for validation purposes.
+ */
+ result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
+ va_arg(param, char *));
+ break;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ case CURLOPT_SSH_KNOWNHOSTS:
+ /*
+ * Store the file name to read known hosts from.
+ */
+ result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_KEYFUNCTION:
+ /* setting to NULL is fine since the ssh.c functions themselves will
+ then rever to use the internal default */
+ data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+ break;
+
+ case CURLOPT_SSH_KEYDATA:
+ /*
+ * Custom client data to pass to the SSH keyfunc callback
+ */
+ data->set.ssh_keyfunc_userp = va_arg(param, void *);
+ break;
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#endif /* USE_LIBSSH2 */
+
+ case CURLOPT_HTTP_TRANSFER_DECODING:
+ /*
+ * disable libcurl transfer encoding is used
+ */
+ data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_HTTP_CONTENT_DECODING:
+ /*
+ * raw data passed to the application when content encoding is used
+ */
+ data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_NEW_FILE_PERMS:
+ /*
+ * Uses these permissions instead of 0644
+ */
+ data->set.new_file_perms = va_arg(param, long);
+ break;
+
+ case CURLOPT_NEW_DIRECTORY_PERMS:
+ /*
+ * Uses these permissions instead of 0755
+ */
+ data->set.new_directory_perms = va_arg(param, long);
+ break;
+
+ case CURLOPT_ADDRESS_SCOPE:
+ /*
+ * We always get longs when passed plain numericals, but for this value we
+ * know that an unsigned int will always hold the value so we blindly
+ * typecast to this type
+ */
+ arg = va_arg(param, long);
+ if((arg < 0) || (arg > 0xf))
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.scope_id = curlx_sltoui(arg);
+ break;
+
+ case CURLOPT_PROTOCOLS:
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ data->set.allowed_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_REDIR_PROTOCOLS:
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ data->set.redir_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_DEFAULT_PROTOCOL:
+ /* Set the protocol to use when the URL doesn't include any protocol */
+ result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_FROM:
+ /* Set the SMTP mail originator */
+ result = setstropt(&data->set.str[STRING_MAIL_FROM],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_AUTH:
+ /* Set the SMTP auth originator */
+ result = setstropt(&data->set.str[STRING_MAIL_AUTH],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_RCPT:
+ /* Set the list of mail recipients */
+ data->set.mail_rcpt = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_SASL_IR:
+ /* Enable/disable SASL initial response */
+ data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_RTSP_REQUEST:
+ {
+ /*
+ * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+ * Would this be better if the RTSPREQ_* were just moved into here?
+ */
+ long curl_rtspreq = va_arg(param, long);
+ Curl_RtspReq rtspreq = RTSPREQ_NONE;
+ switch(curl_rtspreq) {
+ case CURL_RTSPREQ_OPTIONS:
+ rtspreq = RTSPREQ_OPTIONS;
+ break;
+
+ case CURL_RTSPREQ_DESCRIBE:
+ rtspreq = RTSPREQ_DESCRIBE;
+ break;
+
+ case CURL_RTSPREQ_ANNOUNCE:
+ rtspreq = RTSPREQ_ANNOUNCE;
+ break;
+
+ case CURL_RTSPREQ_SETUP:
+ rtspreq = RTSPREQ_SETUP;
+ break;
+
+ case CURL_RTSPREQ_PLAY:
+ rtspreq = RTSPREQ_PLAY;
+ break;
+
+ case CURL_RTSPREQ_PAUSE:
+ rtspreq = RTSPREQ_PAUSE;
+ break;
+
+ case CURL_RTSPREQ_TEARDOWN:
+ rtspreq = RTSPREQ_TEARDOWN;
+ break;
+
+ case CURL_RTSPREQ_GET_PARAMETER:
+ rtspreq = RTSPREQ_GET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_SET_PARAMETER:
+ rtspreq = RTSPREQ_SET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_RECORD:
+ rtspreq = RTSPREQ_RECORD;
+ break;
+
+ case CURL_RTSPREQ_RECEIVE:
+ rtspreq = RTSPREQ_RECEIVE;
+ break;
+ default:
+ rtspreq = RTSPREQ_NONE;
+ }
+
+ data->set.rtspreq = rtspreq;
+ break;
+ }
+
+
+ case CURLOPT_RTSP_SESSION_ID:
+ /*
+ * Set the RTSP Session ID manually. Useful if the application is
+ * resuming a previously established RTSP session
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_STREAM_URI:
+ /*
+ * Set the Stream URI for the RTSP request. Unless the request is
+ * for generic server options, the application will need to set this.
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_TRANSPORT:
+ /*
+ * The content of the Transport: header for the RTSP request
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_CLIENT_CSEQ:
+ /*
+ * Set the CSEQ number to issue for the next RTSP request. Useful if the
+ * application is resuming a previously broken connection. The CSEQ
+ * will increment from this new number henceforth.
+ */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_RTSP_SERVER_CSEQ:
+ /* Same as the above, but for server-initiated requests */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_INTERLEAVEDATA:
+ data->set.rtp_out = va_arg(param, void *);
+ break;
+ case CURLOPT_INTERLEAVEFUNCTION:
+ /* Set the user defined RTP write function */
+ data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+ break;
+
+ case CURLOPT_WILDCARDMATCH:
+ data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_CHUNK_BGN_FUNCTION:
+ data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
+ break;
+ case CURLOPT_CHUNK_END_FUNCTION:
+ data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
+ break;
+ case CURLOPT_FNMATCH_FUNCTION:
+ data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
+ break;
+ case CURLOPT_CHUNK_DATA:
+ data->wildcard.customptr = va_arg(param, void *);
+ break;
+ case CURLOPT_FNMATCH_DATA:
+ data->set.fnmatch_data = va_arg(param, void *);
+ break;
+#ifdef USE_TLS_SRP
+ case CURLOPT_TLSAUTH_USERNAME:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_PROXY_TLSAUTH_USERNAME:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+ !data->set.proxy_ssl.authtype)
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_PASSWORD:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_PROXY_TLSAUTH_PASSWORD:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
+ !data->set.proxy_ssl.authtype)
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_TYPE:
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP;
+ else
+ data->set.ssl.authtype = CURL_TLSAUTH_NONE;
+ break;
+ case CURLOPT_PROXY_TLSAUTH_TYPE:
+ argptr = va_arg(param, char *);
+ if(!argptr ||
+ strncasecompare(argptr, "SRP", strlen("SRP")))
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP;
+ else
+ data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
+ break;
+#endif
+ case CURLOPT_DNS_SERVERS:
+ result = Curl_set_dns_servers(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_INTERFACE:
+ result = Curl_set_dns_interface(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP4:
+ result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP6:
+ result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
+ break;
+
+ case CURLOPT_TCP_KEEPALIVE:
+ data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_TCP_KEEPIDLE:
+ data->set.tcp_keepidle = va_arg(param, long);
+ break;
+ case CURLOPT_TCP_KEEPINTVL:
+ data->set.tcp_keepintvl = va_arg(param, long);
+ break;
+ case CURLOPT_TCP_FASTOPEN:
+#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN)
+ data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURLOPT_SSL_ENABLE_NPN:
+ data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_SSL_ENABLE_ALPN:
+ data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+#ifdef USE_UNIX_SOCKETS
+ case CURLOPT_UNIX_SOCKET_PATH:
+ data->set.abstract_unix_socket = FALSE;
+ result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_ABSTRACT_UNIX_SOCKET:
+ data->set.abstract_unix_socket = TRUE;
+ result = setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH],
+ va_arg(param, char *));
+ break;
+#endif
+
+ case CURLOPT_PATH_AS_IS:
+ data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_PIPEWAIT:
+ data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_STREAM_WEIGHT:
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ arg = va_arg(param, long);
+ if((arg>=1) && (arg <= 256))
+ data->set.stream_weight = (int)arg;
+ break;
+#endif
+ case CURLOPT_STREAM_DEPENDS:
+ case CURLOPT_STREAM_DEPENDS_E:
+ {
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+ if(!dep || GOOD_EASY_HANDLE(dep)) {
+ if(data->set.stream_depends_on) {
+ Curl_http2_remove_child(data->set.stream_depends_on, data);
+ }
+ Curl_http2_add_child(dep, data, (option == CURLOPT_STREAM_DEPENDS_E));
+ }
+ break;
+#endif
+ }
+ case CURLOPT_CONNECT_TO:
+ data->set.connect_to = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_SUPPRESS_CONNECT_HEADERS:
+ data->set.suppress_connect_headers = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ default:
+ /* unknown tag and its companion, just ignore: */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+
+ return result;
+}
+
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+static void conn_reset_postponed_data(struct connectdata *conn, int num)
+{
+ struct postponed_data * const psnd = &(conn->postponed[num]);
+ if(psnd->buffer) {
+ DEBUGASSERT(psnd->allocated_size > 0);
+ DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
+ DEBUGASSERT(psnd->recv_size ?
+ (psnd->recv_processed < psnd->recv_size) :
+ (psnd->recv_processed == 0));
+ DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD);
+ free(psnd->buffer);
+ psnd->buffer = NULL;
+ psnd->allocated_size = 0;
+ psnd->recv_size = 0;
+ psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+ psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+ }
+ else {
+ DEBUGASSERT(psnd->allocated_size == 0);
+ DEBUGASSERT(psnd->recv_size == 0);
+ DEBUGASSERT(psnd->recv_processed == 0);
+ DEBUGASSERT(psnd->bindsock == CURL_SOCKET_BAD);
+ }
+}
+
+static void conn_reset_all_postponed_data(struct connectdata *conn)
+{
+ conn_reset_postponed_data(conn, 0);
+ conn_reset_postponed_data(conn, 1);
+}
+#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+/* Use "do-nothing" macro instead of function when workaround not used */
+#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
+#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+
+static void conn_free(struct connectdata *conn)
+{
+ if(!conn)
+ return;
+
+ /* possible left-overs from the async name resolvers */
+ Curl_resolver_cancel(conn);
+
+ /* close the SSL stuff before we close any sockets since they will/may
+ write to the sockets */
+ Curl_ssl_close(conn, FIRSTSOCKET);
+ Curl_ssl_close(conn, SECONDARYSOCKET);
+
+ /* close possibly still open sockets */
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
+ Curl_closesocket(conn, conn->sock[FIRSTSOCKET]);
+ if(CURL_SOCKET_BAD != conn->tempsock[0])
+ Curl_closesocket(conn, conn->tempsock[0]);
+ if(CURL_SOCKET_BAD != conn->tempsock[1])
+ Curl_closesocket(conn, conn->tempsock[1]);
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ Curl_ntlm_wb_cleanup(conn);
+#endif
+
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ Curl_safefree(conn->oauth_bearer);
+ Curl_safefree(conn->options);
+ Curl_safefree(conn->http_proxy.user);
+ Curl_safefree(conn->socks_proxy.user);
+ Curl_safefree(conn->http_proxy.passwd);
+ Curl_safefree(conn->socks_proxy.passwd);
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ Curl_safefree(conn->allocptr.uagent);
+ Curl_safefree(conn->allocptr.userpwd);
+ Curl_safefree(conn->allocptr.accept_encoding);
+ Curl_safefree(conn->allocptr.te);
+ Curl_safefree(conn->allocptr.rangeline);
+ Curl_safefree(conn->allocptr.ref);
+ Curl_safefree(conn->allocptr.host);
+ Curl_safefree(conn->allocptr.cookiehost);
+ Curl_safefree(conn->allocptr.rtsp_transport);
+ Curl_safefree(conn->trailer);
+ Curl_safefree(conn->host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->secondaryhostname);
+ Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
+ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
+ Curl_safefree(conn->master_buffer);
+ Curl_safefree(conn->connect_buffer);
+
+ conn_reset_all_postponed_data(conn);
+
+ Curl_llist_destroy(&conn->send_pipe, NULL);
+ Curl_llist_destroy(&conn->recv_pipe, NULL);
+
+ Curl_safefree(conn->localdev);
+ Curl_free_primary_ssl_config(&conn->ssl_config);
+ Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+
+#ifdef USE_UNIX_SOCKETS
+ Curl_safefree(conn->unix_domain_socket);
+#endif
+
+ free(conn); /* free all the connection oriented data */
+}
+
+/*
+ * Disconnects the given connection. Note the connection may not be the
+ * primary connection, like when freeing room in the connection cache or
+ * killing of a dead old connection.
+ *
+ * This function MUST NOT reset state in the Curl_easy struct if that
+ * isn't strictly bound to the life-time of *this* particular connection.
+ *
+ */
+
+CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct Curl_easy *data;
+ if(!conn)
+ return CURLE_OK; /* this is closed and fine already */
+ data = conn->data;
+
+ if(!data) {
+ DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n"));
+ return CURLE_OK;
+ }
+
+ /*
+ * If this connection isn't marked to force-close, leave it open if there
+ * are other users of it
+ */
+ if(!conn->bits.close &&
+ (conn->send_pipe.size + conn->recv_pipe.size)) {
+ DEBUGF(infof(data, "Curl_disconnect, usecounter: %d\n",
+ conn->send_pipe.size + conn->recv_pipe.size));
+ return CURLE_OK;
+ }
+
+ if(conn->dns_entry != NULL) {
+ Curl_resolv_unlock(data, conn->dns_entry);
+ conn->dns_entry = NULL;
+ }
+
+ Curl_hostcache_prune(data); /* kill old DNS cache entries */
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
+ /* Cleanup NTLM connection-related data */
+ Curl_http_ntlm_cleanup(conn);
+#endif
+
+ if(conn->handler->disconnect)
+ /* This is set if protocol-specific cleanups should be made */
+ conn->handler->disconnect(conn, dead_connection);
+
+ /* unlink ourselves! */
+ infof(data, "Closing connection %ld\n", conn->connection_id);
+ Curl_conncache_remove_conn(data->state.conn_cache, conn);
+
+ free_fixed_hostname(&conn->host);
+ free_fixed_hostname(&conn->conn_to_host);
+ free_fixed_hostname(&conn->http_proxy.host);
+ free_fixed_hostname(&conn->socks_proxy.host);
+
+ Curl_ssl_close(conn, FIRSTSOCKET);
+
+ /* Indicate to all handles on the pipe that we're dead */
+ if(Curl_pipeline_wanted(data->multi, CURLPIPE_ANY)) {
+ signalPipeClose(&conn->send_pipe, TRUE);
+ signalPipeClose(&conn->recv_pipe, TRUE);
+ }
+
+ conn_free(conn);
+
+ return CURLE_OK;
+}
+
+/*
+ * This function should return TRUE if the socket is to be assumed to
+ * be dead. Most commonly this happens when the server has closed the
+ * connection due to inactivity.
+ */
+static bool SocketIsDead(curl_socket_t sock)
+{
+ int sval;
+ bool ret_val = TRUE;
+
+ sval = SOCKET_READABLE(sock, 0);
+ if(sval == 0)
+ /* timeout */
+ ret_val = FALSE;
+
+ return ret_val;
+}
+
+/*
+ * IsPipeliningPossible()
+ *
+ * Return a bitmask with the available pipelining and multiplexing options for
+ * the given requested connection.
+ */
+static int IsPipeliningPossible(const struct Curl_easy *handle,
+ const struct connectdata *conn)
+{
+ int avail = 0;
+
+ /* If a HTTP protocol and pipelining is enabled */
+ if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ (!conn->bits.protoconnstart || !conn->bits.close)) {
+
+ if(Curl_pipeline_wanted(handle->multi, CURLPIPE_HTTP1) &&
+ (handle->set.httpversion != CURL_HTTP_VERSION_1_0) &&
+ (handle->set.httpreq == HTTPREQ_GET ||
+ handle->set.httpreq == HTTPREQ_HEAD))
+ /* didn't ask for HTTP/1.0 and a GET or HEAD */
+ avail |= CURLPIPE_HTTP1;
+
+ if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) &&
+ (handle->set.httpversion >= CURL_HTTP_VERSION_2))
+ /* allows HTTP/2 */
+ avail |= CURLPIPE_MULTIPLEX;
+ }
+ return avail;
+}
+
+int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
+ struct curl_llist *pipeline)
+{
+ if(pipeline) {
+ struct curl_llist_element *curr;
+
+ curr = pipeline->head;
+ while(curr) {
+ if(curr->ptr == handle) {
+ Curl_llist_remove(pipeline, curr, NULL);
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
+ }
+ }
+
+ return 0;
+}
+
+#if 0 /* this code is saved here as it is useful for debugging purposes */
+static void Curl_printPipeline(struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr;
+
+ curr = pipeline->head;
+ while(curr) {
+ struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
+ infof(data, "Handle in pipeline: %s\n", data->state.path);
+ curr = curr->next;
+ }
+}
+#endif
+
+static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr = pipeline->head;
+ if(curr) {
+ return (struct Curl_easy *) curr->ptr;
+ }
+
+ return NULL;
+}
+
+/* remove the specified connection from all (possible) pipelines and related
+ queues */
+void Curl_getoff_all_pipelines(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ bool recv_head = (conn->readchannel_inuse &&
+ Curl_recvpipe_head(data, conn));
+ bool send_head = (conn->writechannel_inuse &&
+ Curl_sendpipe_head(data, conn));
+
+ if(Curl_removeHandleFromPipeline(data, &conn->recv_pipe) && recv_head)
+ Curl_pipeline_leave_read(conn);
+ if(Curl_removeHandleFromPipeline(data, &conn->send_pipe) && send_head)
+ Curl_pipeline_leave_write(conn);
+}
+
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
+{
+ struct curl_llist_element *curr;
+
+ if(!pipeline)
+ return;
+
+ curr = pipeline->head;
+ while(curr) {
+ struct curl_llist_element *next = curr->next;
+ struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
+
+#ifdef DEBUGBUILD /* debug-only code */
+ if(data->magic != CURLEASY_MAGIC_NUMBER) {
+ /* MAJOR BADNESS */
+ infof(data, "signalPipeClose() found BAAD easy handle\n");
+ }
+#endif
+
+ if(pipe_broke)
+ data->state.pipe_broke = TRUE;
+ Curl_multi_handlePipeBreak(data);
+ Curl_llist_remove(pipeline, curr, NULL);
+ curr = next;
+ }
+}
+
+/*
+ * This function finds the connection in the connection
+ * cache that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+struct connectdata *
+Curl_oldest_idle_connection(struct Curl_easy *data)
+{
+ struct conncache *bc = data->state.conn_cache;
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+ time_t highscore=-1;
+ time_t score;
+ struct timeval now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectbundle *bundle;
+
+ now = Curl_tvnow();
+
+ Curl_hash_start_iterate(&bc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ curr = bundle->conn_list.head;
+ while(curr) {
+ conn = curr->ptr;
+
+ if(!conn->inuse) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_tvdiff(now, conn->now);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ }
+ }
+ curr = curr->next;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+
+ return conn_candidate;
+}
+
+static bool
+proxy_info_matches(const struct proxy_info* data,
+ const struct proxy_info* needle)
+{
+ if((data->proxytype == needle->proxytype) &&
+ (data->port == needle->port) &&
+ Curl_safe_strcasecompare(data->host.name, needle->host.name))
+ return TRUE;
+
+ return FALSE;
+}
+
+
+/*
+ * This function finds the connection in the connection
+ * bundle that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+static struct connectdata *
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
+ struct connectbundle *bundle)
+{
+ struct curl_llist_element *curr;
+ time_t highscore=-1;
+ time_t score;
+ struct timeval now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectdata *conn;
+
+ (void)data;
+
+ now = Curl_tvnow();
+
+ curr = bundle->conn_list.head;
+ while(curr) {
+ conn = curr->ptr;
+
+ if(!conn->inuse) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_tvdiff(now, conn->now);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ }
+ }
+ curr = curr->next;
+ }
+
+ return conn_candidate;
+}
+
+/*
+ * This function checks if given connection is dead and disconnects if so.
+ * (That also removes it from the connection cache.)
+ *
+ * Returns TRUE if the connection actually was dead and disconnected.
+ */
+static bool disconnect_if_dead(struct connectdata *conn,
+ struct Curl_easy *data)
+{
+ size_t pipeLen = conn->send_pipe.size + conn->recv_pipe.size;
+ if(!pipeLen && !conn->inuse) {
+ /* The check for a dead socket makes sense only if there are no
+ handles in pipeline and the connection isn't already marked in
+ use */
+ bool dead;
+ if(conn->handler->protocol & CURLPROTO_RTSP)
+ /* RTSP is a special case due to RTP interleaving */
+ dead = Curl_rtsp_connisdead(conn);
+ else
+ dead = SocketIsDead(conn->sock[FIRSTSOCKET]);
+
+ if(dead) {
+ conn->data = data;
+ infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
+
+ /* disconnect resources */
+ Curl_disconnect(conn, /* dead_connection */TRUE);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*
+ * Wrapper to use disconnect_if_dead() function in Curl_conncache_foreach()
+ *
+ * Returns always 0.
+ */
+static int call_disconnect_if_dead(struct connectdata *conn,
+ void *param)
+{
+ struct Curl_easy* data = (struct Curl_easy*)param;
+ disconnect_if_dead(conn, data);
+ return 0; /* continue iteration */
+}
+
+/*
+ * This function scans the connection cache for half-open/dead connections,
+ * closes and removes them.
+ * The cleanup is done at most once per second.
+ */
+static void prune_dead_connections(struct Curl_easy *data)
+{
+ struct timeval now = Curl_tvnow();
+ time_t elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
+
+ if(elapsed >= 1000L) {
+ Curl_conncache_foreach(data->state.conn_cache, data,
+ call_disconnect_if_dead);
+ data->state.conn_cache->last_cleanup = now;
+ }
+}
+
+
+static size_t max_pipeline_length(struct Curl_multi *multi)
+{
+ return multi ? multi->max_pipeline_length : 0;
+}
+
+
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that has all the significant details
+ * exactly the same and thus should be used instead.
+ *
+ * If there is a match, this function returns TRUE - and has marked the
+ * connection as 'in-use'. It must later be called with ConnectionDone() to
+ * return back to 'idle' (unused) state.
+ *
+ * The force_reuse flag is set if the connection must be used, even if
+ * the pipelining strategy wants to open a new connection instead of reusing.
+ */
+static bool
+ConnectionExists(struct Curl_easy *data,
+ struct connectdata *needle,
+ struct connectdata **usethis,
+ bool *force_reuse,
+ bool *waitpipe)
+{
+ struct connectdata *check;
+ struct connectdata *chosen = 0;
+ bool foundPendingCandidate = FALSE;
+ int canpipe = IsPipeliningPossible(data, needle);
+ struct connectbundle *bundle;
+
+#ifdef USE_NTLM
+ bool wantNTLMhttp = ((data->state.authhost.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP));
+ bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
+ ((data->state.authproxy.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP)));
+#endif
+
+ *force_reuse = FALSE;
+ *waitpipe = FALSE;
+
+ /* We can't pipeline if the site is blacklisted */
+ if((canpipe & CURLPIPE_HTTP1) &&
+ Curl_pipeline_site_blacklisted(data, needle))
+ canpipe &= ~ CURLPIPE_HTTP1;
+
+ /* Look up the bundle with all the connections to this
+ particular host */
+ bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache);
+ if(bundle) {
+ /* Max pipe length is zero (unlimited) for multiplexed connections */
+ size_t max_pipe_len = (bundle->multiuse != BUNDLE_MULTIPLEX)?
+ max_pipeline_length(data->multi):0;
+ size_t best_pipe_len = max_pipe_len;
+ struct curl_llist_element *curr;
+
+ infof(data, "Found bundle for host %s: %p [%s]\n",
+ (needle->bits.conn_to_host ? needle->conn_to_host.name :
+ needle->host.name), (void *)bundle,
+ (bundle->multiuse == BUNDLE_PIPELINING ?
+ "can pipeline" :
+ (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially")));
+
+ /* We can't pipeline if we don't know anything about the server */
+ if(canpipe) {
+ if(bundle->multiuse <= BUNDLE_UNKNOWN) {
+ if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
+ infof(data, "Server doesn't support multi-use yet, wait\n");
+ *waitpipe = TRUE;
+ return FALSE; /* no re-use */
+ }
+
+ infof(data, "Server doesn't support multi-use (yet)\n");
+ canpipe = 0;
+ }
+ if((bundle->multiuse == BUNDLE_PIPELINING) &&
+ !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) {
+ /* not asked for, switch off */
+ infof(data, "Could pipeline, but not asked to!\n");
+ canpipe = 0;
+ }
+ else if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
+ !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) {
+ infof(data, "Could multiplex, but not asked to!\n");
+ canpipe = 0;
+ }
+ }
+
+ curr = bundle->conn_list.head;
+ while(curr) {
+ bool match = FALSE;
+ size_t pipeLen;
+
+ /*
+ * Note that if we use a HTTP proxy in normal mode (no tunneling), we
+ * check connections to that proxy and not to the actual remote server.
+ */
+ check = curr->ptr;
+ curr = curr->next;
+
+ if(disconnect_if_dead(check, data))
+ continue;
+
+ pipeLen = check->send_pipe.size + check->recv_pipe.size;
+
+ if(canpipe) {
+ if(check->bits.protoconnstart && check->bits.close)
+ continue;
+
+ if(!check->bits.multiplex) {
+ /* If not multiplexing, make sure the connection is fine for HTTP/1
+ pipelining */
+ struct Curl_easy* sh = gethandleathead(&check->send_pipe);
+ struct Curl_easy* rh = gethandleathead(&check->recv_pipe);
+ if(sh) {
+ if(!(IsPipeliningPossible(sh, check) & CURLPIPE_HTTP1))
+ continue;
+ }
+ else if(rh) {
+ if(!(IsPipeliningPossible(rh, check) & CURLPIPE_HTTP1))
+ continue;
+ }
+ }
+ }
+ else {
+ if(pipeLen > 0) {
+ /* can only happen within multi handles, and means that another easy
+ handle is using this connection */
+ continue;
+ }
+
+ if(Curl_resolver_asynch()) {
+ /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
+ completed yet and until then we don't re-use this connection */
+ if(!check->ip_addr_str[0]) {
+ infof(data,
+ "Connection #%ld is still name resolving, can't reuse\n",
+ check->connection_id);
+ continue;
+ }
+ }
+
+ if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) ||
+ check->bits.close) {
+ if(!check->bits.close)
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet or that is going
+ to get closed. */
+ infof(data, "Connection #%ld isn't open enough, can't reuse\n",
+ check->connection_id);
+#ifdef DEBUGBUILD
+ if(check->recv_pipe.size > 0) {
+ infof(data,
+ "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
+ check->connection_id);
+ }
+#endif
+ continue;
+ }
+ }
+
+#ifdef USE_UNIX_SOCKETS
+ if(needle->unix_domain_socket) {
+ if(!check->unix_domain_socket)
+ continue;
+ if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
+ continue;
+ if(needle->abstract_unix_socket != check->abstract_unix_socket)
+ continue;
+ }
+ else if(check->unix_domain_socket)
+ continue;
+#endif
+
+ if((needle->handler->flags&PROTOPT_SSL) !=
+ (check->handler->flags&PROTOPT_SSL))
+ /* don't do mixed SSL and non-SSL connections */
+ if(get_protocol_family(check->handler->protocol) !=
+ needle->handler->protocol || !check->tls_upgraded)
+ /* except protocols that have been upgraded via TLS */
+ continue;
+
+ if(needle->bits.httpproxy != check->bits.httpproxy ||
+ needle->bits.socksproxy != check->bits.socksproxy)
+ continue;
+
+ if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy,
+ &check->socks_proxy))
+ continue;
+
+ if(needle->bits.conn_to_host != check->bits.conn_to_host)
+ /* don't mix connections that use the "connect to host" feature and
+ * connections that don't use this feature */
+ continue;
+
+ if(needle->bits.conn_to_port != check->bits.conn_to_port)
+ /* don't mix connections that use the "connect to port" feature and
+ * connections that don't use this feature */
+ continue;
+
+ if(needle->bits.httpproxy) {
+ if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
+ continue;
+
+ if(needle->bits.tunnel_proxy != check->bits.tunnel_proxy)
+ continue;
+
+ if(needle->http_proxy.proxytype == CURLPROXY_HTTPS) {
+ /* use https proxy */
+ if(needle->handler->flags&PROTOPT_SSL) {
+ /* use double layer ssl */
+ if(!Curl_ssl_config_matches(&needle->proxy_ssl_config,
+ &check->proxy_ssl_config))
+ continue;
+ if(check->proxy_ssl[FIRSTSOCKET].state != ssl_connection_complete)
+ continue;
+ }
+ else {
+ if(!Curl_ssl_config_matches(&needle->ssl_config,
+ &check->ssl_config))
+ continue;
+ if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete)
+ continue;
+ }
+ }
+ }
+
+ if(!canpipe && check->inuse)
+ /* this request can't be pipelined but the checked connection is
+ already in use so we skip it */
+ continue;
+
+ if(needle->localdev || needle->localport) {
+ /* If we are bound to a specific local end (IP+port), we must not
+ re-use a random other one, although if we didn't ask for a
+ particular one we can reuse one that was bound.
+
+ This comparison is a bit rough and too strict. Since the input
+ parameters can be specified in numerous ways and still end up the
+ same it would take a lot of processing to make it really accurate.
+ Instead, this matching will assume that re-uses of bound connections
+ will most likely also re-use the exact same binding parameters and
+ missing out a few edge cases shouldn't hurt anyone very much.
+ */
+ if((check->localport != needle->localport) ||
+ (check->localportrange != needle->localportrange) ||
+ (needle->localdev &&
+ (!check->localdev || strcmp(check->localdev, needle->localdev))))
+ continue;
+ }
+
+ if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+ /* This protocol requires credentials per connection,
+ so verify that we're using the same name and password as well */
+ if(strcmp(needle->user, check->user) ||
+ strcmp(needle->passwd, check->passwd)) {
+ /* one of them was different */
+ continue;
+ }
+ }
+
+ if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
+ needle->bits.tunnel_proxy) {
+ /* The requested connection does not use a HTTP proxy or it uses SSL or
+ it is a non-SSL protocol tunneled or it is a non-SSL protocol which
+ is allowed to be upgraded via TLS */
+
+ if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
+ (get_protocol_family(check->handler->protocol) ==
+ needle->handler->protocol && check->tls_upgraded)) &&
+ (!needle->bits.conn_to_host || strcasecompare(
+ needle->conn_to_host.name, check->conn_to_host.name)) &&
+ (!needle->bits.conn_to_port ||
+ needle->conn_to_port == check->conn_to_port) &&
+ strcasecompare(needle->host.name, check->host.name) &&
+ needle->remote_port == check->remote_port) {
+ /* The schemes match or the the protocol family is the same and the
+ previous connection was TLS upgraded, and the hostname and host
+ port match */
+ if(needle->handler->flags & PROTOPT_SSL) {
+ /* This is a SSL connection so verify that we're using the same
+ SSL options as well */
+ if(!Curl_ssl_config_matches(&needle->ssl_config,
+ &check->ssl_config)) {
+ DEBUGF(infof(data,
+ "Connection #%ld has different SSL parameters, "
+ "can't reuse\n",
+ check->connection_id));
+ continue;
+ }
+ if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
+ foundPendingCandidate = TRUE;
+ DEBUGF(infof(data,
+ "Connection #%ld has not started SSL connect, "
+ "can't reuse\n",
+ check->connection_id));
+ continue;
+ }
+ }
+ match = TRUE;
+ }
+ }
+ else {
+ /* The requested connection is using the same HTTP proxy in normal
+ mode (no tunneling) */
+ match = TRUE;
+ }
+
+ if(match) {
+#if defined(USE_NTLM)
+ /* If we are looking for an HTTP+NTLM connection, check if this is
+ already authenticating with the right credentials. If not, keep
+ looking so that we can reuse NTLM connections if
+ possible. (Especially we must not reuse the same connection if
+ partway through a handshake!) */
+ if(wantNTLMhttp) {
+ if(strcmp(needle->user, check->user) ||
+ strcmp(needle->passwd, check->passwd))
+ continue;
+ }
+ else if(check->ntlm.state != NTLMSTATE_NONE) {
+ /* Connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+
+ /* Same for Proxy NTLM authentication */
+ if(wantProxyNTLMhttp) {
+ /* Both check->http_proxy.user and check->http_proxy.passwd can be
+ * NULL */
+ if(!check->http_proxy.user || !check->http_proxy.passwd)
+ continue;
+
+ if(strcmp(needle->http_proxy.user, check->http_proxy.user) ||
+ strcmp(needle->http_proxy.passwd, check->http_proxy.passwd))
+ continue;
+ }
+ else if(check->proxyntlm.state != NTLMSTATE_NONE) {
+ /* Proxy connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+
+ if(wantNTLMhttp || wantProxyNTLMhttp) {
+ /* Credentials are already checked, we can use this connection */
+ chosen = check;
+
+ if((wantNTLMhttp &&
+ (check->ntlm.state != NTLMSTATE_NONE)) ||
+ (wantProxyNTLMhttp &&
+ (check->proxyntlm.state != NTLMSTATE_NONE))) {
+ /* We must use this connection, no other */
+ *force_reuse = TRUE;
+ break;
+ }
+
+ /* Continue look up for a better connection */
+ continue;
+ }
+#endif
+ if(canpipe) {
+ /* We can pipeline if we want to. Let's continue looking for
+ the optimal connection to use, i.e the shortest pipe that is not
+ blacklisted. */
+
+ if(pipeLen == 0) {
+ /* We have the optimal connection. Let's stop looking. */
+ chosen = check;
+ break;
+ }
+
+ /* We can't use the connection if the pipe is full */
+ if(max_pipe_len && (pipeLen >= max_pipe_len)) {
+ infof(data, "Pipe is full, skip (%zu)\n", pipeLen);
+ continue;
+ }
+#ifdef USE_NGHTTP2
+ /* If multiplexed, make sure we don't go over concurrency limit */
+ if(check->bits.multiplex) {
+ /* Multiplexed connections can only be HTTP/2 for now */
+ struct http_conn *httpc = &check->proto.httpc;
+ if(pipeLen >= httpc->settings.max_concurrent_streams) {
+ infof(data, "MAX_CONCURRENT_STREAMS reached, skip (%zu)\n",
+ pipeLen);
+ continue;
+ }
+ }
+#endif
+ /* We can't use the connection if the pipe is penalized */
+ if(Curl_pipeline_penalized(data, check)) {
+ infof(data, "Penalized, skip\n");
+ continue;
+ }
+
+ if(max_pipe_len) {
+ if(pipeLen < best_pipe_len) {
+ /* This connection has a shorter pipe so far. We'll pick this
+ and continue searching */
+ chosen = check;
+ best_pipe_len = pipeLen;
+ continue;
+ }
+ }
+ else {
+ /* When not pipelining (== multiplexed), we have a match here! */
+ chosen = check;
+ infof(data, "Multiplexed connection found!\n");
+ break;
+ }
+ }
+ else {
+ /* We have found a connection. Let's stop searching. */
+ chosen = check;
+ break;
+ }
+ }
+ }
+ }
+
+ if(chosen) {
+ *usethis = chosen;
+ return TRUE; /* yes, we found one to use! */
+ }
+
+ if(foundPendingCandidate && data->set.pipewait) {
+ infof(data,
+ "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n");
+ *waitpipe = TRUE;
+ }
+
+ return FALSE; /* no matching connecting exists */
+}
+
+/* after a TCP connection to the proxy has been verified, this function does
+ the next magic step.
+
+ Note: this function's sub-functions call failf()
+
+*/
+CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->bits.socksproxy) {
+#ifndef CURL_DISABLE_PROXY
+ /* for the secondary socket (FTP), use the "connect to host"
+ * but ignore the "connect to port" (use the secondary port)
+ */
+ const char * const host = conn->bits.httpproxy ?
+ conn->http_proxy.host.name :
+ conn->bits.conn_to_host ?
+ conn->conn_to_host.name :
+ sockindex == SECONDARYSOCKET ?
+ conn->secondaryhostname : conn->host.name;
+ const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port :
+ sockindex == SECONDARYSOCKET ? conn->secondary_port :
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port;
+ conn->bits.socksproxy_connecting = TRUE;
+ switch(conn->socks_proxy.proxytype) {
+ case CURLPROXY_SOCKS5:
+ case CURLPROXY_SOCKS5_HOSTNAME:
+ result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
+ host, port, sockindex, conn);
+ break;
+
+ case CURLPROXY_SOCKS4:
+ case CURLPROXY_SOCKS4A:
+ result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
+ conn);
+ break;
+
+ default:
+ failf(conn->data, "unknown proxytype option given");
+ result = CURLE_COULDNT_CONNECT;
+ } /* switch proxytype */
+ conn->bits.socksproxy_connecting = FALSE;
+#else
+ (void)sockindex;
+#endif /* CURL_DISABLE_PROXY */
+ }
+
+ return result;
+}
+
+/*
+ * verboseconnect() displays verbose information after a connect
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+void Curl_verboseconnect(struct connectdata *conn)
+{
+ if(conn->data->set.verbose)
+ infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+ conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
+ conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+ conn->bits.conn_to_host ? conn->conn_to_host.dispname :
+ conn->host.dispname,
+ conn->ip_addr_str, conn->port, conn->connection_id);
+}
+#endif
+
+int Curl_protocol_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn->handler->proto_getsock)
+ return conn->handler->proto_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+int Curl_doing_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn && conn->handler->doing_getsock)
+ return conn->handler->doing_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+/*
+ * We are doing protocol-specific connecting and this is being called over and
+ * over from the multi interface until the connection phase is done on
+ * protocol layer.
+ */
+
+CURLcode Curl_protocol_connecting(struct connectdata *conn,
+ bool *done)
+{
+ CURLcode result=CURLE_OK;
+
+ if(conn && conn->handler->connecting) {
+ *done = FALSE;
+ result = conn->handler->connecting(conn, done);
+ }
+ else
+ *done = TRUE;
+
+ return result;
+}
+
+/*
+ * We are DOING this is being called over and over from the multi interface
+ * until the DOING phase is done on protocol layer.
+ */
+
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
+{
+ CURLcode result=CURLE_OK;
+
+ if(conn && conn->handler->doing) {
+ *done = FALSE;
+ result = conn->handler->doing(conn, done);
+ }
+ else
+ *done = TRUE;
+
+ return result;
+}
+
+/*
+ * We have discovered that the TCP connection has been successful, we can now
+ * proceed with some action.
+ *
+ */
+CURLcode Curl_protocol_connect(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result=CURLE_OK;
+
+ *protocol_done = FALSE;
+
+ if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
+ /* We already are connected, get back. This may happen when the connect
+ worked fine in the first call, like when we connect to a local server
+ or proxy. Note that we don't know if the protocol is actually done.
+
+ Unless this protocol doesn't have any protocol-connect callback, as
+ then we know we're done. */
+ if(!conn->handler->connecting)
+ *protocol_done = TRUE;
+
+ return CURLE_OK;
+ }
+
+ if(!conn->bits.protoconnstart) {
+
+ result = Curl_proxy_connect(conn, FIRSTSOCKET);
+ if(result)
+ return result;
+
+ if(CONNECT_FIRSTSOCKET_PROXY_SSL())
+ /* wait for HTTPS proxy SSL initialization to complete */
+ return CURLE_OK;
+
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
+ (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE))
+ /* when using an HTTP tunnel proxy, await complete tunnel establishment
+ before proceeding further. Return CURLE_OK so we'll be called again */
+ return CURLE_OK;
+
+ if(conn->handler->connect_it) {
+ /* is there a protocol-specific connect() procedure? */
+
+ /* Call the protocol-specific connect function */
+ result = conn->handler->connect_it(conn, protocol_done);
+ }
+ else
+ *protocol_done = TRUE;
+
+ /* it has started, possibly even completed but that knowledge isn't stored
+ in this bit! */
+ if(!result)
+ conn->bits.protoconnstart = TRUE;
+ }
+
+ return result; /* pass back status */
+}
+
+/*
+ * Helpers for IDNA conversions.
+ */
+static bool is_ASCII_name(const char *hostname)
+{
+ const unsigned char *ch = (const unsigned char *)hostname;
+
+ while(*ch) {
+ if(*ch++ & 0x80)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+static void fix_hostname(struct connectdata *conn, struct hostname *host)
+{
+ size_t len;
+ struct Curl_easy *data = conn->data;
+
+#ifndef USE_LIBIDN2
+ (void)data;
+ (void)conn;
+#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void)conn;
+#endif
+
+ /* set the name we use to display the host name */
+ host->dispname = host->name;
+
+ len = strlen(host->name);
+ if(len && (host->name[len-1] == '.'))
+ /* strip off a single trailing dot if present, primarily for SNI but
+ there's no use for it */
+ host->name[len-1]=0;
+
+ /* Check name for non-ASCII and convert hostname to ACE form if we can */
+ if(!is_ASCII_name(host->name)) {
+#ifdef USE_LIBIDN2
+ if(idn2_check_version(IDN2_VERSION)) {
+ char *ace_hostname = NULL;
+#if IDN2_VERSION_NUMBER >= 0x00140000
+ /* IDN2_NFC_INPUT: Normalize input string using normalization form C.
+ IDN2_NONTRANSITIONAL: Perform Unicode TR46 non-transitional
+ processing. */
+ int flags = IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL;
+#else
+ int flags = IDN2_NFC_INPUT;
+#endif
+ int rc = idn2_lookup_ul((const char *)host->name, &ace_hostname, flags);
+ if(rc == IDN2_OK) {
+ host->encalloc = (char *)ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ else
+ infof(data, "Failed to convert %s to ACE; %s\n", host->name,
+ idn2_strerror(rc));
+ }
+#elif defined(USE_WIN32_IDN)
+ char *ace_hostname = NULL;
+
+ if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) {
+ host->encalloc = ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ else
+ infof(data, "Failed to convert %s to ACE;\n", host->name);
+#else
+ infof(data, "IDN support not present, can't parse Unicode domains\n");
+#endif
+ }
+}
+
+/*
+ * Frees data allocated by fix_hostname()
+ */
+static void free_fixed_hostname(struct hostname *host)
+{
+#if defined(USE_LIBIDN2)
+ if(host->encalloc) {
+ idn2_free(host->encalloc); /* must be freed with idn2_free() since this was
+ allocated by libidn */
+ host->encalloc = NULL;
+ }
+#elif defined(USE_WIN32_IDN)
+ free(host->encalloc); /* must be freed withidn_free() since this was
+ allocated by curl_win32_idn_to_ascii */
+ host->encalloc = NULL;
+#else
+ (void)host;
+#endif
+}
+
+static void llist_dtor(void *user, void *element)
+{
+ (void)user;
+ (void)element;
+ /* Do nothing */
+}
+
+/*
+ * Allocate and initialize a new connectdata object.
+ */
+static struct connectdata *allocate_conn(struct Curl_easy *data)
+{
+ struct connectdata *conn = calloc(1, sizeof(struct connectdata));
+ if(!conn)
+ return NULL;
+
+ conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
+ already from start to avoid NULL
+ situations and checks */
+
+ /* and we setup a few fields in case we end up actually using this struct */
+
+ conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->tempsock[0] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->tempsock[1] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->connection_id = -1; /* no ID */
+ conn->port = -1; /* unknown at this point */
+ conn->remote_port = -1; /* unknown at this point */
+#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD)
+ conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */
+
+ /* Default protocol-independent behavior doesn't support persistent
+ connections, so we set this to force-close. Protocols that support
+ this need to set this to FALSE in their "curl_do" functions. */
+ connclose(conn, "Default to force-close");
+
+ /* Store creation time to help future close decision making */
+ conn->created = Curl_tvnow();
+
+ conn->data = data; /* Setup the association between this connection
+ and the Curl_easy */
+
+ conn->http_proxy.proxytype = data->set.proxytype;
+ conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
+
+#ifdef CURL_DISABLE_PROXY
+
+ conn->bits.proxy = FALSE;
+ conn->bits.httpproxy = FALSE;
+ conn->bits.socksproxy = FALSE;
+ conn->bits.proxy_user_passwd = FALSE;
+ conn->bits.tunnel_proxy = FALSE;
+
+#else /* CURL_DISABLE_PROXY */
+
+ /* note that these two proxy bits are now just on what looks to be
+ requested, they may be altered down the road */
+ conn->bits.proxy = (data->set.str[STRING_PROXY] &&
+ *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
+ conn->bits.httpproxy = (conn->bits.proxy &&
+ (conn->http_proxy.proxytype == CURLPROXY_HTTP ||
+ conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0 ||
+ conn->http_proxy.proxytype == CURLPROXY_HTTPS)) ?
+ TRUE : FALSE;
+ conn->bits.socksproxy = (conn->bits.proxy &&
+ !conn->bits.httpproxy) ? TRUE : FALSE;
+
+ if(data->set.str[STRING_PRE_PROXY] && *data->set.str[STRING_PRE_PROXY]) {
+ conn->bits.proxy = TRUE;
+ conn->bits.socksproxy = TRUE;
+ }
+
+ conn->bits.proxy_user_passwd =
+ (data->set.str[STRING_PROXYUSERNAME]) ? TRUE : FALSE;
+ conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+
+#endif /* CURL_DISABLE_PROXY */
+
+ conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
+ conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+ conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+
+ conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
+ conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
+ conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
+ conn->proxy_ssl_config.verifystatus =
+ data->set.proxy_ssl.primary.verifystatus;
+ conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
+ conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
+
+ conn->ip_version = data->set.ipver;
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->ntlm_auth_hlpr_pid = 0;
+ conn->challenge_header = NULL;
+ conn->response_header = NULL;
+#endif
+
+ if(Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1) &&
+ !conn->master_buffer) {
+ /* Allocate master_buffer to be used for HTTP/1 pipelining */
+ conn->master_buffer = calloc(MASTERBUF_SIZE, sizeof(char));
+ if(!conn->master_buffer)
+ goto error;
+ }
+
+ /* Initialize the pipeline lists */
+ Curl_llist_init(&conn->send_pipe, (curl_llist_dtor) llist_dtor);
+ Curl_llist_init(&conn->recv_pipe, (curl_llist_dtor) llist_dtor);
+
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CLEAR;
+#endif
+
+ /* Store the local bind parameters that will be used for this connection */
+ if(data->set.str[STRING_DEVICE]) {
+ conn->localdev = strdup(data->set.str[STRING_DEVICE]);
+ if(!conn->localdev)
+ goto error;
+ }
+ conn->localportrange = data->set.localportrange;
+ conn->localport = data->set.localport;
+
+ /* the close socket stuff needs to be copied to the connection struct as
+ it may live on without (this specific) Curl_easy */
+ conn->fclosesocket = data->set.fclosesocket;
+ conn->closesocket_client = data->set.closesocket_client;
+
+ return conn;
+ error:
+
+ Curl_llist_destroy(&conn->send_pipe, NULL);
+ Curl_llist_destroy(&conn->recv_pipe, NULL);
+
+ free(conn->master_buffer);
+ free(conn->localdev);
+ free(conn);
+ return NULL;
+}
+
+static CURLcode findprotocol(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *protostr)
+{
+ const struct Curl_handler * const *pp;
+ const struct Curl_handler *p;
+
+ /* Scan protocol handler table and match against 'protostr' to set a few
+ variables based on the URL. Now that the handler may be changed later
+ when the protocol specific setup function is called. */
+ for(pp = protocols; (p = *pp) != NULL; pp++) {
+ if(strcasecompare(p->scheme, protostr)) {
+ /* Protocol found in table. Check if allowed */
+ if(!(data->set.allowed_protocols & p->protocol))
+ /* nope, get out */
+ break;
+
+ /* it is allowed for "normal" request, now do an extra check if this is
+ the result of a redirect */
+ if(data->state.this_is_a_follow &&
+ !(data->set.redir_protocols & p->protocol))
+ /* nope, get out */
+ break;
+
+ /* Perform setup complement if some. */
+ conn->handler = conn->given = p;
+
+ /* 'port' and 'remote_port' are set in setup_connection_internals() */
+ return CURLE_OK;
+ }
+ }
+
+
+ /* The protocol was not found in the table, but we don't have to assign it
+ to anything since it is already assigned to a dummy-struct in the
+ create_conn() function when the connectdata struct is allocated. */
+ failf(data, "Protocol \"%s\" not supported or disabled in " LIBCURL_NAME,
+ protostr);
+
+ return CURLE_UNSUPPORTED_PROTOCOL;
+}
+
+/*
+ * Parse URL and fill in the relevant members of the connection struct.
+ */
+static CURLcode parseurlandfillconn(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *prot_missing,
+ char **userp, char **passwdp,
+ char **optionsp)
+{
+ char *at;
+ char *fragment;
+ char *path = data->state.path;
+ char *query;
+ int i;
+ int rc;
+ const char *protop = "";
+ CURLcode result;
+ bool rebuild_url = FALSE;
+ bool url_has_scheme = FALSE;
+ char protobuf[16];
+
+ *prot_missing = FALSE;
+
+ /* We might pass the entire URL into the request so we need to make sure
+ * there are no bad characters in there.*/
+ if(strpbrk(data->change.url, "\r\n")) {
+ failf(data, "Illegal characters found in URL");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /*************************************************************
+ * Parse the URL.
+ *
+ * We need to parse the url even when using the proxy, because we will need
+ * the hostname and port in case we are trying to SSL connect through the
+ * proxy -- and we don't know if we will need to use SSL until we parse the
+ * url ...
+ ************************************************************/
+ if(data->change.url[0] == ':') {
+ failf(data, "Bad URL, colon is first character");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Make sure we don't mistake a drive letter for a scheme, for example:
+ curld --proto-default file c:/foo/bar.txt */
+ if((('a' <= data->change.url[0] && data->change.url[0] <= 'z') ||
+ ('A' <= data->change.url[0] && data->change.url[0] <= 'Z')) &&
+ data->change.url[1] == ':' && data->set.str[STRING_DEFAULT_PROTOCOL] &&
+ strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file")) {
+ ; /* do nothing */
+ }
+ else { /* check for a scheme */
+ for(i = 0; i < 16 && data->change.url[i]; ++i) {
+ if(data->change.url[i] == '/')
+ break;
+ if(data->change.url[i] == ':') {
+ url_has_scheme = TRUE;
+ break;
+ }
+ }
+ }
+
+ /* handle the file: scheme */
+ if((url_has_scheme && strncasecompare(data->change.url, "file:", 5)) ||
+ (!url_has_scheme && data->set.str[STRING_DEFAULT_PROTOCOL] &&
+ strcasecompare(data->set.str[STRING_DEFAULT_PROTOCOL], "file"))) {
+ bool path_has_drive = FALSE;
+
+ if(url_has_scheme)
+ rc = sscanf(data->change.url, "%*15[^\n/:]:%[^\n]", path);
+ else
+ rc = sscanf(data->change.url, "%[^\n]", path);
+
+ if(rc != 1) {
+ failf(data, "Bad URL");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ if(url_has_scheme && path[0] == '/' && path[1] == '/') {
+ /* Allow omitted hostname (e.g. file:/<path>). This is not strictly
+ * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
+ * file://localhost/<path> is similar to how other schemes treat missing
+ * hostnames. See RFC 1808. */
+
+ /* This cannot be done with strcpy() in a portable manner, since the
+ memory areas overlap! */
+ memmove(path, path + 2, strlen(path + 2)+1);
+ }
+
+ /* the path may start with a drive letter. for backwards compatibility
+ we skip some processing on those paths. */
+ path_has_drive = (('a' <= path[0] && path[0] <= 'z') ||
+ ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':';
+
+ /*
+ * we deal with file://<host>/<path> differently since it supports no
+ * hostname other than "localhost" and "127.0.0.1", which is unique among
+ * the URL protocols specified in RFC 1738
+ */
+ if(path[0] != '/' && !path_has_drive) {
+ /* the URL includes a host name, it must match "localhost" or
+ "127.0.0.1" to be valid */
+ char *ptr;
+ if(!checkprefix("localhost/", path) &&
+ !checkprefix("127.0.0.1/", path)) {
+ failf(data, "Invalid file://hostname/, "
+ "expected localhost or 127.0.0.1 or none");
+ return CURLE_URL_MALFORMAT;
+ }
+ ptr = &path[9]; /* now points to the slash after the host */
+
+ /* there was a host name and slash present
+
+ RFC1738 (section 3.1, page 5) says:
+
+ The rest of the locator consists of data specific to the scheme,
+ and is known as the "url-path". It supplies the details of how the
+ specified resource can be accessed. Note that the "/" between the
+ host (or port) and the url-path is NOT part of the url-path.
+
+ As most agents use file://localhost/foo to get '/foo' although the
+ slash preceding foo is a separator and not a slash for the path,
+ a URL as file://localhost//foo must be valid as well, to refer to
+ the same file with an absolute path.
+ */
+
+ if('/' == ptr[1])
+ /* if there was two slashes, we skip the first one as that is then
+ used truly as a separator */
+ ptr++;
+
+ /* This cannot be made with strcpy, as the memory chunks overlap! */
+ memmove(path, ptr, strlen(ptr)+1);
+
+ path_has_drive = (('a' <= path[0] && path[0] <= 'z') ||
+ ('A' <= path[0] && path[0] <= 'Z')) && path[1] == ':';
+ }
+
+#if !defined(MSDOS) && !defined(WIN32) && !defined(__CYGWIN__)
+ if(path_has_drive) {
+ failf(data, "File drive letters are only accepted in MSDOS/Windows.");
+ return CURLE_URL_MALFORMAT;
+ }
+#endif
+
+ protop = "file"; /* protocol string */
+ *prot_missing = !url_has_scheme;
+ }
+ else {
+ /* clear path */
+ char slashbuf[4];
+ path[0]=0;
+
+ rc = sscanf(data->change.url,
+ "%15[^\n/:]:%3[/]%[^\n/?#]%[^\n]",
+ protobuf, slashbuf, conn->host.name, path);
+ if(2 == rc) {
+ failf(data, "Bad URL");
+ return CURLE_URL_MALFORMAT;
+ }
+ if(3 > rc) {
+
+ /*
+ * The URL was badly formatted, let's try the browser-style _without_
+ * protocol specified like 'http://'.
+ */
+ rc = sscanf(data->change.url, "%[^\n/?#]%[^\n]", conn->host.name, path);
+ if(1 > rc) {
+ /*
+ * We couldn't even get this format.
+ * djgpp 2.04 has a sscanf() bug where 'conn->host.name' is
+ * assigned, but the return value is EOF!
+ */
+#if defined(__DJGPP__) && (DJGPP_MINOR == 4)
+ if(!(rc == -1 && *conn->host.name))
+#endif
+ {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
+ /*
+ * Since there was no protocol part specified in the URL use the
+ * user-specified default protocol. If we weren't given a default make a
+ * guess by matching some protocols against the host's outermost
+ * sub-domain name. Finally if there was no match use HTTP.
+ */
+
+ protop = data->set.str[STRING_DEFAULT_PROTOCOL];
+ if(!protop) {
+ /* Note: if you add a new protocol, please update the list in
+ * lib/version.c too! */
+ if(checkprefix("FTP.", conn->host.name))
+ protop = "ftp";
+ else if(checkprefix("DICT.", conn->host.name))
+ protop = "DICT";
+ else if(checkprefix("LDAP.", conn->host.name))
+ protop = "LDAP";
+ else if(checkprefix("IMAP.", conn->host.name))
+ protop = "IMAP";
+ else if(checkprefix("SMTP.", conn->host.name))
+ protop = "smtp";
+ else if(checkprefix("POP3.", conn->host.name))
+ protop = "pop3";
+ else
+ protop = "http";
+ }
+
+ *prot_missing = TRUE; /* not given in URL */
+ }
+ else {
+ size_t s = strlen(slashbuf);
+ protop = protobuf;
+ if(s != 2) {
+ infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n",
+ s, s>1?"es":"");
+
+ if(data->change.url_alloc)
+ free(data->change.url);
+ /* repair the URL to use two slashes */
+ data->change.url = aprintf("%s://%s%s",
+ protobuf, conn->host.name, path);
+ if(!data->change.url)
+ return CURLE_OUT_OF_MEMORY;
+ data->change.url_alloc = TRUE;
+ }
+ }
+ }
+
+ /* We search for '?' in the host name (but only on the right side of a
+ * @-letter to allow ?-letters in username and password) to handle things
+ * like http://example.com?param= (notice the missing '/').
+ */
+ at = strchr(conn->host.name, '@');
+ if(at)
+ query = strchr(at+1, '?');
+ else
+ query = strchr(conn->host.name, '?');
+
+ if(query) {
+ /* We must insert a slash before the '?'-letter in the URL. If the URL had
+ a slash after the '?', that is where the path currently begins and the
+ '?string' is still part of the host name.
+
+ We must move the trailing part from the host name and put it first in
+ the path. And have it all prefixed with a slash.
+ */
+
+ size_t hostlen = strlen(query);
+ size_t pathlen = strlen(path);
+
+ /* move the existing path plus the zero byte forward, to make room for
+ the host-name part */
+ memmove(path+hostlen+1, path, pathlen+1);
+
+ /* now copy the trailing host part in front of the existing path */
+ memcpy(path+1, query, hostlen);
+
+ path[0]='/'; /* prepend the missing slash */
+ rebuild_url = TRUE;
+
+ *query=0; /* now cut off the hostname at the ? */
+ }
+ else if(!path[0]) {
+ /* if there's no path set, use a single slash */
+ strcpy(path, "/");
+ rebuild_url = TRUE;
+ }
+
+ /* If the URL is malformatted (missing a '/' after hostname before path) we
+ * insert a slash here. The only letters except '/' that can start a path is
+ * '?' and '#' - as controlled by the two sscanf() patterns above.
+ */
+ if(path[0] != '/') {
+ /* We need this function to deal with overlapping memory areas. We know
+ that the memory area 'path' points to is 'urllen' bytes big and that
+ is bigger than the path. Use +1 to move the zero byte too. */
+ memmove(&path[1], path, strlen(path)+1);
+ path[0] = '/';
+ rebuild_url = TRUE;
+ }
+ else if(!data->set.path_as_is) {
+ /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
+ char *newp = Curl_dedotdotify(path);
+ if(!newp)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(strcmp(newp, path)) {
+ rebuild_url = TRUE;
+ free(data->state.pathbuffer);
+ data->state.pathbuffer = newp;
+ data->state.path = newp;
+ path = newp;
+ }
+ else
+ free(newp);
+ }
+
+ /*
+ * "rebuild_url" means that one or more URL components have been modified so
+ * we need to generate an updated full version. We need the corrected URL
+ * when communicating over HTTP proxy and we don't know at this point if
+ * we're using a proxy or not.
+ */
+ if(rebuild_url) {
+ char *reurl;
+
+ size_t plen = strlen(path); /* new path, should be 1 byte longer than
+ the original */
+ size_t prefixlen = strlen(conn->host.name);
+
+ if(!*prot_missing) {
+ size_t protolen = strlen(protop);
+
+ if(curl_strnequal(protop, data->change.url, protolen))
+ prefixlen += protolen;
+ else {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ if(curl_strnequal("://", &data->change.url[protolen], 3))
+ prefixlen += 3;
+ /* only file: is allowed to omit one or both slashes */
+ else if(curl_strnequal("file:", data->change.url, 5))
+ prefixlen += 1 + (data->change.url[5] == '/');
+ else {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
+ reurl = malloc(prefixlen + plen + 1);
+ if(!reurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* copy the prefix */
+ memcpy(reurl, data->change.url, prefixlen);
+
+ /* append the trailing piece + zerobyte */
+ memcpy(&reurl[prefixlen], path, plen + 1);
+
+ /* possible free the old one */
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ infof(data, "Rebuilt URL to: %s\n", reurl);
+
+ data->change.url = reurl;
+ data->change.url_alloc = TRUE; /* free this later */
+ }
+
+ result = findprotocol(data, conn, protop);
+ if(result)
+ return result;
+
+ /*
+ * Parse the login details from the URL and strip them out of
+ * the host name
+ */
+ result = parse_url_login(data, conn, userp, passwdp, optionsp);
+ if(result)
+ return result;
+
+ if(conn->host.name[0] == '[') {
+ /* This looks like an IPv6 address literal. See if there is an address
+ scope if there is no location header */
+ char *percent = strchr(conn->host.name, '%');
+ if(percent) {
+ unsigned int identifier_offset = 3;
+ char *endp;
+ unsigned long scope;
+ if(strncmp("%25", percent, 3) != 0) {
+ infof(data,
+ "Please URL encode %% as %%25, see RFC 6874.\n");
+ identifier_offset = 1;
+ }
+ scope = strtoul(percent + identifier_offset, &endp, 10);
+ if(*endp == ']') {
+ /* The address scope was well formed. Knock it out of the
+ hostname. */
+ memmove(percent, endp, strlen(endp)+1);
+ conn->scope_id = (unsigned int)scope;
+ }
+ else {
+ /* Zone identifier is not numeric */
+#if defined(HAVE_NET_IF_H) && defined(IFNAMSIZ) && defined(HAVE_IF_NAMETOINDEX)
+ char ifname[IFNAMSIZ + 2];
+ char *square_bracket;
+ unsigned int scopeidx = 0;
+ strncpy(ifname, percent + identifier_offset, IFNAMSIZ + 2);
+ /* Ensure nullbyte termination */
+ ifname[IFNAMSIZ + 1] = '\0';
+ square_bracket = strchr(ifname, ']');
+ if(square_bracket) {
+ /* Remove ']' */
+ *square_bracket = '\0';
+ scopeidx = if_nametoindex(ifname);
+ if(scopeidx == 0) {
+ infof(data, "Invalid network interface: %s; %s\n", ifname,
+ strerror(errno));
+ }
+ }
+ if(scopeidx > 0) {
+ char *p = percent + identifier_offset + strlen(ifname);
+
+ /* Remove zone identifier from hostname */
+ memmove(percent, p, strlen(p) + 1);
+ conn->scope_id = scopeidx;
+ }
+ else
+#endif /* HAVE_NET_IF_H && IFNAMSIZ */
+ infof(data, "Invalid IPv6 address format\n");
+ }
+ }
+ }
+
+ if(data->set.scope_id)
+ /* Override any scope that was set above. */
+ conn->scope_id = data->set.scope_id;
+
+ /* Remove the fragment part of the path. Per RFC 2396, this is always the
+ last part of the URI. We are looking for the first '#' so that we deal
+ gracefully with non conformant URI such as http://example.com#foo#bar. */
+ fragment = strchr(path, '#');
+ if(fragment) {
+ *fragment = 0;
+
+ /* we know the path part ended with a fragment, so we know the full URL
+ string does too and we need to cut it off from there so it isn't used
+ over proxy */
+ fragment = strchr(data->change.url, '#');
+ if(fragment)
+ *fragment = 0;
+ }
+
+ /*
+ * So if the URL was A://B/C#D,
+ * protop is A
+ * conn->host.name is B
+ * data->state.path is /C
+ */
+ return CURLE_OK;
+}
+
+/*
+ * If we're doing a resumed transfer, we need to setup our stuff
+ * properly.
+ */
+static CURLcode setup_range(struct Curl_easy *data)
+{
+ struct UrlState *s = &data->state;
+ s->resume_from = data->set.set_resume_from;
+ if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
+ if(s->rangestringalloc)
+ free(s->range);
+
+ if(s->resume_from)
+ s->range = aprintf("%" CURL_FORMAT_CURL_OFF_TU "-", s->resume_from);
+ else
+ s->range = strdup(data->set.str[STRING_SET_RANGE]);
+
+ s->rangestringalloc = (s->range) ? TRUE : FALSE;
+
+ if(!s->range)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* tell ourselves to fetch this range */
+ s->use_range = TRUE; /* enable range download */
+ }
+ else
+ s->use_range = FALSE; /* disable range download */
+
+ return CURLE_OK;
+}
+
+
+/*
+ * setup_connection_internals() -
+ *
+ * Setup connection internals specific to the requested protocol in the
+ * Curl_easy. This is inited and setup before the connection is made but
+ * is about the particular protocol that is to be used.
+ *
+ * This MUST get called after proxy magic has been figured out.
+ */
+static CURLcode setup_connection_internals(struct connectdata *conn)
+{
+ const struct Curl_handler * p;
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+
+ /* in some case in the multi state-machine, we go back to the CONNECT state
+ and then a second (or third or...) call to this function will be made
+ without doing a DISCONNECT or DONE in between (since the connection is
+ yet in place) and therefore this function needs to first make sure
+ there's no lingering previous data allocated. */
+ Curl_free_request_state(data);
+
+ memset(&data->req, 0, sizeof(struct SingleRequest));
+ data->req.maxdownload = -1;
+
+ conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
+
+ /* Perform setup complement if some. */
+ p = conn->handler;
+
+ if(p->setup_connection) {
+ result = (*p->setup_connection)(conn);
+
+ if(result)
+ return result;
+
+ p = conn->handler; /* May have changed. */
+ }
+
+ if(conn->port < 0)
+ /* we check for -1 here since if proxy was detected already, this
+ was very likely already set to the proxy port */
+ conn->port = p->defport;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_free_request_state() should free temp data that was allocated in the
+ * Curl_easy for this single request.
+ */
+
+void Curl_free_request_state(struct Curl_easy *data)
+{
+ Curl_safefree(data->req.protop);
+ Curl_safefree(data->req.newurl);
+}
+
+
+#ifndef CURL_DISABLE_PROXY
+/****************************************************************
+* Checks if the host is in the noproxy list. returns true if it matches
+* and therefore the proxy should NOT be used.
+****************************************************************/
+static bool check_noproxy(const char *name, const char *no_proxy)
+{
+ /* no_proxy=domain1.dom,host.domain2.dom
+ * (a comma-separated list of hosts which should
+ * not be proxied, or an asterisk to override
+ * all proxy variables)
+ */
+ size_t tok_start;
+ size_t tok_end;
+ const char *separator = ", ";
+ size_t no_proxy_len;
+ size_t namelen;
+ char *endptr;
+
+ if(no_proxy && no_proxy[0]) {
+ if(strcasecompare("*", no_proxy)) {
+ return TRUE;
+ }
+
+ /* NO_PROXY was specified and it wasn't just an asterisk */
+
+ no_proxy_len = strlen(no_proxy);
+ endptr = strchr(name, ':');
+ if(endptr)
+ namelen = endptr - name;
+ else
+ namelen = strlen(name);
+
+ for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
+ while(tok_start < no_proxy_len &&
+ strchr(separator, no_proxy[tok_start]) != NULL) {
+ /* Look for the beginning of the token. */
+ ++tok_start;
+ }
+
+ if(tok_start == no_proxy_len)
+ break; /* It was all trailing separator chars, no more tokens. */
+
+ for(tok_end = tok_start; tok_end < no_proxy_len &&
+ strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end)
+ /* Look for the end of the token. */
+ ;
+
+ /* To match previous behaviour, where it was necessary to specify
+ * ".local.com" to prevent matching "notlocal.com", we will leave
+ * the '.' off.
+ */
+ if(no_proxy[tok_start] == '.')
+ ++tok_start;
+
+ if((tok_end - tok_start) <= namelen) {
+ /* Match the last part of the name to the domain we are checking. */
+ const char *checkn = name + namelen - (tok_end - tok_start);
+ if(strncasecompare(no_proxy + tok_start, checkn,
+ tok_end - tok_start)) {
+ if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
+ /* We either have an exact match, or the previous character is a .
+ * so it is within the same domain, so no proxy for this host.
+ */
+ return TRUE;
+ }
+ }
+ } /* if((tok_end - tok_start) <= namelen) */
+ } /* for(tok_start = 0; tok_start < no_proxy_len;
+ tok_start = tok_end + 1) */
+ } /* NO_PROXY was specified and it wasn't just an asterisk */
+
+ return FALSE;
+}
+
+#ifndef CURL_DISABLE_HTTP
+/****************************************************************
+* Detect what (if any) proxy to use. Remember that this selects a host
+* name and is not limited to HTTP proxies only.
+* The returned pointer must be freed by the caller (unless NULL)
+****************************************************************/
+static char *detect_proxy(struct connectdata *conn)
+{
+ char *proxy = NULL;
+
+ /* If proxy was not specified, we check for default proxy environment
+ * variables, to enable i.e Lynx compliance:
+ *
+ * http_proxy=http://some.server.dom:port/
+ * https_proxy=http://some.server.dom:port/
+ * ftp_proxy=http://some.server.dom:port/
+ * no_proxy=domain1.dom,host.domain2.dom
+ * (a comma-separated list of hosts which should
+ * not be proxied, or an asterisk to override
+ * all proxy variables)
+ * all_proxy=http://some.server.dom:port/
+ * (seems to exist for the CERN www lib. Probably
+ * the first to check for.)
+ *
+ * For compatibility, the all-uppercase versions of these variables are
+ * checked if the lowercase versions don't exist.
+ */
+ char proxy_env[128];
+ const char *protop = conn->handler->scheme;
+ char *envp = proxy_env;
+ char *prox;
+
+ /* Now, build <protocol>_proxy and check for such a one to use */
+ while(*protop)
+ *envp++ = (char)tolower((int)*protop++);
+
+ /* append _proxy */
+ strcpy(envp, "_proxy");
+
+ /* read the protocol proxy: */
+ prox=curl_getenv(proxy_env);
+
+ /*
+ * We don't try the uppercase version of HTTP_PROXY because of
+ * security reasons:
+ *
+ * When curl is used in a webserver application
+ * environment (cgi or php), this environment variable can
+ * be controlled by the web server user by setting the
+ * http header 'Proxy:' to some value.
+ *
+ * This can cause 'internal' http/ftp requests to be
+ * arbitrarily redirected by any external attacker.
+ */
+ if(!prox && !strcasecompare("http_proxy", proxy_env)) {
+ /* There was no lowercase variable, try the uppercase version: */
+ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
+ prox=curl_getenv(proxy_env);
+ }
+
+ if(prox)
+ proxy = prox; /* use this */
+ else {
+ proxy = curl_getenv("all_proxy"); /* default proxy to use */
+ if(!proxy)
+ proxy=curl_getenv("ALL_PROXY");
+ }
+
+ return proxy;
+}
+#endif /* CURL_DISABLE_HTTP */
+
+/*
+ * If this is supposed to use a proxy, we need to figure out the proxy
+ * host name, so that we can re-use an existing connection
+ * that may exist registered to the same proxy host.
+ */
+static CURLcode parse_proxy(struct Curl_easy *data,
+ struct connectdata *conn, char *proxy,
+ curl_proxytype proxytype)
+{
+ char *prox_portno;
+ char *endofprot;
+
+ /* We use 'proxyptr' to point to the proxy name from now on... */
+ char *proxyptr;
+ char *portptr;
+ char *atsign;
+ long port = -1;
+ char *proxyuser = NULL;
+ char *proxypasswd = NULL;
+ bool sockstype;
+
+ /* We do the proxy host string parsing here. We want the host name and the
+ * port name. Accept a protocol:// prefix
+ */
+
+ /* Parse the protocol part if present */
+ endofprot = strstr(proxy, "://");
+ if(endofprot) {
+ proxyptr = endofprot+3;
+ if(checkprefix("https", proxy))
+ proxytype = CURLPROXY_HTTPS;
+ else if(checkprefix("socks5h", proxy))
+ proxytype = CURLPROXY_SOCKS5_HOSTNAME;
+ else if(checkprefix("socks5", proxy))
+ proxytype = CURLPROXY_SOCKS5;
+ else if(checkprefix("socks4a", proxy))
+ proxytype = CURLPROXY_SOCKS4A;
+ else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy))
+ proxytype = CURLPROXY_SOCKS4;
+ else if(checkprefix("http:", proxy))
+ ; /* leave it as HTTP or HTTP/1.0 */
+ else {
+ /* Any other xxx:// reject! */
+ failf(data, "Unsupported proxy scheme for \'%s\'", proxy);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+ else
+ proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
+
+#ifndef HTTPS_PROXY_SUPPORT
+ if(proxytype == CURLPROXY_HTTPS) {
+ failf(data, "Unsupported proxy \'%s\'"
+ ", libcurl is built without the HTTPS-proxy support.", proxy);
+ return CURLE_NOT_BUILT_IN;
+ }
+#endif
+
+ sockstype = proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+ proxytype == CURLPROXY_SOCKS5 ||
+ proxytype == CURLPROXY_SOCKS4A ||
+ proxytype == CURLPROXY_SOCKS4;
+
+ /* Is there a username and password given in this proxy url? */
+ atsign = strchr(proxyptr, '@');
+ if(atsign) {
+ CURLcode result =
+ parse_login_details(proxyptr, atsign - proxyptr,
+ &proxyuser, &proxypasswd, NULL);
+ if(result)
+ return result;
+ proxyptr = atsign + 1;
+ }
+
+ /* start scanning for port number at this point */
+ portptr = proxyptr;
+
+ /* detect and extract RFC6874-style IPv6-addresses */
+ if(*proxyptr == '[') {
+ char *ptr = ++proxyptr; /* advance beyond the initial bracket */
+ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+ ptr++;
+ if(*ptr == '%') {
+ /* There might be a zone identifier */
+ if(strncmp("%25", ptr, 3))
+ infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+ ptr++;
+ /* Allow unreserved characters as defined in RFC 3986 */
+ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+ (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+ ptr++;
+ }
+ if(*ptr == ']')
+ /* yeps, it ended nicely with a bracket as well */
+ *ptr++ = 0;
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ portptr = ptr;
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * proxyptr first, but I can't see anything wrong with that as no host
+ * name nor a numeric can legally start with a bracket.
+ */
+ }
+
+ /* Get port number off proxy.server.com:1080 */
+ prox_portno = strchr(portptr, ':');
+ if(prox_portno) {
+ char *endp = NULL;
+
+ *prox_portno = 0x0; /* cut off number from host name */
+ prox_portno ++;
+ /* now set the local port number */
+ port = strtol(prox_portno, &endp, 10);
+ if((endp && *endp && (*endp != '/') && (*endp != ' ')) ||
+ (port < 0) || (port > 65535)) {
+ /* meant to detect for example invalid IPv6 numerical addresses without
+ brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only
+ because we then allow "URL style" with the number followed by a
+ slash, used in curl test cases already. Space is also an acceptable
+ terminating symbol. */
+ infof(data, "No valid port number in proxy string (%s)\n",
+ prox_portno);
+ }
+ else
+ conn->port = port;
+ }
+ else {
+ if(proxyptr[0]=='/')
+ /* If the first character in the proxy string is a slash, fail
+ immediately. The following code will otherwise clear the string which
+ will lead to code running as if no proxy was set! */
+ return CURLE_COULDNT_RESOLVE_PROXY;
+
+ /* without a port number after the host name, some people seem to use
+ a slash so we strip everything from the first slash */
+ atsign = strchr(proxyptr, '/');
+ if(atsign)
+ *atsign = '\0'; /* cut off path part from host name */
+
+ if(data->set.proxyport)
+ /* None given in the proxy string, then get the default one if it is
+ given */
+ port = data->set.proxyport;
+ else {
+ if(proxytype == CURLPROXY_HTTPS)
+ port = CURL_DEFAULT_HTTPS_PROXY_PORT;
+ else
+ port = CURL_DEFAULT_PROXY_PORT;
+ }
+ }
+
+ if(*proxyptr) {
+ struct proxy_info *proxyinfo =
+ sockstype ? &conn->socks_proxy : &conn->http_proxy;
+ proxyinfo->proxytype = proxytype;
+
+ if(proxyuser) {
+ /* found user and password, rip them out. note that we are unescaping
+ them, as there is otherwise no way to have a username or password
+ with reserved characters like ':' in them. */
+ Curl_safefree(proxyinfo->user);
+ proxyinfo->user = curl_easy_unescape(data, proxyuser, 0, NULL);
+ Curl_safefree(proxyuser);
+
+ if(!proxyinfo->user) {
+ Curl_safefree(proxypasswd);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(proxyinfo->passwd);
+ if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
+ proxyinfo->passwd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+ else
+ proxyinfo->passwd = strdup("");
+ Curl_safefree(proxypasswd);
+
+ if(!proxyinfo->passwd)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->bits.proxy_user_passwd = TRUE; /* enable it */
+ }
+
+ if(port >= 0) {
+ proxyinfo->port = port;
+ if(conn->port < 0 || sockstype || !conn->socks_proxy.host.rawalloc)
+ conn->port = port;
+ }
+
+ /* now, clone the cleaned proxy host name */
+ Curl_safefree(proxyinfo->host.rawalloc);
+ proxyinfo->host.rawalloc = strdup(proxyptr);
+ proxyinfo->host.name = proxyinfo->host.rawalloc;
+
+ if(!proxyinfo->host.rawalloc)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(proxyuser);
+ Curl_safefree(proxypasswd);
+
+ return CURLE_OK;
+}
+
+/*
+ * Extract the user and password from the authentication string
+ */
+static CURLcode parse_proxy_auth(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ char proxyuser[MAX_CURL_USER_LENGTH]="";
+ char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
+ CURLcode result;
+
+ if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
+ strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
+ MAX_CURL_USER_LENGTH);
+ proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
+ }
+ if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
+ strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
+ MAX_CURL_PASSWORD_LENGTH);
+ proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
+ }
+
+ result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
+ FALSE);
+ if(!result)
+ result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd,
+ NULL, FALSE);
+ return result;
+}
+
+/* create_conn helper to parse and init proxy values. to be called after unix
+ socket init but before any proxy vars are evaluated. */
+static CURLcode create_conn_helper_init_proxy(struct connectdata *conn)
+{
+ char *proxy = NULL;
+ char *socksproxy = NULL;
+ char *no_proxy = NULL;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ /*************************************************************
+ * Extract the user and password from the authentication string
+ *************************************************************/
+ if(conn->bits.proxy_user_passwd) {
+ result = parse_proxy_auth(data, conn);
+ if(result)
+ goto out;
+ }
+
+ /*************************************************************
+ * Detect what (if any) proxy to use
+ *************************************************************/
+ if(data->set.str[STRING_PROXY]) {
+ proxy = strdup(data->set.str[STRING_PROXY]);
+ /* if global proxy is set, this is it */
+ if(NULL == proxy) {
+ failf(data, "memory shortage");
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ if(data->set.str[STRING_PRE_PROXY]) {
+ socksproxy = strdup(data->set.str[STRING_PRE_PROXY]);
+ /* if global socks proxy is set, this is it */
+ if(NULL == socksproxy) {
+ failf(data, "memory shortage");
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ no_proxy = curl_getenv("no_proxy");
+ if(!no_proxy)
+ no_proxy = curl_getenv("NO_PROXY");
+
+ if(check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY]) ||
+ (!data->set.str[STRING_NOPROXY] &&
+ check_noproxy(conn->host.name, no_proxy))) {
+ Curl_safefree(proxy);
+ Curl_safefree(socksproxy);
+ }
+ else if(!proxy && !socksproxy)
+#ifndef CURL_DISABLE_HTTP
+ /* if the host is not in the noproxy list, detect proxy. */
+ proxy = detect_proxy(conn);
+#else /* !CURL_DISABLE_HTTP */
+ proxy = NULL;
+#endif /* CURL_DISABLE_HTTP */
+
+ Curl_safefree(no_proxy);
+
+#ifdef USE_UNIX_SOCKETS
+ /* For the time being do not mix proxy and unix domain sockets. See #1274 */
+ if(proxy && conn->unix_domain_socket) {
+ free(proxy);
+ proxy = NULL;
+ }
+#endif
+
+ if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
+ free(proxy); /* Don't bother with an empty proxy string or if the
+ protocol doesn't work with network */
+ proxy = NULL;
+ }
+ if(socksproxy && (!*socksproxy ||
+ (conn->handler->flags & PROTOPT_NONETWORK))) {
+ free(socksproxy); /* Don't bother with an empty socks proxy string or if
+ the protocol doesn't work with network */
+ socksproxy = NULL;
+ }
+
+ /***********************************************************************
+ * If this is supposed to use a proxy, we need to figure out the proxy host
+ * name, proxy type and port number, so that we can re-use an existing
+ * connection that may exist registered to the same proxy host.
+ ***********************************************************************/
+ if(proxy || socksproxy) {
+ if(proxy) {
+ result = parse_proxy(data, conn, proxy, conn->http_proxy.proxytype);
+ Curl_safefree(proxy); /* parse_proxy copies the proxy string */
+ if(result)
+ goto out;
+ }
+
+ if(socksproxy) {
+ result = parse_proxy(data, conn, socksproxy,
+ conn->socks_proxy.proxytype);
+ /* parse_proxy copies the socks proxy string */
+ Curl_safefree(socksproxy);
+ if(result)
+ goto out;
+ }
+
+ if(conn->http_proxy.host.rawalloc) {
+#ifdef CURL_DISABLE_HTTP
+ /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
+ result = CURLE_UNSUPPORTED_PROTOCOL;
+ goto out;
+#else
+ /* force this connection's protocol to become HTTP if not already
+ compatible - if it isn't tunneling through */
+ if(!(conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+ !conn->bits.tunnel_proxy)
+ conn->handler = &Curl_handler_http;
+
+ conn->bits.httpproxy = TRUE;
+#endif
+ }
+ else {
+ conn->bits.httpproxy = FALSE; /* not a HTTP proxy */
+ conn->bits.tunnel_proxy = FALSE; /* no tunneling if not HTTP */
+ }
+
+ if(conn->socks_proxy.host.rawalloc) {
+ if(!conn->http_proxy.host.rawalloc) {
+ /* once a socks proxy */
+ if(!conn->socks_proxy.user) {
+ conn->socks_proxy.user = conn->http_proxy.user;
+ conn->http_proxy.user = NULL;
+ Curl_safefree(conn->socks_proxy.passwd);
+ conn->socks_proxy.passwd = conn->http_proxy.passwd;
+ conn->http_proxy.passwd = NULL;
+ }
+ }
+ conn->bits.socksproxy = TRUE;
+ }
+ else
+ conn->bits.socksproxy = FALSE; /* not a socks proxy */
+ }
+ else {
+ conn->bits.socksproxy = FALSE;
+ conn->bits.httpproxy = FALSE;
+ }
+ conn->bits.proxy = conn->bits.httpproxy || conn->bits.socksproxy;
+
+ if(!conn->bits.proxy) {
+ /* we aren't using the proxy after all... */
+ conn->bits.proxy = FALSE;
+ conn->bits.httpproxy = FALSE;
+ conn->bits.socksproxy = FALSE;
+ conn->bits.proxy_user_passwd = FALSE;
+ conn->bits.tunnel_proxy = FALSE;
+ }
+
+out:
+
+ free(socksproxy);
+ free(proxy);
+ return result;
+}
+#endif /* CURL_DISABLE_PROXY */
+
+/*
+ * parse_url_login()
+ *
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
+ *
+ * Inputs: data->set.use_netrc (CURLOPT_NETRC)
+ * conn->host.name
+ *
+ * Outputs: (almost :- all currently undefined)
+ * conn->bits.user_passwd - non-zero if non-default passwords exist
+ * user - non-zero length if defined
+ * passwd - non-zero length if defined
+ * options - non-zero length if defined
+ * conn->host.name - remove user name and password
+ */
+static CURLcode parse_url_login(struct Curl_easy *data,
+ struct connectdata *conn,
+ char **user, char **passwd, char **options)
+{
+ CURLcode result = CURLE_OK;
+ char *userp = NULL;
+ char *passwdp = NULL;
+ char *optionsp = NULL;
+
+ /* At this point, we're hoping all the other special cases have
+ * been taken care of, so conn->host.name is at most
+ * [user[:password][;options]]@]hostname
+ *
+ * We need somewhere to put the embedded details, so do that first.
+ */
+
+ char *ptr = strchr(conn->host.name, '@');
+ char *login = conn->host.name;
+
+ DEBUGASSERT(!**user);
+ DEBUGASSERT(!**passwd);
+ DEBUGASSERT(!**options);
+ DEBUGASSERT(conn->handler);
+
+ if(!ptr)
+ goto out;
+
+ /* We will now try to extract the
+ * possible login information in a string like:
+ * ftp://user:password@ftp.my.site:8021/README */
+ conn->host.name = ++ptr;
+
+ /* So the hostname is sane. Only bother interpreting the
+ * results if we could care. It could still be wasted
+ * work because it might be overtaken by the programmatically
+ * set user/passwd, but doing that first adds more cases here :-(
+ */
+
+ if(data->set.use_netrc == CURL_NETRC_REQUIRED)
+ goto out;
+
+ /* We could use the login information in the URL so extract it. Only parse
+ options if the handler says we should. */
+ result = parse_login_details(login, ptr - login - 1,
+ &userp, &passwdp,
+ (conn->handler->flags & PROTOPT_URLOPTIONS)?
+ &optionsp:NULL);
+ if(result)
+ goto out;
+
+ if(userp) {
+ char *newname;
+
+ /* We have a user in the URL */
+ conn->bits.userpwd_in_url = TRUE;
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+
+ /* Decode the user */
+ result = Curl_urldecode(data, userp, 0, &newname, NULL, FALSE);
+ if(result) {
+ goto out;
+ }
+
+ free(*user);
+ *user = newname;
+ }
+
+ if(passwdp) {
+ /* We have a password in the URL so decode it */
+ char *newpasswd;
+ result = Curl_urldecode(data, passwdp, 0, &newpasswd, NULL, FALSE);
+ if(result) {
+ goto out;
+ }
+
+ free(*passwd);
+ *passwd = newpasswd;
+ }
+
+ if(optionsp) {
+ /* We have an options list in the URL so decode it */
+ char *newoptions;
+ result = Curl_urldecode(data, optionsp, 0, &newoptions, NULL, FALSE);
+ if(result) {
+ goto out;
+ }
+
+ free(*options);
+ *options = newoptions;
+ }
+
+
+ out:
+
+ free(userp);
+ free(passwdp);
+ free(optionsp);
+
+ return result;
+}
+
+/*
+ * parse_login_details()
+ *
+ * This is used to parse a login string for user name, password and options in
+ * the following formats:
+ *
+ * user
+ * user:password
+ * user:password;options
+ * user;options
+ * user;options:password
+ * :password
+ * :password;options
+ * ;options
+ * ;options:password
+ *
+ * Parameters:
+ *
+ * login [in] - The login string.
+ * len [in] - The length of the login string.
+ * userp [in/out] - The address where a pointer to newly allocated memory
+ * holding the user will be stored upon completion.
+ * passdwp [in/out] - The address where a pointer to newly allocated memory
+ * holding the password will be stored upon completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ * holding the options will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode parse_login_details(const char *login, const size_t len,
+ char **userp, char **passwdp,
+ char **optionsp)
+{
+ CURLcode result = CURLE_OK;
+ char *ubuf = NULL;
+ char *pbuf = NULL;
+ char *obuf = NULL;
+ const char *psep = NULL;
+ const char *osep = NULL;
+ size_t ulen;
+ size_t plen;
+ size_t olen;
+
+ /* Attempt to find the password separator */
+ if(passwdp) {
+ psep = strchr(login, ':');
+
+ /* Within the constraint of the login string */
+ if(psep >= login + len)
+ psep = NULL;
+ }
+
+ /* Attempt to find the options separator */
+ if(optionsp) {
+ osep = strchr(login, ';');
+
+ /* Within the constraint of the login string */
+ if(osep >= login + len)
+ osep = NULL;
+ }
+
+ /* Calculate the portion lengths */
+ ulen = (psep ?
+ (size_t)(osep && psep > osep ? osep - login : psep - login) :
+ (osep ? (size_t)(osep - login) : len));
+ plen = (psep ?
+ (osep && osep > psep ? (size_t)(osep - psep) :
+ (size_t)(login + len - psep)) - 1 : 0);
+ olen = (osep ?
+ (psep && psep > osep ? (size_t)(psep - osep) :
+ (size_t)(login + len - osep)) - 1 : 0);
+
+ /* Allocate the user portion buffer */
+ if(userp && ulen) {
+ ubuf = malloc(ulen + 1);
+ if(!ubuf)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allocate the password portion buffer */
+ if(!result && passwdp && plen) {
+ pbuf = malloc(plen + 1);
+ if(!pbuf) {
+ free(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Allocate the options portion buffer */
+ if(!result && optionsp && olen) {
+ obuf = malloc(olen + 1);
+ if(!obuf) {
+ free(pbuf);
+ free(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ if(!result) {
+ /* Store the user portion if necessary */
+ if(ubuf) {
+ memcpy(ubuf, login, ulen);
+ ubuf[ulen] = '\0';
+ Curl_safefree(*userp);
+ *userp = ubuf;
+ }
+
+ /* Store the password portion if necessary */
+ if(pbuf) {
+ memcpy(pbuf, psep + 1, plen);
+ pbuf[plen] = '\0';
+ Curl_safefree(*passwdp);
+ *passwdp = pbuf;
+ }
+
+ /* Store the options portion if necessary */
+ if(obuf) {
+ memcpy(obuf, osep + 1, olen);
+ obuf[olen] = '\0';
+ Curl_safefree(*optionsp);
+ *optionsp = obuf;
+ }
+ }
+
+ return result;
+}
+
+/*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *
+ * No matter if we use a proxy or not, we have to figure out the remote
+ * port number of various reasons.
+ *
+ * To be able to detect port number flawlessly, we must not confuse them
+ * IPv6-specified addresses in the [0::1] style. (RFC2732)
+ *
+ * The conn->host.name is currently [user:passwd@]host[:port] where host
+ * could be a hostname, IPv4 address or IPv6 address.
+ *
+ * The port number embedded in the URL is replaced, if necessary.
+ *************************************************************/
+static CURLcode parse_remote_port(struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ char *portptr;
+ char endbracket;
+
+ /* Note that at this point, the IPv6 address cannot contain any scope
+ suffix as that has already been removed in the parseurlandfillconn()
+ function */
+ if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
+ &endbracket)) &&
+ (']' == endbracket)) {
+ /* this is a RFC2732-style specified IP-address */
+ conn->bits.ipv6_ip = TRUE;
+
+ conn->host.name++; /* skip over the starting bracket */
+ portptr = strchr(conn->host.name, ']');
+ if(portptr) {
+ *portptr++ = '\0'; /* zero terminate, killing the bracket */
+ if(':' != *portptr)
+ portptr = NULL; /* no port number available */
+ }
+ }
+ else {
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) {
+ /* This is a numerical IPv6 address, meaning this is a wrongly formatted
+ URL */
+ failf(data, "IPv6 numerical address used in URL without brackets");
+ return CURLE_URL_MALFORMAT;
+ }
+#endif
+
+ portptr = strchr(conn->host.name, ':');
+ }
+
+ if(data->set.use_port && data->state.allow_port) {
+ /* if set, we use this and ignore the port possibly given in the URL */
+ conn->remote_port = (unsigned short)data->set.use_port;
+ if(portptr)
+ *portptr = '\0'; /* cut off the name there anyway - if there was a port
+ number - since the port number is to be ignored! */
+ if(conn->bits.httpproxy) {
+ /* we need to create new URL with the new port number */
+ char *url;
+ char type[12]="";
+
+ if(conn->bits.type_set)
+ snprintf(type, sizeof(type), ";type=%c",
+ data->set.prefer_ascii?'A':
+ (data->set.ftp_list_only?'D':'I'));
+
+ /*
+ * This synthesized URL isn't always right--suffixes like ;type=A are
+ * stripped off. It would be better to work directly from the original
+ * URL and simply replace the port part of it.
+ */
+ url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme,
+ conn->bits.ipv6_ip?"[":"", conn->host.name,
+ conn->bits.ipv6_ip?"]":"", conn->remote_port,
+ data->state.slash_removed?"/":"", data->state.path,
+ type);
+ if(!url)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = url;
+ data->change.url_alloc = TRUE;
+ }
+ }
+ else if(portptr) {
+ /* no CURLOPT_PORT given, extract the one from the URL */
+
+ char *rest;
+ long port;
+
+ port=strtol(portptr+1, &rest, 10); /* Port number must be decimal */
+
+ if((port < 0) || (port > 0xffff)) {
+ /* Single unix standard says port numbers are 16 bits long */
+ failf(data, "Port number out of range");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ if(rest[0]) {
+ failf(data, "Port number ended with '%c'", rest[0]);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ if(rest != &portptr[1]) {
+ *portptr = '\0'; /* cut off the name there */
+ conn->remote_port = curlx_ultous(port);
+ }
+ else {
+ /* Browser behavior adaptation. If there's a colon with no digits after,
+ just cut off the name there which makes us ignore the colon and just
+ use the default port. Firefox and Chrome both do that. */
+ *portptr = '\0';
+ }
+ }
+
+ /* only if remote_port was not already parsed off the URL we use the
+ default port number */
+ if(conn->remote_port < 0)
+ conn->remote_port = (unsigned short)conn->given->defport;
+
+ return CURLE_OK;
+}
+
+/*
+ * Override the login details from the URL with that in the CURLOPT_USERPWD
+ * option or a .netrc file, if applicable.
+ */
+static CURLcode override_login(struct Curl_easy *data,
+ struct connectdata *conn,
+ char **userp, char **passwdp, char **optionsp)
+{
+ if(data->set.str[STRING_USERNAME]) {
+ free(*userp);
+ *userp = strdup(data->set.str[STRING_USERNAME]);
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->set.str[STRING_PASSWORD]) {
+ free(*passwdp);
+ *passwdp = strdup(data->set.str[STRING_PASSWORD]);
+ if(!*passwdp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->set.str[STRING_OPTIONS]) {
+ free(*optionsp);
+ *optionsp = strdup(data->set.str[STRING_OPTIONS]);
+ if(!*optionsp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ conn->bits.netrc = FALSE;
+ if(data->set.use_netrc != CURL_NETRC_IGNORED) {
+ int ret = Curl_parsenetrc(conn->host.name,
+ userp, passwdp,
+ data->set.str[STRING_NETRC_FILE]);
+ if(ret > 0) {
+ infof(data, "Couldn't find host %s in the "
+ DOT_CHAR "netrc file; using defaults\n",
+ conn->host.name);
+ }
+ else if(ret < 0) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ /* set bits.netrc TRUE to remember that we got the name from a .netrc
+ file, so that it is safe to use even if we followed a Location: to a
+ different host or similar. */
+ conn->bits.netrc = TRUE;
+
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+ }
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Set the login details so they're available in the connection
+ */
+static CURLcode set_login(struct connectdata *conn,
+ const char *user, const char *passwd,
+ const char *options)
+{
+ CURLcode result = CURLE_OK;
+
+ /* If our protocol needs a password and we have none, use the defaults */
+ if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
+ /* Store the default user */
+ conn->user = strdup(CURL_DEFAULT_USER);
+
+ /* Store the default password */
+ if(conn->user)
+ conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
+ else
+ conn->passwd = NULL;
+
+ /* This is the default password, so DON'T set conn->bits.user_passwd */
+ }
+ else {
+ /* Store the user, zero-length if not set */
+ conn->user = strdup(user);
+
+ /* Store the password (only if user is present), zero-length if not set */
+ if(conn->user)
+ conn->passwd = strdup(passwd);
+ else
+ conn->passwd = NULL;
+ }
+
+ if(!conn->user || !conn->passwd)
+ result = CURLE_OUT_OF_MEMORY;
+
+ /* Store the options, null if not set */
+ if(!result && options[0]) {
+ conn->options = strdup(options);
+
+ if(!conn->options)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+/*
+ * Parses a "host:port" string to connect to.
+ * The hostname and the port may be empty; in this case, NULL is returned for
+ * the hostname and -1 for the port.
+ */
+static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
+ const char *host,
+ char **hostname_result,
+ int *port_result)
+{
+ char *host_dup;
+ char *hostptr;
+ char *host_portno;
+ char *portptr;
+ int port = -1;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
+
+ *hostname_result = NULL;
+ *port_result = -1;
+
+ if(!host || !*host)
+ return CURLE_OK;
+
+ host_dup = strdup(host);
+ if(!host_dup)
+ return CURLE_OUT_OF_MEMORY;
+
+ hostptr = host_dup;
+
+ /* start scanning for port number at this point */
+ portptr = hostptr;
+
+ /* detect and extract RFC6874-style IPv6-addresses */
+ if(*hostptr == '[') {
+ char *ptr = ++hostptr; /* advance beyond the initial bracket */
+ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+ ptr++;
+ if(*ptr == '%') {
+ /* There might be a zone identifier */
+ if(strncmp("%25", ptr, 3))
+ infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+ ptr++;
+ /* Allow unreserved characters as defined in RFC 3986 */
+ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+ (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+ ptr++;
+ }
+ if(*ptr == ']')
+ /* yeps, it ended nicely with a bracket as well */
+ *ptr++ = '\0';
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ portptr = ptr;
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * hostptr first, but I can't see anything wrong with that as no host
+ * name nor a numeric can legally start with a bracket.
+ */
+ }
+
+ /* Get port number off server.com:1080 */
+ host_portno = strchr(portptr, ':');
+ if(host_portno) {
+ char *endp = NULL;
+ *host_portno = '\0'; /* cut off number from host name */
+ host_portno++;
+ if(*host_portno) {
+ long portparse = strtol(host_portno, &endp, 10);
+ if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+ infof(data, "No valid port number in connect to host string (%s)\n",
+ host_portno);
+ hostptr = NULL;
+ port = -1;
+ }
+ else
+ port = (int)portparse; /* we know it will fit */
+ }
+ }
+
+ /* now, clone the cleaned host name */
+ if(hostptr) {
+ *hostname_result = strdup(hostptr);
+ if(!*hostname_result) {
+ free(host_dup);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ *port_result = port;
+
+ free(host_dup);
+ return CURLE_OK;
+}
+
+/*
+ * Parses one "connect to" string in the form:
+ * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
+ */
+static CURLcode parse_connect_to_string(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *conn_to_host,
+ char **host_result,
+ int *port_result)
+{
+ CURLcode result = CURLE_OK;
+ const char *ptr = conn_to_host;
+ int host_match = FALSE;
+ int port_match = FALSE;
+
+ *host_result = NULL;
+ *port_result = -1;
+
+ if(*ptr == ':') {
+ /* an empty hostname always matches */
+ host_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's hostname matches */
+ size_t hostname_to_match_len;
+ char *hostname_to_match = aprintf("%s%s%s",
+ conn->bits.ipv6_ip ? "[" : "",
+ conn->host.name,
+ conn->bits.ipv6_ip ? "]" : "");
+ if(!hostname_to_match)
+ return CURLE_OUT_OF_MEMORY;
+ hostname_to_match_len = strlen(hostname_to_match);
+ host_match = strncasecompare(ptr, hostname_to_match,
+ hostname_to_match_len);
+ free(hostname_to_match);
+ ptr += hostname_to_match_len;
+
+ host_match = host_match && *ptr == ':';
+ ptr++;
+ }
+
+ if(host_match) {
+ if(*ptr == ':') {
+ /* an empty port always matches */
+ port_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's port matches */
+ char *ptr_next = strchr(ptr, ':');
+ if(ptr_next) {
+ char *endp = NULL;
+ long port_to_match = strtol(ptr, &endp, 10);
+ if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+ port_match = TRUE;
+ ptr = ptr_next + 1;
+ }
+ }
+ }
+ }
+
+ if(host_match && port_match) {
+ /* parse the hostname and port to connect to */
+ result = parse_connect_to_host_port(data, ptr, host_result, port_result);
+ }
+
+ return result;
+}
+
+/*
+ * Processes all strings in the "connect to" slist, and uses the "connect
+ * to host" and "connect to port" of the first string that matches.
+ */
+static CURLcode parse_connect_to_slist(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct curl_slist *conn_to_host)
+{
+ CURLcode result = CURLE_OK;
+ char *host = NULL;
+ int port = -1;
+
+ while(conn_to_host && !host && port == -1) {
+ result = parse_connect_to_string(data, conn, conn_to_host->data,
+ &host, &port);
+ if(result)
+ return result;
+
+ if(host && *host) {
+ conn->conn_to_host.rawalloc = host;
+ conn->conn_to_host.name = host;
+ conn->bits.conn_to_host = TRUE;
+
+ infof(data, "Connecting to hostname: %s\n", host);
+ }
+ else {
+ /* no "connect to host" */
+ conn->bits.conn_to_host = FALSE;
+ Curl_safefree(host);
+ }
+
+ if(port >= 0) {
+ conn->conn_to_port = port;
+ conn->bits.conn_to_port = TRUE;
+ infof(data, "Connecting to port: %d\n", port);
+ }
+ else {
+ /* no "connect to port" */
+ conn->bits.conn_to_port = FALSE;
+ port = -1;
+ }
+
+ conn_to_host = conn_to_host->next;
+ }
+
+ return result;
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct Curl_easy *data,
+ struct connectdata *conn,
+ bool *async)
+{
+ CURLcode result=CURLE_OK;
+ time_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ /*************************************************************
+ * Resolve the name of the server or proxy
+ *************************************************************/
+ if(conn->bits.reuse)
+ /* We're reusing the connection - no need to resolve anything, and
+ fix_hostname() was called already in create_conn() for the re-use
+ case. */
+ *async = FALSE;
+
+ else {
+ /* this is a fresh connect */
+ int rc;
+ struct Curl_dns_entry *hostaddr;
+
+#ifdef USE_UNIX_SOCKETS
+ if(conn->unix_domain_socket) {
+ /* Unix domain sockets are local. The host gets ignored, just use the
+ * specified domain socket address. Do not cache "DNS entries". There is
+ * no DNS involved and we already have the filesystem path available */
+ const char *path = conn->unix_domain_socket;
+
+ hostaddr = calloc(1, sizeof(struct Curl_dns_entry));
+ if(!hostaddr)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ bool longpath = FALSE;
+ hostaddr->addr = Curl_unix2addr(path, &longpath,
+ conn->abstract_unix_socket);
+ if(hostaddr->addr)
+ hostaddr->inuse++;
+ else {
+ /* Long paths are not supported for now */
+ if(longpath) {
+ failf(data, "Unix socket path too long: '%s'", path);
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ }
+ else
+ result = CURLE_OUT_OF_MEMORY;
+ free(hostaddr);
+ hostaddr = NULL;
+ }
+ }
+ }
+ else
+#endif
+ if(!conn->bits.proxy) {
+ struct hostname *connhost;
+ if(conn->bits.conn_to_host)
+ connhost = &conn->conn_to_host;
+ else
+ connhost = &conn->host;
+
+ /* If not connecting via a proxy, extract the port from the URL, if it is
+ * there, thus overriding any defaults that might have been set above. */
+ if(conn->bits.conn_to_port)
+ conn->port = conn->conn_to_port;
+ else
+ conn->port = conn->remote_port;
+
+ /* Resolve target host right on */
+ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
+ &hostaddr, timeout_ms);
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(rc == CURLRESOLV_TIMEDOUT)
+ result = CURLE_OPERATION_TIMEDOUT;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve host '%s'", connhost->dispname);
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ /* don't return yet, we need to clean up the timeout first */
+ }
+ }
+ else {
+ /* This is a proxy that hasn't been resolved yet. */
+
+ struct hostname * const host = conn->bits.socksproxy ?
+ &conn->socks_proxy.host : &conn->http_proxy.host;
+
+ /* resolve proxy */
+ rc = Curl_resolv_timeout(conn, host->name, (int)conn->port,
+ &hostaddr, timeout_ms);
+
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(rc == CURLRESOLV_TIMEDOUT)
+ result = CURLE_OPERATION_TIMEDOUT;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve proxy '%s'", host->dispname);
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ /* don't return yet, we need to clean up the timeout first */
+ }
+ }
+ DEBUGASSERT(conn->dns_entry == NULL);
+ conn->dns_entry = hostaddr;
+ }
+
+ return result;
+}
+
+/*
+ * Cleanup the connection just allocated before we can move along and use the
+ * previously existing one. All relevant data is copied over and old_conn is
+ * ready for freeing once this function returns.
+ */
+static void reuse_conn(struct connectdata *old_conn,
+ struct connectdata *conn)
+{
+ free_fixed_hostname(&old_conn->http_proxy.host);
+ free_fixed_hostname(&old_conn->socks_proxy.host);
+
+ free(old_conn->http_proxy.host.rawalloc);
+ free(old_conn->socks_proxy.host.rawalloc);
+
+ /* free the SSL config struct from this connection struct as this was
+ allocated in vain and is targeted for destruction */
+ Curl_free_primary_ssl_config(&old_conn->ssl_config);
+ Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config);
+
+ conn->data = old_conn->data;
+
+ /* get the user+password information from the old_conn struct since it may
+ * be new for this request even when we re-use an existing connection */
+ conn->bits.user_passwd = old_conn->bits.user_passwd;
+ if(conn->bits.user_passwd) {
+ /* use the new user name and password though */
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ conn->user = old_conn->user;
+ conn->passwd = old_conn->passwd;
+ old_conn->user = NULL;
+ old_conn->passwd = NULL;
+ }
+
+ conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
+ if(conn->bits.proxy_user_passwd) {
+ /* use the new proxy user name and proxy password though */
+ Curl_safefree(conn->http_proxy.user);
+ Curl_safefree(conn->socks_proxy.user);
+ Curl_safefree(conn->http_proxy.passwd);
+ Curl_safefree(conn->socks_proxy.passwd);
+ conn->http_proxy.user = old_conn->http_proxy.user;
+ conn->socks_proxy.user = old_conn->socks_proxy.user;
+ conn->http_proxy.passwd = old_conn->http_proxy.passwd;
+ conn->socks_proxy.passwd = old_conn->socks_proxy.passwd;
+ old_conn->http_proxy.user = NULL;
+ old_conn->socks_proxy.user = NULL;
+ old_conn->http_proxy.passwd = NULL;
+ old_conn->socks_proxy.passwd = NULL;
+ }
+
+ /* host can change, when doing keepalive with a proxy or if the case is
+ different this time etc */
+ free_fixed_hostname(&conn->host);
+ free_fixed_hostname(&conn->conn_to_host);
+ Curl_safefree(conn->host.rawalloc);
+ Curl_safefree(conn->conn_to_host.rawalloc);
+ conn->host=old_conn->host;
+ conn->bits.conn_to_host = old_conn->bits.conn_to_host;
+ conn->conn_to_host = old_conn->conn_to_host;
+ conn->bits.conn_to_port = old_conn->bits.conn_to_port;
+ conn->conn_to_port = old_conn->conn_to_port;
+
+ /* persist connection info in session handle */
+ Curl_persistconninfo(conn);
+
+ conn_reset_all_postponed_data(old_conn); /* free buffers */
+
+ /* re-use init */
+ conn->bits.reuse = TRUE; /* yes, we're re-using here */
+
+ Curl_safefree(old_conn->user);
+ Curl_safefree(old_conn->passwd);
+ Curl_safefree(old_conn->http_proxy.user);
+ Curl_safefree(old_conn->socks_proxy.user);
+ Curl_safefree(old_conn->http_proxy.passwd);
+ Curl_safefree(old_conn->socks_proxy.passwd);
+ Curl_safefree(old_conn->localdev);
+
+ Curl_llist_destroy(&old_conn->send_pipe, NULL);
+ Curl_llist_destroy(&old_conn->recv_pipe, NULL);
+
+ Curl_safefree(old_conn->master_buffer);
+
+#ifdef USE_UNIX_SOCKETS
+ Curl_safefree(old_conn->unix_domain_socket);
+#endif
+}
+
+/**
+ * create_conn() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param async is set TRUE when an async DNS resolution is pending
+ * @see Curl_setup_conn()
+ *
+ * *NOTE* this function assigns the conn->data pointer!
+ */
+
+static CURLcode create_conn(struct Curl_easy *data,
+ struct connectdata **in_connect,
+ bool *async)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn;
+ struct connectdata *conn_temp = NULL;
+ size_t urllen;
+ char *user = NULL;
+ char *passwd = NULL;
+ char *options = NULL;
+ bool reuse;
+ bool prot_missing = FALSE;
+ bool connections_available = TRUE;
+ bool force_reuse = FALSE;
+ bool waitpipe = FALSE;
+ size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
+ size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
+
+ *async = FALSE;
+
+ /*************************************************************
+ * Check input data
+ *************************************************************/
+
+ if(!data->change.url) {
+ result = CURLE_URL_MALFORMAT;
+ goto out;
+ }
+
+ /* First, split up the current URL in parts so that we can use the
+ parts for checking against the already present connections. In order
+ to not have to modify everything at once, we allocate a temporary
+ connection data struct and fill in for comparison purposes. */
+ conn = allocate_conn(data);
+
+ if(!conn) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /* We must set the return variable as soon as possible, so that our
+ parent can cleanup any possible allocs we may have done before
+ any failure */
+ *in_connect = conn;
+
+ /* This initing continues below, see the comment "Continue connectdata
+ * initialization here" */
+
+ /***********************************************************
+ * We need to allocate memory to store the path in. We get the size of the
+ * full URL to be sure, and we need to make it at least 256 bytes since
+ * other parts of the code will rely on this fact
+ ***********************************************************/
+#define LEAST_PATH_ALLOC 256
+ urllen=strlen(data->change.url);
+ if(urllen < LEAST_PATH_ALLOC)
+ urllen=LEAST_PATH_ALLOC;
+
+ /*
+ * We malloc() the buffers below urllen+2 to make room for 2 possibilities:
+ * 1 - an extra terminating zero
+ * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
+ */
+
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+
+ data->state.pathbuffer = malloc(urllen+2);
+ if(NULL == data->state.pathbuffer) {
+ result = CURLE_OUT_OF_MEMORY; /* really bad error */
+ goto out;
+ }
+ data->state.path = data->state.pathbuffer;
+
+ conn->host.rawalloc = malloc(urllen+2);
+ if(NULL == conn->host.rawalloc) {
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ conn->host.name = conn->host.rawalloc;
+ conn->host.name[0] = 0;
+
+ user = strdup("");
+ passwd = strdup("");
+ options = strdup("");
+ if(!user || !passwd || !options) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
+ &options);
+ if(result)
+ goto out;
+
+ /*************************************************************
+ * No protocol part in URL was used, add it!
+ *************************************************************/
+ if(prot_missing) {
+ /* We're guessing prefixes here and if we're told to use a proxy or if
+ we're gonna follow a Location: later or... then we need the protocol
+ part added so that we have a valid URL. */
+ char *reurl;
+ char *ch_lower;
+
+ reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
+
+ if(!reurl) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /* Change protocol prefix to lower-case */
+ for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
+ *ch_lower = (char)TOLOWER(*ch_lower);
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = reurl;
+ data->change.url_alloc = TRUE; /* free this later */
+ }
+
+ /*************************************************************
+ * If the protocol can't handle url query strings, then cut
+ * off the unhandable part
+ *************************************************************/
+ if((conn->given->flags&PROTOPT_NOURLQUERY)) {
+ char *path_q_sep = strchr(conn->data->state.path, '?');
+ if(path_q_sep) {
+ /* according to rfc3986, allow the query (?foo=bar)
+ also on protocols that can't handle it.
+
+ cut the string-part after '?'
+ */
+
+ /* terminate the string */
+ path_q_sep[0] = 0;
+ }
+ }
+
+ if(data->set.str[STRING_BEARER]) {
+ conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
+ if(!conn->oauth_bearer) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+#ifdef USE_UNIX_SOCKETS
+ if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
+ conn->unix_domain_socket = strdup(data->set.str[STRING_UNIX_SOCKET_PATH]);
+ if(conn->unix_domain_socket == NULL) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ conn->abstract_unix_socket = data->set.abstract_unix_socket;
+ }
+#endif
+
+ /* After the unix socket init but before the proxy vars are used, parse and
+ initialize the proxy vars */
+#ifndef CURL_DISABLE_PROXY
+ result = create_conn_helper_init_proxy(conn);
+ if(result)
+ goto out;
+#endif
+
+ /*************************************************************
+ * If the protocol is using SSL and HTTP proxy is used, we set
+ * the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *************************************************************/
+ result = parse_remote_port(data, conn);
+ if(result)
+ goto out;
+
+ /* Check for overridden login details and set them accordingly so they
+ they are known when protocol->setup_connection is called! */
+ result = override_login(data, conn, &user, &passwd, &options);
+ if(result)
+ goto out;
+ result = set_login(conn, user, passwd, options);
+ if(result)
+ goto out;
+
+ /*************************************************************
+ * Process the "connect to" linked list of hostname/port mappings.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ result = parse_connect_to_slist(data, conn, data->set.connect_to);
+ if(result)
+ goto out;
+
+ /*************************************************************
+ * IDN-fix the hostnames
+ *************************************************************/
+ fix_hostname(conn, &conn->host);
+ if(conn->bits.conn_to_host)
+ fix_hostname(conn, &conn->conn_to_host);
+ if(conn->bits.httpproxy)
+ fix_hostname(conn, &conn->http_proxy.host);
+ if(conn->bits.socksproxy)
+ fix_hostname(conn, &conn->socks_proxy.host);
+
+ /*************************************************************
+ * Check whether the host and the "connect to host" are equal.
+ * Do this after the hostnames have been IDN-fixed.
+ *************************************************************/
+ if(conn->bits.conn_to_host &&
+ strcasecompare(conn->conn_to_host.name, conn->host.name)) {
+ conn->bits.conn_to_host = FALSE;
+ }
+
+ /*************************************************************
+ * Check whether the port and the "connect to port" are equal.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
+ conn->bits.conn_to_port = FALSE;
+ }
+
+ /*************************************************************
+ * If the "connect to" feature is used with an HTTP proxy,
+ * we set the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
+ conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
+ * Setup internals depending on protocol. Needs to be done after
+ * we figured out what/if proxy to use.
+ *************************************************************/
+ result = setup_connection_internals(conn);
+ if(result)
+ goto out;
+
+ conn->recv[FIRSTSOCKET] = Curl_recv_plain;
+ conn->send[FIRSTSOCKET] = Curl_send_plain;
+ conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
+ conn->send[SECONDARYSOCKET] = Curl_send_plain;
+
+ conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
+ /***********************************************************************
+ * file: is a special case in that it doesn't need a network connection
+ ***********************************************************************/
+#ifndef CURL_DISABLE_FILE
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ bool done;
+ /* this is supposed to be the connect function so we better at least check
+ that the file is present here! */
+ DEBUGASSERT(conn->handler->connect_it);
+ result = conn->handler->connect_it(conn, &done);
+
+ /* Setup a "faked" transfer that'll do nothing */
+ if(!result) {
+ conn->data = data;
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
+
+ Curl_conncache_add_conn(data->state.conn_cache, conn);
+
+ /*
+ * Setup whatever necessary for a resumed transfer
+ */
+ result = setup_range(data);
+ if(result) {
+ DEBUGASSERT(conn->handler->done);
+ /* we ignore the return code for the protocol-specific DONE */
+ (void)conn->handler->done(conn, result, FALSE);
+ goto out;
+ }
+
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+ -1, NULL); /* no upload */
+ }
+
+ /* since we skip do_init() */
+ Curl_init_do(data, conn);
+
+ goto out;
+ }
+#endif
+
+ /* Get a cloned copy of the SSL config situation stored in the
+ connection struct. But to get this going nicely, we must first make
+ sure that the strings in the master copy are pointing to the correct
+ strings in the session handle strings array!
+
+ Keep in mind that the pointers in the master copy are pointing to strings
+ that will be freed as part of the Curl_easy struct, but all cloned
+ copies will be separately allocated.
+ */
+ data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG];
+ data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+ data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
+ data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+ data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.proxy_ssl.primary.random_file =
+ data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST_ORIG];
+ data->set.proxy_ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
+
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
+ data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
+ data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
+ data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
+ data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
+ data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY];
+ data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
+ data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
+ data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
+ data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
+ data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
+ data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
+ data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
+ data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+#ifdef USE_TLS_SRP
+ data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG];
+ data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
+ data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG];
+ data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
+#endif
+
+ if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
+ &conn->ssl_config)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
+ &conn->proxy_ssl_config)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ prune_dead_connections(data);
+
+ /*************************************************************
+ * Check the current list of connections to see if we can
+ * re-use an already existing one or if we have to create a
+ * new one.
+ *************************************************************/
+
+ /* reuse_fresh is TRUE if we are told to use a new connection by force, but
+ we only acknowledge this option if this is not a re-used connection
+ already (which happens due to follow-location or during a HTTP
+ authentication phase). */
+ if(data->set.reuse_fresh && !data->state.this_is_a_follow)
+ reuse = FALSE;
+ else
+ reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
+
+ /* If we found a reusable connection, we may still want to
+ open a new connection if we are pipelining. */
+ if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) {
+ size_t pipelen = conn_temp->send_pipe.size + conn_temp->recv_pipe.size;
+ if(pipelen > 0) {
+ infof(data, "Found connection %ld, with requests in the pipe (%zu)\n",
+ conn_temp->connection_id, pipelen);
+
+ if(conn_temp->bundle->num_connections < max_host_connections &&
+ data->state.conn_cache->num_connections < max_total_connections) {
+ /* We want a new connection anyway */
+ reuse = FALSE;
+
+ infof(data, "We can reuse, but we want a new connection anyway\n");
+ }
+ }
+ }
+
+ if(reuse) {
+ /*
+ * We already have a connection for this, we got the former connection
+ * in the conn_temp variable and thus we need to cleanup the one we
+ * just allocated before we can move along and use the previously
+ * existing one.
+ */
+ conn_temp->inuse = TRUE; /* mark this as being in use so that no other
+ handle in a multi stack may nick it */
+ reuse_conn(conn, conn_temp);
+ free(conn); /* we don't need this anymore */
+ conn = conn_temp;
+ *in_connect = conn;
+
+ infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
+ conn->connection_id,
+ conn->bits.proxy?"proxy":"host",
+ conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
+ conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
+ conn->host.dispname);
+ }
+ else {
+ /* We have decided that we want a new connection. However, we may not
+ be able to do that if we have reached the limit of how many
+ connections we are allowed to open. */
+ struct connectbundle *bundle = NULL;
+
+ if(conn->handler->flags & PROTOPT_ALPN_NPN) {
+ /* The protocol wants it, so set the bits if enabled in the easy handle
+ (default) */
+ if(data->set.ssl_enable_alpn)
+ conn->bits.tls_enable_alpn = TRUE;
+ if(data->set.ssl_enable_npn)
+ conn->bits.tls_enable_npn = TRUE;
+ }
+
+ if(waitpipe)
+ /* There is a connection that *might* become usable for pipelining
+ "soon", and we wait for that */
+ connections_available = FALSE;
+ else
+ bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache);
+
+ if(max_host_connections > 0 && bundle &&
+ (bundle->num_connections >= max_host_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The bundle is full. Let's see if we can kill a connection. */
+ conn_candidate = find_oldest_idle_connection_in_bundle(data, bundle);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly, then kill it */
+ conn_candidate->data = data;
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ else {
+ infof(data, "No more connections allowed to host: %d\n",
+ max_host_connections);
+ connections_available = FALSE;
+ }
+ }
+
+ if(connections_available &&
+ (max_total_connections > 0) &&
+ (data->state.conn_cache->num_connections >= max_total_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The cache is full. Let's see if we can kill a connection. */
+ conn_candidate = Curl_oldest_idle_connection(data);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly, then kill it */
+ conn_candidate->data = data;
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ else {
+ infof(data, "No connections available in cache\n");
+ connections_available = FALSE;
+ }
+ }
+
+ if(!connections_available) {
+ infof(data, "No connections available.\n");
+
+ conn_free(conn);
+ *in_connect = NULL;
+
+ result = CURLE_NO_CONNECTION_AVAILABLE;
+ goto out;
+ }
+ else {
+ /*
+ * This is a brand new connection, so let's store it in the connection
+ * cache of ours!
+ */
+ Curl_conncache_add_conn(data->state.conn_cache, conn);
+ }
+
+#if defined(USE_NTLM)
+ /* If NTLM is requested in a part of this connection, make sure we don't
+ assume the state is fine as this is a fresh connection and NTLM is
+ connection based. */
+ if((data->state.authhost.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ data->state.authhost.done) {
+ infof(data, "NTLM picked AND auth done set, clear picked!\n");
+ data->state.authhost.picked = CURLAUTH_NONE;
+ data->state.authhost.done = FALSE;
+ }
+
+ if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ data->state.authproxy.done) {
+ infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n");
+ data->state.authproxy.picked = CURLAUTH_NONE;
+ data->state.authproxy.done = FALSE;
+ }
+#endif
+ }
+
+ /* Mark the connection as used */
+ conn->inuse = TRUE;
+
+ /* Setup and init stuff before DO starts, in preparing for the transfer. */
+ Curl_init_do(data, conn);
+
+ /*
+ * Setup whatever necessary for a resumed transfer
+ */
+ result = setup_range(data);
+ if(result)
+ goto out;
+
+ /* Continue connectdata initialization here. */
+
+ /*
+ * Inherit the proper values from the urldata struct AFTER we have arranged
+ * the persistent connection stuff
+ */
+ conn->seek_func = data->set.seek_func;
+ conn->seek_client = data->set.seek_client;
+
+ /*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+ result = resolve_server(data, conn, async);
+
+out:
+
+ free(options);
+ free(passwd);
+ free(user);
+ return result;
+}
+
+/* Curl_setup_conn() is called after the name resolve initiated in
+ * create_conn() is all done.
+ *
+ * Curl_setup_conn() also handles reused connections
+ *
+ * conn->data MUST already have been setup fine (in create_conn)
+ */
+
+CURLcode Curl_setup_conn(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ /* nothing to setup when not using a network */
+ *protocol_done = TRUE;
+ return result;
+ }
+ *protocol_done = FALSE; /* default to not done */
+
+ /* set proxy_connect_closed to false unconditionally already here since it
+ is used strictly to provide extra information to a parent function in the
+ case of proxy CONNECT failures and we must make sure we don't have it
+ lingering set from a previous invoke */
+ conn->bits.proxy_connect_closed = FALSE;
+
+ /*
+ * Set user-agent. Used for HTTP, but since we can attempt to tunnel
+ * basically anything through a http proxy we can't limit this based on
+ * protocol.
+ */
+ if(data->set.str[STRING_USERAGENT]) {
+ Curl_safefree(conn->allocptr.uagent);
+ conn->allocptr.uagent =
+ aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
+ if(!conn->allocptr.uagent)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ data->req.headerbytecount = 0;
+
+#ifdef CURL_DO_LINEEND_CONV
+ data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
+#endif /* CURL_DO_LINEEND_CONV */
+
+ /* set start time here for timeout purposes in the connect procedure, it
+ is later set again for the progress meter purpose */
+ conn->now = Curl_tvnow();
+
+ if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+ conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
+ result = Curl_connecthost(conn, conn->dns_entry);
+ if(result)
+ return result;
+ }
+ else {
+ Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
+ *protocol_done = TRUE;
+ Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
+ Curl_verboseconnect(conn);
+ }
+
+ conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+ set this here perhaps a second time */
+
+#ifdef __EMX__
+ /*
+ * This check is quite a hack. We're calling _fsetmode to fix the problem
+ * with fwrite converting newline characters (you get mangled text files,
+ * and corrupted binary files when you download to stdout and redirect it to
+ * a file).
+ */
+
+ if((data->set.out)->_handle == NULL) {
+ _fsetmode(stdout, "b");
+ }
+#endif
+
+ return result;
+}
+
+CURLcode Curl_connect(struct Curl_easy *data,
+ struct connectdata **in_connect,
+ bool *asyncp,
+ bool *protocol_done)
+{
+ CURLcode result;
+
+ *asyncp = FALSE; /* assume synchronous resolves by default */
+
+ /* call the stuff that needs to be called */
+ result = create_conn(data, in_connect, asyncp);
+
+ if(!result) {
+ /* no error */
+ if((*in_connect)->send_pipe.size || (*in_connect)->recv_pipe.size)
+ /* pipelining */
+ *protocol_done = TRUE;
+ else if(!*asyncp) {
+ /* DNS resolution is done: that's either because this is a reused
+ connection, in which case DNS was unnecessary, or because DNS
+ really did finish already (synch resolver/fast async resolve) */
+ result = Curl_setup_conn(*in_connect, protocol_done);
+ }
+ }
+
+ if(result == CURLE_NO_CONNECTION_AVAILABLE) {
+ *in_connect = NULL;
+ return result;
+ }
+
+ if(result && *in_connect) {
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(*in_connect, FALSE); /* close the connection */
+ *in_connect = NULL; /* return a NULL */
+ }
+
+ return result;
+}
+
+/*
+ * Curl_init_do() inits the readwrite session. This is inited each time (in
+ * the DO function before the protocol-specific DO functions are invoked) for
+ * a transfer, sometimes multiple times on the same Curl_easy. Make sure
+ * nothing in here depends on stuff that are setup dynamically for the
+ * transfer.
+ *
+ * Allow this function to get called with 'conn' set to NULL.
+ */
+
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
+{
+ struct SingleRequest *k = &data->req;
+
+ if(conn)
+ conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
+ * use */
+
+ data->state.done = FALSE; /* *_done() is not called yet */
+ data->state.expect100header = FALSE;
+
+ if(data->set.opt_no_body)
+ /* in HTTP lingo, no body means using the HEAD request... */
+ data->set.httpreq = HTTPREQ_HEAD;
+ else if(HTTPREQ_HEAD == data->set.httpreq)
+ /* ... but if unset there really is no perfect method that is the
+ "opposite" of HEAD but in reality most people probably think GET
+ then. The important thing is that we can't let it remain HEAD if the
+ opt_no_body is set FALSE since then we'll behave wrong when getting
+ HTTP. */
+ data->set.httpreq = HTTPREQ_GET;
+
+ k->start = Curl_tvnow(); /* start time */
+ k->now = k->start; /* current time is now */
+ k->header = TRUE; /* assume header */
+
+ k->bytecount = 0;
+
+ k->buf = data->state.buffer;
+ k->hbufp = data->state.headerbuff;
+ k->ignorebody=FALSE;
+
+ Curl_speedinit(data);
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+
+ return CURLE_OK;
+}
+
+/*
+* get_protocol_family()
+*
+* This is used to return the protocol family for a given protocol.
+*
+* Parameters:
+*
+* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS.
+*
+* Returns the family as a single bit protocol identifier.
+*/
+
+static unsigned int get_protocol_family(unsigned int protocol)
+{
+ unsigned int family;
+
+ switch(protocol) {
+ case CURLPROTO_HTTP:
+ case CURLPROTO_HTTPS:
+ family = CURLPROTO_HTTP;
+ break;
+
+ case CURLPROTO_FTP:
+ case CURLPROTO_FTPS:
+ family = CURLPROTO_FTP;
+ break;
+
+ case CURLPROTO_SCP:
+ family = CURLPROTO_SCP;
+ break;
+
+ case CURLPROTO_SFTP:
+ family = CURLPROTO_SFTP;
+ break;
+
+ case CURLPROTO_TELNET:
+ family = CURLPROTO_TELNET;
+ break;
+
+ case CURLPROTO_LDAP:
+ case CURLPROTO_LDAPS:
+ family = CURLPROTO_LDAP;
+ break;
+
+ case CURLPROTO_DICT:
+ family = CURLPROTO_DICT;
+ break;
+
+ case CURLPROTO_FILE:
+ family = CURLPROTO_FILE;
+ break;
+
+ case CURLPROTO_TFTP:
+ family = CURLPROTO_TFTP;
+ break;
+
+ case CURLPROTO_IMAP:
+ case CURLPROTO_IMAPS:
+ family = CURLPROTO_IMAP;
+ break;
+
+ case CURLPROTO_POP3:
+ case CURLPROTO_POP3S:
+ family = CURLPROTO_POP3;
+ break;
+
+ case CURLPROTO_SMTP:
+ case CURLPROTO_SMTPS:
+ family = CURLPROTO_SMTP;
+ break;
+
+ case CURLPROTO_RTSP:
+ family = CURLPROTO_RTSP;
+ break;
+
+ case CURLPROTO_RTMP:
+ case CURLPROTO_RTMPS:
+ family = CURLPROTO_RTMP;
+ break;
+
+ case CURLPROTO_RTMPT:
+ case CURLPROTO_RTMPTS:
+ family = CURLPROTO_RTMPT;
+ break;
+
+ case CURLPROTO_RTMPE:
+ family = CURLPROTO_RTMPE;
+ break;
+
+ case CURLPROTO_RTMPTE:
+ family = CURLPROTO_RTMPTE;
+ break;
+
+ case CURLPROTO_GOPHER:
+ family = CURLPROTO_GOPHER;
+ break;
+
+ case CURLPROTO_SMB:
+ case CURLPROTO_SMBS:
+ family = CURLPROTO_SMB;
+ break;
+
+ default:
+ family = 0;
+ break;
+ }
+
+ return family;
+}
diff --git a/Utilities/cmcurl/lib/url.h b/Utilities/cmcurl/lib/url.h
new file mode 100644
index 000000000..f13c8e664
--- /dev/null
+++ b/Utilities/cmcurl/lib/url.h
@@ -0,0 +1,93 @@
+#ifndef HEADER_CURL_URL_H
+#define HEADER_CURL_URL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * Prototypes for library-wide functions provided by url.c
+ */
+
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_open(struct Curl_easy **curl);
+CURLcode Curl_init_userdefined(struct UserDefined *set);
+CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
+ va_list arg);
+CURLcode Curl_dupset(struct Curl_easy * dst, struct Curl_easy * src);
+void Curl_freeset(struct Curl_easy * data);
+CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
+CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
+ bool *async, bool *protocol_connect);
+CURLcode Curl_disconnect(struct connectdata *, bool dead_connection);
+CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
+CURLcode Curl_setup_conn(struct connectdata *conn,
+ bool *protocol_done);
+void Curl_free_request_state(struct Curl_easy *data);
+
+int Curl_protocol_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+int Curl_doing_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+bool Curl_isPipeliningEnabled(const struct Curl_easy *handle);
+CURLcode Curl_addHandleToPipeline(struct Curl_easy *handle,
+ struct curl_llist *pipeline);
+int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
+ struct curl_llist *pipeline);
+struct connectdata *
+Curl_oldest_idle_connection(struct Curl_easy *data);
+/* remove the specified connection from all (possible) pipelines and related
+ queues */
+void Curl_getoff_all_pipelines(struct Curl_easy *data,
+ struct connectdata *conn);
+
+void Curl_close_connections(struct Curl_easy *data);
+
+#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
+#define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless
+ specified */
+
+CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex);
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define Curl_verboseconnect(x) Curl_nop_stmt
+#else
+void Curl_verboseconnect(struct connectdata *conn);
+#endif
+
+#define CONNECT_PROXY_SSL()\
+ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
+ !conn->bits.proxy_ssl_connected[sockindex])
+
+#define CONNECT_FIRSTSOCKET_PROXY_SSL()\
+ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
+ !conn->bits.proxy_ssl_connected[FIRSTSOCKET])
+
+#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\
+ (conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
+ !conn->bits.proxy_ssl_connected[SECONDARYSOCKET])
+
+#endif /* HEADER_CURL_URL_H */
diff --git a/Utilities/cmcurl/lib/urldata.h b/Utilities/cmcurl/lib/urldata.h
new file mode 100644
index 000000000..d4a4a98dc
--- /dev/null
+++ b/Utilities/cmcurl/lib/urldata.h
@@ -0,0 +1,1886 @@
+#ifndef HEADER_CURL_URLDATA_H
+#define HEADER_CURL_URLDATA_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "curl_setup.h"
+
+#define PORT_FTP 21
+#define PORT_FTPS 990
+#define PORT_TELNET 23
+#define PORT_HTTP 80
+#define PORT_HTTPS 443
+#define PORT_DICT 2628
+#define PORT_LDAP 389
+#define PORT_LDAPS 636
+#define PORT_TFTP 69
+#define PORT_SSH 22
+#define PORT_IMAP 143
+#define PORT_IMAPS 993
+#define PORT_POP3 110
+#define PORT_POP3S 995
+#define PORT_SMB 445
+#define PORT_SMBS 445
+#define PORT_SMTP 25
+#define PORT_SMTPS 465 /* sometimes called SSMTP */
+#define PORT_RTSP 554
+#define PORT_RTMP 1935
+#define PORT_RTMPT PORT_HTTP
+#define PORT_RTMPS PORT_HTTPS
+#define PORT_GOPHER 70
+
+#define DICT_MATCH "/MATCH:"
+#define DICT_MATCH2 "/M:"
+#define DICT_MATCH3 "/FIND:"
+#define DICT_DEFINE "/DEFINE:"
+#define DICT_DEFINE2 "/D:"
+#define DICT_DEFINE3 "/LOOKUP:"
+
+#define CURL_DEFAULT_USER "anonymous"
+#define CURL_DEFAULT_PASSWORD "ftp@example.com"
+
+/* Convenience defines for checking protocols or their SSL based version. Each
+ protocol handler should only ever have a single CURLPROTO_ in its protocol
+ field. */
+#define PROTO_FAMILY_HTTP (CURLPROTO_HTTP|CURLPROTO_HTTPS)
+#define PROTO_FAMILY_FTP (CURLPROTO_FTP|CURLPROTO_FTPS)
+#define PROTO_FAMILY_POP3 (CURLPROTO_POP3|CURLPROTO_POP3S)
+#define PROTO_FAMILY_SMB (CURLPROTO_SMB|CURLPROTO_SMBS)
+#define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS)
+
+#define DEFAULT_CONNCACHE_SIZE 5
+
+/* length of longest IPv6 address string including the trailing null */
+#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+
+/* Default FTP/IMAP etc response timeout in milliseconds.
+ Symbian OS panics when given a timeout much greater than 1/2 hour.
+*/
+#define RESP_TIMEOUT (1800*1000)
+
+#include "cookie.h"
+#include "formdata.h"
+
+#ifdef USE_OPENSSL
+#include <openssl/ssl.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#endif /* USE_OPENSSL */
+
+#ifdef USE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#ifdef USE_MBEDTLS
+
+#include <mbedtls/ssl.h>
+#include <mbedtls/version.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+
+#elif defined USE_POLARSSL
+
+#include <polarssl/ssl.h>
+#include <polarssl/version.h>
+#if POLARSSL_VERSION_NUMBER<0x01010000
+#include <polarssl/havege.h>
+#else
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+
+#endif /* USE_POLARSSL */
+
+#ifdef USE_CYASSL
+#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
+#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
+#include <cyassl/openssl/ssl.h>
+#endif
+
+#ifdef USE_NSS
+#include <nspr.h>
+#include <pk11pub.h>
+#endif
+
+#ifdef USE_GSKIT
+#include <gskssl.h>
+#endif
+
+#ifdef USE_AXTLS
+#include <axTLS/config.h>
+#include <axTLS/ssl.h>
+#undef malloc
+#undef calloc
+#undef realloc
+#endif /* USE_AXTLS */
+
+#if defined(USE_SCHANNEL) || defined(USE_WINDOWS_SSPI)
+#include "curl_sspi.h"
+#endif
+#ifdef USE_SCHANNEL
+#include <schnlsp.h>
+#include <schannel.h>
+#endif
+
+#ifdef USE_DARWINSSL
+#include <Security/Security.h>
+/* For some reason, when building for iOS, the omnibus header above does
+ * not include SecureTransport.h as of iOS SDK 5.1. */
+#include <Security/SecureTransport.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "timeval.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* for content-encoding */
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#include <curl/curl.h>
+
+#include "http_chunks.h" /* for the structs and enum stuff */
+#include "hostip.h"
+#include "hash.h"
+#include "splay.h"
+
+#include "imap.h"
+#include "pop3.h"
+#include "smtp.h"
+#include "ftp.h"
+#include "file.h"
+#include "ssh.h"
+#include "http.h"
+#include "rtsp.h"
+#include "smb.h"
+#include "wildcard.h"
+#include "multihandle.h"
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+# include <gss.h>
+# elif defined HAVE_GSSMIT
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_generic.h>
+# else
+# include <gssapi.h>
+# endif
+#endif
+
+#ifdef HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/* The upload buffer size, should not be smaller than CURL_MAX_WRITE_SIZE, as
+ it needs to hold a full buffer as could be sent in a write callback */
+#define UPLOAD_BUFSIZE CURL_MAX_WRITE_SIZE
+
+/* The "master buffer" is for HTTP pipelining */
+#define MASTERBUF_SIZE 16384
+
+/* Initial size of the buffer to store headers in, it'll be enlarged in case
+ of need. */
+#define HEADERSIZE 256
+
+#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
+#define GOOD_EASY_HANDLE(x) \
+ ((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
+
+/* Some convenience macros to get the larger/smaller value out of two given.
+ We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
+#define CURLMIN(x,y) ((x)<(y)?(x):(y))
+
+#ifdef HAVE_GSSAPI
+/* Types needed for krb5-ftp connections */
+struct krb5buffer {
+ void *data;
+ size_t size;
+ size_t index;
+ int eof_flag;
+};
+
+enum protection_level {
+ PROT_NONE, /* first in list */
+ PROT_CLEAR,
+ PROT_SAFE,
+ PROT_CONFIDENTIAL,
+ PROT_PRIVATE,
+ PROT_CMD,
+ PROT_LAST /* last in list */
+};
+#endif
+
+#ifdef USE_SCHANNEL
+/* Structs to store Schannel handles */
+struct curl_schannel_cred {
+ CredHandle cred_handle;
+ TimeStamp time_stamp;
+ int refcount;
+};
+
+struct curl_schannel_ctxt {
+ CtxtHandle ctxt_handle;
+ TimeStamp time_stamp;
+};
+#endif
+
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+ ssl_connect_1,
+ ssl_connect_2,
+ ssl_connect_2_reading,
+ ssl_connect_2_writing,
+ ssl_connect_3,
+ ssl_connect_done
+} ssl_connect_state;
+
+typedef enum {
+ ssl_connection_none,
+ ssl_connection_negotiating,
+ ssl_connection_complete
+} ssl_connection_state;
+
+/* struct for data related to each SSL connection */
+struct ssl_connect_data {
+ /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm
+ but at least asked to or meaning to use it. See 'state' for the exact
+ current state of the connection. */
+ bool use;
+ ssl_connection_state state;
+ ssl_connect_state connecting_state;
+#if defined(USE_OPENSSL)
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+#elif defined(USE_GNUTLS)
+ gnutls_session_t session;
+ gnutls_certificate_credentials_t cred;
+#ifdef USE_TLS_SRP
+ gnutls_srp_client_credentials_t srp_client_cred;
+#endif
+#elif defined(USE_MBEDTLS)
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_entropy_context entropy;
+ mbedtls_ssl_context ssl;
+ int server_fd;
+ mbedtls_x509_crt cacert;
+ mbedtls_x509_crt clicert;
+ mbedtls_x509_crl crl;
+ mbedtls_pk_context pk;
+ mbedtls_ssl_config config;
+ const char *protocols[3];
+#elif defined(USE_POLARSSL)
+ ctr_drbg_context ctr_drbg;
+ entropy_context entropy;
+ ssl_context ssl;
+ int server_fd;
+ x509_crt cacert;
+ x509_crt clicert;
+ x509_crl crl;
+ rsa_context rsa;
+#elif defined(USE_CYASSL)
+ SSL_CTX* ctx;
+ SSL* handle;
+#elif defined(USE_NSS)
+ PRFileDesc *handle;
+ char *client_nickname;
+ struct Curl_easy *data;
+ struct curl_llist obj_list;
+ PK11GenericObject *obj_clicert;
+#elif defined(USE_GSKIT)
+ gsk_handle handle;
+ int iocport;
+ int localfd;
+ int remotefd;
+#elif defined(USE_AXTLS)
+ SSL_CTX* ssl_ctx;
+ SSL* ssl;
+#elif defined(USE_SCHANNEL)
+ struct curl_schannel_cred *cred;
+ struct curl_schannel_ctxt *ctxt;
+ SecPkgContext_StreamSizes stream_sizes;
+ size_t encdata_length, decdata_length;
+ size_t encdata_offset, decdata_offset;
+ unsigned char *encdata_buffer, *decdata_buffer;
+ /* encdata_is_incomplete: if encdata contains only a partial record that
+ can't be decrypted without another Curl_read_plain (that is, status is
+ SEC_E_INCOMPLETE_MESSAGE) then set this true. after Curl_read_plain writes
+ more bytes into encdata then set this back to false. */
+ bool encdata_is_incomplete;
+ unsigned long req_flags, ret_flags;
+ CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */
+ bool recv_sspi_close_notify; /* true if connection closed by close_notify */
+ bool recv_connection_closed; /* true if connection closed, regardless how */
+ bool use_alpn; /* true if ALPN is used for this connection */
+#elif defined(USE_DARWINSSL)
+ SSLContextRef ssl_ctx;
+ curl_socket_t ssl_sockfd;
+ bool ssl_direction; /* true if writing, false if reading */
+ size_t ssl_write_buffered_length;
+#elif defined(USE_SSL)
+#error "SSL backend specific information missing from ssl_connect_data"
+#endif
+};
+
+struct ssl_primary_config {
+ long version; /* what version the client wants to use */
+ long version_max; /* max supported version the client wants to use*/
+ bool verifypeer; /* set TRUE if this is desired */
+ bool verifyhost; /* set TRUE if CN/SAN must match hostname */
+ bool verifystatus; /* set TRUE if certificate status must be checked */
+ char *CApath; /* certificate dir (doesn't work on windows) */
+ char *CAfile; /* certificate to verify peer against */
+ char *clientcert;
+ char *random_file; /* path to file containing "random" data */
+ char *egdsocket; /* path to file containing the EGD daemon socket */
+ char *cipher_list; /* list of ciphers to use */
+ bool sessionid; /* cache session IDs or not */
+};
+
+struct ssl_config_data {
+ struct ssl_primary_config primary;
+ bool enable_beast; /* especially allow this flaw for interoperability's
+ sake*/
+ bool no_revoke; /* disable SSL certificate revocation checks */
+ long certverifyresult; /* result from the certificate verification */
+ char *CRLfile; /* CRL to check certificate revocation */
+ char *issuercert;/* optional issuer certificate filename */
+ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
+ void *fsslctxp; /* parameter for call back */
+ bool certinfo; /* gather lots of certificate info */
+ bool falsestart;
+
+ char *cert; /* client certificate file name */
+ char *cert_type; /* format for certificate (default: PEM)*/
+ char *key; /* private key file name */
+ char *key_type; /* format for private key (default: PEM) */
+ char *key_passwd; /* plain text private key password */
+
+#ifdef USE_TLS_SRP
+ char *username; /* TLS username (for, e.g., SRP) */
+ char *password; /* TLS password (for, e.g., SRP) */
+ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */
+#endif
+};
+
+struct ssl_general_config {
+ size_t max_ssl_sessions; /* SSL session id cache size */
+};
+
+/* information stored about one single SSL session */
+struct curl_ssl_session {
+ char *name; /* host name for which this ID was used */
+ char *conn_to_host; /* host name for the connection (may be NULL) */
+ const char *scheme; /* protocol scheme used */
+ void *sessionid; /* as returned from the SSL layer */
+ size_t idsize; /* if known, otherwise 0 */
+ long age; /* just a number, the higher the more recent */
+ int remote_port; /* remote port */
+ int conn_to_port; /* remote port for the connection (may be -1) */
+ struct ssl_primary_config ssl_config; /* setup for this session */
+};
+
+/* Struct used for Digest challenge-response authentication */
+struct digestdata {
+#if defined(USE_WINDOWS_SSPI)
+ BYTE *input_token;
+ size_t input_token_len;
+ CtxtHandle *http_context;
+#else
+ char *nonce;
+ char *cnonce;
+ char *realm;
+ int algo;
+ bool stale; /* set true for re-negotiation */
+ char *opaque;
+ char *qop;
+ char *algorithm;
+ int nc; /* nounce count */
+#endif
+};
+
+typedef enum {
+ NTLMSTATE_NONE,
+ NTLMSTATE_TYPE1,
+ NTLMSTATE_TYPE2,
+ NTLMSTATE_TYPE3,
+ NTLMSTATE_LAST
+} curlntlm;
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+#endif
+
+/* Struct used for GSSAPI (Kerberos V5) authentication */
+#if defined(USE_KERBEROS5)
+struct kerberos5data {
+#if defined(USE_WINDOWS_SSPI)
+ CredHandle *credentials;
+ CtxtHandle *context;
+ TCHAR *spn;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ size_t token_max;
+ BYTE *output_token;
+#else
+ gss_ctx_id_t context;
+ gss_name_t spn;
+#endif
+};
+#endif
+
+/* Struct used for NTLM challenge-response authentication */
+#if defined(USE_NTLM)
+struct ntlmdata {
+ curlntlm state;
+#ifdef USE_WINDOWS_SSPI
+ CredHandle *credentials;
+ CtxtHandle *context;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ size_t token_max;
+ BYTE *output_token;
+ BYTE *input_token;
+ size_t input_token_len;
+#else
+ unsigned int flags;
+ unsigned char nonce[8];
+ void *target_info; /* TargetInfo received in the ntlm type-2 message */
+ unsigned int target_info_len;
+#endif
+};
+#endif
+
+#ifdef USE_SPNEGO
+struct negotiatedata {
+ /* When doing Negotiate (SPNEGO) auth, we first need to send a token
+ and then validate the received one. */
+ enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state;
+#ifdef HAVE_GSSAPI
+ OM_uint32 status;
+ gss_ctx_id_t context;
+ gss_name_t spn;
+ gss_buffer_desc output_token;
+#else
+#ifdef USE_WINDOWS_SSPI
+ DWORD status;
+ CredHandle *credentials;
+ CtxtHandle *context;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ TCHAR *spn;
+ size_t token_max;
+ BYTE *output_token;
+ size_t output_token_length;
+#endif
+#endif
+};
+#endif
+
+
+/*
+ * Boolean values that concerns this connection.
+ */
+struct ConnectBits {
+ /* always modify bits.close with the connclose() and connkeep() macros! */
+ bool close; /* if set, we close the connection after this request */
+ bool reuse; /* if set, this is a re-used connection */
+ bool conn_to_host; /* if set, this connection has a "connect to host"
+ that overrides the host in the URL */
+ bool conn_to_port; /* if set, this connection has a "connect to port"
+ that overrides the port in the URL (remote port) */
+ bool proxy; /* if set, this transfer is done through a proxy - any type */
+ bool httpproxy; /* if set, this transfer is done through a http proxy */
+ bool socksproxy; /* if set, this transfer is done through a socks proxy */
+ bool user_passwd; /* do we use user+password for this connection? */
+ bool proxy_user_passwd; /* user+password for the proxy? */
+ bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6
+ IP address */
+ bool ipv6; /* we communicate with a site using an IPv6 address */
+
+ bool do_more; /* this is set TRUE if the ->curl_do_more() function is
+ supposed to be called, after ->curl_do() */
+ bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
+ the first time on the first connect function call */
+ bool protoconnstart;/* the protocol layer has STARTED its operation after
+ the TCP layer connect */
+
+ bool retry; /* this connection is about to get closed and then
+ re-attempted at another connection. */
+ bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy.
+ This is implicit when SSL-protocols are used through
+ proxies, but can also be enabled explicitly by
+ apps */
+ bool authneg; /* TRUE when the auth phase has started, which means
+ that we are creating a request with an auth header,
+ but it is not the final request in the auth
+ negotiation. */
+ bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
+ though it will be discarded. When the whole send
+ operation is done, we must call the data rewind
+ callback. */
+ bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
+ EPSV doesn't work we disable it for the forthcoming
+ requests */
+
+ bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
+ EPRT doesn't work we disable it for the forthcoming
+ requests */
+ bool ftp_use_data_ssl; /* Enabled SSL for the data connection */
+ bool netrc; /* name+password provided by netrc */
+ bool userpwd_in_url; /* name+password found in url */
+ bool stream_was_rewound; /* Indicates that the stream was rewound after a
+ request read past the end of its response byte
+ boundary */
+ bool proxy_connect_closed; /* set true if a proxy disconnected the
+ connection in a CONNECT request with auth, so
+ that libcurl should reconnect and continue. */
+ bool bound; /* set true if bind() has already been done on this socket/
+ connection */
+ bool type_set; /* type= was used in the URL */
+ bool multiplex; /* connection is multiplexed */
+
+ bool tcp_fastopen; /* use TCP Fast Open */
+ bool tls_enable_npn; /* TLS NPN extension? */
+ bool tls_enable_alpn; /* TLS ALPN extension? */
+ bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy
+ is complete */
+ bool socksproxy_connecting; /* connecting through a socks proxy */
+};
+
+struct hostname {
+ char *rawalloc; /* allocated "raw" version of the name */
+ char *encalloc; /* allocated IDN-encoded version of the name */
+ char *name; /* name to use internally, might be encoded, might be raw */
+ const char *dispname; /* name to display, as 'name' might be encoded */
+};
+
+/*
+ * Flags on the keepon member of the Curl_transfer_keeper
+ */
+
+#define KEEP_NONE 0
+#define KEEP_RECV (1<<0) /* there is or may be data to read */
+#define KEEP_SEND (1<<1) /* there is or may be data to write */
+#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there
+ might still be data to read */
+#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there
+ might still be data to write */
+#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */
+#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */
+
+#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
+#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
+
+
+#ifdef HAVE_LIBZ
+typedef enum {
+ ZLIB_UNINIT, /* uninitialized */
+ ZLIB_INIT, /* initialized */
+ ZLIB_GZIP_HEADER, /* reading gzip header */
+ ZLIB_GZIP_INFLATING, /* inflating gzip stream */
+ ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
+} zlibInitState;
+#endif
+
+#ifdef CURLRES_ASYNCH
+struct Curl_async {
+ char *hostname;
+ int port;
+ struct Curl_dns_entry *dns;
+ bool done; /* set TRUE when the lookup is complete */
+ int status; /* if done is TRUE, this is the status from the callback */
+ void *os_specific; /* 'struct thread_data' for Windows */
+};
+#endif
+
+#define FIRSTSOCKET 0
+#define SECONDARYSOCKET 1
+
+/* These function pointer types are here only to allow easier typecasting
+ within the source when we need to cast between data pointers (such as NULL)
+ and function pointers. */
+typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *);
+typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
+
+enum expect100 {
+ EXP100_SEND_DATA, /* enough waiting, just send the body now */
+ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
+ EXP100_SENDING_REQUEST, /* still sending the request but will wait for
+ the 100 header once done with the request */
+ EXP100_FAILED /* used on 417 Expectation Failed */
+};
+
+enum upgrade101 {
+ UPGR101_INIT, /* default state */
+ UPGR101_REQUESTED, /* upgrade requested */
+ UPGR101_RECEIVED, /* response received */
+ UPGR101_WORKING /* talking upgraded protocol */
+};
+
+/*
+ * Request specific data in the easy handle (Curl_easy). Previously,
+ * these members were on the connectdata struct but since a conn struct may
+ * now be shared between different Curl_easys, we store connection-specific
+ * data here. This struct only keeps stuff that's interesting for *this*
+ * request, as it will be cleared between multiple ones
+ */
+struct SingleRequest {
+ curl_off_t size; /* -1 if unknown at this point */
+ curl_off_t *bytecountp; /* return number of bytes read or NULL */
+
+ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
+ -1 means unlimited */
+ curl_off_t *writebytecountp; /* return number of bytes written or NULL */
+
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
+
+ long headerbytecount; /* only count received headers */
+ long deductheadercount; /* this amount of bytes doesn't count when we check
+ if anything has been transferred at the end of a
+ connection. We use this counter to make only a
+ 100 reply (without a following second response
+ code) result in a CURLE_GOT_NOTHING error code */
+
+ struct timeval start; /* transfer started at this time */
+ struct timeval now; /* current time */
+ bool header; /* incoming data has HTTP header */
+ enum {
+ HEADER_NORMAL, /* no bad header at all */
+ HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
+ is normal data */
+ HEADER_ALLBAD /* all was believed to be header */
+ } badheader; /* the header was deemed bad and will be
+ written as body */
+ int headerline; /* counts header lines to better track the
+ first one */
+ char *hbufp; /* points at *end* of header line */
+ size_t hbuflen;
+ char *str; /* within buf */
+ char *str_start; /* within buf */
+ char *end_ptr; /* within buf */
+ char *p; /* within headerbuff */
+ bool content_range; /* set TRUE if Content-Range: was found */
+ curl_off_t offset; /* possible resume offset read from the
+ Content-Range: header */
+ int httpcode; /* error code from the 'HTTP/1.? XXX' or
+ 'RTSP/1.? XXX' line */
+ struct timeval start100; /* time stamp to wait for the 100 code from */
+ enum expect100 exp100; /* expect 100 continue state */
+ enum upgrade101 upgr101; /* 101 upgrade state */
+
+ int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */
+
+#define IDENTITY 0 /* No encoding */
+#define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */
+#define GZIP 2 /* gzip algorithm [RFC 1952] */
+
+#ifdef HAVE_LIBZ
+ zlibInitState zlib_init; /* possible zlib init state;
+ undefined if Content-Encoding header. */
+ z_stream z; /* State structure for zlib. */
+#endif
+
+ time_t timeofdoc;
+ long bodywrites;
+
+ char *buf;
+ curl_socket_t maxfd;
+
+ int keepon;
+
+ bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
+ and we're uploading the last chunk */
+
+ bool ignorebody; /* we read a response-body but we ignore it! */
+ bool ignorecl; /* This HTTP response has no body so we ignore the Content-
+ Length: header */
+
+ char *location; /* This points to an allocated version of the Location:
+ header data */
+ char *newurl; /* Set to the new URL to use when a redirect or a retry is
+ wanted */
+
+ /* 'upload_present' is used to keep a byte counter of how much data there is
+ still left in the buffer, aimed for upload. */
+ ssize_t upload_present;
+
+ /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+ buffer, so the next read should read from where this pointer points to,
+ and the 'upload_present' contains the number of bytes available at this
+ position */
+ char *upload_fromhere;
+
+ bool chunk; /* if set, this is a chunked transfer-encoding */
+ bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
+ on upload */
+ bool getheader; /* TRUE if header parsing is wanted */
+
+ bool forbidchunk; /* used only to explicitly forbid chunk-upload for
+ specific upload buffers. See readmoredata() in
+ http.c for details. */
+
+ void *protop; /* Allocated protocol-specific data. Each protocol
+ handler makes sure this points to data it needs. */
+};
+
+/*
+ * Specific protocol handler.
+ */
+
+struct Curl_handler {
+ const char *scheme; /* URL scheme name. */
+
+ /* Complement to setup_connection_internals(). */
+ CURLcode (*setup_connection)(struct connectdata *);
+
+ /* These two functions MUST be set to be protocol dependent */
+ CURLcode (*do_it)(struct connectdata *, bool *done);
+ Curl_done_func done;
+
+ /* If the curl_do() function is better made in two halves, this
+ * curl_do_more() function will be called afterwards, if set. For example
+ * for doing the FTP stuff after the PASV/PORT command.
+ */
+ Curl_do_more_func do_more;
+
+ /* This function *MAY* be set to a protocol-dependent function that is run
+ * after the connect() and everything is done, as a step in the connection.
+ * The 'done' pointer points to a bool that should be set to TRUE if the
+ * function completes before return. If it doesn't complete, the caller
+ * should call the curl_connecting() function until it is.
+ */
+ CURLcode (*connect_it)(struct connectdata *, bool *done);
+
+ /* See above. Currently only used for FTP. */
+ CURLcode (*connecting)(struct connectdata *, bool *done);
+ CURLcode (*doing)(struct connectdata *, bool *done);
+
+ /* Called from the multi interface during the PROTOCONNECT phase, and it
+ should then return a proper fd set */
+ int (*proto_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DOING phase, and it should
+ then return a proper fd set */
+ int (*doing_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DO_MORE phase, and it should
+ then return a proper fd set */
+ int (*domore_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DO_DONE, PERFORM and
+ WAITPERFORM phases, and it should then return a proper fd set. Not setting
+ this will make libcurl use the generic default one. */
+ int (*perform_getsock)(const struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* This function *MAY* be set to a protocol-dependent function that is run
+ * by the curl_disconnect(), as a step in the disconnection. If the handler
+ * is called because the connection has been considered dead, dead_connection
+ * is set to TRUE.
+ */
+ CURLcode (*disconnect)(struct connectdata *, bool dead_connection);
+
+ /* If used, this function gets called from transfer.c:readwrite_data() to
+ allow the protocol to do extra reads/writes */
+ CURLcode (*readwrite)(struct Curl_easy *data, struct connectdata *conn,
+ ssize_t *nread, bool *readmore);
+
+ long defport; /* Default port. */
+ unsigned int protocol; /* See CURLPROTO_* - this needs to be the single
+ specific protocol bit */
+ unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */
+};
+
+#define PROTOPT_NONE 0 /* nothing extra */
+#define PROTOPT_SSL (1<<0) /* uses SSL */
+#define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */
+#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */
+/* some protocols will have to call the underlying functions without regard to
+ what exact state the socket signals. IE even if the socket says "readable",
+ the send function might need to be called while uploading, or vice versa.
+*/
+#define PROTOPT_DIRLOCK (1<<3)
+#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */
+#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it
+ gets a default */
+#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle
+ url query strings (?foo=bar) ! */
+#define PROTOPT_CREDSPERREQUEST (1<<7) /* requires login credentials per
+ request instead of per connection */
+#define PROTOPT_ALPN_NPN (1<<8) /* set ALPN and/or NPN for this */
+#define PROTOPT_STREAM (1<<9) /* a protocol with individual logical streams */
+#define PROTOPT_URLOPTIONS (1<<10) /* allow options part in the userinfo field
+ of the URL */
+
+/* return the count of bytes sent, or -1 on error */
+typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ const void *buf, /* data to write */
+ size_t len, /* max amount to write */
+ CURLcode *err); /* error to return */
+
+/* return the count of bytes read, or -1 on error */
+typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ char *buf, /* store data here */
+ size_t len, /* max amount to read */
+ CURLcode *err); /* error to return */
+
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+struct postponed_data {
+ char *buffer; /* Temporal store for received data during
+ sending, must be freed */
+ size_t allocated_size; /* Size of temporal store */
+ size_t recv_size; /* Size of received data during sending */
+ size_t recv_processed; /* Size of processed part of postponed data */
+#ifdef DEBUGBUILD
+ curl_socket_t bindsock;/* Structure must be bound to specific socket,
+ used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+};
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
+
+struct proxy_info {
+ struct hostname host;
+ long port;
+ curl_proxytype proxytype; /* what kind of proxy that is in use */
+ char *user; /* proxy user name string, allocated */
+ char *passwd; /* proxy password string, allocated */
+};
+
+/*
+ * The connectdata struct contains all fields and variables that should be
+ * unique for an entire connection.
+ */
+struct connectdata {
+ /* 'data' is the CURRENT Curl_easy using this connection -- take great
+ caution that this might very well vary between different times this
+ connection is used! */
+ struct Curl_easy *data;
+
+ struct curl_llist_element bundle_node; /* conncache */
+
+ /* chunk is for HTTP chunked encoding, but is in the general connectdata
+ struct only because we can do just about any protocol through a HTTP proxy
+ and a HTTP proxy may in fact respond using chunked encoding */
+ struct Curl_chunker chunk;
+
+ curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
+ void *closesocket_client;
+
+ bool inuse; /* This is a marker for the connection cache logic. If this is
+ TRUE this handle is being used by an easy handle and cannot
+ be used by any other easy handle without careful
+ consideration (== only for pipelining). */
+
+ /**** Fields set when inited and not modified again */
+ long connection_id; /* Contains a unique number to make it easier to
+ track the connections in the log output */
+
+ /* 'dns_entry' is the particular host we use. This points to an entry in the
+ DNS cache and it will not get pruned while locked. It gets unlocked in
+ Curl_done(). This entry will be NULL if the connection is re-used as then
+ there is no name resolve done. */
+ struct Curl_dns_entry *dns_entry;
+
+ /* 'ip_addr' is the particular IP we connected to. It points to a struct
+ within the DNS cache, so this pointer is only valid as long as the DNS
+ cache entry remains locked. It gets unlocked in Curl_done() */
+ Curl_addrinfo *ip_addr;
+ Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */
+
+ /* 'ip_addr_str' is the ip_addr data as a human readable string.
+ It remains available as long as the connection does, which is longer than
+ the ip_addr itself. */
+ char ip_addr_str[MAX_IPADR_LEN];
+
+ unsigned int scope_id; /* Scope id for IPv6 */
+
+ int socktype; /* SOCK_STREAM or SOCK_DGRAM */
+
+ struct hostname host;
+ char *secondaryhostname; /* secondary socket host name (ftp) */
+ struct hostname conn_to_host; /* the host to connect to. valid only if
+ bits.conn_to_host is set */
+
+ struct proxy_info socks_proxy;
+ struct proxy_info http_proxy;
+
+ long port; /* which port to use locally */
+ int remote_port; /* the remote port, not the proxy port! */
+ int conn_to_port; /* the remote port to connect to. valid only if
+ bits.conn_to_port is set */
+ unsigned short secondary_port; /* secondary socket remote port to connect to
+ (ftp) */
+
+ /* 'primary_ip' and 'primary_port' get filled with peer's numerical
+ ip address and port number whenever an outgoing connection is
+ *attempted* from the primary socket to a remote address. When more
+ than one address is tried for a connection these will hold data
+ for the last attempt. When the connection is actually established
+ these are updated with data which comes directly from the socket. */
+
+ char primary_ip[MAX_IPADR_LEN];
+ long primary_port;
+
+ /* 'local_ip' and 'local_port' get filled with local's numerical
+ ip address and port number whenever an outgoing connection is
+ **established** from the primary socket to a remote address. */
+
+ char local_ip[MAX_IPADR_LEN];
+ long local_port;
+
+ char *user; /* user name string, allocated */
+ char *passwd; /* password string, allocated */
+ char *options; /* options string, allocated */
+
+ char *oauth_bearer; /* bearer token for OAuth 2.0, allocated */
+
+ int httpversion; /* the HTTP version*10 reported by the server */
+ int rtspversion; /* the RTSP version*10 reported by the server */
+
+ struct timeval now; /* "current" time */
+ struct timeval created; /* creation time */
+ curl_socket_t sock[2]; /* two sockets, the second is used for the data
+ transfer when doing FTP */
+ curl_socket_t tempsock[2]; /* temporary sockets for happy eyeballs */
+ bool sock_accepted[2]; /* TRUE if the socket on this index was created with
+ accept() */
+ Curl_recv *recv[2];
+ Curl_send *send[2];
+
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+ struct postponed_data postponed[2]; /* two buffers for two sockets */
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
+ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
+ struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */
+ struct ssl_primary_config ssl_config;
+ struct ssl_primary_config proxy_ssl_config;
+ bool tls_upgraded;
+
+ struct ConnectBits bits; /* various state-flags for this connection */
+
+ /* connecttime: when connect() is called on the current IP address. Used to
+ be able to track when to move on to try next IP - but only when the multi
+ interface is used. */
+ struct timeval connecttime;
+ /* The two fields below get set in Curl_connecthost */
+ int num_addr; /* number of addresses to try to connect to */
+ time_t timeoutms_per_addr; /* how long time in milliseconds to spend on
+ trying to connect to each IP address */
+
+ const struct Curl_handler *handler; /* Connection's protocol handler */
+ const struct Curl_handler *given; /* The protocol first given */
+
+ long ip_version; /* copied from the Curl_easy at creation time */
+
+ /**** curl_get() phase fields */
+
+ curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
+ curl_socket_t writesockfd; /* socket to write to, it may very
+ well be the same we read from.
+ CURL_SOCKET_BAD disables */
+
+ /** Dynamicly allocated strings, MUST be freed before this **/
+ /** struct is killed. **/
+ struct dynamically_allocated_data {
+ char *proxyuserpwd;
+ char *uagent;
+ char *accept_encoding;
+ char *userpwd;
+ char *rangeline;
+ char *ref;
+ char *host;
+ char *cookiehost;
+ char *rtsp_transport;
+ char *te; /* TE: request header */
+ } allocptr;
+
+#ifdef HAVE_GSSAPI
+ int sec_complete; /* if Kerberos is enabled for this connection */
+ enum protection_level command_prot;
+ enum protection_level data_prot;
+ enum protection_level request_data_prot;
+ size_t buffer_size;
+ struct krb5buffer in_buffer;
+ void *app_data;
+ const struct Curl_sec_client_mech *mech;
+ struct sockaddr_in local_addr;
+#endif
+
+#if defined(USE_KERBEROS5) /* Consider moving some of the above GSS-API */
+ struct kerberos5data krb5; /* variables into the structure definition, */
+#endif /* however, some of them are ftp specific. */
+
+ /* the two following *_inuse fields are only flags, not counters in any way.
+ If TRUE it means the channel is in use, and if FALSE it means the channel
+ is up for grabs by one. */
+
+ bool readchannel_inuse; /* whether the read channel is in use by an easy
+ handle */
+ bool writechannel_inuse; /* whether the write channel is in use by an easy
+ handle */
+ struct curl_llist send_pipe; /* List of handles waiting to send on this
+ pipeline */
+ struct curl_llist recv_pipe; /* List of handles waiting to read their
+ responses on this pipeline */
+ char *master_buffer; /* The master buffer allocated on-demand;
+ used for pipelining. */
+ size_t read_pos; /* Current read position in the master buffer */
+ size_t buf_len; /* Length of the buffer?? */
+
+
+ curl_seek_callback seek_func; /* function that seeks the input */
+ void *seek_client; /* pointer to pass to the seek() above */
+
+ /*************** Request - specific items ************/
+
+#if defined(USE_NTLM)
+ struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
+ because it authenticates connections, not
+ single requests! */
+ struct ntlmdata proxyntlm; /* NTLM data for proxy */
+
+#if defined(NTLM_WB_ENABLED)
+ /* used for communication with Samba's winbind daemon helper ntlm_auth */
+ curl_socket_t ntlm_auth_hlpr_socket;
+ pid_t ntlm_auth_hlpr_pid;
+ char *challenge_header;
+ char *response_header;
+#endif
+#endif
+
+ char syserr_buf [256]; /* buffer for Curl_strerror() */
+
+#ifdef CURLRES_ASYNCH
+ /* data used for the asynch name resolve callback */
+ struct Curl_async async;
+#endif
+
+ /* These three are used for chunked-encoding trailer support */
+ char *trailer; /* allocated buffer to store trailer in */
+ int trlMax; /* allocated buffer size */
+ int trlPos; /* index of where to store data */
+
+ union {
+ struct ftp_conn ftpc;
+ struct http_conn httpc;
+ struct ssh_conn sshc;
+ struct tftp_state_data *tftpc;
+ struct imap_conn imapc;
+ struct pop3_conn pop3c;
+ struct smtp_conn smtpc;
+ struct rtsp_conn rtspc;
+ struct smb_conn smbc;
+ void *generic; /* RTMP and LDAP use this */
+ } proto;
+
+ int cselect_bits; /* bitmask of socket events */
+ int waitfor; /* current READ/WRITE bits to wait for */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ int socks5_gssapi_enctype;
+#endif
+
+ /* When this connection is created, store the conditions for the local end
+ bind. This is stored before the actual bind and before any connection is
+ made and will serve the purpose of being used for comparison reasons so
+ that subsequent bound-requested connections aren't accidentally re-using
+ wrong connections. */
+ char *localdev;
+ unsigned short localport;
+ int localportrange;
+
+ /* tunnel as in tunnel through a HTTP proxy with CONNECT */
+ enum {
+ TUNNEL_INIT, /* init/default/no tunnel state */
+ TUNNEL_CONNECT, /* CONNECT has been sent off */
+ TUNNEL_COMPLETE /* CONNECT response received completely */
+ } tunnel_state[2]; /* two separate ones to allow FTP */
+ struct connectbundle *bundle; /* The bundle we are member of */
+
+ int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */
+ char *connect_buffer; /* for CONNECT business */
+
+#ifdef USE_UNIX_SOCKETS
+ char *unix_domain_socket;
+ bool abstract_unix_socket;
+#endif
+};
+
+/* The end of connectdata. */
+
+/*
+ * Struct to keep statistical and informational data.
+ * All variables in this struct must be initialized/reset in Curl_initinfo().
+ */
+struct PureInfo {
+ int httpcode; /* Recent HTTP, FTP, RTSP or SMTP response code */
+ int httpproxycode; /* response code from proxy when received separate */
+ int httpversion; /* the http version number X.Y = X*10+Y */
+ long filetime; /* If requested, this is might get set. Set to -1 if the time
+ was unretrievable. We cannot have this of type time_t,
+ since time_t is unsigned on several platforms such as
+ OpenVMS. */
+ bool timecond; /* set to TRUE if the time condition didn't match, which
+ thus made the document NOT get fetched */
+ long header_size; /* size of read header(s) in bytes */
+ long request_size; /* the amount of bytes sent in the request(s) */
+ unsigned long proxyauthavail; /* what proxy auth types were announced */
+ unsigned long httpauthavail; /* what host auth types were announced */
+ long numconnects; /* how many new connection did libcurl created */
+ char *contenttype; /* the content type of the object */
+ char *wouldredirect; /* URL this would've been redirected to if asked to */
+
+ /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
+ and, 'conn_local_port' are copied over from the connectdata struct in
+ order to allow curl_easy_getinfo() to return this information even when
+ the session handle is no longer associated with a connection, and also
+ allow curl_easy_reset() to clear this information from the session handle
+ without disturbing information which is still alive, and that might be
+ reused, in the connection cache. */
+
+ char conn_primary_ip[MAX_IPADR_LEN];
+ long conn_primary_port;
+
+ char conn_local_ip[MAX_IPADR_LEN];
+ long conn_local_port;
+
+ const char *conn_scheme;
+ unsigned int conn_protocol;
+
+ struct curl_certinfo certs; /* info about the certs, only populated in
+ OpenSSL builds. Asked for with
+ CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+};
+
+
+struct Progress {
+ time_t lastshow; /* time() of the last displayed progress meter or NULL to
+ force redraw at next call */
+ curl_off_t size_dl; /* total expected size */
+ curl_off_t size_ul; /* total expected size */
+ curl_off_t downloaded; /* transferred so far */
+ curl_off_t uploaded; /* transferred so far */
+
+ curl_off_t current_speed; /* uses the currently fastest transfer */
+
+ bool callback; /* set when progress callback is used */
+ int width; /* screen width at download start */
+ int flags; /* see progress.h */
+
+ double timespent;
+
+ curl_off_t dlspeed;
+ curl_off_t ulspeed;
+
+ double t_nslookup;
+ double t_connect;
+ double t_appconnect;
+ double t_pretransfer;
+ double t_starttransfer;
+ double t_redirect;
+
+ struct timeval start;
+ struct timeval t_startsingle;
+ struct timeval t_startop;
+ struct timeval t_acceptdata;
+
+ /* upload speed limit */
+ struct timeval ul_limit_start;
+ curl_off_t ul_limit_size;
+ /* download speed limit */
+ struct timeval dl_limit_start;
+ curl_off_t dl_limit_size;
+
+#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
+
+ curl_off_t speeder[ CURR_TIME ];
+ struct timeval speeder_time[ CURR_TIME ];
+ int speeder_c;
+};
+
+typedef enum {
+ HTTPREQ_NONE, /* first in list */
+ HTTPREQ_GET,
+ HTTPREQ_POST,
+ HTTPREQ_POST_FORM, /* we make a difference internally */
+ HTTPREQ_PUT,
+ HTTPREQ_HEAD,
+ HTTPREQ_CUSTOM,
+ HTTPREQ_LAST /* last in list */
+} Curl_HttpReq;
+
+typedef enum {
+ RTSPREQ_NONE, /* first in list */
+ RTSPREQ_OPTIONS,
+ RTSPREQ_DESCRIBE,
+ RTSPREQ_ANNOUNCE,
+ RTSPREQ_SETUP,
+ RTSPREQ_PLAY,
+ RTSPREQ_PAUSE,
+ RTSPREQ_TEARDOWN,
+ RTSPREQ_GET_PARAMETER,
+ RTSPREQ_SET_PARAMETER,
+ RTSPREQ_RECORD,
+ RTSPREQ_RECEIVE,
+ RTSPREQ_LAST /* last in list */
+} Curl_RtspReq;
+
+/*
+ * Values that are generated, temporary or calculated internally for a
+ * "session handle" must be defined within the 'struct UrlState'. This struct
+ * will be used within the Curl_easy struct. When the 'Curl_easy'
+ * struct is cloned, this data MUST NOT be copied.
+ *
+ * Remember that any "state" information goes globally for the curl handle.
+ * Session-data MUST be put in the connectdata struct and here. */
+#define MAX_CURL_USER_LENGTH 256
+#define MAX_CURL_PASSWORD_LENGTH 256
+
+struct auth {
+ unsigned long want; /* Bitmask set to the authentication methods wanted by
+ app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
+ unsigned long picked;
+ unsigned long avail; /* Bitmask for what the server reports to support for
+ this resource */
+ bool done; /* TRUE when the auth phase is done and ready to do the *actual*
+ request */
+ bool multipass; /* TRUE if this is not yet authenticated but within the
+ auth multipass negotiation */
+ bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should
+ be RFC compliant */
+};
+
+struct Curl_http2_dep {
+ struct Curl_http2_dep *next;
+ struct Curl_easy *data;
+};
+
+/*
+ * This struct is for holding data that was attemped to get sent to the user's
+ * callback but is held due to pausing. One instance per type (BOTH, HEADER,
+ * BODY).
+ */
+struct tempbuf {
+ char *buf; /* allocated buffer to keep data in when a write callback
+ returns to make the connection paused */
+ size_t len; /* size of the 'tempwrite' allocated buffer */
+ int type; /* type of the 'tempwrite' buffer as a bitmask that is used with
+ Curl_client_write() */
+};
+
+/* Timers */
+typedef enum {
+ EXPIRE_100_TIMEOUT,
+ EXPIRE_ASYNC_NAME,
+ EXPIRE_CONNECTTIMEOUT,
+ EXPIRE_DNS_PER_NAME,
+ EXPIRE_HAPPY_EYEBALLS,
+ EXPIRE_MULTI_PENDING,
+ EXPIRE_RUN_NOW,
+ EXPIRE_SPEEDCHECK,
+ EXPIRE_TIMEOUT,
+ EXPIRE_TOOFAST,
+ EXPIRE_LAST /* not an actual timer, used as a marker only */
+} expire_id;
+
+/*
+ * One instance for each timeout an easy handle can set.
+ */
+struct time_node {
+ struct curl_llist_element list;
+ struct timeval time;
+ expire_id eid;
+};
+
+struct UrlState {
+
+ /* Points to the connection cache */
+ struct conncache *conn_cache;
+
+ /* when curl_easy_perform() is called, the multi handle is "owned" by
+ the easy handle so curl_easy_cleanup() on such an easy handle will
+ also close the multi handle! */
+ bool multi_owned_by_easy;
+
+ /* buffers to store authentication data in, as parsed from input options */
+ struct timeval keeps_speed; /* for the progress meter really */
+
+ struct connectdata *lastconnect; /* The last connection, NULL if undefined */
+
+ char *headerbuff; /* allocated buffer to store headers in */
+ size_t headersize; /* size of the allocation */
+
+ char *buffer; /* download buffer */
+ char uploadbuffer[UPLOAD_BUFSIZE+1]; /* upload buffer */
+ curl_off_t current_speed; /* the ProgressShow() function sets this,
+ bytes / second */
+ bool this_is_a_follow; /* this is a followed Location: request */
+
+ char *first_host; /* host name of the first (not followed) request.
+ if set, this should be the host name that we will
+ sent authorization to, no else. Used to make Location:
+ following not keep sending user+password... This is
+ strdup() data.
+ */
+ int first_remote_port; /* remote port of the first (not followed) request */
+ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
+ long sessionage; /* number of the most recent session */
+ unsigned int tempcount; /* number of entries in use in tempwrite, 0 - 3 */
+ struct tempbuf tempwrite[3]; /* BOTH, HEADER, BODY */
+ char *scratch; /* huge buffer[set.buffer_size*2] for upload CRLF replacing */
+ bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
+ This must be set to FALSE every time _easy_perform() is
+ called. */
+ int os_errno; /* filled in with errno whenever an error occurs */
+#ifdef HAVE_SIGNAL
+ /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
+ void (*prev_signal)(int sig);
+#endif
+ bool allow_port; /* Is set.use_port allowed to take effect or not. This
+ is always set TRUE when curl_easy_perform() is called. */
+ struct digestdata digest; /* state data for host Digest auth */
+ struct digestdata proxydigest; /* state data for proxy Digest auth */
+
+#ifdef USE_SPNEGO
+ struct negotiatedata negotiate; /* state data for host Negotiate auth */
+ struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
+#endif
+
+ struct auth authhost; /* auth details for host */
+ struct auth authproxy; /* auth details for proxy */
+
+ bool authproblem; /* TRUE if there's some problem authenticating */
+
+ void *resolver; /* resolver state, if it is used in the URL state -
+ ares_channel f.e. */
+
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
+ ENGINE *engine;
+#endif /* USE_OPENSSL */
+ struct timeval expiretime; /* set this with Curl_expire() only */
+ struct Curl_tree timenode; /* for the splay stuff */
+ struct curl_llist timeoutlist; /* list of pending timeouts */
+ struct time_node expires[EXPIRE_LAST]; /* nodes for each expire type */
+
+ /* a place to store the most recently set FTP entrypath */
+ char *most_recent_ftp_entrypath;
+
+ /* set after initial USER failure, to prevent an authentication loop */
+ bool ftp_trying_alternative;
+
+ int httpversion; /* the lowest HTTP version*10 reported by any server
+ involved in this request */
+ bool expect100header; /* TRUE if we added Expect: 100-continue */
+
+ bool pipe_broke; /* TRUE if the connection we were pipelined on broke
+ and we need to restart from the beginning */
+
+#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \
+ !defined(__SYMBIAN32__)
+/* do FTP line-end conversions on most platforms */
+#define CURL_DO_LINEEND_CONV
+ /* for FTP downloads: track CRLF sequences that span blocks */
+ bool prev_block_had_trailing_cr;
+ /* for FTP downloads: how many CRLFs did we converted to LFs? */
+ curl_off_t crlf_conversions;
+#endif
+ char *pathbuffer;/* allocated buffer to store the URL's path part in */
+ char *path; /* path to use, points to somewhere within the pathbuffer
+ area */
+ bool slash_removed; /* set TRUE if the 'path' points to a path where the
+ initial URL slash separator has been taken off */
+ bool use_range;
+ bool rangestringalloc; /* the range string is malloc()'ed */
+
+ char *range; /* range, if used. See README for detailed specification on
+ this syntax. */
+ curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+ /* This RTSP state information survives requests and connections */
+ long rtsp_next_client_CSeq; /* the session's next client CSeq */
+ long rtsp_next_server_CSeq; /* the session's next server CSeq */
+ long rtsp_CSeq_recv; /* most recent CSeq received */
+
+ curl_off_t infilesize; /* size of file to upload, -1 means unknown.
+ Copied from set.filesize at start of operation */
+
+ size_t drain; /* Increased when this stream has data to read, even if its
+ socket is not necessarily is readable. Decreased when
+ checked. */
+ bool done; /* set to FALSE when Curl_init_do() is called and set to TRUE
+ when multi_done() is called, to prevent multi_done() to get
+ invoked twice when the multi interface is used. */
+
+ curl_read_callback fread_func; /* read callback/function */
+ void *in; /* CURLOPT_READDATA */
+
+ struct Curl_easy *stream_depends_on;
+ bool stream_depends_e; /* set or don't set the Exclusive bit */
+ int stream_weight;
+};
+
+
+/*
+ * This 'DynamicStatic' struct defines dynamic states that actually change
+ * values in the 'UserDefined' area, which MUST be taken into consideration
+ * if the UserDefined struct is cloned or similar. You can probably just
+ * copy these, but each one indicate a special action on other data.
+ */
+
+struct DynamicStatic {
+ char *url; /* work URL, copied from UserDefined */
+ bool url_alloc; /* URL string is malloc()'ed */
+ char *referer; /* referer string */
+ bool referer_alloc; /* referer sting is malloc()ed */
+ struct curl_slist *cookielist; /* list of cookie files set by
+ curl_easy_setopt(COOKIEFILE) calls */
+ struct curl_slist *resolve; /* set to point to the set.resolve list when
+ this should be dealt with in pretransfer */
+};
+
+/*
+ * This 'UserDefined' struct must only contain data that is set once to go
+ * for many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" MUST be defined within the
+ * 'struct UrlState' instead. The only exceptions MUST note the changes in
+ * the 'DynamicStatic' struct.
+ * Character pointer fields point to dynamic storage, unless otherwise stated.
+ */
+
+struct Curl_multi; /* declared and used only in multi.c */
+
+enum dupstring {
+ STRING_CERT_ORIG, /* client certificate file name */
+ STRING_CERT_PROXY, /* client certificate file name */
+ STRING_CERT_TYPE_ORIG, /* format for certificate (default: PEM)*/
+ STRING_CERT_TYPE_PROXY, /* format for certificate (default: PEM)*/
+ STRING_COOKIE, /* HTTP cookie string to send */
+ STRING_COOKIEJAR, /* dump all cookies to this file */
+ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */
+ STRING_DEFAULT_PROTOCOL, /* Protocol to use when the URL doesn't specify */
+ STRING_DEVICE, /* local network interface/address to use */
+ STRING_ENCODING, /* Accept-Encoding string */
+ STRING_FTP_ACCOUNT, /* ftp account data */
+ STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
+ STRING_FTPPORT, /* port to send with the FTP PORT command */
+ STRING_KEY_ORIG, /* private key file name */
+ STRING_KEY_PROXY, /* private key file name */
+ STRING_KEY_PASSWD_ORIG, /* plain text private key password */
+ STRING_KEY_PASSWD_PROXY, /* plain text private key password */
+ STRING_KEY_TYPE_ORIG, /* format for private key (default: PEM) */
+ STRING_KEY_TYPE_PROXY, /* format for private key (default: PEM) */
+ STRING_KRB_LEVEL, /* krb security level */
+ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
+ $HOME/.netrc */
+ STRING_PROXY, /* proxy to use */
+ STRING_PRE_PROXY, /* pre socks proxy to use */
+ STRING_SET_RANGE, /* range, if used */
+ STRING_SET_REFERER, /* custom string for the HTTP referer field */
+ STRING_SET_URL, /* what original URL to work on */
+ STRING_SSL_CAPATH_ORIG, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAPATH_PROXY, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAFILE_ORIG, /* certificate file to verify peer against */
+ STRING_SSL_CAFILE_PROXY, /* certificate file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY_ORIG, /* public key file to verify peer against */
+ STRING_SSL_PINNEDPUBLICKEY_PROXY, /* public key file to verify proxy */
+ STRING_SSL_CIPHER_LIST_ORIG, /* list of ciphers to use */
+ STRING_SSL_CIPHER_LIST_PROXY, /* list of ciphers to use */
+ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */
+ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
+ STRING_USERAGENT, /* User-Agent string */
+ STRING_SSL_CRLFILE_ORIG, /* crl file to check certificate */
+ STRING_SSL_CRLFILE_PROXY, /* crl file to check certificate */
+ STRING_SSL_ISSUERCERT_ORIG, /* issuer cert file to check certificate */
+ STRING_SSL_ISSUERCERT_PROXY, /* issuer cert file to check certificate */
+ STRING_USERNAME, /* <username>, if used */
+ STRING_PASSWORD, /* <password>, if used */
+ STRING_OPTIONS, /* <options>, if used */
+ STRING_PROXYUSERNAME, /* Proxy <username>, if used */
+ STRING_PROXYPASSWORD, /* Proxy <password>, if used */
+ STRING_NOPROXY, /* List of hosts which should not use the proxy, if
+ used */
+ STRING_RTSP_SESSION_ID, /* Session ID to use */
+ STRING_RTSP_STREAM_URI, /* Stream URI for this request */
+ STRING_RTSP_TRANSPORT, /* Transport for this session */
+#ifdef USE_LIBSSH2
+ STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
+ STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
+ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
+#endif
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ STRING_PROXY_SERVICE_NAME, /* Proxy service name */
+#endif
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_SPNEGO)
+ STRING_SERVICE_NAME, /* Service name */
+#endif
+ STRING_MAIL_FROM,
+ STRING_MAIL_AUTH,
+
+#ifdef USE_TLS_SRP
+ STRING_TLSAUTH_USERNAME_ORIG, /* TLS auth <username> */
+ STRING_TLSAUTH_USERNAME_PROXY, /* TLS auth <username> */
+ STRING_TLSAUTH_PASSWORD_ORIG, /* TLS auth <password> */
+ STRING_TLSAUTH_PASSWORD_PROXY, /* TLS auth <password> */
+#endif
+ STRING_BEARER, /* <bearer>, if used */
+#ifdef USE_UNIX_SOCKETS
+ STRING_UNIX_SOCKET_PATH, /* path to Unix socket, if used */
+#endif
+
+ /* -- end of zero-terminated strings -- */
+
+ STRING_LASTZEROTERMINATED,
+
+ /* -- below this are pointers to binary data that cannot be strdup'ed.
+ Each such pointer must be added manually to Curl_dupset() --- */
+
+ STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */
+
+ STRING_LAST /* not used, just an end-of-list marker */
+};
+
+struct UserDefined {
+ FILE *err; /* the stderr user data goes here */
+ void *debugdata; /* the data that will be passed to fdebug */
+ char *errorbuffer; /* (Static) store failure messages in here */
+ long proxyport; /* If non-zero, use this port number by default. If the
+ proxy string features a ":[port]" that one will override
+ this. */
+ void *out; /* CURLOPT_WRITEDATA */
+ void *in_set; /* CURLOPT_READDATA */
+ void *writeheader; /* write the header to this if non-NULL */
+ void *rtp_out; /* write RTP to this if non-NULL */
+ long use_port; /* which port to use (when not using default) */
+ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */
+ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */
+ long followlocation; /* as in HTTP Location: */
+ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
+ for infinity */
+
+ int keep_post; /* keep POSTs as POSTs after a 30x request; each
+ bit represents a request, from 301 to 303 */
+ bool free_referer; /* set TRUE if 'referer' points to a string we
+ allocated */
+ void *postfields; /* if POST, set the fields' values here */
+ curl_seek_callback seek_func; /* function that seeks the input */
+ curl_off_t postfieldsize; /* if POST, this might have a size to use instead
+ of strlen(), and then the data *may* be binary
+ (contain zero bytes) */
+ unsigned short localport; /* local port number to bind to */
+ int localportrange; /* number of additional port numbers to test in case the
+ 'localport' one can't be bind()ed */
+ curl_write_callback fwrite_func; /* function that stores the output */
+ curl_write_callback fwrite_header; /* function that stores headers */
+ curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */
+ curl_read_callback fread_func_set; /* function that reads the input */
+ int is_fread_set; /* boolean, has read callback been set to non-NULL? */
+ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
+ curl_progress_callback fprogress; /* OLD and deprecated progress callback */
+ curl_xferinfo_callback fxferinfo; /* progress callback */
+ curl_debug_callback fdebug; /* function that write informational data */
+ curl_ioctl_callback ioctl_func; /* function for I/O control */
+ curl_sockopt_callback fsockopt; /* function for setting socket options */
+ void *sockopt_client; /* pointer to pass to the socket options callback */
+ curl_opensocket_callback fopensocket; /* function for checking/translating
+ the address and opening the
+ socket */
+ void *opensocket_client;
+ curl_closesocket_callback fclosesocket; /* function for closing the
+ socket */
+ void *closesocket_client;
+
+ void *seek_client; /* pointer to pass to the seek callback */
+ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
+ /* function to convert from the network encoding: */
+ curl_conv_callback convfromnetwork;
+ /* function to convert to the network encoding: */
+ curl_conv_callback convtonetwork;
+ /* function to convert from UTF-8 encoding: */
+ curl_conv_callback convfromutf8;
+
+ void *progress_client; /* pointer to pass to the progress callback */
+ void *ioctl_client; /* pointer to pass to the ioctl callback */
+ long timeout; /* in milliseconds, 0 means no timeout */
+ long connecttimeout; /* in milliseconds, 0 means no timeout */
+ long accepttimeout; /* in milliseconds, 0 means no timeout */
+ long server_response_timeout; /* in milliseconds, 0 means no timeout */
+ long tftp_blksize; /* in bytes, 0 means use default */
+ bool tftp_no_options; /* do not send TFTP options requests */
+ curl_off_t filesize; /* size of file to upload, -1 means unknown */
+ long low_speed_limit; /* bytes/second */
+ long low_speed_time; /* number of seconds */
+ curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */
+ curl_off_t max_recv_speed; /* high speed limit in bytes/second for
+ download */
+ curl_off_t set_resume_from; /* continue [ftp] transfer from here */
+ struct curl_slist *headers; /* linked list of extra headers */
+ struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */
+ struct curl_httppost *httppost; /* linked list of POST data */
+ bool sep_headers; /* handle host and proxy headers separately */
+ bool cookiesession; /* new cookie session? */
+ bool crlf; /* convert crlf on ftp upload(?) */
+ struct curl_slist *quote; /* after connection is established */
+ struct curl_slist *postquote; /* after the transfer */
+ struct curl_slist *prequote; /* before the transfer, after type */
+ struct curl_slist *source_quote; /* 3rd party quote */
+ struct curl_slist *source_prequote; /* in 3rd party transfer mode - before
+ the transfer on source host */
+ struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
+ the transfer on source host */
+ struct curl_slist *telnet_options; /* linked list of telnet options */
+ struct curl_slist *resolve; /* list of names to add/remove from
+ DNS cache */
+ struct curl_slist *connect_to; /* list of host:port mappings to override
+ the hostname and port to connect to */
+ curl_TimeCond timecondition; /* kind of time/date comparison */
+ time_t timevalue; /* what time to compare with */
+ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
+ long httpversion; /* when non-zero, a specific HTTP version requested to
+ be used in the library's request(s) */
+ struct ssl_config_data ssl; /* user defined SSL stuff */
+ struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */
+ struct ssl_general_config general_ssl; /* general user defined SSL stuff */
+ curl_proxytype proxytype; /* what kind of proxy that is in use */
+ long dns_cache_timeout; /* DNS cache timeout */
+ long buffer_size; /* size of receive buffer to use */
+ void *private_data; /* application-private data */
+
+ struct curl_slist *http200aliases; /* linked list of aliases for http200 */
+
+ long ipver; /* the CURL_IPRESOLVE_* defines in the public header file
+ 0 - whatever, 1 - v2, 2 - v6 */
+
+ curl_off_t max_filesize; /* Maximum file size to download */
+
+ curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */
+
+ int ftp_create_missing_dirs; /* 1 - create directories that don't exist
+ 2 - the same but also allow MKD to fail once
+ */
+
+ curl_sshkeycallback ssh_keyfunc; /* key matching callback */
+ void *ssh_keyfunc_userp; /* custom pointer to callback */
+
+/* Here follows boolean settings that define how to behave during
+ this session. They are STATIC, set by libcurl users or at least initially
+ and they don't change during operations. */
+
+ bool printhost; /* printing host name in debug info */
+ bool get_filetime; /* get the time and get of the remote file */
+ bool tunnel_thru_httpproxy; /* use CONNECT through a HTTP proxy */
+ bool prefer_ascii; /* ASCII rather than binary */
+ bool ftp_append; /* append, not overwrite, on upload */
+ bool ftp_list_only; /* switch FTP command for listing directories */
+ bool ftp_use_port; /* use the FTP PORT command */
+ bool hide_progress; /* don't use the progress meter */
+ bool http_fail_on_error; /* fail on HTTP error codes >= 400 */
+ bool http_keep_sending_on_error; /* for HTTP status codes >= 300 */
+ bool http_follow_location; /* follow HTTP redirects */
+ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */
+ bool http_disable_hostname_check_before_authentication;
+ bool include_header; /* include received protocol headers in data output */
+ bool http_set_referer; /* is a custom referer used */
+ bool http_auto_referer; /* set "correct" referer when following location: */
+ bool opt_no_body; /* as set with CURLOPT_NOBODY */
+ bool upload; /* upload request */
+ enum CURL_NETRC_OPTION
+ use_netrc; /* defined in include/curl.h */
+ bool verbose; /* output verbosity */
+ bool krb; /* Kerberos connection requested */
+ bool reuse_forbid; /* forbidden to be reused, close after use */
+ bool reuse_fresh; /* do not re-use an existing connection */
+ bool ftp_use_epsv; /* if EPSV is to be attempted or not */
+ bool ftp_use_eprt; /* if EPRT is to be attempted or not */
+ bool ftp_use_pret; /* if PRET is to be used before PASV or not */
+
+ curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
+ IMAP or POP3 or others! */
+ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
+ curl_ftpccc ftp_ccc; /* FTP CCC options */
+ bool no_signal; /* do not use any signal/alarm handler */
+ bool global_dns_cache; /* subject for future removal */
+ bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */
+ bool ignorecl; /* ignore content length */
+ bool ftp_skip_ip; /* skip the IP address the FTP server passes on to
+ us */
+ bool connect_only; /* make connection, let application use the socket */
+ long ssh_auth_types; /* allowed SSH auth types */
+ bool http_te_skip; /* pass the raw body data to the user, even when
+ transfer-encoded (chunked, compressed) */
+ bool http_ce_skip; /* pass the raw body data to the user, even when
+ content-encoded (chunked, compressed) */
+ long new_file_perms; /* Permissions to use when creating remote files */
+ long new_directory_perms; /* Permissions to use when creating remote dirs */
+ bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP
+ via an HTTP proxy */
+ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
+ unsigned int scope_id; /* Scope id for IPv6 */
+ long allowed_protocols;
+ long redir_protocols;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ bool socks5_gssapi_nec; /* Flag to support NEC SOCKS5 server */
+#endif
+ struct curl_slist *mail_rcpt; /* linked list of mail recipients */
+ bool sasl_ir; /* Enable/disable SASL initial response */
+ /* Common RTSP header options */
+ Curl_RtspReq rtspreq; /* RTSP request type */
+ long rtspversion; /* like httpversion, for RTSP */
+ bool wildcardmatch; /* enable wildcard matching */
+ curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
+ starts */
+ curl_chunk_end_callback chunk_end; /* called after part transferring
+ stopped */
+ curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
+ to pattern (e.g. if WILDCARDMATCH is on) */
+ void *fnmatch_data;
+
+ long gssapi_delegation; /* GSS-API credential delegation, see the
+ documentation of CURLOPT_GSSAPI_DELEGATION */
+
+ bool tcp_keepalive; /* use TCP keepalives */
+ long tcp_keepidle; /* seconds in idle before sending keepalive probe */
+ long tcp_keepintvl; /* seconds between TCP keepalive probes */
+ bool tcp_fastopen; /* use TCP Fast Open */
+
+ size_t maxconnects; /* Max idle connections in the connection cache */
+
+ bool ssl_enable_npn; /* TLS NPN extension? */
+ bool ssl_enable_alpn; /* TLS ALPN extension? */
+ bool path_as_is; /* allow dotdots? */
+ bool pipewait; /* wait for pipe/multiplex status before starting a
+ new connection */
+ long expect_100_timeout; /* in milliseconds */
+ bool suppress_connect_headers; /* suppress proxy CONNECT response headers
+ from user callbacks */
+
+ struct Curl_easy *stream_depends_on;
+ bool stream_depends_e; /* set or don't set the Exclusive bit */
+ int stream_weight;
+
+ struct Curl_http2_dep *stream_dependents;
+
+ bool abstract_unix_socket;
+};
+
+struct Names {
+ struct curl_hash *hostcache;
+ enum {
+ HCACHE_NONE, /* not pointing to anything */
+ HCACHE_GLOBAL, /* points to the (shrug) global one */
+ HCACHE_MULTI, /* points to a shared one in the multi handle */
+ HCACHE_SHARED /* points to a shared one in a shared object */
+ } hostcachetype;
+};
+
+/*
+ * The 'connectdata' struct MUST have all the connection oriented stuff as we
+ * may have several simultaneous connections and connection structs in memory.
+ *
+ * The 'struct UserDefined' must only contain data that is set once to go for
+ * many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" must be defined within the
+ * 'struct UrlState' instead.
+ */
+
+struct Curl_easy {
+ /* first, two fields for the linked list of these */
+ struct Curl_easy *next;
+ struct Curl_easy *prev;
+
+ struct connectdata *easy_conn; /* the "unit's" connection */
+ struct curl_llist_element connect_queue;
+ struct curl_llist_element pipeline_queue;
+
+ CURLMstate mstate; /* the handle's state */
+ CURLcode result; /* previous result */
+
+ struct Curl_message msg; /* A single posted message. */
+
+ /* Array with the plain socket numbers this handle takes care of, in no
+ particular order. Note that all sockets are added to the sockhash, where
+ the state etc are also kept. This array is mostly used to detect when a
+ socket is to be removed from the hash. See singlesocket(). */
+ curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+ int numsocks;
+
+ struct Names dns;
+ struct Curl_multi *multi; /* if non-NULL, points to the multi handle
+ struct to which this "belongs" when used by
+ the multi interface */
+ struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle
+ struct to which this "belongs" when used
+ by the easy interface */
+ struct Curl_share *share; /* Share, handles global variable mutexing */
+ struct SingleRequest req; /* Request-specific data */
+ struct UserDefined set; /* values set by the libcurl user */
+ struct DynamicStatic change; /* possibly modified userdefined data */
+ struct CookieInfo *cookies; /* the cookies, read from files and servers.
+ NOTE that the 'cookie' field in the
+ UserDefined struct defines if the "engine"
+ is to be used or not. */
+ struct Progress progress; /* for all the progress meter data */
+ struct UrlState state; /* struct for fields used for state info and
+ other dynamic purposes */
+ struct WildcardData wildcard; /* wildcard download state info */
+ struct PureInfo info; /* stats, reports and info data */
+ struct curl_tlssessioninfo tsi; /* Information about the TLS session, only
+ valid after a client has asked for it */
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+ iconv_t outbound_cd; /* for translating to the network encoding */
+ iconv_t inbound_cd; /* for translating from the network encoding */
+ iconv_t utf8_cd; /* for translating to UTF8 */
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+ unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */
+};
+
+#define LIBCURL_NAME "libcurl"
+
+#endif /* HEADER_CURL_URLDATA_H */
diff --git a/Utilities/cmcurl/lib/vauth/cleartext.c b/Utilities/cmcurl/lib/vauth/cleartext.c
new file mode 100644
index 000000000..a761ae784
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/cleartext.c
@@ -0,0 +1,165 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC4616 PLAIN authentication
+ * Draft LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_plain_message()
+ *
+ * This is used to generate an already encoded PLAIN message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+ char *plainauth;
+ size_t ulen;
+ size_t plen;
+ size_t plainlen;
+
+ *outlen = 0;
+ *outptr = NULL;
+ ulen = strlen(userp);
+ plen = strlen(passwdp);
+
+ /* Compute binary message length, checking for overflows. */
+ plainlen = 2 * ulen;
+ if(plainlen < ulen)
+ return CURLE_OUT_OF_MEMORY;
+ plainlen += plen;
+ if(plainlen < plen)
+ return CURLE_OUT_OF_MEMORY;
+ plainlen += 2;
+ if(plainlen < 2)
+ return CURLE_OUT_OF_MEMORY;
+
+ plainauth = malloc(plainlen);
+ if(!plainauth)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Calculate the reply */
+ memcpy(plainauth, userp, ulen);
+ plainauth[ulen] = '\0';
+ memcpy(plainauth + ulen + 1, userp, ulen);
+ plainauth[2 * ulen + 1] = '\0';
+ memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
+
+ /* Base64 encode the reply */
+ result = Curl_base64_encode(data, plainauth, plainlen, outptr, outlen);
+ free(plainauth);
+
+ return result;
+}
+
+/*
+ * Curl_auth_create_login_message()
+ *
+ * This is used to generate an already encoded LOGIN message containing the
+ * user name or password ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * valuep [in] - The user name or user's password.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
+ const char *valuep, char **outptr,
+ size_t *outlen)
+{
+ size_t vlen = strlen(valuep);
+
+ if(!vlen) {
+ /* Calculate an empty reply */
+ *outptr = strdup("=");
+ if(*outptr) {
+ *outlen = (size_t) 1;
+ return CURLE_OK;
+ }
+
+ *outlen = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Base64 encode the value */
+ return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
+}
+
+/*
+ * Curl_auth_create_external_message()
+ *
+ * This is used to generate an already encoded EXTERNAL message containing
+ * the user name ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * user [in] - The user name.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
+ const char *user, char **outptr,
+ size_t *outlen)
+{
+ /* This is the same formatting as the login message */
+ return Curl_auth_create_login_message(data, user, outptr, outlen);
+}
diff --git a/Utilities/cmcurl/lib/vauth/cram.c b/Utilities/cmcurl/lib/vauth/cram.c
new file mode 100644
index 000000000..3074a163a
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/cram.c
@@ -0,0 +1,138 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_decode_cram_md5_message()
+ *
+ * This is used to decode an already encoded CRAM-MD5 challenge message.
+ *
+ * Parameters:
+ *
+ * chlg64 [in] - The base64 encoded challenge message.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
+ size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlg64len = strlen(chlg64);
+
+ *outptr = NULL;
+ *outlen = 0;
+
+ /* Decode the challenge if necessary */
+ if(chlg64len && *chlg64 != '=')
+ result = Curl_base64_decode(chlg64, (unsigned char **) outptr, outlen);
+
+ return result;
+}
+
+/*
+ * Curl_auth_create_cram_md5_message()
+ *
+ * This is used to generate an already encoded CRAM-MD5 response message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg [in] - The challenge.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
+ const char *chlg,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ HMAC_context *ctxt;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char *response;
+
+ if(chlg)
+ chlglen = strlen(chlg);
+
+ /* Compute the digest using the password as the key */
+ ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
+ (const unsigned char *) passwdp,
+ curlx_uztoui(strlen(passwdp)));
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Update the digest with the given challenge */
+ if(chlglen > 0)
+ Curl_HMAC_update(ctxt, (const unsigned char *) chlg,
+ curlx_uztoui(chlglen));
+
+ /* Finalise the digest */
+ Curl_HMAC_final(ctxt, digest);
+
+ /* Generate the response */
+ response = aprintf(
+ "%s %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+ userp, digest[0], digest[1], digest[2], digest[3], digest[4],
+ digest[5], digest[6], digest[7], digest[8], digest[9], digest[10],
+ digest[11], digest[12], digest[13], digest[14], digest[15]);
+ if(!response)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, response, 0, outptr, outlen);
+
+ free(response);
+
+ return result;
+}
+
+#endif /* !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/vauth/digest.c b/Utilities/cmcurl/lib/vauth/digest.c
new file mode 100644
index 000000000..185098ed6
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/digest.c
@@ -0,0 +1,893 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_hmac.h"
+#include "curl_md5.h"
+#include "vtls/vtls.h"
+#include "warnless.h"
+#include "strtok.h"
+#include "strcase.h"
+#include "non-ascii.h" /* included for Curl_convert_... prototypes */
+#include "curl_printf.h"
+#include "rand.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if !defined(USE_WINDOWS_SSPI)
+#define DIGEST_QOP_VALUE_AUTH (1 << 0)
+#define DIGEST_QOP_VALUE_AUTH_INT (1 << 1)
+#define DIGEST_QOP_VALUE_AUTH_CONF (1 << 2)
+
+#define DIGEST_QOP_VALUE_STRING_AUTH "auth"
+#define DIGEST_QOP_VALUE_STRING_AUTH_INT "auth-int"
+#define DIGEST_QOP_VALUE_STRING_AUTH_CONF "auth-conf"
+
+/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
+ It converts digest text to ASCII so the MD5 will be correct for
+ what ultimately goes over the network.
+*/
+#define CURL_OUTPUT_DIGEST_CONV(a, b) \
+ result = Curl_convert_to_network(a, (char *)b, strlen((const char *)b)); \
+ if(result) { \
+ free(b); \
+ return result; \
+ }
+#endif /* !USE_WINDOWS_SSPI */
+
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+ const char **endptr)
+{
+ int c;
+ bool starts_with_quote = FALSE;
+ bool escape = FALSE;
+
+ for(c = DIGEST_MAX_VALUE_LENGTH - 1; (*str && (*str != '=') && c--);)
+ *value++ = *str++;
+ *value = 0;
+
+ if('=' != *str++)
+ /* eek, no match */
+ return FALSE;
+
+ if('\"' == *str) {
+ /* This starts with a quote so it must end with one as well! */
+ str++;
+ starts_with_quote = TRUE;
+ }
+
+ for(c = DIGEST_MAX_CONTENT_LENGTH - 1; *str && c--; str++) {
+ switch(*str) {
+ case '\\':
+ if(!escape) {
+ /* possibly the start of an escaped quote */
+ escape = TRUE;
+ *content++ = '\\'; /* Even though this is an escape character, we still
+ store it as-is in the target buffer */
+ continue;
+ }
+ break;
+
+ case ',':
+ if(!starts_with_quote) {
+ /* This signals the end of the content if we didn't get a starting
+ quote and then we do "sloppy" parsing */
+ c = 0; /* the end */
+ continue;
+ }
+ break;
+
+ case '\r':
+ case '\n':
+ /* end of string */
+ c = 0;
+ continue;
+
+ case '\"':
+ if(!escape && starts_with_quote) {
+ /* end of string */
+ c = 0;
+ continue;
+ }
+ break;
+ }
+
+ escape = FALSE;
+ *content++ = *str;
+ }
+
+ *content = 0;
+ *endptr = str;
+
+ return TRUE;
+}
+
+#if !defined(USE_WINDOWS_SSPI)
+/* Convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+static void auth_digest_md5_to_ascii(unsigned char *source, /* 16 bytes */
+ unsigned char *dest) /* 33 bytes */
+{
+ int i;
+ for(i = 0; i < 16; i++)
+ snprintf((char *) &dest[i * 2], 3, "%02x", source[i]);
+}
+
+/* Perform quoted-string escaping as described in RFC2616 and its errata */
+static char *auth_digest_string_quoted(const char *source)
+{
+ char *dest, *d;
+ const char *s = source;
+ size_t n = 1; /* null terminator */
+
+ /* Calculate size needed */
+ while(*s) {
+ ++n;
+ if(*s == '"' || *s == '\\') {
+ ++n;
+ }
+ ++s;
+ }
+
+ dest = malloc(n);
+ if(dest) {
+ s = source;
+ d = dest;
+ while(*s) {
+ if(*s == '"' || *s == '\\') {
+ *d++ = '\\';
+ }
+ *d++ = *s++;
+ }
+ *d = 0;
+ }
+
+ return dest;
+}
+
+/* Retrieves the value for a corresponding key from the challenge string
+ * returns TRUE if the key could be found, FALSE if it does not exists
+ */
+static bool auth_digest_get_key_value(const char *chlg,
+ const char *key,
+ char *value,
+ size_t max_val_len,
+ char end_char)
+{
+ char *find_pos;
+ size_t i;
+
+ find_pos = strstr(chlg, key);
+ if(!find_pos)
+ return FALSE;
+
+ find_pos += strlen(key);
+
+ for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
+ value[i] = *find_pos++;
+ value[i] = '\0';
+
+ return TRUE;
+}
+
+static CURLcode auth_digest_get_qop_values(const char *options, int *value)
+{
+ char *tmp;
+ char *token;
+ char *tok_buf = NULL;
+
+ /* Initialise the output */
+ *value = 0;
+
+ /* Tokenise the list of qop values. Use a temporary clone of the buffer since
+ strtok_r() ruins it. */
+ tmp = strdup(options);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ token = strtok_r(tmp, ",", &tok_buf);
+ while(token != NULL) {
+ if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH))
+ *value |= DIGEST_QOP_VALUE_AUTH;
+ else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT))
+ *value |= DIGEST_QOP_VALUE_AUTH_INT;
+ else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_CONF))
+ *value |= DIGEST_QOP_VALUE_AUTH_CONF;
+
+ token = strtok_r(NULL, ",", &tok_buf);
+ }
+
+ free(tmp);
+
+ return CURLE_OK;
+}
+
+/*
+ * auth_decode_digest_md5_message()
+ *
+ * This is used internally to decode an already encoded DIGEST-MD5 challenge
+ * message into the separate attributes.
+ *
+ * Parameters:
+ *
+ * chlg64 [in] - The base64 encoded challenge message.
+ * nonce [in/out] - The buffer where the nonce will be stored.
+ * nlen [in] - The length of the nonce buffer.
+ * realm [in/out] - The buffer where the realm will be stored.
+ * rlen [in] - The length of the realm buffer.
+ * alg [in/out] - The buffer where the algorithm will be stored.
+ * alen [in] - The length of the algorithm buffer.
+ * qop [in/out] - The buffer where the qop-options will be stored.
+ * qlen [in] - The length of the qop buffer.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode auth_decode_digest_md5_message(const char *chlg64,
+ char *nonce, size_t nlen,
+ char *realm, size_t rlen,
+ char *alg, size_t alen,
+ char *qop, size_t qlen)
+{
+ CURLcode result = CURLE_OK;
+ unsigned char *chlg = NULL;
+ size_t chlglen = 0;
+ size_t chlg64len = strlen(chlg64);
+
+ /* Decode the base-64 encoded challenge message */
+ if(chlg64len && *chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* Retrieve nonce string from the challenge */
+ if(!auth_digest_get_key_value((char *) chlg, "nonce=\"", nonce, nlen,
+ '\"')) {
+ free(chlg);
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Retrieve realm string from the challenge */
+ if(!auth_digest_get_key_value((char *) chlg, "realm=\"", realm, rlen,
+ '\"')) {
+ /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
+ strcpy(realm, "");
+ }
+
+ /* Retrieve algorithm string from the challenge */
+ if(!auth_digest_get_key_value((char *) chlg, "algorithm=", alg, alen, ',')) {
+ free(chlg);
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Retrieve qop-options string from the challenge */
+ if(!auth_digest_get_key_value((char *) chlg, "qop=\"", qop, qlen, '\"')) {
+ free(chlg);
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ free(chlg);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_is_digest_supported()
+ *
+ * This is used to evaluate if DIGEST is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE as DIGEST as handled by libcurl.
+ */
+bool Curl_auth_is_digest_supported(void)
+{
+ return TRUE;
+}
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - The base64 encoded challenge message.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+ const char *chlg64,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t i;
+ MD5_context *ctxt;
+ char *response = NULL;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char HA1_hex[2 * MD5_DIGEST_LEN + 1];
+ char HA2_hex[2 * MD5_DIGEST_LEN + 1];
+ char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
+ char nonce[64];
+ char realm[128];
+ char algorithm[64];
+ char qop_options[64];
+ int qop_values;
+ char cnonce[33];
+ char nonceCount[] = "00000001";
+ char method[] = "AUTHENTICATE";
+ char qop[] = DIGEST_QOP_VALUE_STRING_AUTH;
+ char *spn = NULL;
+
+ /* Decode the challenge message */
+ result = auth_decode_digest_md5_message(chlg64, nonce, sizeof(nonce),
+ realm, sizeof(realm),
+ algorithm, sizeof(algorithm),
+ qop_options, sizeof(qop_options));
+ if(result)
+ return result;
+
+ /* We only support md5 sessions */
+ if(strcmp(algorithm, "md5-sess") != 0)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* Get the qop-values from the qop-options */
+ result = auth_digest_get_qop_values(qop_options, &qop_values);
+ if(result)
+ return result;
+
+ /* We only support auth quality-of-protection */
+ if(!(qop_values & DIGEST_QOP_VALUE_AUTH))
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* Generate 32 random hex chars, 32 bytes + 1 zero termination */
+ result = Curl_rand_hex(data, (unsigned char *)cnonce, sizeof(cnonce));
+ if(result)
+ return result;
+
+ /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) userp,
+ curlx_uztoui(strlen(userp)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) realm,
+ curlx_uztoui(strlen(realm)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
+ curlx_uztoui(strlen(passwdp)));
+ Curl_MD5_final(ctxt, digest);
+
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+ curlx_uztoui(strlen(nonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+ curlx_uztoui(strlen(cnonce)));
+ Curl_MD5_final(ctxt, digest);
+
+ /* Convert calculated 16 octet hex into 32 bytes string */
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
+
+ /* Generate our SPN */
+ spn = Curl_auth_build_spn(service, realm, NULL);
+ if(!spn)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Calculate H(A2) */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt) {
+ free(spn);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_MD5_update(ctxt, (const unsigned char *) method,
+ curlx_uztoui(strlen(method)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) spn,
+ curlx_uztoui(strlen(spn)));
+ Curl_MD5_final(ctxt, digest);
+
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
+
+ /* Now calculate the response hash */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt) {
+ free(spn);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+ curlx_uztoui(strlen(nonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+ Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
+ curlx_uztoui(strlen(nonceCount)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+ curlx_uztoui(strlen(cnonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) qop,
+ curlx_uztoui(strlen(qop)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+ Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
+ Curl_MD5_final(ctxt, digest);
+
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
+
+ /* Generate the response */
+ response = aprintf("username=\"%s\",realm=\"%s\",nonce=\"%s\","
+ "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s,"
+ "qop=%s",
+ userp, realm, nonce,
+ cnonce, nonceCount, spn, resp_hash_hex, qop);
+ free(spn);
+ if(!response)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, response, 0, outptr, outlen);
+
+ free(response);
+
+ return result;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode a HTTP DIGEST challenge message into the separate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg [in] - The challenge message.
+ * digest [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+ struct digestdata *digest)
+{
+ bool before = FALSE; /* got a nonce before */
+ bool foundAuth = FALSE;
+ bool foundAuthInt = FALSE;
+ char *token = NULL;
+ char *tmp = NULL;
+
+ /* If we already have received a nonce, keep that in mind */
+ if(digest->nonce)
+ before = TRUE;
+
+ /* Clean up any former leftovers and initialise to defaults */
+ Curl_auth_digest_cleanup(digest);
+
+ for(;;) {
+ char value[DIGEST_MAX_VALUE_LENGTH];
+ char content[DIGEST_MAX_CONTENT_LENGTH];
+
+ /* Pass all additional spaces here */
+ while(*chlg && ISSPACE(*chlg))
+ chlg++;
+
+ /* Extract a value=content pair */
+ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+ if(strcasecompare(value, "nonce")) {
+ free(digest->nonce);
+ digest->nonce = strdup(content);
+ if(!digest->nonce)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(strcasecompare(value, "stale")) {
+ if(strcasecompare(content, "true")) {
+ digest->stale = TRUE;
+ digest->nc = 1; /* we make a new nonce now */
+ }
+ }
+ else if(strcasecompare(value, "realm")) {
+ free(digest->realm);
+ digest->realm = strdup(content);
+ if(!digest->realm)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(strcasecompare(value, "opaque")) {
+ free(digest->opaque);
+ digest->opaque = strdup(content);
+ if(!digest->opaque)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(strcasecompare(value, "qop")) {
+ char *tok_buf = NULL;
+ /* Tokenize the list and choose auth if possible, use a temporary
+ clone of the buffer since strtok_r() ruins it */
+ tmp = strdup(content);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ token = strtok_r(tmp, ",", &tok_buf);
+ while(token != NULL) {
+ if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH)) {
+ foundAuth = TRUE;
+ }
+ else if(strcasecompare(token, DIGEST_QOP_VALUE_STRING_AUTH_INT)) {
+ foundAuthInt = TRUE;
+ }
+ token = strtok_r(NULL, ",", &tok_buf);
+ }
+
+ free(tmp);
+
+ /* Select only auth or auth-int. Otherwise, ignore */
+ if(foundAuth) {
+ free(digest->qop);
+ digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH);
+ if(!digest->qop)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(foundAuthInt) {
+ free(digest->qop);
+ digest->qop = strdup(DIGEST_QOP_VALUE_STRING_AUTH_INT);
+ if(!digest->qop)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else if(strcasecompare(value, "algorithm")) {
+ free(digest->algorithm);
+ digest->algorithm = strdup(content);
+ if(!digest->algorithm)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(strcasecompare(content, "MD5-sess"))
+ digest->algo = CURLDIGESTALGO_MD5SESS;
+ else if(strcasecompare(content, "MD5"))
+ digest->algo = CURLDIGESTALGO_MD5;
+ else
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+ else {
+ /* Unknown specifier, ignore it! */
+ }
+ }
+ else
+ break; /* We're done here */
+
+ /* Pass all additional spaces here */
+ while(*chlg && ISSPACE(*chlg))
+ chlg++;
+
+ /* Allow the list to be comma-separated */
+ if(',' == *chlg)
+ chlg++;
+ }
+
+ /* We had a nonce since before, and we got another one now without
+ 'stale=true'. This means we provided bad credentials in the previous
+ request */
+ if(before && !digest->stale)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* We got this header without a nonce, that's a bad Digest line! */
+ if(!digest->nonce)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate a HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * request [in] - The HTTP request.
+ * uripath [in] - The path of the HTTP uri.
+ * digest [in/out] - The digest data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+ unsigned char md5buf[16]; /* 16 bytes/128 bits */
+ unsigned char request_digest[33];
+ unsigned char *md5this;
+ unsigned char ha1[33]; /* 32 digits and 1 zero byte */
+ unsigned char ha2[33]; /* 32 digits and 1 zero byte */
+ char cnoncebuf[33];
+ char *cnonce = NULL;
+ size_t cnonce_sz = 0;
+ char *userp_quoted;
+ char *response = NULL;
+ char *tmp = NULL;
+
+ if(!digest->nc)
+ digest->nc = 1;
+
+ if(!digest->cnonce) {
+ result = Curl_rand_hex(data, (unsigned char *)cnoncebuf,
+ sizeof(cnoncebuf));
+ if(result)
+ return result;
+
+ result = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf),
+ &cnonce, &cnonce_sz);
+ if(result)
+ return result;
+
+ digest->cnonce = cnonce;
+ }
+
+ /*
+ If the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+ A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+ If the algorithm is "MD5-sess" then:
+
+ A1 = H(unq(username-value) ":" unq(realm-value) ":" passwd) ":"
+ unq(nonce-value) ":" unq(cnonce-value)
+ */
+
+ md5this = (unsigned char *)
+ aprintf("%s:%s:%s", userp, digest->realm, passwdp);
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ free(md5this);
+ auth_digest_md5_to_ascii(md5buf, ha1);
+
+ if(digest->algo == CURLDIGESTALGO_MD5SESS) {
+ /* nonce and cnonce are OUTSIDE the hash */
+ tmp = aprintf("%s:%s:%s", ha1, digest->nonce, digest->cnonce);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, tmp); /* Convert on non-ASCII machines */
+ Curl_md5it(md5buf, (unsigned char *) tmp);
+ free(tmp);
+ auth_digest_md5_to_ascii(md5buf, ha1);
+ }
+
+ /*
+ If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+ A2 = Method ":" digest-uri-value
+
+ If the "qop" value is "auth-int", then A2 is:
+
+ A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+ (The "Method" value is the HTTP request method as specified in section
+ 5.1.1 of RFC 2616)
+ */
+
+ md5this = (unsigned char *) aprintf("%s:%s", request, uripath);
+
+ if(digest->qop && strcasecompare(digest->qop, "auth-int")) {
+ /* We don't support auth-int for PUT or POST at the moment.
+ TODO: replace md5 of empty string with entity-body for PUT/POST */
+ unsigned char *md5this2 = (unsigned char *)
+ aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e");
+ free(md5this);
+ md5this = md5this2;
+ }
+
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ free(md5this);
+ auth_digest_md5_to_ascii(md5buf, ha2);
+
+ if(digest->qop) {
+ md5this = (unsigned char *) aprintf("%s:%s:%08x:%s:%s:%s",
+ ha1,
+ digest->nonce,
+ digest->nc,
+ digest->cnonce,
+ digest->qop,
+ ha2);
+ }
+ else {
+ md5this = (unsigned char *) aprintf("%s:%s:%s",
+ ha1,
+ digest->nonce,
+ ha2);
+ }
+
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ free(md5this);
+ auth_digest_md5_to_ascii(md5buf, request_digest);
+
+ /* For test case 64 (snooped from a Mozilla 1.3a request)
+
+ Authorization: Digest username="testuser", realm="testrealm", \
+ nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca"
+
+ Digest parameters are all quoted strings. Username which is provided by
+ the user will need double quotes and backslashes within it escaped. For
+ the other fields, this shouldn't be an issue. realm, nonce, and opaque
+ are copied as is from the server, escapes and all. cnonce is generated
+ with web-safe characters. uri is already percent encoded. nc is 8 hex
+ characters. algorithm and qop with standard values only contain web-safe
+ characters.
+ */
+ userp_quoted = auth_digest_string_quoted(userp);
+ if(!userp_quoted)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(digest->qop) {
+ response = aprintf("username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "cnonce=\"%s\", "
+ "nc=%08x, "
+ "qop=%s, "
+ "response=\"%s\"",
+ userp_quoted,
+ digest->realm,
+ digest->nonce,
+ uripath,
+ digest->cnonce,
+ digest->nc,
+ digest->qop,
+ request_digest);
+
+ if(strcasecompare(digest->qop, "auth"))
+ digest->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0
+ padded which tells to the server how many times you are
+ using the same nonce in the qop=auth mode */
+ }
+ else {
+ response = aprintf("username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "response=\"%s\"",
+ userp_quoted,
+ digest->realm,
+ digest->nonce,
+ uripath,
+ request_digest);
+ }
+ free(userp_quoted);
+ if(!response)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Add the optional fields */
+ if(digest->opaque) {
+ /* Append the opaque */
+ tmp = aprintf("%s, opaque=\"%s\"", response, digest->opaque);
+ free(response);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ response = tmp;
+ }
+
+ if(digest->algorithm) {
+ /* Append the algorithm */
+ tmp = aprintf("%s, algorithm=\"%s\"", response, digest->algorithm);
+ free(response);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+
+ response = tmp;
+ }
+
+ /* Return the output */
+ *outptr = response;
+ *outlen = strlen(response);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+ Curl_safefree(digest->nonce);
+ Curl_safefree(digest->cnonce);
+ Curl_safefree(digest->realm);
+ Curl_safefree(digest->opaque);
+ Curl_safefree(digest->qop);
+ Curl_safefree(digest->algorithm);
+
+ digest->nc = 0;
+ digest->algo = CURLDIGESTALGO_MD5; /* default algorithm */
+ digest->stale = FALSE; /* default means normal, not stale */
+}
+#endif /* !USE_WINDOWS_SSPI */
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/vauth/digest.h b/Utilities/cmcurl/lib/vauth/digest.h
new file mode 100644
index 000000000..5722dcece
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/digest.h
@@ -0,0 +1,43 @@
+#ifndef HEADER_CURL_DIGEST_H
+#define HEADER_CURL_DIGEST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#define DIGEST_MAX_VALUE_LENGTH 256
+#define DIGEST_MAX_CONTENT_LENGTH 1024
+
+enum {
+ CURLDIGESTALGO_MD5,
+ CURLDIGESTALGO_MD5SESS
+};
+
+/* This is used to extract the realm from a challenge message */
+bool Curl_auth_digest_get_pair(const char *str, char *value, char *content,
+ const char **endptr);
+
+#endif
+
+#endif /* HEADER_CURL_DIGEST_H */
diff --git a/Utilities/cmcurl/lib/vauth/digest_sspi.c b/Utilities/cmcurl/lib/vauth/digest_sspi.c
new file mode 100644
index 000000000..0bd94442d
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/digest_sspi.c
@@ -0,0 +1,628 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC2831 DIGEST-MD5 authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strdup.h"
+#include "strcase.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+* Curl_auth_is_digest_supported()
+*
+* This is used to evaluate if DIGEST is supported.
+*
+* Parameters: None
+*
+* Returns TRUE if DIGEST is supported by Windows SSPI.
+*/
+bool Curl_auth_is_digest_supported(void)
+{
+ PSecPkgInfo SecurityPackage;
+ SECURITY_STATUS status;
+
+ /* Query the security package for Digest */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
+
+ return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - The base64 encoded challenge message.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+ const char *chlg64,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ TCHAR *spn = NULL;
+ size_t chlglen = 0;
+ size_t token_max = 0;
+ unsigned char *input_token = NULL;
+ unsigned char *output_token = NULL;
+ CredHandle credentials;
+ CtxtHandle context;
+ PSecPkgInfo SecurityPackage;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ SecBuffer chlg_buf;
+ SecBuffer resp_buf;
+ SecBufferDesc chlg_desc;
+ SecBufferDesc resp_desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+ /* Decode the base-64 encoded challenge message */
+ if(strlen(chlg64) && *chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &input_token, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!input_token) {
+ infof(data, "DIGEST-MD5 handshake failure (empty challenge message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Query the security package for DigestSSP */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
+ if(status != SEC_E_OK) {
+ free(input_token);
+
+ return CURLE_NOT_BUILT_IN;
+ }
+
+ token_max = SecurityPackage->cbMaxToken;
+
+ /* Release the package buffer as it is not required anymore */
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+ /* Allocate our response buffer */
+ output_token = malloc(token_max);
+ if(!output_token) {
+ free(input_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Generate our SPN */
+ spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL);
+ if(!spn) {
+ free(output_token);
+ free(input_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(userp && *userp) {
+ /* Populate our identity structure */
+ result = Curl_create_sspi_identity(userp, passwdp, &identity);
+ if(result) {
+ free(spn);
+ free(output_token);
+ free(input_token);
+
+ return result;
+ }
+
+ /* Allow proper cleanup of the identity structure */
+ p_identity = &identity;
+ }
+ else
+ /* Use the current Windows user */
+ p_identity = NULL;
+
+ /* Acquire our credentials handle */
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT(SP_NAME_DIGEST),
+ SECPKG_CRED_OUTBOUND, NULL,
+ p_identity, NULL, NULL,
+ &credentials, &expiry);
+
+ if(status != SEC_E_OK) {
+ Curl_sspi_free_identity(p_identity);
+ free(spn);
+ free(output_token);
+ free(input_token);
+
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 1;
+ chlg_desc.pBuffers = &chlg_buf;
+ chlg_buf.BufferType = SECBUFFER_TOKEN;
+ chlg_buf.pvBuffer = input_token;
+ chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+
+ /* Setup the response "output" security buffer */
+ resp_desc.ulVersion = SECBUFFER_VERSION;
+ resp_desc.cBuffers = 1;
+ resp_desc.pBuffers = &resp_buf;
+ resp_buf.BufferType = SECBUFFER_TOKEN;
+ resp_buf.pvBuffer = output_token;
+ resp_buf.cbBuffer = curlx_uztoul(token_max);
+
+ /* Generate our response message */
+ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL, spn,
+ 0, 0, 0, &chlg_desc, 0,
+ &context, &resp_desc, &attrs,
+ &expiry);
+
+ if(status == SEC_I_COMPLETE_NEEDED ||
+ status == SEC_I_COMPLETE_AND_CONTINUE)
+ s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+ else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+ s_pSecFn->FreeCredentialsHandle(&credentials);
+ Curl_sspi_free_identity(p_identity);
+ free(spn);
+ free(output_token);
+ free(input_token);
+
+ return CURLE_RECV_ERROR;
+ }
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) output_token, resp_buf.cbBuffer,
+ outptr, outlen);
+
+ /* Free our handles */
+ s_pSecFn->DeleteSecurityContext(&context);
+ s_pSecFn->FreeCredentialsHandle(&credentials);
+
+ /* Free the identity structure */
+ Curl_sspi_free_identity(p_identity);
+
+ /* Free the SPN */
+ free(spn);
+
+ /* Free the response buffer */
+ free(output_token);
+
+ /* Free the decoded challenge message */
+ free(input_token);
+
+ return result;
+}
+
+/*
+ * Curl_override_sspi_http_realm()
+ *
+ * This is used to populate the domain in a SSPI identity structure
+ * The realm is extracted from the challenge message and used as the
+ * domain if it is not already explicitly set.
+ *
+ * Parameters:
+ *
+ * chlg [in] - The challenge message.
+ * identity [in/out] - The identity structure.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_override_sspi_http_realm(const char *chlg,
+ SEC_WINNT_AUTH_IDENTITY *identity)
+{
+ xcharp_u domain, dup_domain;
+
+ /* If domain is blank or unset, check challenge message for realm */
+ if(!identity->Domain || !identity->DomainLength) {
+ for(;;) {
+ char value[DIGEST_MAX_VALUE_LENGTH];
+ char content[DIGEST_MAX_CONTENT_LENGTH];
+
+ /* Pass all additional spaces here */
+ while(*chlg && ISSPACE(*chlg))
+ chlg++;
+
+ /* Extract a value=content pair */
+ if(Curl_auth_digest_get_pair(chlg, value, content, &chlg)) {
+ if(strcasecompare(value, "realm")) {
+
+ /* Setup identity's domain and length */
+ domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content);
+ if(!domain.tchar_ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
+ if(!dup_domain.tchar_ptr) {
+ Curl_unicodefree(domain.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ free(identity->Domain);
+ identity->Domain = dup_domain.tbyte_ptr;
+ identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
+ dup_domain.tchar_ptr = NULL;
+
+ Curl_unicodefree(domain.tchar_ptr);
+ }
+ else {
+ /* Unknown specifier, ignore it! */
+ }
+ }
+ else
+ break; /* We're done here */
+
+ /* Pass all additional spaces here */
+ while(*chlg && ISSPACE(*chlg))
+ chlg++;
+
+ /* Allow the list to be comma-separated */
+ if(',' == *chlg)
+ chlg++;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_decode_digest_http_message()
+ *
+ * This is used to decode a HTTP DIGEST challenge message into the separate
+ * attributes.
+ *
+ * Parameters:
+ *
+ * chlg [in] - The challenge message.
+ * digest [in/out] - The digest data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+ struct digestdata *digest)
+{
+ size_t chlglen = strlen(chlg);
+
+ /* We had an input token before so if there's another one now that means we
+ provided bad credentials in the previous request or it's stale. */
+ if(digest->input_token) {
+ bool stale = false;
+ const char *p = chlg;
+
+ /* Check for the 'stale' directive */
+ for(;;) {
+ char value[DIGEST_MAX_VALUE_LENGTH];
+ char content[DIGEST_MAX_CONTENT_LENGTH];
+
+ while(*p && ISSPACE(*p))
+ p++;
+
+ if(!Curl_auth_digest_get_pair(p, value, content, &p))
+ break;
+
+ if(Curl_strcasecompare(value, "stale")
+ && Curl_strcasecompare(content, "true")) {
+ stale = true;
+ break;
+ }
+
+ while(*p && ISSPACE(*p))
+ p++;
+
+ if(',' == *p)
+ p++;
+ }
+
+ if(stale)
+ Curl_auth_digest_cleanup(digest);
+ else
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Store the challenge for use later */
+ digest->input_token = (BYTE *) Curl_memdup(chlg, chlglen + 1);
+ if(!digest->input_token)
+ return CURLE_OUT_OF_MEMORY;
+
+ digest->input_token_len = chlglen;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_digest_http_message()
+ *
+ * This is used to generate a HTTP DIGEST response message ready for sending
+ * to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * request [in] - The HTTP request.
+ * uripath [in] - The path of the HTTP uri.
+ * digest [in/out] - The digest data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uripath,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen)
+{
+ size_t token_max;
+ char *resp;
+ BYTE *output_token;
+ size_t output_token_len = 0;
+ PSecPkgInfo SecurityPackage;
+ SecBuffer chlg_buf[5];
+ SecBufferDesc chlg_desc;
+ SECURITY_STATUS status;
+
+ (void) data;
+
+ /* Query the security package for DigestSSP */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
+ &SecurityPackage);
+ if(status != SEC_E_OK)
+ return CURLE_NOT_BUILT_IN;
+
+ token_max = SecurityPackage->cbMaxToken;
+
+ /* Release the package buffer as it is not required anymore */
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+ /* Allocate the output buffer according to the max token size as indicated
+ by the security package */
+ output_token = malloc(token_max);
+ if(!output_token) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(digest->http_context) {
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 5;
+ chlg_desc.pBuffers = chlg_buf;
+ chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+ chlg_buf[0].pvBuffer = NULL;
+ chlg_buf[0].cbBuffer = 0;
+ chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+ chlg_buf[1].pvBuffer = (void *) request;
+ chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request));
+ chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+ chlg_buf[2].pvBuffer = (void *) uripath;
+ chlg_buf[2].cbBuffer = curlx_uztoul(strlen((const char *) uripath));
+ chlg_buf[3].BufferType = SECBUFFER_PKG_PARAMS;
+ chlg_buf[3].pvBuffer = NULL;
+ chlg_buf[3].cbBuffer = 0;
+ chlg_buf[4].BufferType = SECBUFFER_PADDING;
+ chlg_buf[4].pvBuffer = output_token;
+ chlg_buf[4].cbBuffer = curlx_uztoul(token_max);
+
+ status = s_pSecFn->MakeSignature(digest->http_context, 0, &chlg_desc, 0);
+ if(status == SEC_E_OK)
+ output_token_len = chlg_buf[4].cbBuffer;
+ else { /* delete the context so a new one can be made */
+ infof(data, "digest_sspi: MakeSignature failed, error 0x%08lx\n",
+ (long)status);
+ s_pSecFn->DeleteSecurityContext(digest->http_context);
+ Curl_safefree(digest->http_context);
+ }
+ }
+
+ if(!digest->http_context) {
+ CredHandle credentials;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ SecBuffer resp_buf;
+ SecBufferDesc resp_desc;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+ TCHAR *spn;
+
+ if(userp && *userp) {
+ /* Populate our identity structure */
+ if(Curl_create_sspi_identity(userp, passwdp, &identity)) {
+ free(output_token);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Populate our identity domain */
+ if(Curl_override_sspi_http_realm((const char *) digest->input_token,
+ &identity)) {
+ free(output_token);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allow proper cleanup of the identity structure */
+ p_identity = &identity;
+ }
+ else
+ /* Use the current Windows user */
+ p_identity = NULL;
+
+ /* Acquire our credentials handle */
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT(SP_NAME_DIGEST),
+ SECPKG_CRED_OUTBOUND, NULL,
+ p_identity, NULL, NULL,
+ &credentials, &expiry);
+ if(status != SEC_E_OK) {
+ Curl_sspi_free_identity(p_identity);
+ free(output_token);
+
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Setup the challenge "input" security buffer if present */
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 3;
+ chlg_desc.pBuffers = chlg_buf;
+ chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+ chlg_buf[0].pvBuffer = digest->input_token;
+ chlg_buf[0].cbBuffer = curlx_uztoul(digest->input_token_len);
+ chlg_buf[1].BufferType = SECBUFFER_PKG_PARAMS;
+ chlg_buf[1].pvBuffer = (void *) request;
+ chlg_buf[1].cbBuffer = curlx_uztoul(strlen((const char *) request));
+ chlg_buf[2].BufferType = SECBUFFER_PKG_PARAMS;
+ chlg_buf[2].pvBuffer = NULL;
+ chlg_buf[2].cbBuffer = 0;
+
+ /* Setup the response "output" security buffer */
+ resp_desc.ulVersion = SECBUFFER_VERSION;
+ resp_desc.cBuffers = 1;
+ resp_desc.pBuffers = &resp_buf;
+ resp_buf.BufferType = SECBUFFER_TOKEN;
+ resp_buf.pvBuffer = output_token;
+ resp_buf.cbBuffer = curlx_uztoul(token_max);
+
+ spn = Curl_convert_UTF8_to_tchar((char *) uripath);
+ if(!spn) {
+ s_pSecFn->FreeCredentialsHandle(&credentials);
+
+ Curl_sspi_free_identity(p_identity);
+ free(output_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allocate our new context handle */
+ digest->http_context = calloc(1, sizeof(CtxtHandle));
+ if(!digest->http_context)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Generate our response message */
+ status = s_pSecFn->InitializeSecurityContext(&credentials, NULL,
+ spn,
+ ISC_REQ_USE_HTTP_STYLE, 0, 0,
+ &chlg_desc, 0,
+ digest->http_context,
+ &resp_desc, &attrs, &expiry);
+ Curl_unicodefree(spn);
+
+ if(status == SEC_I_COMPLETE_NEEDED ||
+ status == SEC_I_COMPLETE_AND_CONTINUE)
+ s_pSecFn->CompleteAuthToken(&credentials, &resp_desc);
+ else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+ s_pSecFn->FreeCredentialsHandle(&credentials);
+
+ Curl_sspi_free_identity(p_identity);
+ free(output_token);
+
+ Curl_safefree(digest->http_context);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ output_token_len = resp_buf.cbBuffer;
+
+ s_pSecFn->FreeCredentialsHandle(&credentials);
+ Curl_sspi_free_identity(p_identity);
+ }
+
+ resp = malloc(output_token_len + 1);
+ if(!resp) {
+ free(output_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Copy the generated response */
+ memcpy(resp, output_token, output_token_len);
+ resp[output_token_len] = 0;
+
+ /* Return the response */
+ *outptr = resp;
+ *outlen = output_token_len;
+
+ /* Free the response buffer */
+ free(output_token);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_digest_cleanup()
+ *
+ * This is used to clean up the digest specific data.
+ *
+ * Parameters:
+ *
+ * digest [in/out] - The digest data struct being cleaned up.
+ *
+ */
+void Curl_auth_digest_cleanup(struct digestdata *digest)
+{
+ /* Free the input token */
+ Curl_safefree(digest->input_token);
+
+ /* Reset any variables */
+ digest->input_token_len = 0;
+
+ /* Delete security context */
+ if(digest->http_context) {
+ s_pSecFn->DeleteSecurityContext(digest->http_context);
+ Curl_safefree(digest->http_context);
+ }
+}
+
+#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */
diff --git a/Utilities/cmcurl/lib/vauth/krb5_gssapi.c b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
new file mode 100644
index 000000000..560ecc5bc
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/krb5_gssapi.c
@@ -0,0 +1,401 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && defined(USE_KERBEROS5)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "curl_sasl.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_gssapi.h"
+#include "sendf.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_gssapi_supported()
+ *
+ * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Kerberos V5 is supported by the GSS-API library.
+ */
+bool Curl_auth_is_gssapi_supported(void)
+{
+ return TRUE;
+}
+
+/*
+ * Curl_auth_create_gssapi_user_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * host [in[ - The host name.
+ * mutual_auth [in] - Flag specifying whether or not mutual authentication
+ * is enabled.
+ * chlg64 [in] - Pointer to the optional base64 encoded challenge
+ * message.
+ * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ const char *host,
+ const bool mutual_auth,
+ const char *chlg64,
+ struct kerberos5data *krb5,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ unsigned char *chlg = NULL;
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ OM_uint32 unused_status;
+ gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+ (void) userp;
+ (void) passwdp;
+
+ if(!krb5->spn) {
+ /* Generate our SPN */
+ char *spn = Curl_auth_build_spn(service, NULL, host);
+ if(!spn)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Populate the SPN structure */
+ spn_token.value = spn;
+ spn_token.length = strlen(spn);
+
+ /* Import the SPN */
+ major_status = gss_import_name(&minor_status, &spn_token,
+ GSS_C_NT_HOSTBASED_SERVICE, &krb5->spn);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_import_name() failed: ",
+ major_status, minor_status);
+
+ free(spn);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ free(spn);
+ }
+
+ if(chlg64 && *chlg64) {
+ /* Decode the base-64 encoded challenge message */
+ if(*chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "GSSAPI handshake failure (empty challenge message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ input_token.value = chlg;
+ input_token.length = chlglen;
+ }
+
+ major_status = Curl_gss_init_sec_context(data,
+ &minor_status,
+ &krb5->context,
+ krb5->spn,
+ &Curl_krb5_mech_oid,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ &output_token,
+ mutual_auth,
+ NULL);
+
+ /* Free the decoded challenge as it is not required anymore */
+ free(input_token.value);
+
+ if(GSS_ERROR(major_status)) {
+ if(output_token.value)
+ gss_release_buffer(&unused_status, &output_token);
+
+ Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+ major_status, minor_status);
+
+ return CURLE_RECV_ERROR;
+ }
+
+ if(output_token.value && output_token.length) {
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) output_token.value,
+ output_token.length, outptr, outlen);
+
+ gss_release_buffer(&unused_status, &output_token);
+ }
+ else if(mutual_auth) {
+ *outptr = strdup("");
+ if(!*outptr)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+/*
+ * Curl_auth_create_gssapi_security_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) security
+ * token message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - Pointer to the optional base64 encoded challenge message.
+ * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+ const char *chlg64,
+ struct kerberos5data *krb5,
+ char **outptr,
+ size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ size_t messagelen = 0;
+ unsigned char *chlg = NULL;
+ unsigned char *message = NULL;
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ OM_uint32 unused_status;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ unsigned int indata = 0;
+ unsigned int outdata = 0;
+ gss_qop_t qop = GSS_C_QOP_DEFAULT;
+ unsigned int sec_layer = 0;
+ unsigned int max_size = 0;
+ gss_name_t username = GSS_C_NO_NAME;
+ gss_buffer_desc username_token;
+
+ /* Decode the base-64 encoded input message */
+ if(strlen(chlg64) && *chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "GSSAPI handshake failure (empty security message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Get the fully qualified username back from the context */
+ major_status = gss_inquire_context(&minor_status, krb5->context,
+ &username, NULL, NULL, NULL, NULL,
+ NULL, NULL);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_inquire_context() failed: ",
+ major_status, minor_status);
+
+ free(chlg);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Convert the username from internal format to a displayable token */
+ major_status = gss_display_name(&minor_status, username,
+ &username_token, NULL);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_display_name() failed: ",
+ major_status, minor_status);
+
+ free(chlg);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ input_token.value = chlg;
+ input_token.length = chlglen;
+
+ /* Decrypt the inbound challenge and obtain the qop */
+ major_status = gss_unwrap(&minor_status, krb5->context, &input_token,
+ &output_token, NULL, &qop);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_unwrap() failed: ",
+ major_status, minor_status);
+
+ gss_release_buffer(&unused_status, &username_token);
+ free(chlg);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
+ if(output_token.length != 4) {
+ infof(data, "GSSAPI handshake failure (invalid security data)\n");
+
+ gss_release_buffer(&unused_status, &username_token);
+ free(chlg);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Copy the data out and free the challenge as it is not required anymore */
+ memcpy(&indata, output_token.value, 4);
+ gss_release_buffer(&unused_status, &output_token);
+ free(chlg);
+
+ /* Extract the security layer */
+ sec_layer = indata & 0x000000FF;
+ if(!(sec_layer & GSSAUTH_P_NONE)) {
+ infof(data, "GSSAPI handshake failure (invalid security layer)\n");
+
+ gss_release_buffer(&unused_status, &username_token);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Extract the maximum message size the server can receive */
+ max_size = ntohl(indata & 0xFFFFFF00);
+ if(max_size > 0) {
+ /* The server has told us it supports a maximum receive buffer, however, as
+ we don't require one unless we are encrypting data, we tell the server
+ our receive buffer is zero. */
+ max_size = 0;
+ }
+
+ /* Allocate our message */
+ messagelen = sizeof(outdata) + username_token.length + 1;
+ message = malloc(messagelen);
+ if(!message) {
+ gss_release_buffer(&unused_status, &username_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Populate the message with the security layer, client supported receive
+ message size and authorization identity including the 0x00 based
+ terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization
+ identity is not terminated with the zero-valued (%x00) octet." it seems
+ necessary to include it. */
+ outdata = htonl(max_size) | sec_layer;
+ memcpy(message, &outdata, sizeof(outdata));
+ memcpy(message + sizeof(outdata), username_token.value,
+ username_token.length);
+ message[messagelen - 1] = '\0';
+
+ /* Free the username token as it is not required anymore */
+ gss_release_buffer(&unused_status, &username_token);
+
+ /* Setup the "authentication data" security buffer */
+ input_token.value = message;
+ input_token.length = messagelen;
+
+ /* Encrypt the data */
+ major_status = gss_wrap(&minor_status, krb5->context, 0,
+ GSS_C_QOP_DEFAULT, &input_token, NULL,
+ &output_token);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_wrap() failed: ",
+ major_status, minor_status);
+
+ free(message);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) output_token.value,
+ output_token.length, outptr, outlen);
+
+ /* Free the output buffer */
+ gss_release_buffer(&unused_status, &output_token);
+
+ /* Free the message buffer */
+ free(message);
+
+ return result;
+}
+
+/*
+ * Curl_auth_gssapi_cleanup()
+ *
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
+ *
+ * Parameters:
+ *
+ * krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
+ *
+ */
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
+{
+ OM_uint32 minor_status;
+
+ /* Free our security context */
+ if(krb5->context != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(&minor_status, &krb5->context, GSS_C_NO_BUFFER);
+ krb5->context = GSS_C_NO_CONTEXT;
+ }
+
+ /* Free the SPN */
+ if(krb5->spn != GSS_C_NO_NAME) {
+ gss_release_name(&minor_status, &krb5->spn);
+ krb5->spn = GSS_C_NO_NAME;
+ }
+}
+
+#endif /* HAVE_GSSAPI && USE_KERBEROS5 */
diff --git a/Utilities/cmcurl/lib/vauth/krb5_sspi.c b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
new file mode 100644
index 000000000..1b4cef486
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/krb5_sspi.c
@@ -0,0 +1,518 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC4752 The Kerberos V5 ("GSSAPI") SASL Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_KERBEROS5)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_gssapi_supported()
+ *
+ * This is used to evaluate if GSSAPI (Kerberos V5) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Kerberos V5 is supported by Windows SSPI.
+ */
+bool Curl_auth_is_gssapi_supported(void)
+{
+ PSecPkgInfo SecurityPackage;
+ SECURITY_STATUS status;
+
+ /* Query the security package for Kerberos */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ TEXT(SP_NAME_KERBEROS),
+ &SecurityPackage);
+
+ return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_gssapi_user_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) user token
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * host [in] - The host name.
+ * mutual_auth [in] - Flag specifying whether or not mutual authentication
+ * is enabled.
+ * chlg64 [in] - The optional base64 encoded challenge message.
+ * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ const char *host,
+ const bool mutual_auth,
+ const char *chlg64,
+ struct kerberos5data *krb5,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ unsigned char *chlg = NULL;
+ CtxtHandle context;
+ PSecPkgInfo SecurityPackage;
+ SecBuffer chlg_buf;
+ SecBuffer resp_buf;
+ SecBufferDesc chlg_desc;
+ SecBufferDesc resp_desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+ if(!krb5->spn) {
+ /* Generate our SPN */
+ krb5->spn = Curl_auth_build_spn(service, host, NULL);
+ if(!krb5->spn)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!krb5->output_token) {
+ /* Query the security package for Kerberos */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ TEXT(SP_NAME_KERBEROS),
+ &SecurityPackage);
+ if(status != SEC_E_OK) {
+ return CURLE_NOT_BUILT_IN;
+ }
+
+ krb5->token_max = SecurityPackage->cbMaxToken;
+
+ /* Release the package buffer as it is not required anymore */
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+ /* Allocate our response buffer */
+ krb5->output_token = malloc(krb5->token_max);
+ if(!krb5->output_token)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!krb5->credentials) {
+ /* Do we have credientials to use or are we using single sign-on? */
+ if(userp && *userp) {
+ /* Populate our identity structure */
+ result = Curl_create_sspi_identity(userp, passwdp, &krb5->identity);
+ if(result)
+ return result;
+
+ /* Allow proper cleanup of the identity structure */
+ krb5->p_identity = &krb5->identity;
+ }
+ else
+ /* Use the current Windows user */
+ krb5->p_identity = NULL;
+
+ /* Allocate our credentials handle */
+ krb5->credentials = malloc(sizeof(CredHandle));
+ if(!krb5->credentials)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(krb5->credentials, 0, sizeof(CredHandle));
+
+ /* Acquire our credentials handle */
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *)
+ TEXT(SP_NAME_KERBEROS),
+ SECPKG_CRED_OUTBOUND, NULL,
+ krb5->p_identity, NULL, NULL,
+ krb5->credentials, &expiry);
+ if(status != SEC_E_OK)
+ return CURLE_LOGIN_DENIED;
+
+ /* Allocate our new context handle */
+ krb5->context = malloc(sizeof(CtxtHandle));
+ if(!krb5->context)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(krb5->context, 0, sizeof(CtxtHandle));
+ }
+
+ if(chlg64 && *chlg64) {
+ /* Decode the base-64 encoded challenge message */
+ if(*chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "GSSAPI handshake failure (empty challenge message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 1;
+ chlg_desc.pBuffers = &chlg_buf;
+ chlg_buf.BufferType = SECBUFFER_TOKEN;
+ chlg_buf.pvBuffer = chlg;
+ chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ }
+
+ /* Setup the response "output" security buffer */
+ resp_desc.ulVersion = SECBUFFER_VERSION;
+ resp_desc.cBuffers = 1;
+ resp_desc.pBuffers = &resp_buf;
+ resp_buf.BufferType = SECBUFFER_TOKEN;
+ resp_buf.pvBuffer = krb5->output_token;
+ resp_buf.cbBuffer = curlx_uztoul(krb5->token_max);
+
+ /* Generate our challenge-response message */
+ status = s_pSecFn->InitializeSecurityContext(krb5->credentials,
+ chlg ? krb5->context : NULL,
+ krb5->spn,
+ (mutual_auth ?
+ ISC_REQ_MUTUAL_AUTH : 0),
+ 0, SECURITY_NATIVE_DREP,
+ chlg ? &chlg_desc : NULL, 0,
+ &context,
+ &resp_desc, &attrs,
+ &expiry);
+
+ /* Free the decoded challenge as it is not required anymore */
+ free(chlg);
+
+ if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) {
+ return CURLE_RECV_ERROR;
+ }
+
+ if(memcmp(&context, krb5->context, sizeof(context))) {
+ s_pSecFn->DeleteSecurityContext(krb5->context);
+
+ memcpy(krb5->context, &context, sizeof(context));
+ }
+
+ if(resp_buf.cbBuffer) {
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) resp_buf.pvBuffer,
+ resp_buf.cbBuffer, outptr, outlen);
+ }
+ else if(mutual_auth) {
+ *outptr = strdup("");
+ if(!*outptr)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+/*
+ * Curl_auth_create_gssapi_security_message()
+ *
+ * This is used to generate an already encoded GSSAPI (Kerberos V5) security
+ * token message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - The optional base64 encoded challenge message.
+ * krb5 [in/out] - The Kerberos 5 data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+ const char *chlg64,
+ struct kerberos5data *krb5,
+ char **outptr,
+ size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t offset = 0;
+ size_t chlglen = 0;
+ size_t messagelen = 0;
+ size_t appdatalen = 0;
+ unsigned char *chlg = NULL;
+ unsigned char *trailer = NULL;
+ unsigned char *message = NULL;
+ unsigned char *padding = NULL;
+ unsigned char *appdata = NULL;
+ SecBuffer input_buf[2];
+ SecBuffer wrap_buf[3];
+ SecBufferDesc input_desc;
+ SecBufferDesc wrap_desc;
+ unsigned long indata = 0;
+ unsigned long outdata = 0;
+ unsigned long qop = 0;
+ unsigned long sec_layer = 0;
+ unsigned long max_size = 0;
+ SecPkgContext_Sizes sizes;
+ SecPkgCredentials_Names names;
+ SECURITY_STATUS status;
+ char *user_name;
+
+ /* Decode the base-64 encoded input message */
+ if(strlen(chlg64) && *chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "GSSAPI handshake failure (empty security message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Get our response size information */
+ status = s_pSecFn->QueryContextAttributes(krb5->context,
+ SECPKG_ATTR_SIZES,
+ &sizes);
+ if(status != SEC_E_OK) {
+ free(chlg);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Get the fully qualified username back from the context */
+ status = s_pSecFn->QueryCredentialsAttributes(krb5->credentials,
+ SECPKG_CRED_ATTR_NAMES,
+ &names);
+ if(status != SEC_E_OK) {
+ free(chlg);
+
+ return CURLE_RECV_ERROR;
+ }
+
+ /* Setup the "input" security buffer */
+ input_desc.ulVersion = SECBUFFER_VERSION;
+ input_desc.cBuffers = 2;
+ input_desc.pBuffers = input_buf;
+ input_buf[0].BufferType = SECBUFFER_STREAM;
+ input_buf[0].pvBuffer = chlg;
+ input_buf[0].cbBuffer = curlx_uztoul(chlglen);
+ input_buf[1].BufferType = SECBUFFER_DATA;
+ input_buf[1].pvBuffer = NULL;
+ input_buf[1].cbBuffer = 0;
+
+ /* Decrypt the inbound challenge and obtain the qop */
+ status = s_pSecFn->DecryptMessage(krb5->context, &input_desc, 0, &qop);
+ if(status != SEC_E_OK) {
+ infof(data, "GSSAPI handshake failure (empty security message)\n");
+
+ free(chlg);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Not 4 octets long so fail as per RFC4752 Section 3.1 */
+ if(input_buf[1].cbBuffer != 4) {
+ infof(data, "GSSAPI handshake failure (invalid security data)\n");
+
+ free(chlg);
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Copy the data out and free the challenge as it is not required anymore */
+ memcpy(&indata, input_buf[1].pvBuffer, 4);
+ s_pSecFn->FreeContextBuffer(input_buf[1].pvBuffer);
+ free(chlg);
+
+ /* Extract the security layer */
+ sec_layer = indata & 0x000000FF;
+ if(!(sec_layer & KERB_WRAP_NO_ENCRYPT)) {
+ infof(data, "GSSAPI handshake failure (invalid security layer)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Extract the maximum message size the server can receive */
+ max_size = ntohl(indata & 0xFFFFFF00);
+ if(max_size > 0) {
+ /* The server has told us it supports a maximum receive buffer, however, as
+ we don't require one unless we are encrypting data, we tell the server
+ our receive buffer is zero. */
+ max_size = 0;
+ }
+
+ /* Allocate the trailer */
+ trailer = malloc(sizes.cbSecurityTrailer);
+ if(!trailer)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Convert the user name to UTF8 when operating with Unicode */
+ user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
+ if(!user_name) {
+ free(trailer);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allocate our message */
+ messagelen = sizeof(outdata) + strlen(user_name) + 1;
+ message = malloc(messagelen);
+ if(!message) {
+ free(trailer);
+ Curl_unicodefree(user_name);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Populate the message with the security layer, client supported receive
+ message size and authorization identity including the 0x00 based
+ terminator. Note: Despite RFC4752 Section 3.1 stating "The authorization
+ identity is not terminated with the zero-valued (%x00) octet." it seems
+ necessary to include it. */
+ outdata = htonl(max_size) | sec_layer;
+ memcpy(message, &outdata, sizeof(outdata));
+ strcpy((char *) message + sizeof(outdata), user_name);
+ Curl_unicodefree(user_name);
+
+ /* Allocate the padding */
+ padding = malloc(sizes.cbBlockSize);
+ if(!padding) {
+ free(message);
+ free(trailer);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Setup the "authentication data" security buffer */
+ wrap_desc.ulVersion = SECBUFFER_VERSION;
+ wrap_desc.cBuffers = 3;
+ wrap_desc.pBuffers = wrap_buf;
+ wrap_buf[0].BufferType = SECBUFFER_TOKEN;
+ wrap_buf[0].pvBuffer = trailer;
+ wrap_buf[0].cbBuffer = sizes.cbSecurityTrailer;
+ wrap_buf[1].BufferType = SECBUFFER_DATA;
+ wrap_buf[1].pvBuffer = message;
+ wrap_buf[1].cbBuffer = curlx_uztoul(messagelen);
+ wrap_buf[2].BufferType = SECBUFFER_PADDING;
+ wrap_buf[2].pvBuffer = padding;
+ wrap_buf[2].cbBuffer = sizes.cbBlockSize;
+
+ /* Encrypt the data */
+ status = s_pSecFn->EncryptMessage(krb5->context, KERB_WRAP_NO_ENCRYPT,
+ &wrap_desc, 0);
+ if(status != SEC_E_OK) {
+ free(padding);
+ free(message);
+ free(trailer);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allocate the encryption (wrap) buffer */
+ appdatalen = wrap_buf[0].cbBuffer + wrap_buf[1].cbBuffer +
+ wrap_buf[2].cbBuffer;
+ appdata = malloc(appdatalen);
+ if(!appdata) {
+ free(padding);
+ free(message);
+ free(trailer);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Populate the encryption buffer */
+ memcpy(appdata, wrap_buf[0].pvBuffer, wrap_buf[0].cbBuffer);
+ offset += wrap_buf[0].cbBuffer;
+ memcpy(appdata + offset, wrap_buf[1].pvBuffer, wrap_buf[1].cbBuffer);
+ offset += wrap_buf[1].cbBuffer;
+ memcpy(appdata + offset, wrap_buf[2].pvBuffer, wrap_buf[2].cbBuffer);
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) appdata, appdatalen, outptr,
+ outlen);
+
+ /* Free all of our local buffers */
+ free(appdata);
+ free(padding);
+ free(message);
+ free(trailer);
+
+ return result;
+}
+
+/*
+ * Curl_auth_gssapi_cleanup()
+ *
+ * This is used to clean up the GSSAPI (Kerberos V5) specific data.
+ *
+ * Parameters:
+ *
+ * krb5 [in/out] - The Kerberos 5 data struct being cleaned up.
+ *
+ */
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5)
+{
+ /* Free our security context */
+ if(krb5->context) {
+ s_pSecFn->DeleteSecurityContext(krb5->context);
+ free(krb5->context);
+ krb5->context = NULL;
+ }
+
+ /* Free our credentials handle */
+ if(krb5->credentials) {
+ s_pSecFn->FreeCredentialsHandle(krb5->credentials);
+ free(krb5->credentials);
+ krb5->credentials = NULL;
+ }
+
+ /* Free our identity */
+ Curl_sspi_free_identity(krb5->p_identity);
+ krb5->p_identity = NULL;
+
+ /* Free the SPN and output token */
+ Curl_safefree(krb5->spn);
+ Curl_safefree(krb5->output_token);
+
+ /* Reset any variables */
+ krb5->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_KERBEROS5*/
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.c b/Utilities/cmcurl/lib/vauth/ntlm.c
new file mode 100644
index 000000000..42196455f
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/ntlm.c
@@ -0,0 +1,856 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
+
+/*
+ * NTLM details:
+ *
+ * https://davenport.sourceforge.io/ntlm.html
+ * https://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "non-ascii.h"
+#include "sendf.h"
+#include "curl_base64.h"
+#include "curl_ntlm_core.h"
+#include "curl_gethostname.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "rand.h"
+#include "vtls/vtls.h"
+
+#ifdef USE_NSS
+#include "vtls/nssg.h" /* for Curl_nss_force_init() */
+#endif
+
+#define BUILDING_CURL_NTLM_MSGS_C
+#include "vauth/vauth.h"
+#include "vauth/ntlm.h"
+#include "curl_endian.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* "NTLMSSP" signature is always in ASCII regardless of the platform */
+#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+
+#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
+ (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+static void ntlm_print_flags(FILE *handle, unsigned long flags)
+{
+ if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
+ if(flags & NTLMFLAG_NEGOTIATE_OEM)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
+ if(flags & NTLMFLAG_REQUEST_TARGET)
+ fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
+ if(flags & (1<<3))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
+ if(flags & NTLMFLAG_NEGOTIATE_SIGN)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
+ if(flags & NTLMFLAG_NEGOTIATE_SEAL)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
+ if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
+ if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
+ if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
+ if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
+ if(flags & (1<<10))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
+ if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
+ if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
+ if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
+ if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
+ if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
+ if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
+ if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
+ if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
+ if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
+ if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
+ fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
+ if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
+ fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
+ if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
+ fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
+ if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
+ if(flags & (1<<24))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
+ if(flags & (1<<25))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
+ if(flags & (1<<26))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
+ if(flags & (1<<27))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
+ if(flags & (1<<28))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
+ if(flags & NTLMFLAG_NEGOTIATE_128)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
+ if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
+ if(flags & NTLMFLAG_NEGOTIATE_56)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
+}
+
+static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
+{
+ const char *p = buf;
+
+ (void) handle;
+
+ fprintf(stderr, "0x");
+ while(len-- > 0)
+ fprintf(stderr, "%02.2x", (unsigned int)*p++);
+}
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/*
+ * ntlm_decode_type2_target()
+ *
+ * This is used to decode the "target info" in the NTLM type-2 message
+ * received.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * buffer [in] - The decoded type-2 message.
+ * size [in] - The input buffer size, at least 32 bytes.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
+ unsigned char *buffer,
+ size_t size,
+ struct ntlmdata *ntlm)
+{
+ unsigned short target_info_len = 0;
+ unsigned int target_info_offset = 0;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
+
+ if(size >= 48) {
+ target_info_len = Curl_read16_le(&buffer[40]);
+ target_info_offset = Curl_read32_le(&buffer[44]);
+ if(target_info_len > 0) {
+ if(((target_info_offset + target_info_len) > size) ||
+ (target_info_offset < 48)) {
+ infof(data, "NTLM handshake failure (bad type-2 message). "
+ "Target Info Offset Len is set incorrect by the peer\n");
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ ntlm->target_info = malloc(target_info_len);
+ if(!ntlm->target_info)
+ return CURLE_OUT_OF_MEMORY;
+
+ memcpy(ntlm->target_info, &buffer[target_info_offset], target_info_len);
+ }
+ }
+
+ ntlm->target_info_len = target_info_len;
+
+ return CURLE_OK;
+}
+
+/*
+ NTLM message structure notes:
+
+ A 'short' is a 'network short', a little-endian 16-bit unsigned value.
+
+ A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
+
+ A 'security buffer' represents a triplet used to point to a buffer,
+ consisting of two shorts and one long:
+
+ 1. A 'short' containing the length of the buffer content in bytes.
+ 2. A 'short' containing the allocated space for the buffer in bytes.
+ 3. A 'long' containing the offset to the start of the buffer in bytes,
+ from the beginning of the NTLM message.
+*/
+
+/*
+ * Curl_auth_is_ntlm_supported()
+ *
+ * This is used to evaluate if NTLM is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE as NTLM as handled by libcurl.
+ */
+bool Curl_auth_is_ntlm_supported(void)
+{
+ return TRUE;
+}
+
+/*
+ * Curl_auth_decode_ntlm_type2_message()
+ *
+ * This is used to decode an already encoded NTLM type-2 message. The message
+ * is first decoded from a base64 string into a raw NTLM message and checked
+ * for validity before the appropriate data for creating a type-3 message is
+ * written to the given NTLM data structure.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * type2msg [in] - The base64 encoded type-2 message.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+ const char *type2msg,
+ struct ntlmdata *ntlm)
+{
+ static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+
+ /* NTLM type-2 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x02000000)
+ 12 Target Name security buffer
+ 20 Flags long
+ 24 Challenge 8 bytes
+ (32) Context 8 bytes (two consecutive longs) (*)
+ (40) Target Information security buffer (*)
+ (48) OS Version Structure 8 bytes (*)
+ 32 (48) (56) Start of data block (*)
+ (*) -> Optional
+ */
+
+ CURLcode result = CURLE_OK;
+ unsigned char *type2 = NULL;
+ size_t type2_len = 0;
+
+#if defined(USE_NSS)
+ /* Make sure the crypto backend is initialized */
+ result = Curl_nss_force_init(data);
+ if(result)
+ return result;
+#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void)data;
+#endif
+
+ /* Decode the base-64 encoded type-2 message */
+ if(strlen(type2msg) && *type2msg != '=') {
+ result = Curl_base64_decode(type2msg, &type2, &type2_len);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid type-2 message */
+ if(!type2) {
+ infof(data, "NTLM handshake failure (empty type-2 message)\n");
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ ntlm->flags = 0;
+
+ if((type2_len < 32) ||
+ (memcmp(type2, NTLMSSP_SIGNATURE, 8) != 0) ||
+ (memcmp(type2 + 8, type2_marker, sizeof(type2_marker)) != 0)) {
+ /* This was not a good enough type-2 message */
+ free(type2);
+ infof(data, "NTLM handshake failure (bad type-2 message)\n");
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ ntlm->flags = Curl_read32_le(&type2[20]);
+ memcpy(ntlm->nonce, &type2[24], 8);
+
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_TARGET_INFO) {
+ result = ntlm_decode_type2_target(data, type2, type2_len, ntlm);
+ if(result) {
+ free(type2);
+ infof(data, "NTLM handshake failure (bad type-2 message)\n");
+ return result;
+ }
+ }
+
+ DEBUG_OUT({
+ fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
+ ntlm_print_flags(stderr, ntlm->flags);
+ fprintf(stderr, "\n nonce=");
+ ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
+ fprintf(stderr, "\n****\n");
+ fprintf(stderr, "**** Header %s\n ", header);
+ });
+
+ free(type2);
+
+ return result;
+}
+
+/* copy the source to the destination and fill in zeroes in every
+ other destination byte! */
+static void unicodecpy(unsigned char *dest, const char *src, size_t length)
+{
+ size_t i;
+ for(i = 0; i < length; i++) {
+ dest[2 * i] = (unsigned char)src[i];
+ dest[2 * i + 1] = '\0';
+ }
+}
+
+/*
+ * Curl_auth_create_ntlm_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient using the appropriate compile time crypto API.
+ *
+ * Parameters:
+ *
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+{
+ /* NTLM type-1 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x01000000)
+ 12 Flags long
+ (16) Supplied Domain security buffer (*)
+ (24) Supplied Workstation security buffer (*)
+ (32) OS Version Structure 8 bytes (*)
+ (32) (40) Start of data block (*)
+ (*) -> Optional
+ */
+
+ size_t size;
+
+ unsigned char ntlmbuf[NTLM_BUFSIZE];
+ const char *host = ""; /* empty */
+ const char *domain = ""; /* empty */
+ size_t hostlen = 0;
+ size_t domlen = 0;
+ size_t hostoff = 0;
+ size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
+ domain are empty */
+ (void)userp;
+ (void)passwdp;
+
+ /* Clean up any former leftovers and initialise to defaults */
+ Curl_auth_ntlm_cleanup(ntlm);
+
+#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
+#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
+#else
+#define NTLM2FLAG 0
+#endif
+ snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x01%c%c%c" /* 32-bit type = 1 */
+ "%c%c%c%c" /* 32-bit NTLM flag field */
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host name offset */
+ "%c%c" /* 2 zeroes */
+ "%s" /* host name */
+ "%s", /* domain string */
+ 0, /* trailing zero */
+ 0, 0, 0, /* part of type-1 long */
+
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0, 0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0, 0,
+ host, /* this is empty */
+ domain /* this is empty */);
+
+ /* Initial packet length */
+ size = 32 + hostlen + domlen;
+
+ DEBUG_OUT({
+ fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
+ "0x%08.8x ",
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+ ntlm_print_flags(stderr,
+ NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+ fprintf(stderr, "\n****\n");
+ });
+
+ /* Return with binary blob encoded into base64 */
+ return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+}
+
+/*
+ * Curl_auth_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient using the appropriate compile time crypto API.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+
+{
+ /* NTLM type-3 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x03000000)
+ 12 LM/LMv2 Response security buffer
+ 20 NTLM/NTLMv2 Response security buffer
+ 28 Target Name security buffer
+ 36 User Name security buffer
+ 44 Workstation Name security buffer
+ (52) Session Key security buffer (*)
+ (60) Flags long (*)
+ (64) OS Version Structure 8 bytes (*)
+ 52 (64) (72) Start of data block
+ (*) -> Optional
+ */
+
+ CURLcode result = CURLE_OK;
+ size_t size;
+ unsigned char ntlmbuf[NTLM_BUFSIZE];
+ int lmrespoff;
+ unsigned char lmresp[24]; /* fixed-size */
+#ifdef USE_NTRESPONSES
+ int ntrespoff;
+ unsigned int ntresplen = 24;
+ unsigned char ntresp[24]; /* fixed-size */
+ unsigned char *ptr_ntresp = &ntresp[0];
+ unsigned char *ntlmv2resp = NULL;
+#endif
+ bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
+ char host[HOSTNAME_MAX + 1] = "";
+ const char *user;
+ const char *domain = "";
+ size_t hostoff = 0;
+ size_t useroff = 0;
+ size_t domoff = 0;
+ size_t hostlen = 0;
+ size_t userlen = 0;
+ size_t domlen = 0;
+
+ user = strchr(userp, '\\');
+ if(!user)
+ user = strchr(userp, '/');
+
+ if(user) {
+ domain = userp;
+ domlen = (user - domain);
+ user++;
+ }
+ else
+ user = userp;
+
+ if(user)
+ userlen = strlen(user);
+
+ /* Get the machine's un-qualified host name as NTLM doesn't like the fully
+ qualified domain name */
+ if(Curl_gethostname(host, sizeof(host))) {
+ infof(data, "gethostname() failed, continuing without!\n");
+ hostlen = 0;
+ }
+ else {
+ hostlen = strlen(host);
+ }
+
+#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
+ if(ntlm->target_info_len) {
+ unsigned char ntbuffer[0x18];
+ unsigned char entropy[8];
+ unsigned char ntlmv2hash[0x18];
+
+ result = Curl_rand(data, entropy, 8);
+ if(result)
+ return result;
+
+ result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
+ if(result)
+ return result;
+
+ result = Curl_ntlm_core_mk_ntlmv2_hash(user, userlen, domain, domlen,
+ ntbuffer, ntlmv2hash);
+ if(result)
+ return result;
+
+ /* LMv2 response */
+ result = Curl_ntlm_core_mk_lmv2_resp(ntlmv2hash, entropy,
+ &ntlm->nonce[0], lmresp);
+ if(result)
+ return result;
+
+ /* NTLMv2 response */
+ result = Curl_ntlm_core_mk_ntlmv2_resp(ntlmv2hash, entropy,
+ ntlm, &ntlmv2resp, &ntresplen);
+ if(result)
+ return result;
+
+ ptr_ntresp = ntlmv2resp;
+ }
+ else
+#endif
+
+#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
+ /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+ unsigned char ntbuffer[0x18];
+ unsigned char tmp[0x18];
+ unsigned char md5sum[MD5_DIGEST_LENGTH];
+ unsigned char entropy[8];
+
+ /* Need to create 8 bytes random data */
+ result = Curl_rand(data, entropy, 8);
+ if(result)
+ return result;
+
+ /* 8 bytes random data as challenge in lmresp */
+ memcpy(lmresp, entropy, 8);
+
+ /* Pad with zeros */
+ memset(lmresp + 8, 0, 0x10);
+
+ /* Fill tmp with challenge(nonce?) + entropy */
+ memcpy(tmp, &ntlm->nonce[0], 8);
+ memcpy(tmp + 8, entropy, 8);
+
+ result = Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
+ if(!result)
+ /* We shall only use the first 8 bytes of md5sum, but the des code in
+ Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
+ result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
+ if(result)
+ return result;
+
+ Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
+
+ /* End of NTLM2 Session code */
+
+ }
+ else
+#endif
+ {
+
+#ifdef USE_NTRESPONSES
+ unsigned char ntbuffer[0x18];
+#endif
+ unsigned char lmbuffer[0x18];
+
+#ifdef USE_NTRESPONSES
+ result = Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer);
+ if(result)
+ return result;
+
+ Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
+#endif
+
+ result = Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
+ if(result)
+ return result;
+
+ Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
+
+ /* A safer but less compatible alternative is:
+ * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
+ * See https://davenport.sourceforge.io/ntlm.html#ntlmVersion2 */
+ }
+
+ if(unicode) {
+ domlen = domlen * 2;
+ userlen = userlen * 2;
+ hostlen = hostlen * 2;
+ }
+
+ lmrespoff = 64; /* size of the message header */
+#ifdef USE_NTRESPONSES
+ ntrespoff = lmrespoff + 0x18;
+ domoff = ntrespoff + ntresplen;
+#else
+ domoff = lmrespoff + 0x18;
+#endif
+ useroff = domoff + domlen;
+ hostoff = useroff + userlen;
+
+ /* Create the big type-3 message binary blob */
+ size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x03%c%c%c" /* 32-bit type = 3 */
+
+ "%c%c" /* LanManager length */
+ "%c%c" /* LanManager allocated space */
+ "%c%c" /* LanManager offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* NT-response length */
+ "%c%c" /* NT-response allocated space */
+ "%c%c" /* NT-response offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* user length */
+ "%c%c" /* user allocated space */
+ "%c%c" /* user offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* session key length (unknown purpose) */
+ "%c%c" /* session key allocated space (unknown purpose) */
+ "%c%c" /* session key offset (unknown purpose) */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c%c%c", /* flags */
+
+ /* domain string */
+ /* user string */
+ /* host string */
+ /* LanManager response */
+ /* NT response */
+
+ 0, /* zero termination */
+ 0, 0, 0, /* type-3 long, the 24 upper bits */
+
+ SHORTPAIR(0x18), /* LanManager response length, twice */
+ SHORTPAIR(0x18),
+ SHORTPAIR(lmrespoff),
+ 0x0, 0x0,
+
+#ifdef USE_NTRESPONSES
+ SHORTPAIR(ntresplen), /* NT-response length, twice */
+ SHORTPAIR(ntresplen),
+ SHORTPAIR(ntrespoff),
+ 0x0, 0x0,
+#else
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+#endif
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0x0, 0x0,
+
+ SHORTPAIR(userlen),
+ SHORTPAIR(userlen),
+ SHORTPAIR(useroff),
+ 0x0, 0x0,
+
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0x0, 0x0,
+
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+
+ LONGQUARTET(ntlm->flags));
+
+ DEBUGASSERT(size == 64);
+ DEBUGASSERT(size == (size_t)lmrespoff);
+
+ /* We append the binary hashes */
+ if(size < (NTLM_BUFSIZE - 0x18)) {
+ memcpy(&ntlmbuf[size], lmresp, 0x18);
+ size += 0x18;
+ }
+
+ DEBUG_OUT({
+ fprintf(stderr, "**** TYPE3 header lmresp=");
+ ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
+ });
+
+#ifdef USE_NTRESPONSES
+ if(size < (NTLM_BUFSIZE - ntresplen)) {
+ DEBUGASSERT(size == (size_t)ntrespoff);
+ memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
+ size += ntresplen;
+ }
+
+ DEBUG_OUT({
+ fprintf(stderr, "\n ntresp=");
+ ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], ntresplen);
+ });
+
+ free(ntlmv2resp);/* Free the dynamic buffer allocated for NTLMv2 */
+
+#endif
+
+ DEBUG_OUT({
+ fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+ LONGQUARTET(ntlm->flags), ntlm->flags);
+ ntlm_print_flags(stderr, ntlm->flags);
+ fprintf(stderr, "\n****\n");
+ });
+
+ /* Make sure that the domain, user and host strings fit in the
+ buffer before we copy them there. */
+ if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
+ failf(data, "user + domain + host name too big");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ DEBUGASSERT(size == domoff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], domain, domlen / 2);
+ else
+ memcpy(&ntlmbuf[size], domain, domlen);
+
+ size += domlen;
+
+ DEBUGASSERT(size == useroff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], user, userlen / 2);
+ else
+ memcpy(&ntlmbuf[size], user, userlen);
+
+ size += userlen;
+
+ DEBUGASSERT(size == hostoff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], host, hostlen / 2);
+ else
+ memcpy(&ntlmbuf[size], host, hostlen);
+
+ size += hostlen;
+
+ /* Convert domain, user, and host to ASCII but leave the rest as-is */
+ result = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
+ size - domoff);
+ if(result)
+ return CURLE_CONV_FAILED;
+
+ /* Return with binary blob encoded into base64 */
+ result = Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+
+ Curl_auth_ntlm_cleanup(ntlm);
+
+ return result;
+}
+
+/*
+* Curl_auth_ntlm_cleanup()
+*
+* This is used to clean up the NTLM specific data.
+*
+* Parameters:
+*
+* ntlm [in/out] - The NTLM data struct being cleaned up.
+*
+*/
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+{
+ /* Free the target info */
+ Curl_safefree(ntlm->target_info);
+
+ /* Reset any variables */
+ ntlm->target_info_len = 0;
+}
+
+#endif /* USE_NTLM && !USE_WINDOWS_SSPI */
diff --git a/Utilities/cmcurl/lib/vauth/ntlm.h b/Utilities/cmcurl/lib/vauth/ntlm.h
new file mode 100644
index 000000000..f906a3c7a
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/ntlm.h
@@ -0,0 +1,143 @@
+#ifndef HEADER_CURL_NTLM_H
+#define HEADER_CURL_NTLM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_NTLM
+
+/* NTLM buffer fixed size, large enough for long user + host + domain */
+#define NTLM_BUFSIZE 1024
+
+/* Stuff only required for curl_ntlm_msgs.c */
+#ifdef BUILDING_CURL_NTLM_MSGS_C
+
+/* Flag bits definitions based on https://davenport.sourceforge.io/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+ data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+ message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
+/* Specifies that authenticated communication between the client and server
+ should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
+/* Specifies that authenticated communication between the client and server
+ should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
+/* Indicates that datagram authentication is being used. */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+ sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+ context has been established. This also affects the response fields. */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+ authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+ workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+ machine. Implies that the client may use a pre-established local security
+ context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
+/* Indicates that authenticated communication between the client and server
+ should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a share. Presumably, this is for share-level
+ authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+ protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+ Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128 (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
+/* Indicates that the client will provide an encrypted master key in
+ the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56 (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
+#endif /* BUILDING_CURL_NTLM_MSGS_C */
+
+#endif /* USE_NTLM */
+
+#endif /* HEADER_CURL_NTLM_H */
diff --git a/Utilities/cmcurl/lib/vauth/ntlm_sspi.c b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
new file mode 100644
index 000000000..c3305176d
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/ntlm_sspi.c
@@ -0,0 +1,335 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_NTLM)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_ntlm_supported()
+ *
+ * This is used to evaluate if NTLM is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if NTLM is supported by Windows SSPI.
+ */
+bool Curl_auth_is_ntlm_supported(void)
+{
+ PSecPkgInfo SecurityPackage;
+ SECURITY_STATUS status;
+
+ /* Query the security package for NTLM */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+ &SecurityPackage);
+
+ return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_create_ntlm_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+{
+ PSecPkgInfo SecurityPackage;
+ SecBuffer type_1_buf;
+ SecBufferDesc type_1_desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+ /* Clean up any former leftovers and initialise to defaults */
+ Curl_auth_ntlm_cleanup(ntlm);
+
+ /* Query the security package for NTLM */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
+ &SecurityPackage);
+ if(status != SEC_E_OK)
+ return CURLE_NOT_BUILT_IN;
+
+ ntlm->token_max = SecurityPackage->cbMaxToken;
+
+ /* Release the package buffer as it is not required anymore */
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+ /* Allocate our output buffer */
+ ntlm->output_token = malloc(ntlm->token_max);
+ if(!ntlm->output_token)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(userp && *userp) {
+ CURLcode result;
+
+ /* Populate our identity structure */
+ result = Curl_create_sspi_identity(userp, passwdp, &ntlm->identity);
+ if(result)
+ return result;
+
+ /* Allow proper cleanup of the identity structure */
+ ntlm->p_identity = &ntlm->identity;
+ }
+ else
+ /* Use the current Windows user */
+ ntlm->p_identity = NULL;
+
+ /* Allocate our credentials handle */
+ ntlm->credentials = malloc(sizeof(CredHandle));
+ if(!ntlm->credentials)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(ntlm->credentials, 0, sizeof(CredHandle));
+
+ /* Acquire our credentials handle */
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT(SP_NAME_NTLM),
+ SECPKG_CRED_OUTBOUND, NULL,
+ ntlm->p_identity, NULL, NULL,
+ ntlm->credentials, &expiry);
+ if(status != SEC_E_OK)
+ return CURLE_LOGIN_DENIED;
+
+ /* Allocate our new context handle */
+ ntlm->context = malloc(sizeof(CtxtHandle));
+ if(!ntlm->context)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(ntlm->context, 0, sizeof(CtxtHandle));
+
+ /* Setup the type-1 "output" security buffer */
+ type_1_desc.ulVersion = SECBUFFER_VERSION;
+ type_1_desc.cBuffers = 1;
+ type_1_desc.pBuffers = &type_1_buf;
+ type_1_buf.BufferType = SECBUFFER_TOKEN;
+ type_1_buf.pvBuffer = ntlm->output_token;
+ type_1_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
+
+ /* Generate our type-1 message */
+ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials, NULL,
+ (TCHAR *) TEXT(""),
+ 0, 0, SECURITY_NETWORK_DREP,
+ NULL, 0,
+ ntlm->context, &type_1_desc,
+ &attrs, &expiry);
+ if(status == SEC_I_COMPLETE_NEEDED ||
+ status == SEC_I_COMPLETE_AND_CONTINUE)
+ s_pSecFn->CompleteAuthToken(ntlm->context, &type_1_desc);
+ else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED)
+ return CURLE_RECV_ERROR;
+
+ /* Base64 encode the response */
+ return Curl_base64_encode(NULL, (char *) ntlm->output_token,
+ type_1_buf.cbBuffer, outptr, outlen);
+}
+
+/*
+ * Curl_auth_decode_ntlm_type2_message()
+ *
+ * This is used to decode an already encoded NTLM type-2 message.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * type2msg [in] - The base64 encoded type-2 message.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+ const char *type2msg,
+ struct ntlmdata *ntlm)
+{
+ CURLcode result = CURLE_OK;
+ unsigned char *type2 = NULL;
+ size_t type2_len = 0;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
+
+ /* Decode the base-64 encoded type-2 message */
+ if(strlen(type2msg) && *type2msg != '=') {
+ result = Curl_base64_decode(type2msg, &type2, &type2_len);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid type-2 message */
+ if(!type2) {
+ infof(data, "NTLM handshake failure (empty type-2 message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Simply store the challenge for use later */
+ ntlm->input_token = type2;
+ ntlm->input_token_len = type2_len;
+
+ return result;
+}
+
+/*
+* Curl_auth_create_ntlm_type3_message()
+ * Curl_auth_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The NTLM data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ SecBuffer type_2_buf;
+ SecBuffer type_3_buf;
+ SecBufferDesc type_2_desc;
+ SecBufferDesc type_3_desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+ (void) passwdp;
+ (void) userp;
+
+ /* Setup the type-2 "input" security buffer */
+ type_2_desc.ulVersion = SECBUFFER_VERSION;
+ type_2_desc.cBuffers = 1;
+ type_2_desc.pBuffers = &type_2_buf;
+ type_2_buf.BufferType = SECBUFFER_TOKEN;
+ type_2_buf.pvBuffer = ntlm->input_token;
+ type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len);
+
+ /* Setup the type-3 "output" security buffer */
+ type_3_desc.ulVersion = SECBUFFER_VERSION;
+ type_3_desc.cBuffers = 1;
+ type_3_desc.pBuffers = &type_3_buf;
+ type_3_buf.BufferType = SECBUFFER_TOKEN;
+ type_3_buf.pvBuffer = ntlm->output_token;
+ type_3_buf.cbBuffer = curlx_uztoul(ntlm->token_max);
+
+ /* Generate our type-3 message */
+ status = s_pSecFn->InitializeSecurityContext(ntlm->credentials,
+ ntlm->context,
+ (TCHAR *) TEXT(""),
+ 0, 0, SECURITY_NETWORK_DREP,
+ &type_2_desc,
+ 0, ntlm->context,
+ &type_3_desc,
+ &attrs, &expiry);
+ if(status != SEC_E_OK) {
+ infof(data, "NTLM handshake failure (type-3 message): Status=%x\n",
+ status);
+
+ return CURLE_RECV_ERROR;
+ }
+
+ /* Base64 encode the response */
+ result = Curl_base64_encode(data, (char *) ntlm->output_token,
+ type_3_buf.cbBuffer, outptr, outlen);
+
+ Curl_auth_ntlm_cleanup(ntlm);
+
+ return result;
+}
+
+/*
+ * Curl_auth_ntlm_cleanup()
+ *
+ * This is used to clean up the NTLM specific data.
+ *
+ * Parameters:
+ *
+ * ntlm [in/out] - The NTLM data struct being cleaned up.
+ *
+ */
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm)
+{
+ /* Free our security context */
+ if(ntlm->context) {
+ s_pSecFn->DeleteSecurityContext(ntlm->context);
+ free(ntlm->context);
+ ntlm->context = NULL;
+ }
+
+ /* Free our credentials handle */
+ if(ntlm->credentials) {
+ s_pSecFn->FreeCredentialsHandle(ntlm->credentials);
+ free(ntlm->credentials);
+ ntlm->credentials = NULL;
+ }
+
+ /* Free our identity */
+ Curl_sspi_free_identity(ntlm->p_identity);
+ ntlm->p_identity = NULL;
+
+ /* Free the input and output tokens */
+ Curl_safefree(ntlm->input_token);
+ Curl_safefree(ntlm->output_token);
+
+ /* Reset any variables */
+ ntlm->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_NTLM */
diff --git a/Utilities/cmcurl/lib/vauth/oauth2.c b/Utilities/cmcurl/lib/vauth/oauth2.c
new file mode 100644
index 000000000..6288f89a3
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/oauth2.c
@@ -0,0 +1,86 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "vauth/vauth.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_create_oauth_bearer_message()
+ *
+ * This is used to generate an already encoded OAuth 2.0 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data[in] - The session handle.
+ * user[in] - The user name.
+ * host[in] - The host name(for OAUTHBEARER).
+ * port[in] - The port(for OAUTHBEARER when not Port 80).
+ * bearer[in] - The bearer token.
+ * outptr[in / out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen[out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
+ const char *user,
+ const char *host,
+ const long port,
+ const char *bearer,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ char *oauth = NULL;
+
+ /* Generate the message */
+ if(host == NULL && (port == 0 || port == 80))
+ oauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
+ else if(port == 0 || port == 80)
+ oauth = aprintf("user=%s\1host=%s\1auth=Bearer %s\1\1", user, host,
+ bearer);
+ else
+ oauth = aprintf("user=%s\1host=%s\1port=%ld\1auth=Bearer %s\1\1", user,
+ host, port, bearer);
+ if(!oauth)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Base64 encode the reply */
+ result = Curl_base64_encode(data, oauth, strlen(oauth), outptr, outlen);
+
+ free(oauth);
+
+ return result;
+}
diff --git a/Utilities/cmcurl/lib/vauth/spnego_gssapi.c b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
new file mode 100644
index 000000000..8840db8fd
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/spnego_gssapi.c
@@ -0,0 +1,274 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(HAVE_GSSAPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_gssapi.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_spnego_supported()
+ *
+ * This is used to evaluate if SPNEGO (Negotiate) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Negotiate supported by the GSS-API library.
+ */
+bool Curl_auth_is_spnego_supported(void)
+{
+ return TRUE;
+}
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * host [in] - The host name.
+ * chlg64 [in] - The optional base64 encoded challenge message.
+ * nego [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+ const char *user,
+ const char *password,
+ const char *service,
+ const char *host,
+ const char *chlg64,
+ struct negotiatedata *nego)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ unsigned char *chlg = NULL;
+ OM_uint32 major_status;
+ OM_uint32 minor_status;
+ OM_uint32 unused_status;
+ gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+
+ (void) user;
+ (void) password;
+
+ if(nego->context && nego->status == GSS_S_COMPLETE) {
+ /* We finished successfully our part of authentication, but server
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
+ Curl_auth_spnego_cleanup(nego);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ if(!nego->spn) {
+ /* Generate our SPN */
+ char *spn = Curl_auth_build_spn(service, NULL, host);
+ if(!spn)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Populate the SPN structure */
+ spn_token.value = spn;
+ spn_token.length = strlen(spn);
+
+ /* Import the SPN */
+ major_status = gss_import_name(&minor_status, &spn_token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ &nego->spn);
+ if(GSS_ERROR(major_status)) {
+ Curl_gss_log_error(data, "gss_import_name() failed: ",
+ major_status, minor_status);
+
+ free(spn);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ free(spn);
+ }
+
+ if(chlg64 && *chlg64) {
+ /* Decode the base-64 encoded challenge message */
+ if(*chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "SPNEGO handshake failure (empty challenge message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ input_token.value = chlg;
+ input_token.length = chlglen;
+ }
+
+ /* Generate our challenge-response message */
+ major_status = Curl_gss_init_sec_context(data,
+ &minor_status,
+ &nego->context,
+ nego->spn,
+ &Curl_spnego_mech_oid,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ &output_token,
+ TRUE,
+ NULL);
+
+ /* Free the decoded challenge as it is not required anymore */
+ Curl_safefree(input_token.value);
+
+ nego->status = major_status;
+ if(GSS_ERROR(major_status)) {
+ if(output_token.value)
+ gss_release_buffer(&unused_status, &output_token);
+
+ Curl_gss_log_error(data, "gss_init_sec_context() failed: ",
+ major_status, minor_status);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!output_token.value || !output_token.length) {
+ if(output_token.value)
+ gss_release_buffer(&unused_status, &output_token);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ nego->output_token = output_token;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * nego [in/out] - The Negotiate data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
+ struct negotiatedata *nego,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+ OM_uint32 minor_status;
+
+ /* Base64 encode the already generated response */
+ result = Curl_base64_encode(data,
+ nego->output_token.value,
+ nego->output_token.length,
+ outptr, outlen);
+
+ if(result) {
+ gss_release_buffer(&minor_status, &nego->output_token);
+ nego->output_token.value = NULL;
+ nego->output_token.length = 0;
+
+ return result;
+ }
+
+ if(!*outptr || !*outlen) {
+ gss_release_buffer(&minor_status, &nego->output_token);
+ nego->output_token.value = NULL;
+ nego->output_token.length = 0;
+
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_spnego_cleanup()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+{
+ OM_uint32 minor_status;
+
+ /* Free our security context */
+ if(nego->context != GSS_C_NO_CONTEXT) {
+ gss_delete_sec_context(&minor_status, &nego->context, GSS_C_NO_BUFFER);
+ nego->context = GSS_C_NO_CONTEXT;
+ }
+
+ /* Free the output token */
+ if(nego->output_token.value) {
+ gss_release_buffer(&minor_status, &nego->output_token);
+ nego->output_token.value = NULL;
+ nego->output_token.length = 0;
+
+ }
+
+ /* Free the SPN */
+ if(nego->spn != GSS_C_NO_NAME) {
+ gss_release_name(&minor_status, &nego->spn);
+ nego->spn = GSS_C_NO_NAME;
+ }
+
+ /* Reset any variables */
+ nego->status = 0;
+}
+
+#endif /* HAVE_GSSAPI && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/vauth/spnego_sspi.c b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
new file mode 100644
index 000000000..a6797cdaf
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/spnego_sspi.c
@@ -0,0 +1,324 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * RFC4178 Simple and Protected GSS-API Negotiation Mechanism
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_WINDOWS_SSPI) && defined(USE_SPNEGO)
+
+#include <curl/curl.h>
+
+#include "vauth/vauth.h"
+#include "urldata.h"
+#include "curl_base64.h"
+#include "warnless.h"
+#include "curl_multibyte.h"
+#include "sendf.h"
+#include "strerror.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_is_spnego_supported()
+ *
+ * This is used to evaluate if SPNEGO (Negotiate) is supported.
+ *
+ * Parameters: None
+ *
+ * Returns TRUE if Negotiate is supported by Windows SSPI.
+ */
+bool Curl_auth_is_spnego_supported(void)
+{
+ PSecPkgInfo SecurityPackage;
+ SECURITY_STATUS status;
+
+ /* Query the security package for Negotiate */
+ status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ TEXT(SP_NAME_NEGOTIATE),
+ &SecurityPackage);
+
+ return (status == SEC_E_OK ? TRUE : FALSE);
+}
+
+/*
+ * Curl_auth_decode_spnego_message()
+ *
+ * This is used to decode an already encoded SPNEGO (Negotiate) challenge
+ * message.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * host [in] - The host name.
+ * chlg64 [in] - The optional base64 encoded challenge message.
+ * nego [in/out] - The Negotiate data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+ const char *user,
+ const char *password,
+ const char *service,
+ const char *host,
+ const char *chlg64,
+ struct negotiatedata *nego)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlglen = 0;
+ unsigned char *chlg = NULL;
+ PSecPkgInfo SecurityPackage;
+ SecBuffer chlg_buf;
+ SecBuffer resp_buf;
+ SecBufferDesc chlg_desc;
+ SecBufferDesc resp_desc;
+ unsigned long attrs;
+ TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void) data;
+#endif
+
+ if(nego->context && nego->status == SEC_E_OK) {
+ /* We finished successfully our part of authentication, but server
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
+ Curl_auth_spnego_cleanup(nego);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ if(!nego->spn) {
+ /* Generate our SPN */
+ nego->spn = Curl_auth_build_spn(service, host, NULL);
+ if(!nego->spn)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!nego->output_token) {
+ /* Query the security package for Negotiate */
+ nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
+ TEXT(SP_NAME_NEGOTIATE),
+ &SecurityPackage);
+ if(nego->status != SEC_E_OK)
+ return CURLE_NOT_BUILT_IN;
+
+ nego->token_max = SecurityPackage->cbMaxToken;
+
+ /* Release the package buffer as it is not required anymore */
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+
+ /* Allocate our output buffer */
+ nego->output_token = malloc(nego->token_max);
+ if(!nego->output_token)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!nego->credentials) {
+ /* Do we have credientials to use or are we using single sign-on? */
+ if(user && *user) {
+ /* Populate our identity structure */
+ result = Curl_create_sspi_identity(user, password, &nego->identity);
+ if(result)
+ return result;
+
+ /* Allow proper cleanup of the identity structure */
+ nego->p_identity = &nego->identity;
+ }
+ else
+ /* Use the current Windows user */
+ nego->p_identity = NULL;
+
+ /* Allocate our credentials handle */
+ nego->credentials = malloc(sizeof(CredHandle));
+ if(!nego->credentials)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(nego->credentials, 0, sizeof(CredHandle));
+
+ /* Acquire our credentials handle */
+ nego->status =
+ s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *)TEXT(SP_NAME_NEGOTIATE),
+ SECPKG_CRED_OUTBOUND, NULL,
+ nego->p_identity, NULL, NULL,
+ nego->credentials, &expiry);
+ if(nego->status != SEC_E_OK)
+ return CURLE_LOGIN_DENIED;
+
+ /* Allocate our new context handle */
+ nego->context = malloc(sizeof(CtxtHandle));
+ if(!nego->context)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(nego->context, 0, sizeof(CtxtHandle));
+ }
+
+ if(chlg64 && *chlg64) {
+ /* Decode the base-64 encoded challenge message */
+ if(*chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+ if(result)
+ return result;
+ }
+
+ /* Ensure we have a valid challenge message */
+ if(!chlg) {
+ infof(data, "SPNEGO handshake failure (empty challenge message)\n");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+ }
+
+ /* Setup the challenge "input" security buffer */
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 1;
+ chlg_desc.pBuffers = &chlg_buf;
+ chlg_buf.BufferType = SECBUFFER_TOKEN;
+ chlg_buf.pvBuffer = chlg;
+ chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ }
+
+ /* Setup the response "output" security buffer */
+ resp_desc.ulVersion = SECBUFFER_VERSION;
+ resp_desc.cBuffers = 1;
+ resp_desc.pBuffers = &resp_buf;
+ resp_buf.BufferType = SECBUFFER_TOKEN;
+ resp_buf.pvBuffer = nego->output_token;
+ resp_buf.cbBuffer = curlx_uztoul(nego->token_max);
+
+ /* Generate our challenge-response message */
+ nego->status = s_pSecFn->InitializeSecurityContext(nego->credentials,
+ chlg ? nego->context :
+ NULL,
+ nego->spn,
+ ISC_REQ_CONFIDENTIALITY,
+ 0, SECURITY_NATIVE_DREP,
+ chlg ? &chlg_desc : NULL,
+ 0, nego->context,
+ &resp_desc, &attrs,
+ &expiry);
+
+ /* Free the decoded challenge as it is not required anymore */
+ free(chlg);
+
+ if(GSS_ERROR(nego->status)) {
+ failf(data, "InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(data->easy_conn, nego->status));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(nego->status == SEC_I_COMPLETE_NEEDED ||
+ nego->status == SEC_I_COMPLETE_AND_CONTINUE) {
+ nego->status = s_pSecFn->CompleteAuthToken(nego->context, &resp_desc);
+ if(GSS_ERROR(nego->status)) {
+ return CURLE_RECV_ERROR;
+ }
+ }
+
+ nego->output_token_length = resp_buf.cbBuffer;
+
+ return result;
+}
+
+/*
+ * Curl_auth_create_spnego_message()
+ *
+ * This is used to generate an already encoded SPNEGO (Negotiate) response
+ * message ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * nego [in/out] - The Negotiate data struct being used and modified.
+ * outptr [in/out] - The address where a pointer to newly allocated memory
+ * holding the result will be stored upon completion.
+ * outlen [out] - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
+ struct negotiatedata *nego,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+
+ /* Base64 encode the already generated response */
+ result = Curl_base64_encode(data,
+ (const char *) nego->output_token,
+ nego->output_token_length,
+ outptr, outlen);
+
+ if(result)
+ return result;
+
+ if(!*outptr || !*outlen) {
+ free(*outptr);
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_auth_spnego_cleanup()
+ *
+ * This is used to clean up the SPNEGO (Negotiate) specific data.
+ *
+ * Parameters:
+ *
+ * nego [in/out] - The Negotiate data struct being cleaned up.
+ *
+ */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego)
+{
+ /* Free our security context */
+ if(nego->context) {
+ s_pSecFn->DeleteSecurityContext(nego->context);
+ free(nego->context);
+ nego->context = NULL;
+ }
+
+ /* Free our credentials handle */
+ if(nego->credentials) {
+ s_pSecFn->FreeCredentialsHandle(nego->credentials);
+ free(nego->credentials);
+ nego->credentials = NULL;
+ }
+
+ /* Free our identity */
+ Curl_sspi_free_identity(nego->p_identity);
+ nego->p_identity = NULL;
+
+ /* Free the SPN and output token */
+ Curl_safefree(nego->spn);
+ Curl_safefree(nego->output_token);
+
+ /* Reset any variables */
+ nego->status = 0;
+ nego->token_max = 0;
+}
+
+#endif /* USE_WINDOWS_SSPI && USE_SPNEGO */
diff --git a/Utilities/cmcurl/lib/vauth/vauth.c b/Utilities/cmcurl/lib/vauth/vauth.c
new file mode 100644
index 000000000..b995f34e2
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/vauth.c
@@ -0,0 +1,147 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "vauth.h"
+#include "curl_multibyte.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_auth_build_spn()
+ *
+ * This is used to build a SPN string in the following formats:
+ *
+ * service/host@realm (Not currently used)
+ * service/host (Not used by GSS-API)
+ * service@realm (Not used by Windows SSPI)
+ *
+ * Parameters:
+ *
+ * service [in] - The service type such as http, smtp, pop or imap.
+ * host [in] - The host name.
+ * realm [in] - The realm.
+ *
+ * Returns a pointer to the newly allocated SPN.
+ */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+ const char *realm)
+{
+ char *spn = NULL;
+
+ /* Generate our SPN */
+ if(host && realm)
+ spn = aprintf("%s/%s@%s", service, host, realm);
+ else if(host)
+ spn = aprintf("%s/%s", service, host);
+ else if(realm)
+ spn = aprintf("%s@%s", service, realm);
+
+ /* Return our newly allocated SPN */
+ return spn;
+}
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+ const char *realm)
+{
+ char *utf8_spn = NULL;
+ TCHAR *tchar_spn = NULL;
+
+ (void) realm;
+
+ /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather
+ than doing this ourselves but the first is only available in Windows XP
+ and Windows Server 2003 and the latter is only available in Windows 2000
+ but not Windows95/98/ME or Windows NT4.0 unless the Active Directory
+ Client Extensions are installed. As such it is far simpler for us to
+ formulate the SPN instead. */
+
+ /* Generate our UTF8 based SPN */
+ utf8_spn = aprintf("%s/%s", service, host);
+ if(!utf8_spn) {
+ return NULL;
+ }
+
+ /* Allocate our TCHAR based SPN */
+ tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn);
+ if(!tchar_spn) {
+ free(utf8_spn);
+
+ return NULL;
+ }
+
+ /* Release the UTF8 variant when operating with Unicode */
+ Curl_unicodefree(utf8_spn);
+
+ /* Return our newly allocated SPN */
+ return tchar_spn;
+}
+#endif /* USE_WINDOWS_SSPI */
+
+/*
+* Curl_auth_user_contains_domain()
+*
+* This is used to test if the specified user contains a Windows domain name as
+* follows:
+*
+* User\Domain (Down-level Logon Name)
+* User/Domain (curl Down-level format - for compatibility with existing code)
+* User@Domain (User Principal Name)
+*
+* Note: The user name may be empty when using a GSS-API library or Windows SSPI
+* as the user and domain are either obtained from the credientals cache when
+* using GSS-API or via the currently logged in user's credientals when using
+* Windows SSPI.
+*
+* Parameters:
+*
+* user [in] - The user name.
+*
+* Returns TRUE on success; otherwise FALSE.
+*/
+bool Curl_auth_user_contains_domain(const char *user)
+{
+ bool valid = FALSE;
+
+ if(user && *user) {
+ /* Check we have a domain name or UPN present */
+ char *p = strpbrk(user, "\\/@");
+
+ valid = (p != NULL && p > user && p < user + strlen(user) - 1 ? TRUE :
+ FALSE);
+ }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ else
+ /* User and domain are obtained from the GSS-API credientials cache or the
+ currently logged in user from Windows */
+ valid = TRUE;
+#endif
+
+ return valid;
+}
diff --git a/Utilities/cmcurl/lib/vauth/vauth.h b/Utilities/cmcurl/lib/vauth/vauth.h
new file mode 100644
index 000000000..9d61228c3
--- /dev/null
+++ b/Utilities/cmcurl/lib/vauth/vauth.h
@@ -0,0 +1,204 @@
+#ifndef HEADER_CURL_VAUTH_H
+#define HEADER_CURL_VAUTH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+struct Curl_easy;
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+struct digestdata;
+#endif
+
+#if defined(USE_NTLM)
+struct ntlmdata;
+#endif
+
+#if defined(USE_KERBEROS5)
+struct kerberos5data;
+#endif
+
+#if (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)) && defined(USE_SPNEGO)
+struct negotiatedata;
+#endif
+
+#if defined(USE_WINDOWS_SSPI)
+#define GSS_ERROR(status) (status & 0x80000000)
+#endif
+
+/* This is used to build a SPN string */
+#if !defined(USE_WINDOWS_SSPI)
+char *Curl_auth_build_spn(const char *service, const char *host,
+ const char *realm);
+#else
+TCHAR *Curl_auth_build_spn(const char *service, const char *host,
+ const char *realm);
+#endif
+
+/* This is used to test if the user contains a Windows domain name */
+bool Curl_auth_user_contains_domain(const char *user);
+
+/* This is used to generate a base64 encoded PLAIN cleartext message */
+CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded LOGIN cleartext message */
+CURLcode Curl_auth_create_login_message(struct Curl_easy *data,
+ const char *valuep, char **outptr,
+ size_t *outlen);
+
+/* This is used to generate a base64 encoded EXTERNAL cleartext message */
+CURLcode Curl_auth_create_external_message(struct Curl_easy *data,
+ const char *user, char **outptr,
+ size_t *outlen);
+
+#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+/* This is used to decode a CRAM-MD5 challenge message */
+CURLcode Curl_auth_decode_cram_md5_message(const char *chlg64, char **outptr,
+ size_t *outlen);
+
+/* This is used to generate a CRAM-MD5 response message */
+CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
+ const char *chlg,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen);
+
+/* This is used to evaluate if DIGEST is supported */
+bool Curl_auth_is_digest_supported(void);
+
+/* This is used to generate a base64 encoded DIGEST-MD5 response message */
+CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
+ const char *chlg64,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ char **outptr, size_t *outlen);
+
+/* This is used to decode a HTTP DIGEST challenge message */
+CURLcode Curl_auth_decode_digest_http_message(const char *chlg,
+ struct digestdata *digest);
+
+/* This is used to generate a HTTP DIGEST response message */
+CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const unsigned char *request,
+ const unsigned char *uri,
+ struct digestdata *digest,
+ char **outptr, size_t *outlen);
+
+/* This is used to clean up the digest specific data */
+void Curl_auth_digest_cleanup(struct digestdata *digest);
+#endif /* !CURL_DISABLE_CRYPTO_AUTH */
+
+#if defined(USE_NTLM)
+/* This is used to evaluate if NTLM is supported */
+bool Curl_auth_is_ntlm_supported(void);
+
+/* This is used to generate a base64 encoded NTLM type-1 message */
+CURLcode Curl_auth_create_ntlm_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen);
+
+/* This is used to decode a base64 encoded NTLM type-2 message */
+CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
+ const char *type2msg,
+ struct ntlmdata *ntlm);
+
+/* This is used to generate a base64 encoded NTLM type-3 message */
+CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen);
+
+/* This is used to clean up the NTLM specific data */
+void Curl_auth_ntlm_cleanup(struct ntlmdata *ntlm);
+#endif /* USE_NTLM */
+
+/* This is used to generate a base64 encoded OAuth 2.0 message */
+CURLcode Curl_auth_create_oauth_bearer_message(struct Curl_easy *data,
+ const char *user,
+ const char *host,
+ const long port,
+ const char *bearer,
+ char **outptr, size_t *outlen);
+#if defined(USE_KERBEROS5)
+/* This is used to evaluate if GSSAPI (Kerberos V5) is supported */
+bool Curl_auth_is_gssapi_supported(void);
+
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) user token
+ message */
+CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ const char *host,
+ const bool mutual,
+ const char *chlg64,
+ struct kerberos5data *krb5,
+ char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded GSSAPI (Kerberos V5) security
+ token message */
+CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
+ const char *input,
+ struct kerberos5data *krb5,
+ char **outptr,
+ size_t *outlen);
+
+/* This is used to clean up the GSSAPI specific data */
+void Curl_auth_gssapi_cleanup(struct kerberos5data *krb5);
+#endif /* USE_KERBEROS5 */
+
+#if defined(USE_SPNEGO)
+/* This is used to evaluate if SPNEGO (Negotiate) is supported */
+bool Curl_auth_is_spnego_supported(void);
+
+/* This is used to decode a base64 encoded SPNEGO (Negotiate) challenge
+ message */
+CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
+ const char *user,
+ const char *passwood,
+ const char *service,
+ const char *host,
+ const char *chlg64,
+ struct negotiatedata *nego);
+
+/* This is used to generate a base64 encoded SPNEGO (Negotiate) response
+ message */
+CURLcode Curl_auth_create_spnego_message(struct Curl_easy *data,
+ struct negotiatedata *nego,
+ char **outptr, size_t *outlen);
+
+/* This is used to clean up the SPNEGO specifiec data */
+void Curl_auth_spnego_cleanup(struct negotiatedata *nego);
+
+#endif /* USE_SPNEGO */
+
+#endif /* HEADER_CURL_VAUTH_H */
diff --git a/Utilities/cmcurl/lib/version.c b/Utilities/cmcurl/lib/version.c
new file mode 100644
index 000000000..3d1776813
--- /dev/null
+++ b/Utilities/cmcurl/lib/version.c
@@ -0,0 +1,399 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "vtls/vtls.h"
+#include "http2.h"
+#include "curl_printf.h"
+
+#ifdef USE_ARES
+# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+# define CARES_STATICLIB
+# endif
+# include <ares.h>
+#endif
+
+#ifdef USE_LIBIDN2
+#include <idn2.h>
+#endif
+
+#ifdef USE_LIBPSL
+#include <libpsl.h>
+#endif
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#include <iconv.h>
+#endif
+
+#ifdef USE_LIBRTMP
+#include <librtmp/rtmp.h>
+#endif
+
+#ifdef USE_LIBSSH2
+#include <libssh2.h>
+#endif
+
+#ifdef HAVE_LIBSSH2_VERSION
+/* get it run-time if possible */
+#define CURL_LIBSSH2_VERSION libssh2_version(0)
+#else
+/* use build-time if run-time not possible */
+#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
+#endif
+
+void Curl_version_init(void);
+
+/* For thread safety purposes this function is called by global_init so that
+ the static data in both version functions is initialized. */
+void Curl_version_init(void)
+{
+ curl_version();
+ curl_version_info(CURLVERSION_NOW);
+}
+
+char *curl_version(void)
+{
+ static bool initialized;
+ static char version[200];
+ char *ptr = version;
+ size_t len;
+ size_t left = sizeof(version);
+
+ if(initialized)
+ return version;
+
+ strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION);
+ len = strlen(ptr);
+ left -= len;
+ ptr += len;
+
+ if(left > 1) {
+ len = Curl_ssl_version(ptr + 1, left - 1);
+
+ if(len > 0) {
+ *ptr = ' ';
+ left -= ++len;
+ ptr += len;
+ }
+ }
+
+#ifdef HAVE_LIBZ
+ len = snprintf(ptr, left, " zlib/%s", zlibVersion());
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_ARES
+ /* this function is only present in c-ares, not in the original ares */
+ len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBIDN2
+ if(idn2_check_version(IDN2_VERSION)) {
+ len = snprintf(ptr, left, " libidn2/%s", idn2_check_version(NULL));
+ left -= len;
+ ptr += len;
+ }
+#endif
+#ifdef USE_LIBPSL
+ len = snprintf(ptr, left, " libpsl/%s", psl_get_version());
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_WIN32_IDN
+ len = snprintf(ptr, left, " WinIDN");
+ left -= len;
+ ptr += len;
+#endif
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+ len = snprintf(ptr, left, " iconv/%d.%d",
+ _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
+#else
+ /* version unknown */
+ len = snprintf(ptr, left, " iconv");
+#endif /* _LIBICONV_VERSION */
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBSSH2
+ len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION);
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_NGHTTP2
+ len = Curl_http2_ver(ptr, left);
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBRTMP
+ {
+ char suff[2];
+ if(RTMP_LIB_VERSION & 0xff) {
+ suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
+ suff[1] = '\0';
+ }
+ else
+ suff[0] = '\0';
+
+ snprintf(ptr, left, " librtmp/%d.%d%s",
+ RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+ suff);
+/*
+ If another lib version is added below this one, this code would
+ also have to do:
+
+ len = what snprintf() returned
+
+ left -= len;
+ ptr += len;
+*/
+ }
+#endif
+
+ initialized = true;
+ return version;
+}
+
+/* data for curl_version_info
+
+ Keep the list sorted alphabetically. It is also written so that each
+ protocol line has its own #if line to make things easier on the eye.
+ */
+
+static const char * const protocols[] = {
+#ifndef CURL_DISABLE_DICT
+ "dict",
+#endif
+#ifndef CURL_DISABLE_FILE
+ "file",
+#endif
+#ifndef CURL_DISABLE_FTP
+ "ftp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+ "ftps",
+#endif
+#ifndef CURL_DISABLE_GOPHER
+ "gopher",
+#endif
+#ifndef CURL_DISABLE_HTTP
+ "http",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ "https",
+#endif
+#ifndef CURL_DISABLE_IMAP
+ "imap",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+ "imaps",
+#endif
+#ifndef CURL_DISABLE_LDAP
+ "ldap",
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+ "ldaps",
+#endif
+#endif
+#ifndef CURL_DISABLE_POP3
+ "pop3",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+ "pop3s",
+#endif
+#ifdef USE_LIBRTMP
+ "rtmp",
+#endif
+#ifndef CURL_DISABLE_RTSP
+ "rtsp",
+#endif
+#ifdef USE_LIBSSH2
+ "scp",
+#endif
+#ifdef USE_LIBSSH2
+ "sftp",
+#endif
+#if !defined(CURL_DISABLE_SMB) && defined(USE_NTLM) && \
+ (CURL_SIZEOF_CURL_OFF_T > 4) && \
+ (!defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO))
+ "smb",
+# ifdef USE_SSL
+ "smbs",
+# endif
+#endif
+#ifndef CURL_DISABLE_SMTP
+ "smtp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+ "smtps",
+#endif
+#ifndef CURL_DISABLE_TELNET
+ "telnet",
+#endif
+#ifndef CURL_DISABLE_TFTP
+ "tftp",
+#endif
+
+ NULL
+};
+
+static curl_version_info_data version_info = {
+ CURLVERSION_NOW,
+ LIBCURL_VERSION,
+ LIBCURL_VERSION_NUM,
+ OS, /* as found by configure or set by hand at build-time */
+ 0 /* features is 0 by default */
+#ifdef ENABLE_IPV6
+ | CURL_VERSION_IPV6
+#endif
+#ifdef USE_SSL
+ | CURL_VERSION_SSL
+#endif
+#ifdef USE_NTLM
+ | CURL_VERSION_NTLM
+#endif
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
+ defined(NTLM_WB_ENABLED)
+ | CURL_VERSION_NTLM_WB
+#endif
+#ifdef USE_SPNEGO
+ | CURL_VERSION_SPNEGO
+#endif
+#ifdef USE_KERBEROS5
+ | CURL_VERSION_KERBEROS5
+#endif
+#ifdef HAVE_GSSAPI
+ | CURL_VERSION_GSSAPI
+#endif
+#ifdef USE_WINDOWS_SSPI
+ | CURL_VERSION_SSPI
+#endif
+#ifdef HAVE_LIBZ
+ | CURL_VERSION_LIBZ
+#endif
+#ifdef DEBUGBUILD
+ | CURL_VERSION_DEBUG
+#endif
+#ifdef CURLDEBUG
+ | CURL_VERSION_CURLDEBUG
+#endif
+#ifdef CURLRES_ASYNCH
+ | CURL_VERSION_ASYNCHDNS
+#endif
+#if (CURL_SIZEOF_CURL_OFF_T > 4) && \
+ ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
+ | CURL_VERSION_LARGEFILE
+#endif
+#if defined(CURL_DOES_CONVERSIONS)
+ | CURL_VERSION_CONV
+#endif
+#if defined(USE_TLS_SRP)
+ | CURL_VERSION_TLSAUTH_SRP
+#endif
+#if defined(USE_NGHTTP2)
+ | CURL_VERSION_HTTP2
+#endif
+#if defined(USE_UNIX_SOCKETS)
+ | CURL_VERSION_UNIX_SOCKETS
+#endif
+#if defined(USE_LIBPSL)
+ | CURL_VERSION_PSL
+#endif
+#if defined(HTTPS_PROXY_SUPPORT)
+ | CURL_VERSION_HTTPS_PROXY
+#endif
+ ,
+ NULL, /* ssl_version */
+ 0, /* ssl_version_num, this is kept at zero */
+ NULL, /* zlib_version */
+ protocols,
+ NULL, /* c-ares version */
+ 0, /* c-ares version numerical */
+ NULL, /* libidn version */
+ 0, /* iconv version */
+ NULL, /* ssh lib version */
+};
+
+curl_version_info_data *curl_version_info(CURLversion stamp)
+{
+ static bool initialized;
+#ifdef USE_LIBSSH2
+ static char ssh_buffer[80];
+#endif
+#ifdef USE_SSL
+ static char ssl_buffer[80];
+#endif
+
+ if(initialized)
+ return &version_info;
+
+#ifdef USE_SSL
+ Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
+ version_info.ssl_version = ssl_buffer;
+#endif
+
+#ifdef HAVE_LIBZ
+ version_info.libz_version = zlibVersion();
+ /* libz left NULL if non-existing */
+#endif
+#ifdef USE_ARES
+ {
+ int aresnum;
+ version_info.ares = ares_version(&aresnum);
+ version_info.ares_num = aresnum;
+ }
+#endif
+#ifdef USE_LIBIDN2
+ /* This returns a version string if we use the given version or later,
+ otherwise it returns NULL */
+ version_info.libidn = idn2_check_version(IDN2_VERSION);
+ if(version_info.libidn)
+ version_info.features |= CURL_VERSION_IDN;
+#elif defined(USE_WIN32_IDN)
+ version_info.features |= CURL_VERSION_IDN;
+#endif
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+ version_info.iconv_ver_num = _LIBICONV_VERSION;
+#else
+ /* version unknown */
+ version_info.iconv_ver_num = -1;
+#endif /* _LIBICONV_VERSION */
+#endif
+
+#ifdef USE_LIBSSH2
+ snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
+ version_info.libssh_version = ssh_buffer;
+#endif
+
+ (void)stamp; /* avoid compiler warnings, we don't use this */
+
+ initialized = true;
+ return &version_info;
+}
diff --git a/Utilities/cmcurl/lib/vtls/axtls.c b/Utilities/cmcurl/lib/vtls/axtls.c
new file mode 100644
index 000000000..f0e376640
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/axtls.c
@@ -0,0 +1,706 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, DirecTV, Contact: Eric Hu, <ehu@directv.com>.
+ * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all axTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_AXTLS
+#include <axTLS/config.h>
+#include <axTLS/ssl.h>
+#include "axtls.h"
+
+#include "sendf.h"
+#include "inet_pton.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "curl_printf.h"
+#include "hostcheck.h"
+#include <unistd.h>
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+
+/* Global axTLS init, called from Curl_ssl_init() */
+int Curl_axtls_init(void)
+{
+/* axTLS has no global init. Everything is done through SSL and SSL_CTX
+ * structs stored in connectdata structure. Perhaps can move to axtls.h.
+ */
+ return 1;
+}
+
+int Curl_axtls_cleanup(void)
+{
+ /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */
+ return 1;
+}
+
+static CURLcode map_error_to_curl(int axtls_err)
+{
+ switch(axtls_err) {
+ case SSL_ERROR_NOT_SUPPORTED:
+ case SSL_ERROR_INVALID_VERSION:
+ case -70: /* protocol version alert from server */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ break;
+ case SSL_ERROR_NO_CIPHER:
+ return CURLE_SSL_CIPHER;
+ break;
+ case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
+ case SSL_ERROR_NO_CERT_DEFINED:
+ case -42: /* bad certificate alert from server */
+ case -43: /* unsupported cert alert from server */
+ case -44: /* cert revoked alert from server */
+ case -45: /* cert expired alert from server */
+ case -46: /* cert unknown alert from server */
+ return CURLE_SSL_CERTPROBLEM;
+ break;
+ case SSL_X509_ERROR(X509_NOT_OK):
+ case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
+ case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
+ case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
+ case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
+ case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
+ case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
+ case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
+ case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
+ return CURLE_PEER_FAILED_VERIFICATION;
+ break;
+ case -48: /* unknown ca alert from server */
+ return CURLE_SSL_CACERT;
+ break;
+ case -49: /* access denied alert from server */
+ return CURLE_REMOTE_ACCESS_DENIED;
+ break;
+ case SSL_ERROR_CONN_LOST:
+ case SSL_ERROR_SOCK_SETUP_FAILURE:
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ case SSL_ERROR_INVALID_PROT_MSG:
+ case SSL_ERROR_INVALID_HMAC:
+ case SSL_ERROR_INVALID_SESSION:
+ case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */
+ case SSL_ERROR_FINISHED_INVALID:
+ case SSL_ERROR_NO_CLIENT_RENOG:
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
+ break;
+ }
+}
+
+static Curl_recv axtls_recv;
+static Curl_send axtls_send;
+
+static void free_ssl_structs(struct ssl_connect_data *connssl)
+{
+ if(connssl->ssl) {
+ ssl_free(connssl->ssl);
+ connssl->ssl = NULL;
+ }
+ if(connssl->ssl_ctx) {
+ ssl_ctx_free(connssl->ssl_ctx);
+ connssl->ssl_ctx = NULL;
+ }
+}
+
+/*
+ * For both blocking and non-blocking connects, this function sets up the
+ * ssl context and state. This function is called after the TCP connect
+ * has completed.
+ */
+static CURLcode connect_prep(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ SSL_CTX *ssl_ctx;
+ SSL *ssl = NULL;
+ int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0};
+ int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0};
+ int i, ssl_fcn_return;
+
+ /* Assuming users will not compile in custom key/cert to axTLS.
+ * Also, even for blocking connects, use axTLS non-blocking feature.
+ */
+ uint32_t client_option = SSL_NO_DEFAULT_KEY |
+ SSL_SERVER_VERIFY_LATER |
+ SSL_CONNECT_IN_PARTS;
+
+ if(conn->ssl[sockindex].state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "axtls does not support CURL_SSLVERSION_MAX");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+
+ /* axTLS only supports TLSv1 */
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ break;
+ default:
+ failf(data, "axTLS only supports TLS 1.0 and 1.1, "
+ "and it cannot be specified which one to use");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef AXTLSDEBUG
+ client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
+#endif /* AXTLSDEBUG */
+
+ /* Allocate an SSL_CTX struct */
+ ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
+ if(ssl_ctx == NULL) {
+ failf(data, "unable to create client SSL context");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ conn->ssl[sockindex].ssl_ctx = ssl_ctx;
+ conn->ssl[sockindex].ssl = NULL;
+
+ /* Load the trusted CA cert bundle file */
+ if(SSL_CONN_CONFIG(CAfile)) {
+ if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT,
+ SSL_CONN_CONFIG(CAfile), NULL) != SSL_OK) {
+ infof(data, "error reading ca cert file %s \n",
+ SSL_CONN_CONFIG(CAfile));
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else
+ infof(data, "found certificates in %s\n", SSL_CONN_CONFIG(CAfile));
+ }
+
+ /* gtls.c tasks we're skipping for now:
+ * 1) certificate revocation list checking
+ * 2) dns name assignment to host
+ * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore
+ * 4) set certificate priority. axTLS ignores type and sends certs in
+ * order added. can probably ignore this.
+ */
+
+ /* Load client certificate */
+ if(SSL_SET_OPTION(cert)) {
+ i=0;
+ /* Instead of trying to analyze cert type here, let axTLS try them all. */
+ while(cert_types[i] != 0) {
+ ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
+ SSL_SET_OPTION(cert), NULL);
+ if(ssl_fcn_return == SSL_OK) {
+ infof(data, "successfully read cert file %s \n",
+ SSL_SET_OPTION(cert));
+ break;
+ }
+ i++;
+ }
+ /* Tried all cert types, none worked. */
+ if(cert_types[i] == 0) {
+ failf(data, "%s is not x509 or pkcs12 format",
+ SSL_SET_OPTION(cert));
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load client key.
+ If a pkcs12 file successfully loaded a cert, then there's nothing to do
+ because the key has already been loaded. */
+ if(SSL_SET_OPTION(key) && cert_types[i] != SSL_OBJ_PKCS12) {
+ i=0;
+ /* Instead of trying to analyze key type here, let axTLS try them all. */
+ while(key_types[i] != 0) {
+ ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
+ SSL_SET_OPTION(key), NULL);
+ if(ssl_fcn_return == SSL_OK) {
+ infof(data, "successfully read key file %s \n",
+ SSL_SET_OPTION(key));
+ break;
+ }
+ i++;
+ }
+ /* Tried all key types, none worked. */
+ if(key_types[i] == 0) {
+ failf(data, "Failure: %s is not a supported key file",
+ SSL_SET_OPTION(key));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* gtls.c does more here that is being left out for now
+ * 1) set session credentials. can probably ignore since axtls puts this
+ * info in the ssl_ctx struct
+ * 2) setting up callbacks. these seem gnutls specific
+ */
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ const uint8_t *ssl_sessionid;
+ size_t ssl_idsize;
+
+ /* In axTLS, handshaking happens inside ssl_client_new. */
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize,
+ sockindex)) {
+ /* we got a session id, use it! */
+ infof(data, "SSL re-using session ID\n");
+ ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
+ ssl_sessionid, (uint8_t)ssl_idsize, NULL);
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ if(!ssl)
+ ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0, NULL);
+
+ conn->ssl[sockindex].ssl = ssl;
+ return CURLE_OK;
+}
+
+/*
+ * For both blocking and non-blocking connects, this function finalizes the
+ * SSL connection.
+ */
+static CURLcode connect_finish(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ SSL *ssl = conn->ssl[sockindex].ssl;
+ const char *peer_CN;
+ uint32_t dns_altname_index;
+ const char *dns_altname;
+ int8_t found_subject_alt_names = 0;
+ int8_t found_subject_alt_name_matching_conn = 0;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+
+ /* Here, gtls.c gets the peer certificates and fails out depending on
+ * settings in "data." axTLS api doesn't have get cert chain fcn, so omit?
+ */
+
+ /* Verify server's certificate */
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ if(ssl_verify_cert(ssl) != SSL_OK) {
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "server cert verify failed");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ else
+ infof(data, "\t server certificate verification SKIPPED\n");
+
+ /* Here, gtls.c does issuer verification. axTLS has no straightforward
+ * equivalent, so omitting for now.*/
+
+ /* Here, gtls.c does the following
+ * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but
+ * it seems useful. This is now implemented, by Oscar Koeroo
+ * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert
+ * 3) displays a bunch of cert information. axTLS doesn't support most of
+ * this, but a couple fields are available.
+ */
+
+ /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a
+ risk of an inifite loop */
+ for(dns_altname_index = 0; ; dns_altname_index++) {
+ dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
+ if(dns_altname == NULL) {
+ break;
+ }
+ found_subject_alt_names = 1;
+
+ infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
+ dns_altname, hostname);
+ if(Curl_cert_hostcheck(dns_altname, hostname)) {
+ found_subject_alt_name_matching_conn = 1;
+ break;
+ }
+ }
+
+ /* RFC2818 checks */
+ if(found_subject_alt_names && !found_subject_alt_name_matching_conn) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ /* Break connection ! */
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "\tsubjectAltName(s) do not match %s\n", dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\tsubjectAltName(s) do not match %s\n", dispname);
+ }
+ else if(found_subject_alt_names == 0) {
+ /* Per RFC2818, when no Subject Alt Names were available, examine the peer
+ CN as a legacy fallback */
+ peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME);
+ if(peer_CN == NULL) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "unable to obtain common name from peer certificate");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "unable to obtain common name from peer certificate");
+ }
+ else {
+ if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ /* Break connection ! */
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+ peer_CN, dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+ peer_CN, dispname);
+ }
+ }
+ }
+
+ /* General housekeeping */
+ conn->ssl[sockindex].state = ssl_connection_complete;
+ conn->recv[sockindex] = axtls_recv;
+ conn->send[sockindex] = axtls_send;
+
+ /* Put our freshly minted SSL session in cache */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ const uint8_t *ssl_sessionid = ssl_get_session_id(ssl);
+ size_t ssl_idsize = ssl_get_session_id_size(ssl);
+ Curl_ssl_sessionid_lock(conn);
+ if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize,
+ sockindex) != CURLE_OK)
+ infof(data, "failed to add session to cache\n");
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Use axTLS's non-blocking connection feature to open an SSL connection.
+ * This is called after a TCP connection is already established.
+ */
+CURLcode Curl_axtls_connect_nonblocking(
+ struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ CURLcode conn_step;
+ int ssl_fcn_return;
+ int i;
+
+ *done = FALSE;
+ /* connectdata is calloc'd and connecting_state is only changed in this
+ function, so this is safe, as the state is effectively initialized. */
+ if(conn->ssl[sockindex].connecting_state == ssl_connect_1) {
+ conn_step = connect_prep(conn, sockindex);
+ if(conn_step != CURLE_OK) {
+ Curl_axtls_close(conn, sockindex);
+ return conn_step;
+ }
+ conn->ssl[sockindex].connecting_state = ssl_connect_2;
+ }
+
+ if(conn->ssl[sockindex].connecting_state == ssl_connect_2) {
+ /* Check to make sure handshake was ok. */
+ if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) {
+ /* Loop to perform more work in between sleeps. This is work around the
+ fact that axtls does not expose any knowledge about when work needs
+ to be performed. This can save ~25% of time on SSL handshakes. */
+ for(i=0; i<5; i++) {
+ ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL);
+ if(ssl_fcn_return < 0) {
+ Curl_axtls_close(conn, sockindex);
+ ssl_display_error(ssl_fcn_return); /* goes to stdout. */
+ return map_error_to_curl(ssl_fcn_return);
+ }
+ return CURLE_OK;
+ }
+ }
+ infof(conn->data, "handshake completed successfully\n");
+ conn->ssl[sockindex].connecting_state = ssl_connect_3;
+ }
+
+ if(conn->ssl[sockindex].connecting_state == ssl_connect_3) {
+ conn_step = connect_finish(conn, sockindex);
+ if(conn_step != CURLE_OK) {
+ Curl_axtls_close(conn, sockindex);
+ return conn_step;
+ }
+
+ /* Reset connect state */
+ conn->ssl[sockindex].connecting_state = ssl_connect_1;
+
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ /* Unrecognized state. Things are very bad. */
+ conn->ssl[sockindex].state = ssl_connection_none;
+ conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ /* Return value perhaps not strictly correct, but distinguishes the issue.*/
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+}
+
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic for a blocking connect.
+ */
+CURLcode
+Curl_axtls_connect(struct connectdata *conn,
+ int sockindex)
+
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode conn_step = connect_prep(conn, sockindex);
+ int ssl_fcn_return;
+ SSL *ssl = conn->ssl[sockindex].ssl;
+ long timeout_ms;
+
+ if(conn_step != CURLE_OK) {
+ Curl_axtls_close(conn, sockindex);
+ return conn_step;
+ }
+
+ /* Check to make sure handshake was ok. */
+ while(ssl_handshake_status(ssl) != SSL_OK) {
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ ssl_fcn_return = ssl_read(ssl, NULL);
+ if(ssl_fcn_return < 0) {
+ Curl_axtls_close(conn, sockindex);
+ ssl_display_error(ssl_fcn_return); /* goes to stdout. */
+ return map_error_to_curl(ssl_fcn_return);
+ }
+ /* TODO: avoid polling */
+ Curl_wait_ms(10);
+ }
+ infof(conn->data, "handshake completed successfully\n");
+
+ conn_step = connect_finish(conn, sockindex);
+ if(conn_step != CURLE_OK) {
+ Curl_axtls_close(conn, sockindex);
+ return conn_step;
+ }
+
+ return CURLE_OK;
+}
+
+/* return number of sent (non-SSL) bytes */
+static ssize_t axtls_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *err)
+{
+ /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
+ int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
+
+ infof(conn->data, " axtls_send\n");
+
+ if(rc < 0) {
+ *err = map_error_to_curl(rc);
+ rc = -1; /* generic error code for send failure */
+ }
+
+ *err = CURLE_OK;
+ return rc;
+}
+
+void Curl_axtls_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ infof(conn->data, " Curl_axtls_close\n");
+
+ /* line from openssl.c: (void)SSL_shutdown(connssl->ssl);
+ axTLS compat layer does nothing for SSL_shutdown */
+
+ /* The following line is from openssl.c. There seems to be no axTLS
+ equivalent. ssl_free and ssl_ctx_free close things.
+ SSL_set_connect_state(connssl->handle); */
+
+ free_ssl_structs(connssl);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
+{
+ /* Outline taken from openssl.c since functions are in axTLS compat layer.
+ axTLS's error set is much smaller, so a lot of error-handling was removed.
+ */
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ uint8_t *buf;
+ ssize_t nread;
+
+ infof(conn->data, " Curl_axtls_shutdown\n");
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ (void)SSL_shutdown(connssl->ssl);
+ */
+
+ if(connssl->ssl) {
+ int what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server. buf is managed internally by
+ axTLS and will be released upon calling ssl_free via
+ free_ssl_structs. */
+ nread = (ssize_t)ssl_read(connssl->ssl, &buf);
+
+ if(nread < SSL_OK) {
+ failf(data, "close notify alert not received during shutdown");
+ retval = -1;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ }
+
+ free_ssl_structs(connssl);
+ }
+ return retval;
+}
+
+static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *err)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[num];
+ ssize_t ret = 0;
+ uint8_t *read_buf;
+
+ infof(conn->data, " axtls_recv\n");
+
+ *err = CURLE_OK;
+ if(connssl) {
+ ret = ssl_read(connssl->ssl, &read_buf);
+ if(ret > SSL_OK) {
+ /* ssl_read returns SSL_OK if there is more data to read, so if it is
+ larger, then all data has been read already. */
+ memcpy(buf, read_buf,
+ (size_t)ret > buffersize ? buffersize : (size_t)ret);
+ }
+ else if(ret == SSL_OK) {
+ /* more data to be read, signal caller to call again */
+ *err = CURLE_AGAIN;
+ ret = -1;
+ }
+ else if(ret == -3) {
+ /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS
+ team approves proposed fix. */
+ Curl_axtls_close(conn, num);
+ }
+ else {
+ failf(conn->data, "axTLS recv error (%d)", ret);
+ *err = map_error_to_curl((int) ret);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_axtls_check_cxn(struct connectdata *conn)
+{
+ /* openssl.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
+ axTLS compat layer always returns the last argument, so connection is
+ always alive? */
+
+ infof(conn->data, " Curl_axtls_check_cxn\n");
+ return 1; /* connection still in place */
+}
+
+void Curl_axtls_session_free(void *ptr)
+{
+ (void)ptr;
+ /* free the ID */
+ /* both openssl.c and gtls.c do something here, but axTLS's OpenSSL
+ compatibility layer does nothing, so we do nothing too. */
+}
+
+size_t Curl_axtls_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "axTLS/%s", ssl_version());
+}
+
+CURLcode Curl_axtls_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ static bool ssl_seeded = FALSE;
+ (void)data;
+ if(!ssl_seeded) {
+ ssl_seeded = TRUE;
+ /* Initialize the seed if not already done. This call is not exactly thread
+ * safe (and neither is the ssl_seeded check), but the worst effect of a
+ * race condition is that some global resources will leak. */
+ RNG_initialize();
+ }
+ get_random((int)length, entropy);
+ return CURLE_OK;
+}
+
+#endif /* USE_AXTLS */
diff --git a/Utilities/cmcurl/lib/vtls/axtls.h b/Utilities/cmcurl/lib/vtls/axtls.h
new file mode 100644
index 000000000..53797eadb
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/axtls.h
@@ -0,0 +1,71 @@
+#ifndef HEADER_CURL_AXTLS_H
+#define HEADER_CURL_AXTLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, DirecTV, Contact: Eric Hu <ehu@directv.com>
+ * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifdef USE_AXTLS
+#include "curl/curl.h"
+#include "urldata.h"
+
+int Curl_axtls_init(void);
+int Curl_axtls_cleanup(void);
+CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_axtls_connect_nonblocking(
+ struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+ /* close a SSL connection */
+void Curl_axtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_axtls_session_free(void *ptr);
+size_t Curl_axtls_version(char *buffer, size_t size);
+int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
+int Curl_axtls_check_cxn(struct connectdata *conn);
+CURLcode Curl_axtls_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length);
+
+/* Set the API backend definition to axTLS */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_AXTLS
+
+/* API setup for axTLS */
+#define curlssl_init Curl_axtls_init
+#define curlssl_cleanup Curl_axtls_cleanup
+#define curlssl_connect Curl_axtls_connect
+#define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking
+#define curlssl_session_free(x) Curl_axtls_session_free(x)
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_axtls_close
+#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y)
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_axtls_version
+#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x)
+#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
+#define curlssl_random(x,y,z) Curl_axtls_random(x,y,z)
+
+#endif /* USE_AXTLS */
+#endif /* HEADER_CURL_AXTLS_H */
+
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.c b/Utilities/cmcurl/lib/vtls/cyassl.c
new file mode 100644
index 000000000..01bfdabd1
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/cyassl.c
@@ -0,0 +1,954 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_CYASSL
+
+#define WOLFSSL_OPTIONS_IGNORE_SYS
+/* CyaSSL's version.h, which should contain only the version, should come
+before all other CyaSSL includes and be immediately followed by build config
+aka options.h. https://curl.haxx.se/mail/lib-2015-04/0069.html */
+#include <cyassl/version.h>
+#if defined(HAVE_CYASSL_OPTIONS_H) && (LIBCYASSL_VERSION_HEX > 0x03004008)
+#if defined(CYASSL_API) || defined(WOLFSSL_API)
+/* Safety measure. If either is defined some API include was already included
+and that's a problem since options.h hasn't been included yet. */
+#error "CyaSSL API was included before the CyaSSL build options."
+#endif
+#include <cyassl/options.h>
+#endif
+
+/* To determine what functions are available we rely on one or both of:
+ - the user's options.h generated by CyaSSL/wolfSSL
+ - the symbols detected by curl's configure
+ Since they are markedly different from one another, and one or the other may
+ not be available, we do some checking below to bring things in sync. */
+
+/* HAVE_ALPN is wolfSSL's build time symbol for enabling ALPN in options.h. */
+#ifndef HAVE_ALPN
+#ifdef HAVE_WOLFSSL_USEALPN
+#define HAVE_ALPN
+#endif
+#endif
+
+/* WOLFSSL_ALLOW_SSLV3 is wolfSSL's build time symbol for enabling SSLv3 in
+ options.h, but is only seen in >= 3.6.6 since that's when they started
+ disabling SSLv3 by default. */
+#ifndef WOLFSSL_ALLOW_SSLV3
+#if (LIBCYASSL_VERSION_HEX < 0x03006006) || \
+ defined(HAVE_WOLFSSLV3_CLIENT_METHOD)
+#define WOLFSSL_ALLOW_SSLV3
+#endif
+#endif
+
+/* HAVE_SUPPORTED_CURVES is wolfSSL's build time symbol for enabling the ECC
+ supported curve extension in options.h. Note ECC is enabled separately. */
+#ifndef HAVE_SUPPORTED_CURVES
+#if defined(HAVE_CYASSL_CTX_USESUPPORTEDCURVE) || \
+ defined(HAVE_WOLFSSL_CTX_USESUPPORTEDCURVE)
+#define HAVE_SUPPORTED_CURVES
+#endif
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+
+#include <cyassl/ssl.h>
+#ifdef HAVE_CYASSL_ERROR_SSL_H
+#include <cyassl/error-ssl.h>
+#else
+#include <cyassl/error.h>
+#endif
+#include <cyassl/ctaocrypt/random.h>
+#include <cyassl/ctaocrypt/sha256.h>
+
+#include "cyassl.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if LIBCYASSL_VERSION_HEX < 0x02007002 /* < 2.7.2 */
+#define CYASSL_MAX_ERROR_SZ 80
+#endif
+
+static Curl_recv cyassl_recv;
+static Curl_send cyassl_send;
+
+
+static int do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return SSL_FILETYPE_PEM;
+ if(strcasecompare(type, "PEM"))
+ return SSL_FILETYPE_PEM;
+ if(strcasecompare(type, "DER"))
+ return SSL_FILETYPE_ASN1;
+ return -1;
+}
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+cyassl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ char error_buffer[CYASSL_MAX_ERROR_SZ];
+ char *ciphers;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ SSL_METHOD* req_method = NULL;
+ curl_socket_t sockfd = conn->sock[sockindex];
+#ifdef HAVE_SNI
+ bool sni = FALSE;
+#define use_sni(x) sni = (x)
+#else
+#define use_sni(x) Curl_nop_stmt
+#endif
+
+ if(conssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ if(SSL_CONN_CONFIG(version_max) != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "CyaSSL does not support to set maximum SSL/TLS version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+#if LIBCYASSL_VERSION_HEX >= 0x03003000 /* >= 3.3.0 */
+ /* minimum protocol version is set later after the CTX object is created */
+ req_method = SSLv23_client_method();
+#else
+ infof(data, "CyaSSL <3.3.0 cannot be configured to use TLS 1.0-1.2, "
+ "TLS 1.0 is used exclusively\n");
+ req_method = TLSv1_client_method();
+#endif
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ req_method = TLSv1_client_method();
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ req_method = TLSv1_1_client_method();
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ req_method = TLSv1_2_client_method();
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "CyaSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv3:
+#ifdef WOLFSSL_ALLOW_SSLV3
+ req_method = SSLv3_client_method();
+ use_sni(FALSE);
+#else
+ failf(data, "CyaSSL does not support SSLv3");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "CyaSSL does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(!req_method) {
+ failf(data, "SSL: couldn't create a method!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(conssl->ctx)
+ SSL_CTX_free(conssl->ctx);
+ conssl->ctx = SSL_CTX_new(req_method);
+
+ if(!conssl->ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+#if LIBCYASSL_VERSION_HEX > 0x03004006 /* > 3.4.6 */
+ /* Versions 3.3.0 to 3.4.6 we know the minimum protocol version is whatever
+ minimum version of TLS was built in and at least TLS 1.0. For later library
+ versions that could change (eg TLS 1.0 built in but defaults to TLS 1.1) so
+ we have this short circuit evaluation to find the minimum supported TLS
+ version. We use wolfSSL_CTX_SetMinVersion and not CyaSSL_SetMinVersion
+ because only the former will work before the user's CTX callback is called.
+ */
+ if((wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_1) != 1) &&
+ (wolfSSL_CTX_SetMinVersion(conssl->ctx, WOLFSSL_TLSV1_2) != 1)) {
+ failf(data, "SSL: couldn't set the minimum protocol version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif
+ break;
+ }
+
+ ciphers = SSL_CONN_CONFIG(cipher_list);
+ if(ciphers) {
+ if(!SSL_CTX_set_cipher_list(conssl->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "Cipher selection: %s\n", ciphers);
+ }
+
+#ifndef NO_FILESYSTEM
+ /* load trusted cacert */
+ if(SSL_CONN_CONFIG(CAfile)) {
+ if(1 != SSL_CTX_load_verify_locations(conssl->ctx,
+ SSL_CONN_CONFIG(CAfile),
+ SSL_CONN_CONFIG(CApath))) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s",
+ SSL_CONN_CONFIG(CAfile)?
+ SSL_CONN_CONFIG(CAfile): "none",
+ SSL_CONN_CONFIG(CApath)?
+ SSL_CONN_CONFIG(CApath) : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
+ "none",
+ SSL_CONN_CONFIG(CApath) ? SSL_CONN_CONFIG(CApath):
+ "none");
+ }
+
+ /* Load the client certificate, and private key */
+ if(SSL_SET_OPTION(cert) && SSL_SET_OPTION(key)) {
+ int file_type = do_file_type(SSL_SET_OPTION(cert_type));
+
+ if(SSL_CTX_use_certificate_file(conssl->ctx, SSL_SET_OPTION(cert),
+ file_type) != 1) {
+ failf(data, "unable to use client certificate (no key or wrong pass"
+ " phrase?)");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ file_type = do_file_type(SSL_SET_OPTION(key_type));
+ if(SSL_CTX_use_PrivateKey_file(conssl->ctx, SSL_SET_OPTION(key),
+ file_type) != 1) {
+ failf(data, "unable to set private key");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* !NO_FILESYSTEM */
+
+ /* SSL always tries to verify the peer, this only says whether it should
+ * fail to connect if the verification fails, or if it should continue
+ * anyway. In the latter case the result of the verification is checked with
+ * SSL_get_verify_result() below. */
+ SSL_CTX_set_verify(conssl->ctx,
+ SSL_CONN_CONFIG(verifypeer)?SSL_VERIFY_PEER:
+ SSL_VERIFY_NONE,
+ NULL);
+
+#ifdef HAVE_SNI
+ if(sni) {
+ struct in_addr addr4;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr6;
+#endif
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ size_t hostname_len = strlen(hostname);
+ if((hostname_len < USHRT_MAX) &&
+ (0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr6)) &&
+#endif
+ (CyaSSL_CTX_UseSNI(conssl->ctx, CYASSL_SNI_HOST_NAME, hostname,
+ (unsigned short)hostname_len) != 1)) {
+ infof(data, "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+ }
+ }
+#endif
+
+#ifdef HAVE_SUPPORTED_CURVES
+ /* CyaSSL/wolfSSL does not send the supported ECC curves ext automatically:
+ https://github.com/wolfSSL/wolfssl/issues/366
+ The supported curves below are those also supported by OpenSSL 1.0.2 and
+ in the same order. */
+ CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x17); /* secp256r1 */
+ CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x19); /* secp521r1 */
+ CyaSSL_CTX_UseSupportedCurve(conssl->ctx, 0x18); /* secp384r1 */
+#endif
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ CURLcode result = CURLE_OK;
+ result = (*data->set.ssl.fsslctx)(data, conssl->ctx,
+ data->set.ssl.fsslctxp);
+ if(result) {
+ failf(data, "error signaled by ssl ctx callback");
+ return result;
+ }
+ }
+#ifdef NO_FILESYSTEM
+ else if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "SSL: Certificates couldn't be loaded because CyaSSL was built"
+ " with \"no filesystem\". Either disable peer verification"
+ " (insecure) or if you are building an application with libcurl you"
+ " can load certificates via CURLOPT_SSL_CTX_FUNCTION.");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif
+
+ /* Let's make an SSL structure */
+ if(conssl->handle)
+ SSL_free(conssl->handle);
+ conssl->handle = SSL_new(conssl->ctx);
+ if(!conssl->handle) {
+ failf(data, "SSL: couldn't create a context (handle)!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifdef HAVE_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ char protocols[128];
+ *protocols = '\0';
+
+ /* wolfSSL's ALPN protocol name list format is a comma separated string of
+ protocols in descending order of preference, eg: "h2,http/1.1" */
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ strcpy(protocols + strlen(protocols), NGHTTP2_PROTO_VERSION_ID ",");
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ strcpy(protocols + strlen(protocols), ALPN_HTTP_1_1);
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ if(wolfSSL_UseALPN(conssl->handle, protocols,
+ (unsigned)strlen(protocols),
+ WOLFSSL_ALPN_CONTINUE_ON_MISMATCH) != SSL_SUCCESS) {
+ failf(data, "SSL: failed setting ALPN protocols");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* HAVE_ALPN */
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *ssl_sessionid = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
+ /* we got a session id, use it! */
+ if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ERR_error_string(SSL_get_error(conssl->handle, 0),
+ error_buffer));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof(data, "SSL re-using session ID\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ /* pass the raw socket into the SSL layer */
+ if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
+ failf(data, "SSL: SSL_set_fd failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ conssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+
+static CURLcode
+cyassl_connect_step2(struct connectdata *conn,
+ int sockindex)
+{
+ int ret = -1;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
+ conn->recv[sockindex] = cyassl_recv;
+ conn->send[sockindex] = cyassl_send;
+
+ /* Enable RFC2818 checks */
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ ret = CyaSSL_check_domain_name(conssl->handle, hostname);
+ if(ret == SSL_FAILURE)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ ret = SSL_connect(conssl->handle);
+ if(ret != 1) {
+ char error_buffer[CYASSL_MAX_ERROR_SZ];
+ int detail = SSL_get_error(conssl->handle, ret);
+
+ if(SSL_ERROR_WANT_READ == detail) {
+ conssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ else if(SSL_ERROR_WANT_WRITE == detail) {
+ conssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ /* There is no easy way to override only the CN matching.
+ * This will enable the override of both mismatching SubjectAltNames
+ * as also mismatching CN fields */
+ else if(DOMAIN_NAME_MISMATCH == detail) {
+#if 1
+ failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
+ dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+#else
+ /* When the CyaSSL_check_domain_name() is used and you desire to continue
+ * on a DOMAIN_NAME_MISMATCH, i.e. 'conn->ssl_config.verifyhost == 0',
+ * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
+ * way to do this is currently to switch the CyaSSL_check_domain_name()
+ * in and out based on the 'conn->ssl_config.verifyhost' value. */
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ failf(data,
+ "\tsubject alt name(s) or common name do not match \"%s\"\n",
+ dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ infof(data,
+ "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
+ dispname);
+ return CURLE_OK;
+ }
+#endif
+ }
+#if LIBCYASSL_VERSION_HEX >= 0x02007000 /* 2.7.0 */
+ else if(ASN_NO_SIGNER_E == detail) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "\tCA signer not available for verification\n");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "CA signer not available for verification, "
+ "continuing anyway\n");
+ }
+ }
+#endif
+ else {
+ failf(data, "SSL_connect failed with error %d: %s", detail,
+ ERR_error_string(detail, error_buffer));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ if(pinnedpubkey) {
+#ifdef KEEP_PEER_CERT
+ X509 *x509;
+ const char *x509_der;
+ int x509_der_len;
+ curl_X509certificate x509_parsed;
+ curl_asn1Element *pubkey;
+ CURLcode result;
+
+ x509 = SSL_get_peer_certificate(conssl->handle);
+ if(!x509) {
+ failf(data, "SSL: failed retrieving server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ x509_der = (const char *)CyaSSL_X509_get_der(x509, &x509_der_len);
+ if(!x509_der) {
+ failf(data, "SSL: failed retrieving ASN.1 server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ memset(&x509_parsed, 0, sizeof x509_parsed);
+ if(Curl_parseX509(&x509_parsed, x509_der, x509_der + x509_der_len))
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ pubkey = &x509_parsed.subjectPublicKeyInfo;
+ if(!pubkey->header || pubkey->end <= pubkey->header) {
+ failf(data, "SSL: failed retrieving public key from server certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ (const unsigned char *)pubkey->header,
+ (size_t)(pubkey->end - pubkey->header));
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ return result;
+ }
+#else
+ failf(data, "Library lacks pinning support built-in");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+
+#ifdef HAVE_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ int rc;
+ char *protocol = NULL;
+ unsigned short protocol_len = 0;
+
+ rc = wolfSSL_ALPN_GetProtocol(conssl->handle, &protocol, &protocol_len);
+
+ if(rc == SSL_SUCCESS) {
+ infof(data, "ALPN, server accepted to use %.*s\n", protocol_len,
+ protocol);
+
+ if(protocol_len == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH))
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+#ifdef USE_NGHTTP2
+ else if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+ protocol_len == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(protocol, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN))
+ conn->negnpn = CURL_HTTP_VERSION_2;
+#endif
+ else
+ infof(data, "ALPN, unrecognized protocol %.*s\n", protocol_len,
+ protocol);
+ }
+ else if(rc == SSL_ALPN_NOT_FOUND)
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ else {
+ failf(data, "ALPN, failure getting protocol, error %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif /* HAVE_ALPN */
+
+ conssl->connecting_state = ssl_connect_3;
+#if (LIBCYASSL_VERSION_HEX >= 0x03009010)
+ infof(data, "SSL connection using %s / %s\n",
+ wolfSSL_get_version(conssl->handle),
+ wolfSSL_get_cipher_name(conssl->handle));
+#else
+ infof(data, "SSL connected\n");
+#endif
+
+ return CURLE_OK;
+}
+
+
+static CURLcode
+cyassl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ SSL_SESSION *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+
+ our_ssl_sessionid = SSL_get_session(connssl->handle);
+
+ Curl_ssl_sessionid_lock(conn);
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+ sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+
+ if(!incache) {
+ result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+ 0 /* unknown size */, sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "failed to store ssl session");
+ return result;
+ }
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return result;
+}
+
+
+static ssize_t cyassl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ char error_buffer[CYASSL_MAX_ERROR_SZ];
+ int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+
+ if(rc < 0) {
+ int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_write() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data, "SSL write: %s, errno %d",
+ ERR_error_string(err, error_buffer),
+ SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ }
+ return rc;
+}
+
+void Curl_cyassl_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *conssl = &conn->ssl[sockindex];
+
+ if(conssl->handle) {
+ (void)SSL_shutdown(conssl->handle);
+ SSL_free(conssl->handle);
+ conssl->handle = NULL;
+ }
+ if(conssl->ctx) {
+ SSL_CTX_free(conssl->ctx);
+ conssl->ctx = NULL;
+ }
+}
+
+static ssize_t cyassl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ char error_buffer[CYASSL_MAX_ERROR_SZ];
+ int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ int nread = SSL_read(conn->ssl[num].handle, buf, buffsize);
+
+ if(nread < 0) {
+ int err = SSL_get_error(conn->ssl[num].handle, nread);
+
+ switch(err) {
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_read() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data, "SSL read: %s, errno %d",
+ ERR_error_string(err, error_buffer),
+ SOCKERRNO);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ return nread;
+}
+
+
+void Curl_cyassl_session_free(void *ptr)
+{
+ (void)ptr;
+ /* CyaSSL reuses sessions on own, no free */
+}
+
+
+size_t Curl_cyassl_version(char *buffer, size_t size)
+{
+#if LIBCYASSL_VERSION_HEX >= 0x03006000
+ return snprintf(buffer, size, "wolfSSL/%s", wolfSSL_lib_version());
+#elif defined(WOLFSSL_VERSION)
+ return snprintf(buffer, size, "wolfSSL/%s", WOLFSSL_VERSION);
+#elif defined(CYASSL_VERSION)
+ return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
+#else
+ return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
+#endif
+}
+
+
+int Curl_cyassl_init(void)
+{
+ return (CyaSSL_Init() == SSL_SUCCESS);
+}
+
+
+bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
+{
+ if(conn->ssl[connindex].handle) /* SSL is in use */
+ return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
+ else
+ return FALSE;
+}
+
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
+{
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->handle) {
+ SSL_free(connssl->handle);
+ connssl->handle = NULL;
+ }
+ return retval;
+}
+
+
+static CURLcode
+cyassl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ time_t timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = cyassl_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ result = cyassl_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = cyassl_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = cyassl_recv;
+ conn->send[sockindex] = cyassl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+
+CURLcode
+Curl_cyassl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return cyassl_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_cyassl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = cyassl_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_cyassl_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ RNG rng;
+ (void)data;
+ if(InitRng(&rng))
+ return CURLE_FAILED_INIT;
+ if(length > UINT_MAX)
+ return CURLE_FAILED_INIT;
+ if(RNG_GenerateBlock(&rng, entropy, (unsigned)length))
+ return CURLE_FAILED_INIT;
+ return CURLE_OK;
+}
+
+void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
+{
+ Sha256 SHA256pw;
+ (void)unused;
+ InitSha256(&SHA256pw);
+ Sha256Update(&SHA256pw, tmp, (word32)tmplen);
+ Sha256Final(&SHA256pw, sha256sum);
+}
+
+#endif
diff --git a/Utilities/cmcurl/lib/vtls/cyassl.h b/Utilities/cmcurl/lib/vtls/cyassl.h
new file mode 100644
index 000000000..f47719e4e
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/cyassl.h
@@ -0,0 +1,92 @@
+#ifndef HEADER_CURL_CYASSL_H
+#define HEADER_CURL_CYASSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_CYASSL
+
+/* KEEP_PEER_CERT is a product of the presence of build time symbol
+ OPENSSL_EXTRA without NO_CERTS, depending on the version. KEEP_PEER_CERT is
+ in wolfSSL's settings.h, and the latter two are build time symbols in
+ options.h. */
+#ifndef KEEP_PEER_CERT
+#if defined(HAVE_CYASSL_GET_PEER_CERTIFICATE) || \
+ defined(HAVE_WOLFSSL_GET_PEER_CERTIFICATE) || \
+ (defined(OPENSSL_EXTRA) && !defined(NO_CERTS))
+#define KEEP_PEER_CERT
+#endif
+#endif
+
+CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
+bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex);
+int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
+
+ /* close a SSL connection */
+void Curl_cyassl_close(struct connectdata *conn, int sockindex);
+
+void Curl_cyassl_session_free(void *ptr);
+size_t Curl_cyassl_version(char *buffer, size_t size);
+int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex);
+int Curl_cyassl_init(void);
+CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+CURLcode Curl_cyassl_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length);
+void Curl_cyassl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t unused);
+
+/* Set the API backend definition to CyaSSL */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_CYASSL
+
+/* this backend supports CURLOPT_SSL_CTX_* */
+#define have_curlssl_ssl_ctx 1
+
+#ifdef KEEP_PEER_CERT
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+#endif
+
+/* API setup for CyaSSL */
+#define curlssl_init Curl_cyassl_init
+#define curlssl_cleanup() Curl_nop_stmt
+#define curlssl_connect Curl_cyassl_connect
+#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking
+#define curlssl_session_free(x) Curl_cyassl_session_free(x)
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_cyassl_close
+#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y)
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_cyassl_version
+#define curlssl_check_cxn(x) ((void)x, -1)
+#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y)
+#define curlssl_random(x,y,z) Curl_cyassl_random(x,y,z)
+#define curlssl_sha256sum(a,b,c,d) Curl_cyassl_sha256sum(a,b,c,d)
+
+#endif /* USE_CYASSL */
+#endif /* HEADER_CURL_CYASSL_H */
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.c b/Utilities/cmcurl/lib/vtls/darwinssl.c
new file mode 100644
index 000000000..041766541
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/darwinssl.c
@@ -0,0 +1,2847 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all iOS and Mac OS X SecureTransport-specific code for the
+ * TLS/SSL layer. No code but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#include "urldata.h" /* for the Curl_easy definition */
+#include "curl_base64.h"
+#include "strtok.h"
+
+#ifdef USE_DARWINSSL
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <Security/Security.h>
+#include <Security/SecureTransport.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <CommonCrypto/CommonDigest.h>
+
+/* The Security framework has changed greatly between iOS and different OS X
+ versions, and we will try to support as many of them as we can (back to
+ Leopard and iOS 5) by using macros and weak-linking.
+
+ IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then
+ you must build this project against the 10.8 SDK or later. */
+#if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE))
+
+#if MAC_OS_X_VERSION_MAX_ALLOWED < 1050
+#error "The darwinssl back-end requires Leopard or later."
+#endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */
+
+#define CURL_BUILD_IOS 0
+#define CURL_BUILD_IOS_7 0
+#define CURL_BUILD_MAC 1
+/* This is the maximum API level we are allowed to use when building: */
+#define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050
+#define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+#define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
+#define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+#define CURL_BUILD_MAC_10_9 MAC_OS_X_VERSION_MAX_ALLOWED >= 1090
+/* These macros mean "the following code is present to allow runtime backward
+ compatibility with at least this cat or earlier":
+ (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET
+ environmental variable.) */
+#define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050
+#define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060
+#define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070
+#define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080
+#define CURL_SUPPORT_MAC_10_9 MAC_OS_X_VERSION_MIN_REQUIRED <= 1090
+
+#elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE
+#define CURL_BUILD_IOS 1
+#define CURL_BUILD_IOS_7 __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
+#define CURL_BUILD_MAC 0
+#define CURL_BUILD_MAC_10_5 0
+#define CURL_BUILD_MAC_10_6 0
+#define CURL_BUILD_MAC_10_7 0
+#define CURL_BUILD_MAC_10_8 0
+#define CURL_SUPPORT_MAC_10_5 0
+#define CURL_SUPPORT_MAC_10_6 0
+#define CURL_SUPPORT_MAC_10_7 0
+#define CURL_SUPPORT_MAC_10_8 0
+#define CURL_SUPPORT_MAC_10_9 0
+
+#else
+#error "The darwinssl back-end requires iOS or OS X."
+#endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */
+
+#if CURL_BUILD_MAC
+#include <sys/sysctl.h>
+#endif /* CURL_BUILD_MAC */
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "vtls.h"
+#include "darwinssl.h"
+#include "curl_printf.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* From MacTypes.h (which we can't include because it isn't present in iOS: */
+#define ioErr -36
+#define paramErr -50
+
+#ifdef DARWIN_SSL_PINNEDPUBKEY
+/* both new and old APIs return rsa keys missing the spki header (not DER) */
+static const unsigned char rsa4096SpkiHeader[] = {
+ 0x30, 0x82, 0x02, 0x22, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, 0x03, 0x82, 0x02, 0x0f, 0x00};
+
+static const unsigned char rsa2048SpkiHeader[] = {
+ 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d,
+ 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05,
+ 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00};
+#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+/* the *new* version doesn't return DER encoded ecdsa certs like the old... */
+static const unsigned char ecDsaSecp256r1SpkiHeader[] = {
+ 0x30, 0x59, 0x30, 0x13, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+ 0x01, 0x06, 0x08, 0x2a, 0x86, 0x48,
+ 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
+ 0x42, 0x00};
+
+static const unsigned char ecDsaSecp384r1SpkiHeader[] = {
+ 0x30, 0x76, 0x30, 0x10, 0x06, 0x07,
+ 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02,
+ 0x01, 0x06, 0x05, 0x2b, 0x81, 0x04,
+ 0x00, 0x22, 0x03, 0x62, 0x00};
+#endif /* DARWIN_SSL_PINNEDPUBKEY_V1 */
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+
+/* The following two functions were ripped from Apple sample code,
+ * with some modifications: */
+static OSStatus SocketRead(SSLConnectionRef connection,
+ void *data, /* owned by
+ * caller, data
+ * RETURNED */
+ size_t *dataLength) /* IN/OUT */
+{
+ size_t bytesToGo = *dataLength;
+ size_t initLen = bytesToGo;
+ UInt8 *currData = (UInt8 *)data;
+ /*int sock = *(int *)connection;*/
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ int sock = connssl->ssl_sockfd;
+ OSStatus rtn = noErr;
+ size_t bytesRead;
+ ssize_t rrtn;
+ int theErr;
+
+ *dataLength = 0;
+
+ for(;;) {
+ bytesRead = 0;
+ rrtn = read(sock, currData, bytesToGo);
+ if(rrtn <= 0) {
+ /* this is guesswork... */
+ theErr = errno;
+ if(rrtn == 0) { /* EOF = server hung up */
+ /* the framework will turn this into errSSLClosedNoNotify */
+ rtn = errSSLClosedGraceful;
+ }
+ else /* do the switch */
+ switch(theErr) {
+ case ENOENT:
+ /* connection closed */
+ rtn = errSSLClosedGraceful;
+ break;
+ case ECONNRESET:
+ rtn = errSSLClosedAbort;
+ break;
+ case EAGAIN:
+ rtn = errSSLWouldBlock;
+ connssl->ssl_direction = false;
+ break;
+ default:
+ rtn = ioErr;
+ break;
+ }
+ break;
+ }
+ else {
+ bytesRead = rrtn;
+ }
+ bytesToGo -= bytesRead;
+ currData += bytesRead;
+
+ if(bytesToGo == 0) {
+ /* filled buffer with incoming data, done */
+ break;
+ }
+ }
+ *dataLength = initLen - bytesToGo;
+
+ return rtn;
+}
+
+static OSStatus SocketWrite(SSLConnectionRef connection,
+ const void *data,
+ size_t *dataLength) /* IN/OUT */
+{
+ size_t bytesSent = 0;
+ /*int sock = *(int *)connection;*/
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ int sock = connssl->ssl_sockfd;
+ ssize_t length;
+ size_t dataLen = *dataLength;
+ const UInt8 *dataPtr = (UInt8 *)data;
+ OSStatus ortn;
+ int theErr;
+
+ *dataLength = 0;
+
+ do {
+ length = write(sock,
+ (char *)dataPtr + bytesSent,
+ dataLen - bytesSent);
+ } while((length > 0) &&
+ ( (bytesSent += length) < dataLen) );
+
+ if(length <= 0) {
+ theErr = errno;
+ if(theErr == EAGAIN) {
+ ortn = errSSLWouldBlock;
+ connssl->ssl_direction = true;
+ }
+ else {
+ ortn = ioErr;
+ }
+ }
+ else {
+ ortn = noErr;
+ }
+ *dataLength = bytesSent;
+ return ortn;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher)
+{
+ switch(cipher) {
+ /* SSL version 3.0 */
+ case SSL_RSA_WITH_NULL_MD5:
+ return "SSL_RSA_WITH_NULL_MD5";
+ break;
+ case SSL_RSA_WITH_NULL_SHA:
+ return "SSL_RSA_WITH_NULL_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ return "SSL_RSA_EXPORT_WITH_RC4_40_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_MD5:
+ return "SSL_RSA_WITH_RC4_128_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_SHA:
+ return "SSL_RSA_WITH_RC4_128_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5";
+ break;
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ return "SSL_RSA_WITH_IDEA_CBC_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ return "SSL_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ return "SSL_DH_DSS_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ return "SSL_DH_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ return "SSL_DHE_DSS_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ return "SSL_DHE_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
+ return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5";
+ break;
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ return "SSL_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ return "SSL_DH_anon_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ return "SSL_FORTEZZA_DMS_WITH_NULL_SHA";
+ break;
+ case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
+ return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
+ break;
+ /* TLS 1.0 with AES (RFC 3268)
+ (Apparently these are used in SSLv3 implementations as well.) */
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+ break;
+ /* SSL version 2.0 */
+ case SSL_RSA_WITH_RC2_CBC_MD5:
+ return "SSL_RSA_WITH_RC2_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ return "SSL_RSA_WITH_IDEA_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_DES_CBC_MD5:
+ return "SSL_RSA_WITH_DES_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
+ return "SSL_RSA_WITH_3DES_EDE_CBC_MD5";
+ break;
+ }
+ return "SSL_NULL_WITH_NULL_NULL";
+}
+
+CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher)
+{
+ switch(cipher) {
+ /* TLS 1.0 with AES (RFC 3268) */
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+ break;
+#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
+ /* TLS 1.0 with ECDSA (RFC 4492) */
+ case TLS_ECDH_ECDSA_WITH_NULL_SHA:
+ return "TLS_ECDH_ECDSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_NULL_SHA:
+ return "TLS_ECDH_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_NULL_SHA:
+ return "TLS_ECDHE_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_NULL_SHA:
+ return "TLS_ECDH_anon_WITH_NULL_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_RC4_128_SHA:
+ return "TLS_ECDH_anon_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
+ break;
+#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ /* TLS 1.2 (RFC 5246) */
+ case TLS_RSA_WITH_NULL_MD5:
+ return "TLS_RSA_WITH_NULL_MD5";
+ break;
+ case TLS_RSA_WITH_NULL_SHA:
+ return "TLS_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_RSA_WITH_RC4_128_MD5:
+ return "TLS_RSA_WITH_RC4_128_MD5";
+ break;
+ case TLS_RSA_WITH_RC4_128_SHA:
+ return "TLS_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_NULL_SHA256:
+ return "TLS_RSA_WITH_NULL_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ return "TLS_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
+ break;
+ /* TLS 1.2 with AES GCM (RFC 5288) */
+ case TLS_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
+ break;
+ /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+ return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+ break;
+#else
+ case SSL_RSA_WITH_NULL_MD5:
+ return "TLS_RSA_WITH_NULL_MD5";
+ break;
+ case SSL_RSA_WITH_NULL_SHA:
+ return "TLS_RSA_WITH_NULL_SHA";
+ break;
+ case SSL_RSA_WITH_RC4_128_MD5:
+ return "TLS_RSA_WITH_RC4_128_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_SHA:
+ return "TLS_RSA_WITH_RC4_128_SHA";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ return "TLS_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* TLS PSK (RFC 4279): */
+ case TLS_PSK_WITH_RC4_128_SHA:
+ return "TLS_PSK_WITH_RC4_128_SHA";
+ break;
+ case TLS_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_PSK_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_PSK_WITH_AES_128_CBC_SHA:
+ return "TLS_PSK_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_PSK_WITH_AES_256_CBC_SHA:
+ return "TLS_PSK_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_PSK_WITH_RC4_128_SHA:
+ return "TLS_DHE_PSK_WITH_RC4_128_SHA";
+ break;
+ case TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DHE_PSK_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DHE_PSK_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_PSK_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_RSA_PSK_WITH_RC4_128_SHA:
+ return "TLS_RSA_PSK_WITH_RC4_128_SHA";
+ break;
+ case TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_RSA_PSK_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_RSA_PSK_WITH_AES_128_CBC_SHA:
+ return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_RSA_PSK_WITH_AES_256_CBC_SHA:
+ return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA";
+ break;
+ /* More TLS PSK (RFC 4785): */
+ case TLS_PSK_WITH_NULL_SHA:
+ return "TLS_PSK_WITH_NULL_SHA";
+ break;
+ case TLS_DHE_PSK_WITH_NULL_SHA:
+ return "TLS_DHE_PSK_WITH_NULL_SHA";
+ break;
+ case TLS_RSA_PSK_WITH_NULL_SHA:
+ return "TLS_RSA_PSK_WITH_NULL_SHA";
+ break;
+ /* Even more TLS PSK (RFC 5487): */
+ case TLS_PSK_WITH_AES_128_GCM_SHA256:
+ return "TLS_PSK_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_PSK_WITH_AES_256_GCM_SHA384:
+ return "TLS_PSK_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DHE_PSK_WITH_AES_128_GCM_SHA256:
+ return "TLS_DHE_PSK_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DHE_PSK_WITH_AES_256_GCM_SHA384:
+ return "TLS_DHE_PSK_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_RSA_PSK_WITH_AES_128_GCM_SHA256:
+ return "TLS_RSA_PSK_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_RSA_PSK_WITH_AES_256_GCM_SHA384:
+ return "TLS_PSK_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_PSK_WITH_AES_128_CBC_SHA256:
+ return "TLS_PSK_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_PSK_WITH_AES_256_CBC_SHA384:
+ return "TLS_PSK_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_PSK_WITH_NULL_SHA256:
+ return "TLS_PSK_WITH_NULL_SHA256";
+ break;
+ case TLS_PSK_WITH_NULL_SHA384:
+ return "TLS_PSK_WITH_NULL_SHA384";
+ break;
+ case TLS_DHE_PSK_WITH_AES_128_CBC_SHA256:
+ return "TLS_DHE_PSK_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DHE_PSK_WITH_AES_256_CBC_SHA384:
+ return "TLS_DHE_PSK_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_DHE_PSK_WITH_NULL_SHA256:
+ return "TLS_DHE_PSK_WITH_NULL_SHA256";
+ break;
+ case TLS_DHE_PSK_WITH_NULL_SHA384:
+ return "TLS_RSA_PSK_WITH_NULL_SHA384";
+ break;
+ case TLS_RSA_PSK_WITH_AES_128_CBC_SHA256:
+ return "TLS_RSA_PSK_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_RSA_PSK_WITH_AES_256_CBC_SHA384:
+ return "TLS_RSA_PSK_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_RSA_PSK_WITH_NULL_SHA256:
+ return "TLS_RSA_PSK_WITH_NULL_SHA256";
+ break;
+ case TLS_RSA_PSK_WITH_NULL_SHA384:
+ return "TLS_RSA_PSK_WITH_NULL_SHA384";
+ break;
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+ }
+ return "TLS_NULL_WITH_NULL_NULL";
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+#if CURL_BUILD_MAC
+CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
+{
+ int mib[2];
+ char *os_version;
+ size_t os_version_len;
+ char *os_version_major, *os_version_minor;
+ char *tok_buf;
+
+ /* Get the Darwin kernel version from the kernel using sysctl(): */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELEASE;
+ if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
+ return;
+ os_version = malloc(os_version_len*sizeof(char));
+ if(!os_version)
+ return;
+ if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
+ free(os_version);
+ return;
+ }
+
+ /* Parse the version: */
+ os_version_major = strtok_r(os_version, ".", &tok_buf);
+ os_version_minor = strtok_r(NULL, ".", &tok_buf);
+ *major = atoi(os_version_major);
+ *minor = atoi(os_version_minor);
+ free(os_version);
+}
+#endif /* CURL_BUILD_MAC */
+
+/* Apple provides a myriad of ways of getting information about a certificate
+ into a string. Some aren't available under iOS or newer cats. So here's
+ a unified function for getting a string describing the certificate that
+ ought to work in all cats starting with Leopard. */
+CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
+{
+ CFStringRef server_cert_summary = CFSTR("(null)");
+
+#if CURL_BUILD_IOS
+ /* iOS: There's only one way to do this. */
+ server_cert_summary = SecCertificateCopySubjectSummary(cert);
+#else
+#if CURL_BUILD_MAC_10_7
+ /* Lion & later: Get the long description if we can. */
+ if(SecCertificateCopyLongDescription != NULL)
+ server_cert_summary =
+ SecCertificateCopyLongDescription(NULL, cert, NULL);
+ else
+#endif /* CURL_BUILD_MAC_10_7 */
+#if CURL_BUILD_MAC_10_6
+ /* Snow Leopard: Get the certificate summary. */
+ if(SecCertificateCopySubjectSummary != NULL)
+ server_cert_summary = SecCertificateCopySubjectSummary(cert);
+ else
+#endif /* CURL_BUILD_MAC_10_6 */
+ /* Leopard is as far back as we go... */
+ (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
+#endif /* CURL_BUILD_IOS */
+ return server_cert_summary;
+}
+
+#if CURL_SUPPORT_MAC_10_6
+/* The SecKeychainSearch API was deprecated in Lion, and using it will raise
+ deprecation warnings, so let's not compile this unless it's necessary: */
+static OSStatus CopyIdentityWithLabelOldSchool(char *label,
+ SecIdentityRef *out_c_a_k)
+{
+ OSStatus status = errSecItemNotFound;
+ SecKeychainAttributeList attr_list;
+ SecKeychainAttribute attr;
+ SecKeychainSearchRef search = NULL;
+ SecCertificateRef cert = NULL;
+
+ /* Set up the attribute list: */
+ attr_list.count = 1L;
+ attr_list.attr = &attr;
+
+ /* Set up our lone search criterion: */
+ attr.tag = kSecLabelItemAttr;
+ attr.data = label;
+ attr.length = (UInt32)strlen(label);
+
+ /* Start searching: */
+ status = SecKeychainSearchCreateFromAttributes(NULL,
+ kSecCertificateItemClass,
+ &attr_list,
+ &search);
+ if(status == noErr) {
+ status = SecKeychainSearchCopyNext(search,
+ (SecKeychainItemRef *)&cert);
+ if(status == noErr && cert) {
+ /* If we found a certificate, does it have a private key? */
+ status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k);
+ CFRelease(cert);
+ }
+ }
+
+ if(search)
+ CFRelease(search);
+ return status;
+}
+#endif /* CURL_SUPPORT_MAC_10_6 */
+
+static OSStatus CopyIdentityWithLabel(char *label,
+ SecIdentityRef *out_cert_and_key)
+{
+ OSStatus status = errSecItemNotFound;
+
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+ CFArrayRef keys_list;
+ CFIndex keys_list_count;
+ CFIndex i;
+ CFStringRef common_name;
+
+ /* SecItemCopyMatching() was introduced in iOS and Snow Leopard.
+ kSecClassIdentity was introduced in Lion. If both exist, let's use them
+ to find the certificate. */
+ if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) {
+ CFTypeRef keys[5];
+ CFTypeRef values[5];
+ CFDictionaryRef query_dict;
+ CFStringRef label_cf = CFStringCreateWithCString(NULL, label,
+ kCFStringEncodingUTF8);
+
+ /* Set up our search criteria and expected results: */
+ values[0] = kSecClassIdentity; /* we want a certificate and a key */
+ keys[0] = kSecClass;
+ values[1] = kCFBooleanTrue; /* we want a reference */
+ keys[1] = kSecReturnRef;
+ values[2] = kSecMatchLimitAll; /* kSecMatchLimitOne would be better if the
+ * label matching below worked correctly */
+ keys[2] = kSecMatchLimit;
+ /* identity searches need a SecPolicyRef in order to work */
+ values[3] = SecPolicyCreateSSL(false, NULL);
+ keys[3] = kSecMatchPolicy;
+ /* match the name of the certificate (doesn't work in macOS 10.12.1) */
+ values[4] = label_cf;
+ keys[4] = kSecAttrLabel;
+ query_dict = CFDictionaryCreate(NULL, (const void **)keys,
+ (const void **)values, 5L,
+ &kCFCopyStringDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFRelease(values[3]);
+
+ /* Do we have a match? */
+ status = SecItemCopyMatching(query_dict, (CFTypeRef *) &keys_list);
+
+ /* Because kSecAttrLabel matching doesn't work with kSecClassIdentity,
+ * we need to find the correct identity ourselves */
+ if(status == noErr) {
+ keys_list_count = CFArrayGetCount(keys_list);
+ *out_cert_and_key = NULL;
+ status = 1;
+ for(i=0; i<keys_list_count; i++) {
+ OSStatus err = noErr;
+ SecCertificateRef cert = NULL;
+ SecIdentityRef identity =
+ (SecIdentityRef) CFArrayGetValueAtIndex(keys_list, i);
+ err = SecIdentityCopyCertificate(identity, &cert);
+ if(err == noErr) {
+#if CURL_BUILD_IOS
+ common_name = SecCertificateCopySubjectSummary(cert);
+#elif CURL_BUILD_MAC_10_7
+ SecCertificateCopyCommonName(cert, &common_name);
+#endif
+ if(CFStringCompare(common_name, label_cf, 0) == kCFCompareEqualTo) {
+ CFRelease(cert);
+ CFRelease(common_name);
+ CFRetain(identity);
+ *out_cert_and_key = identity;
+ status = noErr;
+ break;
+ }
+ CFRelease(common_name);
+ }
+ CFRelease(cert);
+ }
+ }
+
+ if(keys_list)
+ CFRelease(keys_list);
+ CFRelease(query_dict);
+ CFRelease(label_cf);
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_6
+ /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */
+ status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
+#endif /* CURL_SUPPORT_MAC_10_6 */
+ }
+#elif CURL_SUPPORT_MAC_10_6
+ /* For developers building on older cats, we have no choice but to fall back
+ to SecKeychainSearch. */
+ status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key);
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+ return status;
+}
+
+static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
+ const char *cPassword,
+ SecIdentityRef *out_cert_and_key)
+{
+ OSStatus status = errSecItemNotFound;
+ CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
+ (const UInt8 *)cPath, strlen(cPath), false);
+ CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
+ cPassword, kCFStringEncodingUTF8) : NULL;
+ CFDataRef pkcs_data = NULL;
+
+ /* We can import P12 files on iOS or OS X 10.7 or later: */
+ /* These constants are documented as having first appeared in 10.6 but they
+ raise linker errors when used on that cat for some reason. */
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+ if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
+ NULL, NULL, &status)) {
+ const void *cKeys[] = {kSecImportExportPassphrase};
+ const void *cValues[] = {password};
+ CFDictionaryRef options = CFDictionaryCreate(NULL, cKeys, cValues,
+ password ? 1L : 0L, NULL, NULL);
+ CFArrayRef items = NULL;
+
+ /* Here we go: */
+ status = SecPKCS12Import(pkcs_data, options, &items);
+ if(status == errSecSuccess && items && CFArrayGetCount(items)) {
+ CFDictionaryRef identity_and_trust = CFArrayGetValueAtIndex(items, 0L);
+ const void *temp_identity = CFDictionaryGetValue(identity_and_trust,
+ kSecImportItemIdentity);
+
+ /* Retain the identity; we don't care about any other data... */
+ CFRetain(temp_identity);
+ *out_cert_and_key = (SecIdentityRef)temp_identity;
+ }
+
+ if(items)
+ CFRelease(items);
+ CFRelease(options);
+ CFRelease(pkcs_data);
+ }
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+ if(password)
+ CFRelease(password);
+ CFRelease(pkcs_url);
+ return status;
+}
+
+/* This code was borrowed from nss.c, with some modifications:
+ * Determine whether the nickname passed in is a filename that needs to
+ * be loaded as a PEM or a regular NSS nickname.
+ *
+ * returns 1 for a file
+ * returns 0 for not a file
+ */
+CF_INLINE bool is_file(const char *filename)
+{
+ struct_stat st;
+
+ if(filename == NULL)
+ return false;
+
+ if(stat(filename, &st) == 0)
+ return S_ISREG(st.st_mode);
+ return false;
+}
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+static CURLcode darwinssl_version_from_curl(long *darwinver, long ssl_version)
+{
+ switch(ssl_version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ *darwinver = kTLSProtocol1;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1:
+ *darwinver = kTLSProtocol11;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2:
+ *darwinver = kTLSProtocol12;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+#endif
+
+static CURLcode
+set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version << 16;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLSetProtocolVersionMax != NULL) {
+ SSLProtocol darwin_ver_min = kTLSProtocol1;
+ SSLProtocol darwin_ver_max = kTLSProtocol1;
+ CURLcode result = darwinssl_version_from_curl(&darwin_ver_min,
+ ssl_version);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ result = darwinssl_version_from_curl(&darwin_ver_max,
+ ssl_version_max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, darwin_ver_min);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, darwin_ver_max);
+ return result;
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ long i = ssl_version;
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocolAll,
+ false);
+ for(; i <= (ssl_version_max >> 16); i++) {
+ switch(i) {
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "DarwinSSL: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ return CURLE_OK;
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+ failf(data, "DarwinSSL: cannot set SSL protocol");
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode darwinssl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif /* ENABLE_IPV6 */
+ size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i;
+ SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL;
+ OSStatus err = noErr;
+#if CURL_BUILD_MAC
+ int darwinver_maj = 0, darwinver_min = 0;
+
+ GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
+
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLCreateContext != NULL) { /* use the newer API if avaialble */
+ if(connssl->ssl_ctx)
+ CFRelease(connssl->ssl_ctx);
+ connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+ if(!connssl->ssl_ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else {
+ /* The old ST API does not exist under iOS, so don't compile it: */
+#if CURL_SUPPORT_MAC_10_8
+ if(connssl->ssl_ctx)
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+ err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(err != noErr) {
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ if(connssl->ssl_ctx)
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+ err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(err != noErr) {
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+ connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */
+
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLSetProtocolVersionMax != NULL) {
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2);
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocolAll,
+ false);
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol2,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ if(conn->ssl_config.version_max != CURL_SSLVERSION_MAX_NONE) {
+ failf(data, "Your version of the OS does not support to set maximum"
+ " SSL/TLS version");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ failf(data, "Your version of the OS does not support TLSv1.1");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_2:
+ failf(data, "Your version of the OS does not support TLSv1.2");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Your version of the OS does not support TLSv1.3");
+ return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_SSLv2:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol2,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ if(err != noErr) {
+ failf(data, "Your version of the OS does not support SSLv3");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+ if(SSL_SET_OPTION(key)) {
+ infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure "
+ "Transport. The private key must be in the Keychain.\n");
+ }
+
+ if(ssl_cert) {
+ SecIdentityRef cert_and_key = NULL;
+ bool is_cert_file = is_file(ssl_cert);
+
+ /* User wants to authenticate with a client cert. Look for it:
+ If we detect that this is a file on disk, then let's load it.
+ Otherwise, assume that the user wants to use an identity loaded
+ from the Keychain. */
+ if(is_cert_file) {
+ if(!SSL_SET_OPTION(cert_type))
+ infof(data, "WARNING: SSL: Certificate type not set, assuming "
+ "PKCS#12 format.\n");
+ else if(strncmp(SSL_SET_OPTION(cert_type), "P12",
+ strlen(SSL_SET_OPTION(cert_type))) != 0)
+ infof(data, "WARNING: SSL: The Security framework only supports "
+ "loading identities that are in PKCS#12 format.\n");
+
+ err = CopyIdentityFromPKCS12File(ssl_cert,
+ SSL_SET_OPTION(key_passwd), &cert_and_key);
+ }
+ else
+ err = CopyIdentityWithLabel(ssl_cert, &cert_and_key);
+
+ if(err == noErr && cert_and_key) {
+ SecCertificateRef cert = NULL;
+ CFTypeRef certs_c[1];
+ CFArrayRef certs;
+
+ /* If we found one, print it out: */
+ err = SecIdentityCopyCertificate(cert_and_key, &cert);
+ if(err == noErr) {
+ CFStringRef cert_summary = CopyCertSubject(cert);
+ char cert_summary_c[128];
+
+ if(cert_summary) {
+ memset(cert_summary_c, 0, 128);
+ if(CFStringGetCString(cert_summary,
+ cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Client certificate: %s\n", cert_summary_c);
+ }
+ CFRelease(cert_summary);
+ CFRelease(cert);
+ }
+ }
+ certs_c[0] = cert_and_key;
+ certs = CFArrayCreate(NULL, (const void **)certs_c, 1L,
+ &kCFTypeArrayCallBacks);
+ err = SSLSetCertificate(connssl->ssl_ctx, certs);
+ if(certs)
+ CFRelease(certs);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ CFRelease(cert_and_key);
+ }
+ else {
+ switch(err) {
+ case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
+ failf(data, "SSL: Incorrect password for the certificate \"%s\" "
+ "and its private key.", ssl_cert);
+ break;
+ case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
+ failf(data, "SSL: Couldn't make sense of the data in the "
+ "certificate \"%s\" and its private key.",
+ ssl_cert);
+ break;
+ case -25260: /* errSecPassphraseRequired */
+ failf(data, "SSL The certificate \"%s\" requires a password.",
+ ssl_cert);
+ break;
+ case errSecItemNotFound:
+ failf(data, "SSL: Can't find the certificate \"%s\" and its private "
+ "key in the Keychain.", ssl_cert);
+ break;
+ default:
+ failf(data, "SSL: Can't load the certificate \"%s\" and its private "
+ "key: OSStatus %d", ssl_cert, err);
+ break;
+ }
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* SSL always tries to verify the peer, this only says whether it should
+ * fail to connect if the verification fails, or if it should continue
+ * anyway. In the latter case the result of the verification is checked with
+ * SSL_get_verify_result() below. */
+#if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS
+ /* Snow Leopard introduced the SSLSetSessionOption() function, but due to
+ a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag
+ works, it doesn't work as expected under Snow Leopard, Lion or
+ Mountain Lion.
+ So we need to call SSLSetEnableCertVerify() on those older cats in order
+ to disable certificate validation if the user turned that off.
+ (SecureTransport will always validate the certificate chain by
+ default.)
+ Note:
+ Darwin 11.x.x is Lion (10.7)
+ Darwin 12.x.x is Mountain Lion (10.8)
+ Darwin 13.x.x is Mavericks (10.9)
+ Darwin 14.x.x is Yosemite (10.10)
+ Darwin 15.x.x is El Capitan (10.11)
+ */
+#if CURL_BUILD_MAC
+ if(SSLSetSessionOption != NULL && darwinver_maj >= 13) {
+#else
+ if(SSLSetSessionOption != NULL) {
+#endif /* CURL_BUILD_MAC */
+ bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile;
+ err = SSLSetSessionOption(connssl->ssl_ctx,
+ kSSLSessionOptionBreakOnServerAuth,
+ break_on_auth);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ err = SSLSetEnableCertVerify(connssl->ssl_ctx,
+ conn->ssl_config.verifypeer?true:false);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ err = SSLSetEnableCertVerify(connssl->ssl_ctx,
+ conn->ssl_config.verifypeer?true:false);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
+
+ if(ssl_cafile && verifypeer) {
+ bool is_cert_file = is_file(ssl_cafile);
+
+ if(!is_cert_file) {
+ failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ /* Configure hostname check. SNI is used if available.
+ * Both hostname check and SNI require SSLSetPeerDomainName().
+ * Also: the verifyhost setting influences SNI usage */
+ if(conn->ssl_config.verifyhost) {
+ err = SSLSetPeerDomainName(connssl->ssl_ctx, hostname,
+ strlen(hostname));
+
+ if(err != noErr) {
+ infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
+ err);
+ }
+
+ if((Curl_inet_pton(AF_INET, hostname, &addr))
+ #ifdef ENABLE_IPV6
+ || (Curl_inet_pton(AF_INET6, hostname, &addr))
+ #endif
+ ) {
+ infof(data, "WARNING: using IP address, SNI is being disabled by "
+ "the OS.\n");
+ }
+ }
+ else {
+ infof(data, "WARNING: disabling hostname validation also disables SNI.\n");
+ }
+
+ /* Disable cipher suites that ST supports but are not safe. These ciphers
+ are unlikely to be used in any case since ST gives other ciphers a much
+ higher priority, but it's probably better that we not connect at all than
+ to give the user a false sense of security if the server only supports
+ insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
+ (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count);
+ all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(all_ciphers && allowed_ciphers &&
+ SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
+ &all_ciphers_count) == noErr) {
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+#if CURL_BUILD_MAC
+ /* There's a known bug in early versions of Mountain Lion where ST's ECC
+ ciphers (cipher suite 0xC001 through 0xC032) simply do not work.
+ Work around the problem here by disabling those ciphers if we are
+ running in an affected version of OS X. */
+ if(darwinver_maj == 12 && darwinver_min <= 3 &&
+ all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+ continue;
+ }
+#endif /* CURL_BUILD_MAC */
+ switch(all_ciphers[i]) {
+ /* Disable NULL ciphersuites: */
+ case SSL_NULL_WITH_NULL_NULL:
+ case SSL_RSA_WITH_NULL_MD5:
+ case SSL_RSA_WITH_NULL_SHA:
+ case 0x003B: /* TLS_RSA_WITH_NULL_SHA256 */
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ case 0xC001: /* TLS_ECDH_ECDSA_WITH_NULL_SHA */
+ case 0xC006: /* TLS_ECDHE_ECDSA_WITH_NULL_SHA */
+ case 0xC00B: /* TLS_ECDH_RSA_WITH_NULL_SHA */
+ case 0xC010: /* TLS_ECDHE_RSA_WITH_NULL_SHA */
+ case 0x002C: /* TLS_PSK_WITH_NULL_SHA */
+ case 0x002D: /* TLS_DHE_PSK_WITH_NULL_SHA */
+ case 0x002E: /* TLS_RSA_PSK_WITH_NULL_SHA */
+ case 0x00B0: /* TLS_PSK_WITH_NULL_SHA256 */
+ case 0x00B1: /* TLS_PSK_WITH_NULL_SHA384 */
+ case 0x00B4: /* TLS_DHE_PSK_WITH_NULL_SHA256 */
+ case 0x00B5: /* TLS_DHE_PSK_WITH_NULL_SHA384 */
+ case 0x00B8: /* TLS_RSA_PSK_WITH_NULL_SHA256 */
+ case 0x00B9: /* TLS_RSA_PSK_WITH_NULL_SHA384 */
+ /* Disable anonymous ciphersuites: */
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
+ case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
+ case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
+ case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
+ case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
+ case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
+ case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
+ case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
+ case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
+ /* Disable weak key ciphersuites: */
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ /* Disable IDEA: */
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ /* Disable RC4: */
+ case SSL_RSA_WITH_RC4_128_MD5:
+ case SSL_RSA_WITH_RC4_128_SHA:
+ case 0xC002: /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA */
+ case 0xC007: /* TLS_ECDHE_ECDSA_WITH_RC4_128_SHA*/
+ case 0xC00C: /* TLS_ECDH_RSA_WITH_RC4_128_SHA */
+ case 0xC011: /* TLS_ECDHE_RSA_WITH_RC4_128_SHA */
+ case 0x008A: /* TLS_PSK_WITH_RC4_128_SHA */
+ case 0x008E: /* TLS_DHE_PSK_WITH_RC4_128_SHA */
+ case 0x0092: /* TLS_RSA_PSK_WITH_RC4_128_SHA */
+ break;
+ default: /* enable everything else */
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ break;
+ }
+ }
+ err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ failf(data, "SSL: Failed to allocate memory for allowed ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ /* We want to enable 1/n-1 when using a CBC cipher unless the user
+ specifically doesn't want us doing that: */
+ if(SSLSetSessionOption != NULL) {
+ /* TODO s/data->set.ssl.enable_beast/SSL_SET_OPTION(enable_beast)/g */
+ SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionSendOneByteRecord,
+ !data->set.ssl.enable_beast);
+ SSLSetSessionOption(connssl->ssl_ctx, kSSLSessionOptionFalseStart,
+ data->set.ssl.falsestart); /* false start support */
+ }
+#endif /* CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7 */
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ char *ssl_sessionid;
+ size_t ssl_sessionid_len;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid,
+ &ssl_sessionid_len, sockindex)) {
+ /* we got a session id, use it! */
+ err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+ Curl_ssl_sessionid_unlock(conn);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof(data, "SSL re-using session ID\n");
+ }
+ /* If there isn't one, then let's make one up! This has to be done prior
+ to starting the handshake. */
+ else {
+ CURLcode result;
+ ssl_sessionid =
+ aprintf("%s:%d:%d:%s:%hu", ssl_cafile,
+ verifypeer, SSL_CONN_CONFIG(verifyhost), hostname, port);
+ ssl_sessionid_len = strlen(ssl_sessionid);
+
+ err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len);
+ if(err != noErr) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ result = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len,
+ sockindex);
+ Curl_ssl_sessionid_unlock(conn);
+ if(result) {
+ failf(data, "failed to store ssl session");
+ return result;
+ }
+ }
+ }
+
+ err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* pass the raw socket into the SSL layers */
+ /* We need to store the FD in a constant memory address, because
+ * SSLSetConnection() will not copy that address. I've found that
+ * conn->sock[sockindex] may change on its own. */
+ connssl->ssl_sockfd = sockfd;
+ err = SSLSetConnection(connssl->ssl_ctx, connssl);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetConnection() failed: %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
+{
+ char *sep_start, *sep_end, *cert_start, *cert_end;
+ size_t i, j, err;
+ size_t len;
+ unsigned char *b64;
+
+ /* Jump through the separators at the beginning of the certificate. */
+ sep_start = strstr(in, "-----");
+ if(sep_start == NULL)
+ return 0;
+ cert_start = strstr(sep_start + 1, "-----");
+ if(cert_start == NULL)
+ return -1;
+
+ cert_start += 5;
+
+ /* Find separator after the end of the certificate. */
+ cert_end = strstr(cert_start, "-----");
+ if(cert_end == NULL)
+ return -1;
+
+ sep_end = strstr(cert_end + 1, "-----");
+ if(sep_end == NULL)
+ return -1;
+ sep_end += 5;
+
+ len = cert_end - cert_start;
+ b64 = malloc(len + 1);
+ if(!b64)
+ return -1;
+
+ /* Create base64 string without linefeeds. */
+ for(i = 0, j = 0; i < len; i++) {
+ if(cert_start[i] != '\r' && cert_start[i] != '\n')
+ b64[j++] = cert_start[i];
+ }
+ b64[j] = '\0';
+
+ err = Curl_base64_decode((const char *)b64, out, outlen);
+ free(b64);
+ if(err) {
+ free(*out);
+ return -1;
+ }
+
+ return sep_end - in;
+}
+
+static int read_cert(const char *file, unsigned char **out, size_t *outlen)
+{
+ int fd;
+ ssize_t n, len = 0, cap = 512;
+ unsigned char buf[cap], *data;
+
+ fd = open(file, 0);
+ if(fd < 0)
+ return -1;
+
+ data = malloc(cap);
+ if(!data) {
+ close(fd);
+ return -1;
+ }
+
+ for(;;) {
+ n = read(fd, buf, sizeof(buf));
+ if(n < 0) {
+ close(fd);
+ free(data);
+ return -1;
+ }
+ else if(n == 0) {
+ close(fd);
+ break;
+ }
+
+ if(len + n >= cap) {
+ cap *= 2;
+ data = realloc(data, cap);
+ if(!data) {
+ close(fd);
+ return -1;
+ }
+ }
+
+ memcpy(data + len, buf, n);
+ len += n;
+ }
+ data[len] = '\0';
+
+ *out = data;
+ *outlen = len;
+
+ return 0;
+}
+
+static int sslerr_to_curlerr(struct Curl_easy *data, int err)
+{
+ switch(err) {
+ case errSSLXCertChainInvalid:
+ failf(data, "SSL certificate problem: Invalid certificate chain");
+ return CURLE_SSL_CACERT;
+ case errSSLUnknownRootCert:
+ failf(data, "SSL certificate problem: Untrusted root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLNoRootCert:
+ failf(data, "SSL certificate problem: No root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLCertExpired:
+ failf(data, "SSL certificate problem: Certificate chain had an "
+ "expired certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLBadCert:
+ failf(data, "SSL certificate problem: Couldn't understand the server "
+ "certificate format");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLHostNameMismatch:
+ failf(data, "SSL certificate peer hostname mismatch");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ default:
+ failf(data, "SSL unexpected certificate error %d", err);
+ return CURLE_SSL_CACERT;
+ }
+}
+
+static int append_cert_to_array(struct Curl_easy *data,
+ unsigned char *buf, size_t buflen,
+ CFMutableArrayRef array)
+{
+ CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
+ if(!certdata) {
+ failf(data, "SSL: failed to allocate array for CA certificate");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ SecCertificateRef cacert =
+ SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
+ CFRelease(certdata);
+ if(!cacert) {
+ failf(data, "SSL: failed to create SecCertificate from CA certificate");
+ return CURLE_SSL_CACERT;
+ }
+
+ /* Check if cacert is valid. */
+ CFStringRef subject = CopyCertSubject(cacert);
+ if(subject) {
+ char subject_cbuf[128];
+ memset(subject_cbuf, 0, 128);
+ if(!CFStringGetCString(subject,
+ subject_cbuf,
+ 128,
+ kCFStringEncodingUTF8)) {
+ CFRelease(cacert);
+ failf(data, "SSL: invalid CA certificate subject");
+ return CURLE_SSL_CACERT;
+ }
+ CFRelease(subject);
+ }
+ else {
+ CFRelease(cacert);
+ failf(data, "SSL: invalid CA certificate");
+ return CURLE_SSL_CACERT;
+ }
+
+ CFArrayAppendValue(array, cacert);
+ CFRelease(cacert);
+
+ return CURLE_OK;
+}
+
+static int verify_cert(const char *cafile, struct Curl_easy *data,
+ SSLContextRef ctx)
+{
+ int n = 0, rc;
+ long res;
+ unsigned char *certbuf, *der;
+ size_t buflen, derlen, offset = 0;
+
+ if(read_cert(cafile, &certbuf, &buflen) < 0) {
+ failf(data, "SSL: failed to read or invalid CA certificate");
+ return CURLE_SSL_CACERT;
+ }
+
+ /*
+ * Certbuf now contains the contents of the certificate file, which can be
+ * - a single DER certificate,
+ * - a single PEM certificate or
+ * - a bunch of PEM certificates (certificate bundle).
+ *
+ * Go through certbuf, and convert any PEM certificate in it into DER
+ * format.
+ */
+ CFMutableArrayRef array = CFArrayCreateMutable(kCFAllocatorDefault, 0,
+ &kCFTypeArrayCallBacks);
+ if(array == NULL) {
+ free(certbuf);
+ failf(data, "SSL: out of memory creating CA certificate array");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ while(offset < buflen) {
+ n++;
+
+ /*
+ * Check if the certificate is in PEM format, and convert it to DER. If
+ * this fails, we assume the certificate is in DER format.
+ */
+ res = pem_to_der((const char *)certbuf + offset, &der, &derlen);
+ if(res < 0) {
+ free(certbuf);
+ CFRelease(array);
+ failf(data, "SSL: invalid CA certificate #%d (offset %d) in bundle",
+ n, offset);
+ return CURLE_SSL_CACERT;
+ }
+ offset += res;
+
+ if(res == 0 && offset == 0) {
+ /* This is not a PEM file, probably a certificate in DER format. */
+ rc = append_cert_to_array(data, certbuf, buflen, array);
+ free(certbuf);
+ if(rc != CURLE_OK) {
+ CFRelease(array);
+ return rc;
+ }
+ break;
+ }
+ else if(res == 0) {
+ /* No more certificates in the bundle. */
+ free(certbuf);
+ break;
+ }
+
+ rc = append_cert_to_array(data, der, derlen, array);
+ free(der);
+ if(rc != CURLE_OK) {
+ free(certbuf);
+ CFRelease(array);
+ return rc;
+ }
+ }
+
+ SecTrustRef trust;
+ OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
+ if(trust == NULL) {
+ failf(data, "SSL: error getting certificate chain");
+ CFRelease(array);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(ret != noErr) {
+ CFRelease(array);
+ return sslerr_to_curlerr(data, ret);
+ }
+
+ ret = SecTrustSetAnchorCertificates(trust, array);
+ if(ret != noErr) {
+ CFRelease(trust);
+ return sslerr_to_curlerr(data, ret);
+ }
+ ret = SecTrustSetAnchorCertificatesOnly(trust, true);
+ if(ret != noErr) {
+ CFRelease(trust);
+ return sslerr_to_curlerr(data, ret);
+ }
+
+ SecTrustResultType trust_eval = 0;
+ ret = SecTrustEvaluate(trust, &trust_eval);
+ CFRelease(array);
+ CFRelease(trust);
+ if(ret != noErr) {
+ return sslerr_to_curlerr(data, ret);
+ }
+
+ switch(trust_eval) {
+ case kSecTrustResultUnspecified:
+ case kSecTrustResultProceed:
+ return CURLE_OK;
+
+ case kSecTrustResultRecoverableTrustFailure:
+ case kSecTrustResultDeny:
+ default:
+ failf(data, "SSL: certificate verification failed (result: %d)",
+ trust_eval);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+}
+
+#ifdef DARWIN_SSL_PINNEDPUBKEY
+static CURLcode pkp_pin_peer_pubkey(struct SessionHandle *data,
+ SSLContextRef ctx,
+ const char *pinnedpubkey)
+{ /* Scratch */
+ size_t pubkeylen, realpubkeylen, spkiHeaderLength = 24;
+ unsigned char *pubkey = NULL, *realpubkey = NULL, *spkiHeader = NULL;
+ CFDataRef publicKeyBits = NULL;
+
+ /* Result is returned to caller */
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ /* if a path wasn't specified, don't pin */
+ if(!pinnedpubkey)
+ return CURLE_OK;
+
+
+ if(!ctx)
+ return result;
+
+ do {
+ SecTrustRef trust;
+ OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
+ if(ret != noErr || trust == NULL)
+ break;
+
+ SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
+ CFRelease(trust);
+ if(keyRef == NULL)
+ break;
+
+#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+
+ publicKeyBits = SecKeyCopyExternalRepresentation(keyRef, NULL);
+ CFRelease(keyRef);
+ if(publicKeyBits == NULL)
+ break;
+
+#elif DARWIN_SSL_PINNEDPUBKEY_V2
+
+ OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+ &publicKeyBits);
+ CFRelease(keyRef);
+ if(success != errSecSuccess || publicKeyBits == NULL)
+ break;
+
+#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */
+
+ pubkeylen = CFDataGetLength(publicKeyBits);
+ pubkey = CFDataGetBytePtr(publicKeyBits);
+
+ switch(pubkeylen) {
+ case 526:
+ /* 4096 bit RSA pubkeylen == 526 */
+ spkiHeader = rsa4096SpkiHeader;
+ break;
+ case 270:
+ /* 2048 bit RSA pubkeylen == 270 */
+ spkiHeader = rsa2048SpkiHeader;
+ break;
+#ifdef DARWIN_SSL_PINNEDPUBKEY_V1
+ case 65:
+ /* ecDSA secp256r1 pubkeylen == 65 */
+ spkiHeader = ecDsaSecp256r1SpkiHeader;
+ spkiHeaderLength = 26;
+ break;
+ case 97:
+ /* ecDSA secp384r1 pubkeylen == 97 */
+ spkiHeader = ecDsaSecp384r1SpkiHeader;
+ spkiHeaderLength = 23;
+ break;
+ default:
+ infof(data, "SSL: unhandled public key length: %d\n", pubkeylen);
+#elif DARWIN_SSL_PINNEDPUBKEY_V2
+ default:
+ /* ecDSA secp256r1 pubkeylen == 91 header already included?
+ * ecDSA secp384r1 header already included too
+ * we assume rest of algorithms do same, so do nothing
+ */
+ result = Curl_pin_peer_pubkey(data, pinnedpubkey, pubkey,
+ pubkeylen);
+#endif /* DARWIN_SSL_PINNEDPUBKEY_V2 */
+ continue; /* break from loop */
+ }
+
+ realpubkeylen = pubkeylen + spkiHeaderLength;
+ realpubkey = malloc(realpubkeylen);
+ if(!realpubkey)
+ break;
+
+ memcpy(realpubkey, spkiHeader, spkiHeaderLength);
+ memcpy(realpubkey + spkiHeaderLength, pubkey, pubkeylen);
+
+ result = Curl_pin_peer_pubkey(data, pinnedpubkey, realpubkey,
+ realpubkeylen);
+
+ } while(0);
+
+ Curl_safefree(realpubkey);
+ if(publicKeyBits != NULL)
+ CFRelease(publicKeyBits);
+
+ return result;
+}
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+
+static CURLcode
+darwinssl_connect_step2(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ OSStatus err;
+ SSLCipherSuite cipher;
+ SSLProtocol protocol = 0;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
+
+ /* Here goes nothing: */
+ err = SSLHandshake(connssl->ssl_ctx);
+
+ if(err != noErr) {
+ switch(err) {
+ case errSSLWouldBlock: /* they're not done with us yet */
+ connssl->connecting_state = connssl->ssl_direction ?
+ ssl_connect_2_writing : ssl_connect_2_reading;
+ return CURLE_OK;
+
+ /* The below is errSSLServerAuthCompleted; it's not defined in
+ Leopard's headers */
+ case -9841:
+ if(SSL_CONN_CONFIG(CAfile) && SSL_CONN_CONFIG(verifypeer)) {
+ int res = verify_cert(SSL_CONN_CONFIG(CAfile), data,
+ connssl->ssl_ctx);
+ if(res != CURLE_OK)
+ return res;
+ }
+ /* the documentation says we need to call SSLHandshake() again */
+ return darwinssl_connect_step2(conn, sockindex);
+
+ /* These are all certificate problems with the server: */
+ case errSSLXCertChainInvalid:
+ failf(data, "SSL certificate problem: Invalid certificate chain");
+ return CURLE_SSL_CACERT;
+ case errSSLUnknownRootCert:
+ failf(data, "SSL certificate problem: Untrusted root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLNoRootCert:
+ failf(data, "SSL certificate problem: No root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLCertExpired:
+ failf(data, "SSL certificate problem: Certificate chain had an "
+ "expired certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLBadCert:
+ failf(data, "SSL certificate problem: Couldn't understand the server "
+ "certificate format");
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* These are all certificate problems with the client: */
+ case errSecAuthFailed:
+ failf(data, "SSL authentication failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLPeerHandshakeFail:
+ failf(data, "SSL peer handshake failed, the server most likely "
+ "requires a client certificate to connect");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLPeerUnknownCA:
+ failf(data, "SSL server rejected the client certificate due to "
+ "the certificate being signed by an unknown certificate "
+ "authority");
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* This error is raised if the server's cert didn't match the server's
+ host name: */
+ case errSSLHostNameMismatch:
+ failf(data, "SSL certificate peer verification failed, the "
+ "certificate did not match \"%s\"\n", conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ /* Generic handshake errors: */
+ case errSSLConnectionRefused:
+ failf(data, "Server dropped the connection during the SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLClosedAbort:
+ failf(data, "Server aborted the SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLNegotiation:
+ failf(data, "Could not negotiate an SSL cipher suite with the server");
+ return CURLE_SSL_CONNECT_ERROR;
+ /* Sometimes paramErr happens with buggy ciphers: */
+ case paramErr: case errSSLInternal:
+ failf(data, "Internal SSL engine error encountered during the "
+ "SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLFatalAlert:
+ failf(data, "Fatal SSL engine error encountered during the SSL "
+ "handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unknown SSL protocol error in connection to %s:%d",
+ hostname, err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ /* we have been connected fine, we're not waiting for anything else. */
+ connssl->connecting_state = ssl_connect_3;
+
+#ifdef DARWIN_SSL_PINNEDPUBKEY
+ if(data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]) {
+ CURLcode result = pkp_pin_peer_pubkey(data, connssl->ssl_ctx,
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG]);
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ return result;
+ }
+ }
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+
+ /* Informational message */
+ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher);
+ (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol);
+ switch(protocol) {
+ case kSSLProtocol2:
+ infof(data, "SSL 2.0 connection using %s\n",
+ SSLCipherNameForNumber(cipher));
+ break;
+ case kSSLProtocol3:
+ infof(data, "SSL 3.0 connection using %s\n",
+ SSLCipherNameForNumber(cipher));
+ break;
+ case kTLSProtocol1:
+ infof(data, "TLS 1.0 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ case kTLSProtocol11:
+ infof(data, "TLS 1.1 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+ case kTLSProtocol12:
+ infof(data, "TLS 1.2 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+#endif
+ default:
+ infof(data, "Unknown protocol connection\n");
+ break;
+ }
+
+ return CURLE_OK;
+ }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+/* This should be called during step3 of the connection at the earliest */
+static void
+show_verbose_server_cert(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CFStringRef server_cert_summary;
+ char server_cert_summary_c[128];
+ CFArrayRef server_certs = NULL;
+ SecCertificateRef server_cert;
+ OSStatus err;
+ CFIndex i, count;
+ SecTrustRef trust = NULL;
+
+ if(!connssl->ssl_ctx)
+ return;
+
+#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+#if CURL_BUILD_IOS
+#pragma unused(server_certs)
+ err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
+ a null trust, so be on guard for that: */
+ if(err == noErr && trust) {
+ count = SecTrustGetCertificateCount(trust);
+ for(i = 0L ; i < count ; i++) {
+ server_cert = SecTrustGetCertificateAtIndex(trust, i);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(trust);
+ }
+#else
+ /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
+ The function SecTrustGetCertificateAtIndex() is officially present
+ in Lion, but it is unfortunately also present in Snow Leopard as
+ private API and doesn't work as expected. So we have to look for
+ a different symbol to make sure this code is only executed under
+ Lion or later. */
+ if(SecTrustEvaluateAsync != NULL) {
+#pragma unused(server_certs)
+ err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ /* For some reason, SSLCopyPeerTrust() can return noErr and yet return
+ a null trust, so be on guard for that: */
+ if(err == noErr && trust) {
+ count = SecTrustGetCertificateCount(trust);
+ for(i = 0L ; i < count ; i++) {
+ server_cert = SecTrustGetCertificateAtIndex(trust, i);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(trust);
+ }
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ /* Just in case SSLCopyPeerCertificates() returns null too... */
+ if(err == noErr && server_certs) {
+ count = CFArrayGetCount(server_certs);
+ for(i = 0L ; i < count ; i++) {
+ server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs,
+ i);
+
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(server_certs);
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#endif /* CURL_BUILD_IOS */
+#else
+#pragma unused(trust)
+ err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ if(err == noErr) {
+ count = CFArrayGetCount(server_certs);
+ for(i = 0L ; i < count ; i++) {
+ server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(server_certs);
+ }
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
+static CURLcode
+darwinssl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ /* There is no step 3!
+ * Well, okay, if verbose mode is on, let's print the details of the
+ * server certificates. */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ if(data->set.verbose)
+ show_verbose_server_cert(conn, sockindex);
+#endif
+
+ connssl->connecting_state = ssl_connect_done;
+ return CURLE_OK;
+}
+
+static Curl_recv darwinssl_recv;
+static Curl_send darwinssl_send;
+
+static CURLcode
+darwinssl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = darwinssl_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if this
+ * connection is done nonblocking and this loop would execute again. This
+ * permits the owner of a multi handle to abort a connection attempt
+ * before step2 has completed while ensuring that a client using select()
+ * or epoll() will always have a valid fdset to wait on.
+ */
+ result = darwinssl_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
+
+ } /* repeat step2 until all transactions are done. */
+
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = darwinssl_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = darwinssl_recv;
+ conn->send[sockindex] = darwinssl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return darwinssl_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_darwinssl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = darwinssl_connect_common(conn, sockindex, FALSE, &done);
+
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->ssl_ctx) {
+ (void)SSLClose(connssl->ssl_ctx);
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLCreateContext != NULL)
+ CFRelease(connssl->ssl_ctx);
+#if CURL_SUPPORT_MAC_10_8
+ else
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+#endif /* CURL_SUPPORT_MAC_10_8 */
+#else
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+ connssl->ssl_ctx = NULL;
+ }
+ connssl->ssl_sockfd = 0;
+}
+
+int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ ssize_t nread;
+ int what;
+ int rc;
+ char buf[120];
+
+ if(!connssl->ssl_ctx)
+ return 0;
+
+ if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+ return 0;
+
+ Curl_darwinssl_close(conn, sockindex);
+
+ rc = 0;
+
+ what = SOCKET_READABLE(conn->sock[sockindex], SSL_SHUTDOWN_TIMEOUT);
+
+ for(;;) {
+ if(what < 0) {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ rc = -1;
+ break;
+ }
+
+ if(!what) { /* timeout */
+ failf(data, "SSL shutdown timeout");
+ break;
+ }
+
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server. No way to SSL_Read now, so use read(). */
+
+ nread = read(conn->sock[sockindex], buf, sizeof(buf));
+
+ if(nread < 0) {
+ failf(data, "read: %s", strerror(errno));
+ rc = -1;
+ }
+
+ if(nread <= 0)
+ break;
+
+ what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ }
+
+ return rc;
+}
+
+void Curl_darwinssl_session_free(void *ptr)
+{
+ /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a
+ cached session ID inside the Security framework. There is a private
+ function that does this, but I don't want to have to explain to you why I
+ got your application rejected from the App Store due to the use of a
+ private API, so the best we can do is free up our own char array that we
+ created way back in darwinssl_connect_step1... */
+ Curl_safefree(ptr);
+}
+
+size_t Curl_darwinssl_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "SecureTransport");
+}
+
+/*
+ * This function uses SSLGetSessionState to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_darwinssl_check_cxn(struct connectdata *conn)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ OSStatus err;
+ SSLSessionState state;
+
+ if(connssl->ssl_ctx) {
+ err = SSLGetSessionState(connssl->ssl_ctx, &state);
+ if(err == noErr)
+ return state == kSSLConnected || state == kSSLHandshake;
+ return -1;
+ }
+ return 0;
+}
+
+bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+ int connindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ OSStatus err;
+ size_t buffer;
+
+ if(connssl->ssl_ctx) { /* SSL is in use */
+ err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer);
+ if(err == noErr)
+ return buffer > 0UL;
+ return false;
+ }
+ else
+ return false;
+}
+
+CURLcode Curl_darwinssl_random(unsigned char *entropy,
+ size_t length)
+{
+ /* arc4random_buf() isn't available on cats older than Lion, so let's
+ do this manually for the benefit of the older cats. */
+ size_t i;
+ u_int32_t random_number = 0;
+
+ for(i = 0 ; i < length ; i++) {
+ if(i % sizeof(u_int32_t) == 0)
+ random_number = arc4random();
+ entropy[i] = random_number & 0xFF;
+ random_number >>= 8;
+ }
+ i = random_number = 0;
+ return CURLE_OK;
+}
+
+void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+ (void)md5len;
+ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
+}
+
+void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
+{
+ assert(sha256len >= SHA256_DIGEST_LENGTH);
+ (void)CC_SHA256(tmp, (CC_LONG)tmplen, sha256sum);
+}
+
+bool Curl_darwinssl_false_start(void)
+{
+#if CURL_BUILD_MAC_10_9 || CURL_BUILD_IOS_7
+ if(SSLSetSessionOption != NULL)
+ return TRUE;
+#endif
+ return FALSE;
+}
+
+static ssize_t darwinssl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ /*struct Curl_easy *data = conn->data;*/
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ size_t processed = 0UL;
+ OSStatus err;
+
+ /* The SSLWrite() function works a little differently than expected. The
+ fourth argument (processed) is currently documented in Apple's
+ documentation as: "On return, the length, in bytes, of the data actually
+ written."
+
+ Now, one could interpret that as "written to the socket," but actually,
+ it returns the amount of data that was written to a buffer internal to
+ the SSLContextRef instead. So it's possible for SSLWrite() to return
+ errSSLWouldBlock and a number of bytes "written" because those bytes were
+ encrypted and written to a buffer, not to the socket.
+
+ So if this happens, then we need to keep calling SSLWrite() over and
+ over again with no new data until it quits returning errSSLWouldBlock. */
+
+ /* Do we have buffered data to write from the last time we were called? */
+ if(connssl->ssl_write_buffered_length) {
+ /* Write the buffered data: */
+ err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed);
+ switch(err) {
+ case noErr:
+ /* processed is always going to be 0 because we didn't write to
+ the buffer, so return how much was written to the socket */
+ processed = connssl->ssl_write_buffered_length;
+ connssl->ssl_write_buffered_length = 0UL;
+ break;
+ case errSSLWouldBlock: /* argh, try again */
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ default:
+ failf(conn->data, "SSLWrite() returned error %d", err);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1L;
+ }
+ }
+ else {
+ /* We've got new data to write: */
+ err = SSLWrite(connssl->ssl_ctx, mem, len, &processed);
+ if(err != noErr) {
+ switch(err) {
+ case errSSLWouldBlock:
+ /* Data was buffered but not sent, we have to tell the caller
+ to try sending again, and remember how much was buffered */
+ connssl->ssl_write_buffered_length = len;
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ default:
+ failf(conn->data, "SSLWrite() returned error %d", err);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1L;
+ }
+ }
+ }
+ return (ssize_t)processed;
+}
+
+static ssize_t darwinssl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ /*struct Curl_easy *data = conn->data;*/
+ struct ssl_connect_data *connssl = &conn->ssl[num];
+ size_t processed = 0UL;
+ OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
+
+ if(err != noErr) {
+ switch(err) {
+ case errSSLWouldBlock: /* return how much we read (if anything) */
+ if(processed)
+ return (ssize_t)processed;
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ break;
+
+ /* errSSLClosedGraceful - server gracefully shut down the SSL session
+ errSSLClosedNoNotify - server hung up on us instead of sending a
+ closure alert notice, read() is returning 0
+ Either way, inform the caller that the server disconnected. */
+ case errSSLClosedGraceful:
+ case errSSLClosedNoNotify:
+ *curlcode = CURLE_OK;
+ return -1L;
+ break;
+
+ default:
+ failf(conn->data, "SSLRead() return error %d", err);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1L;
+ break;
+ }
+ }
+ return (ssize_t)processed;
+}
+
+#endif /* USE_DARWINSSL */
diff --git a/Utilities/cmcurl/lib/vtls/darwinssl.h b/Utilities/cmcurl/lib/vtls/darwinssl.h
new file mode 100644
index 000000000..fd372ffa0
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/darwinssl.h
@@ -0,0 +1,100 @@
+#ifndef HEADER_CURL_DARWINSSL_H
+#define HEADER_CURL_DARWINSSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2014, Nick Zitzmann, <nickzman@gmail.com>.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_DARWINSSL
+
+CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* close a SSL connection */
+void Curl_darwinssl_close(struct connectdata *conn, int sockindex);
+
+void Curl_darwinssl_session_free(void *ptr);
+size_t Curl_darwinssl_version(char *buffer, size_t size);
+int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex);
+int Curl_darwinssl_check_cxn(struct connectdata *conn);
+bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+ int connindex);
+
+CURLcode Curl_darwinssl_random(unsigned char *entropy,
+ size_t length);
+void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len);
+void Curl_darwinssl_sha256sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len);
+bool Curl_darwinssl_false_start(void);
+
+/* Set the API backend definition to SecureTransport */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_DARWINSSL
+
+/* pinned public key support tests */
+
+/* version 1 supports macOS 10.12+ and iOS 10+ */
+#if ((TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000) || \
+ (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200))
+#define DARWIN_SSL_PINNEDPUBKEY_V1 1
+#endif
+
+/* version 2 supports MacOSX 10.7+ */
+#if (!TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070)
+#define DARWIN_SSL_PINNEDPUBKEY_V2 1
+#endif
+
+#if defined(DARWIN_SSL_PINNEDPUBKEY_V1) || defined(DARWIN_SSL_PINNEDPUBKEY_V2)
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define DARWIN_SSL_PINNEDPUBKEY 1
+#define have_curlssl_pinnedpubkey 1
+#endif /* DARWIN_SSL_PINNEDPUBKEY */
+
+/* API setup for SecureTransport */
+#define curlssl_init() (1)
+#define curlssl_cleanup() Curl_nop_stmt
+#define curlssl_connect Curl_darwinssl_connect
+#define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking
+#define curlssl_session_free(x) Curl_darwinssl_session_free(x)
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_darwinssl_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_darwinssl_version
+#define curlssl_check_cxn Curl_darwinssl_check_cxn
+#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y)
+#define curlssl_random(x,y,z) ((void)x, Curl_darwinssl_random(y,z))
+#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d)
+#define curlssl_sha256sum(a,b,c,d) Curl_darwinssl_sha256sum(a,b,c,d)
+#define curlssl_false_start() Curl_darwinssl_false_start()
+
+#endif /* USE_DARWINSSL */
+#endif /* HEADER_CURL_DARWINSSL_H */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.c b/Utilities/cmcurl/lib/vtls/gskit.c
new file mode 100644
index 000000000..bf75bddc2
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/gskit.c
@@ -0,0 +1,1337 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_GSKIT
+
+#include <gskssl.h>
+#include <qsoasync.h>
+
+/* Some symbols are undefined/unsupported on OS400 versions < V7R1. */
+#ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST
+#define GSK_SSL_EXTN_SERVERNAME_REQUEST 230
+#endif
+
+#ifndef GSK_TLSV10_CIPHER_SPECS
+#define GSK_TLSV10_CIPHER_SPECS 236
+#endif
+
+#ifndef GSK_TLSV11_CIPHER_SPECS
+#define GSK_TLSV11_CIPHER_SPECS 237
+#endif
+
+#ifndef GSK_TLSV12_CIPHER_SPECS
+#define GSK_TLSV12_CIPHER_SPECS 238
+#endif
+
+#ifndef GSK_PROTOCOL_TLSV11
+#define GSK_PROTOCOL_TLSV11 437
+#endif
+
+#ifndef GSK_PROTOCOL_TLSV12
+#define GSK_PROTOCOL_TLSV12 438
+#endif
+
+#ifndef GSK_FALSE
+#define GSK_FALSE 0
+#endif
+
+#ifndef GSK_TRUE
+#define GSK_TRUE 1
+#endif
+
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "gskit.h"
+#include "vtls.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+/* Directions. */
+#define SOS_READ 0x01
+#define SOS_WRITE 0x02
+
+/* SSL version flags. */
+#define CURL_GSKPROTO_SSLV2 0
+#define CURL_GSKPROTO_SSLV2_MASK (1 << CURL_GSKPROTO_SSLV2)
+#define CURL_GSKPROTO_SSLV3 1
+#define CURL_GSKPROTO_SSLV3_MASK (1 << CURL_GSKPROTO_SSLV3)
+#define CURL_GSKPROTO_TLSV10 2
+#define CURL_GSKPROTO_TLSV10_MASK (1 << CURL_GSKPROTO_TLSV10)
+#define CURL_GSKPROTO_TLSV11 3
+#define CURL_GSKPROTO_TLSV11_MASK (1 << CURL_GSKPROTO_TLSV11)
+#define CURL_GSKPROTO_TLSV12 4
+#define CURL_GSKPROTO_TLSV12_MASK (1 << CURL_GSKPROTO_TLSV12)
+#define CURL_GSKPROTO_LAST 5
+
+
+/* Supported ciphers. */
+typedef struct {
+ const char *name; /* Cipher name. */
+ const char *gsktoken; /* Corresponding token for GSKit String. */
+ unsigned int versions; /* SSL version flags. */
+} gskit_cipher;
+
+static const gskit_cipher ciphertable[] = {
+ { "null-md5", "01",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
+ { "null-sha", "02",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
+ { "exp-rc4-md5", "03",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
+ { "rc4-md5", "04",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
+ { "rc4-sha", "05",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
+ { "exp-rc2-cbc-md5", "06",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK },
+ { "exp-des-cbc-sha", "09",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK },
+ { "des-cbc3-sha", "0A",
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
+ { "aes128-sha", "2F",
+ CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
+ CURL_GSKPROTO_TLSV12_MASK },
+ { "aes256-sha", "35",
+ CURL_GSKPROTO_TLSV10_MASK | CURL_GSKPROTO_TLSV11_MASK |
+ CURL_GSKPROTO_TLSV12_MASK },
+ { "null-sha256", "3B", CURL_GSKPROTO_TLSV12_MASK },
+ { "aes128-sha256", "3C", CURL_GSKPROTO_TLSV12_MASK },
+ { "aes256-sha256", "3D", CURL_GSKPROTO_TLSV12_MASK },
+ { "aes128-gcm-sha256",
+ "9C", CURL_GSKPROTO_TLSV12_MASK },
+ { "aes256-gcm-sha384",
+ "9D", CURL_GSKPROTO_TLSV12_MASK },
+ { "rc4-md5", "1", CURL_GSKPROTO_SSLV2_MASK },
+ { "exp-rc4-md5", "2", CURL_GSKPROTO_SSLV2_MASK },
+ { "rc2-md5", "3", CURL_GSKPROTO_SSLV2_MASK },
+ { "exp-rc2-md5", "4", CURL_GSKPROTO_SSLV2_MASK },
+ { "des-cbc-md5", "6", CURL_GSKPROTO_SSLV2_MASK },
+ { "des-cbc3-md5", "7", CURL_GSKPROTO_SSLV2_MASK },
+ { (const char *) NULL, (const char *) NULL, 0 }
+};
+
+
+static bool is_separator(char c)
+{
+ /* Return whether character is a cipher list separator. */
+ switch(c) {
+ case ' ':
+ case '\t':
+ case ':':
+ case ',':
+ case ';':
+ return true;
+ }
+ return false;
+}
+
+
+static CURLcode gskit_status(struct Curl_easy *data, int rc,
+ const char *procname, CURLcode defcode)
+{
+ /* Process GSKit status and map it to a CURLcode. */
+ switch(rc) {
+ case GSK_OK:
+ case GSK_OS400_ASYNCHRONOUS_SOC_INIT:
+ return CURLE_OK;
+ case GSK_KEYRING_OPEN_ERROR:
+ case GSK_OS400_ERROR_NO_ACCESS:
+ return CURLE_SSL_CACERT_BADFILE;
+ case GSK_INSUFFICIENT_STORAGE:
+ return CURLE_OUT_OF_MEMORY;
+ case GSK_ERROR_BAD_V2_CIPHER:
+ case GSK_ERROR_BAD_V3_CIPHER:
+ case GSK_ERROR_NO_CIPHERS:
+ return CURLE_SSL_CIPHER;
+ case GSK_OS400_ERROR_NOT_TRUSTED_ROOT:
+ case GSK_ERROR_CERT_VALIDATION:
+ return CURLE_PEER_FAILED_VERIFICATION;
+ case GSK_OS400_ERROR_TIMED_OUT:
+ return CURLE_OPERATION_TIMEDOUT;
+ case GSK_WOULD_BLOCK:
+ return CURLE_AGAIN;
+ case GSK_OS400_ERROR_NOT_REGISTERED:
+ break;
+ case GSK_ERROR_IO:
+ switch(errno) {
+ case ENOMEM:
+ return CURLE_OUT_OF_MEMORY;
+ default:
+ failf(data, "%s I/O error: %s", procname, strerror(errno));
+ break;
+ }
+ break;
+ default:
+ failf(data, "%s: %s", procname, gsk_strerror(rc));
+ break;
+ }
+ return defcode;
+}
+
+
+static CURLcode set_enum(struct Curl_easy *data, gsk_handle h,
+ GSK_ENUM_ID id, GSK_ENUM_VALUE value, bool unsupported_ok)
+{
+ int rc = gsk_attribute_set_enum(h, id, value);
+
+ switch(rc) {
+ case GSK_OK:
+ return CURLE_OK;
+ case GSK_ERROR_IO:
+ failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno));
+ break;
+ case GSK_ATTRIBUTE_INVALID_ID:
+ if(unsupported_ok)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ default:
+ failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc));
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_buffer(struct Curl_easy *data, gsk_handle h,
+ GSK_BUF_ID id, const char *buffer, bool unsupported_ok)
+{
+ int rc = gsk_attribute_set_buffer(h, id, buffer, 0);
+
+ switch(rc) {
+ case GSK_OK:
+ return CURLE_OK;
+ case GSK_ERROR_IO:
+ failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno));
+ break;
+ case GSK_ATTRIBUTE_INVALID_ID:
+ if(unsupported_ok)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ default:
+ failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc));
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_numeric(struct Curl_easy *data,
+ gsk_handle h, GSK_NUM_ID id, int value)
+{
+ int rc = gsk_attribute_set_numeric_value(h, id, value);
+
+ switch(rc) {
+ case GSK_OK:
+ return CURLE_OK;
+ case GSK_ERROR_IO:
+ failf(data, "gsk_attribute_set_numeric_value() I/O error: %s",
+ strerror(errno));
+ break;
+ default:
+ failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc));
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_callback(struct Curl_easy *data,
+ gsk_handle h, GSK_CALLBACK_ID id, void *info)
+{
+ int rc = gsk_attribute_set_callback(h, id, info);
+
+ switch(rc) {
+ case GSK_OK:
+ return CURLE_OK;
+ case GSK_ERROR_IO:
+ failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno));
+ break;
+ default:
+ failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc));
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+
+static CURLcode set_ciphers(struct connectdata *conn,
+ gsk_handle h, unsigned int *protoflags)
+{
+ struct Curl_easy *data = conn->data;
+ const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
+ const char *clp;
+ const gskit_cipher *ctp;
+ int i;
+ int l;
+ bool unsupported;
+ CURLcode result;
+ struct {
+ char *buf;
+ char *ptr;
+ } ciphers[CURL_GSKPROTO_LAST];
+
+ /* Compile cipher list into GSKit-compatible cipher lists. */
+
+ if(!cipherlist)
+ return CURLE_OK;
+ while(is_separator(*cipherlist)) /* Skip initial separators. */
+ cipherlist++;
+ if(!*cipherlist)
+ return CURLE_OK;
+
+ /* We allocate GSKit buffers of the same size as the input string: since
+ GSKit tokens are always shorter than their cipher names, allocated buffers
+ will always be large enough to accommodate the result. */
+ l = strlen(cipherlist) + 1;
+ memset((char *) ciphers, 0, sizeof ciphers);
+ for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
+ ciphers[i].buf = malloc(l);
+ if(!ciphers[i].buf) {
+ while(i--)
+ free(ciphers[i].buf);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ciphers[i].ptr = ciphers[i].buf;
+ *ciphers[i].ptr = '\0';
+ }
+
+ /* Process each cipher in input string. */
+ unsupported = FALSE;
+ result = CURLE_OK;
+ for(;;) {
+ for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);)
+ cipherlist++;
+ l = cipherlist - clp;
+ if(!l)
+ break;
+ /* Search the cipher in our table. */
+ for(ctp = ciphertable; ctp->name; ctp++)
+ if(strncasecompare(ctp->name, clp, l) && !ctp->name[l])
+ break;
+ if(!ctp->name) {
+ failf(data, "Unknown cipher %.*s", l, clp);
+ result = CURLE_SSL_CIPHER;
+ }
+ else {
+ unsupported |= !(ctp->versions & (CURL_GSKPROTO_SSLV2_MASK |
+ CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK));
+ for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
+ if(ctp->versions & (1 << i)) {
+ strcpy(ciphers[i].ptr, ctp->gsktoken);
+ ciphers[i].ptr += strlen(ctp->gsktoken);
+ }
+ }
+ }
+
+ /* Advance to next cipher name or end of string. */
+ while(is_separator(*cipherlist))
+ cipherlist++;
+ }
+
+ /* Disable protocols with empty cipher lists. */
+ for(i = 0; i < CURL_GSKPROTO_LAST; i++) {
+ if(!(*protoflags & (1 << i)) || !ciphers[i].buf[0]) {
+ *protoflags &= ~(1 << i);
+ ciphers[i].buf[0] = '\0';
+ }
+ }
+
+ /* Try to set-up TLSv1.1 and TLSv2.1 ciphers. */
+ if(*protoflags & CURL_GSKPROTO_TLSV11_MASK) {
+ result = set_buffer(data, h, GSK_TLSV11_CIPHER_SPECS,
+ ciphers[CURL_GSKPROTO_TLSV11].buf, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ result = CURLE_OK;
+ if(unsupported) {
+ failf(data, "TLSv1.1-only ciphers are not yet supported");
+ result = CURLE_SSL_CIPHER;
+ }
+ }
+ }
+ if(!result && (*protoflags & CURL_GSKPROTO_TLSV12_MASK)) {
+ result = set_buffer(data, h, GSK_TLSV12_CIPHER_SPECS,
+ ciphers[CURL_GSKPROTO_TLSV12].buf, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ result = CURLE_OK;
+ if(unsupported) {
+ failf(data, "TLSv1.2-only ciphers are not yet supported");
+ result = CURLE_SSL_CIPHER;
+ }
+ }
+ }
+
+ /* Try to set-up TLSv1.0 ciphers. If not successful, concatenate them to
+ the SSLv3 ciphers. OS/400 prior to version 7.1 will understand it. */
+ if(!result && (*protoflags & CURL_GSKPROTO_TLSV10_MASK)) {
+ result = set_buffer(data, h, GSK_TLSV10_CIPHER_SPECS,
+ ciphers[CURL_GSKPROTO_TLSV10].buf, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ result = CURLE_OK;
+ strcpy(ciphers[CURL_GSKPROTO_SSLV3].ptr,
+ ciphers[CURL_GSKPROTO_TLSV10].ptr);
+ }
+ }
+
+ /* Set-up other ciphers. */
+ if(!result && (*protoflags & CURL_GSKPROTO_SSLV3_MASK))
+ result = set_buffer(data, h, GSK_V3_CIPHER_SPECS,
+ ciphers[CURL_GSKPROTO_SSLV3].buf, FALSE);
+ if(!result && (*protoflags & CURL_GSKPROTO_SSLV2_MASK))
+ result = set_buffer(data, h, GSK_V2_CIPHER_SPECS,
+ ciphers[CURL_GSKPROTO_SSLV2].buf, FALSE);
+
+ /* Clean-up. */
+ for(i = 0; i < CURL_GSKPROTO_LAST; i++)
+ free(ciphers[i].buf);
+
+ return result;
+}
+
+
+int Curl_gskit_init(void)
+{
+ /* No initialisation needed. */
+
+ return 1;
+}
+
+
+void Curl_gskit_cleanup(void)
+{
+ /* Nothing to do. */
+}
+
+
+static CURLcode init_environment(struct Curl_easy *data,
+ gsk_handle *envir, const char *appid,
+ const char *file, const char *label,
+ const char *password)
+{
+ int rc;
+ CURLcode result;
+ gsk_handle h;
+
+ /* Creates the GSKit environment. */
+
+ rc = gsk_environment_open(&h);
+ switch(rc) {
+ case GSK_OK:
+ break;
+ case GSK_INSUFFICIENT_STORAGE:
+ return CURLE_OUT_OF_MEMORY;
+ default:
+ failf(data, "gsk_environment_open(): %s", gsk_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ result = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION, FALSE);
+ if(!result && appid)
+ result = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid, FALSE);
+ if(!result && file)
+ result = set_buffer(data, h, GSK_KEYRING_FILE, file, FALSE);
+ if(!result && label)
+ result = set_buffer(data, h, GSK_KEYRING_LABEL, label, FALSE);
+ if(!result && password)
+ result = set_buffer(data, h, GSK_KEYRING_PW, password, FALSE);
+
+ if(!result) {
+ /* Locate CAs, Client certificate and key according to our settings.
+ Note: this call may be blocking for some tenths of seconds. */
+ result = gskit_status(data, gsk_environment_init(h),
+ "gsk_environment_init()", CURLE_SSL_CERTPROBLEM);
+ if(!result) {
+ *envir = h;
+ return result;
+ }
+ }
+ /* Error: rollback. */
+ gsk_environment_close(&h);
+ return result;
+}
+
+
+static void cancel_async_handshake(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ Qso_OverlappedIO_t cstat;
+
+ if(QsoCancelOperation(conn->sock[sockindex], 0) > 0)
+ QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL);
+}
+
+
+static void close_async_handshake(struct ssl_connect_data *connssl)
+{
+ QsoDestroyIOCompletionPort(connssl->iocport);
+ connssl->iocport = -1;
+}
+
+/* SSL over SSL
+ * Problems:
+ * 1) GSKit can only perform SSL on an AF_INET or AF_INET6 stream socket. To
+ * pipe an SSL stream into another, it is therefore needed to have a pair
+ * of such communicating sockets and handle the pipelining explicitly.
+ * 2) OS/400 socketpair() is only implemented for domain AF_UNIX, thus cannot
+ * be used to produce the pipeline.
+ * The solution is to simulate socketpair() for AF_INET with low-level API
+ * listen(), bind() and connect().
+ */
+
+static int
+inetsocketpair(int sv[2])
+{
+ int lfd; /* Listening socket. */
+ int sfd; /* Server socket. */
+ int cfd; /* Client socket. */
+ int len;
+ struct sockaddr_in addr1;
+ struct sockaddr_in addr2;
+
+ /* Create listening socket on a local dynamic port. */
+ lfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(lfd < 0)
+ return -1;
+ memset((char *) &addr1, 0, sizeof addr1);
+ addr1.sin_family = AF_INET;
+ addr1.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+ addr1.sin_port = 0;
+ if(bind(lfd, (struct sockaddr *) &addr1, sizeof addr1) ||
+ listen(lfd, 2) < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Get the allocated port. */
+ len = sizeof addr1;
+ if(getsockname(lfd, (struct sockaddr *) &addr1, &len) < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Create the client socket. */
+ cfd = socket(AF_INET, SOCK_STREAM, 0);
+ if(cfd < 0) {
+ close(lfd);
+ return -1;
+ }
+
+ /* Request unblocking connection to the listening socket. */
+ curlx_nonblock(cfd, TRUE);
+ if(connect(cfd, (struct sockaddr *) &addr1, sizeof addr1) < 0 &&
+ errno != EINPROGRESS) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
+
+ /* Get the client dynamic port for intrusion check below. */
+ len = sizeof addr2;
+ if(getsockname(cfd, (struct sockaddr *) &addr2, &len) < 0) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
+
+ /* Accept the incoming connection and get the server socket. */
+ curlx_nonblock(lfd, TRUE);
+ for(;;) {
+ len = sizeof addr1;
+ sfd = accept(lfd, (struct sockaddr *) &addr1, &len);
+ if(sfd < 0) {
+ close(lfd);
+ close(cfd);
+ return -1;
+ }
+
+ /* Check for possible intrusion from an external process. */
+ if(addr1.sin_addr.s_addr == addr2.sin_addr.s_addr &&
+ addr1.sin_port == addr2.sin_port)
+ break;
+
+ /* Intrusion: reject incoming connection. */
+ close(sfd);
+ }
+
+ /* Done, return sockets and succeed. */
+ close(lfd);
+ curlx_nonblock(cfd, FALSE);
+ sv[0] = cfd;
+ sv[1] = sfd;
+ return 0;
+}
+
+static int pipe_ssloverssl(struct connectdata *conn, int sockindex,
+ int directions)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connproxyssl = &conn->proxy_ssl[sockindex];
+ fd_set fds_read;
+ fd_set fds_write;
+ int n;
+ int m;
+ int i;
+ int ret = 0;
+ struct timeval tv = {0, 0};
+ char buf[CURL_MAX_WRITE_SIZE];
+
+ if(!connssl->use || !connproxyssl->use)
+ return 0; /* No SSL over SSL: OK. */
+
+ FD_ZERO(&fds_read);
+ FD_ZERO(&fds_write);
+ n = -1;
+ if(directions & SOS_READ) {
+ FD_SET(connssl->remotefd, &fds_write);
+ n = connssl->remotefd;
+ }
+ if(directions & SOS_WRITE) {
+ FD_SET(connssl->remotefd, &fds_read);
+ n = connssl->remotefd;
+ FD_SET(conn->sock[sockindex], &fds_write);
+ if(n < conn->sock[sockindex])
+ n = conn->sock[sockindex];
+ }
+ i = select(n + 1, &fds_read, &fds_write, NULL, &tv);
+ if(i < 0)
+ return -1; /* Select error. */
+
+ if(FD_ISSET(connssl->remotefd, &fds_write)) {
+ /* Try getting data from HTTPS proxy and pipe it upstream. */
+ n = 0;
+ i = gsk_secure_soc_read(connproxyssl->handle, buf, sizeof buf, &n);
+ switch(i) {
+ case GSK_OK:
+ if(n) {
+ i = write(connssl->remotefd, buf, n);
+ if(i < 0)
+ return -1;
+ ret = 1;
+ }
+ break;
+ case GSK_OS400_ERROR_TIMED_OUT:
+ case GSK_WOULD_BLOCK:
+ break;
+ default:
+ return -1;
+ }
+ }
+
+ if(FD_ISSET(connssl->remotefd, &fds_read) &&
+ FD_ISSET(conn->sock[sockindex], &fds_write)) {
+ /* Pipe data to HTTPS proxy. */
+ n = read(connssl->remotefd, buf, sizeof buf);
+ if(n < 0)
+ return -1;
+ if(n) {
+ i = gsk_secure_soc_write(connproxyssl->handle, buf, n, &m);
+ if(i != GSK_OK || n != m)
+ return -1;
+ ret = 1;
+ }
+ }
+
+ return ret; /* OK */
+}
+
+
+static void close_one(struct ssl_connect_data *connssl,
+ struct connectdata *conn, int sockindex)
+{
+ if(connssl->handle) {
+ gskit_status(conn->data, gsk_secure_soc_close(&connssl->handle),
+ "gsk_secure_soc_close()", 0);
+ /* Last chance to drain output. */
+ while(pipe_ssloverssl(conn, sockindex, SOS_WRITE) > 0)
+ ;
+ connssl->handle = (gsk_handle) NULL;
+ if(connssl->localfd >= 0) {
+ close(connssl->localfd);
+ connssl->localfd = -1;
+ }
+ if(connssl->remotefd >= 0) {
+ close(connssl->remotefd);
+ connssl->remotefd = -1;
+ }
+ }
+ if(connssl->iocport >= 0)
+ close_async_handshake(connssl);
+}
+
+
+static ssize_t gskit_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *curlcode)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode cc = CURLE_SEND_ERROR;
+ int written;
+
+ if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) >= 0) {
+ cc = gskit_status(data,
+ gsk_secure_soc_write(conn->ssl[sockindex].handle,
+ (char *) mem, (int) len, &written),
+ "gsk_secure_soc_write()", CURLE_SEND_ERROR);
+ if(cc == CURLE_OK)
+ if(pipe_ssloverssl(conn, sockindex, SOS_WRITE) < 0)
+ cc = CURLE_SEND_ERROR;
+ }
+ if(cc != CURLE_OK) {
+ *curlcode = cc;
+ written = -1;
+ }
+ return (ssize_t) written; /* number of bytes */
+}
+
+
+static ssize_t gskit_recv(struct connectdata *conn, int num, char *buf,
+ size_t buffersize, CURLcode *curlcode)
+{
+ struct Curl_easy *data = conn->data;
+ int buffsize;
+ int nread;
+ CURLcode cc = CURLE_RECV_ERROR;
+
+ if(pipe_ssloverssl(conn, num, SOS_READ) >= 0) {
+ buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize;
+ cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle,
+ buf, buffsize, &nread),
+ "gsk_secure_soc_read()", CURLE_RECV_ERROR);
+ }
+ switch(cc) {
+ case CURLE_OK:
+ break;
+ case CURLE_OPERATION_TIMEDOUT:
+ cc = CURLE_AGAIN;
+ default:
+ *curlcode = cc;
+ nread = -1;
+ break;
+ }
+ return (ssize_t) nread;
+}
+
+static CURLcode
+set_ssl_version_min_max(unsigned int *protoflags, struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long i = ssl_version;
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_TLSv1_2;
+ break;
+ }
+ for(; i <= (ssl_version_max >> 16); ++i) {
+ switch(i) {
+ case CURL_SSLVERSION_TLSv1_0:
+ *protoflags |= CURL_GSKPROTO_TLSV10_MASK;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ *protoflags |= CURL_GSKPROTO_TLSV11_MASK;
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "GSKit: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ gsk_handle envir;
+ CURLcode result;
+ int rc;
+ const char * const keyringfile = SSL_CONN_CONFIG(CAfile);
+ const char * const keyringpwd = SSL_SET_OPTION(key_passwd);
+ const char * const keyringlabel = SSL_SET_OPTION(cert);
+ const long int ssl_version = SSL_CONN_CONFIG(version);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
+ conn->host.name;
+ const char *sni;
+ unsigned int protoflags = 0;
+ long timeout;
+ Qso_OverlappedIO_t commarea;
+ int sockpair[2];
+ static const int sobufsize = CURL_MAX_WRITE_SIZE;
+
+ /* Create SSL environment, start (preferably asynchronous) handshake. */
+
+ connssl->handle = (gsk_handle) NULL;
+ connssl->iocport = -1;
+ connssl->localfd = -1;
+ connssl->remotefd = -1;
+
+ /* GSKit supports two ways of specifying an SSL context: either by
+ * application identifier (that should have been defined at the system
+ * level) or by keyring file, password and certificate label.
+ * Local certificate name (CURLOPT_SSLCERT) is used to hold either the
+ * application identifier of the certificate label.
+ * Key password (CURLOPT_KEYPASSWD) holds the keyring password.
+ * It is not possible to have different keyrings for the CAs and the
+ * local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify
+ * the keyring file.
+ * If no key password is given and the keyring is the system keyring,
+ * application identifier mode is tried first, as recommended in IBM doc.
+ */
+
+ envir = (gsk_handle) NULL;
+
+ if(keyringlabel && *keyringlabel && !keyringpwd &&
+ !strcmp(keyringfile, CURL_CA_BUNDLE)) {
+ /* Try application identifier mode. */
+ init_environment(data, &envir, keyringlabel, (const char *) NULL,
+ (const char *) NULL, (const char *) NULL);
+ }
+
+ if(!envir) {
+ /* Use keyring mode. */
+ result = init_environment(data, &envir, (const char *) NULL,
+ keyringfile, keyringlabel, keyringpwd);
+ if(result)
+ return result;
+ }
+
+ /* Create secure session. */
+ result = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle),
+ "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR);
+ gsk_environment_close(&envir);
+ if(result)
+ return result;
+
+ /* Establish a pipelining socket pair for SSL over SSL. */
+ if(conn->proxy_ssl[sockindex].use) {
+ if(inetsocketpair(sockpair))
+ return CURLE_SSL_CONNECT_ERROR;
+ connssl->localfd = sockpair[0];
+ connssl->remotefd = sockpair[1];
+ setsockopt(connssl->localfd, SOL_SOCKET, SO_RCVBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->remotefd, SOL_SOCKET, SO_RCVBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->localfd, SOL_SOCKET, SO_SNDBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ setsockopt(connssl->remotefd, SOL_SOCKET, SO_SNDBUF,
+ (void *) sobufsize, sizeof sobufsize);
+ curlx_nonblock(connssl->localfd, TRUE);
+ curlx_nonblock(connssl->remotefd, TRUE);
+ }
+
+ /* Determine which SSL/TLS version should be enabled. */
+ sni = hostname;
+ switch(ssl_version) {
+ case CURL_SSLVERSION_SSLv2:
+ protoflags = CURL_GSKPROTO_SSLV2_MASK;
+ sni = NULL;
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ protoflags = CURL_GSKPROTO_SSLV3_MASK;
+ sni = NULL;
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ protoflags = CURL_GSKPROTO_TLSV10_MASK |
+ CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK;
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ result = set_ssl_version_min_max(&protoflags, conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* Process SNI. Ignore if not supported (on OS400 < V7R1). */
+ if(sni) {
+ result = set_buffer(data, connssl->handle,
+ GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL)
+ result = CURLE_OK;
+ }
+
+ /* Set session parameters. */
+ if(!result) {
+ /* Compute the handshake timeout. Since GSKit granularity is 1 second,
+ we round up the required value. */
+ timeout = Curl_timeleft(data, NULL, TRUE);
+ if(timeout < 0)
+ result = CURLE_OPERATION_TIMEDOUT;
+ else
+ result = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT,
+ (timeout + 999) / 1000);
+ }
+ if(!result)
+ result = set_numeric(data, connssl->handle, GSK_OS400_READ_TIMEOUT, 1);
+ if(!result)
+ result = set_numeric(data, connssl->handle, GSK_FD, connssl->localfd >= 0?
+ connssl->localfd: conn->sock[sockindex]);
+ if(!result)
+ result = set_ciphers(conn, connssl->handle, &protoflags);
+ if(!protoflags) {
+ failf(data, "No SSL protocol/cipher combination enabled");
+ result = CURLE_SSL_CIPHER;
+ }
+ if(!result)
+ result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2,
+ (protoflags & CURL_GSKPROTO_SSLV2_MASK)?
+ GSK_PROTOCOL_SSLV2_ON: GSK_PROTOCOL_SSLV2_OFF, FALSE);
+ if(!result)
+ result = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3,
+ (protoflags & CURL_GSKPROTO_SSLV3_MASK)?
+ GSK_PROTOCOL_SSLV3_ON: GSK_PROTOCOL_SSLV3_OFF, FALSE);
+ if(!result)
+ result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1,
+ (protoflags & CURL_GSKPROTO_TLSV10_MASK)?
+ GSK_PROTOCOL_TLSV1_ON: GSK_PROTOCOL_TLSV1_OFF, FALSE);
+ if(!result) {
+ result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV11,
+ (protoflags & CURL_GSKPROTO_TLSV11_MASK)?
+ GSK_TRUE: GSK_FALSE, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ result = CURLE_OK;
+ if(protoflags == CURL_GSKPROTO_TLSV11_MASK) {
+ failf(data, "TLS 1.1 not yet supported");
+ result = CURLE_SSL_CIPHER;
+ }
+ }
+ }
+ if(!result) {
+ result = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV12,
+ (protoflags & CURL_GSKPROTO_TLSV12_MASK)?
+ GSK_TRUE: GSK_FALSE, TRUE);
+ if(result == CURLE_UNSUPPORTED_PROTOCOL) {
+ result = CURLE_OK;
+ if(protoflags == CURL_GSKPROTO_TLSV12_MASK) {
+ failf(data, "TLS 1.2 not yet supported");
+ result = CURLE_SSL_CIPHER;
+ }
+ }
+ }
+ if(!result)
+ result = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE,
+ verifypeer? GSK_SERVER_AUTH_FULL:
+ GSK_SERVER_AUTH_PASSTHRU, FALSE);
+
+ if(!result) {
+ /* Start handshake. Try asynchronous first. */
+ memset(&commarea, 0, sizeof commarea);
+ connssl->iocport = QsoCreateIOCompletionPort();
+ if(connssl->iocport != -1) {
+ result = gskit_status(data,
+ gsk_secure_soc_startInit(connssl->handle,
+ connssl->iocport,
+ &commarea),
+ "gsk_secure_soc_startInit()",
+ CURLE_SSL_CONNECT_ERROR);
+ if(!result) {
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+ }
+ else
+ close_async_handshake(connssl);
+ }
+ else if(errno != ENOBUFS)
+ result = gskit_status(data, GSK_ERROR_IO,
+ "QsoCreateIOCompletionPort()", 0);
+ else if(conn->proxy_ssl[sockindex].use) {
+ /* Cannot pipeline while handshaking synchronously. */
+ result = CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ /* No more completion port available. Use synchronous IO. */
+ result = gskit_status(data, gsk_secure_soc_init(connssl->handle),
+ "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR);
+ if(!result) {
+ connssl->connecting_state = ssl_connect_3;
+ return CURLE_OK;
+ }
+ }
+ }
+
+ /* Error: rollback. */
+ close_one(connssl, conn, sockindex);
+ return result;
+}
+
+
+static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
+ bool nonblocking)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ Qso_OverlappedIO_t cstat;
+ long timeout_ms;
+ struct timeval stmv;
+ CURLcode result;
+
+ /* Poll or wait for end of SSL asynchronous handshake. */
+
+ for(;;) {
+ timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
+ if(timeout_ms < 0)
+ timeout_ms = 0;
+ stmv.tv_sec = timeout_ms / 1000;
+ stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000;
+ switch(QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) {
+ case 1: /* Operation complete. */
+ break;
+ case -1: /* An error occurred: handshake still in progress. */
+ if(errno == EINTR) {
+ if(nonblocking)
+ return CURLE_OK;
+ continue; /* Retry. */
+ }
+ if(errno != ETIME) {
+ failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno));
+ cancel_async_handshake(conn, sockindex);
+ close_async_handshake(connssl);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* FALL INTO... */
+ case 0: /* Handshake in progress, timeout occurred. */
+ if(nonblocking)
+ return CURLE_OK;
+ cancel_async_handshake(conn, sockindex);
+ close_async_handshake(connssl);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ break;
+ }
+ result = gskit_status(data, cstat.returnValue, "SSL handshake",
+ CURLE_SSL_CONNECT_ERROR);
+ if(!result)
+ connssl->connecting_state = ssl_connect_3;
+ close_async_handshake(connssl);
+ return result;
+}
+
+
+static CURLcode gskit_connect_step3(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ const gsk_cert_data_elem *cdev;
+ int cdec;
+ const gsk_cert_data_elem *p;
+ const char *cert = (const char *) NULL;
+ const char *certend;
+ const char *ptr;
+ int i;
+ CURLcode result;
+
+ /* SSL handshake done: gather certificate info and verify host. */
+
+ if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle,
+ GSK_PARTNER_CERT_INFO,
+ &cdev, &cdec),
+ "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) ==
+ CURLE_OK) {
+ infof(data, "Server certificate:\n");
+ p = cdev;
+ for(i = 0; i++ < cdec; p++)
+ switch(p->cert_data_id) {
+ case CERT_BODY_DER:
+ cert = p->cert_data_p;
+ certend = cert + cdev->cert_data_l;
+ break;
+ case CERT_DN_PRINTABLE:
+ infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p);
+ break;
+ case CERT_ISSUER_DN_PRINTABLE:
+ infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p);
+ break;
+ case CERT_VALID_FROM:
+ infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p);
+ break;
+ case CERT_VALID_TO:
+ infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p);
+ break;
+ }
+ }
+
+ /* Verify host. */
+ result = Curl_verifyhost(conn, cert, certend);
+ if(result)
+ return result;
+
+ /* The only place GSKit can get the whole CA chain is a validation
+ callback where no user data pointer is available. Therefore it's not
+ possible to copy this chain into our structures for CAINFO.
+ However the server certificate may be available, thus we can return
+ info about it. */
+ if(data->set.ssl.certinfo) {
+ result = Curl_ssl_init_certinfo(data, 1);
+ if(result)
+ return result;
+
+ if(cert) {
+ result = Curl_extract_certinfo(conn, 0, cert, certend);
+ if(result)
+ return result;
+ }
+ }
+
+ /* Check pinned public key. */
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ if(!result && ptr) {
+ curl_X509certificate x509;
+ curl_asn1Element *p;
+
+ if(Curl_parseX509(&x509, cert, certend))
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ p = &x509.subjectPublicKeyInfo;
+ result = Curl_pin_peer_pubkey(data, ptr, p->header, p->end - p->header);
+ if(result) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ return result;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+ return CURLE_OK;
+}
+
+
+static CURLcode gskit_connect_common(struct connectdata *conn, int sockindex,
+ bool nonblocking, bool *done)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long timeout_ms;
+ Qso_OverlappedIO_t cstat;
+ CURLcode result = CURLE_OK;
+
+ *done = connssl->state == ssl_connection_complete;
+ if(*done)
+ return CURLE_OK;
+
+ /* Step 1: create session, start handshake. */
+ if(connssl->connecting_state == ssl_connect_1) {
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ }
+ else
+ result = gskit_connect_step1(conn, sockindex);
+ }
+
+ /* Handle handshake pipelining. */
+ if(!result)
+ if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ result = CURLE_SSL_CONNECT_ERROR;
+
+ /* Step 2: check if handshake is over. */
+ if(!result && connssl->connecting_state == ssl_connect_2) {
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ result = CURLE_OPERATION_TIMEDOUT;
+ }
+ else
+ result = gskit_connect_step2(conn, sockindex, nonblocking);
+ }
+
+ /* Handle handshake pipelining. */
+ if(!result)
+ if(pipe_ssloverssl(conn, sockindex, SOS_READ | SOS_WRITE) < 0)
+ result = CURLE_SSL_CONNECT_ERROR;
+
+ /* Step 3: gather certificate info, verify host. */
+ if(!result && connssl->connecting_state == ssl_connect_3)
+ result = gskit_connect_step3(conn, sockindex);
+
+ if(result)
+ close_one(connssl, conn, sockindex);
+ else if(connssl->connecting_state == ssl_connect_done) {
+ connssl->state = ssl_connection_complete;
+ connssl->connecting_state = ssl_connect_1;
+ conn->recv[sockindex] = gskit_recv;
+ conn->send[sockindex] = gskit_send;
+ *done = TRUE;
+ }
+
+ return result;
+}
+
+
+CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ CURLcode result;
+
+ result = gskit_connect_common(conn, sockindex, TRUE, done);
+ if(*done || result)
+ conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ return result;
+}
+
+
+CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode result;
+ bool done;
+
+ conn->ssl[sockindex].connecting_state = ssl_connect_1;
+ result = gskit_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+
+void Curl_gskit_close(struct connectdata *conn, int sockindex)
+{
+ close_one(&conn->ssl[sockindex], conn, sockindex);
+ close_one(&conn->proxy_ssl[sockindex], conn, sockindex);
+}
+
+
+int Curl_gskit_shutdown(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ ssize_t nread;
+ int what;
+ int rc;
+ char buf[120];
+
+ if(!connssl->handle)
+ return 0;
+
+ if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+ return 0;
+
+ close_one(connssl, conn, sockindex);
+ rc = 0;
+ what = SOCKET_READABLE(conn->sock[sockindex],
+ SSL_SHUTDOWN_TIMEOUT);
+
+ for(;;) {
+ if(what < 0) {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ rc = -1;
+ break;
+ }
+
+ if(!what) { /* timeout */
+ failf(data, "SSL shutdown timeout");
+ break;
+ }
+
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server. No way to gsk_secure_soc_read() now, so
+ use read(). */
+
+ nread = read(conn->sock[sockindex], buf, sizeof(buf));
+
+ if(nread < 0) {
+ failf(data, "read: %s", strerror(errno));
+ rc = -1;
+ }
+
+ if(nread <= 0)
+ break;
+
+ what = SOCKET_READABLE(conn->sock[sockindex], 0);
+ }
+
+ return rc;
+}
+
+
+size_t Curl_gskit_version(char *buffer, size_t size)
+{
+ strncpy(buffer, "GSKit", size);
+ return strlen(buffer);
+}
+
+
+int Curl_gskit_check_cxn(struct connectdata *cxn)
+{
+ int err;
+ int errlen;
+
+ /* The only thing that can be tested here is at the socket level. */
+
+ if(!cxn->ssl[FIRSTSOCKET].handle)
+ return 0; /* connection has been closed */
+
+ err = 0;
+ errlen = sizeof err;
+
+ if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR,
+ (unsigned char *) &err, &errlen) ||
+ errlen != sizeof err || err)
+ return 0; /* connection has been closed */
+
+ return -1; /* connection status unknown */
+}
+
+#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/vtls/gskit.h b/Utilities/cmcurl/lib/vtls/gskit.h
new file mode 100644
index 000000000..229759217
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/gskit.h
@@ -0,0 +1,74 @@
+#ifndef HEADER_CURL_GSKIT_H
+#define HEADER_CURL_GSKIT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * This header should only be needed to get included by vtls.c and gskit.c
+ */
+
+#include "urldata.h"
+
+#ifdef USE_GSKIT
+int Curl_gskit_init(void);
+void Curl_gskit_cleanup(void);
+CURLcode Curl_gskit_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_gskit_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done);
+void Curl_gskit_close(struct connectdata *conn, int sockindex);
+int Curl_gskit_shutdown(struct connectdata *conn, int sockindex);
+
+size_t Curl_gskit_version(char *buffer, size_t size);
+int Curl_gskit_check_cxn(struct connectdata *cxn);
+
+/* Support HTTPS-proxy */
+/* TODO: add '#define HTTPS_PROXY_SUPPORT 1' and fix test #1014 (if need) */
+
+/* Set the API backend definition to GSKit */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_GSKIT
+
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
+/* API setup for GSKit */
+#define curlssl_init Curl_gskit_init
+#define curlssl_cleanup Curl_gskit_cleanup
+#define curlssl_connect Curl_gskit_connect
+#define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking
+
+/* No session handling for GSKit */
+#define curlssl_session_free(x) Curl_nop_stmt
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_gskit_close
+#define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y)
+#define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN
+#define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN
+#define curlssl_engines_list(x) NULL
+#define curlssl_version Curl_gskit_version
+#define curlssl_check_cxn(x) Curl_gskit_check_cxn(x)
+#define curlssl_data_pending(x,y) 0
+#define curlssl_random(x,y,z) (x=x, y=y, z=z, CURLE_NOT_BUILT_IN)
+
+#endif /* USE_GSKIT */
+
+#endif /* HEADER_CURL_GSKIT_H */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.c b/Utilities/cmcurl/lib/vtls/gtls.c
new file mode 100644
index 000000000..844be2de1
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/gtls.c
@@ -0,0 +1,1790 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ * Note: don't use the GnuTLS' *_t variable type names in this source code,
+ * since they were not present in 1.0.X.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_GNUTLS
+
+#include <gnutls/abstract.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#ifdef USE_GNUTLS_NETTLE
+#include <gnutls/crypto.h>
+#include <nettle/md5.h>
+#include <nettle/sha2.h>
+#else
+#include <gcrypt.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "gtls.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "warnless.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ Some hackish cast macros based on:
+ https://developer.gnome.org/glib/unstable/glib-Type-Conversion-Macros.html
+*/
+#ifndef GNUTLS_POINTER_TO_INT_CAST
+#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
+#endif
+#ifndef GNUTLS_INT_TO_POINTER_CAST
+#define GNUTLS_INT_TO_POINTER_CAST(i) ((void *) (long) (i))
+#endif
+
+/* Enable GnuTLS debugging by defining GTLSDEBUG */
+/*#define GTLSDEBUG */
+
+#ifdef GTLSDEBUG
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "|<%d>| %s", level, str);
+}
+#endif
+static bool gtls_inited = FALSE;
+
+#if defined(GNUTLS_VERSION_NUMBER)
+# if (GNUTLS_VERSION_NUMBER >= 0x020c00)
+# undef gnutls_transport_set_lowat
+# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
+# define USE_GNUTLS_PRIORITY_SET_DIRECT 1
+# endif
+# if (GNUTLS_VERSION_NUMBER >= 0x020c03)
+# define GNUTLS_MAPS_WINSOCK_ERRORS 1
+# endif
+
+# if HAVE_GNUTLS_ALPN_SET_PROTOCOLS
+# define HAS_ALPN
+# endif
+
+# if HAVE_GNUTLS_OCSP_REQ_INIT
+# define HAS_OCSP
+# endif
+
+# if (GNUTLS_VERSION_NUMBER >= 0x030306)
+# define HAS_CAPATH
+# endif
+#endif
+
+#ifdef HAS_OCSP
+# include <gnutls/ocsp.h>
+#endif
+
+/*
+ * Custom push and pull callback functions used by GNU TLS to read and write
+ * to the socket. These functions are simple wrappers to send() and recv()
+ * (although here using the sread/swrite macros as defined by
+ * curl_setup_once.h).
+ * We use custom functions rather than the GNU TLS defaults because it allows
+ * us to get specific about the fourth "flags" argument, and to use arbitrary
+ * private data with gnutls_transport_set_ptr if we wish.
+ *
+ * When these custom push and pull callbacks fail, GNU TLS checks its own
+ * session-specific error variable, and when not set also its own global
+ * errno variable, in order to take appropriate action. GNU TLS does not
+ * require that the transport is actually a socket. This implies that for
+ * Windows builds these callbacks should ideally set the session-specific
+ * error variable using function gnutls_transport_set_errno or as a last
+ * resort global errno variable using gnutls_transport_set_global_errno,
+ * with a transport agnostic error value. This implies that some winsock
+ * error translation must take place in these callbacks.
+ *
+ * Paragraph above applies to GNU TLS versions older than 2.12.3, since
+ * this version GNU TLS does its own internal winsock error translation
+ * using system_errno() function.
+ */
+
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+# define gtls_EINTR 4
+# define gtls_EIO 5
+# define gtls_EAGAIN 11
+static int gtls_mapped_sockerrno(void)
+{
+ switch(SOCKERRNO) {
+ case WSAEWOULDBLOCK:
+ return gtls_EAGAIN;
+ case WSAEINTR:
+ return gtls_EINTR;
+ default:
+ break;
+ }
+ return gtls_EIO;
+}
+#endif
+
+static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
+{
+ ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+ if(ret < 0)
+ gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
+#endif
+ return ret;
+}
+
+static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
+{
+ ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+ if(ret < 0)
+ gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
+#endif
+ return ret;
+}
+
+static ssize_t Curl_gtls_push_ssl(void *s, const void *buf, size_t len)
+{
+ return gnutls_record_send((gnutls_session_t) s, buf, len);
+}
+
+static ssize_t Curl_gtls_pull_ssl(void *s, void *buf, size_t len)
+{
+ return gnutls_record_recv((gnutls_session_t) s, buf, len);
+}
+
+/* Curl_gtls_init()
+ *
+ * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
+ * are not thread-safe and thus this function itself is not thread-safe and
+ * must only be called from within curl_global_init() to keep the thread
+ * situation under control!
+ */
+int Curl_gtls_init(void)
+{
+ int ret = 1;
+ if(!gtls_inited) {
+ ret = gnutls_global_init()?0:1;
+#ifdef GTLSDEBUG
+ gnutls_global_set_log_function(tls_log_func);
+ gnutls_global_set_log_level(2);
+#endif
+ gtls_inited = TRUE;
+ }
+ return ret;
+}
+
+int Curl_gtls_cleanup(void)
+{
+ if(gtls_inited) {
+ gnutls_global_deinit();
+ gtls_inited = FALSE;
+ }
+ return 1;
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void showtime(struct Curl_easy *data,
+ const char *text,
+ time_t stamp)
+{
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+ char str[96];
+ CURLcode result = Curl_gmtime(stamp, &buffer);
+ if(result)
+ return;
+
+ snprintf(str,
+ sizeof(str),
+ "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT",
+ text,
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ infof(data, "%s\n", str);
+}
+#endif
+
+static gnutls_datum_t load_file(const char *file)
+{
+ FILE *f;
+ gnutls_datum_t loaded_file = { NULL, 0 };
+ long filelen;
+ void *ptr;
+
+ f = fopen(file, "rb");
+ if(!f)
+ return loaded_file;
+ if(fseek(f, 0, SEEK_END) != 0
+ || (filelen = ftell(f)) < 0
+ || fseek(f, 0, SEEK_SET) != 0
+ || !(ptr = malloc((size_t)filelen)))
+ goto out;
+ if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
+ free(ptr);
+ goto out;
+ }
+
+ loaded_file.data = ptr;
+ loaded_file.size = (unsigned int)filelen;
+out:
+ fclose(f);
+ return loaded_file;
+}
+
+static void unload_file(gnutls_datum_t data)
+{
+ free(data.data);
+}
+
+
+/* this function does a SSL/TLS (re-)handshake */
+static CURLcode handshake(struct connectdata *conn,
+ int sockindex,
+ bool duringconnect,
+ bool nonblocking)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ gnutls_session_t session = conn->ssl[sockindex].session;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ time_t timeout_ms;
+ int rc;
+ int what;
+
+ for(;;) {
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, duringconnect);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking?0:
+ timeout_ms?timeout_ms:1000);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking)
+ return CURLE_OK;
+ else if(timeout_ms) {
+ /* timeout */
+ failf(data, "SSL connection timeout at %ld", (long)timeout_ms);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ rc = gnutls_handshake(session);
+
+ if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
+ connssl->connecting_state =
+ gnutls_record_get_direction(session)?
+ ssl_connect_2_writing:ssl_connect_2_reading;
+ continue;
+ }
+ else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
+ const char *strerr = NULL;
+
+ if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
+ int alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
+ }
+
+ if(strerr == NULL)
+ strerr = gnutls_strerror(rc);
+
+ infof(data, "gnutls_handshake() warning: %s\n", strerr);
+ continue;
+ }
+ else if(rc < 0) {
+ const char *strerr = NULL;
+
+ if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
+ int alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
+ }
+
+ if(strerr == NULL)
+ strerr = gnutls_strerror(rc);
+
+ failf(data, "gnutls_handshake() failed: %s", strerr);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+ return CURLE_OK;
+ }
+}
+
+static gnutls_x509_crt_fmt_t do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return GNUTLS_X509_FMT_PEM;
+ if(strcasecompare(type, "PEM"))
+ return GNUTLS_X509_FMT_PEM;
+ if(strcasecompare(type, "DER"))
+ return GNUTLS_X509_FMT_DER;
+ return -1;
+}
+
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+static CURLcode
+set_ssl_version_min_max(int *list, size_t list_size, struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long i = ssl_version;
+ long protocol_priority_idx = 0;
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version << 16;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ for(; i <= (ssl_version_max >> 16) &&
+ protocol_priority_idx < list_size; ++i) {
+ switch(i) {
+ case CURL_SSLVERSION_TLSv1_0:
+ protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_0;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_1;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ protocol_priority[protocol_priority_idx++] = GNUTLS_TLS1_2;
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "GnuTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ return CURLE_OK;
+}
+#else
+#define GNUTLS_CIPHERS "NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509"
+/* If GnuTLS was compiled without support for SRP it will error out if SRP is
+ requested in the priority string, so treat it specially
+ */
+#define GNUTLS_SRP "+SRP"
+
+static CURLcode
+set_ssl_version_min_max(const char **prioritylist, struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ if(ssl_version == CURL_SSLVERSION_TLSv1_3 ||
+ ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) {
+ failf(data, "GnuTLS: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
+ ssl_version_max = ssl_version << 16;
+ }
+ switch(ssl_version | ssl_version_max) {
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.0:" GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_1:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.0:+VERS-TLS1.1:" GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.0:+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_1:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.1:" GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_1 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.1:+VERS-TLS1.2:" GNUTLS_SRP;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_2 | CURL_SSLVERSION_MAX_DEFAULT:
+ *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:"
+ "+VERS-TLS1.2:" GNUTLS_SRP;
+ return CURLE_OK;
+ }
+
+ failf(data, "GnuTLS: cannot set ssl protocol");
+ return CURLE_SSL_CONNECT_ERROR;
+}
+#endif
+
+static CURLcode
+gtls_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ unsigned int init_flags;
+ gnutls_session_t session;
+ int rc;
+ bool sni = TRUE; /* default is SNI enabled */
+ void *transport_ptr = NULL;
+ gnutls_push_func gnutls_transport_push = NULL;
+ gnutls_pull_func gnutls_transport_pull = NULL;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+ static const int cipher_priority[] = {
+ /* These two ciphers were added to GnuTLS as late as ver. 3.0.1,
+ but this code path is only ever used for ver. < 2.12.0.
+ GNUTLS_CIPHER_AES_128_GCM,
+ GNUTLS_CIPHER_AES_256_GCM,
+ */
+ GNUTLS_CIPHER_AES_128_CBC,
+ GNUTLS_CIPHER_AES_256_CBC,
+ GNUTLS_CIPHER_CAMELLIA_128_CBC,
+ GNUTLS_CIPHER_CAMELLIA_256_CBC,
+ GNUTLS_CIPHER_3DES_CBC,
+ };
+ static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+ int protocol_priority[] = { 0, 0, 0, 0 };
+#else
+ const char *prioritylist;
+ const char *err = NULL;
+#endif
+
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ if(conn->ssl[sockindex].state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ if(!gtls_inited)
+ Curl_gtls_init();
+
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef USE_TLS_SRP
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
+ infof(data, "Using TLS-SRP username: %s\n", SSL_SET_OPTION(username));
+
+ rc = gnutls_srp_allocate_client_credentials(
+ &conn->ssl[sockindex].srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
+ srp_client_cred,
+ SSL_SET_OPTION(username),
+ SSL_SET_OPTION(password));
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+#endif
+
+ if(SSL_CONN_CONFIG(CAfile)) {
+ /* set the trusted CA cert bundle file */
+ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+ rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
+ SSL_CONN_CONFIG(CAfile),
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ infof(data, "error reading ca cert file %s (%s)\n",
+ SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
+ if(SSL_CONN_CONFIG(verifypeer))
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else
+ infof(data, "found %d certificates in %s\n", rc,
+ SSL_CONN_CONFIG(CAfile));
+ }
+
+#ifdef HAS_CAPATH
+ if(SSL_CONN_CONFIG(CApath)) {
+ /* set the trusted CA cert directory */
+ rc = gnutls_certificate_set_x509_trust_dir(conn->ssl[sockindex].cred,
+ SSL_CONN_CONFIG(CApath),
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ infof(data, "error reading ca cert file %s (%s)\n",
+ SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
+ if(SSL_CONN_CONFIG(verifypeer))
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else
+ infof(data, "found %d certificates in %s\n",
+ rc, SSL_CONN_CONFIG(CApath));
+ }
+#endif
+
+#ifdef CURL_CA_FALLBACK
+ /* use system ca certificate store as fallback */
+ if(SSL_CONN_CONFIG(verifypeer) &&
+ !(SSL_CONN_CONFIG(CAfile) || SSL_CONN_CONFIG(CApath))) {
+ gnutls_certificate_set_x509_system_trust(conn->ssl[sockindex].cred);
+ }
+#endif
+
+ if(SSL_SET_OPTION(CRLfile)) {
+ /* set the CRL list file */
+ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
+ SSL_SET_OPTION(CRLfile),
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ failf(data, "error reading crl file %s (%s)",
+ SSL_SET_OPTION(CRLfile), gnutls_strerror(rc));
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ else
+ infof(data, "found %d CRL in %s\n",
+ rc, SSL_SET_OPTION(CRLfile));
+ }
+
+ /* Initialize TLS session as a client */
+ init_flags = GNUTLS_CLIENT;
+
+#if defined(GNUTLS_NO_TICKETS)
+ /* Disable TLS session tickets */
+ init_flags |= GNUTLS_NO_TICKETS;
+#endif
+
+ rc = gnutls_init(&conn->ssl[sockindex].session, init_flags);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_init() failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* convenient assign */
+ session = conn->ssl[sockindex].session;
+
+ if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
+#endif
+ sni &&
+ (gnutls_server_name_set(session, GNUTLS_NAME_DNS, hostname,
+ strlen(hostname)) < 0))
+ infof(data, "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+
+ /* Use default priorities */
+ rc = gnutls_set_default_priority(session);
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+ rc = gnutls_cipher_set_priority(session, cipher_priority);
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* Sets the priority on the certificate types supported by gnutls. Priority
+ is higher for types specified before others. After specifying the types
+ you want, you must append a 0. */
+ rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ if(SSL_CONN_CONFIG(cipher_list) != NULL) {
+ failf(data, "can't pass a custom cipher list to older GnuTLS"
+ " versions");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_SSLv3:
+ protocol_priority[0] = GNUTLS_SSL3;
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ protocol_priority[0] = GNUTLS_TLS1_0;
+ protocol_priority[1] = GNUTLS_TLS1_1;
+ protocol_priority[2] = GNUTLS_TLS1_2;
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(protocol_priority,
+ sizeof(protocol_priority)/sizeof(protocol_priority[0]), conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ rc = gnutls_protocol_set_priority(session, protocol_priority);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "Did you pass a valid GnuTLS cipher list?");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#else
+ /* Ensure +SRP comes at the *end* of all relevant strings so that it can be
+ * removed if a run-time error indicates that SRP is not supported by this
+ * GnuTLS version */
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_SSLv3:
+ prioritylist = GNUTLS_CIPHERS ":-VERS-TLS-ALL:+VERS-SSL3.0";
+ sni = false;
+ break;
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:" GNUTLS_SRP;
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(&prioritylist, conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv2:
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ rc = gnutls_priority_set_direct(session, prioritylist, &err);
+ if((rc == GNUTLS_E_INVALID_REQUEST) && err) {
+ if(!strcmp(err, GNUTLS_SRP)) {
+ /* This GnuTLS was probably compiled without support for SRP.
+ * Note that fact and try again without it. */
+ int validprioritylen = curlx_uztosi(err - prioritylist);
+ char *prioritycopy = strdup(prioritylist);
+ if(!prioritycopy)
+ return CURLE_OUT_OF_MEMORY;
+
+ infof(data, "This GnuTLS does not support SRP\n");
+ if(validprioritylen)
+ /* Remove the :+SRP */
+ prioritycopy[validprioritylen - 1] = 0;
+ rc = gnutls_priority_set_direct(session, prioritycopy, &err);
+ free(prioritycopy);
+ }
+ }
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "Error %d setting GnuTLS cipher list starting with %s",
+ rc, err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ int cur = 0;
+ gnutls_datum_t protocols[2];
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
+ protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
+ cur++;
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ protocols[cur].data = (unsigned char *)ALPN_HTTP_1_1;
+ protocols[cur].size = ALPN_HTTP_1_1_LENGTH;
+ cur++;
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ gnutls_alpn_set_protocols(session, protocols, cur, 0);
+ }
+#endif
+
+ if(SSL_SET_OPTION(cert)) {
+ if(SSL_SET_OPTION(key_passwd)) {
+#if HAVE_GNUTLS_CERTIFICATE_SET_X509_KEY_FILE2
+ const unsigned int supported_key_encryption_algorithms =
+ GNUTLS_PKCS_USE_PKCS12_3DES | GNUTLS_PKCS_USE_PKCS12_ARCFOUR |
+ GNUTLS_PKCS_USE_PKCS12_RC2_40 | GNUTLS_PKCS_USE_PBES2_3DES |
+ GNUTLS_PKCS_USE_PBES2_AES_128 | GNUTLS_PKCS_USE_PBES2_AES_192 |
+ GNUTLS_PKCS_USE_PBES2_AES_256;
+ rc = gnutls_certificate_set_x509_key_file2(
+ conn->ssl[sockindex].cred,
+ SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key) ?
+ SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+ do_file_type(SSL_SET_OPTION(cert_type)),
+ SSL_SET_OPTION(key_passwd),
+ supported_key_encryption_algorithms);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data,
+ "error reading X.509 potentially-encrypted key file: %s",
+ gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#else
+ failf(data, "gnutls lacks support for encrypted key files");
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ }
+ else {
+ if(gnutls_certificate_set_x509_key_file(
+ conn->ssl[sockindex].cred,
+ SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key) ?
+ SSL_SET_OPTION(key) : SSL_SET_OPTION(cert),
+ do_file_type(SSL_SET_OPTION(cert_type)) ) !=
+ GNUTLS_E_SUCCESS) {
+ failf(data, "error reading X.509 key or certificate file");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ }
+
+#ifdef USE_TLS_SRP
+ /* put the credentials to the current session */
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP) {
+ rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
+ conn->ssl[sockindex].srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else
+#endif
+ {
+ rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+ conn->ssl[sockindex].cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ if(conn->proxy_ssl[sockindex].use) {
+ transport_ptr = conn->proxy_ssl[sockindex].session;
+ gnutls_transport_push = Curl_gtls_push_ssl;
+ gnutls_transport_pull = Curl_gtls_pull_ssl;
+ }
+ else {
+ /* file descriptor for the socket */
+ transport_ptr = GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]);
+ gnutls_transport_push = Curl_gtls_push;
+ gnutls_transport_pull = Curl_gtls_pull;
+ }
+
+ /* set the connection handle */
+ gnutls_transport_set_ptr(session, transport_ptr);
+
+ /* register callback functions to send and receive data. */
+ gnutls_transport_set_push_function(session, gnutls_transport_push);
+ gnutls_transport_set_pull_function(session, gnutls_transport_pull);
+
+ /* lowat must be set to zero when using custom push and pull functions. */
+ gnutls_transport_set_lowat(session, 0);
+
+#ifdef HAS_OCSP
+ if(SSL_CONN_CONFIG(verifystatus)) {
+ rc = gnutls_ocsp_status_request_enable_client(session, NULL, 0, NULL);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_ocsp_status_request_enable_client() failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#endif
+
+ /* This might be a reconnect, so we check for a session ID in the cache
+ to speed up things */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *ssl_sessionid;
+ size_t ssl_idsize;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize, sockindex)) {
+ /* we got a session id, use it! */
+ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+
+ /* Informational message */
+ infof(data, "SSL re-using session ID\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
+ gnutls_x509_crt_t cert,
+ const char *pinnedpubkey)
+{
+ /* Scratch */
+ size_t len1 = 0, len2 = 0;
+ unsigned char *buff1 = NULL;
+
+ gnutls_pubkey_t key = NULL;
+
+ /* Result is returned to caller */
+ int ret = 0;
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ /* if a path wasn't specified, don't pin */
+ if(NULL == pinnedpubkey)
+ return CURLE_OK;
+
+ if(NULL == cert)
+ return result;
+
+ do {
+ /* Begin Gyrations to get the public key */
+ gnutls_pubkey_init(&key);
+
+ ret = gnutls_pubkey_import_x509(key, cert, 0);
+ if(ret < 0)
+ break; /* failed */
+
+ ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, NULL, &len1);
+ if(ret != GNUTLS_E_SHORT_MEMORY_BUFFER || len1 == 0)
+ break; /* failed */
+
+ buff1 = malloc(len1);
+ if(NULL == buff1)
+ break; /* failed */
+
+ len2 = len1;
+
+ ret = gnutls_pubkey_export(key, GNUTLS_X509_FMT_DER, buff1, &len2);
+ if(ret < 0 || len1 != len2)
+ break; /* failed */
+
+ /* End Gyrations */
+
+ /* The one good exit point */
+ result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
+ } while(0);
+
+ if(NULL != key)
+ gnutls_pubkey_deinit(key);
+
+ Curl_safefree(buff1);
+
+ return result;
+}
+
+static Curl_recv gtls_recv;
+static Curl_send gtls_send;
+
+static CURLcode
+gtls_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ unsigned int cert_list_size;
+ const gnutls_datum_t *chainp;
+ unsigned int verify_status = 0;
+ gnutls_x509_crt_t x509_cert, x509_issuer;
+ gnutls_datum_t issuerp;
+ char certbuf[256] = ""; /* big enough? */
+ size_t size;
+ time_t certclock;
+ const char *ptr;
+ struct Curl_easy *data = conn->data;
+ gnutls_session_t session = conn->ssl[sockindex].session;
+ int rc;
+#ifdef HAS_ALPN
+ gnutls_datum_t proto;
+#endif
+ CURLcode result = CURLE_OK;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ unsigned int algo;
+ unsigned int bits;
+ gnutls_protocol_t version = gnutls_protocol_get_version(session);
+#endif
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
+ ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
+ gnutls_cipher_get(session),
+ gnutls_mac_get(session));
+
+ infof(data, "SSL connection using %s / %s\n",
+ gnutls_protocol_get_name(version), ptr);
+
+ /* This function will return the peer's raw certificate (chain) as sent by
+ the peer. These certificates are in raw format (DER encoded for
+ X.509). In case of a X.509 then a certificate list may be present. The
+ first certificate in the list is the peer's certificate, following the
+ issuer's certificate, then the issuer's issuer etc. */
+
+ chainp = gnutls_certificate_get_peers(session, &cert_list_size);
+ if(!chainp) {
+ if(SSL_CONN_CONFIG(verifypeer) ||
+ SSL_CONN_CONFIG(verifyhost) ||
+ SSL_SET_OPTION(issuercert)) {
+#ifdef USE_TLS_SRP
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
+ && SSL_SET_OPTION(username) != NULL
+ && !SSL_CONN_CONFIG(verifypeer)
+ && gnutls_cipher_get(session)) {
+ /* no peer cert, but auth is ok if we have SRP user and cipher and no
+ peer verify */
+ }
+ else {
+#endif
+ failf(data, "failed to get server cert");
+ return CURLE_PEER_FAILED_VERIFICATION;
+#ifdef USE_TLS_SRP
+ }
+#endif
+ }
+ infof(data, "\t common name: WARNING couldn't obtain\n");
+ }
+
+ if(data->set.ssl.certinfo && chainp) {
+ unsigned int i;
+
+ result = Curl_ssl_init_certinfo(data, cert_list_size);
+ if(result)
+ return result;
+
+ for(i = 0; i < cert_list_size; i++) {
+ const char *beg = (const char *) chainp[i].data;
+ const char *end = beg + chainp[i].size;
+
+ result = Curl_extract_certinfo(conn, i, beg, end);
+ if(result)
+ return result;
+ }
+ }
+
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ /* This function will try to verify the peer's certificate and return its
+ status (trusted, invalid etc.). The value of status should be one or
+ more of the gnutls_certificate_status_t enumerated elements bitwise
+ or'd. To avoid denial of service attacks some default upper limits
+ regarding the certificate key size and chain size are set. To override
+ them use gnutls_certificate_set_verify_limits(). */
+
+ rc = gnutls_certificate_verify_peers2(session, &verify_status);
+ if(rc < 0) {
+ failf(data, "server cert verify failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* verify_status is a bitmask of gnutls_certificate_status bits */
+ if(verify_status & GNUTLS_CERT_INVALID) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "server certificate verification failed. CAfile: %s "
+ "CRLfile: %s", SSL_CONN_CONFIG(CAfile) ? SSL_CONN_CONFIG(CAfile):
+ "none",
+ SSL_SET_OPTION(CRLfile)?SSL_SET_OPTION(CRLfile):"none");
+ return CURLE_SSL_CACERT;
+ }
+ else
+ infof(data, "\t server certificate verification FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate verification OK\n");
+ }
+ else
+ infof(data, "\t server certificate verification SKIPPED\n");
+
+#ifdef HAS_OCSP
+ if(SSL_CONN_CONFIG(verifystatus)) {
+ if(gnutls_ocsp_status_request_is_checked(session, 0) == 0) {
+ gnutls_datum_t status_request;
+ gnutls_ocsp_resp_t ocsp_resp;
+
+ gnutls_ocsp_cert_status_t status;
+ gnutls_x509_crl_reason_t reason;
+
+ rc = gnutls_ocsp_status_request_get(session, &status_request);
+
+ infof(data, "\t server certificate status verification FAILED\n");
+
+ if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) {
+ failf(data, "No OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+
+ gnutls_ocsp_resp_init(&ocsp_resp);
+
+ rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request);
+ if(rc < 0) {
+ failf(data, "Invalid OCSP response received");
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+
+ rc = gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL,
+ &status, NULL, NULL, NULL, &reason);
+
+ switch(status) {
+ case GNUTLS_OCSP_CERT_GOOD:
+ break;
+
+ case GNUTLS_OCSP_CERT_REVOKED: {
+ const char *crl_reason;
+
+ switch(reason) {
+ default:
+ case GNUTLS_X509_CRLREASON_UNSPECIFIED:
+ crl_reason = "unspecified reason";
+ break;
+
+ case GNUTLS_X509_CRLREASON_KEYCOMPROMISE:
+ crl_reason = "private key compromised";
+ break;
+
+ case GNUTLS_X509_CRLREASON_CACOMPROMISE:
+ crl_reason = "CA compromised";
+ break;
+
+ case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED:
+ crl_reason = "affiliation has changed";
+ break;
+
+ case GNUTLS_X509_CRLREASON_SUPERSEDED:
+ crl_reason = "certificate superseded";
+ break;
+
+ case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION:
+ crl_reason = "operation has ceased";
+ break;
+
+ case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD:
+ crl_reason = "certificate is on hold";
+ break;
+
+ case GNUTLS_X509_CRLREASON_REMOVEFROMCRL:
+ crl_reason = "will be removed from delta CRL";
+ break;
+
+ case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN:
+ crl_reason = "privilege withdrawn";
+ break;
+
+ case GNUTLS_X509_CRLREASON_AACOMPROMISE:
+ crl_reason = "AA compromised";
+ break;
+ }
+
+ failf(data, "Server certificate was revoked: %s", crl_reason);
+ break;
+ }
+
+ default:
+ case GNUTLS_OCSP_CERT_UNKNOWN:
+ failf(data, "Server certificate status is unknown");
+ break;
+ }
+
+ gnutls_ocsp_resp_deinit(ocsp_resp);
+
+ return CURLE_SSL_INVALIDCERTSTATUS;
+ }
+ else
+ infof(data, "\t server certificate status verification OK\n");
+ }
+ else
+ infof(data, "\t server certificate status verification SKIPPED\n");
+#endif
+
+ /* initialize an X.509 certificate structure. */
+ gnutls_x509_crt_init(&x509_cert);
+
+ if(chainp)
+ /* convert the given DER or PEM encoded Certificate to the native
+ gnutls_x509_crt_t format */
+ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
+
+ if(SSL_SET_OPTION(issuercert)) {
+ gnutls_x509_crt_init(&x509_issuer);
+ issuerp = load_file(SSL_SET_OPTION(issuercert));
+ gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
+ rc = gnutls_x509_crt_check_issuer(x509_cert, x509_issuer);
+ gnutls_x509_crt_deinit(x509_issuer);
+ unload_file(issuerp);
+ if(rc <= 0) {
+ failf(data, "server certificate issuer check failed (IssuerCert: %s)",
+ SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+ infof(data, "\t server certificate issuer check OK (Issuer Cert: %s)\n",
+ SSL_SET_OPTION(issuercert)?SSL_SET_OPTION(issuercert):"none");
+ }
+
+ size=sizeof(certbuf);
+ rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
+ 0, /* the first and only one */
+ FALSE,
+ certbuf,
+ &size);
+ if(rc) {
+ infof(data, "error fetching CN from cert:%s\n",
+ gnutls_strerror(rc));
+ }
+
+ /* This function will check if the given certificate's subject matches the
+ given hostname. This is a basic implementation of the matching described
+ in RFC2818 (HTTPS), which takes into account wildcards, and the subject
+ alternative name PKIX extension. Returns non zero on success, and zero on
+ failure. */
+ rc = gnutls_x509_crt_check_hostname(x509_cert, hostname);
+#if GNUTLS_VERSION_NUMBER < 0x030306
+ /* Before 3.3.6, gnutls_x509_crt_check_hostname() didn't check IP
+ addresses. */
+ if(!rc) {
+#ifdef ENABLE_IPV6
+ #define use_addr in6_addr
+#else
+ #define use_addr in_addr
+#endif
+ unsigned char addrbuf[sizeof(struct use_addr)];
+ unsigned char certaddr[sizeof(struct use_addr)];
+ size_t addrlen = 0, certaddrlen;
+ int i;
+ int ret = 0;
+
+ if(Curl_inet_pton(AF_INET, hostname, addrbuf) > 0)
+ addrlen = 4;
+#ifdef ENABLE_IPV6
+ else if(Curl_inet_pton(AF_INET6, hostname, addrbuf) > 0)
+ addrlen = 16;
+#endif
+
+ if(addrlen) {
+ for(i=0; ; i++) {
+ certaddrlen = sizeof(certaddr);
+ ret = gnutls_x509_crt_get_subject_alt_name(x509_cert, i, certaddr,
+ &certaddrlen, NULL);
+ /* If this happens, it wasn't an IP address. */
+ if(ret == GNUTLS_E_SHORT_MEMORY_BUFFER)
+ continue;
+ if(ret < 0)
+ break;
+ if(ret != GNUTLS_SAN_IPADDRESS)
+ continue;
+ if(certaddrlen == addrlen && !memcmp(addrbuf, certaddr, addrlen)) {
+ rc = 1;
+ break;
+ }
+ }
+ }
+ }
+#endif
+ if(!rc) {
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ failf(data, "SSL: certificate subject name (%s) does not match "
+ "target host name '%s'", certbuf, dispname);
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t common name: %s (does not match '%s')\n",
+ certbuf, dispname);
+ }
+ else
+ infof(data, "\t common name: %s (matched)\n", certbuf);
+
+ /* Check for time-based validity */
+ certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+
+ if(certclock == (time_t)-1) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "server cert expiration date verify failed");
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else
+ infof(data, "\t server certificate expiration date verify FAILED\n");
+ }
+ else {
+ if(certclock < time(NULL)) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "server certificate expiration date has passed.");
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate expiration date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate expiration date OK\n");
+ }
+
+ certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+
+ if(certclock == (time_t)-1) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "server cert activation date verify failed");
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else
+ infof(data, "\t server certificate activation date verify FAILED\n");
+ }
+ else {
+ if(certclock > time(NULL)) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ failf(data, "server certificate not activated yet.");
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate activation date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate activation date OK\n");
+ }
+
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ if(ptr) {
+ result = pkp_pin_peer_pubkey(data, x509_cert, ptr);
+ if(result != CURLE_OK) {
+ failf(data, "SSL: public key does not match pinned public key!");
+ gnutls_x509_crt_deinit(x509_cert);
+ return result;
+ }
+ }
+
+ /* Show:
+
+ - subject
+ - start date
+ - expire date
+ - common name
+ - issuer
+
+ */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ /* public key algorithm's parameters */
+ algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
+ infof(data, "\t certificate public key: %s\n",
+ gnutls_pk_algorithm_get_name(algo));
+
+ /* version of the X.509 certificate. */
+ infof(data, "\t certificate version: #%d\n",
+ gnutls_x509_crt_get_version(x509_cert));
+
+
+ size = sizeof(certbuf);
+ gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
+ infof(data, "\t subject: %s\n", certbuf);
+
+ certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+ showtime(data, "start date", certclock);
+
+ certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+ showtime(data, "expire date", certclock);
+
+ size = sizeof(certbuf);
+ gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
+ infof(data, "\t issuer: %s\n", certbuf);
+
+ /* compression algorithm (if any) */
+ ptr = gnutls_compression_get_name(gnutls_compression_get(session));
+ /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
+ infof(data, "\t compression: %s\n", ptr);
+#endif
+
+ gnutls_x509_crt_deinit(x509_cert);
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ rc = gnutls_alpn_get_selected_protocol(session, &proto);
+ if(rc == 0) {
+ infof(data, "ALPN, server accepted to use %.*s\n", proto.size,
+ proto.data);
+
+#ifdef USE_NGHTTP2
+ if(proto.size == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(NGHTTP2_PROTO_VERSION_ID, proto.data,
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(proto.size == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, proto.data, ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+ else
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ }
+#endif
+
+ conn->ssl[sockindex].state = ssl_connection_complete;
+ conn->recv[sockindex] = gtls_recv;
+ conn->send[sockindex] = gtls_send;
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+ bool incache;
+ void *ssl_sessionid;
+ void *connect_sessionid;
+ size_t connect_idsize = 0;
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+ if(connect_sessionid) {
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ Curl_ssl_sessionid_lock(conn);
+ incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL,
+ sockindex));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(conn, ssl_sessionid);
+ }
+
+ /* store this session id */
+ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize,
+ sockindex);
+ Curl_ssl_sessionid_unlock(conn);
+ if(result) {
+ free(connect_sessionid);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic.
+ */
+/* We use connssl->connecting_state to keep track of the connection status;
+ there are three states: 'ssl_connect_1' (not started yet or complete),
+ 'ssl_connect_2_reading' (waiting for data from server), and
+ 'ssl_connect_2_writing' (waiting to be able to write).
+ */
+static CURLcode
+gtls_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ int rc;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ /* Initiate the connection, if not already done */
+ if(ssl_connect_1==connssl->connecting_state) {
+ rc = gtls_connect_step1(conn, sockindex);
+ if(rc)
+ return rc;
+ }
+
+ rc = handshake(conn, sockindex, TRUE, nonblocking);
+ if(rc)
+ /* handshake() sets its own error message with failf() */
+ return rc;
+
+ /* Finish connecting once the handshake is done */
+ if(ssl_connect_1==connssl->connecting_state) {
+ rc = gtls_connect_step3(conn, sockindex);
+ if(rc)
+ return rc;
+ }
+
+ *done = ssl_connect_1==connssl->connecting_state;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_gtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return gtls_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_gtls_connect(struct connectdata *conn,
+ int sockindex)
+
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = gtls_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+bool Curl_gtls_data_pending(const struct connectdata *conn, int connindex)
+{
+ bool res = FALSE;
+ if(conn->ssl[connindex].session &&
+ 0 != gnutls_record_check_pending(conn->ssl[connindex].session))
+ res = TRUE;
+
+ if(conn->proxy_ssl[connindex].session &&
+ 0 != gnutls_record_check_pending(conn->proxy_ssl[connindex].session))
+ res = TRUE;
+
+ return res;
+}
+
+static ssize_t gtls_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
+
+ if(rc < 0) {
+ *curlcode = (rc == GNUTLS_E_AGAIN)
+ ? CURLE_AGAIN
+ : CURLE_SEND_ERROR;
+
+ rc = -1;
+ }
+
+ return rc;
+}
+
+static void close_one(struct ssl_connect_data *ssl)
+{
+ if(ssl->session) {
+ gnutls_bye(ssl->session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(ssl->session);
+ ssl->session = NULL;
+ }
+ if(ssl->cred) {
+ gnutls_certificate_free_credentials(ssl->cred);
+ ssl->cred = NULL;
+ }
+#ifdef USE_TLS_SRP
+ if(ssl->srp_client_cred) {
+ gnutls_srp_free_client_credentials(ssl->srp_client_cred);
+ ssl->srp_client_cred = NULL;
+ }
+#endif
+}
+
+void Curl_gtls_close(struct connectdata *conn, int sockindex)
+{
+ close_one(&conn->ssl[sockindex]);
+ close_one(&conn->proxy_ssl[sockindex]);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+{
+ ssize_t result;
+ int retval = 0;
+ struct Curl_easy *data = conn->data;
+ int done = 0;
+ char buf[120];
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
+
+ if(conn->ssl[sockindex].session) {
+ while(!done) {
+ int what = SOCKET_READABLE(conn->sock[sockindex],
+ SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server */
+ result = gnutls_record_recv(conn->ssl[sockindex].session,
+ buf, sizeof(buf));
+ switch(result) {
+ case 0:
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = 1;
+ break;
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+ break;
+ default:
+ retval = -1;
+ done = 1;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = 1;
+ break;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = 1;
+ }
+ }
+ gnutls_deinit(conn->ssl[sockindex].session);
+ }
+ gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+
+#ifdef USE_TLS_SRP
+ if(SSL_SET_OPTION(authtype) == CURL_TLSAUTH_SRP
+ && SSL_SET_OPTION(username) != NULL)
+ gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
+#endif
+
+ conn->ssl[sockindex].cred = NULL;
+ conn->ssl[sockindex].session = NULL;
+
+ return retval;
+}
+
+static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ ssize_t ret;
+
+ ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
+ if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
+
+ if(ret == GNUTLS_E_REHANDSHAKE) {
+ /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
+ proper way" takes a whole lot of work. */
+ CURLcode result = handshake(conn, num, FALSE, FALSE);
+ if(result)
+ /* handshake() writes error message on its own */
+ *curlcode = result;
+ else
+ *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
+ return -1;
+ }
+
+ if(ret < 0) {
+ failf(conn->data, "GnuTLS recv error (%d): %s",
+ (int)ret, gnutls_strerror((int)ret));
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ return ret;
+}
+
+void Curl_gtls_session_free(void *ptr)
+{
+ free(ptr);
+}
+
+size_t Curl_gtls_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
+}
+
+#ifndef USE_GNUTLS_NETTLE
+static int Curl_gtls_seed(struct Curl_easy *data)
+{
+ /* we have the "SSL is seeded" boolean static to prevent multiple
+ time-consuming seedings in vain */
+ static bool ssl_seeded = FALSE;
+
+ /* Quickly add a bit of entropy */
+ gcry_fast_random_poll();
+
+ if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+ data->set.str[STRING_SSL_EGDSOCKET]) {
+
+ /* TODO: to a good job seeding the RNG
+ This may involve the gcry_control function and these options:
+ GCRYCTL_SET_RANDOM_SEED_FILE
+ GCRYCTL_SET_RNDEGD_SOCKET
+ */
+ ssl_seeded = TRUE;
+ }
+ return 0;
+}
+#endif
+
+/* data might be NULL! */
+CURLcode Curl_gtls_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
+{
+#if defined(USE_GNUTLS_NETTLE)
+ int rc;
+ (void)data;
+ rc = gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
+ return rc?CURLE_FAILED_INIT:CURLE_OK;
+#elif defined(USE_GNUTLS)
+ if(data)
+ Curl_gtls_seed(data); /* Initiate the seed if not already done */
+ gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
+#endif
+ return CURLE_OK;
+}
+
+void Curl_gtls_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+#if defined(USE_GNUTLS_NETTLE)
+ struct md5_ctx MD5pw;
+ md5_init(&MD5pw);
+ md5_update(&MD5pw, (unsigned int)tmplen, tmp);
+ md5_digest(&MD5pw, (unsigned int)md5len, md5sum);
+#elif defined(USE_GNUTLS)
+ gcry_md_hd_t MD5pw;
+ gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
+ gcry_md_write(MD5pw, tmp, tmplen);
+ memcpy(md5sum, gcry_md_read(MD5pw, 0), md5len);
+ gcry_md_close(MD5pw);
+#endif
+}
+
+void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
+{
+#if defined(USE_GNUTLS_NETTLE)
+ struct sha256_ctx SHA256pw;
+ sha256_init(&SHA256pw);
+ sha256_update(&SHA256pw, (unsigned int)tmplen, tmp);
+ sha256_digest(&SHA256pw, (unsigned int)sha256len, sha256sum);
+#elif defined(USE_GNUTLS)
+ gcry_md_hd_t SHA256pw;
+ gcry_md_open(&SHA256pw, GCRY_MD_SHA256, 0);
+ gcry_md_write(SHA256pw, tmp, tmplen);
+ memcpy(sha256sum, gcry_md_read(SHA256pw, 0), sha256len);
+ gcry_md_close(SHA256pw);
+#endif
+}
+
+bool Curl_gtls_cert_status_request(void)
+{
+#ifdef HAS_OCSP
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+#endif /* USE_GNUTLS */
diff --git a/Utilities/cmcurl/lib/vtls/gtls.h b/Utilities/cmcurl/lib/vtls/gtls.h
new file mode 100644
index 000000000..462c04853
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/gtls.h
@@ -0,0 +1,96 @@
+#ifndef HEADER_CURL_GTLS_H
+#define HEADER_CURL_GTLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_GNUTLS
+
+#include "urldata.h"
+
+int Curl_gtls_init(void);
+int Curl_gtls_cleanup(void);
+CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+bool Curl_gtls_data_pending(const struct connectdata *conn,
+ int connindex);
+
+ /* close a SSL connection */
+void Curl_gtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_gtls_session_free(void *ptr);
+size_t Curl_gtls_version(char *buffer, size_t size);
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
+CURLcode Curl_gtls_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length);
+void Curl_gtls_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len);
+void Curl_gtls_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len);
+
+bool Curl_gtls_cert_status_request(void);
+
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
+/* Set the API backend definition to GnuTLS */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_GNUTLS
+
+/* this backend supports the CAPATH option */
+#define have_curlssl_ca_path 1
+
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* API setup for GnuTLS */
+#define curlssl_init Curl_gtls_init
+#define curlssl_cleanup Curl_gtls_cleanup
+#define curlssl_connect Curl_gtls_connect
+#define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking
+#define curlssl_session_free(x) Curl_gtls_session_free(x)
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_gtls_close
+#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y)
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_gtls_version
+#define curlssl_check_cxn(x) ((void)x, -1)
+#define curlssl_data_pending(x,y) Curl_gtls_data_pending(x,y)
+#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
+#define curlssl_sha256sum(a,b,c,d) Curl_gtls_sha256sum(a,b,c,d)
+#define curlssl_cert_status_request() Curl_gtls_cert_status_request()
+
+#endif /* USE_GNUTLS */
+#endif /* HEADER_CURL_GTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.c b/Utilities/cmcurl/lib/vtls/mbedtls.c
new file mode 100644
index 000000000..037babe38
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.c
@@ -0,0 +1,1010 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all mbedTLS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+#include <mbedtls/version.h>
+#if MBEDTLS_VERSION_NUMBER >= 0x02040000
+#include <mbedtls/net_sockets.h>
+#else
+#include <mbedtls/net.h>
+#endif
+#include <mbedtls/ssl.h>
+#include <mbedtls/certs.h>
+#include <mbedtls/x509.h>
+
+#include <mbedtls/error.h>
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+#include <mbedtls/sha256.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "mbedtls.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "polarssl_threadlock.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* apply threading? */
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#define THREADING_SUPPORT
+#endif
+
+#if defined(THREADING_SUPPORT)
+static mbedtls_entropy_context ts_entropy;
+
+static int entropy_init_initialized = 0;
+
+/* start of entropy_init_mutex() */
+static void entropy_init_mutex(mbedtls_entropy_context *ctx)
+{
+ /* lock 0 = entropy_init_mutex() */
+ Curl_polarsslthreadlock_lock_function(0);
+ if(entropy_init_initialized == 0) {
+ mbedtls_entropy_init(ctx);
+ entropy_init_initialized = 1;
+ }
+ Curl_polarsslthreadlock_unlock_function(0);
+}
+/* end of entropy_init_mutex() */
+
+/* start of entropy_func_mutex() */
+static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
+{
+ int ret;
+ /* lock 1 = entropy_func_mutex() */
+ Curl_polarsslthreadlock_lock_function(1);
+ ret = mbedtls_entropy_func(data, output, len);
+ Curl_polarsslthreadlock_unlock_function(1);
+
+ return ret;
+}
+/* end of entropy_func_mutex() */
+
+#endif /* THREADING_SUPPORT */
+
+/* Define this to enable lots of debugging for mbedTLS */
+#undef MBEDTLS_DEBUG
+
+#ifdef MBEDTLS_DEBUG
+static void mbed_debug(void *context, int level, const char *f_name,
+ int line_nb, const char *line)
+{
+ struct Curl_easy *data = NULL;
+
+ if(!context)
+ return;
+
+ data = (struct Curl_easy *)context;
+
+ infof(data, "%s", line);
+ (void) level;
+}
+#else
+#endif
+
+/* ALPN for http2? */
+#ifdef USE_NGHTTP2
+# undef HAS_ALPN
+# ifdef MBEDTLS_SSL_ALPN
+# define HAS_ALPN
+# endif
+#endif
+
+
+/*
+ * profile
+ */
+static const mbedtls_x509_crt_profile mbedtls_x509_crt_profile_fr =
+{
+ /* Hashes from SHA-1 and above */
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA1) |
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_RIPEMD160) |
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA224) |
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA256) |
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA384) |
+ MBEDTLS_X509_ID_FLAG(MBEDTLS_MD_SHA512),
+ 0xFFFFFFF, /* Any PK alg */
+ 0xFFFFFFF, /* Any curve */
+ 1024, /* RSA min key len */
+};
+
+/* See https://tls.mbed.org/discussions/generic/
+ howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES (38 + 2 * MBEDTLS_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES (30 + 2 * MBEDTLS_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
+static Curl_recv mbed_recv;
+static Curl_send mbed_send;
+
+static CURLcode mbedtls_version_from_curl(int *mbedver, long version)
+{
+ switch(version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_1;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_2;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2:
+ *mbedver = MBEDTLS_SSL_MINOR_VERSION_3;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+static CURLcode
+set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ int mbedtls_ver_min = MBEDTLS_SSL_MINOR_VERSION_1;
+ int mbedtls_ver_max = MBEDTLS_SSL_MINOR_VERSION_1;
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ CURLcode result = CURLE_OK;
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version << 16;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ result = mbedtls_version_from_curl(&mbedtls_ver_min, ssl_version);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ result = mbedtls_version_from_curl(&mbedtls_ver_max, ssl_version_max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+
+ mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ver_min);
+ mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ mbedtls_ver_max);
+
+ return result;
+}
+
+static CURLcode
+mbed_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+ int ret = -1;
+ char errorbuf[128];
+ errorbuf[0]=0;
+
+ /* mbedTLS only supports SSLv3 and TLSv1 */
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
+ failf(data, "mbedTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef THREADING_SUPPORT
+ entropy_init_mutex(&ts_entropy);
+ mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+
+ ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, entropy_func_mutex,
+ &ts_entropy, NULL, 0);
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#else
+ mbedtls_entropy_init(&connssl->entropy);
+ mbedtls_ctr_drbg_init(&connssl->ctr_drbg);
+
+ ret = mbedtls_ctr_drbg_seed(&connssl->ctr_drbg, mbedtls_entropy_func,
+ &connssl->entropy, NULL, 0);
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Failed - mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#endif /* THREADING_SUPPORT */
+
+ /* Load the trusted CA */
+ mbedtls_x509_crt_init(&connssl->cacert);
+
+ if(ssl_cafile) {
+ ret = mbedtls_x509_crt_parse_file(&connssl->cacert, ssl_cafile);
+
+ if(ret<0) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Error reading ca cert file %s - mbedTLS: (-0x%04X) %s",
+ ssl_cafile, -ret, errorbuf);
+
+ if(verifypeer)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ if(ssl_capath) {
+ ret = mbedtls_x509_crt_parse_path(&connssl->cacert, ssl_capath);
+
+ if(ret<0) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Error reading ca cert path %s - mbedTLS: (-0x%04X) %s",
+ ssl_capath, -ret, errorbuf);
+
+ if(verifypeer)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ /* Load the client certificate */
+ mbedtls_x509_crt_init(&connssl->clicert);
+
+ if(ssl_cert) {
+ ret = mbedtls_x509_crt_parse_file(&connssl->clicert, ssl_cert);
+
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Error reading client cert file %s - mbedTLS: (-0x%04X) %s",
+ ssl_cert, -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the client private key */
+ mbedtls_pk_init(&connssl->pk);
+
+ if(SSL_SET_OPTION(key)) {
+ ret = mbedtls_pk_parse_keyfile(&connssl->pk, SSL_SET_OPTION(key),
+ SSL_SET_OPTION(key_passwd));
+ if(ret == 0 && !mbedtls_pk_can_do(&connssl->pk, MBEDTLS_PK_RSA))
+ ret = MBEDTLS_ERR_PK_TYPE_MISMATCH;
+
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Error reading private key %s - mbedTLS: (-0x%04X) %s",
+ SSL_SET_OPTION(key), -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the CRL */
+ mbedtls_x509_crl_init(&connssl->crl);
+
+ if(ssl_crlfile) {
+ ret = mbedtls_x509_crl_parse_file(&connssl->crl, ssl_crlfile);
+
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Error reading CRL file %s - mbedTLS: (-0x%04X) %s",
+ ssl_crlfile, -ret, errorbuf);
+
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ }
+
+ infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
+
+ mbedtls_ssl_config_init(&connssl->config);
+
+ mbedtls_ssl_init(&connssl->ssl);
+ if(mbedtls_ssl_setup(&connssl->ssl, &connssl->config)) {
+ failf(data, "mbedTLS: ssl_init failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ ret = mbedtls_ssl_config_defaults(&connssl->config,
+ MBEDTLS_SSL_IS_CLIENT,
+ MBEDTLS_SSL_TRANSPORT_STREAM,
+ MBEDTLS_SSL_PRESET_DEFAULT);
+ if(ret) {
+ failf(data, "mbedTLS: ssl_config failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* new profile with RSA min key len = 1024 ... */
+ mbedtls_ssl_conf_cert_profile(&connssl->config,
+ &mbedtls_x509_crt_profile_fr);
+
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_1);
+ infof(data, "mbedTLS: Set min SSL version to TLS 1.0\n");
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ mbedtls_ssl_conf_min_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_0);
+ mbedtls_ssl_conf_max_version(&connssl->config, MBEDTLS_SSL_MAJOR_VERSION_3,
+ MBEDTLS_SSL_MINOR_VERSION_0);
+ infof(data, "mbedTLS: Set SSL version to SSLv3\n");
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ mbedtls_ssl_conf_authmode(&connssl->config, MBEDTLS_SSL_VERIFY_OPTIONAL);
+
+ mbedtls_ssl_conf_rng(&connssl->config, mbedtls_ctr_drbg_random,
+ &connssl->ctr_drbg);
+ mbedtls_ssl_set_bio(&connssl->ssl, &conn->sock[sockindex],
+ mbedtls_net_send,
+ mbedtls_net_recv,
+ NULL /* rev_timeout() */);
+
+ mbedtls_ssl_conf_ciphersuites(&connssl->config,
+ mbedtls_ssl_list_ciphersuites());
+
+#if defined(MBEDTLS_SSL_RENEGOTIATION)
+ mbedtls_ssl_conf_renegotiation(&connssl->config,
+ MBEDTLS_SSL_RENEGOTIATION_ENABLED);
+#endif
+
+#if defined(MBEDTLS_SSL_SESSION_TICKETS)
+ mbedtls_ssl_conf_session_tickets(&connssl->config,
+ MBEDTLS_SSL_SESSION_TICKETS_DISABLED);
+#endif
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *old_session = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
+ ret = mbedtls_ssl_set_session(&connssl->ssl, old_session);
+ if(ret) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "mbedtls_ssl_set_session returned -0x%x", -ret);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ infof(data, "mbedTLS re-using session\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ mbedtls_ssl_conf_ca_chain(&connssl->config,
+ &connssl->cacert,
+ &connssl->crl);
+
+ if(SSL_SET_OPTION(key)) {
+ mbedtls_ssl_conf_own_cert(&connssl->config,
+ &connssl->clicert, &connssl->pk);
+ }
+ if(mbedtls_ssl_set_hostname(&connssl->ssl, hostname)) {
+ /* mbedtls_ssl_set_hostname() sets the name to use in CN/SAN checks *and*
+ the name to set in the SNI extension. So even if curl connects to a
+ host specified as an IP address, this function must be used. */
+ failf(data, "couldn't set hostname in mbedTLS");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ const char **p = &connssl->protocols[0];
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2)
+ *p++ = NGHTTP2_PROTO_VERSION_ID;
+#endif
+ *p++ = ALPN_HTTP_1_1;
+ *p = NULL;
+ /* this function doesn't clone the protocols array, which is why we need
+ to keep it around */
+ if(mbedtls_ssl_conf_alpn_protocols(&connssl->config,
+ &connssl->protocols[0])) {
+ failf(data, "Failed setting ALPN protocols");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ for(p = &connssl->protocols[0]; *p; ++p)
+ infof(data, "ALPN, offering %s\n", *p);
+ }
+#endif
+
+#ifdef MBEDTLS_DEBUG
+ /* In order to make that work in mbedtls MBEDTLS_DEBUG_C must be defined. */
+ mbedtls_ssl_conf_dbg(&connssl->config, mbed_debug, data);
+ /* - 0 No debug
+ * - 1 Error
+ * - 2 State change
+ * - 3 Informational
+ * - 4 Verbose
+ */
+ mbedtls_debug_set_threshold(4);
+#endif
+
+ /* give application a chance to interfere with mbedTLS set up. */
+ if(data->set.ssl.fsslctx) {
+ ret = (*data->set.ssl.fsslctx)(data, &connssl->config,
+ data->set.ssl.fsslctxp);
+ if(ret) {
+ failf(data, "error signaled by ssl ctx callback");
+ return ret;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step2(struct connectdata *conn,
+ int sockindex)
+{
+ int ret;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ const mbedtls_x509_crt *peercert;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
+#ifdef HAS_ALPN
+ const char *next_protocol;
+#endif
+
+ char errorbuf[128];
+ errorbuf[0] = 0;
+
+ conn->recv[sockindex] = mbed_recv;
+ conn->send[sockindex] = mbed_send;
+
+ ret = mbedtls_ssl_handshake(&connssl->ssl);
+
+ if(ret == MBEDTLS_ERR_SSL_WANT_READ) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ else if(ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ else if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "ssl_handshake returned - mbedTLS: (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "mbedTLS: Handshake complete, cipher is %s\n",
+ mbedtls_ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
+ );
+
+ ret = mbedtls_ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+
+ if(ret && SSL_CONN_CONFIG(verifypeer)) {
+ if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
+ failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+ if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
+ failf(data, "Cert verify failed: BADCERT_REVOKED");
+ return CURLE_SSL_CACERT;
+ }
+
+ if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+ failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+ if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+ failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ peercert = mbedtls_ssl_get_peer_cert(&connssl->ssl);
+
+ if(peercert && data->set.verbose) {
+ const size_t bufsize = 16384;
+ char *buffer = malloc(bufsize);
+
+ if(!buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(mbedtls_x509_crt_info(buffer, bufsize, "* ", peercert) > 0)
+ infof(data, "Dumping cert info:\n%s\n", buffer);
+ else
+ infof(data, "Unable to dump certificate information.\n");
+
+ free(buffer);
+ }
+
+ if(pinnedpubkey) {
+ int size;
+ CURLcode result;
+ mbedtls_x509_crt *p;
+ unsigned char pubkey[PUB_DER_MAX_BYTES];
+
+ if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+ failf(data, "Failed due to missing peer certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ p = calloc(1, sizeof(*p));
+
+ if(!p)
+ return CURLE_OUT_OF_MEMORY;
+
+ mbedtls_x509_crt_init(p);
+
+ /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der
+ needs a non-const key, for now.
+ https://github.com/ARMmbed/mbedtls/issues/396 */
+ if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+ failf(data, "Failed copying peer certificate");
+ mbedtls_x509_crt_free(p);
+ free(p);
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+
+ if(size <= 0) {
+ failf(data, "Failed copying public key from peer certificate");
+ mbedtls_x509_crt_free(p);
+ free(p);
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ /* mbedtls_pk_write_pubkey_der writes data at the end of the buffer. */
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ &pubkey[PUB_DER_MAX_BYTES - size], size);
+ if(result) {
+ mbedtls_x509_crt_free(p);
+ free(p);
+ return result;
+ }
+
+ mbedtls_x509_crt_free(p);
+ free(p);
+ }
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ next_protocol = mbedtls_ssl_get_alpn_protocol(&connssl->ssl);
+
+ if(next_protocol) {
+ infof(data, "ALPN, server accepted to use %s\n", next_protocol);
+#ifdef USE_NGHTTP2
+ if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN) &&
+ !next_protocol[NGHTTP2_PROTO_VERSION_ID_LEN]) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH) &&
+ !next_protocol[ALPN_HTTP_1_1_LENGTH]) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+ else {
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ }
+ }
+#endif
+
+ connssl->connecting_state = ssl_connect_3;
+ infof(data, "SSL connected\n");
+
+ return CURLE_OK;
+}
+
+static CURLcode
+mbed_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ int ret;
+ mbedtls_ssl_session *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+
+ our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
+ if(!our_ssl_sessionid)
+ return CURLE_OUT_OF_MEMORY;
+
+ mbedtls_ssl_session_init(our_ssl_sessionid);
+
+ ret = mbedtls_ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+ if(ret) {
+ free(our_ssl_sessionid);
+ failf(data, "mbedtls_ssl_get_session returned -0x%x", -ret);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* If there's already a matching session in the cache, delete it */
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
+ Curl_ssl_sessionid_unlock(conn);
+ if(retcode) {
+ free(our_ssl_sessionid);
+ failf(data, "failed to store ssl session");
+ return retcode;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return CURLE_OK;
+}
+
+static ssize_t mbed_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+
+ ret = mbedtls_ssl_write(&conn->ssl[sockindex].ssl,
+ (unsigned char *)mem, len);
+
+ if(ret < 0) {
+ *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_WRITE) ?
+ CURLE_AGAIN : CURLE_SEND_ERROR;
+ ret = -1;
+ }
+
+ return ret;
+}
+
+void Curl_mbedtls_close_all(struct Curl_easy *data)
+{
+ (void)data;
+}
+
+void Curl_mbedtls_close(struct connectdata *conn, int sockindex)
+{
+ mbedtls_pk_free(&conn->ssl[sockindex].pk);
+ mbedtls_x509_crt_free(&conn->ssl[sockindex].clicert);
+ mbedtls_x509_crt_free(&conn->ssl[sockindex].cacert);
+ mbedtls_x509_crl_free(&conn->ssl[sockindex].crl);
+ mbedtls_ssl_config_free(&conn->ssl[sockindex].config);
+ mbedtls_ssl_free(&conn->ssl[sockindex].ssl);
+ mbedtls_ctr_drbg_free(&conn->ssl[sockindex].ctr_drbg);
+#ifndef THREADING_SUPPORT
+ mbedtls_entropy_free(&conn->ssl[sockindex].entropy);
+#endif /* THREADING_SUPPORT */
+}
+
+static ssize_t mbed_recv(struct connectdata *conn, int num,
+ char *buf, size_t buffersize,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+ ssize_t len = -1;
+
+ memset(buf, 0, buffersize);
+ ret = mbedtls_ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf,
+ buffersize);
+
+ if(ret <= 0) {
+ if(ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY)
+ return 0;
+
+ *curlcode = (ret == MBEDTLS_ERR_SSL_WANT_READ) ?
+ CURLE_AGAIN : CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ len = ret;
+
+ return len;
+}
+
+void Curl_mbedtls_session_free(void *ptr)
+{
+ mbedtls_ssl_session_free(ptr);
+ free(ptr);
+}
+
+size_t Curl_mbedtls_version(char *buffer, size_t size)
+{
+ unsigned int version = mbedtls_version_get_number();
+ return snprintf(buffer, size, "mbedTLS/%d.%d.%d", version>>24,
+ (version>>16)&0xff, (version>>8)&0xff);
+}
+
+CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length)
+{
+#if defined(MBEDTLS_CTR_DRBG_C)
+ int ret = -1;
+ char errorbuf[128];
+ mbedtls_entropy_context ctr_entropy;
+ mbedtls_ctr_drbg_context ctr_drbg;
+ mbedtls_entropy_init(&ctr_entropy);
+ mbedtls_ctr_drbg_init(&ctr_drbg);
+ errorbuf[0]=0;
+
+ ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
+ &ctr_entropy, NULL, 0);
+
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "Failed - mbedTLS: ctr_drbg_seed returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+ else {
+ ret = mbedtls_ctr_drbg_random(&ctr_drbg, entropy, length);
+
+ if(ret) {
+#ifdef MBEDTLS_ERROR_C
+ mbedtls_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* MBEDTLS_ERROR_C */
+ failf(data, "mbedTLS: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+ }
+
+ mbedtls_ctr_drbg_free(&ctr_drbg);
+ mbedtls_entropy_free(&ctr_entropy);
+
+ return ret == 0 ? CURLE_OK : CURLE_FAILED_INIT;
+#elif defined(MBEDTLS_HAVEGE_C)
+ mbedtls_havege_state hs;
+ mbedtls_havege_init(&hs);
+ mbedtls_havege_random(&hs, entropy, length);
+ mbedtls_havege_free(&hs);
+ return CURLE_OK;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+static CURLcode
+mbed_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode retcode;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ retcode = mbed_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking ? 0 : timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ retcode = mbed_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3==connssl->connecting_state) {
+ retcode = mbed_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done==connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = mbed_recv;
+ conn->send[sockindex] = mbed_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return mbed_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_mbedtls_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = mbed_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+/*
+ * return 0 error initializing SSL
+ * return 1 SSL initialized successfully
+ */
+int Curl_mbedtls_init(void)
+{
+ return Curl_polarsslthreadlock_thread_setup();
+}
+
+void Curl_mbedtls_cleanup(void)
+{
+ (void)Curl_polarsslthreadlock_thread_cleanup();
+}
+
+int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex)
+{
+ return mbedtls_ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0;
+}
+
+#endif /* USE_MBEDTLS */
diff --git a/Utilities/cmcurl/lib/vtls/mbedtls.h b/Utilities/cmcurl/lib/vtls/mbedtls.h
new file mode 100644
index 000000000..71d17a491
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/mbedtls.h
@@ -0,0 +1,82 @@
+#ifndef HEADER_CURL_MBEDTLS_H
+#define HEADER_CURL_MBEDTLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_MBEDTLS
+
+#include <mbedtls/sha256.h>
+
+/* Called on first use mbedTLS, setup threading if supported */
+int Curl_mbedtls_init(void);
+void Curl_mbedtls_cleanup(void);
+int Curl_mbedtls_data_pending(const struct connectdata *conn, int sockindex);
+
+CURLcode Curl_mbedtls_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_mbedtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* tell mbedTLS to close down all open information regarding connections (and
+ thus session ID caching etc) */
+void Curl_mbedtls_close_all(struct Curl_easy *data);
+
+ /* close a SSL connection */
+void Curl_mbedtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_mbedtls_session_free(void *ptr);
+size_t Curl_mbedtls_version(char *buffer, size_t size);
+int Curl_mbedtls_shutdown(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_mbedtls_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* this backend supports CURLOPT_SSL_CTX_* */
+#define have_curlssl_ssl_ctx 1
+
+/* API setup for mbedTLS */
+#define curlssl_init() Curl_mbedtls_init()
+#define curlssl_cleanup() Curl_mbedtls_cleanup()
+#define curlssl_connect Curl_mbedtls_connect
+#define curlssl_connect_nonblocking Curl_mbedtls_connect_nonblocking
+#define curlssl_session_free(x) Curl_mbedtls_session_free(x)
+#define curlssl_close_all Curl_mbedtls_close_all
+#define curlssl_close Curl_mbedtls_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_mbedtls_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) Curl_mbedtls_data_pending(x, y)
+#define CURL_SSL_BACKEND CURLSSLBACKEND_MBEDTLS
+#define curlssl_sha256sum(a,b,c,d) mbedtls_sha256(a,b,c,0)
+#define curlssl_random(x,y,z) Curl_mbedtls_random(x, y, z)
+
+#endif /* USE_MBEDTLS */
+#endif /* HEADER_CURL_MBEDTLS_H */
diff --git a/Utilities/cmcurl/lib/vtls/nss.c b/Utilities/cmcurl/lib/vtls/nss.c
new file mode 100644
index 000000000..cd0138930
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/nss.c
@@ -0,0 +1,2311 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all NSS-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_NSS
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "connect.h"
+#include "strcase.h"
+#include "select.h"
+#include "vtls.h"
+#include "llist.h"
+#include "curl_printf.h"
+#include "nssg.h"
+#include <nspr.h>
+#include <nss.h>
+#include <ssl.h>
+#include <sslerr.h>
+#include <secerr.h>
+#include <secmod.h>
+#include <sslproto.h>
+#include <prtypes.h>
+#include <pk11pub.h>
+#include <prio.h>
+#include <secitem.h>
+#include <secport.h>
+#include <certdb.h>
+#include <base64.h>
+#include <cert.h>
+#include <prerror.h>
+#include <keyhi.h> /* for SECKEY_DestroyPublicKey() */
+#include <private/pprio.h> /* for PR_ImportTCPSocket */
+
+#define NSSVERNUM ((NSS_VMAJOR<<16)|(NSS_VMINOR<<8)|NSS_VPATCH)
+
+#if NSSVERNUM >= 0x030f00 /* 3.15.0 */
+#include <ocsp.h>
+#endif
+
+#include "strcase.h"
+#include "warnless.h"
+#include "x509asn1.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SSL_DIR "/etc/pki/nssdb"
+
+/* enough to fit the string "PEM Token #[0|1]" */
+#define SLOTSIZE 13
+
+static PRLock *nss_initlock = NULL;
+static PRLock *nss_crllock = NULL;
+static PRLock *nss_findslot_lock = NULL;
+static PRLock *nss_trustload_lock = NULL;
+static struct curl_llist nss_crl_list;
+static NSSInitContext *nss_context = NULL;
+static volatile int initialized = 0;
+
+/* type used to wrap pointers as list nodes */
+struct ptr_list_wrap {
+ void *ptr;
+ struct curl_llist_element node;
+};
+
+typedef struct {
+ const char *name;
+ int num;
+} cipher_s;
+
+#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
+ CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
+ ptr->type = (_type); \
+ ptr->pValue = (_val); \
+ ptr->ulValueLen = (_len); \
+} WHILE_FALSE
+
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+
+#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
+static const cipher_s cipherlist[] = {
+ /* SSL2 cipher suites */
+ {"rc4", SSL_EN_RC4_128_WITH_MD5},
+ {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
+ {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
+ {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
+ {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
+ {"des", SSL_EN_DES_64_CBC_WITH_MD5},
+ {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
+ /* SSL3/TLS cipher suites */
+ {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
+ {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
+ {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
+ {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
+ {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
+ {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
+ {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
+ {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
+ {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
+ {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
+ {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
+ {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
+ /* TLS 1.0: Exportable 56-bit Cipher Suites. */
+ {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
+ {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
+ /* AES ciphers. */
+ {"dhe_dss_aes_128_cbc_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
+ {"dhe_dss_aes_256_cbc_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
+ {"dhe_rsa_aes_128_cbc_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+ {"dhe_rsa_aes_256_cbc_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
+ {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
+ /* ECC ciphers. */
+ {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
+ {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
+ {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
+ {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+ {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
+ {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
+ {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
+ {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
+ {"ecdhe_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
+ {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
+ {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
+ {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
+ {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
+#ifdef TLS_RSA_WITH_NULL_SHA256
+ /* new HMAC-SHA256 cipher suites specified in RFC */
+ {"rsa_null_sha_256", TLS_RSA_WITH_NULL_SHA256},
+ {"rsa_aes_128_cbc_sha_256", TLS_RSA_WITH_AES_128_CBC_SHA256},
+ {"rsa_aes_256_cbc_sha_256", TLS_RSA_WITH_AES_256_CBC_SHA256},
+ {"dhe_rsa_aes_128_cbc_sha_256", TLS_DHE_RSA_WITH_AES_128_CBC_SHA256},
+ {"dhe_rsa_aes_256_cbc_sha_256", TLS_DHE_RSA_WITH_AES_256_CBC_SHA256},
+ {"ecdhe_ecdsa_aes_128_cbc_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256},
+ {"ecdhe_rsa_aes_128_cbc_sha_256", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256},
+#endif
+#ifdef TLS_RSA_WITH_AES_128_GCM_SHA256
+ /* AES GCM cipher suites in RFC 5288 and RFC 5289 */
+ {"rsa_aes_128_gcm_sha_256", TLS_RSA_WITH_AES_128_GCM_SHA256},
+ {"dhe_rsa_aes_128_gcm_sha_256", TLS_DHE_RSA_WITH_AES_128_GCM_SHA256},
+ {"dhe_dss_aes_128_gcm_sha_256", TLS_DHE_DSS_WITH_AES_128_GCM_SHA256},
+ {"ecdhe_ecdsa_aes_128_gcm_sha_256", TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ {"ecdh_ecdsa_aes_128_gcm_sha_256", TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256},
+ {"ecdhe_rsa_aes_128_gcm_sha_256", TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256},
+ {"ecdh_rsa_aes_128_gcm_sha_256", TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256},
+#endif
+#ifdef TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ /* cipher suites using SHA384 */
+ {"rsa_aes_256_gcm_sha_384", TLS_RSA_WITH_AES_256_GCM_SHA384},
+ {"dhe_rsa_aes_256_gcm_sha_384", TLS_DHE_RSA_WITH_AES_256_GCM_SHA384},
+ {"dhe_dss_aes_256_gcm_sha_384", TLS_DHE_DSS_WITH_AES_256_GCM_SHA384},
+ {"ecdhe_ecdsa_aes_256_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384},
+ {"ecdhe_rsa_aes_256_sha_384", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384},
+ {"ecdhe_ecdsa_aes_256_gcm_sha_384", TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384},
+ {"ecdhe_rsa_aes_256_gcm_sha_384", TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384},
+#endif
+#ifdef TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ /* chacha20-poly1305 cipher suites */
+ {"ecdhe_rsa_chacha20_poly1305_sha_256",
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"ecdhe_ecdsa_chacha20_poly1305_sha_256",
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256},
+ {"dhe_rsa_chacha20_poly1305_sha_256",
+ TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+#endif
+};
+
+static const char *pem_library = "libnsspem.so";
+static SECMODModule *pem_module = NULL;
+
+static const char *trust_library = "libnssckbi.so";
+static SECMODModule *trust_module = NULL;
+
+/* NSPR I/O layer we use to detect blocking direction during SSL handshake */
+static PRDescIdentity nspr_io_identity = PR_INVALID_IO_LAYER;
+static PRIOMethods nspr_io_methods;
+
+static const char *nss_error_to_name(PRErrorCode code)
+{
+ const char *name = PR_ErrorToName(code);
+ if(name)
+ return name;
+
+ return "unknown error";
+}
+
+static void nss_print_error_message(struct Curl_easy *data, PRUint32 err)
+{
+ failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+}
+
+static SECStatus set_ciphers(struct Curl_easy *data, PRFileDesc * model,
+ char *cipher_list)
+{
+ unsigned int i;
+ PRBool cipher_state[NUM_OF_CIPHERS];
+ PRBool found;
+ char *cipher;
+
+ /* use accessors to avoid dynamic linking issues after an update of NSS */
+ const PRUint16 num_implemented_ciphers = SSL_GetNumImplementedCiphers();
+ const PRUint16 *implemented_ciphers = SSL_GetImplementedCiphers();
+ if(!implemented_ciphers)
+ return SECFailure;
+
+ /* First disable all ciphers. This uses a different max value in case
+ * NSS adds more ciphers later we don't want them available by
+ * accident
+ */
+ for(i = 0; i < num_implemented_ciphers; i++) {
+ SSL_CipherPrefSet(model, implemented_ciphers[i], PR_FALSE);
+ }
+
+ /* Set every entry in our list to false */
+ for(i = 0; i < NUM_OF_CIPHERS; i++) {
+ cipher_state[i] = PR_FALSE;
+ }
+
+ cipher = cipher_list;
+
+ while(cipher_list && (cipher_list[0])) {
+ while((*cipher) && (ISSPACE(*cipher)))
+ ++cipher;
+
+ cipher_list = strchr(cipher, ',');
+ if(cipher_list) {
+ *cipher_list++ = '\0';
+ }
+
+ found = PR_FALSE;
+
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ if(strcasecompare(cipher, cipherlist[i].name)) {
+ cipher_state[i] = PR_TRUE;
+ found = PR_TRUE;
+ break;
+ }
+ }
+
+ if(found == PR_FALSE) {
+ failf(data, "Unknown cipher in list: %s", cipher);
+ return SECFailure;
+ }
+
+ if(cipher_list) {
+ cipher = cipher_list;
+ }
+ }
+
+ /* Finally actually enable the selected ciphers */
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ if(!cipher_state[i])
+ continue;
+
+ if(SSL_CipherPrefSet(model, cipherlist[i].num, PR_TRUE) != SECSuccess) {
+ failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
+ return SECFailure;
+ }
+ }
+
+ return SECSuccess;
+}
+
+/*
+ * Return true if at least one cipher-suite is enabled. Used to determine
+ * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
+ */
+static bool any_cipher_enabled(void)
+{
+ unsigned int i;
+
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ PRInt32 policy = 0;
+ SSL_CipherPolicyGet(cipherlist[i].num, &policy);
+ if(policy)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * Determine whether the nickname passed in is a filename that needs to
+ * be loaded as a PEM or a regular NSS nickname.
+ *
+ * returns 1 for a file
+ * returns 0 for not a file (NSS nickname)
+ */
+static int is_file(const char *filename)
+{
+ struct_stat st;
+
+ if(filename == NULL)
+ return 0;
+
+ if(stat(filename, &st) == 0)
+ if(S_ISREG(st.st_mode))
+ return 1;
+
+ return 0;
+}
+
+/* Check if the given string is filename or nickname of a certificate. If the
+ * given string is recognized as filename, return NULL. If the given string is
+ * recognized as nickname, return a duplicated string. The returned string
+ * should be later deallocated using free(). If the OOM failure occurs, we
+ * return NULL, too.
+ */
+static char *dup_nickname(struct Curl_easy *data, const char *str)
+{
+ const char *n;
+
+ if(!is_file(str))
+ /* no such file exists, use the string as nickname */
+ return strdup(str);
+
+ /* search the first slash; we require at least one slash in a file name */
+ n = strchr(str, '/');
+ if(!n) {
+ infof(data, "warning: certificate file name \"%s\" handled as nickname; "
+ "please use \"./%s\" to force file name\n", str, str);
+ return strdup(str);
+ }
+
+ /* we'll use the PEM reader to read the certificate from file */
+ return NULL;
+}
+
+/* Lock/unlock wrapper for PK11_FindSlotByName() to work around race condition
+ * in nssSlot_IsTokenPresent() causing spurious SEC_ERROR_NO_TOKEN. For more
+ * details, go to <https://bugzilla.mozilla.org/1297397>.
+ */
+static PK11SlotInfo* nss_find_slot_by_name(const char *slot_name)
+{
+ PK11SlotInfo *slot;
+ PR_Lock(nss_findslot_lock);
+ slot = PK11_FindSlotByName(slot_name);
+ PR_Unlock(nss_findslot_lock);
+ return slot;
+}
+
+/* wrap 'ptr' as list node and tail-insert into 'list' */
+static CURLcode insert_wrapped_ptr(struct curl_llist *list, void *ptr)
+{
+ struct ptr_list_wrap *wrap = malloc(sizeof *wrap);
+ if(!wrap)
+ return CURLE_OUT_OF_MEMORY;
+
+ wrap->ptr = ptr;
+ Curl_llist_insert_next(list, list->tail, wrap, &wrap->node);
+ return CURLE_OK;
+}
+
+/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
+ * the call succeeds, append the object handle to the list of objects so that
+ * the object can be destroyed in Curl_nss_close(). */
+static CURLcode nss_create_object(struct ssl_connect_data *ssl,
+ CK_OBJECT_CLASS obj_class,
+ const char *filename, bool cacert)
+{
+ PK11SlotInfo *slot;
+ PK11GenericObject *obj;
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_BBOOL ckfalse = CK_FALSE;
+ CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
+ int attr_cnt = 0;
+ CURLcode result = (cacert)
+ ? CURLE_SSL_CACERT_BADFILE
+ : CURLE_SSL_CERTPROBLEM;
+
+ const int slot_id = (cacert) ? 0 : 1;
+ char *slot_name = aprintf("PEM Token #%d", slot_id);
+ if(!slot_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ slot = nss_find_slot_by_name(slot_name);
+ free(slot_name);
+ if(!slot)
+ return result;
+
+ PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
+ PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
+ PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
+ (CK_ULONG)strlen(filename) + 1);
+
+ if(CKO_CERTIFICATE == obj_class) {
+ CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
+ PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
+ }
+
+ obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
+ PK11_FreeSlot(slot);
+ if(!obj)
+ return result;
+
+ if(insert_wrapped_ptr(&ssl->obj_list, obj) != CURLE_OK) {
+ PK11_DestroyGenericObject(obj);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!cacert && CKO_CERTIFICATE == obj_class)
+ /* store reference to a client certificate */
+ ssl->obj_clicert = obj;
+
+ return CURLE_OK;
+}
+
+/* Destroy the NSS object whose handle is given by ptr. This function is
+ * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
+ * NSS objects in Curl_nss_close() */
+static void nss_destroy_object(void *user, void *ptr)
+{
+ struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
+ PK11GenericObject *obj = (PK11GenericObject *) wrap->ptr;
+ (void) user;
+ PK11_DestroyGenericObject(obj);
+ free(wrap);
+}
+
+/* same as nss_destroy_object() but for CRL items */
+static void nss_destroy_crl_item(void *user, void *ptr)
+{
+ struct ptr_list_wrap *wrap = (struct ptr_list_wrap *) ptr;
+ SECItem *crl_der = (SECItem *) wrap->ptr;
+ (void) user;
+ SECITEM_FreeItem(crl_der, PR_TRUE);
+ free(wrap);
+}
+
+static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
+ const char *filename, PRBool cacert)
+{
+ CURLcode result = (cacert)
+ ? CURLE_SSL_CACERT_BADFILE
+ : CURLE_SSL_CERTPROBLEM;
+
+ /* libnsspem.so leaks memory if the requested file does not exist. For more
+ * details, go to <https://bugzilla.redhat.com/734760>. */
+ if(is_file(filename))
+ result = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
+
+ if(!result && !cacert) {
+ /* we have successfully loaded a client certificate */
+ CERTCertificate *cert;
+ char *nickname = NULL;
+ char *n = strrchr(filename, '/');
+ if(n)
+ n++;
+
+ /* The following undocumented magic helps to avoid a SIGSEGV on call
+ * of PK11_ReadRawAttribute() from SelectClientCert() when using an
+ * immature version of libnsspem.so. For more details, go to
+ * <https://bugzilla.redhat.com/733685>. */
+ nickname = aprintf("PEM Token #1:%s", n);
+ if(nickname) {
+ cert = PK11_FindCertFromNickname(nickname, NULL);
+ if(cert)
+ CERT_DestroyCertificate(cert);
+
+ free(nickname);
+ }
+ }
+
+ return result;
+}
+
+/* add given CRL to cache if it is not already there */
+static CURLcode nss_cache_crl(SECItem *crl_der)
+{
+ CERTCertDBHandle *db = CERT_GetDefaultCertDB();
+ CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crl_der, 0);
+ if(crl) {
+ /* CRL already cached */
+ SEC_DestroyCrl(crl);
+ SECITEM_FreeItem(crl_der, PR_TRUE);
+ return CURLE_OK;
+ }
+
+ /* acquire lock before call of CERT_CacheCRL() and accessing nss_crl_list */
+ PR_Lock(nss_crllock);
+
+ /* store the CRL item so that we can free it in Curl_nss_cleanup() */
+ if(insert_wrapped_ptr(&nss_crl_list, crl_der) != CURLE_OK) {
+ SECITEM_FreeItem(crl_der, PR_TRUE);
+ PR_Unlock(nss_crllock);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(SECSuccess != CERT_CacheCRL(db, crl_der)) {
+ /* unable to cache CRL */
+ PR_Unlock(nss_crllock);
+ return CURLE_SSL_CRL_BADFILE;
+ }
+
+ /* we need to clear session cache, so that the CRL could take effect */
+ SSL_ClearSessionCache();
+ PR_Unlock(nss_crllock);
+ return CURLE_OK;
+}
+
+static CURLcode nss_load_crl(const char *crlfilename)
+{
+ PRFileDesc *infile;
+ PRFileInfo info;
+ SECItem filedata = { 0, NULL, 0 };
+ SECItem *crl_der = NULL;
+ char *body;
+
+ infile = PR_Open(crlfilename, PR_RDONLY, 0);
+ if(!infile)
+ return CURLE_SSL_CRL_BADFILE;
+
+ if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
+ goto fail;
+
+ if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
+ goto fail;
+
+ if(info.size != PR_Read(infile, filedata.data, info.size))
+ goto fail;
+
+ crl_der = SECITEM_AllocItem(NULL, NULL, 0U);
+ if(!crl_der)
+ goto fail;
+
+ /* place a trailing zero right after the visible data */
+ body = (char *)filedata.data;
+ body[--filedata.len] = '\0';
+
+ body = strstr(body, "-----BEGIN");
+ if(body) {
+ /* assume ASCII */
+ char *trailer;
+ char *begin = PORT_Strchr(body, '\n');
+ if(!begin)
+ begin = PORT_Strchr(body, '\r');
+ if(!begin)
+ goto fail;
+
+ trailer = strstr(++begin, "-----END");
+ if(!trailer)
+ goto fail;
+
+ /* retrieve DER from ASCII */
+ *trailer = '\0';
+ if(ATOB_ConvertAsciiToItem(crl_der, begin))
+ goto fail;
+
+ SECITEM_FreeItem(&filedata, PR_FALSE);
+ }
+ else
+ /* assume DER */
+ *crl_der = filedata;
+
+ PR_Close(infile);
+ return nss_cache_crl(crl_der);
+
+fail:
+ PR_Close(infile);
+ SECITEM_FreeItem(crl_der, PR_TRUE);
+ SECITEM_FreeItem(&filedata, PR_FALSE);
+ return CURLE_SSL_CRL_BADFILE;
+}
+
+static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
+ char *key_file)
+{
+ PK11SlotInfo *slot, *tmp;
+ SECStatus status;
+ CURLcode result;
+ struct ssl_connect_data *ssl = conn->ssl;
+ struct Curl_easy *data = conn->data;
+
+ (void)sockindex; /* unused */
+
+ result = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
+ if(result) {
+ PR_SetError(SEC_ERROR_BAD_KEY, 0);
+ return result;
+ }
+
+ slot = nss_find_slot_by_name("PEM Token #1");
+ if(!slot)
+ return CURLE_SSL_CERTPROBLEM;
+
+ /* This will force the token to be seen as re-inserted */
+ tmp = SECMOD_WaitForAnyTokenEvent(pem_module, 0, 0);
+ if(tmp)
+ PK11_FreeSlot(tmp);
+ PK11_IsPresent(slot);
+
+ status = PK11_Authenticate(slot, PR_TRUE, SSL_SET_OPTION(key_passwd));
+ PK11_FreeSlot(slot);
+
+ return (SECSuccess == status) ? CURLE_OK : CURLE_SSL_CERTPROBLEM;
+}
+
+static int display_error(struct connectdata *conn, PRInt32 err,
+ const char *filename)
+{
+ switch(err) {
+ case SEC_ERROR_BAD_PASSWORD:
+ failf(conn->data, "Unable to load client key: Incorrect password");
+ return 1;
+ case SEC_ERROR_UNKNOWN_CERT:
+ failf(conn->data, "Unable to load certificate %s", filename);
+ return 1;
+ default:
+ break;
+ }
+ return 0; /* The caller will print a generic error */
+}
+
+static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
+ char *cert_file, char *key_file)
+{
+ struct Curl_easy *data = conn->data;
+ CURLcode result;
+
+ if(cert_file) {
+ result = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
+ if(result) {
+ const PRErrorCode err = PR_GetError();
+ if(!display_error(conn, err, cert_file)) {
+ const char *err_name = nss_error_to_name(err);
+ failf(data, "unable to load client cert: %d (%s)", err, err_name);
+ }
+
+ return result;
+ }
+ }
+
+ if(key_file || (is_file(cert_file))) {
+ if(key_file)
+ result = nss_load_key(conn, sockindex, key_file);
+ else
+ /* In case the cert file also has the key */
+ result = nss_load_key(conn, sockindex, cert_file);
+ if(result) {
+ const PRErrorCode err = PR_GetError();
+ if(!display_error(conn, err, key_file)) {
+ const char *err_name = nss_error_to_name(err);
+ failf(data, "unable to load client key: %d (%s)", err, err_name);
+ }
+
+ return result;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static char *nss_get_password(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+ (void)slot; /* unused */
+
+ if(retry || NULL == arg)
+ return NULL;
+ else
+ return (char *)PORT_Strdup((char *)arg);
+}
+
+/* bypass the default SSL_AuthCertificate() hook in case we do not want to
+ * verify peer */
+static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
+ PRBool isServer)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+
+#ifdef SSL_ENABLE_OCSP_STAPLING
+ if(SSL_CONN_CONFIG(verifystatus)) {
+ SECStatus cacheResult;
+
+ const SECItemArray *csa = SSL_PeerStapledOCSPResponses(fd);
+ if(!csa) {
+ failf(conn->data, "Invalid OCSP response");
+ return SECFailure;
+ }
+
+ if(csa->len == 0) {
+ failf(conn->data, "No OCSP response received");
+ return SECFailure;
+ }
+
+ cacheResult = CERT_CacheOCSPResponseFromSideChannel(
+ CERT_GetDefaultCertDB(), SSL_PeerCertificate(fd),
+ PR_Now(), &csa->items[0], arg
+ );
+
+ if(cacheResult != SECSuccess) {
+ failf(conn->data, "Invalid OCSP response");
+ return cacheResult;
+ }
+ }
+#endif
+
+ if(!SSL_CONN_CONFIG(verifypeer)) {
+ infof(conn->data, "skipping SSL peer certificate verification\n");
+ return SECSuccess;
+ }
+
+ return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
+}
+
+/**
+ * Inform the application that the handshake is complete.
+ */
+static void HandshakeCallback(PRFileDesc *sock, void *arg)
+{
+ struct connectdata *conn = (struct connectdata*) arg;
+ unsigned int buflenmax = 50;
+ unsigned char buf[50];
+ unsigned int buflen;
+ SSLNextProtoState state;
+
+ if(!conn->bits.tls_enable_npn && !conn->bits.tls_enable_alpn) {
+ return;
+ }
+
+ if(SSL_GetNextProto(sock, &state, buf, &buflen, buflenmax) == SECSuccess) {
+
+ switch(state) {
+#if NSSVERNUM >= 0x031a00 /* 3.26.0 */
+ /* used by NSS internally to implement 0-RTT */
+ case SSL_NEXT_PROTO_EARLY_VALUE:
+ /* fall through! */
+#endif
+ case SSL_NEXT_PROTO_NO_SUPPORT:
+ case SSL_NEXT_PROTO_NO_OVERLAP:
+ infof(conn->data, "ALPN/NPN, server did not agree to a protocol\n");
+ return;
+#ifdef SSL_ENABLE_ALPN
+ case SSL_NEXT_PROTO_SELECTED:
+ infof(conn->data, "ALPN, server accepted to use %.*s\n", buflen, buf);
+ break;
+#endif
+ case SSL_NEXT_PROTO_NEGOTIATED:
+ infof(conn->data, "NPN, server accepted to use %.*s\n", buflen, buf);
+ break;
+ }
+
+#ifdef USE_NGHTTP2
+ if(buflen == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(NGHTTP2_PROTO_VERSION_ID, buf, NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(buflen == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, buf, ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+}
+
+#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
+static SECStatus CanFalseStartCallback(PRFileDesc *sock, void *client_data,
+ PRBool *canFalseStart)
+{
+ struct connectdata *conn = client_data;
+ struct Curl_easy *data = conn->data;
+
+ SSLChannelInfo channelInfo;
+ SSLCipherSuiteInfo cipherInfo;
+
+ SECStatus rv;
+ PRBool negotiatedExtension;
+
+ *canFalseStart = PR_FALSE;
+
+ if(SSL_GetChannelInfo(sock, &channelInfo, sizeof(channelInfo)) != SECSuccess)
+ return SECFailure;
+
+ if(SSL_GetCipherSuiteInfo(channelInfo.cipherSuite, &cipherInfo,
+ sizeof(cipherInfo)) != SECSuccess)
+ return SECFailure;
+
+ /* Prevent version downgrade attacks from TLS 1.2, and avoid False Start for
+ * TLS 1.3 and later. See https://bugzilla.mozilla.org/show_bug.cgi?id=861310
+ */
+ if(channelInfo.protocolVersion != SSL_LIBRARY_VERSION_TLS_1_2)
+ goto end;
+
+ /* Only allow ECDHE key exchange algorithm.
+ * See https://bugzilla.mozilla.org/show_bug.cgi?id=952863 */
+ if(cipherInfo.keaType != ssl_kea_ecdh)
+ goto end;
+
+ /* Prevent downgrade attacks on the symmetric cipher. We do not allow CBC
+ * mode due to BEAST, POODLE, and other attacks on the MAC-then-Encrypt
+ * design. See https://bugzilla.mozilla.org/show_bug.cgi?id=1109766 */
+ if(cipherInfo.symCipher != ssl_calg_aes_gcm)
+ goto end;
+
+ /* Enforce ALPN or NPN to do False Start, as an indicator of server
+ * compatibility. */
+ rv = SSL_HandshakeNegotiatedExtension(sock, ssl_app_layer_protocol_xtn,
+ &negotiatedExtension);
+ if(rv != SECSuccess || !negotiatedExtension) {
+ rv = SSL_HandshakeNegotiatedExtension(sock, ssl_next_proto_nego_xtn,
+ &negotiatedExtension);
+ }
+
+ if(rv != SECSuccess || !negotiatedExtension)
+ goto end;
+
+ *canFalseStart = PR_TRUE;
+
+ infof(data, "Trying TLS False Start\n");
+
+end:
+ return SECSuccess;
+}
+#endif
+
+static void display_cert_info(struct Curl_easy *data,
+ CERTCertificate *cert)
+{
+ char *subject, *issuer, *common_name;
+ PRExplodedTime printableTime;
+ char timeString[256];
+ PRTime notBefore, notAfter;
+
+ subject = CERT_NameToAscii(&cert->subject);
+ issuer = CERT_NameToAscii(&cert->issuer);
+ common_name = CERT_GetCommonName(&cert->subject);
+ infof(data, "\tsubject: %s\n", subject);
+
+ CERT_GetCertTimes(cert, &notBefore, &notAfter);
+ PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(data, "\tstart date: %s\n", timeString);
+ PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(data, "\texpire date: %s\n", timeString);
+ infof(data, "\tcommon name: %s\n", common_name);
+ infof(data, "\tissuer: %s\n", issuer);
+
+ PR_Free(subject);
+ PR_Free(issuer);
+ PR_Free(common_name);
+}
+
+static CURLcode display_conn_info(struct connectdata *conn, PRFileDesc *sock)
+{
+ CURLcode result = CURLE_OK;
+ SSLChannelInfo channel;
+ SSLCipherSuiteInfo suite;
+ CERTCertificate *cert;
+ CERTCertificate *cert2;
+ CERTCertificate *cert3;
+ PRTime now;
+ int i;
+
+ if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
+ SECSuccess && channel.length == sizeof channel &&
+ channel.cipherSuite) {
+ if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
+ &suite, sizeof suite) == SECSuccess) {
+ infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
+ }
+ }
+
+ cert = SSL_PeerCertificate(sock);
+ if(cert) {
+ infof(conn->data, "Server certificate:\n");
+
+ if(!conn->data->set.ssl.certinfo) {
+ display_cert_info(conn->data, cert);
+ CERT_DestroyCertificate(cert);
+ }
+ else {
+ /* Count certificates in chain. */
+ now = PR_Now();
+ i = 1;
+ if(!cert->isRoot) {
+ cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
+ while(cert2) {
+ i++;
+ if(cert2->isRoot) {
+ CERT_DestroyCertificate(cert2);
+ break;
+ }
+ cert3 = CERT_FindCertIssuer(cert2, now, certUsageSSLCA);
+ CERT_DestroyCertificate(cert2);
+ cert2 = cert3;
+ }
+ }
+
+ result = Curl_ssl_init_certinfo(conn->data, i);
+ if(!result) {
+ for(i = 0; cert; cert = cert2) {
+ result = Curl_extract_certinfo(conn, i++, (char *)cert->derCert.data,
+ (char *)cert->derCert.data +
+ cert->derCert.len);
+ if(result)
+ break;
+
+ if(cert->isRoot) {
+ CERT_DestroyCertificate(cert);
+ break;
+ }
+
+ cert2 = CERT_FindCertIssuer(cert, now, certUsageSSLCA);
+ CERT_DestroyCertificate(cert);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ struct Curl_easy *data = conn->data;
+ PRErrorCode err = PR_GetError();
+ CERTCertificate *cert;
+
+ /* remember the cert verification result */
+ if(SSL_IS_PROXY())
+ data->set.proxy_ssl.certverifyresult = err;
+ else
+ data->set.ssl.certverifyresult = err;
+
+ if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
+ /* we are asked not to verify the host name */
+ return SECSuccess;
+
+ /* print only info about the cert, the error is printed off the callback */
+ cert = SSL_PeerCertificate(sock);
+ if(cert) {
+ infof(data, "Server certificate:\n");
+ display_cert_info(data, cert);
+ CERT_DestroyCertificate(cert);
+ }
+
+ return SECFailure;
+}
+
+/**
+ *
+ * Check that the Peer certificate's issuer certificate matches the one found
+ * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
+ * issuer check, so we provide comments that mimic the OpenSSL
+ * X509_check_issued function (in x509v3/v3_purp.c)
+ */
+static SECStatus check_issuer_cert(PRFileDesc *sock,
+ char *issuer_nickname)
+{
+ CERTCertificate *cert, *cert_issuer, *issuer;
+ SECStatus res=SECSuccess;
+ void *proto_win = NULL;
+
+ cert = SSL_PeerCertificate(sock);
+ cert_issuer = CERT_FindCertIssuer(cert, PR_Now(), certUsageObjectSigner);
+
+ proto_win = SSL_RevealPinArg(sock);
+ issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
+
+ if((!cert_issuer) || (!issuer))
+ res = SECFailure;
+ else if(SECITEM_CompareItem(&cert_issuer->derCert,
+ &issuer->derCert)!=SECEqual)
+ res = SECFailure;
+
+ CERT_DestroyCertificate(cert);
+ CERT_DestroyCertificate(issuer);
+ CERT_DestroyCertificate(cert_issuer);
+ return res;
+}
+
+static CURLcode cmp_peer_pubkey(struct ssl_connect_data *connssl,
+ const char *pinnedpubkey)
+{
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ struct Curl_easy *data = connssl->data;
+ CERTCertificate *cert;
+
+ if(!pinnedpubkey)
+ /* no pinned public key specified */
+ return CURLE_OK;
+
+ /* get peer certificate */
+ cert = SSL_PeerCertificate(connssl->handle);
+ if(cert) {
+ /* extract public key from peer certificate */
+ SECKEYPublicKey *pubkey = CERT_ExtractPublicKey(cert);
+ if(pubkey) {
+ /* encode the public key as DER */
+ SECItem *cert_der = PK11_DEREncodePublicKey(pubkey);
+ if(cert_der) {
+ /* compare the public key with the pinned public key */
+ result = Curl_pin_peer_pubkey(data, pinnedpubkey, cert_der->data,
+ cert_der->len);
+ SECITEM_FreeItem(cert_der, PR_TRUE);
+ }
+ SECKEY_DestroyPublicKey(pubkey);
+ }
+ CERT_DestroyCertificate(cert);
+ }
+
+ /* report the resulting status */
+ switch(result) {
+ case CURLE_OK:
+ infof(data, "pinned public key verified successfully!\n");
+ break;
+ case CURLE_SSL_PINNEDPUBKEYNOTMATCH:
+ failf(data, "failed to verify pinned public key");
+ break;
+ default:
+ /* OOM, etc. */
+ break;
+ }
+
+ return result;
+}
+
+/**
+ *
+ * Callback to pick the SSL client certificate.
+ */
+static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
+ struct CERTDistNamesStr *caNames,
+ struct CERTCertificateStr **pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey)
+{
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
+ struct Curl_easy *data = connssl->data;
+ const char *nickname = connssl->client_nickname;
+ static const char pem_slotname[] = "PEM Token #1";
+
+ if(connssl->obj_clicert) {
+ /* use the cert/key provided by PEM reader */
+ SECItem cert_der = { 0, NULL, 0 };
+ void *proto_win = SSL_RevealPinArg(sock);
+ struct CERTCertificateStr *cert;
+ struct SECKEYPrivateKeyStr *key;
+
+ PK11SlotInfo *slot = nss_find_slot_by_name(pem_slotname);
+ if(NULL == slot) {
+ failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
+ return SECFailure;
+ }
+
+ if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
+ &cert_der) != SECSuccess) {
+ failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
+ PK11_FreeSlot(slot);
+ return SECFailure;
+ }
+
+ cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
+ SECITEM_FreeItem(&cert_der, PR_FALSE);
+ if(NULL == cert) {
+ failf(data, "NSS: client certificate from file not found");
+ PK11_FreeSlot(slot);
+ return SECFailure;
+ }
+
+ key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
+ PK11_FreeSlot(slot);
+ if(NULL == key) {
+ failf(data, "NSS: private key from file not found");
+ CERT_DestroyCertificate(cert);
+ return SECFailure;
+ }
+
+ infof(data, "NSS: client certificate from file\n");
+ display_cert_info(data, cert);
+
+ *pRetCert = cert;
+ *pRetKey = key;
+ return SECSuccess;
+ }
+
+ /* use the default NSS hook */
+ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
+ pRetCert, pRetKey)
+ || NULL == *pRetCert) {
+
+ if(NULL == nickname)
+ failf(data, "NSS: client certificate not found (nickname not "
+ "specified)");
+ else
+ failf(data, "NSS: client certificate not found: %s", nickname);
+
+ return SECFailure;
+ }
+
+ /* get certificate nickname if any */
+ nickname = (*pRetCert)->nickname;
+ if(NULL == nickname)
+ nickname = "[unknown]";
+
+ if(!strncmp(nickname, pem_slotname, sizeof(pem_slotname) - 1U)) {
+ failf(data, "NSS: refusing previously loaded certificate from file: %s",
+ nickname);
+ return SECFailure;
+ }
+
+ if(NULL == *pRetKey) {
+ failf(data, "NSS: private key not found for certificate: %s", nickname);
+ return SECFailure;
+ }
+
+ infof(data, "NSS: using client certificate: %s\n", nickname);
+ display_cert_info(data, *pRetCert);
+ return SECSuccess;
+}
+
+/* update blocking direction in case of PR_WOULD_BLOCK_ERROR */
+static void nss_update_connecting_state(ssl_connect_state state, void *secret)
+{
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)secret;
+ if(PR_GetError() != PR_WOULD_BLOCK_ERROR)
+ /* an unrelated error is passing by */
+ return;
+
+ switch(connssl->connecting_state) {
+ case ssl_connect_2:
+ case ssl_connect_2_reading:
+ case ssl_connect_2_writing:
+ break;
+ default:
+ /* we are not called from an SSL handshake */
+ return;
+ }
+
+ /* update the state accordingly */
+ connssl->connecting_state = state;
+}
+
+/* recv() wrapper we use to detect blocking direction during SSL handshake */
+static PRInt32 nspr_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ const PRRecvFN recv_fn = fd->lower->methods->recv;
+ const PRInt32 rv = recv_fn(fd->lower, buf, amount, flags, timeout);
+ if(rv < 0)
+ /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
+ nss_update_connecting_state(ssl_connect_2_reading, fd->secret);
+ return rv;
+}
+
+/* send() wrapper we use to detect blocking direction during SSL handshake */
+static PRInt32 nspr_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+ PRIntn flags, PRIntervalTime timeout)
+{
+ const PRSendFN send_fn = fd->lower->methods->send;
+ const PRInt32 rv = send_fn(fd->lower, buf, amount, flags, timeout);
+ if(rv < 0)
+ /* check for PR_WOULD_BLOCK_ERROR and update blocking direction */
+ nss_update_connecting_state(ssl_connect_2_writing, fd->secret);
+ return rv;
+}
+
+/* close() wrapper to avoid assertion failure due to fd->secret != NULL */
+static PRStatus nspr_io_close(PRFileDesc *fd)
+{
+ const PRCloseFN close_fn = PR_GetDefaultIOMethods()->close;
+ fd->secret = NULL;
+ return close_fn(fd);
+}
+
+/* load a PKCS #11 module */
+static CURLcode nss_load_module(SECMODModule **pmod, const char *library,
+ const char *name)
+{
+ char *config_string;
+ SECMODModule *module = *pmod;
+ if(module)
+ /* already loaded */
+ return CURLE_OK;
+
+ config_string = aprintf("library=%s name=%s", library, name);
+ if(!config_string)
+ return CURLE_OUT_OF_MEMORY;
+
+ module = SECMOD_LoadUserModule(config_string, NULL, PR_FALSE);
+ free(config_string);
+
+ if(module && module->loaded) {
+ /* loaded successfully */
+ *pmod = module;
+ return CURLE_OK;
+ }
+
+ if(module)
+ SECMOD_DestroyModule(module);
+ return CURLE_FAILED_INIT;
+}
+
+/* unload a PKCS #11 module */
+static void nss_unload_module(SECMODModule **pmod)
+{
+ SECMODModule *module = *pmod;
+ if(!module)
+ /* not loaded */
+ return;
+
+ if(SECMOD_UnloadUserModule(module) != SECSuccess)
+ /* unload failed */
+ return;
+
+ SECMOD_DestroyModule(module);
+ *pmod = NULL;
+}
+
+/* data might be NULL */
+static CURLcode nss_init_core(struct Curl_easy *data, const char *cert_dir)
+{
+ NSSInitParameters initparams;
+
+ if(nss_context != NULL)
+ return CURLE_OK;
+
+ memset((void *) &initparams, '\0', sizeof(initparams));
+ initparams.length = sizeof(initparams);
+
+ if(cert_dir) {
+ char *certpath = aprintf("sql:%s", cert_dir);
+ if(!certpath)
+ return CURLE_OUT_OF_MEMORY;
+
+ infof(data, "Initializing NSS with certpath: %s\n", certpath);
+ nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
+ NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
+ free(certpath);
+
+ if(nss_context != NULL)
+ return CURLE_OK;
+
+ infof(data, "Unable to initialize NSS database\n");
+ }
+
+ infof(data, "Initializing NSS with certpath: none\n");
+ nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
+ | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
+ if(nss_context != NULL)
+ return CURLE_OK;
+
+ infof(data, "Unable to initialize NSS\n");
+ return CURLE_SSL_CACERT_BADFILE;
+}
+
+/* data might be NULL */
+static CURLcode nss_init(struct Curl_easy *data)
+{
+ char *cert_dir;
+ struct_stat st;
+ CURLcode result;
+
+ if(initialized)
+ return CURLE_OK;
+
+ /* list of all CRL items we need to destroy in Curl_nss_cleanup() */
+ Curl_llist_init(&nss_crl_list, nss_destroy_crl_item);
+
+ /* First we check if $SSL_DIR points to a valid dir */
+ cert_dir = getenv("SSL_DIR");
+ if(cert_dir) {
+ if((stat(cert_dir, &st) != 0) ||
+ (!S_ISDIR(st.st_mode))) {
+ cert_dir = NULL;
+ }
+ }
+
+ /* Now we check if the default location is a valid dir */
+ if(!cert_dir) {
+ if((stat(SSL_DIR, &st) == 0) &&
+ (S_ISDIR(st.st_mode))) {
+ cert_dir = (char *)SSL_DIR;
+ }
+ }
+
+ if(nspr_io_identity == PR_INVALID_IO_LAYER) {
+ /* allocate an identity for our own NSPR I/O layer */
+ nspr_io_identity = PR_GetUniqueIdentity("libcurl");
+ if(nspr_io_identity == PR_INVALID_IO_LAYER)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* the default methods just call down to the lower I/O layer */
+ memcpy(&nspr_io_methods, PR_GetDefaultIOMethods(), sizeof nspr_io_methods);
+
+ /* override certain methods in the table by our wrappers */
+ nspr_io_methods.recv = nspr_io_recv;
+ nspr_io_methods.send = nspr_io_send;
+ nspr_io_methods.close = nspr_io_close;
+ }
+
+ result = nss_init_core(data, cert_dir);
+ if(result)
+ return result;
+
+ if(!any_cipher_enabled())
+ NSS_SetDomesticPolicy();
+
+ initialized = 1;
+
+ return CURLE_OK;
+}
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_nss_init(void)
+{
+ /* curl_global_init() is not thread-safe so this test is ok */
+ if(nss_initlock == NULL) {
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
+ nss_initlock = PR_NewLock();
+ nss_crllock = PR_NewLock();
+ nss_findslot_lock = PR_NewLock();
+ nss_trustload_lock = PR_NewLock();
+ }
+
+ /* We will actually initialize NSS later */
+
+ return 1;
+}
+
+/* data might be NULL */
+CURLcode Curl_nss_force_init(struct Curl_easy *data)
+{
+ CURLcode result;
+ if(!nss_initlock) {
+ if(data)
+ failf(data, "unable to initialize NSS, curl_global_init() should have "
+ "been called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
+ return CURLE_FAILED_INIT;
+ }
+
+ PR_Lock(nss_initlock);
+ result = nss_init(data);
+ PR_Unlock(nss_initlock);
+
+ return result;
+}
+
+/* Global cleanup */
+void Curl_nss_cleanup(void)
+{
+ /* This function isn't required to be threadsafe and this is only done
+ * as a safety feature.
+ */
+ PR_Lock(nss_initlock);
+ if(initialized) {
+ /* Free references to client certificates held in the SSL session cache.
+ * Omitting this hampers destruction of the security module owning
+ * the certificates. */
+ SSL_ClearSessionCache();
+
+ nss_unload_module(&pem_module);
+ nss_unload_module(&trust_module);
+ NSS_ShutdownContext(nss_context);
+ nss_context = NULL;
+ }
+
+ /* destroy all CRL items */
+ Curl_llist_destroy(&nss_crl_list, NULL);
+
+ PR_Unlock(nss_initlock);
+
+ PR_DestroyLock(nss_initlock);
+ PR_DestroyLock(nss_crllock);
+ PR_DestroyLock(nss_findslot_lock);
+ PR_DestroyLock(nss_trustload_lock);
+ nss_initlock = NULL;
+
+ initialized = 0;
+}
+
+/*
+ * This function uses SSL_peek to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int
+Curl_nss_check_cxn(struct connectdata *conn)
+{
+ int rc;
+ char buf;
+
+ rc =
+ PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
+ PR_SecondsToInterval(1));
+ if(rc > 0)
+ return 1; /* connection still in place */
+
+ if(rc == 0)
+ return 0; /* connection has been closed */
+
+ return -1; /* connection status unknown */
+}
+
+static void nss_close(struct ssl_connect_data *connssl)
+{
+ /* before the cleanup, check whether we are using a client certificate */
+ const bool client_cert = (connssl->client_nickname != NULL)
+ || (connssl->obj_clicert != NULL);
+
+ free(connssl->client_nickname);
+ connssl->client_nickname = NULL;
+
+ /* destroy all NSS objects in order to avoid failure of NSS shutdown */
+ Curl_llist_destroy(&connssl->obj_list, NULL);
+ connssl->obj_clicert = NULL;
+
+ if(connssl->handle) {
+ if(client_cert)
+ /* A server might require different authentication based on the
+ * particular path being requested by the client. To support this
+ * scenario, we must ensure that a connection will never reuse the
+ * authentication data from a previous connection. */
+ SSL_InvalidateSession(connssl->handle);
+
+ PR_Close(connssl->handle);
+ connssl->handle = NULL;
+ }
+}
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_nss_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
+
+ if(connssl->handle || connssl_proxy->handle) {
+ /* NSS closes the socket we previously handed to it, so we must mark it
+ as closed to avoid double close */
+ fake_sclose(conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ }
+
+ if(connssl->handle)
+ /* nss_close(connssl) will transitively close also connssl_proxy->handle
+ if both are used. Clear it to avoid a double close leading to crash. */
+ connssl_proxy->handle = NULL;
+
+ nss_close(connssl);
+ nss_close(connssl_proxy);
+}
+
+/* return true if NSS can provide error code (and possibly msg) for the
+ error */
+static bool is_nss_error(CURLcode err)
+{
+ switch(err) {
+ case CURLE_PEER_FAILED_VERIFICATION:
+ case CURLE_SSL_CACERT:
+ case CURLE_SSL_CERTPROBLEM:
+ case CURLE_SSL_CONNECT_ERROR:
+ case CURLE_SSL_ISSUER_ERROR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* return true if the given error code is related to a client certificate */
+static bool is_cc_error(PRInt32 err)
+{
+ switch(err) {
+ case SSL_ERROR_BAD_CERT_ALERT:
+ case SSL_ERROR_EXPIRED_CERT_ALERT:
+ case SSL_ERROR_REVOKED_CERT_ALERT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static Curl_recv nss_recv;
+static Curl_send nss_send;
+
+static CURLcode nss_load_ca_certificates(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ const char *cafile = SSL_CONN_CONFIG(CAfile);
+ const char *capath = SSL_CONN_CONFIG(CApath);
+ bool use_trust_module;
+ CURLcode result = CURLE_OK;
+
+ /* treat empty string as unset */
+ if(cafile && !cafile[0])
+ cafile = NULL;
+ if(capath && !capath[0])
+ capath = NULL;
+
+ infof(data, " CAfile: %s\n CApath: %s\n",
+ cafile ? cafile : "none",
+ capath ? capath : "none");
+
+ /* load libnssckbi.so if no other trust roots were specified */
+ use_trust_module = !cafile && !capath;
+
+ PR_Lock(nss_trustload_lock);
+ if(use_trust_module && !trust_module) {
+ /* libnssckbi.so needed but not yet loaded --> load it! */
+ result = nss_load_module(&trust_module, trust_library, "trust");
+ infof(data, "%s %s\n", (result) ? "failed to load" : "loaded",
+ trust_library);
+ if(result == CURLE_FAILED_INIT)
+ /* make the error non-fatal if we are not going to verify peer */
+ result = CURLE_SSL_CACERT_BADFILE;
+ }
+ else if(!use_trust_module && trust_module) {
+ /* libnssckbi.so not needed but already loaded --> unload it! */
+ infof(data, "unloading %s\n", trust_library);
+ nss_unload_module(&trust_module);
+ }
+ PR_Unlock(nss_trustload_lock);
+
+ if(cafile)
+ result = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
+
+ if(result)
+ return result;
+
+ if(capath) {
+ struct_stat st;
+ if(stat(capath, &st) == -1)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ if(S_ISDIR(st.st_mode)) {
+ PRDirEntry *entry;
+ PRDir *dir = PR_OpenDir(capath);
+ if(!dir)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
+ char *fullpath = aprintf("%s/%s", capath, entry->name);
+ if(!fullpath) {
+ PR_CloseDir(dir);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
+ /* This is purposefully tolerant of errors so non-PEM files can
+ * be in the same directory */
+ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
+
+ free(fullpath);
+ }
+
+ PR_CloseDir(dir);
+ }
+ else
+ infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode nss_sslver_from_curl(PRUint16 *nssver, long version)
+{
+ switch(version) {
+ case CURL_SSLVERSION_TLSv1:
+ /* TODO: set sslver->max to SSL_LIBRARY_VERSION_TLS_1_3 once stable */
+#ifdef SSL_LIBRARY_VERSION_TLS_1_2
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
+#elif defined SSL_LIBRARY_VERSION_TLS_1_1
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
+#else
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
+#endif
+ return CURLE_OK;
+
+ case CURL_SSLVERSION_SSLv2:
+ *nssver = SSL_LIBRARY_VERSION_2;
+ return CURLE_OK;
+
+ case CURL_SSLVERSION_SSLv3:
+ *nssver = SSL_LIBRARY_VERSION_3_0;
+ return CURLE_OK;
+
+ case CURL_SSLVERSION_TLSv1_0:
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_0;
+ return CURLE_OK;
+
+ case CURL_SSLVERSION_TLSv1_1:
+#ifdef SSL_LIBRARY_VERSION_TLS_1_1
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_1;
+ return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+
+ case CURL_SSLVERSION_TLSv1_2:
+#ifdef SSL_LIBRARY_VERSION_TLS_1_2
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_2;
+ return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+
+ case CURL_SSLVERSION_TLSv1_3:
+#ifdef SSL_LIBRARY_VERSION_TLS_1_3
+ *nssver = SSL_LIBRARY_VERSION_TLS_1_3;
+ return CURLE_OK;
+#else
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+}
+
+static CURLcode nss_init_sslver(SSLVersionRange *sslver,
+ struct Curl_easy *data,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ const long min = SSL_CONN_CONFIG(version);
+ const long max = SSL_CONN_CONFIG(version_max);
+
+ /* map CURL_SSLVERSION_DEFAULT to NSS default */
+ if(min == CURL_SSLVERSION_DEFAULT || max == CURL_SSLVERSION_MAX_DEFAULT) {
+ /* map CURL_SSLVERSION_DEFAULT to NSS default */
+ if(SSL_VersionRangeGetDefault(ssl_variant_stream, sslver) != SECSuccess)
+ return CURLE_SSL_CONNECT_ERROR;
+ /* ... but make sure we use at least TLSv1.0 according to libcurl API */
+ if(sslver->min < SSL_LIBRARY_VERSION_TLS_1_0)
+ sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ }
+
+ switch(min) {
+ case CURL_SSLVERSION_DEFAULT:
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ sslver->min = SSL_LIBRARY_VERSION_TLS_1_0;
+ break;
+ default:
+ result = nss_sslver_from_curl(&sslver->min, min);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ if(max == CURL_SSLVERSION_MAX_NONE)
+ sslver->max = sslver->min;
+ }
+
+ switch(max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ break;
+ default:
+ result = nss_sslver_from_curl(&sslver->max, max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode nss_fail_connect(struct ssl_connect_data *connssl,
+ struct Curl_easy *data,
+ CURLcode curlerr)
+{
+ PRErrorCode err = 0;
+
+ if(is_nss_error(curlerr)) {
+ /* read NSPR error code */
+ err = PR_GetError();
+ if(is_cc_error(err))
+ curlerr = CURLE_SSL_CERTPROBLEM;
+
+ /* print the error number and error string */
+ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(data, err);
+ }
+
+ /* cleanup on connection failure */
+ Curl_llist_destroy(&connssl->obj_list, NULL);
+
+ return curlerr;
+}
+
+/* Switch the SSL socket into blocking or non-blocking mode. */
+static CURLcode nss_set_blocking(struct ssl_connect_data *connssl,
+ struct Curl_easy *data,
+ bool blocking)
+{
+ static PRSocketOptionData sock_opt;
+ sock_opt.option = PR_SockOpt_Nonblocking;
+ sock_opt.value.non_blocking = !blocking;
+
+ if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
+ return nss_fail_connect(connssl, data, CURLE_SSL_CONNECT_ERROR);
+
+ return CURLE_OK;
+}
+
+static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
+{
+ PRFileDesc *model = NULL;
+ PRFileDesc *nspr_io = NULL;
+ PRFileDesc *nspr_io_stub = NULL;
+ PRBool ssl_no_cache;
+ PRBool ssl_cbc_random_iv;
+ struct Curl_easy *data = conn->data;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result;
+ bool second_layer = FALSE;
+
+ SSLVersionRange sslver = {
+ SSL_LIBRARY_VERSION_TLS_1_0, /* min */
+ SSL_LIBRARY_VERSION_TLS_1_0 /* max */
+ };
+
+ connssl->data = data;
+
+ /* list of all NSS objects we need to destroy in Curl_nss_close() */
+ Curl_llist_init(&connssl->obj_list, nss_destroy_object);
+
+ /* FIXME. NSS doesn't support multiple databases open at the same time. */
+ PR_Lock(nss_initlock);
+ result = nss_init(conn->data);
+ if(result) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
+
+ PK11_SetPasswordFunc(nss_get_password);
+
+ result = nss_load_module(&pem_module, pem_library, "PEM");
+ PR_Unlock(nss_initlock);
+ if(result == CURLE_FAILED_INIT)
+ infof(data, "WARNING: failed to load NSS PEM library %s. Using "
+ "OpenSSL PEM certificates will not work.\n", pem_library);
+ else if(result)
+ goto error;
+
+ result = CURLE_SSL_CONNECT_ERROR;
+
+ model = PR_NewTCPSocket();
+ if(!model)
+ goto error;
+ model = SSL_ImportFD(NULL, model);
+
+ if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
+ goto error;
+
+ /* do not use SSL cache if disabled or we are not going to verify peer */
+ ssl_no_cache = (SSL_SET_OPTION(primary.sessionid)
+ && SSL_CONN_CONFIG(verifypeer)) ? PR_FALSE : PR_TRUE;
+ if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
+ goto error;
+
+ /* enable/disable the requested SSL version(s) */
+ if(nss_init_sslver(&sslver, data, conn) != CURLE_OK)
+ goto error;
+ if(SSL_VersionRangeSet(model, &sslver) != SECSuccess)
+ goto error;
+
+ ssl_cbc_random_iv = !SSL_SET_OPTION(enable_beast);
+#ifdef SSL_CBC_RANDOM_IV
+ /* unless the user explicitly asks to allow the protocol vulnerability, we
+ use the work-around */
+ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
+ infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
+ ssl_cbc_random_iv);
+#else
+ if(ssl_cbc_random_iv)
+ infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
+#endif
+
+ if(SSL_CONN_CONFIG(cipher_list)) {
+ if(set_ciphers(data, model, SSL_CONN_CONFIG(cipher_list)) != SECSuccess) {
+ result = CURLE_SSL_CIPHER;
+ goto error;
+ }
+ }
+
+ if(!SSL_CONN_CONFIG(verifypeer) && SSL_CONN_CONFIG(verifyhost))
+ infof(data, "warning: ignoring value of ssl.verifyhost\n");
+
+ /* bypass the default SSL_AuthCertificate() hook in case we do not want to
+ * verify peer */
+ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
+ goto error;
+
+ /* not checked yet */
+ if(SSL_IS_PROXY())
+ data->set.proxy_ssl.certverifyresult = 0;
+ else
+ data->set.ssl.certverifyresult = 0;
+
+ if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
+ goto error;
+
+ if(SSL_HandshakeCallback(model, HandshakeCallback, conn) != SECSuccess)
+ goto error;
+
+ {
+ const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
+ if((rv == CURLE_SSL_CACERT_BADFILE) && !SSL_CONN_CONFIG(verifypeer))
+ /* not a fatal error because we are not going to verify the peer */
+ infof(data, "warning: CA certificates failed to load\n");
+ else if(rv) {
+ result = rv;
+ goto error;
+ }
+ }
+
+ if(SSL_SET_OPTION(CRLfile)) {
+ const CURLcode rv = nss_load_crl(SSL_SET_OPTION(CRLfile));
+ if(rv) {
+ result = rv;
+ goto error;
+ }
+ infof(data, " CRLfile: %s\n", SSL_SET_OPTION(CRLfile));
+ }
+
+ if(SSL_SET_OPTION(cert)) {
+ char *nickname = dup_nickname(data, SSL_SET_OPTION(cert));
+ if(nickname) {
+ /* we are not going to use libnsspem.so to read the client cert */
+ connssl->obj_clicert = NULL;
+ }
+ else {
+ CURLcode rv = cert_stuff(conn, sockindex, SSL_SET_OPTION(cert),
+ SSL_SET_OPTION(key));
+ if(rv) {
+ /* failf() is already done in cert_stuff() */
+ result = rv;
+ goto error;
+ }
+ }
+
+ /* store the nickname for SelectClientCert() called during handshake */
+ connssl->client_nickname = nickname;
+ }
+ else
+ connssl->client_nickname = NULL;
+
+ if(SSL_GetClientAuthDataHook(model, SelectClientCert,
+ (void *)connssl) != SECSuccess) {
+ result = CURLE_SSL_CERTPROBLEM;
+ goto error;
+ }
+
+ if(conn->proxy_ssl[sockindex].use) {
+ DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
+ DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ nspr_io = conn->proxy_ssl[sockindex].handle;
+ second_layer = TRUE;
+ }
+ else {
+ /* wrap OS file descriptor by NSPR's file descriptor abstraction */
+ nspr_io = PR_ImportTCPSocket(sockfd);
+ if(!nspr_io)
+ goto error;
+ }
+
+ /* create our own NSPR I/O layer */
+ nspr_io_stub = PR_CreateIOLayerStub(nspr_io_identity, &nspr_io_methods);
+ if(!nspr_io_stub) {
+ if(!second_layer)
+ PR_Close(nspr_io);
+ goto error;
+ }
+
+ /* make the per-connection data accessible from NSPR I/O callbacks */
+ nspr_io_stub->secret = (void *)connssl;
+
+ /* push our new layer to the NSPR I/O stack */
+ if(PR_PushIOLayer(nspr_io, PR_TOP_IO_LAYER, nspr_io_stub) != PR_SUCCESS) {
+ if(!second_layer)
+ PR_Close(nspr_io);
+ PR_Close(nspr_io_stub);
+ goto error;
+ }
+
+ /* import our model socket onto the current I/O stack */
+ connssl->handle = SSL_ImportFD(model, nspr_io);
+ if(!connssl->handle) {
+ if(!second_layer)
+ PR_Close(nspr_io);
+ goto error;
+ }
+
+ PR_Close(model); /* We don't need this any more */
+ model = NULL;
+
+ /* This is the password associated with the cert that we're using */
+ if(SSL_SET_OPTION(key_passwd)) {
+ SSL_SetPKCS11PinArg(connssl->handle, SSL_SET_OPTION(key_passwd));
+ }
+
+#ifdef SSL_ENABLE_OCSP_STAPLING
+ if(SSL_CONN_CONFIG(verifystatus)) {
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_OCSP_STAPLING, PR_TRUE)
+ != SECSuccess)
+ goto error;
+ }
+#endif
+
+#ifdef SSL_ENABLE_NPN
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_NPN, conn->bits.tls_enable_npn
+ ? PR_TRUE : PR_FALSE) != SECSuccess)
+ goto error;
+#endif
+
+#ifdef SSL_ENABLE_ALPN
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_ALPN, conn->bits.tls_enable_alpn
+ ? PR_TRUE : PR_FALSE) != SECSuccess)
+ goto error;
+#endif
+
+#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
+ if(data->set.ssl.falsestart) {
+ if(SSL_OptionSet(connssl->handle, SSL_ENABLE_FALSE_START, PR_TRUE)
+ != SECSuccess)
+ goto error;
+
+ if(SSL_SetCanFalseStartCallback(connssl->handle, CanFalseStartCallback,
+ conn) != SECSuccess)
+ goto error;
+ }
+#endif
+
+#if defined(SSL_ENABLE_NPN) || defined(SSL_ENABLE_ALPN)
+ if(conn->bits.tls_enable_npn || conn->bits.tls_enable_alpn) {
+ int cur = 0;
+ unsigned char protocols[128];
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
+ memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN);
+ cur += NGHTTP2_PROTO_VERSION_ID_LEN;
+ }
+#endif
+ protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
+ memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
+ cur += ALPN_HTTP_1_1_LENGTH;
+
+ if(SSL_SetNextProtoNego(connssl->handle, protocols, cur) != SECSuccess)
+ goto error;
+ }
+#endif
+
+
+ /* Force handshake on next I/O */
+ if(SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE)
+ != SECSuccess)
+ goto error;
+
+ /* propagate hostname to the TLS layer */
+ if(SSL_SetURL(connssl->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name) != SECSuccess)
+ goto error;
+
+ /* prevent NSS from re-using the session for a different hostname */
+ if(SSL_SetSockPeerID(connssl->handle, SSL_IS_PROXY() ?
+ conn->http_proxy.host.name : conn->host.name)
+ != SECSuccess)
+ goto error;
+
+ return CURLE_OK;
+
+error:
+ if(model)
+ PR_Close(model);
+
+ return nss_fail_connect(connssl, data, result);
+}
+
+static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ CURLcode result = CURLE_SSL_CONNECT_ERROR;
+ PRUint32 timeout;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
+
+ /* check timeout situation */
+ const time_t time_left = Curl_timeleft(data, NULL, TRUE);
+ if(time_left < 0) {
+ failf(data, "timed out before SSL handshake");
+ result = CURLE_OPERATION_TIMEDOUT;
+ goto error;
+ }
+
+ /* Force the handshake now */
+ timeout = PR_MillisecondsToInterval((PRUint32) time_left);
+ if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
+ if(PR_GetError() == PR_WOULD_BLOCK_ERROR)
+ /* blocking direction is updated by nss_update_connecting_state() */
+ return CURLE_AGAIN;
+ else if(*certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ else if(*certverifyresult != 0)
+ result = CURLE_SSL_CACERT;
+ goto error;
+ }
+
+ result = display_conn_info(conn, connssl->handle);
+ if(result)
+ goto error;
+
+ if(SSL_SET_OPTION(issuercert)) {
+ SECStatus ret = SECFailure;
+ char *nickname = dup_nickname(data, SSL_SET_OPTION(issuercert));
+ if(nickname) {
+ /* we support only nicknames in case of issuercert for now */
+ ret = check_issuer_cert(connssl->handle, nickname);
+ free(nickname);
+ }
+
+ if(SECFailure == ret) {
+ infof(data, "SSL certificate issuer check failed\n");
+ result = CURLE_SSL_ISSUER_ERROR;
+ goto error;
+ }
+ else {
+ infof(data, "SSL certificate issuer check ok\n");
+ }
+ }
+
+ result = cmp_peer_pubkey(connssl, pinnedpubkey);
+ if(result)
+ /* status already printed */
+ goto error;
+
+ return CURLE_OK;
+
+error:
+ return nss_fail_connect(connssl, data, result);
+}
+
+static CURLcode nss_connect_common(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ const bool blocking = (done == NULL);
+ CURLcode result;
+
+ if(connssl->state == ssl_connection_complete) {
+ if(!blocking)
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(connssl->connecting_state == ssl_connect_1) {
+ result = nss_setup_connect(conn, sockindex);
+ if(result)
+ /* we do not expect CURLE_AGAIN from nss_setup_connect() */
+ return result;
+
+ connssl->connecting_state = ssl_connect_2;
+ }
+
+ /* enable/disable blocking mode before handshake */
+ result = nss_set_blocking(connssl, data, blocking);
+ if(result)
+ return result;
+
+ result = nss_do_connect(conn, sockindex);
+ switch(result) {
+ case CURLE_OK:
+ break;
+ case CURLE_AGAIN:
+ if(!blocking)
+ /* CURLE_AGAIN in non-blocking mode is not an error */
+ return CURLE_OK;
+ /* fall through */
+ default:
+ return result;
+ }
+
+ if(blocking) {
+ /* in blocking mode, set NSS non-blocking mode _after_ SSL handshake */
+ result = nss_set_blocking(connssl, data, /* blocking */ FALSE);
+ if(result)
+ return result;
+ }
+ else
+ /* signal completed SSL handshake */
+ *done = TRUE;
+
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = nss_recv;
+ conn->send[sockindex] = nss_send;
+
+ /* ssl_connect_done is never used outside, go back to the initial state */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+{
+ return nss_connect_common(conn, sockindex, /* blocking */ NULL);
+}
+
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+ int sockindex, bool *done)
+{
+ return nss_connect_common(conn, sockindex, done);
+}
+
+static ssize_t nss_send(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ const void *mem, /* send this data */
+ size_t len, /* amount to write */
+ CURLcode *curlcode)
+{
+ ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0,
+ PR_INTERVAL_NO_WAIT);
+ if(rc < 0) {
+ PRInt32 err = PR_GetError();
+ if(err == PR_WOULD_BLOCK_ERROR)
+ *curlcode = CURLE_AGAIN;
+ else {
+ /* print the error number and error string */
+ const char *err_name = nss_error_to_name(err);
+ infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(conn->data, err);
+
+ *curlcode = (is_cc_error(err))
+ ? CURLE_SSL_CERTPROBLEM
+ : CURLE_SEND_ERROR;
+ }
+
+ return -1;
+ }
+
+ return rc; /* number of bytes */
+}
+
+static ssize_t nss_recv(struct connectdata * conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0,
+ PR_INTERVAL_NO_WAIT);
+ if(nread < 0) {
+ /* failed SSL read */
+ PRInt32 err = PR_GetError();
+
+ if(err == PR_WOULD_BLOCK_ERROR)
+ *curlcode = CURLE_AGAIN;
+ else {
+ /* print the error number and error string */
+ const char *err_name = nss_error_to_name(err);
+ infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(conn->data, err);
+
+ *curlcode = (is_cc_error(err))
+ ? CURLE_SSL_CERTPROBLEM
+ : CURLE_RECV_ERROR;
+ }
+
+ return -1;
+ }
+
+ return nread;
+}
+
+size_t Curl_nss_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
+}
+
+/* data might be NULL */
+int Curl_nss_seed(struct Curl_easy *data)
+{
+ /* make sure that NSS is initialized */
+ return !!Curl_nss_force_init(data);
+}
+
+/* data might be NULL */
+CURLcode Curl_nss_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ Curl_nss_seed(data); /* Initiate the seed if not already done */
+
+ if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length)))
+ /* signal a failure */
+ return CURLE_FAILED_INIT;
+
+ return CURLE_OK;
+}
+
+void Curl_nss_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+ PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
+ unsigned int MD5out;
+
+ PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
+ PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
+ PK11_DestroyContext(MD5pw, PR_TRUE);
+}
+
+void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len)
+{
+ PK11Context *SHA256pw = PK11_CreateDigestContext(SEC_OID_SHA256);
+ unsigned int SHA256out;
+
+ PK11_DigestOp(SHA256pw, tmp, curlx_uztoui(tmplen));
+ PK11_DigestFinal(SHA256pw, sha256sum, &SHA256out, curlx_uztoui(sha256len));
+ PK11_DestroyContext(SHA256pw, PR_TRUE);
+}
+
+bool Curl_nss_cert_status_request(void)
+{
+#ifdef SSL_ENABLE_OCSP_STAPLING
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+bool Curl_nss_false_start(void)
+{
+#if NSSVERNUM >= 0x030f04 /* 3.15.4 */
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+#endif /* USE_NSS */
diff --git a/Utilities/cmcurl/lib/vtls/nssg.h b/Utilities/cmcurl/lib/vtls/nssg.h
new file mode 100644
index 000000000..8c46929ff
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/nssg.h
@@ -0,0 +1,108 @@
+#ifndef HEADER_CURL_NSSG_H
+#define HEADER_CURL_NSSG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_NSS
+/*
+ * This header should only be needed to get included by vtls.c and nss.c
+ */
+
+#include "urldata.h"
+
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+/* close a SSL connection */
+void Curl_nss_close(struct connectdata *conn, int sockindex);
+
+int Curl_nss_init(void);
+void Curl_nss_cleanup(void);
+
+size_t Curl_nss_version(char *buffer, size_t size);
+int Curl_nss_check_cxn(struct connectdata *cxn);
+int Curl_nss_seed(struct Curl_easy *data);
+
+/* initialize NSS library if not already */
+CURLcode Curl_nss_force_init(struct Curl_easy *data);
+
+CURLcode Curl_nss_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length);
+
+void Curl_nss_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len);
+
+void Curl_nss_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum, /* output */
+ size_t sha256len);
+
+bool Curl_nss_cert_status_request(void);
+
+bool Curl_nss_false_start(void);
+
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
+/* Set the API backend definition to NSS */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_NSS
+
+/* this backend supports the CAPATH option */
+#define have_curlssl_ca_path 1
+
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* API setup for NSS */
+#define curlssl_init Curl_nss_init
+#define curlssl_cleanup Curl_nss_cleanup
+#define curlssl_connect Curl_nss_connect
+#define curlssl_connect_nonblocking Curl_nss_connect_nonblocking
+
+/* NSS has its own session ID cache */
+#define curlssl_session_free(x) Curl_nop_stmt
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_nss_close
+/* NSS has no shutdown function provided and thus always fail */
+#define curlssl_shutdown(x,y) ((void)x, (void)y, 1)
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_nss_version
+#define curlssl_check_cxn(x) Curl_nss_check_cxn(x)
+#define curlssl_data_pending(x,y) ((void)x, (void)y, 0)
+#define curlssl_random(x,y,z) Curl_nss_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d)
+#define curlssl_sha256sum(a,b,c,d) Curl_nss_sha256sum(a,b,c,d)
+#define curlssl_cert_status_request() Curl_nss_cert_status_request()
+#define curlssl_false_start() Curl_nss_false_start()
+
+#endif /* USE_NSS */
+#endif /* HEADER_CURL_NSSG_H */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.c b/Utilities/cmcurl/lib/vtls/openssl.c
new file mode 100644
index 000000000..dbee36929
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/openssl.c
@@ -0,0 +1,3377 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ */
+
+/*
+ * The original SSLeay-using code for curl was written by Linas Vepstas and
+ * Sampo Kellomaki 1998.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_OPENSSL
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "inet_pton.h"
+#include "openssl.h"
+#include "connect.h"
+#include "slist.h"
+#include "select.h"
+#include "vtls.h"
+#include "strcase.h"
+#include "hostcheck.h"
+#include "curl_printf.h"
+
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_DSA
+#include <openssl/dsa.h>
+#endif
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#include <openssl/conf.h>
+#include <openssl/bn.h>
+#include <openssl/rsa.h>
+
+#ifdef HAVE_OPENSSL_PKCS12_H
+#include <openssl/pkcs12.h>
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_OCSP)
+#include <openssl/ocsp.h>
+#endif
+
+#include "warnless.h"
+#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef OPENSSL_VERSION_NUMBER
+#error "OPENSSL_VERSION_NUMBER not defined"
+#endif
+
+#if defined(HAVE_OPENSSL_ENGINE_H)
+#include <openssl/ui.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#define SSL_METHOD_QUAL const
+#else
+#define SSL_METHOD_QUAL
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10000000L)
+#define HAVE_ERR_REMOVE_THREAD_STATE 1
+#endif
+
+#if !defined(HAVE_SSLV2_CLIENT_METHOD) || \
+ OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0+ has no SSLv2 */
+#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
+#define OPENSSL_NO_SSL2
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && /* OpenSSL 1.1.0+ */ \
+ !defined(LIBRESSL_VERSION_NUMBER)
+#define SSLEAY_VERSION_NUMBER OPENSSL_VERSION_NUMBER
+#define HAVE_X509_GET0_EXTENSIONS 1 /* added in 1.1.0 -pre1 */
+#define HAVE_OPAQUE_EVP_PKEY 1 /* since 1.1.0 -pre3 */
+#define HAVE_OPAQUE_RSA_DSA_DH 1 /* since 1.1.0 -pre5 */
+#define CONST_EXTS const
+#define CONST_ASN1_BIT_STRING const
+#define HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED 1
+#else
+/* For OpenSSL before 1.1.0 */
+#define ASN1_STRING_get0_data(x) ASN1_STRING_data(x)
+#define X509_get0_notBefore(x) X509_get_notBefore(x)
+#define X509_get0_notAfter(x) X509_get_notAfter(x)
+#define CONST_EXTS /* nope */
+#define CONST_ASN1_BIT_STRING /* nope */
+#ifdef LIBRESSL_VERSION_NUMBER
+static unsigned long OpenSSL_version_num(void)
+{
+ return LIBRESSL_VERSION_NUMBER;
+}
+#else
+#define OpenSSL_version_num() SSLeay()
+#endif
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* 1.0.2 or later */ \
+ !defined(LIBRESSL_VERSION_NUMBER)
+#define HAVE_X509_GET0_SIGNATURE 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10002003L && \
+ OPENSSL_VERSION_NUMBER <= 0x10002FFFL && \
+ !defined(OPENSSL_NO_COMP)
+#define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1
+#endif
+
+#if (OPENSSL_VERSION_NUMBER < 0x0090808fL)
+/* not present in older OpenSSL */
+#define OPENSSL_load_builtin_modules(x)
+#endif
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define OSSL_PACKAGE "LibreSSL"
+#elif defined(OPENSSL_IS_BORINGSSL)
+#define OSSL_PACKAGE "BoringSSL"
+#else
+#define OSSL_PACKAGE "OpenSSL"
+#endif
+
+/*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entropy to properly seed OpenSSL's PRNG.
+ */
+#define RAND_LOAD_LENGTH 1024
+
+static const char *SSL_ERROR_to_str(int err)
+{
+ switch(err) {
+ case SSL_ERROR_NONE:
+ return "SSL_ERROR_NONE";
+ case SSL_ERROR_SSL:
+ return "SSL_ERROR_SSL";
+ case SSL_ERROR_WANT_READ:
+ return "SSL_ERROR_WANT_READ";
+ case SSL_ERROR_WANT_WRITE:
+ return "SSL_ERROR_WANT_WRITE";
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ return "SSL_ERROR_WANT_X509_LOOKUP";
+ case SSL_ERROR_SYSCALL:
+ return "SSL_ERROR_SYSCALL";
+ case SSL_ERROR_ZERO_RETURN:
+ return "SSL_ERROR_ZERO_RETURN";
+ case SSL_ERROR_WANT_CONNECT:
+ return "SSL_ERROR_WANT_CONNECT";
+ case SSL_ERROR_WANT_ACCEPT:
+ return "SSL_ERROR_WANT_ACCEPT";
+#if defined(SSL_ERROR_WANT_ASYNC)
+ case SSL_ERROR_WANT_ASYNC:
+ return "SSL_ERROR_WANT_ASYNC";
+#endif
+#if defined(SSL_ERROR_WANT_ASYNC_JOB)
+ case SSL_ERROR_WANT_ASYNC_JOB:
+ return "SSL_ERROR_WANT_ASYNC_JOB";
+#endif
+#if defined(SSL_ERROR_WANT_EARLY)
+ case SSL_ERROR_WANT_EARLY:
+ return "SSL_ERROR_WANT_EARLY";
+#endif
+ default:
+ return "SSL_ERROR unknown";
+ }
+}
+
+/* Return error string for last OpenSSL error
+ */
+static char *ossl_strerror(unsigned long error, char *buf, size_t size)
+{
+ ERR_error_string_n(error, buf, size);
+ return buf;
+}
+
+static int passwd_callback(char *buf, int num, int encrypting,
+ void *global_passwd)
+{
+ DEBUGASSERT(0 == encrypting);
+
+ if(!encrypting) {
+ int klen = curlx_uztosi(strlen((char *)global_passwd));
+ if(num > klen) {
+ memcpy(buf, global_passwd, klen+1);
+ return klen;
+ }
+ }
+ return 0;
+}
+
+/*
+ * rand_enough() returns TRUE if we have seeded the random engine properly.
+ */
+static bool rand_enough(void)
+{
+ return (0 != RAND_status()) ? TRUE : FALSE;
+}
+
+static CURLcode Curl_ossl_seed(struct Curl_easy *data)
+{
+ /* we have the "SSL is seeded" boolean static to prevent multiple
+ time-consuming seedings in vain */
+ static bool ssl_seeded = FALSE;
+ int nread=0;
+ char fname[256];
+
+ if(ssl_seeded)
+ return CURLE_OK;
+
+ if(rand_enough()) {
+ /* OpenSSL 1.1.0+ will return here */
+ ssl_seeded = TRUE;
+ return CURLE_OK;
+ }
+
+#ifndef RANDOM_FILE
+ /* if RANDOM_FILE isn't defined, we only perform this if an option tells
+ us to! */
+ if(data->set.str[STRING_SSL_RANDOM_FILE])
+#define RANDOM_FILE "" /* doesn't matter won't be used */
+#endif
+ {
+ /* let the option override the define */
+ nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
+ data->set.str[STRING_SSL_RANDOM_FILE]:
+ RANDOM_FILE),
+ RAND_LOAD_LENGTH);
+ if(rand_enough())
+ return nread;
+ }
+
+#if defined(HAVE_RAND_EGD)
+ /* only available in OpenSSL 0.9.5 and later */
+ /* EGD_SOCKET is set at configure time or not at all */
+#ifndef EGD_SOCKET
+ /* If we don't have the define set, we only do this if the egd-option
+ is set */
+ if(data->set.str[STRING_SSL_EGDSOCKET])
+#define EGD_SOCKET "" /* doesn't matter won't be used */
+#endif
+ {
+ /* If there's an option and a define, the option overrides the
+ define */
+ int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
+ data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
+ if(-1 != ret) {
+ nread += ret;
+ if(rand_enough())
+ return nread;
+ }
+ }
+#endif
+
+ /* If we get here, it means we need to seed the PRNG using a "silly"
+ approach! */
+ do {
+ unsigned char randb[64];
+ int len = sizeof(randb);
+ if(!RAND_bytes(randb, len))
+ break;
+ RAND_add(randb, len, (len >> 1));
+ } while(!rand_enough());
+
+ /* generates a default path for the random seed file */
+ fname[0]=0; /* blank it first */
+ RAND_file_name(fname, sizeof(fname));
+ if(fname[0]) {
+ /* we got a file name to try */
+ nread += RAND_load_file(fname, RAND_LOAD_LENGTH);
+ if(rand_enough())
+ return nread;
+ }
+
+ infof(data, "libcurl is now using a weak random seed!\n");
+ return CURLE_SSL_CONNECT_ERROR; /* confusing error code */
+}
+
+#ifndef SSL_FILETYPE_ENGINE
+#define SSL_FILETYPE_ENGINE 42
+#endif
+#ifndef SSL_FILETYPE_PKCS12
+#define SSL_FILETYPE_PKCS12 43
+#endif
+static int do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return SSL_FILETYPE_PEM;
+ if(strcasecompare(type, "PEM"))
+ return SSL_FILETYPE_PEM;
+ if(strcasecompare(type, "DER"))
+ return SSL_FILETYPE_ASN1;
+ if(strcasecompare(type, "ENG"))
+ return SSL_FILETYPE_ENGINE;
+ if(strcasecompare(type, "P12"))
+ return SSL_FILETYPE_PKCS12;
+ return -1;
+}
+
+#if defined(HAVE_OPENSSL_ENGINE_H)
+/*
+ * Supply default password to the engine user interface conversation.
+ * The password is passed by OpenSSL engine from ENGINE_load_private_key()
+ * last argument to the ui and can be obtained by UI_get0_user_data(ui) here.
+ */
+static int ssl_ui_reader(UI *ui, UI_STRING *uis)
+{
+ const char *password;
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT:
+ case UIT_VERIFY:
+ password = (const char *)UI_get0_user_data(ui);
+ if(password && (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
+ UI_set_result(ui, uis, password);
+ return 1;
+ }
+ default:
+ break;
+ }
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+}
+
+/*
+ * Suppress interactive request for a default password if available.
+ */
+static int ssl_ui_writer(UI *ui, UI_STRING *uis)
+{
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT:
+ case UIT_VERIFY:
+ if(UI_get0_user_data(ui) &&
+ (UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD)) {
+ return 1;
+ }
+ default:
+ break;
+ }
+ return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
+}
+#endif
+
+static
+int cert_stuff(struct connectdata *conn,
+ SSL_CTX* ctx,
+ char *cert_file,
+ const char *cert_type,
+ char *key_file,
+ const char *key_type,
+ char *key_passwd)
+{
+ struct Curl_easy *data = conn->data;
+ char error_buffer[256];
+
+ int file_type = do_file_type(cert_type);
+
+ if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
+ SSL *ssl;
+ X509 *x509;
+ int cert_done = 0;
+
+ if(key_passwd) {
+ /* set the password in the callback userdata */
+ SSL_CTX_set_default_passwd_cb_userdata(ctx, key_passwd);
+ /* Set passwd callback: */
+ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+ }
+
+
+ switch(file_type) {
+ case SSL_FILETYPE_PEM:
+ /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
+ if(SSL_CTX_use_certificate_chain_file(ctx,
+ cert_file) != 1) {
+ failf(data,
+ "could not load PEM client certificate, " OSSL_PACKAGE
+ " error %s, "
+ "(no key found, wrong pass phrase, or wrong file format?)",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return 0;
+ }
+ break;
+
+ case SSL_FILETYPE_ASN1:
+ /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
+ we use the case above for PEM so this can only be performed with
+ ASN1 files. */
+ if(SSL_CTX_use_certificate_file(ctx,
+ cert_file,
+ file_type) != 1) {
+ failf(data,
+ "could not load ASN1 client certificate, " OSSL_PACKAGE
+ " error %s, "
+ "(no key found, wrong pass phrase, or wrong file format?)",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return 0;
+ }
+ break;
+ case SSL_FILETYPE_ENGINE:
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
+ {
+ if(data->state.engine) {
+ const char *cmd_name = "LOAD_CERT_CTRL";
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } params;
+
+ params.cert_id = cert_file;
+ params.cert = NULL;
+
+ /* Does the engine supports LOAD_CERT_CTRL ? */
+ if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+ 0, (void *)cmd_name, NULL)) {
+ failf(data, "ssl engine does not support loading certificates");
+ return 0;
+ }
+
+ /* Load the certificate from the engine */
+ if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
+ 0, &params, NULL, 1)) {
+ failf(data, "ssl engine cannot load client cert with id"
+ " '%s' [%s]", cert_file,
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return 0;
+ }
+
+ if(!params.cert) {
+ failf(data, "ssl engine didn't initialized the certificate "
+ "properly.");
+ return 0;
+ }
+
+ if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
+ failf(data, "unable to set client certificate");
+ X509_free(params.cert);
+ return 0;
+ }
+ X509_free(params.cert); /* we don't need the handle any more... */
+ }
+ else {
+ failf(data, "crypto engine not set, can't load certificate");
+ return 0;
+ }
+ }
+ break;
+#else
+ failf(data, "file type ENG for certificate not implemented");
+ return 0;
+#endif
+
+ case SSL_FILETYPE_PKCS12:
+ {
+#ifdef HAVE_OPENSSL_PKCS12_H
+ FILE *f;
+ PKCS12 *p12;
+ EVP_PKEY *pri;
+ STACK_OF(X509) *ca = NULL;
+
+ f = fopen(cert_file, "rb");
+ if(!f) {
+ failf(data, "could not open PKCS12 file '%s'", cert_file);
+ return 0;
+ }
+ p12 = d2i_PKCS12_fp(f, NULL);
+ fclose(f);
+
+ if(!p12) {
+ failf(data, "error reading PKCS12 file '%s'", cert_file);
+ return 0;
+ }
+
+ PKCS12_PBE_add();
+
+ if(!PKCS12_parse(p12, key_passwd, &pri, &x509,
+ &ca)) {
+ failf(data,
+ "could not parse PKCS12 file, check password, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ PKCS12_free(p12);
+ return 0;
+ }
+
+ PKCS12_free(p12);
+
+ if(SSL_CTX_use_certificate(ctx, x509) != 1) {
+ failf(data,
+ "could not load PKCS12 client certificate, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ goto fail;
+ }
+
+ if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
+ failf(data, "unable to use private key from PKCS12 file '%s'",
+ cert_file);
+ goto fail;
+ }
+
+ if(!SSL_CTX_check_private_key (ctx)) {
+ failf(data, "private key from PKCS12 file '%s' "
+ "does not match certificate in same file", cert_file);
+ goto fail;
+ }
+ /* Set Certificate Verification chain */
+ if(ca) {
+ while(sk_X509_num(ca)) {
+ /*
+ * Note that sk_X509_pop() is used below to make sure the cert is
+ * removed from the stack properly before getting passed to
+ * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously
+ * we used sk_X509_value() instead, but then we'd clean it in the
+ * subsequent sk_X509_pop_free() call.
+ */
+ X509 *x = sk_X509_pop(ca);
+ if(!SSL_CTX_add_client_CA(ctx, x)) {
+ X509_free(x);
+ failf(data, "cannot add certificate to client CA list");
+ goto fail;
+ }
+ if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
+ X509_free(x);
+ failf(data, "cannot add certificate to certificate chain");
+ goto fail;
+ }
+ }
+ }
+
+ cert_done = 1;
+ fail:
+ EVP_PKEY_free(pri);
+ X509_free(x509);
+ sk_X509_pop_free(ca, X509_free);
+
+ if(!cert_done)
+ return 0; /* failure! */
+ break;
+#else
+ failf(data, "file type P12 for certificate not supported");
+ return 0;
+#endif
+ }
+ default:
+ failf(data, "not supported file type '%s' for certificate", cert_type);
+ return 0;
+ }
+
+ file_type = do_file_type(key_type);
+
+ switch(file_type) {
+ case SSL_FILETYPE_PEM:
+ if(cert_done)
+ break;
+ if(!key_file)
+ /* cert & key can only be in PEM case in the same file */
+ key_file=cert_file;
+ /* FALLTHROUGH */
+ case SSL_FILETYPE_ASN1:
+ if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
+ failf(data, "unable to set private key file: '%s' type %s",
+ key_file, key_type?key_type:"PEM");
+ return 0;
+ }
+ break;
+ case SSL_FILETYPE_ENGINE:
+#ifdef HAVE_OPENSSL_ENGINE_H
+ { /* XXXX still needs some work */
+ EVP_PKEY *priv_key = NULL;
+ if(data->state.engine) {
+ UI_METHOD *ui_method =
+ UI_create_method((char *)"curl user interface");
+ if(!ui_method) {
+ failf(data, "unable do create " OSSL_PACKAGE
+ " user-interface method");
+ return 0;
+ }
+ UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
+ UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
+ UI_method_set_reader(ui_method, ssl_ui_reader);
+ UI_method_set_writer(ui_method, ssl_ui_writer);
+ /* the typecast below was added to please mingw32 */
+ priv_key = (EVP_PKEY *)
+ ENGINE_load_private_key(data->state.engine, key_file,
+ ui_method,
+ key_passwd);
+ UI_destroy_method(ui_method);
+ if(!priv_key) {
+ failf(data, "failed to load private key from crypto engine");
+ return 0;
+ }
+ if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+ failf(data, "unable to set private key");
+ EVP_PKEY_free(priv_key);
+ return 0;
+ }
+ EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
+ }
+ else {
+ failf(data, "crypto engine not set, can't load private key");
+ return 0;
+ }
+ }
+ break;
+#else
+ failf(data, "file type ENG for private key not supported");
+ return 0;
+#endif
+ case SSL_FILETYPE_PKCS12:
+ if(!cert_done) {
+ failf(data, "file type P12 for private key not supported");
+ return 0;
+ }
+ break;
+ default:
+ failf(data, "not supported file type for private key");
+ return 0;
+ }
+
+ ssl=SSL_new(ctx);
+ if(!ssl) {
+ failf(data, "unable to create an SSL structure");
+ return 0;
+ }
+
+ x509=SSL_get_certificate(ssl);
+
+ /* This version was provided by Evan Jordan and is supposed to not
+ leak memory as the previous version: */
+ if(x509) {
+ EVP_PKEY *pktmp = X509_get_pubkey(x509);
+ EVP_PKEY_copy_parameters(pktmp, SSL_get_privatekey(ssl));
+ EVP_PKEY_free(pktmp);
+ }
+
+ SSL_free(ssl);
+
+ /* If we are using DSA, we can copy the parameters from
+ * the private key */
+
+
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if(!SSL_CTX_check_private_key(ctx)) {
+ failf(data, "Private key does not match the certificate public key");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/* returns non-zero on failure */
+static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+{
+#if 0
+ return X509_NAME_oneline(a, buf, size);
+#else
+ BIO *bio_out = BIO_new(BIO_s_mem());
+ BUF_MEM *biomem;
+ int rc;
+
+ if(!bio_out)
+ return 1; /* alloc failed! */
+
+ rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+ BIO_get_mem_ptr(bio_out, &biomem);
+
+ if((size_t)biomem->length < size)
+ size = biomem->length;
+ else
+ size--; /* don't overwrite the buffer end */
+
+ memcpy(buf, biomem->data, size);
+ buf[size]=0;
+
+ BIO_free(bio_out);
+
+ return !rc;
+#endif
+}
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ossl_init(void)
+{
+ OPENSSL_load_builtin_modules();
+
+#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+ ENGINE_load_builtin_engines();
+#endif
+
+ /* OPENSSL_config(NULL); is "strongly recommended" to use but unfortunately
+ that function makes an exit() call on wrongly formatted config files
+ which makes it hard to use in some situations. OPENSSL_config() itself
+ calls CONF_modules_load_file() and we use that instead and we ignore
+ its return code! */
+
+ /* CONF_MFLAGS_DEFAULT_SECTION introduced some time between 0.9.8b and
+ 0.9.8e */
+#ifndef CONF_MFLAGS_DEFAULT_SECTION
+#define CONF_MFLAGS_DEFAULT_SECTION 0x0
+#endif
+
+ CONF_modules_load_file(NULL, NULL,
+ CONF_MFLAGS_DEFAULT_SECTION|
+ CONF_MFLAGS_IGNORE_MISSING_FILE);
+
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+ /* OpenSSL 1.1.0+ takes care of initialization itself */
+#else
+ /* Lets get nice error messages */
+ SSL_load_error_strings();
+
+ /* Init the global ciphers and digests */
+ if(!SSLeay_add_ssl_algorithms())
+ return 0;
+
+ OpenSSL_add_all_algorithms();
+#endif
+
+ return 1;
+}
+
+/* Global cleanup */
+void Curl_ossl_cleanup(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+ /* OpenSSL 1.1 deprecates all these cleanup functions and
+ turns them into no-ops in OpenSSL 1.0 compatibility mode */
+#else
+ /* Free ciphers and digests lists */
+ EVP_cleanup();
+
+#ifdef HAVE_ENGINE_CLEANUP
+ /* Free engine list */
+ ENGINE_cleanup();
+#endif
+
+ /* Free OpenSSL error strings */
+ ERR_free_strings();
+
+ /* Free thread local error state, destroying hash upon zero refcount */
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+ ERR_remove_thread_state(NULL);
+#else
+ ERR_remove_state(0);
+#endif
+
+ /* Free all memory allocated by all configuration modules */
+ CONF_modules_free();
+
+#ifdef HAVE_SSL_COMP_FREE_COMPRESSION_METHODS
+ SSL_COMP_free_compression_methods();
+#endif
+#endif
+}
+
+/*
+ * This function is used to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_ossl_check_cxn(struct connectdata *conn)
+{
+ /* SSL_peek takes data out of the raw recv buffer without peeking so we use
+ recv MSG_PEEK instead. Bug #795 */
+#ifdef MSG_PEEK
+ char buf;
+ ssize_t nread;
+ nread = recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+ (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK);
+ if(nread == 0)
+ return 0; /* connection has been closed */
+ if(nread == 1)
+ return 1; /* connection still in place */
+ else if(nread == -1) {
+ int err = SOCKERRNO;
+ if(err == EINPROGRESS ||
+#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
+ err == EAGAIN ||
+#endif
+ err == EWOULDBLOCK)
+ return 1; /* connection still in place */
+ if(err == ECONNRESET ||
+#ifdef ECONNABORTED
+ err == ECONNABORTED ||
+#endif
+#ifdef ENETDOWN
+ err == ENETDOWN ||
+#endif
+#ifdef ENETRESET
+ err == ENETRESET ||
+#endif
+#ifdef ESHUTDOWN
+ err == ESHUTDOWN ||
+#endif
+#ifdef ETIMEDOUT
+ err == ETIMEDOUT ||
+#endif
+ err == ENOTCONN)
+ return 0; /* connection has been closed */
+ }
+#endif
+ return -1; /* connection status unknown */
+}
+
+/* Selects an OpenSSL crypto engine
+ */
+CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine)
+{
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
+ ENGINE *e;
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+ e = ENGINE_by_id(engine);
+#else
+ /* avoid memory leak */
+ for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+ const char *e_id = ENGINE_get_id(e);
+ if(!strcmp(engine, e_id))
+ break;
+ }
+#endif
+
+ if(!e) {
+ failf(data, "SSL Engine '%s' not found", engine);
+ return CURLE_SSL_ENGINE_NOTFOUND;
+ }
+
+ if(data->state.engine) {
+ ENGINE_finish(data->state.engine);
+ ENGINE_free(data->state.engine);
+ data->state.engine = NULL;
+ }
+ if(!ENGINE_init(e)) {
+ char buf[256];
+
+ ENGINE_free(e);
+ failf(data, "Failed to initialise SSL Engine '%s':\n%s",
+ engine, ossl_strerror(ERR_get_error(), buf, sizeof(buf)));
+ return CURLE_SSL_ENGINE_INITFAILED;
+ }
+ data->state.engine = e;
+ return CURLE_OK;
+#else
+ (void)engine;
+ failf(data, "SSL Engine not supported");
+ return CURLE_SSL_ENGINE_NOTFOUND;
+#endif
+}
+
+/* Sets engine as default for all SSL operations
+ */
+CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data)
+{
+#ifdef HAVE_OPENSSL_ENGINE_H
+ if(data->state.engine) {
+ if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
+ infof(data, "set default crypto engine '%s'\n",
+ ENGINE_get_id(data->state.engine));
+ }
+ else {
+ failf(data, "set default crypto engine '%s' failed",
+ ENGINE_get_id(data->state.engine));
+ return CURLE_SSL_ENGINE_SETFAILED;
+ }
+ }
+#else
+ (void) data;
+#endif
+ return CURLE_OK;
+}
+
+/* Return list of OpenSSL crypto engine names.
+ */
+struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data)
+{
+ struct curl_slist *list = NULL;
+#if defined(USE_OPENSSL) && defined(HAVE_OPENSSL_ENGINE_H)
+ struct curl_slist *beg;
+ ENGINE *e;
+
+ for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+ beg = curl_slist_append(list, ENGINE_get_id(e));
+ if(!beg) {
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ list = beg;
+ }
+#endif
+ (void) data;
+ return list;
+}
+
+
+static void ossl_close(struct ssl_connect_data *connssl)
+{
+ if(connssl->handle) {
+ (void)SSL_shutdown(connssl->handle);
+ SSL_set_connect_state(connssl->handle);
+
+ SSL_free(connssl->handle);
+ connssl->handle = NULL;
+ }
+ if(connssl->ctx) {
+ SSL_CTX_free(connssl->ctx);
+ connssl->ctx = NULL;
+ }
+}
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_ossl_close(struct connectdata *conn, int sockindex)
+{
+ ossl_close(&conn->ssl[sockindex]);
+ ossl_close(&conn->proxy_ssl[sockindex]);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
+{
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+ char buf[256]; /* We will use this for the OpenSSL error buffer, so it has
+ to be at least 256 bytes long. */
+ unsigned long sslerror;
+ ssize_t nread;
+ int buffsize;
+ int err;
+ int done = 0;
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ (void)SSL_shutdown(connssl->handle);
+
+ if(connssl->handle) {
+ buffsize = (int)sizeof(buf);
+ while(!done) {
+ int what = SOCKET_READABLE(conn->sock[sockindex],
+ SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ ERR_clear_error();
+
+ /* Something to read, let's do it and hope that it is the close
+ notify alert from the server */
+ nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
+ buffsize);
+ err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
+
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = 1;
+ break;
+ case SSL_ERROR_WANT_READ:
+ /* there's data pending, re-invoke SSL_read() */
+ infof(data, "SSL_ERROR_WANT_READ\n");
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /* SSL wants a write. Really odd. Let's bail out. */
+ infof(data, "SSL_ERROR_WANT_WRITE\n");
+ done = 1;
+ break;
+ default:
+ /* openssl/ssl.h says "look at error stack/return value/errno" */
+ sslerror = ERR_get_error();
+ failf(conn->data, OSSL_PACKAGE " SSL_read on shutdown: %s, errno %d",
+ (sslerror ?
+ ossl_strerror(sslerror, buf, sizeof(buf)) :
+ SSL_ERROR_to_str(err)),
+ SOCKERRNO);
+ done = 1;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = 1;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = 1;
+ }
+ } /* while()-loop for the select() */
+
+ if(data->set.verbose) {
+#ifdef HAVE_SSL_GET_SHUTDOWN
+ switch(SSL_get_shutdown(connssl->handle)) {
+ case SSL_SENT_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
+ break;
+ case SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
+ break;
+ case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
+ "SSL_RECEIVED__SHUTDOWN\n");
+ break;
+ }
+#endif
+ }
+
+ SSL_free(connssl->handle);
+ connssl->handle = NULL;
+ }
+ return retval;
+}
+
+void Curl_ossl_session_free(void *ptr)
+{
+ /* free the ID */
+ SSL_SESSION_free(ptr);
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+void Curl_ossl_close_all(struct Curl_easy *data)
+{
+#ifdef HAVE_OPENSSL_ENGINE_H
+ if(data->state.engine) {
+ ENGINE_finish(data->state.engine);
+ ENGINE_free(data->state.engine);
+ data->state.engine = NULL;
+ }
+#else
+ (void)data;
+#endif
+#if !defined(HAVE_ERR_REMOVE_THREAD_STATE_DEPRECATED) && \
+ defined(HAVE_ERR_REMOVE_THREAD_STATE)
+ /* OpenSSL 1.0.1 and 1.0.2 build an error queue that is stored per-thread
+ so we need to clean it here in case the thread will be killed. All OpenSSL
+ code should extract the error in association with the error so clearing
+ this queue here should be harmless at worst. */
+ ERR_remove_thread_state(NULL);
+#endif
+}
+
+/* ====================================================== */
+
+
+/* Quote from RFC2818 section 3.1 "Server Identity"
+
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead.
+
+ Matching is performed using the matching rules specified by
+ [RFC2459]. If more than one identity of a given type is present in
+ the certificate (e.g., more than one dNSName name, a match in any one
+ of the set is considered acceptable.) Names may contain the wildcard
+ character * which is considered to match any single domain name
+ component or component fragment. E.g., *.a.com matches foo.a.com but
+ not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI.
+
+*/
+static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
+{
+ bool matched = FALSE;
+ int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+ size_t addrlen = 0;
+ struct Curl_easy *data = conn->data;
+ STACK_OF(GENERAL_NAME) *altnames;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+ CURLcode result = CURLE_OK;
+ bool dNSName = FALSE; /* if a dNSName field exists in the cert */
+ bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.dispname : conn->host.dispname;
+
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, hostname, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in6_addr);
+ }
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, hostname, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ }
+
+ /* get a "list" of alternative names */
+ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
+
+ if(altnames) {
+ int numalts;
+ int i;
+ bool dnsmatched = FALSE;
+ bool ipmatched = FALSE;
+
+ /* get amount of alternatives, RFC2459 claims there MUST be at least
+ one, but we don't depend on it... */
+ numalts = sk_GENERAL_NAME_num(altnames);
+
+ /* loop through all alternatives - until a dnsmatch */
+ for(i=0; (i < numalts) && !dnsmatched; i++) {
+ /* get a handle to alternative name number i */
+ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
+
+ if(check->type == GEN_DNS)
+ dNSName = TRUE;
+ else if(check->type == GEN_IPADD)
+ iPAddress = TRUE;
+
+ /* only check alternatives of the same type the target is */
+ if(check->type == target) {
+ /* get data and length */
+ const char *altptr = (char *)ASN1_STRING_get0_data(check->d.ia5);
+ size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
+
+ switch(target) {
+ case GEN_DNS: /* name/pattern comparison */
+ /* The OpenSSL man page explicitly says: "In general it cannot be
+ assumed that the data returned by ASN1_STRING_data() is null
+ terminated or does not contain embedded nulls." But also that
+ "The actual format of the data will depend on the actual string
+ type itself: for example for and IA5String the data will be ASCII"
+
+ Gisle researched the OpenSSL sources:
+ "I checked the 0.9.6 and 0.9.8 sources before my patch and
+ it always 0-terminates an IA5String."
+ */
+ if((altlen == strlen(altptr)) &&
+ /* if this isn't true, there was an embedded zero in the name
+ string and we cannot match it. */
+ Curl_cert_hostcheck(altptr, hostname)) {
+ dnsmatched = TRUE;
+ infof(data,
+ " subjectAltName: host \"%s\" matched cert's \"%s\"\n",
+ dispname, altptr);
+ }
+ break;
+
+ case GEN_IPADD: /* IP address comparison */
+ /* compare alternative IP address if the data chunk is the same size
+ our server IP address is */
+ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) {
+ ipmatched = TRUE;
+ infof(data,
+ " subjectAltName: host \"%s\" matched cert's IP address!\n",
+ dispname);
+ }
+ break;
+ }
+ }
+ }
+ GENERAL_NAMES_free(altnames);
+
+ if(dnsmatched || ipmatched)
+ matched = TRUE;
+ }
+
+ if(matched)
+ /* an alternative name matched */
+ ;
+ else if(dNSName || iPAddress) {
+ infof(data, " subjectAltName does not match %s\n", dispname);
+ failf(data, "SSL: no alternative certificate subject name matches "
+ "target host name '%s'", dispname);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ /* we have to look to the last occurrence of a commonName in the
+ distinguished one to get the most significant one. */
+ int j, i=-1;
+
+ /* The following is done because of a bug in 0.9.6b */
+
+ unsigned char *nulstr = (unsigned char *)"";
+ unsigned char *peer_CN = nulstr;
+
+ X509_NAME *name = X509_get_subject_name(server_cert);
+ if(name)
+ while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
+ i=j;
+
+ /* we have the name entry and we will now convert this to a string
+ that we can use for comparison. Doing this we support BMPstring,
+ UTF8 etc. */
+
+ if(i>=0) {
+ ASN1_STRING *tmp =
+ X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, i));
+
+ /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+ is already UTF-8 encoded. We check for this case and copy the raw
+ string manually to avoid the problem. This code can be made
+ conditional in the future when OpenSSL has been fixed. Work-around
+ brought by Alexis S. L. Carvalho. */
+ if(tmp) {
+ if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+ j = ASN1_STRING_length(tmp);
+ if(j >= 0) {
+ peer_CN = OPENSSL_malloc(j+1);
+ if(peer_CN) {
+ memcpy(peer_CN, ASN1_STRING_get0_data(tmp), j);
+ peer_CN[j] = '\0';
+ }
+ }
+ }
+ else /* not a UTF8 name */
+ j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+ if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) {
+ /* there was a terminating zero before the end of string, this
+ cannot match and we return failure! */
+ failf(data, "SSL: illegal cert name field");
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(peer_CN == nulstr)
+ peer_CN = NULL;
+ else {
+ /* convert peer_CN from UTF8 */
+ CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
+ /* Curl_convert_from_utf8 calls failf if unsuccessful */
+ if(rc) {
+ OPENSSL_free(peer_CN);
+ return rc;
+ }
+ }
+
+ if(result)
+ /* error already detected, pass through */
+ ;
+ else if(!peer_CN) {
+ failf(data,
+ "SSL: unable to obtain common name from peer certificate");
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else if(!Curl_cert_hostcheck((const char *)peer_CN, hostname)) {
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", peer_CN, dispname);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ infof(data, " common name: %s (matched)\n", peer_CN);
+ }
+ if(peer_CN)
+ OPENSSL_free(peer_CN);
+ }
+
+ return result;
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_NO_OCSP)
+static CURLcode verifystatus(struct connectdata *conn,
+ struct ssl_connect_data *connssl)
+{
+ int i, ocsp_status;
+ const unsigned char *p;
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+
+ OCSP_RESPONSE *rsp = NULL;
+ OCSP_BASICRESP *br = NULL;
+ X509_STORE *st = NULL;
+ STACK_OF(X509) *ch = NULL;
+
+ long len = SSL_get_tlsext_status_ocsp_resp(connssl->handle, &p);
+
+ if(!p) {
+ failf(data, "No OCSP response received");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
+ if(!rsp) {
+ failf(data, "Invalid OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ ocsp_status = OCSP_response_status(rsp);
+ if(ocsp_status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
+ failf(data, "Invalid OCSP response status: %s (%d)",
+ OCSP_response_status_str(ocsp_status), ocsp_status);
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ br = OCSP_response_get1_basic(rsp);
+ if(!br) {
+ failf(data, "Invalid OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ ch = SSL_get_peer_cert_chain(connssl->handle);
+ st = SSL_CTX_get_cert_store(connssl->ctx);
+
+#if ((OPENSSL_VERSION_NUMBER <= 0x1000201fL) /* Fixed after 1.0.2a */ || \
+ (defined(LIBRESSL_VERSION_NUMBER) && \
+ LIBRESSL_VERSION_NUMBER <= 0x2040200fL))
+ /* The authorized responder cert in the OCSP response MUST be signed by the
+ peer cert's issuer (see RFC6960 section 4.2.2.2). If that's a root cert,
+ no problem, but if it's an intermediate cert OpenSSL has a bug where it
+ expects this issuer to be present in the chain embedded in the OCSP
+ response. So we add it if necessary. */
+
+ /* First make sure the peer cert chain includes both a peer and an issuer,
+ and the OCSP response contains a responder cert. */
+ if(sk_X509_num(ch) >= 2 && sk_X509_num(br->certs) >= 1) {
+ X509 *responder = sk_X509_value(br->certs, sk_X509_num(br->certs) - 1);
+
+ /* Find issuer of responder cert and add it to the OCSP response chain */
+ for(i = 0; i < sk_X509_num(ch); i++) {
+ X509 *issuer = sk_X509_value(ch, i);
+ if(X509_check_issued(issuer, responder) == X509_V_OK) {
+ if(!OCSP_basic_add1_cert(br, issuer)) {
+ failf(data, "Could not add issuer cert to OCSP response");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+ }
+ }
+ }
+#endif
+
+ if(OCSP_basic_verify(br, ch, st, 0) <= 0) {
+ failf(data, "OCSP response verification failed");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ for(i = 0; i < OCSP_resp_count(br); i++) {
+ int cert_status, crl_reason;
+ OCSP_SINGLERESP *single = NULL;
+
+ ASN1_GENERALIZEDTIME *rev, *thisupd, *nextupd;
+
+ single = OCSP_resp_get0(br, i);
+ if(!single)
+ continue;
+
+ cert_status = OCSP_single_get0_status(single, &crl_reason, &rev,
+ &thisupd, &nextupd);
+
+ if(!OCSP_check_validity(thisupd, nextupd, 300L, -1L)) {
+ failf(data, "OCSP response has expired");
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+
+ infof(data, "SSL certificate status: %s (%d)\n",
+ OCSP_cert_status_str(cert_status), cert_status);
+
+ switch(cert_status) {
+ case V_OCSP_CERTSTATUS_GOOD:
+ break;
+
+ case V_OCSP_CERTSTATUS_REVOKED:
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+
+ failf(data, "SSL certificate revocation reason: %s (%d)",
+ OCSP_crl_reason_str(crl_reason), crl_reason);
+ goto end;
+
+ case V_OCSP_CERTSTATUS_UNKNOWN:
+ result = CURLE_SSL_INVALIDCERTSTATUS;
+ goto end;
+ }
+ }
+
+end:
+ if(br) OCSP_BASICRESP_free(br);
+ OCSP_RESPONSE_free(rsp);
+
+ return result;
+}
+#endif
+
+#endif /* USE_OPENSSL */
+
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+ and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+#ifdef SSL2_VERSION_MAJOR
+ if(ssl_ver == SSL2_VERSION_MAJOR) {
+ switch(msg) {
+ case SSL2_MT_ERROR:
+ return "Error";
+ case SSL2_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL2_MT_CLIENT_MASTER_KEY:
+ return "Client key";
+ case SSL2_MT_CLIENT_FINISHED:
+ return "Client finished";
+ case SSL2_MT_SERVER_HELLO:
+ return "Server hello";
+ case SSL2_MT_SERVER_VERIFY:
+ return "Server verify";
+ case SSL2_MT_SERVER_FINISHED:
+ return "Server finished";
+ case SSL2_MT_REQUEST_CERTIFICATE:
+ return "Request CERT";
+ case SSL2_MT_CLIENT_CERTIFICATE:
+ return "Client CERT";
+ }
+ }
+ else
+#endif
+ if(ssl_ver == SSL3_VERSION_MAJOR) {
+ switch(msg) {
+ case SSL3_MT_HELLO_REQUEST:
+ return "Hello request";
+ case SSL3_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL3_MT_SERVER_HELLO:
+ return "Server hello";
+#ifdef SSL3_MT_NEWSESSION_TICKET
+ case SSL3_MT_NEWSESSION_TICKET:
+ return "Newsession Ticket";
+#endif
+ case SSL3_MT_CERTIFICATE:
+ return "Certificate";
+ case SSL3_MT_SERVER_KEY_EXCHANGE:
+ return "Server key exchange";
+ case SSL3_MT_CLIENT_KEY_EXCHANGE:
+ return "Client key exchange";
+ case SSL3_MT_CERTIFICATE_REQUEST:
+ return "Request CERT";
+ case SSL3_MT_SERVER_DONE:
+ return "Server finished";
+ case SSL3_MT_CERTIFICATE_VERIFY:
+ return "CERT verify";
+ case SSL3_MT_FINISHED:
+ return "Finished";
+#ifdef SSL3_MT_CERTIFICATE_STATUS
+ case SSL3_MT_CERTIFICATE_STATUS:
+ return "Certificate Status";
+#endif
+ }
+ }
+ return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+ switch(type) {
+#ifdef SSL3_RT_HEADER
+ case SSL3_RT_HEADER:
+ return "TLS header";
+#endif
+ case SSL3_RT_CHANGE_CIPHER_SPEC:
+ return "TLS change cipher";
+ case SSL3_RT_ALERT:
+ return "TLS alert";
+ case SSL3_RT_HANDSHAKE:
+ return "TLS handshake";
+ case SSL3_RT_APPLICATION_DATA:
+ return "TLS app data";
+ default:
+ return "TLS Unknown";
+ }
+}
+
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
+ const void *buf, size_t len, SSL *ssl,
+ void *userp)
+{
+ struct Curl_easy *data;
+ const char *msg_name, *tls_rt_name;
+ char ssl_buf[1024];
+ char unknown[32];
+ int msg_type, txt_len;
+ const char *verstr = NULL;
+ struct connectdata *conn = userp;
+
+ if(!conn || !conn->data || !conn->data->set.fdebug ||
+ (direction != 0 && direction != 1))
+ return;
+
+ data = conn->data;
+
+ switch(ssl_ver) {
+#ifdef SSL2_VERSION /* removed in recent versions */
+ case SSL2_VERSION:
+ verstr = "SSLv2";
+ break;
+#endif
+#ifdef SSL3_VERSION
+ case SSL3_VERSION:
+ verstr = "SSLv3";
+ break;
+#endif
+ case TLS1_VERSION:
+ verstr = "TLSv1.0";
+ break;
+#ifdef TLS1_1_VERSION
+ case TLS1_1_VERSION:
+ verstr = "TLSv1.1";
+ break;
+#endif
+#ifdef TLS1_2_VERSION
+ case TLS1_2_VERSION:
+ verstr = "TLSv1.2";
+ break;
+#endif
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ verstr = "TLSv1.3";
+ break;
+#endif
+ case 0:
+ break;
+ default:
+ snprintf(unknown, sizeof(unknown), "(%x)", ssl_ver);
+ verstr = unknown;
+ break;
+ }
+
+ if(ssl_ver) {
+ /* the info given when the version is zero is not that useful for us */
+
+ ssl_ver >>= 8; /* check the upper 8 bits only below */
+
+ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+ * always pass-up content-type as 0. But the interesting message-type
+ * is at 'buf[0]'.
+ */
+ if(ssl_ver == SSL3_VERSION_MAJOR && content_type)
+ tls_rt_name = tls_rt_type(content_type);
+ else
+ tls_rt_name = "";
+
+ msg_type = *(char *)buf;
+ msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+ txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "%s (%s), %s, %s (%d):\n",
+ verstr, direction?"OUT":"IN",
+ tls_rt_name, msg_name, msg_type);
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+ }
+
+ Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+ CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
+ (void) ssl;
+}
+#endif
+
+#ifdef USE_OPENSSL
+/* ====================================================== */
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+# define use_sni(x) sni = (x)
+#else
+# define use_sni(x) Curl_nop_stmt
+#endif
+
+/* Check for OpenSSL 1.0.2 which has ALPN support. */
+#undef HAS_ALPN
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L \
+ && !defined(OPENSSL_NO_TLSEXT)
+# define HAS_ALPN 1
+#endif
+
+/* Check for OpenSSL 1.0.1 which has NPN support. */
+#undef HAS_NPN
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L \
+ && !defined(OPENSSL_NO_TLSEXT) \
+ && !defined(OPENSSL_NO_NEXTPROTONEG)
+# define HAS_NPN 1
+#endif
+
+#ifdef HAS_NPN
+
+/*
+ * in is a list of length prefixed strings. this function has to select
+ * the protocol we want to use from the list and write its string into out.
+ */
+
+static int
+select_next_protocol(unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ const char *key, unsigned int keylen)
+{
+ unsigned int i;
+ for(i = 0; i + keylen <= inlen; i += in[i] + 1) {
+ if(memcmp(&in[i + 1], key, keylen) == 0) {
+ *out = (unsigned char *) &in[i + 1];
+ *outlen = in[i];
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+select_next_proto_cb(SSL *ssl,
+ unsigned char **out, unsigned char *outlen,
+ const unsigned char *in, unsigned int inlen,
+ void *arg)
+{
+ struct connectdata *conn = (struct connectdata*) arg;
+
+ (void)ssl;
+
+#ifdef USE_NGHTTP2
+ if(conn->data->set.httpversion >= CURL_HTTP_VERSION_2 &&
+ !select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ infof(conn->data, "NPN, negotiated HTTP2 (%s)\n",
+ NGHTTP2_PROTO_VERSION_ID);
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ return SSL_TLSEXT_ERR_OK;
+ }
+#endif
+
+ if(!select_next_protocol(out, outlen, in, inlen, ALPN_HTTP_1_1,
+ ALPN_HTTP_1_1_LENGTH)) {
+ infof(conn->data, "NPN, negotiated HTTP1.1\n");
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ return SSL_TLSEXT_ERR_OK;
+ }
+
+ infof(conn->data, "NPN, no overlap, use HTTP1.1\n");
+ *out = (unsigned char *)ALPN_HTTP_1_1;
+ *outlen = ALPN_HTTP_1_1_LENGTH;
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+
+ return SSL_TLSEXT_ERR_OK;
+}
+#endif /* HAS_NPN */
+
+static const char *
+get_ssl_version_txt(SSL *ssl)
+{
+ if(!ssl)
+ return "";
+
+ switch(SSL_version(ssl)) {
+#ifdef TLS1_3_VERSION
+ case TLS1_3_VERSION:
+ return "TLSv1.3";
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ case TLS1_2_VERSION:
+ return "TLSv1.2";
+ case TLS1_1_VERSION:
+ return "TLSv1.1";
+#endif
+ case TLS1_VERSION:
+ return "TLSv1.0";
+ case SSL3_VERSION:
+ return "SSLv3";
+ case SSL2_VERSION:
+ return "SSLv2";
+ }
+ return "unknown";
+}
+
+static CURLcode
+set_ssl_version_min_max(long *ctx_options, struct connectdata *conn,
+ int sockindex)
+{
+#if (OPENSSL_VERSION_NUMBER < 0x1000100FL) || !defined(TLS1_3_VERSION)
+ /* convoluted #if condition just to avoid compiler warnings on unused
+ variable */
+ struct Curl_easy *data = conn->data;
+#endif
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+
+ if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) {
+ ssl_version_max = ssl_version << 16;
+ }
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_TLSv1_3:
+#ifdef TLS1_3_VERSION
+ {
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SSL_CTX_set_max_proto_version(connssl->ctx, TLS1_3_VERSION);
+ *ctx_options |= SSL_OP_NO_TLSv1_2;
+ }
+#else
+ (void)sockindex;
+ failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ case CURL_SSLVERSION_TLSv1_2:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_1;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.2 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.1 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_TLSv1_0:
+ *ctx_options |= SSL_OP_NO_SSLv2;
+ *ctx_options |= SSL_OP_NO_SSLv3;
+ break;
+ }
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_TLSv1_0:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_1;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_MAX_TLSv1_1:
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ *ctx_options |= SSL_OP_NO_TLSv1_2;
+#endif
+ /* FALLTHROUGH */
+ case CURL_SSLVERSION_MAX_TLSv1_2:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+#ifdef TLS1_3_VERSION
+ *ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+ break;
+ case CURL_SSLVERSION_MAX_TLSv1_3:
+#ifdef TLS1_3_VERSION
+ break;
+#else
+ failf(data, OSSL_PACKAGE " was built without TLS 1.3 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ return CURLE_OK;
+}
+
+static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
+{
+ CURLcode result = CURLE_OK;
+ char *ciphers;
+ struct Curl_easy *data = conn->data;
+ SSL_METHOD_QUAL SSL_METHOD *req_method = NULL;
+ X509_LOOKUP *lookup = NULL;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long ctx_options = 0;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ bool sni;
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+#endif
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ const long int ssl_version = SSL_CONN_CONFIG(version);
+#ifdef USE_TLS_SRP
+ const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
+#endif
+ char * const ssl_cert = SSL_SET_OPTION(cert);
+ const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
+ const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
+ const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
+ const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
+ char error_buffer[256];
+
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+
+ /* Make funny stuff to get random input */
+ result = Curl_ossl_seed(data);
+ if(result)
+ return result;
+
+ *certverifyresult = !X509_V_OK;
+
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ /* it will be handled later with the context options */
+#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \
+ !defined(LIBRESSL_VERSION_NUMBER)
+ req_method = TLS_client_method();
+#else
+ req_method = SSLv23_client_method();
+#endif
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+#ifdef OPENSSL_NO_SSL2
+ failf(data, OSSL_PACKAGE " was built without SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+#else
+#ifdef USE_TLS_SRP
+ if(ssl_authtype == CURL_TLSAUTH_SRP)
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ req_method = SSLv2_client_method();
+ use_sni(FALSE);
+ break;
+#endif
+ case CURL_SSLVERSION_SSLv3:
+#ifdef OPENSSL_NO_SSL3_METHOD
+ failf(data, OSSL_PACKAGE " was built without SSLv3 support");
+ return CURLE_NOT_BUILT_IN;
+#else
+#ifdef USE_TLS_SRP
+ if(ssl_authtype == CURL_TLSAUTH_SRP)
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ req_method = SSLv3_client_method();
+ use_sni(FALSE);
+ break;
+#endif
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(connssl->ctx)
+ SSL_CTX_free(connssl->ctx);
+ connssl->ctx = SSL_CTX_new(req_method);
+
+ if(!connssl->ctx) {
+ failf(data, "SSL: couldn't create a context: %s",
+ ossl_strerror(ERR_peek_error(), error_buffer, sizeof(error_buffer)));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+ if(data->set.fdebug && data->set.verbose) {
+ /* the SSL trace callback is only used for verbose logging */
+ SSL_CTX_set_msg_callback(connssl->ctx, ssl_tls_trace);
+ SSL_CTX_set_msg_callback_arg(connssl->ctx, conn);
+ }
+#endif
+
+ /* OpenSSL contains code to work-around lots of bugs and flaws in various
+ SSL-implementations. SSL_CTX_set_options() is used to enabled those
+ work-arounds. The man page for this option states that SSL_OP_ALL enables
+ all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
+ enable the bug workaround options if compatibility with somewhat broken
+ implementations is desired."
+
+ The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
+ disable "rfc4507bis session ticket support". rfc4507bis was later turned
+ into the proper RFC5077 it seems: https://tools.ietf.org/html/rfc5077
+
+ The enabled extension concerns the session management. I wonder how often
+ libcurl stops a connection and then resumes a TLS session. also, sending
+ the session data is some overhead. .I suggest that you just use your
+ proposed patch (which explicitly disables TICKET).
+
+ If someone writes an application with libcurl and openssl who wants to
+ enable the feature, one can do this in the SSL callback.
+
+ SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper
+ interoperability with web server Netscape Enterprise Server 2.0.1 which
+ was released back in 1996.
+
+ Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has
+ become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate
+ CVE-2010-4180 when using previous OpenSSL versions we no longer enable
+ this option regardless of OpenSSL version and SSL_OP_ALL definition.
+
+ OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
+ (https://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
+ SSL_OP_ALL that _disables_ that work-around despite the fact that
+ SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
+ keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
+ must not be set.
+ */
+
+ ctx_options = SSL_OP_ALL;
+
+#ifdef SSL_OP_NO_TICKET
+ ctx_options |= SSL_OP_NO_TICKET;
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+ ctx_options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+ /* mitigate CVE-2010-4180 */
+ ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+#endif
+
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ /* unless the user explicitly ask to allow the protocol vulnerability we
+ use the work-around */
+ if(!SSL_SET_OPTION(enable_beast))
+ ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+#endif
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_SSLv3:
+#ifdef USE_TLS_SRP
+ if(ssl_authtype == CURL_TLSAUTH_SRP) {
+ infof(data, "Set version TLSv1.x for SRP authorisation\n");
+ }
+#endif
+ ctx_options |= SSL_OP_NO_SSLv2;
+ ctx_options |= SSL_OP_NO_TLSv1;
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ ctx_options |= SSL_OP_NO_TLSv1_1;
+ ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+#endif
+ break;
+
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ctx_options |= SSL_OP_NO_SSLv2;
+ ctx_options |= SSL_OP_NO_SSLv3;
+ break;
+
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ result = set_ssl_version_min_max(&ctx_options, conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
+ break;
+
+ case CURL_SSLVERSION_SSLv2:
+#ifndef OPENSSL_NO_SSL2
+ ctx_options |= SSL_OP_NO_SSLv3;
+ ctx_options |= SSL_OP_NO_TLSv1;
+#if OPENSSL_VERSION_NUMBER >= 0x1000100FL
+ ctx_options |= SSL_OP_NO_TLSv1_1;
+ ctx_options |= SSL_OP_NO_TLSv1_2;
+#ifdef TLS1_3_VERSION
+ ctx_options |= SSL_OP_NO_TLSv1_3;
+#endif
+#endif
+ break;
+#else
+ failf(data, OSSL_PACKAGE " was built without SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+#endif
+
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ SSL_CTX_set_options(connssl->ctx, ctx_options);
+
+#ifdef HAS_NPN
+ if(conn->bits.tls_enable_npn)
+ SSL_CTX_set_next_proto_select_cb(connssl->ctx, select_next_proto_cb, conn);
+#endif
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ int cur = 0;
+ unsigned char protocols[128];
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
+
+ memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN);
+ cur += NGHTTP2_PROTO_VERSION_ID_LEN;
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ protocols[cur++] = ALPN_HTTP_1_1_LENGTH;
+ memcpy(&protocols[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
+ cur += ALPN_HTTP_1_1_LENGTH;
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ /* expects length prefixed preference ordered list of protocols in wire
+ * format
+ */
+ SSL_CTX_set_alpn_protos(connssl->ctx, protocols, cur);
+ }
+#endif
+
+ if(ssl_cert || ssl_cert_type) {
+ if(!cert_stuff(conn, connssl->ctx, ssl_cert, ssl_cert_type,
+ SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
+ SSL_SET_OPTION(key_passwd))) {
+ /* failf() is already done in cert_stuff() */
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ ciphers = SSL_CONN_CONFIG(cipher_list);
+ if(!ciphers)
+ ciphers = (char *)DEFAULT_CIPHER_SELECTION;
+ if(!SSL_CTX_set_cipher_list(connssl->ctx, ciphers)) {
+ failf(data, "failed setting cipher list: %s", ciphers);
+ return CURLE_SSL_CIPHER;
+ }
+ infof(data, "Cipher selection: %s\n", ciphers);
+
+#ifdef USE_TLS_SRP
+ if(ssl_authtype == CURL_TLSAUTH_SRP) {
+ char * const ssl_username = SSL_SET_OPTION(username);
+
+ infof(data, "Using TLS-SRP username: %s\n", ssl_username);
+
+ if(!SSL_CTX_set_srp_username(connssl->ctx, ssl_username)) {
+ failf(data, "Unable to set SRP user name");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ if(!SSL_CTX_set_srp_password(connssl->ctx, SSL_SET_OPTION(password))) {
+ failf(data, "failed setting SRP password");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ if(!SSL_CONN_CONFIG(cipher_list)) {
+ infof(data, "Setting cipher list SRP\n");
+
+ if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
+ failf(data, "failed setting SRP cipher list");
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
+#endif
+
+ if(ssl_cafile || ssl_capath) {
+ /* tell SSL where to find CA certificates that are used to verify
+ the servers certificate. */
+ if(!SSL_CTX_load_verify_locations(connssl->ctx, ssl_cafile, ssl_capath)) {
+ if(verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ /* Just continue with a warning if no strict certificate verification
+ is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ ssl_cafile ? ssl_cafile : "none",
+ ssl_capath ? ssl_capath : "none");
+ }
+#ifdef CURL_CA_FALLBACK
+ else if(verifypeer) {
+ /* verfying the peer without any CA certificates won't
+ work so use openssl's built in default as fallback */
+ SSL_CTX_set_default_verify_paths(connssl->ctx);
+ }
+#endif
+
+ if(ssl_crlfile) {
+ /* tell SSL where to find CRL file that is used to check certificate
+ * revocation */
+ lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_LOOKUP_file());
+ if(!lookup ||
+ (!X509_load_crl_file(lookup, ssl_crlfile, X509_FILETYPE_PEM)) ) {
+ failf(data, "error loading CRL file: %s", ssl_crlfile);
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ /* Everything is fine. */
+ infof(data, "successfully load CRL file:\n");
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+
+ infof(data, " CRLfile: %s\n", ssl_crlfile);
+ }
+
+ /* Try building a chain using issuers in the trusted store first to avoid
+ problems with server-sent legacy intermediates.
+ Newer versions of OpenSSL do alternate chain checking by default which
+ gives us the same fix without as much of a performance hit (slight), so we
+ prefer that if available.
+ https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
+ */
+#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
+ if(verifypeer) {
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_V_FLAG_TRUSTED_FIRST);
+ }
+#endif
+
+ /* SSL always tries to verify the peer, this only says whether it should
+ * fail to connect if the verification fails, or if it should continue
+ * anyway. In the latter case the result of the verification is checked with
+ * SSL_get_verify_result() below. */
+ SSL_CTX_set_verify(connssl->ctx,
+ verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ result = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ data->set.ssl.fsslctxp);
+ if(result) {
+ failf(data, "error signaled by ssl ctx callback");
+ return result;
+ }
+ }
+
+ /* Lets make an SSL structure */
+ if(connssl->handle)
+ SSL_free(connssl->handle);
+ connssl->handle = SSL_new(connssl->ctx);
+ if(!connssl->handle) {
+ failf(data, "SSL: couldn't create a context (handle)!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_NO_OCSP)
+ if(SSL_CONN_CONFIG(verifystatus))
+ SSL_set_tlsext_status_type(connssl->handle, TLSEXT_STATUSTYPE_ocsp);
+#endif
+
+ SSL_set_connect_state(connssl->handle);
+
+ connssl->server_cert = 0x0;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if((0 == Curl_inet_pton(AF_INET, hostname, &addr)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, hostname, &addr)) &&
+#endif
+ sni &&
+ !SSL_set_tlsext_host_name(connssl->handle, hostname))
+ infof(data, "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+#endif
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *ssl_sessionid = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL, sockindex)) {
+ /* we got a session id, use it! */
+ if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof(data, "SSL re-using session ID\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ if(conn->proxy_ssl[sockindex].use) {
+ BIO *const bio = BIO_new(BIO_f_ssl());
+ DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
+ DEBUGASSERT(conn->proxy_ssl[sockindex].handle != NULL);
+ DEBUGASSERT(bio != NULL);
+ BIO_set_ssl(bio, conn->proxy_ssl[sockindex].handle, FALSE);
+ SSL_set_bio(connssl->handle, bio, bio);
+ }
+ else if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ /* pass the raw socket into the SSL layers */
+ failf(data, "SSL: SSL_set_fd failed: %s",
+ ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ int err;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
+
+ ERR_clear_error();
+
+ err = SSL_connect(connssl->handle);
+
+ /* 1 is fine
+ 0 is "not successful but was shut down controlled"
+ <0 is "handshake was not successful, because a fatal error occurred" */
+ if(1 != err) {
+ int detail = SSL_get_error(connssl->handle, err);
+
+ if(SSL_ERROR_WANT_READ == detail) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ if(SSL_ERROR_WANT_WRITE == detail) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ else {
+ /* untreated error */
+ unsigned long errdetail;
+ char error_buffer[256]="";
+ CURLcode result;
+ long lerr;
+ int lib;
+ int reason;
+
+ /* the connection failed, we're not waiting for anything else. */
+ connssl->connecting_state = ssl_connect_2;
+
+ /* Get the earliest error code from the thread's error queue and removes
+ the entry. */
+ errdetail = ERR_get_error();
+
+ /* Extract which lib and reason */
+ lib = ERR_GET_LIB(errdetail);
+ reason = ERR_GET_REASON(errdetail);
+
+ if((lib == ERR_LIB_SSL) &&
+ (reason == SSL_R_CERTIFICATE_VERIFY_FAILED)) {
+ result = CURLE_SSL_CACERT;
+
+ lerr = SSL_get_verify_result(connssl->handle);
+ if(lerr != X509_V_OK) {
+ *certverifyresult = lerr;
+ snprintf(error_buffer, sizeof(error_buffer),
+ "SSL certificate problem: %s",
+ X509_verify_cert_error_string(lerr));
+ }
+ else
+ /* strcpy() is fine here as long as the string fits within
+ error_buffer */
+ strcpy(error_buffer, "SSL certificate verification failed");
+ }
+ else {
+ result = CURLE_SSL_CONNECT_ERROR;
+ ossl_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ }
+
+ /* detail is already set to the SSL error above */
+
+ /* If we e.g. use SSLv2 request-method and the server doesn't like us
+ * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+ * the SO_ERROR is also lost.
+ */
+ if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
+ const char * const hostname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.name : conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+ failf(data, OSSL_PACKAGE " SSL_connect: %s in connection to %s:%ld ",
+ SSL_ERROR_to_str(detail), hostname, port);
+ return result;
+ }
+
+ /* Could be a CERT problem */
+ failf(data, "%s", error_buffer);
+
+ return result;
+ }
+ }
+ else {
+ /* we have been connected fine, we're not waiting for anything else. */
+ connssl->connecting_state = ssl_connect_3;
+
+ /* Informational message */
+ infof(data, "SSL connection using %s / %s\n",
+ get_ssl_version_txt(connssl->handle),
+ SSL_get_cipher(connssl->handle));
+
+#ifdef HAS_ALPN
+ /* Sets data and len to negotiated protocol, len is 0 if no protocol was
+ * negotiated
+ */
+ if(conn->bits.tls_enable_alpn) {
+ const unsigned char *neg_protocol;
+ unsigned int len;
+ SSL_get0_alpn_selected(connssl->handle, &neg_protocol, &len);
+ if(len != 0) {
+ infof(data, "ALPN, server accepted to use %.*s\n", len, neg_protocol);
+
+#ifdef USE_NGHTTP2
+ if(len == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(NGHTTP2_PROTO_VERSION_ID, neg_protocol, len)) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(len == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, neg_protocol, ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+ else
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ }
+#endif
+
+ return CURLE_OK;
+ }
+}
+
+static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
+{
+ int i, ilen;
+
+ ilen = (int)len;
+ if(ilen < 0)
+ return 1; /* buffer too big */
+
+ i = i2t_ASN1_OBJECT(buf, ilen, a);
+
+ if(i >= ilen)
+ return 1; /* buffer too small */
+
+ return 0;
+}
+
+#define push_certinfo(_label, _num) \
+do { \
+ long info_len = BIO_get_mem_data(mem, &ptr); \
+ Curl_ssl_push_certinfo_len(data, _num, _label, ptr, info_len); \
+ if(1!=BIO_reset(mem)) \
+ break; \
+} WHILE_FALSE
+
+static void pubkey_show(struct Curl_easy *data,
+ BIO *mem,
+ int num,
+ const char *type,
+ const char *name,
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ const
+#endif
+ BIGNUM *bn)
+{
+ char *ptr;
+ char namebuf[32];
+
+ snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+
+ if(bn)
+ BN_print(mem, bn);
+ push_certinfo(namebuf, num);
+}
+
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+#define print_pubkey_BN(_type, _name, _num) \
+ pubkey_show(data, mem, _num, #_type, #_name, _name)
+
+#else
+#define print_pubkey_BN(_type, _name, _num) \
+do { \
+ if(_type->_name) { \
+ pubkey_show(data, mem, _num, #_type, #_name, _type->_name); \
+ } \
+} WHILE_FALSE
+#endif
+
+static int X509V3_ext(struct Curl_easy *data,
+ int certnum,
+ CONST_EXTS STACK_OF(X509_EXTENSION) *exts)
+{
+ int i;
+ size_t j;
+
+ if((int)sk_X509_EXTENSION_num(exts) <= 0)
+ /* no extensions, bail out */
+ return 1;
+
+ for(i=0; i < (int)sk_X509_EXTENSION_num(exts); i++) {
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+ BUF_MEM *biomem;
+ char buf[512];
+ char *ptr=buf;
+ char namebuf[128];
+ BIO *bio_out = BIO_new(BIO_s_mem());
+
+ if(!bio_out)
+ return 1;
+
+ obj = X509_EXTENSION_get_object(ext);
+
+ asn1_object_dump(obj, namebuf, sizeof(namebuf));
+
+ if(!X509V3_EXT_print(bio_out, ext, 0, 0))
+ ASN1_STRING_print(bio_out, (ASN1_STRING *)X509_EXTENSION_get_data(ext));
+
+ BIO_get_mem_ptr(bio_out, &biomem);
+
+ for(j = 0; j < (size_t)biomem->length; j++) {
+ const char *sep="";
+ if(biomem->data[j] == '\n') {
+ sep=", ";
+ j++; /* skip the newline */
+ };
+ while((j<(size_t)biomem->length) && (biomem->data[j] == ' '))
+ j++;
+ if(j<(size_t)biomem->length)
+ ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
+ biomem->data[j]);
+ }
+
+ Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
+
+ BIO_free(bio_out);
+
+ }
+ return 0; /* all is fine */
+}
+
+static CURLcode get_cert_chain(struct connectdata *conn,
+ struct ssl_connect_data *connssl)
+
+{
+ CURLcode result;
+ STACK_OF(X509) *sk;
+ int i;
+ struct Curl_easy *data = conn->data;
+ int numcerts;
+ BIO *mem;
+
+ sk = SSL_get_peer_cert_chain(connssl->handle);
+ if(!sk) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ numcerts = sk_X509_num(sk);
+
+ result = Curl_ssl_init_certinfo(data, numcerts);
+ if(result) {
+ return result;
+ }
+
+ mem = BIO_new(BIO_s_mem());
+
+ for(i = 0; i < numcerts; i++) {
+ ASN1_INTEGER *num;
+ X509 *x = sk_X509_value(sk, i);
+ EVP_PKEY *pubkey=NULL;
+ int j;
+ char *ptr;
+ CONST_ASN1_BIT_STRING ASN1_BIT_STRING *psig = NULL;
+
+ X509_NAME_print_ex(mem, X509_get_subject_name(x), 0, XN_FLAG_ONELINE);
+ push_certinfo("Subject", i);
+
+ X509_NAME_print_ex(mem, X509_get_issuer_name(x), 0, XN_FLAG_ONELINE);
+ push_certinfo("Issuer", i);
+
+ BIO_printf(mem, "%lx", X509_get_version(x));
+ push_certinfo("Version", i);
+
+ num = X509_get_serialNumber(x);
+ if(num->type == V_ASN1_NEG_INTEGER)
+ BIO_puts(mem, "-");
+ for(j = 0; j < num->length; j++)
+ BIO_printf(mem, "%02x", num->data[j]);
+ push_certinfo("Serial Number", i);
+
+#if defined(HAVE_X509_GET0_SIGNATURE) && defined(HAVE_X509_GET0_EXTENSIONS)
+ {
+ const X509_ALGOR *palg = NULL;
+ ASN1_STRING *a = ASN1_STRING_new();
+ if(a) {
+ X509_get0_signature(&psig, &palg, x);
+ X509_signature_print(mem, palg, a);
+ ASN1_STRING_free(a);
+
+ if(palg) {
+ i2a_ASN1_OBJECT(mem, palg->algorithm);
+ push_certinfo("Public Key Algorithm", i);
+ }
+ }
+ X509V3_ext(data, i, X509_get0_extensions(x));
+ }
+#else
+ {
+ /* before OpenSSL 1.0.2 */
+ X509_CINF *cinf = x->cert_info;
+
+ i2a_ASN1_OBJECT(mem, cinf->signature->algorithm);
+ push_certinfo("Signature Algorithm", i);
+
+ i2a_ASN1_OBJECT(mem, cinf->key->algor->algorithm);
+ push_certinfo("Public Key Algorithm", i);
+
+ X509V3_ext(data, i, cinf->extensions);
+
+ psig = x->signature;
+ }
+#endif
+
+ ASN1_TIME_print(mem, X509_get0_notBefore(x));
+ push_certinfo("Start date", i);
+
+ ASN1_TIME_print(mem, X509_get0_notAfter(x));
+ push_certinfo("Expire date", i);
+
+ pubkey = X509_get_pubkey(x);
+ if(!pubkey)
+ infof(data, " Unable to load public key\n");
+ else {
+ int pktype;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ pktype = EVP_PKEY_id(pubkey);
+#else
+ pktype = pubkey->type;
+#endif
+ switch(pktype) {
+ case EVP_PKEY_RSA:
+ {
+ RSA *rsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ rsa = EVP_PKEY_get0_RSA(pubkey);
+#else
+ rsa = pubkey->pkey.rsa;
+#endif
+
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ {
+ const BIGNUM *n;
+ const BIGNUM *e;
+
+ RSA_get0_key(rsa, &n, &e, NULL);
+ BN_print(mem, n);
+ push_certinfo("RSA Public Key", i);
+ print_pubkey_BN(rsa, n, i);
+ print_pubkey_BN(rsa, e, i);
+ }
+#else
+ BIO_printf(mem, "%d", BN_num_bits(rsa->n));
+ push_certinfo("RSA Public Key", i);
+ print_pubkey_BN(rsa, n, i);
+ print_pubkey_BN(rsa, e, i);
+#endif
+
+ break;
+ }
+ case EVP_PKEY_DSA:
+ {
+#ifndef OPENSSL_NO_DSA
+ DSA *dsa;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ dsa = EVP_PKEY_get0_DSA(pubkey);
+#else
+ dsa = pubkey->pkey.dsa;
+#endif
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ {
+ const BIGNUM *p;
+ const BIGNUM *q;
+ const BIGNUM *g;
+ const BIGNUM *pub_key;
+
+ DSA_get0_pqg(dsa, &p, &q, &g);
+ DSA_get0_key(dsa, &pub_key, NULL);
+
+ print_pubkey_BN(dsa, p, i);
+ print_pubkey_BN(dsa, q, i);
+ print_pubkey_BN(dsa, g, i);
+ print_pubkey_BN(dsa, pub_key, i);
+ }
+#else
+ print_pubkey_BN(dsa, p, i);
+ print_pubkey_BN(dsa, q, i);
+ print_pubkey_BN(dsa, g, i);
+ print_pubkey_BN(dsa, pub_key, i);
+#endif
+#endif /* !OPENSSL_NO_DSA */
+ break;
+ }
+ case EVP_PKEY_DH:
+ {
+ DH *dh;
+#ifdef HAVE_OPAQUE_EVP_PKEY
+ dh = EVP_PKEY_get0_DH(pubkey);
+#else
+ dh = pubkey->pkey.dh;
+#endif
+#ifdef HAVE_OPAQUE_RSA_DSA_DH
+ {
+ const BIGNUM *p;
+ const BIGNUM *q;
+ const BIGNUM *g;
+ const BIGNUM *pub_key;
+ DH_get0_pqg(dh, &p, &q, &g);
+ DH_get0_key(dh, &pub_key, NULL);
+ print_pubkey_BN(dh, p, i);
+ print_pubkey_BN(dh, q, i);
+ print_pubkey_BN(dh, g, i);
+ print_pubkey_BN(dh, pub_key, i);
+ }
+#else
+ print_pubkey_BN(dh, p, i);
+ print_pubkey_BN(dh, g, i);
+ print_pubkey_BN(dh, pub_key, i);
+#endif
+ break;
+ }
+#if 0
+ case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
+ /* left TODO */
+ break;
+#endif
+ }
+ EVP_PKEY_free(pubkey);
+ }
+
+ if(psig) {
+ for(j = 0; j < psig->length; j++)
+ BIO_printf(mem, "%02x:", psig->data[j]);
+ push_certinfo("Signature", i);
+ }
+
+ PEM_write_bio_X509(mem, x);
+ push_certinfo("Cert", i);
+ }
+
+ BIO_free(mem);
+
+ return CURLE_OK;
+}
+
+/*
+ * Heavily modified from:
+ * https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#OpenSSL
+ */
+static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert,
+ const char *pinnedpubkey)
+{
+ /* Scratch */
+ int len1 = 0, len2 = 0;
+ unsigned char *buff1 = NULL, *temp = NULL;
+
+ /* Result is returned to caller */
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+
+ /* if a path wasn't specified, don't pin */
+ if(!pinnedpubkey)
+ return CURLE_OK;
+
+ if(!cert)
+ return result;
+
+ do {
+ /* Begin Gyrations to get the subjectPublicKeyInfo */
+ /* Thanks to Viktor Dukhovni on the OpenSSL mailing list */
+
+ /* https://groups.google.com/group/mailing.openssl.users/browse_thread
+ /thread/d61858dae102c6c7 */
+ len1 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
+ if(len1 < 1)
+ break; /* failed */
+
+ /* https://www.openssl.org/docs/crypto/buffer.html */
+ buff1 = temp = malloc(len1);
+ if(!buff1)
+ break; /* failed */
+
+ /* https://www.openssl.org/docs/crypto/d2i_X509.html */
+ len2 = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &temp);
+
+ /*
+ * These checks are verifying we got back the same values as when we
+ * sized the buffer. It's pretty weak since they should always be the
+ * same. But it gives us something to test.
+ */
+ if((len1 != len2) || !temp || ((temp - buff1) != len1))
+ break; /* failed */
+
+ /* End Gyrations */
+
+ /* The one good exit point */
+ result = Curl_pin_peer_pubkey(data, pinnedpubkey, buff1, len1);
+ } while(0);
+
+ /* https://www.openssl.org/docs/crypto/buffer.html */
+ if(buff1)
+ free(buff1);
+
+ return result;
+}
+
+/*
+ * Get the server cert, verify it and show it etc, only call failf() if the
+ * 'strict' argument is TRUE as otherwise all this is for informational
+ * purposes only!
+ *
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack.
+ */
+static CURLcode servercert(struct connectdata *conn,
+ struct ssl_connect_data *connssl,
+ bool strict)
+{
+ CURLcode result = CURLE_OK;
+ int rc;
+ long lerr, len;
+ struct Curl_easy *data = conn->data;
+ X509 *issuer;
+ FILE *fp;
+ char buffer[2048];
+ const char *ptr;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+ BIO *mem = BIO_new(BIO_s_mem());
+
+ if(data->set.ssl.certinfo)
+ /* we've been asked to gather certificate info! */
+ (void)get_cert_chain(conn, connssl);
+
+ connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+ if(!connssl->server_cert) {
+ BIO_free(mem);
+ if(!strict)
+ return CURLE_OK;
+
+ failf(data, "SSL: couldn't get peer certificate!");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ infof(data, "%s certificate:\n", SSL_IS_PROXY() ? "Proxy" : "Server");
+
+ rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
+ buffer, sizeof(buffer));
+ infof(data, " subject: %s\n", rc?"[NONE]":buffer);
+
+ ASN1_TIME_print(mem, X509_get0_notBefore(connssl->server_cert));
+ len = BIO_get_mem_data(mem, (char **) &ptr);
+ infof(data, " start date: %.*s\n", len, ptr);
+ rc = BIO_reset(mem);
+
+ ASN1_TIME_print(mem, X509_get0_notAfter(connssl->server_cert));
+ len = BIO_get_mem_data(mem, (char **) &ptr);
+ infof(data, " expire date: %.*s\n", len, ptr);
+ rc = BIO_reset(mem);
+
+ BIO_free(mem);
+
+ if(SSL_CONN_CONFIG(verifyhost)) {
+ result = verifyhost(conn, connssl->server_cert);
+ if(result) {
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return result;
+ }
+ }
+
+ rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
+ buffer, sizeof(buffer));
+ if(rc) {
+ if(strict)
+ failf(data, "SSL: couldn't get X509-issuer name!");
+ result = CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ infof(data, " issuer: %s\n", buffer);
+
+ /* We could do all sorts of certificate verification stuff here before
+ deallocating the certificate. */
+
+ /* e.g. match issuer name with provided issuer certificate */
+ if(SSL_SET_OPTION(issuercert)) {
+ fp = fopen(SSL_SET_OPTION(issuercert), FOPEN_READTEXT);
+ if(!fp) {
+ if(strict)
+ failf(data, "SSL: Unable to open issuer cert (%s)",
+ SSL_SET_OPTION(issuercert));
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+
+ issuer = PEM_read_X509(fp, NULL, ZERO_NULL, NULL);
+ if(!issuer) {
+ if(strict)
+ failf(data, "SSL: Unable to read issuer cert (%s)",
+ SSL_SET_OPTION(issuercert));
+ X509_free(connssl->server_cert);
+ X509_free(issuer);
+ fclose(fp);
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+
+ fclose(fp);
+
+ if(X509_check_issued(issuer, connssl->server_cert) != X509_V_OK) {
+ if(strict)
+ failf(data, "SSL: Certificate issuer check failed (%s)",
+ SSL_SET_OPTION(issuercert));
+ X509_free(connssl->server_cert);
+ X509_free(issuer);
+ connssl->server_cert = NULL;
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+
+ infof(data, " SSL certificate issuer check ok (%s)\n",
+ SSL_SET_OPTION(issuercert));
+ X509_free(issuer);
+ }
+
+ lerr = *certverifyresult = SSL_get_verify_result(connssl->handle);
+
+ if(*certverifyresult != X509_V_OK) {
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ /* We probably never reach this, because SSL_connect() will fail
+ and we return earlier if verifypeer is set? */
+ if(strict)
+ failf(data, "SSL certificate verify result: %s (%ld)",
+ X509_verify_cert_error_string(lerr), lerr);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, " SSL certificate verify result: %s (%ld),"
+ " continuing anyway.\n",
+ X509_verify_cert_error_string(lerr), lerr);
+ }
+ else
+ infof(data, " SSL certificate verify ok.\n");
+ }
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_NO_OCSP)
+ if(SSL_CONN_CONFIG(verifystatus)) {
+ result = verifystatus(conn, connssl);
+ if(result) {
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return result;
+ }
+ }
+#endif
+
+ if(!strict)
+ /* when not strict, we don't bother about the verify cert problems */
+ result = CURLE_OK;
+
+ ptr = SSL_IS_PROXY() ? data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ if(!result && ptr) {
+ result = pkp_pin_peer_pubkey(data, connssl->server_cert, ptr);
+ if(result)
+ failf(data, "SSL: public key does not match pinned public key!");
+ }
+
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ connssl->connecting_state = ssl_connect_done;
+
+ return result;
+}
+
+static CURLcode ossl_connect_step3(struct connectdata *conn, int sockindex)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ SSL_SESSION *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+
+ our_ssl_sessionid = SSL_get1_session(connssl->handle);
+
+ /* SSL_get1_session() will increment the reference count and the session
+ will stay in memory until explicitly freed with SSL_SESSION_free(3),
+ regardless of its state. */
+
+ Curl_ssl_sessionid_lock(conn);
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL,
+ sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+
+ if(!incache) {
+ result = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+ 0 /* unknown size */, sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "failed to store ssl session");
+ return result;
+ }
+ }
+ else {
+ /* Session was incache, so refcount already incremented earlier.
+ * Avoid further increments with each SSL_get1_session() call.
+ * This does not free the session as refcount remains > 0
+ */
+ SSL_SESSION_free(our_ssl_sessionid);
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ /*
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
+ * verify the peer ignore faults and failures from the server cert
+ * operations.
+ */
+
+ result = servercert(conn, connssl, (SSL_CONN_CONFIG(verifypeer) ||
+ SSL_CONN_CONFIG(verifyhost)));
+
+ if(!result)
+ connssl->connecting_state = ssl_connect_done;
+
+ return result;
+}
+
+static Curl_recv ossl_recv;
+static Curl_send ossl_send;
+
+static CURLcode ossl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ time_t timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1 == connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = ossl_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if this
+ * connection is done nonblocking and this loop would execute again. This
+ * permits the owner of a multi handle to abort a connection attempt
+ * before step2 has completed while ensuring that a client using select()
+ * or epoll() will always have a valid fdset to wait on.
+ */
+ result = ossl_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = ossl_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = ossl_recv;
+ conn->send[sockindex] = ossl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return ossl_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = ossl_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+bool Curl_ossl_data_pending(const struct connectdata *conn, int connindex)
+{
+ if(conn->ssl[connindex].handle)
+ /* SSL is in use */
+ return (0 != SSL_pending(conn->ssl[connindex].handle) ||
+ (conn->proxy_ssl[connindex].handle &&
+ 0 != SSL_pending(conn->proxy_ssl[connindex].handle))) ?
+ TRUE : FALSE;
+ return FALSE;
+}
+
+static ssize_t ossl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ /* SSL_write() is said to return 'int' while write() and send() returns
+ 'size_t' */
+ int err;
+ char error_buffer[256];
+ unsigned long sslerror;
+ int memlen;
+ int rc;
+
+ ERR_clear_error();
+
+ memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+
+ if(rc <= 0) {
+ err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* The operation did not complete; the same TLS/SSL I/O function
+ should be called again later. This is basically an EWOULDBLOCK
+ equivalent. */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ case SSL_ERROR_SYSCALL:
+ failf(conn->data, "SSL_write() returned SYSCALL, errno = %d",
+ SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ case SSL_ERROR_SSL:
+ /* A failure in the SSL library occurred, usually a protocol error.
+ The OpenSSL error queue contains more information on the error. */
+ sslerror = ERR_get_error();
+ if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
+ ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
+ conn->ssl[sockindex].state == ssl_connection_complete &&
+ conn->proxy_ssl[sockindex].state == ssl_connection_complete) {
+ char ver[120];
+ Curl_ossl_version(ver, 120);
+ failf(conn->data, "Error: %s does not support double SSL tunneling.",
+ ver);
+ }
+ else
+ failf(conn->data, "SSL_write() error: %s",
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)));
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ /* a true error */
+ failf(conn->data, OSSL_PACKAGE " SSL_write: %s, errno %d",
+ SSL_ERROR_to_str(err), SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ *curlcode = CURLE_OK;
+ return (ssize_t)rc; /* number of bytes */
+}
+
+static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ char error_buffer[256];
+ unsigned long sslerror;
+ ssize_t nread;
+ int buffsize;
+
+ ERR_clear_error();
+
+ buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
+ if(nread <= 0) {
+ /* failed SSL_read */
+ int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
+
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_read() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
+ value/errno" */
+ /* https://www.openssl.org/docs/crypto/ERR_get_error.html */
+ sslerror = ERR_get_error();
+ if((nread < 0) || sslerror) {
+ /* If the return code was negative or there actually is an error in the
+ queue */
+ failf(conn->data, OSSL_PACKAGE " SSL_read: %s, errno %d",
+ (sslerror ?
+ ossl_strerror(sslerror, error_buffer, sizeof(error_buffer)) :
+ SSL_ERROR_to_str(err)),
+ SOCKERRNO);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ }
+ return nread;
+}
+
+size_t Curl_ossl_version(char *buffer, size_t size)
+{
+#ifdef OPENSSL_IS_BORINGSSL
+ return snprintf(buffer, size, OSSL_PACKAGE);
+#else /* OPENSSL_IS_BORINGSSL */
+ char sub[3];
+ unsigned long ssleay_value;
+ sub[2]='\0';
+ sub[1]='\0';
+ ssleay_value=OpenSSL_version_num();
+ if(ssleay_value < 0x906000) {
+ ssleay_value=SSLEAY_VERSION_NUMBER;
+ sub[0]='\0';
+ }
+ else {
+ if(ssleay_value&0xff0) {
+ int minor_ver = (ssleay_value >> 4) & 0xff;
+ if(minor_ver > 26) {
+ /* handle extended version introduced for 0.9.8za */
+ sub[1] = (char) ((minor_ver - 1) % 26 + 'a' + 1);
+ sub[0] = 'z';
+ }
+ else {
+ sub[0] = (char) (minor_ver + 'a' - 1);
+ }
+ }
+ else
+ sub[0]='\0';
+ }
+
+ return snprintf(buffer, size, "%s/%lx.%lx.%lx%s",
+ OSSL_PACKAGE,
+ (ssleay_value>>28)&0xf,
+ (ssleay_value>>20)&0xff,
+ (ssleay_value>>12)&0xff,
+ sub);
+#endif /* OPENSSL_IS_BORINGSSL */
+}
+
+/* can be called with data == NULL */
+CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length)
+{
+ int rc;
+ if(data) {
+ if(Curl_ossl_seed(data)) /* Initiate the seed if not already done */
+ return CURLE_FAILED_INIT; /* couldn't seed for some reason */
+ }
+ else {
+ if(!rand_enough())
+ return CURLE_FAILED_INIT;
+ }
+ /* RAND_bytes() returns 1 on success, 0 otherwise. */
+ rc = RAND_bytes(entropy, curlx_uztosi(length));
+ return (rc == 1 ? CURLE_OK : CURLE_FAILED_INIT);
+}
+
+void Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused)
+{
+ MD5_CTX MD5pw;
+ (void)unused;
+ MD5_Init(&MD5pw);
+ MD5_Update(&MD5pw, tmp, tmplen);
+ MD5_Final(md5sum, &MD5pw);
+}
+
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused)
+{
+ SHA256_CTX SHA256pw;
+ (void)unused;
+ SHA256_Init(&SHA256pw);
+ SHA256_Update(&SHA256pw, tmp, tmplen);
+ SHA256_Final(sha256sum, &SHA256pw);
+}
+#endif
+
+bool Curl_ossl_cert_status_request(void)
+{
+#if (OPENSSL_VERSION_NUMBER >= 0x0090808fL) && !defined(OPENSSL_NO_TLSEXT) && \
+ !defined(OPENSSL_NO_OCSP)
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+#endif /* USE_OPENSSL */
diff --git a/Utilities/cmcurl/lib/vtls/openssl.h b/Utilities/cmcurl/lib/vtls/openssl.h
new file mode 100644
index 000000000..b9648d514
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/openssl.h
@@ -0,0 +1,126 @@
+#ifndef HEADER_CURL_SSLUSE_H
+#define HEADER_CURL_SSLUSE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef USE_OPENSSL
+/*
+ * This header should only be needed to get included by vtls.c and openssl.c
+ */
+
+#include "urldata.h"
+
+CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* close a SSL connection */
+void Curl_ossl_close(struct connectdata *conn, int sockindex);
+
+/* tell OpenSSL to close down all open information regarding connections (and
+ thus session ID caching etc) */
+void Curl_ossl_close_all(struct Curl_easy *data);
+
+/* Sets an OpenSSL engine */
+CURLcode Curl_ossl_set_engine(struct Curl_easy *data, const char *engine);
+
+/* function provided for the generic SSL-layer, called when a session id
+ should be freed */
+void Curl_ossl_session_free(void *ptr);
+
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ossl_set_engine_default(struct Curl_easy *data);
+
+/* Build list of OpenSSL engines */
+struct curl_slist *Curl_ossl_engines_list(struct Curl_easy *data);
+
+int Curl_ossl_init(void);
+void Curl_ossl_cleanup(void);
+
+size_t Curl_ossl_version(char *buffer, size_t size);
+int Curl_ossl_check_cxn(struct connectdata *cxn);
+int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
+bool Curl_ossl_data_pending(const struct connectdata *conn,
+ int connindex);
+
+/* return 0 if a find random is filled in */
+CURLcode Curl_ossl_random(struct Curl_easy *data, unsigned char *entropy,
+ size_t length);
+void Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused);
+void Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *sha256sum /* output */,
+ size_t unused);
+
+bool Curl_ossl_cert_status_request(void);
+
+/* Support HTTPS-proxy */
+#define HTTPS_PROXY_SUPPORT 1
+
+/* Set the API backend definition to OpenSSL */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_OPENSSL
+
+/* this backend supports the CAPATH option */
+#define have_curlssl_ca_path 1
+
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
+/* this backend supports CURLOPT_SSL_CTX_* */
+#define have_curlssl_ssl_ctx 1
+
+/* this backend supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* API setup for OpenSSL */
+#define curlssl_init Curl_ossl_init
+#define curlssl_cleanup Curl_ossl_cleanup
+#define curlssl_connect Curl_ossl_connect
+#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking
+#define curlssl_session_free(x) Curl_ossl_session_free(x)
+#define curlssl_close_all Curl_ossl_close_all
+#define curlssl_close Curl_ossl_close
+#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y)
+#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y)
+#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x)
+#define curlssl_engines_list(x) Curl_ossl_engines_list(x)
+#define curlssl_version Curl_ossl_version
+#define curlssl_check_cxn Curl_ossl_check_cxn
+#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
+#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+#define curlssl_sha256sum(a,b,c,d) Curl_ossl_sha256sum(a,b,c,d)
+#endif
+#define curlssl_cert_status_request() Curl_ossl_cert_status_request()
+
+#define DEFAULT_CIPHER_SELECTION \
+ "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
+
+#endif /* USE_OPENSSL */
+#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/Utilities/cmcurl/lib/vtls/polarssl.c b/Utilities/cmcurl/lib/vtls/polarssl.c
new file mode 100644
index 000000000..669091cb5
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/polarssl.c
@@ -0,0 +1,873 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_POLARSSL
+
+#include <polarssl/net.h>
+#include <polarssl/ssl.h>
+#include <polarssl/certs.h>
+#include <polarssl/x509.h>
+#include <polarssl/version.h>
+#include <polarssl/sha256.h>
+
+#if POLARSSL_VERSION_NUMBER < 0x01030000
+#error too old PolarSSL
+#endif
+
+#include <polarssl/error.h>
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "polarssl.h"
+#include "vtls.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "strcase.h"
+#include "polarssl_threadlock.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* See https://tls.mbed.org/discussions/generic/
+ howto-determine-exact-buffer-len-for-mbedtls_pk_write_pubkey_der
+*/
+#define RSA_PUB_DER_MAX_BYTES (38 + 2 * POLARSSL_MPI_MAX_SIZE)
+#define ECP_PUB_DER_MAX_BYTES (30 + 2 * POLARSSL_ECP_MAX_BYTES)
+
+#define PUB_DER_MAX_BYTES (RSA_PUB_DER_MAX_BYTES > ECP_PUB_DER_MAX_BYTES ? \
+ RSA_PUB_DER_MAX_BYTES : ECP_PUB_DER_MAX_BYTES)
+
+/* apply threading? */
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#define THREADING_SUPPORT
+#endif
+
+#ifndef POLARSSL_ERROR_C
+#define error_strerror(x,y,z)
+#endif /* POLARSSL_ERROR_C */
+
+
+#if defined(THREADING_SUPPORT)
+static entropy_context entropy;
+
+static int entropy_init_initialized = 0;
+
+/* start of entropy_init_mutex() */
+static void entropy_init_mutex(entropy_context *ctx)
+{
+ /* lock 0 = entropy_init_mutex() */
+ Curl_polarsslthreadlock_lock_function(0);
+ if(entropy_init_initialized == 0) {
+ entropy_init(ctx);
+ entropy_init_initialized = 1;
+ }
+ Curl_polarsslthreadlock_unlock_function(0);
+}
+/* end of entropy_init_mutex() */
+
+/* start of entropy_func_mutex() */
+static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
+{
+ int ret;
+ /* lock 1 = entropy_func_mutex() */
+ Curl_polarsslthreadlock_lock_function(1);
+ ret = entropy_func(data, output, len);
+ Curl_polarsslthreadlock_unlock_function(1);
+
+ return ret;
+}
+/* end of entropy_func_mutex() */
+
+#endif /* THREADING_SUPPORT */
+
+/* Define this to enable lots of debugging for PolarSSL */
+#undef POLARSSL_DEBUG
+
+#ifdef POLARSSL_DEBUG
+static void polarssl_debug(void *context, int level, const char *line)
+{
+ struct Curl_easy *data = NULL;
+
+ if(!context)
+ return;
+
+ data = (struct Curl_easy *)context;
+
+ infof(data, "%s", line);
+ (void) level;
+}
+#else
+#endif
+
+/* ALPN for http2? */
+#ifdef POLARSSL_SSL_ALPN
+# define HAS_ALPN
+#endif
+
+static Curl_recv polarssl_recv;
+static Curl_send polarssl_send;
+
+static CURLcode polarssl_version_from_curl(int *polarver, long ssl_version)
+{
+ switch(ssl_version) {
+ case CURL_SSLVERSION_TLSv1_0:
+ *polarver = SSL_MINOR_VERSION_1;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_1:
+ *polarver = SSL_MINOR_VERSION_2;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_2:
+ *polarver = SSL_MINOR_VERSION_3;
+ return CURLE_OK;
+ case CURL_SSLVERSION_TLSv1_3:
+ break;
+ }
+ return CURLE_SSL_CONNECT_ERROR;
+}
+
+static CURLcode
+set_ssl_version_min_max(struct connectdata *conn, int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ int ssl_min_ver = SSL_MINOR_VERSION_1;
+ int ssl_max_ver = SSL_MINOR_VERSION_1;
+ CURLcode result = CURLE_OK;
+
+ switch(ssl_version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ssl_version = CURL_SSLVERSION_TLSv1_0;
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version << 16;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+
+ result = polarssl_version_from_curl(&ssl_min_ver, ssl_version);
+ if(result) {
+ failf(data, "unsupported min version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+ result = polarssl_version_from_curl(&ssl_max_ver, ssl_version_max >> 16);
+ if(result) {
+ failf(data, "unsupported max version passed via CURLOPT_SSLVERSION");
+ return result;
+ }
+
+ ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_min_ver);
+ ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3, ssl_max_ver);
+
+ return result;
+}
+
+static CURLcode
+polarssl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ const char *capath = SSL_CONN_CONFIG(CApath);
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+ const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+ int ret = -1;
+ char errorbuf[128];
+ errorbuf[0]=0;
+
+ /* PolarSSL only supports SSLv3 and TLSv1 */
+ if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
+ failf(data, "PolarSSL does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef THREADING_SUPPORT
+ entropy_init_mutex(&entropy);
+
+ if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy,
+ NULL, 0)) != 0) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#else
+ entropy_init(&connssl->entropy);
+
+ if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy,
+ NULL, 0)) != 0) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#endif /* THREADING_SUPPORT */
+
+ /* Load the trusted CA */
+ memset(&connssl->cacert, 0, sizeof(x509_crt));
+
+ if(SSL_CONN_CONFIG(CAfile)) {
+ ret = x509_crt_parse_file(&connssl->cacert,
+ SSL_CONN_CONFIG(CAfile));
+
+ if(ret<0) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s",
+ SSL_CONN_CONFIG(CAfile), -ret, errorbuf);
+
+ if(SSL_CONN_CONFIG(verifypeer))
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ if(capath) {
+ ret = x509_crt_parse_path(&connssl->cacert, capath);
+
+ if(ret<0) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error reading ca cert path %s - PolarSSL: (-0x%04X) %s",
+ capath, -ret, errorbuf);
+
+ if(SSL_CONN_CONFIG(verifypeer))
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ /* Load the client certificate */
+ memset(&connssl->clicert, 0, sizeof(x509_crt));
+
+ if(SSL_SET_OPTION(cert)) {
+ ret = x509_crt_parse_file(&connssl->clicert,
+ SSL_SET_OPTION(cert));
+
+ if(ret) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s",
+ SSL_SET_OPTION(cert), -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the client private key */
+ if(SSL_SET_OPTION(key)) {
+ pk_context pk;
+ pk_init(&pk);
+ ret = pk_parse_keyfile(&pk, SSL_SET_OPTION(key),
+ SSL_SET_OPTION(key_passwd));
+ if(ret == 0 && !pk_can_do(&pk, POLARSSL_PK_RSA))
+ ret = POLARSSL_ERR_PK_TYPE_MISMATCH;
+ if(ret == 0)
+ rsa_copy(&connssl->rsa, pk_rsa(pk));
+ else
+ rsa_free(&connssl->rsa);
+ pk_free(&pk);
+
+ if(ret) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s",
+ SSL_SET_OPTION(key), -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the CRL */
+ memset(&connssl->crl, 0, sizeof(x509_crl));
+
+ if(SSL_SET_OPTION(CRLfile)) {
+ ret = x509_crl_parse_file(&connssl->crl,
+ SSL_SET_OPTION(CRLfile));
+
+ if(ret) {
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s",
+ SSL_SET_OPTION(CRLfile), -ret, errorbuf);
+
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ }
+
+ infof(data, "PolarSSL: Connecting to %s:%d\n", hostname, port);
+
+ if(ssl_init(&connssl->ssl)) {
+ failf(data, "PolarSSL: ssl_init failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ switch(SSL_CONN_CONFIG(version)) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ SSL_MINOR_VERSION_1);
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ ssl_set_min_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ SSL_MINOR_VERSION_0);
+ ssl_set_max_version(&connssl->ssl, SSL_MAJOR_VERSION_3,
+ SSL_MINOR_VERSION_0);
+ infof(data, "PolarSSL: Forced min. SSL Version to be SSLv3\n");
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ CURLcode result = set_ssl_version_min_max(conn, sockindex);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT);
+ ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL);
+
+ ssl_set_rng(&connssl->ssl, ctr_drbg_random,
+ &connssl->ctr_drbg);
+ ssl_set_bio(&connssl->ssl,
+ net_recv, &conn->sock[sockindex],
+ net_send, &conn->sock[sockindex]);
+
+ ssl_set_ciphersuites(&connssl->ssl, ssl_list_ciphersuites());
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ void *old_session = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &old_session, NULL, sockindex)) {
+ ret = ssl_set_session(&connssl->ssl, old_session);
+ if(ret) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "ssl_set_session returned -0x%x", -ret);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ infof(data, "PolarSSL re-using session\n");
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ ssl_set_ca_chain(&connssl->ssl,
+ &connssl->cacert,
+ &connssl->crl,
+ hostname);
+
+ ssl_set_own_cert_rsa(&connssl->ssl,
+ &connssl->clicert, &connssl->rsa);
+
+ if(ssl_set_hostname(&connssl->ssl, hostname)) {
+ /* ssl_set_hostname() sets the name to use in CN/SAN checks *and* the name
+ to set in the SNI extension. So even if curl connects to a host
+ specified as an IP address, this function must be used. */
+ failf(data, "couldn't set hostname in PolarSSL");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ static const char *protocols[3];
+ int cur = 0;
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
+ infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ protocols[cur++] = ALPN_HTTP_1_1;
+ infof(data, "ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ protocols[cur] = NULL;
+
+ ssl_set_alpn_protocols(&connssl->ssl, protocols);
+ }
+#endif
+
+#ifdef POLARSSL_DEBUG
+ ssl_set_dbg(&connssl->ssl, polarssl_debug, data);
+#endif
+
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+polarssl_connect_step2(struct connectdata *conn,
+ int sockindex)
+{
+ int ret;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ char buffer[1024];
+ const char * const pinnedpubkey = SSL_IS_PROXY() ?
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+
+
+ char errorbuf[128];
+ errorbuf[0] = 0;
+
+ conn->recv[sockindex] = polarssl_recv;
+ conn->send[sockindex] = polarssl_send;
+
+ ret = ssl_handshake(&connssl->ssl);
+
+ switch(ret) {
+ case 0:
+ break;
+
+ case POLARSSL_ERR_NET_WANT_READ:
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+
+ case POLARSSL_ERR_NET_WANT_WRITE:
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+
+ default:
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s",
+ -ret, errorbuf);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
+ ssl_get_ciphersuite(&conn->ssl[sockindex].ssl) );
+
+ ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+
+ if(ret && SSL_CONN_CONFIG(verifypeer)) {
+ if(ret & BADCERT_EXPIRED)
+ failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+ if(ret & BADCERT_REVOKED) {
+ failf(data, "Cert verify failed: BADCERT_REVOKED");
+ return CURLE_SSL_CACERT;
+ }
+
+ if(ret & BADCERT_CN_MISMATCH)
+ failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+ if(ret & BADCERT_NOT_TRUSTED)
+ failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(ssl_get_peer_cert(&(connssl->ssl))) {
+ /* If the session was resumed, there will be no peer certs */
+ memset(buffer, 0, sizeof(buffer));
+
+ if(x509_crt_info(buffer, sizeof(buffer), (char *)"* ",
+ ssl_get_peer_cert(&(connssl->ssl))) != -1)
+ infof(data, "Dumping cert info:\n%s\n", buffer);
+ }
+
+ /* adapted from mbedtls.c */
+ if(pinnedpubkey) {
+ int size;
+ CURLcode result;
+ x509_crt *p;
+ unsigned char pubkey[PUB_DER_MAX_BYTES];
+ const x509_crt *peercert;
+
+ peercert = ssl_get_peer_cert(&connssl->ssl);
+
+ if(!peercert || !peercert->raw.p || !peercert->raw.len) {
+ failf(data, "Failed due to missing peer certificate");
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ p = calloc(1, sizeof(*p));
+
+ if(!p)
+ return CURLE_OUT_OF_MEMORY;
+
+ x509_crt_init(p);
+
+ /* Make a copy of our const peercert because pk_write_pubkey_der
+ needs a non-const key, for now.
+ https://github.com/ARMmbed/mbedtls/issues/396 */
+ if(x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) {
+ failf(data, "Failed copying peer certificate");
+ x509_crt_free(p);
+ free(p);
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ size = pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES);
+
+ if(size <= 0) {
+ failf(data, "Failed copying public key from peer certificate");
+ x509_crt_free(p);
+ free(p);
+ return CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+ }
+
+ /* pk_write_pubkey_der writes data at the end of the buffer. */
+ result = Curl_pin_peer_pubkey(data,
+ pinnedpubkey,
+ &pubkey[PUB_DER_MAX_BYTES - size], size);
+ if(result) {
+ x509_crt_free(p);
+ free(p);
+ return result;
+ }
+
+ x509_crt_free(p);
+ free(p);
+ }
+
+#ifdef HAS_ALPN
+ if(conn->bits.tls_enable_alpn) {
+ const char *next_protocol = ssl_get_alpn_protocol(&connssl->ssl);
+
+ if(next_protocol != NULL) {
+ infof(data, "ALPN, server accepted to use %s\n", next_protocol);
+
+#ifdef USE_NGHTTP2
+ if(!strncmp(next_protocol, NGHTTP2_PROTO_VERSION_ID,
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(!strncmp(next_protocol, ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+ else
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ }
+#endif
+
+ connssl->connecting_state = ssl_connect_3;
+ infof(data, "SSL connected\n");
+
+ return CURLE_OK;
+}
+
+static CURLcode
+polarssl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct Curl_easy *data = conn->data;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ int ret;
+ ssl_session *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
+
+ our_ssl_sessionid = malloc(sizeof(ssl_session));
+ if(!our_ssl_sessionid)
+ return CURLE_OUT_OF_MEMORY;
+
+ memset(our_ssl_sessionid, 0, sizeof(ssl_session));
+
+ ret = ssl_get_session(&connssl->ssl, our_ssl_sessionid);
+ if(ret) {
+ failf(data, "ssl_get_session returned -0x%x", -ret);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* If there's already a matching session in the cache, delete it */
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL, sockindex))
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid, 0, sockindex);
+ Curl_ssl_sessionid_unlock(conn);
+ if(retcode) {
+ free(our_ssl_sessionid);
+ failf(data, "failed to store ssl session");
+ return retcode;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return CURLE_OK;
+}
+
+static ssize_t polarssl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+
+ ret = ssl_write(&conn->ssl[sockindex].ssl,
+ (unsigned char *)mem, len);
+
+ if(ret < 0) {
+ *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ?
+ CURLE_AGAIN : CURLE_SEND_ERROR;
+ ret = -1;
+ }
+
+ return ret;
+}
+
+void Curl_polarssl_close(struct connectdata *conn, int sockindex)
+{
+ rsa_free(&conn->ssl[sockindex].rsa);
+ x509_crt_free(&conn->ssl[sockindex].clicert);
+ x509_crt_free(&conn->ssl[sockindex].cacert);
+ x509_crl_free(&conn->ssl[sockindex].crl);
+ ssl_free(&conn->ssl[sockindex].ssl);
+}
+
+static ssize_t polarssl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+ ssize_t len = -1;
+
+ memset(buf, 0, buffersize);
+ ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize);
+
+ if(ret <= 0) {
+ if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
+ return 0;
+
+ *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ?
+ CURLE_AGAIN : CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ len = ret;
+
+ return len;
+}
+
+void Curl_polarssl_session_free(void *ptr)
+{
+ ssl_session_free(ptr);
+ free(ptr);
+}
+
+/* 1.3.10 was the first rebranded version. All new releases (in 1.3 branch and
+ higher) will be mbed TLS branded.. */
+
+size_t Curl_polarssl_version(char *buffer, size_t size)
+{
+ unsigned int version = version_get_number();
+ return snprintf(buffer, size, "%s/%d.%d.%d",
+ version >= 0x01030A00?"mbedTLS":"PolarSSL",
+ version>>24, (version>>16)&0xff, (version>>8)&0xff);
+}
+
+static CURLcode
+polarssl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1 == connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = polarssl_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading ||
+ connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ result = polarssl_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = polarssl_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = polarssl_recv;
+ conn->send[sockindex] = polarssl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_polarssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return polarssl_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_polarssl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = polarssl_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+/*
+ * return 0 error initializing SSL
+ * return 1 SSL initialized successfully
+ */
+int Curl_polarssl_init(void)
+{
+ return Curl_polarsslthreadlock_thread_setup();
+}
+
+void Curl_polarssl_cleanup(void)
+{
+ (void)Curl_polarsslthreadlock_thread_cleanup();
+}
+
+
+int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex)
+{
+ return ssl_get_bytes_avail(&conn->ssl[sockindex].ssl) != 0;
+}
+
+#endif /* USE_POLARSSL */
diff --git a/Utilities/cmcurl/lib/vtls/polarssl.h b/Utilities/cmcurl/lib/vtls/polarssl.h
new file mode 100644
index 000000000..47af7b417
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/polarssl.h
@@ -0,0 +1,82 @@
+#ifndef HEADER_CURL_POLARSSL_H
+#define HEADER_CURL_POLARSSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_POLARSSL
+
+#include <polarssl/sha256.h>
+
+/* Called on first use PolarSSL, setup threading if supported */
+int Curl_polarssl_init(void);
+void Curl_polarssl_cleanup(void);
+int Curl_polarssl_data_pending(const struct connectdata *conn, int sockindex);
+
+
+CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+ /* close a SSL connection */
+void Curl_polarssl_close(struct connectdata *conn, int sockindex);
+
+void Curl_polarssl_session_free(void *ptr);
+size_t Curl_polarssl_version(char *buffer, size_t size);
+int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
+
+/* Set the API backend definition to PolarSSL */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_POLARSSL
+
+/* this backend supports the CAPATH option */
+#define have_curlssl_ca_path 1
+
+/* this backends supports CURLOPT_PINNEDPUBLICKEY */
+#define have_curlssl_pinnedpubkey 1
+
+/* API setup for PolarSSL */
+#define curlssl_init() Curl_polarssl_init()
+#define curlssl_cleanup() Curl_polarssl_cleanup()
+#define curlssl_connect Curl_polarssl_connect
+#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking
+#define curlssl_session_free(x) Curl_polarssl_session_free(x)
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_polarssl_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_polarssl_version
+#define curlssl_check_cxn(x) ((void)x, -1)
+#define curlssl_data_pending(x,y) Curl_polarssl_data_pending(x, y)
+#define curlssl_sha256sum(a,b,c,d) sha256(a,b,c,0)
+
+/* This might cause libcurl to use a weeker random!
+ TODO: implement proper use of Polarssl's CTR-DRBG or HMAC-DRBG and use that
+*/
+#define curlssl_random(x,y,z) ((void)x, (void)y, (void)z, CURLE_NOT_BUILT_IN)
+
+#endif /* USE_POLARSSL */
+#endif /* HEADER_CURL_POLARSSL_H */
diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c
new file mode 100644
index 000000000..b1eb7b746
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.c
@@ -0,0 +1,153 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2013-2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if (defined(USE_POLARSSL) || defined(USE_MBEDTLS)) && \
+ (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32))
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#include "polarssl_threadlock.h"
+#include "curl_printf.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* number of thread locks */
+#define NUMT 2
+
+/* This array will store all of the mutexes available to PolarSSL. */
+static POLARSSL_MUTEX_T *mutex_buf = NULL;
+
+int Curl_polarsslthreadlock_thread_setup(void)
+{
+ int i;
+ int ret;
+
+ mutex_buf = calloc(NUMT * sizeof(POLARSSL_MUTEX_T), 1);
+ if(!mutex_buf)
+ return 0; /* error, no number of threads defined */
+
+#ifdef HAVE_PTHREAD_H
+ for(i = 0; i < NUMT; i++) {
+ ret = pthread_mutex_init(&mutex_buf[i], NULL);
+ if(ret)
+ return 0; /* pthread_mutex_init failed */
+ }
+#elif defined(HAVE_PROCESS_H)
+ for(i = 0; i < NUMT; i++) {
+ mutex_buf[i] = CreateMutex(0, FALSE, 0);
+ if(mutex_buf[i] == 0)
+ return 0; /* CreateMutex failed */
+ }
+#endif /* HAVE_PTHREAD_H */
+
+ return 1; /* OK */
+}
+
+int Curl_polarsslthreadlock_thread_cleanup(void)
+{
+ int i;
+ int ret;
+
+ if(!mutex_buf)
+ return 0; /* error, no threads locks defined */
+
+#ifdef HAVE_PTHREAD_H
+ for(i = 0; i < NUMT; i++) {
+ ret = pthread_mutex_destroy(&mutex_buf[i]);
+ if(ret)
+ return 0; /* pthread_mutex_destroy failed */
+ }
+#elif defined(HAVE_PROCESS_H)
+ for(i = 0; i < NUMT; i++) {
+ ret = CloseHandle(mutex_buf[i]);
+ if(!ret)
+ return 0; /* CloseHandle failed */
+ }
+#endif /* HAVE_PTHREAD_H */
+ free(mutex_buf);
+ mutex_buf = NULL;
+
+ return 1; /* OK */
+}
+
+int Curl_polarsslthreadlock_lock_function(int n)
+{
+ int ret;
+#ifdef HAVE_PTHREAD_H
+ if(n < NUMT) {
+ ret = pthread_mutex_lock(&mutex_buf[n]);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_lock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#elif defined(HAVE_PROCESS_H)
+ if(n < NUMT) {
+ ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_lock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#endif /* HAVE_PTHREAD_H */
+ return 1; /* OK */
+}
+
+int Curl_polarsslthreadlock_unlock_function(int n)
+{
+ int ret;
+#ifdef HAVE_PTHREAD_H
+ if(n < NUMT) {
+ ret = pthread_mutex_unlock(&mutex_buf[n]);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_unlock_function failed\n"));
+ return 0; /* pthread_mutex_unlock failed */
+ }
+ }
+#elif defined(HAVE_PROCESS_H)
+ if(n < NUMT) {
+ ret = ReleaseMutex(mutex_buf[n]);
+ if(!ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_unlock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#endif /* HAVE_PTHREAD_H */
+ return 1; /* OK */
+}
+
+#endif /* USE_POLARSSL || USE_MBEDTLS */
diff --git a/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h
new file mode 100644
index 000000000..dda5359b8
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/polarssl_threadlock.h
@@ -0,0 +1,53 @@
+#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H
+#define HEADER_CURL_POLARSSL_THREADLOCK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2013-2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if (defined USE_POLARSSL) || (defined USE_MBEDTLS)
+
+#if defined(USE_THREADS_POSIX)
+# define POLARSSL_MUTEX_T pthread_mutex_t
+#elif defined(USE_THREADS_WIN32)
+# define POLARSSL_MUTEX_T HANDLE
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+int Curl_polarsslthreadlock_thread_setup(void);
+int Curl_polarsslthreadlock_thread_cleanup(void);
+int Curl_polarsslthreadlock_lock_function(int n);
+int Curl_polarsslthreadlock_unlock_function(int n);
+
+#else
+
+#define Curl_polarsslthreadlock_thread_setup() 1
+#define Curl_polarsslthreadlock_thread_cleanup() 1
+#define Curl_polarsslthreadlock_lock_function(x) 1
+#define Curl_polarsslthreadlock_unlock_function(x) 1
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* USE_POLARSSL */
+
+#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.c b/Utilities/cmcurl/lib/vtls/schannel.c
new file mode 100644
index 000000000..94603018b
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/schannel.c
@@ -0,0 +1,1728 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
+ * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all SChannel-specific code for the TLS/SSL layer. No code
+ * but vtls.c should ever call or use these functions.
+ *
+ */
+
+/*
+ * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
+ * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * Thanks for code and inspiration!
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#ifndef USE_WINDOWS_SSPI
+# error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "curl_sspi.h"
+#include "schannel.h"
+#include "vtls.h"
+#include "sendf.h"
+#include "connect.h" /* for the connect timeout */
+#include "strerror.h"
+#include "select.h" /* for the socket readyness */
+#include "inet_pton.h" /* for IP addr SNI check */
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "x509asn1.h"
+#include "curl_printf.h"
+#include "system_win32.h"
+#include "hostcheck.h"
+
+ /* The last #include file should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* ALPN requires version 8.1 of the Windows SDK, which was
+ shipped with Visual Studio 2013, aka _MSC_VER 1800:
+
+ https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx
+*/
+#if defined(_MSC_VER) && (_MSC_VER >= 1800) && !defined(_USING_V110_SDK71_)
+# define HAS_ALPN 1
+#endif
+
+/* Uncomment to force verbose output
+ * #define infof(x, y, ...) printf(y, __VA_ARGS__)
+ * #define failf(x, y, ...) printf(y, __VA_ARGS__)
+ */
+
+static Curl_recv schannel_recv;
+static Curl_send schannel_send;
+
+#ifdef _WIN32_WCE
+static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
+#endif
+
+static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
+ void *BufDataPtr, unsigned long BufByteSize)
+{
+ buffer->cbBuffer = BufByteSize;
+ buffer->BufferType = BufType;
+ buffer->pvBuffer = BufDataPtr;
+}
+
+static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
+ unsigned long NumArrElem)
+{
+ desc->ulVersion = SECBUFFER_VERSION;
+ desc->pBuffers = BufArr;
+ desc->cBuffers = NumArrElem;
+}
+
+static CURLcode
+set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
+{
+ struct Curl_easy *data = conn->data;
+ long ssl_version = SSL_CONN_CONFIG(version);
+ long ssl_version_max = SSL_CONN_CONFIG(version_max);
+ long i = ssl_version;
+
+ switch(ssl_version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ ssl_version_max = ssl_version << 16;
+ break;
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
+ }
+ for(; i <= (ssl_version_max >> 16); ++i) {
+ switch(i) {
+ case CURL_SSLVERSION_TLSv1_0:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "Schannel: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step1(struct connectdata *conn, int sockindex)
+{
+ ssize_t written = -1;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SecBuffer outbuf;
+ SecBufferDesc outbuf_desc;
+ SecBuffer inbuf;
+ SecBufferDesc inbuf_desc;
+#ifdef HAS_ALPN
+ unsigned char alpn_buffer[128];
+#endif
+ SCHANNEL_CRED schannel_cred;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ struct curl_schannel_cred *old_cred = NULL;
+ struct in_addr addr;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr6;
+#endif
+ TCHAR *host_name;
+ CURLcode result;
+ char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
+ hostname, conn->remote_port);
+
+ if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
+ VERSION_LESS_THAN_EQUAL)) {
+ /* SChannel in Windows XP (OS version 5.1) uses legacy handshakes and
+ algorithms that may not be supported by all servers. */
+ infof(data, "schannel: WinSSL version is old and may not be able to "
+ "connect to some servers due to lack of SNI, algorithms, etc.\n");
+ }
+
+#ifdef HAS_ALPN
+ /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
+ Also it doesn't seem to be supported for Wine, see curl bug #983. */
+ connssl->use_alpn = conn->bits.tls_enable_alpn &&
+ !GetProcAddress(GetModuleHandleA("ntdll"),
+ "wine_get_version") &&
+ Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL);
+#else
+ connssl->use_alpn = false;
+#endif
+
+ connssl->cred = NULL;
+
+ /* check for an existing re-usable credential handle */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ Curl_ssl_sessionid_lock(conn);
+ if(!Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL, sockindex)) {
+ connssl->cred = old_cred;
+ infof(data, "schannel: re-using existing credential handle\n");
+
+ /* increment the reference counter of the credential/session handle */
+ connssl->cred->refcount++;
+ infof(data, "schannel: incremented credential handle refcount = %d\n",
+ connssl->cred->refcount);
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ if(!connssl->cred) {
+ /* setup Schannel API options */
+ memset(&schannel_cred, 0, sizeof(schannel_cred));
+ schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+
+ if(conn->ssl_config.verifypeer) {
+#ifdef _WIN32_WCE
+ /* certificate validation on CE doesn't seem to work right; we'll
+ do it following a more manual process. */
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+ SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+#else
+ schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION;
+ /* TODO s/data->set.ssl.no_revoke/SSL_SET_OPTION(no_revoke)/g */
+ if(data->set.ssl.no_revoke)
+ schannel_cred.dwFlags |= SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+ else
+ schannel_cred.dwFlags |= SCH_CRED_REVOCATION_CHECK_CHAIN;
+#endif
+ if(data->set.ssl.no_revoke)
+ infof(data, "schannel: disabled server certificate revocation "
+ "checks\n");
+ else
+ infof(data, "schannel: checking server certificate revocation\n");
+ }
+ else {
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+ SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+ infof(data, "schannel: disabled server certificate revocation checks\n");
+ }
+
+ if(!conn->ssl_config.verifyhost) {
+ schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+ infof(data, "schannel: verifyhost setting prevents Schannel from "
+ "comparing the supplied target name with the subject "
+ "names in server certificates.\n");
+ }
+
+ switch(conn->ssl_config.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
+ SP_PROT_TLS1_1_CLIENT |
+ SP_PROT_TLS1_2_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_0:
+ case CURL_SSLVERSION_TLSv1_1:
+ case CURL_SSLVERSION_TLSv1_2:
+ case CURL_SSLVERSION_TLSv1_3:
+ {
+ result = set_ssl_version_min_max(&schannel_cred, conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
+ case CURL_SSLVERSION_SSLv3:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
+ break;
+ default:
+ failf(data, "Unrecognized parameter passed via CURLOPT_SSLVERSION");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* allocate memory for the re-usable credential handle */
+ connssl->cred = (struct curl_schannel_cred *)
+ malloc(sizeof(struct curl_schannel_cred));
+ if(!connssl->cred) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
+ connssl->cred->refcount = 1;
+
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
+ */
+ sspi_status =
+ s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
+ SECPKG_CRED_OUTBOUND, NULL,
+ &schannel_cred, NULL, NULL,
+ &connssl->cred->cred_handle,
+ &connssl->cred->time_stamp);
+
+ if(sspi_status != SEC_E_OK) {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ Curl_safefree(connssl->cred);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* Warn if SNI is disabled due to use of an IP address */
+ if(Curl_inet_pton(AF_INET, hostname, &addr)
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, hostname, &addr6)
+#endif
+ ) {
+ infof(data, "schannel: using IP address, SNI is not supported by OS.\n");
+ }
+
+#ifdef HAS_ALPN
+ if(connssl->use_alpn) {
+ int cur = 0;
+ int list_start_index = 0;
+ unsigned int *extension_len = NULL;
+ unsigned short* list_len = NULL;
+
+ /* The first four bytes will be an unsigned int indicating number
+ of bytes of data in the rest of the the buffer. */
+ extension_len = (unsigned int *)(&alpn_buffer[cur]);
+ cur += sizeof(unsigned int);
+
+ /* The next four bytes are an indicator that this buffer will contain
+ ALPN data, as opposed to NPN, for example. */
+ *(unsigned int *)&alpn_buffer[cur] =
+ SecApplicationProtocolNegotiationExt_ALPN;
+ cur += sizeof(unsigned int);
+
+ /* The next two bytes will be an unsigned short indicating the number
+ of bytes used to list the preferred protocols. */
+ list_len = (unsigned short*)(&alpn_buffer[cur]);
+ cur += sizeof(unsigned short);
+
+ list_start_index = cur;
+
+#ifdef USE_NGHTTP2
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2) {
+ memcpy(&alpn_buffer[cur], NGHTTP2_PROTO_ALPN, NGHTTP2_PROTO_ALPN_LEN);
+ cur += NGHTTP2_PROTO_ALPN_LEN;
+ infof(data, "schannel: ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
+ }
+#endif
+
+ alpn_buffer[cur++] = ALPN_HTTP_1_1_LENGTH;
+ memcpy(&alpn_buffer[cur], ALPN_HTTP_1_1, ALPN_HTTP_1_1_LENGTH);
+ cur += ALPN_HTTP_1_1_LENGTH;
+ infof(data, "schannel: ALPN, offering %s\n", ALPN_HTTP_1_1);
+
+ *list_len = curlx_uitous(cur - list_start_index);
+ *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
+
+ InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
+ InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+ }
+ else
+ {
+ InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+ }
+#else /* HAS_ALPN */
+ InitSecBuffer(&inbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
+#endif
+
+ /* setup output buffer */
+ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+ /* setup request flags */
+ connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ /* allocate memory for the security context handle */
+ connssl->ctxt = (struct curl_schannel_ctxt *)
+ malloc(sizeof(struct curl_schannel_ctxt));
+ if(!connssl->ctxt) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
+
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Schannel InitializeSecurityContext:
+ https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
+
+ At the moment we don't pass inbuf unless we're using ALPN since we only
+ use it for that, and Wine (for which we currently disable ALPN) is giving
+ us problems with inbuf regardless. https://github.com/curl/curl/issues/983
+ */
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle, NULL, host_name, connssl->req_flags, 0, 0,
+ (connssl->use_alpn ? &inbuf_desc : NULL),
+ 0, &connssl->ctxt->ctxt_handle,
+ &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ Curl_safefree(connssl->ctxt);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "schannel: sending initial handshake data: "
+ "sending %lu bytes...\n", outbuf.cbBuffer);
+
+ /* send initial handshake data which is now stored in output buffer */
+ result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+ outbuf.cbBuffer, &written);
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+ failf(data, "schannel: failed to send initial handshake data: "
+ "sent %zd of %lu bytes", written, outbuf.cbBuffer);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "schannel: sent initial handshake data: "
+ "sent %zd bytes\n", written);
+
+ connssl->recv_unrecoverable_err = CURLE_OK;
+ connssl->recv_sspi_close_notify = false;
+ connssl->recv_connection_closed = false;
+ connssl->encdata_is_incomplete = false;
+
+ /* continue to second handshake step */
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step2(struct connectdata *conn, int sockindex)
+{
+ int i;
+ ssize_t nread = -1, written = -1;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ unsigned char *reallocated_buffer;
+ size_t reallocated_length;
+ SecBuffer outbuf[3];
+ SecBufferDesc outbuf_desc;
+ SecBuffer inbuf[2];
+ SecBufferDesc inbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ TCHAR *host_name;
+ CURLcode result;
+ bool doread;
+ char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
+ hostname, conn->remote_port);
+
+ if(!connssl->cred || !connssl->ctxt)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* buffer to store previously received and decrypted data */
+ if(connssl->decdata_buffer == NULL) {
+ connssl->decdata_offset = 0;
+ connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ connssl->decdata_buffer = malloc(connssl->decdata_length);
+ if(connssl->decdata_buffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* buffer to store previously received and encrypted data */
+ if(connssl->encdata_buffer == NULL) {
+ connssl->encdata_is_incomplete = false;
+ connssl->encdata_offset = 0;
+ connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ connssl->encdata_buffer = malloc(connssl->encdata_length);
+ if(connssl->encdata_buffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* if we need a bigger buffer to read a full message, increase buffer now */
+ if(connssl->encdata_length - connssl->encdata_offset <
+ CURL_SCHANNEL_BUFFER_FREE_SIZE) {
+ /* increase internal encrypted data buffer */
+ reallocated_length = connssl->encdata_offset +
+ CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ reallocated_buffer = realloc(connssl->encdata_buffer,
+ reallocated_length);
+
+ if(reallocated_buffer == NULL) {
+ failf(data, "schannel: unable to re-allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ connssl->encdata_buffer = reallocated_buffer;
+ connssl->encdata_length = reallocated_length;
+ }
+ }
+
+ for(;;) {
+ if(doread) {
+ /* read encrypted handshake data from socket */
+ result = Curl_read_plain(conn->sock[sockindex],
+ (char *) (connssl->encdata_buffer +
+ connssl->encdata_offset),
+ connssl->encdata_length -
+ connssl->encdata_offset,
+ &nread);
+ if(result == CURLE_AGAIN) {
+ if(connssl->connecting_state != ssl_connect_2_writing)
+ connssl->connecting_state = ssl_connect_2_reading;
+ infof(data, "schannel: failed to receive handshake, "
+ "need more data\n");
+ return CURLE_OK;
+ }
+ else if((result != CURLE_OK) || (nread == 0)) {
+ failf(data, "schannel: failed to receive handshake, "
+ "SSL/TLS connection failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* increase encrypted data buffer offset */
+ connssl->encdata_offset += nread;
+ connssl->encdata_is_incomplete = false;
+ infof(data, "schannel: encrypted data got %zd\n", nread);
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ /* setup input buffers */
+ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
+ curlx_uztoul(connssl->encdata_offset));
+ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&inbuf_desc, inbuf, 2);
+
+ /* setup output buffers */
+ InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
+ InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
+ InitSecBuffer(&outbuf[2], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, outbuf, 3);
+
+ if(inbuf[0].pvBuffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* copy received handshake data into input buffer */
+ memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
+ connssl->encdata_offset);
+
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
+ */
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
+ host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+ &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ /* free buffer for received handshake data */
+ Curl_safefree(inbuf[0].pvBuffer);
+
+ /* check if the handshake was incomplete */
+ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+ connssl->encdata_is_incomplete = true;
+ connssl->connecting_state = ssl_connect_2_reading;
+ infof(data, "schannel: received incomplete message, need more data\n");
+ return CURLE_OK;
+ }
+
+ /* If the server has requested a client certificate, attempt to continue
+ the handshake without one. This will allow connections to servers which
+ request a client certificate but do not require it. */
+ if(sspi_status == SEC_I_INCOMPLETE_CREDENTIALS &&
+ !(connssl->req_flags & ISC_REQ_USE_SUPPLIED_CREDS)) {
+ connssl->req_flags |= ISC_REQ_USE_SUPPLIED_CREDS;
+ connssl->connecting_state = ssl_connect_2_writing;
+ infof(data, "schannel: a client certificate has been requested\n");
+ return CURLE_OK;
+ }
+
+ /* check if the handshake needs to be continued */
+ if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
+ for(i = 0; i < 3; i++) {
+ /* search for handshake tokens that need to be send */
+ if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
+ infof(data, "schannel: sending next handshake data: "
+ "sending %lu bytes...\n", outbuf[i].cbBuffer);
+
+ /* send handshake token to server */
+ result = Curl_write_plain(conn, conn->sock[sockindex],
+ outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+ &written);
+ if((result != CURLE_OK) ||
+ (outbuf[i].cbBuffer != (size_t) written)) {
+ failf(data, "schannel: failed to send next handshake data: "
+ "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* free obsolete buffer */
+ if(outbuf[i].pvBuffer != NULL) {
+ s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
+ }
+ }
+ }
+ else {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return sspi_status == SEC_E_UNTRUSTED_ROOT ?
+ CURLE_SSL_CACERT_BADFILE : CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* check if there was additional remaining encrypted data */
+ if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
+ infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
+ /*
+ There are two cases where we could be getting extra data here:
+ 1) If we're renegotiating a connection and the handshake is already
+ complete (from the server perspective), it can encrypted app data
+ (not handshake data) in an extra buffer at this point.
+ 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
+ connection and this extra data is part of the handshake.
+ We should process the data immediately; waiting for the socket to
+ be ready may fail since the server is done sending handshake data.
+ */
+ /* check if the remaining data is less than the total amount
+ and therefore begins after the already processed data */
+ if(connssl->encdata_offset > inbuf[1].cbBuffer) {
+ memmove(connssl->encdata_buffer,
+ (connssl->encdata_buffer + connssl->encdata_offset) -
+ inbuf[1].cbBuffer, inbuf[1].cbBuffer);
+ connssl->encdata_offset = inbuf[1].cbBuffer;
+ if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+ doread = FALSE;
+ continue;
+ }
+ }
+ }
+ else {
+ connssl->encdata_offset = 0;
+ }
+ break;
+ }
+
+ /* check if the handshake needs to be continued */
+ if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+
+ /* check if the handshake is complete */
+ if(sspi_status == SEC_E_OK) {
+ connssl->connecting_state = ssl_connect_3;
+ infof(data, "schannel: SSL/TLS handshake complete\n");
+ }
+
+#ifdef _WIN32_WCE
+ /* Windows CE doesn't do any server certificate validation.
+ We have to do it manually. */
+ if(conn->ssl_config.verifypeer)
+ return verify_certificate(conn, sockindex);
+#endif
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step3(struct connectdata *conn, int sockindex)
+{
+ CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ CERT_CONTEXT *ccert_context = NULL;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+#endif
+#ifdef HAS_ALPN
+ SecPkgContext_ApplicationProtocol alpn_result;
+#endif
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
+ hostname, conn->remote_port);
+
+ if(!connssl->cred)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* check if the required context attributes are met */
+ if(connssl->ret_flags != connssl->req_flags) {
+ if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
+ failf(data, "schannel: failed to setup sequence detection");
+ if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
+ failf(data, "schannel: failed to setup replay detection");
+ if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
+ failf(data, "schannel: failed to setup confidentiality");
+ if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+ failf(data, "schannel: failed to setup memory allocation");
+ if(!(connssl->ret_flags & ISC_RET_STREAM))
+ failf(data, "schannel: failed to setup stream orientation");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef HAS_ALPN
+ if(connssl->use_alpn) {
+ sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
+
+ if(sspi_status != SEC_E_OK) {
+ failf(data, "schannel: failed to retrieve ALPN result");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(alpn_result.ProtoNegoStatus ==
+ SecApplicationProtocolNegotiationStatus_Success) {
+
+ infof(data, "schannel: ALPN, server accepted to use %.*s\n",
+ alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
+
+#ifdef USE_NGHTTP2
+ if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
+ !memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ conn->negnpn = CURL_HTTP_VERSION_2;
+ }
+ else
+#endif
+ if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
+ ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
+ }
+ else
+ infof(data, "ALPN, server did not agree to a protocol\n");
+ }
+#endif
+
+ /* save the current session data for possible re-use */
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ struct curl_schannel_cred *old_cred = NULL;
+
+ Curl_ssl_sessionid_lock(conn);
+ incache = !(Curl_ssl_getsessionid(conn, (void **)&old_cred, NULL,
+ sockindex));
+ if(incache) {
+ if(old_cred != connssl->cred) {
+ infof(data, "schannel: old credential handle is stale, removing\n");
+ /* we're not taking old_cred ownership here, no refcount++ is needed */
+ Curl_ssl_delsessionid(conn, (void *)old_cred);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ result = Curl_ssl_addsessionid(conn, (void *)connssl->cred,
+ sizeof(struct curl_schannel_cred),
+ sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(conn);
+ failf(data, "schannel: failed to store credential handle");
+ return result;
+ }
+ else {
+ /* this cred session is now also referenced by sessionid cache */
+ connssl->cred->refcount++;
+ infof(data, "schannel: stored credential handle in session cache\n");
+ }
+ }
+ Curl_ssl_sessionid_unlock(conn);
+ }
+
+ if(data->set.ssl.certinfo) {
+ sspi_status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
+
+ if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
+ failf(data, "schannel: failed to retrieve remote cert context");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ result = Curl_ssl_init_certinfo(data, 1);
+ if(!result) {
+ if(((ccert_context->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
+ (ccert_context->cbCertEncoded > 0)) {
+
+ const char *beg = (const char *) ccert_context->pbCertEncoded;
+ const char *end = beg + ccert_context->cbCertEncoded;
+ result = Curl_extract_certinfo(conn, 0, beg, end);
+ }
+ }
+ CertFreeCertificateContext(ccert_context);
+ if(result)
+ return result;
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_common(struct connectdata *conn, int sockindex,
+ bool nonblocking, bool *done)
+{
+ CURLcode result;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ time_t timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1 == connssl->connecting_state) {
+ /* check out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ result = schannel_connect_step1(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking ? 0 : timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ result = schannel_connect_step2(conn, sockindex);
+ if(result || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return result;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ result = schannel_connect_step3(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = schannel_recv;
+ conn->send[sockindex] = schannel_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* reset our connection state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+static ssize_t
+schannel_send(struct connectdata *conn, int sockindex,
+ const void *buf, size_t len, CURLcode *err)
+{
+ ssize_t written = -1;
+ size_t data_len = 0;
+ unsigned char *data = NULL;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SecBuffer outbuf[4];
+ SecBufferDesc outbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ CURLcode result;
+
+ /* check if the maximum stream sizes were queried */
+ if(connssl->stream_sizes.cbMaximumMessage == 0) {
+ sspi_status = s_pSecFn->QueryContextAttributes(
+ &connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_STREAM_SIZES,
+ &connssl->stream_sizes);
+ if(sspi_status != SEC_E_OK) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+ }
+
+ /* check if the buffer is longer than the maximum message length */
+ if(len > connssl->stream_sizes.cbMaximumMessage) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ /* calculate the complete message length and allocate a buffer for it */
+ data_len = connssl->stream_sizes.cbHeader + len +
+ connssl->stream_sizes.cbTrailer;
+ data = (unsigned char *) malloc(data_len);
+ if(data == NULL) {
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+
+ /* setup output buffers (header, data, trailer, empty) */
+ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
+ data, connssl->stream_sizes.cbHeader);
+ InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
+ data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
+ InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
+ data + connssl->stream_sizes.cbHeader + len,
+ connssl->stream_sizes.cbTrailer);
+ InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, outbuf, 4);
+
+ /* copy data into output buffer */
+ memcpy(outbuf[1].pvBuffer, buf, len);
+
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
+ sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
+ &outbuf_desc, 0);
+
+ /* check if the message was encrypted */
+ if(sspi_status == SEC_E_OK) {
+ written = 0;
+
+ /* send the encrypted message including header, data and trailer */
+ len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
+
+ /*
+ It's important to send the full message which includes the header,
+ encrypted payload, and trailer. Until the client receives all the
+ data a coherent message has not been delivered and the client
+ can't read any of it.
+
+ If we wanted to buffer the unwritten encrypted bytes, we would
+ tell the client that all data it has requested to be sent has been
+ sent. The unwritten encrypted bytes would be the first bytes to
+ send on the next invocation.
+ Here's the catch with this - if we tell the client that all the
+ bytes have been sent, will the client call this method again to
+ send the buffered data? Looking at who calls this function, it
+ seems the answer is NO.
+ */
+
+ /* send entire message or fail */
+ while(len > (size_t)written) {
+ ssize_t this_write;
+ time_t timeleft;
+ int what;
+
+ this_write = 0;
+
+ timeleft = Curl_timeleft(conn->data, NULL, FALSE);
+ if(timeleft < 0) {
+ /* we already got the timeout */
+ failf(conn->data, "schannel: timed out sending data "
+ "(bytes sent: %zd)", written);
+ *err = CURLE_OPERATION_TIMEDOUT;
+ written = -1;
+ break;
+ }
+
+ what = SOCKET_WRITABLE(conn->sock[sockindex], timeleft);
+ if(what < 0) {
+ /* fatal error */
+ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ *err = CURLE_SEND_ERROR;
+ written = -1;
+ break;
+ }
+ else if(0 == what) {
+ failf(conn->data, "schannel: timed out sending data "
+ "(bytes sent: %zd)", written);
+ *err = CURLE_OPERATION_TIMEDOUT;
+ written = -1;
+ break;
+ }
+ /* socket is writable */
+
+ result = Curl_write_plain(conn, conn->sock[sockindex], data + written,
+ len - written, &this_write);
+ if(result == CURLE_AGAIN)
+ continue;
+ else if(result != CURLE_OK) {
+ *err = result;
+ written = -1;
+ break;
+ }
+
+ written += this_write;
+ }
+ }
+ else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
+ *err = CURLE_OUT_OF_MEMORY;
+ }
+ else{
+ *err = CURLE_SEND_ERROR;
+ }
+
+ Curl_safefree(data);
+
+ if(len == (size_t)written)
+ /* Encrypted message including header, data and trailer entirely sent.
+ The return value is the number of unencrypted bytes that were sent. */
+ written = outbuf[1].cbBuffer;
+
+ return written;
+}
+
+static ssize_t
+schannel_recv(struct connectdata *conn, int sockindex,
+ char *buf, size_t len, CURLcode *err)
+{
+ size_t size = 0;
+ ssize_t nread = -1;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ unsigned char *reallocated_buffer;
+ size_t reallocated_length;
+ bool done = FALSE;
+ SecBuffer inbuf[4];
+ SecBufferDesc inbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ /* we want the length of the encrypted buffer to be at least large enough
+ that it can hold all the bytes requested and some TLS record overhead. */
+ size_t min_encdata_length = len + CURL_SCHANNEL_BUFFER_FREE_SIZE;
+
+ /****************************************************************************
+ * Don't return or set connssl->recv_unrecoverable_err unless in the cleanup.
+ * The pattern for return error is set *err, optional infof, goto cleanup.
+ *
+ * Our priority is to always return as much decrypted data to the caller as
+ * possible, even if an error occurs. The state of the decrypted buffer must
+ * always be valid. Transfer of decrypted data to the caller's buffer is
+ * handled in the cleanup.
+ */
+
+ infof(data, "schannel: client wants to read %zu bytes\n", len);
+ *err = CURLE_OK;
+
+ if(len && len <= connssl->decdata_offset) {
+ infof(data, "schannel: enough decrypted data is already available\n");
+ goto cleanup;
+ }
+ else if(connssl->recv_unrecoverable_err) {
+ *err = connssl->recv_unrecoverable_err;
+ infof(data, "schannel: an unrecoverable error occurred in a prior call\n");
+ goto cleanup;
+ }
+ else if(connssl->recv_sspi_close_notify) {
+ /* once a server has indicated shutdown there is no more encrypted data */
+ infof(data, "schannel: server indicated shutdown in a prior call\n");
+ goto cleanup;
+ }
+ else if(!len) {
+ /* It's debatable what to return when !len. Regardless we can't return
+ immediately because there may be data to decrypt (in the case we want to
+ decrypt all encrypted cached data) so handle !len later in cleanup.
+ */
+ ; /* do nothing */
+ }
+ else if(!connssl->recv_connection_closed) {
+ /* increase enc buffer in order to fit the requested amount of data */
+ size = connssl->encdata_length - connssl->encdata_offset;
+ if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
+ connssl->encdata_length < min_encdata_length) {
+ reallocated_length = connssl->encdata_offset +
+ CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ if(reallocated_length < min_encdata_length) {
+ reallocated_length = min_encdata_length;
+ }
+ reallocated_buffer = realloc(connssl->encdata_buffer,
+ reallocated_length);
+ if(reallocated_buffer == NULL) {
+ *err = CURLE_OUT_OF_MEMORY;
+ failf(data, "schannel: unable to re-allocate memory");
+ goto cleanup;
+ }
+
+ connssl->encdata_buffer = reallocated_buffer;
+ connssl->encdata_length = reallocated_length;
+ size = connssl->encdata_length - connssl->encdata_offset;
+ infof(data, "schannel: encdata_buffer resized %zu\n",
+ connssl->encdata_length);
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ /* read encrypted data from socket */
+ *err = Curl_read_plain(conn->sock[sockindex],
+ (char *)(connssl->encdata_buffer +
+ connssl->encdata_offset),
+ size, &nread);
+ if(*err) {
+ nread = -1;
+ if(*err == CURLE_AGAIN)
+ infof(data, "schannel: Curl_read_plain returned CURLE_AGAIN\n");
+ else if(*err == CURLE_RECV_ERROR)
+ infof(data, "schannel: Curl_read_plain returned CURLE_RECV_ERROR\n");
+ else
+ infof(data, "schannel: Curl_read_plain returned error %d\n", *err);
+ }
+ else if(nread == 0) {
+ connssl->recv_connection_closed = true;
+ infof(data, "schannel: server closed the connection\n");
+ }
+ else if(nread > 0) {
+ connssl->encdata_offset += (size_t)nread;
+ connssl->encdata_is_incomplete = false;
+ infof(data, "schannel: encrypted data got %zd\n", nread);
+ }
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ /* decrypt loop */
+ while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
+ (!len || connssl->decdata_offset < len ||
+ connssl->recv_connection_closed)) {
+ /* prepare data buffer for DecryptMessage call */
+ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
+ curlx_uztoul(connssl->encdata_offset));
+
+ /* we need 3 more empty input buffers for possible output */
+ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&inbuf_desc, inbuf, 4);
+
+ /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
+ */
+ sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
+ &inbuf_desc, 0, NULL);
+
+ /* check if everything went fine (server may want to renegotiate
+ or shutdown the connection context) */
+ if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
+ sspi_status == SEC_I_CONTEXT_EXPIRED) {
+ /* check for successfully decrypted data, even before actual
+ renegotiation or shutdown of the connection context */
+ if(inbuf[1].BufferType == SECBUFFER_DATA) {
+ infof(data, "schannel: decrypted data length: %lu\n",
+ inbuf[1].cbBuffer);
+
+ /* increase buffer in order to fit the received amount of data */
+ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
+ inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ if(connssl->decdata_length - connssl->decdata_offset < size ||
+ connssl->decdata_length < len) {
+ /* increase internal decrypted data buffer */
+ reallocated_length = connssl->decdata_offset + size;
+ /* make sure that the requested amount of data fits */
+ if(reallocated_length < len) {
+ reallocated_length = len;
+ }
+ reallocated_buffer = realloc(connssl->decdata_buffer,
+ reallocated_length);
+ if(reallocated_buffer == NULL) {
+ *err = CURLE_OUT_OF_MEMORY;
+ failf(data, "schannel: unable to re-allocate memory");
+ goto cleanup;
+ }
+ connssl->decdata_buffer = reallocated_buffer;
+ connssl->decdata_length = reallocated_length;
+ }
+
+ /* copy decrypted data to internal buffer */
+ size = inbuf[1].cbBuffer;
+ if(size) {
+ memcpy(connssl->decdata_buffer + connssl->decdata_offset,
+ inbuf[1].pvBuffer, size);
+ connssl->decdata_offset += size;
+ }
+
+ infof(data, "schannel: decrypted data added: %zu\n", size);
+ infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+ }
+
+ /* check for remaining encrypted data */
+ if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
+ infof(data, "schannel: encrypted data length: %lu\n",
+ inbuf[3].cbBuffer);
+
+ /* check if the remaining data is less than the total amount
+ * and therefore begins after the already processed data
+ */
+ if(connssl->encdata_offset > inbuf[3].cbBuffer) {
+ /* move remaining encrypted data forward to the beginning of
+ buffer */
+ memmove(connssl->encdata_buffer,
+ (connssl->encdata_buffer + connssl->encdata_offset) -
+ inbuf[3].cbBuffer, inbuf[3].cbBuffer);
+ connssl->encdata_offset = inbuf[3].cbBuffer;
+ }
+
+ infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+ }
+ else {
+ /* reset encrypted buffer offset, because there is no data remaining */
+ connssl->encdata_offset = 0;
+ }
+
+ /* check if server wants to renegotiate the connection context */
+ if(sspi_status == SEC_I_RENEGOTIATE) {
+ infof(data, "schannel: remote party requests renegotiation\n");
+ if(*err && *err != CURLE_AGAIN) {
+ infof(data, "schannel: can't renogotiate, an error is pending\n");
+ goto cleanup;
+ }
+ if(connssl->encdata_offset) {
+ *err = CURLE_RECV_ERROR;
+ infof(data, "schannel: can't renogotiate, "
+ "encrypted data available\n");
+ goto cleanup;
+ }
+ /* begin renegotiation */
+ infof(data, "schannel: renegotiating SSL/TLS connection\n");
+ connssl->state = ssl_connection_negotiating;
+ connssl->connecting_state = ssl_connect_2_writing;
+ *err = schannel_connect_common(conn, sockindex, FALSE, &done);
+ if(*err) {
+ infof(data, "schannel: renegotiation failed\n");
+ goto cleanup;
+ }
+ /* now retry receiving data */
+ sspi_status = SEC_E_OK;
+ infof(data, "schannel: SSL/TLS connection renegotiated\n");
+ continue;
+ }
+ /* check if the server closed the connection */
+ else if(sspi_status == SEC_I_CONTEXT_EXPIRED) {
+ /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not
+ returned so we have to work around that in cleanup. */
+ connssl->recv_sspi_close_notify = true;
+ if(!connssl->recv_connection_closed) {
+ connssl->recv_connection_closed = true;
+ infof(data, "schannel: server closed the connection\n");
+ }
+ goto cleanup;
+ }
+ }
+ else if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+ connssl->encdata_is_incomplete = true;
+ if(!*err)
+ *err = CURLE_AGAIN;
+ infof(data, "schannel: failed to decrypt data, need more data\n");
+ goto cleanup;
+ }
+ else {
+ *err = CURLE_RECV_ERROR;
+ infof(data, "schannel: failed to read data from server: %s\n",
+ Curl_sspi_strerror(conn, sspi_status));
+ goto cleanup;
+ }
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+
+cleanup:
+ /* Warning- there is no guarantee the encdata state is valid at this point */
+ infof(data, "schannel: schannel_recv cleanup\n");
+
+ /* Error if the connection has closed without a close_notify.
+ Behavior here is a matter of debate. We don't want to be vulnerable to a
+ truncation attack however there's some browser precedent for ignoring the
+ close_notify for compatibility reasons.
+ Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
+ return close_notify. In that case if the connection was closed we assume it
+ was graceful (close_notify) since there doesn't seem to be a way to tell.
+ */
+ if(len && !connssl->decdata_offset && connssl->recv_connection_closed &&
+ !connssl->recv_sspi_close_notify) {
+ bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
+ VERSION_EQUAL);
+
+ if(isWin2k && sspi_status == SEC_E_OK)
+ connssl->recv_sspi_close_notify = true;
+ else {
+ *err = CURLE_RECV_ERROR;
+ infof(data, "schannel: server closed abruptly (missing close_notify)\n");
+ }
+ }
+
+ /* Any error other than CURLE_AGAIN is an unrecoverable error. */
+ if(*err && *err != CURLE_AGAIN)
+ connssl->recv_unrecoverable_err = *err;
+
+ size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
+ if(size) {
+ memcpy(buf, connssl->decdata_buffer, size);
+ memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
+ connssl->decdata_offset - size);
+ connssl->decdata_offset -= size;
+
+ infof(data, "schannel: decrypted data returned %zu\n", size);
+ infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+ *err = CURLE_OK;
+ return (ssize_t)size;
+ }
+
+ if(!*err && !connssl->recv_connection_closed)
+ *err = CURLE_AGAIN;
+
+ /* It's debatable what to return when !len. We could return whatever error we
+ got from decryption but instead we override here so the return is consistent.
+ */
+ if(!len)
+ *err = CURLE_OK;
+
+ return *err ? -1 : 0;
+}
+
+CURLcode
+Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ return schannel_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_schannel_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode result;
+ bool done = FALSE;
+
+ result = schannel_connect_common(conn, sockindex, FALSE, &done);
+ if(result)
+ return result;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->use) /* SSL/TLS is in use */
+ return (connssl->decdata_offset > 0 ||
+ (connssl->encdata_offset > 0 && !connssl->encdata_is_incomplete));
+ else
+ return FALSE;
+}
+
+void Curl_schannel_close(struct connectdata *conn, int sockindex)
+{
+ if(conn->ssl[sockindex].use)
+ /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
+ Curl_ssl_shutdown(conn, sockindex);
+}
+
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
+{
+ /* See https://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
+ * Shutting Down an Schannel Connection
+ */
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+ conn->host.name;
+
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
+ hostname, conn->remote_port);
+
+ if(connssl->cred && connssl->ctxt) {
+ SecBufferDesc BuffDesc;
+ SecBuffer Buffer;
+ SECURITY_STATUS sspi_status;
+ SecBuffer outbuf;
+ SecBufferDesc outbuf_desc;
+ CURLcode result;
+ TCHAR *host_name;
+ DWORD dwshut = SCHANNEL_SHUTDOWN;
+
+ InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
+ InitSecBufferDesc(&BuffDesc, &Buffer, 1);
+
+ sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
+ &BuffDesc);
+
+ if(sspi_status != SEC_E_OK)
+ failf(data, "schannel: ApplyControlToken failure: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+
+ host_name = Curl_convert_UTF8_to_tchar(hostname);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* setup output buffer */
+ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle,
+ &connssl->ctxt->ctxt_handle,
+ host_name,
+ connssl->req_flags,
+ 0,
+ 0,
+ NULL,
+ 0,
+ &connssl->ctxt->ctxt_handle,
+ &outbuf_desc,
+ &connssl->ret_flags,
+ &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
+ /* send close message which is in output buffer */
+ ssize_t written;
+ result = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+ outbuf.cbBuffer, &written);
+
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ if((result != CURLE_OK) || (outbuf.cbBuffer != (size_t) written)) {
+ infof(data, "schannel: failed to send close msg: %s"
+ " (bytes written: %zd)\n", curl_easy_strerror(result), written);
+ }
+ }
+ }
+
+ /* free SSPI Schannel API security context handle */
+ if(connssl->ctxt) {
+ infof(data, "schannel: clear security context handle\n");
+ s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
+ Curl_safefree(connssl->ctxt);
+ }
+
+ /* free SSPI Schannel API credential handle */
+ if(connssl->cred) {
+ Curl_ssl_sessionid_lock(conn);
+ Curl_schannel_session_free(connssl->cred);
+ Curl_ssl_sessionid_unlock(conn);
+ connssl->cred = NULL;
+ }
+
+ /* free internal buffer for received encrypted data */
+ if(connssl->encdata_buffer != NULL) {
+ Curl_safefree(connssl->encdata_buffer);
+ connssl->encdata_length = 0;
+ connssl->encdata_offset = 0;
+ connssl->encdata_is_incomplete = false;
+ }
+
+ /* free internal buffer for received decrypted data */
+ if(connssl->decdata_buffer != NULL) {
+ Curl_safefree(connssl->decdata_buffer);
+ connssl->decdata_length = 0;
+ connssl->decdata_offset = 0;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_schannel_session_free(void *ptr)
+{
+ /* this is expected to be called under sessionid lock */
+ struct curl_schannel_cred *cred = ptr;
+
+ cred->refcount--;
+ if(cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
+ }
+}
+
+int Curl_schannel_init(void)
+{
+ return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
+}
+
+void Curl_schannel_cleanup(void)
+{
+ Curl_sspi_global_cleanup();
+}
+
+size_t Curl_schannel_version(char *buffer, size_t size)
+{
+ size = snprintf(buffer, size, "WinSSL");
+
+ return size;
+}
+
+CURLcode Curl_schannel_random(unsigned char *entropy, size_t length)
+{
+ HCRYPTPROV hCryptProv = 0;
+
+ if(!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+ return CURLE_FAILED_INIT;
+
+ if(!CryptGenRandom(hCryptProv, (DWORD)length, entropy)) {
+ CryptReleaseContext(hCryptProv, 0UL);
+ return CURLE_FAILED_INIT;
+ }
+
+ CryptReleaseContext(hCryptProv, 0UL);
+ return CURLE_OK;
+}
+
+#ifdef _WIN32_WCE
+static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+{
+ SECURITY_STATUS status;
+ struct Curl_easy *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result = CURLE_OK;
+ CERT_CONTEXT *pCertContextServer = NULL;
+ const CERT_CHAIN_CONTEXT *pChainContext = NULL;
+ const char * const conn_hostname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.name :
+ conn->host.name;
+
+ status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
+
+ if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ failf(data, "schannel: Failed to read remote certificate context: %s",
+ Curl_sspi_strerror(conn, status));
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK) {
+ CERT_CHAIN_PARA ChainPara;
+ memset(&ChainPara, 0, sizeof(ChainPara));
+ ChainPara.cbSize = sizeof(ChainPara);
+
+ if(!CertGetCertificateChain(NULL,
+ pCertContextServer,
+ NULL,
+ pCertContextServer->hCertStore,
+ &ChainPara,
+ (data->set.ssl.no_revoke ? 0 :
+ CERT_CHAIN_REVOCATION_CHECK_CHAIN),
+ NULL,
+ &pChainContext)) {
+ failf(data, "schannel: CertGetCertificateChain failed: %s",
+ Curl_sspi_strerror(conn, GetLastError()));
+ pChainContext = NULL;
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK) {
+ CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
+ DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED);
+ dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
+ if(dwTrustErrorMask) {
+ if(dwTrustErrorMask & CERT_TRUST_IS_REVOKED)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_REVOKED");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_PARTIAL_CHAIN");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_UNTRUSTED_ROOT");
+ else if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_NOT_TIME_VALID");
+ else
+ failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
+ dwTrustErrorMask);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(conn->ssl_config.verifyhost) {
+ TCHAR cert_hostname_buff[256];
+ DWORD len;
+
+ /* TODO: Fix this for certificates with multiple alternative names.
+ Right now we're only asking for the first preferred alternative name.
+ Instead we'd need to do all via CERT_NAME_SEARCH_ALL_NAMES_FLAG
+ (if WinCE supports that?) and run this section in a loop for each.
+ https://msdn.microsoft.com/en-us/library/windows/desktop/aa376086.aspx
+ curl: (51) schannel: CertGetNameString() certificate hostname
+ (.google.com) did not match connection (google.com)
+ */
+ len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ CERT_NAME_DISABLE_IE4_UTF8_FLAG,
+ NULL,
+ cert_hostname_buff,
+ 256);
+ if(len > 0) {
+ const char *cert_hostname;
+
+ /* Comparing the cert name and the connection hostname encoded as UTF-8
+ * is acceptable since both values are assumed to use ASCII
+ * (or some equivalent) encoding
+ */
+ cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname_buff);
+ if(!cert_hostname) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else{
+ int match_result;
+
+ match_result = Curl_cert_hostcheck(cert_hostname, conn->host.name);
+ if(match_result == CURL_HOST_MATCH) {
+ infof(data,
+ "schannel: connection hostname (%s) validated "
+ "against certificate name (%s)\n",
+ conn->host.name,
+ cert_hostname);
+ result = CURLE_OK;
+ }
+ else{
+ failf(data,
+ "schannel: connection hostname (%s) "
+ "does not match certificate name (%s)",
+ conn->host.name,
+ cert_hostname);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ Curl_unicodefree(cert_hostname);
+ }
+ }
+ else {
+ failf(data,
+ "schannel: CertGetNameString did not provide any "
+ "certificate name information");
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(pChainContext)
+ CertFreeCertificateChain(pChainContext);
+
+ if(pCertContextServer)
+ CertFreeCertificateContext(pCertContextServer);
+
+ return result;
+}
+#endif /* _WIN32_WCE */
+
+#endif /* USE_SCHANNEL */
diff --git a/Utilities/cmcurl/lib/vtls/schannel.h b/Utilities/cmcurl/lib/vtls/schannel.h
new file mode 100644
index 000000000..8627c63c9
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/schannel.h
@@ -0,0 +1,121 @@
+#ifndef HEADER_CURL_SCHANNEL_H
+#define HEADER_CURL_SCHANNEL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
+ * Copyright (C) 2012 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#include "urldata.h"
+
+#ifndef UNISP_NAME_A
+#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME_W
+#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME
+#ifdef UNICODE
+#define UNISP_NAME UNISP_NAME_W
+#else
+#define UNISP_NAME UNISP_NAME_A
+#endif
+#endif
+
+#ifndef SP_PROT_SSL2_CLIENT
+#define SP_PROT_SSL2_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_SSL3_CLIENT
+#define SP_PROT_SSL3_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_TLS1_CLIENT
+#define SP_PROT_TLS1_CLIENT 0x00000080
+#endif
+
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
+#endif
+
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT 0x00000200
+#endif
+
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT 0x00000800
+#endif
+
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT 17
+#endif
+
+/* Both schannel buffer sizes must be > 0 */
+#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
+
+
+CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
+void Curl_schannel_close(struct connectdata *conn, int sockindex);
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
+void Curl_schannel_session_free(void *ptr);
+
+int Curl_schannel_init(void);
+void Curl_schannel_cleanup(void);
+size_t Curl_schannel_version(char *buffer, size_t size);
+
+CURLcode Curl_schannel_random(unsigned char *entropy, size_t length);
+
+/* Set the API backend definition to Schannel */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_SCHANNEL
+
+/* this backend supports CURLOPT_CERTINFO */
+#define have_curlssl_certinfo 1
+
+/* API setup for Schannel */
+#define curlssl_init Curl_schannel_init
+#define curlssl_cleanup Curl_schannel_cleanup
+#define curlssl_connect Curl_schannel_connect
+#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
+#define curlssl_session_free Curl_schannel_session_free
+#define curlssl_close_all(x) ((void)x)
+#define curlssl_close Curl_schannel_close
+#define curlssl_shutdown Curl_schannel_shutdown
+#define curlssl_set_engine(x,y) ((void)x, (void)y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) ((void)x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) ((void)x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_schannel_version
+#define curlssl_check_cxn(x) ((void)x, -1)
+#define curlssl_data_pending Curl_schannel_data_pending
+#define curlssl_random(x,y,z) ((void)x, Curl_schannel_random(y,z))
+
+#endif /* USE_SCHANNEL */
+#endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.c b/Utilities/cmcurl/lib/vtls/vtls.c
new file mode 100644
index 000000000..d5d0971c4
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/vtls.c
@@ -0,0 +1,987 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/* This file is for implementing all "generic" SSL functions that all libcurl
+ internals should use. It is then responsible for calling the proper
+ "backend" function.
+
+ SSL-functions in libcurl should call functions in this source file, and not
+ to any specific SSL-layer.
+
+ Curl_ssl_ - prefix for generic ones
+ Curl_ossl_ - prefix for OpenSSL ones
+ Curl_gtls_ - prefix for GnuTLS ones
+ Curl_nss_ - prefix for NSS ones
+ Curl_gskit_ - prefix for GSKit ones
+ Curl_polarssl_ - prefix for PolarSSL ones
+ Curl_cyassl_ - prefix for CyaSSL ones
+ Curl_schannel_ - prefix for Schannel SSPI ones
+ Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
+
+ Note that this source code uses curlssl_* functions, and they are all
+ defines/macros #defined by the lib-specific header files.
+
+ "SSL/TLS Strong Encryption: An Introduction"
+ https://httpd.apache.org/docs/2.0/ssl/ssl_intro.html
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "urldata.h"
+
+#include "vtls.h" /* generic SSL protos etc */
+#include "slist.h"
+#include "sendf.h"
+#include "strcase.h"
+#include "url.h"
+#include "progress.h"
+#include "share.h"
+#include "multiif.h"
+#include "timeval.h"
+#include "curl_md5.h"
+#include "warnless.h"
+#include "curl_base64.h"
+#include "curl_printf.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* convenience macro to check if this handle is using a shared SSL session */
+#define SSLSESSION_SHARED(data) (data->share && \
+ (data->share->specifier & \
+ (1<<CURL_LOCK_DATA_SSL_SESSION)))
+
+#define CLONE_STRING(var) \
+ if(source->var) { \
+ dest->var = strdup(source->var); \
+ if(!dest->var) \
+ return FALSE; \
+ } \
+ else \
+ dest->var = NULL;
+
+bool
+Curl_ssl_config_matches(struct ssl_primary_config* data,
+ struct ssl_primary_config* needle)
+{
+ if((data->version == needle->version) &&
+ (data->version_max == needle->version_max) &&
+ (data->verifypeer == needle->verifypeer) &&
+ (data->verifyhost == needle->verifyhost) &&
+ Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
+ Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
+ Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
+ Curl_safe_strcasecompare(data->cipher_list, needle->cipher_list))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool
+Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest)
+{
+ dest->verifyhost = source->verifyhost;
+ dest->verifypeer = source->verifypeer;
+ dest->version = source->version;
+ dest->version_max = source->version_max;
+
+ CLONE_STRING(CAfile);
+ CLONE_STRING(CApath);
+ CLONE_STRING(cipher_list);
+ CLONE_STRING(egdsocket);
+ CLONE_STRING(random_file);
+ CLONE_STRING(clientcert);
+
+ /* Disable dest sessionid cache if a client cert is used, CVE-2016-5419. */
+ dest->sessionid = (dest->clientcert ? false : source->sessionid);
+ return TRUE;
+}
+
+void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
+{
+ Curl_safefree(sslc->CAfile);
+ Curl_safefree(sslc->CApath);
+ Curl_safefree(sslc->cipher_list);
+ Curl_safefree(sslc->egdsocket);
+ Curl_safefree(sslc->random_file);
+ Curl_safefree(sslc->clientcert);
+}
+
+int Curl_ssl_backend(void)
+{
+ return (int)CURL_SSL_BACKEND;
+}
+
+#ifdef USE_SSL
+
+/* "global" init done? */
+static bool init_ssl=FALSE;
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ssl_init(void)
+{
+ /* make sure this is only done once */
+ if(init_ssl)
+ return 1;
+ init_ssl = TRUE; /* never again */
+
+ return curlssl_init();
+}
+
+
+/* Global cleanup */
+void Curl_ssl_cleanup(void)
+{
+ if(init_ssl) {
+ /* only cleanup if we did a previous init */
+ curlssl_cleanup();
+ init_ssl = FALSE;
+ }
+}
+
+static bool ssl_prefs_check(struct Curl_easy *data)
+{
+ /* check for CURLOPT_SSLVERSION invalid parameter value */
+ const long sslver = data->set.ssl.primary.version;
+ if((sslver < 0) || (sslver >= CURL_SSLVERSION_LAST)) {
+ failf(data, "Unrecognized parameter value passed via CURLOPT_SSLVERSION");
+ return FALSE;
+ }
+
+ switch(data->set.ssl.primary.version_max) {
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ break;
+
+ default:
+ if((data->set.ssl.primary.version_max >> 16) < sslver) {
+ failf(data, "CURL_SSLVERSION_MAX incompatible with CURL_SSLVERSION");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static CURLcode
+ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
+{
+ DEBUGASSERT(conn->bits.proxy_ssl_connected[sockindex]);
+ if(ssl_connection_complete == conn->ssl[sockindex].state &&
+ !conn->proxy_ssl[sockindex].use) {
+#if defined(HTTPS_PROXY_SUPPORT)
+ conn->proxy_ssl[sockindex] = conn->ssl[sockindex];
+ memset(&conn->ssl[sockindex], 0, sizeof(conn->ssl[sockindex]));
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_ssl_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode result;
+
+ if(conn->bits.proxy_ssl_connected[sockindex]) {
+ result = ssl_connect_init_proxy(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(!ssl_prefs_check(conn->data))
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* mark this is being ssl-enabled from here on. */
+ conn->ssl[sockindex].use = TRUE;
+ conn->ssl[sockindex].state = ssl_connection_negotiating;
+
+ result = curlssl_connect(conn, sockindex);
+
+ if(!result)
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+
+ return result;
+}
+
+CURLcode
+Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ CURLcode result;
+ if(conn->bits.proxy_ssl_connected[sockindex]) {
+ result = ssl_connect_init_proxy(conn, sockindex);
+ if(result)
+ return result;
+ }
+
+ if(!ssl_prefs_check(conn->data))
+ return CURLE_SSL_CONNECT_ERROR;
+
+ /* mark this is being ssl requested from here on. */
+ conn->ssl[sockindex].use = TRUE;
+#ifdef curlssl_connect_nonblocking
+ result = curlssl_connect_nonblocking(conn, sockindex, done);
+#else
+ *done = TRUE; /* fallback to BLOCKING */
+ result = curlssl_connect(conn, sockindex);
+#endif /* non-blocking connect support */
+ if(!result && *done)
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+ return result;
+}
+
+/*
+ * Lock shared SSL session data
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn)
+{
+ if(SSLSESSION_SHARED(conn->data))
+ Curl_share_lock(conn->data,
+ CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+}
+
+/*
+ * Unlock shared SSL session data
+ */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn)
+{
+ if(SSLSESSION_SHARED(conn->data))
+ Curl_share_unlock(conn->data, CURL_LOCK_DATA_SSL_SESSION);
+}
+
+/*
+ * Check if there's a session ID for the given connection in the cache, and if
+ * there's one suitable, it is provided. Returns TRUE when no entry matched.
+ */
+bool Curl_ssl_getsessionid(struct connectdata *conn,
+ void **ssl_sessionid,
+ size_t *idsize, /* set 0 if unknown */
+ int sockindex)
+{
+ struct curl_ssl_session *check;
+ struct Curl_easy *data = conn->data;
+ size_t i;
+ long *general_age;
+ bool no_match = TRUE;
+
+ const bool isProxy = CONNECT_PROXY_SSL();
+ struct ssl_primary_config * const ssl_config = isProxy ?
+ &conn->proxy_ssl_config :
+ &conn->ssl_config;
+ const char * const name = isProxy ? conn->http_proxy.host.name :
+ conn->host.name;
+ int port = isProxy ? (int)conn->port : conn->remote_port;
+ *ssl_sessionid = NULL;
+
+ DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+
+ if(!SSL_SET_OPTION(primary.sessionid))
+ /* session ID re-use is disabled */
+ return TRUE;
+
+ /* Lock if shared */
+ if(SSLSESSION_SHARED(data))
+ general_age = &data->share->sessionage;
+ else
+ general_age = &data->state.sessionage;
+
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
+ check = &data->state.session[i];
+ if(!check->sessionid)
+ /* not session ID means blank entry */
+ continue;
+ if(strcasecompare(name, check->name) &&
+ ((!conn->bits.conn_to_host && !check->conn_to_host) ||
+ (conn->bits.conn_to_host && check->conn_to_host &&
+ strcasecompare(conn->conn_to_host.name, check->conn_to_host))) &&
+ ((!conn->bits.conn_to_port && check->conn_to_port == -1) ||
+ (conn->bits.conn_to_port && check->conn_to_port != -1 &&
+ conn->conn_to_port == check->conn_to_port)) &&
+ (port == check->remote_port) &&
+ strcasecompare(conn->handler->scheme, check->scheme) &&
+ Curl_ssl_config_matches(ssl_config, &check->ssl_config)) {
+ /* yes, we have a session ID! */
+ (*general_age)++; /* increase general age */
+ check->age = *general_age; /* set this as used in this age */
+ *ssl_sessionid = check->sessionid;
+ if(idsize)
+ *idsize = check->idsize;
+ no_match = FALSE;
+ break;
+ }
+ }
+
+ return no_match;
+}
+
+/*
+ * Kill a single session ID entry in the cache.
+ */
+void Curl_ssl_kill_session(struct curl_ssl_session *session)
+{
+ if(session->sessionid) {
+ /* defensive check */
+
+ /* free the ID the SSL-layer specific way */
+ curlssl_session_free(session->sessionid);
+
+ session->sessionid = NULL;
+ session->age = 0; /* fresh */
+
+ Curl_free_primary_ssl_config(&session->ssl_config);
+
+ Curl_safefree(session->name);
+ Curl_safefree(session->conn_to_host);
+ }
+}
+
+/*
+ * Delete the given session ID from the cache.
+ */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
+{
+ size_t i;
+ struct Curl_easy *data=conn->data;
+
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++) {
+ struct curl_ssl_session *check = &data->state.session[i];
+
+ if(check->sessionid == ssl_sessionid) {
+ Curl_ssl_kill_session(check);
+ break;
+ }
+ }
+}
+
+/*
+ * Store session id in the session cache. The ID passed on to this function
+ * must already have been extracted and allocated the proper way for the SSL
+ * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
+ * later on.
+ */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+ void *ssl_sessionid,
+ size_t idsize,
+ int sockindex)
+{
+ size_t i;
+ struct Curl_easy *data=conn->data; /* the mother of all structs */
+ struct curl_ssl_session *store = &data->state.session[0];
+ long oldest_age=data->state.session[0].age; /* zero if unused */
+ char *clone_host;
+ char *clone_conn_to_host;
+ int conn_to_port;
+ long *general_age;
+ const bool isProxy = CONNECT_PROXY_SSL();
+ struct ssl_primary_config * const ssl_config = isProxy ?
+ &conn->proxy_ssl_config :
+ &conn->ssl_config;
+
+ DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
+
+ clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
+ if(!clone_host)
+ return CURLE_OUT_OF_MEMORY; /* bail out */
+
+ if(conn->bits.conn_to_host) {
+ clone_conn_to_host = strdup(conn->conn_to_host.name);
+ if(!clone_conn_to_host) {
+ free(clone_host);
+ return CURLE_OUT_OF_MEMORY; /* bail out */
+ }
+ }
+ else
+ clone_conn_to_host = NULL;
+
+ if(conn->bits.conn_to_port)
+ conn_to_port = conn->conn_to_port;
+ else
+ conn_to_port = -1;
+
+ /* Now we should add the session ID and the host name to the cache, (remove
+ the oldest if necessary) */
+
+ /* If using shared SSL session, lock! */
+ if(SSLSESSION_SHARED(data)) {
+ general_age = &data->share->sessionage;
+ }
+ else {
+ general_age = &data->state.sessionage;
+ }
+
+ /* find an empty slot for us, or find the oldest */
+ for(i = 1; (i < data->set.general_ssl.max_ssl_sessions) &&
+ data->state.session[i].sessionid; i++) {
+ if(data->state.session[i].age < oldest_age) {
+ oldest_age = data->state.session[i].age;
+ store = &data->state.session[i];
+ }
+ }
+ if(i == data->set.general_ssl.max_ssl_sessions)
+ /* cache is full, we must "kill" the oldest entry! */
+ Curl_ssl_kill_session(store);
+ else
+ store = &data->state.session[i]; /* use this slot */
+
+ /* now init the session struct wisely */
+ store->sessionid = ssl_sessionid;
+ store->idsize = idsize;
+ store->age = *general_age; /* set current age */
+ /* free it if there's one already present */
+ free(store->name);
+ free(store->conn_to_host);
+ store->name = clone_host; /* clone host name */
+ store->conn_to_host = clone_conn_to_host; /* clone connect to host name */
+ store->conn_to_port = conn_to_port; /* connect to port number */
+ /* port number */
+ store->remote_port = isProxy ? (int)conn->port : conn->remote_port;
+ store->scheme = conn->handler->scheme;
+
+ if(!Curl_clone_primary_ssl_config(ssl_config, &store->ssl_config)) {
+ store->sessionid = NULL; /* let caller free sessionid */
+ free(clone_host);
+ free(clone_conn_to_host);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+
+void Curl_ssl_close_all(struct Curl_easy *data)
+{
+ size_t i;
+ /* kill the session ID cache if not shared */
+ if(data->state.session && !SSLSESSION_SHARED(data)) {
+ for(i = 0; i < data->set.general_ssl.max_ssl_sessions; i++)
+ /* the single-killer function handles empty table slots */
+ Curl_ssl_kill_session(&data->state.session[i]);
+
+ /* free the cache data */
+ Curl_safefree(data->state.session);
+ }
+
+ curlssl_close_all(data);
+}
+
+#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+ defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS) || \
+ defined(USE_MBEDTLS)
+int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ if(connssl->connecting_state == ssl_connect_2_writing) {
+ /* write mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+ }
+ if(connssl->connecting_state == ssl_connect_2_reading) {
+ /* read mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_READSOCK(0);
+ }
+
+ return GETSOCK_BLANK;
+}
+#else
+int Curl_ssl_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return GETSOCK_BLANK;
+}
+/* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL || USE_DARWINSSL || USE_NSS */
+#endif
+
+void Curl_ssl_close(struct connectdata *conn, int sockindex)
+{
+ DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+ curlssl_close(conn, sockindex);
+}
+
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
+{
+ if(curlssl_shutdown(conn, sockindex))
+ return CURLE_SSL_SHUTDOWN_FAILED;
+
+ conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
+ conn->ssl[sockindex].state = ssl_connection_none;
+
+ conn->recv[sockindex] = Curl_recv_plain;
+ conn->send[sockindex] = Curl_send_plain;
+
+ return CURLE_OK;
+}
+
+/* Selects an SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine)
+{
+ return curlssl_set_engine(data, engine);
+}
+
+/* Selects the default SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data)
+{
+ return curlssl_set_engine_default(data);
+}
+
+/* Return list of OpenSSL crypto engine names. */
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data)
+{
+ return curlssl_engines_list(data);
+}
+
+/*
+ * This sets up a session ID cache to the specified size. Make sure this code
+ * is agnostic to what underlying SSL technology we use.
+ */
+CURLcode Curl_ssl_initsessions(struct Curl_easy *data, size_t amount)
+{
+ struct curl_ssl_session *session;
+
+ if(data->state.session)
+ /* this is just a precaution to prevent multiple inits */
+ return CURLE_OK;
+
+ session = calloc(amount, sizeof(struct curl_ssl_session));
+ if(!session)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* store the info in the SSL section */
+ data->set.general_ssl.max_ssl_sessions = amount;
+ data->state.session = session;
+ data->state.sessionage = 1; /* this is brand new */
+ return CURLE_OK;
+}
+
+size_t Curl_ssl_version(char *buffer, size_t size)
+{
+ return curlssl_version(buffer, size);
+}
+
+/*
+ * This function tries to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_ssl_check_cxn(struct connectdata *conn)
+{
+ return curlssl_check_cxn(conn);
+}
+
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+ int connindex)
+{
+ return curlssl_data_pending(conn, connindex);
+}
+
+void Curl_ssl_free_certinfo(struct Curl_easy *data)
+{
+ int i;
+ struct curl_certinfo *ci = &data->info.certs;
+
+ if(ci->num_of_certs) {
+ /* free all individual lists used */
+ for(i=0; i<ci->num_of_certs; i++) {
+ curl_slist_free_all(ci->certinfo[i]);
+ ci->certinfo[i] = NULL;
+ }
+
+ free(ci->certinfo); /* free the actual array too */
+ ci->certinfo = NULL;
+ ci->num_of_certs = 0;
+ }
+}
+
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
+{
+ struct curl_certinfo *ci = &data->info.certs;
+ struct curl_slist **table;
+
+ /* Free any previous certificate information structures */
+ Curl_ssl_free_certinfo(data);
+
+ /* Allocate the required certificate information structures */
+ table = calloc((size_t) num, sizeof(struct curl_slist *));
+ if(!table)
+ return CURLE_OUT_OF_MEMORY;
+
+ ci->num_of_certs = num;
+ ci->certinfo = table;
+
+ return CURLE_OK;
+}
+
+/*
+ * 'value' is NOT a zero terminated string
+ */
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
+ int certnum,
+ const char *label,
+ const char *value,
+ size_t valuelen)
+{
+ struct curl_certinfo *ci = &data->info.certs;
+ char *output;
+ struct curl_slist *nl;
+ CURLcode result = CURLE_OK;
+ size_t labellen = strlen(label);
+ size_t outlen = labellen + 1 + valuelen + 1; /* label:value\0 */
+
+ output = malloc(outlen);
+ if(!output)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* sprintf the label and colon */
+ snprintf(output, outlen, "%s:", label);
+
+ /* memcpy the value (it might not be zero terminated) */
+ memcpy(&output[labellen+1], value, valuelen);
+
+ /* zero terminate the output */
+ output[labellen + 1 + valuelen] = 0;
+
+ nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
+ if(!nl) {
+ free(output);
+ curl_slist_free_all(ci->certinfo[certnum]);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ ci->certinfo[certnum] = nl;
+ return result;
+}
+
+/*
+ * This is a convenience function for push_certinfo_len that takes a zero
+ * terminated value.
+ */
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data,
+ int certnum,
+ const char *label,
+ const char *value)
+{
+ size_t valuelen = strlen(value);
+
+ return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
+CURLcode Curl_ssl_random(struct Curl_easy *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ return curlssl_random(data, entropy, length);
+}
+
+/*
+ * Public key pem to der conversion
+ */
+
+static CURLcode pubkey_pem_to_der(const char *pem,
+ unsigned char **der, size_t *der_len)
+{
+ char *stripped_pem, *begin_pos, *end_pos;
+ size_t pem_count, stripped_pem_count = 0, pem_len;
+ CURLcode result;
+
+ /* if no pem, exit. */
+ if(!pem)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ begin_pos = strstr(pem, "-----BEGIN PUBLIC KEY-----");
+ if(!begin_pos)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ pem_count = begin_pos - pem;
+ /* Invalid if not at beginning AND not directly following \n */
+ if(0 != pem_count && '\n' != pem[pem_count - 1])
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ /* 26 is length of "-----BEGIN PUBLIC KEY-----" */
+ pem_count += 26;
+
+ /* Invalid if not directly following \n */
+ end_pos = strstr(pem + pem_count, "\n-----END PUBLIC KEY-----");
+ if(!end_pos)
+ return CURLE_BAD_CONTENT_ENCODING;
+
+ pem_len = end_pos - pem;
+
+ stripped_pem = malloc(pem_len - pem_count + 1);
+ if(!stripped_pem)
+ return CURLE_OUT_OF_MEMORY;
+
+ /*
+ * Here we loop through the pem array one character at a time between the
+ * correct indices, and place each character that is not '\n' or '\r'
+ * into the stripped_pem array, which should represent the raw base64 string
+ */
+ while(pem_count < pem_len) {
+ if('\n' != pem[pem_count] && '\r' != pem[pem_count])
+ stripped_pem[stripped_pem_count++] = pem[pem_count];
+ ++pem_count;
+ }
+ /* Place the null terminator in the correct place */
+ stripped_pem[stripped_pem_count] = '\0';
+
+ result = Curl_base64_decode(stripped_pem, der, der_len);
+
+ Curl_safefree(stripped_pem);
+
+ return result;
+}
+
+/*
+ * Generic pinned public key check.
+ */
+
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+ const char *pinnedpubkey,
+ const unsigned char *pubkey, size_t pubkeylen)
+{
+ FILE *fp;
+ unsigned char *buf = NULL, *pem_ptr = NULL;
+ long filesize;
+ size_t size, pem_len;
+ CURLcode pem_read;
+ CURLcode result = CURLE_SSL_PINNEDPUBKEYNOTMATCH;
+#ifdef curlssl_sha256sum
+ CURLcode encode;
+ size_t encodedlen, pinkeylen;
+ char *encoded, *pinkeycopy, *begin_pos, *end_pos;
+ unsigned char *sha256sumdigest = NULL;
+#endif
+
+ /* if a path wasn't specified, don't pin */
+ if(!pinnedpubkey)
+ return CURLE_OK;
+ if(!pubkey || !pubkeylen)
+ return result;
+
+ /* only do this if pinnedpubkey starts with "sha256//", length 8 */
+ if(strncmp(pinnedpubkey, "sha256//", 8) == 0) {
+#ifdef curlssl_sha256sum
+ /* compute sha256sum of public key */
+ sha256sumdigest = malloc(SHA256_DIGEST_LENGTH);
+ if(!sha256sumdigest)
+ return CURLE_OUT_OF_MEMORY;
+ curlssl_sha256sum(pubkey, pubkeylen,
+ sha256sumdigest, SHA256_DIGEST_LENGTH);
+ encode = Curl_base64_encode(data, (char *)sha256sumdigest,
+ SHA256_DIGEST_LENGTH, &encoded, &encodedlen);
+ Curl_safefree(sha256sumdigest);
+
+ if(encode)
+ return encode;
+
+ infof(data, "\t public key hash: sha256//%s\n", encoded);
+
+ /* it starts with sha256//, copy so we can modify it */
+ pinkeylen = strlen(pinnedpubkey) + 1;
+ pinkeycopy = malloc(pinkeylen);
+ if(!pinkeycopy) {
+ Curl_safefree(encoded);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(pinkeycopy, pinnedpubkey, pinkeylen);
+ /* point begin_pos to the copy, and start extracting keys */
+ begin_pos = pinkeycopy;
+ do {
+ end_pos = strstr(begin_pos, ";sha256//");
+ /*
+ * if there is an end_pos, null terminate,
+ * otherwise it'll go to the end of the original string
+ */
+ if(end_pos)
+ end_pos[0] = '\0';
+
+ /* compare base64 sha256 digests, 8 is the length of "sha256//" */
+ if(encodedlen == strlen(begin_pos + 8) &&
+ !memcmp(encoded, begin_pos + 8, encodedlen)) {
+ result = CURLE_OK;
+ break;
+ }
+
+ /*
+ * change back the null-terminator we changed earlier,
+ * and look for next begin
+ */
+ if(end_pos) {
+ end_pos[0] = ';';
+ begin_pos = strstr(end_pos, "sha256//");
+ }
+ } while(end_pos && begin_pos);
+ Curl_safefree(encoded);
+ Curl_safefree(pinkeycopy);
+#else
+ /* without sha256 support, this cannot match */
+ (void)data;
+#endif
+ return result;
+ }
+
+ fp = fopen(pinnedpubkey, "rb");
+ if(!fp)
+ return result;
+
+ do {
+ /* Determine the file's size */
+ if(fseek(fp, 0, SEEK_END))
+ break;
+ filesize = ftell(fp);
+ if(fseek(fp, 0, SEEK_SET))
+ break;
+ if(filesize < 0 || filesize > MAX_PINNED_PUBKEY_SIZE)
+ break;
+
+ /*
+ * if the size of our certificate is bigger than the file
+ * size then it can't match
+ */
+ size = curlx_sotouz((curl_off_t) filesize);
+ if(pubkeylen > size)
+ break;
+
+ /*
+ * Allocate buffer for the pinned key
+ * With 1 additional byte for null terminator in case of PEM key
+ */
+ buf = malloc(size + 1);
+ if(!buf)
+ break;
+
+ /* Returns number of elements read, which should be 1 */
+ if((int) fread(buf, size, 1, fp) != 1)
+ break;
+
+ /* If the sizes are the same, it can't be base64 encoded, must be der */
+ if(pubkeylen == size) {
+ if(!memcmp(pubkey, buf, pubkeylen))
+ result = CURLE_OK;
+ break;
+ }
+
+ /*
+ * Otherwise we will assume it's PEM and try to decode it
+ * after placing null terminator
+ */
+ buf[size] = '\0';
+ pem_read = pubkey_pem_to_der((const char *)buf, &pem_ptr, &pem_len);
+ /* if it wasn't read successfully, exit */
+ if(pem_read)
+ break;
+
+ /*
+ * if the size of our certificate doesn't match the size of
+ * the decoded file, they can't be the same, otherwise compare
+ */
+ if(pubkeylen == pem_len && !memcmp(pubkey, pem_ptr, pubkeylen))
+ result = CURLE_OK;
+ } while(0);
+
+ Curl_safefree(buf);
+ Curl_safefree(pem_ptr);
+ fclose(fp);
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+#ifdef curlssl_md5sum
+ curlssl_md5sum(tmp, tmplen, md5sum, md5len);
+#else
+ MD5_context *MD5pw;
+
+ (void) md5len;
+
+ MD5pw = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!MD5pw)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_MD5_update(MD5pw, tmp, curlx_uztoui(tmplen));
+ Curl_MD5_final(MD5pw, md5sum);
+#endif
+ return CURLE_OK;
+}
+#endif
+
+/*
+ * Check whether the SSL backend supports the status_request extension.
+ */
+bool Curl_ssl_cert_status_request(void)
+{
+#ifdef curlssl_cert_status_request
+ return curlssl_cert_status_request();
+#else
+ return FALSE;
+#endif
+}
+
+/*
+ * Check whether the SSL backend supports false start.
+ */
+bool Curl_ssl_false_start(void)
+{
+#ifdef curlssl_false_start
+ return curlssl_false_start();
+#else
+ return FALSE;
+#endif
+}
+
+#endif /* USE_SSL */
diff --git a/Utilities/cmcurl/lib/vtls/vtls.h b/Utilities/cmcurl/lib/vtls/vtls.h
new file mode 100644
index 000000000..2aabeda20
--- /dev/null
+++ b/Utilities/cmcurl/lib/vtls/vtls.h
@@ -0,0 +1,202 @@
+#ifndef HEADER_CURL_VTLS_H
+#define HEADER_CURL_VTLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include "openssl.h" /* OpenSSL versions */
+#include "gtls.h" /* GnuTLS versions */
+#include "nssg.h" /* NSS versions */
+#include "gskit.h" /* Global Secure ToolKit versions */
+#include "polarssl.h" /* PolarSSL versions */
+#include "axtls.h" /* axTLS versions */
+#include "cyassl.h" /* CyaSSL versions */
+#include "schannel.h" /* Schannel SSPI version */
+#include "darwinssl.h" /* SecureTransport (Darwin) version */
+#include "mbedtls.h" /* mbedTLS versions */
+
+#ifndef MAX_PINNED_PUBKEY_SIZE
+#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
+#endif
+
+#ifndef MD5_DIGEST_LENGTH
+#define MD5_DIGEST_LENGTH 16 /* fixed size */
+#endif
+
+#ifndef SHA256_DIGEST_LENGTH
+#define SHA256_DIGEST_LENGTH 32 /* fixed size */
+#endif
+
+/* see https://tools.ietf.org/html/draft-ietf-tls-applayerprotoneg-04 */
+#define ALPN_HTTP_1_1_LENGTH 8
+#define ALPN_HTTP_1_1 "http/1.1"
+
+/* set of helper macros for the backends to access the correct fields. For the
+ proxy or for the remote host - to properly support HTTPS proxy */
+
+#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
+ ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
+ CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
+#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \
+ data->set.ssl.var)
+#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \
+ conn->proxy_ssl_config.var : conn->ssl_config.var)
+
+bool Curl_ssl_config_matches(struct ssl_primary_config* data,
+ struct ssl_primary_config* needle);
+bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
+ struct ssl_primary_config *dest);
+void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc);
+int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+
+int Curl_ssl_backend(void);
+
+#ifdef USE_SSL
+int Curl_ssl_init(void);
+void Curl_ssl_cleanup(void);
+CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+/* tell the SSL stuff to close down all open information regarding
+ connections (and thus session ID caching etc) */
+void Curl_ssl_close_all(struct Curl_easy *data);
+void Curl_ssl_close(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_set_engine(struct Curl_easy *data, const char *engine);
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ssl_set_engine_default(struct Curl_easy *data);
+struct curl_slist *Curl_ssl_engines_list(struct Curl_easy *data);
+
+/* init the SSL session ID cache */
+CURLcode Curl_ssl_initsessions(struct Curl_easy *, size_t);
+size_t Curl_ssl_version(char *buffer, size_t size);
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+ int connindex);
+int Curl_ssl_check_cxn(struct connectdata *conn);
+
+/* Certificate information list handling. */
+
+void Curl_ssl_free_certinfo(struct Curl_easy *data);
+CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data, int certnum,
+ const char *label, const char *value,
+ size_t valuelen);
+CURLcode Curl_ssl_push_certinfo(struct Curl_easy *data, int certnum,
+ const char *label, const char *value);
+
+/* Functions to be used by SSL library adaptation functions */
+
+/* Lock session cache mutex.
+ * Call this before calling other Curl_ssl_*session* functions
+ * Caller should unlock this mutex as soon as possible, as it may block
+ * other SSL connection from making progress.
+ * The purpose of explicitly locking SSL session cache data is to allow
+ * individual SSL engines to manage session lifetime in their specific way.
+ */
+void Curl_ssl_sessionid_lock(struct connectdata *conn);
+
+/* Unlock session cache mutex */
+void Curl_ssl_sessionid_unlock(struct connectdata *conn);
+
+/* extract a session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must make sure that the ownership of returned sessionid object
+ * is properly taken (e.g. its refcount is incremented
+ * under sessionid mutex).
+ */
+bool Curl_ssl_getsessionid(struct connectdata *conn,
+ void **ssl_sessionid,
+ size_t *idsize, /* set 0 if unknown */
+ int sockindex);
+/* add a new session ID
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * Caller must ensure that it has properly shared ownership of this sessionid
+ * object with cache (e.g. incrementing refcount on success)
+ */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+ void *ssl_sessionid,
+ size_t idsize,
+ int sockindex);
+/* Kill a single session ID entry in the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
+void Curl_ssl_kill_session(struct curl_ssl_session *session);
+/* delete a session from the cache
+ * Sessionid mutex must be locked (see Curl_ssl_sessionid_lock).
+ * This will call engine-specific curlssl_session_free function, which must
+ * take sessionid object ownership from sessionid cache
+ * (e.g. decrement refcount).
+ */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
+
+/* get N random bytes into the buffer */
+CURLcode Curl_ssl_random(struct Curl_easy *data, unsigned char *buffer,
+ size_t length);
+CURLcode Curl_ssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len);
+/* Check pinned public key. */
+CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data,
+ const char *pinnedpubkey,
+ const unsigned char *pubkey, size_t pubkeylen);
+
+bool Curl_ssl_cert_status_request(void);
+
+bool Curl_ssl_false_start(void);
+
+#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+
+#else
+/* Set the API backend definition to none */
+#define CURL_SSL_BACKEND CURLSSLBACKEND_NONE
+
+/* When SSL support is not present, just define away these function calls */
+#define Curl_ssl_init() 1
+#define Curl_ssl_cleanup() Curl_nop_stmt
+#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_close_all(x) Curl_nop_stmt
+#define Curl_ssl_close(x,y) Curl_nop_stmt
+#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
+#define Curl_ssl_engines_list(x) NULL
+#define Curl_ssl_send(a,b,c,d,e) -1
+#define Curl_ssl_recv(a,b,c,d,e) -1
+#define Curl_ssl_initsessions(x,y) CURLE_OK
+#define Curl_ssl_version(x,y) 0
+#define Curl_ssl_data_pending(x,y) 0
+#define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
+#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN
+#define Curl_ssl_kill_session(x) Curl_nop_stmt
+#define Curl_ssl_random(x,y,z) ((void)x, CURLE_NOT_BUILT_IN)
+#define Curl_ssl_cert_status_request() FALSE
+#define Curl_ssl_false_start() FALSE
+#endif
+
+#endif /* HEADER_CURL_VTLS_H */
diff --git a/Utilities/cmcurl/lib/warnless.c b/Utilities/cmcurl/lib/warnless.c
new file mode 100644
index 000000000..fb085c86d
--- /dev/null
+++ b/Utilities/cmcurl/lib/warnless.c
@@ -0,0 +1,546 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#define BUILDING_WARNLESS_C 1
+
+#include "warnless.h"
+
+#define CURL_MASK_SCHAR 0x7F
+#define CURL_MASK_UCHAR 0xFF
+
+#if (SIZEOF_SHORT == 2)
+# define CURL_MASK_SSHORT 0x7FFF
+# define CURL_MASK_USHORT 0xFFFF
+#elif (SIZEOF_SHORT == 4)
+# define CURL_MASK_SSHORT 0x7FFFFFFF
+# define CURL_MASK_USHORT 0xFFFFFFFF
+#elif (SIZEOF_SHORT == 8)
+# define CURL_MASK_SSHORT 0x7FFFFFFFFFFFFFFF
+# define CURL_MASK_USHORT 0xFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_SHORT not defined"
+#endif
+
+#if (SIZEOF_INT == 2)
+# define CURL_MASK_SINT 0x7FFF
+# define CURL_MASK_UINT 0xFFFF
+#elif (SIZEOF_INT == 4)
+# define CURL_MASK_SINT 0x7FFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFF
+#elif (SIZEOF_INT == 8)
+# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFF
+#elif (SIZEOF_INT == 16)
+# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_INT not defined"
+#endif
+
+#if (CURL_SIZEOF_LONG == 2)
+# define CURL_MASK_SLONG 0x7FFFL
+# define CURL_MASK_ULONG 0xFFFFUL
+#elif (CURL_SIZEOF_LONG == 4)
+# define CURL_MASK_SLONG 0x7FFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 8)
+# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 16)
+# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
+#else
+# error "CURL_SIZEOF_LONG not defined"
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T == 2)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 4)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 8)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 16)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+#else
+# error "CURL_SIZEOF_CURL_OFF_T not defined"
+#endif
+
+#if (SIZEOF_SIZE_T == SIZEOF_SHORT)
+# define CURL_MASK_SSIZE_T CURL_MASK_SSHORT
+# define CURL_MASK_USIZE_T CURL_MASK_USHORT
+#elif (SIZEOF_SIZE_T == SIZEOF_INT)
+# define CURL_MASK_SSIZE_T CURL_MASK_SINT
+# define CURL_MASK_USIZE_T CURL_MASK_UINT
+#elif (SIZEOF_SIZE_T == CURL_SIZEOF_LONG)
+# define CURL_MASK_SSIZE_T CURL_MASK_SLONG
+# define CURL_MASK_USIZE_T CURL_MASK_ULONG
+#elif (SIZEOF_SIZE_T == CURL_SIZEOF_CURL_OFF_T)
+# define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT
+# define CURL_MASK_USIZE_T CURL_MASK_UCOFFT
+#else
+# error "SIZEOF_SIZE_T not defined"
+#endif
+
+/*
+** unsigned long to unsigned short
+*/
+
+unsigned short curlx_ultous(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
+ return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to unsigned char
+*/
+
+unsigned char curlx_ultouc(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR);
+ return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to signed int
+*/
+
+int curlx_ultosi(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT);
+ return (int)(ulnum & (unsigned long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed curl_off_t
+*/
+
+curl_off_t curlx_uztoso(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#elif defined(_MSC_VER)
+# pragma warning(push)
+# pragma warning(disable:4310) /* cast truncates constant value */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SCOFFT);
+ return (curl_off_t)(uznum & (size_t) CURL_MASK_SCOFFT);
+
+#if defined(__INTEL_COMPILER) || defined(_MSC_VER)
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed int
+*/
+
+int curlx_uztosi(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT);
+ return (int)(uznum & (size_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned long
+*/
+
+unsigned long curlx_uztoul(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if (CURL_SIZEOF_LONG < SIZEOF_SIZE_T)
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
+#endif
+ return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned int
+*/
+
+unsigned int curlx_uztoui(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if (SIZEOF_INT < SIZEOF_SIZE_T)
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to signed int
+*/
+
+int curlx_sltosi(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
+#endif
+ return (int)(slnum & (long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned int
+*/
+
+unsigned int curlx_sltoui(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(slnum & (long) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned short
+*/
+
+unsigned short curlx_sltous(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT);
+ return (unsigned short)(slnum & (long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed ssize_t
+*/
+
+ssize_t curlx_uztosz(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T);
+ return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed curl_off_t to unsigned size_t
+*/
+
+size_t curlx_sotouz(curl_off_t sonum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sonum >= 0);
+ return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed ssize_t to signed int
+*/
+
+int curlx_sztosi(ssize_t sznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sznum >= 0);
+#if (SIZEOF_INT < SIZEOF_SIZE_T)
+ DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
+#endif
+ return (int)(sznum & (ssize_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to unsigned short
+*/
+
+unsigned short curlx_uitous(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_USHORT);
+ return (unsigned short) (uinum & (unsigned int) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to unsigned char
+*/
+
+unsigned char curlx_uitouc(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_UCHAR);
+ return (unsigned char) (uinum & (unsigned int) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned int to signed int
+*/
+
+int curlx_uitosi(unsigned int uinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uinum <= (unsigned int) CURL_MASK_SINT);
+ return (int) (uinum & (unsigned int) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to unsigned size_t
+*/
+
+size_t curlx_sitouz(int sinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sinum >= 0);
+ return (size_t) sinum;
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/*
+** curl_socket_t to signed int
+*/
+
+int curlx_sktosi(curl_socket_t s)
+{
+ return (int)((ssize_t) s);
+}
+
+/*
+** signed int to curl_socket_t
+*/
+
+curl_socket_t curlx_sitosk(int i)
+{
+ return (curl_socket_t)((ssize_t) i);
+}
+
+#endif /* USE_WINSOCK */
+
+#if defined(WIN32) || defined(_WIN32)
+
+ssize_t curlx_read(int fd, void *buf, size_t count)
+{
+ return (ssize_t)read(fd, buf, curlx_uztoui(count));
+}
+
+ssize_t curlx_write(int fd, const void *buf, size_t count)
+{
+ return (ssize_t)write(fd, buf, curlx_uztoui(count));
+}
+
+#endif /* WIN32 || _WIN32 */
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:1469) /* clobber ignored */
+ return FD_ISSET(fd, fdset);
+ #pragma warning(pop)
+}
+
+void curlx_FD_SET(int fd, fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:1469) /* clobber ignored */
+ FD_SET(fd, fdset);
+ #pragma warning(pop)
+}
+
+void curlx_FD_ZERO(fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:593) /* variable was set but never used */
+ FD_ZERO(fdset);
+ #pragma warning(pop)
+}
+
+unsigned short curlx_htons(unsigned short usnum)
+{
+#if (__INTEL_COMPILER == 910) && defined(__i386__)
+ return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF));
+#else
+ #pragma warning(push)
+ #pragma warning(disable:810) /* conversion may lose significant bits */
+ return htons(usnum);
+ #pragma warning(pop)
+#endif
+}
+
+unsigned short curlx_ntohs(unsigned short usnum)
+{
+#if (__INTEL_COMPILER == 910) && defined(__i386__)
+ return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF));
+#else
+ #pragma warning(push)
+ #pragma warning(disable:810) /* conversion may lose significant bits */
+ return ntohs(usnum);
+ #pragma warning(pop)
+#endif
+}
+
+#endif /* __INTEL_COMPILER && __unix__ */
diff --git a/Utilities/cmcurl/lib/warnless.h b/Utilities/cmcurl/lib/warnless.h
new file mode 100644
index 000000000..ab6d29998
--- /dev/null
+++ b/Utilities/cmcurl/lib/warnless.h
@@ -0,0 +1,113 @@
+#ifndef HEADER_CURL_WARNLESS_H
+#define HEADER_CURL_WARNLESS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#ifdef USE_WINSOCK
+#include <curl/curl.h> /* for curl_socket_t */
+#endif
+
+unsigned short curlx_ultous(unsigned long ulnum);
+
+unsigned char curlx_ultouc(unsigned long ulnum);
+
+int curlx_ultosi(unsigned long ulnum);
+
+int curlx_uztosi(size_t uznum);
+
+curl_off_t curlx_uztoso(size_t uznum);
+
+unsigned long curlx_uztoul(size_t uznum);
+
+unsigned int curlx_uztoui(size_t uznum);
+
+int curlx_sltosi(long slnum);
+
+unsigned int curlx_sltoui(long slnum);
+
+unsigned short curlx_sltous(long slnum);
+
+ssize_t curlx_uztosz(size_t uznum);
+
+size_t curlx_sotouz(curl_off_t sonum);
+
+int curlx_sztosi(ssize_t sznum);
+
+unsigned short curlx_uitous(unsigned int uinum);
+
+unsigned char curlx_uitouc(unsigned int uinum);
+
+int curlx_uitosi(unsigned int uinum);
+
+size_t curlx_sitouz(int sinum);
+
+#ifdef USE_WINSOCK
+
+int curlx_sktosi(curl_socket_t s);
+
+curl_socket_t curlx_sitosk(int i);
+
+#endif /* USE_WINSOCK */
+
+#if defined(WIN32) || defined(_WIN32)
+
+ssize_t curlx_read(int fd, void *buf, size_t count);
+
+ssize_t curlx_write(int fd, const void *buf, size_t count);
+
+#ifndef BUILDING_WARNLESS_C
+# undef read
+# define read(fd, buf, count) curlx_read(fd, buf, count)
+# undef write
+# define write(fd, buf, count) curlx_write(fd, buf, count)
+#endif
+
+#endif /* WIN32 || _WIN32 */
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset);
+
+void curlx_FD_SET(int fd, fd_set *fdset);
+
+void curlx_FD_ZERO(fd_set *fdset);
+
+unsigned short curlx_htons(unsigned short usnum);
+
+unsigned short curlx_ntohs(unsigned short usnum);
+
+#ifndef BUILDING_WARNLESS_C
+# undef FD_ISSET
+# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b))
+# undef FD_SET
+# define FD_SET(a,b) curlx_FD_SET((a),(b))
+# undef FD_ZERO
+# define FD_ZERO(a) curlx_FD_ZERO((a))
+# undef htons
+# define htons(a) curlx_htons((a))
+# undef ntohs
+# define ntohs(a) curlx_ntohs((a))
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#endif /* HEADER_CURL_WARNLESS_H */
diff --git a/Utilities/cmcurl/lib/wildcard.c b/Utilities/cmcurl/lib/wildcard.c
new file mode 100644
index 000000000..af45c79bd
--- /dev/null
+++ b/Utilities/cmcurl/lib/wildcard.c
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "wildcard.h"
+#include "llist.h"
+#include "fileinfo.h"
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc)
+{
+ Curl_llist_init(&wc->filelist, Curl_fileinfo_dtor);
+ wc->state = CURLWC_INIT;
+
+ return CURLE_OK;
+}
+
+void Curl_wildcard_dtor(struct WildcardData *wc)
+{
+ if(!wc)
+ return;
+
+ if(wc->tmp_dtor) {
+ wc->tmp_dtor(wc->tmp);
+ wc->tmp_dtor = ZERO_NULL;
+ wc->tmp = NULL;
+ }
+ DEBUGASSERT(wc->tmp == NULL);
+
+ Curl_llist_destroy(&wc->filelist, NULL);
+
+
+ free(wc->path);
+ wc->path = NULL;
+ free(wc->pattern);
+ wc->pattern = NULL;
+
+ wc->customptr = NULL;
+ wc->state = CURLWC_INIT;
+}
diff --git a/Utilities/cmcurl/lib/wildcard.h b/Utilities/cmcurl/lib/wildcard.h
new file mode 100644
index 000000000..8a5e4b769
--- /dev/null
+++ b/Utilities/cmcurl/lib/wildcard.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_WILDCARD_H
+#define HEADER_CURL_WILDCARD_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include <curl/curl.h>
+
+#include "llist.h"
+
+/* list of wildcard process states */
+typedef enum {
+ CURLWC_CLEAR = 0,
+ CURLWC_INIT = 1,
+ CURLWC_MATCHING, /* library is trying to get list of addresses for
+ downloading */
+ CURLWC_DOWNLOADING,
+ CURLWC_CLEAN, /* deallocate resources and reset settings */
+ CURLWC_SKIP, /* skip over concrete file */
+ CURLWC_ERROR, /* error cases */
+ CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop
+ will end */
+} curl_wildcard_states;
+
+typedef void (*curl_wildcard_tmp_dtor)(void *ptr);
+
+/* struct keeping information about wildcard download process */
+struct WildcardData {
+ curl_wildcard_states state;
+ char *path; /* path to the directory, where we trying wildcard-match */
+ char *pattern; /* wildcard pattern */
+ struct curl_llist filelist; /* llist with struct Curl_fileinfo */
+ void *tmp; /* pointer to protocol specific temporary data */
+ curl_wildcard_tmp_dtor tmp_dtor;
+ void *customptr; /* for CURLOPT_CHUNK_DATA pointer */
+};
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc);
+void Curl_wildcard_dtor(struct WildcardData *wc);
+
+struct Curl_easy;
+
+#endif /* HEADER_CURL_WILDCARD_H */
diff --git a/Utilities/cmcurl/lib/x509asn1.c b/Utilities/cmcurl/lib/x509asn1.c
new file mode 100644
index 000000000..bba20233f
--- /dev/null
+++ b/Utilities/cmcurl/lib/x509asn1.c
@@ -0,0 +1,1200 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
+ defined(USE_CYASSL) || defined(USE_SCHANNEL)
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "strcase.h"
+#include "hostcheck.h"
+#include "vtls/vtls.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "curl_base64.h"
+#include "x509asn1.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/* For overflow checks. */
+#define CURL_SIZE_T_MAX ((size_t)-1)
+
+
+/* ASN.1 OIDs. */
+static const char cnOID[] = "2.5.4.3"; /* Common name. */
+static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
+
+static const curl_OID OIDtable[] = {
+ { "1.2.840.10040.4.1", "dsa" },
+ { "1.2.840.10040.4.3", "dsa-with-sha1" },
+ { "1.2.840.10045.2.1", "ecPublicKey" },
+ { "1.2.840.10045.3.0.1", "c2pnb163v1" },
+ { "1.2.840.10045.4.1", "ecdsa-with-SHA1" },
+ { "1.2.840.10046.2.1", "dhpublicnumber" },
+ { "1.2.840.113549.1.1.1", "rsaEncryption" },
+ { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" },
+ { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" },
+ { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" },
+ { "1.2.840.113549.1.1.10", "RSASSA-PSS" },
+ { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" },
+ { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" },
+ { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" },
+ { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" },
+ { "1.2.840.113549.2.2", "md2" },
+ { "1.2.840.113549.2.5", "md5" },
+ { "1.3.14.3.2.26", "sha1" },
+ { cnOID, "CN" },
+ { "2.5.4.4", "SN" },
+ { "2.5.4.5", "serialNumber" },
+ { "2.5.4.6", "C" },
+ { "2.5.4.7", "L" },
+ { "2.5.4.8", "ST" },
+ { "2.5.4.9", "streetAddress" },
+ { "2.5.4.10", "O" },
+ { "2.5.4.11", "OU" },
+ { "2.5.4.12", "title" },
+ { "2.5.4.13", "description" },
+ { "2.5.4.17", "postalCode" },
+ { "2.5.4.41", "name" },
+ { "2.5.4.42", "givenName" },
+ { "2.5.4.43", "initials" },
+ { "2.5.4.44", "generationQualifier" },
+ { "2.5.4.45", "X500UniqueIdentifier" },
+ { "2.5.4.46", "dnQualifier" },
+ { "2.5.4.65", "pseudonym" },
+ { "1.2.840.113549.1.9.1", "emailAddress" },
+ { "2.5.4.72", "role" },
+ { sanOID, "subjectAltName" },
+ { "2.5.29.18", "issuerAltName" },
+ { "2.5.29.19", "basicConstraints" },
+ { "2.16.840.1.101.3.4.2.4", "sha224" },
+ { "2.16.840.1.101.3.4.2.1", "sha256" },
+ { "2.16.840.1.101.3.4.2.2", "sha384" },
+ { "2.16.840.1.101.3.4.2.3", "sha512" },
+ { (const char *) NULL, (const char *) NULL }
+};
+
+/*
+ * Lightweight ASN.1 parser.
+ * In particular, it does not check for syntactic/lexical errors.
+ * It is intended to support certificate information gathering for SSL backends
+ * that offer a mean to get certificates as a whole, but do not supply
+ * entry points to get particular certificate sub-fields.
+ * Please note there is no pretention here to rewrite a full SSL library.
+ */
+
+
+const char *Curl_getASN1Element(curl_asn1Element *elem,
+ const char *beg, const char *end)
+{
+ unsigned char b;
+ unsigned long len;
+ curl_asn1Element lelem;
+
+ /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
+ ending at `end'.
+ Returns a pointer in source string after the parsed element, or NULL
+ if an error occurs. */
+ if(!beg || !end || beg >= end || !*beg ||
+ (size_t)(end - beg) > CURL_ASN1_MAX)
+ return (const char *) NULL;
+
+ /* Process header byte. */
+ elem->header = beg;
+ b = (unsigned char) *beg++;
+ elem->constructed = (b & 0x20) != 0;
+ elem->class = (b >> 6) & 3;
+ b &= 0x1F;
+ if(b == 0x1F)
+ return (const char *) NULL; /* Long tag values not supported here. */
+ elem->tag = b;
+
+ /* Process length. */
+ if(beg >= end)
+ return (const char *) NULL;
+ b = (unsigned char) *beg++;
+ if(!(b & 0x80))
+ len = b;
+ else if(!(b &= 0x7F)) {
+ /* Unspecified length. Since we have all the data, we can determine the
+ effective length by skipping element until an end element is found. */
+ if(!elem->constructed)
+ return (const char *) NULL;
+ elem->beg = beg;
+ while(beg < end && *beg) {
+ beg = Curl_getASN1Element(&lelem, beg, end);
+ if(!beg)
+ return (const char *) NULL;
+ }
+ if(beg >= end)
+ return (const char *) NULL;
+ elem->end = beg;
+ return beg + 1;
+ }
+ else if((unsigned)b > (size_t)(end - beg))
+ return (const char *) NULL; /* Does not fit in source. */
+ else {
+ /* Get long length. */
+ len = 0;
+ do {
+ if(len & 0xFF000000L)
+ return (const char *) NULL; /* Lengths > 32 bits are not supported. */
+ len = (len << 8) | (unsigned char) *beg++;
+ } while(--b);
+ }
+ if(len > (size_t)(end - beg))
+ return (const char *) NULL; /* Element data does not fit in source. */
+ elem->beg = beg;
+ elem->end = beg + len;
+ return elem->end;
+}
+
+static const curl_OID * searchOID(const char *oid)
+{
+ const curl_OID *op;
+
+ /* Search the null terminated OID or OID identifier in local table.
+ Return the table entry pointer or NULL if not found. */
+
+ for(op = OIDtable; op->numoid; op++)
+ if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
+ return op;
+
+ return (const curl_OID *) NULL;
+}
+
+static const char *bool2str(const char *beg, const char *end)
+{
+ /* Convert an ASN.1 Boolean value into its string representation.
+ Return the dynamically allocated string, or NULL if source is not an
+ ASN.1 Boolean value. */
+
+ if(end - beg != 1)
+ return (const char *) NULL;
+ return strdup(*beg? "TRUE": "FALSE");
+}
+
+static const char *octet2str(const char *beg, const char *end)
+{
+ size_t n = end - beg;
+ char *buf = NULL;
+
+ /* Convert an ASN.1 octet string to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(n <= (CURL_SIZE_T_MAX - 1) / 3) {
+ buf = malloc(3 * n + 1);
+ if(buf)
+ for(n = 0; beg < end; n += 3)
+ snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
+ }
+ return buf;
+}
+
+static const char *bit2str(const char *beg, const char *end)
+{
+ /* Convert an ASN.1 bit string to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(++beg > end)
+ return (const char *) NULL;
+ return octet2str(beg, end);
+}
+
+static const char *int2str(const char *beg, const char *end)
+{
+ long val = 0;
+ size_t n = end - beg;
+
+ /* Convert an ASN.1 integer value into its string representation.
+ Return the dynamically allocated string, or NULL if source is not an
+ ASN.1 integer value. */
+
+ if(!n)
+ return (const char *) NULL;
+
+ if(n > 4)
+ return octet2str(beg, end);
+
+ /* Represent integers <= 32-bit as a single value. */
+ if(*beg & 0x80)
+ val = ~val;
+
+ do
+ val = (val << 8) | *(const unsigned char *) beg++;
+ while(beg < end);
+ return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val);
+}
+
+static ssize_t
+utf8asn1str(char **to, int type, const char *from, const char *end)
+{
+ size_t inlength = end - from;
+ int size = 1;
+ size_t outlength;
+ int charsize;
+ unsigned int wc;
+ char *buf;
+
+ /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
+ destination buffer dynamically. The allocation size will normally be too
+ large: this is to avoid buffer overflows.
+ Terminate the string with a nul byte and return the converted
+ string length. */
+
+ *to = (char *) NULL;
+ switch(type) {
+ case CURL_ASN1_BMP_STRING:
+ size = 2;
+ break;
+ case CURL_ASN1_UNIVERSAL_STRING:
+ size = 4;
+ break;
+ case CURL_ASN1_NUMERIC_STRING:
+ case CURL_ASN1_PRINTABLE_STRING:
+ case CURL_ASN1_TELETEX_STRING:
+ case CURL_ASN1_IA5_STRING:
+ case CURL_ASN1_VISIBLE_STRING:
+ case CURL_ASN1_UTF8_STRING:
+ break;
+ default:
+ return -1; /* Conversion not supported. */
+ }
+
+ if(inlength % size)
+ return -1; /* Length inconsistent with character size. */
+ if(inlength / size > (CURL_SIZE_T_MAX - 1) / 4)
+ return -1; /* Too big. */
+ buf = malloc(4 * (inlength / size) + 1);
+ if(!buf)
+ return -1; /* Not enough memory. */
+
+ if(type == CURL_ASN1_UTF8_STRING) {
+ /* Just copy. */
+ outlength = inlength;
+ if(outlength)
+ memcpy(buf, from, outlength);
+ }
+ else {
+ for(outlength = 0; from < end;) {
+ wc = 0;
+ switch(size) {
+ case 4:
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ /* fallthrough */
+ case 2:
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ /* fallthrough */
+ default: /* case 1: */
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ }
+ charsize = 1;
+ if(wc >= 0x00000080) {
+ if(wc >= 0x00000800) {
+ if(wc >= 0x00010000) {
+ if(wc >= 0x00200000) {
+ free(buf);
+ return -1; /* Invalid char. size for target encoding. */
+ }
+ buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x00010000;
+ charsize++;
+ }
+ buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x00000800;
+ charsize++;
+ }
+ buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x000000C0;
+ charsize++;
+ }
+ buf[outlength] = (char) wc;
+ outlength += charsize;
+ }
+ }
+ buf[outlength] = '\0';
+ *to = buf;
+ return outlength;
+}
+
+static const char *string2str(int type, const char *beg, const char *end)
+{
+ char *buf;
+
+ /* Convert an ASN.1 String into its UTF-8 string representation.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(utf8asn1str(&buf, type, beg, end) < 0)
+ return (const char *) NULL;
+ return buf;
+}
+
+static int encodeUint(char *buf, int n, unsigned int x)
+{
+ int i = 0;
+ unsigned int y = x / 10;
+
+ /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'.
+ Return the total number of encoded digits, even if larger than `n'. */
+
+ if(y) {
+ i += encodeUint(buf, n, y);
+ x -= y * 10;
+ }
+ if(i < n)
+ buf[i] = (char) ('0' + x);
+ i++;
+ if(i < n)
+ buf[i] = '\0'; /* Store a terminator if possible. */
+ return i;
+}
+
+static int encodeOID(char *buf, int n, const char *beg, const char *end)
+{
+ int i = 0;
+ unsigned int x;
+ unsigned int y;
+
+ /* Convert an ASN.1 OID into its dotted string representation.
+ Store the result in th `n'-byte buffer at `buf'.
+ Return the converted string length, or -1 if an error occurs. */
+
+ /* Process the first two numbers. */
+ y = *(const unsigned char *) beg++;
+ x = y / 40;
+ y -= x * 40;
+ i += encodeUint(buf + i, n - i, x);
+ if(i < n)
+ buf[i] = '.';
+ i++;
+ i += encodeUint(buf + i, n - i, y);
+
+ /* Process the trailing numbers. */
+ while(beg < end) {
+ if(i < n)
+ buf[i] = '.';
+ i++;
+ x = 0;
+ do {
+ if(x & 0xFF000000)
+ return -1;
+ y = *(const unsigned char *) beg++;
+ x = (x << 7) | (y & 0x7F);
+ } while(y & 0x80);
+ i += encodeUint(buf + i, n - i, x);
+ }
+ if(i < n)
+ buf[i] = '\0';
+ return i;
+}
+
+static const char *OID2str(const char *beg, const char *end, bool symbolic)
+{
+ char *buf = (char *) NULL;
+ const curl_OID * op;
+ int n;
+
+ /* Convert an ASN.1 OID into its dotted or symbolic string representation.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(beg < end) {
+ n = encodeOID((char *) NULL, -1, beg, end);
+ if(n >= 0) {
+ buf = malloc(n + 1);
+ if(buf) {
+ encodeOID(buf, n, beg, end);
+ buf[n] = '\0';
+
+ if(symbolic) {
+ op = searchOID(buf);
+ if(op) {
+ free(buf);
+ buf = strdup(op->textoid);
+ }
+ }
+ }
+ }
+ }
+ return buf;
+}
+
+static const char *GTime2str(const char *beg, const char *end)
+{
+ const char *tzp;
+ const char *fracp;
+ char sec1, sec2;
+ size_t fracl;
+ size_t tzl;
+ const char *sep = "";
+
+ /* Convert an ASN.1 Generalized time to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
+ ;
+
+ /* Get seconds digits. */
+ sec1 = '0';
+ switch(fracp - beg - 12) {
+ case 0:
+ sec2 = '0';
+ break;
+ case 2:
+ sec1 = fracp[-2];
+ /* FALLTHROUGH */
+ case 1:
+ sec2 = fracp[-1];
+ break;
+ default:
+ return (const char *) NULL;
+ }
+
+ /* Scan for timezone, measure fractional seconds. */
+ tzp = fracp;
+ fracl = 0;
+ if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+ fracp++;
+ do
+ tzp++;
+ while(tzp < end && *tzp >= '0' && *tzp <= '9');
+ /* Strip leading zeroes in fractional seconds. */
+ for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+ ;
+ }
+
+ /* Process timezone. */
+ if(tzp >= end)
+ ; /* Nothing to do. */
+ else if(*tzp == 'Z') {
+ tzp = " GMT";
+ end = tzp + 4;
+ }
+ else {
+ sep = " ";
+ tzp++;
+ }
+
+ tzl = end - tzp;
+ return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+ beg, beg + 4, beg + 6,
+ beg + 8, beg + 10, sec1, sec2,
+ fracl? ".": "", fracl, fracp,
+ sep, tzl, tzp);
+}
+
+static const char *UTime2str(const char *beg, const char *end)
+{
+ const char *tzp;
+ size_t tzl;
+ const char *sec;
+
+ /* Convert an ASN.1 UTC time to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
+ ;
+ /* Get the seconds. */
+ sec = beg + 10;
+ switch(tzp - sec) {
+ case 0:
+ sec = "00";
+ case 2:
+ break;
+ default:
+ return (const char *) NULL;
+ }
+
+ /* Process timezone. */
+ if(tzp >= end)
+ return (const char *) NULL;
+ if(*tzp == 'Z') {
+ tzp = "GMT";
+ end = tzp + 3;
+ }
+ else
+ tzp++;
+
+ tzl = end - tzp;
+ return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
+ 20 - (*beg >= '5'), beg, beg + 2, beg + 4,
+ beg + 6, beg + 8, sec,
+ tzl, tzp);
+}
+
+const char *Curl_ASN1tostr(curl_asn1Element *elem, int type)
+{
+ /* Convert an ASN.1 element to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(elem->constructed)
+ return (const char *) NULL; /* No conversion of structured elements. */
+
+ if(!type)
+ type = elem->tag; /* Type not forced: use element tag as type. */
+
+ switch(type) {
+ case CURL_ASN1_BOOLEAN:
+ return bool2str(elem->beg, elem->end);
+ case CURL_ASN1_INTEGER:
+ case CURL_ASN1_ENUMERATED:
+ return int2str(elem->beg, elem->end);
+ case CURL_ASN1_BIT_STRING:
+ return bit2str(elem->beg, elem->end);
+ case CURL_ASN1_OCTET_STRING:
+ return octet2str(elem->beg, elem->end);
+ case CURL_ASN1_NULL:
+ return strdup("");
+ case CURL_ASN1_OBJECT_IDENTIFIER:
+ return OID2str(elem->beg, elem->end, TRUE);
+ case CURL_ASN1_UTC_TIME:
+ return UTime2str(elem->beg, elem->end);
+ case CURL_ASN1_GENERALIZED_TIME:
+ return GTime2str(elem->beg, elem->end);
+ case CURL_ASN1_UTF8_STRING:
+ case CURL_ASN1_NUMERIC_STRING:
+ case CURL_ASN1_PRINTABLE_STRING:
+ case CURL_ASN1_TELETEX_STRING:
+ case CURL_ASN1_IA5_STRING:
+ case CURL_ASN1_VISIBLE_STRING:
+ case CURL_ASN1_UNIVERSAL_STRING:
+ case CURL_ASN1_BMP_STRING:
+ return string2str(type, elem->beg, elem->end);
+ }
+
+ return (const char *) NULL; /* Unsupported. */
+}
+
+static ssize_t encodeDN(char *buf, size_t n, curl_asn1Element *dn)
+{
+ curl_asn1Element rdn;
+ curl_asn1Element atv;
+ curl_asn1Element oid;
+ curl_asn1Element value;
+ size_t l = 0;
+ const char *p1;
+ const char *p2;
+ const char *p3;
+ const char *str;
+
+ /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
+ Return the total string length, even if larger than `n'. */
+
+ for(p1 = dn->beg; p1 < dn->end;) {
+ p1 = Curl_getASN1Element(&rdn, p1, dn->end);
+ for(p2 = rdn.beg; p2 < rdn.end;) {
+ p2 = Curl_getASN1Element(&atv, p2, rdn.end);
+ p3 = Curl_getASN1Element(&oid, atv.beg, atv.end);
+ Curl_getASN1Element(&value, p3, atv.end);
+ str = Curl_ASN1tostr(&oid, 0);
+ if(!str)
+ return -1;
+
+ /* Encode delimiter.
+ If attribute has a short uppercase name, delimiter is ", ". */
+ if(l) {
+ for(p3 = str; isupper(*p3); p3++)
+ ;
+ for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ }
+
+ /* Encode attribute name. */
+ for(p3 = str; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
+
+ /* Generate equal sign. */
+ if(l < n)
+ buf[l] = '=';
+ l++;
+
+ /* Generate value. */
+ str = Curl_ASN1tostr(&value, 0);
+ if(!str)
+ return -1;
+ for(p3 = str; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
+ }
+ }
+
+ return l;
+}
+
+const char *Curl_DNtostr(curl_asn1Element *dn)
+{
+ char *buf = (char *) NULL;
+ ssize_t n = encodeDN(buf, 0, dn);
+
+ /* Convert an ASN.1 distinguished name into a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(n >= 0) {
+ buf = malloc(n + 1);
+ if(buf) {
+ encodeDN(buf, n + 1, dn);
+ buf[n] = '\0';
+ }
+ }
+ return (const char *) buf;
+}
+
+/*
+ * X509 parser.
+ */
+
+int Curl_parseX509(curl_X509certificate *cert,
+ const char *beg, const char *end)
+{
+ curl_asn1Element elem;
+ curl_asn1Element tbsCertificate;
+ const char *ccp;
+ static const char defaultVersion = 0; /* v1. */
+
+ /* ASN.1 parse an X509 certificate into structure subfields.
+ Syntax is assumed to have already been checked by the SSL backend.
+ See RFC 5280. */
+
+ cert->certificate.header = NULL;
+ cert->certificate.beg = beg;
+ cert->certificate.end = end;
+
+ /* Get the sequence content. */
+ if(!Curl_getASN1Element(&elem, beg, end))
+ return -1; /* Invalid bounds/size. */
+ beg = elem.beg;
+ end = elem.end;
+
+ /* Get tbsCertificate. */
+ beg = Curl_getASN1Element(&tbsCertificate, beg, end);
+ /* Skip the signatureAlgorithm. */
+ beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+ /* Get the signatureValue. */
+ Curl_getASN1Element(&cert->signature, beg, end);
+
+ /* Parse TBSCertificate. */
+ beg = tbsCertificate.beg;
+ end = tbsCertificate.end;
+ /* Get optional version, get serialNumber. */
+ cert->version.header = NULL;
+ cert->version.beg = &defaultVersion;
+ cert->version.end = &defaultVersion + sizeof defaultVersion;;
+ beg = Curl_getASN1Element(&elem, beg, end);
+ if(elem.tag == 0) {
+ Curl_getASN1Element(&cert->version, elem.beg, elem.end);
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ cert->serialNumber = elem;
+ /* Get signature algorithm. */
+ beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+ /* Get issuer. */
+ beg = Curl_getASN1Element(&cert->issuer, beg, end);
+ /* Get notBefore and notAfter. */
+ beg = Curl_getASN1Element(&elem, beg, end);
+ ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end);
+ Curl_getASN1Element(&cert->notAfter, ccp, elem.end);
+ /* Get subject. */
+ beg = Curl_getASN1Element(&cert->subject, beg, end);
+ /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
+ beg = Curl_getASN1Element(&cert->subjectPublicKeyInfo, beg, end);
+ ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm,
+ cert->subjectPublicKeyInfo.beg,
+ cert->subjectPublicKeyInfo.end);
+ Curl_getASN1Element(&cert->subjectPublicKey, ccp,
+ cert->subjectPublicKeyInfo.end);
+ /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
+ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
+ cert->extensions.tag = elem.tag = 0;
+ cert->issuerUniqueID.header = cert->subjectUniqueID.header = NULL;
+ cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
+ cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
+ cert->extensions.header = NULL;
+ cert->extensions.beg = cert->extensions.end = "";
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ if(elem.tag == 1) {
+ cert->issuerUniqueID = elem;
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ if(elem.tag == 2) {
+ cert->subjectUniqueID = elem;
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ if(elem.tag == 3)
+ Curl_getASN1Element(&cert->extensions, elem.beg, elem.end);
+ return 0;
+}
+
+static size_t copySubstring(char *to, const char *from)
+{
+ size_t i;
+
+ /* Copy at most 64-characters, terminate with a newline and returns the
+ effective number of stored characters. */
+
+ for(i = 0; i < 64; i++) {
+ to[i] = *from;
+ if(!*from++)
+ break;
+ }
+
+ to[i++] = '\n';
+ return i;
+}
+
+static const char *dumpAlgo(curl_asn1Element *param,
+ const char *beg, const char *end)
+{
+ curl_asn1Element oid;
+
+ /* Get algorithm parameters and return algorithm name. */
+
+ beg = Curl_getASN1Element(&oid, beg, end);
+ param->header = NULL;
+ param->tag = 0;
+ param->beg = param->end = end;
+ if(beg < end)
+ Curl_getASN1Element(param, beg, end);
+ return OID2str(oid.beg, oid.end, TRUE);
+}
+
+static void do_pubkey_field(struct Curl_easy *data, int certnum,
+ const char *label, curl_asn1Element *elem)
+{
+ const char *output;
+
+ /* Generate a certificate information record for the public key. */
+
+ output = Curl_ASN1tostr(elem, 0);
+ if(output) {
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, label, output);
+ if(!certnum)
+ infof(data, " %s: %s\n", label, output);
+ free((char *) output);
+ }
+}
+
+static void do_pubkey(struct Curl_easy *data, int certnum,
+ const char *algo, curl_asn1Element *param,
+ curl_asn1Element *pubkey)
+{
+ curl_asn1Element elem;
+ curl_asn1Element pk;
+ const char *p;
+ const char *q;
+ unsigned long len;
+ unsigned int i;
+
+ /* Generate all information records for the public key. */
+
+ /* Get the public key (single element). */
+ Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
+
+ if(strcasecompare(algo, "rsaEncryption")) {
+ p = Curl_getASN1Element(&elem, pk.beg, pk.end);
+ /* Compute key length. */
+ for(q = elem.beg; !*q && q < elem.end; q++)
+ ;
+ len = (unsigned long)((elem.end - q) * 8);
+ if(len)
+ for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
+ len--;
+ if(len > 32)
+ elem.beg = q; /* Strip leading zero bytes. */
+ if(!certnum)
+ infof(data, " RSA Public Key (%lu bits)\n", len);
+ if(data->set.ssl.certinfo) {
+ q = curl_maprintf("%lu", len);
+ if(q) {
+ Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
+ free((char *) q);
+ }
+ }
+ /* Generate coefficients. */
+ do_pubkey_field(data, certnum, "rsa(n)", &elem);
+ Curl_getASN1Element(&elem, p, pk.end);
+ do_pubkey_field(data, certnum, "rsa(e)", &elem);
+ }
+ else if(strcasecompare(algo, "dsa")) {
+ p = Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dsa(p)", &elem);
+ p = Curl_getASN1Element(&elem, p, param->end);
+ do_pubkey_field(data, certnum, "dsa(q)", &elem);
+ Curl_getASN1Element(&elem, p, param->end);
+ do_pubkey_field(data, certnum, "dsa(g)", &elem);
+ do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+ }
+ else if(strcasecompare(algo, "dhpublicnumber")) {
+ p = Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dh(p)", &elem);
+ Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dh(g)", &elem);
+ do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
+ }
+#if 0 /* Patent-encumbered. */
+ else if(strcasecompare(algo, "ecPublicKey")) {
+ /* Left TODO. */
+ }
+#endif
+}
+
+CURLcode Curl_extract_certinfo(struct connectdata *conn,
+ int certnum,
+ const char *beg,
+ const char *end)
+{
+ curl_X509certificate cert;
+ struct Curl_easy *data = conn->data;
+ curl_asn1Element param;
+ const char *ccp;
+ char *cp1;
+ size_t cl1;
+ char *cp2;
+ CURLcode result;
+ unsigned long version;
+ size_t i;
+ size_t j;
+
+ if(!data->set.ssl.certinfo)
+ if(certnum)
+ return CURLE_OK;
+
+ /* Prepare the certificate information for curl_easy_getinfo(). */
+
+ /* Extract the certificate ASN.1 elements. */
+ if(Curl_parseX509(&cert, beg, end))
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Subject. */
+ ccp = Curl_DNtostr(&cert.subject);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+ if(!certnum)
+ infof(data, "%2d Subject: %s\n", certnum, ccp);
+ free((char *) ccp);
+
+ /* Issuer. */
+ ccp = Curl_DNtostr(&cert.issuer);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+ if(!certnum)
+ infof(data, " Issuer: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Version (always fits in less than 32 bits). */
+ version = 0;
+ for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
+ version = (version << 8) | *(const unsigned char *) ccp;
+ if(data->set.ssl.certinfo) {
+ ccp = curl_maprintf("%lx", version);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
+ free((char *) ccp);
+ }
+ if(!certnum)
+ infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
+
+ /* Serial number. */
+ ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+ if(!certnum)
+ infof(data, " Serial Number: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Signature algorithm .*/
+ ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
+ cert.signatureAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+ if(!certnum)
+ infof(data, " Signature Algorithm: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Start Date. */
+ ccp = Curl_ASN1tostr(&cert.notBefore, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
+ if(!certnum)
+ infof(data, " Start Date: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Expire Date. */
+ ccp = Curl_ASN1tostr(&cert.notAfter, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+ if(!certnum)
+ infof(data, " Expire Date: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Public Key Algorithm. */
+ ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
+ cert.subjectPublicKeyAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
+ if(!certnum)
+ infof(data, " Public Key Algorithm: %s\n", ccp);
+ do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+ free((char *) ccp);
+
+/* TODO: extensions. */
+
+ /* Signature. */
+ ccp = Curl_ASN1tostr(&cert.signature, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
+ if(!certnum)
+ infof(data, " Signature: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Generate PEM certificate. */
+ result = Curl_base64_encode(data, cert.certificate.beg,
+ cert.certificate.end - cert.certificate.beg,
+ &cp1, &cl1);
+ if(result)
+ return result;
+ /* Compute the number of characters in final certificate string. Format is:
+ -----BEGIN CERTIFICATE-----\n
+ <max 64 base64 characters>\n
+ .
+ .
+ .
+ -----END CERTIFICATE-----\n
+ */
+ i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
+ cp2 = malloc(i + 1);
+ if(!cp2) {
+ free(cp1);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* Build the certificate string. */
+ i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
+ for(j = 0; j < cl1; j += 64)
+ i += copySubstring(cp2 + i, cp1 + j);
+ i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
+ cp2[i] = '\0';
+ free(cp1);
+ if(data->set.ssl.certinfo)
+ Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
+ if(!certnum)
+ infof(data, "%s\n", cp2);
+ free(cp2);
+ return CURLE_OK;
+}
+
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
+
+#if defined(USE_GSKIT)
+
+static const char *checkOID(const char *beg, const char *end,
+ const char *oid)
+{
+ curl_asn1Element e;
+ const char *ccp;
+ const char *p;
+ bool matched;
+
+ /* Check if first ASN.1 element at `beg' is the given OID.
+ Return a pointer in the source after the OID if found, else NULL. */
+
+ ccp = Curl_getASN1Element(&e, beg, end);
+ if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
+ return (const char *) NULL;
+
+ p = OID2str(e.beg, e.end, FALSE);
+ if(!p)
+ return (const char *) NULL;
+
+ matched = !strcmp(p, oid);
+ free((char *) p);
+ return matched? ccp: (const char *) NULL;
+}
+
+CURLcode Curl_verifyhost(struct connectdata *conn,
+ const char *beg, const char *end)
+{
+ struct Curl_easy *data = conn->data;
+ curl_X509certificate cert;
+ curl_asn1Element dn;
+ curl_asn1Element elem;
+ curl_asn1Element ext;
+ curl_asn1Element name;
+ const char *p;
+ const char *q;
+ char *dnsname;
+ int matched = -1;
+ size_t addrlen = (size_t) -1;
+ ssize_t len;
+ const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
+ conn->host.name;
+ const char * const dispname = SSL_IS_PROXY()?
+ conn->http_proxy.host.dispname:
+ conn->host.dispname;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+
+ /* Verify that connection server matches info in X509 certificate at
+ `beg'..`end'. */
+
+ if(!SSL_CONN_CONFIG(verifyhost))
+ return CURLE_OK;
+
+ if(Curl_parseX509(&cert, beg, end))
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ /* Get the server IP address. */
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, hostname, &addr))
+ addrlen = sizeof(struct in6_addr);
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, hostname, &addr))
+ addrlen = sizeof(struct in_addr);
+
+ /* Process extensions. */
+ for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
+ p = Curl_getASN1Element(&ext, p, cert.extensions.end);
+ /* Check if extension is a subjectAlternativeName. */
+ ext.beg = checkOID(ext.beg, ext.end, sanOID);
+ if(ext.beg) {
+ ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+ /* Skip critical if present. */
+ if(elem.tag == CURL_ASN1_BOOLEAN)
+ ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+ /* Parse the octet string contents: is a single sequence. */
+ Curl_getASN1Element(&elem, elem.beg, elem.end);
+ /* Check all GeneralNames. */
+ for(q = elem.beg; matched != 1 && q < elem.end;) {
+ q = Curl_getASN1Element(&name, q, elem.end);
+ switch(name.tag) {
+ case 2: /* DNS name. */
+ len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
+ name.beg, name.end);
+ if(len > 0 && (size_t)len == strlen(dnsname))
+ matched = Curl_cert_hostcheck(dnsname, hostname);
+ else
+ matched = 0;
+ free(dnsname);
+ break;
+
+ case 7: /* IP address. */
+ matched = (size_t) (name.end - q) == addrlen &&
+ !memcmp(&addr, q, addrlen);
+ break;
+ }
+ }
+ }
+ }
+
+ switch(matched) {
+ case 1:
+ /* an alternative name matched the server hostname */
+ infof(data, "\t subjectAltName: %s matched\n", dispname);
+ return CURLE_OK;
+ case 0:
+ /* an alternative name field existed, but didn't match and then
+ we MUST fail */
+ infof(data, "\t subjectAltName does not match %s\n", dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ /* Process subject. */
+ name.header = NULL;
+ name.beg = name.end = "";
+ q = cert.subject.beg;
+ /* we have to look to the last occurrence of a commonName in the
+ distinguished one to get the most significant one. */
+ while(q < cert.subject.end) {
+ q = Curl_getASN1Element(&dn, q, cert.subject.end);
+ for(p = dn.beg; p < dn.end;) {
+ p = Curl_getASN1Element(&elem, p, dn.end);
+ /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
+ elem.beg = checkOID(elem.beg, elem.end, cnOID);
+ if(elem.beg)
+ name = elem; /* Latch CN. */
+ }
+ }
+
+ /* Check the CN if found. */
+ if(!Curl_getASN1Element(&elem, name.beg, name.end))
+ failf(data, "SSL: unable to obtain common name from peer certificate");
+ else {
+ len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
+ if(len < 0) {
+ free(dnsname);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
+ failf(data, "SSL: illegal cert name field");
+ else if(Curl_cert_hostcheck((const char *) dnsname, hostname)) {
+ infof(data, "\t common name: %s (matched)\n", dnsname);
+ free(dnsname);
+ return CURLE_OK;
+ }
+ else
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", dnsname, dispname);
+ free(dnsname);
+ }
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+}
+
+#endif /* USE_GSKIT */
diff --git a/Utilities/cmcurl/lib/x509asn1.h b/Utilities/cmcurl/lib/x509asn1.h
new file mode 100644
index 000000000..ce4029792
--- /dev/null
+++ b/Utilities/cmcurl/lib/x509asn1.h
@@ -0,0 +1,134 @@
+#ifndef HEADER_CURL_X509ASN1_H
+#define HEADER_CURL_X509ASN1_H
+
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(USE_GSKIT) || defined(USE_NSS) || defined(USE_GNUTLS) || \
+ defined(USE_CYASSL) || defined(USE_SCHANNEL)
+
+#include "urldata.h"
+
+/*
+ * Constants.
+ */
+
+/* Largest supported ASN.1 structure. */
+#define CURL_ASN1_MAX ((size_t) 0x40000) /* 256K */
+
+/* ASN.1 classes. */
+#define CURL_ASN1_UNIVERSAL 0
+#define CURL_ASN1_APPLICATION 1
+#define CURL_ASN1_CONTEXT_SPECIFIC 2
+#define CURL_ASN1_PRIVATE 3
+
+/* ASN.1 types. */
+#define CURL_ASN1_BOOLEAN 1
+#define CURL_ASN1_INTEGER 2
+#define CURL_ASN1_BIT_STRING 3
+#define CURL_ASN1_OCTET_STRING 4
+#define CURL_ASN1_NULL 5
+#define CURL_ASN1_OBJECT_IDENTIFIER 6
+#define CURL_ASN1_OBJECT_DESCRIPTOR 7
+#define CURL_ASN1_INSTANCE_OF 8
+#define CURL_ASN1_REAL 9
+#define CURL_ASN1_ENUMERATED 10
+#define CURL_ASN1_EMBEDDED 11
+#define CURL_ASN1_UTF8_STRING 12
+#define CURL_ASN1_RELATIVE_OID 13
+#define CURL_ASN1_SEQUENCE 16
+#define CURL_ASN1_SET 17
+#define CURL_ASN1_NUMERIC_STRING 18
+#define CURL_ASN1_PRINTABLE_STRING 19
+#define CURL_ASN1_TELETEX_STRING 20
+#define CURL_ASN1_VIDEOTEX_STRING 21
+#define CURL_ASN1_IA5_STRING 22
+#define CURL_ASN1_UTC_TIME 23
+#define CURL_ASN1_GENERALIZED_TIME 24
+#define CURL_ASN1_GRAPHIC_STRING 25
+#define CURL_ASN1_VISIBLE_STRING 26
+#define CURL_ASN1_GENERAL_STRING 27
+#define CURL_ASN1_UNIVERSAL_STRING 28
+#define CURL_ASN1_CHARACTER_STRING 29
+#define CURL_ASN1_BMP_STRING 30
+
+
+/*
+ * Types.
+ */
+
+/* ASN.1 parsed element. */
+typedef struct {
+ const char * header; /* Pointer to header byte. */
+ const char * beg; /* Pointer to element data. */
+ const char * end; /* Pointer to 1st byte after element. */
+ unsigned char class; /* ASN.1 element class. */
+ unsigned char tag; /* ASN.1 element tag. */
+ bool constructed; /* Element is constructed. */
+} curl_asn1Element;
+
+
+/* ASN.1 OID table entry. */
+typedef struct {
+ const char * numoid; /* Dotted-numeric OID. */
+ const char * textoid; /* OID name. */
+} curl_OID;
+
+
+/* X509 certificate: RFC 5280. */
+typedef struct {
+ curl_asn1Element certificate;
+ curl_asn1Element version;
+ curl_asn1Element serialNumber;
+ curl_asn1Element signatureAlgorithm;
+ curl_asn1Element signature;
+ curl_asn1Element issuer;
+ curl_asn1Element notBefore;
+ curl_asn1Element notAfter;
+ curl_asn1Element subject;
+ curl_asn1Element subjectPublicKeyInfo;
+ curl_asn1Element subjectPublicKeyAlgorithm;
+ curl_asn1Element subjectPublicKey;
+ curl_asn1Element issuerUniqueID;
+ curl_asn1Element subjectUniqueID;
+ curl_asn1Element extensions;
+} curl_X509certificate;
+
+
+/*
+ * Prototypes.
+ */
+
+const char *Curl_getASN1Element(curl_asn1Element *elem,
+ const char *beg, const char *end);
+const char *Curl_ASN1tostr(curl_asn1Element *elem, int type);
+const char *Curl_DNtostr(curl_asn1Element *dn);
+int Curl_parseX509(curl_X509certificate *cert,
+ const char *beg, const char *end);
+CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum,
+ const char *beg, const char *end);
+CURLcode Curl_verifyhost(struct connectdata *conn,
+ const char *beg, const char *end);
+#endif /* USE_GSKIT or USE_NSS or USE_GNUTLS or USE_CYASSL or USE_SCHANNEL */
+#endif /* HEADER_CURL_X509ASN1_H */
diff --git a/Utilities/cmcurl/llist.c b/Utilities/cmcurl/llist.c
deleted file mode 100644
index 921d1d1f9..000000000
--- a/Utilities/cmcurl/llist.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "llist.h"
-#include "memory.h"
-
-/* this must be the last include file */
-#include "memdebug.h"
-
-void
-Curl_llist_init(struct curl_llist *l, curl_llist_dtor dtor)
-{
- l->size = 0;
- l->dtor = dtor;
- l->head = NULL;
- l->tail = NULL;
-}
-
-struct curl_llist *
-Curl_llist_alloc(curl_llist_dtor dtor)
-{
- struct curl_llist *list;
-
- list = (struct curl_llist *)malloc(sizeof(struct curl_llist));
- if(NULL == list)
- return NULL;
-
- Curl_llist_init(list, dtor);
-
- return list;
-}
-
-/*
- * Curl_llist_insert_next() returns 1 on success and 0 on failure.
- */
-int
-Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
- const void *p)
-{
- struct curl_llist_element *ne =
- (struct curl_llist_element *) malloc(sizeof(struct curl_llist_element));
- if(!ne)
- return 0;
-
- ne->ptr = (void *) p;
- if (list->size == 0) {
- list->head = ne;
- list->head->prev = NULL;
- list->head->next = NULL;
- list->tail = ne;
- }
- else {
- ne->next = e->next;
- ne->prev = e;
- if (e->next) {
- e->next->prev = ne;
- }
- else {
- list->tail = ne;
- }
- e->next = ne;
- }
-
- ++list->size;
-
- return 1;
-}
-
-int
-Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
- void *user)
-{
- if (e == NULL || list->size == 0)
- return 1;
-
- if (e == list->head) {
- list->head = e->next;
-
- if (list->head == NULL)
- list->tail = NULL;
- else
- e->next->prev = NULL;
- } else {
- e->prev->next = e->next;
- if (!e->next)
- list->tail = e->prev;
- else
- e->next->prev = e->prev;
- }
-
- list->dtor(user, e->ptr);
- free(e);
- --list->size;
-
- return 1;
-}
-
-void
-Curl_llist_destroy(struct curl_llist *list, void *user)
-{
- if(list) {
- while (list->size > 0)
- Curl_llist_remove(list, list->tail, user);
-
- free(list);
- }
-}
-
-size_t
-Curl_llist_count(struct curl_llist *list)
-{
- return list->size;
-}
diff --git a/Utilities/cmcurl/llist.h b/Utilities/cmcurl/llist.h
deleted file mode 100644
index 5c7a8a008..000000000
--- a/Utilities/cmcurl/llist.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __LLIST_H
-#define __LLIST_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include <stddef.h>
-
-typedef void (*curl_llist_dtor)(void *, void *);
-
-struct curl_llist_element {
- void *ptr;
-
- struct curl_llist_element *prev;
- struct curl_llist_element *next;
-};
-
-struct curl_llist {
- struct curl_llist_element *head;
- struct curl_llist_element *tail;
-
- curl_llist_dtor dtor;
-
- size_t size;
-};
-
-void Curl_llist_init(struct curl_llist *, curl_llist_dtor);
-struct curl_llist *Curl_llist_alloc(curl_llist_dtor);
-int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
- const void *);
-int Curl_llist_insert_prev(struct curl_llist *, struct curl_llist_element *,
- const void *);
-int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
- void *);
-int Curl_llist_remove_next(struct curl_llist *, struct curl_llist_element *,
- void *);
-size_t Curl_llist_count(struct curl_llist *);
-void Curl_llist_destroy(struct curl_llist *, void *);
-
-#endif
diff --git a/Utilities/cmcurl/md5.c b/Utilities/cmcurl/md5.c
deleted file mode 100644
index 4cfb073ea..000000000
--- a/Utilities/cmcurl/md5.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_CRYPTO_AUTH
-
-#if !defined(USE_SSLEAY) || !defined(USE_OPENSSL)
-/* This code segment is only used if OpenSSL is not provided, as if it is
- we use the MD5-function provided there instead. No good duplicating
- code! */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-#include <string.h>
-
-/* UINT4 defines a four byte word */
-typedef unsigned int UINT4;
-
-/* MD5 context. */
-struct md5_ctx {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-};
-
-typedef struct md5_ctx MD5_CTX;
-
-static void MD5_Init(struct md5_ctx *);
-static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int);
-static void MD5_Final(unsigned char [16], struct md5_ctx *);
-
-/* Constants for MD5Transform routine.
- */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-static void MD5Transform(UINT4 [4], const unsigned char [64]);
-static void Encode(unsigned char *, UINT4 *, unsigned int);
-static void Decode(UINT4 *, const unsigned char *, unsigned int);
-
-static const unsigned char PADDING[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-static void MD5_Init(struct md5_ctx *context)
-{
- context->count[0] = context->count[1] = 0;
- /* Load magic initialization constants. */
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
- operation, processing another message block, and updating the
- context.
- */
-static void MD5_Update (struct md5_ctx *context, /* context */
- const unsigned char *input, /* input block */
- unsigned int inputLen) /* length of input block */
-{
- unsigned int i, bufindex, partLen;
-
- /* Compute number of bytes mod 64 */
- bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
- /* Update number of bits */
- if ((context->count[0] += ((UINT4)inputLen << 3))
- < ((UINT4)inputLen << 3))
- context->count[1]++;
- context->count[1] += ((UINT4)inputLen >> 29);
-
- partLen = 64 - bufindex;
-
- /* Transform as many times as possible. */
- if (inputLen >= partLen) {
- memcpy((void *)&context->buffer[bufindex], (void *)input, partLen);
- MD5Transform(context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform(context->state, &input[i]);
-
- bufindex = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- memcpy((void *)&context->buffer[bufindex], (void *)&input[i], inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- the message digest and zeroizing the context.
-*/
-static void MD5_Final(unsigned char digest[16], /* message digest */
- struct md5_ctx *context) /* context */
-{
- unsigned char bits[8];
- unsigned int count, padLen;
-
- /* Save number of bits */
- Encode (bits, context->count, 8);
-
- /* Pad out to 56 mod 64. */
- count = (unsigned int)((context->count[0] >> 3) & 0x3f);
- padLen = (count < 56) ? (56 - count) : (120 - count);
- MD5_Update (context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD5_Update (context, bits, 8);
-
- /* Store state in digest */
- Encode (digest, context->state, 16);
-
- /* Zeroize sensitive information. */
- memset ((void *)context, 0, sizeof (*context));
-}
-
-/* MD5 basic transformation. Transforms state based on block. */
-static void MD5Transform(UINT4 state[4],
- const unsigned char block[64])
-{
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode (x, block, 64);
-
- /* Round 1 */
- FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
- FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
- FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
- FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
- FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
- FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
- FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
- FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
- FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
- FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
- FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
- GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
- GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
- GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
- GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
- GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
- GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
- GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
- GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
- GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
- GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
- HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
- HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
- HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
- HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
- HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
- HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
- HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
- HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
- HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
- II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
- II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
- II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
- II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
- II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
- II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
- II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
- II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
- II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- /* Zeroize sensitive information. */
- memset((void *)x, 0, sizeof (x));
-}
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
- a multiple of 4.
- */
-static void Encode (unsigned char *output,
- UINT4 *input,
- unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
- a multiple of 4.
-*/
-static void Decode (UINT4 *output,
- const unsigned char *input,
- unsigned int len)
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
- (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-#else
-/* If OpenSSL is present */
-#include <openssl/md5.h>
-#include <string.h>
-#endif
-
-#include "md5.h"
-
-void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
- const unsigned char *input)
-{
- MD5_CTX ctx;
- MD5_Init(&ctx);
- MD5_Update(&ctx, input, (unsigned int)strlen((char *)input));
- MD5_Final(outbuffer, &ctx);
-}
-
-#endif
diff --git a/Utilities/cmcurl/md5.h b/Utilities/cmcurl/md5.h
deleted file mode 100644
index 63cc70e84..000000000
--- a/Utilities/cmcurl/md5.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __MD5_H
-#define __MD5_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-void Curl_md5it(unsigned char *output,
- const unsigned char *input);
-
-#endif
diff --git a/Utilities/cmcurl/memdebug.c b/Utilities/cmcurl/memdebug.c
deleted file mode 100644
index a8cca44cb..000000000
--- a/Utilities/cmcurl/memdebug.c
+++ /dev/null
@@ -1,298 +0,0 @@
-#ifdef CURLDEBUG
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <curl/curl.h>
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#define _MPRINTF_REPLACE
-#include <curl/mprintf.h>
-#include "urldata.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
-#include "memory.h"
-#include "memdebug.h"
-
-struct memdebug {
- size_t size;
- double mem[1];
- /* I'm hoping this is the thing with the strictest alignment
- * requirements. That also means we waste some space :-( */
-};
-
-/*
- * Note that these debug functions are very simple and they are meant to
- * remain so. For advanced analysis, record a log file and write perl scripts
- * to analyze them!
- *
- * Don't use these with multithreaded test programs!
- */
-
-#define logfile curl_debuglogfile
-FILE *curl_debuglogfile = NULL;
-static bool memlimit = FALSE; /* enable memory limit */
-static long memsize = 0; /* set number of mallocs allowed */
-
-/* this sets the log file name */
-void curl_memdebug(const char *logname)
-{
- if (!logfile) {
- if(logname)
- logfile = fopen(logname, "w");
- else
- logfile = stderr;
- }
-}
-
-/* This function sets the number of malloc() calls that should return
- successfully! */
-void curl_memlimit(long limit)
-{
- if (!memlimit) {
- memlimit = TRUE;
- memsize = limit;
- }
-}
-
-/* returns TRUE if this isn't allowed! */
-static bool countcheck(const char *func, int line, const char *source)
-{
- /* if source is NULL, then the call is made internally and this check
- should not be made */
- if(memlimit && source) {
- if(!memsize) {
- if(logfile && source)
- fprintf(logfile, "LIMIT %s:%d %s reached memlimit\n",
- source, line, func);
- if(source)
- fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
- source, line, func);
- errno = ENOMEM;
- return TRUE; /* RETURN ERROR! */
- }
- else
- memsize--; /* countdown */
-
- /* log the countdown */
- if(logfile && source)
- fprintf(logfile, "LIMIT %s:%d %ld ALLOCS left\n",
- source, line, memsize);
-
- }
-
- return FALSE; /* allow this */
-}
-
-void *curl_domalloc(size_t wantedsize, int line, const char *source)
-{
- struct memdebug *mem;
- size_t size;
-
- if(countcheck("malloc", line, source))
- return NULL;
-
- /* alloc at least 64 bytes */
- size = sizeof(struct memdebug)+wantedsize;
-
- mem=(struct memdebug *)(Curl_cmalloc)(size);
- if(mem) {
- /* fill memory with junk */
- memset(mem->mem, 0xA5, wantedsize);
- mem->size = wantedsize;
- }
-
- if(logfile && source)
- fprintf(logfile, "MEM %s:%d malloc(%zd) = %p\n",
- source, line, wantedsize, mem ? mem->mem : 0);
- return (mem ? mem->mem : NULL);
-}
-
-void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
- int line, const char *source)
-{
- struct memdebug *mem;
- size_t size, user_size;
-
- if(countcheck("calloc", line, source))
- return NULL;
-
- /* alloc at least 64 bytes */
- user_size = wanted_size * wanted_elements;
- size = sizeof(struct memdebug) + user_size;
-
- mem = (struct memdebug *)(Curl_cmalloc)(size);
- if(mem) {
- /* fill memory with zeroes */
- memset(mem->mem, 0, user_size);
- mem->size = user_size;
- }
-
- if(logfile && source)
- fprintf(logfile, "MEM %s:%d calloc(%u,%u) = %p\n",
- source, line, wanted_elements, wanted_size, mem ? mem->mem : 0);
- return (mem ? mem->mem : NULL);
-}
-
-char *curl_dostrdup(const char *str, int line, const char *source)
-{
- char *mem;
- size_t len;
-
- curlassert(str != NULL);
-
- if(countcheck("strdup", line, source))
- return NULL;
-
- len=strlen(str)+1;
-
- mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
- if (mem)
- memcpy(mem, str, len);
-
- if(logfile)
- fprintf(logfile, "MEM %s:%d strdup(%p) (%zd) = %p\n",
- source, line, str, len, mem);
-
- return mem;
-}
-
-/* We provide a realloc() that accepts a NULL as pointer, which then
- performs a malloc(). In order to work with ares. */
-void *curl_dorealloc(void *ptr, size_t wantedsize,
- int line, const char *source)
-{
- struct memdebug *mem=NULL;
-
- size_t size = sizeof(struct memdebug)+wantedsize;
-
- if(countcheck("realloc", line, source))
- return NULL;
-
- if(ptr)
- mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
-
- mem=(struct memdebug *)(Curl_crealloc)(mem, size);
- if(logfile)
- fprintf(logfile, "MEM %s:%d realloc(%p, %zd) = %p\n",
- source, line, ptr, wantedsize, mem?mem->mem:NULL);
-
- if(mem) {
- mem->size = wantedsize;
- return mem->mem;
- }
-
- return NULL;
-}
-
-void curl_dofree(void *ptr, int line, const char *source)
-{
- struct memdebug *mem;
-
- curlassert(ptr != NULL);
-
- mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
-
- /* destroy */
- memset(mem->mem, 0x13, mem->size);
-
- /* free for real */
- (Curl_cfree)(mem);
-
- if(logfile)
- fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
-}
-
-int curl_socket(int domain, int type, int protocol, int line,
- const char *source)
-{
- int sockfd=(socket)(domain, type, protocol);
- if(logfile && (sockfd!=-1))
- fprintf(logfile, "FD %s:%d socket() = %d\n",
- source, line, sockfd);
- return sockfd;
-}
-
-int curl_accept(int s, void *saddr, void *saddrlen,
- int line, const char *source)
-{
- struct sockaddr *addr = (struct sockaddr *)saddr;
- socklen_t *addrlen = (socklen_t *)saddrlen;
- int sockfd=(accept)(s, addr, addrlen);
- if(logfile)
- fprintf(logfile, "FD %s:%d accept() = %d\n",
- source, line, sockfd);
- return sockfd;
-}
-
-/* this is our own defined way to close sockets on *ALL* platforms */
-int curl_sclose(int sockfd, int line, const char *source)
-{
- int res=sclose(sockfd);
- if(logfile)
- fprintf(logfile, "FD %s:%d sclose(%d)\n",
- source, line, sockfd);
- return res;
-}
-
-FILE *curl_fopen(const char *file, const char *mode,
- int line, const char *source)
-{
- FILE *res=(fopen)(file, mode);
- if(logfile)
- fprintf(logfile, "FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
- source, line, file, mode, res);
- return res;
-}
-
-int curl_fclose(FILE *file, int line, const char *source)
-{
- int res;
-
- curlassert(file != NULL);
-
- res=(fclose)(file);
- if(logfile)
- fprintf(logfile, "FILE %s:%d fclose(%p)\n",
- source, line, file);
- return res;
-}
-#else
-#ifdef VMS
-int VOID_VAR_MEMDEBUG;
-#else
-/* we provide a fake do-nothing function here to avoid compiler warnings */
-void curl_memdebug(void) {}
-#endif /* VMS */
-#endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/memdebug.h b/Utilities/cmcurl/memdebug.h
deleted file mode 100644
index a4ce7e59a..000000000
--- a/Utilities/cmcurl/memdebug.h
+++ /dev/null
@@ -1,125 +0,0 @@
-#ifdef CURLDEBUG
-#ifndef _CURL_MEDEBUG_H
-#define _CURL_MEDEBUG_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * CAUTION: this header is designed to work when included by the app-side
- * as well as the library. Do not mix with library internals!
- */
-
-#include "setup.h"
-
-#include <curl/curl.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <stdio.h>
-#ifdef HAVE_MEMORY_H
-#include <memory.h>
-#endif
-
-#define logfile curl_debuglogfile
-
-extern FILE *logfile;
-
-/* memory functions */
-CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
-CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line, const char *source);
-CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, const char *source);
-CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
-CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
-CURL_EXTERN void curl_memdebug(const char *logname);
-CURL_EXTERN void curl_memlimit(long limit);
-
-/* file descriptor manipulators */
-CURL_EXTERN int curl_socket(int domain, int type, int protocol, int line , const char *);
-CURL_EXTERN int curl_sclose(int sockfd, int, const char *source);
-CURL_EXTERN int curl_accept(int s, void *addr, void *addrlen,
- int line, const char *source);
-
-/* FILE functions */
-CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
- const char *source);
-CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
-
-#ifndef MEMDEBUG_NODEFINES
-
-/* Set this symbol on the command-line, recompile all lib-sources */
-#undef strdup
-#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
-#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
-#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
-#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
-#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
-
-#define socket(domain,type,protocol)\
- curl_socket(domain,type,protocol,__LINE__,__FILE__)
-#undef accept /* for those with accept as a macro */
-#define accept(sock,addr,len)\
- curl_accept(sock,addr,len,__LINE__,__FILE__)
-
-#if defined(getaddrinfo) && defined(__osf__)
-/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
- our macro as for other platforms. Instead, we redefine the new name they
- define getaddrinfo to become! */
-#define ogetaddrinfo(host,serv,hint,res) \
- curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
-#else
-#undef getaddrinfo
-#define getaddrinfo(host,serv,hint,res) \
- curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
-#endif
-
-#ifdef HAVE_GETNAMEINFO
-#undef getnameinfo
-#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
- curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
- __FILE__)
-#endif
-
-#undef freeaddrinfo
-#define freeaddrinfo(data) \
- curl_dofreeaddrinfo(data,__LINE__,__FILE__)
-
-/* sclose is probably already defined, redefine it! */
-#undef sclose
-#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
-/* ares-adjusted define: */
-#undef closesocket
-#define closesocket(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
-
-#undef fopen
-#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
-#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
-
-#endif /* MEMDEBUG_NODEFINES */
-
-#endif /* _CURL_MEDEBUG_H */
-#endif /* CURLDEBUG */
diff --git a/Utilities/cmcurl/memory.h b/Utilities/cmcurl/memory.h
deleted file mode 100644
index 076d20a28..000000000
--- a/Utilities/cmcurl/memory.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _CURL_MEMORY_H
-#define _CURL_MEMORY_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <curl/curl.h> /* for the typedefs */
-
-extern curl_malloc_callback Curl_cmalloc;
-extern curl_free_callback Curl_cfree;
-extern curl_realloc_callback Curl_crealloc;
-extern curl_strdup_callback Curl_cstrdup;
-extern curl_calloc_callback Curl_ccalloc;
-
-#ifndef CURLDEBUG
-/* Only do this define-mania if we're not using the memdebug system, as that
- has preference on this magic. */
-#undef strdup
-#define strdup(ptr) Curl_cstrdup(ptr)
-#undef malloc
-#define malloc(size) Curl_cmalloc(size)
-#undef calloc
-#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
-#undef realloc
-#define realloc(ptr,size) Curl_crealloc(ptr, size)
-#undef free
-#define free(ptr) Curl_cfree(ptr)
-
-#endif
-
-#endif /* _CURL_MEMORY_H */
diff --git a/Utilities/cmcurl/mprintf.c b/Utilities/cmcurl/mprintf.c
deleted file mode 100644
index 8b2f3d07e..000000000
--- a/Utilities/cmcurl/mprintf.c
+++ /dev/null
@@ -1,1218 +0,0 @@
-/****************************************************************************
- *
- * $Id$
- *
- *************************************************************************
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
- * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
- *
- * Purpose:
- * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
- * 1.0. A full blooded printf() clone with full support for <num>$
- * everywhere (parameters, widths and precisions) including variabled
- * sized parameters (like doubles, long longs, long doubles and even
- * void * in 64-bit architectures).
- *
- * Current restrictions:
- * - Max 128 parameters
- * - No 'long double' support.
- *
- * If you ever want truly portable and good *printf() clones, the project that
- * took on from here is named 'Trio' and you find more details on the trio web
- * page at http://daniel.haxx.se/trio/
- */
-
-
-#include "setup.h"
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#if defined(DJGPP) && (DJGPP_MINOR < 4)
-#undef _MPRINTF_REPLACE /* don't use x_was_used() here */
-#endif
-
-#include <curl/mprintf.h>
-
-#ifndef SIZEOF_SIZE_T
-/* default to 4 bytes for size_t unless defined in the config.h */
-#define SIZEOF_SIZE_T 4
-#endif
-
-#ifdef DPRINTF_DEBUG
-#define HAVE_LONGLONG
-#define LONG_LONG long long
-#define ENABLE_64BIT
-#endif
-
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
-#define MAX_PARAMETERS 128 /* lame static limit */
-
-#undef TRUE
-#undef FALSE
-#undef BOOL
-#ifdef __cplusplus
-# define TRUE true
-# define FALSE false
-# define BOOL bool
-#else
-# define TRUE ((char)(1 == 1))
-# define FALSE ((char)(0 == 1))
-# define BOOL char
-#endif
-
-#ifdef _AMIGASF
-# undef FORMAT_INT
-#endif
-
-/* Lower-case digits. */
-static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
-
-/* Upper-case digits. */
-static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
-#define OUTCHAR(x) \
- do{ \
- if(stream((unsigned char)(x), (FILE *)data) != -1) \
- done++; \
- else \
- return done; /* return immediately on failure */ \
- } while(0)
-
-/* Data type to read from the arglist */
-typedef enum {
- FORMAT_UNKNOWN = 0,
- FORMAT_STRING,
- FORMAT_PTR,
- FORMAT_INT,
- FORMAT_INTPTR,
- FORMAT_LONG,
- FORMAT_LONGLONG,
- FORMAT_DOUBLE,
- FORMAT_LONGDOUBLE,
- FORMAT_WIDTH /* For internal use */
-} FormatType;
-
-/* convertion and display flags */
-enum {
- FLAGS_NEW = 0,
- FLAGS_SPACE = 1<<0,
- FLAGS_SHOWSIGN = 1<<1,
- FLAGS_LEFT = 1<<2,
- FLAGS_ALT = 1<<3,
- FLAGS_SHORT = 1<<4,
- FLAGS_LONG = 1<<5,
- FLAGS_LONGLONG = 1<<6,
- FLAGS_LONGDOUBLE = 1<<7,
- FLAGS_PAD_NIL = 1<<8,
- FLAGS_UNSIGNED = 1<<9,
- FLAGS_OCTAL = 1<<10,
- FLAGS_HEX = 1<<11,
- FLAGS_UPPER = 1<<12,
- FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
- FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
- FLAGS_PREC = 1<<15, /* precision was specified */
- FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
- FLAGS_CHAR = 1<<17, /* %c story */
- FLAGS_FLOATE = 1<<18, /* %e or %E */
- FLAGS_FLOATG = 1<<19 /* %g or %G */
-};
-
-typedef struct {
- FormatType type;
- int flags;
- long width; /* width OR width parameter number */
- long precision; /* precision OR precision parameter number */
- union {
- char *str;
- void *ptr;
- long num;
-#ifdef ENABLE_64BIT
- LONG_LONG lnum;
-#endif
- double dnum;
- } data;
-} va_stack_t;
-
-struct nsprintf {
- char *buffer;
- size_t length;
- size_t max;
-};
-
-struct asprintf {
- char *buffer; /* allocated buffer */
- size_t len; /* length of string */
- size_t alloc; /* length of alloc */
- bool fail; /* TRUE if an alloc has failed and thus the output is not
- the complete data */
-};
-
-int curl_msprintf(char *buffer, const char *format, ...);
-
-static long dprintf_DollarString(char *input, char **end)
-{
- int number=0;
- while(ISDIGIT(*input)) {
- number *= 10;
- number += *input-'0';
- input++;
- }
- if(number && ('$'==*input++)) {
- *end = input;
- return number;
- }
- return 0;
-}
-
-static BOOL dprintf_IsQualifierNoDollar(char c)
-{
- switch (c) {
- case '-': case '+': case ' ': case '#': case '.':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'h': case 'l': case 'L': case 'z': case 'q':
- case '*': case 'O':
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-#ifdef DPRINTF_DEBUG2
-int dprintf_Pass1Report(va_stack_t *vto, int max)
-{
- int i;
- char buffer[128];
- int bit;
- int flags;
-
- for(i=0; i<max; i++) {
- char *type;
- switch(vto[i].type) {
- case FORMAT_UNKNOWN:
- type = "unknown";
- break;
- case FORMAT_STRING:
- type ="string";
- break;
- case FORMAT_PTR:
- type ="pointer";
- break;
- case FORMAT_INT:
- type = "int";
- break;
- case FORMAT_LONG:
- type = "long";
- break;
- case FORMAT_LONGLONG:
- type = "long long";
- break;
- case FORMAT_DOUBLE:
- type = "double";
- break;
- case FORMAT_LONGDOUBLE:
- type = "long double";
- break;
- }
-
-
- buffer[0]=0;
-
- for(bit=0; bit<31; bit++) {
- flags = vto[i].flags & (1<<bit);
-
- if(flags & FLAGS_SPACE)
- strcat(buffer, "space ");
- else if(flags & FLAGS_SHOWSIGN)
- strcat(buffer, "plus ");
- else if(flags & FLAGS_LEFT)
- strcat(buffer, "left ");
- else if(flags & FLAGS_ALT)
- strcat(buffer, "alt ");
- else if(flags & FLAGS_SHORT)
- strcat(buffer, "short ");
- else if(flags & FLAGS_LONG)
- strcat(buffer, "long ");
- else if(flags & FLAGS_LONGLONG)
- strcat(buffer, "longlong ");
- else if(flags & FLAGS_LONGDOUBLE)
- strcat(buffer, "longdouble ");
- else if(flags & FLAGS_PAD_NIL)
- strcat(buffer, "padnil ");
- else if(flags & FLAGS_UNSIGNED)
- strcat(buffer, "unsigned ");
- else if(flags & FLAGS_OCTAL)
- strcat(buffer, "octal ");
- else if(flags & FLAGS_HEX)
- strcat(buffer, "hex ");
- else if(flags & FLAGS_UPPER)
- strcat(buffer, "upper ");
- else if(flags & FLAGS_WIDTH)
- strcat(buffer, "width ");
- else if(flags & FLAGS_WIDTHPARAM)
- strcat(buffer, "widthparam ");
- else if(flags & FLAGS_PREC)
- strcat(buffer, "precision ");
- else if(flags & FLAGS_PRECPARAM)
- strcat(buffer, "precparam ");
- else if(flags & FLAGS_CHAR)
- strcat(buffer, "char ");
- else if(flags & FLAGS_FLOATE)
- strcat(buffer, "floate ");
- else if(flags & FLAGS_FLOATG)
- strcat(buffer, "floatg ");
- }
- printf("REPORT: %d. %s [%s]\n", i, type, buffer);
-
- }
-
-
-}
-#endif
-
-/******************************************************************
- *
- * Pass 1:
- * Create an index with the type of each parameter entry and its
- * value (may vary in size)
- *
- ******************************************************************/
-
-static long dprintf_Pass1(char *format, va_stack_t *vto, char **endpos,
- va_list arglist)
-{
- char *fmt = format;
- int param_num = 0;
- long this_param;
- long width;
- long precision;
- int flags;
- long max_param=0;
- long i;
-
- while (*fmt) {
- if (*fmt++ == '%') {
- if (*fmt == '%') {
- fmt++;
- continue; /* while */
- }
-
- flags = FLAGS_NEW;
-
- /* Handle the positional case (N$) */
-
- param_num++;
-
- this_param = dprintf_DollarString(fmt, &fmt);
- if (0 == this_param)
- /* we got no positional, get the next counter */
- this_param = param_num;
-
- if (this_param > max_param)
- max_param = this_param;
-
- /*
- * The parameter with number 'i' should be used. Next, we need
- * to get SIZE and TYPE of the parameter. Add the information
- * to our array.
- */
-
- width = 0;
- precision = 0;
-
- /* Handle the flags */
-
- while (dprintf_IsQualifierNoDollar(*fmt)) {
- switch (*fmt++) {
- case ' ':
- flags |= FLAGS_SPACE;
- break;
- case '+':
- flags |= FLAGS_SHOWSIGN;
- break;
- case '-':
- flags |= FLAGS_LEFT;
- flags &= ~FLAGS_PAD_NIL;
- break;
- case '#':
- flags |= FLAGS_ALT;
- break;
- case '.':
- flags |= FLAGS_PREC;
- if ('*' == *fmt) {
- /* The precision is picked from a specified parameter */
-
- flags |= FLAGS_PRECPARAM;
- fmt++;
- param_num++;
-
- i = dprintf_DollarString(fmt, &fmt);
- if (i)
- precision = i;
- else
- precision = param_num;
-
- if (precision > max_param)
- max_param = precision;
- }
- else {
- flags |= FLAGS_PREC;
- precision = strtol(fmt, &fmt, 10);
- }
- break;
- case 'h':
- flags |= FLAGS_SHORT;
- break;
- case 'l':
- if (flags & FLAGS_LONG)
- flags |= FLAGS_LONGLONG;
- else
- flags |= FLAGS_LONG;
- break;
- case 'L':
- flags |= FLAGS_LONGDOUBLE;
- break;
- case 'q':
- flags |= FLAGS_LONGLONG;
- break;
- case 'z':
- /* the code below generates a warning if -Wunreachable-code is
- used */
-#if SIZEOF_SIZE_T>4
- flags |= FLAGS_LONGLONG;
-#else
- flags |= FLAGS_LONG;
-#endif
- break;
- case 'O':
-#if SIZEOF_CURL_OFF_T > 4
- flags |= FLAGS_LONGLONG;
-#else
- flags |= FLAGS_LONG;
-#endif
- break;
- case '0':
- if (!(flags & FLAGS_LEFT))
- flags |= FLAGS_PAD_NIL;
- /* FALLTHROUGH */
- case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- flags |= FLAGS_WIDTH;
- width = strtol(fmt-1, &fmt, 10);
- break;
- case '*': /* Special case */
- flags |= FLAGS_WIDTHPARAM;
- param_num++;
-
- i = dprintf_DollarString(fmt, &fmt);
- if(i)
- width = i;
- else
- width = param_num;
- if(width > max_param)
- max_param=width;
- break;
- default:
- break;
- }
- } /* switch */
-
- /* Handle the specifier */
-
- i = this_param - 1;
-
- switch (*fmt) {
- case 'S':
- flags |= FLAGS_ALT;
- /* FALLTHROUGH */
- case 's':
- vto[i].type = FORMAT_STRING;
- break;
- case 'n':
- vto[i].type = FORMAT_INTPTR;
- break;
- case 'p':
- vto[i].type = FORMAT_PTR;
- break;
- case 'd': case 'i':
- vto[i].type = FORMAT_INT;
- break;
- case 'u':
- vto[i].type = FORMAT_INT;
- flags |= FLAGS_UNSIGNED;
- break;
- case 'o':
- vto[i].type = FORMAT_INT;
- flags |= FLAGS_OCTAL;
- break;
- case 'x':
- vto[i].type = FORMAT_INT;
- flags |= FLAGS_HEX;
- break;
- case 'X':
- vto[i].type = FORMAT_INT;
- flags |= FLAGS_HEX|FLAGS_UPPER;
- break;
- case 'c':
- vto[i].type = FORMAT_INT;
- flags |= FLAGS_CHAR;
- break;
- case 'f':
- vto[i].type = FORMAT_DOUBLE;
- break;
- case 'e':
- vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATE;
- break;
- case 'E':
- vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATE|FLAGS_UPPER;
- break;
- case 'g':
- vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATG;
- break;
- case 'G':
- vto[i].type = FORMAT_DOUBLE;
- flags |= FLAGS_FLOATG|FLAGS_UPPER;
- break;
- default:
- vto[i].type = FORMAT_UNKNOWN;
- break;
- } /* switch */
-
- vto[i].flags = flags;
- vto[i].width = width;
- vto[i].precision = precision;
-
- if (flags & FLAGS_WIDTHPARAM) {
- /* we have the width specified from a parameter, so we make that
- parameter's info setup properly */
- vto[i].width = width - 1;
- i = width - 1;
- vto[i].type = FORMAT_WIDTH;
- vto[i].flags = FLAGS_NEW;
- vto[i].precision = vto[i].width = 0; /* can't use width or precision
- of width! */
- }
- if (flags & FLAGS_PRECPARAM) {
- /* we have the precision specified from a parameter, so we make that
- parameter's info setup properly */
- vto[i].precision = precision - 1;
- i = precision - 1;
- vto[i].type = FORMAT_WIDTH;
- vto[i].flags = FLAGS_NEW;
- vto[i].precision = vto[i].width = 0; /* can't use width or precision
- of width! */
- }
- *endpos++ = fmt + 1; /* end of this sequence */
- }
- }
-
-#ifdef DPRINTF_DEBUG2
- dprintf_Pass1Report(vto, max_param);
-#endif
-
- /* Read the arg list parameters into our data list */
- for (i=0; i<max_param; i++) {
- if ((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH))
- {
- /* Width/precision arguments must be read before the main argument
- * they are attached to
- */
- vto[i + 1].data.num = va_arg(arglist, int);
- }
-
- switch (vto[i].type)
- {
- case FORMAT_STRING:
- vto[i].data.str = va_arg(arglist, char *);
- break;
-
- case FORMAT_INTPTR:
- case FORMAT_UNKNOWN:
- case FORMAT_PTR:
- vto[i].data.ptr = va_arg(arglist, void *);
- break;
-
- case FORMAT_INT:
-#ifdef ENABLE_64BIT
- if(vto[i].flags & FLAGS_LONGLONG)
- vto[i].data.lnum = va_arg(arglist, LONG_LONG);
- else
-#endif
- if(vto[i].flags & FLAGS_LONG)
- vto[i].data.num = va_arg(arglist, long);
- else
- vto[i].data.num = va_arg(arglist, int);
- break;
-
- case FORMAT_DOUBLE:
- vto[i].data.dnum = va_arg(arglist, double);
- break;
-
- case FORMAT_WIDTH:
- /* Argument has been read. Silently convert it into an integer
- * for later use
- */
- vto[i].type = FORMAT_INT;
- break;
-
- default:
- break;
- }
- }
-
- return max_param;
-
-}
-
-static int dprintf_formatf(
- void *data, /* untouched by format(), just sent to the stream() function in
- the second argument */
- /* function pointer called for each output character */
- int (*stream)(int, FILE *),
- const char *format, /* %-formatted string */
- va_list ap_save) /* list of parameters */
-{
- /* Base-36 digits for numbers. */
- const char *digits = lower_digits;
-
- /* Pointer into the format string. */
- char *f;
-
- /* Number of characters written. */
- int done = 0;
-
- long param; /* current parameter to read */
- long param_num=0; /* parameter counter */
-
- va_stack_t vto[MAX_PARAMETERS];
- char *endpos[MAX_PARAMETERS];
- char **end;
-
- char work[BUFFSIZE];
-
- va_stack_t *p;
-
- /* Do the actual %-code parsing */
- dprintf_Pass1((char *)format, vto, endpos, ap_save);
-
- end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
- created for us */
-
- f = (char *)format;
- while (*f != '\0') {
- /* Format spec modifiers. */
- char alt;
-
- /* Width of a field. */
- long width;
-
- /* Precision of a field. */
- long prec;
-
- /* Decimal integer is negative. */
- char is_neg;
-
- /* Base of a number to be written. */
- long base;
-
- /* Integral values to be written. */
-#ifdef ENABLE_64BIT
- unsigned LONG_LONG num;
-#else
- unsigned long num;
-#endif
- long signed_num;
-
- if (*f != '%') {
- /* This isn't a format spec, so write everything out until the next one
- OR end of string is reached. */
- do {
- OUTCHAR(*f);
- } while(*++f && ('%' != *f));
- continue;
- }
-
- ++f;
-
- /* Check for "%%". Note that although the ANSI standard lists
- '%' as a conversion specifier, it says "The complete format
- specification shall be `%%'," so we can avoid all the width
- and precision processing. */
- if (*f == '%') {
- ++f;
- OUTCHAR('%');
- continue;
- }
-
- /* If this is a positional parameter, the position must follow imediately
- after the %, thus create a %<num>$ sequence */
- param=dprintf_DollarString(f, &f);
-
- if(!param)
- param = param_num;
- else
- --param;
-
- param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
- third %s will pick the 3rd argument */
-
- p = &vto[param];
-
- /* pick up the specified width */
- if(p->flags & FLAGS_WIDTHPARAM)
- width = vto[p->width].data.num;
- else
- width = p->width;
-
- /* pick up the specified precision */
- if(p->flags & FLAGS_PRECPARAM)
- prec = vto[p->precision].data.num;
- else if(p->flags & FLAGS_PREC)
- prec = p->precision;
- else
- prec = -1;
-
- alt = (p->flags & FLAGS_ALT)?TRUE:FALSE;
-
- switch (p->type) {
- case FORMAT_INT:
- num = p->data.num;
- if(p->flags & FLAGS_CHAR) {
- /* Character. */
- if (!(p->flags & FLAGS_LEFT))
- while (--width > 0)
- OUTCHAR(' ');
- OUTCHAR((char) num);
- if (p->flags & FLAGS_LEFT)
- while (--width > 0)
- OUTCHAR(' ');
- break;
- }
- if(p->flags & FLAGS_UNSIGNED) {
- /* Decimal unsigned integer. */
- base = 10;
- goto unsigned_number;
- }
- if(p->flags & FLAGS_OCTAL) {
- /* Octal unsigned integer. */
- base = 8;
- goto unsigned_number;
- }
- if(p->flags & FLAGS_HEX) {
- /* Hexadecimal unsigned integer. */
-
- digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
- base = 16;
- goto unsigned_number;
- }
-
- /* Decimal integer. */
- base = 10;
-
-#ifdef ENABLE_64BIT
- if(p->flags & FLAGS_LONGLONG) {
- /* long long */
- is_neg = p->data.lnum < 0;
- num = is_neg ? (- p->data.lnum) : p->data.lnum;
- }
- else
-#endif
- {
- signed_num = (long) num;
- is_neg = signed_num < 0;
- num = is_neg ? (- signed_num) : signed_num;
- }
- goto number;
-
- unsigned_number:
- /* Unsigned number of base BASE. */
- is_neg = 0;
-
- number:
- /* Number of base BASE. */
- {
- char *workend = &work[sizeof(work) - 1];
- char *w;
-
- /* Supply a default precision if none was given. */
- if (prec == -1)
- prec = 1;
-
- /* Put the number in WORK. */
- w = workend;
- while (num > 0) {
- *w-- = digits[num % base];
- num /= base;
- }
- width -= (long)(workend - w);
- prec -= (long)(workend - w);
-
- if (alt && base == 8 && prec <= 0) {
- *w-- = '0';
- --width;
- }
-
- if (prec > 0) {
- width -= prec;
- while (prec-- > 0)
- *w-- = '0';
- }
-
- if (alt && base == 16)
- width -= 2;
-
- if (is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
- --width;
-
- if (!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
- while (width-- > 0)
- OUTCHAR(' ');
-
- if (is_neg)
- OUTCHAR('-');
- else if (p->flags & FLAGS_SHOWSIGN)
- OUTCHAR('+');
- else if (p->flags & FLAGS_SPACE)
- OUTCHAR(' ');
-
- if (alt && base == 16) {
- OUTCHAR('0');
- if(p->flags & FLAGS_UPPER)
- OUTCHAR('X');
- else
- OUTCHAR('x');
- }
-
- if (!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
- while (width-- > 0)
- OUTCHAR('0');
-
- /* Write the number. */
- while (++w <= workend) {
- OUTCHAR(*w);
- }
-
- if (p->flags & FLAGS_LEFT)
- while (width-- > 0)
- OUTCHAR(' ');
- }
- break;
-
- case FORMAT_STRING:
- /* String. */
- {
- static const char null[] = "(nil)";
- const char *str;
- size_t len;
-
- str = (char *) p->data.str;
- if ( str == NULL) {
- /* Write null[] if there's space. */
- if (prec == -1 || prec >= (long) sizeof(null) - 1) {
- str = null;
- len = sizeof(null) - 1;
- /* Disable quotes around (nil) */
- p->flags &= (~FLAGS_ALT);
- }
- else {
- str = "";
- len = 0;
- }
- }
- else
- len = strlen(str);
-
- if (prec != -1 && (size_t) prec < len)
- len = prec;
- width -= (long)len;
-
- if (p->flags & FLAGS_ALT)
- OUTCHAR('"');
-
- if (!(p->flags&FLAGS_LEFT))
- while (width-- > 0)
- OUTCHAR(' ');
-
- while (len-- > 0)
- OUTCHAR(*str++);
- if (p->flags&FLAGS_LEFT)
- while (width-- > 0)
- OUTCHAR(' ');
-
- if (p->flags & FLAGS_ALT)
- OUTCHAR('"');
- }
- break;
-
- case FORMAT_PTR:
- /* Generic pointer. */
- {
- void *ptr;
- ptr = (void *) p->data.ptr;
- if (ptr != NULL) {
- /* If the pointer is not NULL, write it as a %#x spec. */
- base = 16;
- digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
- alt = 1;
- num = (size_t) ptr;
- is_neg = 0;
- goto number;
- }
- else {
- /* Write "(nil)" for a nil pointer. */
- static const char strnil[] = "(nil)";
- const char *point;
-
- width -= sizeof(strnil) - 1;
- if (p->flags & FLAGS_LEFT)
- while (width-- > 0)
- OUTCHAR(' ');
- for (point = strnil; *point != '\0'; ++point)
- OUTCHAR(*point);
- if (! (p->flags & FLAGS_LEFT))
- while (width-- > 0)
- OUTCHAR(' ');
- }
- }
- break;
-
- case FORMAT_DOUBLE:
- {
- char formatbuf[32]="%";
- char *fptr;
- size_t left = sizeof(formatbuf)-strlen(formatbuf);
- int len;
-
- width = -1;
- if (p->flags & FLAGS_WIDTH)
- width = p->width;
- else if (p->flags & FLAGS_WIDTHPARAM)
- width = vto[p->width].data.num;
-
- prec = -1;
- if (p->flags & FLAGS_PREC)
- prec = p->precision;
- else if (p->flags & FLAGS_PRECPARAM)
- prec = vto[p->precision].data.num;
-
- if (p->flags & FLAGS_LEFT)
- strcat(formatbuf, "-");
- if (p->flags & FLAGS_SHOWSIGN)
- strcat(formatbuf, "+");
- if (p->flags & FLAGS_SPACE)
- strcat(formatbuf, " ");
- if (p->flags & FLAGS_ALT)
- strcat(formatbuf, "#");
-
- fptr=&formatbuf[strlen(formatbuf)];
-
- if(width >= 0) {
- /* RECURSIVE USAGE */
- len = curl_msnprintf(fptr, left, "%ld", width);
- fptr += len;
- left -= len;
- }
- if(prec >= 0) {
- /* RECURSIVE USAGE */
- len = curl_msnprintf(fptr, left, ".%ld", prec);
- fptr += len;
- left -= len;
- }
- if (p->flags & FLAGS_LONG)
- *fptr++ = 'l';
-
- if (p->flags & FLAGS_FLOATE)
- *fptr++ = p->flags&FLAGS_UPPER ? 'E':'e';
- else if (p->flags & FLAGS_FLOATG)
- *fptr++ = p->flags & FLAGS_UPPER ? 'G' : 'g';
- else
- *fptr++ = 'f';
-
- *fptr = 0; /* and a final zero termination */
-
- /* NOTE NOTE NOTE!! Not all sprintf() implementations returns number
- of output characters */
- (sprintf)(work, formatbuf, p->data.dnum);
-
- for(fptr=work; *fptr; fptr++)
- OUTCHAR(*fptr);
- }
- break;
-
- case FORMAT_INTPTR:
- /* Answer the count of characters written. */
-#ifdef ENABLE_64BIT
- if (p->flags & FLAGS_LONGLONG)
- *(LONG_LONG *) p->data.ptr = (LONG_LONG)done;
- else
-#endif
- if (p->flags & FLAGS_LONG)
- *(long *) p->data.ptr = (long)done;
- else if (!(p->flags & FLAGS_SHORT))
- *(int *) p->data.ptr = (int)done;
- else
- *(short *) p->data.ptr = (short)done;
- break;
-
- default:
- break;
- }
- f = *end++; /* goto end of %-code */
-
- }
- return done;
-}
-
-/* fputc() look-alike */
-static int addbyter(int output, FILE *data)
-{
- struct nsprintf *infop=(struct nsprintf *)data;
- unsigned char outc = (unsigned char)output;
-
- if(infop->length < infop->max) {
- /* only do this if we haven't reached max length yet */
- infop->buffer[0] = outc; /* store */
- infop->buffer++; /* increase pointer */
- infop->length++; /* we are now one byte larger */
- return outc; /* fputc() returns like this on success */
- }
- return -1;
-}
-
-int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
- va_list ap_save)
-{
- int retcode;
- struct nsprintf info;
-
- info.buffer = buffer;
- info.length = 0;
- info.max = maxlength;
-
- retcode = dprintf_formatf(&info, addbyter, format, ap_save);
- if(info.max) {
- /* we terminate this with a zero byte */
- if(info.max == info.length)
- /* we're at maximum, scrap the last letter */
- info.buffer[-1] = 0;
- else
- info.buffer[0] = 0;
- }
- return retcode;
-}
-
-int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
-{
- int retcode;
- va_list ap_save; /* argument pointer */
- va_start(ap_save, format);
- retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
- va_end(ap_save);
- return retcode;
-}
-
-/* fputc() look-alike */
-static int alloc_addbyter(int output, FILE *data)
-{
- struct asprintf *infop=(struct asprintf *)data;
- unsigned char outc = (unsigned char)output;
-
- if(!infop->buffer) {
- infop->buffer=(char *)malloc(32);
- if(!infop->buffer) {
- infop->fail = TRUE;
- return -1; /* fail */
- }
- infop->alloc = 32;
- infop->len =0;
- }
- else if(infop->len+1 >= infop->alloc) {
- char *newptr;
-
- newptr = (char *)realloc(infop->buffer, infop->alloc*2);
-
- if(!newptr) {
- infop->fail = TRUE;
- return -1;
- }
- infop->buffer = newptr;
- infop->alloc *= 2;
- }
-
- infop->buffer[ infop->len ] = outc;
-
- infop->len++;
-
- return outc; /* fputc() returns like this on success */
-}
-
-char *curl_maprintf(const char *format, ...)
-{
- va_list ap_save; /* argument pointer */
- int retcode;
- struct asprintf info;
-
- info.buffer = NULL;
- info.len = 0;
- info.alloc = 0;
- info.fail = FALSE;
-
- va_start(ap_save, format);
- retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
- va_end(ap_save);
- if((-1 == retcode) || info.fail) {
- if(info.alloc)
- free(info.buffer);
- return NULL;
- }
- if(info.alloc) {
- info.buffer[info.len] = 0; /* we terminate this with a zero byte */
- return info.buffer;
- }
- else
- return strdup("");
-}
-
-char *curl_mvaprintf(const char *format, va_list ap_save)
-{
- int retcode;
- struct asprintf info;
-
- info.buffer = NULL;
- info.len = 0;
- info.alloc = 0;
- info.fail = FALSE;
-
- retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
- if((-1 == retcode) || info.fail) {
- if(info.alloc)
- free(info.buffer);
- return NULL;
- }
-
- if(info.alloc) {
- info.buffer[info.len] = 0; /* we terminate this with a zero byte */
- return info.buffer;
- }
- else
- return strdup("");
-}
-
-static int storebuffer(int output, FILE *data)
-{
- char **buffer = (char **)data;
- unsigned char outc = (unsigned char)output;
- **buffer = outc;
- (*buffer)++;
- return outc; /* act like fputc() ! */
-}
-
-int curl_msprintf(char *buffer, const char *format, ...)
-{
- va_list ap_save; /* argument pointer */
- int retcode;
- va_start(ap_save, format);
- retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
- va_end(ap_save);
- *buffer=0; /* we terminate this with a zero byte */
- return retcode;
-}
-
-int curl_mprintf(const char *format, ...)
-{
- int retcode;
- va_list ap_save; /* argument pointer */
- va_start(ap_save, format);
-
- retcode = dprintf_formatf(stdout, fputc, format, ap_save);
- va_end(ap_save);
- return retcode;
-}
-
-int curl_mfprintf(FILE *whereto, const char *format, ...)
-{
- int retcode;
- va_list ap_save; /* argument pointer */
- va_start(ap_save, format);
- retcode = dprintf_formatf(whereto, fputc, format, ap_save);
- va_end(ap_save);
- return retcode;
-}
-
-int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
-{
- int retcode;
- retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
- *buffer=0; /* we terminate this with a zero byte */
- return retcode;
-}
-
-int curl_mvprintf(const char *format, va_list ap_save)
-{
- return dprintf_formatf(stdout, fputc, format, ap_save);
-}
-
-int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
-{
- return dprintf_formatf(whereto, fputc, format, ap_save);
-}
-
-#ifdef DPRINTF_DEBUG
-int main()
-{
- char buffer[129];
- char *ptr;
-#ifdef ENABLE_64BIT
- long long one=99;
- long long two=100;
- long long test = 0x1000000000LL;
- curl_mprintf("%lld %lld %lld\n", one, two, test);
-#endif
-
- curl_mprintf("%3d %5d\n", 10, 1998);
-
- ptr=curl_maprintf("test this then baby %s%s%s%s%s%s %d %d %d loser baby get a hit in yer face now!", "", "pretty long string pretty long string pretty long string pretty long string pretty long string", "/", "/", "/", "pretty long string", 1998, 1999, 2001);
-
- puts(ptr);
-
- memset(ptr, 55, strlen(ptr)+1);
-
- free(ptr);
-
-#if 1
- curl_mprintf(buffer, "%s %s %d", "daniel", "stenberg", 19988);
- puts(buffer);
-
- curl_mfprintf(stderr, "%s %#08x\n", "dummy", 65);
-
- printf("%s %#08x\n", "dummy", 65);
- {
- double tryout = 3.14156592;
- curl_mprintf(buffer, "%.2g %G %f %e %E", tryout, tryout, tryout, tryout, tryout);
- puts(buffer);
- printf("%.2g %G %f %e %E\n", tryout, tryout, tryout, tryout, tryout);
- }
-#endif
-
- return 0;
-}
-
-#endif
diff --git a/Utilities/cmcurl/multi.c b/Utilities/cmcurl/multi.c
deleted file mode 100644
index b501f296f..000000000
--- a/Utilities/cmcurl/multi.c
+++ /dev/null
@@ -1,1988 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <curl/curl.h>
-
-#include "urldata.h"
-#include "transfer.h"
-#include "url.h"
-#include "connect.h"
-#include "progress.h"
-#include "memory.h"
-#include "easyif.h"
-#include "multiif.h"
-#include "sendf.h"
-#include "timeval.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-struct Curl_message {
- /* the 'CURLMsg' is the part that is visible to the external user */
- struct CURLMsg extmsg;
- struct Curl_message *next;
-};
-
-typedef enum {
- CURLM_STATE_INIT, /* start in this state */
- CURLM_STATE_CONNECT, /* resolve/connect has been sent off */
- CURLM_STATE_WAITRESOLVE, /* awaiting the resolve to finalize */
- CURLM_STATE_WAITCONNECT, /* awaiting the connect to finalize */
- CURLM_STATE_PROTOCONNECT, /* completing the protocol-specific connect
- phase */
- CURLM_STATE_WAITDO, /* wait for our turn to send the request */
- CURLM_STATE_DO, /* start send off the request (part 1) */
- CURLM_STATE_DOING, /* sending off the request (part 1) */
- CURLM_STATE_DO_MORE, /* send off the request (part 2) */
- CURLM_STATE_DO_DONE, /* done sending off request */
- CURLM_STATE_WAITPERFORM, /* wait for our turn to read the response */
- CURLM_STATE_PERFORM, /* transfer data */
- CURLM_STATE_TOOFAST, /* wait because limit-rate exceeded */
- CURLM_STATE_DONE, /* post data transfer operation */
- CURLM_STATE_COMPLETED, /* operation complete */
- CURLM_STATE_CANCELLED, /* cancelled */
-
- CURLM_STATE_LAST /* not a true state, never use this */
-} CURLMstate;
-
-/* we support N sockets per easy handle. Set the corresponding bit to what
- action we should wait for */
-#define MAX_SOCKSPEREASYHANDLE 5
-#define GETSOCK_READABLE (0x00ff)
-#define GETSOCK_WRITABLE (0xff00)
-
-struct closure {
- struct closure *next; /* a simple one-way list of structs */
- struct SessionHandle *easy_handle;
-};
-
-struct Curl_one_easy {
- /* first, two fields for the linked list of these */
- struct Curl_one_easy *next;
- struct Curl_one_easy *prev;
-
- struct SessionHandle *easy_handle; /* the easy handle for this unit */
- struct connectdata *easy_conn; /* the "unit's" connection */
-
- CURLMstate state; /* the handle's state */
- CURLcode result; /* previous result */
-
- struct Curl_message *msg; /* A pointer to one single posted message.
- Cleanup should be done on this pointer NOT on
- the linked list in Curl_multi. This message
- will be deleted when this handle is removed
- from the multi-handle */
- int msg_num; /* number of messages left in 'msg' to return */
-
- /* Array with the plain socket numbers this handle takes care of, in no
- particular order. Note that all sockets are added to the sockhash, where
- the state etc are also kept. This array is mostly used to detect when a
- socket is to be removed from the hash. See singlesocket(). */
- curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
- int numsocks;
-};
-
-#define CURL_MULTI_HANDLE 0x000bab1e
-
-#define GOOD_MULTI_HANDLE(x) \
- ((x)&&(((struct Curl_multi *)x)->type == CURL_MULTI_HANDLE))
-#define GOOD_EASY_HANDLE(x) \
- (((struct SessionHandle *)x)->magic == CURLEASY_MAGIC_NUMBER)
-
-/* This is the struct known as CURLM on the outside */
-struct Curl_multi {
- /* First a simple identifier to easier detect if a user mix up
- this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
- long type;
-
- /* We have a linked list with easy handles */
- struct Curl_one_easy easy;
-
- int num_easy; /* amount of entries in the linked list above. */
- int num_msgs; /* amount of messages in the easy handles */
- int num_alive; /* amount of easy handles that are added but have not yet
- reached COMPLETE state */
-
- /* callback function and user data pointer for the *socket() API */
- curl_socket_callback socket_cb;
- void *socket_userp;
-
- /* Hostname cache */
- struct curl_hash *hostcache;
-
- /* timetree points to the splay-tree of time nodes to figure out expire
- times of all currently set timers */
- struct Curl_tree *timetree;
-
- /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
- the pluralis form, there can be more than one easy handle waiting on the
- same actual socket) */
- struct curl_hash *sockhash;
-
- /* Whether pipelining is enabled for this multi handle */
- bool pipelining_enabled;
-
- /* shared connection cache */
- struct conncache *connc;
-
- /* list of easy handles kept around for doing nice connection closures */
- struct closure *closure;
-
- /* timer callback and user data pointer for the *socket() API */
- curl_multi_timer_callback timer_cb;
- void *timer_userp;
- time_t timer_lastcall; /* the fixed time for the timeout for the previous
- callback */
-};
-
-static bool multi_conn_using(struct Curl_multi *multi,
- struct SessionHandle *data);
-static void singlesocket(struct Curl_multi *multi,
- struct Curl_one_easy *easy);
-static void add_closure(struct Curl_multi *multi,
- struct SessionHandle *data);
-static int update_timer(struct Curl_multi *multi);
-
-#ifdef CURLDEBUG
-static const char *statename[]={
- "INIT",
- "CONNECT",
- "WAITRESOLVE",
- "WAITCONNECT",
- "PROTOCONNECT",
- "WAITDO",
- "DO",
- "DOING",
- "DO_MORE",
- "DO_DONE",
- "WAITPERFORM",
- "PERFORM",
- "TOOFAST",
- "DONE",
- "COMPLETED",
- "CANCELLED"
-};
-
-void curl_multi_dump(CURLM *multi_handle);
-#endif
-
-/* always use this function to change state, to make debugging easier */
-static void multistate(struct Curl_one_easy *easy, CURLMstate state)
-{
-#ifdef CURLDEBUG
- long index = -1;
-#endif
- CURLMstate oldstate = easy->state;
-
- if(oldstate == state)
- /* don't bother when the new state is the same as the old state */
- return;
-
- easy->state = state;
-
-#ifdef CURLDEBUG
- if(easy->state > CURLM_STATE_CONNECT &&
- easy->state < CURLM_STATE_COMPLETED)
- index = easy->easy_conn->connectindex;
-
- infof(easy->easy_handle,
- "STATE: %s => %s handle %p; (connection #%ld) \n",
- statename[oldstate], statename[easy->state],
- (char *)easy, index);
-#endif
- if(state == CURLM_STATE_COMPLETED)
- /* changing to COMPLETED means there's one less easy handle 'alive' */
- easy->easy_handle->multi->num_alive--;
-}
-
-/*
- * We add one of these structs to the sockhash for a particular socket
- */
-
-struct Curl_sh_entry {
- struct SessionHandle *easy;
- time_t timestamp;
- long inuse;
- int action; /* what action READ/WRITE this socket waits for */
- curl_socket_t socket; /* mainly to ease debugging */
- void *socketp; /* settable by users with curl_multi_assign() */
-};
-/* bits for 'action' having no bits means this socket is not expecting any
- action */
-#define SH_READ 1
-#define SH_WRITE 2
-
-/* make sure this socket is present in the hash for this handle */
-static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
- curl_socket_t s,
- struct SessionHandle *data)
-{
- struct Curl_sh_entry *there =
- Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
- struct Curl_sh_entry *check;
-
- if(there)
- /* it is present, return fine */
- return there;
-
- /* not present, add it */
- check = calloc(sizeof(struct Curl_sh_entry), 1);
- if(!check)
- return NULL; /* major failure */
- check->easy = data;
- check->socket = s;
-
- /* make/add new hash entry */
- if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
- free(check);
- return NULL; /* major failure */
- }
-
- return check; /* things are good in sockhash land */
-}
-
-
-/* delete the given socket + handle from the hash */
-static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
-{
- struct Curl_sh_entry *there =
- Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
-
- if(there) {
- /* this socket is in the hash */
- /* We remove the hash entry. (This'll end up in a call to
- sh_freeentry().) */
- Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
- }
-}
-
-/*
- * free a sockhash entry
- */
-static void sh_freeentry(void *freethis)
-{
- struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
-
- free(p);
-}
-
-/*
- * sh_init() creates a new socket hash and returns the handle for it.
- *
- * Quote from README.multi_socket:
- *
- * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
- * is somewhat of a bottle neck. Its current implementation may be a bit too
- * limiting. It simply has a fixed-size array, and on each entry in the array
- * it has a linked list with entries. So the hash only checks which list to
- * scan through. The code I had used so for used a list with merely 7 slots
- * (as that is what the DNS hash uses) but with 7000 connections that would
- * make an average of 1000 nodes in each list to run through. I upped that to
- * 97 slots (I believe a prime is suitable) and noticed a significant speed
- * increase. I need to reconsider the hash implementation or use a rather
- * large default value like this. At 9000 connections I was still below 10us
- * per call."
- *
- */
-static struct curl_hash *sh_init(void)
-{
- return Curl_hash_alloc(97, sh_freeentry);
-}
-
-CURLM *curl_multi_init(void)
-{
- struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1);
-
- if(!multi)
- return NULL;
-
- multi->type = CURL_MULTI_HANDLE;
-
- multi->hostcache = Curl_mk_dnscache();
- if(!multi->hostcache) {
- /* failure, free mem and bail out */
- free(multi);
- return NULL;
- }
-
- multi->sockhash = sh_init();
- if(!multi->sockhash) {
- /* failure, free mem and bail out */
- Curl_hash_destroy(multi->hostcache);
- free(multi);
- return NULL;
- }
-
- multi->connc = Curl_mk_connc(CONNCACHE_MULTI, -1);
- if(!multi->connc) {
- Curl_hash_destroy(multi->hostcache);
- free(multi);
- return NULL;
- }
-
- return (CURLM *) multi;
-}
-
-CURLMcode curl_multi_add_handle(CURLM *multi_handle,
- CURL *easy_handle)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
- struct closure *cl;
- struct closure *prev=NULL;
-
- /* First, make some basic checks that the CURLM handle is a good handle */
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- /* Verify that we got a somewhat good easy handle too */
- if(!GOOD_EASY_HANDLE(easy_handle))
- return CURLM_BAD_EASY_HANDLE;
-
- /* Prevent users to add the same handle more than once! */
- if(((struct SessionHandle *)easy_handle)->multi)
- /* possibly we should create a new unique error code for this condition */
- return CURLM_BAD_EASY_HANDLE;
-
- /* Now, time to add an easy handle to the multi stack */
- easy = (struct Curl_one_easy *)calloc(sizeof(struct Curl_one_easy), 1);
- if(!easy)
- return CURLM_OUT_OF_MEMORY;
-
- cl = multi->closure;
- while(cl) {
- struct closure *next = cl->next;
- if(cl->easy_handle == (struct SessionHandle *)easy_handle) {
- /* remove this handle from the closure list */
- free(cl);
- if(prev)
- prev->next = next;
- else
- multi->closure = next;
- break; /* no need to continue since this handle can only be present once
- in the list */
- }
- cl = next;
- }
-
- /* set the easy handle */
- easy->easy_handle = easy_handle;
- multistate(easy, CURLM_STATE_INIT);
-
- /* for multi interface connections, we share DNS cache automatically if the
- easy handle's one is currently private. */
- if (easy->easy_handle->dns.hostcache &&
- (easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
- Curl_hash_destroy(easy->easy_handle->dns.hostcache);
- easy->easy_handle->dns.hostcache = NULL;
- easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
- }
-
- if (!easy->easy_handle->dns.hostcache ||
- (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
- easy->easy_handle->dns.hostcache = multi->hostcache;
- easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
- }
-
- if(easy->easy_handle->state.connc) {
- if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) {
- /* kill old private version */
- Curl_rm_connc(easy->easy_handle->state.connc);
- /* point out our shared one instead */
- easy->easy_handle->state.connc = multi->connc;
- }
- /* else it is already using multi? */
- }
- else
- /* point out our shared one */
- easy->easy_handle->state.connc = multi->connc;
-
- /* Make sure the type is setup correctly */
- easy->easy_handle->state.connc->type = CONNCACHE_MULTI;
-
- /* We add this new entry first in the list. We make our 'next' point to the
- previous next and our 'prev' point back to the 'first' struct */
- easy->next = multi->easy.next;
- easy->prev = &multi->easy;
-
- /* make 'easy' the first node in the chain */
- multi->easy.next = easy;
-
- /* if there was a next node, make sure its 'prev' pointer links back to
- the new node */
- if(easy->next)
- easy->next->prev = easy;
-
- Curl_easy_addmulti(easy_handle, multi_handle);
-
- /* make the SessionHandle struct refer back to this struct */
- easy->easy_handle->set.one_easy = easy;
-
- /* increase the node-counter */
- multi->num_easy++;
-
- if((multi->num_easy * 4) > multi->connc->num) {
- /* We want the connection cache to have plenty room. Before we supported
- the shared cache every single easy handle had 5 entries in their cache
- by default. */
- CURLcode res = Curl_ch_connc(easy_handle, multi->connc,
- multi->connc->num*4);
- if(res != CURLE_OK)
- /* TODO: we need to do some cleaning up here! */
- return CURLM_OUT_OF_MEMORY;
- }
-
- /* increase the alive-counter */
- multi->num_alive++;
-
- update_timer(multi);
- return CURLM_OK;
-}
-
-#if 0
-/* Debug-function, used like this:
- *
- * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
- *
- * Enable the hash print function first by editing hash.c
- */
-static void debug_print_sock_hash(void *p)
-{
- struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
-
- fprintf(stderr, " [easy %p/magic %x/socket %d]",
- (void *)sh->easy, sh->easy->magic, sh->socket);
-}
-#endif
-
-CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
- CURL *curl_handle)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
-
- /* First, make some basic checks that the CURLM handle is a good handle */
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- /* Verify that we got a somewhat good easy handle too */
- if(!GOOD_EASY_HANDLE(curl_handle))
- return CURLM_BAD_EASY_HANDLE;
-
- /* scan through the list and remove the 'curl_handle' */
- easy = multi->easy.next;
- while(easy) {
- if(easy->easy_handle == (struct SessionHandle *)curl_handle)
- break;
- easy=easy->next;
- }
-
- if(easy) {
- bool premature = (bool)(easy->state != CURLM_STATE_COMPLETED);
-
- /* If the 'state' is not INIT or COMPLETED, we might need to do something
- nice to put the easy_handle in a good known state when this returns. */
- if(premature)
- /* this handle is "alive" so we need to count down the total number of
- alive connections when this is removed */
- multi->num_alive--;
-
- if (easy->easy_handle->state.is_in_pipeline &&
- easy->state > CURLM_STATE_DO) {
- /* If the handle is in a pipeline and has finished sending off its
- request, we need to remember the fact that we want to remove this
- handle but do the actual removal at a later time */
- easy->easy_handle->state.cancelled = TRUE;
- return CURLM_OK;
- }
-
- /* The timer must be shut down before easy->multi is set to NULL,
- else the timenode will remain in the splay tree after
- curl_easy_cleanup is called. */
- Curl_expire(easy->easy_handle, 0);
-
- if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
- /* clear out the usage of the shared DNS cache */
- easy->easy_handle->dns.hostcache = NULL;
- easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
- }
-
- /* if we have a connection we must call Curl_done() here so that we
- don't leave a half-baked one around */
- if(easy->easy_conn) {
- /* Set up the association right */
- easy->easy_conn->data = easy->easy_handle;
-
- /* Curl_done() clears the conn->data field to lose the association
- between the easy handle and the connection */
- Curl_done(&easy->easy_conn, easy->result, premature);
-
- if(easy->easy_conn)
- /* the connection is still alive, set back the association to enable
- the check below to trigger TRUE */
- easy->easy_conn->data = easy->easy_handle;
- }
-
- /* If this easy_handle was the last one in charge for one or more
- connections a the shared connection cache, we might need to keep this
- handle around until either A) the connection is closed and killed
- properly, or B) another easy_handle uses the connection.
-
- The reason why we need to have a easy_handle associated with a live
- connection is simply that some connections will need a handle to get
- closed down properly. Currently, the only connections that need to keep
- a easy_handle handle around are using FTP(S). Such connections have
- the PROT_CLOSEACTION bit set.
-
- Thus, we need to check for all connections in the shared cache that
- points to this handle and are using PROT_CLOSEACTION. If there's any,
- we need to add this handle to the list of "easy handles kept around for
- nice connection closures".
- */
- if(multi_conn_using(multi, easy->easy_handle)) {
- /* There's at least one connection using this handle so we must keep
- this handle around. We also keep the connection cache pointer
- pointing to the shared one since that will be used on close as
- well. */
- easy->easy_handle->state.shared_conn = multi;
-
- /* this handle is still being used by a shared connection cache and
- thus we leave it around for now */
- add_closure(multi, easy->easy_handle);
- }
-
- if(easy->easy_handle->state.connc->type == CONNCACHE_MULTI) {
- /* if this was using the shared connection cache we clear the pointer
- to that since we're not part of that handle anymore */
- easy->easy_handle->state.connc = NULL;
-
- /* and modify the connectindex since this handle can't point to the
- connection cache anymore */
- if(easy->easy_conn)
- easy->easy_conn->connectindex = -1;
- }
-
- /* change state without using multistate(), only to make singlesocket() do
- what we want */
- easy->state = CURLM_STATE_COMPLETED;
- singlesocket(multi, easy); /* to let the application know what sockets
- that vanish with this handle */
-
- Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association
- to this multi handle */
-
- /* make the previous node point to our next */
- if(easy->prev)
- easy->prev->next = easy->next;
- /* make our next point to our previous node */
- if(easy->next)
- easy->next->prev = easy->prev;
-
- easy->easy_handle->set.one_easy = NULL; /* detached */
-
- /* NOTE NOTE NOTE
- We do not touch the easy handle here! */
- if (easy->msg)
- free(easy->msg);
- free(easy);
-
- multi->num_easy--; /* one less to care about now */
-
- update_timer(multi);
- return CURLM_OK;
- }
- else
- return CURLM_BAD_EASY_HANDLE; /* twasn't found */
-}
-
-bool Curl_multi_canPipeline(struct Curl_multi* multi)
-{
- return multi->pipelining_enabled;
-}
-
-static int waitconnect_getsock(struct connectdata *conn,
- curl_socket_t *sock,
- int numsocks)
-{
- if(!numsocks)
- return GETSOCK_BLANK;
-
- sock[0] = conn->sock[FIRSTSOCKET];
- return GETSOCK_WRITESOCK(0);
-}
-
-static int domore_getsock(struct connectdata *conn,
- curl_socket_t *sock,
- int numsocks)
-{
- if(!numsocks)
- return GETSOCK_BLANK;
-
- /* When in DO_MORE state, we could be either waiting for us
- to connect to a remote site, or we could wait for that site
- to connect to us. It makes a difference in the way: if we
- connect to the site we wait for the socket to become writable, if
- the site connects to us we wait for it to become readable */
- sock[0] = conn->sock[SECONDARYSOCKET];
-
- return GETSOCK_WRITESOCK(0);
-}
-
-/* returns bitmapped flags for this handle and its sockets */
-static int multi_getsock(struct Curl_one_easy *easy,
- curl_socket_t *socks, /* points to numsocks number
- of sockets */
- int numsocks)
-{
- if (easy->easy_handle->state.pipe_broke) {
- return 0;
- }
-
- if (easy->state > CURLM_STATE_CONNECT &&
- easy->state < CURLM_STATE_COMPLETED) {
- /* Set up ownership correctly */
- easy->easy_conn->data = easy->easy_handle;
- }
-
- switch(easy->state) {
- case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
- default:
- /* this will get called with CURLM_STATE_COMPLETED when a handle is
- removed */
- return 0;
-
- case CURLM_STATE_WAITRESOLVE:
- return Curl_resolv_getsock(easy->easy_conn, socks, numsocks);
-
- case CURLM_STATE_PROTOCONNECT:
- return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
-
- case CURLM_STATE_DOING:
- return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
-
- case CURLM_STATE_WAITCONNECT:
- return waitconnect_getsock(easy->easy_conn, socks, numsocks);
-
- case CURLM_STATE_DO_MORE:
- return domore_getsock(easy->easy_conn, socks, numsocks);
-
- case CURLM_STATE_PERFORM:
- case CURLM_STATE_WAITPERFORM:
- return Curl_single_getsock(easy->easy_conn, socks, numsocks);
- }
-
-}
-
-CURLMcode curl_multi_fdset(CURLM *multi_handle,
- fd_set *read_fd_set, fd_set *write_fd_set,
- fd_set *exc_fd_set, int *max_fd)
-{
- /* Scan through all the easy handles to get the file descriptors set.
- Some easy handles may not have connected to the remote host yet,
- and then we must make sure that is done. */
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
- int this_max_fd=-1;
- curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
- int bitmap;
- int i;
- (void)exc_fd_set; /* not used */
-
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- easy=multi->easy.next;
- while(easy) {
- bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
-
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
- curl_socket_t s = CURL_SOCKET_BAD;
-
- if(bitmap & GETSOCK_READSOCK(i)) {
- FD_SET(sockbunch[i], read_fd_set);
- s = sockbunch[i];
- }
- if(bitmap & GETSOCK_WRITESOCK(i)) {
- FD_SET(sockbunch[i], write_fd_set);
- s = sockbunch[i];
- }
- if(s == CURL_SOCKET_BAD)
- /* this socket is unused, break out of loop */
- break;
- else {
- if((int)s > this_max_fd)
- this_max_fd = (int)s;
- }
- }
-
- easy = easy->next; /* check next handle */
- }
-
- *max_fd = this_max_fd;
-
- return CURLM_OK;
-}
-
-static CURLMcode multi_runsingle(struct Curl_multi *multi,
- struct Curl_one_easy *easy)
-{
- struct Curl_message *msg = NULL;
- bool connected;
- bool async;
- bool protocol_connect;
- bool dophase_done;
- bool done;
- CURLMcode result = CURLM_OK;
- struct Curl_transfer_keeper *k;
-
- do {
-
- if(!GOOD_EASY_HANDLE(easy->easy_handle))
- return CURLM_BAD_EASY_HANDLE;
-
- if (easy->easy_handle->state.pipe_broke) {
- infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n",
- easy, easy->easy_handle->reqdata.path);
- if(easy->easy_handle->state.is_in_pipeline) {
- /* Head back to the CONNECT state */
- multistate(easy, CURLM_STATE_CONNECT);
- result = CURLM_CALL_MULTI_PERFORM;
- easy->result = CURLE_OK;
- } else {
- easy->result = CURLE_COULDNT_CONNECT;
- multistate(easy, CURLM_STATE_COMPLETED);
- }
-
- easy->easy_handle->state.pipe_broke = FALSE;
- easy->easy_conn = NULL;
- break;
- }
-
- if (easy->state > CURLM_STATE_CONNECT &&
- easy->state < CURLM_STATE_COMPLETED) {
- /* Make sure we set the connection's current owner */
- easy->easy_conn->data = easy->easy_handle;
- }
-
- if (CURLM_STATE_WAITCONNECT <= easy->state &&
- easy->state <= CURLM_STATE_DO &&
- easy->easy_handle->change.url_changed) {
- char *gotourl;
- Curl_posttransfer(easy->easy_handle);
-
- easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
- /* We make sure that the pipe broken flag is reset
- because in this case, it isn't an actual break */
- easy->easy_handle->state.pipe_broke = FALSE;
- if(CURLE_OK == easy->result) {
- gotourl = strdup(easy->easy_handle->change.url);
- if(gotourl) {
- easy->easy_handle->change.url_changed = FALSE;
- easy->result = Curl_follow(easy->easy_handle, gotourl, FALSE);
- if(CURLE_OK == easy->result)
- multistate(easy, CURLM_STATE_CONNECT);
- else
- free(gotourl);
- }
- else {
- easy->result = CURLE_OUT_OF_MEMORY;
- multistate(easy, CURLM_STATE_COMPLETED);
- break;
- }
- }
- }
-
- easy->easy_handle->change.url_changed = FALSE;
-
- switch(easy->state) {
- case CURLM_STATE_INIT:
- /* init this transfer. */
- easy->result=Curl_pretransfer(easy->easy_handle);
-
- if(CURLE_OK == easy->result) {
- /* after init, go CONNECT */
- multistate(easy, CURLM_STATE_CONNECT);
- result = CURLM_CALL_MULTI_PERFORM;
-
- easy->easy_handle->state.used_interface = Curl_if_multi;
- }
- break;
-
- case CURLM_STATE_CONNECT:
- /* Connect. We get a connection identifier filled in. */
- Curl_pgrsTime(easy->easy_handle, TIMER_STARTSINGLE);
- easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn,
- &async, &protocol_connect);
-
- if(CURLE_OK == easy->result) {
- /* Add this handle to the send pipeline */
- Curl_addHandleToPipeline(easy->easy_handle,
- easy->easy_conn->send_pipe);
-
- if(async)
- /* We're now waiting for an asynchronous name lookup */
- multistate(easy, CURLM_STATE_WAITRESOLVE);
- else {
- /* after the connect has been sent off, go WAITCONNECT unless the
- protocol connect is already done and we can go directly to
- WAITDO! */
- result = CURLM_CALL_MULTI_PERFORM;
-
- if(protocol_connect) {
- multistate(easy, CURLM_STATE_WAITDO);
- } else {
- multistate(easy, CURLM_STATE_WAITCONNECT);
- }
- }
- }
- break;
-
- case CURLM_STATE_WAITRESOLVE:
- /* awaiting an asynch name resolve to complete */
- {
- struct Curl_dns_entry *dns = NULL;
-
- /* check if we have the name resolved by now */
- easy->result = Curl_is_resolved(easy->easy_conn, &dns);
-
- if(dns) {
- /* Perform the next step in the connection phase, and then move on
- to the WAITCONNECT state */
- easy->result = Curl_async_resolved(easy->easy_conn,
- &protocol_connect);
-
- if(CURLE_OK != easy->result)
- /* if Curl_async_resolved() returns failure, the connection struct
- is already freed and gone */
- easy->easy_conn = NULL; /* no more connection */
- else {
- /* call again please so that we get the next socket setup */
- result = CURLM_CALL_MULTI_PERFORM;
- if(protocol_connect)
- multistate(easy, CURLM_STATE_DO);
- else
- multistate(easy, CURLM_STATE_WAITCONNECT);
- }
- }
-
- if(CURLE_OK != easy->result) {
- /* failure detected */
- Curl_disconnect(easy->easy_conn); /* disconnect properly */
- easy->easy_conn = NULL; /* no more connection */
- break;
- }
- }
- break;
-
- case CURLM_STATE_WAITCONNECT:
- /* awaiting a completion of an asynch connect */
- easy->result = Curl_is_connected(easy->easy_conn,
- FIRSTSOCKET,
- &connected);
- if(connected)
- easy->result = Curl_protocol_connect(easy->easy_conn,
- &protocol_connect);
-
- if(CURLE_OK != easy->result) {
- /* failure detected */
- Curl_disconnect(easy->easy_conn); /* close the connection */
- easy->easy_conn = NULL; /* no more connection */
- break;
- }
-
- if(connected) {
- if(!protocol_connect) {
- /* We have a TCP connection, but 'protocol_connect' may be false
- and then we continue to 'STATE_PROTOCONNECT'. If protocol
- connect is TRUE, we move on to STATE_DO. */
- multistate(easy, CURLM_STATE_PROTOCONNECT);
- }
- else {
- /* after the connect has completed, go WAITDO */
- multistate(easy, CURLM_STATE_WAITDO);
-
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- break;
-
- case CURLM_STATE_PROTOCONNECT:
- /* protocol-specific connect phase */
- easy->result = Curl_protocol_connecting(easy->easy_conn,
- &protocol_connect);
- if(protocol_connect) {
- /* after the connect has completed, go WAITDO */
- multistate(easy, CURLM_STATE_WAITDO);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- else if(easy->result) {
- /* failure detected */
- Curl_posttransfer(easy->easy_handle);
- Curl_done(&easy->easy_conn, easy->result, FALSE);
- Curl_disconnect(easy->easy_conn); /* close the connection */
- easy->easy_conn = NULL; /* no more connection */
- }
- break;
-
- case CURLM_STATE_WAITDO:
- /* Wait for our turn to DO when we're pipelining requests */
-#ifdef CURLDEBUG
- infof(easy->easy_handle, "Conn %d send pipe %d inuse %d athead %d\n",
- easy->easy_conn->connectindex,
- easy->easy_conn->send_pipe->size,
- easy->easy_conn->writechannel_inuse,
- Curl_isHandleAtHead(easy->easy_handle,
- easy->easy_conn->send_pipe));
-#endif
- if (!easy->easy_conn->writechannel_inuse &&
- Curl_isHandleAtHead(easy->easy_handle,
- easy->easy_conn->send_pipe)) {
- /* Grab the channel */
- easy->easy_conn->writechannel_inuse = TRUE;
- multistate(easy, CURLM_STATE_DO);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- break;
-
- case CURLM_STATE_DO:
- if(easy->easy_handle->set.connect_only) {
- /* keep connection open for application to use the socket */
- easy->easy_conn->bits.close = FALSE;
- multistate(easy, CURLM_STATE_DONE);
- easy->result = CURLE_OK;
- result = CURLM_OK;
- }
- else {
- /* Perform the protocol's DO action */
- easy->result = Curl_do(&easy->easy_conn,
- &dophase_done);
-
- if(CURLE_OK == easy->result) {
-
- if(!dophase_done) {
- /* DO was not completed in one function call, we must continue
- DOING... */
- multistate(easy, CURLM_STATE_DOING);
- result = CURLM_OK;
- }
-
- /* after DO, go DO_DONE... or DO_MORE */
- else if(easy->easy_conn->bits.do_more) {
- /* we're supposed to do more, but we need to sit down, relax
- and wait a little while first */
- multistate(easy, CURLM_STATE_DO_MORE);
- result = CURLM_OK;
- }
- else {
- /* we're done with the DO, now DO_DONE */
- easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- multistate(easy, CURLM_STATE_DO_DONE);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- }
- else {
- /* failure detected */
- Curl_posttransfer(easy->easy_handle);
- Curl_done(&easy->easy_conn, easy->result, FALSE);
- Curl_disconnect(easy->easy_conn); /* close the connection */
- easy->easy_conn = NULL; /* no more connection */
- }
- }
- break;
-
- case CURLM_STATE_DOING:
- /* we continue DOING until the DO phase is complete */
- easy->result = Curl_protocol_doing(easy->easy_conn,
- &dophase_done);
- if(CURLE_OK == easy->result) {
- if(dophase_done) {
- /* after DO, go PERFORM... or DO_MORE */
- if(easy->easy_conn->bits.do_more) {
- /* we're supposed to do more, but we need to sit down, relax
- and wait a little while first */
- multistate(easy, CURLM_STATE_DO_MORE);
- result = CURLM_OK;
- }
- else {
- /* we're done with the DO, now DO_DONE */
- easy->result = Curl_readwrite_init(easy->easy_conn);
- if(CURLE_OK == easy->result) {
- multistate(easy, CURLM_STATE_DO_DONE);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- } /* dophase_done */
- }
- else {
- /* failure detected */
- Curl_posttransfer(easy->easy_handle);
- Curl_done(&easy->easy_conn, easy->result, FALSE);
- Curl_disconnect(easy->easy_conn); /* close the connection */
- easy->easy_conn = NULL; /* no more connection */
- }
- break;
-
- case CURLM_STATE_DO_MORE:
- /* Ready to do more? */
- easy->result = Curl_is_connected(easy->easy_conn,
- SECONDARYSOCKET,
- &connected);
- if(connected) {
- /*
- * When we are connected, DO MORE and then go DO_DONE
- */
- easy->result = Curl_do_more(easy->easy_conn);
-
- if(CURLE_OK == easy->result)
- easy->result = Curl_readwrite_init(easy->easy_conn);
- else
- /* Remove ourselves from the send pipeline */
- Curl_removeHandleFromPipeline(easy->easy_handle,
- easy->easy_conn->send_pipe);
-
- if(CURLE_OK == easy->result) {
- multistate(easy, CURLM_STATE_DO_DONE);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
- break;
-
- case CURLM_STATE_DO_DONE:
- /* Remove ourselves from the send pipeline */
- Curl_removeHandleFromPipeline(easy->easy_handle,
- easy->easy_conn->send_pipe);
- /* Add ourselves to the recv pipeline */
- Curl_addHandleToPipeline(easy->easy_handle,
- easy->easy_conn->recv_pipe);
- multistate(easy, CURLM_STATE_WAITPERFORM);
- result = CURLM_CALL_MULTI_PERFORM;
- break;
-
- case CURLM_STATE_WAITPERFORM:
-#ifdef CURLDEBUG
- infof(easy->easy_handle, "Conn %d recv pipe %d inuse %d athead %d\n",
- easy->easy_conn->connectindex,
- easy->easy_conn->recv_pipe->size,
- easy->easy_conn->readchannel_inuse,
- Curl_isHandleAtHead(easy->easy_handle,
- easy->easy_conn->recv_pipe));
-#endif
- /* Wait for our turn to PERFORM */
- if (!easy->easy_conn->readchannel_inuse &&
- Curl_isHandleAtHead(easy->easy_handle,
- easy->easy_conn->recv_pipe)) {
- /* Grab the channel */
- easy->easy_conn->readchannel_inuse = TRUE;
- multistate(easy, CURLM_STATE_PERFORM);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- break;
-
- case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
- /* if both rates are within spec, resume transfer */
- Curl_pgrsUpdate(easy->easy_conn);
- if ( ( ( easy->easy_handle->set.max_send_speed == 0 ) ||
- ( easy->easy_handle->progress.ulspeed <
- easy->easy_handle->set.max_send_speed ) ) &&
- ( ( easy->easy_handle->set.max_recv_speed == 0 ) ||
- ( easy->easy_handle->progress.dlspeed <
- easy->easy_handle->set.max_recv_speed ) )
- )
- multistate(easy, CURLM_STATE_PERFORM);
- break;
-
- case CURLM_STATE_PERFORM:
- /* check if over speed */
- if ( ( ( easy->easy_handle->set.max_send_speed > 0 ) &&
- ( easy->easy_handle->progress.ulspeed >
- easy->easy_handle->set.max_send_speed ) ) ||
- ( ( easy->easy_handle->set.max_recv_speed > 0 ) &&
- ( easy->easy_handle->progress.dlspeed >
- easy->easy_handle->set.max_recv_speed ) )
- ) {
- /* Transfer is over the speed limit. Change state. TODO: Call
- * Curl_expire() with the time left until we're targeted to be below
- * the speed limit again. */
- multistate(easy, CURLM_STATE_TOOFAST );
- break;
- }
-
- /* read/write data if it is ready to do so */
- easy->result = Curl_readwrite(easy->easy_conn, &done);
-
- k = &easy->easy_handle->reqdata.keep;
-
- if (!(k->keepon & KEEP_READ)) {
- /* We're done reading */
- easy->easy_conn->readchannel_inuse = FALSE;
- }
-
- if (!(k->keepon & KEEP_WRITE)) {
- /* We're done writing */
- easy->easy_conn->writechannel_inuse = FALSE;
- }
-
- if(easy->result) {
- /* The transfer phase returned error, we mark the connection to get
- * closed to prevent being re-used. This is becasue we can't
- * possibly know if the connection is in a good shape or not now. */
- easy->easy_conn->bits.close = TRUE;
-
- if(CURL_SOCKET_BAD != easy->easy_conn->sock[SECONDARYSOCKET]) {
- /* if we failed anywhere, we must clean up the secondary socket if
- it was used */
- sclose(easy->easy_conn->sock[SECONDARYSOCKET]);
- easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- }
- Curl_posttransfer(easy->easy_handle);
- Curl_done(&easy->easy_conn, easy->result, FALSE);
- }
- else if(TRUE == done) {
- char *newurl;
- bool retry = Curl_retry_request(easy->easy_conn, &newurl);
-
- /* call this even if the readwrite function returned error */
- Curl_posttransfer(easy->easy_handle);
-
- /* When we follow redirects, must to go back to the CONNECT state */
- if(easy->easy_handle->reqdata.newurl || retry) {
- Curl_removeHandleFromPipeline(easy->easy_handle,
- easy->easy_conn->recv_pipe);
- if(!retry) {
- /* if the URL is a follow-location and not just a retried request
- then figure out the URL here */
- newurl = easy->easy_handle->reqdata.newurl;
- easy->easy_handle->reqdata.newurl = NULL;
- }
- easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
- if(easy->result == CURLE_OK)
- easy->result = Curl_follow(easy->easy_handle, newurl, retry);
- if(CURLE_OK == easy->result) {
- multistate(easy, CURLM_STATE_CONNECT);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- else
- /* Since we "took it", we are in charge of freeing this on
- failure */
- free(newurl);
- }
- else {
- /* after the transfer is done, go DONE */
- multistate(easy, CURLM_STATE_DONE);
- result = CURLM_CALL_MULTI_PERFORM;
- }
- }
-
- break;
-
- case CURLM_STATE_DONE:
- /* Remove ourselves from the receive pipeline */
- Curl_removeHandleFromPipeline(easy->easy_handle,
- easy->easy_conn->recv_pipe);
- easy->easy_handle->state.is_in_pipeline = FALSE;
-
- if (easy->easy_conn->bits.stream_was_rewound) {
- /* This request read past its response boundary so we quickly
- let the other requests consume those bytes since there is no
- guarantee that the socket will become active again */
- result = CURLM_CALL_MULTI_PERFORM;
- }
-
- if (!easy->easy_handle->state.cancelled) {
- /* post-transfer command */
- easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
-
- /* after we have DONE what we're supposed to do, go COMPLETED, and
- it doesn't matter what the Curl_done() returned! */
- multistate(easy, CURLM_STATE_COMPLETED);
- }
-
- break;
-
- case CURLM_STATE_COMPLETED:
- if (easy->easy_handle->state.cancelled)
- /* Go into the CANCELLED state if we were cancelled */
- multistate(easy, CURLM_STATE_CANCELLED);
-
- /* this is a completed transfer, it is likely to still be connected */
-
- /* This node should be delinked from the list now and we should post
- an information message that we are complete. */
- break;
-
- case CURLM_STATE_CANCELLED:
- /* Cancelled transfer, wait to be cleaned up */
- break;
-
- default:
- return CURLM_INTERNAL_ERROR;
- }
-
- if(CURLM_STATE_COMPLETED != easy->state) {
- if(CURLE_OK != easy->result) {
- /*
- * If an error was returned, and we aren't in completed state now,
- * then we go to completed and consider this transfer aborted.
- */
- easy->easy_handle->state.is_in_pipeline = FALSE;
- easy->easy_handle->state.pipe_broke = FALSE;
-
- if(easy->easy_conn) {
- /* if this has a connection, unsubscribe from the pipelines */
- easy->easy_conn->writechannel_inuse = FALSE;
- easy->easy_conn->readchannel_inuse = FALSE;
- }
- multistate(easy, CURLM_STATE_COMPLETED);
- }
- }
-
- } while (easy->easy_handle->change.url_changed);
-
- if ((CURLM_STATE_COMPLETED == easy->state) && !easy->msg) {
- if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
- /* clear out the usage of the shared DNS cache */
- easy->easy_handle->dns.hostcache = NULL;
- easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
- }
-
- /* now add a node to the Curl_message linked list with this info */
- msg = (struct Curl_message *)malloc(sizeof(struct Curl_message));
-
- if(!msg)
- return CURLM_OUT_OF_MEMORY;
-
- msg->extmsg.msg = CURLMSG_DONE;
- msg->extmsg.easy_handle = easy->easy_handle;
- msg->extmsg.data.result = easy->result;
- msg->next = NULL;
-
- easy->msg = msg;
- easy->msg_num = 1; /* there is one unread message here */
-
- multi->num_msgs++; /* increase message counter */
- }
-
- return result;
-}
-
-
-CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
- CURLMcode returncode=CURLM_OK;
- struct Curl_tree *t;
-
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- easy=multi->easy.next;
- while(easy) {
- CURLMcode result;
-
- if (easy->easy_handle->state.cancelled &&
- easy->state == CURLM_STATE_CANCELLED) {
- /* Remove cancelled handles once it's safe to do so */
- Curl_multi_rmeasy(multi_handle, easy->easy_handle);
- easy->easy_handle = NULL;
- easy = easy->next;
- continue;
- }
-
- result = multi_runsingle(multi, easy);
- if(result)
- returncode = result;
-
- easy = easy->next; /* operate on next handle */
- }
-
- /*
- * Simply remove all expired timers from the splay since handles are dealt
- * with unconditionally by this function and curl_multi_timeout() requires
- * that already passed/handled expire times are removed from the splay.
- */
- do {
- struct timeval now = Curl_tvnow();
- int key = now.tv_sec; /* drop the usec part */
-
- multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
- if (t) {
- struct SessionHandle *d = t->payload;
- struct timeval* tv = &d->state.expiretime;
-
- /* clear the expire times within the handles that we remove from the
- splay tree */
- tv->tv_sec = 0;
- tv->tv_usec = 0;
- }
-
- } while(t);
-
- *running_handles = multi->num_alive;
-
- if ( CURLM_OK == returncode )
- update_timer(multi);
- return returncode;
-}
-
-/* This is called when an easy handle is cleanup'ed that is part of a multi
- handle */
-void Curl_multi_rmeasy(void *multi_handle, CURL *easy_handle)
-{
- curl_multi_remove_handle(multi_handle, easy_handle);
-}
-
-
-CURLMcode curl_multi_cleanup(CURLM *multi_handle)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
- struct Curl_one_easy *nexteasy;
- int i;
- struct closure *cl;
- struct closure *n;
-
- if(GOOD_MULTI_HANDLE(multi)) {
- multi->type = 0; /* not good anymore */
- Curl_hash_destroy(multi->hostcache);
- Curl_hash_destroy(multi->sockhash);
-
- /* go over all connections that have close actions */
- for(i=0; i< multi->connc->num; i++) {
- if(multi->connc->connects[i] &&
- multi->connc->connects[i]->protocol & PROT_CLOSEACTION) {
- Curl_disconnect(multi->connc->connects[i]);
- multi->connc->connects[i] = NULL;
- }
- }
- /* now walk through the list of handles we kept around only to be
- able to close connections "properly" */
- cl = multi->closure;
- while(cl) {
- cl->easy_handle->state.shared_conn = NULL; /* no more shared */
- if(cl->easy_handle->state.closed)
- /* close handle only if curl_easy_cleanup() already has been called
- for this easy handle */
- Curl_close(cl->easy_handle);
- n = cl->next;
- free(cl);
- cl= n;
- }
-
- Curl_rm_connc(multi->connc);
-
- /* remove all easy handles */
- easy = multi->easy.next;
- while(easy) {
- nexteasy=easy->next;
- if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
- /* clear out the usage of the shared DNS cache */
- easy->easy_handle->dns.hostcache = NULL;
- easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
- }
-
- /* Clear the pointer to the connection cache */
- easy->easy_handle->state.connc = NULL;
-
- Curl_easy_addmulti(easy->easy_handle, NULL); /* clear the association */
-
- if (easy->msg)
- free(easy->msg);
- free(easy);
- easy = nexteasy;
- }
-
- free(multi);
-
- return CURLM_OK;
- }
- else
- return CURLM_BAD_HANDLE;
-}
-
-CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-
- *msgs_in_queue = 0; /* default to none */
-
- if(GOOD_MULTI_HANDLE(multi)) {
- struct Curl_one_easy *easy;
-
- if(!multi->num_msgs)
- return NULL; /* no messages left to return */
-
- easy=multi->easy.next;
- while(easy) {
- if(easy->msg_num) {
- easy->msg_num--;
- break;
- }
- easy = easy->next;
- }
- if(!easy)
- return NULL; /* this means internal count confusion really */
-
- multi->num_msgs--;
- *msgs_in_queue = multi->num_msgs;
-
- return &easy->msg->extmsg;
- }
- else
- return NULL;
-}
-
-/*
- * singlesocket() checks what sockets we deal with and their "action state"
- * and if we have a different state in any of those sockets from last time we
- * call the callback accordingly.
- */
-static void singlesocket(struct Curl_multi *multi,
- struct Curl_one_easy *easy)
-{
- curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
- int i;
- struct Curl_sh_entry *entry;
- curl_socket_t s;
- int num;
- unsigned int curraction;
-
- memset(&socks, 0, sizeof(socks));
- for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
- socks[i] = CURL_SOCKET_BAD;
-
- /* Fill in the 'current' struct with the state as it is now: what sockets to
- supervise and for what actions */
- curraction = multi_getsock(easy, socks, MAX_SOCKSPEREASYHANDLE);
-
- /* We have 0 .. N sockets already and we get to know about the 0 .. M
- sockets we should have from now on. Detect the differences, remove no
- longer supervised ones and add new ones */
-
- /* walk over the sockets we got right now */
- for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
- (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
- i++) {
- int action = CURL_POLL_NONE;
-
- s = socks[i];
-
- /* get it from the hash */
- entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
-
- if(curraction & GETSOCK_READSOCK(i))
- action |= CURL_POLL_IN;
- if(curraction & GETSOCK_WRITESOCK(i))
- action |= CURL_POLL_OUT;
-
- if(entry) {
- /* yeps, already present so check if it has the same action set */
- if(entry->action == action)
- /* same, continue */
- continue;
- }
- else {
- /* this is a socket we didn't have before, add it! */
- entry = sh_addentry(multi->sockhash, s, easy->easy_handle);
- if(!entry)
- /* fatal */
- return;
- }
-
- multi->socket_cb(easy->easy_handle,
- s,
- action,
- multi->socket_userp,
- entry ? entry->socketp : NULL);
-
- entry->action = action; /* store the current action state */
- }
-
- num = i; /* number of sockets */
-
- /* when we've walked over all the sockets we should have right now, we must
- make sure to detect sockets that are removed */
- for(i=0; i< easy->numsocks; i++) {
- int j;
- s = easy->sockets[i];
- for(j=0; j<num; j++) {
- if(s == socks[j]) {
- /* this is still supervised */
- s = CURL_SOCKET_BAD;
- break;
- }
- }
- if(s != CURL_SOCKET_BAD) {
- /* this socket has been removed. Remove it */
-
- entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
- if(entry) {
- /* just a precaution, this socket really SHOULD be in the hash already
- but in case it isn't, we don't have to tell the app to remove it
- either since it never got to know about it */
- multi->socket_cb(easy->easy_handle,
- s,
- CURL_POLL_REMOVE,
- multi->socket_userp,
- entry ? entry->socketp : NULL);
-
- sh_delentry(multi->sockhash, s);
- }
- }
- }
-
- memcpy(easy->sockets, socks, num*sizeof(curl_socket_t));
- easy->numsocks = num;
-}
-
-static CURLMcode multi_socket(struct Curl_multi *multi,
- bool checkall,
- curl_socket_t s,
- int *running_handles)
-{
- CURLMcode result = CURLM_OK;
- struct SessionHandle *data = NULL;
- struct Curl_tree *t;
-
- if(checkall) {
- struct Curl_one_easy *easyp;
- /* *perform() deals with running_handles on its own */
- result = curl_multi_perform(multi, running_handles);
-
- /* walk through each easy handle and do the socket state change magic
- and callbacks */
- easyp=multi->easy.next;
- while(easyp) {
- singlesocket(multi, easyp);
- easyp = easyp->next;
- }
-
- /* or should we fall-through and do the timer-based stuff? */
- return result;
- }
- else if (s != CURL_SOCKET_TIMEOUT) {
-
- struct Curl_sh_entry *entry =
- Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
-
- if(!entry)
- /* unmatched socket, major problemo! */
- return CURLM_BAD_SOCKET; /* better return code? */
-
- data = entry->easy;
-
- if(data->magic != CURLEASY_MAGIC_NUMBER)
- /* bad bad bad bad bad bad bad */
- return CURLM_INTERNAL_ERROR;
-
- result = multi_runsingle(multi, data->set.one_easy);
-
- if(result == CURLM_OK)
- /* get the socket(s) and check if the state has been changed since
- last */
- singlesocket(multi, data->set.one_easy);
-
- /* Now we fall-through and do the timer-based stuff, since we don't want
- to force the user to have to deal with timeouts as long as at least one
- connection in fact has traffic. */
-
- data = NULL; /* set data to NULL again to avoid calling multi_runsingle()
- in case there's no need to */
- }
-
- /*
- * The loop following here will go on as long as there are expire-times left
- * to process in the splay and 'data' will be re-assigned for every expired
- * handle we deal with.
- */
- do {
- int key;
- struct timeval now;
-
- /* the first loop lap 'data' can be NULL */
- if(data) {
- result = multi_runsingle(multi, data->set.one_easy);
-
- if(result == CURLM_OK)
- /* get the socket(s) and check if the state has been changed since
- last */
- singlesocket(multi, data->set.one_easy);
- }
-
- /* Check if there's one (more) expired timer to deal with! This function
- extracts a matching node if there is one */
-
- now = Curl_tvnow();
- key = now.tv_sec; /* drop the usec part */
-
- multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
- if(t) {
- /* assign 'data' to be the easy handle we just removed from the splay
- tree */
- data = t->payload;
- /* clear the expire time within the handle we removed from the
- splay tree */
- data->state.expiretime.tv_sec = 0;
- data->state.expiretime.tv_usec = 0;
- }
-
- } while(t);
-
- *running_handles = multi->num_alive;
- return result;
-}
-
-CURLMcode curl_multi_setopt(CURLM *multi_handle,
- CURLMoption option, ...)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- CURLMcode res = CURLM_OK;
- va_list param;
-
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- va_start(param, option);
-
- switch(option) {
- case CURLMOPT_SOCKETFUNCTION:
- multi->socket_cb = va_arg(param, curl_socket_callback);
- break;
- case CURLMOPT_SOCKETDATA:
- multi->socket_userp = va_arg(param, void *);
- break;
- case CURLMOPT_PIPELINING:
- multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
- break;
- case CURLMOPT_TIMERFUNCTION:
- multi->timer_cb = va_arg(param, curl_multi_timer_callback);
- break;
- case CURLMOPT_TIMERDATA:
- multi->timer_userp = va_arg(param, void *);
- break;
- default:
- res = CURLM_UNKNOWN_OPTION;
- break;
- }
- va_end(param);
- return res;
-}
-
-
-CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
- int *running_handles)
-{
- CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
- running_handles);
- if (CURLM_OK == result)
- update_timer((struct Curl_multi *)multi_handle);
- return result;
-}
-
-CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
-
-{
- CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
- TRUE, CURL_SOCKET_BAD, running_handles);
- if (CURLM_OK == result)
- update_timer((struct Curl_multi *)multi_handle);
- return result;
-}
-
-static CURLMcode multi_timeout(struct Curl_multi *multi,
- long *timeout_ms)
-{
- if(multi->timetree) {
- /* we have a tree of expire times */
- struct timeval now = Curl_tvnow();
-
- /* splay the lowest to the bottom */
- multi->timetree = Curl_splay(0, multi->timetree);
-
- /* At least currently, the splay key is a time_t for the expire time */
- *timeout_ms = (multi->timetree->key - now.tv_sec) * 1000 -
- now.tv_usec/1000;
- if(*timeout_ms < 0)
- /* 0 means immediately */
- *timeout_ms = 0;
- }
- else
- *timeout_ms = -1;
-
- return CURLM_OK;
-}
-
-CURLMcode curl_multi_timeout(CURLM *multi_handle,
- long *timeout_ms)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
-
- /* First, make some basic checks that the CURLM handle is a good handle */
- if(!GOOD_MULTI_HANDLE(multi))
- return CURLM_BAD_HANDLE;
-
- return multi_timeout(multi, timeout_ms);
-}
-
-/*
- * Tell the application it should update its timers, if it subscribes to the
- * update timer callback.
- */
-static int update_timer(struct Curl_multi *multi)
-{
- long timeout_ms;
- if (!multi->timer_cb)
- return 0;
- if ( multi_timeout(multi, &timeout_ms) != CURLM_OK )
- return -1;
- if ( timeout_ms < 0 )
- return 0;
-
- /* When multi_timeout() is done, multi->timetree points to the node with the
- * timeout we got the (relative) time-out time for. We can thus easily check
- * if this is the same (fixed) time as we got in a previous call and then
- * avoid calling the callback again. */
- if(multi->timetree->key == multi->timer_lastcall)
- return 0;
-
- multi->timer_lastcall = multi->timetree->key;
-
- return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
-}
-
-/* given a number of milliseconds from now to use to set the 'act before
- this'-time for the transfer, to be extracted by curl_multi_timeout() */
-void Curl_expire(struct SessionHandle *data, long milli)
-{
- struct Curl_multi *multi = data->multi;
- struct timeval *nowp = &data->state.expiretime;
- int rc;
-
- /* this is only interesting for multi-interface using libcurl, and only
- while there is still a multi interface struct remaining! */
- if(!multi)
- return;
-
- if(!milli) {
- /* No timeout, clear the time data. */
- if(nowp->tv_sec) {
- /* Since this is an cleared time, we must remove the previous entry from
- the splay tree */
- rc = Curl_splayremovebyaddr(multi->timetree,
- &data->state.timenode,
- &multi->timetree);
- if(rc)
- infof(data, "Internal error clearing splay node = %d\n", rc);
- infof(data, "Expire cleared\n");
- nowp->tv_sec = 0;
- nowp->tv_usec = 0;
- }
- }
- else {
- struct timeval set;
- int rest;
-
- set = Curl_tvnow();
- set.tv_sec += milli/1000;
- set.tv_usec += (milli%1000)*1000;
-
- rest = (int)(set.tv_usec - 1000000);
- if(rest > 0) {
- /* bigger than a full microsec */
- set.tv_sec++;
- set.tv_usec -= 1000000;
- }
-
- if(nowp->tv_sec) {
- /* This means that the struct is added as a node in the splay tree.
- Compare if the new time is earlier, and only remove-old/add-new if it
- is. */
- long diff = curlx_tvdiff(set, *nowp);
- if(diff > 0)
- /* the new expire time was later so we don't change this */
- return;
-
- /* Since this is an updated time, we must remove the previous entry from
- the splay tree first and then re-add the new value */
- rc = Curl_splayremovebyaddr(multi->timetree,
- &data->state.timenode,
- &multi->timetree);
- if(rc)
- infof(data, "Internal error removing splay node = %d\n", rc);
- }
-
- *nowp = set;
-#if 0
- infof(data, "Expire at %ld / %ld (%ldms)\n",
- (long)nowp->tv_sec, (long)nowp->tv_usec, milli);
-#endif
- data->state.timenode.payload = data;
- multi->timetree = Curl_splayinsert((int)nowp->tv_sec,
- multi->timetree,
- &data->state.timenode);
- }
-#if 0
- Curl_splayprint(multi->timetree, 0, TRUE);
-#endif
-}
-
-CURLMcode curl_multi_assign(CURLM *multi_handle,
- curl_socket_t s, void *hashp)
-{
- struct Curl_sh_entry *there = NULL;
- struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
-
- if(s != CURL_SOCKET_BAD)
- there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
-
- if(!there)
- return CURLM_BAD_SOCKET;
-
- there->socketp = hashp;
-
- return CURLM_OK;
-}
-
-static bool multi_conn_using(struct Curl_multi *multi,
- struct SessionHandle *data)
-{
- /* any live CLOSEACTION-connections pointing to the give 'data' ? */
- int i;
-
- for(i=0; i< multi->connc->num; i++) {
- if(multi->connc->connects[i] &&
- (multi->connc->connects[i]->data == data) &&
- multi->connc->connects[i]->protocol & PROT_CLOSEACTION)
- return TRUE;
- }
-
- return FALSE;
-}
-
-/* Add the given data pointer to the list of 'closure handles' that are kept
- around only to be able to close some connections nicely - just make sure
- that this handle isn't already added, like for the cases when an easy
- handle is removed, added and removed again... */
-static void add_closure(struct Curl_multi *multi,
- struct SessionHandle *data)
-{
- int i;
- struct closure *cl = (struct closure *)calloc(sizeof(struct closure), 1);
- struct closure *p=NULL;
- struct closure *n;
- if(cl) {
- cl->easy_handle = data;
- cl->next = multi->closure;
- multi->closure = cl;
- }
-
- p = multi->closure;
- cl = p->next; /* start immediately on the second since the first is the one
- we just added and it is _very_ likely to actually exist
- used in the cache since that's the whole purpose of adding
- it to this list! */
-
- /* When adding, scan through all the other currently kept handles and see if
- there are any connections still referring to them and kill them if not. */
- while(cl) {
- bool inuse = FALSE;
- for(i=0; i< multi->connc->num; i++) {
- if(multi->connc->connects[i] &&
- (multi->connc->connects[i]->data == cl->easy_handle)) {
- inuse = TRUE;
- break;
- }
- }
-
- n = cl->next;
-
- if(!inuse) {
- /* cl->easy_handle is now killable */
- infof(data, "Delayed kill of easy handle %p\n", cl->easy_handle);
- /* unmark it as not having a connection around that uses it anymore */
- cl->easy_handle->state.shared_conn= NULL;
- Curl_close(cl->easy_handle);
- if(p)
- p->next = n;
- else
- multi->closure = n;
- free(cl);
- }
- else
- p = cl;
-
- cl = n;
- }
-
-}
-
-#ifdef CURLDEBUG
-void curl_multi_dump(CURLM *multi_handle)
-{
- struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
- struct Curl_one_easy *easy;
- int i;
- fprintf(stderr, "* Multi status: %d handles, %d alive\n",
- multi->num_easy, multi->num_alive);
- for(easy=multi->easy.next; easy; easy = easy->next) {
- if(easy->state != CURLM_STATE_COMPLETED) {
- /* only display handles that are not completed */
- fprintf(stderr, "handle %p, state %s, %d sockets\n",
- (void *)easy->easy_handle,
- statename[easy->state], easy->numsocks);
- for(i=0; i < easy->numsocks; i++) {
- curl_socket_t s = easy->sockets[i];
- struct Curl_sh_entry *entry =
- Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
-
- fprintf(stderr, "%d ", (int)s);
- if(!entry) {
- fprintf(stderr, "INTERNAL CONFUSION\n");
- continue;
- }
- fprintf(stderr, "[%s %s] ",
- entry->action&CURL_POLL_IN?"RECVING":"",
- entry->action&CURL_POLL_OUT?"SENDING":"");
- }
- if(easy->numsocks)
- fprintf(stderr, "\n");
- }
- }
-}
-#endif
diff --git a/Utilities/cmcurl/multiif.h b/Utilities/cmcurl/multiif.h
deleted file mode 100644
index 800aa0f5d..000000000
--- a/Utilities/cmcurl/multiif.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __MULTIIF_H
-#define __MULTIIF_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * Prototypes for library-wide functions provided by multi.c
- */
-void Curl_expire(struct SessionHandle *data, long milli);
-
-void Curl_multi_rmeasy(void *multi, CURL *data);
-
-bool Curl_multi_canPipeline(struct Curl_multi* multi);
-
-/* the write bits start at bit 16 for the *getsock() bitmap */
-#define GETSOCK_WRITEBITSTART 16
-
-#define GETSOCK_BLANK 0 /* no bits set */
-
-/* set the bit for the given sock number to make the bitmap for writable */
-#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
-
-/* set the bit for the given sock number to make the bitmap for readable */
-#define GETSOCK_READSOCK(x) (1 << (x))
-
-#endif /* __MULTIIF_H */
diff --git a/Utilities/cmcurl/netrc.c b/Utilities/cmcurl/netrc.c
deleted file mode 100644
index 54d175989..000000000
--- a/Utilities/cmcurl/netrc.c
+++ /dev/null
@@ -1,247 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#ifdef HAVE_PWD_H
-#include <pwd.h>
-#endif
-#ifdef VMS
-#include <unixlib.h>
-#endif
-
-#include <curl/curl.h>
-#include "netrc.h"
-
-#include "strequal.h"
-#include "strtok.h"
-#include "memory.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* Debug this single source file with:
- 'make netrc' then run './netrc'!
-
- Oh, make sure you have a .netrc file too ;-)
- */
-
-/* Get user and password from .netrc when given a machine name */
-
-enum {
- NOTHING,
- HOSTFOUND, /* the 'machine' keyword was found */
- HOSTCOMPLETE, /* the machine name following the keyword was found too */
- HOSTVALID, /* this is "our" machine! */
-
- HOSTEND /* LAST enum */
-};
-
-/* make sure we have room for at least this size: */
-#define LOGINSIZE 64
-#define PASSWORDSIZE 64
-
-/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
-int Curl_parsenetrc(char *host,
- char *login,
- char *password,
- char *netrcfile)
-{
- FILE *file;
- int retcode=1;
- int specific_login = (login[0] != 0);
- char *home = NULL;
- bool home_alloc = FALSE;
- bool netrc_alloc = FALSE;
- int state=NOTHING;
-
- char state_login=0; /* Found a login keyword */
- char state_password=0; /* Found a password keyword */
- int state_our_login=FALSE; /* With specific_login, found *our* login name */
-
-#define NETRC DOT_CHAR "netrc"
-
-#ifdef CURLDEBUG
- {
- /* This is a hack to allow testing.
- * If compiled with --enable-debug and CURL_DEBUG_NETRC is defined,
- * then it's the path to a substitute .netrc for testing purposes *only* */
-
- char *override = curl_getenv("CURL_DEBUG_NETRC");
-
- if (override) {
- fprintf(stderr, "NETRC: overridden " NETRC " file: %s\n", override);
- netrcfile = override;
- netrc_alloc = TRUE;
- }
- }
-#endif /* CURLDEBUG */
- if(!netrcfile) {
- home = curl_getenv("HOME"); /* portable environment reader */
- if(home) {
- home_alloc = TRUE;
-#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
- }
- else {
- struct passwd *pw;
- pw= getpwuid(geteuid());
- if (pw) {
-#ifdef VMS
- home = decc$translate_vms(pw->pw_dir);
-#else
- home = pw->pw_dir;
-#endif
- }
-#endif
- }
-
- if(!home)
- return -1;
-
- netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
- if(!netrcfile) {
- if(home_alloc)
- free(home);
- return -1;
- }
- netrc_alloc = TRUE;
- }
-
- file = fopen(netrcfile, "r");
- if(file) {
- char *tok;
- char *tok_buf;
- bool done=FALSE;
- char netrcbuffer[256];
-
- while(!done && fgets(netrcbuffer, sizeof(netrcbuffer), file)) {
- tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
- while(!done && tok) {
-
- if (login[0] && password[0]) {
- done=TRUE;
- break;
- }
-
- switch(state) {
- case NOTHING:
- if(strequal("machine", tok)) {
- /* the next tok is the machine name, this is in itself the
- delimiter that starts the stuff entered for this machine,
- after this we need to search for 'login' and
- 'password'. */
- state=HOSTFOUND;
- }
- break;
- case HOSTFOUND:
- if(strequal(host, tok)) {
- /* and yes, this is our host! */
- state=HOSTVALID;
-#ifdef _NETRC_DEBUG
- fprintf(stderr, "HOST: %s\n", tok);
-#endif
- retcode=0; /* we did find our host */
- }
- else
- /* not our host */
- state=NOTHING;
- break;
- case HOSTVALID:
- /* we are now parsing sub-keywords concerning "our" host */
- if(state_login) {
- if (specific_login) {
- state_our_login = strequal(login, tok);
- }
- else {
- strncpy(login, tok, LOGINSIZE-1);
-#ifdef _NETRC_DEBUG
- fprintf(stderr, "LOGIN: %s\n", login);
-#endif
- }
- state_login=0;
- }
- else if(state_password) {
- if (state_our_login || !specific_login) {
- strncpy(password, tok, PASSWORDSIZE-1);
-#ifdef _NETRC_DEBUG
- fprintf(stderr, "PASSWORD: %s\n", password);
-#endif
- }
- state_password=0;
- }
- else if(strequal("login", tok))
- state_login=1;
- else if(strequal("password", tok))
- state_password=1;
- else if(strequal("machine", tok)) {
- /* ok, there's machine here go => */
- state = HOSTFOUND;
- state_our_login = FALSE;
- }
- break;
- } /* switch (state) */
-
- tok = strtok_r(NULL, " \t\n", &tok_buf);
- } /* while (tok) */
- } /* while fgets() */
-
- fclose(file);
- }
-
- if(home_alloc)
- free(home);
- if(netrc_alloc)
- free(netrcfile);
-
- return retcode;
-}
-
-#ifdef _NETRC_DEBUG
-int main(int argc, char **argv)
-{
- char login[64]="";
- char password[64]="";
-
- if(argc<2)
- return -1;
-
- if(0 == ParseNetrc(argv[1], login, password)) {
- printf("HOST: %s LOGIN: %s PASSWORD: %s\n",
- argv[1], login, password);
- }
-}
-
-#endif
diff --git a/Utilities/cmcurl/netrc.h b/Utilities/cmcurl/netrc.h
deleted file mode 100644
index 939c552df..000000000
--- a/Utilities/cmcurl/netrc.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __NETRC_H
-#define __NETRC_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-int Curl_parsenetrc(char *host,
- char *login,
- char *password,
- char *filename);
- /* Assume: password[0]=0, host[0] != 0.
- * If login[0] = 0, search for login and password within a machine section
- * in the netrc.
- * If login[0] != 0, search for password within machine and login.
- */
-#endif
diff --git a/Utilities/cmcurl/nwlib.c b/Utilities/cmcurl/nwlib.c
deleted file mode 100644
index b0eea56c7..000000000
--- a/Utilities/cmcurl/nwlib.c
+++ /dev/null
@@ -1,300 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <library.h>
-#include <netware.h>
-#include <screen.h>
-#include <nks/thread.h>
-#include <nks/synch.h>
-
-#include "memory.h"
-#include "memdebug.h"
-
-typedef struct
-{
- int _errno;
- void *twentybytes;
-} libthreaddata_t;
-
-typedef struct
-{
- int x;
- int y;
- int z;
- void *tenbytes;
- NXKey_t perthreadkey; /* if -1, no key obtained... */
- NXMutex_t *lock;
-} libdata_t;
-
-int gLibId = -1;
-void *gLibHandle = (void *) NULL;
-rtag_t gAllocTag = (rtag_t) NULL;
-NXMutex_t *gLibLock = (NXMutex_t *) NULL;
-
-/* internal library function prototypes... */
-int DisposeLibraryData ( void * );
-void DisposeThreadData ( void * );
-int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata );
-
-
-int _NonAppStart( void *NLMHandle,
- void *errorScreen,
- const char *cmdLine,
- const char *loadDirPath,
- size_t uninitializedDataLength,
- void *NLMFileHandle,
- int (*readRoutineP)( int conn,
- void *fileHandle, size_t offset,
- size_t nbytes,
- size_t *bytesRead,
- void *buffer ),
- size_t customDataOffset,
- size_t customDataSize,
- int messageCount,
- const char **messages )
-{
- NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
-
-#ifndef __GNUC__
-#pragma unused(cmdLine)
-#pragma unused(loadDirPath)
-#pragma unused(uninitializedDataLength)
-#pragma unused(NLMFileHandle)
-#pragma unused(readRoutineP)
-#pragma unused(customDataOffset)
-#pragma unused(customDataSize)
-#pragma unused(messageCount)
-#pragma unused(messages)
-#endif
-
-/*
-** Here we process our command line, post errors (to the error screen),
-** perform initializations and anything else we need to do before being able
-** to accept calls into us. If we succeed, we return non-zero and the NetWare
-** Loader will leave us up, otherwise we fail to load and get dumped.
-*/
- gAllocTag = AllocateResourceTag(NLMHandle,
- "<library-name> memory allocations",
- AllocSignature);
-
- if (!gAllocTag) {
- OutputToScreen(errorScreen, "Unable to allocate resource tag for "
- "library memory allocations.\n");
- return -1;
- }
-
- gLibId = register_library(DisposeLibraryData);
-
- if (gLibId < -1) {
- OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
- return -1;
- }
-
- gLibHandle = NLMHandle;
-
- gLibLock = NXMutexAlloc(0, 0, &liblock);
-
- if (!gLibLock) {
- OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
- return -1;
- }
-
- return 0;
-}
-
-/*
-** Here we clean up any resources we allocated. Resource tags is a big part
-** of what we created, but NetWare doesn't ask us to free those.
-*/
-void _NonAppStop( void )
-{
- (void) unregister_library(gLibId);
- NXMutexFree(gLibLock);
-}
-
-/*
-** This function cannot be the first in the file for if the file is linked
-** first, then the check-unload function's offset will be nlmname.nlm+0
-** which is how to tell that there isn't one. When the check function is
-** first in the linked objects, it is ambiguous. For this reason, we will
-** put it inside this file after the stop function.
-**
-** Here we check to see if it's alright to ourselves to be unloaded. If not,
-** we return a non-zero value. Right now, there isn't any reason not to allow
-** it.
-*/
-int _NonAppCheckUnload( void )
-{
- return 0;
-}
-
-int GetOrSetUpData(int id, libdata_t **appData,
- libthreaddata_t **threadData )
-{
- int err;
- libdata_t *app_data;
- libthreaddata_t *thread_data;
- NXKey_t key;
- NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
-
- err = 0;
- thread_data = (libthreaddata_t *) NULL;
-
-/*
-** Attempt to get our data for the application calling us. This is where we
-** store whatever application-specific information we need to carry in support
-** of calling applications.
-*/
- app_data = (libdata_t *) get_app_data(id);
-
- if (!app_data) {
-/*
-** This application hasn't called us before; set up application AND per-thread
-** data. Of course, just in case a thread from this same application is calling
-** us simultaneously, we better lock our application data-creation mutex. We
-** also need to recheck for data after we acquire the lock because WE might be
-** that other thread that was too late to create the data and the first thread
-** in will have created it.
-*/
- NXLock(gLibLock);
-
- if (!(app_data = (libdata_t *) get_app_data(id))) {
- app_data = (libdata_t *) malloc(sizeof(libdata_t));
-
- if (app_data) {
- memset(app_data, 0, sizeof(libdata_t));
-
- app_data->tenbytes = malloc(10);
- app_data->lock = NXMutexAlloc(0, 0, &liblock);
-
- if (!app_data->tenbytes || !app_data->lock) {
- if (app_data->lock)
- NXMutexFree(app_data->lock);
-
- free(app_data);
- app_data = (libdata_t *) NULL;
- err = ENOMEM;
- }
-
- if (app_data) {
-/*
-** Here we burn in the application data that we were trying to get by calling
-** get_app_data(). Next time we call the first function, we'll get this data
-** we're just now setting. We also go on here to establish the per-thread data
-** for the calling thread, something we'll have to do on each application
-** thread the first time it calls us.
-*/
- err = set_app_data(gLibId, app_data);
-
- if (err) {
- free(app_data);
- app_data = (libdata_t *) NULL;
- err = ENOMEM;
- }
- else {
- /* create key for thread-specific data... */
- err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
-
- if (err) /* (no more keys left?) */
- key = -1;
-
- app_data->perthreadkey = key;
- }
- }
- }
- }
-
- NXUnlock(gLibLock);
- }
-
- if (app_data) {
- key = app_data->perthreadkey;
-
- if (key != -1 /* couldn't create a key? no thread data */
- && !(err = NXKeyGetValue(key, (void **) &thread_data))
- && !thread_data) {
-/*
-** Allocate the per-thread data for the calling thread. Regardless of whether
-** there was already application data or not, this may be the first call by a
-** a new thread. The fact that we allocation 20 bytes on a pointer is not very
-** important, this just helps to demonstrate that we can have arbitrarily
-** complex per-thread data.
-*/
- thread_data = (libthreaddata_t *) malloc(sizeof(libthreaddata_t));
-
- if (thread_data) {
- thread_data->_errno = 0;
- thread_data->twentybytes = malloc(20);
-
- if (!thread_data->twentybytes) {
- free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
- err = ENOMEM;
- }
-
- if ((err = NXKeySetValue(key, thread_data))) {
- free(thread_data->twentybytes);
- free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
- }
- }
- }
- }
-
- if (appData)
- *appData = app_data;
-
- if (threadData)
- *threadData = thread_data;
-
- return err;
-}
-
-int DisposeLibraryData( void *data)
-{
- if (data) {
- void *tenbytes = ((libdata_t *) data)->tenbytes;
-
- if (tenbytes)
- free(tenbytes);
-
- free(data);
- }
-
- return 0;
-}
-
-void DisposeThreadData(void *data)
-{
- if (data) {
- void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
-
- if (twentybytes)
- free(twentybytes);
-
- free(data);
- }
-}
diff --git a/Utilities/cmcurl/parsedate.c b/Utilities/cmcurl/parsedate.c
deleted file mode 100644
index ef91585e5..000000000
--- a/Utilities/cmcurl/parsedate.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-/*
- A brief summary of the date string formats this parser groks:
-
- RFC 2616 3.3.1
-
- Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
- Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
- Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
-
- we support dates without week day name:
-
- 06 Nov 1994 08:49:37 GMT
- 06-Nov-94 08:49:37 GMT
- Nov 6 08:49:37 1994
-
- without the time zone:
-
- 06 Nov 1994 08:49:37
- 06-Nov-94 08:49:37
-
- weird order:
-
- 1994 Nov 6 08:49:37 (GNU date fails)
- GMT 08:49:37 06-Nov-94 Sunday
- 94 6 Nov 08:49:37 (GNU date fails)
-
- time left out:
-
- 1994 Nov 6
- 06-Nov-94
- Sun Nov 6 94
-
- unusual separators:
-
- 1994.Nov.6
- Sun/Nov/6/94/GMT
-
- commonly used time zone names:
-
- Sun, 06 Nov 1994 08:49:37 CET
- 06 Nov 1994 08:49:37 EST
-
- time zones specified using RFC822 style:
-
- Sun, 12 Sep 2004 15:05:58 -0700
- Sat, 11 Sep 2004 21:32:11 +0200
-
- compact numerical date strings:
-
- 20040912 15:05:58 -0700
- 20040911 +0200
-
-*/
-#include "setup.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* for strtol() */
-#endif
-
-#include <curl/curl.h>
-
-static time_t Curl_parsedate(const char *date);
-
-const char * const Curl_wkday[] =
-{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
-static const char * const weekday[] =
-{ "Monday", "Tuesday", "Wednesday", "Thursday",
- "Friday", "Saturday", "Sunday" };
-const char * const Curl_month[]=
-{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-
-struct tzinfo {
- const char *name;
- int offset; /* +/- in minutes */
-};
-
-/* Here's a bunch of frequently used time zone names. These were supported
- by the old getdate parser. */
-#define tDAYZONE -60 /* offset for daylight savings time */
-static const struct tzinfo tz[]= {
- {"GMT", 0}, /* Greenwich Mean */
- {"UTC", 0}, /* Universal (Coordinated) */
- {"WET", 0}, /* Western European */
- {"BST", 0 tDAYZONE}, /* British Summer */
- {"WAT", 60}, /* West Africa */
- {"AST", 240}, /* Atlantic Standard */
- {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */
- {"EST", 300}, /* Eastern Standard */
- {"EDT", 300 tDAYZONE}, /* Eastern Daylight */
- {"CST", 360}, /* Central Standard */
- {"CDT", 360 tDAYZONE}, /* Central Daylight */
- {"MST", 420}, /* Mountain Standard */
- {"MDT", 420 tDAYZONE}, /* Mountain Daylight */
- {"PST", 480}, /* Pacific Standard */
- {"PDT", 480 tDAYZONE}, /* Pacific Daylight */
- {"YST", 540}, /* Yukon Standard */
- {"YDT", 540 tDAYZONE}, /* Yukon Daylight */
- {"HST", 600}, /* Hawaii Standard */
- {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */
- {"CAT", 600}, /* Central Alaska */
- {"AHST", 600}, /* Alaska-Hawaii Standard */
- {"NT", 660}, /* Nome */
- {"IDLW", 720}, /* International Date Line West */
- {"CET", -60}, /* Central European */
- {"MET", -60}, /* Middle European */
- {"MEWT", -60}, /* Middle European Winter */
- {"MEST", -60 tDAYZONE}, /* Middle European Summer */
- {"CEST", -60 tDAYZONE}, /* Central European Summer */
- {"MESZ", -60 tDAYZONE}, /* Middle European Summer */
- {"FWT", -60}, /* French Winter */
- {"FST", -60 tDAYZONE}, /* French Summer */
- {"EET", -120}, /* Eastern Europe, USSR Zone 1 */
- {"WAST", -420}, /* West Australian Standard */
- {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
- {"CCT", -480}, /* China Coast, USSR Zone 7 */
- {"JST", -540}, /* Japan Standard, USSR Zone 8 */
- {"EAST", -600}, /* Eastern Australian Standard */
- {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
- {"GST", -600}, /* Guam Standard, USSR Zone 9 */
- {"NZT", -720}, /* New Zealand */
- {"NZST", -720}, /* New Zealand Standard */
- {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
- {"IDLE", -720}, /* International Date Line East */
-};
-
-/* returns:
- -1 no day
- 0 monday - 6 sunday
-*/
-
-static int checkday(char *check, size_t len)
-{
- int i;
- const char * const *what;
- bool found= FALSE;
- if(len > 3)
- what = &weekday[0];
- else
- what = &Curl_wkday[0];
- for(i=0; i<7; i++) {
- if(curl_strequal(check, what[0])) {
- found=TRUE;
- break;
- }
- what++;
- }
- return found?i:-1;
-}
-
-static int checkmonth(char *check)
-{
- int i;
- const char * const *what;
- bool found= FALSE;
-
- what = &Curl_month[0];
- for(i=0; i<12; i++) {
- if(curl_strequal(check, what[0])) {
- found=TRUE;
- break;
- }
- what++;
- }
- return found?i:-1; /* return the offset or -1, no real offset is -1 */
-}
-
-/* return the time zone offset between GMT and the input one, in number
- of seconds or -1 if the timezone wasn't found/legal */
-
-static int checktz(char *check)
-{
- unsigned int i;
- const struct tzinfo *what;
- bool found= FALSE;
-
- what = tz;
- for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
- if(curl_strequal(check, what->name)) {
- found=TRUE;
- break;
- }
- what++;
- }
- return found?what->offset*60:-1;
-}
-
-static void skip(const char **date)
-{
- /* skip everything that aren't letters or digits */
- while(**date && !ISALNUM(**date))
- (*date)++;
-}
-
-enum assume {
- DATE_MDAY,
- DATE_YEAR,
- DATE_TIME
-};
-
-static time_t Curl_parsedate(const char *date)
-{
- time_t t = 0;
- int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
- int monnum=-1; /* month of the year number, 0-11 */
- int mdaynum=-1; /* day of month, 1 - 31 */
- int hournum=-1;
- int minnum=-1;
- int secnum=-1;
- int yearnum=-1;
- int tzoff=-1;
- struct tm tm;
- enum assume dignext = DATE_MDAY;
- const char *indate = date; /* save the original pointer */
- int part = 0; /* max 6 parts */
-
- while(*date && (part < 6)) {
- bool found=FALSE;
-
- skip(&date);
-
- if(ISALPHA(*date)) {
- /* a name coming up */
- char buf[32]="";
- size_t len;
- sscanf(date, "%31[A-Za-z]", buf);
- len = strlen(buf);
-
- if(wdaynum == -1) {
- wdaynum = checkday(buf, len);
- if(wdaynum != -1)
- found = TRUE;
- }
- if(!found && (monnum == -1)) {
- monnum = checkmonth(buf);
- if(monnum != -1)
- found = TRUE;
- }
-
- if(!found && (tzoff == -1)) {
- /* this just must be a time zone string */
- tzoff = checktz(buf);
- if(tzoff != -1)
- found = TRUE;
- }
-
- if(!found)
- return -1; /* bad string */
-
- date += len;
- }
- else if(ISDIGIT(*date)) {
- /* a digit */
- int val;
- char *end;
- if((secnum == -1) &&
- (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
- /* time stamp! */
- date += 8;
- found = TRUE;
- }
- else {
- val = (int)strtol(date, &end, 10);
-
- if((tzoff == -1) &&
- ((end - date) == 4) &&
- (val < 1300) &&
- (indate< date) &&
- ((date[-1] == '+' || date[-1] == '-'))) {
- /* four digits and a value less than 1300 and it is preceeded with
- a plus or minus. This is a time zone indication. */
- found = TRUE;
- tzoff = (val/100 * 60 + val%100)*60;
-
- /* the + and - prefix indicates the local time compared to GMT,
- this we need ther reversed math to get what we want */
- tzoff = date[-1]=='+'?-tzoff:tzoff;
- }
-
- if(((end - date) == 8) &&
- (yearnum == -1) &&
- (monnum == -1) &&
- (mdaynum == -1)) {
- /* 8 digits, no year, month or day yet. This is YYYYMMDD */
- found = TRUE;
- yearnum = val/10000;
- monnum = (val%10000)/100-1; /* month is 0 - 11 */
- mdaynum = val%100;
- }
-
- if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
- if((val > 0) && (val<32)) {
- mdaynum = val;
- found = TRUE;
- }
- dignext = DATE_YEAR;
- }
-
- if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
- yearnum = val;
- found = TRUE;
- if(yearnum < 1900) {
- if (yearnum > 70)
- yearnum += 1900;
- else
- yearnum += 2000;
- }
- if(mdaynum == -1)
- dignext = DATE_MDAY;
- }
-
- if(!found)
- return -1;
-
- date = end;
- }
- }
-
- part++;
- }
-
- if(-1 == secnum)
- secnum = minnum = hournum = 0; /* no time, make it zero */
-
- if((-1 == mdaynum) ||
- (-1 == monnum) ||
- (-1 == yearnum))
- /* lacks vital info, fail */
- return -1;
-
-#if SIZEOF_TIME_T < 5
- /* 32 bit time_t can only hold dates to the beginning of 2038 */
- if(yearnum > 2037)
- return 0x7fffffff;
-#endif
-
- tm.tm_sec = secnum;
- tm.tm_min = minnum;
- tm.tm_hour = hournum;
- tm.tm_mday = mdaynum;
- tm.tm_mon = monnum;
- tm.tm_year = yearnum - 1900;
- tm.tm_wday = 0;
- tm.tm_yday = 0;
- tm.tm_isdst = 0;
-
- /* mktime() returns a time_t. time_t is often 32 bits, even on many
- architectures that feature 64 bit 'long'.
-
- Some systems have 64 bit time_t and deal with years beyond 2038. However,
- even some of the systems with 64 bit time_t returns -1 for dates beyond
- 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
- */
- t = mktime(&tm);
-
- /* time zone adjust (cast t to int to compare to negative one) */
- if(-1 != (int)t) {
- struct tm *gmt;
- long delta;
- time_t t2;
-
-#ifdef HAVE_GMTIME_R
- /* thread-safe version */
- struct tm keeptime2;
- gmt = (struct tm *)gmtime_r(&t, &keeptime2);
- if(!gmt)
- return -1; /* illegal date/time */
- t2 = mktime(gmt);
-#else
- /* It seems that at least the MSVC version of mktime() doesn't work
- properly if it gets the 'gmt' pointer passed in (which is a pointer
- returned from gmtime() pointing to static memory), so instead we copy
- the tm struct to a local struct and pass a pointer to that struct as
- input to mktime(). */
- struct tm gmt2;
- gmt = gmtime(&t); /* use gmtime_r() if available */
- if(!gmt)
- return -1; /* illegal date/time */
- gmt2 = *gmt;
- t2 = mktime(&gmt2);
-#endif
-
- /* Add the time zone diff (between the given timezone and GMT) and the
- diff between the local time zone and GMT. */
- delta = (long)((tzoff!=-1?tzoff:0) + (t - t2));
-
- if((delta>0) && (t + delta < t))
- return -1; /* time_t overflow */
-
- t += delta;
- }
-
- return t;
-}
-
-time_t curl_getdate(const char *p, const time_t *now)
-{
- (void)now;
- return Curl_parsedate(p);
-}
diff --git a/Utilities/cmcurl/parsedate.h b/Utilities/cmcurl/parsedate.h
deleted file mode 100644
index 0ea2d83c3..000000000
--- a/Utilities/cmcurl/parsedate.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __PARSEDATE_H
-#define __PARSEDATEL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-extern const char * const Curl_wkday[7];
-extern const char * const Curl_month[12];
-
-#endif
diff --git a/Utilities/cmcurl/progress.c b/Utilities/cmcurl/progress.c
deleted file mode 100644
index 5ba829a03..000000000
--- a/Utilities/cmcurl/progress.c
+++ /dev/null
@@ -1,424 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <time.h>
-
-#if defined(__EMX__)
-#include <stdlib.h>
-#endif
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "progress.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
- byte) */
-static void time2str(char *r, long t)
-{
- long h;
- if(!t) {
- strcpy(r, "--:--:--");
- return;
- }
- h = (t/3600);
- if(h <= 99) {
- long m = (t-(h*3600))/60;
- long s = (t-(h*3600)-(m*60));
- snprintf(r, 9, "%2ld:%02ld:%02ld",h,m,s);
- }
- else {
- /* this equals to more than 99 hours, switch to a more suitable output
- format to fit within the limits. */
- if(h/24 <= 999)
- snprintf(r, 9, "%3ldd %02ldh", h/24, h-(h/24)*24);
- else
- snprintf(r, 9, "%7ldd", h/24);
- }
-}
-
-/* The point of this function would be to return a string of the input data,
- but never longer than 5 columns (+ one zero byte).
- Add suffix k, M, G when suitable... */
-static char *max5data(curl_off_t bytes, char *max5)
-{
-#define ONE_KILOBYTE 1024
-#define ONE_MEGABYTE (1024* ONE_KILOBYTE)
-#define ONE_GIGABYTE (1024* ONE_MEGABYTE)
-#define ONE_TERRABYTE ((curl_off_t)1024* ONE_GIGABYTE)
-#define ONE_PETABYTE ((curl_off_t)1024* ONE_TERRABYTE)
-
- if(bytes < 100000) {
- snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
- }
- else if(bytes < (10000*ONE_KILOBYTE)) {
- snprintf(max5, 6, "%4" FORMAT_OFF_T "k", (curl_off_t)(bytes/ONE_KILOBYTE));
- }
- else if(bytes < (100*ONE_MEGABYTE)) {
- /* 'XX.XM' is good as long as we're less than 100 megs */
- snprintf(max5, 6, "%2d.%0dM",
- (int)(bytes/ONE_MEGABYTE),
- (int)(bytes%ONE_MEGABYTE)/(ONE_MEGABYTE/10) );
- }
-#if SIZEOF_CURL_OFF_T > 4
- else if(bytes < ( (curl_off_t)10000*ONE_MEGABYTE))
- /* 'XXXXM' is good until we're at 10000MB or above */
- snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
-
- else if(bytes < (curl_off_t)100*ONE_GIGABYTE)
- /* 10000 MB - 100 GB, we show it as XX.XG */
- snprintf(max5, 6, "%2d.%0dG",
- (int)(bytes/ONE_GIGABYTE),
- (int)(bytes%ONE_GIGABYTE)/(ONE_GIGABYTE/10) );
-
- else if(bytes < (curl_off_t)10000 * ONE_GIGABYTE)
- /* up to 10000GB, display without decimal: XXXXG */
- snprintf(max5, 6, "%4dG", (int)(bytes/ONE_GIGABYTE));
-
- else if(bytes < (curl_off_t)10000 * ONE_TERRABYTE)
- /* up to 10000TB, display without decimal: XXXXT */
- snprintf(max5, 6, "%4dT", (int)(bytes/ONE_TERRABYTE));
- else {
- /* up to 10000PB, display without decimal: XXXXP */
- snprintf(max5, 6, "%4dP", (int)(bytes/ONE_PETABYTE));
-
- /* 16384 petabytes (16 exabytes) is maximum a 64 bit number can hold,
- but this type is signed so 8192PB will be max.*/
- }
-
-#else
- else
- snprintf(max5, 6, "%4" FORMAT_OFF_T "M", (curl_off_t)(bytes/ONE_MEGABYTE));
-#endif
-
- return max5;
-}
-
-/*
-
- New proposed interface, 9th of February 2000:
-
- pgrsStartNow() - sets start time
- pgrsSetDownloadSize(x) - known expected download size
- pgrsSetUploadSize(x) - known expected upload size
- pgrsSetDownloadCounter() - amount of data currently downloaded
- pgrsSetUploadCounter() - amount of data currently uploaded
- pgrsUpdate() - show progress
- pgrsDone() - transfer complete
-
-*/
-
-void Curl_pgrsDone(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- data->progress.lastshow=0;
- Curl_pgrsUpdate(conn); /* the final (forced) update */
-
- data->progress.speeder_c = 0; /* reset the progress meter display */
-}
-
-/* reset all times except redirect */
-void Curl_pgrsResetTimes(struct SessionHandle *data)
-{
- data->progress.t_nslookup = 0.0;
- data->progress.t_connect = 0.0;
- data->progress.t_pretransfer = 0.0;
- data->progress.t_starttransfer = 0.0;
-}
-
-void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
-{
- switch(timer) {
- default:
- case TIMER_NONE:
- /* mistake filter */
- break;
- case TIMER_STARTSINGLE:
- /* This is set at the start of a single fetch */
- data->progress.t_startsingle = Curl_tvnow();
- break;
-
- case TIMER_NAMELOOKUP:
- data->progress.t_nslookup =
- Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
- break;
- case TIMER_CONNECT:
- data->progress.t_connect =
- Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
- break;
- case TIMER_PRETRANSFER:
- data->progress.t_pretransfer =
- Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
- break;
- case TIMER_STARTTRANSFER:
- data->progress.t_starttransfer =
- Curl_tvdiff_secs(Curl_tvnow(), data->progress.t_startsingle);
- break;
- case TIMER_POSTRANSFER:
- /* this is the normal end-of-transfer thing */
- break;
- case TIMER_REDIRECT:
- data->progress.t_redirect =
- Curl_tvdiff_secs(Curl_tvnow(), data->progress.start);
- break;
- }
-}
-
-void Curl_pgrsStartNow(struct SessionHandle *data)
-{
- data->progress.speeder_c = 0; /* reset the progress meter display */
- data->progress.start = Curl_tvnow();
-}
-
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
-{
- data->progress.downloaded = size;
-}
-
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
-{
- data->progress.uploaded = size;
-}
-
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
-{
- data->progress.size_dl = size;
- if(size > 0)
- data->progress.flags |= PGRS_DL_SIZE_KNOWN;
- else
- data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
-}
-
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
-{
- data->progress.size_ul = size;
- if(size > 0)
- data->progress.flags |= PGRS_UL_SIZE_KNOWN;
- else
- data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
-}
-
-int Curl_pgrsUpdate(struct connectdata *conn)
-{
- struct timeval now;
- int result;
- char max5[6][10];
- int dlpercen=0;
- int ulpercen=0;
- int total_percen=0;
- curl_off_t total_transfer;
- curl_off_t total_expected_transfer;
- long timespent;
- struct SessionHandle *data = conn->data;
- int nowindex = data->progress.speeder_c% CURR_TIME;
- int checkindex;
- int countindex; /* amount of seconds stored in the speeder array */
- char time_left[10];
- char time_total[10];
- char time_spent[10];
- long ulestimate=0;
- long dlestimate=0;
- long total_estimate;
-
- if(data->progress.flags & PGRS_HIDE)
- ; /* We do enter this function even if we don't wanna see anything, since
- this is were lots of the calculations are being made that will be used
- even when not displayed! */
- else if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
- if (!data->progress.callback) {
- if(data->reqdata.resume_from)
- fprintf(data->set.err,
- "** Resuming transfer from byte position %" FORMAT_OFF_T
- "\n",
- data->reqdata.resume_from);
- fprintf(data->set.err,
- " %% Total %% Received %% Xferd Average Speed Time Time Time Current\n"
- " Dload Upload Total Spent Left Speed\n");
- }
- data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
- }
-
- now = Curl_tvnow(); /* what time is it */
-
- /* The time spent so far (from the start) */
- data->progress.timespent = Curl_tvdiff_secs(now, data->progress.start);
- timespent = (long)data->progress.timespent;
-
- /* The average download speed this far */
- data->progress.dlspeed = (curl_off_t)
- ((double)data->progress.downloaded/
- (data->progress.timespent>0?data->progress.timespent:1));
-
- /* The average upload speed this far */
- data->progress.ulspeed = (curl_off_t)
- ((double)data->progress.uploaded/
- (data->progress.timespent>0?data->progress.timespent:1));
-
- if(data->progress.lastshow == Curl_tvlong(now))
- return 0; /* never update this more than once a second if the end isn't
- reached */
- data->progress.lastshow = now.tv_sec;
-
- /* Let's do the "current speed" thing, which should use the fastest
- of the dl/ul speeds. Store the fasted speed at entry 'nowindex'. */
- data->progress.speeder[ nowindex ] =
- data->progress.downloaded>data->progress.uploaded?
- data->progress.downloaded:data->progress.uploaded;
-
- /* remember the exact time for this moment */
- data->progress.speeder_time [ nowindex ] = now;
-
- /* advance our speeder_c counter, which is increased every time we get
- here and we expect it to never wrap as 2^32 is a lot of seconds! */
- data->progress.speeder_c++;
-
- /* figure out how many index entries of data we have stored in our speeder
- array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
- transfer. Imagine, after one second we have filled in two entries,
- after two seconds we've filled in three entries etc. */
- countindex = ((data->progress.speeder_c>=CURR_TIME)?
- CURR_TIME:data->progress.speeder_c) - 1;
-
- /* first of all, we don't do this if there's no counted seconds yet */
- if(countindex) {
- long span_ms;
-
- /* Get the index position to compare with the 'nowindex' position.
- Get the oldest entry possible. While we have less than CURR_TIME
- entries, the first entry will remain the oldest. */
- checkindex = (data->progress.speeder_c>=CURR_TIME)?
- data->progress.speeder_c%CURR_TIME:0;
-
- /* Figure out the exact time for the time span */
- span_ms = Curl_tvdiff(now,
- data->progress.speeder_time[checkindex]);
- if(0 == span_ms)
- span_ms=1; /* at least one millisecond MUST have passed */
-
- /* Calculate the average speed the last 'span_ms' milliseconds */
- {
- curl_off_t amount = data->progress.speeder[nowindex]-
- data->progress.speeder[checkindex];
-
- if(amount > 4294967 /* 0xffffffff/1000 */)
- /* the 'amount' value is bigger than would fit in 32 bits if
- multiplied with 1000, so we use the double math for this */
- data->progress.current_speed = (curl_off_t)
- ((double)amount/((double)span_ms/1000.0));
- else
- /* the 'amount' value is small enough to fit within 32 bits even
- when multiplied with 1000 */
- data->progress.current_speed = amount*1000/span_ms;
- }
- }
- else
- /* the first second we use the main average */
- data->progress.current_speed =
- (data->progress.ulspeed>data->progress.dlspeed)?
- data->progress.ulspeed:data->progress.dlspeed;
-
- if(data->progress.flags & PGRS_HIDE)
- return 0;
-
- else if(data->set.fprogress) {
- /* There's a callback set, so we call that instead of writing
- anything ourselves. This really is the way to go. */
- result= data->set.fprogress(data->set.progress_client,
- (double)data->progress.size_dl,
- (double)data->progress.downloaded,
- (double)data->progress.size_ul,
- (double)data->progress.uploaded);
- if(result)
- failf(data, "Callback aborted");
- return result;
- }
-
- /* Figure out the estimated time of arrival for the upload */
- if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
- (data->progress.ulspeed>0) &&
- (data->progress.size_ul > 100) ) {
- ulestimate = (long)(data->progress.size_ul / data->progress.ulspeed);
- ulpercen = (int)(100*(data->progress.uploaded/100) /
- (data->progress.size_ul/100) );
- }
-
- /* ... and the download */
- if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
- (data->progress.dlspeed>0) &&
- (data->progress.size_dl>100)) {
- dlestimate = (long)(data->progress.size_dl / data->progress.dlspeed);
- dlpercen = (int)(100*(data->progress.downloaded/100) /
- (data->progress.size_dl/100));
- }
-
- /* Now figure out which of them that is slower and use for the for
- total estimate! */
- total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
-
- /* create the three time strings */
- time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
- time2str(time_total, total_estimate);
- time2str(time_spent, timespent);
-
- /* Get the total amount of data expected to get transfered */
- total_expected_transfer =
- (data->progress.flags & PGRS_UL_SIZE_KNOWN?
- data->progress.size_ul:data->progress.uploaded)+
- (data->progress.flags & PGRS_DL_SIZE_KNOWN?
- data->progress.size_dl:data->progress.downloaded);
-
- /* We have transfered this much so far */
- total_transfer = data->progress.downloaded + data->progress.uploaded;
-
- /* Get the percentage of data transfered so far */
- if(total_expected_transfer > 100)
- total_percen=(int)(100*(total_transfer/100) /
- (total_expected_transfer/100) );
-
- fprintf(data->set.err,
- "\r%3d %s %3d %s %3d %s %s %s %s %s %s %s",
- total_percen, /* 3 letters */ /* total % */
- max5data(total_expected_transfer, max5[2]), /* total size */
- dlpercen, /* 3 letters */ /* rcvd % */
- max5data(data->progress.downloaded, max5[0]), /* rcvd size */
- ulpercen, /* 3 letters */ /* xfer % */
- max5data(data->progress.uploaded, max5[1]), /* xfer size */
- max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
- max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
- time_total, /* 8 letters */ /* total time */
- time_spent, /* 8 letters */ /* time spent */
- time_left, /* 8 letters */ /* time left */
- max5data(data->progress.current_speed, max5[5]) /* current speed */
- );
-
- /* we flush the output stream to make it appear as soon as possible */
- fflush(data->set.err);
-
- return 0;
-}
diff --git a/Utilities/cmcurl/progress.h b/Utilities/cmcurl/progress.h
deleted file mode 100644
index ad9d6623e..000000000
--- a/Utilities/cmcurl/progress.h
+++ /dev/null
@@ -1,70 +0,0 @@
-#ifndef __PROGRESS_H
-#define __PROGRESS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "timeval.h"
-
-
-typedef enum {
- TIMER_NONE,
- TIMER_NAMELOOKUP,
- TIMER_CONNECT,
- TIMER_PRETRANSFER,
- TIMER_STARTTRANSFER,
- TIMER_POSTRANSFER,
- TIMER_STARTSINGLE,
- TIMER_REDIRECT,
- TIMER_LAST /* must be last */
-} timerid;
-
-void Curl_pgrsDone(struct connectdata *);
-void Curl_pgrsStartNow(struct SessionHandle *data);
-void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size);
-void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size);
-int Curl_pgrsUpdate(struct connectdata *);
-void Curl_pgrsResetTimes(struct SessionHandle *data);
-void Curl_pgrsTime(struct SessionHandle *data, timerid timer);
-
-
-/* Don't show progress for sizes smaller than: */
-#define LEAST_SIZE_PROGRESS BUFSIZE
-
-#define PROGRESS_DOWNLOAD (1<<0)
-#define PROGRESS_UPLOAD (1<<1)
-#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD)
-
-#define PGRS_SHOW_DL (1<<0)
-#define PGRS_SHOW_UL (1<<1)
-#define PGRS_DONE_DL (1<<2)
-#define PGRS_DONE_UL (1<<3)
-#define PGRS_HIDE (1<<4)
-#define PGRS_UL_SIZE_KNOWN (1<<5)
-#define PGRS_DL_SIZE_KNOWN (1<<6)
-
-#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
-
-
-#endif /* __PROGRESS_H */
diff --git a/Utilities/cmcurl/security.c b/Utilities/cmcurl/security.c
deleted file mode 100644
index 4c9aed812..000000000
--- a/Utilities/cmcurl/security.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
- * use in Curl. His latest changes were done 2000-09-18.
- *
- * It has since been patched and modified a lot by Daniel Stenberg
- * <daniel@haxx.se> to make it better applied to curl conditions, and to make
- * it not use globals, pollute name space and more. This source code awaits a
- * rewrite to work around the paragraph 2 in the BSD licenses as explained
- * below.
- *
- * Copyright (c) 1998, 1999 Kungliga Tekniska Högskolan
- * (Royal Institute of Technology, Stockholm, Sweden).
- * 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.
- *
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE. */
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_FTP
-#ifdef HAVE_KRB4
-
-#define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */
-#include <curl/mprintf.h>
-
-#include <stdlib.h>
-#include <string.h>
-#include <netdb.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include "urldata.h"
-#include "krb4.h"
-#include "base64.h"
-#include "sendf.h"
-#include "ftp.h"
-#include "memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define min(a, b) ((a) < (b) ? (a) : (b))
-
-static const struct {
- enum protection_level level;
- const char *name;
-} level_names[] = {
- { prot_clear, "clear" },
- { prot_safe, "safe" },
- { prot_confidential, "confidential" },
- { prot_private, "private" }
-};
-
-static enum protection_level
-name_to_level(const char *name)
-{
- int i;
- for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
- if(curl_strnequal(level_names[i].name, name, strlen(name)))
- return level_names[i].level;
- return (enum protection_level)-1;
-}
-
-static const struct Curl_sec_client_mech * const mechs[] = {
-#ifdef KRB5
- /* not supported */
-#endif
-#ifdef HAVE_KRB4
- &Curl_krb4_client_mech,
-#endif
- NULL
-};
-
-int
-Curl_sec_getc(struct connectdata *conn, FILE *F)
-{
- if(conn->sec_complete && conn->data_prot) {
- char c;
- if(Curl_sec_read(conn, fileno(F), &c, 1) <= 0)
- return EOF;
- return c;
- }
- else
- return getc(F);
-}
-
-static int
-block_read(int fd, void *buf, size_t len)
-{
- unsigned char *p = buf;
- int b;
- while(len) {
- b = read(fd, p, len);
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
- len -= b;
- p += b;
- }
- return p - (unsigned char*)buf;
-}
-
-static int
-block_write(int fd, void *buf, size_t len)
-{
- unsigned char *p = buf;
- int b;
- while(len) {
- b = write(fd, p, len);
- if(b < 0)
- return -1;
- len -= b;
- p += b;
- }
- return p - (unsigned char*)buf;
-}
-
-static int
-sec_get_data(struct connectdata *conn,
- int fd, struct krb4buffer *buf)
-{
- int len;
- int b;
-
- b = block_read(fd, &len, sizeof(len));
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
- len = ntohl(len);
- buf->data = realloc(buf->data, len);
- b = block_read(fd, buf->data, len);
- if (b == 0)
- return 0;
- else if (b < 0)
- return -1;
- buf->size = (conn->mech->decode)(conn->app_data, buf->data, len,
- conn->data_prot, conn);
- buf->index = 0;
- return 0;
-}
-
-static size_t
-buffer_read(struct krb4buffer *buf, void *data, size_t len)
-{
- len = min(len, buf->size - buf->index);
- memcpy(data, (char*)buf->data + buf->index, len);
- buf->index += len;
- return len;
-}
-
-static size_t
-buffer_write(struct krb4buffer *buf, void *data, size_t len)
-{
- if(buf->index + len > buf->size) {
- void *tmp;
- if(buf->data == NULL)
- tmp = malloc(1024);
- else
- tmp = realloc(buf->data, buf->index + len);
- if(tmp == NULL)
- return -1;
- buf->data = tmp;
- buf->size = buf->index + len;
- }
- memcpy((char*)buf->data + buf->index, data, len);
- buf->index += len;
- return len;
-}
-
-int
-Curl_sec_read(struct connectdata *conn, int fd, void *buffer, int length)
-{
- size_t len;
- int rx = 0;
-
- if(conn->sec_complete == 0 || conn->data_prot == 0)
- return read(fd, buffer, length);
-
- if(conn->in_buffer.eof_flag){
- conn->in_buffer.eof_flag = 0;
- return 0;
- }
-
- len = buffer_read(&conn->in_buffer, buffer, length);
- length -= len;
- rx += len;
- buffer = (char*)buffer + len;
-
- while(length) {
- if(sec_get_data(conn, fd, &conn->in_buffer) < 0)
- return -1;
- if(conn->in_buffer.size == 0) {
- if(rx)
- conn->in_buffer.eof_flag = 1;
- return rx;
- }
- len = buffer_read(&conn->in_buffer, buffer, length);
- length -= len;
- rx += len;
- buffer = (char*)buffer + len;
- }
- return rx;
-}
-
-static int
-sec_send(struct connectdata *conn, int fd, char *from, int length)
-{
- int bytes;
- void *buf;
- bytes = (conn->mech->encode)(conn->app_data, from, length, conn->data_prot,
- &buf, conn);
- bytes = htonl(bytes);
- block_write(fd, &bytes, sizeof(bytes));
- block_write(fd, buf, ntohl(bytes));
- free(buf);
- return length;
-}
-
-int
-Curl_sec_fflush_fd(struct connectdata *conn, int fd)
-{
- if(conn->data_prot != prot_clear) {
- if(conn->out_buffer.index > 0){
- Curl_sec_write(conn, fd,
- conn->out_buffer.data, conn->out_buffer.index);
- conn->out_buffer.index = 0;
- }
- sec_send(conn, fd, NULL, 0);
- }
- return 0;
-}
-
-int
-Curl_sec_write(struct connectdata *conn, int fd, char *buffer, int length)
-{
- int len = conn->buffer_size;
- int tx = 0;
-
- if(conn->data_prot == prot_clear)
- return write(fd, buffer, length);
-
- len -= (conn->mech->overhead)(conn->app_data, conn->data_prot, len);
- while(length){
- if(length < len)
- len = length;
- sec_send(conn, fd, buffer, len);
- length -= len;
- buffer += len;
- tx += len;
- }
- return tx;
-}
-
-ssize_t
-Curl_sec_send(struct connectdata *conn, int num, char *buffer, int length)
-{
- curl_socket_t fd = conn->sock[num];
- return (ssize_t)Curl_sec_write(conn, fd, buffer, length);
-}
-
-int
-Curl_sec_putc(struct connectdata *conn, int c, FILE *F)
-{
- char ch = c;
- if(conn->data_prot == prot_clear)
- return putc(c, F);
-
- buffer_write(&conn->out_buffer, &ch, 1);
- if(c == '\n' || conn->out_buffer.index >= 1024 /* XXX */) {
- Curl_sec_write(conn, fileno(F), conn->out_buffer.data,
- conn->out_buffer.index);
- conn->out_buffer.index = 0;
- }
- return c;
-}
-
-int
-Curl_sec_read_msg(struct connectdata *conn, char *s, int level)
-{
- int len;
- unsigned char *buf;
- int code;
-
- len = Curl_base64_decode(s + 4, &buf); /* XXX */
- if(len > 0)
- len = (conn->mech->decode)(conn->app_data, buf, len, level, conn);
- else
- return -1;
-
- if(len < 0) {
- free(buf);
- return -1;
- }
-
- buf[len] = '\0';
-
- if(buf[3] == '-')
- code = 0;
- else
- sscanf((char *)buf, "%d", &code);
- if(buf[len-1] == '\n')
- buf[len-1] = '\0';
- strcpy(s, (char *)buf);
- free(buf);
- return code;
-}
-
-enum protection_level
-Curl_set_command_prot(struct connectdata *conn, enum protection_level level)
-{
- enum protection_level old = conn->command_prot;
- conn->command_prot = level;
- return old;
-}
-
-static int
-sec_prot_internal(struct connectdata *conn, int level)
-{
- char *p;
- unsigned int s = 1048576;
- ssize_t nread;
-
- if(!conn->sec_complete){
- infof(conn->data, "No security data exchange has taken place.\n");
- return -1;
- }
-
- if(level){
- int code;
- if(Curl_ftpsendf(conn, "PBSZ %u", s))
- return -1;
-
- if(Curl_GetFTPResponse(&nread, conn, &code))
- return -1;
-
- if(code/100 != '2'){
- failf(conn->data, "Failed to set protection buffer size.");
- return -1;
- }
- conn->buffer_size = s;
-
- p = strstr(conn->data->state.buffer, "PBSZ=");
- if(p)
- sscanf(p, "PBSZ=%u", &s);
- if(s < conn->buffer_size)
- conn->buffer_size = s;
- }
-
- if(Curl_ftpsendf(conn, "PROT %c", level["CSEP"]))
- return -1;
-
- if(Curl_GetFTPResponse(&nread, conn, NULL))
- return -1;
-
- if(conn->data->state.buffer[0] != '2'){
- failf(conn->data, "Failed to set protection level.");
- return -1;
- }
-
- conn->data_prot = (enum protection_level)level;
- return 0;
-}
-
-void
-Curl_sec_set_protection_level(struct connectdata *conn)
-{
- if(conn->sec_complete && conn->data_prot != conn->request_data_prot)
- sec_prot_internal(conn, conn->request_data_prot);
-}
-
-
-int
-Curl_sec_request_prot(struct connectdata *conn, const char *level)
-{
- int l = name_to_level(level);
- if(l == -1)
- return -1;
- conn->request_data_prot = (enum protection_level)l;
- return 0;
-}
-
-int
-Curl_sec_login(struct connectdata *conn)
-{
- int ret;
- const struct Curl_sec_client_mech * const *m;
- ssize_t nread;
- struct SessionHandle *data=conn->data;
- int ftpcode;
-
- for(m = mechs; *m && (*m)->name; m++) {
- void *tmp;
-
- tmp = realloc(conn->app_data, (*m)->size);
- if (tmp == NULL) {
- failf (data, "realloc %u failed", (*m)->size);
- return -1;
- }
- conn->app_data = tmp;
-
- if((*m)->init && (*(*m)->init)(conn->app_data) != 0) {
- infof(data, "Skipping %s...\n", (*m)->name);
- continue;
- }
- infof(data, "Trying %s...\n", (*m)->name);
-
- if(Curl_ftpsendf(conn, "AUTH %s", (*m)->name))
- return -1;
-
- if(Curl_GetFTPResponse(&nread, conn, &ftpcode))
- return -1;
-
- if(conn->data->state.buffer[0] != '3'){
- switch(ftpcode) {
- case 504:
- infof(data,
- "%s is not supported by the server.\n", (*m)->name);
- break;
- case 534:
- infof(data, "%s rejected as security mechanism.\n", (*m)->name);
- break;
- default:
- if(conn->data->state.buffer[0] == '5') {
- infof(data, "The server doesn't support the FTP "
- "security extensions.\n");
- return -1;
- }
- break;
- }
- continue;
- }
-
- ret = (*(*m)->auth)(conn->app_data, conn);
-
- if(ret == AUTH_CONTINUE)
- continue;
- else if(ret != AUTH_OK){
- /* mechanism is supposed to output error string */
- return -1;
- }
- conn->mech = *m;
- conn->sec_complete = 1;
- conn->command_prot = prot_safe;
- break;
- }
-
- return *m == NULL;
-}
-
-void
-Curl_sec_end(struct connectdata *conn)
-{
- if (conn->mech != NULL) {
- if(conn->mech->end)
- (conn->mech->end)(conn->app_data);
- memset(conn->app_data, 0, conn->mech->size);
- free(conn->app_data);
- conn->app_data = NULL;
- }
- conn->sec_complete = 0;
- conn->data_prot = (enum protection_level)0;
- conn->mech=NULL;
-}
-
-#endif /* HAVE_KRB4 */
-#endif /* CURL_DISABLE_FTP */
diff --git a/Utilities/cmcurl/select.c b/Utilities/cmcurl/select.c
deleted file mode 100644
index 51adbcf37..000000000
--- a/Utilities/cmcurl/select.c
+++ /dev/null
@@ -1,315 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <errno.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-
-#ifndef HAVE_SELECT
-#error "We can't compile without select() support!"
-#endif
-
-#if defined(__BEOS__) && !defined(__HAIKU__)
-/* BeOS has FD_SET defined in socket.h */
-#include <socket.h>
-#endif
-
-#ifdef __MSDOS__
-#include <dos.h> /* delay() */
-#endif
-
-#include <curl/curl.h>
-
-#include "urldata.h"
-#include "connect.h"
-#include "select.h"
-
-#if defined(USE_WINSOCK) || defined(TPF)
-#define VERIFY_SOCK(x) /* sockets are not in range [0..FD_SETSIZE] */
-#else
-#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
-#define VERIFY_SOCK(x) do { \
- if(!VALID_SOCK(x)) { \
- errno = EINVAL; \
- return -1; \
- } \
-} while(0)
-#endif
-
-/*
- * This is an internal function used for waiting for read or write
- * events on single file descriptors. It attempts to replace select()
- * in order to avoid limits with FD_SETSIZE.
- *
- * Return values:
- * -1 = system call error
- * 0 = timeout
- * CSELECT_IN | CSELECT_OUT | CSELECT_ERR
- */
-int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms)
-{
-#if (defined(HAVE_POLL) && !defined(_POLL_EMUL_H_)) || defined(CURL_HAVE_WSAPOLL)
- struct pollfd pfd[2];
- int num;
- int r;
- int ret;
-
- num = 0;
- if (readfd != CURL_SOCKET_BAD) {
- pfd[num].fd = readfd;
- pfd[num].events = POLLIN;
- num++;
- }
- if (writefd != CURL_SOCKET_BAD) {
- pfd[num].fd = writefd;
- pfd[num].events = POLLOUT;
- num++;
- }
-
-#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_)
- do {
- r = poll(pfd, num, timeout_ms);
- } while((r == -1) && (errno == EINTR));
-#else
- r = WSAPoll(pfd, num, timeout_ms);
-#endif
-
- if (r < 0)
- return -1;
- if (r == 0)
- return 0;
-
- ret = 0;
- num = 0;
- if (readfd != CURL_SOCKET_BAD) {
- if (pfd[num].revents & (POLLIN|POLLHUP))
- ret |= CSELECT_IN;
- if (pfd[num].revents & POLLERR) {
-#ifdef __CYGWIN__
- /* Cygwin 1.5.21 needs this hack to pass test 160 */
- if (errno == EINPROGRESS)
- ret |= CSELECT_IN;
- else
-#endif
- ret |= CSELECT_ERR;
- }
- num++;
- }
- if (writefd != CURL_SOCKET_BAD) {
- if (pfd[num].revents & POLLOUT)
- ret |= CSELECT_OUT;
- if (pfd[num].revents & (POLLERR|POLLHUP))
- ret |= CSELECT_ERR;
- }
-
- return ret;
-#else
- struct timeval timeout;
- fd_set fds_read;
- fd_set fds_write;
- fd_set fds_err;
- curl_socket_t maxfd;
- int r;
- int ret;
-
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
-
- if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) {
- /* According to POSIX we should pass in NULL pointers if we don't want to
- wait for anything in particular but just use the timeout function.
- Windows however returns immediately if done so. I copied the MSDOS
- delay() use from src/main.c that already had this work-around. */
-#ifdef WIN32
- Sleep(timeout_ms);
-#elif defined(__MSDOS__)
- delay(timeout_ms);
-#else
- select(0, NULL, NULL, NULL, &timeout);
-#endif
- return 0;
- }
-
- FD_ZERO(&fds_err);
- maxfd = (curl_socket_t)-1;
-
- FD_ZERO(&fds_read);
- if (readfd != CURL_SOCKET_BAD) {
- VERIFY_SOCK(readfd);
- FD_SET(readfd, &fds_read);
- FD_SET(readfd, &fds_err);
- maxfd = readfd;
- }
-
- FD_ZERO(&fds_write);
- if (writefd != CURL_SOCKET_BAD) {
- VERIFY_SOCK(writefd);
- FD_SET(writefd, &fds_write);
- FD_SET(writefd, &fds_err);
- if (writefd > maxfd)
- maxfd = writefd;
- }
-
- do {
- r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, &timeout);
- } while((r == -1) && (Curl_sockerrno() == EINTR));
-
- if (r < 0)
- return -1;
- if (r == 0)
- return 0;
-
- ret = 0;
- if (readfd != CURL_SOCKET_BAD) {
- if (FD_ISSET(readfd, &fds_read))
- ret |= CSELECT_IN;
- if (FD_ISSET(readfd, &fds_err))
- ret |= CSELECT_ERR;
- }
- if (writefd != CURL_SOCKET_BAD) {
- if (FD_ISSET(writefd, &fds_write))
- ret |= CSELECT_OUT;
- if (FD_ISSET(writefd, &fds_err))
- ret |= CSELECT_ERR;
- }
-
- return ret;
-#endif
-}
-
-/*
- * This is a wrapper around poll(). If poll() does not exist, then
- * select() is used instead. An error is returned if select() is
- * being used and a file descriptor too large for FD_SETSIZE.
- *
- * Return values:
- * -1 = system call error or fd >= FD_SETSIZE
- * 0 = timeout
- * 1 = number of structures with non zero revent fields
- */
-int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
-{
- int r;
-#if defined(HAVE_POLL) && !defined(_POLL_EMUL_H_)
- do {
- r = poll(ufds, nfds, timeout_ms);
- } while((r == -1) && (errno == EINTR));
-#elif defined(CURL_HAVE_WSAPOLL)
- r = WSAPoll(ufds, nfds, timeout_ms);
-#else
- struct timeval timeout;
- struct timeval *ptimeout;
- fd_set fds_read;
- fd_set fds_write;
- fd_set fds_err;
- curl_socket_t maxfd;
- unsigned int i;
-
- FD_ZERO(&fds_read);
- FD_ZERO(&fds_write);
- FD_ZERO(&fds_err);
- maxfd = (curl_socket_t)-1;
-
- for (i = 0; i < nfds; i++) {
- if (ufds[i].fd == CURL_SOCKET_BAD)
- continue;
-#ifndef USE_WINSOCK /* winsock sockets are not in range [0..FD_SETSIZE] */
- if (ufds[i].fd >= FD_SETSIZE) {
- errno = EINVAL;
- return -1;
- }
-#endif
- if (ufds[i].fd > maxfd)
- maxfd = ufds[i].fd;
- if (ufds[i].events & POLLIN)
- FD_SET(ufds[i].fd, &fds_read);
- if (ufds[i].events & POLLOUT)
- FD_SET(ufds[i].fd, &fds_write);
- if (ufds[i].events & POLLERR)
- FD_SET(ufds[i].fd, &fds_err);
- }
-
- if (timeout_ms < 0) {
- ptimeout = NULL; /* wait forever */
- } else {
- timeout.tv_sec = timeout_ms / 1000;
- timeout.tv_usec = (timeout_ms % 1000) * 1000;
- ptimeout = &timeout;
- }
-
- do {
- r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
- } while((r == -1) && (Curl_sockerrno() == EINTR));
-
- if (r < 0)
- return -1;
- if (r == 0)
- return 0;
-
- r = 0;
- for (i = 0; i < nfds; i++) {
- ufds[i].revents = 0;
- if (ufds[i].fd == CURL_SOCKET_BAD)
- continue;
- if (FD_ISSET(ufds[i].fd, &fds_read))
- ufds[i].revents |= POLLIN;
- if (FD_ISSET(ufds[i].fd, &fds_write))
- ufds[i].revents |= POLLOUT;
- if (FD_ISSET(ufds[i].fd, &fds_err))
- ufds[i].revents |= POLLERR;
- if (ufds[i].revents != 0)
- r++;
- }
-#endif
- return r;
-}
-
-#ifdef TPF
-/*
- * This is a replacement for select() on the TPF platform.
- * It is used whenever libcurl calls select().
- * The call below to tpf_process_signals() is required because
- * TPF's select calls are not signal interruptible.
- *
- * Return values are the same as select's.
- */
-int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
- fd_set* excepts, struct timeval* tv)
-{
- int rc;
-
- rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
- tpf_process_signals();
- return(rc);
-}
-#endif /* TPF */
diff --git a/Utilities/cmcurl/select.h b/Utilities/cmcurl/select.h
deleted file mode 100644
index 7573b1f54..000000000
--- a/Utilities/cmcurl/select.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __SELECT_H
-#define __SELECT_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifdef HAVE_SYS_POLL_H
-#include <sys/poll.h>
-#else
-#ifndef POLLIN
-#define POLLIN 0x01
-#define POLLPRI 0x02
-#define POLLOUT 0x04
-#define POLLERR 0x08
-#define POLLHUP 0x10
-#define POLLNVAL 0x20
-
-struct pollfd
-{
- curl_socket_t fd;
- short events;
- short revents;
-};
-#endif
-
-#endif
-
-#define CSELECT_IN 0x01
-#define CSELECT_OUT 0x02
-#define CSELECT_ERR 0x04
-
-int Curl_select(curl_socket_t readfd, curl_socket_t writefd, int timeout_ms);
-
-int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
-
-#ifdef TPF
-int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
- fd_set* excepts, struct timeval* tv);
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/sendf.c b/Utilities/cmcurl/sendf.c
deleted file mode 100644
index 500bf66f0..000000000
--- a/Utilities/cmcurl/sendf.c
+++ /dev/null
@@ -1,663 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h> /* required for send() & recv() prototypes */
-#endif
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "connect.h" /* for the Curl_sockerrno() proto */
-#include "sslgen.h"
-#include "ssh.h"
-#include "multiif.h"
-
-#define _MPRINTF_REPLACE /* use the internal *printf() functions */
-#include <curl/mprintf.h>
-
-#ifdef HAVE_KRB4
-#include "krb4.h"
-#else
-#define Curl_sec_send(a,b,c,d) -1
-#define Curl_sec_read(a,b,c,d) -1
-#endif
-
-#include <string.h>
-#include "memory.h"
-#include "strerror.h"
-#include "easyif.h" /* for the Curl_convert_from_network prototype */
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* returns last node in linked list */
-static struct curl_slist *slist_get_last(struct curl_slist *list)
-{
- struct curl_slist *item;
-
- /* if caller passed us a NULL, return now */
- if (!list)
- return NULL;
-
- /* loop through to find the last item */
- item = list;
- while (item->next) {
- item = item->next;
- }
- return item;
-}
-
-/*
- * curl_slist_append() appends a string to the linked list. It always retunrs
- * the address of the first record, so that you can sure this function as an
- * initialization function as well as an append function. If you find this
- * bothersome, then simply create a separate _init function and call it
- * appropriately from within the proram.
- */
-struct curl_slist *curl_slist_append(struct curl_slist *list,
- const char *data)
-{
- struct curl_slist *last;
- struct curl_slist *new_item;
-
- new_item = (struct curl_slist *) malloc(sizeof(struct curl_slist));
- if (new_item) {
- char *dup = strdup(data);
- if(dup) {
- new_item->next = NULL;
- new_item->data = dup;
- }
- else {
- free(new_item);
- return NULL;
- }
- }
- else
- return NULL;
-
- if (list) {
- last = slist_get_last(list);
- last->next = new_item;
- return list;
- }
-
- /* if this is the first item, then new_item *is* the list */
- return new_item;
-}
-
-/* be nice and clean up resources */
-void curl_slist_free_all(struct curl_slist *list)
-{
- struct curl_slist *next;
- struct curl_slist *item;
-
- if (!list)
- return;
-
- item = list;
- do {
- next = item->next;
-
- if (item->data) {
- free(item->data);
- }
- free(item);
- item = next;
- } while (next);
-}
-
-#ifdef CURL_DO_LINEEND_CONV
-/*
- * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
- * (\n), with special processing for CRLF sequences that are split between two
- * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
- * size of the data is returned.
- */
-static size_t convert_lineends(struct SessionHandle *data,
- char *startPtr, size_t size)
-{
- char *inPtr, *outPtr;
-
- /* sanity check */
- if ((startPtr == NULL) || (size < 1)) {
- return(size);
- }
-
- if (data->state.prev_block_had_trailing_cr == TRUE) {
- /* The previous block of incoming data
- had a trailing CR, which was turned into a LF. */
- if (*startPtr == '\n') {
- /* This block of incoming data starts with the
- previous block's LF so get rid of it */
- memcpy(startPtr, startPtr+1, size-1);
- size--;
- /* and it wasn't a bare CR but a CRLF conversion instead */
- data->state.crlf_conversions++;
- }
- data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
- }
-
- /* find 1st CR, if any */
- inPtr = outPtr = memchr(startPtr, '\r', size);
- if (inPtr) {
- /* at least one CR, now look for CRLF */
- while (inPtr < (startPtr+size-1)) {
- /* note that it's size-1, so we'll never look past the last byte */
- if (memcmp(inPtr, "\r\n", 2) == 0) {
- /* CRLF found, bump past the CR and copy the NL */
- inPtr++;
- *outPtr = *inPtr;
- /* keep track of how many CRLFs we converted */
- data->state.crlf_conversions++;
- }
- else {
- if (*inPtr == '\r') {
- /* lone CR, move LF instead */
- *outPtr = '\n';
- }
- else {
- /* not a CRLF nor a CR, just copy whatever it is */
- *outPtr = *inPtr;
- }
- }
- outPtr++;
- inPtr++;
- } /* end of while loop */
-
- if (inPtr < startPtr+size) {
- /* handle last byte */
- if (*inPtr == '\r') {
- /* deal with a CR at the end of the buffer */
- *outPtr = '\n'; /* copy a NL instead */
- /* note that a CRLF might be split across two blocks */
- data->state.prev_block_had_trailing_cr = TRUE;
- }
- else {
- /* copy last byte */
- *outPtr = *inPtr;
- }
- outPtr++;
- inPtr++;
- }
- if (outPtr < startPtr+size) {
- /* tidy up by null terminating the now shorter data */
- *outPtr = '\0';
- }
- return(outPtr - startPtr);
- }
- return(size);
-}
-#endif /* CURL_DO_LINEEND_CONV */
-
-/* Curl_infof() is for info message along the way */
-
-void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
-{
- if(data && data->set.verbose) {
- va_list ap;
- size_t len;
- char print_buffer[1024 + 1];
- va_start(ap, fmt);
- vsnprintf(print_buffer, 1024, fmt, ap);
- va_end(ap);
- len = strlen(print_buffer);
- Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
- }
-}
-
-/* Curl_failf() is for messages stating why we failed.
- * The message SHALL NOT include any LF or CR.
- */
-
-void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
-{
- va_list ap;
- size_t len;
- va_start(ap, fmt);
-
- vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
-
- if(data->set.errorbuffer && !data->state.errorbuf) {
- snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
- data->state.errorbuf = TRUE; /* wrote error string */
- }
- if(data->set.verbose) {
- len = strlen(data->state.buffer);
- if(len < BUFSIZE - 1) {
- data->state.buffer[len] = '\n';
- data->state.buffer[++len] = '\0';
- }
- Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
- }
-
- va_end(ap);
-}
-
-/* Curl_sendf() sends formated data to the server */
-CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
- const char *fmt, ...)
-{
- struct SessionHandle *data = conn->data;
- ssize_t bytes_written;
- size_t write_len;
- CURLcode res = CURLE_OK;
- char *s;
- char *sptr;
- va_list ap;
- va_start(ap, fmt);
- s = vaprintf(fmt, ap); /* returns an allocated string */
- va_end(ap);
- if(!s)
- return CURLE_OUT_OF_MEMORY; /* failure */
-
- bytes_written=0;
- write_len = strlen(s);
- sptr = s;
-
- while (1) {
- /* Write the buffer to the socket */
- res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
-
- if(CURLE_OK != res)
- break;
-
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
-
- if((size_t)bytes_written != write_len) {
- /* if not all was written at once, we must advance the pointer, decrease
- the size left and try again! */
- write_len -= bytes_written;
- sptr += bytes_written;
- }
- else
- break;
- }
-
- free(s); /* free the output string */
-
- return res;
-}
-
-static ssize_t Curl_plain_send(struct connectdata *conn,
- int num,
- void *mem,
- size_t len)
-{
- curl_socket_t sockfd = conn->sock[num];
- ssize_t bytes_written = swrite(sockfd, mem, len);
-
- if(-1 == bytes_written) {
- int err = Curl_sockerrno();
-
- if(
-#ifdef WSAEWOULDBLOCK
- /* This is how Windows does it */
- (WSAEWOULDBLOCK == err)
-#else
- /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
- due to its inability to send off data without blocking. We therefor
- treat both error codes the same here */
- (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
-#endif
- )
- /* this is just a case of EWOULDBLOCK */
- bytes_written=0;
- else
- failf(conn->data, "Send failure: %s",
- Curl_strerror(conn, err));
- }
- return bytes_written;
-}
-
-/*
- * Curl_write() is an internal write function that sends data to the
- * server. Works with plain sockets, SCP, SSL or kerberos.
- */
-CURLcode Curl_write(struct connectdata *conn,
- curl_socket_t sockfd,
- void *mem,
- size_t len,
- ssize_t *written)
-{
- ssize_t bytes_written;
- CURLcode retcode;
- int num = (sockfd == conn->sock[SECONDARYSOCKET]);
-
- if (conn->ssl[num].use)
- /* only TRUE if SSL enabled */
- bytes_written = Curl_ssl_send(conn, num, mem, len);
-#ifdef USE_LIBSSH2
- else if (conn->protocol & PROT_SCP)
- bytes_written = Curl_scp_send(conn, num, mem, len);
- else if (conn->protocol & PROT_SFTP)
- bytes_written = Curl_sftp_send(conn, num, mem, len);
-#endif /* !USE_LIBSSH2 */
- else if(conn->sec_complete)
- /* only TRUE if krb4 enabled */
- bytes_written = Curl_sec_send(conn, num, mem, len);
- else
- bytes_written = Curl_plain_send(conn, num, mem, len);
-
- *written = bytes_written;
- retcode = (-1 != bytes_written)?CURLE_OK:CURLE_SEND_ERROR;
-
- return retcode;
-}
-
-/* client_write() sends data to the write callback(s)
-
- The bit pattern defines to what "streams" to write to. Body and/or header.
- The defines are in sendf.h of course.
- */
-CURLcode Curl_client_write(struct connectdata *conn,
- int type,
- char *ptr,
- size_t len)
-{
- struct SessionHandle *data = conn->data;
- size_t wrote;
-
- if (data->state.cancelled) {
- /* We just suck everything into a black hole */
- return CURLE_OK;
- }
-
- if(0 == len)
- len = strlen(ptr);
-
- if(type & CLIENTWRITE_BODY) {
- if((conn->protocol&PROT_FTP) && conn->proto.ftpc.transfertype == 'A') {
-#ifdef CURL_DOES_CONVERSIONS
- /* convert from the network encoding */
- size_t rc;
- rc = Curl_convert_from_network(data, ptr, len);
- /* Curl_convert_from_network calls failf if unsuccessful */
- if(rc != CURLE_OK)
- return rc;
-#endif /* CURL_DOES_CONVERSIONS */
-
-#ifdef CURL_DO_LINEEND_CONV
- /* convert end-of-line markers */
- len = convert_lineends(data, ptr, len);
-#endif /* CURL_DO_LINEEND_CONV */
- }
- /* If the previous block of data ended with CR and this block of data is
- just a NL, then the length might be zero */
- if (len) {
- wrote = data->set.fwrite(ptr, 1, len, data->set.out);
- }
- else {
- wrote = len;
- }
-
- if(wrote != len) {
- failf (data, "Failed writing body");
- return CURLE_WRITE_ERROR;
- }
- }
-
- if((type & CLIENTWRITE_HEADER) &&
- (data->set.fwrite_header || data->set.writeheader) ) {
- /*
- * Write headers to the same callback or to the especially setup
- * header callback function (added after version 7.7.1).
- */
- curl_write_callback writeit=
- data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite;
-
- /* Note: The header is in the host encoding
- regardless of the ftp transfer mode (ASCII/Image) */
-
- wrote = writeit(ptr, 1, len, data->set.writeheader);
- if(wrote != len) {
- failf (data, "Failed writing header");
- return CURLE_WRITE_ERROR;
- }
- }
-
- return CURLE_OK;
-}
-
-#ifndef MIN
-#define MIN(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-/*
- * Internal read-from-socket function. This is meant to deal with plain
- * sockets, SSL sockets and kerberos sockets.
- *
- * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
- * a regular CURLcode value.
- */
-int Curl_read(struct connectdata *conn, /* connection data */
- curl_socket_t sockfd, /* read from this socket */
- char *buf, /* store read data here */
- size_t sizerequested, /* max amount to read */
- ssize_t *n) /* amount bytes read */
-{
- ssize_t nread;
- size_t bytesfromsocket = 0;
- char *buffertofill = NULL;
- bool pipelining = (bool)(conn->data->multi &&
- Curl_multi_canPipeline(conn->data->multi));
-
- /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
- If it is the second socket, we set num to 1. Otherwise to 0. This lets
- us use the correct ssl handle. */
- int num = (sockfd == conn->sock[SECONDARYSOCKET]);
-
- *n=0; /* reset amount to zero */
-
- /* If session can pipeline, check connection buffer */
- if(pipelining) {
- size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
-
- /* Copy from our master buffer first if we have some unread data there*/
- if (bytestocopy > 0) {
- memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
- conn->read_pos += bytestocopy;
- conn->bits.stream_was_rewound = FALSE;
-
- *n = (ssize_t)bytestocopy;
- return CURLE_OK;
- }
- /* If we come here, it means that there is no data to read from the buffer,
- * so we read from the socket */
- bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));
- buffertofill = conn->master_buffer;
- }
- else {
- bytesfromsocket = MIN((long)sizerequested, conn->data->set.buffer_size ?
- conn->data->set.buffer_size : BUFSIZE);
- buffertofill = buf;
- }
-
- if(conn->ssl[num].use) {
- nread = Curl_ssl_recv(conn, num, buffertofill, bytesfromsocket);
-
- if(nread == -1) {
- return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
- }
- }
-#ifdef USE_LIBSSH2
- else if (conn->protocol & PROT_SCP) {
- nread = Curl_scp_recv(conn, num, buffertofill, bytesfromsocket);
- /* TODO: return CURLE_OK also for nread <= 0
- read failures and timeouts ? */
- }
- else if (conn->protocol & PROT_SFTP) {
- nread = Curl_sftp_recv(conn, num, buffertofill, bytesfromsocket);
- }
-#endif /* !USE_LIBSSH2 */
- else {
- if(conn->sec_complete)
- nread = Curl_sec_read(conn, sockfd, buffertofill,
- bytesfromsocket);
- else
- nread = sread(sockfd, buffertofill, bytesfromsocket);
-
- if(-1 == nread) {
- int err = Curl_sockerrno();
-#ifdef USE_WINSOCK
- if(WSAEWOULDBLOCK == err)
-#else
- if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
-#endif
- return -1;
- }
- }
-
- if (nread >= 0) {
- if(pipelining) {
- memcpy(buf, conn->master_buffer, nread);
- conn->buf_len = nread;
- conn->read_pos = nread;
- }
-
- *n += nread;
- }
-
- return CURLE_OK;
-}
-
-/* return 0 on success */
-static int showit(struct SessionHandle *data, curl_infotype type,
- char *ptr, size_t size)
-{
- static const char * const s_infotype[CURLINFO_END] = {
- "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
-
-#ifdef CURL_DOES_CONVERSIONS
- char buf[BUFSIZE+1];
- size_t conv_size = 0;
-
- switch(type) {
- case CURLINFO_HEADER_OUT:
- /* assume output headers are ASCII */
- /* copy the data into my buffer so the original is unchanged */
- if (size > BUFSIZE) {
- size = BUFSIZE; /* truncate if necessary */
- buf[BUFSIZE] = '\0';
- }
- conv_size = size;
- memcpy(buf, ptr, size);
- /* Special processing is needed for this block if it
- * contains both headers and data (separated by CRLFCRLF).
- * We want to convert just the headers, leaving the data as-is.
- */
- if(size > 4) {
- size_t i;
- for(i = 0; i < size-4; i++) {
- if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
- /* convert everthing through this CRLFCRLF but no further */
- conv_size = i + 4;
- break;
- }
- }
- }
-
- Curl_convert_from_network(data, buf, conv_size);
- /* Curl_convert_from_network calls failf if unsuccessful */
- /* we might as well continue even if it fails... */
- ptr = buf; /* switch pointer to use my buffer instead */
- break;
- default:
- /* leave everything else as-is */
- break;
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(data->set.fdebug)
- return (*data->set.fdebug)(data, type, ptr, size,
- data->set.debugdata);
-
- switch(type) {
- case CURLINFO_TEXT:
- case CURLINFO_HEADER_OUT:
- case CURLINFO_HEADER_IN:
- fwrite(s_infotype[type], 2, 1, data->set.err);
- fwrite(ptr, size, 1, data->set.err);
-#ifdef CURL_DOES_CONVERSIONS
- if(size != conv_size) {
- /* we had untranslated data so we need an explicit newline */
- fwrite("\n", 1, 1, data->set.err);
- }
-#endif
- break;
- default: /* nada */
- break;
- }
- return 0;
-}
-
-int Curl_debug(struct SessionHandle *data, curl_infotype type,
- char *ptr, size_t size,
- struct connectdata *conn)
-{
- int rc;
- if(data->set.printhost && conn && conn->host.dispname) {
- char buffer[160];
- const char *t=NULL;
- const char *w="Data";
- switch (type) {
- case CURLINFO_HEADER_IN:
- w = "Header";
- case CURLINFO_DATA_IN:
- t = "from";
- break;
- case CURLINFO_HEADER_OUT:
- w = "Header";
- case CURLINFO_DATA_OUT:
- t = "to";
- break;
- default:
- break;
- }
-
- if(t) {
- snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
- conn->host.dispname);
- rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
- if(rc)
- return rc;
- }
- }
- rc = showit(data, type, ptr, size);
- return rc;
-}
diff --git a/Utilities/cmcurl/sendf.h b/Utilities/cmcurl/sendf.h
deleted file mode 100644
index 7877df823..000000000
--- a/Utilities/cmcurl/sendf.h
+++ /dev/null
@@ -1,72 +0,0 @@
-#ifndef __SENDF_H
-#define __SENDF_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
- const char *fmt, ...);
-void Curl_infof(struct SessionHandle *, const char *fmt, ...);
-void Curl_failf(struct SessionHandle *, const char *fmt, ...);
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
-#if defined(__GNUC__)
-/* This style of variable argument macros is a gcc extension */
-#define infof(x...) /*ignore*/
-#else
-/* C99 compilers could use this if we could detect them */
-/*#define infof(...) */
-/* Cast the args to void to make them a noop, side effects notwithstanding */
-#define infof (void)
-#endif
-#else
-#define infof Curl_infof
-#endif
-#define failf Curl_failf
-
-#define CLIENTWRITE_BODY 1
-#define CLIENTWRITE_HEADER 2
-#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
-
-CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
- size_t len);
-
-void Curl_read_rewind(struct connectdata *conn,
- size_t extraBytesRead);
-
-/* internal read-function, does plain socket, SSL and krb4 */
-int Curl_read(struct connectdata *conn, curl_socket_t sockfd,
- char *buf, size_t buffersize,
- ssize_t *n);
-/* internal write-function, does plain socket, SSL and krb4 */
-CURLcode Curl_write(struct connectdata *conn,
- curl_socket_t sockfd,
- void *mem, size_t len,
- ssize_t *written);
-
-/* the function used to output verbose information */
-int Curl_debug(struct SessionHandle *handle, curl_infotype type,
- char *data, size_t size,
- struct connectdata *conn);
-
-
-#endif
diff --git a/Utilities/cmcurl/setup.h b/Utilities/cmcurl/setup.h
deleted file mode 100644
index 5ae881fba..000000000
--- a/Utilities/cmcurl/setup.h
+++ /dev/null
@@ -1,390 +0,0 @@
-#ifndef __LIB_CURL_SETUP_H
-#define __LIB_CURL_SETUP_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifdef HTTP_ONLY
-#define CURL_DISABLE_TFTP
-#define CURL_DISABLE_FTP
-#define CURL_DISABLE_LDAP
-#define CURL_DISABLE_TELNET
-#define CURL_DISABLE_DICT
-#define CURL_DISABLE_FILE
-#endif /* HTTP_ONLY */
-
-#if !defined(WIN32) && defined(__WIN32__)
-/* Borland fix */
-#define WIN32
-#endif
-
-#if !defined(WIN32) && defined(_WIN32)
-/* VS2005 on x64 fix */
-#define WIN32
-#endif
-
-#if defined(__clang__)
-# pragma clang diagnostic ignored "-Wcast-align"
-#endif
-
-/*
- * Include configuration script results or hand-crafted
- * configuration file for platforms which lack config tool.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#else
-
-/*
-#ifdef _WIN32_WCE
-#include "config-win32ce.h"
-#else
-#ifdef WIN32
-#include "config-win32.h"
-#endif
-#endif
-*/
-
-#ifdef macintosh
-#include "config-mac.h"
-#endif
-
-#ifdef AMIGA
-#include "amigaos.h"
-#endif
-
-#ifdef TPF
-#include "config-tpf.h" /* hand-modified TPF config.h */
-/* change which select is used for libcurl */
-#define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
-#endif
-
-#endif /* HAVE_CONFIG_H */
-
-/*
- * Include header files for windows builds before redefining anything.
- * Use this preproessor block only to include or exclude windows.h,
- * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
- * to any other further and independant block. Under Cygwin things work
- * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
- * never be included when __CYGWIN__ is defined. configure script takes
- * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
- * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
- */
-
-#ifdef HAVE_WINDOWS_H
-# ifndef WIN32_LEAN_AND_MEAN
-# define WIN32_LEAN_AND_MEAN
-# endif
-# include <windows.h>
-# ifdef HAVE_WINSOCK2_H
-# include <winsock2.h>
-# ifdef HAVE_WS2TCPIP_H
-# include <ws2tcpip.h>
-# endif
-# else
-# ifdef HAVE_WINSOCK_H
-# include <winsock.h>
-# endif
-# endif
-#endif
-
-/*
- * Define USE_WINSOCK to 2 if we have and use WINSOCK2 API, else
- * define USE_WINSOCK to 1 if we have and use WINSOCK API, else
- * undefine USE_WINSOCK.
- */
-
-#undef USE_WINSOCK
-
-#ifdef HAVE_WINSOCK2_H
-# define USE_WINSOCK 2
-#else
-# ifdef HAVE_WINSOCK_H
-# define USE_WINSOCK 1
-# endif
-#endif
-
-
-#ifndef TRUE
-#define TRUE 1
-#endif
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-#if !defined(__cplusplus) && !defined(__BEOS__) && !defined(__ECOS) && !defined(typedef_bool)
-typedef unsigned char bool;
-#define typedef_bool
-#endif
-
-#ifdef HAVE_LONGLONG
-#define LONG_LONG long long
-#define ENABLE_64BIT
-#else
-#ifdef _MSC_VER
-#define LONG_LONG __int64
-#define ENABLE_64BIT
-#endif /* _MSC_VER */
-#endif /* HAVE_LONGLONG */
-
-#ifndef SIZEOF_CURL_OFF_T
-/* If we don't know the size here, we assume a conservative size: 4. When
- building libcurl, the actual size of this variable should be define in the
- config*.h file. */
-#define SIZEOF_CURL_OFF_T 4
-#endif
-
-/* We set up our internal preferred (CURL_)FORMAT_OFF_T here */
-#if SIZEOF_CURL_OFF_T > 4
-#define FORMAT_OFF_T "lld"
-#else
-#define FORMAT_OFF_T "ld"
-#endif /* SIZEOF_CURL_OFF_T */
-
-#ifndef _REENTRANT
-/* Solaris needs _REENTRANT set for a few function prototypes and things to
- appear in the #include files. We need to #define it before all #include
- files. Unixware needs it to build proper reentrant code. Others may also
- need it. */
-#define _REENTRANT
-#endif
-
-#include <stdio.h>
-#ifdef HAVE_ASSERT_H
-#include <assert.h>
-#endif
-#include <errno.h>
-
-#ifdef __TANDEM /* for nsr-tandem-nsk systems */
-#include <floss.h>
-#endif
-
-#ifndef STDC_HEADERS /* no standard C headers! */
-#include <curl/stdcheaders.h>
-#endif
-
-/*
- * PellesC cludge section (yikes);
- * - It has 'ssize_t', but it is in <unistd.h>. The way the headers
- * on Win32 are included, forces me to include this header here.
- * - sys_nerr, EINTR is missing in v4.0 or older.
- */
-#ifdef __POCC__
- #include <sys/types.h>
- #include <unistd.h>
- #if (__POCC__ <= 400)
- #define sys_nerr EILSEQ /* for strerror.c */
- #define EINTR -1 /* for select.c */
- #endif
-#endif
-
-/*
- * Salford-C cludge section (mostly borrowed from wxWidgets).
- */
-#ifdef __SALFORDC__
- #pragma suppress 353 /* Possible nested comments */
- #pragma suppress 593 /* Define not used */
- #pragma suppress 61 /* enum has no name */
- #pragma suppress 106 /* unnamed, unused parameter */
- #include <clib.h>
-#endif
-
-#if defined(CURLDEBUG) && defined(HAVE_ASSERT_H)
-#define curlassert(x) assert(x)
-#else
-/* does nothing without CURLDEBUG defined */
-#define curlassert(x)
-#endif
-
-
-/* To make large file support transparent even on Windows */
-#if defined(WIN32) && (SIZEOF_CURL_OFF_T > 4)
-#include <sys/stat.h> /* must come first before we redefine stat() */
-#include <io.h>
-#define lseek(x,y,z) _lseeki64(x, y, z)
-#define struct_stat struct _stati64
-#define stat(file,st) _stati64(file,st)
-#define fstat(fd,st) _fstati64(fd,st)
-#else
-#define struct_stat struct stat
-#endif /* Win32 with large file support */
-
-
-/* Below we define some functions. They should
- 1. close a socket
-
- 4. set the SIGALRM signal timeout
- 5. set dir/file naming defines
- */
-
-#ifdef WIN32
-
-#if !defined(__CYGWIN__)
-#define sclose(x) closesocket(x)
-
-#undef HAVE_ALARM
-#else
- /* gcc-for-win is still good :) */
-#define sclose(x) close(x)
-#define HAVE_ALARM
-#endif /* !GNU or mingw */
-
-#define DIR_CHAR "\\"
-#define DOT_CHAR "_"
-
-#else /* WIN32 */
-
-#ifdef MSDOS /* Watt-32 */
-#include <sys/ioctl.h>
-#define sclose(x) close_s(x)
-#define select(n,r,w,x,t) select_s(n,r,w,x,t)
-#define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
-#define IOCTL_3_ARGS
-#include <tcp.h>
-#ifdef word
-#undef word
-#endif
-
-#else /* MSDOS */
-
-#ifdef __VMS
-#define IOCTL_3_ARGS 1
-#endif
-
-#ifdef __BEOS__
-#define sclose(x) closesocket(x)
-#else /* __BEOS__ */
-#define sclose(x) close(x)
-#endif /* __BEOS__ */
-
-#define HAVE_ALARM
-
-#endif /* MSDOS */
-
-#ifdef _AMIGASF
-#undef HAVE_ALARM
-#undef sclose
-#define sclose(x) CloseSocket(x)
-#endif
-
-#define DIR_CHAR "/"
-#ifndef DOT_CHAR
-#define DOT_CHAR "."
-#endif
-
-#ifdef MSDOS
-#undef DOT_CHAR
-#define DOT_CHAR "_"
-#endif
-
-#ifndef fileno /* sunos 4 have this as a macro! */
-int fileno( FILE *stream);
-#endif
-
-#endif /* WIN32 */
-
-#if defined(WIN32) && !defined(__CYGWIN__) && !defined(USE_ARES) && \
- !defined(__LCC__) /* lcc-win32 doesn't have _beginthreadex() */
-#ifdef ENABLE_IPV6
-#define USE_THREADING_GETADDRINFO
-#else
-#define USE_THREADING_GETHOSTBYNAME /* Cygwin uses alarm() function */
-#endif
-#endif
-
-/* "cl -ML" or "cl -MLd" implies a single-threaded runtime library where
- _beginthreadex() is not available */
-#if (defined(_MSC_VER) && !defined(__POCC__)) && !defined(_MT) && !defined(USE_ARES)
-#undef USE_THREADING_GETADDRINFO
-#undef USE_THREADING_GETHOSTBYNAME
-#define CURL_NO__BEGINTHREADEX
-#endif
-
-/*
- * msvc 6.0 does not have struct sockaddr_storage and
- * does not define IPPROTO_ESP in winsock2.h. But both
- * are available if PSDK is properly installed.
- */
-
-#ifdef _MSC_VER
-#if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
-#undef HAVE_STRUCT_SOCKADDR_STORAGE
-#endif
-#endif
-
-#ifdef mpeix
-#define IOCTL_3_ARGS
-#endif
-
-#ifdef NETWARE
-#undef HAVE_ALARM
-#endif
-
-#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H)
-/* The lib was present and the tld.h header (which is missing in libidn 0.3.X
- but we only work with libidn 0.4.1 or later) */
-#define USE_LIBIDN
-#endif
-
-#ifndef SIZEOF_TIME_T
-/* assume default size of time_t to be 32 bit */
-#define SIZEOF_TIME_T 4
-#endif
-
-#define LIBIDN_REQUIRED_VERSION "0.4.1"
-
-#ifdef __UCLIBC__
-#define HAVE_INET_NTOA_R_2_ARGS 1
-#endif
-
-#if defined(USE_GNUTLS) || defined(USE_SSLEAY)
-#define USE_SSL /* Either OpenSSL || GnuTLS */
-#endif
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
-#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI)
-#define USE_NTLM
-#endif
-#endif
-
-#ifdef CURLDEBUG
-#define DEBUGF(x) x
-#else
-#define DEBUGF(x)
-#endif
-
-/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
-#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
-#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
-#endif
-
-/*
- * Include macros and defines that should only be processed once.
- */
-
-#ifndef __SETUP_ONCE_H
-#include "setup_once.h"
-#endif
-
-#endif /* __LIB_CURL_SETUP_H */
diff --git a/Utilities/cmcurl/setup_once.h b/Utilities/cmcurl/setup_once.h
deleted file mode 100644
index ee6864158..000000000
--- a/Utilities/cmcurl/setup_once.h
+++ /dev/null
@@ -1,153 +0,0 @@
-#ifndef __SETUP_ONCE_H
-#define __SETUP_ONCE_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-
-/********************************************************************
- * NOTICE *
- * ======== *
- * *
- * Content of header files lib/setup_once.h and ares/setup_once.h *
- * must be kept in sync. Modify the other one if you change this. *
- * *
- ********************************************************************/
-
-
-/*
- * If we have the MSG_NOSIGNAL define, make sure we use
- * it as the fourth argument of function send()
- */
-
-#ifdef HAVE_MSG_NOSIGNAL
-#define SEND_4TH_ARG MSG_NOSIGNAL
-#else
-#define SEND_4TH_ARG 0
-#endif
-
-
-/*
- * The definitions for the return type and arguments types
- * of functions recv() and send() belong and come from the
- * configuration file. Do not define them in any other place.
- *
- * HAVE_RECV is defined if you have a function named recv()
- * which is used to read incoming data from sockets. If your
- * function has another name then don't define HAVE_RECV.
- *
- * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
- * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
- * be defined.
- *
- * HAVE_SEND is defined if you have a function named send()
- * which is used to write outgoing data on a connected socket.
- * If yours has another name then don't define HAVE_SEND.
- *
- * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
- * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
- * SEND_TYPE_RETV must also be defined.
- */
-
-#ifdef HAVE_RECV
-#if !defined(RECV_TYPE_ARG1) || \
- !defined(RECV_TYPE_ARG2) || \
- !defined(RECV_TYPE_ARG3) || \
- !defined(RECV_TYPE_ARG4) || \
- !defined(RECV_TYPE_RETV)
- /* */
- Error Missing_definition_of_return_and_arguments_types_of_recv
- /* */
-#else
-#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
- (RECV_TYPE_ARG2)(y), \
- (RECV_TYPE_ARG3)(z), \
- (RECV_TYPE_ARG4)(0))
-#endif
-#else /* HAVE_RECV */
-#ifndef sread
- /* */
- Error Missing_definition_of_macro_sread
- /* */
-#endif
-#endif /* HAVE_RECV */
-
-#ifdef HAVE_SEND
-#if !defined(SEND_TYPE_ARG1) || \
- !defined(SEND_QUAL_ARG2) || \
- !defined(SEND_TYPE_ARG2) || \
- !defined(SEND_TYPE_ARG3) || \
- !defined(SEND_TYPE_ARG4) || \
- !defined(SEND_TYPE_RETV)
- /* */
- Error Missing_definition_of_return_and_arguments_types_of_send
- /* */
-#else
-#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
- (SEND_TYPE_ARG2)(y), \
- (SEND_TYPE_ARG3)(z), \
- (SEND_TYPE_ARG4)(SEND_4TH_ARG))
-#endif
-#else /* HAVE_SEND */
-#ifndef swrite
- /* */
- Error Missing_definition_of_macro_swrite
- /* */
-#endif
-#endif /* HAVE_SEND */
-
-
-/*
- * Uppercase macro versions of ANSI/ISO is*() functions/macros which
- * avoid negative number inputs with argument byte codes > 127.
- */
-
-#define ISSPACE(x) (isspace((int) ((unsigned char)x)))
-#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
-#define ISALNUM(x) (isalnum((int) ((unsigned char)x)))
-#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
-#define ISGRAPH(x) (isgraph((int) ((unsigned char)x)))
-#define ISALPHA(x) (isalpha((int) ((unsigned char)x)))
-#define ISPRINT(x) (isprint((int) ((unsigned char)x)))
-
-
-/*
- * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
- */
-
-#ifndef HAVE_SIG_ATOMIC_T
-typedef int sig_atomic_t;
-#define HAVE_SIG_ATOMIC_T
-#endif
-
-
-/*
- * Default return type for signal handlers.
- */
-
-#ifndef RETSIGTYPE
-#define RETSIGTYPE void
-#endif
-
-
-#endif /* __SETUP_ONCE_H */
-
diff --git a/Utilities/cmcurl/share.c b/Utilities/cmcurl/share.c
deleted file mode 100644
index de13b6021..000000000
--- a/Utilities/cmcurl/share.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <curl/curl.h>
-#include "urldata.h"
-#include "share.h"
-#include "memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-CURLSH *
-curl_share_init(void)
-{
- struct Curl_share *share =
- (struct Curl_share *)malloc(sizeof(struct Curl_share));
- if (share) {
- memset (share, 0, sizeof(struct Curl_share));
- share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
- }
-
- return share;
-}
-
-CURLSHcode
-curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
-{
- struct Curl_share *share = (struct Curl_share *)sh;
- va_list param;
- int type;
- curl_lock_function lockfunc;
- curl_unlock_function unlockfunc;
- void *ptr;
-
- if (share->dirty)
- /* don't allow setting options while one or more handles are already
- using this share */
- return CURLSHE_IN_USE;
-
- va_start(param, option);
-
- switch(option) {
- case CURLSHOPT_SHARE:
- /* this is a type this share will share */
- type = va_arg(param, int);
- share->specifier |= (1<<type);
- switch( type ) {
- case CURL_LOCK_DATA_DNS:
- if (!share->hostcache) {
- share->hostcache = Curl_mk_dnscache();
- if(!share->hostcache)
- return CURLSHE_NOMEM;
- }
- break;
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- case CURL_LOCK_DATA_COOKIE:
- if (!share->cookies) {
- share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
- if(!share->cookies)
- return CURLSHE_NOMEM;
- }
- break;
-#endif /* CURL_DISABLE_HTTP */
-
- case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */
- case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
-
- default:
- return CURLSHE_BAD_OPTION;
- }
- break;
-
- case CURLSHOPT_UNSHARE:
- /* this is a type this share will no longer share */
- type = va_arg(param, int);
- share->specifier &= ~(1<<type);
- switch( type )
- {
- case CURL_LOCK_DATA_DNS:
- if (share->hostcache) {
- Curl_hash_destroy(share->hostcache);
- share->hostcache = NULL;
- }
- break;
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- case CURL_LOCK_DATA_COOKIE:
- if (share->cookies) {
- Curl_cookie_cleanup(share->cookies);
- share->cookies = NULL;
- }
- break;
-#endif /* CURL_DISABLE_HTTP */
-
- case CURL_LOCK_DATA_SSL_SESSION:
- break;
-
- case CURL_LOCK_DATA_CONNECT:
- break;
-
- default:
- return CURLSHE_BAD_OPTION;
- }
- break;
-
- case CURLSHOPT_LOCKFUNC:
- lockfunc = va_arg(param, curl_lock_function);
- share->lockfunc = lockfunc;
- break;
-
- case CURLSHOPT_UNLOCKFUNC:
- unlockfunc = va_arg(param, curl_unlock_function);
- share->unlockfunc = unlockfunc;
- break;
-
- case CURLSHOPT_USERDATA:
- ptr = va_arg(param, void *);
- share->clientdata = ptr;
- break;
-
- default:
- return CURLSHE_BAD_OPTION;
- }
-
- return CURLSHE_OK;
-}
-
-CURLSHcode
-curl_share_cleanup(CURLSH *sh)
-{
- struct Curl_share *share = (struct Curl_share *)sh;
-
- if (share == NULL)
- return CURLSHE_INVALID;
-
- if(share->lockfunc)
- share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
- share->clientdata);
-
- if (share->dirty) {
- if(share->unlockfunc)
- share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
- return CURLSHE_IN_USE;
- }
-
- if(share->hostcache)
- Curl_hash_destroy(share->hostcache);
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- if(share->cookies)
- Curl_cookie_cleanup(share->cookies);
-#endif /* CURL_DISABLE_HTTP */
-
- if(share->unlockfunc)
- share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
- free(share);
-
- return CURLSHE_OK;
-}
-
-
-CURLSHcode
-Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
- curl_lock_access accesstype)
-{
- struct Curl_share *share = data->share;
-
- if (share == NULL)
- return CURLSHE_INVALID;
-
- if(share->specifier & (1<<type)) {
- if(share->lockfunc) /* only call this if set! */
- share->lockfunc(data, type, accesstype, share->clientdata);
- }
- /* else if we don't share this, pretend successful lock */
-
- return CURLSHE_OK;
-}
-
-CURLSHcode
-Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
-{
- struct Curl_share *share = data->share;
-
- if (share == NULL)
- return CURLSHE_INVALID;
-
- if(share->specifier & (1<<type)) {
- if(share->unlockfunc) /* only call this if set! */
- share->unlockfunc (data, type, share->clientdata);
- }
-
- return CURLSHE_OK;
-}
diff --git a/Utilities/cmcurl/share.h b/Utilities/cmcurl/share.h
deleted file mode 100644
index 5cfe8c792..000000000
--- a/Utilities/cmcurl/share.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __CURL_SHARE_H
-#define __CURL_SHARE_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include <curl/curl.h>
-#include "cookie.h"
-
-/* SalfordC says "A structure member may not be volatile". Hence:
- */
-#ifdef __SALFORDC__
-#define CURL_VOLATILE
-#else
-#define CURL_VOLATILE volatile
-#endif
-
-/* this struct is libcurl-private, don't export details */
-struct Curl_share {
- unsigned int specifier;
- CURL_VOLATILE unsigned int dirty;
-
- curl_lock_function lockfunc;
- curl_unlock_function unlockfunc;
- void *clientdata;
-
- struct curl_hash *hostcache;
- struct CookieInfo *cookies;
-};
-
-CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data,
- curl_lock_access);
-CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data);
-
-#endif /* __CURL_SHARE_H */
diff --git a/Utilities/cmcurl/sockaddr.h b/Utilities/cmcurl/sockaddr.h
deleted file mode 100644
index 78dad4d9e..000000000
--- a/Utilities/cmcurl/sockaddr.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __SOCKADDR_H
-#define __SOCKADDR_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
-struct Curl_sockaddr_storage {
- struct sockaddr_storage buffer;
-};
-#else
-struct Curl_sockaddr_storage {
- char buffer[256]; /* this should be big enough to fit a lot */
-};
-#endif
-
-#endif /* __SOCKADDR_H */
diff --git a/Utilities/cmcurl/socks.c b/Utilities/cmcurl/socks.c
deleted file mode 100644
index e0e947b80..000000000
--- a/Utilities/cmcurl/socks.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "strequal.h"
-#include "select.h"
-#include "connect.h"
-#include "timeval.h"
-#include "socks.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/*
- * Helper read-from-socket functions. Does the same as Curl_read() but it
- * blocks until all bytes amount of buffersize will be read. No more, no less.
- *
- * This is STUPID BLOCKING behaviour which we frown upon, but right now this
- * is what we have...
- */
-static int blockread_all(struct connectdata *conn, /* connection data */
- curl_socket_t sockfd, /* read from this socket */
- char *buf, /* store read data here */
- ssize_t buffersize, /* max amount to read */
- ssize_t *n, /* amount bytes read */
- long conn_timeout) /* timeout for data wait
- relative to
- conn->created */
-{
- ssize_t nread;
- ssize_t allread = 0;
- int result;
- struct timeval tvnow;
- long conntime;
- *n = 0;
- do {
- tvnow = Curl_tvnow();
- /* calculating how long connection is establishing */
- conntime = Curl_tvdiff(tvnow, conn->created);
- if(conntime > conn_timeout) {
- /* we already got the timeout */
- result = ~CURLE_OK;
- break;
- }
- if(Curl_select(sockfd, CURL_SOCKET_BAD,
- (int)(conn_timeout - conntime)) <= 0) {
- result = ~CURLE_OK;
- break;
- }
- result = Curl_read(conn, sockfd, buf, buffersize, &nread);
- if(result)
- break;
-
- if(buffersize == nread) {
- allread += nread;
- *n = allread;
- result = CURLE_OK;
- break;
- }
- buffersize -= nread;
- buf += nread;
- allread += nread;
- } while(1);
- return result;
-}
-
-/*
-* This function logs in to a SOCKS4 proxy and sends the specifics to the final
-* destination server.
-*
-* Reference :
-* http://socks.permeo.com/protocol/socks4.protocol
-*
-* Note :
-* Nonsupport "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
-* Nonsupport "Identification Protocol (RFC1413)"
-*/
-CURLcode Curl_SOCKS4(const char *proxy_name,
- struct connectdata *conn)
-{
- unsigned char socksreq[262]; /* room for SOCKS4 request incl. user id */
- int result;
- CURLcode code;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- long timeout;
- struct SessionHandle *data = conn->data;
-
- /* get timeout */
- if(data->set.timeout && data->set.connecttimeout) {
- if (data->set.timeout < data->set.connecttimeout)
- timeout = data->set.timeout*1000;
- else
- timeout = data->set.connecttimeout*1000;
- }
- else if(data->set.timeout)
- timeout = data->set.timeout*1000;
- else if(data->set.connecttimeout)
- timeout = data->set.connecttimeout*1000;
- else
- timeout = DEFAULT_CONNECT_TIMEOUT;
-
- Curl_nonblock(sock, FALSE);
-
- /*
- * Compose socks4 request
- *
- * Request format
- *
- * +----+----+----+----+----+----+----+----+----+----+....+----+
- * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
- * +----+----+----+----+----+----+----+----+----+----+....+----+
- * # of bytes: 1 1 2 4 variable 1
- */
-
- socksreq[0] = 4; /* version (SOCKS4) */
- socksreq[1] = 1; /* connect */
- *((unsigned short*)&socksreq[2]) = htons(conn->remote_port);
-
- /* DNS resolve */
- {
- struct Curl_dns_entry *dns;
- Curl_addrinfo *hp=NULL;
- int rc;
-
- rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
-
- if(rc == CURLRESOLV_ERROR)
- return CURLE_COULDNT_RESOLVE_PROXY;
-
- if(rc == CURLRESOLV_PENDING)
- /* this requires that we're in "wait for resolve" state */
- rc = Curl_wait_for_resolv(conn, &dns);
-
- /*
- * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
- * returns a Curl_addrinfo pointer that may not always look the same.
- */
- if(dns)
- hp=dns->addr;
- if (hp) {
- char buf[64];
- unsigned short ip[4];
- Curl_printable_address(hp, buf, sizeof(buf));
-
- if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
- &ip[0], &ip[1], &ip[2], &ip[3])) {
- /* Set DSTIP */
- socksreq[4] = (unsigned char)ip[0];
- socksreq[5] = (unsigned char)ip[1];
- socksreq[6] = (unsigned char)ip[2];
- socksreq[7] = (unsigned char)ip[3];
- }
- else
- hp = NULL; /* fail! */
-
- Curl_resolv_unlock(data, dns); /* not used anymore from now on */
-
- }
- if(!hp) {
- failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
- conn->host.name);
- return CURLE_COULDNT_RESOLVE_HOST;
- }
- }
-
- /*
- * This is currently not supporting "Identification Protocol (RFC1413)".
- */
- socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
- if(proxy_name) {
- size_t plen = strlen(proxy_name);
- if(plen >= sizeof(socksreq) - 8) {
- failf(data, "Too long SOCKS proxy name, can't use!\n");
- return CURLE_COULDNT_CONNECT;
- }
- /* copy the proxy name WITH trailing zero */
- memcpy(socksreq + 8, proxy_name, plen+1);
- }
-
- /*
- * Make connection
- */
- {
- ssize_t actualread;
- ssize_t written;
- int packetsize = 9 +
- (int)strlen((char*)socksreq + 8); /* size including NUL */
-
- /* Send request */
- code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
- if ((code != CURLE_OK) || (written != packetsize)) {
- failf(data, "Failed to send SOCKS4 connect request.");
- return CURLE_COULDNT_CONNECT;
- }
-
- packetsize = 8; /* receive data size */
-
- /* Receive response */
- result = blockread_all(conn, sock, (char *)socksreq, packetsize,
- &actualread, timeout);
- if ((result != CURLE_OK) || (actualread != packetsize)) {
- failf(data, "Failed to receive SOCKS4 connect request ack.");
- return CURLE_COULDNT_CONNECT;
- }
-
- /*
- * Response format
- *
- * +----+----+----+----+----+----+----+----+
- * | VN | CD | DSTPORT | DSTIP |
- * +----+----+----+----+----+----+----+----+
- * # of bytes: 1 1 2 4
- *
- * VN is the version of the reply code and should be 0. CD is the result
- * code with one of the following values:
- *
- * 90: request granted
- * 91: request rejected or failed
- * 92: request rejected because SOCKS server cannot connect to
- * identd on the client
- * 93: request rejected because the client program and identd
- * report different user-ids
- */
-
- /* wrong version ? */
- if (socksreq[0] != 0) {
- failf(data,
- "SOCKS4 reply has wrong version, version should be 4.");
- return CURLE_COULDNT_CONNECT;
- }
-
- /* Result */
- switch(socksreq[1])
- {
- case 90:
- infof(data, "SOCKS4 request granted.\n");
- break;
- case 91:
- failf(data,
- "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
- ", request rejected or failed.",
- (unsigned char)socksreq[4], (unsigned char)socksreq[5],
- (unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
- socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- case 92:
- failf(data,
- "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
- ", request rejected because SOCKS server cannot connect to "
- "identd on the client.",
- (unsigned char)socksreq[4], (unsigned char)socksreq[5],
- (unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
- socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- case 93:
- failf(data,
- "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
- ", request rejected because the client program and identd "
- "report different user-ids.",
- (unsigned char)socksreq[4], (unsigned char)socksreq[5],
- (unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
- socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- default:
- failf(data,
- "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
- ", Unknown.",
- (unsigned char)socksreq[4], (unsigned char)socksreq[5],
- (unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
- socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- }
- }
-
- Curl_nonblock(sock, TRUE);
-
- return CURLE_OK; /* Proxy was successful! */
-}
-
-/*
- * This function logs in to a SOCKS5 proxy and sends the specifics to the final
- * destination server.
- */
-CURLcode Curl_SOCKS5(const char *proxy_name,
- const char *proxy_password,
- struct connectdata *conn)
-{
- /*
- According to the RFC1928, section "6. Replies". This is what a SOCK5
- replies:
-
- +----+-----+-------+------+----------+----------+
- |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
- +----+-----+-------+------+----------+----------+
- | 1 | 1 | X'00' | 1 | Variable | 2 |
- +----+-----+-------+------+----------+----------+
-
- Where:
-
- o VER protocol version: X'05'
- o REP Reply field:
- o X'00' succeeded
- */
-
- unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
- ssize_t actualread;
- ssize_t written;
- int result;
- CURLcode code;
- curl_socket_t sock = conn->sock[FIRSTSOCKET];
- struct SessionHandle *data = conn->data;
- long timeout;
-
- /* get timeout */
- if(data->set.timeout && data->set.connecttimeout) {
- if (data->set.timeout < data->set.connecttimeout)
- timeout = data->set.timeout*1000;
- else
- timeout = data->set.connecttimeout*1000;
- }
- else if(data->set.timeout)
- timeout = data->set.timeout*1000;
- else if(data->set.connecttimeout)
- timeout = data->set.connecttimeout*1000;
- else
- timeout = DEFAULT_CONNECT_TIMEOUT;
-
- Curl_nonblock(sock, TRUE);
-
- /* wait until socket gets connected */
- result = Curl_select(CURL_SOCKET_BAD, sock, (int)timeout);
-
- if(-1 == result) {
- failf(conn->data, "SOCKS5: no connection here");
- return CURLE_COULDNT_CONNECT;
- }
- else if(0 == result) {
- failf(conn->data, "SOCKS5: connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- if(result & CSELECT_ERR) {
- failf(conn->data, "SOCKS5: error occured during connection");
- return CURLE_COULDNT_CONNECT;
- }
-
- socksreq[0] = 5; /* version */
- socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
- socksreq[2] = 0; /* no authentication */
- socksreq[3] = 2; /* username/password */
-
- Curl_nonblock(sock, FALSE);
-
- code = Curl_write(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
- &written);
- if ((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
- failf(data, "Unable to send initial SOCKS5 request.");
- return CURLE_COULDNT_CONNECT;
- }
-
- Curl_nonblock(sock, TRUE);
-
- result = Curl_select(sock, CURL_SOCKET_BAD, (int)timeout);
-
- if(-1 == result) {
- failf(conn->data, "SOCKS5 nothing to read");
- return CURLE_COULDNT_CONNECT;
- }
- else if(0 == result) {
- failf(conn->data, "SOCKS5 read timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
-
- if(result & CSELECT_ERR) {
- failf(conn->data, "SOCKS5 read error occured");
- return CURLE_RECV_ERROR;
- }
-
- Curl_nonblock(sock, FALSE);
-
- result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread, timeout);
- if ((result != CURLE_OK) || (actualread != 2)) {
- failf(data, "Unable to receive initial SOCKS5 response.");
- return CURLE_COULDNT_CONNECT;
- }
-
- if (socksreq[0] != 5) {
- failf(data, "Received invalid version in initial SOCKS5 response.");
- return CURLE_COULDNT_CONNECT;
- }
- if (socksreq[1] == 0) {
- /* Nothing to do, no authentication needed */
- ;
- }
- else if (socksreq[1] == 2) {
- /* Needs user name and password */
- size_t userlen, pwlen;
- int len;
- if(proxy_name && proxy_password) {
- userlen = strlen(proxy_name);
- pwlen = proxy_password?strlen(proxy_password):0;
- }
- else {
- userlen = 0;
- pwlen = 0;
- }
-
- /* username/password request looks like
- * +----+------+----------+------+----------+
- * |VER | ULEN | UNAME | PLEN | PASSWD |
- * +----+------+----------+------+----------+
- * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
- * +----+------+----------+------+----------+
- */
- len = 0;
- socksreq[len++] = 1; /* username/pw subnegotiation version */
- socksreq[len++] = (char) userlen;
- memcpy(socksreq + len, proxy_name, (int) userlen);
- len += userlen;
- socksreq[len++] = (char) pwlen;
- memcpy(socksreq + len, proxy_password, (int) pwlen);
- len += pwlen;
-
- code = Curl_write(conn, sock, (char *)socksreq, len, &written);
- if ((code != CURLE_OK) || (len != written)) {
- failf(data, "Failed to send SOCKS5 sub-negotiation request.");
- return CURLE_COULDNT_CONNECT;
- }
-
- result=blockread_all(conn, sock, (char *)socksreq, 2, &actualread,
- timeout);
- if ((result != CURLE_OK) || (actualread != 2)) {
- failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
- return CURLE_COULDNT_CONNECT;
- }
-
- /* ignore the first (VER) byte */
- if (socksreq[1] != 0) { /* status */
- failf(data, "User was rejected by the SOCKS5 server (%d %d).",
- socksreq[0], socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- }
-
- /* Everything is good so far, user was authenticated! */
- }
- else {
- /* error */
- if (socksreq[1] == 1) {
- failf(data,
- "SOCKS5 GSSAPI per-message authentication is not supported.");
- return CURLE_COULDNT_CONNECT;
- }
- else if (socksreq[1] == 255) {
- if (!proxy_name || !*proxy_name) {
- failf(data,
- "No authentication method was acceptable. (It is quite likely"
- " that the SOCKS5 server wanted a username/password, since none"
- " was supplied to the server on this connection.)");
- }
- else {
- failf(data, "No authentication method was acceptable.");
- }
- return CURLE_COULDNT_CONNECT;
- }
- else {
- failf(data,
- "Undocumented SOCKS5 mode attempted to be used by server.");
- return CURLE_COULDNT_CONNECT;
- }
- }
-
- /* Authentication is complete, now specify destination to the proxy */
- socksreq[0] = 5; /* version (SOCKS5) */
- socksreq[1] = 1; /* connect */
- socksreq[2] = 0; /* must be zero */
- socksreq[3] = 1; /* IPv4 = 1 */
-
- {
- struct Curl_dns_entry *dns;
- Curl_addrinfo *hp=NULL;
- int rc = Curl_resolv(conn, conn->host.name, (int)conn->remote_port, &dns);
-
- if(rc == CURLRESOLV_ERROR)
- return CURLE_COULDNT_RESOLVE_HOST;
-
- if(rc == CURLRESOLV_PENDING)
- /* this requires that we're in "wait for resolve" state */
- rc = Curl_wait_for_resolv(conn, &dns);
-
- /*
- * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
- * returns a Curl_addrinfo pointer that may not always look the same.
- */
- if(dns)
- hp=dns->addr;
- if (hp) {
- char buf[64];
- unsigned short ip[4];
- Curl_printable_address(hp, buf, sizeof(buf));
-
- if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
- &ip[0], &ip[1], &ip[2], &ip[3])) {
- socksreq[4] = (unsigned char)ip[0];
- socksreq[5] = (unsigned char)ip[1];
- socksreq[6] = (unsigned char)ip[2];
- socksreq[7] = (unsigned char)ip[3];
- }
- else
- hp = NULL; /* fail! */
-
- Curl_resolv_unlock(data, dns); /* not used anymore from now on */
- }
- if(!hp) {
- failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
- conn->host.name);
- return CURLE_COULDNT_RESOLVE_HOST;
- }
- }
-
- *((unsigned short*)&socksreq[8]) = htons(conn->remote_port);
-
- {
- const int packetsize = 10;
-
- code = Curl_write(conn, sock, (char *)socksreq, packetsize, &written);
- if ((code != CURLE_OK) || (written != packetsize)) {
- failf(data, "Failed to send SOCKS5 connect request.");
- return CURLE_COULDNT_CONNECT;
- }
-
- result = blockread_all(conn, sock, (char *)socksreq, packetsize,
- &actualread, timeout);
- if ((result != CURLE_OK) || (actualread != packetsize)) {
- failf(data, "Failed to receive SOCKS5 connect request ack.");
- return CURLE_COULDNT_CONNECT;
- }
-
- if (socksreq[0] != 5) { /* version */
- failf(data,
- "SOCKS5 reply has wrong version, version should be 5.");
- return CURLE_COULDNT_CONNECT;
- }
- if (socksreq[1] != 0) { /* Anything besides 0 is an error */
- failf(data,
- "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
- (unsigned char)socksreq[4], (unsigned char)socksreq[5],
- (unsigned char)socksreq[6], (unsigned char)socksreq[7],
- (unsigned int)ntohs(*(unsigned short*)(&socksreq[8])),
- socksreq[1]);
- return CURLE_COULDNT_CONNECT;
- }
- }
-
- Curl_nonblock(sock, TRUE);
- return CURLE_OK; /* Proxy was successful! */
-}
diff --git a/Utilities/cmcurl/socks.h b/Utilities/cmcurl/socks.h
deleted file mode 100644
index 0da987998..000000000
--- a/Utilities/cmcurl/socks.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#ifndef __SOCKS_H
-#define __SOCKS_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * This function logs in to a SOCKS4 proxy and sends the specifics to the
- * final destination server.
- */
-CURLcode Curl_SOCKS4(const char *proxy_name,
- struct connectdata *conn);
-
-/*
- * This function logs in to a SOCKS5 proxy and sends the specifics to the
- * final destination server.
- */
-CURLcode Curl_SOCKS5(const char *proxy_name,
- const char *proxy_password,
- struct connectdata *conn);
-
-#endif
diff --git a/Utilities/cmcurl/speedcheck.c b/Utilities/cmcurl/speedcheck.c
deleted file mode 100644
index adda8a963..000000000
--- a/Utilities/cmcurl/speedcheck.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "multiif.h"
-#include "speedcheck.h"
-
-void Curl_speedinit(struct SessionHandle *data)
-{
- memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
-}
-
-CURLcode Curl_speedcheck(struct SessionHandle *data,
- struct timeval now)
-{
- if((data->progress.current_speed >= 0) &&
- data->set.low_speed_time &&
- (Curl_tvlong(data->state.keeps_speed) != 0) &&
- (data->progress.current_speed < data->set.low_speed_limit)) {
- long howlong = Curl_tvdiff(now, data->state.keeps_speed);
-
- /* We are now below the "low speed limit". If we are below it
- for "low speed time" seconds we consider that enough reason
- to abort the download. */
-
- if( (howlong/1000) > data->set.low_speed_time) {
- /* we have been this slow for long enough, now die */
- failf(data,
- "Operation too slow. "
- "Less than %d bytes/sec transfered the last %d seconds",
- data->set.low_speed_limit,
- data->set.low_speed_time);
- return CURLE_OPERATION_TIMEOUTED;
- }
- Curl_expire(data, howlong);
- }
- else {
- /* we keep up the required speed all right */
- data->state.keeps_speed = now;
-
- if(data->set.low_speed_limit)
- /* if there is a low speed limit enabled, we set the expire timer to
- make this connection's speed get checked again no later than when
- this time is up */
- Curl_expire(data, data->set.low_speed_time*1000);
- }
- return CURLE_OK;
-}
diff --git a/Utilities/cmcurl/speedcheck.h b/Utilities/cmcurl/speedcheck.h
deleted file mode 100644
index 62475f640..000000000
--- a/Utilities/cmcurl/speedcheck.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __SPEEDCHECK_H
-#define __SPEEDCHECK_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include "timeval.h"
-
-void Curl_speedinit(struct SessionHandle *data);
-CURLcode Curl_speedcheck(struct SessionHandle *data,
- struct timeval now);
-
-#endif
diff --git a/Utilities/cmcurl/splay.c b/Utilities/cmcurl/splay.c
deleted file mode 100644
index 9fb66c76a..000000000
--- a/Utilities/cmcurl/splay.c
+++ /dev/null
@@ -1,425 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1997 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "splay.h"
-
-#define compare(i,j) ((i)-(j))
-
-/* Set this to a key value that will *NEVER* appear otherwise */
-#define KEY_NOTUSED -1
-
-/*
- * Splay using the key i (which may or may not be in the tree.) The starting
- * root is t.
- */
-struct Curl_tree *Curl_splay(int i, struct Curl_tree *t)
-{
- struct Curl_tree N, *l, *r, *y;
- int comp;
-
- if (t == NULL)
- return t;
- N.smaller = N.larger = NULL;
- l = r = &N;
-
- for (;;) {
- comp = compare(i, t->key);
- if (comp < 0) {
- if (t->smaller == NULL)
- break;
- if (compare(i, t->smaller->key) < 0) {
- y = t->smaller; /* rotate smaller */
- t->smaller = y->larger;
- y->larger = t;
- t = y;
- if (t->smaller == NULL)
- break;
- }
- r->smaller = t; /* link smaller */
- r = t;
- t = t->smaller;
- }
- else if (comp > 0) {
- if (t->larger == NULL)
- break;
- if (compare(i, t->larger->key) > 0) {
- y = t->larger; /* rotate larger */
- t->larger = y->smaller;
- y->smaller = t;
- t = y;
- if (t->larger == NULL)
- break;
- }
- l->larger = t; /* link larger */
- l = t;
- t = t->larger;
- }
- else
- break;
- }
-
- l->larger = t->smaller; /* assemble */
- r->smaller = t->larger;
- t->smaller = N.larger;
- t->larger = N.smaller;
-
- return t;
-}
-
-/* Insert key i into the tree t. Return a pointer to the resulting tree or
- NULL if something went wrong. */
-struct Curl_tree *Curl_splayinsert(int i,
- struct Curl_tree *t,
- struct Curl_tree *node)
-{
- if (node == NULL)
- return t;
-
- if (t != NULL) {
- t = Curl_splay(i,t);
- if (compare(i, t->key)==0) {
- /* There already exists a node in the tree with the very same key. Build
- a linked list of nodes. We make the new 'node' struct the new master
- node and make the previous node the first one in the 'same' list. */
-
- node->same = t;
- node->key = i;
- node->smaller = t->smaller;
- node->larger = t->larger;
-
- t->smaller = node; /* in the sub node for this same key, we use the
- smaller pointer to point back to the master
- node */
-
- t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
- to quickly identify this node as a subnode */
-
- return node; /* new root node */
- }
- }
-
- if (t == NULL) {
- node->smaller = node->larger = NULL;
- }
- else if (compare(i, t->key) < 0) {
- node->smaller = t->smaller;
- node->larger = t;
- t->smaller = NULL;
-
- }
- else {
- node->larger = t->larger;
- node->smaller = t;
- t->larger = NULL;
- }
- node->key = i;
-
- node->same = NULL; /* no identical node (yet) */
- return node;
-}
-
-#if 0
-/* Deletes 'i' from the tree if it's there (with an exact match). Returns a
- pointer to the resulting tree.
-
- Function not used in libcurl.
-*/
-struct Curl_tree *Curl_splayremove(int i, struct Curl_tree *t,
- struct Curl_tree **removed)
-{
- struct Curl_tree *x;
-
- *removed = NULL; /* default to no removed */
-
- if (t==NULL)
- return NULL;
-
- t = Curl_splay(i,t);
- if (compare(i, t->key) == 0) { /* found it */
-
- /* FIRST! Check if there is a list with identical sizes */
- if((x = t->same)) {
- /* there is, pick one from the list */
-
- /* 'x' is the new root node */
-
- x->key = t->key;
- x->larger = t->larger;
- x->smaller = t->smaller;
-
- *removed = t;
- return x; /* new root */
- }
-
- if (t->smaller == NULL) {
- x = t->larger;
- }
- else {
- x = Curl_splay(i, t->smaller);
- x->larger = t->larger;
- }
- *removed = t;
-
- return x;
- }
- else
- return t; /* It wasn't there */
-}
-#endif
-
-/* Finds and deletes the best-fit node from the tree. Return a pointer to the
- resulting tree. best-fit means the node with the given or lower number */
-struct Curl_tree *Curl_splaygetbest(int i, struct Curl_tree *t,
- struct Curl_tree **removed)
-{
- struct Curl_tree *x;
-
- if (!t) {
- *removed = NULL; /* none removed since there was no root */
- return NULL;
- }
-
- t = Curl_splay(i,t);
- if(compare(i, t->key) < 0) {
- /* too big node, try the smaller chain */
- if(t->smaller)
- t=Curl_splay(t->smaller->key, t);
- else {
- /* fail */
- *removed = NULL;
- return t;
- }
- }
-
- if (compare(i, t->key) >= 0) { /* found it */
- /* FIRST! Check if there is a list with identical sizes */
- x = t->same;
- if(x) {
- /* there is, pick one from the list */
-
- /* 'x' is the new root node */
-
- x->key = t->key;
- x->larger = t->larger;
- x->smaller = t->smaller;
-
- *removed = t;
- return x; /* new root */
- }
-
- if (t->smaller == NULL) {
- x = t->larger;
- }
- else {
- x = Curl_splay(i, t->smaller);
- x->larger = t->larger;
- }
- *removed = t;
-
- return x;
- }
- else {
- *removed = NULL; /* no match */
- return t; /* It wasn't there */
- }
-}
-
-
-/* Deletes the very node we point out from the tree if it's there. Stores a
- pointer to the new resulting tree in 'newroot'.
-
- Returns zero on success and non-zero on errors! TODO: document error codes.
- When returning error, it does not touch the 'newroot' pointer.
-
- NOTE: when the last node of the tree is removed, there's no tree left so
- 'newroot' will be made to point to NULL.
-*/
-int Curl_splayremovebyaddr(struct Curl_tree *t,
- struct Curl_tree *remove,
- struct Curl_tree **newroot)
-{
- struct Curl_tree *x;
-
- if (!t || !remove)
- return 1;
-
- if(KEY_NOTUSED == remove->key) {
- /* Key set to NOTUSED means it is a subnode within a 'same' linked list
- and thus we can unlink it easily. The 'smaller' link of a subnode
- links to the parent node. */
- if (remove->smaller == NULL)
- return 3;
-
- remove->smaller->same = remove->same;
- if(remove->same)
- remove->same->smaller = remove->smaller;
-
- /* Ensures that double-remove gets caught. */
- remove->smaller = NULL;
-
- /* voila, we're done! */
- *newroot = t; /* return the same root */
- return 0;
- }
-
- t = Curl_splay(remove->key, t);
-
- /* First make sure that we got the same root node as the one we want
- to remove, as otherwise we might be trying to remove a node that
- isn't actually in the tree.
-
- We cannot just compare the keys here as a double remove in quick
- succession of a node with key != KEY_NOTUSED && same != NULL
- could return the same key but a different node. */
- if(t != remove)
- return 2;
-
- /* Check if there is a list with identical sizes, as then we're trying to
- remove the root node of a list of nodes with identical keys. */
- x = t->same;
- if(x) {
- /* 'x' is the new root node, we just make it use the root node's
- smaller/larger links */
-
- x->key = t->key;
- x->larger = t->larger;
- x->smaller = t->smaller;
- }
- else {
- /* Remove the root node */
- if (t->smaller == NULL)
- x = t->larger;
- else {
- x = Curl_splay(remove->key, t->smaller);
- x->larger = t->larger;
- }
- }
-
- *newroot = x; /* store new root pointer */
-
- return 0;
-}
-
-#ifdef CURLDEBUG
-
-void Curl_splayprint(struct Curl_tree * t, int d, char output)
-{
- struct Curl_tree *node;
- int i;
- int count;
- if (t == NULL)
- return;
-
- Curl_splayprint(t->larger, d+1, output);
- for (i=0; i<d; i++)
- if(output)
- printf(" ");
-
- if(output) {
- printf("%d[%d]", t->key, i);
- }
-
- for(count=0, node = t->same; node; node = node->same, count++)
- ;
-
- if(output) {
- if(count)
- printf(" [%d more]\n", count);
- else
- printf("\n");
- }
-
- Curl_splayprint(t->smaller, d+1, output);
-}
-#endif
-
-#ifdef TEST_SPLAY
-
-/*#define TEST2 */
-#define MAX 50
-#define TEST2
-
-/* A sample use of these functions. Start with the empty tree, insert some
- stuff into it, and then delete it */
-int main(int argc, char **argv)
-{
- struct Curl_tree *root, *t;
- void *ptrs[MAX];
- int adds=0;
- int rc;
-
- long sizes[]={
- 50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300,
- 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200,
- 300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120,
- 200, 300, 220, 80, 90};
- int i;
- root = NULL; /* the empty tree */
-
- for (i = 0; i < MAX; i++) {
- int key;
- ptrs[i] = t = (struct Curl_tree *)malloc(sizeof(struct Curl_tree));
-
-#ifdef TEST2
- key = sizes[i];
-#elif defined(TEST1)
- key = (541*i)%1023;
-#elif defined(TEST3)
- key = 100;
-#endif
-
- t->payload = (void *)key; /* for simplicity */
- if(!t) {
- puts("out of memory!");
- return 0;
- }
- root = Curl_splayinsert(key, root, t);
- }
-
-#if 0
- puts("Result:");
- Curl_splayprint(root, 0, 1);
-#endif
-
-#if 1
- for (i = 0; i < MAX; i++) {
- int rem = (i+7)%MAX;
- struct Curl_tree *r;
- printf("Tree look:\n");
- Curl_splayprint(root, 0, 1);
- printf("remove pointer %d, payload %d\n", rem,
- (int)((struct Curl_tree *)ptrs[rem])->payload);
- rc = Curl_splayremovebyaddr(root, (struct Curl_tree *)ptrs[rem], &root);
- if(rc)
- /* failed! */
- printf("remove %d failed!\n", rem);
- }
-#endif
-
- return 0;
-}
-
-#endif /* TEST_SPLAY */
diff --git a/Utilities/cmcurl/splay.h b/Utilities/cmcurl/splay.h
deleted file mode 100644
index 16745341e..000000000
--- a/Utilities/cmcurl/splay.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef __SPLAY_H
-#define __SPLAY_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1997 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-struct Curl_tree {
- struct Curl_tree *smaller; /* smaller node */
- struct Curl_tree *larger; /* larger node */
- struct Curl_tree *same; /* points to a node with identical key */
- int key; /* the "sort" key */
- void *payload; /* data the splay code doesn't care about */
-};
-
-struct Curl_tree *Curl_splay(int i, struct Curl_tree *t);
-struct Curl_tree *Curl_splayinsert(int key, struct Curl_tree *t,
- struct Curl_tree *newnode);
-#if 0
-struct Curl_tree *Curl_splayremove(int key, struct Curl_tree *t,
- struct Curl_tree **removed);
-#endif
-
-struct Curl_tree *Curl_splaygetbest(int key, struct Curl_tree *t,
- struct Curl_tree **removed);
-int Curl_splayremovebyaddr(struct Curl_tree *t,
- struct Curl_tree *remove,
- struct Curl_tree **newroot);
-
-#ifdef CURLDEBUG
-void Curl_splayprint(struct Curl_tree * t, int d, char output);
-#else
-#define Curl_splayprint(x,y,z)
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/ssh.c b/Utilities/cmcurl/ssh.c
deleted file mode 100644
index 24cba1bac..000000000
--- a/Utilities/cmcurl/ssh.c
+++ /dev/null
@@ -1,979 +0,0 @@
-/***************************************************************************
-* _ _ ____ _
-* Project ___| | | | _ \| |
-* / __| | | | |_) | |
-* | (__| |_| | _ <| |___
-* \___|\___/|_| \_\_____|
-*
-* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
-*
-* This software is licensed as described in the file COPYING, which
-* you should have received as part of this distribution. The terms
-* are also available at http://curl.haxx.se/docs/copyright.html.
-*
-* You may opt to use, copy, modify, merge, publish, distribute and/or sell
-* copies of the Software, and permit persons to whom the Software is
-* furnished to do so, under the terms of the COPYING file.
-*
-* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-* KIND, either express or implied.
-*
-* $Id$
-***************************************************************************/
-
-/* #define CURL_LIBSSH2_DEBUG */
-
-#include "setup.h"
-
-#ifdef USE_LIBSSH2
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <limits.h>
-
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-#ifdef HAVE_FCNTL_H
-#include <fcntl.h>
-#endif
-
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-
-#ifdef WIN32
-
-#else /* probably some kind of unix */
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <sys/types.h>
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#endif
-#endif
-
-#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
-#undef in_addr_t
-#define in_addr_t unsigned long
-#endif
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sendf.h"
-#include "easyif.h" /* for Curl_convert_... prototypes */
-
-#include "if2ip.h"
-#include "hostip.h"
-#include "progress.h"
-#include "transfer.h"
-#include "escape.h"
-#include "http.h" /* for HTTP proxy tunnel stuff */
-#include "ssh.h"
-#include "url.h"
-#include "speedcheck.h"
-#include "getinfo.h"
-
-#include "strtoofft.h"
-#include "strequal.h"
-#include "sslgen.h"
-#include "connect.h"
-#include "strerror.h"
-#include "memory.h"
-#include "inet_ntop.h"
-#include "select.h"
-#include "parsedate.h" /* for the week day and month names */
-#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "multiif.h"
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(WIN32) || defined(MSDOS) || defined(__EMX__)
-#define DIRSEP '\\'
-#else
-#define DIRSEP '/'
-#endif
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#ifdef CURLDEBUG
-#include "memdebug.h"
-#endif
-
-#ifndef LIBSSH2_SFTP_S_IRUSR
-/* Here's a work-around for those of you who happend to run a libssh2 version
- that is 0.14 or older. We should remove this kludge as soon as we can
- require a more recent libssh2 release. */
-#ifndef S_IRGRP
-#define S_IRGRP 0
-#endif
-
-#ifndef S_IROTH
-#define S_IROTH 0
-#endif
-
-#define LIBSSH2_SFTP_S_IRUSR S_IRUSR
-#define LIBSSH2_SFTP_S_IWUSR S_IWUSR
-#define LIBSSH2_SFTP_S_IRGRP S_IRGRP
-#define LIBSSH2_SFTP_S_IROTH S_IROTH
-#define LIBSSH2_SFTP_S_IRUSR S_IRUSR
-#define LIBSSH2_SFTP_S_IWUSR S_IWUSR
-#define LIBSSH2_SFTP_S_IRGRP S_IRGRP
-#define LIBSSH2_SFTP_S_IROTH S_IROTH
-#define LIBSSH2_SFTP_S_IFMT S_IFMT
-#define LIBSSH2_SFTP_S_IFDIR S_IFDIR
-#define LIBSSH2_SFTP_S_IFLNK S_IFLNK
-#define LIBSSH2_SFTP_S_IFSOCK S_IFSOCK
-#define LIBSSH2_SFTP_S_IFCHR S_IFCHR
-#define LIBSSH2_SFTP_S_IFBLK S_IFBLK
-#define LIBSSH2_SFTP_S_IXUSR S_IXUSR
-#define LIBSSH2_SFTP_S_IWGRP S_IWGRP
-#define LIBSSH2_SFTP_S_IXGRP S_IXGRP
-#define LIBSSH2_SFTP_S_IWOTH S_IWOTH
-#define LIBSSH2_SFTP_S_IXOTH S_IXOTH
-#endif
-
-static LIBSSH2_ALLOC_FUNC(libssh2_malloc);
-static LIBSSH2_REALLOC_FUNC(libssh2_realloc);
-static LIBSSH2_FREE_FUNC(libssh2_free);
-
-static void
-kbd_callback(const char *name, int name_len, const char *instruction,
- int instruction_len, int num_prompts,
- const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
- LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
- void **abstract)
-{
- struct SSHPROTO *ssh = (struct SSHPROTO *)*abstract;
-
-#ifdef CURL_LIBSSH2_DEBUG
- fprintf(stderr, "name=%s\n", name);
- fprintf(stderr, "name_len=%d\n", name_len);
- fprintf(stderr, "instruction=%s\n", instruction);
- fprintf(stderr, "instruction_len=%d\n", instruction_len);
- fprintf(stderr, "num_prompts=%d\n", num_prompts);
-#else
- (void)name;
- (void)name_len;
- (void)instruction;
- (void)instruction_len;
-#endif /* CURL_LIBSSH2_DEBUG */
- if (num_prompts == 1) {
- responses[0].text = strdup(ssh->passwd);
- responses[0].length = strlen(ssh->passwd);
- }
- (void)prompts;
- (void)abstract;
-} /* kbd_callback */
-
-static CURLcode libssh2_error_to_CURLE(struct connectdata *conn)
-{
- int errorcode;
- struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
-
- /* Get the libssh2 error code and string */
- errorcode = libssh2_session_last_error(scp->ssh_session, &scp->errorstr,
- NULL, 0);
- if (errorcode == LIBSSH2_FX_OK)
- return CURLE_OK;
-
- infof(conn->data, "libssh2 error %d, '%s'\n", errorcode, scp->errorstr);
-
- /* TODO: map some of the libssh2 errors to the more appropriate CURLcode
- error code, and possibly add a few new SSH-related one. We must however
- not return or even depend on libssh2 errors in the public libcurl API */
-
- return CURLE_SSH;
-}
-
-static LIBSSH2_ALLOC_FUNC(libssh2_malloc)
-{
- return malloc(count);
- (void)abstract;
-}
-
-static LIBSSH2_REALLOC_FUNC(libssh2_realloc)
-{
- return realloc(ptr, count);
- (void)abstract;
-}
-
-static LIBSSH2_FREE_FUNC(libssh2_free)
-{
- free(ptr);
- (void)abstract;
-}
-
-static CURLcode ssh_init(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- struct SSHPROTO *ssh;
- if (data->reqdata.proto.ssh)
- return CURLE_OK;
-
- ssh = (struct SSHPROTO *)calloc(sizeof(struct SSHPROTO), 1);
- if (!ssh)
- return CURLE_OUT_OF_MEMORY;
-
- data->reqdata.proto.ssh = ssh;
-
- /* get some initial data into the ssh struct */
- ssh->bytecountp = &data->reqdata.keep.bytecount;
-
- /* no need to duplicate them, this connectdata struct won't change */
- ssh->user = conn->user;
- ssh->passwd = conn->passwd;
-
- ssh->errorstr = NULL;
-
- ssh->ssh_session = NULL;
- ssh->ssh_channel = NULL;
- ssh->sftp_session = NULL;
- ssh->sftp_handle = NULL;
-
- return CURLE_OK;
-}
-
-/*
- * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
- * do protocol-specific actions at connect-time.
- */
-CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done)
-{
- int i;
- struct SSHPROTO *ssh;
- const char *fingerprint;
- const char *authlist;
- char *home;
- char rsa_pub[PATH_MAX];
- char rsa[PATH_MAX];
- char tempHome[PATH_MAX];
- curl_socket_t sock;
- char *real_path;
- char *working_path;
- int working_path_len;
- bool authed = FALSE;
- CURLcode result;
- struct SessionHandle *data = conn->data;
-
- rsa_pub[0] = rsa[0] = '\0';
-
- result = ssh_init(conn);
- if (result)
- return result;
-
- ssh = data->reqdata.proto.ssh;
-
- working_path = curl_easy_unescape(data, data->reqdata.path, 0,
- &working_path_len);
- if (!working_path)
- return CURLE_OUT_OF_MEMORY;
-
-#ifdef CURL_LIBSSH2_DEBUG
- if (ssh->user) {
- infof(data, "User: %s\n", ssh->user);
- }
- if (ssh->passwd) {
- infof(data, "Password: %s\n", ssh->passwd);
- }
-#endif /* CURL_LIBSSH2_DEBUG */
- sock = conn->sock[FIRSTSOCKET];
- ssh->ssh_session = libssh2_session_init_ex(libssh2_malloc, libssh2_free,
- libssh2_realloc, ssh);
- if (ssh->ssh_session == NULL) {
- failf(data, "Failure initialising ssh session\n");
- Curl_safefree(ssh->path);
- return CURLE_FAILED_INIT;
- }
-#ifdef CURL_LIBSSH2_DEBUG
- infof(data, "SSH socket: %d\n", sock);
-#endif /* CURL_LIBSSH2_DEBUG */
-
- if (libssh2_session_startup(ssh->ssh_session, sock)) {
- failf(data, "Failure establishing ssh session\n");
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- Curl_safefree(ssh->path);
- return CURLE_FAILED_INIT;
- }
-
- /*
- * Before we authenticate we should check the hostkey's fingerprint against
- * our known hosts. How that is handled (reading from file, whatever) is
- * up to us. As for know not much is implemented, besides showing how to
- * get the fingerprint.
- */
- fingerprint = libssh2_hostkey_hash(ssh->ssh_session,
- LIBSSH2_HOSTKEY_HASH_MD5);
-
-#ifdef CURL_LIBSSH2_DEBUG
- /* The fingerprint points to static storage (!), don't free() it. */
- infof(data, "Fingerprint: ");
- for (i = 0; i < 16; i++) {
- infof(data, "%02X ", (unsigned char) fingerprint[i]);
- }
- infof(data, "\n");
-#endif /* CURL_LIBSSH2_DEBUG */
-
- /* TBD - methods to check the host keys need to be done */
-
- /*
- * Figure out authentication methods
- * NB: As soon as we have provided a username to an openssh server we must
- * never change it later. Thus, always specify the correct username here,
- * even though the libssh2 docs kind of indicate that it should be possible
- * to get a 'generic' list (not user-specific) of authentication methods,
- * presumably with a blank username. That won't work in my experience.
- * So always specify it here.
- */
- authlist = libssh2_userauth_list(ssh->ssh_session, ssh->user,
- strlen(ssh->user));
-
- /*
- * Check the supported auth types in the order I feel is most secure with the
- * requested type of authentication
- */
- if ((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
- (strstr(authlist, "publickey") != NULL)) {
- /* To ponder about: should really the lib be messing about with the HOME
- environment variable etc? */
- home = curl_getenv("HOME");
-
- if (data->set.ssh_public_key)
- snprintf(rsa_pub, sizeof(rsa_pub), "%s", data->set.ssh_public_key);
- else if (home)
- snprintf(rsa_pub, sizeof(rsa_pub), "%s/.ssh/id_dsa.pub", home);
-
- if (data->set.ssh_private_key)
- snprintf(rsa, sizeof(rsa), "%s", data->set.ssh_private_key);
- else if (home)
- snprintf(rsa, sizeof(rsa), "%s/.ssh/id_dsa", home);
-
- curl_free(home);
-
- if (rsa_pub[0]) {
- /* The function below checks if the files exists, no need to stat() here.
- */
- if (libssh2_userauth_publickey_fromfile(ssh->ssh_session, ssh->user,
- rsa_pub, rsa, "") == 0) {
- authed = TRUE;
- }
- }
- }
- if (!authed &&
- (data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
- (strstr(authlist, "password") != NULL)) {
- if (!libssh2_userauth_password(ssh->ssh_session, ssh->user, ssh->passwd))
- authed = TRUE;
- }
- if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
- (strstr(authlist, "hostbased") != NULL)) {
- }
- if (!authed && (data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
- && (strstr(authlist, "keyboard-interactive") != NULL)) {
- /* Authentication failed. Continue with keyboard-interactive now. */
- if (libssh2_userauth_keyboard_interactive_ex(ssh->ssh_session, ssh->user,
- strlen(ssh->user),
- &kbd_callback) == 0) {
- authed = TRUE;
- }
- }
-
- if (!authed) {
- failf(data, "Authentication failure\n");
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- Curl_safefree(ssh->path);
- return CURLE_FAILED_INIT;
- }
-
- /*
- * At this point we have an authenticated ssh session.
- */
- conn->sockfd = sock;
- conn->writesockfd = CURL_SOCKET_BAD;
-
- if (conn->protocol == PROT_SFTP) {
- /*
- * Start the libssh2 sftp session
- */
- ssh->sftp_session = libssh2_sftp_init(ssh->ssh_session);
- if (ssh->sftp_session == NULL) {
- failf(data, "Failure initialising sftp session\n");
- libssh2_sftp_shutdown(ssh->sftp_session);
- ssh->sftp_session = NULL;
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- return CURLE_FAILED_INIT;
- }
-
- /*
- * Get the "home" directory
- */
- i = libssh2_sftp_realpath(ssh->sftp_session, ".", tempHome, PATH_MAX-1);
- if (i > 0) {
- /* It seems that this string is not always NULL terminated */
- tempHome[i] = '\0';
- ssh->homedir = (char *)strdup(tempHome);
- if (!ssh->homedir) {
- libssh2_sftp_shutdown(ssh->sftp_session);
- ssh->sftp_session = NULL;
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
- }
- else {
- /* Return the error type */
- i = libssh2_sftp_last_error(ssh->sftp_session);
- DEBUGF(infof(data, "error = %d\n", i));
- }
- }
-
- /* Check for /~/ , indicating realative to the users home directory */
- if (conn->protocol == PROT_SCP) {
- real_path = (char *)malloc(working_path_len+1);
- if (real_path == NULL) {
- Curl_safefree(working_path);
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
- if (working_path[1] == '~')
- /* It is referenced to the home directory, so strip the leading '/' */
- memcpy(real_path, working_path+1, 1 + working_path_len-1);
- else
- memcpy(real_path, working_path, 1 + working_path_len);
- }
- else if (conn->protocol == PROT_SFTP) {
- if (working_path[1] == '~') {
- real_path = (char *)malloc(strlen(ssh->homedir) +
- working_path_len + 1);
- if (real_path == NULL) {
- libssh2_sftp_shutdown(ssh->sftp_session);
- ssh->sftp_session = NULL;
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- Curl_safefree(working_path);
- return CURLE_OUT_OF_MEMORY;
- }
- /* It is referenced to the home directory, so strip the leading '/' */
- memcpy(real_path, ssh->homedir, strlen(ssh->homedir));
- real_path[strlen(ssh->homedir)] = '/';
- real_path[strlen(ssh->homedir)+1] = '\0';
- if (working_path_len > 3) {
- memcpy(real_path+strlen(ssh->homedir)+1, working_path + 3,
- 1 + working_path_len -3);
- }
- }
- else {
- real_path = (char *)malloc(working_path_len+1);
- if (real_path == NULL) {
- libssh2_session_free(ssh->ssh_session);
- ssh->ssh_session = NULL;
- Curl_safefree(working_path);
- return CURLE_OUT_OF_MEMORY;
- }
- memcpy(real_path, working_path, 1+working_path_len);
- }
- }
- else
- return CURLE_FAILED_INIT;
-
- Curl_safefree(working_path);
- ssh->path = real_path;
-
- *done = TRUE;
- return CURLE_OK;
-}
-
-CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
-{
- struct stat sb;
- struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
- CURLcode res = CURLE_OK;
-
- *done = TRUE; /* unconditionally */
-
- if (conn->data->set.upload) {
- /*
- * NOTE!!! libssh2 requires that the destination path is a full path
- * that includes the destination file and name OR ends in a "/" .
- * If this is not done the destination file will be named the
- * same name as the last directory in the path.
- */
- scp->ssh_channel = libssh2_scp_send_ex(scp->ssh_session, scp->path,
- LIBSSH2_SFTP_S_IRUSR|
- LIBSSH2_SFTP_S_IWUSR|
- LIBSSH2_SFTP_S_IRGRP|
- LIBSSH2_SFTP_S_IROTH,
- conn->data->set.infilesize, 0, 0);
- if (!scp->ssh_channel)
- return CURLE_FAILED_INIT;
-
- /* upload data */
- res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
- }
- else {
- /*
- * We must check the remote file, if it is a directory no vaules will
- * be set in sb
- */
- curl_off_t bytecount;
- memset(&sb, 0, sizeof(struct stat));
- scp->ssh_channel = libssh2_scp_recv(scp->ssh_session, scp->path, &sb);
- if (!scp->ssh_channel) {
- if ((sb.st_mode == 0) && (sb.st_atime == 0) && (sb.st_mtime == 0) &&
- (sb.st_size == 0)) {
- /* Since sb is still empty, it is likely the file was not found */
- return CURLE_REMOTE_FILE_NOT_FOUND;
- }
- return libssh2_error_to_CURLE(conn);
- }
- /* download data */
- bytecount = (curl_off_t) sb.st_size;
- conn->data->reqdata.maxdownload = (curl_off_t) sb.st_size;
- res = Curl_setup_transfer(conn, FIRSTSOCKET,
- bytecount, FALSE, NULL, -1, NULL);
- }
-
- return res;
-}
-
-CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status,
- bool premature)
-{
- struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
- (void)premature; /* not used */
-
- Curl_safefree(scp->path);
- scp->path = NULL;
-
- if (scp->ssh_channel) {
- if (libssh2_channel_close(scp->ssh_channel) < 0) {
- infof(conn->data, "Failed to stop libssh2 channel subsystem\n");
- }
- }
-
- if (scp->ssh_session) {
- libssh2_session_disconnect(scp->ssh_session, "Shutdown");
- libssh2_session_free(scp->ssh_session);
- scp->ssh_session = NULL;
- }
-
- free(conn->data->reqdata.proto.ssh);
- conn->data->reqdata.proto.ssh = NULL;
- Curl_pgrsDone(conn);
-
- (void)status; /* unused */
-
- return CURLE_OK;
-}
-
-/* return number of received (decrypted) bytes */
-ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
- void *mem, size_t len)
-{
- ssize_t nwrite;
-
- /* libssh2_channel_write() returns int
- *
- * NOTE: we should not store nor rely on connection-related data to be
- * in the SessionHandle struct
- */
- nwrite = (ssize_t)
- libssh2_channel_write(conn->data->reqdata.proto.ssh->ssh_channel,
- mem, len);
- (void)sockindex;
- return nwrite;
-}
-
-/*
- * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
- * a regular CURLcode value.
- */
-ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len)
-{
- ssize_t nread;
-
- /* libssh2_channel_read() returns int
- *
- * NOTE: we should not store nor rely on connection-related data to be
- * in the SessionHandle struct
- */
-
- nread = (ssize_t)
- libssh2_channel_read(conn->data->reqdata.proto.ssh->ssh_channel,
- mem, len);
- (void)sockindex;
- return nread;
-}
-
-/*
- * =============== SFTP ===============
- */
-
-CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
-{
- LIBSSH2_SFTP_ATTRIBUTES attrs;
- struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
- CURLcode res = CURLE_OK;
- struct SessionHandle *data = conn->data;
- curl_off_t bytecount = 0;
- char *buf = data->state.buffer;
-
- *done = TRUE; /* unconditionally */
-
- if (data->set.upload) {
- /*
- * NOTE!!! libssh2 requires that the destination path is a full path
- * that includes the destination file and name OR ends in a "/" .
- * If this is not done the destination file will be named the
- * same name as the last directory in the path.
- */
- sftp->sftp_handle =
- libssh2_sftp_open(sftp->sftp_session, sftp->path,
- LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT,
- LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
- LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
- if (!sftp->sftp_handle)
- return CURLE_FAILED_INIT;
-
- /* upload data */
- res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
- }
- else {
- if (sftp->path[strlen(sftp->path)-1] == '/') {
- /*
- * This is a directory that we are trying to get, so produce a
- * directory listing
- *
- * **BLOCKING behaviour** This should be made into a state machine and
- * get a separate function called from Curl_sftp_recv() when there is
- * data to read from the network, instead of "hanging" here.
- */
- char filename[PATH_MAX+1];
- int len, totalLen, currLen;
- char *line;
-
- sftp->sftp_handle =
- libssh2_sftp_opendir(sftp->sftp_session, sftp->path);
- if (!sftp->sftp_handle)
- return CURLE_SSH;
-
- while ((len = libssh2_sftp_readdir(sftp->sftp_handle, filename,
- PATH_MAX, &attrs)) > 0) {
- filename[len] = '\0';
-
- if (data->set.ftp_list_only) {
- if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
- ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFDIR)) {
- infof(data, "%s\n", filename);
- }
- }
- else {
- totalLen = 80 + len;
- line = (char *)malloc(totalLen);
- if (!line)
- return CURLE_OUT_OF_MEMORY;
-
- if (!(attrs.flags & LIBSSH2_SFTP_ATTR_UIDGID))
- attrs.uid = attrs.gid =0;
-
- currLen = snprintf(line, totalLen, "---------- 1 %5d %5d",
- attrs.uid, attrs.gid);
-
- if (attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) {
- if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFDIR) {
- line[0] = 'd';
- }
- else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFLNK) {
- line[0] = 'l';
- }
- else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFSOCK) {
- line[0] = 's';
- }
- else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFCHR) {
- line[0] = 'c';
- }
- else if ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFBLK) {
- line[0] = 'b';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IRUSR) {
- line[1] = 'r';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IWUSR) {
- line[2] = 'w';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IXUSR) {
- line[3] = 'x';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IRGRP) {
- line[4] = 'r';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IWGRP) {
- line[5] = 'w';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IXGRP) {
- line[6] = 'x';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IROTH) {
- line[7] = 'r';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IWOTH) {
- line[8] = 'w';
- }
- if (attrs.permissions & LIBSSH2_SFTP_S_IXOTH) {
- line[9] = 'x';
- }
- }
- if (attrs.flags & LIBSSH2_SFTP_ATTR_SIZE) {
- currLen += snprintf(line+currLen, totalLen-currLen, "%11lld",
- attrs.filesize);
- }
- if (attrs.flags & LIBSSH2_SFTP_ATTR_ACMODTIME) {
- const char *months[12] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
- struct tm *nowParts;
- time_t now, remoteTime;
-
- now = time(NULL);
- remoteTime = (time_t)attrs.mtime;
- nowParts = localtime(&remoteTime);
-
- if ((time_t)attrs.mtime > (now - (3600 * 24 * 180))) {
- currLen += snprintf(line+currLen, totalLen-currLen,
- " %s %2d %2d:%02d", months[nowParts->tm_mon],
- nowParts->tm_mday, nowParts->tm_hour,
- nowParts->tm_min);
- }
- else {
- currLen += snprintf(line+currLen, totalLen-currLen,
- " %s %2d %5d", months[nowParts->tm_mon],
- nowParts->tm_mday, 1900+nowParts->tm_year);
- }
- }
- currLen += snprintf(line+currLen, totalLen-currLen, " %s", filename);
- if ((attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
- ((attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFLNK)) {
- char linkPath[PATH_MAX + 1];
-
- snprintf(linkPath, PATH_MAX, "%s%s", sftp->path, filename);
- len = libssh2_sftp_readlink(sftp->sftp_session, linkPath, filename,
- PATH_MAX);
- line = realloc(line, totalLen + 4 + len);
- if (!line)
- return CURLE_OUT_OF_MEMORY;
-
- currLen += snprintf(line+currLen, totalLen-currLen, " -> %s",
- filename);
- }
-
- currLen += snprintf(line+currLen, totalLen-currLen, "\n");
- res = Curl_client_write(conn, CLIENTWRITE_BODY, line, 0);
- free(line);
- }
- }
- libssh2_sftp_closedir(sftp->sftp_handle);
- sftp->sftp_handle = NULL;
-
- /* no data to transfer */
- res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- }
- else {
- /*
- * Work on getting the specified file
- */
- sftp->sftp_handle =
- libssh2_sftp_open(sftp->sftp_session, sftp->path, LIBSSH2_FXF_READ,
- LIBSSH2_SFTP_S_IRUSR|LIBSSH2_SFTP_S_IWUSR|
- LIBSSH2_SFTP_S_IRGRP|LIBSSH2_SFTP_S_IROTH);
- if (!sftp->sftp_handle)
- return CURLE_SSH;
-
- if (libssh2_sftp_stat(sftp->sftp_session, sftp->path, &attrs)) {
- /*
- * libssh2_sftp_open() didn't return an error, so maybe the server
- * just doesn't support stat()
- */
- data->reqdata.size = -1;
- data->reqdata.maxdownload = -1;
- }
- else {
- data->reqdata.size = attrs.filesize;
- data->reqdata.maxdownload = attrs.filesize;
- Curl_pgrsSetDownloadSize(data, attrs.filesize);
- }
-
- Curl_pgrsTime(data, TIMER_STARTTRANSFER);
-
- /* Now download data. The libssh2 0.14 doesn't offer any way to do this
- without using this BLOCKING approach, so here's room for improvement
- once libssh2 can return EWOULDBLOCK to us. */
-#if 0
- /* code left here just because this is what this function will use the
- day libssh2 is improved */
- res = Curl_setup_transfer(conn, FIRSTSOCKET,
- bytecount, FALSE, NULL, -1, NULL);
-#endif
- while (res == CURLE_OK) {
- size_t nread;
- /* NOTE: most *read() functions return ssize_t but this returns size_t
- which normally is unsigned! */
- nread = libssh2_sftp_read(data->reqdata.proto.ssh->sftp_handle,
- buf, BUFSIZE-1);
-
- if (nread > 0)
- buf[nread] = 0;
-
- /* this check can be changed to a <= 0 when nread is changed to a
- signed variable type */
- if ((nread == 0) || (nread == (size_t)~0))
- break;
-
- bytecount += nread;
-
- res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
- if(res)
- return res;
-
- Curl_pgrsSetDownloadCounter(data, bytecount);
-
- if(Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
- else {
- struct timeval now = Curl_tvnow();
- res = Curl_speedcheck(data, now);
- }
- }
- if(Curl_pgrsUpdate(conn))
- res = CURLE_ABORTED_BY_CALLBACK;
-
- /* no (more) data to transfer */
- res = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- }
- }
-
- return res;
-}
-
-CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
- bool premature)
-{
- struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
- (void)premature; /* not used */
-
- Curl_safefree(sftp->path);
- sftp->path = NULL;
-
- Curl_safefree(sftp->homedir);
- sftp->homedir = NULL;
-
- if (sftp->sftp_handle) {
- if (libssh2_sftp_close(sftp->sftp_handle) < 0) {
- infof(conn->data, "Failed to close libssh2 file\n");
- }
- }
-
- if (sftp->sftp_session) {
- if (libssh2_sftp_shutdown(sftp->sftp_session) < 0) {
- infof(conn->data, "Failed to stop libssh2 sftp subsystem\n");
- }
- }
-
- if (sftp->ssh_channel) {
- if (libssh2_channel_close(sftp->ssh_channel) < 0) {
- infof(conn->data, "Failed to stop libssh2 channel subsystem\n");
- }
- }
-
- if (sftp->ssh_session) {
- libssh2_session_disconnect(sftp->ssh_session, "Shutdown");
- libssh2_session_free(sftp->ssh_session);
- sftp->ssh_session = NULL;
- }
-
- free(conn->data->reqdata.proto.ssh);
- conn->data->reqdata.proto.ssh = NULL;
- Curl_pgrsDone(conn);
-
- (void)status; /* unused */
-
- return CURLE_OK;
-}
-
-/* return number of received (decrypted) bytes */
-ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
- void *mem, size_t len)
-{
- ssize_t nwrite;
-
- /* libssh2_sftp_write() returns size_t !*/
-
- nwrite = (ssize_t)
- libssh2_sftp_write(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
- (void)sockindex;
- return nwrite;
-}
-
-/*
- * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
- * a regular CURLcode value.
- */
-ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len)
-{
- ssize_t nread;
-
- /* libssh2_sftp_read() returns size_t !*/
-
- nread = (ssize_t)
- libssh2_sftp_read(conn->data->reqdata.proto.ssh->sftp_handle, mem, len);
- (void)sockindex;
- return nread;
-}
-
-#endif /* USE_LIBSSH2 */
diff --git a/Utilities/cmcurl/ssh.h b/Utilities/cmcurl/ssh.h
deleted file mode 100644
index d9144903b..000000000
--- a/Utilities/cmcurl/ssh.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef __SSH_H
-#define __SSH_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifdef USE_LIBSSH2
-
-CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done);
-
-CURLcode Curl_scp_do(struct connectdata *conn, bool *done);
-CURLcode Curl_scp_done(struct connectdata *conn, CURLcode, bool premature);
-
-ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
- void *mem, size_t len);
-ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len);
-
-CURLcode Curl_sftp_do(struct connectdata *conn, bool *done);
-CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode, bool premature);
-
-ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
- void *mem, size_t len);
-ssize_t Curl_sftp_recv(struct connectdata *conn, int sockindex,
- char *mem, size_t len);
-
-#endif /* USE_LIBSSH2 */
-
-#endif /* __SSH_H */
diff --git a/Utilities/cmcurl/sslgen.c b/Utilities/cmcurl/sslgen.c
deleted file mode 100644
index f110a51ea..000000000
--- a/Utilities/cmcurl/sslgen.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* This file is for "generic" SSL functions that all libcurl internals should
- use. It is responsible for calling the proper 'ossl' function in ssluse.c
- (OpenSSL based) or the 'gtls' function in gtls.c (GnuTLS based).
-
- SSL-functions in libcurl should call functions in this source file, and not
- to any specific SSL-layer.
-
- Curl_ssl_ - prefix for generic ones
- Curl_ossl_ - prefix for OpenSSL ones
- Curl_gtls_ - prefix for GnuTLS ones
-
- "SSL/TLS Strong Encryption: An Introduction"
- http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
-*/
-
-#include "setup.h"
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "urldata.h"
-#define SSLGEN_C
-#include "sslgen.h" /* generic SSL protos etc */
-#include "ssluse.h" /* OpenSSL versions */
-#include "gtls.h" /* GnuTLS versions */
-#include "sendf.h"
-#include "strequal.h"
-#include "url.h"
-#include "memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* "global" init done? */
-static bool init_ssl=FALSE;
-
-static bool safe_strequal(char* str1, char* str2);
-
-static bool safe_strequal(char* str1, char* str2)
-{
- if(str1 && str2)
- /* both pointers point to something then compare them */
- return (bool)(0 != strequal(str1, str2));
- else
- /* if both pointers are NULL then treat them as equal */
- return (bool)(!str1 && !str2);
-}
-
-bool
-Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle)
-{
- if((data->version == needle->version) &&
- (data->verifypeer == needle->verifypeer) &&
- (data->verifyhost == needle->verifyhost) &&
- safe_strequal(data->CApath, needle->CApath) &&
- safe_strequal(data->CAfile, needle->CAfile) &&
- safe_strequal(data->random_file, needle->random_file) &&
- safe_strequal(data->egdsocket, needle->egdsocket) &&
- safe_strequal(data->cipher_list, needle->cipher_list))
- return TRUE;
-
- return FALSE;
-}
-
-bool
-Curl_clone_ssl_config(struct ssl_config_data *source,
- struct ssl_config_data *dest)
-{
- dest->verifyhost = source->verifyhost;
- dest->verifypeer = source->verifypeer;
- dest->version = source->version;
-
- if(source->CAfile) {
- dest->CAfile = strdup(source->CAfile);
- if(!dest->CAfile)
- return FALSE;
- }
-
- if(source->CApath) {
- dest->CApath = strdup(source->CApath);
- if(!dest->CApath)
- return FALSE;
- }
-
- if(source->cipher_list) {
- dest->cipher_list = strdup(source->cipher_list);
- if(!dest->cipher_list)
- return FALSE;
- }
-
- if(source->egdsocket) {
- dest->egdsocket = strdup(source->egdsocket);
- if(!dest->egdsocket)
- return FALSE;
- }
-
- if(source->random_file) {
- dest->random_file = strdup(source->random_file);
- if(!dest->random_file)
- return FALSE;
- }
-
- return TRUE;
-}
-
-void Curl_free_ssl_config(struct ssl_config_data* sslc)
-{
- if(sslc->CAfile)
- free(sslc->CAfile);
-
- if(sslc->CApath)
- free(sslc->CApath);
-
- if(sslc->cipher_list)
- free(sslc->cipher_list);
-
- if(sslc->egdsocket)
- free(sslc->egdsocket);
-
- if(sslc->random_file)
- free(sslc->random_file);
-}
-
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-int Curl_ssl_init(void)
-{
- /* make sure this is only done once */
- if(init_ssl)
- return 1;
- init_ssl = TRUE; /* never again */
-
-#ifdef USE_SSLEAY
- return Curl_ossl_init();
-#else
-#ifdef USE_GNUTLS
- return Curl_gtls_init();
-#else
- /* no SSL support */
- return 1;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-
-/* Global cleanup */
-void Curl_ssl_cleanup(void)
-{
- if(init_ssl) {
- /* only cleanup if we did a previous init */
-#ifdef USE_SSLEAY
- Curl_ossl_cleanup();
-#else
-#ifdef USE_GNUTLS
- Curl_gtls_cleanup();
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
- init_ssl = FALSE;
- }
-}
-
-CURLcode
-Curl_ssl_connect(struct connectdata *conn, int sockindex)
-{
-#ifdef USE_SSL
- /* mark this is being ssl enabled from here on. */
- conn->ssl[sockindex].use = TRUE;
-
-#ifdef USE_SSLEAY
- return Curl_ossl_connect(conn, sockindex);
-#else
-#ifdef USE_GNUTLS
- return Curl_gtls_connect(conn, sockindex);
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-
-#else
- /* without SSL */
- (void)conn;
- (void)sockindex;
- return CURLE_OK;
-#endif /* USE_SSL */
-}
-
-CURLcode
-Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
- bool *done)
-{
-#if defined(USE_SSL) && defined(USE_SSLEAY)
- /* mark this is being ssl enabled from here on. */
- conn->ssl[sockindex].use = TRUE;
- return Curl_ossl_connect_nonblocking(conn, sockindex, done);
-
-#else
- /* not implemented!
- fallback to BLOCKING call. */
- *done = TRUE;
- return Curl_ssl_connect(conn, sockindex);
-#endif
-}
-
-#ifdef USE_SSL
-
-/*
- * Check if there's a session ID for the given connection in the cache, and if
- * there's one suitable, it is provided. Returns TRUE when no entry matched.
- */
-int Curl_ssl_getsessionid(struct connectdata *conn,
- void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */
-{
- struct curl_ssl_session *check;
- struct SessionHandle *data = conn->data;
- long i;
-
- if(!conn->ssl_config.sessionid)
- /* session ID re-use is disabled */
- return TRUE;
-
- for(i=0; i< data->set.ssl.numsessions; i++) {
- check = &data->state.session[i];
- if(!check->sessionid)
- /* not session ID means blank entry */
- continue;
- if(curl_strequal(conn->host.name, check->name) &&
- (conn->remote_port == check->remote_port) &&
- Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
- /* yes, we have a session ID! */
- data->state.sessionage++; /* increase general age */
- check->age = data->state.sessionage; /* set this as used in this age */
- *ssl_sessionid = check->sessionid;
- if(idsize)
- *idsize = check->idsize;
- return FALSE;
- }
- }
- *ssl_sessionid = NULL;
- return TRUE;
-}
-
-/*
- * Kill a single session ID entry in the cache.
- */
-static int kill_session(struct curl_ssl_session *session)
-{
- if(session->sessionid) {
- /* defensive check */
-
- /* free the ID the SSL-layer specific way */
-#ifdef USE_SSLEAY
- Curl_ossl_session_free(session->sessionid);
-#else
- Curl_gtls_session_free(session->sessionid);
-#endif
- session->sessionid=NULL;
- session->age = 0; /* fresh */
-
- Curl_free_ssl_config(&session->ssl_config);
-
- Curl_safefree(session->name);
- session->name = NULL; /* no name */
-
- return 0; /* ok */
- }
- else
- return 1;
-}
-
-/*
- * Store session id in the session cache. The ID passed on to this function
- * must already have been extracted and allocated the proper way for the SSL
- * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
- * later on.
- */
-CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
- void *ssl_sessionid,
- size_t idsize)
-{
- int i;
- struct SessionHandle *data=conn->data; /* the mother of all structs */
- struct curl_ssl_session *store = &data->state.session[0];
- long oldest_age=data->state.session[0].age; /* zero if unused */
- char *clone_host;
-
- /* Even though session ID re-use might be disabled, that only disables USING
- IT. We still store it here in case the re-using is again enabled for an
- upcoming transfer */
-
- clone_host = strdup(conn->host.name);
- if(!clone_host)
- return CURLE_OUT_OF_MEMORY; /* bail out */
-
- /* Now we should add the session ID and the host name to the cache, (remove
- the oldest if necessary) */
-
- /* find an empty slot for us, or find the oldest */
- for(i=1; (i<data->set.ssl.numsessions) &&
- data->state.session[i].sessionid; i++) {
- if(data->state.session[i].age < oldest_age) {
- oldest_age = data->state.session[i].age;
- store = &data->state.session[i];
- }
- }
- if(i == data->set.ssl.numsessions)
- /* cache is full, we must "kill" the oldest entry! */
- kill_session(store);
- else
- store = &data->state.session[i]; /* use this slot */
-
- /* now init the session struct wisely */
- store->sessionid = ssl_sessionid;
- store->idsize = idsize;
- store->age = data->state.sessionage; /* set current age */
- store->name = clone_host; /* clone host name */
- store->remote_port = conn->remote_port; /* port number */
-
- if (!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config))
- return CURLE_OUT_OF_MEMORY;
-
- return CURLE_OK;
-}
-
-
-#endif
-
-void Curl_ssl_close_all(struct SessionHandle *data)
-{
-#ifdef USE_SSL
- int i;
- /* kill the session ID cache */
- if(data->state.session) {
- for(i=0; i< data->set.ssl.numsessions; i++)
- /* the single-killer function handles empty table slots */
- kill_session(&data->state.session[i]);
-
- /* free the cache data */
- free(data->state.session);
- data->state.session = NULL;
- }
-#ifdef USE_SSLEAY
- Curl_ossl_close_all(data);
-#else
-#ifdef USE_GNUTLS
- Curl_gtls_close_all(data);
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-#else /* USE_SSL */
- (void)data;
-#endif /* USE_SSL */
-}
-
-void Curl_ssl_close(struct connectdata *conn)
-{
- if(conn->ssl[FIRSTSOCKET].use) {
-#ifdef USE_SSLEAY
- Curl_ossl_close(conn);
-#else
-#ifdef USE_GNUTLS
- Curl_gtls_close(conn);
-#else
- (void)conn;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
- }
-}
-
-CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
-{
- if(conn->ssl[sockindex].use) {
-#ifdef USE_SSLEAY
- if(Curl_ossl_shutdown(conn, sockindex))
- return CURLE_SSL_SHUTDOWN_FAILED;
-#else
-#ifdef USE_GNUTLS
- if(Curl_gtls_shutdown(conn, sockindex))
- return CURLE_SSL_SHUTDOWN_FAILED;
-#else
- (void)conn;
- (void)sockindex;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
- }
- return CURLE_OK;
-}
-
-/* Selects an (Open)SSL crypto engine
- */
-CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_set_engine(data, engine);
-#else
-#ifdef USE_GNUTLS
- /* FIX: add code here */
- (void)data;
- (void)engine;
- return CURLE_FAILED_INIT;
-#else
- /* no SSL layer */
- (void)data;
- (void)engine;
- return CURLE_FAILED_INIT;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-/* Selects an (Open?)SSL crypto engine
- */
-CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_set_engine_default(data);
-#else
-#ifdef USE_GNUTLS
- /* FIX: add code here */
- (void)data;
- return CURLE_FAILED_INIT;
-#else
- /* No SSL layer */
- (void)data;
- return CURLE_FAILED_INIT;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-/* Return list of OpenSSL crypto engine names. */
-struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_engines_list(data);
-#else
-#ifdef USE_GNUTLS
- /* FIX: add code here? */
- (void)data;
- return NULL;
-#else
- (void)data;
- return NULL;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-/* return number of sent (non-SSL) bytes */
-ssize_t Curl_ssl_send(struct connectdata *conn,
- int sockindex,
- void *mem,
- size_t len)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_send(conn, sockindex, mem, len);
-#else
-#ifdef USE_GNUTLS
- return Curl_gtls_send(conn, sockindex, mem, len);
-#else
- (void)conn;
- (void)sockindex;
- (void)mem;
- (void)len;
- return 0;
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-/* return number of received (decrypted) bytes */
-
-/*
- * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
- * a regular CURLcode value.
- */
-ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
- int sockindex, /* socketindex */
- char *mem, /* store read data here */
- size_t len) /* max amount to read */
-{
-#ifdef USE_SSL
- ssize_t nread;
- bool block = FALSE;
-
-#ifdef USE_SSLEAY
- nread = Curl_ossl_recv(conn, sockindex, mem, len, &block);
-#else
-#ifdef USE_GNUTLS
- nread = Curl_gtls_recv(conn, sockindex, mem, len, &block);
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
- if(nread == -1) {
- if(!block)
- return 0; /* this is a true error, not EWOULDBLOCK */
- else
- return -1;
- }
-
- return (int)nread;
-
-#else /* USE_SSL */
- (void)conn;
- (void)sockindex;
- (void)mem;
- (void)len;
- return 0;
-#endif /* USE_SSL */
-}
-
-
-/*
- * This sets up a session ID cache to the specified size. Make sure this code
- * is agnostic to what underlying SSL technology we use.
- */
-CURLcode Curl_ssl_initsessions(struct SessionHandle *data, long amount)
-{
-#ifdef USE_SSL
- struct curl_ssl_session *session;
-
- if(data->state.session)
- /* this is just a precaution to prevent multiple inits */
- return CURLE_OK;
-
- session = (struct curl_ssl_session *)
- calloc(sizeof(struct curl_ssl_session), amount);
- if(!session)
- return CURLE_OUT_OF_MEMORY;
-
- /* store the info in the SSL section */
- data->set.ssl.numsessions = amount;
- data->state.session = session;
- data->state.sessionage = 1; /* this is brand new */
-#else
- /* without SSL, do nothing */
- (void)data;
- (void)amount;
-#endif
-
- return CURLE_OK;
-}
-
-size_t Curl_ssl_version(char *buffer, size_t size)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_version(buffer, size);
-#else
-#ifdef USE_GNUTLS
- return Curl_gtls_version(buffer, size);
-#else
- (void)buffer;
- (void)size;
- return 0; /* no SSL support */
-#endif /* USE_GNUTLS */
-#endif /* USE_SSLEAY */
-}
-
-
-/*
- * This function tries to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-int Curl_ssl_check_cxn(struct connectdata *conn)
-{
-#ifdef USE_SSLEAY
- return Curl_ossl_check_cxn(conn);
-#else
- (void)conn;
- /* TODO: we lack implementation of this for GnuTLS */
- return -1; /* connection status unknown */
-#endif /* USE_SSLEAY */
-}
-
-bool Curl_ssl_data_pending(struct connectdata *conn,
- int connindex)
-{
-#ifdef USE_SSLEAY
- /* OpenSSL-specific */
- if(conn->ssl[connindex].handle)
- /* SSL is in use */
- return SSL_pending(conn->ssl[connindex].handle);
-#else
- (void)conn;
- (void)connindex;
-#endif
- return FALSE; /* nothing pending */
-
-}
diff --git a/Utilities/cmcurl/sslgen.h b/Utilities/cmcurl/sslgen.h
deleted file mode 100644
index c24d46bf3..000000000
--- a/Utilities/cmcurl/sslgen.h
+++ /dev/null
@@ -1,84 +0,0 @@
-#ifndef __SSLGEN_H
-#define __SSLGEN_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-bool Curl_ssl_config_matches(struct ssl_config_data* data,
- struct ssl_config_data* needle);
-bool Curl_clone_ssl_config(struct ssl_config_data* source,
- struct ssl_config_data* dest);
-void Curl_free_ssl_config(struct ssl_config_data* sslc);
-
-int Curl_ssl_init(void);
-void Curl_ssl_cleanup(void);
-CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-void Curl_ssl_close(struct connectdata *conn);
-/* tell the SSL stuff to close down all open information regarding
- connections (and thus session ID caching etc) */
-void Curl_ssl_close_all(struct SessionHandle *data);
-CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
-/* Sets engine as default for all SSL operations */
-CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
-ssize_t Curl_ssl_send(struct connectdata *conn,
- int sockindex,
- void *mem,
- size_t len);
-ssize_t Curl_ssl_recv(struct connectdata *conn, /* connection data */
- int sockindex, /* socketindex */
- char *mem, /* store read data here */
- size_t len); /* max amount to read */
-
-/* init the SSL session ID cache */
-CURLcode Curl_ssl_initsessions(struct SessionHandle *, long);
-/* extract a session ID */
-int Curl_ssl_getsessionid(struct connectdata *conn,
- void **ssl_sessionid,
- size_t *idsize) /* set 0 if unknown */;
-/* add a new session ID */
-CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
- void *ssl_sessionid,
- size_t idsize);
-
-
-struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
-
-size_t Curl_ssl_version(char *buffer, size_t size);
-
-int Curl_ssl_check_cxn(struct connectdata *conn);
-
-CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
-
-bool Curl_ssl_data_pending(struct connectdata *conn,
- int connindex);
-
-#if !defined(USE_SSL) && !defined(SSLGEN_C)
-/* set up blank macros for none-SSL builds */
-#define Curl_ssl_close_all(x)
-#endif
-
-#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
-
-#endif
diff --git a/Utilities/cmcurl/ssluse.c b/Utilities/cmcurl/ssluse.c
deleted file mode 100644
index 6709278fa..000000000
--- a/Utilities/cmcurl/ssluse.c
+++ /dev/null
@@ -1,1950 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
- * but sslgen.c should ever call or use these functions.
- */
-
-/*
- * The original SSLeay-using code for curl was written by Linas Vepstas and
- * Sampo Kellomaki 1998.
- */
-
-#include "setup.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-
-#include "urldata.h"
-#include "sendf.h"
-#include "formdata.h" /* for the boundary function */
-#include "url.h" /* for the ssl config check function */
-#include "inet_pton.h"
-#include "ssluse.h"
-#include "connect.h" /* Curl_sockerrno() proto */
-#include "strequal.h"
-#include "select.h"
-#include "sslgen.h"
-
-#define _MPRINTF_REPLACE /* use the internal *printf() functions */
-#include <curl/mprintf.h>
-
-#ifdef USE_SSLEAY
-
-#ifdef USE_OPENSSL
-#include <openssl/rand.h>
-#include <openssl/x509v3.h>
-#else
-#include <rand.h>
-#include <x509v3.h>
-#endif
-
-#include "memory.h"
-#include "easyif.h" /* for Curl_convert_from_utf8 prototype */
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#ifndef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
-#define HAVE_SSL_GET1_SESSION 1
-#else
-#undef HAVE_SSL_GET1_SESSION
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00904100L
-#define HAVE_USERDATA_IN_PWD_CALLBACK 1
-#else
-#undef HAVE_USERDATA_IN_PWD_CALLBACK
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00907001L
-/* ENGINE_load_private_key() takes four arguments */
-#define HAVE_ENGINE_LOAD_FOUR_ARGS
-#else
-/* ENGINE_load_private_key() takes three arguments */
-#undef HAVE_ENGINE_LOAD_FOUR_ARGS
-#endif
-
-#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H)
-/* OpenSSL has PKCS 12 support */
-#define HAVE_PKCS12_SUPPORT
-#else
-/* OpenSSL/SSLEay does not have PKCS12 support */
-#undef HAVE_PKCS12_SUPPORT
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00906001L
-#define HAVE_ERR_ERROR_STRING_N 1
-#endif
-
-#if OPENSSL_VERSION_NUMBER >= 0x00909000L
-#define SSL_METHOD_QUAL const
-#else
-#define SSL_METHOD_QUAL
-#endif
-
-/*
- * Number of bytes to read from the random number seed file. This must be
- * a finite value (because some entropy "files" like /dev/urandom have
- * an infinite length), but must be large enough to provide enough
- * entopy to properly seed OpenSSL's PRNG.
- */
-#define RAND_LOAD_LENGTH 1024
-
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
-static char global_passwd[64];
-#endif
-
-static int passwd_callback(char *buf, int num, int verify
-#if HAVE_USERDATA_IN_PWD_CALLBACK
- /* This was introduced in 0.9.4, we can set this
- using SSL_CTX_set_default_passwd_cb_userdata()
- */
- , void *global_passwd
-#endif
- )
-{
- if(verify)
- fprintf(stderr, "%s\n", buf);
- else {
- if(num > (int)strlen((char *)global_passwd)) {
- strcpy(buf, global_passwd);
- return (int)strlen(buf);
- }
- }
- return 0;
-}
-
-/*
- * rand_enough() is a function that returns TRUE if we have seeded the random
- * engine properly. We use some preprocessor magic to provide a seed_enough()
- * macro to use, just to prevent a compiler warning on this function if we
- * pass in an argument that is never used.
- */
-
-#ifdef HAVE_RAND_STATUS
-#define seed_enough(x) rand_enough()
-static bool rand_enough(void)
-{
- return (bool)(0 != RAND_status());
-}
-#else
-#define seed_enough(x) rand_enough(x)
-static bool rand_enough(int nread)
-{
- /* this is a very silly decision to make */
- return (bool)(nread > 500);
-}
-#endif
-
-static int ossl_seed(struct SessionHandle *data)
-{
- char *buf = data->state.buffer; /* point to the big buffer */
- int nread=0;
-
- /* Q: should we add support for a random file name as a libcurl option?
- A: Yes, it is here */
-
-#ifndef RANDOM_FILE
- /* if RANDOM_FILE isn't defined, we only perform this if an option tells
- us to! */
- if(data->set.ssl.random_file)
-#define RANDOM_FILE "" /* doesn't matter won't be used */
-#endif
- {
- /* let the option override the define */
- nread += RAND_load_file((data->set.ssl.random_file?
- data->set.ssl.random_file:RANDOM_FILE),
- RAND_LOAD_LENGTH);
- if(seed_enough(nread))
- return nread;
- }
-
-#if defined(HAVE_RAND_EGD)
- /* only available in OpenSSL 0.9.5 and later */
- /* EGD_SOCKET is set at configure time or not at all */
-#ifndef EGD_SOCKET
- /* If we don't have the define set, we only do this if the egd-option
- is set */
- if(data->set.ssl.egdsocket)
-#define EGD_SOCKET "" /* doesn't matter won't be used */
-#endif
- {
- /* If there's an option and a define, the option overrides the
- define */
- int ret = RAND_egd(data->set.ssl.egdsocket?
- data->set.ssl.egdsocket:EGD_SOCKET);
- if(-1 != ret) {
- nread += ret;
- if(seed_enough(nread))
- return nread;
- }
- }
-#endif
-
- /* If we get here, it means we need to seed the PRNG using a "silly"
- approach! */
-#ifdef HAVE_RAND_SCREEN
- /* This one gets a random value by reading the currently shown screen */
- RAND_screen();
- nread = 100; /* just a value */
-#else
- {
- int len;
- char *area;
-
- /* Changed call to RAND_seed to use the underlying RAND_add implementation
- * directly. Do this in a loop, with the amount of additional entropy
- * being dependent upon the algorithm used by Curl_FormBoundary(): N bytes
- * of a 7-bit ascii set. -- Richard Gorton, March 11 2003.
- */
-
- do {
- area = Curl_FormBoundary();
- if(!area)
- return 3; /* out of memory */
-
- len = (int)strlen(area);
- RAND_add(area, len, (len >> 1));
-
- free(area); /* now remove the random junk */
- } while (!RAND_status());
- }
-#endif
-
- /* generates a default path for the random seed file */
- buf[0]=0; /* blank it first */
- RAND_file_name(buf, BUFSIZE);
- if(buf[0]) {
- /* we got a file name to try */
- nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
- if(seed_enough(nread))
- return nread;
- }
-
- infof(data, "libcurl is now using a weak random seed!\n");
- return nread;
-}
-
-int Curl_ossl_seed(struct SessionHandle *data)
-{
- /* we have the "SSL is seeded" boolean static to prevent multiple
- time-consuming seedings in vain */
- static bool ssl_seeded = FALSE;
-
- if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
- ossl_seed(data);
- ssl_seeded = TRUE;
- }
- return 0;
-}
-
-
-#ifndef SSL_FILETYPE_ENGINE
-#define SSL_FILETYPE_ENGINE 42
-#endif
-#ifndef SSL_FILETYPE_PKCS12
-#define SSL_FILETYPE_PKCS12 43
-#endif
-static int do_file_type(const char *type)
-{
- if(!type || !type[0])
- return SSL_FILETYPE_PEM;
- if(curl_strequal(type, "PEM"))
- return SSL_FILETYPE_PEM;
- if(curl_strequal(type, "DER"))
- return SSL_FILETYPE_ASN1;
- if(curl_strequal(type, "ENG"))
- return SSL_FILETYPE_ENGINE;
- if(curl_strequal(type, "P12"))
- return SSL_FILETYPE_PKCS12;
- return -1;
-}
-
-static
-int cert_stuff(struct connectdata *conn,
- SSL_CTX* ctx,
- char *cert_file,
- const char *cert_type,
- char *key_file,
- const char *key_type)
-{
- struct SessionHandle *data = conn->data;
- int file_type;
-
- if(cert_file != NULL) {
- SSL *ssl;
- X509 *x509;
- int cert_done = 0;
-
- if(data->set.key_passwd) {
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /*
- * If password has been given, we store that in the global
- * area (*shudder*) for a while:
- */
- size_t len = strlen(data->set.key_passwd);
- if(len < sizeof(global_passwd))
- memcpy(global_passwd, data->set.key_passwd, len+1);
-#else
- /*
- * We set the password in the callback userdata
- */
- SSL_CTX_set_default_passwd_cb_userdata(ctx,
- data->set.key_passwd);
-#endif
- /* Set passwd callback: */
- SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
- }
-
- file_type = do_file_type(cert_type);
-
-#define SSL_CLIENT_CERT_ERR \
- "unable to use client certificate (no key found or wrong pass phrase?)"
-
- switch(file_type) {
- case SSL_FILETYPE_PEM:
- /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- if(SSL_CTX_use_certificate_chain_file(ctx,
- cert_file) != 1) {
- failf(data, SSL_CLIENT_CERT_ERR);
- return 0;
- }
- break;
-
- case SSL_FILETYPE_ASN1:
- /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
- we use the case above for PEM so this can only be performed with
- ASN1 files. */
- if(SSL_CTX_use_certificate_file(ctx,
- cert_file,
- file_type) != 1) {
- failf(data, SSL_CLIENT_CERT_ERR);
- return 0;
- }
- break;
- case SSL_FILETYPE_ENGINE:
- failf(data, "file type ENG for certificate not implemented");
- return 0;
-
- case SSL_FILETYPE_PKCS12:
- {
-#ifdef HAVE_PKCS12_SUPPORT
- FILE *f;
- PKCS12 *p12;
- EVP_PKEY *pri;
-
- f = fopen(cert_file,"rb");
- if (!f) {
- failf(data, "could not open PKCS12 file '%s'", cert_file);
- return 0;
- }
- p12 = d2i_PKCS12_fp(f, NULL);
- fclose(f);
-
- PKCS12_PBE_add();
-
- if (!PKCS12_parse(p12, data->set.key_passwd, &pri, &x509, NULL)) {
- failf(data,
- "could not parse PKCS12 file, check password, OpenSSL error %s",
- ERR_error_string(ERR_get_error(), NULL) );
- return 0;
- }
-
- PKCS12_free(p12);
-
- if(SSL_CTX_use_certificate(ctx, x509) != 1) {
- failf(data, SSL_CLIENT_CERT_ERR);
- EVP_PKEY_free(pri);
- X509_free(x509);
- return 0;
- }
-
- if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
- failf(data, "unable to use private key from PKCS12 file '%s'",
- cert_file);
- EVP_PKEY_free(pri);
- X509_free(x509);
- return 0;
- }
-
- EVP_PKEY_free(pri);
- X509_free(x509);
- cert_done = 1;
- break;
-#else
- failf(data, "file type P12 for certificate not supported");
- return 0;
-#endif
- }
- default:
- failf(data, "not supported file type '%s' for certificate", cert_type);
- return 0;
- }
-
- file_type = do_file_type(key_type);
-
- switch(file_type) {
- case SSL_FILETYPE_PEM:
- if(cert_done)
- break;
- if(key_file == NULL)
- /* cert & key can only be in PEM case in the same file */
- key_file=cert_file;
- case SSL_FILETYPE_ASN1:
- if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
- failf(data, "unable to set private key file: '%s' type %s\n",
- key_file, key_type?key_type:"PEM");
- return 0;
- }
- break;
- case SSL_FILETYPE_ENGINE:
-#ifdef HAVE_OPENSSL_ENGINE_H
- { /* XXXX still needs some work */
- EVP_PKEY *priv_key = NULL;
- if(conn && conn->data && conn->data->state.engine) {
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- UI_METHOD *ui_method = UI_OpenSSL();
-#endif
- if(!key_file || !key_file[0]) {
- failf(data, "no key set to load from crypto engine\n");
- return 0;
- }
- /* the typecast below was added to please MinGW32 */
- priv_key = (EVP_PKEY *)
- ENGINE_load_private_key(conn->data->state.engine,key_file,
-#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
- ui_method,
-#endif
- data->set.key_passwd);
- if(!priv_key) {
- failf(data, "failed to load private key from crypto engine\n");
- return 0;
- }
- if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
- failf(data, "unable to set private key\n");
- EVP_PKEY_free(priv_key);
- return 0;
- }
- EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
- }
- else {
- failf(data, "crypto engine not set, can't load private key\n");
- return 0;
- }
- }
- break;
-#else
- failf(data, "file type ENG for private key not supported\n");
- return 0;
-#endif
- case SSL_FILETYPE_PKCS12:
- if(!cert_done) {
- failf(data, "file type P12 for private key not supported\n");
- return 0;
- }
- break;
- default:
- failf(data, "not supported file type for private key\n");
- return 0;
- }
-
- ssl=SSL_new(ctx);
- if (NULL == ssl) {
- failf(data,"unable to create an SSL structure\n");
- return 0;
- }
-
- x509=SSL_get_certificate(ssl);
-
- /* This version was provided by Evan Jordan and is supposed to not
- leak memory as the previous version: */
- if(x509 != NULL) {
- EVP_PKEY *pktmp = X509_get_pubkey(x509);
- EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
- EVP_PKEY_free(pktmp);
- }
-
- SSL_free(ssl);
-
- /* If we are using DSA, we can copy the parameters from
- * the private key */
-
-
- /* Now we know that a key and cert have been set against
- * the SSL context */
- if(!SSL_CTX_check_private_key(ctx)) {
- failf(data, "Private key does not match the certificate public key");
- return(0);
- }
-#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
- /* erase it now */
- memset(global_passwd, 0, sizeof(global_passwd));
-#endif
- }
- return(1);
-}
-
-static
-int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
-{
- X509 *err_cert;
- char buf[256];
-
- err_cert=X509_STORE_CTX_get_current_cert(ctx);
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
- return ok;
-}
-
-/* Return error string for last OpenSSL error
- */
-static char *SSL_strerror(unsigned long error, char *buf, size_t size)
-{
-#ifdef HAVE_ERR_ERROR_STRING_N
- /* OpenSSL 0.9.6 and later has a function named
- ERRO_error_string_n() that takes the size of the buffer as a
- third argument */
- ERR_error_string_n(error, buf, size);
-#else
- (void) size;
- ERR_error_string(error, buf);
-#endif
- return (buf);
-}
-
-#endif /* USE_SSLEAY */
-
-#ifdef USE_SSLEAY
-/**
- * Global SSL init
- *
- * @retval 0 error initializing SSL
- * @retval 1 SSL initialized successfully
- */
-int Curl_ossl_init(void)
-{
-#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
- ENGINE_load_builtin_engines();
-#endif
-
- /* Lets get nice error messages */
- SSL_load_error_strings();
-
- /* Setup all the global SSL stuff */
- if (!SSLeay_add_ssl_algorithms())
- return 0;
-
- return 1;
-}
-
-#endif /* USE_SSLEAY */
-
-#ifdef USE_SSLEAY
-
-/* Global cleanup */
-void Curl_ossl_cleanup(void)
-{
- /* Free the SSL error strings */
- ERR_free_strings();
-
- /* EVP_cleanup() removes all ciphers and digests from the
- table. */
- EVP_cleanup();
-
-#ifdef HAVE_ENGINE_cleanup
- ENGINE_cleanup();
-#endif
-
-#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
- /* this function was not present in 0.9.6b, but was added sometimes
- later */
- CRYPTO_cleanup_all_ex_data();
-#endif
-}
-
-/*
- * This function uses SSL_peek to determine connection status.
- *
- * Return codes:
- * 1 means the connection is still in place
- * 0 means the connection has been closed
- * -1 means the connection status is unknown
- */
-int Curl_ossl_check_cxn(struct connectdata *conn)
-{
- int rc;
- char buf;
-
- rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
- if (rc > 0)
- return 1; /* connection still in place */
-
- if (rc == 0)
- return 0; /* connection has been closed */
-
- return -1; /* connection status unknown */
-}
-
-#endif /* USE_SSLEAY */
-
-/* Selects an OpenSSL crypto engine
- */
-CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
-{
-#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
- ENGINE *e = ENGINE_by_id(engine);
-
- if (!e) {
- failf(data, "SSL Engine '%s' not found", engine);
- return (CURLE_SSL_ENGINE_NOTFOUND);
- }
-
- if (data->state.engine) {
- ENGINE_finish(data->state.engine);
- ENGINE_free(data->state.engine);
- data->state.engine = NULL;
- }
- if (!ENGINE_init(e)) {
- char buf[256];
-
- ENGINE_free(e);
- failf(data, "Failed to initialise SSL Engine '%s':\n%s",
- engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
- return (CURLE_SSL_ENGINE_INITFAILED);
- }
- data->state.engine = e;
- return (CURLE_OK);
-#else
- (void)engine;
- failf(data, "SSL Engine not supported");
- return (CURLE_SSL_ENGINE_NOTFOUND);
-#endif
-}
-
-#ifdef USE_SSLEAY
-/* Sets engine as default for all SSL operations
- */
-CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
-{
-#ifdef HAVE_OPENSSL_ENGINE_H
- if (data->state.engine) {
- if (ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
- infof(data,"set default crypto engine '%s'\n", ENGINE_get_id(data->state.engine));
- }
- else {
- failf(data, "set default crypto engine '%s' failed", ENGINE_get_id(data->state.engine));
- return CURLE_SSL_ENGINE_SETFAILED;
- }
- }
-#else
- (void) data;
-#endif
- return CURLE_OK;
-}
-#endif /* USE_SSLEAY */
-
-/* Return list of OpenSSL crypto engine names.
- */
-struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
-{
- struct curl_slist *list = NULL;
-#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
- ENGINE *e;
-
- for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
- list = curl_slist_append(list, ENGINE_get_id(e));
-#endif
- (void) data;
- return (list);
-}
-
-
-#ifdef USE_SSLEAY
-
-/*
- * This function is called when an SSL connection is closed.
- */
-void Curl_ossl_close(struct connectdata *conn)
-{
- int i;
- /*
- ERR_remove_state() frees the error queue associated with
- thread pid. If pid == 0, the current thread will have its
- error queue removed.
-
- Since error queue data structures are allocated
- automatically for new threads, they must be freed when
- threads are terminated in oder to avoid memory leaks.
- */
- ERR_remove_state(0);
-
- for(i=0; i<2; i++) {
- struct ssl_connect_data *connssl = &conn->ssl[i];
-
- if(connssl->handle) {
- (void)SSL_shutdown(connssl->handle);
- SSL_set_connect_state(connssl->handle);
-
- SSL_free (connssl->handle);
- connssl->handle = NULL;
- }
- if(connssl->ctx) {
- SSL_CTX_free (connssl->ctx);
- connssl->ctx = NULL;
- }
- connssl->use = FALSE; /* get back to ordinary socket usage */
- }
-}
-
-/*
- * This function is called to shut down the SSL layer but keep the
- * socket open (CCC - Clear Command Channel)
- */
-int Curl_ossl_shutdown(struct connectdata *conn, int sockindex)
-{
- int retval = 0;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- struct SessionHandle *data = conn->data;
- char buf[120]; /* We will use this for the OpenSSL error buffer, so it has
- to be at least 120 bytes long. */
- unsigned long sslerror;
- ssize_t nread;
- int err;
- int done = 0;
-
- /* This has only been tested on the proftpd server, and the mod_tls code
- sends a close notify alert without waiting for a close notify alert in
- response. Thus we wait for a close notify alert from the server, but
- we do not send one. Let's hope other servers do the same... */
-
- if(connssl->handle) {
- while(!done) {
- int what = Curl_select(conn->sock[sockindex],
- CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
- if(what > 0) {
- /* Something to read, let's do it and hope that it is the close
- notify alert from the server */
- nread = (ssize_t)SSL_read(conn->ssl[sockindex].handle, buf,
- sizeof(buf));
- err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
-
- switch(err) {
- case SSL_ERROR_NONE: /* this is not an error */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- /* This is the expected response. There was no data but only
- the close notify alert */
- done = 1;
- break;
- case SSL_ERROR_WANT_READ:
- /* there's data pending, re-invoke SSL_read() */
- infof(data, "SSL_ERROR_WANT_READ\n");
- break;
- case SSL_ERROR_WANT_WRITE:
- /* SSL wants a write. Really odd. Let's bail out. */
- infof(data, "SSL_ERROR_WANT_WRITE\n");
- done = 1;
- break;
- default:
- /* openssl/ssl.h says "look at error stack/return value/errno" */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(sslerror, buf),
- Curl_sockerrno() );
- done = 1;
- break;
- }
- }
- else if(0 == what) {
- /* timeout */
- failf(data, "SSL shutdown timeout");
- done = 1;
- break;
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
- retval = -1;
- done = 1;
- }
- } /* while()-loop for the select() */
-
- if(data->set.verbose) {
- switch(SSL_get_shutdown(connssl->handle)) {
- case SSL_SENT_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
- break;
- case SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
- break;
- case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
- infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
- "SSL_RECEIVED__SHUTDOWN\n");
- break;
- }
- }
-
- connssl->use = FALSE; /* get back to ordinary socket usage */
-
- SSL_free (connssl->handle);
- connssl->handle = NULL;
- }
- return retval;
-}
-
-void Curl_ossl_session_free(void *ptr)
-{
- /* free the ID */
- SSL_SESSION_free(ptr);
-}
-
-/*
- * This function is called when the 'data' struct is going away. Close
- * down everything and free all resources!
- */
-int Curl_ossl_close_all(struct SessionHandle *data)
-{
-#ifdef HAVE_OPENSSL_ENGINE_H
- if(data->state.engine) {
- ENGINE_finish(data->state.engine);
- ENGINE_free(data->state.engine);
- data->state.engine = NULL;
- }
-#else
- (void)data;
-#endif
- return 0;
-}
-
-static int Curl_ASN1_UTCTIME_output(struct connectdata *conn,
- const char *prefix,
- ASN1_UTCTIME *tm)
-{
- char *asn1_string;
- int gmt=FALSE;
- int i;
- int year=0,month=0,day=0,hour=0,minute=0,second=0;
- struct SessionHandle *data = conn->data;
-
- if(!data->set.verbose)
- return 0;
-
- i=tm->length;
- asn1_string=(char *)tm->data;
-
- if(i < 10)
- return 1;
- if(asn1_string[i-1] == 'Z')
- gmt=TRUE;
- for (i=0; i<10; i++)
- if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
- return 2;
-
- year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
- if(year < 50)
- year+=100;
-
- month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
- if((month > 12) || (month < 1))
- return 3;
-
- day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
- hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
- minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
-
- if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
- (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
- second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
-
- infof(data,
- "%s%04d-%02d-%02d %02d:%02d:%02d %s\n",
- prefix, year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
-
- return 0;
-}
-
-#endif
-
-/* ====================================================== */
-#ifdef USE_SSLEAY
-
-/*
- * Match a hostname against a wildcard pattern.
- * E.g.
- * "foo.host.com" matches "*.host.com".
- *
- * We are a bit more liberal than RFC2818 describes in that we
- * accept multiple "*" in pattern (similar to what some other browsers do).
- * E.g.
- * "abc.def.domain.com" should strickly not match "*.domain.com", but we
- * don't consider "." to be important in CERT checking.
- */
-#define HOST_NOMATCH 0
-#define HOST_MATCH 1
-
-static int hostmatch(const char *hostname, const char *pattern)
-{
- while (1) {
- int c = *pattern++;
-
- if (c == '\0')
- return (*hostname ? HOST_NOMATCH : HOST_MATCH);
-
- if (c == '*') {
- c = *pattern;
- if (c == '\0') /* "*\0" matches anything remaining */
- return HOST_MATCH;
-
- while (*hostname) {
- /* The only recursive function in libcurl! */
- if (hostmatch(hostname++,pattern) == HOST_MATCH)
- return HOST_MATCH;
- }
- break;
- }
-
- if (toupper(c) != toupper(*hostname++))
- break;
- }
- return HOST_NOMATCH;
-}
-
-static int
-cert_hostcheck(const char *match_pattern, const char *hostname)
-{
- if (!match_pattern || !*match_pattern ||
- !hostname || !*hostname) /* sanity check */
- return 0;
-
- if(curl_strequal(hostname,match_pattern)) /* trivial case */
- return 1;
-
- if (hostmatch(hostname,match_pattern) == HOST_MATCH)
- return 1;
- return 0;
-}
-
-/* Quote from RFC2818 section 3.1 "Server Identity"
-
- If a subjectAltName extension of type dNSName is present, that MUST
- be used as the identity. Otherwise, the (most specific) Common Name
- field in the Subject field of the certificate MUST be used. Although
- the use of the Common Name is existing practice, it is deprecated and
- Certification Authorities are encouraged to use the dNSName instead.
-
- Matching is performed using the matching rules specified by
- [RFC2459]. If more than one identity of a given type is present in
- the certificate (e.g., more than one dNSName name, a match in any one
- of the set is considered acceptable.) Names may contain the wildcard
- character * which is considered to match any single domain name
- component or component fragment. E.g., *.a.com matches foo.a.com but
- not bar.foo.a.com. f*.com matches foo.com but not bar.com.
-
- In some cases, the URI is specified as an IP address rather than a
- hostname. In this case, the iPAddress subjectAltName must be present
- in the certificate and must exactly match the IP in the URI.
-
-*/
-static CURLcode verifyhost(struct connectdata *conn,
- X509 *server_cert)
-{
- bool matched = FALSE; /* no alternative match yet */
- int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
- int addrlen = 0;
- struct SessionHandle *data = conn->data;
- STACK_OF(GENERAL_NAME) *altnames;
-#ifdef ENABLE_IPV6
- struct in6_addr addr;
-#else
- struct in_addr addr;
-#endif
- CURLcode res = CURLE_OK;
-
-#ifdef ENABLE_IPV6
- if(conn->bits.ipv6_ip &&
- Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in6_addr);
- }
- else
-#endif
- if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
- target = GEN_IPADD;
- addrlen = sizeof(struct in_addr);
- }
-
- /* get a "list" of alternative names */
- altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
-
- if(altnames) {
- int numalts;
- int i;
-
- /* get amount of alternatives, RFC2459 claims there MUST be at least
- one, but we don't depend on it... */
- numalts = sk_GENERAL_NAME_num(altnames);
-
- /* loop through all alternatives while none has matched */
- for (i=0; (i<numalts) && !matched; i++) {
- /* get a handle to alternative name number i */
- const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
-
- /* only check alternatives of the same type the target is */
- if(check->type == target) {
- /* get data and length */
- const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
- int altlen;
-
- switch(target) {
- case GEN_DNS: /* name/pattern comparison */
- /* The OpenSSL man page explicitly says: "In general it cannot be
- assumed that the data returned by ASN1_STRING_data() is null
- terminated or does not contain embedded nulls." But also that
- "The actual format of the data will depend on the actual string
- type itself: for example for and IA5String the data will be ASCII"
-
- Gisle researched the OpenSSL sources:
- "I checked the 0.9.6 and 0.9.8 sources before my patch and
- it always 0-terminates an IA5String."
- */
- if (cert_hostcheck(altptr, conn->host.name))
- matched = TRUE;
- break;
-
- case GEN_IPADD: /* IP address comparison */
- /* compare alternative IP address if the data chunk is the same size
- our server IP address is */
- altlen = ASN1_STRING_length(check->d.ia5);
- if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
- matched = TRUE;
- break;
- }
- }
- }
- GENERAL_NAMES_free(altnames);
- }
-
- if(matched)
- /* an alternative name matched the server hostname */
- infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
- else {
- /* we have to look to the last occurence of a commonName in the
- distinguished one to get the most significant one. */
- int j,i=-1 ;
-
-/* The following is done because of a bug in 0.9.6b */
-
- unsigned char *nulstr = (unsigned char *)"";
- unsigned char *peer_CN = nulstr;
-
- X509_NAME *name = X509_get_subject_name(server_cert) ;
- if (name)
- while ((j=X509_NAME_get_index_by_NID(name,NID_commonName,i))>=0)
- i=j;
-
- /* we have the name entry and we will now convert this to a string
- that we can use for comparison. Doing this we support BMPstring,
- UTF8 etc. */
-
- if (i>=0) {
- ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
-
- /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
- is already UTF-8 encoded. We check for this case and copy the raw
- string manually to avoid the problem. This code can be made
- conditional in the future when OpenSSL has been fixed. Work-around
- brought by Alexis S. L. Carvalho. */
- if (tmp && ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
- j = ASN1_STRING_length(tmp);
- if (j >= 0) {
- peer_CN = OPENSSL_malloc(j+1);
- if (peer_CN) {
- memcpy(peer_CN, ASN1_STRING_data(tmp), j);
- peer_CN[j] = '\0';
- }
- }
- }
- else /* not a UTF8 name */
- j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
- }
-
- if (peer_CN == nulstr)
- peer_CN = NULL;
-#ifdef CURL_DOES_CONVERSIONS
- else {
- /* convert peer_CN from UTF8 */
- size_t rc;
- rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
- /* Curl_convert_from_utf8 calls failf if unsuccessful */
- if (rc != CURLE_OK) {
- return(rc);
- }
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- if (!peer_CN) {
- if(data->set.ssl.verifyhost > 1) {
- failf(data,
- "SSL: unable to obtain common name from peer certificate");
- return CURLE_SSL_PEER_CERTIFICATE;
- }
- else {
- /* Consider verifyhost == 1 as an "OK" for a missing CN field, but we
- output a note about the situation */
- infof(data, "\t common name: WARNING couldn't obtain\n");
- }
- }
- else if(!cert_hostcheck((const char *)peer_CN, conn->host.name)) {
- if(data->set.ssl.verifyhost > 1) {
- failf(data, "SSL: certificate subject name '%s' does not match "
- "target host name '%s'", peer_CN, conn->host.dispname);
- res = CURLE_SSL_PEER_CERTIFICATE;
- }
- else
- infof(data, "\t common name: %s (does not match '%s')\n",
- peer_CN, conn->host.dispname);
- }
- else {
- infof(data, "\t common name: %s (matched)\n", peer_CN);
- }
- if(peer_CN)
- OPENSSL_free(peer_CN);
- }
- return res;
-}
-#endif
-
-/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
- and thus this cannot be done there. */
-#ifdef SSL_CTRL_SET_MSG_CALLBACK
-
-static const char *ssl_msg_type(int ssl_ver, int msg)
-{
- if (ssl_ver == SSL2_VERSION_MAJOR) {
- switch (msg) {
- case SSL2_MT_ERROR:
- return "Error";
- case SSL2_MT_CLIENT_HELLO:
- return "Client hello";
- case SSL2_MT_CLIENT_MASTER_KEY:
- return "Client key";
- case SSL2_MT_CLIENT_FINISHED:
- return "Client finished";
- case SSL2_MT_SERVER_HELLO:
- return "Server hello";
- case SSL2_MT_SERVER_VERIFY:
- return "Server verify";
- case SSL2_MT_SERVER_FINISHED:
- return "Server finished";
- case SSL2_MT_REQUEST_CERTIFICATE:
- return "Request CERT";
- case SSL2_MT_CLIENT_CERTIFICATE:
- return "Client CERT";
- }
- }
- else if (ssl_ver == SSL3_VERSION_MAJOR) {
- switch (msg) {
- case SSL3_MT_HELLO_REQUEST:
- return "Hello request";
- case SSL3_MT_CLIENT_HELLO:
- return "Client hello";
- case SSL3_MT_SERVER_HELLO:
- return "Server hello";
- case SSL3_MT_CERTIFICATE:
- return "CERT";
- case SSL3_MT_SERVER_KEY_EXCHANGE:
- return "Server key exchange";
- case SSL3_MT_CLIENT_KEY_EXCHANGE:
- return "Client key exchange";
- case SSL3_MT_CERTIFICATE_REQUEST:
- return "Request CERT";
- case SSL3_MT_SERVER_DONE:
- return "Server finished";
- case SSL3_MT_CERTIFICATE_VERIFY:
- return "CERT verify";
- case SSL3_MT_FINISHED:
- return "Finished";
- }
- }
- return "Unknown";
-}
-
-static const char *tls_rt_type(int type)
-{
- return (
- type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
- type == SSL3_RT_ALERT ? "TLS alert, " :
- type == SSL3_RT_HANDSHAKE ? "TLS handshake, " :
- type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " :
- "TLS Unknown, ");
-}
-
-
-/*
- * Our callback from the SSL/TLS layers.
- */
-static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
- const void *buf, size_t len, const SSL *ssl,
- struct connectdata *conn)
-{
- struct SessionHandle *data;
- const char *msg_name, *tls_rt_name;
- char ssl_buf[1024];
- int ver, msg_type, txt_len;
-
- if (!conn || !conn->data || !conn->data->set.fdebug ||
- (direction != 0 && direction != 1))
- return;
-
- data = conn->data;
- ssl_ver >>= 8;
- ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
- ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
-
- /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
- * always pass-up content-type as 0. But the interesting message-type
- * is at 'buf[0]'.
- */
- if (ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
- tls_rt_name = tls_rt_type(content_type);
- else
- tls_rt_name = "";
-
- msg_type = *(char*)buf;
- msg_name = ssl_msg_type(ssl_ver, msg_type);
-
- txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n",
- ver, tls_rt_name, msg_name, msg_type);
- Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
-
- Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
- CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
- (void) ssl;
-}
-#endif
-
-#ifdef USE_SSLEAY
-/* ====================================================== */
-
-static CURLcode
-Curl_ossl_connect_step1(struct connectdata *conn,
- int sockindex)
-{
- CURLcode retcode = CURLE_OK;
-
- struct SessionHandle *data = conn->data;
- SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
- void *ssl_sessionid=NULL;
- curl_socket_t sockfd = conn->sock[sockindex];
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- curlassert(ssl_connect_1 == connssl->connecting_state);
-
- /* Make funny stuff to get random input */
- Curl_ossl_seed(data);
-
- /* check to see if we've been told to use an explicit SSL/TLS version */
- switch(data->set.ssl.version) {
- default:
- case CURL_SSLVERSION_DEFAULT:
- /* we try to figure out version */
- req_method = SSLv23_client_method();
- break;
- case CURL_SSLVERSION_TLSv1:
- req_method = TLSv1_client_method();
- break;
- case CURL_SSLVERSION_SSLv2:
-#ifdef OPENSSL_NO_SSL2
- failf(data, "OpenSSL was built without SSLv2 support");
- return CURLE_NOT_BUILT_IN;
-#else
- req_method = SSLv2_client_method();
- break;
-#endif
- case CURL_SSLVERSION_SSLv3:
- req_method = SSLv3_client_method();
- break;
- }
-
- if (connssl->ctx)
- SSL_CTX_free(connssl->ctx);
- connssl->ctx = SSL_CTX_new(req_method);
-
- if(!connssl->ctx) {
- failf(data, "SSL: couldn't create a context!");
- return CURLE_OUT_OF_MEMORY;
- }
-
-#ifdef SSL_CTRL_SET_MSG_CALLBACK
- if (data->set.fdebug && data->set.verbose) {
- /* the SSL trace callback is only used for verbose logging so we only
- inform about failures of setting it */
- if (!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
- (void (*)(void))ssl_tls_trace)) {
- infof(data, "SSL: couldn't set callback!\n");
- }
- else if (!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0,
- conn)) {
- infof(data, "SSL: couldn't set callback argument!\n");
- }
- }
-#endif
-
- /* OpenSSL contains code to work-around lots of bugs and flaws in various
- SSL-implementations. SSL_CTX_set_options() is used to enabled those
- work-arounds. The man page for this option states that SSL_OP_ALL enables
- all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
- enable the bug workaround options if compatibility with somewhat broken
- implementations is desired."
-
- */
- SSL_CTX_set_options(connssl->ctx, SSL_OP_ALL);
-
-#if 0
- /*
- * Not sure it's needed to tell SSL_connect() that socket is
- * non-blocking. It doesn't seem to care, but just return with
- * SSL_ERROR_WANT_x.
- */
- if (data->state.used_interface == Curl_if_multi)
- SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
-#endif
-
- if(data->set.cert) {
- if(!cert_stuff(conn,
- connssl->ctx,
- data->set.cert,
- data->set.cert_type,
- data->set.key,
- data->set.key_type)) {
- /* failf() is already done in cert_stuff() */
- return CURLE_SSL_CERTPROBLEM;
- }
- }
-
- if(data->set.ssl.cipher_list) {
- if(!SSL_CTX_set_cipher_list(connssl->ctx,
- data->set.ssl.cipher_list)) {
- failf(data, "failed setting cipher list");
- return CURLE_SSL_CIPHER;
- }
- }
-
- if (data->set.ssl.CAfile || data->set.ssl.CApath) {
- /* tell SSL where to find CA certificates that are used to verify
- the servers certificate. */
- if (!SSL_CTX_load_verify_locations(connssl->ctx, data->set.ssl.CAfile,
- data->set.ssl.CApath)) {
- if (data->set.ssl.verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data,"error setting certificate verify locations:\n"
- " CAfile: %s\n CApath: %s\n",
- data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
- data->set.ssl.CApath ? data->set.ssl.CApath : "none");
- return CURLE_SSL_CACERT_BADFILE;
- }
- else {
- /* Just continue with a warning if no strict certificate verification
- is required. */
- infof(data, "error setting certificate verify locations,"
- " continuing anyway:\n");
- }
- }
- else {
- /* Everything is fine. */
- infof(data, "successfully set certificate verify locations:\n");
- }
- infof(data,
- " CAfile: %s\n"
- " CApath: %s\n",
- data->set.ssl.CAfile ? data->set.ssl.CAfile : "none",
- data->set.ssl.CApath ? data->set.ssl.CApath : "none");
- }
- /* SSL always tries to verify the peer, this only says whether it should
- * fail to connect if the verification fails, or if it should continue
- * anyway. In the latter case the result of the verification is checked with
- * SSL_get_verify_result() below. */
- SSL_CTX_set_verify(connssl->ctx,
- data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
- cert_verify_callback);
-
- /* give application a chance to interfere with SSL set up. */
- if(data->set.ssl.fsslctx) {
- retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
- data->set.ssl.fsslctxp);
- if(retcode) {
- failf(data,"error signaled by ssl ctx callback");
- return retcode;
- }
- }
-
- /* Lets make an SSL structure */
- if (connssl->handle)
- SSL_free(connssl->handle);
- connssl->handle = SSL_new(connssl->ctx);
- if (!connssl->handle) {
- failf(data, "SSL: couldn't create a context (handle)!");
- return CURLE_OUT_OF_MEMORY;
- }
- SSL_set_connect_state(connssl->handle);
-
- connssl->server_cert = 0x0;
-
- /* Check if there's a cached ID we can/should use here! */
- if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
- /* we got a session id, use it! */
- if (!SSL_set_session(connssl->handle, ssl_sessionid)) {
- failf(data, "SSL: SSL_set_session failed: %s",
- ERR_error_string(ERR_get_error(),NULL));
- return CURLE_SSL_CONNECT_ERROR;
- }
- /* Informational message */
- infof (data, "SSL re-using session ID\n");
- }
-
- /* pass the raw socket into the SSL layers */
- if (!SSL_set_fd(connssl->handle, sockfd)) {
- failf(data, "SSL: SSL_set_fd failed: %s",
- ERR_error_string(ERR_get_error(),NULL));
- return CURLE_SSL_CONNECT_ERROR;
- }
-
- connssl->connecting_state = ssl_connect_2;
- return CURLE_OK;
-}
-
-static CURLcode
-Curl_ossl_connect_step2(struct connectdata *conn,
- int sockindex, long *timeout_ms)
-{
- struct SessionHandle *data = conn->data;
- int err;
- long has_passed;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- curlassert(ssl_connect_2 == connssl->connecting_state
- || ssl_connect_2_reading == connssl->connecting_state
- || ssl_connect_2_writing == connssl->connecting_state);
-
- /* Find out if any timeout is set. If not, use 300 seconds.
- Otherwise, figure out the most strict timeout of the two possible one
- and then how much time that has elapsed to know how much time we
- allow for the connect call */
- if(data->set.timeout && data->set.connecttimeout) {
- /* get the most strict timeout of the ones converted to milliseconds */
- if(data->set.timeout<data->set.connecttimeout)
- *timeout_ms = data->set.timeout*1000;
- else
- *timeout_ms = data->set.connecttimeout*1000;
- }
- else if(data->set.timeout)
- *timeout_ms = data->set.timeout*1000;
- else if(data->set.connecttimeout)
- *timeout_ms = data->set.connecttimeout*1000;
- else
- /* no particular time-out has been set */
- *timeout_ms= DEFAULT_CONNECT_TIMEOUT;
-
- /* Evaluate in milliseconds how much time that has passed */
- has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
-
- /* subtract the passed time */
- *timeout_ms -= has_passed;
-
- if(*timeout_ms < 0) {
- /* a precaution, no need to continue if time already is up */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEOUTED;
- }
-
- err = SSL_connect(connssl->handle);
-
- /* 1 is fine
- 0 is "not successful but was shut down controlled"
- <0 is "handshake was not successful, because a fatal error occurred" */
- if(1 != err) {
- int detail = SSL_get_error(connssl->handle, err);
-
- if(SSL_ERROR_WANT_READ == detail) {
- connssl->connecting_state = ssl_connect_2_reading;
- return CURLE_OK;
- }
- else if(SSL_ERROR_WANT_WRITE == detail) {
- connssl->connecting_state = ssl_connect_2_writing;
- return CURLE_OK;
- }
- else {
- /* untreated error */
- unsigned long errdetail;
- char error_buffer[256]; /* OpenSSL documents that this must be at least
- 256 bytes long. */
- CURLcode rc;
- const char *cert_problem = NULL;
-
- connssl->connecting_state = ssl_connect_2; /* the connection failed,
- we're not waiting for
- anything else. */
-
- errdetail = ERR_get_error(); /* Gets the earliest error code from the
- thread's error queue and removes the
- entry. */
-
- switch(errdetail) {
- case 0x1407E086:
- /* 1407E086:
- SSL routines:
- SSL2_SET_CERTIFICATE:
- certificate verify failed */
- /* fall-through */
- case 0x14090086:
- /* 14090086:
- SSL routines:
- SSL3_GET_SERVER_CERTIFICATE:
- certificate verify failed */
- cert_problem = "SSL certificate problem, verify that the CA cert is"
- " OK. Details:\n";
- rc = CURLE_SSL_CACERT;
- break;
- default:
- rc = CURLE_SSL_CONNECT_ERROR;
- break;
- }
-
- /* detail is already set to the SSL error above */
-
- /* If we e.g. use SSLv2 request-method and the server doesn't like us
- * (RST connection etc.), OpenSSL gives no explanation whatsoever and
- * the SO_ERROR is also lost.
- */
- if (CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
- failf(data, "Unknown SSL protocol error in connection to %s:%d ",
- conn->host.name, conn->port);
- return rc;
- }
- /* Could be a CERT problem */
-
- SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
- failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
- return rc;
- }
- }
- else {
- /* we have been connected fine, we're not waiting for anything else. */
- connssl->connecting_state = ssl_connect_3;
-
- /* Informational message */
- infof (data, "SSL connection using %s\n",
- SSL_get_cipher(connssl->handle));
-
- return CURLE_OK;
- }
-}
-
-static CURLcode
-Curl_ossl_connect_step3(struct connectdata *conn,
- int sockindex)
-{
- CURLcode retcode = CURLE_OK;
- char * str;
- long lerr;
- ASN1_TIME *certdate;
- void *ssl_sessionid=NULL;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
-
- curlassert(ssl_connect_3 == connssl->connecting_state);
-
- if(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
- /* Since this is not a cached session ID, then we want to stach this one
- in the cache! */
- SSL_SESSION *our_ssl_sessionid;
-#ifdef HAVE_SSL_GET1_SESSION
- our_ssl_sessionid = SSL_get1_session(connssl->handle);
-
- /* SSL_get1_session() will increment the reference
- count and the session will stay in memory until explicitly freed with
- SSL_SESSION_free(3), regardless of its state.
- This function was introduced in openssl 0.9.5a. */
-#else
- our_ssl_sessionid = SSL_get_session(connssl->handle);
-
- /* if SSL_get1_session() is unavailable, use SSL_get_session().
- This is an inferior option because the session can be flushed
- at any time by openssl. It is included only so curl compiles
- under versions of openssl < 0.9.5a.
-
- WARNING: How curl behaves if it's session is flushed is
- untested.
- */
-#endif
- retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
- 0 /* unknown size */);
- if(retcode) {
- failf(data, "failed to store ssl session");
- return retcode;
- }
- }
-
-
- /* Get server's certificate (note: beware of dynamic allocation) - opt */
- /* major serious hack alert -- we should check certificates
- * to authenticate the server; otherwise we risk man-in-the-middle
- * attack
- */
-
- connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
- if(!connssl->server_cert) {
- failf(data, "SSL: couldn't get peer certificate!");
- return CURLE_SSL_PEER_CERTIFICATE;
- }
- infof (data, "Server certificate:\n");
-
- str = X509_NAME_oneline(X509_get_subject_name(connssl->server_cert),
- NULL, 0);
- if(!str) {
- failf(data, "SSL: couldn't get X509-subject!");
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- return CURLE_SSL_CONNECT_ERROR;
- }
- infof(data, "\t subject: %s\n", str);
- CRYPTO_free(str);
-
- certdate = X509_get_notBefore(connssl->server_cert);
- Curl_ASN1_UTCTIME_output(conn, "\t start date: ", certdate);
-
- certdate = X509_get_notAfter(connssl->server_cert);
- Curl_ASN1_UTCTIME_output(conn, "\t expire date: ", certdate);
-
- if(data->set.ssl.verifyhost) {
- retcode = verifyhost(conn, connssl->server_cert);
- if(retcode) {
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- return retcode;
- }
- }
-
- str = X509_NAME_oneline(X509_get_issuer_name(connssl->server_cert),
- NULL, 0);
- if(!str) {
- failf(data, "SSL: couldn't get X509-issuer name!");
- retcode = CURLE_SSL_CONNECT_ERROR;
- }
- else {
- infof(data, "\t issuer: %s\n", str);
- CRYPTO_free(str);
-
- /* We could do all sorts of certificate verification stuff here before
- deallocating the certificate. */
-
- lerr = data->set.ssl.certverifyresult=
- SSL_get_verify_result(connssl->handle);
- if(data->set.ssl.certverifyresult != X509_V_OK) {
- if(data->set.ssl.verifypeer) {
- /* We probably never reach this, because SSL_connect() will fail
- and we return earlyer if verifypeer is set? */
- failf(data, "SSL certificate verify result: %s (%ld)",
- X509_verify_cert_error_string(lerr), lerr);
- retcode = CURLE_SSL_PEER_CERTIFICATE;
- }
- else
- infof(data, "SSL certificate verify result: %s (%ld),"
- " continuing anyway.\n",
- X509_verify_cert_error_string(lerr), lerr);
- }
- else
- infof(data, "SSL certificate verify ok.\n");
- }
-
- X509_free(connssl->server_cert);
- connssl->server_cert = NULL;
- connssl->connecting_state = ssl_connect_done;
- return retcode;
-}
-
-static CURLcode
-Curl_ossl_connect_common(struct connectdata *conn,
- int sockindex,
- bool nonblocking,
- bool *done)
-{
- CURLcode retcode;
- struct SessionHandle *data = conn->data;
- struct ssl_connect_data *connssl = &conn->ssl[sockindex];
- curl_socket_t sockfd = conn->sock[sockindex];
- long timeout_ms;
-
- if (ssl_connect_1==connssl->connecting_state) {
- retcode = Curl_ossl_connect_step1(conn, sockindex);
- if (retcode)
- return retcode;
- }
-
- timeout_ms = 0;
- while (ssl_connect_2 == connssl->connecting_state ||
- ssl_connect_2_reading == connssl->connecting_state ||
- ssl_connect_2_writing == connssl->connecting_state) {
-
- /* if ssl is expecting something, check if it's available. */
- if (connssl->connecting_state == ssl_connect_2_reading
- || connssl->connecting_state == ssl_connect_2_writing) {
-
- int writefd = ssl_connect_2_writing==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
- int readfd = ssl_connect_2_reading==
- connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
-
- while(1) {
- int what = Curl_select(readfd, writefd, nonblocking?0:(int)timeout_ms);
- if(what > 0)
- /* readable or writable, go loop in the outer loop */
- break;
- else if(0 == what) {
- if (nonblocking) {
- *done = FALSE;
- return CURLE_OK;
- }
- else {
- /* timeout */
- failf(data, "SSL connection timeout");
- return CURLE_OPERATION_TIMEDOUT;
- }
- }
- else {
- /* anything that gets here is fatally bad */
- failf(data, "select on SSL socket, errno: %d", Curl_sockerrno());
- return CURLE_SSL_CONNECT_ERROR;
- }
- } /* while()-loop for the select() */
- }
-
- /* get the timeout from step2 to avoid computing it twice. */
- retcode = Curl_ossl_connect_step2(conn, sockindex, &timeout_ms);
- if (retcode)
- return retcode;
-
- } /* repeat step2 until all transactions are done. */
-
-
- if (ssl_connect_3==connssl->connecting_state) {
- retcode = Curl_ossl_connect_step3(conn, sockindex);
- if (retcode)
- return retcode;
- }
-
- if (ssl_connect_done==connssl->connecting_state) {
- *done = TRUE;
- }
- else {
- *done = FALSE;
- }
-
- /* Reset our connect state machine */
- connssl->connecting_state = ssl_connect_1;
-
- return CURLE_OK;
-}
-
-CURLcode
-Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done)
-{
- return Curl_ossl_connect_common(conn, sockindex, TRUE, done);
-}
-
-CURLcode
-Curl_ossl_connect(struct connectdata *conn,
- int sockindex)
-{
- CURLcode retcode;
- bool done = FALSE;
-
- retcode = Curl_ossl_connect_common(conn, sockindex, FALSE, &done);
- if (retcode)
- return retcode;
-
- curlassert(done);
-
- return CURLE_OK;
-}
-
-/* return number of sent (non-SSL) bytes */
-ssize_t Curl_ossl_send(struct connectdata *conn,
- int sockindex,
- void *mem,
- size_t len)
-{
- /* SSL_write() is said to return 'int' while write() and send() returns
- 'size_t' */
- int err;
- char error_buffer[120]; /* OpenSSL documents that this must be at least 120
- bytes long. */
- unsigned long sslerror;
- int rc = SSL_write(conn->ssl[sockindex].handle, mem, (int)len);
-
- if(rc < 0) {
- err = SSL_get_error(conn->ssl[sockindex].handle, rc);
-
- switch(err) {
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* The operation did not complete; the same TLS/SSL I/O function
- should be called again later. This is basicly an EWOULDBLOCK
- equivalent. */
- return 0;
- case SSL_ERROR_SYSCALL:
- failf(conn->data, "SSL_write() returned SYSCALL, errno = %d\n",
- Curl_sockerrno());
- return -1;
- case SSL_ERROR_SSL:
- /* A failure in the SSL library occurred, usually a protocol error.
- The OpenSSL error queue contains more information on the error. */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL_write() error: %s\n",
- ERR_error_string(sslerror, error_buffer));
- return -1;
- }
- /* a true error */
- failf(conn->data, "SSL_write() return error %d\n", err);
- return -1;
- }
- return (ssize_t)rc; /* number of bytes */
-}
-
-/*
- * If the read would block we return -1 and set 'wouldblock' to TRUE.
- * Otherwise we return the amount of data read. Other errors should return -1
- * and set 'wouldblock' to FALSE.
- */
-ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- bool *wouldblock)
-{
- char error_buffer[120]; /* OpenSSL documents that this must be at
- least 120 bytes long. */
- unsigned long sslerror;
- ssize_t nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf,
- (int)buffersize);
- *wouldblock = FALSE;
- if(nread < 0) {
- /* failed SSL_read */
- int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
-
- switch(err) {
- case SSL_ERROR_NONE: /* this is not an error */
- case SSL_ERROR_ZERO_RETURN: /* no more data */
- break;
- case SSL_ERROR_WANT_READ:
- case SSL_ERROR_WANT_WRITE:
- /* there's data pending, re-invoke SSL_read() */
- *wouldblock = TRUE;
- return -1; /* basically EWOULDBLOCK */
- default:
- /* openssl/ssl.h says "look at error stack/return value/errno" */
- sslerror = ERR_get_error();
- failf(conn->data, "SSL read: %s, errno %d",
- ERR_error_string(sslerror, error_buffer),
- Curl_sockerrno() );
- return -1;
- }
- }
- return nread;
-}
-
-size_t Curl_ossl_version(char *buffer, size_t size)
-{
-#ifdef YASSL_VERSION
- /* yassl provides an OpenSSL API compatiblity layer so it looks identical
- to OpenSSL in all other aspects */
- return snprintf(buffer, size, " yassl/%s", YASSL_VERSION);
-#else /* YASSL_VERSION */
-
-#if (SSLEAY_VERSION_NUMBER >= 0x905000)
- {
- char sub[2];
- unsigned long ssleay_value;
- sub[1]='\0';
- ssleay_value=SSLeay();
- if(ssleay_value < 0x906000) {
- ssleay_value=SSLEAY_VERSION_NUMBER;
- sub[0]='\0';
- }
- else {
- if(ssleay_value&0xff0) {
- sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
- }
- else
- sub[0]='\0';
- }
-
- return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx%s",
- (ssleay_value>>28)&0xf,
- (ssleay_value>>20)&0xff,
- (ssleay_value>>12)&0xff,
- sub);
- }
-
-#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
-
-#if (SSLEAY_VERSION_NUMBER >= 0x900000)
- return snprintf(buffer, size, " OpenSSL/%lx.%lx.%lx",
- (SSLEAY_VERSION_NUMBER>>28)&0xff,
- (SSLEAY_VERSION_NUMBER>>20)&0xff,
- (SSLEAY_VERSION_NUMBER>>12)&0xf);
-
-#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
- {
- char sub[2];
- sub[1]='\0';
- if(SSLEAY_VERSION_NUMBER&0x0f) {
- sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1;
- }
- else
- sub[0]='\0';
-
- return snprintf(buffer, size, " SSL/%x.%x.%x%s",
- (SSLEAY_VERSION_NUMBER>>12)&0xff,
- (SSLEAY_VERSION_NUMBER>>8)&0xf,
- (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
- }
-#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
-#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
-
-#endif /* YASSL_VERSION */
-}
-#endif /* USE_SSLEAY */
diff --git a/Utilities/cmcurl/ssluse.h b/Utilities/cmcurl/ssluse.h
deleted file mode 100644
index 5bb7090c5..000000000
--- a/Utilities/cmcurl/ssluse.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __SSLUSE_H
-#define __SSLUSE_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * This header should only be needed to get included by sslgen.c and ssluse.c
- */
-
-#include "urldata.h"
-CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
-CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
- int sockindex,
- bool *done);
-void Curl_ossl_close(struct connectdata *conn); /* close a SSL connection */
-/* tell OpenSSL to close down all open information regarding connections (and
- thus session ID caching etc) */
-int Curl_ossl_close_all(struct SessionHandle *data);
-/* Sets an OpenSSL engine */
-CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);
-
-/* function provided for the generic SSL-layer, called when a session id
- should be freed */
-void Curl_ossl_session_free(void *ptr);
-
-/* Sets engine as default for all SSL operations */
-CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
-
-/* Build list of OpenSSL engines */
-struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
-
-int Curl_ossl_init(void);
-void Curl_ossl_cleanup(void);
-
-ssize_t Curl_ossl_send(struct connectdata *conn,
- int sockindex,
- void *mem,
- size_t len);
-ssize_t Curl_ossl_recv(struct connectdata *conn, /* connection data */
- int num, /* socketindex */
- char *buf, /* store read data here */
- size_t buffersize, /* max amount to read */
- bool *wouldblock);
-
-size_t Curl_ossl_version(char *buffer, size_t size);
-int Curl_ossl_check_cxn(struct connectdata *cxn);
-int Curl_ossl_seed(struct SessionHandle *data);
-
-int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
-
-#endif
diff --git a/Utilities/cmcurl/strdup.c b/Utilities/cmcurl/strdup.c
deleted file mode 100644
index e16e08a72..000000000
--- a/Utilities/cmcurl/strdup.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include "strdup.h"
-
-#ifndef HAVE_STRDUP
-char *curlx_strdup(const char *str)
-{
- int len;
- char *newstr;
-
- if (!str)
- return (char *)NULL;
-
- len = strlen(str);
- newstr = (char *) malloc((len+1)*sizeof(char));
- if (!newstr)
- return (char *)NULL;
-
- strcpy(newstr,str);
-
- return newstr;
-
-}
-#endif
diff --git a/Utilities/cmcurl/strdup.h b/Utilities/cmcurl/strdup.h
deleted file mode 100644
index 3206db3cf..000000000
--- a/Utilities/cmcurl/strdup.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifndef _CURL_STRDUP_H
-#define _CURL_STRDUP_H
-
-#include "setup.h"
-
-#ifndef HAVE_STRDUP
-extern char *curlx_strdup(const char *str);
-#endif
-
-#endif
-
diff --git a/Utilities/cmcurl/strequal.c b/Utilities/cmcurl/strequal.c
deleted file mode 100644
index 83796f667..000000000
--- a/Utilities/cmcurl/strequal.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <ctype.h>
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-
-#include "strequal.h"
-
-#if defined(HAVE_STRCASECMP) && defined(__STRICT_ANSI__)
-/* this is for "-ansi -Wall -pedantic" to stop complaining! */
-extern int (strcasecmp)(const char *s1, const char *s2);
-extern int (strncasecmp)(const char *s1, const char *s2, size_t n);
-#endif
-
-int curl_strequal(const char *first, const char *second)
-{
-#if defined(HAVE_STRCASECMP)
- return !(strcasecmp)(first, second);
-#elif defined(HAVE_STRCMPI)
- return !(strcmpi)(first, second);
-#elif defined(HAVE_STRICMP)
- return !(stricmp)(first, second);
-#else
- while (*first && *second) {
- if (toupper(*first) != toupper(*second)) {
- break;
- }
- first++;
- second++;
- }
- return toupper(*first) == toupper(*second);
-#endif
-}
-
-int curl_strnequal(const char *first, const char *second, size_t max)
-{
-#if defined(HAVE_STRCASECMP)
- return !strncasecmp(first, second, max);
-#elif defined(HAVE_STRCMPI)
- return !strncmpi(first, second, max);
-#elif defined(HAVE_STRICMP)
- return !strnicmp(first, second, max);
-#else
- while (*first && *second && max) {
- if (toupper(*first) != toupper(*second)) {
- break;
- }
- max--;
- first++;
- second++;
- }
- if(0 == max)
- return 1; /* they are equal this far */
-
- return toupper(*first) == toupper(*second);
-#endif
-}
-
-/*
- * Curl_strcasestr() finds the first occurrence of the substring needle in the
- * string haystack. The terminating `\0' characters are not compared. The
- * matching is done CASE INSENSITIVE, which thus is the difference between
- * this and strstr().
- */
-char *Curl_strcasestr(const char *haystack, const char *needle)
-{
- size_t nlen = strlen(needle);
- size_t hlen = strlen(haystack);
-
- while(hlen-- >= nlen) {
- if(curl_strnequal(haystack, needle, nlen))
- return (char *)haystack;
- haystack++;
- }
- return NULL;
-}
diff --git a/Utilities/cmcurl/strequal.h b/Utilities/cmcurl/strequal.h
deleted file mode 100644
index 6718c3c0e..000000000
--- a/Utilities/cmcurl/strequal.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __STREQUAL_H
-#define __STREQUAL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <curl/curl.h>
-
-#define strequal(a,b) curl_strequal(a,b)
-#define strnequal(a,b,c) curl_strnequal(a,b,c)
-
-/* checkprefix() is a shorter version of the above, used when the first
- argument is zero-byte terminated */
-#define checkprefix(a,b) strnequal(a,b,strlen(a))
-
-/* case insensitive strstr() */
-char *Curl_strcasestr(const char *haystack, const char *needle);
-
-#endif
diff --git a/Utilities/cmcurl/strerror.c b/Utilities/cmcurl/strerror.c
deleted file mode 100644
index 74c345779..000000000
--- a/Utilities/cmcurl/strerror.c
+++ /dev/null
@@ -1,751 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 2004 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifdef HAVE_STRERROR_R
-#if !defined(HAVE_POSIX_STRERROR_R) && !defined(HAVE_GLIBC_STRERROR_R)
-#error "you MUST have either POSIX or glibc strerror_r if strerror_r is found"
-#endif /* !POSIX && !glibc */
-#endif /* HAVE_STRERROR_R */
-
-#include <curl/curl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#ifdef USE_LIBIDN
-#include <idna.h>
-#endif
-
-#include "strerror.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#if defined(HAVE_STRERROR_R) && defined(HAVE_NO_STRERROR_R_DECL)
-#ifdef HAVE_POSIX_STRERROR_R
-/* seen on AIX 5100-02 gcc 2.9 */
-extern int strerror_r(int errnum, char *strerrbuf, size_t buflen);
-#else
-extern char *strerror_r(int errnum, char *buf, size_t buflen);
-#endif
-#endif
-
-const char *
-curl_easy_strerror(CURLcode error)
-{
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- switch (error) {
- case CURLE_OK:
- return "no error";
-
- case CURLE_UNSUPPORTED_PROTOCOL:
- return "unsupported protocol";
-
- case CURLE_FAILED_INIT:
- return "failed init";
-
- case CURLE_URL_MALFORMAT:
- return "URL using bad/illegal format or missing URL";
-
- case CURLE_NOT_BUILT_IN:
- return "A requested feature, protocol or option was not found built-in in"
- " this libcurl due to a build-time decision.";
-
- case CURLE_COULDNT_RESOLVE_PROXY:
- return "couldn't resolve proxy name";
-
- case CURLE_COULDNT_RESOLVE_HOST:
- return "couldn't resolve host name";
-
- case CURLE_COULDNT_CONNECT:
- return "couldn't connect to server";
-
- case CURLE_FTP_WEIRD_SERVER_REPLY:
- return "FTP: weird server reply";
-
- case CURLE_FTP_ACCESS_DENIED:
- return "FTP: access denied";
-
- case CURLE_FTP_WEIRD_PASS_REPLY:
- return "FTP: unknown PASS reply";
-
- case CURLE_FTP_WEIRD_USER_REPLY:
- return "FTP: unknown USER reply";
-
- case CURLE_FTP_WEIRD_PASV_REPLY:
- return "FTP: unknown PASV reply";
-
- case CURLE_FTP_WEIRD_227_FORMAT:
- return "FTP: unknown 227 response format";
-
- case CURLE_FTP_CANT_GET_HOST:
- return "FTP: can't figure out the host in the PASV response";
-
- case CURLE_FTP_CANT_RECONNECT:
- return "FTP: can't connect to server the response code is unknown";
-
- case CURLE_FTP_COULDNT_SET_BINARY:
- return "FTP: couldn't set binary mode";
-
- case CURLE_PARTIAL_FILE:
- return "Transferred a partial file";
-
- case CURLE_FTP_COULDNT_RETR_FILE:
- return "FTP: couldn't retrieve (RETR failed) the specified file";
-
- case CURLE_FTP_WRITE_ERROR:
- return "FTP: the post-transfer acknowledge response was not OK";
-
- case CURLE_FTP_QUOTE_ERROR:
- return "FTP: a quote command returned error";
-
- case CURLE_HTTP_RETURNED_ERROR:
- return "HTTP response code said error";
-
- case CURLE_WRITE_ERROR:
- return "failed writing received data to disk/application";
-
- case CURLE_FTP_COULDNT_STOR_FILE:
- return "failed FTP upload (the STOR command)";
-
- case CURLE_READ_ERROR:
- return "failed to open/read local data from file/application";
-
- case CURLE_OUT_OF_MEMORY:
-#ifdef CURL_DOES_CONVERSIONS
- return "conversion failed -or- out of memory";
-#else
- return "out of memory";
-#endif /* CURL_DOES_CONVERSIONS */
-
- case CURLE_OPERATION_TIMEOUTED:
- return "a timeout was reached";
-
- case CURLE_FTP_COULDNT_SET_ASCII:
- return "FTP could not set ASCII mode (TYPE A)";
-
- case CURLE_FTP_PORT_FAILED:
- return "FTP command PORT failed";
-
- case CURLE_FTP_COULDNT_USE_REST:
- return "FTP command REST failed";
-
- case CURLE_FTP_COULDNT_GET_SIZE:
- return "FTP command SIZE failed";
-
- case CURLE_HTTP_RANGE_ERROR:
- return "a range was requested but the server did not deliver it";
-
- case CURLE_HTTP_POST_ERROR:
- return "internal problem setting up the POST";
-
- case CURLE_SSL_CONNECT_ERROR:
- return "SSL connect error";
-
- case CURLE_BAD_DOWNLOAD_RESUME:
- return "couldn't resume download";
-
- case CURLE_FILE_COULDNT_READ_FILE:
- return "couldn't read a file:// file";
-
- case CURLE_LDAP_CANNOT_BIND:
- return "LDAP: cannot bind";
-
- case CURLE_LDAP_SEARCH_FAILED:
- return "LDAP: search failed";
-
- case CURLE_LIBRARY_NOT_FOUND:
- return "a required shared library was not found";
-
- case CURLE_FUNCTION_NOT_FOUND:
- return "a required function in the shared library was not found";
-
- case CURLE_ABORTED_BY_CALLBACK:
- return "the operation was aborted by an application callback";
-
- case CURLE_BAD_FUNCTION_ARGUMENT:
- return "a libcurl function was given a bad argument";
-
- case CURLE_INTERFACE_FAILED:
- return "failed binding local connection end";
-
- case CURLE_TOO_MANY_REDIRECTS :
- return "number of redirects hit maximum amount";
-
- case CURLE_UNKNOWN_TELNET_OPTION:
- return "User specified an unknown option";
-
- case CURLE_TELNET_OPTION_SYNTAX :
- return "Malformed telnet option";
-
- case CURLE_SSL_PEER_CERTIFICATE:
- return "SSL peer certificate was not ok";
-
- case CURLE_GOT_NOTHING:
- return "server returned nothing (no headers, no data)";
-
- case CURLE_SSL_ENGINE_NOTFOUND:
- return "SSL crypto engine not found";
-
- case CURLE_SSL_ENGINE_SETFAILED:
- return "can not set SSL crypto engine as default";
-
- case CURLE_SSL_ENGINE_INITFAILED:
- return "failed to initialise SSL crypto engine";
-
- case CURLE_SEND_ERROR:
- return "failed sending data to the peer";
-
- case CURLE_RECV_ERROR:
- return "failure when receiving data from the peer";
-
- case CURLE_SHARE_IN_USE:
- return "share is already in use";
-
- case CURLE_SSL_CERTPROBLEM:
- return "problem with the local SSL certificate";
-
- case CURLE_SSL_CIPHER:
- return "couldn't use specified SSL cipher";
-
- case CURLE_SSL_CACERT:
- return "peer certificate cannot be authenticated with known CA certificates";
-
- case CURLE_SSL_CACERT_BADFILE:
- return "problem with the SSL CA cert (path? access rights?)";
-
- case CURLE_BAD_CONTENT_ENCODING:
- return "Unrecognized HTTP Content-Encoding";
-
- case CURLE_LDAP_INVALID_URL:
- return "Invalid LDAP URL";
-
- case CURLE_FILESIZE_EXCEEDED:
- return "Maximum file size exceeded";
-
- case CURLE_FTP_SSL_FAILED:
- return "Requested FTP SSL level failed";
-
- case CURLE_SSL_SHUTDOWN_FAILED:
- return "Failed to shut down the SSL connection";
-
- case CURLE_SEND_FAIL_REWIND:
- return "Send failed since rewinding of the data stream failed";
-
- case CURLE_LOGIN_DENIED:
- return "FTP: login denied";
-
- case CURLE_TFTP_NOTFOUND:
- return "TFTP: File Not Found";
-
- case CURLE_TFTP_PERM:
- return "TFTP: Access Violation";
-
- case CURLE_TFTP_DISKFULL:
- return "TFTP: Disk full or allocation exceeded";
-
- case CURLE_TFTP_ILLEGAL:
- return "TFTP: Illegal operation";
-
- case CURLE_TFTP_UNKNOWNID:
- return "TFTP: Unknown transfer ID";
-
- case CURLE_TFTP_EXISTS:
- return "TFTP: File already exists";
-
- case CURLE_TFTP_NOSUCHUSER:
- return "TFTP: No such user";
-
- case CURLE_CONV_FAILED:
- return "conversion failed";
-
- case CURLE_CONV_REQD:
- return "caller must register CURLOPT_CONV_ callback options";
-
- case CURLE_REMOTE_FILE_NOT_FOUND:
- return "Remote file not found";
-
- case CURLE_SSH:
- return "Error in the SSH layer";
-
- /* error codes not used by current libcurl */
- case CURLE_FTP_USER_PASSWORD_INCORRECT:
- case CURLE_MALFORMAT_USER:
- case CURLE_BAD_CALLING_ORDER:
- case CURLE_BAD_PASSWORD_ENTERED:
- case CURLE_OBSOLETE:
- case CURL_LAST:
- break;
- }
- /*
- * By using a switch, gcc -Wall will complain about enum values
- * which do not appear, helping keep this function up-to-date.
- * By using gcc -Wall -Werror, you can't forget.
- *
- * A table would not have the same benefit. Most compilers will
- * generate code very similar to a table in any case, so there
- * is little performance gain from a table. And something is broken
- * for the user's application, anyways, so does it matter how fast
- * it _doesn't_ work?
- *
- * The line number for the error will be near this comment, which
- * is why it is here, and not at the start of the switch.
- */
- return "unknown error";
-#else
- if (error == CURLE_OK)
- return "no error";
- else
- return "error";
-#endif
-}
-
-const char *
-curl_multi_strerror(CURLMcode error)
-{
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- switch (error) {
- case CURLM_CALL_MULTI_PERFORM:
- return "please call curl_multi_perform() soon";
-
- case CURLM_OK:
- return "no error";
-
- case CURLM_BAD_HANDLE:
- return "invalid multi handle";
-
- case CURLM_BAD_EASY_HANDLE:
- return "invalid easy handle";
-
- case CURLM_OUT_OF_MEMORY:
- return "out of memory";
-
- case CURLM_INTERNAL_ERROR:
- return "internal error";
-
- case CURLM_BAD_SOCKET:
- return "invalid socket argument";
-
- case CURLM_UNKNOWN_OPTION:
- return "unknown option";
-
- case CURLM_LAST:
- break;
- }
-
- return "unknown error";
-#else
- if (error == CURLM_OK)
- return "no error";
- else
- return "error";
-#endif
-}
-
-const char *
-curl_share_strerror(CURLSHcode error)
-{
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- switch (error) {
- case CURLSHE_OK:
- return "no error";
-
- case CURLSHE_BAD_OPTION:
- return "unknown share option";
-
- case CURLSHE_IN_USE:
- return "share currently in use";
-
- case CURLSHE_INVALID:
- return "invalid share handle";
-
- case CURLSHE_NOMEM:
- return "out of memory";
-
- case CURLSHE_LAST:
- break;
- }
-
- return "CURLSH unknown";
-#else
- if (error == CURLSHE_OK)
- return "no error";
- else
- return "error";
-#endif
-}
-
-#ifdef USE_WINSOCK
-
-/* This function handles most / all (?) Winsock errors cURL is able to produce.
- */
-static const char *
-get_winsock_error (int err, char *buf, size_t len)
-{
- const char *p;
-
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- switch (err) {
- case WSAEINTR:
- p = "Call interrupted.";
- break;
- case WSAEBADF:
- p = "Bad file";
- break;
- case WSAEACCES:
- p = "Bad access";
- break;
- case WSAEFAULT:
- p = "Bad argument";
- break;
- case WSAEINVAL:
- p = "Invalid arguments";
- break;
- case WSAEMFILE:
- p = "Out of file descriptors";
- break;
- case WSAEWOULDBLOCK:
- p = "Call would block";
- break;
- case WSAEINPROGRESS:
- case WSAEALREADY:
- p = "Blocking call in progress";
- break;
- case WSAENOTSOCK:
- p = "Descriptor is not a socket.";
- break;
- case WSAEDESTADDRREQ:
- p = "Need destination address";
- break;
- case WSAEMSGSIZE:
- p = "Bad message size";
- break;
- case WSAEPROTOTYPE:
- p = "Bad protocol";
- break;
- case WSAENOPROTOOPT:
- p = "Protocol option is unsupported";
- break;
- case WSAEPROTONOSUPPORT:
- p = "Protocol is unsupported";
- break;
- case WSAESOCKTNOSUPPORT:
- p = "Socket is unsupported";
- break;
- case WSAEOPNOTSUPP:
- p = "Operation not supported";
- break;
- case WSAEAFNOSUPPORT:
- p = "Address family not supported";
- break;
- case WSAEPFNOSUPPORT:
- p = "Protocol family not supported";
- break;
- case WSAEADDRINUSE:
- p = "Address already in use";
- break;
- case WSAEADDRNOTAVAIL:
- p = "Address not available";
- break;
- case WSAENETDOWN:
- p = "Network down";
- break;
- case WSAENETUNREACH:
- p = "Network unreachable";
- break;
- case WSAENETRESET:
- p = "Network has been reset";
- break;
- case WSAECONNABORTED:
- p = "Connection was aborted";
- break;
- case WSAECONNRESET:
- p = "Connection was reset";
- break;
- case WSAENOBUFS:
- p = "No buffer space";
- break;
- case WSAEISCONN:
- p = "Socket is already connected";
- break;
- case WSAENOTCONN:
- p = "Socket is not connected";
- break;
- case WSAESHUTDOWN:
- p = "Socket has been shut down";
- break;
- case WSAETOOMANYREFS:
- p = "Too many references";
- break;
- case WSAETIMEDOUT:
- p = "Timed out";
- break;
- case WSAECONNREFUSED:
- p = "Connection refused";
- break;
- case WSAELOOP:
- p = "Loop??";
- break;
- case WSAENAMETOOLONG:
- p = "Name too long";
- break;
- case WSAEHOSTDOWN:
- p = "Host down";
- break;
- case WSAEHOSTUNREACH:
- p = "Host unreachable";
- break;
- case WSAENOTEMPTY:
- p = "Not empty";
- break;
- case WSAEPROCLIM:
- p = "Process limit reached";
- break;
- case WSAEUSERS:
- p = "Too many users";
- break;
- case WSAEDQUOT:
- p = "Bad quota";
- break;
- case WSAESTALE:
- p = "Something is stale";
- break;
- case WSAEREMOTE:
- p = "Remote error";
- break;
-#ifdef WSAEDISCON /* missing in SalfordC! */
- case WSAEDISCON:
- p = "Disconnected";
- break;
-#endif
- /* Extended Winsock errors */
- case WSASYSNOTREADY:
- p = "Winsock library is not ready";
- break;
- case WSANOTINITIALISED:
- p = "Winsock library not initialised";
- break;
- case WSAVERNOTSUPPORTED:
- p = "Winsock version not supported.";
- break;
-
- /* getXbyY() errors (already handled in herrmsg):
- * Authoritative Answer: Host not found */
- case WSAHOST_NOT_FOUND:
- p = "Host not found";
- break;
-
- /* Non-Authoritative: Host not found, or SERVERFAIL */
- case WSATRY_AGAIN:
- p = "Host not found, try again";
- break;
-
- /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
- case WSANO_RECOVERY:
- p = "Unrecoverable error in call to nameserver";
- break;
-
- /* Valid name, no data record of requested type */
- case WSANO_DATA:
- p = "No data record of requested type";
- break;
-
- default:
- return NULL;
- }
-#else
- if (error == CURLE_OK)
- return NULL;
- else
- p = "error";
-#endif
- strncpy (buf, p, len);
- buf [len-1] = '\0';
- return buf;
-}
-#endif /* USE_WINSOCK */
-
-/*
- * Our thread-safe and smart strerror() replacement.
- *
- * The 'err' argument passed in to this function MUST be a true errno number
- * as reported on this system. We do no range checking on the number before
- * we pass it to the "number-to-message" convertion function and there might
- * be systems that don't do proper range checking in there themselves.
- *
- * We don't do range checking (on systems other than Windows) since there is
- * no good reliable and portable way to do it.
- */
-const char *Curl_strerror(struct connectdata *conn, int err)
-{
- char *buf, *p;
- size_t max;
-
- curlassert(conn);
- curlassert(err >= 0);
-
- buf = conn->syserr_buf;
- max = sizeof(conn->syserr_buf)-1;
- *buf = '\0';
-
-#ifdef USE_WINSOCK
-
-#ifdef _WIN32_WCE
- buf[0]=0;
- {
- wchar_t wbuf[256];
-
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
- LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL);
- wcstombs(buf,wbuf,max);
- }
-
-#else
-
- /* 'sys_nerr' is the maximum errno number, it is not widely portable */
- if (err >= 0 && err < sys_nerr)
- strncpy(buf, strerror(err), max);
- else {
- if (!get_winsock_error(err, buf, max) &&
- !FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
- LANG_NEUTRAL, buf, (DWORD)max, NULL))
- snprintf(buf, max, "Unknown error %d (%#x)", err, err);
- }
-#endif
-#else /* not USE_WINSOCK coming up */
-
- /* These should be atomic and hopefully thread-safe */
-#ifdef HAVE_STRERROR_R
- /* There are two different APIs for strerror_r(). The POSIX and the GLIBC
- versions. */
-#ifdef HAVE_POSIX_STRERROR_R
- strerror_r(err, buf, max);
- /* this may set errno to ERANGE if insufficient storage was supplied via
- 'strerrbuf' and 'buflen' to contain the generated message string, or
- EINVAL if the value of 'errnum' is not a valid error number.*/
-#else
- {
- /* HAVE_GLIBC_STRERROR_R */
- char buffer[256];
- char *msg = strerror_r(err, buffer, sizeof(buffer));
- /* this version of strerror_r() only *might* use the buffer we pass to
- the function, but it always returns the error message as a pointer,
- so we must copy that string unconditionally (if non-NULL) */
- if(msg)
- strncpy(buf, msg, max);
- else
- snprintf(buf, max, "Unknown error %d", err);
- }
-#endif /* end of HAVE_GLIBC_STRERROR_R */
-#else /* HAVE_STRERROR_R */
- strncpy(buf, strerror(err), max);
-#endif /* end of HAVE_STRERROR_R */
-#endif /* end of ! USE_WINSOCK */
-
- buf[max] = '\0'; /* make sure the string is zero terminated */
-
- /* strip trailing '\r\n' or '\n'. */
- if ((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
- *p = '\0';
- if ((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
- *p = '\0';
- return buf;
-}
-
-#ifdef USE_LIBIDN
-/*
- * Return error-string for libidn status as returned from idna_to_ascii_lz().
- */
-const char *Curl_idn_strerror (struct connectdata *conn, int err)
-{
-#ifdef HAVE_IDNA_STRERROR
- (void)conn;
- return idna_strerror((Idna_rc) err);
-#else
- const char *str;
- char *buf;
- size_t max;
-
- curlassert(conn);
-
- buf = conn->syserr_buf;
- max = sizeof(conn->syserr_buf)-1;
-
-#ifndef CURL_DISABLE_VERBOSE_STRINGS
- switch ((Idna_rc)err) {
- case IDNA_SUCCESS:
- str = "No error";
- break;
- case IDNA_STRINGPREP_ERROR:
- str = "Error in string preparation";
- break;
- case IDNA_PUNYCODE_ERROR:
- str = "Error in Punycode operation";
- break;
- case IDNA_CONTAINS_NON_LDH:
- str = "Illegal ASCII characters";
- break;
- case IDNA_CONTAINS_MINUS:
- str = "Contains minus";
- break;
- case IDNA_INVALID_LENGTH:
- str = "Invalid output length";
- break;
- case IDNA_NO_ACE_PREFIX:
- str = "No ACE prefix (\"xn--\")";
- break;
- case IDNA_ROUNDTRIP_VERIFY_ERROR:
- str = "Roundtrip verify error";
- break;
- case IDNA_CONTAINS_ACE_PREFIX:
- str = "Already have ACE prefix (\"xn--\")";
- break;
- case IDNA_ICONV_ERROR:
- str = "Locale conversion failed";
- break;
- case IDNA_MALLOC_ERROR:
- str = "Allocation failed";
- break;
- case IDNA_DLOPEN_ERROR:
- str = "dlopen() error";
- break;
- default:
- snprintf(buf, max, "error %d", (int)err);
- str = NULL;
- break;
- }
-#else
- if ((Idna_rc)err == IDNA_SUCCESS)
- str = "No error";
- else
- str = "error";
-#endif
- if (str)
- strncpy(buf, str, max);
- buf[max] = '\0';
- return (buf);
-#endif
-}
-#endif /* USE_LIBIDN */
diff --git a/Utilities/cmcurl/strerror.h b/Utilities/cmcurl/strerror.h
deleted file mode 100644
index b28050437..000000000
--- a/Utilities/cmcurl/strerror.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __CURL_STRERROR_H
-#define __CURL_STRERROR_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "urldata.h"
-
-const char *Curl_strerror (struct connectdata *conn, int err);
-
-#ifdef USE_LIBIDN
-const char *Curl_idn_strerror (struct connectdata *conn, int err);
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/strtok.c b/Utilities/cmcurl/strtok.c
deleted file mode 100644
index 630e4e029..000000000
--- a/Utilities/cmcurl/strtok.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef HAVE_STRTOK_R
-#include <stddef.h>
-#include <string.h>
-
-#include "strtok.h"
-
-char *
-Curl_strtok_r(char *ptr, const char *sep, char **end)
-{
- if (!ptr)
- /* we got NULL input so then we get our last position instead */
- ptr = *end;
-
- /* pass all letters that are including in the separator string */
- while (*ptr && strchr(sep, *ptr))
- ++ptr;
-
- if (*ptr) {
- /* so this is where the next piece of string starts */
- char *start = ptr;
-
- /* set the end pointer to the first byte after the start */
- *end = start + 1;
-
- /* scan through the string to find where it ends, it ends on a
- null byte or a character that exists in the separator string */
- while (**end && !strchr(sep, **end))
- ++*end;
-
- if (**end) {
- /* the end is not a null byte */
- **end = '\0'; /* zero terminate it! */
- ++*end; /* advance the last pointer to beyond the null byte */
- }
-
- return start; /* return the position where the string starts */
- }
-
- /* we ended up on a null byte, there are no more strings to find! */
- return NULL;
-}
-
-#endif /* this was only compiled if strtok_r wasn't present */
diff --git a/Utilities/cmcurl/strtok.h b/Utilities/cmcurl/strtok.h
deleted file mode 100644
index cf9fac8c7..000000000
--- a/Utilities/cmcurl/strtok.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#ifndef _CURL_STRTOK_R_H
-#define _CURL_STRTOK_R_H
-
-#include "setup.h"
-#include <stddef.h>
-
-#ifndef HAVE_STRTOK_R
-char *Curl_strtok_r(char *s, const char *delim, char **last);
-#define strtok_r Curl_strtok_r
-#else
-#include <string.h>
-#endif
-
-#endif
-
diff --git a/Utilities/cmcurl/strtoofft.c b/Utilities/cmcurl/strtoofft.c
deleted file mode 100644
index 3ab1bfdff..000000000
--- a/Utilities/cmcurl/strtoofft.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-#include "strtoofft.h"
-
-/*
- * NOTE:
- *
- * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
- * could use in case strtoll() doesn't exist... See
- * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
- */
-
-#ifdef NEED_CURL_STRTOLL
-#include <stdlib.h>
-#include <ctype.h>
-#include <errno.h>
-
-static int get_char(char c, int base);
-
-/**
- * Emulated version of the strtoll function. This extracts a long long
- * value from the given input string and returns it.
- */
-curl_off_t
-curlx_strtoll(const char *nptr, char **endptr, int base)
-{
- char *end;
- int is_negative = 0;
- int overflow;
- int i;
- curl_off_t value = 0;
- curl_off_t newval;
-
- /* Skip leading whitespace. */
- end = (char *)nptr;
- while (ISSPACE(end[0])) {
- end++;
- }
-
- /* Handle the sign, if any. */
- if (end[0] == '-') {
- is_negative = 1;
- end++;
- }
- else if (end[0] == '+') {
- end++;
- }
- else if (end[0] == '\0') {
- /* We had nothing but perhaps some whitespace -- there was no number. */
- if (endptr) {
- *endptr = end;
- }
- return 0;
- }
-
- /* Handle special beginnings, if present and allowed. */
- if (end[0] == '0' && end[1] == 'x') {
- if (base == 16 || base == 0) {
- end += 2;
- base = 16;
- }
- }
- else if (end[0] == '0') {
- if (base == 8 || base == 0) {
- end++;
- base = 8;
- }
- }
-
- /* Matching strtol, if the base is 0 and it doesn't look like
- * the number is octal or hex, we assume it's base 10.
- */
- if (base == 0) {
- base = 10;
- }
-
- /* Loop handling digits. */
- value = 0;
- overflow = 0;
- for (i = get_char(end[0], base);
- i != -1;
- end++, i = get_char(end[0], base)) {
- newval = base * value + i;
- if (newval < value) {
- /* We've overflowed. */
- overflow = 1;
- break;
- }
- else
- value = newval;
- }
-
- if (!overflow) {
- if (is_negative) {
- /* Fix the sign. */
- value *= -1;
- }
- }
- else {
- if (is_negative)
- value = CURL_LLONG_MIN;
- else
- value = CURL_LLONG_MAX;
-
- errno = ERANGE;
- }
-
- if (endptr)
- *endptr = end;
-
- return value;
-}
-
-/**
- * Returns the value of c in the given base, or -1 if c cannot
- * be interpreted properly in that base (i.e., is out of range,
- * is a null, etc.).
- *
- * @param c the character to interpret according to base
- * @param base the base in which to interpret c
- *
- * @return the value of c in base, or -1 if c isn't in range
- */
-static int get_char(char c, int base)
-{
- int value = -1;
- if (c <= '9' && c >= '0') {
- value = c - '0';
- }
- else if (c <= 'Z' && c >= 'A') {
- value = c - 'A' + 10;
- }
- else if (c <= 'z' && c >= 'a') {
- value = c - 'a' + 10;
- }
-
- if (value >= base) {
- value = -1;
- }
-
- return value;
-}
-#endif /* Only present if we need strtoll, but don't have it. */
diff --git a/Utilities/cmcurl/strtoofft.h b/Utilities/cmcurl/strtoofft.h
deleted file mode 100644
index e27b43261..000000000
--- a/Utilities/cmcurl/strtoofft.h
+++ /dev/null
@@ -1,73 +0,0 @@
-#ifndef _CURL_STRTOOFFT_H
-#define _CURL_STRTOOFFT_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2004, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * CAUTION: this header is designed to work when included by the app-side
- * as well as the library. Do not mix with library internals!
- */
-
-#include "setup.h"
-#include <stddef.h>
-#include <curl/curl.h> /* for the curl_off_t type */
-
-/* Determine what type of file offset conversion handling we wish to use. For
- * systems with a 32-bit curl_off_t type, we should use strtol. For systems
- * with a 64-bit curl_off_t type, we should use strtoll if it exists, and if
- * not, should try to emulate its functionality. At any rate, we define
- * 'strtoofft' such that it can be used to work with curl_off_t's regardless.
- */
-#if (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8)
-#if HAVE_STRTOLL
-#define curlx_strtoofft strtoll
-#else /* HAVE_STRTOLL */
-
-/* For MSVC7 we can use _strtoi64() which seems to be a strtoll() clone */
-#if defined(_MSC_VER) && (_MSC_VER >= 1300)
-#define curlx_strtoofft _strtoi64
-#else /* MSVC7 or later */
-curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
-#define curlx_strtoofft curlx_strtoll
-#define NEED_CURL_STRTOLL
-#endif /* MSVC7 or later */
-
-#endif /* HAVE_STRTOLL */
-#else /* (SIZEOF_CURL_OFF_T > 4) && (SIZEOF_LONG < 8) */
-/* simply use strtol() to get numbers, either 32 or 64 bit */
-#define curlx_strtoofft strtol
-#endif
-
-#if defined(_MSC_VER) || defined(__WATCOMC__)
-#define CURL_LLONG_MIN 0x8000000000000000i64
-#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFi64
-#elif defined(HAVE_LL)
-#define CURL_LLONG_MIN 0x8000000000000000LL
-#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFLL
-#else
-#define CURL_LLONG_MIN 0x8000000000000000L
-#define CURL_LLONG_MAX 0x7FFFFFFFFFFFFFFFL
-#endif
-
-#endif
-
diff --git a/Utilities/cmcurl/telnet.c b/Utilities/cmcurl/telnet.c
deleted file mode 100644
index 97d22b788..000000000
--- a/Utilities/cmcurl/telnet.c
+++ /dev/null
@@ -1,1403 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_TELNET
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#if defined(WIN32)
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "transfer.h"
-#include "sendf.h"
-#include "telnet.h"
-#include "connect.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#define TELOPTS
-#define TELCMDS
-
-#include "arpa_telnet.h"
-#include "memory.h"
-#include "select.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define SUBBUFSIZE 512
-
-#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer;
-#define CURL_SB_TERM(x) { x->subend = x->subpointer; CURL_SB_CLEAR(x); }
-#define CURL_SB_ACCUM(x,c) \
- if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
- *x->subpointer++ = (c); \
- }
-
-#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
-#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
-#define CURL_SB_EOF(x) (x->subpointer >= x->subend)
-#define CURL_SB_LEN(x) (x->subend - x->subpointer)
-
-#ifdef USE_WINSOCK
-typedef FARPROC WSOCK2_FUNC;
-static CURLcode check_wsock2 ( struct SessionHandle *data );
-#endif
-
-static
-void telrcv(struct connectdata *,
- unsigned char *inbuf, /* Data received from socket */
- ssize_t count); /* Number of bytes received */
-
-static void printoption(struct SessionHandle *data,
- const char *direction,
- int cmd, int option);
-
-static void negotiate(struct connectdata *);
-static void send_negotiation(struct connectdata *, int cmd, int option);
-static void set_local_option(struct connectdata *, int cmd, int option);
-static void set_remote_option(struct connectdata *, int cmd, int option);
-
-static void printsub(struct SessionHandle *data,
- int direction, unsigned char *pointer,
- size_t length);
-static void suboption(struct connectdata *);
-
-/* For negotiation compliant to RFC 1143 */
-#define CURL_NO 0
-#define CURL_YES 1
-#define CURL_WANTYES 2
-#define CURL_WANTNO 3
-
-#define CURL_EMPTY 0
-#define CURL_OPPOSITE 1
-
-/*
- * Telnet receiver states for fsm
- */
-typedef enum
-{
- CURL_TS_DATA = 0,
- CURL_TS_IAC,
- CURL_TS_WILL,
- CURL_TS_WONT,
- CURL_TS_DO,
- CURL_TS_DONT,
- CURL_TS_CR,
- CURL_TS_SB, /* sub-option collection */
- CURL_TS_SE /* looking for sub-option end */
-} TelnetReceive;
-
-struct TELNET {
- int please_negotiate;
- int already_negotiated;
- int us[256];
- int usq[256];
- int us_preferred[256];
- int him[256];
- int himq[256];
- int him_preferred[256];
- char subopt_ttype[32]; /* Set with suboption TTYPE */
- char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
- struct curl_slist *telnet_vars; /* Environment variables */
-
- /* suboptions */
- unsigned char subbuffer[SUBBUFSIZE];
- unsigned char *subpointer, *subend; /* buffer for sub-options */
-
- TelnetReceive telrcv_state;
-};
-
-#ifdef USE_WINSOCK
-static CURLcode
-check_wsock2 ( struct SessionHandle *data )
-{
- int err;
- WORD wVersionRequested;
- WSADATA wsaData;
-
- curlassert(data);
-
- /* telnet requires at least WinSock 2.0 so ask for it. */
- wVersionRequested = MAKEWORD(2, 0);
-
- err = WSAStartup(wVersionRequested, &wsaData);
-
- /* We must've called this once already, so this call */
- /* should always succeed. But, just in case... */
- if (err != 0) {
- failf(data,"WSAStartup failed (%d)",err);
- return CURLE_FAILED_INIT;
- }
-
- /* We have to have a WSACleanup call for every successful */
- /* WSAStartup call. */
- WSACleanup();
-
- /* Check that our version is supported */
- if (LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
- HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
- /* Our version isn't supported */
- failf(data,"insufficient winsock version to support "
- "telnet");
- return CURLE_FAILED_INIT;
- }
-
- /* Our version is supported */
- return CURLE_OK;
-}
-#endif
-
-static
-CURLcode init_telnet(struct connectdata *conn)
-{
- struct TELNET *tn;
-
- tn = (struct TELNET *)calloc(1, sizeof(struct TELNET));
- if(!tn)
- return CURLE_OUT_OF_MEMORY;
-
- conn->data->reqdata.proto.telnet = (void *)tn; /* make us known */
-
- tn->telrcv_state = CURL_TS_DATA;
-
- /* Init suboptions */
- CURL_SB_CLEAR(tn);
-
- /* Set the options we want by default */
- tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
- tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
- tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
- tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
-
- return CURLE_OK;
-}
-
-static void negotiate(struct connectdata *conn)
-{
- int i;
- struct TELNET *tn = (struct TELNET *) conn->data->reqdata.proto.telnet;
-
- for(i = 0;i < CURL_NTELOPTS;i++)
- {
- if(tn->us_preferred[i] == CURL_YES)
- set_local_option(conn, i, CURL_YES);
-
- if(tn->him_preferred[i] == CURL_YES)
- set_remote_option(conn, i, CURL_YES);
- }
-}
-
-static void printoption(struct SessionHandle *data,
- const char *direction, int cmd, int option)
-{
- const char *fmt;
- const char *opt;
-
- if (data->set.verbose)
- {
- if (cmd == CURL_IAC)
- {
- if (CURL_TELCMD_OK(option))
- infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
- else
- infof(data, "%s IAC %d\n", direction, option);
- }
- else
- {
- fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
- (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
- if (fmt)
- {
- if (CURL_TELOPT_OK(option))
- opt = CURL_TELOPT(option);
- else if (option == CURL_TELOPT_EXOPL)
- opt = "EXOPL";
- else
- opt = NULL;
-
- if(opt)
- infof(data, "%s %s %s\n", direction, fmt, opt);
- else
- infof(data, "%s %s %d\n", direction, fmt, option);
- }
- else
- infof(data, "%s %d %d\n", direction, cmd, option);
- }
- }
-}
-
-static void send_negotiation(struct connectdata *conn, int cmd, int option)
-{
- unsigned char buf[3];
- ssize_t bytes_written;
- int err;
- struct SessionHandle *data = conn->data;
-
- buf[0] = CURL_IAC;
- buf[1] = (unsigned char)cmd;
- buf[2] = (unsigned char)option;
-
- bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
- if(bytes_written < 0) {
- err = Curl_sockerrno();
- failf(data,"Sending data failed (%d)",err);
- }
-
- printoption(conn->data, "SENT", cmd, option);
-}
-
-static
-void set_remote_option(struct connectdata *conn, int option, int newstate)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- if(newstate == CURL_YES)
- {
- switch(tn->him[option])
- {
- case CURL_NO:
- tn->him[option] = CURL_WANTYES;
- send_negotiation(conn, CURL_DO, option);
- break;
-
- case CURL_YES:
- /* Already enabled */
- break;
-
- case CURL_WANTNO:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- /* Already negotiating for CURL_YES, queue the request */
- tn->himq[option] = CURL_OPPOSITE;
- break;
- case CURL_OPPOSITE:
- /* Error: already queued an enable request */
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- /* Error: already negotiating for enable */
- break;
- case CURL_OPPOSITE:
- tn->himq[option] = CURL_EMPTY;
- break;
- }
- break;
- }
- }
- else /* NO */
- {
- switch(tn->him[option])
- {
- case CURL_NO:
- /* Already disabled */
- break;
-
- case CURL_YES:
- tn->him[option] = CURL_WANTNO;
- send_negotiation(conn, CURL_DONT, option);
- break;
-
- case CURL_WANTNO:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- /* Already negotiating for NO */
- break;
- case CURL_OPPOSITE:
- tn->himq[option] = CURL_EMPTY;
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- tn->himq[option] = CURL_OPPOSITE;
- break;
- case CURL_OPPOSITE:
- break;
- }
- break;
- }
- }
-}
-
-static
-void rec_will(struct connectdata *conn, int option)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- switch(tn->him[option])
- {
- case CURL_NO:
- if(tn->him_preferred[option] == CURL_YES)
- {
- tn->him[option] = CURL_YES;
- send_negotiation(conn, CURL_DO, option);
- }
- else
- {
- send_negotiation(conn, CURL_DONT, option);
- }
- break;
-
- case CURL_YES:
- /* Already enabled */
- break;
-
- case CURL_WANTNO:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- /* Error: DONT answered by WILL */
- tn->him[option] = CURL_NO;
- break;
- case CURL_OPPOSITE:
- /* Error: DONT answered by WILL */
- tn->him[option] = CURL_YES;
- tn->himq[option] = CURL_EMPTY;
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- tn->him[option] = CURL_YES;
- break;
- case CURL_OPPOSITE:
- tn->him[option] = CURL_WANTNO;
- tn->himq[option] = CURL_EMPTY;
- send_negotiation(conn, CURL_DONT, option);
- break;
- }
- break;
- }
-}
-
-static
-void rec_wont(struct connectdata *conn, int option)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- switch(tn->him[option])
- {
- case CURL_NO:
- /* Already disabled */
- break;
-
- case CURL_YES:
- tn->him[option] = CURL_NO;
- send_negotiation(conn, CURL_DONT, option);
- break;
-
- case CURL_WANTNO:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- tn->him[option] = CURL_NO;
- break;
-
- case CURL_OPPOSITE:
- tn->him[option] = CURL_WANTYES;
- tn->himq[option] = CURL_EMPTY;
- send_negotiation(conn, CURL_DO, option);
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->himq[option])
- {
- case CURL_EMPTY:
- tn->him[option] = CURL_NO;
- break;
- case CURL_OPPOSITE:
- tn->him[option] = CURL_NO;
- tn->himq[option] = CURL_EMPTY;
- break;
- }
- break;
- }
-}
-
-static void
-set_local_option(struct connectdata *conn, int option, int newstate)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- if(newstate == CURL_YES)
- {
- switch(tn->us[option])
- {
- case CURL_NO:
- tn->us[option] = CURL_WANTYES;
- send_negotiation(conn, CURL_WILL, option);
- break;
-
- case CURL_YES:
- /* Already enabled */
- break;
-
- case CURL_WANTNO:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- /* Already negotiating for CURL_YES, queue the request */
- tn->usq[option] = CURL_OPPOSITE;
- break;
- case CURL_OPPOSITE:
- /* Error: already queued an enable request */
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- /* Error: already negotiating for enable */
- break;
- case CURL_OPPOSITE:
- tn->usq[option] = CURL_EMPTY;
- break;
- }
- break;
- }
- }
- else /* NO */
- {
- switch(tn->us[option])
- {
- case CURL_NO:
- /* Already disabled */
- break;
-
- case CURL_YES:
- tn->us[option] = CURL_WANTNO;
- send_negotiation(conn, CURL_WONT, option);
- break;
-
- case CURL_WANTNO:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- /* Already negotiating for NO */
- break;
- case CURL_OPPOSITE:
- tn->usq[option] = CURL_EMPTY;
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- tn->usq[option] = CURL_OPPOSITE;
- break;
- case CURL_OPPOSITE:
- break;
- }
- break;
- }
- }
-}
-
-static
-void rec_do(struct connectdata *conn, int option)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- switch(tn->us[option])
- {
- case CURL_NO:
- if(tn->us_preferred[option] == CURL_YES)
- {
- tn->us[option] = CURL_YES;
- send_negotiation(conn, CURL_WILL, option);
- }
- else
- {
- send_negotiation(conn, CURL_WONT, option);
- }
- break;
-
- case CURL_YES:
- /* Already enabled */
- break;
-
- case CURL_WANTNO:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- /* Error: DONT answered by WILL */
- tn->us[option] = CURL_NO;
- break;
- case CURL_OPPOSITE:
- /* Error: DONT answered by WILL */
- tn->us[option] = CURL_YES;
- tn->usq[option] = CURL_EMPTY;
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- tn->us[option] = CURL_YES;
- break;
- case CURL_OPPOSITE:
- tn->us[option] = CURL_WANTNO;
- tn->himq[option] = CURL_EMPTY;
- send_negotiation(conn, CURL_WONT, option);
- break;
- }
- break;
- }
-}
-
-static
-void rec_dont(struct connectdata *conn, int option)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- switch(tn->us[option])
- {
- case CURL_NO:
- /* Already disabled */
- break;
-
- case CURL_YES:
- tn->us[option] = CURL_NO;
- send_negotiation(conn, CURL_WONT, option);
- break;
-
- case CURL_WANTNO:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- tn->us[option] = CURL_NO;
- break;
-
- case CURL_OPPOSITE:
- tn->us[option] = CURL_WANTYES;
- tn->usq[option] = CURL_EMPTY;
- send_negotiation(conn, CURL_WILL, option);
- break;
- }
- break;
-
- case CURL_WANTYES:
- switch(tn->usq[option])
- {
- case CURL_EMPTY:
- tn->us[option] = CURL_NO;
- break;
- case CURL_OPPOSITE:
- tn->us[option] = CURL_NO;
- tn->usq[option] = CURL_EMPTY;
- break;
- }
- break;
- }
-}
-
-
-static void printsub(struct SessionHandle *data,
- int direction, /* '<' or '>' */
- unsigned char *pointer, /* where suboption data is */
- size_t length) /* length of suboption data */
-{
- unsigned int i = 0;
-
- if (data->set.verbose)
- {
- if (direction)
- {
- infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
- if (length >= 3)
- {
- int j;
-
- i = pointer[length-2];
- j = pointer[length-1];
-
- if (i != CURL_IAC || j != CURL_SE)
- {
- infof(data, "(terminated by ");
- if (CURL_TELOPT_OK(i))
- infof(data, "%s ", CURL_TELOPT(i));
- else if (CURL_TELCMD_OK(i))
- infof(data, "%s ", CURL_TELCMD(i));
- else
- infof(data, "%d ", i);
- if (CURL_TELOPT_OK(j))
- infof(data, "%s", CURL_TELOPT(j));
- else if (CURL_TELCMD_OK(j))
- infof(data, "%s", CURL_TELCMD(j));
- else
- infof(data, "%d", j);
- infof(data, ", not IAC SE!) ");
- }
- }
- length -= 2;
- }
- if (length < 1)
- {
- infof(data, "(Empty suboption?)");
- return;
- }
-
- if (CURL_TELOPT_OK(pointer[0])) {
- switch(pointer[0]) {
- case CURL_TELOPT_TTYPE:
- case CURL_TELOPT_XDISPLOC:
- case CURL_TELOPT_NEW_ENVIRON:
- infof(data, "%s", CURL_TELOPT(pointer[0]));
- break;
- default:
- infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
- break;
- }
- }
- else
- infof(data, "%d (unknown)", pointer[i]);
-
- switch(pointer[1]) {
- case CURL_TELQUAL_IS:
- infof(data, " IS");
- break;
- case CURL_TELQUAL_SEND:
- infof(data, " SEND");
- break;
- case CURL_TELQUAL_INFO:
- infof(data, " INFO/REPLY");
- break;
- case CURL_TELQUAL_NAME:
- infof(data, " NAME");
- break;
- }
-
- switch(pointer[0]) {
- case CURL_TELOPT_TTYPE:
- case CURL_TELOPT_XDISPLOC:
- pointer[length] = 0;
- infof(data, " \"%s\"", &pointer[2]);
- break;
- case CURL_TELOPT_NEW_ENVIRON:
- if(pointer[1] == CURL_TELQUAL_IS) {
- infof(data, " ");
- for(i = 3;i < length;i++) {
- switch(pointer[i]) {
- case CURL_NEW_ENV_VAR:
- infof(data, ", ");
- break;
- case CURL_NEW_ENV_VALUE:
- infof(data, " = ");
- break;
- default:
- infof(data, "%c", pointer[i]);
- break;
- }
- }
- }
- break;
- default:
- for (i = 2; i < length; i++)
- infof(data, " %.2x", pointer[i]);
- break;
- }
-
- if (direction)
- {
- infof(data, "\n");
- }
- }
-}
-
-static CURLcode check_telnet_options(struct connectdata *conn)
-{
- struct curl_slist *head;
- char option_keyword[128];
- char option_arg[256];
- char *buf;
- struct SessionHandle *data = conn->data;
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
-
- /* Add the user name as an environment variable if it
- was given on the command line */
- if(conn->bits.user_passwd)
- {
- snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
- tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg);
-
- tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
- }
-
- for(head = data->set.telnet_options; head; head=head->next) {
- if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
- option_keyword, option_arg) == 2) {
-
- /* Terminal type */
- if(curl_strequal(option_keyword, "TTYPE")) {
- strncpy(tn->subopt_ttype, option_arg, 31);
- tn->subopt_ttype[31] = 0; /* String termination */
- tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
- continue;
- }
-
- /* Display variable */
- if(curl_strequal(option_keyword, "XDISPLOC")) {
- strncpy(tn->subopt_xdisploc, option_arg, 127);
- tn->subopt_xdisploc[127] = 0; /* String termination */
- tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
- continue;
- }
-
- /* Environment variable */
- if(curl_strequal(option_keyword, "NEW_ENV")) {
- buf = strdup(option_arg);
- if(!buf)
- return CURLE_OUT_OF_MEMORY;
- tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
- tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
- continue;
- }
-
- failf(data, "Unknown telnet option %s", head->data);
- return CURLE_UNKNOWN_TELNET_OPTION;
- } else {
- failf(data, "Syntax error in telnet option: %s", head->data);
- return CURLE_TELNET_OPTION_SYNTAX;
- }
- }
-
- return CURLE_OK;
-}
-
-/*
- * suboption()
- *
- * Look at the sub-option buffer, and try to be helpful to the other
- * side.
- */
-
-static void suboption(struct connectdata *conn)
-{
- struct curl_slist *v;
- unsigned char temp[2048];
- ssize_t bytes_written;
- size_t len;
- size_t tmplen;
- int err;
- char varname[128];
- char varval[128];
- struct SessionHandle *data = conn->data;
- struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet;
-
- printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
- switch (CURL_SB_GET(tn)) {
- case CURL_TELOPT_TTYPE:
- len = strlen(tn->subopt_ttype) + 4 + 2;
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
- CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
- bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
- if(bytes_written < 0) {
- err = Curl_sockerrno();
- failf(data,"Sending data failed (%d)",err);
- }
- printsub(data, '>', &temp[2], len-2);
- break;
- case CURL_TELOPT_XDISPLOC:
- len = strlen(tn->subopt_xdisploc) + 4 + 2;
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
- CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
- bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
- if(bytes_written < 0) {
- err = Curl_sockerrno();
- failf(data,"Sending data failed (%d)",err);
- }
- printsub(data, '>', &temp[2], len-2);
- break;
- case CURL_TELOPT_NEW_ENVIRON:
- snprintf((char *)temp, sizeof(temp),
- "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
- CURL_TELQUAL_IS);
- len = 4;
-
- for(v = tn->telnet_vars;v;v = v->next) {
- tmplen = (strlen(v->data) + 1);
- /* Add the variable only if it fits */
- if(len + tmplen < (int)sizeof(temp)-6) {
- sscanf(v->data, "%127[^,],%127s", varname, varval);
- snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
- CURL_NEW_ENV_VALUE, varval);
- len += tmplen;
- }
- }
- snprintf((char *)&temp[len], sizeof(temp) - len,
- "%c%c", CURL_IAC, CURL_SE);
- len += 2;
- bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
- if(bytes_written < 0) {
- err = Curl_sockerrno();
- failf(data,"Sending data failed (%d)",err);
- }
- printsub(data, '>', &temp[2], len-2);
- break;
- }
- return;
-}
-
-static
-void telrcv(struct connectdata *conn,
- unsigned char *inbuf, /* Data received from socket */
- ssize_t count) /* Number of bytes received */
-{
- unsigned char c;
- int in = 0;
- struct SessionHandle *data = conn->data;
- struct TELNET *tn = (struct TELNET *)data->reqdata.proto.telnet;
-
- while(count--)
- {
- c = inbuf[in++];
-
- switch (tn->telrcv_state)
- {
- case CURL_TS_CR:
- tn->telrcv_state = CURL_TS_DATA;
- if (c == '\0')
- {
- break; /* Ignore \0 after CR */
- }
-
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
- continue;
-
- case CURL_TS_DATA:
- if (c == CURL_IAC)
- {
- tn->telrcv_state = CURL_TS_IAC;
- break;
- }
- else if(c == '\r')
- {
- tn->telrcv_state = CURL_TS_CR;
- }
-
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
- continue;
-
- case CURL_TS_IAC:
- process_iac:
- switch (c)
- {
- case CURL_WILL:
- tn->telrcv_state = CURL_TS_WILL;
- continue;
- case CURL_WONT:
- tn->telrcv_state = CURL_TS_WONT;
- continue;
- case CURL_DO:
- tn->telrcv_state = CURL_TS_DO;
- continue;
- case CURL_DONT:
- tn->telrcv_state = CURL_TS_DONT;
- continue;
- case CURL_SB:
- CURL_SB_CLEAR(tn);
- tn->telrcv_state = CURL_TS_SB;
- continue;
- case CURL_IAC:
- Curl_client_write(conn, CLIENTWRITE_BODY, (char *)&c, 1);
- break;
- case CURL_DM:
- case CURL_NOP:
- case CURL_GA:
- default:
- printoption(data, "RCVD", CURL_IAC, c);
- break;
- }
- tn->telrcv_state = CURL_TS_DATA;
- continue;
-
- case CURL_TS_WILL:
- printoption(data, "RCVD", CURL_WILL, c);
- tn->please_negotiate = 1;
- rec_will(conn, c);
- tn->telrcv_state = CURL_TS_DATA;
- continue;
-
- case CURL_TS_WONT:
- printoption(data, "RCVD", CURL_WONT, c);
- tn->please_negotiate = 1;
- rec_wont(conn, c);
- tn->telrcv_state = CURL_TS_DATA;
- continue;
-
- case CURL_TS_DO:
- printoption(data, "RCVD", CURL_DO, c);
- tn->please_negotiate = 1;
- rec_do(conn, c);
- tn->telrcv_state = CURL_TS_DATA;
- continue;
-
- case CURL_TS_DONT:
- printoption(data, "RCVD", CURL_DONT, c);
- tn->please_negotiate = 1;
- rec_dont(conn, c);
- tn->telrcv_state = CURL_TS_DATA;
- continue;
-
- case CURL_TS_SB:
- if (c == CURL_IAC)
- {
- tn->telrcv_state = CURL_TS_SE;
- }
- else
- {
- CURL_SB_ACCUM(tn,c);
- }
- continue;
-
- case CURL_TS_SE:
- if (c != CURL_SE)
- {
- if (c != CURL_IAC)
- {
- /*
- * This is an error. We only expect to get "IAC IAC" or "IAC SE".
- * Several things may have happend. An IAC was not doubled, the
- * IAC SE was left off, or another option got inserted into the
- * suboption are all possibilities. If we assume that the IAC was
- * not doubled, and really the IAC SE was left off, we could get
- * into an infinate loop here. So, instead, we terminate the
- * suboption, and process the partial suboption if we can.
- */
- CURL_SB_ACCUM(tn, CURL_IAC);
- CURL_SB_ACCUM(tn, c);
- tn->subpointer -= 2;
- CURL_SB_TERM(tn);
-
- printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
- suboption(conn); /* handle sub-option */
- tn->telrcv_state = CURL_TS_IAC;
- goto process_iac;
- }
- CURL_SB_ACCUM(tn,c);
- tn->telrcv_state = CURL_TS_SB;
- }
- else
- {
- CURL_SB_ACCUM(tn, CURL_IAC);
- CURL_SB_ACCUM(tn, CURL_SE);
- tn->subpointer -= 2;
- CURL_SB_TERM(tn);
- suboption(conn); /* handle sub-option */
- tn->telrcv_state = CURL_TS_DATA;
- }
- break;
- }
- }
-}
-
-CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature)
-{
- struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
- (void)status; /* unused */
- (void)premature; /* not used */
-
- curl_slist_free_all(tn->telnet_vars);
-
- free(conn->data->reqdata.proto.telnet);
- conn->data->reqdata.proto.telnet = NULL;
-
- return CURLE_OK;
-}
-
-CURLcode Curl_telnet(struct connectdata *conn, bool *done)
-{
- CURLcode code;
- struct SessionHandle *data = conn->data;
- curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-#ifdef USE_WINSOCK
- HMODULE wsock2;
- WSOCK2_FUNC close_event_func;
- WSOCK2_FUNC create_event_func;
- WSOCK2_FUNC event_select_func;
- WSOCK2_FUNC enum_netevents_func;
- WSAEVENT event_handle;
- WSANETWORKEVENTS events;
- HANDLE stdin_handle;
- HANDLE objs[2];
- DWORD obj_count;
- DWORD wait_timeout;
- DWORD waitret;
- DWORD readfile_read;
-#else
- int interval_ms;
- struct pollfd pfd[2];
-#endif
- ssize_t nread;
- bool keepon = TRUE;
- char *buf = data->state.buffer;
- struct TELNET *tn;
-
- *done = TRUE; /* uncontionally */
-
- code = init_telnet(conn);
- if(code)
- return code;
-
- tn = (struct TELNET *)data->reqdata.proto.telnet;
-
- code = check_telnet_options(conn);
- if(code)
- return code;
-
-#ifdef USE_WINSOCK
- /*
- ** This functionality only works with WinSock >= 2.0. So,
- ** make sure have it.
- */
- code = check_wsock2(data);
- if (code)
- return code;
-
- /* OK, so we have WinSock 2.0. We need to dynamically */
- /* load ws2_32.dll and get the function pointers we need. */
- wsock2 = LoadLibrary("WS2_32.DLL");
- if (wsock2 == NULL) {
- failf(data,"failed to load WS2_32.DLL (%d)",GetLastError());
- return CURLE_FAILED_INIT;
- }
-
- /* Grab a pointer to WSACreateEvent */
- create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
- if (create_event_func == NULL) {
- failf(data,"failed to find WSACreateEvent function (%d)",
- GetLastError());
- FreeLibrary(wsock2);
- return CURLE_FAILED_INIT;
- }
-
- /* And WSACloseEvent */
- close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
- if (close_event_func == NULL) {
- failf(data,"failed to find WSACloseEvent function (%d)",
- GetLastError());
- FreeLibrary(wsock2);
- return CURLE_FAILED_INIT;
- }
-
- /* And WSAEventSelect */
- event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
- if (event_select_func == NULL) {
- failf(data,"failed to find WSAEventSelect function (%d)",
- GetLastError());
- FreeLibrary(wsock2);
- return CURLE_FAILED_INIT;
- }
-
- /* And WSAEnumNetworkEvents */
- enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
- if (enum_netevents_func == NULL) {
- failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
- GetLastError());
- FreeLibrary(wsock2);
- return CURLE_FAILED_INIT;
- }
-
- /* We want to wait for both stdin and the socket. Since
- ** the select() function in winsock only works on sockets
- ** we have to use the WaitForMultipleObjects() call.
- */
-
- /* First, create a sockets event object */
- event_handle = (WSAEVENT)create_event_func();
- if (event_handle == WSA_INVALID_EVENT) {
- failf(data,"WSACreateEvent failed (%d)",WSAGetLastError());
- FreeLibrary(wsock2);
- return CURLE_FAILED_INIT;
- }
-
- /* The get the Windows file handle for stdin */
- stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
-
- /* Create the list of objects to wait for */
- objs[0] = event_handle;
- objs[1] = stdin_handle;
-
- /* Tell winsock what events we want to listen to */
- if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) {
- close_event_func(event_handle);
- FreeLibrary(wsock2);
- return 0;
- }
-
- /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
- else use the old WaitForMultipleObjects() way */
- if(GetFileType(stdin_handle) == FILE_TYPE_PIPE) {
- /* Don't wait for stdin_handle, just wait for event_handle */
- obj_count = 1;
- /* Check stdin_handle per 100 milliseconds */
- wait_timeout = 100;
- } else {
- obj_count = 2;
- wait_timeout = INFINITE;
- }
-
- /* Keep on listening and act on events */
- while(keepon) {
- waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
- switch(waitret) {
- case WAIT_TIMEOUT:
- {
- unsigned char outbuf[2];
- int out_count = 0;
- ssize_t bytes_written;
- char *buffer = buf;
-
- while(1) {
- if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) {
- keepon = FALSE;
- break;
- }
- nread = readfile_read;
-
- if(!nread)
- break;
-
- if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
- &readfile_read, NULL)) {
- keepon = FALSE;
- break;
- }
- nread = readfile_read;
-
- while(nread--) {
- outbuf[0] = *buffer++;
- out_count = 1;
- if(outbuf[0] == CURL_IAC)
- outbuf[out_count++] = CURL_IAC;
-
- Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
- out_count, &bytes_written);
- }
- }
- }
- break;
-
- case WAIT_OBJECT_0 + 1:
- {
- unsigned char outbuf[2];
- int out_count = 0;
- ssize_t bytes_written;
- char *buffer = buf;
-
- if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
- &readfile_read, NULL)) {
- keepon = FALSE;
- break;
- }
- nread = readfile_read;
-
- while(nread--) {
- outbuf[0] = *buffer++;
- out_count = 1;
- if(outbuf[0] == CURL_IAC)
- outbuf[out_count++] = CURL_IAC;
-
- Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
- out_count, &bytes_written);
- }
- }
- break;
-
- case WAIT_OBJECT_0:
- if(enum_netevents_func(sockfd, event_handle, &events)
- != SOCKET_ERROR) {
- if(events.lNetworkEvents & FD_READ) {
- /* This reallu OUGHT to check its return code. */
- (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
-
- telrcv(conn, (unsigned char *)buf, nread);
-
- fflush(stdout);
-
- /* Negotiate if the peer has started negotiating,
- otherwise don't. We don't want to speak telnet with
- non-telnet servers, like POP or SMTP. */
- if(tn->please_negotiate && !tn->already_negotiated) {
- negotiate(conn);
- tn->already_negotiated = 1;
- }
- }
-
- if(events.lNetworkEvents & FD_CLOSE) {
- keepon = FALSE;
- }
- }
- break;
- }
- }
-
- /* We called WSACreateEvent, so call WSACloseEvent */
- if (close_event_func(event_handle) == FALSE) {
- infof(data,"WSACloseEvent failed (%d)",WSAGetLastError());
- }
-
- /* "Forget" pointers into the library we're about to free */
- create_event_func = NULL;
- close_event_func = NULL;
- event_select_func = NULL;
- enum_netevents_func = NULL;
-
- /* We called LoadLibrary, so call FreeLibrary */
- if (!FreeLibrary(wsock2))
- infof(data,"FreeLibrary(wsock2) failed (%d)",GetLastError());
-#else
- pfd[0].fd = sockfd;
- pfd[0].events = POLLIN;
- pfd[1].fd = 0;
- pfd[1].events = POLLIN;
- interval_ms = 1 * 1000;
-
- while (keepon) {
- switch (Curl_poll(pfd, 2, interval_ms)) {
- case -1: /* error, stop reading */
- keepon = FALSE;
- continue;
- case 0: /* timeout */
- break;
- default: /* read! */
- if(pfd[1].revents & POLLIN) { /* read from stdin */
- unsigned char outbuf[2];
- int out_count = 0;
- ssize_t bytes_written;
- char *buffer = buf;
-
- nread = read(0, buf, 255);
-
- while(nread--) {
- outbuf[0] = *buffer++;
- out_count = 1;
- if(outbuf[0] == CURL_IAC)
- outbuf[out_count++] = CURL_IAC;
-
- Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf,
- out_count, &bytes_written);
- }
- }
-
- if(pfd[0].revents & POLLIN) {
- /* This OUGHT to check the return code... */
- (void)Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
-
- /* if we receive 0 or less here, the server closed the connection and
- we bail out from this! */
- if (nread <= 0) {
- keepon = FALSE;
- break;
- }
-
- telrcv(conn, (unsigned char *)buf, nread);
-
- /* Negotiate if the peer has started negotiating,
- otherwise don't. We don't want to speak telnet with
- non-telnet servers, like POP or SMTP. */
- if(tn->please_negotiate && !tn->already_negotiated) {
- negotiate(conn);
- tn->already_negotiated = 1;
- }
- }
- }
- if(data->set.timeout) {
- struct timeval now; /* current time */
- now = Curl_tvnow();
- if(Curl_tvdiff(now, conn->created)/1000 >= data->set.timeout) {
- failf(data, "Time-out");
- code = CURLE_OPERATION_TIMEOUTED;
- keepon = FALSE;
- }
- }
- }
-#endif
- /* mark this as "no further transfer wanted" */
- Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
-
- return code;
-}
-#endif
diff --git a/Utilities/cmcurl/telnet.h b/Utilities/cmcurl/telnet.h
deleted file mode 100644
index 693abf3f8..000000000
--- a/Utilities/cmcurl/telnet.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __TELNET_H
-#define __TELNET_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_TELNET
-CURLcode Curl_telnet(struct connectdata *conn, bool *done);
-CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature);
-#endif
-#endif
diff --git a/Utilities/cmcurl/tftp.c b/Utilities/cmcurl/tftp.c
deleted file mode 100644
index 0e2e7ab45..000000000
--- a/Utilities/cmcurl/tftp.c
+++ /dev/null
@@ -1,816 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#ifndef CURL_DISABLE_TFTP
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#if defined(WIN32)
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "transfer.h"
-#include "sendf.h"
-#include "tftp.h"
-#include "progress.h"
-#include "connect.h"
-#include "strerror.h"
-#include "sockaddr.h" /* required for Curl_sockaddr_storage */
-#include "url.h"
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#include "memory.h"
-#include "select.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* RFC2348 allows the block size to be negotiated, but we don't support that */
-#define TFTP_BLOCKSIZE 512
-
-typedef enum {
- TFTP_MODE_NETASCII=0,
- TFTP_MODE_OCTET
-} tftp_mode_t;
-
-typedef enum {
- TFTP_STATE_START=0,
- TFTP_STATE_RX,
- TFTP_STATE_TX,
- TFTP_STATE_FIN
-} tftp_state_t;
-
-typedef enum {
- TFTP_EVENT_INIT=0,
- TFTP_EVENT_RRQ = 1,
- TFTP_EVENT_WRQ = 2,
- TFTP_EVENT_DATA = 3,
- TFTP_EVENT_ACK = 4,
- TFTP_EVENT_ERROR = 5,
- TFTP_EVENT_TIMEOUT
-} tftp_event_t;
-
-typedef enum {
- TFTP_ERR_UNDEF=0,
- TFTP_ERR_NOTFOUND,
- TFTP_ERR_PERM,
- TFTP_ERR_DISKFULL,
- TFTP_ERR_ILLEGAL,
- TFTP_ERR_UNKNOWNID,
- TFTP_ERR_EXISTS,
- TFTP_ERR_NOSUCHUSER,
- TFTP_ERR_TIMEOUT,
- TFTP_ERR_NORESPONSE
-} tftp_error_t;
-
-typedef struct tftp_packet {
- unsigned char data[2 + 2 + TFTP_BLOCKSIZE];
-} tftp_packet_t;
-
-typedef struct tftp_state_data {
- tftp_state_t state;
- tftp_mode_t mode;
- tftp_error_t error;
- struct connectdata *conn;
- curl_socket_t sockfd;
- int retries;
- int retry_time;
- int retry_max;
- time_t start_time;
- time_t max_time;
- unsigned short block;
- struct Curl_sockaddr_storage local_addr;
- socklen_t local_addrlen;
- struct Curl_sockaddr_storage remote_addr;
- socklen_t remote_addrlen;
- int rbytes;
- int sbytes;
- tftp_packet_t rpacket;
- tftp_packet_t spacket;
-} tftp_state_data_t;
-
-
-/* Forward declarations */
-static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
-static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
-void tftp_set_timeouts(tftp_state_data_t *state) ;
-
-/**********************************************************
- *
- * tftp_set_timeouts -
- *
- * Set timeouts based on state machine state.
- * Use user provided connect timeouts until DATA or ACK
- * packet is received, then use user-provided transfer timeouts
- *
- *
- **********************************************************/
-void tftp_set_timeouts(tftp_state_data_t *state)
-{
-
- struct SessionHandle *data = state->conn->data;
- time_t maxtime, timeout;
-
- time(&state->start_time);
- if(state->state == TFTP_STATE_START) {
- /* Compute drop-dead time */
- maxtime = (time_t)(data->set.connecttimeout?data->set.connecttimeout:30);
- state->max_time = state->start_time+maxtime;
-
- /* Set per-block timeout to total */
- timeout = maxtime ;
-
- /* Average restart after 5 seconds */
- state->retry_max = (int)(timeout/5);
-
- /* Compute the re-start interval to suit the timeout */
- state->retry_time = (int)(timeout/state->retry_max);
- if(state->retry_time<1)
- state->retry_time=1;
-
- }
- else {
-
- /* Compute drop-dead time */
- maxtime = (time_t)(data->set.timeout?data->set.timeout:3600);
- state->max_time = state->start_time+maxtime;
-
- /* Set per-block timeout to 10% of total */
- timeout = maxtime/10 ;
-
- /* Average reposting an ACK after 15 seconds */
- state->retry_max = (int)(timeout/15);
- }
- /* But bound the total number */
- if(state->retry_max<3)
- state->retry_max=3;
-
- if(state->retry_max>50)
- state->retry_max=50;
-
- /* Compute the re-ACK interval to suit the timeout */
- state->retry_time = (int)(timeout/state->retry_max);
- if(state->retry_time<1)
- state->retry_time=1;
-
- infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n",
- state->state, (state->max_time-state->start_time),
- state->retry_time, state->retry_max);
-}
-
-/**********************************************************
- *
- * tftp_set_send_first
- *
- * Event handler for the START state
- *
- **********************************************************/
-
-static void setpacketevent(tftp_packet_t *packet, unsigned short num)
-{
- packet->data[0] = (unsigned char)(num >> 8);
- packet->data[1] = (unsigned char)(num & 0xff);
-}
-
-
-static void setpacketblock(tftp_packet_t *packet, unsigned short num)
-{
- packet->data[2] = (unsigned char)(num >> 8);
- packet->data[3] = (unsigned char)(num & 0xff);
-}
-
-static unsigned short getrpacketevent(tftp_packet_t *packet)
-{
- return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
-}
-
-static unsigned short getrpacketblock(tftp_packet_t *packet)
-{
- return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
-}
-
-static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
-{
- int sbytes;
- const char *mode = "octet";
- char *filename;
- struct SessionHandle *data = state->conn->data;
- CURLcode res = CURLE_OK;
-
- /* Set ascii mode if -B flag was used */
- if(data->set.prefer_ascii)
- mode = "netascii";
-
- switch(event) {
-
- case TFTP_EVENT_INIT: /* Send the first packet out */
- case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
- /* Increment the retry counter, quit if over the limit */
- state->retries++;
- if(state->retries>state->retry_max) {
- state->error = TFTP_ERR_NORESPONSE;
- state->state = TFTP_STATE_FIN;
- return res;
- }
-
- if(data->set.upload) {
- /* If we are uploading, send an WRQ */
- setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
- state->conn->data->reqdata.upload_fromhere = (char *)&state->spacket.data[4];
- if(data->set.infilesize != -1)
- Curl_pgrsSetUploadSize(data, data->set.infilesize);
- }
- else {
- /* If we are downloading, send an RRQ */
- setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
- }
- /* As RFC3617 describes the separator slash is not actually part of the
- file name so we skip the always-present first letter of the path string. */
- filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0,
- NULL);
- snprintf((char *)&state->spacket.data[2],
- TFTP_BLOCKSIZE,
- "%s%c%s%c", filename, '\0', mode, '\0');
- sbytes = 4 + (int)strlen(filename) + (int)strlen(mode);
- sbytes = sendto(state->sockfd, (void *)&state->spacket,
- sbytes, 0,
- state->conn->ip_addr->ai_addr,
- state->conn->ip_addr->ai_addrlen);
- if(sbytes < 0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- }
- Curl_safefree(filename);
- break;
-
- case TFTP_EVENT_ACK: /* Connected for transmit */
- infof(data, "%s\n", "Connected for transmit");
- state->state = TFTP_STATE_TX;
- tftp_set_timeouts(state);
- return tftp_tx(state, event);
-
- case TFTP_EVENT_DATA: /* connected for receive */
- infof(data, "%s\n", "Connected for receive");
- state->state = TFTP_STATE_RX;
- tftp_set_timeouts(state);
- return tftp_rx(state, event);
-
- case TFTP_EVENT_ERROR:
- state->state = TFTP_STATE_FIN;
- break;
-
- default:
- failf(state->conn->data, "tftp_send_first: internal error\n");
- break;
- }
- return res;
-}
-
-/**********************************************************
- *
- * tftp_rx
- *
- * Event handler for the RX state
- *
- **********************************************************/
-static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
-{
- int sbytes;
- int rblock;
- struct SessionHandle *data = state->conn->data;
-
- switch(event) {
-
- case TFTP_EVENT_DATA:
-
- /* Is this the block we expect? */
- rblock = getrpacketblock(&state->rpacket);
- if ((state->block+1) != rblock) {
- /* No, log it, up the retry count and fail if over the limit */
- infof(data,
- "Received unexpected DATA packet block %d\n", rblock);
- state->retries++;
- if (state->retries>state->retry_max) {
- failf(data, "tftp_rx: giving up waiting for block %d\n",
- state->block+1);
- return CURLE_TFTP_ILLEGAL;
- }
- }
- /* This is the expected block. Reset counters and ACK it. */
- state->block = (unsigned short)rblock;
- state->retries = 0;
- setpacketevent(&state->spacket, TFTP_EVENT_ACK);
- setpacketblock(&state->spacket, state->block);
- sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4, SEND_4TH_ARG,
- (struct sockaddr *)&state->remote_addr,
- state->remote_addrlen);
- if(sbytes < 0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- }
-
- /* Check if completed (That is, a less than full packet is received) */
- if (state->rbytes < (int)sizeof(state->spacket)){
- state->state = TFTP_STATE_FIN;
- }
- else {
- state->state = TFTP_STATE_RX;
- }
- break;
-
- case TFTP_EVENT_TIMEOUT:
- /* Increment the retry count and fail if over the limit */
- state->retries++;
- infof(data,
- "Timeout waiting for block %d ACK. Retries = %d\n", state->retries);
- if(state->retries > state->retry_max) {
- state->error = TFTP_ERR_TIMEOUT;
- state->state = TFTP_STATE_FIN;
- }
- else {
- /* Resend the previous ACK */
- sbytes = sendto(state->sockfd, (void *)&state->spacket,
- 4, SEND_4TH_ARG,
- (struct sockaddr *)&state->remote_addr,
- state->remote_addrlen);
- /* Check all sbytes were sent */
- if(sbytes<0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- }
- }
- break;
-
- case TFTP_EVENT_ERROR:
- state->state = TFTP_STATE_FIN;
- break;
-
- default:
- failf(data, "%s\n", "tftp_rx: internal error");
- break;
- }
- Curl_pgrsSetDownloadCounter(data,
- (curl_off_t) state->block*TFTP_BLOCKSIZE);
- return CURLE_OK;
-}
-
-/**********************************************************
- *
- * tftp_tx
- *
- * Event handler for the TX state
- *
- **********************************************************/
-static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
-{
- struct SessionHandle *data = state->conn->data;
- int sbytes;
- int rblock;
- CURLcode res = CURLE_OK;
-
- switch(event) {
-
- case TFTP_EVENT_ACK:
- /* Ack the packet */
- rblock = getrpacketblock(&state->rpacket);
-
- if(rblock != state->block) {
- /* This isn't the expected block. Log it and up the retry counter */
- infof(data, "Received ACK for block %d, expecting %d\n",
- rblock, state->block);
- state->retries++;
- /* Bail out if over the maximum */
- if(state->retries>state->retry_max) {
- failf(data, "tftp_tx: giving up waiting for block %d ack",
- state->block);
- res = CURLE_SEND_ERROR;
- }
- else {
- /* Re-send the data packet */
- sbytes = sendto(state->sockfd, (void *)&state->spacket,
- 4+state->sbytes, SEND_4TH_ARG,
- (struct sockaddr *)&state->remote_addr,
- state->remote_addrlen);
- /* Check all sbytes were sent */
- if(sbytes<0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- res = CURLE_SEND_ERROR;
- }
- }
- return res;
- }
- /* This is the expected packet. Reset the counters and send the next
- block */
- state->block++;
- state->retries = 0;
- setpacketevent(&state->spacket, TFTP_EVENT_DATA);
- setpacketblock(&state->spacket, state->block);
- if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) {
- state->state = TFTP_STATE_FIN;
- return CURLE_OK;
- }
- res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes);
- if(res)
- return res;
- sbytes = sendto(state->sockfd, (void *)state->spacket.data,
- 4+state->sbytes, SEND_4TH_ARG,
- (struct sockaddr *)&state->remote_addr,
- state->remote_addrlen);
- /* Check all sbytes were sent */
- if(sbytes<0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- }
- break;
-
- case TFTP_EVENT_TIMEOUT:
- /* Increment the retry counter and log the timeout */
- state->retries++;
- infof(data, "Timeout waiting for block %d ACK. "
- " Retries = %d\n", state->retries);
- /* Decide if we've had enough */
- if(state->retries > state->retry_max) {
- state->error = TFTP_ERR_TIMEOUT;
- state->state = TFTP_STATE_FIN;
- } else {
- /* Re-send the data packet */
- sbytes = sendto(state->sockfd, (void *)&state->spacket,
- 4+state->sbytes, SEND_4TH_ARG,
- (struct sockaddr *)&state->remote_addr,
- state->remote_addrlen);
- /* Check all sbytes were sent */
- if(sbytes<0) {
- failf(data, "%s\n", Curl_strerror(state->conn, Curl_sockerrno()));
- }
- }
- break;
-
- case TFTP_EVENT_ERROR:
- state->state = TFTP_STATE_FIN;
- break;
-
- default:
- failf(data, "%s\n", "tftp_tx: internal error");
- break;
- }
-
- /* Update the progress meter */
- Curl_pgrsSetUploadCounter(data, (curl_off_t) state->block*TFTP_BLOCKSIZE);
-
- return res;
-}
-
-/**********************************************************
- *
- * tftp_state_machine
- *
- * The tftp state machine event dispatcher
- *
- **********************************************************/
-static CURLcode tftp_state_machine(tftp_state_data_t *state,
- tftp_event_t event)
-{
- CURLcode res = CURLE_OK;
- struct SessionHandle *data = state->conn->data;
- switch(state->state) {
- case TFTP_STATE_START:
- DEBUGF(infof(data, "TFTP_STATE_START\n"));
- res = tftp_send_first(state, event);
- break;
- case TFTP_STATE_RX:
- DEBUGF(infof(data, "TFTP_STATE_RX\n"));
- res = tftp_rx(state, event);
- break;
- case TFTP_STATE_TX:
- DEBUGF(infof(data, "TFTP_STATE_TX\n"));
- res = tftp_tx(state, event);
- break;
- case TFTP_STATE_FIN:
- infof(data, "%s\n", "TFTP finished");
- break;
- default:
- DEBUGF(infof(data, "STATE: %d\n", state->state));
- failf(data, "%s\n", "Internal state machine error");
- res = CURLE_TFTP_ILLEGAL;
- break;
- }
- return res;
-}
-
-
-/**********************************************************
- *
- * Curl_tftp_connect
- *
- * The connect callback
- *
- **********************************************************/
-CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done)
-{
- CURLcode code;
- tftp_state_data_t *state;
- int rc;
-
- state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t),
- 1);
- if(!state)
- return CURLE_OUT_OF_MEMORY;
-
- conn->bits.close = FALSE; /* keep it open if possible */
-
- state->conn = conn;
- state->sockfd = state->conn->sock[FIRSTSOCKET];
- state->state = TFTP_STATE_START;
-
- ((struct sockaddr *)&state->local_addr)->sa_family =
- conn->ip_addr->ai_family;
-
- tftp_set_timeouts(state);
-
- if(!conn->bits.reuse) {
- /* If not reused, bind to any interface, random UDP port. If it is reused,
- * this has already been done!
- *
- * We once used the size of the local_addr struct as the third argument for
- * bind() to better work with IPv6 or whatever size the struct could have,
- * but we learned that at least Tru64, AIX and IRIX *requires* the size of
- * that argument to match the exact size of a 'sockaddr_in' struct when
- * running IPv4-only.
- *
- * Therefore we use the size from the address we connected to, which we
- * assume uses the same IP version and thus hopefully this works for both
- * IPv4 and IPv6...
- */
- rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
- conn->ip_addr->ai_addrlen);
- if(rc) {
- failf(conn->data, "bind() failed; %s\n",
- Curl_strerror(conn, Curl_sockerrno()));
- return CURLE_COULDNT_CONNECT;
- }
- }
-
- Curl_pgrsStartNow(conn->data);
-
- *done = TRUE;
- code = CURLE_OK;
- return(code);
-}
-
-/**********************************************************
- *
- * Curl_tftp_done
- *
- * The done callback
- *
- **********************************************************/
-CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status,
- bool premature)
-{
- (void)status; /* unused */
- (void)premature; /* not used */
-
-#if 0
- free(conn->data->reqdata.proto.tftp);
- conn->data->reqdata.proto.tftp = NULL;
-#endif
- Curl_pgrsDone(conn);
-
- return CURLE_OK;
-}
-
-
-/**********************************************************
- *
- * Curl_tftp
- *
- * The do callback
- *
- * This callback handles the entire TFTP transfer
- *
- **********************************************************/
-
-CURLcode Curl_tftp(struct connectdata *conn, bool *done)
-{
- struct SessionHandle *data = conn->data;
- tftp_state_data_t *state =
- (tftp_state_data_t *) conn->data->reqdata.proto.tftp;
- tftp_event_t event;
- CURLcode code;
- int rc;
- struct Curl_sockaddr_storage fromaddr;
- socklen_t fromlen;
- int check_time = 0;
-
- *done = TRUE;
-
- /*
- Since connections can be re-used between SessionHandles, this might be a
- connection already existing but on a fresh SessionHandle struct so we must
- make sure we have a good 'struct TFTP' to play with. For new connections,
- the struct TFTP is allocated and setup in the Curl_tftp_connect() function.
- */
- if(!state) {
- code = Curl_tftp_connect(conn, done);
- if(code)
- return code;
- state = (tftp_state_data_t *)conn->data->reqdata.proto.tftp;
- }
-
- /* Run the TFTP State Machine */
- for(tftp_state_machine(state, TFTP_EVENT_INIT);
- state->state != TFTP_STATE_FIN;
- tftp_state_machine(state, event) ) {
-
- /* Wait until ready to read or timeout occurs */
- rc=Curl_select(state->sockfd, CURL_SOCKET_BAD, state->retry_time * 1000);
-
- if(rc == -1) {
- /* bail out */
- int error = Curl_sockerrno();
- failf(data, "%s\n", Curl_strerror(conn, error));
- event = TFTP_EVENT_ERROR;
- }
- else if (rc==0) {
- /* A timeout occured */
- event = TFTP_EVENT_TIMEOUT;
-
- /* Force a look at transfer timeouts */
- check_time = 0;
-
- }
- else {
-
- /* Receive the packet */
- fromlen=sizeof(fromaddr);
- state->rbytes = recvfrom(state->sockfd,
- (void *)&state->rpacket, sizeof(state->rpacket),
- 0, (struct sockaddr *)&fromaddr, &fromlen);
- if(state->remote_addrlen==0) {
- memcpy(&state->remote_addr, &fromaddr, fromlen);
- state->remote_addrlen = fromlen;
- }
-
- /* Sanity check packet length */
- if (state->rbytes < 4) {
- failf(conn->data, "Received too short packet\n");
- /* Not a timeout, but how best to handle it? */
- event = TFTP_EVENT_TIMEOUT;
- }
- else {
-
- /* The event is given by the TFTP packet time */
- event = (tftp_event_t)getrpacketevent(&state->rpacket);
-
- switch(event) {
- case TFTP_EVENT_DATA:
- /* Don't pass to the client empty or retransmitted packets */
- if (state->rbytes > 4 &&
- ((state->block+1) == getrpacketblock(&state->rpacket))) {
- code = Curl_client_write(conn, CLIENTWRITE_BODY,
- (char *)&state->rpacket.data[4],
- state->rbytes-4);
- if(code)
- return code;
- }
- break;
- case TFTP_EVENT_ERROR:
- state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
- infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]);
- break;
- case TFTP_EVENT_ACK:
- break;
- case TFTP_EVENT_RRQ:
- case TFTP_EVENT_WRQ:
- default:
- failf(conn->data, "%s\n", "Internal error: Unexpected packet");
- break;
- }
-
- /* Update the progress meter */
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
- }
- }
-
- /* Check for transfer timeout every 10 blocks, or after timeout */
- if(check_time%10==0) {
- time_t current;
- time(&current);
- if(current>state->max_time) {
- DEBUGF(infof(data, "timeout: %d > %d\n",
- current, state->max_time));
- state->error = TFTP_ERR_TIMEOUT;
- state->state = TFTP_STATE_FIN;
- }
- }
-
- }
-
- /* Tell curl we're done */
- code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
- if(code)
- return code;
-
- /* If we have encountered an error */
- if(state->error) {
-
- /* Translate internal error codes to curl error codes */
- switch(state->error) {
- case TFTP_ERR_NOTFOUND:
- code = CURLE_TFTP_NOTFOUND;
- break;
- case TFTP_ERR_PERM:
- code = CURLE_TFTP_PERM;
- break;
- case TFTP_ERR_DISKFULL:
- code = CURLE_TFTP_DISKFULL;
- break;
- case TFTP_ERR_ILLEGAL:
- code = CURLE_TFTP_ILLEGAL;
- break;
- case TFTP_ERR_UNKNOWNID:
- code = CURLE_TFTP_UNKNOWNID;
- break;
- case TFTP_ERR_EXISTS:
- code = CURLE_TFTP_EXISTS;
- break;
- case TFTP_ERR_NOSUCHUSER:
- code = CURLE_TFTP_NOSUCHUSER;
- break;
- case TFTP_ERR_TIMEOUT:
- code = CURLE_OPERATION_TIMEOUTED;
- break;
- case TFTP_ERR_NORESPONSE:
- code = CURLE_COULDNT_CONNECT;
- break;
- default:
- code= CURLE_ABORTED_BY_CALLBACK;
- break;
- }
- }
- else
- code = CURLE_OK;
- return code;
-}
-#endif
diff --git a/Utilities/cmcurl/tftp.h b/Utilities/cmcurl/tftp.h
deleted file mode 100644
index c7125417b..000000000
--- a/Utilities/cmcurl/tftp.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __TFTP_H
-#define __TFTP_H
-
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-#ifndef CURL_DISABLE_TFTP
-CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done);
-CURLcode Curl_tftp(struct connectdata *conn, bool *done);
-CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature);
-#endif
-#endif
diff --git a/Utilities/cmcurl/timeval.c b/Utilities/cmcurl/timeval.c
deleted file mode 100644
index bb9c0a174..000000000
--- a/Utilities/cmcurl/timeval.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "timeval.h"
-
-#ifndef HAVE_GETTIMEOFDAY
-
-#ifdef WIN32
-#include <mmsystem.h>
-
-static int gettimeofday(struct timeval *tp, void *nothing)
-{
-#ifdef WITHOUT_MM_LIB
- SYSTEMTIME st;
- time_t tt;
- struct tm tmtm;
- /* mktime converts local to UTC */
- GetLocalTime (&st);
- tmtm.tm_sec = st.wSecond;
- tmtm.tm_min = st.wMinute;
- tmtm.tm_hour = st.wHour;
- tmtm.tm_mday = st.wDay;
- tmtm.tm_mon = st.wMonth - 1;
- tmtm.tm_year = st.wYear - 1900;
- tmtm.tm_isdst = -1;
- tt = mktime (&tmtm);
- tp->tv_sec = tt;
- tp->tv_usec = st.wMilliseconds * 1000;
-#else
- /**
- ** The earlier time calculations using GetLocalTime
- ** had a time resolution of 10ms.The timeGetTime, part
- ** of multimedia apis offer a better time resolution
- ** of 1ms.Need to link against winmm.lib for this
- **/
- unsigned long Ticks = 0;
- unsigned long Sec =0;
- unsigned long Usec = 0;
- Ticks = timeGetTime();
-
- Sec = Ticks/1000;
- Usec = (Ticks - (Sec*1000))*1000;
- tp->tv_sec = Sec;
- tp->tv_usec = Usec;
-#endif /* WITHOUT_MM_LIB */
- (void)nothing;
- return 0;
-}
-#else /* WIN32 */
-/* non-win32 version of Curl_gettimeofday() */
-static int gettimeofday(struct timeval *tp, void *nothing)
-{
- (void)nothing; /* we don't support specific time-zones */
- tp->tv_sec = (long)time(NULL);
- tp->tv_usec = 0;
- return 0;
-}
-#endif /* WIN32 */
-#endif /* HAVE_GETTIMEOFDAY */
-
-/* Return the current time in a timeval struct */
-struct timeval curlx_tvnow(void)
-{
- struct timeval now;
- (void)gettimeofday(&now, NULL);
- return now;
-}
-
-/*
- * Make sure that the first argument is the more recent time, as otherwise
- * we'll get a weird negative time-diff back...
- *
- * Returns: the time difference in number of milliseconds.
- */
-long curlx_tvdiff(struct timeval newer, struct timeval older)
-{
- return (newer.tv_sec-older.tv_sec)*1000+
- (newer.tv_usec-older.tv_usec)/1000;
-}
-
-/*
- * Same as curlx_tvdiff but with full usec resolution.
- *
- * Returns: the time difference in seconds with subsecond resolution.
- */
-double curlx_tvdiff_secs(struct timeval newer, struct timeval older)
-{
- return (double)(newer.tv_sec-older.tv_sec)+
- (double)(newer.tv_usec-older.tv_usec)/1000000.0;
-}
-
-/* return the number of seconds in the given input timeval struct */
-long Curl_tvlong(struct timeval t1)
-{
- return t1.tv_sec;
-}
diff --git a/Utilities/cmcurl/timeval.h b/Utilities/cmcurl/timeval.h
deleted file mode 100644
index effd741da..000000000
--- a/Utilities/cmcurl/timeval.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef __TIMEVAL_H
-#define __TIMEVAL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/*
- * CAUTION: this header is designed to work when included by the app-side
- * as well as the library. Do not mix with library internals!
- */
-
-#include "setup.h"
-
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#ifdef TIME_WITH_SYS_TIME
-#include <time.h>
-#endif
-#else
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
-#endif
-
-#ifndef HAVE_STRUCT_TIMEVAL
-struct timeval {
- long tv_sec;
- long tv_usec;
-};
-#endif
-
-struct timeval curlx_tvnow(void);
-
-/*
- * Make sure that the first argument (t1) is the more recent time and t2 is
- * the older time, as otherwise you get a weird negative time-diff back...
- *
- * Returns: the time difference in number of milliseconds.
- */
-long curlx_tvdiff(struct timeval t1, struct timeval t2);
-
-/*
- * Same as curlx_tvdiff but with full usec resolution.
- *
- * Returns: the time difference in seconds with subsecond resolution.
- */
-double curlx_tvdiff_secs(struct timeval t1, struct timeval t2);
-
-long Curl_tvlong(struct timeval t1);
-
-/* These two defines below exist to provide the older API for library
- internals only. */
-#define Curl_tvnow() curlx_tvnow()
-#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
-#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y)
-
-#endif
diff --git a/Utilities/cmcurl/transfer.c b/Utilities/cmcurl/transfer.c
deleted file mode 100644
index 5cb3361d2..000000000
--- a/Utilities/cmcurl/transfer.c
+++ /dev/null
@@ -1,2494 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-/* -- WIN32 approved -- */
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
-#include <errno.h>
-
-#include "strtoofft.h"
-#include "strequal.h"
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifdef HAVE_SYS_SELECT_H
-#include <sys/select.h>
-#endif
-
-#ifndef HAVE_SOCKET
-#error "We can't compile without socket() support!"
-#endif
-
-#endif
-
-#include "urldata.h"
-#include <curl/curl.h>
-#include "netrc.h"
-
-#include "content_encoding.h"
-#include "hostip.h"
-#include "transfer.h"
-#include "sendf.h"
-#include "speedcheck.h"
-#include "progress.h"
-#include "http.h"
-#include "url.h"
-#include "getinfo.h"
-#include "sslgen.h"
-#include "http_digest.h"
-#include "http_ntlm.h"
-#include "http_negotiate.h"
-#include "share.h"
-#include "memory.h"
-#include "select.h"
-#include "multiif.h"
-#include "easyif.h" /* for Curl_convert_to_network prototype */
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */
-
-/*
- * This function will call the read callback to fill our buffer with data
- * to upload.
- */
-CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
-{
- struct SessionHandle *data = conn->data;
- size_t buffersize = (size_t)bytes;
- int nread;
-
- if(conn->bits.upload_chunky) {
- /* if chunked Transfer-Encoding */
- buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
- data->reqdata.upload_fromhere += 10; /* 32bit hex + CRLF */
- }
-
- /* this function returns a size_t, so we typecast to int to prevent warnings
- with picky compilers */
- nread = (int)conn->fread(data->reqdata.upload_fromhere, 1,
- buffersize, conn->fread_in);
-
- if(nread == CURL_READFUNC_ABORT) {
- failf(data, "operation aborted by callback\n");
- return CURLE_ABORTED_BY_CALLBACK;
- }
-
- if(!conn->bits.forbidchunk && conn->bits.upload_chunky) {
- /* if chunked Transfer-Encoding */
- char hexbuffer[11];
- int hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
- "%x\r\n", nread);
- /* move buffer pointer */
- data->reqdata.upload_fromhere -= hexlen;
- nread += hexlen;
-
- /* copy the prefix to the buffer */
- memcpy(data->reqdata.upload_fromhere, hexbuffer, hexlen);
-
- /* always append CRLF to the data */
- memcpy(data->reqdata.upload_fromhere + nread, "\r\n", 2);
-
- if((nread - hexlen) == 0) {
- /* mark this as done once this chunk is transfered */
- data->reqdata.keep.upload_done = TRUE;
- }
-
- nread+=2; /* for the added CRLF */
- }
-
- *nreadp = nread;
-
-#ifdef CURL_DOES_CONVERSIONS
- if(data->set.prefer_ascii) {
- CURLcode res;
- res = Curl_convert_to_network(data, data->reqdata.upload_fromhere, nread);
- /* Curl_convert_to_network calls failf if unsuccessful */
- if(res != CURLE_OK) {
- return(res);
- }
- }
-#endif /* CURL_DOES_CONVERSIONS */
-
- return CURLE_OK;
-}
-
-/*
- * checkhttpprefix()
- *
- * Returns TRUE if member of the list matches prefix of string
- */
-static bool
-checkhttpprefix(struct SessionHandle *data,
- const char *s)
-{
- struct curl_slist *head = data->set.http200aliases;
- bool rc = FALSE;
-#ifdef CURL_DOES_CONVERSIONS
- /* convert from the network encoding using a scratch area */
- char *scratch = calloc(1, strlen(s)+1);
- if (NULL == scratch) {
- failf (data, "Failed to calloc memory for conversion!");
- return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
- }
- strcpy(scratch, s);
- if (CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- free(scratch);
- return FALSE; /* can't return CURLE_foobar so return FALSE */
- }
- s = scratch;
-#endif /* CURL_DOES_CONVERSIONS */
-
- while (head) {
- if (checkprefix(head->data, s)) {
- rc = TRUE;
- break;
- }
- head = head->next;
- }
-
- if ((rc != TRUE) && (checkprefix("HTTP/", s))) {
- rc = TRUE;
- }
-
-#ifdef CURL_DOES_CONVERSIONS
- free(scratch);
-#endif /* CURL_DOES_CONVERSIONS */
- return rc;
-}
-
-/*
- * Curl_readrewind() rewinds the read stream. This typically (so far) only
- * used for HTTP POST/PUT with multi-pass authentication when a sending was
- * denied and a resend is necessary.
- */
-CURLcode Curl_readrewind(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
-
- conn->bits.rewindaftersend = FALSE; /* we rewind now */
-
- /* We have sent away data. If not using CURLOPT_POSTFIELDS or
- CURLOPT_HTTPPOST, call app to rewind
- */
- if(data->set.postfields ||
- (data->set.httpreq == HTTPREQ_POST_FORM))
- ; /* do nothing */
- else {
- if(data->set.ioctl) {
- curlioerr err;
-
- err = (data->set.ioctl) (data, CURLIOCMD_RESTARTREAD,
- data->set.ioctl_client);
- infof(data, "the ioctl callback returned %d\n", (int)err);
-
- if(err) {
- /* FIXME: convert to a human readable error message */
- failf(data, "ioctl callback returned error %d\n", (int)err);
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- else {
- /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
- given FILE * stream and we can actually attempt to rewind that
- ourself with fseek() */
- if(data->set.fread == (curl_read_callback)fread) {
- if(-1 != fseek(data->set.in, 0, SEEK_SET))
- /* successful rewind */
- return CURLE_OK;
- }
-
- /* no callback set or failure aboe, makes us fail at once */
- failf(data, "necessary data rewind wasn't possible\n");
- return CURLE_SEND_FAIL_REWIND;
- }
- }
- return CURLE_OK;
-}
-
-static int data_pending(struct connectdata *conn)
-{
- return Curl_ssl_data_pending(conn, FIRSTSOCKET);
-}
-
-#ifndef MIN
-#define MIN(a,b) (a < b ? a : b)
-#endif
-
-static void read_rewind(struct connectdata *conn,
- size_t thismuch)
-{
- conn->read_pos -= thismuch;
- conn->bits.stream_was_rewound = TRUE;
-
-#ifdef CURLDEBUG
- {
- char buf[512 + 1];
- size_t show;
-
- show = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
- memcpy(buf, conn->master_buffer + conn->read_pos, show);
- buf[show] = '\0';
-
- DEBUGF(infof(conn->data,
- "Buffer after stream rewind (read_pos = %d): [%s]",
- conn->read_pos, buf));
- }
-#endif
-}
-
-/*
- * Curl_readwrite() is the low-level function to be called when data is to
- * be read and written to/from the connection.
- */
-CURLcode Curl_readwrite(struct connectdata *conn,
- bool *done)
-{
- struct SessionHandle *data = conn->data;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- CURLcode result;
- ssize_t nread; /* number of bytes read */
- int didwhat=0;
-
- curl_socket_t fd_read;
- curl_socket_t fd_write;
- int select_res;
-
- curl_off_t contentlength;
-
- /* only use the proper socket if the *_HOLD bit is not set simultaneously as
- then we are in rate limiting state in that transfer direction */
-
- if((k->keepon & (KEEP_READ|KEEP_READ_HOLD)) == KEEP_READ)
- fd_read = conn->sockfd;
- else
- fd_read = CURL_SOCKET_BAD;
-
- if((k->keepon & (KEEP_WRITE|KEEP_WRITE_HOLD)) == KEEP_WRITE)
- fd_write = conn->writesockfd;
- else
- fd_write = CURL_SOCKET_BAD;
-
- select_res = Curl_select(fd_read, fd_write, 0);
- if(select_res == CSELECT_ERR) {
- failf(data, "select/poll returned error");
- return CURLE_SEND_ERROR;
- }
-
- do {
- /* We go ahead and do a read if we have a readable socket or if
- the stream was rewound (in which case we have data in a
- buffer) */
- if((k->keepon & KEEP_READ) &&
- ((select_res & CSELECT_IN) || conn->bits.stream_was_rewound)) {
- /* read */
- bool is_empty_data = FALSE;
-
- /* This is where we loop until we have read everything there is to
- read or we get a EWOULDBLOCK */
- do {
- size_t buffersize = data->set.buffer_size?
- data->set.buffer_size : BUFSIZE;
- size_t bytestoread = buffersize;
- int readrc;
-
- if (k->size != -1 && !k->header) {
- /* make sure we don't read "too much" if we can help it since we
- might be pipelining and then someone else might want to read what
- follows! */
- curl_off_t totalleft = k->size - k->bytecount;
- if(totalleft < (curl_off_t)bytestoread)
- bytestoread = (size_t)totalleft;
- }
-
- /* receive data from the network! */
- readrc = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
-
- /* subzero, this would've blocked */
- if(0 > readrc)
- break; /* get out of loop */
-
- /* get the CURLcode from the int */
- result = (CURLcode)readrc;
-
- if(result>0)
- return result;
-
- if ((k->bytecount == 0) && (k->writebytecount == 0)) {
- Curl_pgrsTime(data, TIMER_STARTTRANSFER);
- if(k->wait100_after_headers)
- /* set time stamp to compare with when waiting for the 100 */
- k->start100 = Curl_tvnow();
- }
-
- didwhat |= KEEP_READ;
- /* indicates data of zero size, i.e. empty file */
- is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0));
-
- /* NULL terminate, allowing string ops to be used */
- if (0 < nread || is_empty_data) {
- k->buf[nread] = 0;
- }
- else if (0 >= nread) {
- /* if we receive 0 or less here, the server closed the connection
- and we bail out from this! */
-
- k->keepon &= ~KEEP_READ;
- break;
- }
-
- /* Default buffer to use when we write the buffer, it may be changed
- in the flow below before the actual storing is done. */
- k->str = k->buf;
-
- /* Since this is a two-state thing, we check if we are parsing
- headers at the moment or not. */
- if (k->header) {
- /* we are in parse-the-header-mode */
- bool stop_reading = FALSE;
-
- /* header line within buffer loop */
- do {
- size_t hbufp_index;
- size_t rest_length;
- size_t full_length;
- int writetype;
-
- /* str_start is start of line within buf */
- k->str_start = k->str;
-
- /* data is in network encoding so use 0x0a instead of '\n' */
- k->end_ptr = memchr(k->str_start, 0x0a, nread);
-
- if (!k->end_ptr) {
- /* Not a complete header line within buffer, append the data to
- the end of the headerbuff. */
-
- if (k->hbuflen + nread >= data->state.headersize) {
- /* We enlarge the header buffer as it is too small */
- char *newbuff;
- size_t newsize=CURLMAX((k->hbuflen+nread)*3/2,
- data->state.headersize*2);
- hbufp_index = k->hbufp - data->state.headerbuff;
- newbuff = (char *)realloc(data->state.headerbuff, newsize);
- if(!newbuff) {
- failf (data, "Failed to alloc memory for big header!");
- return CURLE_OUT_OF_MEMORY;
- }
- data->state.headersize=newsize;
- data->state.headerbuff = newbuff;
- k->hbufp = data->state.headerbuff + hbufp_index;
- }
- memcpy(k->hbufp, k->str, nread);
- k->hbufp += nread;
- k->hbuflen += nread;
- if (!k->headerline && (k->hbuflen>5)) {
- /* make a first check that this looks like a HTTP header */
- if(!checkhttpprefix(data, data->state.headerbuff)) {
- /* this is not the beginning of a HTTP first header line */
- k->header = FALSE;
- k->badheader = HEADER_ALLBAD;
- break;
- }
- }
-
- break; /* read more and try again */
- }
-
- /* decrease the size of the remaining (supposed) header line */
- rest_length = (k->end_ptr - k->str)+1;
- nread -= (ssize_t)rest_length;
-
- k->str = k->end_ptr + 1; /* move past new line */
-
- full_length = k->str - k->str_start;
-
- /*
- * We're about to copy a chunk of data to the end of the
- * already received header. We make sure that the full string
- * fit in the allocated header buffer, or else we enlarge
- * it.
- */
- if (k->hbuflen + full_length >=
- data->state.headersize) {
- char *newbuff;
- size_t newsize=CURLMAX((k->hbuflen+full_length)*3/2,
- data->state.headersize*2);
- hbufp_index = k->hbufp - data->state.headerbuff;
- newbuff = (char *)realloc(data->state.headerbuff, newsize);
- if(!newbuff) {
- failf (data, "Failed to alloc memory for big header!");
- return CURLE_OUT_OF_MEMORY;
- }
- data->state.headersize= newsize;
- data->state.headerbuff = newbuff;
- k->hbufp = data->state.headerbuff + hbufp_index;
- }
-
- /* copy to end of line */
- memcpy(k->hbufp, k->str_start, full_length);
- k->hbufp += full_length;
- k->hbuflen += full_length;
- *k->hbufp = 0;
- k->end_ptr = k->hbufp;
-
- k->p = data->state.headerbuff;
-
- /****
- * We now have a FULL header line that p points to
- *****/
-
- if(!k->headerline) {
- /* the first read header */
- if((k->hbuflen>5) &&
- !checkhttpprefix(data, data->state.headerbuff)) {
- /* this is not the beginning of a HTTP first header line */
- k->header = FALSE;
- if(nread)
- /* since there's more, this is a partial bad header */
- k->badheader = HEADER_PARTHEADER;
- else {
- /* this was all we read so its all a bad header */
- k->badheader = HEADER_ALLBAD;
- nread = (ssize_t)rest_length;
- }
- break;
- }
- }
-
- /* headers are in network encoding so
- use 0x0a and 0x0d instead of '\n' and '\r' */
- if ((0x0a == *k->p) || (0x0d == *k->p)) {
- size_t headerlen;
- /* Zero-length header line means end of headers! */
-
-#ifdef CURL_DOES_CONVERSIONS
- if (0x0d == *k->p) {
- *k->p = '\r'; /* replace with CR in host encoding */
- k->p++; /* pass the CR byte */
- }
- if (0x0a == *k->p) {
- *k->p = '\n'; /* replace with LF in host encoding */
- k->p++; /* pass the LF byte */
- }
-#else
- if ('\r' == *k->p)
- k->p++; /* pass the \r byte */
- if ('\n' == *k->p)
- k->p++; /* pass the \n byte */
-#endif /* CURL_DOES_CONVERSIONS */
-
- if(100 == k->httpcode) {
- /*
- * We have made a HTTP PUT or POST and this is 1.1-lingo
- * that tells us that the server is OK with this and ready
- * to receive the data.
- * However, we'll get more headers now so we must get
- * back into the header-parsing state!
- */
- k->header = TRUE;
- k->headerline = 0; /* restart the header line counter */
- /* if we did wait for this do enable write now! */
- if (k->write_after_100_header) {
-
- k->write_after_100_header = FALSE;
- k->keepon |= KEEP_WRITE;
- }
- }
- else {
- k->header = FALSE; /* no more header to parse! */
-
- if((k->size == -1) && !conn->bits.chunk && !conn->bits.close)
- /* When connection is not to get closed, but no
- Content-Length nor Content-Encoding chunked have been
- received, there is no body in this response. We don't set
- stop_reading TRUE since that would also prevent necessary
- authentication actions to take place. */
- conn->bits.no_body = TRUE;
-
- }
-
- if (417 == k->httpcode) {
- /*
- * we got: "417 Expectation Failed" this means:
- * we have made a HTTP call and our Expect Header
- * seems to cause a problem => abort the write operations
- * (or prevent them from starting).
- */
- k->write_after_100_header = FALSE;
- k->keepon &= ~KEEP_WRITE;
- }
-
-#ifndef CURL_DISABLE_HTTP
- /*
- * When all the headers have been parsed, see if we should give
- * up and return an error.
- */
- if (Curl_http_should_fail(conn)) {
- failf (data, "The requested URL returned error: %d",
- k->httpcode);
- return CURLE_HTTP_RETURNED_ERROR;
- }
-#endif /* CURL_DISABLE_HTTP */
-
- /* now, only output this if the header AND body are requested:
- */
- writetype = CLIENTWRITE_HEADER;
- if (data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
-
- headerlen = k->p - data->state.headerbuff;
-
- result = Curl_client_write(conn, writetype,
- data->state.headerbuff,
- headerlen);
- if(result)
- return result;
-
- data->info.header_size += (long)headerlen;
- conn->headerbytecount += (long)headerlen;
-
- conn->deductheadercount =
- (100 == k->httpcode)?conn->headerbytecount:0;
-
- if (data->reqdata.resume_from &&
- (data->set.httpreq==HTTPREQ_GET) &&
- (k->httpcode == 416)) {
- /* "Requested Range Not Satisfiable" */
- stop_reading = TRUE;
- }
-
-#ifndef CURL_DISABLE_HTTP
- if(!stop_reading) {
- /* Curl_http_auth_act() checks what authentication methods
- * that are available and decides which one (if any) to
- * use. It will set 'newurl' if an auth metod was picked. */
- result = Curl_http_auth_act(conn);
-
- if(result)
- return result;
-
- if(conn->bits.rewindaftersend) {
- /* We rewind after a complete send, so thus we continue
- sending now */
- infof(data, "Keep sending data to get tossed away!\n");
- k->keepon |= KEEP_WRITE;
- }
- }
-#endif /* CURL_DISABLE_HTTP */
-
- if(!k->header) {
- /*
- * really end-of-headers.
- *
- * If we requested a "no body", this is a good time to get
- * out and return home.
- */
- if(conn->bits.no_body)
- stop_reading = TRUE;
- else {
- /* If we know the expected size of this document, we set the
- maximum download size to the size of the expected
- document or else, we won't know when to stop reading!
-
- Note that we set the download maximum even if we read a
- "Connection: close" header, to make sure that
- "Content-Length: 0" still prevents us from attempting to
- read the (missing) response-body.
- */
- /* According to RFC2616 section 4.4, we MUST ignore
- Content-Length: headers if we are now receiving data
- using chunked Transfer-Encoding.
- */
- if(conn->bits.chunk)
- k->size=-1;
-
- }
- if(-1 != k->size) {
- /* We do this operation even if no_body is true, since this
- data might be retrieved later with curl_easy_getinfo()
- and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
-
- Curl_pgrsSetDownloadSize(data, k->size);
- k->maxdownload = k->size;
- }
- /* If max download size is *zero* (nothing) we already
- have nothing and can safely return ok now! */
- if(0 == k->maxdownload)
- stop_reading = TRUE;
-
- if(stop_reading) {
- /* we make sure that this socket isn't read more now */
- k->keepon &= ~KEEP_READ;
- }
-
- break; /* exit header line loop */
- }
-
- /* We continue reading headers, so reset the line-based
- header parsing variables hbufp && hbuflen */
- k->hbufp = data->state.headerbuff;
- k->hbuflen = 0;
- continue;
- }
-
- /*
- * Checks for special headers coming up.
- */
-
- if (!k->headerline++) {
- /* This is the first header, it MUST be the error code line
- or else we consider this to be the body right away! */
- int httpversion_major;
- int nc;
-#ifdef CURL_DOES_CONVERSIONS
-#define HEADER1 scratch
-#define SCRATCHSIZE 21
- CURLcode res;
- char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
- /* We can't really convert this yet because we
- don't know if it's the 1st header line or the body.
- So we do a partial conversion into a scratch area,
- leaving the data at k->p as-is.
- */
- strncpy(&scratch[0], k->p, SCRATCHSIZE);
- scratch[SCRATCHSIZE] = 0; /* null terminate */
- res = Curl_convert_from_network(data,
- &scratch[0],
- SCRATCHSIZE);
- if (CURLE_OK != res) {
- /* Curl_convert_from_network calls failf if unsuccessful */
- return res;
- }
-#else
-#define HEADER1 k->p /* no conversion needed, just use k->p */
-#endif /* CURL_DOES_CONVERSIONS */
-
- nc = sscanf(HEADER1,
- " HTTP/%d.%d %3d",
- &httpversion_major,
- &k->httpversion,
- &k->httpcode);
- if (nc==3) {
- k->httpversion += 10 * httpversion_major;
- }
- else {
- /* this is the real world, not a Nirvana
- NCSA 1.5.x returns this crap when asked for HTTP/1.1
- */
- nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
- k->httpversion = 10;
-
- /* If user has set option HTTP200ALIASES,
- compare header line against list of aliases
- */
- if (!nc) {
- if (checkhttpprefix(data, k->p)) {
- nc = 1;
- k->httpcode = 200;
- k->httpversion =
- (data->set.httpversion==CURL_HTTP_VERSION_1_0)? 10 : 11;
- }
- }
- }
-
- if (nc) {
- data->info.httpcode = k->httpcode;
- data->info.httpversion = k->httpversion;
-
- /*
- * This code executes as part of processing the header. As a
- * result, it's not totally clear how to interpret the
- * response code yet as that depends on what other headers may
- * be present. 401 and 407 may be errors, but may be OK
- * depending on how authentication is working. Other codes
- * are definitely errors, so give up here.
- */
- if (data->set.http_fail_on_error && (k->httpcode >= 400) &&
- ((k->httpcode != 401) || !data->set.userpwd) &&
- ((k->httpcode != 407) || !data->set.proxyuserpwd) ) {
-
- if (data->reqdata.resume_from &&
- (data->set.httpreq==HTTPREQ_GET) &&
- (k->httpcode == 416)) {
- /* "Requested Range Not Satisfiable", just proceed and
- pretend this is no error */
- }
- else {
- /* serious error, go home! */
- failf (data, "The requested URL returned error: %d",
- k->httpcode);
- return CURLE_HTTP_RETURNED_ERROR;
- }
- }
-
- if(k->httpversion == 10)
- /* Default action for HTTP/1.0 must be to close, unless
- we get one of those fancy headers that tell us the
- server keeps it open for us! */
- conn->bits.close = TRUE;
-
- switch(k->httpcode) {
- case 204:
- /* (quote from RFC2616, section 10.2.5): The server has
- * fulfilled the request but does not need to return an
- * entity-body ... The 204 response MUST NOT include a
- * message-body, and thus is always terminated by the first
- * empty line after the header fields. */
- /* FALLTHROUGH */
- case 416: /* Requested Range Not Satisfiable, it has the
- Content-Length: set as the "real" document but no
- actual response is sent. */
- case 304:
- /* (quote from RFC2616, section 10.3.5): The 304 response
- * MUST NOT contain a message-body, and thus is always
- * terminated by the first empty line after the header
- * fields. */
- k->size=0;
- k->maxdownload=0;
- k->ignorecl = TRUE; /* ignore Content-Length headers */
- break;
- default:
- /* nothing */
- break;
- }
- }
- else {
- k->header = FALSE; /* this is not a header line */
- break;
- }
- }
-
-#ifdef CURL_DOES_CONVERSIONS
- /* convert from the network encoding */
- result = Curl_convert_from_network(data, k->p, strlen(k->p));
- if (CURLE_OK != result) {
- return(result);
- }
- /* Curl_convert_from_network calls failf if unsuccessful */
-#endif /* CURL_DOES_CONVERSIONS */
-
- /* Check for Content-Length: header lines to get size. Ignore
- the header completely if we get a 416 response as then we're
- resuming a document that we don't get, and this header contains
- info about the true size of the document we didn't get now. */
- if (!k->ignorecl && !data->set.ignorecl &&
- checkprefix("Content-Length:", k->p)) {
- contentlength = curlx_strtoofft(k->p+15, NULL, 10);
- if (data->set.max_filesize &&
- contentlength > data->set.max_filesize) {
- failf(data, "Maximum file size exceeded");
- return CURLE_FILESIZE_EXCEEDED;
- }
- if(contentlength >= 0) {
- k->size = contentlength;
- k->maxdownload = k->size;
- }
- else {
- /* Negative Content-Length is really odd, and we know it
- happens for example when older Apache servers send large
- files */
- conn->bits.close = TRUE;
- infof(data, "Negative content-length: %" FORMAT_OFF_T
- ", closing after transfer\n", contentlength);
- }
- }
- /* check for Content-Type: header lines to get the mime-type */
- else if (checkprefix("Content-Type:", k->p)) {
- char *start;
- char *end;
- size_t len;
-
- /* Find the first non-space letter */
- for(start=k->p+13;
- *start && ISSPACE(*start);
- start++)
- ; /* empty loop */
-
- /* data is now in the host encoding so
- use '\r' and '\n' instead of 0x0d and 0x0a */
- end = strchr(start, '\r');
- if(!end)
- end = strchr(start, '\n');
-
- if(end) {
- /* skip all trailing space letters */
- for(; ISSPACE(*end) && (end > start); end--)
- ; /* empty loop */
-
- /* get length of the type */
- len = end-start+1;
-
- /* allocate memory of a cloned copy */
- Curl_safefree(data->info.contenttype);
-
- data->info.contenttype = malloc(len + 1);
- if (NULL == data->info.contenttype)
- return CURLE_OUT_OF_MEMORY;
-
- /* copy the content-type string */
- memcpy(data->info.contenttype, start, len);
- data->info.contenttype[len] = 0; /* zero terminate */
- }
- }
-#ifndef CURL_DISABLE_HTTP
- else if((k->httpversion == 10) &&
- conn->bits.httpproxy &&
- Curl_compareheader(k->p,
- "Proxy-Connection:", "keep-alive")) {
- /*
- * When a HTTP/1.0 reply comes when using a proxy, the
- * 'Proxy-Connection: keep-alive' line tells us the
- * connection will be kept alive for our pleasure.
- * Default action for 1.0 is to close.
- */
- conn->bits.close = FALSE; /* don't close when done */
- infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
- }
- else if((k->httpversion == 11) &&
- conn->bits.httpproxy &&
- Curl_compareheader(k->p,
- "Proxy-Connection:", "close")) {
- /*
- * We get a HTTP/1.1 response from a proxy and it says it'll
- * close down after this transfer.
- */
- conn->bits.close = TRUE; /* close when done */
- infof(data, "HTTP/1.1 proxy connection set close!\n");
- }
- else if((k->httpversion == 10) &&
- Curl_compareheader(k->p, "Connection:", "keep-alive")) {
- /*
- * A HTTP/1.0 reply with the 'Connection: keep-alive' line
- * tells us the connection will be kept alive for our
- * pleasure. Default action for 1.0 is to close.
- *
- * [RFC2068, section 19.7.1] */
- conn->bits.close = FALSE; /* don't close when done */
- infof(data, "HTTP/1.0 connection set to keep alive!\n");
- }
- else if (Curl_compareheader(k->p, "Connection:", "close")) {
- /*
- * [RFC 2616, section 8.1.2.1]
- * "Connection: close" is HTTP/1.1 language and means that
- * the connection will close when this request has been
- * served.
- */
- conn->bits.close = TRUE; /* close when done */
- }
- else if (Curl_compareheader(k->p,
- "Transfer-Encoding:", "chunked")) {
- /*
- * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
- * means that the server will send a series of "chunks". Each
- * chunk starts with line with info (including size of the
- * coming block) (terminated with CRLF), then a block of data
- * with the previously mentioned size. There can be any amount
- * of chunks, and a chunk-data set to zero signals the
- * end-of-chunks. */
- conn->bits.chunk = TRUE; /* chunks coming our way */
-
- /* init our chunky engine */
- Curl_httpchunk_init(conn);
- }
-
- else if (checkprefix("Trailer:", k->p) ||
- checkprefix("Trailers:", k->p)) {
- /*
- * This test helps Curl_httpchunk_read() to determine to look
- * for well formed trailers after the zero chunksize record. In
- * this case a CRLF is required after the zero chunksize record
- * when no trailers are sent, or after the last trailer record.
- *
- * It seems both Trailer: and Trailers: occur in the wild.
- */
- conn->bits.trailerHdrPresent = TRUE;
- }
-
- else if (checkprefix("Content-Encoding:", k->p) &&
- data->set.encoding) {
- /*
- * Process Content-Encoding. Look for the values: identity,
- * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
- * x-compress are the same as gzip and compress. (Sec 3.5 RFC
- * 2616). zlib cannot handle compress. However, errors are
- * handled further down when the response body is processed
- */
- char *start;
-
- /* Find the first non-space letter */
- for(start=k->p+17;
- *start && ISSPACE(*start);
- start++)
- ; /* empty loop */
-
- /* Record the content-encoding for later use */
- if (checkprefix("identity", start))
- k->content_encoding = IDENTITY;
- else if (checkprefix("deflate", start))
- k->content_encoding = DEFLATE;
- else if (checkprefix("gzip", start)
- || checkprefix("x-gzip", start))
- k->content_encoding = GZIP;
- else if (checkprefix("compress", start)
- || checkprefix("x-compress", start))
- k->content_encoding = COMPRESS;
- }
- else if (checkprefix("Content-Range:", k->p)) {
- /* Content-Range: bytes [num]-
- Content-Range: bytes: [num]-
- Content-Range: [num]-
-
- The second format was added since Sun's webserver
- JavaWebServer/1.1.1 obviously sends the header this way!
- The third added since some servers use that!
- */
-
- char *ptr = k->p + 14;
-
- /* Move forward until first digit */
- while(*ptr && !ISDIGIT(*ptr))
- ptr++;
-
- k->offset = curlx_strtoofft(ptr, NULL, 10);
-
- if (data->reqdata.resume_from == k->offset)
- /* we asked for a resume and we got it */
- k->content_range = TRUE;
- }
-#if !defined(CURL_DISABLE_COOKIES)
- else if(data->cookies &&
- checkprefix("Set-Cookie:", k->p)) {
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
- CURL_LOCK_ACCESS_SINGLE);
- Curl_cookie_add(data,
- data->cookies, TRUE, k->p+11,
- /* If there is a custom-set Host: name, use it
- here, or else use real peer host name. */
- conn->allocptr.cookiehost?
- conn->allocptr.cookiehost:conn->host.name,
- data->reqdata.path);
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
- }
-#endif
- else if(checkprefix("Last-Modified:", k->p) &&
- (data->set.timecondition || data->set.get_filetime) ) {
- time_t secs=time(NULL);
- k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
- &secs);
- if(data->set.get_filetime)
- data->info.filetime = (long)k->timeofdoc;
- }
- else if((checkprefix("WWW-Authenticate:", k->p) &&
- (401 == k->httpcode)) ||
- (checkprefix("Proxy-authenticate:", k->p) &&
- (407 == k->httpcode))) {
- result = Curl_http_input_auth(conn, k->httpcode, k->p);
- if(result)
- return result;
- }
- else if ((k->httpcode >= 300 && k->httpcode < 400) &&
- checkprefix("Location:", k->p)) {
- if(data->set.http_follow_location) {
- /* this is the URL that the server advices us to get instead */
- char *ptr;
- char *start=k->p;
- char backup;
-
- start += 9; /* pass "Location:" */
-
- /* Skip spaces and tabs. We do this to support multiple
- white spaces after the "Location:" keyword. */
- while(*start && ISSPACE(*start ))
- start++;
-
- /* Scan through the string from the end to find the last
- non-space. k->end_ptr points to the actual terminating zero
- letter, move pointer one letter back and start from
- there. This logic strips off trailing whitespace, but keeps
- any embedded whitespace. */
- ptr = k->end_ptr-1;
- while((ptr>=start) && ISSPACE(*ptr))
- ptr--;
- ptr++;
-
- backup = *ptr; /* store the ending letter */
- if(ptr != start) {
- *ptr = '\0'; /* zero terminate */
- data->reqdata.newurl = strdup(start); /* clone string */
- *ptr = backup; /* restore ending letter */
- if(!data->reqdata.newurl)
- return CURLE_OUT_OF_MEMORY;
- }
- }
- }
-#endif /* CURL_DISABLE_HTTP */
-
- /*
- * End of header-checks. Write them to the client.
- */
-
- writetype = CLIENTWRITE_HEADER;
- if (data->set.include_header)
- writetype |= CLIENTWRITE_BODY;
-
- if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN,
- k->p, (size_t)k->hbuflen, conn);
-
- result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
- if(result)
- return result;
-
- data->info.header_size += (long)k->hbuflen;
- conn->headerbytecount += (long)k->hbuflen;
-
- /* reset hbufp pointer && hbuflen */
- k->hbufp = data->state.headerbuff;
- k->hbuflen = 0;
- }
- while (!stop_reading && *k->str); /* header line within buffer */
-
- if(stop_reading)
- /* We've stopped dealing with input, get out of the do-while loop */
- break;
-
- /* We might have reached the end of the header part here, but
- there might be a non-header part left in the end of the read
- buffer. */
-
- } /* end if header mode */
-
- /* This is not an 'else if' since it may be a rest from the header
- parsing, where the beginning of the buffer is headers and the end
- is non-headers. */
- if (k->str && !k->header && (nread > 0 || is_empty_data)) {
-
- if(0 == k->bodywrites && !is_empty_data) {
- /* These checks are only made the first time we are about to
- write a piece of the body */
- if(conn->protocol&PROT_HTTP) {
- /* HTTP-only checks */
-
- if (data->reqdata.newurl) {
- if(conn->bits.close) {
- /* Abort after the headers if "follow Location" is set
- and we're set to close anyway. */
- k->keepon &= ~KEEP_READ;
- *done = TRUE;
- return CURLE_OK;
- }
- /* We have a new url to load, but since we want to be able
- to re-use this connection properly, we read the full
- response in "ignore more" */
- k->ignorebody = TRUE;
- infof(data, "Ignoring the response-body\n");
- }
- if (data->reqdata.resume_from && !k->content_range &&
- (data->set.httpreq==HTTPREQ_GET) &&
- !k->ignorebody) {
- /* we wanted to resume a download, although the server doesn't
- * seem to support this and we did this with a GET (if it
- * wasn't a GET we did a POST or PUT resume) */
- failf(data, "HTTP server doesn't seem to support "
- "byte ranges. Cannot resume.");
- return CURLE_HTTP_RANGE_ERROR;
- }
-
- if(data->set.timecondition && !data->reqdata.range) {
- /* A time condition has been set AND no ranges have been
- requested. This seems to be what chapter 13.3.4 of
- RFC 2616 defines to be the correct action for a
- HTTP/1.1 client */
- if((k->timeofdoc > 0) && (data->set.timevalue > 0)) {
- switch(data->set.timecondition) {
- case CURL_TIMECOND_IFMODSINCE:
- default:
- if(k->timeofdoc < data->set.timevalue) {
- infof(data,
- "The requested document is not new enough\n");
- *done = TRUE;
- return CURLE_OK;
- }
- break;
- case CURL_TIMECOND_IFUNMODSINCE:
- if(k->timeofdoc > data->set.timevalue) {
- infof(data,
- "The requested document is not old enough\n");
- *done = TRUE;
- return CURLE_OK;
- }
- break;
- } /* switch */
- } /* two valid time strings */
- } /* we have a time condition */
-
- } /* this is HTTP */
- } /* this is the first time we write a body part */
- k->bodywrites++;
-
- /* pass data to the debug function before it gets "dechunked" */
- if(data->set.verbose) {
- if(k->badheader) {
- Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
- (size_t)k->hbuflen, conn);
- if(k->badheader == HEADER_PARTHEADER)
- Curl_debug(data, CURLINFO_DATA_IN,
- k->str, (size_t)nread, conn);
- }
- else
- Curl_debug(data, CURLINFO_DATA_IN,
- k->str, (size_t)nread, conn);
- }
-
-#ifndef CURL_DISABLE_HTTP
- if(conn->bits.chunk) {
- /*
- * Bless me father for I have sinned. Here comes a chunked
- * transfer flying and we need to decode this properly. While
- * the name says read, this function both reads and writes away
- * the data. The returned 'nread' holds the number of actual
- * data it wrote to the client. */
-
- CHUNKcode res =
- Curl_httpchunk_read(conn, k->str, nread, &nread);
-
- if(CHUNKE_OK < res) {
- if(CHUNKE_WRITE_ERROR == res) {
- failf(data, "Failed writing data");
- return CURLE_WRITE_ERROR;
- }
- failf(data, "Received problem %d in the chunky parser", res);
- return CURLE_RECV_ERROR;
- }
- else if(CHUNKE_STOP == res) {
- /* we're done reading chunks! */
- k->keepon &= ~KEEP_READ; /* read no more */
-
- /* There are now possibly N number of bytes at the end of the
- str buffer that weren't written to the client, but we don't
- care about them right now. */
- }
- /* If it returned OK, we just keep going */
- }
-#endif /* CURL_DISABLE_HTTP */
-
- if((-1 != k->maxdownload) &&
- (k->bytecount + nread >= k->maxdownload)) {
- /* The 'excess' amount below can't be more than BUFSIZE which
- always will fit in a size_t */
- size_t excess = (size_t)(k->bytecount + nread - k->maxdownload);
- if (excess > 0 && !k->ignorebody) {
- infof(data,
- "Rewinding stream by : %d"
- " bytes on url %s (size = %" FORMAT_OFF_T
- ", maxdownload = %" FORMAT_OFF_T
- ", bytecount = %" FORMAT_OFF_T ", nread = %d)\n",
- excess, conn->data->reqdata.path,
- k->size, k->maxdownload, k->bytecount, nread);
- read_rewind(conn, excess);
- }
-
- nread = (ssize_t) (k->maxdownload - k->bytecount);
- if(nread < 0 ) /* this should be unusual */
- nread = 0;
-
- k->keepon &= ~KEEP_READ; /* we're done reading */
- }
-
- k->bytecount += nread;
-
- Curl_pgrsSetDownloadCounter(data, k->bytecount);
-
- if(!conn->bits.chunk && (nread || k->badheader || is_empty_data)) {
- /* If this is chunky transfer, it was already written */
-
- if(k->badheader && !k->ignorebody) {
- /* we parsed a piece of data wrongly assuming it was a header
- and now we output it as body instead */
- result = Curl_client_write(conn, CLIENTWRITE_BODY,
- data->state.headerbuff,
- k->hbuflen);
- if(result)
- return result;
- }
- if(k->badheader < HEADER_ALLBAD) {
- /* This switch handles various content encodings. If there's an
- error here, be sure to check over the almost identical code
- in http_chunks.c.
- Make sure that ALL_CONTENT_ENCODINGS contains all the
- encodings handled here. */
-#ifdef HAVE_LIBZ
- switch (k->content_encoding) {
- case IDENTITY:
-#endif
- /* This is the default when the server sends no
- Content-Encoding header. See Curl_readwrite_init; the
- memset() call initializes k->content_encoding to zero. */
- if(!k->ignorebody)
- result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
- nread);
-#ifdef HAVE_LIBZ
- break;
-
- case DEFLATE:
- /* Assume CLIENTWRITE_BODY; headers are not encoded. */
- if(!k->ignorebody)
- result = Curl_unencode_deflate_write(conn, k, nread);
- break;
-
- case GZIP:
- /* Assume CLIENTWRITE_BODY; headers are not encoded. */
- if(!k->ignorebody)
- result = Curl_unencode_gzip_write(conn, k, nread);
- break;
-
- case COMPRESS:
- default:
- failf (data, "Unrecognized content encoding type. "
- "libcurl understands `identity', `deflate' and `gzip' "
- "content encodings.");
- result = CURLE_BAD_CONTENT_ENCODING;
- break;
- }
-#endif
- }
- k->badheader = HEADER_NORMAL; /* taken care of now */
-
- if(result)
- return result;
- }
-
- } /* if (! header and data to read ) */
-
- if (is_empty_data) {
- /* if we received nothing, the server closed the connection and we
- are done */
- k->keepon &= ~KEEP_READ;
- }
-
- } while(data_pending(conn));
-
- } /* if( read from socket ) */
-
- /* If we still have writing to do, we check if we have a writable
- socket. */
- if((k->keepon & KEEP_WRITE) && (select_res & CSELECT_OUT)) {
- /* write */
-
- int i, si;
- ssize_t bytes_written;
- bool writedone=TRUE;
-
- if ((k->bytecount == 0) && (k->writebytecount == 0))
- Curl_pgrsTime(data, TIMER_STARTTRANSFER);
-
- didwhat |= KEEP_WRITE;
-
- /*
- * We loop here to do the READ and SEND loop until we run out of
- * data to send or until we get EWOULDBLOCK back
- */
- do {
-
- /* only read more data if there's no upload data already
- present in the upload buffer */
- if(0 == data->reqdata.upload_present) {
- /* init the "upload from here" pointer */
- data->reqdata.upload_fromhere = k->uploadbuf;
-
- if(!k->upload_done) {
- /* HTTP pollution, this should be written nicer to become more
- protocol agnostic. */
- int fillcount;
-
- if(k->wait100_after_headers &&
- (data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
- /* If this call is to send body data, we must take some action:
- We have sent off the full HTTP 1.1 request, and we shall now
- go into the Expect: 100 state and await such a header */
- k->wait100_after_headers = FALSE; /* headers sent */
- k->write_after_100_header = TRUE; /* wait for the header */
- k->keepon &= ~KEEP_WRITE; /* disable writing */
- k->start100 = Curl_tvnow(); /* timeout count starts now */
- didwhat &= ~KEEP_WRITE; /* we didn't write anything actually */
- break;
- }
-
- result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
- if(result)
- return result;
-
- nread = (ssize_t)fillcount;
- }
- else
- nread = 0; /* we're done uploading/reading */
-
- /* the signed int typecase of nread of for systems that has
- unsigned size_t */
- if (nread<=0) {
- /* done */
- k->keepon &= ~KEEP_WRITE; /* we're done writing */
- writedone = TRUE;
-
- if(conn->bits.rewindaftersend) {
- result = Curl_readrewind(conn);
- if(result)
- return result;
- }
- break;
- }
-
- /* store number of bytes available for upload */
- data->reqdata.upload_present = nread;
-
- /* convert LF to CRLF if so asked */
-#ifdef CURL_DO_LINEEND_CONV
- /* always convert if we're FTPing in ASCII mode */
- if ((data->set.crlf) || (data->set.prefer_ascii)) {
-#else
- if (data->set.crlf) {
-#endif /* CURL_DO_LINEEND_CONV */
- if(data->state.scratch == NULL)
- data->state.scratch = malloc(2*BUFSIZE);
- if(data->state.scratch == NULL) {
- failf (data, "Failed to alloc scratch buffer!");
- return CURLE_OUT_OF_MEMORY;
- }
- /*
- * ASCII/EBCDIC Note: This is presumably a text (not binary)
- * transfer so the data should already be in ASCII.
- * That means the hex values for ASCII CR (0x0d) & LF (0x0a)
- * must be used instead of the escape sequences \r & \n.
- */
- for(i = 0, si = 0; i < nread; i++, si++) {
- if (data->reqdata.upload_fromhere[i] == 0x0a) {
- data->state.scratch[si++] = 0x0d;
- data->state.scratch[si] = 0x0a;
- if (!data->set.crlf) {
- /* we're here only because FTP is in ASCII mode...
- bump infilesize for the LF we just added */
- data->set.infilesize++;
- }
- }
- else
- data->state.scratch[si] = data->reqdata.upload_fromhere[i];
- }
- if(si != nread) {
- /* only perform the special operation if we really did replace
- anything */
- nread = si;
-
- /* upload from the new (replaced) buffer instead */
- data->reqdata.upload_fromhere = data->state.scratch;
-
- /* set the new amount too */
- data->reqdata.upload_present = nread;
- }
- }
- }
- else {
- /* We have a partial buffer left from a previous "round". Use
- that instead of reading more data */
- }
-
- /* write to socket (send away data) */
- result = Curl_write(conn,
- conn->writesockfd, /* socket to send to */
- data->reqdata.upload_fromhere, /* buffer pointer */
- data->reqdata.upload_present, /* buffer size */
- &bytes_written); /* actually send away */
- if(result)
- return result;
-
- if(data->set.verbose)
- /* show the data before we change the pointer upload_fromhere */
- Curl_debug(data, CURLINFO_DATA_OUT, data->reqdata.upload_fromhere,
- (size_t)bytes_written, conn);
-
- if(data->reqdata.upload_present != bytes_written) {
- /* we only wrote a part of the buffer (if anything), deal with it! */
-
- /* store the amount of bytes left in the buffer to write */
- data->reqdata.upload_present -= bytes_written;
-
- /* advance the pointer where to find the buffer when the next send
- is to happen */
- data->reqdata.upload_fromhere += bytes_written;
-
- writedone = TRUE; /* we are done, stop the loop */
- }
- else {
- /* we've uploaded that buffer now */
- data->reqdata.upload_fromhere = k->uploadbuf;
- data->reqdata.upload_present = 0; /* no more bytes left */
-
- if(k->upload_done) {
- /* switch off writing, we're done! */
- k->keepon &= ~KEEP_WRITE; /* we're done writing */
- writedone = TRUE;
- }
- }
-
- k->writebytecount += bytes_written;
- Curl_pgrsSetUploadCounter(data, k->writebytecount);
-
- } while(!writedone); /* loop until we're done writing! */
-
- }
-
- } while(0); /* just to break out from! */
-
- k->now = Curl_tvnow();
- if(didwhat) {
- /* Update read/write counters */
- if(k->bytecountp)
- *k->bytecountp = k->bytecount; /* read count */
- if(k->writebytecountp)
- *k->writebytecountp = k->writebytecount; /* write count */
- }
- else {
- /* no read no write, this is a timeout? */
- if (k->write_after_100_header) {
- /* This should allow some time for the header to arrive, but only a
- very short time as otherwise it'll be too much wasted times too
- often. */
-
- /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
-
- Therefore, when a client sends this header field to an origin server
- (possibly via a proxy) from which it has never seen a 100 (Continue)
- status, the client SHOULD NOT wait for an indefinite period before
- sending the request body.
-
- */
-
- long ms = Curl_tvdiff(k->now, k->start100);
- if(ms > CURL_TIMEOUT_EXPECT_100) {
- /* we've waited long enough, continue anyway */
- k->write_after_100_header = FALSE;
- k->keepon |= KEEP_WRITE;
- }
- }
- }
-
- if(Curl_pgrsUpdate(conn))
- result = CURLE_ABORTED_BY_CALLBACK;
- else
- result = Curl_speedcheck(data, k->now);
- if (result)
- return result;
-
- if (data->set.timeout &&
- ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) {
- if (k->size != -1) {
- failf(data, "Operation timed out after %d seconds with %"
- FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
- data->set.timeout, k->bytecount, k->size);
- } else {
- failf(data, "Operation timed out after %d seconds with %"
- FORMAT_OFF_T " bytes received",
- data->set.timeout, k->bytecount);
- }
- return CURLE_OPERATION_TIMEOUTED;
- }
-
- if(!k->keepon) {
- /*
- * The transfer has been performed. Just make some general checks before
- * returning.
- */
-
- if(!(conn->bits.no_body) && (k->size != -1) &&
- (k->bytecount != k->size) &&
-#ifdef CURL_DO_LINEEND_CONV
- /* Most FTP servers don't adjust their file SIZE response for CRLFs,
- so we'll check to see if the discrepancy can be explained
- by the number of CRLFs we've changed to LFs.
- */
- (k->bytecount != (k->size + data->state.crlf_conversions)) &&
-#endif /* CURL_DO_LINEEND_CONV */
- !data->reqdata.newurl) {
- failf(data, "transfer closed with %" FORMAT_OFF_T
- " bytes remaining to read",
- k->size - k->bytecount);
- return CURLE_PARTIAL_FILE;
- }
- else if(!(conn->bits.no_body) &&
- conn->bits.chunk &&
- (data->reqdata.proto.http->chunk.state != CHUNK_STOP)) {
- /*
- * In chunked mode, return an error if the connection is closed prior to
- * the empty (terminiating) chunk is read.
- *
- * The condition above used to check for
- * conn->proto.http->chunk.datasize != 0 which is true after reading
- * *any* chunk, not just the empty chunk.
- *
- */
- failf(data, "transfer closed with outstanding read data remaining");
- return CURLE_PARTIAL_FILE;
- }
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
- }
-
- /* Now update the "done" boolean we return */
- *done = (bool)(0 == (k->keepon&(KEEP_READ|KEEP_WRITE)));
-
- return CURLE_OK;
-}
-
-
-/*
- * Curl_readwrite_init() inits the readwrite session. This is inited each time for a
- * transfer, sometimes multiple times on the same SessionHandle
- */
-
-CURLcode Curl_readwrite_init(struct connectdata *conn)
-{
- struct SessionHandle *data = conn->data;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
-
- /* NB: the content encoding software depends on this initialization of
- Curl_transfer_keeper.*/
- memset(k, 0, sizeof(struct Curl_transfer_keeper));
-
- k->start = Curl_tvnow(); /* start time */
- k->now = k->start; /* current time is now */
- k->header = TRUE; /* assume header */
- k->httpversion = -1; /* unknown at this point */
-
- k->size = data->reqdata.size;
- k->maxdownload = data->reqdata.maxdownload;
- k->bytecountp = data->reqdata.bytecountp;
- k->writebytecountp = data->reqdata.writebytecountp;
-
- k->bytecount = 0;
-
- k->buf = data->state.buffer;
- k->uploadbuf = data->state.uploadbuffer;
- k->maxfd = (conn->sockfd>conn->writesockfd?
- conn->sockfd:conn->writesockfd)+1;
- k->hbufp = data->state.headerbuff;
- k->ignorebody=FALSE;
-
- Curl_pgrsTime(data, TIMER_PRETRANSFER);
- Curl_speedinit(data);
-
- Curl_pgrsSetUploadCounter(data, 0);
- Curl_pgrsSetDownloadCounter(data, 0);
-
- if (!conn->bits.getheader) {
- k->header = FALSE;
- if(k->size > 0)
- Curl_pgrsSetDownloadSize(data, k->size);
- }
- /* we want header and/or body, if neither then don't do this! */
- if(conn->bits.getheader || !conn->bits.no_body) {
-
- if(conn->sockfd != CURL_SOCKET_BAD) {
- k->keepon |= KEEP_READ;
- }
-
- if(conn->writesockfd != CURL_SOCKET_BAD) {
- /* HTTP 1.1 magic:
-
- Even if we require a 100-return code before uploading data, we might
- need to write data before that since the REQUEST may not have been
- finished sent off just yet.
-
- Thus, we must check if the request has been sent before we set the
- state info where we wait for the 100-return code
- */
- if (data->state.expect100header &&
- (data->reqdata.proto.http->sending == HTTPSEND_BODY)) {
- /* wait with write until we either got 100-continue or a timeout */
- k->write_after_100_header = TRUE;
- k->start100 = k->start;
- }
- else {
- if(data->state.expect100header)
- /* when we've sent off the rest of the headers, we must await a
- 100-continue */
- k->wait100_after_headers = TRUE;
- k->keepon |= KEEP_WRITE;
- }
- }
- }
-
- return CURLE_OK;
-}
-
-/*
- * Curl_single_getsock() gets called by the multi interface code when the app
- * has requested to get the sockets for the current connection. This function
- * will then be called once for every connection that the multi interface
- * keeps track of. This function will only be called for connections that are
- * in the proper state to have this information available.
- */
-int Curl_single_getsock(struct connectdata *conn,
- curl_socket_t *sock, /* points to numsocks number
- of sockets */
- int numsocks)
-{
- struct SessionHandle *data = conn->data;
- int bitmap = GETSOCK_BLANK;
- int index = 0;
-
- if(numsocks < 2)
- /* simple check but we might need two slots */
- return GETSOCK_BLANK;
-
- if(data->reqdata.keep.keepon & KEEP_READ) {
- bitmap |= GETSOCK_READSOCK(index);
- sock[index] = conn->sockfd;
- }
-
- if(data->reqdata.keep.keepon & KEEP_WRITE) {
-
- if((conn->sockfd != conn->writesockfd) ||
- !(data->reqdata.keep.keepon & KEEP_READ)) {
- /* only if they are not the same socket or we didn't have a readable
- one, we increase index */
- if(data->reqdata.keep.keepon & KEEP_READ)
- index++; /* increase index if we need two entries */
- sock[index] = conn->writesockfd;
- }
-
- bitmap |= GETSOCK_WRITESOCK(index);
- }
-
- return bitmap;
-}
-
-
-/*
- * Transfer()
- *
- * This function is what performs the actual transfer. It is capable of
- * doing both ways simultaneously.
- * The transfer must already have been setup by a call to Curl_setup_transfer().
- *
- * Note that headers are created in a preallocated buffer of a default size.
- * That buffer can be enlarged on demand, but it is never shrunken again.
- *
- * Parts of this function was once written by the friendly Mark Butler
- * <butlerm@xmission.com>.
- */
-
-static CURLcode
-Transfer(struct connectdata *conn)
-{
- CURLcode result;
- struct SessionHandle *data = conn->data;
- struct Curl_transfer_keeper *k = &data->reqdata.keep;
- bool done=FALSE;
-
- if(!(conn->protocol & PROT_FILE))
- /* Only do this if we are not transferring FILE:, since the file: treatment
- is different*/
- Curl_readwrite_init(conn);
-
- if((conn->sockfd == CURL_SOCKET_BAD) &&
- (conn->writesockfd == CURL_SOCKET_BAD))
- /* nothing to read, nothing to write, we're already OK! */
- return CURLE_OK;
-
- /* we want header and/or body, if neither then don't do this! */
- if(!conn->bits.getheader && conn->bits.no_body)
- return CURLE_OK;
-
- while (!done) {
- curl_socket_t fd_read;
- curl_socket_t fd_write;
-
- /* limit-rate logic: if speed exceeds threshold, then do not include fd in
- select set. The current speed is recalculated in each Curl_readwrite()
- call */
- if ((k->keepon & KEEP_WRITE) &&
- (!data->set.max_send_speed ||
- (data->progress.ulspeed < data->set.max_send_speed) )) {
- fd_write = conn->writesockfd;
- k->keepon &= ~KEEP_WRITE_HOLD;
- }
- else {
- fd_write = CURL_SOCKET_BAD;
- if(k->keepon & KEEP_WRITE)
- k->keepon |= KEEP_WRITE_HOLD; /* hold it */
- }
-
- if ((k->keepon & KEEP_READ) &&
- (!data->set.max_recv_speed ||
- (data->progress.dlspeed < data->set.max_recv_speed)) ) {
- fd_read = conn->sockfd;
- k->keepon &= ~KEEP_READ_HOLD;
- }
- else {
- fd_read = CURL_SOCKET_BAD;
- if(k->keepon & KEEP_READ)
- k->keepon |= KEEP_READ_HOLD; /* hold it */
- }
-
- /* The *_HOLD logic is necessary since even though there might be no
- traffic during the select interval, we still call Curl_readwrite() for
- the timeout case and if we limit transfer speed we must make sure that
- this function doesn't transfer anything while in HOLD status. */
-
- switch (Curl_select(fd_read, fd_write, 1000)) {
- case -1: /* select() error, stop reading */
-#ifdef EINTR
- /* The EINTR is not serious, and it seems you might get this more
- ofen when using the lib in a multi-threaded environment! */
- if(errno == EINTR)
- ;
- else
-#endif
- done = TRUE; /* no more read or write */
- continue;
- case 0: /* timeout */
- default: /* readable descriptors */
-
- result = Curl_readwrite(conn, &done);
- break;
- }
- if(result)
- return result;
-
- /* "done" signals to us if the transfer(s) are ready */
- }
-
- return CURLE_OK;
-}
-
-/*
- * Curl_pretransfer() is called immediately before a transfer starts.
- */
-CURLcode Curl_pretransfer(struct SessionHandle *data)
-{
- CURLcode res;
- if(!data->change.url) {
- /* we can't do anything wihout URL */
- failf(data, "No URL set!\n");
- return CURLE_URL_MALFORMAT;
- }
-
- /* Init the SSL session ID cache here. We do it here since we want to do it
- after the *_setopt() calls (that could change the size of the cache) but
- before any transfer takes place. */
- res = Curl_ssl_initsessions(data, data->set.ssl.numsessions);
- if(res)
- return res;
-
- data->set.followlocation=0; /* reset the location-follow counter */
- data->state.this_is_a_follow = FALSE; /* reset this */
- data->state.errorbuf = FALSE; /* no error has occurred */
-
- data->state.authproblem = FALSE;
- data->state.authhost.want = data->set.httpauth;
- data->state.authproxy.want = data->set.proxyauth;
-
- /* If there is a list of cookie files to read, do it now! */
- if(data->change.cookielist) {
- Curl_cookie_loadfiles(data);
- }
-
- /* Allow data->set.use_port to set which port to use. This needs to be
- * disabled for example when we follow Location: headers to URLs using
- * different ports! */
- data->state.allow_port = TRUE;
-
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
- /*************************************************************
- * Tell signal handler to ignore SIGPIPE
- *************************************************************/
- if(!data->set.no_signal)
- data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
-#endif
-
- Curl_initinfo(data); /* reset session-specific information "variables" */
- Curl_pgrsStartNow(data);
-
- return CURLE_OK;
-}
-
-/*
- * Curl_posttransfer() is called immediately after a transfer ends
- */
-CURLcode Curl_posttransfer(struct SessionHandle *data)
-{
-#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
- /* restore the signal handler for SIGPIPE before we get back */
- if(!data->set.no_signal)
- signal(SIGPIPE, data->state.prev_signal);
-#else
- (void)data; /* unused parameter */
-#endif
-
- if(!(data->progress.flags & PGRS_HIDE) &&
- !data->progress.callback)
- /* only output if we don't use a progress callback and we're not hidden */
- fprintf(data->set.err, "\n");
-
- return CURLE_OK;
-}
-
-/*
- * strlen_url() returns the length of the given URL if the spaces within the
- * URL were properly URL encoded.
- */
-static int strlen_url(char *url)
-{
- char *ptr;
- int newlen=0;
- bool left=TRUE; /* left side of the ? */
-
- for(ptr=url; *ptr; ptr++) {
- switch(*ptr) {
- case '?':
- left=FALSE;
- default:
- newlen++;
- break;
- case ' ':
- if(left)
- newlen+=3;
- else
- newlen++;
- break;
- }
- }
- return newlen;
-}
-
-/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
- * the source URL accordingly.
- */
-static void strcpy_url(char *output, char *url)
-{
- /* we must add this with whitespace-replacing */
- bool left=TRUE;
- char *iptr;
- char *optr = output;
- for(iptr = url; /* read from here */
- *iptr; /* until zero byte */
- iptr++) {
- switch(*iptr) {
- case '?':
- left=FALSE;
- default:
- *optr++=*iptr;
- break;
- case ' ':
- if(left) {
- *optr++='%'; /* add a '%' */
- *optr++='2'; /* add a '2' */
- *optr++='0'; /* add a '0' */
- }
- else
- *optr++='+'; /* add a '+' here */
- break;
- }
- }
- *optr=0; /* zero terminate output buffer */
-
-}
-
-/*
- * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
- * as given by the remote server and set up the new URL to request.
- */
-CURLcode Curl_follow(struct SessionHandle *data,
- char *newurl, /* this 'newurl' is the Location: string,
- and it must be malloc()ed before passed
- here */
- bool retry) /* set TRUE if this is a request retry as
- opposed to a real redirect following */
-{
- /* Location: redirect */
- char prot[16]; /* URL protocol string storage */
- char letter; /* used for a silly sscanf */
- size_t newlen;
- char *newest;
-
- if(!retry) {
- if ((data->set.maxredirs != -1) &&
- (data->set.followlocation >= data->set.maxredirs)) {
- failf(data,"Maximum (%d) redirects followed", data->set.maxredirs);
- return CURLE_TOO_MANY_REDIRECTS;
- }
-
- /* mark the next request as a followed location: */
- data->state.this_is_a_follow = TRUE;
-
- data->set.followlocation++; /* count location-followers */
- }
-
- if(data->set.http_auto_referer) {
- /* We are asked to automatically set the previous URL as the
- referer when we get the next URL. We pick the ->url field,
- which may or may not be 100% correct */
-
- if(data->change.referer_alloc)
- /* If we already have an allocated referer, free this first */
- free(data->change.referer);
-
- data->change.referer = strdup(data->change.url);
- data->change.referer_alloc = TRUE; /* yes, free this later */
- }
-
- if(2 != sscanf(newurl, "%15[^?&/:]://%c", prot, &letter)) {
- /***
- *DANG* this is an RFC 2068 violation. The URL is supposed
- to be absolute and this doesn't seem to be that!
- ***
- Instead, we have to TRY to append this new path to the old URL
- to the right of the host part. Oh crap, this is doomed to cause
- problems in the future...
- */
- char *protsep;
- char *pathsep;
-
- char *useurl = newurl;
- size_t urllen;
-
- /* we must make our own copy of the URL to play with, as it may
- point to read-only data */
- char *url_clone=strdup(data->change.url);
-
- if(!url_clone)
- return CURLE_OUT_OF_MEMORY; /* skip out of this NOW */
-
- /* protsep points to the start of the host name */
- protsep=strstr(url_clone, "//");
- if(!protsep)
- protsep=url_clone;
- else
- protsep+=2; /* pass the slashes */
-
- if('/' != newurl[0]) {
- int level=0;
-
- /* First we need to find out if there's a ?-letter in the URL,
- and cut it and the right-side of that off */
- pathsep = strchr(protsep, '?');
- if(pathsep)
- *pathsep=0;
-
- /* we have a relative path to append to the last slash if
- there's one available */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep=0;
-
- /* Check if there's any slash after the host name, and if so,
- remember that position instead */
- pathsep = strchr(protsep, '/');
- if(pathsep)
- protsep = pathsep+1;
- else
- protsep = NULL;
-
- /* now deal with one "./" or any amount of "../" in the newurl
- and act accordingly */
-
- if((useurl[0] == '.') && (useurl[1] == '/'))
- useurl+=2; /* just skip the "./" */
-
- while((useurl[0] == '.') &&
- (useurl[1] == '.') &&
- (useurl[2] == '/')) {
- level++;
- useurl+=3; /* pass the "../" */
- }
-
- if(protsep) {
- while(level--) {
- /* cut off one more level from the right of the original URL */
- pathsep = strrchr(protsep, '/');
- if(pathsep)
- *pathsep=0;
- else {
- *protsep=0;
- break;
- }
- }
- }
- }
- else {
- /* We got a new absolute path for this server, cut off from the
- first slash */
- pathsep = strchr(protsep, '/');
- if(pathsep) {
- /* When people use badly formatted URLs, such as
- "http://www.url.com?dir=/home/daniel" we must not use the first
- slash, if there's a ?-letter before it! */
- char *sep = strchr(protsep, '?');
- if(sep && (sep < pathsep))
- pathsep = sep;
- *pathsep=0;
- }
- else {
- /* There was no slash. Now, since we might be operating on a badly
- formatted URL, such as "http://www.url.com?id=2380" which doesn't
- use a slash separator as it is supposed to, we need to check for a
- ?-letter as well! */
- pathsep = strchr(protsep, '?');
- if(pathsep)
- *pathsep=0;
- }
- }
-
- /* If the new part contains a space, this is a mighty stupid redirect
- but we still make an effort to do "right". To the left of a '?'
- letter we replace each space with %20 while it is replaced with '+'
- on the right side of the '?' letter.
- */
- newlen = strlen_url(useurl);
-
- urllen = strlen(url_clone);
-
- newest=(char *)malloc( urllen + 1 + /* possible slash */
- newlen + 1 /* zero byte */);
-
- if(!newest) {
- free(url_clone); /* don't leak this */
- return CURLE_OUT_OF_MEMORY; /* go out from this */
- }
-
- /* copy over the root url part */
- memcpy(newest, url_clone, urllen);
-
- /* check if we need to append a slash */
- if(('/' == useurl[0]) || (protsep && !*protsep))
- ;
- else
- newest[urllen++]='/';
-
- /* then append the new piece on the right side */
- strcpy_url(&newest[urllen], useurl);
-
- free(newurl); /* newurl is the allocated pointer */
- free(url_clone);
- newurl = newest;
- }
- else {
- /* This is an absolute URL, don't allow the custom port number */
- data->state.allow_port = FALSE;
-
- if(strchr(newurl, ' ')) {
- /* This new URL contains at least one space, this is a mighty stupid
- redirect but we still make an effort to do "right". */
- newlen = strlen_url(newurl);
-
- newest = malloc(newlen+1); /* get memory for this */
- if(newest) {
- strcpy_url(newest, newurl); /* create a space-free URL */
-
- free(newurl); /* that was no good */
- newurl = newest; /* use this instead now */
- }
- }
-
- }
-
- if(data->change.url_alloc)
- free(data->change.url);
- else
- data->change.url_alloc = TRUE; /* the URL is allocated */
-
- data->change.url = newurl;
- newurl = NULL; /* don't free! */
-
- infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
-
- /*
- * We get here when the HTTP code is 300-399 (and 401). We need to perform
- * differently based on exactly what return code there was.
- *
- * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
- * a HTTP (proxy-) authentication scheme other than Basic.
- */
- switch(data->info.httpcode) {
- /* 401 - Act on a www-authentication, we keep on moving and do the
- Authorization: XXXX header in the HTTP request code snippet */
- /* 407 - Act on a proxy-authentication, we keep on moving and do the
- Proxy-Authorization: XXXX header in the HTTP request code snippet */
- /* 300 - Multiple Choices */
- /* 306 - Not used */
- /* 307 - Temporary Redirect */
- default: /* for all above (and the unknown ones) */
- /* Some codes are explicitly mentioned since I've checked RFC2616 and they
- * seem to be OK to POST to.
- */
- break;
- case 301: /* Moved Permanently */
- /* (quote from RFC2616, section 10.3.2):
- *
- * Note: When automatically redirecting a POST request after receiving a
- * 301 status code, some existing HTTP/1.0 user agents will erroneously
- * change it into a GET request.
- *
- * ----
- *
- * Warning: Because most of importants user agents do this obvious RFC2616
- * violation, many webservers expect this misbehavior. So these servers
- * often answers to a POST request with an error page. To be sure that
- * libcurl gets the page that most user agents would get, libcurl has to
- * force GET:
- */
- if( data->set.httpreq == HTTPREQ_POST
- || data->set.httpreq == HTTPREQ_POST_FORM) {
- infof(data,
- "Violate RFC 2616/10.3.2 and switch from POST to GET\n");
- data->set.httpreq = HTTPREQ_GET;
- }
- break;
- case 302: /* Found */
- /* (From 10.3.3)
-
- Note: RFC 1945 and RFC 2068 specify that the client is not allowed
- to change the method on the redirected request. However, most
- existing user agent implementations treat 302 as if it were a 303
- response, performing a GET on the Location field-value regardless
- of the original request method. The status codes 303 and 307 have
- been added for servers that wish to make unambiguously clear which
- kind of reaction is expected of the client.
-
- (From 10.3.4)
-
- Note: Many pre-HTTP/1.1 user agents do not understand the 303
- status. When interoperability with such clients is a concern, the
- 302 status code may be used instead, since most user agents react
- to a 302 response as described here for 303.
- */
- case 303: /* See Other */
- /* Disable both types of POSTs, since doing a second POST when
- * following isn't what anyone would want! */
- if(data->set.httpreq != HTTPREQ_GET) {
- data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
- infof(data, "Disables POST, goes with %s\n",
- data->set.opt_no_body?"HEAD":"GET");
- }
- break;
- case 304: /* Not Modified */
- /* 304 means we did a conditional request and it was "Not modified".
- * We shouldn't get any Location: header in this response!
- */
- break;
- case 305: /* Use Proxy */
- /* (quote from RFC2616, section 10.3.6):
- * "The requested resource MUST be accessed through the proxy given
- * by the Location field. The Location field gives the URI of the
- * proxy. The recipient is expected to repeat this single request
- * via the proxy. 305 responses MUST only be generated by origin
- * servers."
- */
- break;
- }
- Curl_pgrsTime(data, TIMER_REDIRECT);
- Curl_pgrsResetTimes(data);
-
- return CURLE_OK;
-}
-
-static CURLcode
-Curl_connect_host(struct SessionHandle *data,
- struct connectdata **conn)
-{
- CURLcode res = CURLE_OK;
- int urlchanged = FALSE;
-
- do {
- bool async;
- bool protocol_done=TRUE; /* will be TRUE always since this is only used
- within the easy interface */
- Curl_pgrsTime(data, TIMER_STARTSINGLE);
- data->change.url_changed = FALSE;
- res = Curl_connect(data, conn, &async, &protocol_done);
-
- if((CURLE_OK == res) && async) {
- /* Now, if async is TRUE here, we need to wait for the name
- to resolve */
- res = Curl_wait_for_resolv(*conn, NULL);
- if(CURLE_OK == res)
- /* Resolved, continue with the connection */
- res = Curl_async_resolved(*conn, &protocol_done);
- else
- /* if we can't resolve, we kill this "connection" now */
- (void)Curl_disconnect(*conn);
- }
- if(res)
- break;
-
- /* If a callback (or something) has altered the URL we should use within
- the Curl_connect(), we detect it here and act as if we are redirected
- to the new URL */
- urlchanged = data->change.url_changed;
- if ((CURLE_OK == res) && urlchanged) {
- res = Curl_done(conn, res, FALSE);
- if(CURLE_OK == res) {
- char *gotourl = strdup(data->change.url);
- res = Curl_follow(data, gotourl, FALSE);
- if(res)
- free(gotourl);
- }
- }
- } while (urlchanged && res == CURLE_OK);
-
- return res;
-}
-
-/* Returns TRUE and sets '*url' if a request retry is wanted */
-bool Curl_retry_request(struct connectdata *conn,
- char **url)
-{
- bool retry = FALSE;
- struct SessionHandle *data = conn->data;
-
- if((data->reqdata.keep.bytecount+conn->headerbytecount == 0) &&
- conn->bits.reuse &&
- !conn->bits.no_body) {
- /* We got no data, we attempted to re-use a connection and yet we want a
- "body". This might happen if the connection was left alive when we were
- done using it before, but that was closed when we wanted to read from
- it again. Bad luck. Retry the same request on a fresh connect! */
- infof(conn->data, "Connection died, retrying a fresh connect\n");
- *url = strdup(conn->data->change.url);
-
- conn->bits.close = TRUE; /* close this connection */
- conn->bits.retry = TRUE; /* mark this as a connection we're about
- to retry. Marking it this way should
- prevent i.e HTTP transfers to return
- error just because nothing has been
- transfered! */
- retry = TRUE;
- }
-
- return retry;
-}
-
-/*
- * Curl_perform() is the internal high-level function that gets called by the
- * external curl_easy_perform() function. It inits, performs and cleans up a
- * single file transfer.
- */
-CURLcode Curl_perform(struct SessionHandle *data)
-{
- CURLcode res;
- CURLcode res2;
- struct connectdata *conn=NULL;
- char *newurl = NULL; /* possibly a new URL to follow to! */
- bool retry = FALSE;
-
- data->state.used_interface = Curl_if_easy;
-
- res = Curl_pretransfer(data);
- if(res)
- return res;
-
- /*
- * It is important that there is NO 'return' from this function at any other
- * place than falling down to the end of the function! This is because we
- * have cleanup stuff that must be done before we get back, and that is only
- * performed after this do-while loop.
- */
-
- do {
- res = Curl_connect_host(data, &conn); /* primary connection */
-
- if(res == CURLE_OK) {
- bool do_done;
- if(data->set.connect_only) {
- /* keep connection open for application to use the socket */
- conn->bits.close = FALSE;
- res = Curl_done(&conn, CURLE_OK, FALSE);
- break;
- }
- res = Curl_do(&conn, &do_done);
-
- if(res == CURLE_OK) {
- res = Transfer(conn); /* now fetch that URL please */
- if(res == CURLE_OK) {
- retry = Curl_retry_request(conn, &newurl);
-
- if(!retry)
- /*
- * We must duplicate the new URL here as the connection data may
- * be free()ed in the Curl_done() function.
- */
- newurl = data->reqdata.newurl?strdup(data->reqdata.newurl):NULL;
- }
- else {
- /* The transfer phase returned error, we mark the connection to get
- * closed to prevent being re-used. This is becasue we can't
- * possibly know if the connection is in a good shape or not now. */
- conn->bits.close = TRUE;
-
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
- /* if we failed anywhere, we must clean up the secondary socket if
- it was used */
- sclose(conn->sock[SECONDARYSOCKET]);
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
- }
- }
-
- /* Always run Curl_done(), even if some of the previous calls
- failed, but return the previous (original) error code */
- res2 = Curl_done(&conn, res, FALSE);
-
- if(CURLE_OK == res)
- res = res2;
- }
- else
- /* Curl_do() failed, clean up left-overs in the done-call */
- res2 = Curl_done(&conn, res, FALSE);
-
- /*
- * Important: 'conn' cannot be used here, since it may have been closed
- * in 'Curl_done' or other functions.
- */
-
- if((res == CURLE_OK) && newurl) {
- res = Curl_follow(data, newurl, retry);
- if(CURLE_OK == res) {
- newurl = NULL;
- continue;
- }
- }
- }
- break; /* it only reaches here when this shouldn't loop */
-
- } while(1); /* loop if Location: */
-
- if(newurl)
- free(newurl);
-
- if(res && !data->state.errorbuf) {
- /*
- * As an extra precaution: if no error string has been set and there was
- * an error, use the strerror() string or if things are so bad that not
- * even that is good, set a bad string that mentions the error code.
- */
- const char *str = curl_easy_strerror(res);
- if(!str)
- failf(data, "unspecified error %d", (int)res);
- else
- failf(data, "%s", str);
- }
-
- /* run post-transfer uncondionally, but don't clobber the return code if
- we already have an error code recorder */
- res2 = Curl_posttransfer(data);
- if(!res && res2)
- res = res2;
-
- return res;
-}
-
-/*
- * Curl_setup_transfer() is called to setup some basic properties for the
- * upcoming transfer.
- */
-CURLcode
-Curl_setup_transfer(
- struct connectdata *c_conn, /* connection data */
- int sockindex, /* socket index to read from or -1 */
- curl_off_t size, /* -1 if unknown at this point */
- bool getheader, /* TRUE if header parsing is wanted */
- curl_off_t *bytecountp, /* return number of bytes read or NULL */
- int writesockindex, /* socket index to write to, it may very
- well be the same we read from. -1
- disables */
- curl_off_t *writecountp /* return number of bytes written or
- NULL */
- )
-{
- struct connectdata *conn = (struct connectdata *)c_conn;
- struct SessionHandle *data = conn->data;
-
- if(!conn)
- return CURLE_BAD_FUNCTION_ARGUMENT;
-
- curlassert((sockindex <= 1) && (sockindex >= -1));
-
- /* now copy all input parameters */
- conn->sockfd = sockindex == -1 ?
- CURL_SOCKET_BAD : conn->sock[sockindex];
- conn->writesockfd = writesockindex == -1 ?
- CURL_SOCKET_BAD:conn->sock[writesockindex];
- conn->bits.getheader = getheader;
-
- data->reqdata.size = size;
- data->reqdata.bytecountp = bytecountp;
- data->reqdata.writebytecountp = writecountp;
-
- return CURLE_OK;
-}
diff --git a/Utilities/cmcurl/transfer.h b/Utilities/cmcurl/transfer.h
deleted file mode 100644
index 3c415cc72..000000000
--- a/Utilities/cmcurl/transfer.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __TRANSFER_H
-#define __TRANSFER_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-CURLcode Curl_perform(struct SessionHandle *data);
-CURLcode Curl_pretransfer(struct SessionHandle *data);
-CURLcode Curl_second_connect(struct connectdata *conn);
-CURLcode Curl_posttransfer(struct SessionHandle *data);
-CURLcode Curl_follow(struct SessionHandle *data, char *newurl, bool retry);
-CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
-int Curl_single_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-CURLcode Curl_readwrite_init(struct connectdata *conn);
-CURLcode Curl_readrewind(struct connectdata *conn);
-CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
-bool Curl_retry_request(struct connectdata *conn, char **url);
-
-/* This sets up a forthcoming transfer */
-CURLcode
-Curl_setup_transfer (struct connectdata *data,
- int sockindex, /* socket index to read from or -1 */
- curl_off_t size, /* -1 if unknown at this point */
- bool getheader, /* TRUE if header parsing is wanted */
- curl_off_t *bytecountp, /* return number of bytes read */
- int writesockindex, /* socket index to write to, it may
- very well be the same we read from.
- -1 disables */
- curl_off_t *writecountp /* return number of bytes written */
-);
-#endif
diff --git a/Utilities/cmcurl/url.c b/Utilities/cmcurl/url.c
deleted file mode 100644
index da12231f1..000000000
--- a/Utilities/cmcurl/url.c
+++ /dev/null
@@ -1,4252 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* -- WIN32 approved -- */
-
-#include "setup.h"
-
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#include <errno.h>
-
-#ifdef WIN32
-#include <time.h>
-#include <io.h>
-#else
-#ifdef HAVE_SYS_SOCKET_H
-#include <sys/socket.h>
-#endif
-#include <netinet/in.h>
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <netdb.h>
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#include <sys/ioctl.h>
-#include <signal.h>
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#ifdef VMS
-#include <in.h>
-#include <inet.h>
-#endif
-
-#ifdef HAVE_SETJMP_H
-#include <setjmp.h>
-#endif
-
-#ifndef HAVE_SOCKET
-#error "We can't compile without socket() support!"
-#endif
-#endif
-
-#ifdef USE_LIBIDN
-#include <idna.h>
-#include <tld.h>
-#include <stringprep.h>
-#ifdef HAVE_IDN_FREE_H
-#include <idn-free.h>
-#else
-void idn_free (void *ptr); /* prototype from idn-free.h, not provided by
- libidn 0.4.5's make install! */
-#endif
-#ifndef HAVE_IDN_FREE
-/* if idn_free() was not found in this version of libidn, use plain free()
- instead */
-#define idn_free(x) (free)(x)
-#endif
-#endif /* USE_LIBIDN */
-
-#include "urldata.h"
-#include "netrc.h"
-
-#include "formdata.h"
-#include "base64.h"
-#include "sslgen.h"
-#include "hostip.h"
-#include "transfer.h"
-#include "sendf.h"
-#include "progress.h"
-#include "cookie.h"
-#include "strequal.h"
-#include "strerror.h"
-#include "escape.h"
-#include "strtok.h"
-#include "share.h"
-#include "content_encoding.h"
-#include "http_digest.h"
-#include "http_negotiate.h"
-#include "select.h"
-#include "multiif.h"
-#include "easyif.h"
-
-/* And now for the protocols */
-#include "ftp.h"
-#include "dict.h"
-#include "telnet.h"
-#include "tftp.h"
-#include "http.h"
-#include "file.h"
-#include "ldap.h"
-#include "ssh.h"
-#include "url.h"
-#include "connect.h"
-#include "inet_ntop.h"
-#include "http_ntlm.h"
-#include "socks.h"
-#include <ca-bundle.h>
-
-#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
-#include "inet_ntoa_r.h"
-#endif
-
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-#ifdef HAVE_KRB4
-#include "krb4.h"
-#endif
-#include "memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-/* Local static prototypes */
-static long ConnectionKillOne(struct SessionHandle *data);
-static bool ConnectionExists(struct SessionHandle *data,
- struct connectdata *needle,
- struct connectdata **usethis);
-static long ConnectionStore(struct SessionHandle *data,
- struct connectdata *conn);
-static bool IsPipeliningPossible(struct SessionHandle *handle);
-static bool IsPipeliningEnabled(struct SessionHandle *handle);
-static void conn_free(struct connectdata *conn);
-
-static void signalPipeClose(struct curl_llist *pipe);
-
-#define MAX_PIPELINE_LENGTH 5
-
-/*
- * We use this ZERO_NULL to avoid picky compiler warnings,
- * when assigning a NULL pointer to a function pointer var.
- */
-
-#define ZERO_NULL 0
-
-#ifndef USE_ARES
-/* not for ares builds */
-
-#ifndef WIN32
-/* not for WIN32 builds */
-
-#ifdef HAVE_SIGSETJMP
-extern sigjmp_buf curl_jmpenv;
-#endif
-
-#ifdef SIGALRM
-static
-RETSIGTYPE alarmfunc(int sig)
-{
- /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
- (void)sig;
-#ifdef HAVE_SIGSETJMP
- siglongjmp(curl_jmpenv, 1);
-#endif
- /*return;*/ /* not reahed, and has no effect anyway */
-}
-#endif /* SIGALRM */
-#endif /* WIN32 */
-#endif /* USE_ARES */
-
-void Curl_safefree(void *ptr)
-{
- if(ptr)
- free(ptr);
-}
-
-static void close_connections(struct SessionHandle *data)
-{
- /* Loop through all open connections and kill them one by one */
- while(-1 != ConnectionKillOne(data))
- ; /* empty loop */
-}
-
-/*
- * This is the internal function curl_easy_cleanup() calls. This should
- * cleanup and free all resources associated with this sessionhandle.
- *
- * NOTE: if we ever add something that attempts to write to a socket or
- * similar here, we must ignore SIGPIPE first. It is currently only done
- * when curl_easy_perform() is invoked.
- */
-
-CURLcode Curl_close(struct SessionHandle *data)
-{
- struct Curl_multi *m = data->multi;
-
-#ifdef CURLDEBUG
- /* only for debugging, scan through all connections and see if there's a
- pipe reference still identifying this handle */
-
- if(data->state.is_in_pipeline)
- fprintf(stderr, "CLOSED when in pipeline!\n");
-
- if(data->state.connc && data->state.connc->type == CONNCACHE_MULTI) {
- struct conncache *c = data->state.connc;
- int i;
- struct curl_llist *pipe;
- struct curl_llist_element *curr;
- struct connectdata *connptr;
-
- for(i=0; i< c->num; i++) {
- connptr = c->connects[i];
- if(!connptr)
- continue;
-
- pipe = connptr->send_pipe;
- if(pipe) {
- for (curr = pipe->head; curr; curr=curr->next) {
- if(data == (struct SessionHandle *) curr->ptr) {
- fprintf(stderr,
- "MAJOR problem we %p are still in send pipe for %p done %d\n",
- data, connptr, connptr->bits.done);
- }
- }
- }
- pipe = connptr->recv_pipe;
- if(pipe) {
- for (curr = pipe->head; curr; curr=curr->next) {
- if(data == (struct SessionHandle *) curr->ptr) {
- fprintf(stderr,
- "MAJOR problem we %p are still in recv pipe for %p done %d\n",
- data, connptr, connptr->bits.done);
- }
- }
- }
- }
- }
-#endif
-
- if(m)
- /* This handle is still part of a multi handle, take care of this first
- and detach this handle from there. */
- Curl_multi_rmeasy(data->multi, data);
-
- data->magic = 0; /* force a clear AFTER the possibly enforced removal from
- the multi handle, since that function uses the magic
- field! */
-
- if(data->state.connc) {
-
- if(data->state.connc->type == CONNCACHE_PRIVATE) {
- /* close all connections still alive that are in the private connection
- cache, as we no longer have the pointer left to the shared one. */
- close_connections(data);
-
- /* free the connection cache if allocated privately */
- Curl_rm_connc(data->state.connc);
- }
- }
-
- if(data->state.shared_conn) {
- /* marked to be used by a pending connection so we can't kill this handle
- just yet */
- data->state.closed = TRUE;
- return CURLE_OK;
- }
-
- if ( ! (data->share && data->share->hostcache) ) {
- if ( !Curl_global_host_cache_use(data)) {
- Curl_hash_destroy(data->dns.hostcache);
- }
- }
-
- /* Free the pathbuffer */
- Curl_safefree(data->reqdata.pathbuffer);
- Curl_safefree(data->reqdata.proto.generic);
-
- /* Close down all open SSL info and sessions */
- Curl_ssl_close_all(data);
- Curl_safefree(data->state.first_host);
- Curl_safefree(data->state.scratch);
-
- if(data->change.referer_alloc)
- free(data->change.referer);
-
- if(data->change.url_alloc)
- free(data->change.url);
-
- Curl_safefree(data->state.headerbuff);
-
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
- if(data->set.cookiejar) {
- if(data->change.cookielist) {
- /* If there is a list of cookie files to read, do it first so that
- we have all the told files read before we write the new jar */
- Curl_cookie_loadfiles(data);
- }
-
- /* we have a "destination" for all the cookies to get dumped to */
- if(Curl_cookie_output(data->cookies, data->set.cookiejar))
- infof(data, "WARNING: failed to save cookies in %s\n",
- data->set.cookiejar);
- }
- else {
- if(data->change.cookielist)
- /* since nothing is written, we can just free the list of cookie file
- names */
- curl_slist_free_all(data->change.cookielist); /* clean up list */
- }
-
- if( !data->share || (data->cookies != data->share->cookies) ) {
- Curl_cookie_cleanup(data->cookies);
- }
- Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
-#endif
-
- Curl_digest_cleanup(data);
-
- Curl_safefree(data->info.contenttype);
-
- /* this destroys the channel and we cannot use it anymore after this */
- ares_destroy(data->state.areschannel);
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
- /* close iconv conversion descriptors */
- if (data->inbound_cd != (iconv_t)-1) {
- iconv_close(data->inbound_cd);
- }
- if (data->outbound_cd != (iconv_t)-1) {
- iconv_close(data->outbound_cd);
- }
- if (data->utf8_cd != (iconv_t)-1) {
- iconv_close(data->utf8_cd);
- }
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-
- /* No longer a dirty share, if it exists */
- if (data->share)
- data->share->dirty--;
-
- free(data);
- return CURLE_OK;
-}
-
-/* create a connection cache of a private or multi type */
-struct conncache *Curl_mk_connc(int type,
- int amount) /* set -1 to use default */
-{
- /* It is subject for debate how many default connections to have for a multi
- connection cache... */
- int default_amount = amount == -1?
- ((type == CONNCACHE_PRIVATE)?5:10):amount;
- struct conncache *c;
-
- c= calloc(sizeof(struct conncache), 1);
- if(!c)
- return NULL;
-
- c->connects = calloc(sizeof(struct connectdata *), default_amount);
- if(!c->connects) {
- free(c);
- return NULL;
- }
-
- c->num = default_amount;
-
- return c;
-}
-
-/* Change number of entries of a connection cache */
-CURLcode Curl_ch_connc(struct SessionHandle *data,
- struct conncache *c,
- long newamount)
-{
- long i;
- struct connectdata **newptr;
-
- if(newamount < 1)
- newamount = 1; /* we better have at least one entry */
-
- if(!c) {
- /* we get a NULL pointer passed in as connection cache, which means that
- there is no cache created for this SessionHandle just yet, we create a
- brand new with the requested size.
- */
- data->state.connc = Curl_mk_connc(CONNCACHE_PRIVATE, newamount);
- if(!data->state.connc)
- return CURLE_OUT_OF_MEMORY;
- return CURLE_OK;
- }
-
- if(newamount < c->num) {
- /* Since this number is *decreased* from the existing number, we must
- close the possibly open connections that live on the indexes that
- are being removed!
-
- NOTE: for conncache_multi cases we must make sure that we only
- close handles not in use.
- */
- for(i=newamount; i< c->num; i++)
- Curl_disconnect(c->connects[i]);
-
- /* If the most recent connection is no longer valid, mark it
- invalid. */
- if(data->state.lastconnect <= newamount)
- data->state.lastconnect = -1;
- }
- if(newamount > 0) {
- newptr= (struct connectdata **)
- realloc(c->connects, sizeof(struct connectdata *) * newamount);
- if(!newptr)
- /* we closed a few connections in vain, but so what? */
- return CURLE_OUT_OF_MEMORY;
-
- /* nullify the newly added pointers */
- for(i=c->num; i<newamount; i++)
- newptr[i] = NULL;
-
- c->connects = newptr;
- c->num = newamount;
- }
- /* we no longer support less than 1 as size for the connection cache, and
- I'm not sure it ever worked to set it to zero */
- return CURLE_OK;
-}
-
-/* Free a connection cache. This is called from Curl_close() and
- curl_multi_cleanup(). */
-void Curl_rm_connc(struct conncache *c)
-{
- if(c->connects) {
- int i;
- for(i = 0; i < c->num; ++i)
- conn_free(c->connects[i]);
-
- free(c->connects);
- }
-
- free(c);
-}
-
-/**
- * Curl_open()
- *
- * @param curl is a pointer to a sessionhandle pointer that gets set by this
- * function.
- * @return CURLcode
- */
-
-CURLcode Curl_open(struct SessionHandle **curl)
-{
- CURLcode res = CURLE_OK;
- struct SessionHandle *data;
-
- /* Very simple start-up: alloc the struct, init it with zeroes and return */
- data = (struct SessionHandle *)calloc(1, sizeof(struct SessionHandle));
- if(!data)
- /* this is a very serious error */
- return CURLE_OUT_OF_MEMORY;
-
- data->magic = CURLEASY_MAGIC_NUMBER;
-
-#ifdef USE_ARES
- if(ARES_SUCCESS != ares_init(&data->state.areschannel)) {
- free(data);
- return CURLE_FAILED_INIT;
- }
- /* make sure that all other returns from this function should destroy the
- ares channel before returning error! */
-#endif
-
- /* We do some initial setup here, all those fields that can't be just 0 */
-
- data->state.headerbuff=(char*)malloc(HEADERSIZE);
- if(!data->state.headerbuff)
- res = CURLE_OUT_OF_MEMORY;
- else {
- data->state.headersize=HEADERSIZE;
-
- data->set.out = stdout; /* default output to stdout */
- data->set.in = stdin; /* default input from stdin */
- data->set.err = stderr; /* default stderr to stderr */
-
- /* use fwrite as default function to store output */
- data->set.fwrite = (curl_write_callback)fwrite;
-
- /* use fread as default function to read input */
- data->set.fread = (curl_read_callback)fread;
-
- /* conversion callbacks for non-ASCII hosts */
- data->set.convfromnetwork = (curl_conv_callback)ZERO_NULL;
- data->set.convtonetwork = (curl_conv_callback)ZERO_NULL;
- data->set.convfromutf8 = (curl_conv_callback)ZERO_NULL;
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
- /* conversion descriptors for iconv calls */
- data->outbound_cd = (iconv_t)-1;
- data->inbound_cd = (iconv_t)-1;
- data->utf8_cd = (iconv_t)-1;
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-
- data->set.infilesize = -1; /* we don't know any size */
- data->set.postfieldsize = -1;
- data->set.maxredirs = -1; /* allow any amount by default */
- data->state.current_speed = -1; /* init to negative == impossible */
-
- data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
- data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
- data->set.ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
- data->set.ftp_filemethod = FTPFILE_MULTICWD;
- data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
-
- /* make libcurl quiet by default: */
- data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
- data->progress.flags |= PGRS_HIDE;
-
- /* Set the default size of the SSL session ID cache */
- data->set.ssl.numsessions = 5;
-
- data->set.proxyport = 1080;
- data->set.proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
- data->set.httpauth = CURLAUTH_BASIC; /* defaults to basic */
- data->set.proxyauth = CURLAUTH_BASIC; /* defaults to basic */
-
- /* This no longer creates a connection cache here. It is instead made on
- the first call to curl_easy_perform() or when the handle is added to a
- multi stack. */
-
- data->set.ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
- type */
-
- /* most recent connection is not yet defined */
- data->state.lastconnect = -1;
-
- Curl_easy_initHandleData(data);
-
- /*
- * libcurl 7.10 introduced SSL verification *by default*! This needs to be
- * switched off unless wanted.
- */
- data->set.ssl.verifypeer = TRUE;
- data->set.ssl.verifyhost = 2;
- data->set.ssl.sessionid = TRUE; /* session ID caching enabled by default */
-#ifdef CURL_CA_BUNDLE
- /* This is our preferred CA cert bundle since install time */
- data->set.ssl.CAfile = (char *)CURL_CA_BUNDLE;
-#endif
- }
-
- if(res) {
- ares_destroy(data->state.areschannel);
- if(data->state.headerbuff)
- free(data->state.headerbuff);
- free(data);
- data = NULL;
- }
- else
- *curl = data;
-
- return res;
-}
-
-CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
- va_list param)
-{
- char *argptr;
- CURLcode result = CURLE_OK;
-
- switch(option) {
- case CURLOPT_DNS_CACHE_TIMEOUT:
- data->set.dns_cache_timeout = va_arg(param, int);
- break;
- case CURLOPT_DNS_USE_GLOBAL_CACHE:
- {
- int use_cache = va_arg(param, int);
- if (use_cache) {
- Curl_global_host_cache_init();
- }
-
- data->set.global_dns_cache = (bool)(0 != use_cache);
- }
- break;
- case CURLOPT_SSL_CIPHER_LIST:
- /* set a list of cipher we want to use in the SSL connection */
- data->set.ssl.cipher_list = va_arg(param, char *);
- break;
-
- case CURLOPT_RANDOM_FILE:
- /*
- * This is the path name to a file that contains random data to seed
- * the random SSL stuff with. The file is only used for reading.
- */
- data->set.ssl.random_file = va_arg(param, char *);
- break;
- case CURLOPT_EGDSOCKET:
- /*
- * The Entropy Gathering Daemon socket pathname
- */
- data->set.ssl.egdsocket = va_arg(param, char *);
- break;
- case CURLOPT_MAXCONNECTS:
- /*
- * Set the absolute number of maximum simultaneous alive connection that
- * libcurl is allowed to have.
- */
- result = Curl_ch_connc(data, data->state.connc, va_arg(param, long));
- break;
- case CURLOPT_FORBID_REUSE:
- /*
- * When this transfer is done, it must not be left to be reused by a
- * subsequent transfer but shall be closed immediately.
- */
- data->set.reuse_forbid = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_FRESH_CONNECT:
- /*
- * This transfer shall not use a previously cached connection but
- * should be made with a fresh new connect!
- */
- data->set.reuse_fresh = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_VERBOSE:
- /*
- * Verbose means infof() calls that give a lot of information about
- * the connection and transfer procedures as well as internal choices.
- */
- data->set.verbose = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_HEADER:
- /*
- * Set to include the header in the general data output stream.
- */
- data->set.include_header = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_NOPROGRESS:
- /*
- * Shut off the internal supported progress meter
- */
- data->set.hide_progress = (bool)(0 != va_arg(param, long));
- if(data->set.hide_progress)
- data->progress.flags |= PGRS_HIDE;
- else
- data->progress.flags &= ~PGRS_HIDE;
- break;
- case CURLOPT_NOBODY:
- /*
- * Do not include the body part in the output data stream.
- */
- data->set.opt_no_body = (bool)(0 != va_arg(param, long));
- if(data->set.opt_no_body)
- /* in HTTP lingo, this means using the HEAD request */
- data->set.httpreq = HTTPREQ_HEAD;
- break;
- case CURLOPT_FAILONERROR:
- /*
- * Don't output the >=300 error code HTML-page, but instead only
- * return error.
- */
- data->set.http_fail_on_error = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_UPLOAD:
- case CURLOPT_PUT:
- /*
- * We want to sent data to the remote host. If this is HTTP, that equals
- * using the PUT request.
- */
- data->set.upload = (bool)(0 != va_arg(param, long));
- if(data->set.upload)
- /* If this is HTTP, PUT is what's needed to "upload" */
- data->set.httpreq = HTTPREQ_PUT;
- break;
- case CURLOPT_FILETIME:
- /*
- * Try to get the file time of the remote document. The time will
- * later (possibly) become available using curl_easy_getinfo().
- */
- data->set.get_filetime = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_FTP_CREATE_MISSING_DIRS:
- /*
- * An FTP option that modifies an upload to create missing directories on
- * the server.
- */
- data->set.ftp_create_missing_dirs = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_FTP_RESPONSE_TIMEOUT:
- /*
- * An FTP option that specifies how quickly an FTP response must be
- * obtained before it is considered failure.
- */
- data->set.ftp_response_timeout = va_arg( param , long );
- break;
- case CURLOPT_FTPLISTONLY:
- /*
- * An FTP option that changes the command to one that asks for a list
- * only, no file info details.
- */
- data->set.ftp_list_only = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_FTPAPPEND:
- /*
- * We want to upload and append to an existing (FTP) file.
- */
- data->set.ftp_append = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_FTP_FILEMETHOD:
- /*
- * How do access files over FTP.
- */
- data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long);
- break;
- case CURLOPT_NETRC:
- /*
- * Parse the $HOME/.netrc file
- */
- data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
- break;
- case CURLOPT_NETRC_FILE:
- /*
- * Use this file instead of the $HOME/.netrc file
- */
- data->set.netrc_file = va_arg(param, char *);
- break;
- case CURLOPT_TRANSFERTEXT:
- /*
- * This option was previously named 'FTPASCII'. Renamed to work with
- * more protocols than merely FTP.
- *
- * Transfer using ASCII (instead of BINARY).
- */
- data->set.prefer_ascii = (bool)(0 != va_arg(param, long));
- break;
- case CURLOPT_TIMECONDITION:
- /*
- * Set HTTP time condition. This must be one of the defines in the
- * curl/curl.h header file.
- */
- data->set.timecondition = (curl_TimeCond)va_arg(param, long);
- break;
- case CURLOPT_TIMEVALUE:
- /*
- * This is the value to compare with the remote document with the
- * method set with CURLOPT_TIMECONDITION
- */
- data->set.timevalue = (time_t)va_arg(param, long);
- break;
- case CURLOPT_SSLVERSION:
- /*
- * Set explicit SSL version to try to connect with, as some SSL
- * implementations are lame.
- */
- data->set.ssl.version = va_arg(param, long);
- break;
-
-#ifndef CURL_DISABLE_HTTP
- case CURLOPT_AUTOREFERER:
- /*
- * Switch on automatic referer that gets set if curl follows locations.
- */
- data->set.http_auto_referer = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_ENCODING:
- /*
- * String to use at the value of Accept-Encoding header.
- *
- * If the encoding is set to "" we use an Accept-Encoding header that
- * encompasses all the encodings we support.
- * If the encoding is set to NULL we don't send an Accept-Encoding header
- * and ignore an received Content-Encoding header.
- *
- */
- data->set.encoding = va_arg(param, char *);
- if(data->set.encoding && !*data->set.encoding)
- data->set.encoding = (char*)ALL_CONTENT_ENCODINGS;
- break;
-
- case CURLOPT_FOLLOWLOCATION:
- /*
- * Follow Location: header hints on a HTTP-server.
- */
- data->set.http_follow_location = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_UNRESTRICTED_AUTH:
- /*
- * Send authentication (user+password) when following locations, even when
- * hostname changed.
- */
- data->set.http_disable_hostname_check_before_authentication =
- (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_MAXREDIRS:
- /*
- * The maximum amount of hops you allow curl to follow Location:
- * headers. This should mostly be used to detect never-ending loops.
- */
- data->set.maxredirs = va_arg(param, long);
- break;
-
- case CURLOPT_POST:
- /* Does this option serve a purpose anymore? Yes it does, when
- CURLOPT_POSTFIELDS isn't used and the POST data is read off the
- callback! */
- if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_POST;
- data->set.opt_no_body = FALSE; /* this is implied */
- }
- else
- data->set.httpreq = HTTPREQ_GET;
- break;
-
- case CURLOPT_POSTFIELDS:
- /*
- * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
- */
- data->set.postfields = va_arg(param, char *);
- data->set.httpreq = HTTPREQ_POST;
- break;
-
- case CURLOPT_POSTFIELDSIZE:
- /*
- * The size of the POSTFIELD data to prevent libcurl to do strlen() to
- * figure it out. Enables binary posts.
- */
- data->set.postfieldsize = va_arg(param, long);
- break;
-
- case CURLOPT_POSTFIELDSIZE_LARGE:
- /*
- * The size of the POSTFIELD data to prevent libcurl to do strlen() to
- * figure it out. Enables binary posts.
- */
- data->set.postfieldsize = va_arg(param, curl_off_t);
- break;
-
- case CURLOPT_HTTPPOST:
- /*
- * Set to make us do HTTP POST
- */
- data->set.httppost = va_arg(param, struct curl_httppost *);
- data->set.httpreq = HTTPREQ_POST_FORM;
- data->set.opt_no_body = FALSE; /* this is implied */
- break;
-
- case CURLOPT_REFERER:
- /*
- * String to set in the HTTP Referer: field.
- */
- if(data->change.referer_alloc) {
- free(data->change.referer);
- data->change.referer_alloc = FALSE;
- }
- data->set.set_referer = va_arg(param, char *);
- data->change.referer = data->set.set_referer;
- break;
-
- case CURLOPT_USERAGENT:
- /*
- * String to use in the HTTP User-Agent field
- */
- data->set.useragent = va_arg(param, char *);
- break;
-
- case CURLOPT_HTTPHEADER:
- /*
- * Set a list with HTTP headers to use (or replace internals with)
- */
- data->set.headers = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_HTTP200ALIASES:
- /*
- * Set a list of aliases for HTTP 200 in response header
- */
- data->set.http200aliases = va_arg(param, struct curl_slist *);
- break;
-
-#if !defined(CURL_DISABLE_COOKIES)
- case CURLOPT_COOKIE:
- /*
- * Cookie string to send to the remote server in the request.
- */
- data->set.cookie = va_arg(param, char *);
- break;
-
- case CURLOPT_COOKIEFILE:
- /*
- * Set cookie file to read and parse. Can be used multiple times.
- */
- argptr = (char *)va_arg(param, void *);
- if(argptr) {
- struct curl_slist *cl;
- /* append the cookie file name to the list of file names, and deal with
- them later */
- cl = curl_slist_append(data->change.cookielist, argptr);
-
- if(!cl)
- return CURLE_OUT_OF_MEMORY;
-
- data->change.cookielist = cl;
- }
- break;
-
- case CURLOPT_COOKIEJAR:
- /*
- * Set cookie file name to dump all cookies to when we're done.
- */
- data->set.cookiejar = (char *)va_arg(param, void *);
-
- /*
- * Activate the cookie parser. This may or may not already
- * have been made.
- */
- data->cookies = Curl_cookie_init(data, NULL, data->cookies,
- data->set.cookiesession);
- break;
-
- case CURLOPT_COOKIESESSION:
- /*
- * Set this option to TRUE to start a new "cookie session". It will
- * prevent the forthcoming read-cookies-from-file actions to accept
- * cookies that are marked as being session cookies, as they belong to a
- * previous session.
- *
- * In the original Netscape cookie spec, "session cookies" are cookies
- * with no expire date set. RFC2109 describes the same action if no
- * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
- * a 'Discard' action that can enforce the discard even for cookies that
- * have a Max-Age.
- *
- * We run mostly with the original cookie spec, as hardly anyone implements
- * anything else.
- */
- data->set.cookiesession = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_COOKIELIST:
- argptr = va_arg(param, char *);
-
- if(argptr == NULL)
- break;
-
- if(strequal(argptr, "ALL")) {
- /* clear all cookies */
- Curl_cookie_clearall(data->cookies);
- break;
- }
- else if(strequal(argptr, "SESS")) {
- /* clear session cookies */
- Curl_cookie_clearsess(data->cookies);
- break;
- }
-
- if(!data->cookies)
- /* if cookie engine was not running, activate it */
- data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
-
- argptr = strdup(argptr);
- if(!argptr) {
- result = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- if(checkprefix("Set-Cookie:", argptr))
- /* HTTP Header format line */
- Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
-
- else
- /* Netscape format line */
- Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
-
- free(argptr);
- break;
-#endif /* CURL_DISABLE_COOKIES */
-
- case CURLOPT_HTTPGET:
- /*
- * Set to force us do HTTP GET
- */
- if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_GET;
- data->set.upload = FALSE; /* switch off upload */
- data->set.opt_no_body = FALSE; /* this is implied */
- }
- break;
-
- case CURLOPT_HTTP_VERSION:
- /*
- * This sets a requested HTTP version to be used. The value is one of
- * the listed enums in curl/curl.h.
- */
- data->set.httpversion = va_arg(param, long);
- break;
-
- case CURLOPT_HTTPPROXYTUNNEL:
- /*
- * Tunnel operations through the proxy instead of normal proxy use
- */
- data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_CUSTOMREQUEST:
- /*
- * Set a custom string to use as request
- */
- data->set.customrequest = va_arg(param, char *);
-
- /* we don't set
- data->set.httpreq = HTTPREQ_CUSTOM;
- here, we continue as if we were using the already set type
- and this just changes the actual request keyword */
- break;
-
- case CURLOPT_PROXYPORT:
- /*
- * Explicitly set HTTP proxy port number.
- */
- data->set.proxyport = va_arg(param, long);
- break;
-
- case CURLOPT_HTTPAUTH:
- /*
- * Set HTTP Authentication type BITMASK.
- */
- {
- long auth = va_arg(param, long);
- /* switch off bits we can't support */
-#ifndef USE_NTLM
- auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
-#endif
-#ifndef HAVE_GSSAPI
- auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
-#endif
- if(!auth)
- return CURLE_FAILED_INIT; /* no supported types left! */
-
- data->set.httpauth = auth;
- }
- break;
-
- case CURLOPT_PROXYAUTH:
- /*
- * Set HTTP Authentication type BITMASK.
- */
- {
- long auth = va_arg(param, long);
- /* switch off bits we can't support */
-#ifndef USE_NTLM
- auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */
-#endif
-#ifndef HAVE_GSSAPI
- auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI */
-#endif
- if(!auth)
- return CURLE_FAILED_INIT; /* no supported types left! */
-
- data->set.proxyauth = auth;
- }
- break;
-#endif /* CURL_DISABLE_HTTP */
-
- case CURLOPT_PROXY:
- /*
- * Set proxy server:port to use as HTTP proxy.
- *
- * If the proxy is set to "" we explicitly say that we don't want to use a
- * proxy (even though there might be environment variables saying so).
- *
- * Setting it to NULL, means no proxy but allows the environment variables
- * to decide for us.
- */
- data->set.proxy = va_arg(param, char *);
- break;
-
- case CURLOPT_WRITEHEADER:
- /*
- * Custom pointer to pass the header write callback function
- */
- data->set.writeheader = (void *)va_arg(param, void *);
- break;
- case CURLOPT_ERRORBUFFER:
- /*
- * Error buffer provided by the caller to get the human readable
- * error string in.
- */
- data->set.errorbuffer = va_arg(param, char *);
- break;
- case CURLOPT_FILE:
- /*
- * FILE pointer to write to or include in the data write callback
- */
- data->set.out = va_arg(param, FILE *);
- break;
- case CURLOPT_FTPPORT:
- /*
- * Use FTP PORT, this also specifies which IP address to use
- */
- data->set.ftpport = va_arg(param, char *);
- data->set.ftp_use_port = (bool)(NULL != data->set.ftpport);
- break;
-
- case CURLOPT_FTP_USE_EPRT:
- data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_FTP_USE_EPSV:
- data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_FTP_SSL_CCC:
- data->set.ftp_use_ccc = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_FTP_SKIP_PASV_IP:
- /*
- * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
- * bypass of the IP address in PASV responses.
- */
- data->set.ftp_skip_ip = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_INFILE:
- /*
- * FILE pointer to read the file to be uploaded from. Or possibly
- * used as argument to the read callback.
- */
- data->set.in = va_arg(param, FILE *);
- break;
- case CURLOPT_INFILESIZE:
- /*
- * If known, this should inform curl about the file size of the
- * to-be-uploaded file.
- */
- data->set.infilesize = va_arg(param, long);
- break;
- case CURLOPT_INFILESIZE_LARGE:
- /*
- * If known, this should inform curl about the file size of the
- * to-be-uploaded file.
- */
- data->set.infilesize = va_arg(param, curl_off_t);
- break;
- case CURLOPT_LOW_SPEED_LIMIT:
- /*
- * The low speed limit that if transfers are below this for
- * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
- */
- data->set.low_speed_limit=va_arg(param, long);
- break;
- case CURLOPT_MAX_SEND_SPEED_LARGE:
- /*
- * The max speed limit that sends transfer more than
- * CURLOPT_MAX_SEND_PER_SECOND bytes per second the transfer is
- * throttled..
- */
- data->set.max_send_speed=va_arg(param, curl_off_t);
- break;
- case CURLOPT_MAX_RECV_SPEED_LARGE:
- /*
- * The max speed limit that sends transfer more than
- * CURLOPT_MAX_RECV_PER_SECOND bytes per second the transfer is
- * throttled..
- */
- data->set.max_recv_speed=va_arg(param, curl_off_t);
- break;
- case CURLOPT_LOW_SPEED_TIME:
- /*
- * The low speed time that if transfers are below the set
- * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
- */
- data->set.low_speed_time=va_arg(param, long);
- break;
- case CURLOPT_URL:
- /*
- * The URL to fetch.
- */
- if(data->change.url_alloc) {
- /* the already set URL is allocated, free it first! */
- free(data->change.url);
- data->change.url_alloc=FALSE;
- }
- data->set.set_url = va_arg(param, char *);
- data->change.url = data->set.set_url;
- data->change.url_changed = TRUE;
- break;
- case CURLOPT_PORT:
- /*
- * The port number to use when getting the URL
- */
- data->set.use_port = va_arg(param, long);
- break;
- case CURLOPT_TIMEOUT:
- /*
- * The maximum time you allow curl to use for a single transfer
- * operation.
- */
- data->set.timeout = va_arg(param, long);
- break;
- case CURLOPT_CONNECTTIMEOUT:
- /*
- * The maximum time you allow curl to use to connect.
- */
- data->set.connecttimeout = va_arg(param, long);
- break;
-
- case CURLOPT_USERPWD:
- /*
- * user:password to use in the operation
- */
- data->set.userpwd = va_arg(param, char *);
- break;
- case CURLOPT_POSTQUOTE:
- /*
- * List of RAW FTP commands to use after a transfer
- */
- data->set.postquote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_PREQUOTE:
- /*
- * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
- */
- data->set.prequote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_QUOTE:
- /*
- * List of RAW FTP commands to use before a transfer
- */
- data->set.quote = va_arg(param, struct curl_slist *);
- break;
- case CURLOPT_PROGRESSFUNCTION:
- /*
- * Progress callback function
- */
- data->set.fprogress = va_arg(param, curl_progress_callback);
- if(data->set.fprogress)
- data->progress.callback = TRUE; /* no longer internal */
- else
- data->progress.callback = FALSE; /* NULL enforces internal */
-
- break;
- case CURLOPT_PROGRESSDATA:
- /*
- * Custom client data to pass to the progress callback
- */
- data->set.progress_client = va_arg(param, void *);
- break;
- case CURLOPT_PROXYUSERPWD:
- /*
- * user:password needed to use the proxy
- */
- data->set.proxyuserpwd = va_arg(param, char *);
- break;
- case CURLOPT_RANGE:
- /*
- * What range of the file you want to transfer
- */
- data->set.set_range = va_arg(param, char *);
- break;
- case CURLOPT_RESUME_FROM:
- /*
- * Resume transfer at the give file position
- */
- data->set.set_resume_from = va_arg(param, long);
- break;
- case CURLOPT_RESUME_FROM_LARGE:
- /*
- * Resume transfer at the give file position
- */
- data->set.set_resume_from = va_arg(param, curl_off_t);
- break;
- case CURLOPT_DEBUGFUNCTION:
- /*
- * stderr write callback.
- */
- data->set.fdebug = va_arg(param, curl_debug_callback);
- /*
- * if the callback provided is NULL, it'll use the default callback
- */
- break;
- case CURLOPT_DEBUGDATA:
- /*
- * Set to a void * that should receive all error writes. This
- * defaults to CURLOPT_STDERR for normal operations.
- */
- data->set.debugdata = va_arg(param, void *);
- break;
- case CURLOPT_STDERR:
- /*
- * Set to a FILE * that should receive all error writes. This
- * defaults to stderr for normal operations.
- */
- data->set.err = va_arg(param, FILE *);
- if(!data->set.err)
- data->set.err = stderr;
- break;
- case CURLOPT_HEADERFUNCTION:
- /*
- * Set header write callback
- */
- data->set.fwrite_header = va_arg(param, curl_write_callback);
- break;
- case CURLOPT_WRITEFUNCTION:
- /*
- * Set data write callback
- */
- data->set.fwrite = va_arg(param, curl_write_callback);
- if(!data->set.fwrite)
- /* When set to NULL, reset to our internal default function */
- data->set.fwrite = (curl_write_callback)fwrite;
- break;
- case CURLOPT_READFUNCTION:
- /*
- * Read data callback
- */
- data->set.fread = va_arg(param, curl_read_callback);
- if(!data->set.fread)
- /* When set to NULL, reset to our internal default function */
- data->set.fread = (curl_read_callback)fread;
- break;
- case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
- /*
- * "Convert from network encoding" callback
- */
- data->set.convfromnetwork = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_CONV_TO_NETWORK_FUNCTION:
- /*
- * "Convert to network encoding" callback
- */
- data->set.convtonetwork = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_CONV_FROM_UTF8_FUNCTION:
- /*
- * "Convert from UTF-8 encoding" callback
- */
- data->set.convfromutf8 = va_arg(param, curl_conv_callback);
- break;
- case CURLOPT_IOCTLFUNCTION:
- /*
- * I/O control callback. Might be NULL.
- */
- data->set.ioctl = va_arg(param, curl_ioctl_callback);
- break;
- case CURLOPT_IOCTLDATA:
- /*
- * I/O control data pointer. Might be NULL.
- */
- data->set.ioctl_client = va_arg(param, void *);
- break;
- case CURLOPT_SSLCERT:
- /*
- * String that holds file name of the SSL certificate to use
- */
- data->set.cert = va_arg(param, char *);
- break;
- case CURLOPT_SSLCERTTYPE:
- /*
- * String that holds file type of the SSL certificate to use
- */
- data->set.cert_type = va_arg(param, char *);
- break;
- case CURLOPT_SSLKEY:
- /*
- * String that holds file name of the SSL certificate to use
- */
- data->set.key = va_arg(param, char *);
- break;
- case CURLOPT_SSLKEYTYPE:
- /*
- * String that holds file type of the SSL certificate to use
- */
- data->set.key_type = va_arg(param, char *);
- break;
- case CURLOPT_SSLKEYPASSWD:
- /*
- * String that holds the SSL private key password.
- */
- data->set.key_passwd = va_arg(param, char *);
- break;
- case CURLOPT_SSLENGINE:
- /*
- * String that holds the SSL crypto engine.
- */
- argptr = va_arg(param, char *);
- if (argptr && argptr[0])
- result = Curl_ssl_set_engine(data, argptr);
- break;
-
- case CURLOPT_SSLENGINE_DEFAULT:
- /*
- * flag to set engine as default.
- */
- result = Curl_ssl_set_engine_default(data);
- break;
- case CURLOPT_CRLF:
- /*
- * Kludgy option to enable CRLF conversions. Subject for removal.
- */
- data->set.crlf = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_INTERFACE:
- /*
- * Set what interface or address/hostname to bind the socket to when
- * performing an operation and thus what from-IP your connection will use.
- */
- data->set.device = va_arg(param, char *);
- break;
- case CURLOPT_LOCALPORT:
- /*
- * Set what local port to bind the socket to when performing an operation.
- */
- data->set.localport = (unsigned short) va_arg(param, long);
- break;
- case CURLOPT_LOCALPORTRANGE:
- /*
- * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
- */
- data->set.localportrange = (int) va_arg(param, long);
- break;
- case CURLOPT_KRB4LEVEL:
- /*
- * A string that defines the krb4 security level.
- */
- data->set.krb4_level = va_arg(param, char *);
- data->set.krb4 = (bool)(NULL != data->set.krb4_level);
- break;
- case CURLOPT_SSL_VERIFYPEER:
- /*
- * Enable peer SSL verifying.
- */
- data->set.ssl.verifypeer = va_arg(param, long);
- break;
- case CURLOPT_SSL_VERIFYHOST:
- /*
- * Enable verification of the CN contained in the peer certificate
- */
- data->set.ssl.verifyhost = va_arg(param, long);
- break;
- case CURLOPT_SSL_CTX_FUNCTION:
- /*
- * Set a SSL_CTX callback
- */
- data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
- break;
- case CURLOPT_SSL_CTX_DATA:
- /*
- * Set a SSL_CTX callback parameter pointer
- */
- data->set.ssl.fsslctxp = va_arg(param, void *);
- break;
- case CURLOPT_CAINFO:
- /*
- * Set CA info for SSL connection. Specify file name of the CA certificate
- */
- data->set.ssl.CAfile = va_arg(param, char *);
- break;
- case CURLOPT_CAPATH:
- /*
- * Set CA path info for SSL connection. Specify directory name of the CA
- * certificates which have been prepared using openssl c_rehash utility.
- */
- /* This does not work on windows. */
- data->set.ssl.CApath = va_arg(param, char *);
- break;
- case CURLOPT_TELNETOPTIONS:
- /*
- * Set a linked list of telnet options
- */
- data->set.telnet_options = va_arg(param, struct curl_slist *);
- break;
-
- case CURLOPT_BUFFERSIZE:
- /*
- * The application kindly asks for a differently sized receive buffer.
- * If it seems reasonable, we'll use it.
- */
- data->set.buffer_size = va_arg(param, long);
-
- if((data->set.buffer_size> (BUFSIZE -1 )) ||
- (data->set.buffer_size < 1))
- data->set.buffer_size = 0; /* huge internal default */
-
- break;
-
- case CURLOPT_NOSIGNAL:
- /*
- * The application asks not to set any signal() or alarm() handlers,
- * even when using a timeout.
- */
- data->set.no_signal = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_SHARE:
- {
- struct Curl_share *set;
- set = va_arg(param, struct Curl_share *);
-
- /* disconnect from old share, if any */
- if(data->share) {
- Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
- if(data->dns.hostcachetype == HCACHE_SHARED) {
- data->dns.hostcache = NULL;
- data->dns.hostcachetype = HCACHE_NONE;
- }
-
- if(data->share->cookies == data->cookies)
- data->cookies = NULL;
-
- data->share->dirty--;
-
- Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
- data->share = NULL;
- }
-
- /* use new share if it set */
- data->share = set;
- if(data->share) {
-
- Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
-
- data->share->dirty++;
-
- if(data->share->hostcache) {
- /* use shared host cache, first free the private one if any */
- if(data->dns.hostcachetype == HCACHE_PRIVATE)
- Curl_hash_destroy(data->dns.hostcache);
-
- data->dns.hostcache = data->share->hostcache;
- data->dns.hostcachetype = HCACHE_SHARED;
- }
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- if(data->share->cookies) {
- /* use shared cookie list, first free own one if any */
- if (data->cookies)
- Curl_cookie_cleanup(data->cookies);
- data->cookies = data->share->cookies;
- }
-#endif /* CURL_DISABLE_HTTP */
- Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
-
- }
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
- /* check cookie list is set */
- if(!data->cookies)
- data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE );
-#endif /* CURL_DISABLE_HTTP */
- /* check for host cache not needed,
- * it will be done by curl_easy_perform */
- }
- break;
-
- case CURLOPT_PROXYTYPE:
- /*
- * Set proxy type. HTTP/SOCKS4/SOCKS5
- */
- data->set.proxytype = (curl_proxytype)va_arg(param, long);
- break;
-
- case CURLOPT_PRIVATE:
- /*
- * Set private data pointer.
- */
- data->set.private_data = va_arg(param, char *);
- break;
-
- case CURLOPT_MAXFILESIZE:
- /*
- * Set the maximum size of a file to download.
- */
- data->set.max_filesize = va_arg(param, long);
- break;
-
- case CURLOPT_FTP_SSL:
- /*
- * Make FTP transfers attempt to use SSL/TLS.
- */
- data->set.ftp_ssl = (curl_ftpssl)va_arg(param, long);
- break;
-
- case CURLOPT_FTPSSLAUTH:
- /*
- * Set a specific auth for FTP-SSL transfers.
- */
- data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long);
- break;
-
- case CURLOPT_IPRESOLVE:
- data->set.ip_version = va_arg(param, long);
- break;
-
- case CURLOPT_MAXFILESIZE_LARGE:
- /*
- * Set the maximum size of a file to download.
- */
- data->set.max_filesize = va_arg(param, curl_off_t);
- break;
-
- case CURLOPT_TCP_NODELAY:
- /*
- * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
- * algorithm
- */
- data->set.tcp_nodelay = (bool)(0 != va_arg(param, long));
- break;
-
- /*
- case CURLOPT_SOURCE_URL:
- case CURLOPT_SOURCE_USERPWD:
- case CURLOPT_SOURCE_QUOTE:
- case CURLOPT_SOURCE_PREQUOTE:
- case CURLOPT_SOURCE_POSTQUOTE:
- These former 3rd party transfer options are deprecated */
-
- case CURLOPT_FTP_ACCOUNT:
- data->set.ftp_account = va_arg(param, char *);
- break;
-
- case CURLOPT_IGNORE_CONTENT_LENGTH:
- data->set.ignorecl = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_CONNECT_ONLY:
- /*
- * No data transfer, set up connection and let application use the socket
- */
- data->set.connect_only = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_FTP_ALTERNATIVE_TO_USER:
- data->set.ftp_alternative_to_user = va_arg(param, char *);
- break;
-
- case CURLOPT_SOCKOPTFUNCTION:
- /*
- * socket callback function: called after socket() but before connect()
- */
- data->set.fsockopt = va_arg(param, curl_sockopt_callback);
- break;
-
- case CURLOPT_SOCKOPTDATA:
- /*
- * socket callback data pointer. Might be NULL.
- */
- data->set.sockopt_client = va_arg(param, void *);
- break;
-
- case CURLOPT_SSL_SESSIONID_CACHE:
- data->set.ssl.sessionid = (bool)(0 != va_arg(param, long));
- break;
-
- case CURLOPT_SSH_AUTH_TYPES:
- data->set.ssh_auth_types = va_arg(param, long);
- break;
-
- case CURLOPT_SSH_PUBLIC_KEYFILE:
- /*
- * Use this file instead of the $HOME/.ssh/id_dsa.pub file
- */
- data->set.ssh_public_key = va_arg(param, char *);
- break;
-
- case CURLOPT_SSH_PRIVATE_KEYFILE:
- /*
- * Use this file instead of the $HOME/.ssh/id_dsa file
- */
- data->set.ssh_private_key = va_arg(param, char *);
- break;
-
- default:
- /* unknown tag and its companion, just ignore: */
- result = CURLE_FAILED_INIT; /* correct this */
- break;
- }
-
- return result;
-}
-
-static void conn_free(struct connectdata *conn)
-{
- if (!conn)
- return;
-
- /* close possibly still open sockets */
- if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
- sclose(conn->sock[SECONDARYSOCKET]);
- if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
- sclose(conn->sock[FIRSTSOCKET]);
-
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- Curl_safefree(conn->proxyuser);
- Curl_safefree(conn->proxypasswd);
- Curl_safefree(conn->allocptr.proxyuserpwd);
- Curl_safefree(conn->allocptr.uagent);
- Curl_safefree(conn->allocptr.userpwd);
- Curl_safefree(conn->allocptr.accept_encoding);
- Curl_safefree(conn->allocptr.rangeline);
- Curl_safefree(conn->allocptr.ref);
- Curl_safefree(conn->allocptr.host);
- Curl_safefree(conn->allocptr.cookiehost);
- Curl_safefree(conn->ip_addr_str);
- Curl_safefree(conn->trailer);
- Curl_safefree(conn->host.rawalloc); /* host name buffer */
- Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
-
- Curl_llist_destroy(conn->send_pipe, NULL);
- Curl_llist_destroy(conn->recv_pipe, NULL);
-
- /* possible left-overs from the async name resolvers */
-#if defined(USE_ARES)
- Curl_safefree(conn->async.hostname);
- Curl_safefree(conn->async.os_specific);
-#elif defined(CURLRES_THREADED)
- Curl_destroy_thread_data(&conn->async);
-#endif
-
- Curl_free_ssl_config(&conn->ssl_config);
-
- free(conn); /* free all the connection oriented data */
-}
-
-CURLcode Curl_disconnect(struct connectdata *conn)
-{
- struct SessionHandle *data;
- if(!conn)
- return CURLE_OK; /* this is closed and fine already */
- data = conn->data;
-
- if(!data) {
- DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
- return CURLE_OK;
- }
-
-#if defined(CURLDEBUG) && defined(AGGRESIVE_TEST)
- /* scan for DNS cache entries still marked as in use */
- Curl_hash_apply(data->hostcache,
- NULL, Curl_scan_cache_used);
-#endif
-
- Curl_expire(data, 0); /* shut off timers */
- Curl_hostcache_prune(data); /* kill old DNS cache entries */
-
- /*
- * The range string is usually freed in curl_done(), but we might
- * get here *instead* if we fail prematurely. Thus we need to be able
- * to free this resource here as well.
- */
- if(data->reqdata.rangestringalloc) {
- free(data->reqdata.range);
- data->reqdata.rangestringalloc = FALSE;
- }
-
- if((conn->ntlm.state != NTLMSTATE_NONE) ||
- (conn->proxyntlm.state != NTLMSTATE_NONE)) {
- /* Authentication data is a mix of connection-related and sessionhandle-
- related stuff. NTLM is connection-related so when we close the shop
- we shall forget. */
- data->state.authhost.done = FALSE;
- data->state.authhost.picked =
- data->state.authhost.want;
-
- data->state.authproxy.done = FALSE;
- data->state.authproxy.picked =
- data->state.authproxy.want;
-
- data->state.authproblem = FALSE;
-
- Curl_ntlm_cleanup(conn);
- }
-
- if(conn->curl_disconnect)
- /* This is set if protocol-specific cleanups should be made */
- conn->curl_disconnect(conn);
-
- if(-1 != conn->connectindex) {
- /* unlink ourselves! */
- infof(data, "Closing connection #%ld\n", conn->connectindex);
- if(data->state.connc)
- /* only clear the table entry if we still know in which cache we
- used to be in */
- data->state.connc->connects[conn->connectindex] = NULL;
- }
-
-#ifdef USE_LIBIDN
- if(conn->host.encalloc)
- idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
- with idn_free() since this was allocated
- by libidn */
- if(conn->proxy.encalloc)
- idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
- freed with idn_free() since this was
- allocated by libidn */
-#endif
-
- Curl_ssl_close(conn);
-
- /* Indicate to all handles on the pipe that we're dead */
- if (IsPipeliningEnabled(data)) {
- signalPipeClose(conn->send_pipe);
- signalPipeClose(conn->recv_pipe);
- }
-
- conn_free(conn);
-
- return CURLE_OK;
-}
-
-/*
- * This function should return TRUE if the socket is to be assumed to
- * be dead. Most commonly this happens when the server has closed the
- * connection due to inactivity.
- */
-static bool SocketIsDead(curl_socket_t sock)
-{
- int sval;
- bool ret_val = TRUE;
-
- sval = Curl_select(sock, CURL_SOCKET_BAD, 0);
- if(sval == 0)
- /* timeout */
- ret_val = FALSE;
-
- return ret_val;
-}
-
-static bool IsPipeliningPossible(struct SessionHandle *handle)
-{
- if (handle->multi && Curl_multi_canPipeline(handle->multi) &&
- (handle->set.httpreq == HTTPREQ_GET ||
- handle->set.httpreq == HTTPREQ_HEAD) &&
- handle->set.httpversion != CURL_HTTP_VERSION_1_0)
- return TRUE;
-
- return FALSE;
-}
-
-static bool IsPipeliningEnabled(struct SessionHandle *handle)
-{
- if (handle->multi && Curl_multi_canPipeline(handle->multi))
- return TRUE;
-
- return FALSE;
-}
-
-void Curl_addHandleToPipeline(struct SessionHandle *data,
- struct curl_llist *pipe)
-{
-#ifdef CURLDEBUG
- if(!IsPipeliningPossible(data)) {
- /* when not pipelined, there MUST be no handle in the list already */
- if(pipe->head)
- infof(data, "PIPE when no PIPE supposed!\n");
- }
-#endif
- Curl_llist_insert_next(pipe, pipe->tail, data);
-}
-
-
-int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
- struct curl_llist *pipe)
-{
- struct curl_llist_element *curr;
-
- curr = pipe->head;
- while (curr) {
- if (curr->ptr == handle) {
- Curl_llist_remove(pipe, curr, NULL);
- return 1; /* we removed a handle */
- }
- curr = curr->next;
- }
-
- return 0;
-}
-
-#if 0 /* this code is saved here as it is useful for debugging purposes */
-static void Curl_printPipeline(struct curl_llist *pipe)
-{
- struct curl_llist_element *curr;
-
- curr = pipe->head;
- while (curr) {
- struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
- infof(data, "Handle in pipeline: %s\n",
- data->reqdata.path);
- curr = curr->next;
- }
-}
-#endif
-
-bool Curl_isHandleAtHead(struct SessionHandle *handle,
- struct curl_llist *pipe)
-{
- struct curl_llist_element *curr = pipe->head;
- if (curr) {
- return (bool)(curr->ptr == handle);
- }
-
- return FALSE;
-}
-
-static void signalPipeClose(struct curl_llist *pipe)
-{
- struct curl_llist_element *curr;
-
- curr = pipe->head;
- while (curr) {
- struct curl_llist_element *next = curr->next;
- struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
-
-#ifdef CURLDEBUG /* debug-only code */
- if(data->magic != CURLEASY_MAGIC_NUMBER) {
- /* MAJOR BADNESS */
- fprintf(stderr, "signalPipeClose() found BAAD easy handle\n");
- }
- else
-#endif
-
- data->state.pipe_broke = TRUE;
- Curl_llist_remove(pipe, curr, NULL);
- curr = next;
- }
-}
-
-
-/*
- * Given one filled in connection struct (named needle), this function should
- * detect if there already is one that has all the significant details
- * exactly the same and thus should be used instead.
- *
- * If there is a match, this function returns TRUE - and has marked the
- * connection as 'in-use'. It must later be called with ConnectionDone() to
- * return back to 'idle' (unused) state.
- */
-static bool
-ConnectionExists(struct SessionHandle *data,
- struct connectdata *needle,
- struct connectdata **usethis)
-{
- long i;
- struct connectdata *check;
- bool canPipeline = IsPipeliningPossible(data);
-
- for(i=0; i< data->state.connc->num; i++) {
- bool match = FALSE;
- /*
- * Note that if we use a HTTP proxy, we check connections to that
- * proxy and not to the actual remote server.
- */
- check = data->state.connc->connects[i];
- if(!check)
- /* NULL pointer means not filled-in entry */
- continue;
-
- if (check->connectindex == -1) {
- check->connectindex = i; /* Set this appropriately since it might have
- been set to -1 when the easy was removed
- from the multi */
- }
-
- infof(data, "Examining connection #%ld for reuse\n", check->connectindex);
-
- if(check->inuse && !canPipeline) {
- /* can only happen within multi handles, and means that another easy
- handle is using this connection */
- continue;
- }
-
-#ifdef CURLRES_ASYNCH
- /* ip_addr_str is NULL only if the resolving of the name hasn't completed
- yet and until then we don't re-use this connection */
- if (!check->ip_addr_str) {
- infof(data,
- "Connection #%ld has not finished name resolve, can't reuse\n",
- check->connectindex);
- continue;
- }
-#endif
-
- if (check->send_pipe->size +
- check->recv_pipe->size >= MAX_PIPELINE_LENGTH) {
- infof(data, "Connection #%ld has its pipeline full, can't reuse\n",
- check->connectindex);
- continue;
- }
-
- if (data->state.is_in_pipeline && check->bits.close) {
- /* Don't pick a connection that is going to be closed */
- infof(data, "Connection #%ld has been marked for close, can't reuse\n",
- check->connectindex);
- continue;
- }
-
- if((needle->protocol&PROT_SSL) != (check->protocol&PROT_SSL))
- /* don't do mixed SSL and non-SSL connections */
- continue;
-
- if(!needle->bits.httpproxy || needle->protocol&PROT_SSL) {
- /* The requested connection does not use a HTTP proxy or it
- uses SSL. */
-
- if(!(needle->protocol&PROT_SSL) && check->bits.httpproxy)
- /* we don't do SSL but the cached connection has a proxy,
- then don't match this */
- continue;
-
- if(strequal(needle->protostr, check->protostr) &&
- strequal(needle->host.name, check->host.name) &&
- (needle->remote_port == check->remote_port) ) {
- if(needle->protocol & PROT_SSL) {
- /* This is SSL, verify that we're using the same
- ssl options as well */
- if(!Curl_ssl_config_matches(&needle->ssl_config,
- &check->ssl_config)) {
- infof(data,
- "Connection #%ld has different SSL parameters, "
- "can't reuse\n",
- check->connectindex );
- continue;
- }
- }
- if((needle->protocol & PROT_FTP) ||
- ((needle->protocol & PROT_HTTP) &&
- (data->state.authhost.want==CURLAUTH_NTLM))) {
- /* This is FTP or HTTP+NTLM, verify that we're using the same name
- and password as well */
- if(!strequal(needle->user, check->user) ||
- !strequal(needle->passwd, check->passwd)) {
- /* one of them was different */
- continue;
- }
- }
- match = TRUE;
- }
- }
- else { /* The requested needle connection is using a proxy,
- is the checked one using the same? */
- if(check->bits.httpproxy &&
- strequal(needle->proxy.name, check->proxy.name) &&
- needle->port == check->port) {
- /* This is the same proxy connection, use it! */
- match = TRUE;
- }
- }
-
- if(match) {
- if (!IsPipeliningEnabled(data)) {
- /* The check for a dead socket makes sense only in the
- non-pipelining case */
- bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
- if(dead) {
- check->data = data;
- infof(data, "Connection #%d seems to be dead!\n", i);
-
- Curl_disconnect(check); /* disconnect resources */
- data->state.connc->connects[i]=NULL; /* nothing here */
-
- return FALSE;
- }
- }
-
- check->inuse = TRUE; /* mark this as being in use so that no other
- handle in a multi stack may nick it */
-
- if (canPipeline) {
- /* Mark the connection as being in a pipeline */
- check->is_in_pipeline = TRUE;
- }
-
- check->connectindex = i; /* Set this appropriately since it might have
- been set to -1 when the easy was removed
- from the multi */
- *usethis = check;
- return TRUE; /* yes, we found one to use! */
- }
- }
-
- return FALSE; /* no matching connecting exists */
-}
-
-
-
-/*
- * This function frees/closes a connection in the connection cache. This
- * should take the previously set policy into account when deciding which
- * of the connections to kill.
- */
-static long
-ConnectionKillOne(struct SessionHandle *data)
-{
- long i;
- struct connectdata *conn;
- long highscore=-1;
- long connindex=-1;
- long score;
- struct timeval now;
-
- now = Curl_tvnow();
-
- for(i=0; data->state.connc && (i< data->state.connc->num); i++) {
- conn = data->state.connc->connects[i];
-
- if(!conn || conn->inuse)
- continue;
-
- /* Set higher score for the age passed since the connection was used */
- score = Curl_tvdiff(now, conn->now);
-
- if(score > highscore) {
- highscore = score;
- connindex = i;
- }
- }
- if(connindex >= 0) {
- /* Set the connection's owner correctly */
- conn = data->state.connc->connects[connindex];
- conn->data = data;
-
- /* the winner gets the honour of being disconnected */
- (void)Curl_disconnect(conn);
-
- /* clean the array entry */
- data->state.connc->connects[connindex] = NULL;
- }
-
- return connindex; /* return the available index or -1 */
-}
-
-/* this connection can now be marked 'idle' */
-static void
-ConnectionDone(struct connectdata *conn)
-{
- conn->inuse = FALSE;
- if (!conn->send_pipe && !conn->recv_pipe)
- conn->is_in_pipeline = FALSE;
-}
-
-/*
- * The given input connection struct pointer is to be stored. If the "cache"
- * is already full, we must clean out the most suitable using the previously
- * set policy.
- *
- * The given connection should be unique. That must've been checked prior to
- * this call.
- */
-static long
-ConnectionStore(struct SessionHandle *data,
- struct connectdata *conn)
-{
- long i;
- for(i=0; i< data->state.connc->num; i++) {
- if(!data->state.connc->connects[i])
- break;
- }
- if(i == data->state.connc->num) {
- /* there was no room available, kill one */
- i = ConnectionKillOne(data);
- if(-1 != i)
- infof(data, "Connection (#%d) was killed to make room (holds %d)\n",
- i, data->state.connc->num);
- else
- infof(data, "This connection did not fit in the connection cache\n");
- }
-
- conn->connectindex = i; /* Make the child know where the pointer to this
- particular data is stored. But note that this -1
- if this is not within the cache and this is
- probably not checked for everywhere (yet). */
- conn->inuse = TRUE;
- if(-1 != i) {
- /* Only do this if a true index was returned, if -1 was returned there
- is no room in the cache for an unknown reason and we cannot store
- this there.
-
- TODO: make sure we really can work with more handles than positions in
- the cache, or possibly we should (allow to automatically) resize the
- connection cache when we add more easy handles to a multi handle!
- */
- data->state.connc->connects[i] = conn; /* fill in this */
- conn->data = data;
- }
-
- return i;
-}
-
-static CURLcode ConnectPlease(struct SessionHandle *data,
- struct connectdata *conn,
- struct Curl_dns_entry *hostaddr,
- bool *connected)
-{
- CURLcode result;
- Curl_addrinfo *addr;
- char *hostname = conn->bits.httpproxy?conn->proxy.name:conn->host.name;
-
- infof(data, "About to connect() to %s%s port %d (#%d)\n",
- conn->bits.httpproxy?"proxy ":"",
- hostname, conn->port, conn->connectindex);
-
- /*************************************************************
- * Connect to server/proxy
- *************************************************************/
- result= Curl_connecthost(conn,
- hostaddr,
- &conn->sock[FIRSTSOCKET],
- &addr,
- connected);
- if(CURLE_OK == result) {
- /* All is cool, then we store the current information */
- conn->dns_entry = hostaddr;
- conn->ip_addr = addr;
-
- Curl_store_ip_addr(conn);
-
- switch(data->set.proxytype) {
- case CURLPROXY_SOCKS5:
- result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, conn);
- break;
- case CURLPROXY_HTTP:
- /* do nothing here. handled later. */
- break;
- case CURLPROXY_SOCKS4:
- result = Curl_SOCKS4(conn->proxyuser, conn);
- break;
- default:
- failf(data, "unknown proxytype option given");
- result = CURLE_COULDNT_CONNECT;
- break;
- }
- }
-
- return result;
-}
-
-/*
- * verboseconnect() displays verbose information after a connect
- */
-static void verboseconnect(struct connectdata *conn)
-{
- infof(conn->data, "Connected to %s (%s) port %d (#%d)\n",
- conn->bits.httpproxy ? conn->proxy.dispname : conn->host.dispname,
- conn->ip_addr_str, conn->port, conn->connectindex);
-}
-
-int Curl_protocol_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn->curl_proto_getsock)
- return conn->curl_proto_getsock(conn, socks, numsocks);
- return GETSOCK_BLANK;
-}
-
-int Curl_doing_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn && conn->curl_doing_getsock)
- return conn->curl_doing_getsock(conn, socks, numsocks);
- return GETSOCK_BLANK;
-}
-
-/*
- * We are doing protocol-specific connecting and this is being called over and
- * over from the multi interface until the connection phase is done on
- * protocol layer.
- */
-
-CURLcode Curl_protocol_connecting(struct connectdata *conn,
- bool *done)
-{
- CURLcode result=CURLE_OK;
-
- if(conn && conn->curl_connecting) {
- *done = FALSE;
- result = conn->curl_connecting(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We are DOING this is being called over and over from the multi interface
- * until the DOING phase is done on protocol layer.
- */
-
-CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
-{
- CURLcode result=CURLE_OK;
-
- if(conn && conn->curl_doing) {
- *done = FALSE;
- result = conn->curl_doing(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We have discovered that the TCP connection has been successful, we can now
- * proceed with some action.
- *
- */
-CURLcode Curl_protocol_connect(struct connectdata *conn,
- bool *protocol_done)
-{
- CURLcode result=CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- *protocol_done = FALSE;
-
- if(conn->bits.tcpconnect && conn->bits.protoconnstart) {
- /* We already are connected, get back. This may happen when the connect
- worked fine in the first call, like when we connect to a local server
- or proxy. Note that we don't know if the protocol is actually done.
-
- Unless this protocol doesn't have any protocol-connect callback, as
- then we know we're done. */
- if(!conn->curl_connecting)
- *protocol_done = TRUE;
-
- return CURLE_OK;
- }
-
- if(!conn->bits.tcpconnect) {
-
- Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
-
- if(data->set.verbose)
- verboseconnect(conn);
- }
-
- if(!conn->bits.protoconnstart) {
- if(conn->curl_connect) {
- /* is there a protocol-specific connect() procedure? */
-
- /* Set start time here for timeout purposes in the connect procedure, it
- is later set again for the progress meter purpose */
- conn->now = Curl_tvnow();
-
- /* Call the protocol-specific connect function */
- result = conn->curl_connect(conn, protocol_done);
- }
- else
- *protocol_done = TRUE;
-
- /* it has started, possibly even completed but that knowledge isn't stored
- in this bit! */
- if (!result)
- conn->bits.protoconnstart = TRUE;
- }
-
- return result; /* pass back status */
-}
-
-/*
- * Helpers for IDNA convertions.
- */
-#ifdef USE_LIBIDN
-static bool is_ASCII_name(const char *hostname)
-{
- const unsigned char *ch = (const unsigned char*)hostname;
-
- while (*ch) {
- if (*ch++ & 0x80)
- return FALSE;
- }
- return TRUE;
-}
-
-/*
- * Check if characters in hostname is allowed in Top Level Domain.
- */
-static bool tld_check_name(struct SessionHandle *data,
- const char *ace_hostname)
-{
- size_t err_pos;
- char *uc_name = NULL;
- int rc;
-
- /* Convert (and downcase) ACE-name back into locale's character set */
- rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
- if (rc != IDNA_SUCCESS)
- return (FALSE);
-
- rc = tld_check_lz(uc_name, &err_pos, NULL);
- if (rc == TLD_INVALID)
- infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
-#ifdef HAVE_TLD_STRERROR
- tld_strerror((Tld_rc)rc),
-#else
- "<no msg>",
-#endif
- err_pos, uc_name[err_pos],
- uc_name[err_pos] & 255);
- else if (rc != TLD_SUCCESS)
- infof(data, "WARNING: TLD check for %s failed; %s\n",
- uc_name,
-#ifdef HAVE_TLD_STRERROR
- tld_strerror((Tld_rc)rc)
-#else
- "<no msg>"
-#endif
- );
- if (uc_name)
- idn_free(uc_name);
- return (bool)(rc == TLD_SUCCESS);
-}
-#endif
-
-static void fix_hostname(struct SessionHandle *data,
- struct connectdata *conn, struct hostname *host)
-{
- /* set the name we use to display the host name */
- host->dispname = host->name;
-
-#ifdef USE_LIBIDN
- /*************************************************************
- * Check name for non-ASCII and convert hostname to ACE form.
- *************************************************************/
- if (!is_ASCII_name(host->name) &&
- stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
- char *ace_hostname = NULL;
- int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
- infof (data, "Input domain encoded as `%s'\n",
- stringprep_locale_charset ());
- if (rc != IDNA_SUCCESS)
- infof(data, "Failed to convert %s to ACE; %s\n",
- host->name, Curl_idn_strerror(conn,rc));
- else {
- /* tld_check_name() displays a warning if the host name contains
- "illegal" characters for this TLD */
- (void)tld_check_name(data, ace_hostname);
-
- host->encalloc = ace_hostname;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
- }
- }
-#else
- (void)data; /* never used */
- (void)conn; /* never used */
-#endif
-}
-
-/*
- * Parse URL and fill in the relevant members of the connection struct.
- */
-static CURLcode ParseURLAndFillConnection(struct SessionHandle *data,
- struct connectdata *conn)
-{
- char *at;
- char *tmp;
-
- char *path = data->reqdata.path;
-
- /*************************************************************
- * Parse the URL.
- *
- * We need to parse the url even when using the proxy, because we will need
- * the hostname and port in case we are trying to SSL connect through the
- * proxy -- and we don't know if we will need to use SSL until we parse the
- * url ...
- ************************************************************/
- if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
- conn->protostr,
- path)) && strequal(conn->protostr, "file")) {
- if(path[0] == '/' && path[1] == '/') {
- /* Allow omitted hostname (e.g. file:/<path>). This is not strictly
- * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
- * file://localhost/<path> is similar to how other schemes treat missing
- * hostnames. See RFC 1808. */
-
- /* This cannot be done with strcpy() in a portable manner, since the
- memory areas overlap! */
- memmove(path, path + 2, strlen(path + 2)+1);
- }
- /*
- * we deal with file://<host>/<path> differently since it supports no
- * hostname other than "localhost" and "127.0.0.1", which is unique among
- * the URL protocols specified in RFC 1738
- */
- if(path[0] != '/') {
- /* the URL included a host name, we ignore host names in file:// URLs
- as the standards don't define what to do with them */
- char *ptr=strchr(path, '/');
- if(ptr) {
- /* there was a slash present
-
- RFC1738 (section 3.1, page 5) says:
-
- The rest of the locator consists of data specific to the scheme,
- and is known as the "url-path". It supplies the details of how the
- specified resource can be accessed. Note that the "/" between the
- host (or port) and the url-path is NOT part of the url-path.
-
- As most agents use file://localhost/foo to get '/foo' although the
- slash preceding foo is a separator and not a slash for the path,
- a URL as file://localhost//foo must be valid as well, to refer to
- the same file with an absolute path.
- */
-
- if(ptr[1] && ('/' == ptr[1]))
- /* if there was two slashes, we skip the first one as that is then
- used truly as a separator */
- ptr++;
-
- /* This cannot be made with strcpy, as the memory chunks overlap! */
- memmove(path, ptr, strlen(ptr)+1);
- }
- }
-
- strcpy(conn->protostr, "file"); /* store protocol string lowercase */
- }
- else {
- /* clear path */
- path[0]=0;
-
- if (2 > sscanf(data->change.url,
- "%15[^\n:]://%[^\n/]%[^\n]",
- conn->protostr,
- conn->host.name, path)) {
-
- /*
- * The URL was badly formatted, let's try the browser-style _without_
- * protocol specified like 'http://'.
- */
- if((1 > sscanf(data->change.url, "%[^\n/]%[^\n]",
- conn->host.name, path)) ) {
- /*
- * We couldn't even get this format.
- */
- failf(data, "<url> malformed");
- return CURLE_URL_MALFORMAT;
- }
-
- /*
- * Since there was no protocol part specified, we guess what protocol it
- * is based on the first letters of the server name.
- */
-
- /* Note: if you add a new protocol, please update the list in
- * lib/version.c too! */
-
- if(checkprefix("FTP.", conn->host.name))
- strcpy(conn->protostr, "ftp");
- else if (checkprefix("DICT.", conn->host.name))
- strcpy(conn->protostr, "DICT");
- else if (checkprefix("LDAP.", conn->host.name))
- strcpy(conn->protostr, "LDAP");
- else {
- strcpy(conn->protostr, "http");
- }
-
- conn->protocol |= PROT_MISSING; /* not given in URL */
- }
- }
-
- /* We search for '?' in the host name (but only on the right side of a
- * @-letter to allow ?-letters in username and password) to handle things
- * like http://example.com?param= (notice the missing '/').
- */
- at = strchr(conn->host.name, '@');
- if(at)
- tmp = strchr(at+1, '?');
- else
- tmp = strchr(conn->host.name, '?');
-
- if(tmp) {
- /* We must insert a slash before the '?'-letter in the URL. If the URL had
- a slash after the '?', that is where the path currently begins and the
- '?string' is still part of the host name.
-
- We must move the trailing part from the host name and put it first in
- the path. And have it all prefixed with a slash.
- */
-
- size_t hostlen = strlen(tmp);
- size_t pathlen = strlen(path);
-
- /* move the existing path plus the zero byte forward, to make room for
- the host-name part */
- memmove(path+hostlen+1, path, pathlen+1);
-
- /* now copy the trailing host part in front of the existing path */
- memcpy(path+1, tmp, hostlen);
-
- path[0]='/'; /* prepend the missing slash */
-
- *tmp=0; /* now cut off the hostname at the ? */
- }
- else if(!path[0]) {
- /* if there's no path set, use a single slash */
- strcpy(path, "/");
- }
-
- /* If the URL is malformatted (missing a '/' after hostname before path) we
- * insert a slash here. The only letter except '/' we accept to start a path
- * is '?'.
- */
- if(path[0] == '?') {
- /* We need this function to deal with overlapping memory areas. We know
- that the memory area 'path' points to is 'urllen' bytes big and that
- is bigger than the path. Use +1 to move the zero byte too. */
- memmove(&path[1], path, strlen(path)+1);
- path[0] = '/';
- }
-
- /*
- * So if the URL was A://B/C,
- * conn->protostr is A
- * conn->host.name is B
- * data->reqdata.path is /C
- */
-
- return CURLE_OK;
-}
-
-static void llist_dtor(void *user, void *element)
-{
- (void)user;
- (void)element;
- /* Do nothing */
-}
-
-
-/**
- * CreateConnection() sets up a new connectdata struct, or re-uses an already
- * existing one, and resolves host name.
- *
- * if this function returns CURLE_OK and *async is set to TRUE, the resolve
- * response will be coming asynchronously. If *async is FALSE, the name is
- * already resolved.
- *
- * @param data The sessionhandle pointer
- * @param in_connect is set to the next connection data pointer
- * @param addr is set to the new dns entry for this connection. If this
- * connection is re-used it will be NULL.
- * @param async is set TRUE/FALSE depending on the nature of this lookup
- * @return CURLcode
- * @see SetupConnection()
- *
- * *NOTE* this function assigns the conn->data pointer!
- */
-
-static CURLcode CreateConnection(struct SessionHandle *data,
- struct connectdata **in_connect,
- struct Curl_dns_entry **addr,
- bool *async)
-{
-
- char *tmp;
- CURLcode result=CURLE_OK;
- struct connectdata *conn;
- struct connectdata *conn_temp = NULL;
- size_t urllen;
- struct Curl_dns_entry *hostaddr;
-#if defined(HAVE_ALARM) && !defined(USE_ARES)
- unsigned int prev_alarm=0;
-#endif
- char endbracket;
- char user[MAX_CURL_USER_LENGTH];
- char passwd[MAX_CURL_PASSWORD_LENGTH];
- int rc;
- bool reuse;
- char *proxy;
- bool proxy_alloc = FALSE;
-
-#ifndef USE_ARES
-#ifdef SIGALRM
-#ifdef HAVE_SIGACTION
- struct sigaction keep_sigact; /* store the old struct here */
- bool keep_copysig=FALSE; /* did copy it? */
-#else
-#ifdef HAVE_SIGNAL
- void (*keep_sigact)(int); /* store the old handler here */
-#endif /* HAVE_SIGNAL */
-#endif /* HAVE_SIGACTION */
-#endif /* SIGALRM */
-#endif /* USE_ARES */
-
- *addr = NULL; /* nothing yet */
- *async = FALSE;
-
- /*************************************************************
- * Check input data
- *************************************************************/
-
- if(!data->change.url)
- return CURLE_URL_MALFORMAT;
-
- /* First, split up the current URL in parts so that we can use the
- parts for checking against the already present connections. In order
- to not have to modify everything at once, we allocate a temporary
- connection data struct and fill in for comparison purposes. */
-
- conn = (struct connectdata *)calloc(sizeof(struct connectdata), 1);
- if(!conn) {
- *in_connect = NULL; /* clear the pointer */
- return CURLE_OUT_OF_MEMORY;
- }
- /* We must set the return variable as soon as possible, so that our
- parent can cleanup any possible allocs we may have done before
- any failure */
- *in_connect = conn;
-
- /* and we setup a few fields in case we end up actually using this struct */
-
- conn->data = data; /* Setup the association between this connection
- and the SessionHandle */
-
- conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
- conn->connectindex = -1; /* no index */
-
- conn->bits.httpproxy = (bool)(data->set.proxy /* http proxy or not */
- && *data->set.proxy
- && (data->set.proxytype == CURLPROXY_HTTP));
- proxy = data->set.proxy; /* if global proxy is set, this is it */
-
- /* Default protocol-independent behavior doesn't support persistent
- connections, so we set this to force-close. Protocols that support
- this need to set this to FALSE in their "curl_do" functions. */
- conn->bits.close = TRUE;
-
- conn->readchannel_inuse = FALSE;
- conn->writechannel_inuse = FALSE;
-
- conn->read_pos = 0;
- conn->buf_len = 0;
-
- /* Initialize the pipeline lists */
- conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
- conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
-
- /* Store creation time to help future close decision making */
- conn->created = Curl_tvnow();
-
- /* range status */
- data->reqdata.use_range = (bool)(NULL != data->set.set_range);
-
- data->reqdata.range = data->set.set_range; /* clone the range setting */
- data->reqdata.resume_from = data->set.set_resume_from;
-
- conn->bits.user_passwd = (bool)(NULL != data->set.userpwd);
- conn->bits.proxy_user_passwd = (bool)(NULL != data->set.proxyuserpwd);
- conn->bits.no_body = data->set.opt_no_body;
- conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
- conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
- conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
-
- /* This initing continues below, see the comment "Continue connectdata
- * initialization here" */
-
- /***********************************************************
- * We need to allocate memory to store the path in. We get the size of the
- * full URL to be sure, and we need to make it at least 256 bytes since
- * other parts of the code will rely on this fact
- ***********************************************************/
-#define LEAST_PATH_ALLOC 256
- urllen=strlen(data->change.url);
- if(urllen < LEAST_PATH_ALLOC)
- urllen=LEAST_PATH_ALLOC;
-
- if (!data->set.source_url /* 3rd party FTP */
- && data->reqdata.pathbuffer) {
- /* Free the old buffer */
- free(data->reqdata.pathbuffer);
- }
-
- /*
- * We malloc() the buffers below urllen+2 to make room for to possibilities:
- * 1 - an extra terminating zero
- * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
- */
-
- data->reqdata.pathbuffer=(char *)malloc(urllen+2);
- if(NULL == data->reqdata.pathbuffer)
- return CURLE_OUT_OF_MEMORY; /* really bad error */
- data->reqdata.path = data->reqdata.pathbuffer;
-
- conn->host.rawalloc=(char *)malloc(urllen+2);
- if(NULL == conn->host.rawalloc)
- return CURLE_OUT_OF_MEMORY;
-
- conn->host.name = conn->host.rawalloc;
- conn->host.name[0] = 0;
-
- result = ParseURLAndFillConnection(data, conn);
- if (result != CURLE_OK) {
- return result;
- }
-
- /*************************************************************
- * Take care of proxy authentication stuff
- *************************************************************/
- if(conn->bits.proxy_user_passwd) {
- char proxyuser[MAX_CURL_USER_LENGTH]="";
- char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
-
- sscanf(data->set.proxyuserpwd,
- "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
- proxyuser, proxypasswd);
-
- conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
- if(!conn->proxyuser)
- return CURLE_OUT_OF_MEMORY;
-
- conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
- if(!conn->proxypasswd)
- return CURLE_OUT_OF_MEMORY;
- }
-
-#ifndef CURL_DISABLE_HTTP
- /*************************************************************
- * Detect what (if any) proxy to use
- *************************************************************/
- if(!conn->bits.httpproxy) {
- /* If proxy was not specified, we check for default proxy environment
- * variables, to enable i.e Lynx compliance:
- *
- * http_proxy=http://some.server.dom:port/
- * https_proxy=http://some.server.dom:port/
- * ftp_proxy=http://some.server.dom:port/
- * no_proxy=domain1.dom,host.domain2.dom
- * (a comma-separated list of hosts which should
- * not be proxied, or an asterisk to override
- * all proxy variables)
- * all_proxy=http://some.server.dom:port/
- * (seems to exist for the CERN www lib. Probably
- * the first to check for.)
- *
- * For compatibility, the all-uppercase versions of these variables are
- * checked if the lowercase versions don't exist.
- */
- char *no_proxy=NULL;
- char *no_proxy_tok_buf;
- char proxy_env[128];
-
- no_proxy=curl_getenv("no_proxy");
- if(!no_proxy)
- no_proxy=curl_getenv("NO_PROXY");
-
- if(!no_proxy || !strequal("*", no_proxy)) {
- /* NO_PROXY wasn't specified or it wasn't just an asterisk */
- char *nope;
-
- nope=no_proxy?strtok_r(no_proxy, ", ", &no_proxy_tok_buf):NULL;
- while(nope) {
- size_t namelen;
- char *endptr = strchr(conn->host.name, ':');
- if(endptr)
- namelen=endptr-conn->host.name;
- else
- namelen=strlen(conn->host.name);
-
- if(strlen(nope) <= namelen) {
- char *checkn=
- conn->host.name + namelen - strlen(nope);
- if(checkprefix(nope, checkn)) {
- /* no proxy for this host! */
- break;
- }
- }
- nope=strtok_r(NULL, ", ", &no_proxy_tok_buf);
- }
- if(!nope) {
- /* It was not listed as without proxy */
- char *protop = conn->protostr;
- char *envp = proxy_env;
- char *prox;
-
- /* Now, build <protocol>_proxy and check for such a one to use */
- while(*protop)
- *envp++ = (char)tolower((int)*protop++);
-
- /* append _proxy */
- strcpy(envp, "_proxy");
-
- /* read the protocol proxy: */
- prox=curl_getenv(proxy_env);
-
- /*
- * We don't try the uppercase version of HTTP_PROXY because of
- * security reasons:
- *
- * When curl is used in a webserver application
- * environment (cgi or php), this environment variable can
- * be controlled by the web server user by setting the
- * http header 'Proxy:' to some value.
- *
- * This can cause 'internal' http/ftp requests to be
- * arbitrarily redirected by any external attacker.
- */
- if(!prox && !strequal("http_proxy", proxy_env)) {
- /* There was no lowercase variable, try the uppercase version: */
- for(envp = proxy_env; *envp; envp++)
- *envp = (char)toupper((int)*envp);
- prox=curl_getenv(proxy_env);
- }
-
- if(prox && *prox) { /* don't count "" strings */
- proxy = prox; /* use this */
- }
- else {
- proxy = curl_getenv("all_proxy"); /* default proxy to use */
- if(!proxy)
- proxy=curl_getenv("ALL_PROXY");
- }
-
- if(proxy && *proxy) {
- long bits = conn->protocol & (PROT_HTTPS|PROT_SSL|PROT_MISSING);
- /* force this to become HTTP */
- conn->protocol = PROT_HTTP | bits;
-
- proxy_alloc=TRUE; /* this needs to be freed later */
- conn->bits.httpproxy = TRUE;
- }
- } /* if (!nope) - it wasn't specified non-proxy */
- } /* NO_PROXY wasn't specified or '*' */
- if(no_proxy)
- free(no_proxy);
- } /* if not using proxy */
-#endif /* CURL_DISABLE_HTTP */
-
- /*************************************************************
- * No protocol part in URL was used, add it!
- *************************************************************/
- if(conn->protocol&PROT_MISSING) {
- /* We're guessing prefixes here and if we're told to use a proxy or if
- we're gonna follow a Location: later or... then we need the protocol
- part added so that we have a valid URL. */
- char *reurl;
-
- reurl = aprintf("%s://%s", conn->protostr, data->change.url);
-
- if(!reurl)
- return CURLE_OUT_OF_MEMORY;
-
- data->change.url = reurl;
- data->change.url_alloc = TRUE; /* free this later */
- conn->protocol &= ~PROT_MISSING; /* switch that one off again */
- }
-
-#ifndef CURL_DISABLE_HTTP
- /************************************************************
- * RESUME on a HTTP page is a tricky business. First, let's just check that
- * 'range' isn't used, then set the range parameter and leave the resume as
- * it is to inform about this situation for later use. We will then
- * "attempt" to resume, and if we're talking to a HTTP/1.1 (or later)
- * server, we will get the document resumed. If we talk to a HTTP/1.0
- * server, we just fail since we can't rewind the file writing from within
- * this function.
- ***********************************************************/
- if(data->reqdata.resume_from) {
- if(!data->reqdata.use_range) {
- /* if it already was in use, we just skip this */
- data->reqdata.range = aprintf("%" FORMAT_OFF_T "-", data->reqdata.resume_from);
- if(!data->reqdata.range)
- return CURLE_OUT_OF_MEMORY;
- data->reqdata.rangestringalloc = TRUE; /* mark as allocated */
- data->reqdata.use_range = 1; /* switch on range usage */
- }
- }
-#endif
- /*************************************************************
- * Setup internals depending on protocol
- *************************************************************/
-
- conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
-
- if (strequal(conn->protostr, "HTTP")) {
-#ifndef CURL_DISABLE_HTTP
- conn->port = PORT_HTTP;
- conn->remote_port = PORT_HTTP;
- conn->protocol |= PROT_HTTP;
- conn->curl_do = Curl_http;
- conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
- conn->curl_done = Curl_http_done;
- conn->curl_connect = Curl_http_connect;
-#else
- failf(data, LIBCURL_NAME
- " was built with HTTP disabled, http: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
- else if (strequal(conn->protostr, "HTTPS")) {
-#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
-
- conn->port = PORT_HTTPS;
- conn->remote_port = PORT_HTTPS;
- conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
-
- conn->curl_do = Curl_http;
- conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
- conn->curl_done = Curl_http_done;
- conn->curl_connect = Curl_http_connect;
- conn->curl_connecting = Curl_https_connecting;
- conn->curl_proto_getsock = Curl_https_getsock;
-
-#else /* USE_SSL */
- failf(data, LIBCURL_NAME
- " was built with SSL disabled, https: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif /* !USE_SSL */
- }
- else if(strequal(conn->protostr, "FTP") ||
- strequal(conn->protostr, "FTPS")) {
-
-#ifndef CURL_DISABLE_FTP
- char *type;
- int port = PORT_FTP;
-
- if(strequal(conn->protostr, "FTPS")) {
-#ifdef USE_SSL
- conn->protocol |= PROT_FTPS|PROT_SSL;
- conn->ssl[SECONDARYSOCKET].use = TRUE; /* send data securely */
- port = PORT_FTPS;
-#else
- failf(data, LIBCURL_NAME
- " was built with SSL disabled, ftps: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif /* !USE_SSL */
- }
-
- conn->port = port;
- conn->remote_port = (unsigned short)port;
- conn->protocol |= PROT_FTP;
-
- if(proxy && *proxy && !data->set.tunnel_thru_httpproxy) {
- /* Unless we have asked to tunnel ftp operations through the proxy, we
- switch and use HTTP operations only */
-#ifndef CURL_DISABLE_HTTP
- conn->curl_do = Curl_http;
- conn->curl_done = Curl_http_done;
- conn->protocol = PROT_HTTP; /* switch to HTTP */
-#else
- failf(data, "FTP over http proxy requires HTTP support built-in!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
- else {
- conn->curl_do = Curl_ftp;
- conn->curl_do_more = Curl_ftp_nextconnect;
- conn->curl_done = Curl_ftp_done;
- conn->curl_connect = Curl_ftp_connect;
- conn->curl_connecting = Curl_ftp_multi_statemach;
- conn->curl_doing = Curl_ftp_doing;
- conn->curl_proto_getsock = Curl_ftp_getsock;
- conn->curl_doing_getsock = Curl_ftp_getsock;
- conn->curl_disconnect = Curl_ftp_disconnect;
- }
-
- data->reqdata.path++; /* don't include the initial slash */
-
- /* FTP URLs support an extension like ";type=<typecode>" that
- * we'll try to get now! */
- type=strstr(data->reqdata.path, ";type=");
- if(!type) {
- type=strstr(conn->host.rawalloc, ";type=");
- }
- if(type) {
- char command;
- *type=0; /* it was in the middle of the hostname */
- command = (char)toupper((int)type[6]);
- switch(command) {
- case 'A': /* ASCII mode */
- data->set.prefer_ascii = TRUE;
- break;
- case 'D': /* directory mode */
- data->set.ftp_list_only = TRUE;
- break;
- case 'I': /* binary mode */
- default:
- /* switch off ASCII */
- data->set.prefer_ascii = FALSE;
- break;
- }
- }
-#else /* CURL_DISABLE_FTP */
- failf(data, LIBCURL_NAME
- " was built with FTP disabled, ftp/ftps: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
- else if(strequal(conn->protostr, "TELNET")) {
-#ifndef CURL_DISABLE_TELNET
- /* telnet testing factory */
- conn->protocol |= PROT_TELNET;
-
- conn->port = PORT_TELNET;
- conn->remote_port = PORT_TELNET;
- conn->curl_do = Curl_telnet;
- conn->curl_done = Curl_telnet_done;
-#else
- failf(data, LIBCURL_NAME
- " was built with TELNET disabled!");
-#endif
- }
- else if (strequal(conn->protostr, "DICT")) {
-#ifndef CURL_DISABLE_DICT
- conn->protocol |= PROT_DICT;
- conn->port = PORT_DICT;
- conn->remote_port = PORT_DICT;
- conn->curl_do = Curl_dict;
- /* no DICT-specific done */
- conn->curl_done = (Curl_done_func)ZERO_NULL;
-#else
- failf(data, LIBCURL_NAME
- " was built with DICT disabled!");
-#endif
- }
- else if (strequal(conn->protostr, "LDAP")) {
-#ifndef CURL_DISABLE_LDAP
- conn->protocol |= PROT_LDAP;
- conn->port = PORT_LDAP;
- conn->remote_port = PORT_LDAP;
- conn->curl_do = Curl_ldap;
- /* no LDAP-specific done */
- conn->curl_done = (Curl_done_func)ZERO_NULL;
-#else
- failf(data, LIBCURL_NAME
- " was built with LDAP disabled!");
-#endif
- }
- else if (strequal(conn->protostr, "FILE")) {
-#ifndef CURL_DISABLE_FILE
- conn->protocol |= PROT_FILE;
-
- conn->curl_do = Curl_file;
- conn->curl_done = Curl_file_done;
-
- /* anyway, this is supposed to be the connect function so we better
- at least check that the file is present here! */
- result = Curl_file_connect(conn);
-
- /* Setup a "faked" transfer that'll do nothing */
- if(CURLE_OK == result) {
- conn->data = data;
- conn->bits.tcpconnect = TRUE; /* we are "connected */
- ConnectionStore(data, conn);
-
- result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
- -1, NULL); /* no upload */
- }
-
- return result;
-#else
- failf(data, LIBCURL_NAME
- " was built with FILE disabled!");
-#endif
- }
- else if (strequal(conn->protostr, "TFTP")) {
-#ifndef CURL_DISABLE_TFTP
- char *type;
- conn->socktype = SOCK_DGRAM; /* UDP datagram based */
- conn->protocol |= PROT_TFTP;
- conn->port = PORT_TFTP;
- conn->remote_port = PORT_TFTP;
- conn->curl_connect = Curl_tftp_connect;
- conn->curl_do = Curl_tftp;
- conn->curl_done = Curl_tftp_done;
- /* TFTP URLs support an extension like ";mode=<typecode>" that
- * we'll try to get now! */
- type=strstr(data->reqdata.path, ";mode=");
- if(!type) {
- type=strstr(conn->host.rawalloc, ";mode=");
- }
- if(type) {
- char command;
- *type=0; /* it was in the middle of the hostname */
- command = (char)toupper((int)type[6]);
- switch(command) {
- case 'A': /* ASCII mode */
- case 'N': /* NETASCII mode */
- data->set.prefer_ascii = TRUE;
- break;
- case 'O': /* octet mode */
- case 'I': /* binary mode */
- default:
- /* switch off ASCII */
- data->set.prefer_ascii = FALSE;
- break;
- }
- }
-#else
- failf(data, LIBCURL_NAME
- " was built with TFTP disabled!");
-#endif
- }
- else if (strequal(conn->protostr, "SCP")) {
-#ifdef USE_LIBSSH2
- conn->port = PORT_SSH;
- conn->remote_port = PORT_SSH;
- conn->protocol = PROT_SCP;
- conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */
- conn->curl_do = Curl_scp_do;
- conn->curl_done = Curl_scp_done;
- conn->curl_do_more = (Curl_do_more_func)ZERO_NULL;
-#else
- failf(data, LIBCURL_NAME
- " was built without LIBSSH2, scp: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
- }
- else if (strequal(conn->protostr, "SFTP")) {
-#ifdef USE_LIBSSH2
- conn->port = PORT_SSH;
- conn->remote_port = PORT_SSH;
- conn->protocol = PROT_SFTP;
- conn->curl_connect = Curl_ssh_connect; /* ssh_connect? */
- conn->curl_do = Curl_sftp_do;
- conn->curl_done = Curl_sftp_done;
- conn->curl_do_more = (Curl_do_more_func)NULL;
-#else
- failf(data, LIBCURL_NAME
- " was built without LIBSSH2, scp: not supported!");
- return CURLE_UNSUPPORTED_PROTOCOL;
-#endif
-}
-else {
- /* We fell through all checks and thus we don't support the specified
- protocol */
- failf(data, "Unsupported protocol: %s", conn->protostr);
- return CURLE_UNSUPPORTED_PROTOCOL;
- }
-
- if(proxy && *proxy) {
- /* If this is supposed to use a proxy, we need to figure out the proxy
- host name name, so that we can re-use an existing connection
- that may exist registered to the same proxy host. */
-
- char *prox_portno;
- char *endofprot;
-
- /* We need to make a duplicate of the proxy so that we can modify the
- string safely. If 'proxy_alloc' is TRUE, the string is already
- allocated and we can treat it as duplicated. */
- char *proxydup=proxy_alloc?proxy:strdup(proxy);
-
- /* We use 'proxyptr' to point to the proxy name from now on... */
- char *proxyptr=proxydup;
- char *portptr;
- char *atsign;
-
- if(NULL == proxydup) {
- failf(data, "memory shortage");
- return CURLE_OUT_OF_MEMORY;
- }
-
- /* We do the proxy host string parsing here. We want the host name and the
- * port name. Accept a protocol:// prefix, even though it should just be
- * ignored.
- */
-
- /* Skip the protocol part if present */
- endofprot=strstr(proxyptr, "://");
- if(endofprot)
- proxyptr = endofprot+3;
-
- /* Is there a username and password given in this proxy url? */
- atsign = strchr(proxyptr, '@');
- if(atsign) {
- char proxyuser[MAX_CURL_USER_LENGTH];
- char proxypasswd[MAX_CURL_PASSWORD_LENGTH];
- proxypasswd[0] = 0;
-
- if(1 <= sscanf(proxyptr,
- "%" MAX_CURL_USER_LENGTH_TXT"[^:]:"
- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
- proxyuser, proxypasswd)) {
- CURLcode res = CURLE_OK;
-
- /* found user and password, rip them out. note that we are
- unescaping them, as there is otherwise no way to have a
- username or password with reserved characters like ':' in
- them. */
- Curl_safefree(conn->proxyuser);
- conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
-
- if(!conn->proxyuser)
- res = CURLE_OUT_OF_MEMORY;
- else {
- Curl_safefree(conn->proxypasswd);
- conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
-
- if(!conn->proxypasswd)
- res = CURLE_OUT_OF_MEMORY;
- }
-
- if(CURLE_OK == res) {
- conn->bits.proxy_user_passwd = TRUE; /* enable it */
- atsign = strdup(atsign+1); /* the right side of the @-letter */
-
- if(atsign) {
- free(proxydup); /* free the former proxy string */
- proxydup = proxyptr = atsign; /* now use this instead */
- }
- else
- res = CURLE_OUT_OF_MEMORY;
- }
-
- if(res) {
- free(proxydup); /* free the allocated proxy string */
- return res;
- }
- }
- }
-
- /* start scanning for port number at this point */
- portptr = proxyptr;
-
- /* detect and extract RFC2732-style IPv6-addresses */
- if(*proxyptr == '[') {
- char *ptr = ++proxyptr; /* advance beyond the initial bracket */
- while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':')))
- ptr++;
- if(*ptr == ']') {
- /* yeps, it ended nicely with a bracket as well */
- *ptr = 0;
- portptr = ptr+1;
- }
- /* Note that if this didn't end with a bracket, we still advanced the
- * proxyptr first, but I can't see anything wrong with that as no host
- * name nor a numeric can legally start with a bracket.
- */
- }
-
- /* Get port number off proxy.server.com:1080 */
- prox_portno = strchr(portptr, ':');
- if (prox_portno) {
- *prox_portno = 0x0; /* cut off number from host name */
- prox_portno ++;
- /* now set the local port number */
- conn->port = atoi(prox_portno);
- }
- else if(data->set.proxyport) {
- /* None given in the proxy string, then get the default one if it is
- given */
- conn->port = data->set.proxyport;
- }
-
- /* now, clone the cleaned proxy host name */
- conn->proxy.rawalloc = strdup(proxyptr);
- conn->proxy.name = conn->proxy.rawalloc;
-
- free(proxydup); /* free the duplicate pointer and not the modified */
- proxy = NULL; /* this may have just been freed */
- if(!conn->proxy.rawalloc)
- return CURLE_OUT_OF_MEMORY;
- }
-
- /*************************************************************
- * If the protocol is using SSL and HTTP proxy is used, we set
- * the tunnel_proxy bit.
- *************************************************************/
- if((conn->protocol&PROT_SSL) && conn->bits.httpproxy)
- conn->bits.tunnel_proxy = TRUE;
-
- /*************************************************************
- * Take care of user and password authentication stuff
- *************************************************************/
-
- /*
- * Inputs: data->set.userpwd (CURLOPT_USERPWD)
- * data->set.fpasswd (CURLOPT_PASSWDFUNCTION)
- * data->set.use_netrc (CURLOPT_NETRC)
- * conn->host.name
- * netrc file
- * hard-coded defaults
- *
- * Outputs: (almost :- all currently undefined)
- * conn->bits.user_passwd - non-zero if non-default passwords exist
- * conn->user - non-zero length if defined
- * conn->passwd - ditto
- * conn->host.name - remove user name and password
- */
-
- /* At this point, we're hoping all the other special cases have
- * been taken care of, so conn->host.name is at most
- * [user[:password]]@]hostname
- *
- * We need somewhere to put the embedded details, so do that first.
- */
-
- user[0] =0; /* to make everything well-defined */
- passwd[0]=0;
-
- if (conn->protocol & (PROT_FTP|PROT_HTTP|PROT_SCP|PROT_SFTP)) {
- /* This is a FTP, HTTP, SCP or SFTP URL, we will now try to extract the
- * possible user+password pair in a string like:
- * ftp://user:password@ftp.my.site:8021/README */
- char *ptr=strchr(conn->host.name, '@');
- char *userpass = conn->host.name;
- if(ptr != NULL) {
- /* there's a user+password given here, to the left of the @ */
-
- conn->host.name = ++ptr;
-
- /* So the hostname is sane. Only bother interpreting the
- * results if we could care. It could still be wasted
- * work because it might be overtaken by the programmatically
- * set user/passwd, but doing that first adds more cases here :-(
- */
-
- if (data->set.use_netrc != CURL_NETRC_REQUIRED) {
- /* We could use the one in the URL */
-
- conn->bits.user_passwd = 1; /* enable user+password */
-
- if(*userpass != ':') {
- /* the name is given, get user+password */
- sscanf(userpass, "%" MAX_CURL_USER_LENGTH_TXT "[^:@]:"
- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]",
- user, passwd);
- }
- else
- /* no name given, get the password only */
- sscanf(userpass, ":%" MAX_CURL_PASSWORD_LENGTH_TXT "[^@]", passwd);
-
- if(user[0]) {
- char *newname=curl_easy_unescape(data, user, 0, NULL);
- if(!newname)
- return CURLE_OUT_OF_MEMORY;
- if(strlen(newname) < sizeof(user))
- strcpy(user, newname);
-
- /* if the new name is longer than accepted, then just use
- the unconverted name, it'll be wrong but what the heck */
- free(newname);
- }
- if (passwd[0]) {
- /* we have a password found in the URL, decode it! */
- char *newpasswd=curl_easy_unescape(data, passwd, 0, NULL);
- if(!newpasswd)
- return CURLE_OUT_OF_MEMORY;
- if(strlen(newpasswd) < sizeof(passwd))
- strcpy(passwd, newpasswd);
-
- free(newpasswd);
- }
- }
- }
- }
-
- /*************************************************************
- * Figure out the remote port number
- *
- * No matter if we use a proxy or not, we have to figure out the remote
- * port number of various reasons.
- *
- * To be able to detect port number flawlessly, we must not confuse them
- * IPv6-specified addresses in the [0::1] style. (RFC2732)
- *
- * The conn->host.name is currently [user:passwd@]host[:port] where host
- * could be a hostname, IPv4 address or IPv6 address.
- *************************************************************/
- if((1 == sscanf(conn->host.name, "[%*39[0-9a-fA-F:.]%c", &endbracket)) &&
- (']' == endbracket)) {
- /* this is a RFC2732-style specified IP-address */
- conn->bits.ipv6_ip = TRUE;
-
- conn->host.name++; /* pass the starting bracket */
- tmp = strchr(conn->host.name, ']');
- *tmp = 0; /* zero terminate */
- tmp++; /* pass the ending bracket */
- if(':' != *tmp)
- tmp = NULL; /* no port number available */
- }
- else
- tmp = strrchr(conn->host.name, ':');
-
- if(data->set.use_port && data->state.allow_port) {
- /* if set, we use this and ignore the port possibly given in the URL */
- conn->remote_port = (unsigned short)data->set.use_port;
- if(tmp)
- *tmp = '\0'; /* cut off the name there anyway - if there was a port
- number - since the port number is to be ignored! */
- if(conn->bits.httpproxy) {
- /* we need to create new URL with the new port number */
- char *url;
-
- url = aprintf("http://%s:%d%s", conn->host.name, conn->remote_port,
- data->reqdata.path);
- if(!url)
- return CURLE_OUT_OF_MEMORY;
-
- if(data->change.url_alloc)
- free(data->change.url);
-
- data->change.url = url;
- data->change.url_alloc = TRUE;
- }
- }
- else if (tmp) {
- /* no CURLOPT_PORT given, extract the one from the URL */
-
- char *rest;
- unsigned long port;
-
- port=strtoul(tmp+1, &rest, 10); /* Port number must be decimal */
-
- if (rest != (tmp+1) && *rest == '\0') {
- /* The colon really did have only digits after it,
- * so it is either a port number or a mistake */
-
- if (port > 0xffff) { /* Single unix standard says port numbers are
- * 16 bits long */
- failf(data, "Port number too large: %lu", port);
- return CURLE_URL_MALFORMAT;
- }
-
- *tmp = '\0'; /* cut off the name there */
- conn->remote_port = (unsigned short)port;
- }
- }
-
- /* Programmatically set password:
- * - always applies, if available
- * - takes precedence over the values we just set above
- * so scribble it over the top.
- * User-supplied passwords are assumed not to need unescaping.
- *
- * user_password is set in "inherit initial knowledge' above,
- * so it doesn't have to be set in this block
- */
- if (data->set.userpwd != NULL) {
- /* the name is given, get user+password */
- sscanf(data->set.userpwd,
- "%" MAX_CURL_USER_LENGTH_TXT "[^:]:"
- "%" MAX_CURL_PASSWORD_LENGTH_TXT "[^\n]",
- user, passwd);
- }
-
- conn->bits.netrc = FALSE;
- if (data->set.use_netrc != CURL_NETRC_IGNORED) {
- if(Curl_parsenetrc(conn->host.name,
- user, passwd,
- data->set.netrc_file)) {
- infof(data, "Couldn't find host %s in the " DOT_CHAR
- "netrc file, using defaults\n",
- conn->host.name);
- }
- else {
- /* set bits.netrc TRUE to remember that we got the name from a .netrc
- file, so that it is safe to use even if we followed a Location: to a
- different host or similar. */
- conn->bits.netrc = TRUE;
-
- conn->bits.user_passwd = 1; /* enable user+password */
- }
- }
-
- /* If our protocol needs a password and we have none, use the defaults */
- if ( (conn->protocol & PROT_FTP) &&
- !conn->bits.user_passwd) {
-
- conn->user = strdup(CURL_DEFAULT_USER);
- conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
- /* This is the default password, so DON'T set conn->bits.user_passwd */
- }
- else {
- /* store user + password, zero-length if not set */
- conn->user = strdup(user);
- conn->passwd = strdup(passwd);
- }
- if(!conn->user || !conn->passwd)
- return CURLE_OUT_OF_MEMORY;
-
- /*************************************************************
- * Check the current list of connections to see if we can
- * re-use an already existing one or if we have to create a
- * new one.
- *************************************************************/
-
- /* get a cloned copy of the SSL config situation stored in the
- connection struct */
- if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config))
- return CURLE_OUT_OF_MEMORY;
-
- /* reuse_fresh is TRUE if we are told to use a new connection by force, but
- we only acknowledge this option if this is not a re-used connection
- already (which happens due to follow-location or during a HTTP
- authentication phase). */
- if(data->set.reuse_fresh && !data->state.this_is_a_follow)
- reuse = FALSE;
- else
- reuse = ConnectionExists(data, conn, &conn_temp);
-
- if(reuse) {
- /*
- * We already have a connection for this, we got the former connection
- * in the conn_temp variable and thus we need to cleanup the one we
- * just allocated before we can move along and use the previously
- * existing one.
- */
- struct connectdata *old_conn = conn;
-
- if(old_conn->proxy.rawalloc)
- free(old_conn->proxy.rawalloc);
-
- /* free the SSL config struct from this connection struct as this was
- allocated in vain and is targeted for destruction */
- Curl_free_ssl_config(&conn->ssl_config);
-
- conn = conn_temp; /* use this connection from now on */
-
- conn->data = old_conn->data;
-
- /* get the user+password information from the old_conn struct since it may
- * be new for this request even when we re-use an existing connection */
- conn->bits.user_passwd = old_conn->bits.user_passwd;
- if (conn->bits.user_passwd) {
- /* use the new user namd and password though */
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- conn->user = old_conn->user;
- conn->passwd = old_conn->passwd;
- old_conn->user = NULL;
- old_conn->passwd = NULL;
- }
-
- conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
- if (conn->bits.proxy_user_passwd) {
- /* use the new proxy user name and proxy password though */
- Curl_safefree(conn->proxyuser);
- Curl_safefree(conn->proxypasswd);
- conn->proxyuser = old_conn->proxyuser;
- conn->proxypasswd = old_conn->proxypasswd;
- old_conn->proxyuser = NULL;
- old_conn->proxypasswd = NULL;
- }
-
- /* host can change, when doing keepalive with a proxy ! */
- if (conn->bits.httpproxy) {
- free(conn->host.rawalloc);
- conn->host=old_conn->host;
- }
-
- /* get the newly set value, not the old one */
- conn->bits.no_body = old_conn->bits.no_body;
-
- if (!conn->bits.httpproxy)
- free(old_conn->host.rawalloc); /* free the newly allocated name buffer */
-
- /* re-use init */
- conn->bits.reuse = TRUE; /* yes, we're re-using here */
- conn->bits.chunk = FALSE; /* always assume not chunked unless told
- otherwise */
-
- Curl_safefree(old_conn->user);
- Curl_safefree(old_conn->passwd);
- Curl_safefree(old_conn->proxyuser);
- Curl_safefree(old_conn->proxypasswd);
- Curl_llist_destroy(old_conn->send_pipe, NULL);
- Curl_llist_destroy(old_conn->recv_pipe, NULL);
-
- free(old_conn); /* we don't need this anymore */
-
- /*
- * If we're doing a resumed transfer, we need to setup our stuff
- * properly.
- */
- data->reqdata.resume_from = data->set.set_resume_from;
- if (data->reqdata.resume_from) {
- if (data->reqdata.rangestringalloc == TRUE)
- free(data->reqdata.range);
- data->reqdata.range = aprintf("%" FORMAT_OFF_T "-",
- data->reqdata.resume_from);
- if(!data->reqdata.range)
- return CURLE_OUT_OF_MEMORY;
-
- /* tell ourselves to fetch this range */
- data->reqdata.use_range = TRUE; /* enable range download */
- data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */
- }
- else if (data->set.set_range) {
- /* There is a range, but is not a resume, useful for random ftp access */
- data->reqdata.range = strdup(data->set.set_range);
- if(!data->reqdata.range)
- return CURLE_OUT_OF_MEMORY;
- data->reqdata.rangestringalloc = TRUE; /* mark range string allocated */
- data->reqdata.use_range = TRUE; /* enable range download */
- }
- else
- data->reqdata.use_range = FALSE; /* disable range download */
-
- *in_connect = conn; /* return this instead! */
-
- infof(data, "Re-using existing connection! (#%ld) with host %s\n",
- conn->connectindex,
- conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
- }
- else {
- /*
- * This is a brand new connection, so let's store it in the connection
- * cache of ours!
- */
- ConnectionStore(data, conn);
- }
-
- /* Continue connectdata initialization here. */
-
- /*
- *
- * Inherit the proper values from the urldata struct AFTER we have arranged
- * the persistent connection stuff */
- conn->fread = data->set.fread;
- conn->fread_in = data->set.in;
-
- if ((conn->protocol&PROT_HTTP) &&
- data->set.upload &&
- (data->set.infilesize == -1) &&
- (data->set.httpversion != CURL_HTTP_VERSION_1_0)) {
- /* HTTP, upload, unknown file size and not HTTP 1.0 */
- conn->bits.upload_chunky = TRUE;
- }
- else {
- /* else, no chunky upload */
- conn->bits.upload_chunky = FALSE;
- }
-
-#ifndef USE_ARES
- /*************************************************************
- * Set timeout if that is being used, and we're not using an asynchronous
- * name resolve.
- *************************************************************/
- if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
- /*************************************************************
- * Set signal handler to catch SIGALRM
- * Store the old value to be able to set it back later!
- *************************************************************/
-
-#ifdef SIGALRM
-#ifdef HAVE_ALARM
- long shortest;
-#endif
-#ifdef HAVE_SIGACTION
- struct sigaction sigact;
- sigaction(SIGALRM, NULL, &sigact);
- keep_sigact = sigact;
- keep_copysig = TRUE; /* yes, we have a copy */
- sigact.sa_handler = alarmfunc;
-#ifdef SA_RESTART
- /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
- sigact.sa_flags &= ~SA_RESTART;
-#endif
- /* now set the new struct */
- sigaction(SIGALRM, &sigact, NULL);
-#else /* HAVE_SIGACTION */
- /* no sigaction(), revert to the much lamer signal() */
-#ifdef HAVE_SIGNAL
- keep_sigact = signal(SIGALRM, alarmfunc);
-#endif
-#endif /* HAVE_SIGACTION */
-
- /* We set the timeout on the name resolving phase first, separately from
- * the download/upload part to allow a maximum time on everything. This is
- * a signal-based timeout, why it won't work and shouldn't be used in
- * multi-threaded environments. */
-
-#ifdef HAVE_ALARM
- shortest = data->set.timeout; /* default to this timeout value */
- if(shortest && data->set.connecttimeout &&
- (data->set.connecttimeout < shortest))
- /* if both are set, pick the shortest */
- shortest = data->set.connecttimeout;
- else if(!shortest)
- /* if timeout is not set, use the connect timeout */
- shortest = data->set.connecttimeout;
-
- /* alarm() makes a signal get sent when the timeout fires off, and that
- will abort system calls */
- prev_alarm = alarm((unsigned int) shortest);
- /* We can expect the conn->created time to be "now", as that was just
- recently set in the beginning of this function and nothing slow
- has been done since then until now. */
-#endif
-#endif /* SIGALRM */
- }
-#endif /* USE_ARES */
-
- /*************************************************************
- * Resolve the name of the server or proxy
- *************************************************************/
- if(conn->bits.reuse) {
- /* re-used connection, no resolving is necessary */
- hostaddr = NULL;
- /* we'll need to clear conn->dns_entry later in Curl_disconnect() */
-
- if (conn->bits.httpproxy)
- fix_hostname(data, conn, &conn->host);
- }
- else {
- /* this is a fresh connect */
-
- /* set a pointer to the hostname we display */
- fix_hostname(data, conn, &conn->host);
-
- if(!conn->proxy.name || !*conn->proxy.name) {
- /* If not connecting via a proxy, extract the port from the URL, if it is
- * there, thus overriding any defaults that might have been set above. */
- conn->port = conn->remote_port; /* it is the same port */
-
- /* Resolve target host right on */
- rc = Curl_resolv(conn, conn->host.name, (int)conn->port, &hostaddr);
- if(rc == CURLRESOLV_PENDING)
- *async = TRUE;
-
- else if(!hostaddr) {
- failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
- result = CURLE_COULDNT_RESOLVE_HOST;
- /* don't return yet, we need to clean up the timeout first */
- }
- }
- else {
- /* This is a proxy that hasn't been resolved yet. */
-
- /* IDN-fix the proxy name */
- fix_hostname(data, conn, &conn->proxy);
-
- /* resolve proxy */
- rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &hostaddr);
-
- if(rc == CURLRESOLV_PENDING)
- *async = TRUE;
-
- else if(!hostaddr) {
- failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
- result = CURLE_COULDNT_RESOLVE_PROXY;
- /* don't return yet, we need to clean up the timeout first */
- }
- }
- }
- *addr = hostaddr;
-
-#if defined(HAVE_ALARM) && defined(SIGALRM) && !defined(USE_ARES)
- if((data->set.timeout || data->set.connecttimeout) && !data->set.no_signal) {
-#ifdef HAVE_SIGACTION
- if(keep_copysig) {
- /* we got a struct as it looked before, now put that one back nice
- and clean */
- sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
- }
-#else
-#ifdef HAVE_SIGNAL
- /* restore the previous SIGALRM handler */
- signal(SIGALRM, keep_sigact);
-#endif
-#endif /* HAVE_SIGACTION */
-
- /* switch back the alarm() to either zero or to what it was before minus
- the time we spent until now! */
- if(prev_alarm) {
- /* there was an alarm() set before us, now put it back */
- unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
- unsigned long alarm_set;
-
- /* the alarm period is counted in even number of seconds */
- alarm_set = prev_alarm - elapsed_ms/1000;
-
- if(!alarm_set ||
- ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
- /* if the alarm time-left reached zero or turned "negative" (counted
- with unsigned values), we should fire off a SIGALRM here, but we
- won't, and zero would be to switch it off so we never set it to
- less than 1! */
- alarm(1);
- result = CURLE_OPERATION_TIMEOUTED;
- failf(data, "Previous alarm fired off!");
- }
- else
- alarm((unsigned int)alarm_set);
- }
- else
- alarm(0); /* just shut it off */
- }
-#endif
-
- return result;
-}
-
-/* SetupConnection() is called after the name resolve initiated in
- * CreateConnection() is all done.
- *
- * NOTE: the argument 'hostaddr' is NULL when this function is called for a
- * re-used connection.
- *
- * conn->data MUST already have been setup fine (in CreateConnection)
- */
-
-static CURLcode SetupConnection(struct connectdata *conn,
- struct Curl_dns_entry *hostaddr,
- bool *protocol_done)
-{
- CURLcode result=CURLE_OK;
- struct SessionHandle *data = conn->data;
-
- Curl_pgrsTime(data, TIMER_NAMELOOKUP);
-
- if(conn->protocol & PROT_FILE) {
- /* There's nothing in this function to setup if we're only doing
- a file:// transfer */
- *protocol_done = TRUE;
- return result;
- }
- *protocol_done = FALSE; /* default to not done */
-
- /*************************************************************
- * Send user-agent to HTTP proxies even if the target protocol
- * isn't HTTP.
- *************************************************************/
- if((conn->protocol&PROT_HTTP) || conn->bits.httpproxy) {
- if(data->set.useragent) {
- Curl_safefree(conn->allocptr.uagent);
- conn->allocptr.uagent =
- aprintf("User-Agent: %s\r\n", data->set.useragent);
- if(!conn->allocptr.uagent)
- return CURLE_OUT_OF_MEMORY;
- }
- }
-
- conn->headerbytecount = 0;
-
-#ifdef CURL_DO_LINEEND_CONV
- data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
-#endif /* CURL_DO_LINEEND_CONV */
-
- for(;;) {
- /* loop for CURL_SERVER_CLOSED_CONNECTION */
-
- if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
- bool connected = FALSE;
-
- /* Connect only if not already connected! */
- result = ConnectPlease(data, conn, hostaddr, &connected);
-
- if(connected) {
- result = Curl_protocol_connect(conn, protocol_done);
- if(CURLE_OK == result)
- conn->bits.tcpconnect = TRUE;
- }
- else
- conn->bits.tcpconnect = FALSE;
-
- /* if the connection was closed by the server while exchanging
- authentication information, retry with the new set
- authentication information */
- if(conn->bits.proxy_connect_closed) {
- /* reset the error buffer */
- if (data->set.errorbuffer)
- data->set.errorbuffer[0] = '\0';
- data->state.errorbuf = FALSE;
- continue;
- }
-
- if(CURLE_OK != result)
- return result;
- }
- else {
- Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- conn->bits.tcpconnect = TRUE;
- *protocol_done = TRUE;
- if(data->set.verbose)
- verboseconnect(conn);
- }
- /* Stop the loop now */
- break;
- }
-
- conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
- set this here perhaps a second time */
-
-#ifdef __EMX__
- /* 20000330 mgs
- * the check is quite a hack...
- * we're calling _fsetmode to fix the problem with fwrite converting newline
- * characters (you get mangled text files, and corrupted binary files when
- * you download to stdout and redirect it to a file). */
-
- if ((data->set.out)->_handle == NULL) {
- _fsetmode(stdout, "b");
- }
-#endif
-
- return CURLE_OK;
-}
-
-CURLcode Curl_connect(struct SessionHandle *data,
- struct connectdata **in_connect,
- bool *asyncp,
- bool *protocol_done)
-{
- CURLcode code;
- struct Curl_dns_entry *dns;
-
- *asyncp = FALSE; /* assume synchronous resolves by default */
-
- /* call the stuff that needs to be called */
- code = CreateConnection(data, in_connect, &dns, asyncp);
-
- if(CURLE_OK == code) {
- /* no error */
- if(dns || !*asyncp)
- /* If an address is available it means that we already have the name
- resolved, OR it isn't async. if this is a re-used connection 'dns'
- will be NULL here. Continue connecting from here */
- code = SetupConnection(*in_connect, dns, protocol_done);
- /* else
- response will be received and treated async wise */
- }
-
- if(CURLE_OK != code) {
- /* We're not allowed to return failure with memory left allocated
- in the connectdata struct, free those here */
- if(*in_connect) {
- Curl_disconnect(*in_connect); /* close the connection */
- *in_connect = NULL; /* return a NULL */
- }
- }
- else {
- if ((*in_connect)->is_in_pipeline)
- data->state.is_in_pipeline = TRUE;
- }
-
- return code;
-}
-
-/* Call this function after Curl_connect() has returned async=TRUE and
- then a successful name resolve has been received.
-
- Note: this function disconnects and frees the conn data in case of
- resolve failure */
-CURLcode Curl_async_resolved(struct connectdata *conn,
- bool *protocol_done)
-{
-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
- defined(USE_THREADING_GETADDRINFO)
- CURLcode code = SetupConnection(conn, conn->async.dns, protocol_done);
-
- if(code)
- /* We're not allowed to return failure with memory left allocated
- in the connectdata struct, free those here */
- Curl_disconnect(conn); /* close the connection */
-
- return code;
-#else
- (void)conn;
- (void)protocol_done;
- return CURLE_OK;
-#endif
-}
-
-
-CURLcode Curl_done(struct connectdata **connp,
- CURLcode status, bool premature) /* an error if this is called after an
- error was detected */
-{
- CURLcode result;
- struct connectdata *conn = *connp;
- struct SessionHandle *data = conn->data;
-
- Curl_expire(data, 0); /* stop timer */
-
- if(conn->bits.done)
- return CURLE_OK; /* Curl_done() has already been called */
-
- conn->bits.done = TRUE; /* called just now! */
-
- if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
- conn->readchannel_inuse)
- conn->readchannel_inuse = FALSE;
- if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
- conn->writechannel_inuse)
- conn->writechannel_inuse = FALSE;
-
- /* cleanups done even if the connection is re-used */
- if(data->reqdata.rangestringalloc) {
- free(data->reqdata.range);
- data->reqdata.rangestringalloc = FALSE;
- }
-
- /* Cleanup possible redirect junk */
- if(data->reqdata.newurl) {
- free(data->reqdata.newurl);
- data->reqdata.newurl = NULL;
- }
-
- if(conn->dns_entry) {
- Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
- conn->dns_entry = NULL;
- }
-
- /* this calls the protocol-specific function pointer previously set */
- if(conn->curl_done)
- result = conn->curl_done(conn, status, premature);
- else
- result = CURLE_OK;
-
- Curl_pgrsDone(conn); /* done with the operation */
-
- /* for ares-using, make sure all possible outstanding requests are properly
- cancelled before we proceed */
- ares_cancel(data->state.areschannel);
-
- /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
- forced us to close this no matter what we think.
-
- if conn->bits.close is TRUE, it means that the connection should be
- closed in spite of all our efforts to be nice, due to protocol
- restrictions in our or the server's end */
- if(data->set.reuse_forbid || conn->bits.close) {
- CURLcode res2 = Curl_disconnect(conn); /* close the connection */
-
- *connp = NULL; /* to make the caller of this function better detect that
- this was actually killed here */
-
- /* If we had an error already, make sure we return that one. But
- if we got a new error, return that. */
- if(!result && res2)
- result = res2;
- }
- else {
- ConnectionDone(conn); /* the connection is no longer in use */
-
- /* remember the most recently used connection */
- data->state.lastconnect = conn->connectindex;
-
- infof(data, "Connection #%ld to host %s left intact\n",
- conn->connectindex,
- conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
- }
-
- return result;
-}
-
-CURLcode Curl_do(struct connectdata **connp, bool *done)
-{
- CURLcode result=CURLE_OK;
- struct connectdata *conn = *connp;
- struct SessionHandle *data = conn->data;
-
- conn->bits.done = FALSE; /* Curl_done() is not called yet */
- conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
-
- if(conn->curl_do) {
- /* generic protocol-specific function pointer set in curl_connect() */
- result = conn->curl_do(conn, done);
-
- /* This was formerly done in transfer.c, but we better do it here */
-
- if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
- /* This was a re-use of a connection and we got a write error in the
- * DO-phase. Then we DISCONNECT this connection and have another attempt
- * to CONNECT and then DO again! The retry cannot possibly find another
- * connection to re-use, since we only keep one possible connection for
- * each. */
-
- infof(data, "Re-used connection seems dead, get a new one\n");
-
- conn->bits.close = TRUE; /* enforce close of this connection */
- result = Curl_done(&conn, result, FALSE); /* we are so done with this */
-
- /* conn may no longer be a good pointer */
-
- /*
- * According to bug report #1330310. We need to check for
- * CURLE_SEND_ERROR here as well. I figure this could happen when the
- * request failed on a FTP connection and thus Curl_done() itself tried
- * to use the connection (again). Slight Lack of feedback in the report,
- * but I don't think this extra check can do much harm.
- */
- if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
- bool async;
- bool protocol_done = TRUE;
-
- /* Now, redo the connect and get a new connection */
- result = Curl_connect(data, connp, &async, &protocol_done);
- if(CURLE_OK == result) {
- /* We have connected or sent away a name resolve query fine */
-
- conn = *connp; /* setup conn to again point to something nice */
- if(async) {
- /* Now, if async is TRUE here, we need to wait for the name
- to resolve */
- result = Curl_wait_for_resolv(conn, NULL);
- if(result)
- return result;
-
- /* Resolved, continue with the connection */
- result = Curl_async_resolved(conn, &protocol_done);
- if(result)
- return result;
- }
-
- /* ... finally back to actually retry the DO phase */
- result = conn->curl_do(conn, done);
- }
- }
- }
- }
- return result;
-}
-
-CURLcode Curl_do_more(struct connectdata *conn)
-{
- CURLcode result=CURLE_OK;
-
- if(conn->curl_do_more)
- result = conn->curl_do_more(conn);
-
- return result;
-}
diff --git a/Utilities/cmcurl/url.h b/Utilities/cmcurl/url.h
deleted file mode 100644
index 446b3d91a..000000000
--- a/Utilities/cmcurl/url.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#ifndef __URL_H
-#define __URL_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include <stdarg.h> /* to make sure we have ap_list */
-
-/*
- * Prototypes for library-wide functions provided by url.c
- */
-
-CURLcode Curl_open(struct SessionHandle **curl);
-CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
- va_list arg);
-CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
- bool *async, bool *protocol_connect);
-CURLcode Curl_async_resolved(struct connectdata *conn,
- bool *protocol_connect);
-CURLcode Curl_do(struct connectdata **, bool *done);
-CURLcode Curl_do_more(struct connectdata *);
-CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
-CURLcode Curl_disconnect(struct connectdata *);
-CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
-CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
-CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
-void Curl_safefree(void *ptr);
-
-/* create a connection cache */
-struct conncache *Curl_mk_connc(int type, int amount);
-/* free a connection cache */
-void Curl_rm_connc(struct conncache *c);
-/* Change number of entries of a connection cache */
-CURLcode Curl_ch_connc(struct SessionHandle *data,
- struct conncache *c,
- long newamount);
-
-int Curl_protocol_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-int Curl_doing_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-
-void Curl_addHandleToPipeline(struct SessionHandle *handle,
- struct curl_llist *pipe);
-int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
- struct curl_llist *pipe);
-bool Curl_isHandleAtHead(struct SessionHandle *handle,
- struct curl_llist *pipe);
-
-void Curl_close_connections(struct SessionHandle *data);
-
-#if 0
-CURLcode Curl_protocol_fdset(struct connectdata *conn,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- int *max_fdp);
-CURLcode Curl_doing_fdset(struct connectdata *conn,
- fd_set *read_fd_set,
- fd_set *write_fd_set,
- int *max_fdp);
-#endif
-
-#endif
diff --git a/Utilities/cmcurl/urldata.h b/Utilities/cmcurl/urldata.h
deleted file mode 100644
index 46d956d1a..000000000
--- a/Utilities/cmcurl/urldata.h
+++ /dev/null
@@ -1,1340 +0,0 @@
-#ifndef __URLDATA_H
-#define __URLDATA_H
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-/* This file is for lib internal stuff */
-
-#include "setup.h"
-
-#define PORT_FTP 21
-#define PORT_FTPS 990
-#define PORT_TELNET 23
-#define PORT_HTTP 80
-#define PORT_HTTPS 443
-#define PORT_DICT 2628
-#define PORT_LDAP 389
-#define PORT_TFTP 69
-#define PORT_SSH 22
-
-#define DICT_MATCH "/MATCH:"
-#define DICT_MATCH2 "/M:"
-#define DICT_MATCH3 "/FIND:"
-#define DICT_DEFINE "/DEFINE:"
-#define DICT_DEFINE2 "/D:"
-#define DICT_DEFINE3 "/LOOKUP:"
-
-#define CURL_DEFAULT_USER "anonymous"
-#define CURL_DEFAULT_PASSWORD "curl_by_daniel@haxx.se"
-
-#include "cookie.h"
-#include "formdata.h"
-
-#ifdef USE_SSLEAY
-#ifdef USE_OPENSSL
-#include "openssl/rsa.h"
-#include "openssl/crypto.h"
-#include "openssl/x509.h"
-#include "openssl/pem.h"
-#include "openssl/ssl.h"
-#include "openssl/err.h"
-#ifdef HAVE_OPENSSL_ENGINE_H
-#include <openssl/engine.h>
-#endif
-#ifdef HAVE_OPENSSL_PKCS12_H
-#include <openssl/pkcs12.h>
-#endif
-#else /* SSLeay-style includes */
-#include "rsa.h"
-#include "crypto.h"
-#include "x509.h"
-#include "pem.h"
-#include "ssl.h"
-#include "err.h"
-#endif /* USE_OPENSSL */
-#endif /* USE_SSLEAY */
-
-#ifdef USE_GNUTLS
-#include <gnutls/gnutls.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
-#include "timeval.h"
-
-#ifdef HAVE_ZLIB_H
-#include <zlib.h> /* for content-encoding */
-#endif
-
-#ifdef USE_ARES
-#include <ares.h>
-#endif
-
-#include <curl/curl.h>
-
-#include "http_chunks.h" /* for the structs and enum stuff */
-#include "hostip.h"
-#include "hash.h"
-#include "splay.h"
-
-#ifdef HAVE_GSSAPI
-# ifdef HAVE_GSSGNU
-# include <gss.h>
-# elif defined HAVE_GSSMIT
-# include <gssapi/gssapi.h>
-# include <gssapi/gssapi_generic.h>
-# else
-# include <gssapi.h>
-# endif
-#endif
-
-#ifdef HAVE_LIBSSH2_H
-#include <libssh2.h>
-#include <libssh2_sftp.h>
-#endif /* HAVE_LIBSSH2_H */
-
-/* Download buffer size, keep it fairly big for speed reasons */
-#undef BUFSIZE
-#define BUFSIZE CURL_MAX_WRITE_SIZE
-
-/* Initial size of the buffer to store headers in, it'll be enlarged in case
- of need. */
-#define HEADERSIZE 256
-
-#define CURLEASY_MAGIC_NUMBER 0xc0dedbad
-
-/* Just a convenience macro to get the larger value out of two given.
- We prefix with CURL to prevent name collisions. */
-#define CURLMAX(x,y) ((x)>(y)?(x):(y))
-
-#ifdef HAVE_KRB4
-/* Types needed for krb4-ftp connections */
-struct krb4buffer {
- void *data;
- size_t size;
- size_t index;
- int eof_flag;
-};
-enum protection_level {
- prot_clear,
- prot_safe,
- prot_confidential,
- prot_private
-};
-#endif
-
-/* enum for the nonblocking SSL connection state machine */
-typedef enum {
- ssl_connect_1,
- ssl_connect_2,
- ssl_connect_2_reading,
- ssl_connect_2_writing,
- ssl_connect_3,
- ssl_connect_done
-} ssl_connect_state;
-
-/* struct for data related to each SSL connection */
-struct ssl_connect_data {
- bool use; /* use ssl encrypted communications TRUE/FALSE */
-#ifdef USE_SSLEAY
- /* these ones requires specific SSL-types */
- SSL_CTX* ctx;
- SSL* handle;
- X509* server_cert;
- ssl_connect_state connecting_state;
-#endif /* USE_SSLEAY */
-#ifdef USE_GNUTLS
- gnutls_session session;
- gnutls_certificate_credentials cred;
-#endif /* USE_GNUTLS */
-};
-
-struct ssl_config_data {
- long version; /* what version the client wants to use */
- long certverifyresult; /* result from the certificate verification */
- long verifypeer; /* set TRUE if this is desired */
- long verifyhost; /* 0: no verify
- 1: check that CN exists
- 2: CN must match hostname */
- char *CApath; /* DOES NOT WORK ON WINDOWS */
- char *CAfile; /* cerficate to verify peer against */
- char *random_file; /* path to file containing "random" data */
- char *egdsocket; /* path to file containing the EGD daemon socket */
- char *cipher_list; /* list of ciphers to use */
- long numsessions; /* SSL session id cache size */
- curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
- void *fsslctxp; /* parameter for call back */
- bool sessionid; /* cache session IDs or not */
-};
-
-/* information stored about one single SSL session */
-struct curl_ssl_session {
- char *name; /* host name for which this ID was used */
- void *sessionid; /* as returned from the SSL layer */
- size_t idsize; /* if known, otherwise 0 */
- long age; /* just a number, the higher the more recent */
- unsigned short remote_port; /* remote port to connect to */
- struct ssl_config_data ssl_config; /* setup for this session */
-};
-
-/* Struct used for Digest challenge-response authentication */
-struct digestdata {
- char *nonce;
- char *cnonce;
- char *realm;
- int algo;
- bool stale; /* set true for re-negotiation */
- char *opaque;
- char *qop;
- char *algorithm;
- int nc; /* nounce count */
-};
-
-typedef enum {
- NTLMSTATE_NONE,
- NTLMSTATE_TYPE1,
- NTLMSTATE_TYPE2,
- NTLMSTATE_TYPE3,
- NTLMSTATE_LAST
-} curlntlm;
-
-#ifdef USE_WINDOWS_SSPI
-/* When including these headers, you must define either SECURITY_WIN32
- * or SECURITY_KERNEL, indicating who is compiling the code.
- */
-#define SECURITY_WIN32 1
-#include <security.h>
-#include <sspi.h>
-#include <rpc.h>
-#endif
-
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
-#include <iconv.h>
-#endif
-
-/* Struct used for NTLM challenge-response authentication */
-struct ntlmdata {
- curlntlm state;
-#ifdef USE_WINDOWS_SSPI
- CredHandle handle;
- CtxtHandle c_handle;
- SEC_WINNT_AUTH_IDENTITY identity;
- SEC_WINNT_AUTH_IDENTITY *p_identity;
- int has_handles;
- void *type_2;
- int n_type_2;
-#else
- unsigned int flags;
- unsigned char nonce[8];
-#endif
-};
-
-#ifdef HAVE_GSSAPI
-struct negotiatedata {
- bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */
- const char* protocol; /* "GSS-Negotiate" or "Negotiate" */
- OM_uint32 status;
- gss_ctx_id_t context;
- gss_name_t server_name;
- gss_buffer_desc output_token;
-};
-#endif
-
-/****************************************************************************
- * HTTP unique setup
- ***************************************************************************/
-struct HTTP {
- struct FormData *sendit;
- curl_off_t postsize; /* off_t to handle large file sizes */
- char *postdata;
-
- const char *p_pragma; /* Pragma: string */
- const char *p_accept; /* Accept: string */
- curl_off_t readbytecount;
- curl_off_t writebytecount;
-
- /* For FORM posting */
- struct Form form;
- struct Curl_chunker chunk;
-
- struct back {
- curl_read_callback fread; /* backup storage for fread pointer */
- void *fread_in; /* backup storage for fread_in pointer */
- char *postdata;
- curl_off_t postsize;
- } backup;
-
- enum {
- HTTPSEND_NADA, /* init */
- HTTPSEND_REQUEST, /* sending a request */
- HTTPSEND_BODY, /* sending body */
- HTTPSEND_LAST /* never use this */
- } sending;
-
- void *send_buffer; /* used if the request couldn't be sent in one chunk,
- points to an allocated send_buffer struct */
-};
-
-/****************************************************************************
- * FTP unique setup
- ***************************************************************************/
-typedef enum {
- FTP_STOP, /* do nothing state, stops the state machine */
- FTP_WAIT220, /* waiting for the initial 220 response immediately after
- a connect */
- FTP_AUTH,
- FTP_USER,
- FTP_PASS,
- FTP_ACCT,
- FTP_PBSZ,
- FTP_PROT,
- FTP_CCC,
- FTP_PWD,
- FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
- FTP_RETR_PREQUOTE,
- FTP_STOR_PREQUOTE,
- FTP_POSTQUOTE,
- FTP_CWD, /* change dir */
- FTP_MKD, /* if the dir didn't exist */
- FTP_MDTM, /* to figure out the datestamp */
- FTP_TYPE, /* to set type when doing a head-like request */
- FTP_LIST_TYPE, /* set type when about to do a dir list */
- FTP_RETR_TYPE, /* set type when about to RETR a file */
- FTP_STOR_TYPE, /* set type when about to STOR a file */
- FTP_SIZE, /* get the remote file's size for head-like request */
- FTP_RETR_SIZE, /* get the remote file's size for RETR */
- FTP_STOR_SIZE, /* get the size for (resumed) STOR */
- FTP_REST, /* when used to check if the server supports it in head-like */
- FTP_RETR_REST, /* when asking for "resume" in for RETR */
- FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
- FTP_PASV, /* generic state for PASV and EPSV, check count1 */
- FTP_LIST, /* generic state for LIST, NLST or a custom list command */
- FTP_RETR,
- FTP_STOR, /* generic state for STOR and APPE */
- FTP_QUIT,
- FTP_LAST /* never used */
-} ftpstate;
-
-typedef enum {
- FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */
- FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */
- FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the file */
-} curl_ftpfile;
-
-/* This FTP struct is used in the SessionHandle. All FTP data that is
- connection-oriented must be in FTP_conn to properly deal with the fact that
- perhaps the SessionHandle is changed between the times the connection is
- used. */
-struct FTP {
- curl_off_t *bytecountp;
- char *user; /* user name string */
- char *passwd; /* password string */
- char *urlpath; /* the originally given path part of the URL */
- char *file; /* decoded file */
- bool no_transfer; /* nothing was transfered, (possibly because a resumed
- transfer already was complete) */
- curl_off_t downloadsize;
-};
-
-/* ftp_conn is used for striuct connection-oriented data in the connectdata
- struct */
-struct ftp_conn {
- char *entrypath; /* the PWD reply when we logged on */
- char **dirs; /* realloc()ed array for path components */
- int dirdepth; /* number of entries used in the 'dirs' array */
- int diralloc; /* number of entries allocated for the 'dirs' array */
- char *cache; /* data cache between getresponse()-calls */
- curl_off_t cache_size; /* size of cache in bytes */
- bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
- file size and 226/250 status check. It should still
- read the line, just ignore the result. */
- long response_time; /* When no timeout is given, this is the amount of
- seconds we await for an FTP response. Initialized
- in Curl_ftp_connect() */
- bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If
- the connection has timed out or been closed, this
- should be FALSE when it gets to Curl_ftp_quit() */
- bool cwddone; /* if it has been determined that the proper CWD combo
- already has been done */
- bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent
- caching the current directory */
- char *prevpath; /* conn->path from the previous transfer */
- char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
- and others (A/I or zero) */
- size_t nread_resp; /* number of bytes currently read of a server response */
- char *linestart_resp; /* line start pointer for the FTP server response
- reader function */
-
- int count1; /* general purpose counter for the state machine */
- int count2; /* general purpose counter for the state machine */
- int count3; /* general purpose counter for the state machine */
- char *sendthis; /* allocated pointer to a buffer that is to be sent to the
- ftp server */
- size_t sendleft; /* number of bytes left to send from the sendthis buffer */
- size_t sendsize; /* total size of the sendthis buffer */
- struct timeval response; /* set to Curl_tvnow() when a command has been sent
- off, used to time-out response reading */
- ftpstate state; /* always use ftp.c:state() to change state! */
-};
-
-struct SSHPROTO {
- curl_off_t *bytecountp;
- char *user;
- char *passwd;
- char *path; /* the path we operate on */
- char *homedir;
- char *errorstr;
-#ifdef USE_LIBSSH2
- LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
- LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
- LIBSSH2_SFTP *sftp_session; /* SFTP handle */
- LIBSSH2_SFTP_HANDLE *sftp_handle;
-#endif /* USE_LIBSSH2 */
-};
-
-
-/****************************************************************************
- * FILE unique setup
- ***************************************************************************/
-struct FILEPROTO {
- char *path; /* the path we operate on */
- char *freepath; /* pointer to the allocated block we must free, this might
- differ from the 'path' pointer */
- int fd; /* open file descriptor to read from! */
-};
-
-/*
- * Boolean values that concerns this connection.
- */
-struct ConnectBits {
- bool close; /* if set, we close the connection after this request */
- bool reuse; /* if set, this is a re-used connection */
- bool chunk; /* if set, this is a chunked transfer-encoding */
- bool httpproxy; /* if set, this transfer is done through a http proxy */
- bool user_passwd; /* do we use user+password for this connection? */
- bool proxy_user_passwd; /* user+password for the proxy? */
- bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6
- IP address */
- bool ipv6; /* we communicate with a site using an IPv6 address */
-
- bool do_more; /* this is set TRUE if the ->curl_do_more() function is
- supposed to be called, after ->curl_do() */
-
- bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
- on upload */
- bool getheader; /* TRUE if header parsing is wanted */
-
- bool forbidchunk; /* used only to explicitly forbid chunk-upload for
- specific upload buffers. See readmoredata() in
- http.c for details. */
-
- bool tcpconnect; /* the TCP layer (or simimlar) is connected, this is set
- the first time on the first connect function call */
- bool protoconnstart;/* the protocol layer has STARTED its operation after
- the TCP layer connect */
-
- bool retry; /* this connection is about to get closed and then
- re-attempted at another connection. */
- bool no_body; /* CURLOPT_NO_BODY (or similar) was set */
- bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy.
- This is implicit when SSL-protocols are used through
- proxies, but can also be enabled explicitly by
- apps */
- bool authneg; /* TRUE when the auth phase has started, which means
- that we are creating a request with an auth header,
- but it is not the final request in the auth
- negotiation. */
- bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
- though it will be discarded. When the whole send
- operation is done, we must call the data rewind
- callback. */
- bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
- EPSV doesn't work we disable it for the forthcoming
- requests */
-
- bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
- EPRT doesn't work we disable it for the forthcoming
- requests */
- bool netrc; /* name+password provided by netrc */
-
- bool trailerHdrPresent; /* Set when Trailer: header found in HTTP response.
- Required to determine whether to look for trailers
- in case of Transfer-Encoding: chunking */
- bool done; /* set to FALSE when Curl_do() is called and set to TRUE
- when Curl_done() is called, to prevent Curl_done() to
- get invoked twice when the multi interface is
- used. */
- bool stream_was_rewound; /* Indicates that the stream was rewound after a
- request read past the end of its response byte
- boundary */
- bool proxy_connect_closed; /* set true if a proxy disconnected the
- connection in a CONNECT request with auth, so
- that libcurl should reconnect and continue. */
-};
-
-struct hostname {
- char *rawalloc; /* allocated "raw" version of the name */
- char *encalloc; /* allocated IDN-encoded version of the name */
- char *name; /* name to use internally, might be encoded, might be raw */
- char *dispname; /* name to display, as 'name' might be encoded */
-};
-
-/*
- * Flags on the keepon member of the Curl_transfer_keeper
- */
-
-#define KEEP_NONE 0
-#define KEEP_READ 1 /* there is or may be data to read */
-#define KEEP_WRITE 2 /* there is or may be data to write */
-#define KEEP_READ_HOLD 4 /* when set, no reading should be done but there
- might still be data to read */
-#define KEEP_WRITE_HOLD 8 /* when set, no writing should be done but there
- might still be data to write */
-
-/*
- * This struct is all the previously local variables from Curl_perform() moved
- * to struct to allow the function to return and get re-invoked better without
- * losing state.
- */
-
-struct Curl_transfer_keeper {
-
- /** Values copied over from the HandleData struct each time on init **/
-
- curl_off_t size; /* -1 if unknown at this point */
- curl_off_t *bytecountp; /* return number of bytes read or NULL */
-
- curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0
- means unlimited */
- curl_off_t *writebytecountp; /* return number of bytes written or NULL */
-
- /** End of HandleData struct copies **/
-
- curl_off_t bytecount; /* total number of bytes read */
- curl_off_t writebytecount; /* number of bytes written */
-
- struct timeval start; /* transfer started at this time */
- struct timeval now; /* current time */
- bool header; /* incoming data has HTTP header */
- enum {
- HEADER_NORMAL, /* no bad header at all */
- HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
- is normal data */
- HEADER_ALLBAD /* all was believed to be header */
- } badheader; /* the header was deemed bad and will be
- written as body */
- int headerline; /* counts header lines to better track the
- first one */
- char *hbufp; /* points at *end* of header line */
- size_t hbuflen;
- char *str; /* within buf */
- char *str_start; /* within buf */
- char *end_ptr; /* within buf */
- char *p; /* within headerbuff */
- bool content_range; /* set TRUE if Content-Range: was found */
- curl_off_t offset; /* possible resume offset read from the
- Content-Range: header */
- int httpcode; /* error code from the 'HTTP/1.? XXX' line */
- int httpversion; /* the HTTP version*10 */
- struct timeval start100; /* time stamp to wait for the 100 code from */
- bool write_after_100_header; /* TRUE = we enable the write after we
- received a 100-continue/timeout or
- FALSE = directly */
- bool wait100_after_headers; /* TRUE = after the request-headers have been
- sent off properly, we go into the wait100
- state, FALSE = don't */
- int content_encoding; /* What content encoding. sec 3.5, RFC2616. */
-
-#define IDENTITY 0 /* No encoding */
-#define DEFLATE 1 /* zlib delfate [RFC 1950 & 1951] */
-#define GZIP 2 /* gzip algorithm [RFC 1952] */
-#define COMPRESS 3 /* Not handled, added for completeness */
-
-#ifdef HAVE_LIBZ
- bool zlib_init; /* True if zlib already initialized;
- undefined if Content-Encoding header. */
- z_stream z; /* State structure for zlib. */
-#endif
-
- time_t timeofdoc;
- long bodywrites;
-
- char *buf;
- char *uploadbuf;
- curl_socket_t maxfd;
-
- int keepon;
-
- bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
- and we're uploading the last chunk */
-
- bool ignorebody; /* we read a response-body but we ignore it! */
- bool ignorecl; /* This HTTP response has no body so we ignore the Content-
- Length: header */
-};
-
-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
- defined(USE_THREADING_GETADDRINFO)
-struct Curl_async {
- char *hostname;
- int port;
- struct Curl_dns_entry *dns;
- bool done; /* set TRUE when the lookup is complete */
- int status; /* if done is TRUE, this is the status from the callback */
- void *os_specific; /* 'struct thread_data' for Windows */
-};
-#endif
-
-#define FIRSTSOCKET 0
-#define SECONDARYSOCKET 1
-
-/* These function pointer types are here only to allow easier typecasting
- within the source when we need to cast between data pointers (such as NULL)
- and function pointers. */
-typedef CURLcode (*Curl_do_more_func)(struct connectdata *);
-typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
-
-
-/*
- * Store's request specific data in the easy handle (SessionHandle).
- * Previously, these members were on the connectdata struct but since
- * a conn struct may now be shared between different SessionHandles,
- * we store connection-specific data here.
- *
- */
-struct HandleData {
- char *pathbuffer;/* allocated buffer to store the URL's path part in */
- char *path; /* path to use, points to somewhere within the pathbuffer
- area */
-
- char *newurl; /* This can only be set if a Location: was in the
- document headers */
-
- /* This struct is inited when needed */
- struct Curl_transfer_keeper keep;
-
- /* 'upload_present' is used to keep a byte counter of how much data there is
- still left in the buffer, aimed for upload. */
- ssize_t upload_present;
-
- /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
- buffer, so the next read should read from where this pointer points to,
- and the 'upload_present' contains the number of bytes available at this
- position */
- char *upload_fromhere;
-
- curl_off_t size; /* -1 if unknown at this point */
- curl_off_t *bytecountp; /* return number of bytes read or NULL */
-
- curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch, 0
- means unlimited */
- curl_off_t *writebytecountp; /* return number of bytes written or NULL */
-
- bool use_range;
- bool rangestringalloc; /* the range string is malloc()'ed */
-
- char *range; /* range, if used. See README for detailed specification on
- this syntax. */
- curl_off_t resume_from; /* continue [ftp] transfer from here */
-
- /* Protocol specific data */
-
- union {
- struct HTTP *http;
- struct HTTP *https; /* alias, just for the sake of being more readable */
- struct FTP *ftp;
- void *tftp; /* private for tftp.c-eyes only */
- struct FILEPROTO *file;
- void *telnet; /* private for telnet.c-eyes only */
- void *generic;
- struct SSHPROTO *ssh;
- } proto;
-};
-
-/*
- * The connectdata struct contains all fields and variables that should be
- * unique for an entire connection.
- */
-struct connectdata {
- /* 'data' is the CURRENT SessionHandle using this connection -- take great
- caution that this might very well vary between different times this
- connection is used! */
- struct SessionHandle *data;
-
- bool inuse; /* This is a marker for the connection cache logic. If this is
- TRUE this handle is being used by an easy handle and cannot
- be used by any other easy handle without careful
- consideration (== only for pipelining). */
-
- /**** Fields set when inited and not modified again */
- long connectindex; /* what index in the connection cache connects index this
- particular struct has */
- long protocol; /* PROT_* flags concerning the protocol set */
-#define PROT_MISSING (1<<0)
-#define PROT_HTTP (1<<2)
-#define PROT_HTTPS (1<<3)
-#define PROT_FTP (1<<4)
-#define PROT_TELNET (1<<5)
-#define PROT_DICT (1<<6)
-#define PROT_LDAP (1<<7)
-#define PROT_FILE (1<<8)
-#define PROT_FTPS (1<<9)
-#define PROT_SSL (1<<10) /* protocol requires SSL */
-#define PROT_TFTP (1<<11)
-#define PROT_SCP (1<<12)
-#define PROT_SFTP (1<<13)
-
-#define PROT_CLOSEACTION PROT_FTP /* these ones need action before socket
- close */
-
- /* 'dns_entry' is the particular host we use. This points to an entry in the
- DNS cache and it will not get pruned while locked. It gets unlocked in
- Curl_done(). This entry will be NULL if the connection is re-used as then
- there is no name resolve done. */
- struct Curl_dns_entry *dns_entry;
-
- /* 'ip_addr' is the particular IP we connected to. It points to a struct
- within the DNS cache, so this pointer is only valid as long as the DNS
- cache entry remains locked. It gets unlocked in Curl_done() */
- Curl_addrinfo *ip_addr;
-
- /* 'ip_addr_str' is the ip_addr data as a human readable malloc()ed string.
- It remains available as long as the connection does, which is longer than
- the ip_addr itself. Set with Curl_store_ip_addr() when ip_addr has been
- set. */
- char *ip_addr_str;
-
- char protostr[16]; /* store the protocol string in this buffer */
- int socktype; /* SOCK_STREAM or SOCK_DGRAM */
-
- struct hostname host;
- struct hostname proxy;
-
- long port; /* which port to use locally */
- unsigned short remote_port; /* what remote port to connect to,
- not the proxy port! */
-
- long headerbytecount; /* only count received headers */
- long deductheadercount; /* this amount of bytes doesn't count when we check
- if anything has been transfered at the end of
- a connection. We use this counter to make only
- a 100 reply (without a following second response
- code) result in a CURLE_GOT_NOTHING error code */
-
- char *user; /* user name string, allocated */
- char *passwd; /* password string, allocated */
-
- char *proxyuser; /* proxy user name string, allocated */
- char *proxypasswd; /* proxy password string, allocated */
-
- struct timeval now; /* "current" time */
- struct timeval created; /* creation time */
- curl_socket_t sock[2]; /* two sockets, the second is used for the data
- transfer when doing FTP */
-
- struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
- struct ssl_config_data ssl_config;
-
- struct ConnectBits bits; /* various state-flags for this connection */
-
- /* These two functions MUST be set by the curl_connect() function to be
- be protocol dependent */
- CURLcode (*curl_do)(struct connectdata *, bool *done);
- Curl_done_func curl_done;
-
- /* If the curl_do() function is better made in two halves, this
- * curl_do_more() function will be called afterwards, if set. For example
- * for doing the FTP stuff after the PASV/PORT command.
- */
- Curl_do_more_func curl_do_more;
-
- /* This function *MAY* be set to a protocol-dependent function that is run
- * after the connect() and everything is done, as a step in the connection.
- * The 'done' pointer points to a bool that should be set to TRUE if the
- * function completes before return. If it doesn't complete, the caller
- * should call the curl_connecting() function until it is.
- */
- CURLcode (*curl_connect)(struct connectdata *, bool *done);
-
- /* See above. Currently only used for FTP. */
- CURLcode (*curl_connecting)(struct connectdata *, bool *done);
- CURLcode (*curl_doing)(struct connectdata *, bool *done);
-
- /* Called from the multi interface during the PROTOCONNECT phase, and it
- should then return a proper fd set */
- int (*curl_proto_getsock)(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-
- /* Called from the multi interface during the DOING phase, and it should
- then return a proper fd set */
- int (*curl_doing_getsock)(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks);
-
- /* This function *MAY* be set to a protocol-dependent function that is run
- * by the curl_disconnect(), as a step in the disconnection.
- */
- CURLcode (*curl_disconnect)(struct connectdata *);
-
- /* This function *MAY* be set to a protocol-dependent function that is run
- * in the curl_close() function if protocol-specific cleanups are required.
- */
- CURLcode (*curl_close)(struct connectdata *);
-
- /**** curl_get() phase fields */
-
- curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
- curl_socket_t writesockfd; /* socket to write to, it may very
- well be the same we read from.
- CURL_SOCKET_BAD disables */
-
- /** Dynamicly allocated strings, may need to be freed before this **/
- /** struct is killed. **/
- struct dynamically_allocated_data {
- char *proxyuserpwd; /* free later if not NULL! */
- char *uagent; /* free later if not NULL! */
- char *accept_encoding; /* free later if not NULL! */
- char *userpwd; /* free later if not NULL! */
- char *rangeline; /* free later if not NULL! */
- char *ref; /* free later if not NULL! */
- char *host; /* free later if not NULL */
- char *cookiehost; /* free later if not NULL */
- } allocptr;
-
- int sec_complete; /* if krb4 is enabled for this connection */
-#ifdef HAVE_KRB4
- enum protection_level command_prot;
- enum protection_level data_prot;
- enum protection_level request_data_prot;
- size_t buffer_size;
- struct krb4buffer in_buffer, out_buffer;
- void *app_data;
- const struct Curl_sec_client_mech *mech;
- struct sockaddr_in local_addr;
-#endif
-
- bool readchannel_inuse; /* whether the read channel is in use by an easy
- handle */
- bool writechannel_inuse; /* whether the write channel is in use by an easy
- handle */
- bool is_in_pipeline; /* TRUE if this connection is in a pipeline */
-
- struct curl_llist *send_pipe; /* List of handles waiting to
- send on this pipeline */
- struct curl_llist *recv_pipe; /* List of handles waiting to read
- their responses on this pipeline */
-
- char master_buffer[BUFSIZE]; /* The master buffer for this connection. */
- size_t read_pos; /* Current read position in the master buffer */
- size_t buf_len; /* Length of the buffer?? */
-
-
- /*************** Request - specific items ************/
-
- /* previously this was in the urldata struct */
- curl_read_callback fread; /* function that reads the input */
- void *fread_in; /* pointer to pass to the fread() above */
-
- struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
- because it authenticates connections, not
- single requests! */
- struct ntlmdata proxyntlm; /* NTLM data for proxy */
-
- char syserr_buf [256]; /* buffer for Curl_strerror() */
-
-#if defined(USE_ARES) || defined(USE_THREADING_GETHOSTBYNAME) || \
- defined(USE_THREADING_GETADDRINFO)
- /* data used for the asynch name resolve callback */
- struct Curl_async async;
-#endif
-
- /* These three are used for chunked-encoding trailer support */
- char *trailer; /* allocated buffer to store trailer in */
- int trlMax; /* allocated buffer size */
- int trlPos; /* index of where to store data */
-
- union {
- struct ftp_conn ftpc;
- } proto;
-};
-
-/* The end of connectdata. */
-
-/*
- * Struct to keep statistical and informational data.
- */
-struct PureInfo {
- int httpcode; /* Recent HTTP or FTP response code */
- int httpproxycode;
- int httpversion;
- long filetime; /* If requested, this is might get set. Set to -1 if the time
- was unretrievable. We cannot have this of type time_t,
- since time_t is unsigned on several platforms such as
- OpenVMS. */
- long header_size; /* size of read header(s) in bytes */
- long request_size; /* the amount of bytes sent in the request(s) */
-
- long proxyauthavail;
- long httpauthavail;
-
- long numconnects; /* how many new connection did libcurl created */
-
- char *contenttype; /* the content type of the object */
-};
-
-
-struct Progress {
- long lastshow; /* time() of the last displayed progress meter or NULL to
- force redraw at next call */
- curl_off_t size_dl; /* total expected size */
- curl_off_t size_ul; /* total expected size */
- curl_off_t downloaded; /* transfered so far */
- curl_off_t uploaded; /* transfered so far */
-
- curl_off_t current_speed; /* uses the currently fastest transfer */
-
- bool callback; /* set when progress callback is used */
- int width; /* screen width at download start */
- int flags; /* see progress.h */
-
- double timespent;
-
- curl_off_t dlspeed;
- curl_off_t ulspeed;
-
- double t_nslookup;
- double t_connect;
- double t_pretransfer;
- double t_starttransfer;
- double t_redirect;
-
- struct timeval start;
- struct timeval t_startsingle;
-#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
-
- curl_off_t speeder[ CURR_TIME ];
- struct timeval speeder_time[ CURR_TIME ];
- int speeder_c;
-};
-
-typedef enum {
- HTTPREQ_NONE, /* first in list */
- HTTPREQ_GET,
- HTTPREQ_POST,
- HTTPREQ_POST_FORM, /* we make a difference internally */
- HTTPREQ_PUT,
- HTTPREQ_HEAD,
- HTTPREQ_CUSTOM,
- HTTPREQ_LAST /* last in list */
-} Curl_HttpReq;
-
-/*
- * Values that are generated, temporary or calculated internally for a
- * "session handle" must be defined within the 'struct UrlState'. This struct
- * will be used within the SessionHandle struct. When the 'SessionHandle'
- * struct is cloned, this data MUST NOT be copied.
- *
- * Remember that any "state" information goes globally for the curl handle.
- * Session-data MUST be put in the connectdata struct and here. */
-#define MAX_CURL_USER_LENGTH 256
-#define MAX_CURL_PASSWORD_LENGTH 256
-#define MAX_CURL_USER_LENGTH_TXT "255"
-#define MAX_CURL_PASSWORD_LENGTH_TXT "255"
-
-struct auth {
- long want; /* Bitmask set to the authentication methods wanted by the app
- (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
- long picked;
- long avail; /* bitmask for what the server reports to support for this
- resource */
- bool done; /* TRUE when the auth phase is done and ready to do the *actual*
- request */
- bool multi; /* TRUE if this is not yet authenticated but within the auth
- multipass negotiation */
-
-};
-
-struct conncache {
- /* 'connects' will be an allocated array with pointers. If the pointer is
- set, it holds an allocated connection. */
- struct connectdata **connects;
- long num; /* number of entries of the 'connects' array */
- enum {
- CONNCACHE_PRIVATE, /* used for an easy handle alone */
- CONNCACHE_MULTI /* shared within a multi handle */
- } type;
-};
-
-
-struct UrlState {
- enum {
- Curl_if_none,
- Curl_if_easy,
- Curl_if_multi
- } used_interface;
-
- struct conncache *connc; /* points to the connection cache this handle
- uses */
-
- /* buffers to store authentication data in, as parsed from input options */
- struct timeval keeps_speed; /* for the progress meter really */
-
- long lastconnect; /* index of most recent connect or -1 if undefined */
-
- char *headerbuff; /* allocated buffer to store headers in */
- size_t headersize; /* size of the allocation */
-
- char buffer[BUFSIZE+1]; /* download buffer */
- char uploadbuffer[BUFSIZE+1]; /* upload buffer */
- curl_off_t current_speed; /* the ProgressShow() funcion sets this,
- bytes / second */
- bool this_is_a_follow; /* this is a followed Location: request */
-
- bool is_in_pipeline; /* Indicates whether this handle is part of a pipeline */
-
- char *first_host; /* if set, this should be the host name that we will
- sent authorization to, no else. Used to make Location:
- following not keep sending user+password... This is
- strdup() data.
- */
-
- struct curl_ssl_session *session; /* array of 'numsessions' size */
- long sessionage; /* number of the most recent session */
-
- char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */
- bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
- This must be set to FALSE every time _easy_perform() is
- called. */
- int os_errno; /* filled in with errno whenever an error occurs */
-#ifdef HAVE_SIGNAL
- /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
- void (*prev_signal)(int sig);
-#endif
- bool allow_port; /* Is set.use_port allowed to take effect or not. This
- is always set TRUE when curl_easy_perform() is called. */
-
- struct digestdata digest;
- struct digestdata proxydigest;
-
-#ifdef HAVE_GSSAPI
- struct negotiatedata negotiate;
-#endif
-
- struct auth authhost;
- struct auth authproxy;
-
- bool authproblem; /* TRUE if there's some problem authenticating */
-
-#ifdef USE_ARES
- ares_channel areschannel; /* for name resolves */
-#endif
-
-#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
- ENGINE *engine;
-#endif /* USE_SSLEAY */
- struct timeval expiretime; /* set this with Curl_expire() only */
- struct Curl_tree timenode; /* for the splay stuff */
-
- /* a place to store the most recenlty set FTP entrypath */
- char *most_recent_ftp_entrypath;
-
- /* set after initial USER failure, to prevent an authentication loop */
- bool ftp_trying_alternative;
-
- bool expect100header; /* TRUE if we added Expect: 100-continue */
-
- bool pipe_broke; /* TRUE if the connection we were pipelined on broke
- and we need to restart from the beginning */
- bool cancelled; /* TRUE if the request was cancelled */
-
-#ifndef WIN32
-/* do FTP line-end conversions on most platforms */
-#define CURL_DO_LINEEND_CONV
- /* for FTP downloads: track CRLF sequences that span blocks */
- bool prev_block_had_trailing_cr;
- /* for FTP downloads: how many CRLFs did we converted to LFs? */
- curl_off_t crlf_conversions;
-#endif
- /* If set to non-NULL, there's a connection in a shared connection cache
- that uses this handle so we can't kill this SessionHandle just yet but
- must keep it around and add it to the list of handles to kill once all
- its connections are gone */
- void *shared_conn;
- bool closed; /* set to TRUE when curl_easy_cleanup() has been called on this
- handle, but it is kept around as mentioned for
- shared_conn */
-};
-
-
-/*
- * This 'DynamicStatic' struct defines dynamic states that actually change
- * values in the 'UserDefined' area, which MUST be taken into consideration
- * if the UserDefined struct is cloned or similar. You can probably just
- * copy these, but each one indicate a special action on other data.
- */
-
-struct DynamicStatic {
- char *url; /* work URL, copied from UserDefined */
- bool url_alloc; /* URL string is malloc()'ed */
- bool url_changed; /* set on CURL_OPT_URL, used to detect if the URL was
- changed after the connect phase, as we allow callback
- to change it and if so, we reconnect to use the new
- URL instead */
- char *referer; /* referer string */
- bool referer_alloc; /* referer sting is malloc()ed */
- struct curl_slist *cookielist; /* list of cookie files set by
- curl_easy_setopt(COOKIEFILE) calls */
-};
-
-/*
- * This 'UserDefined' struct must only contain data that is set once to go
- * for many (perhaps) independent connections. Values that are generated or
- * calculated internally for the "session handle" MUST be defined within the
- * 'struct UrlState' instead. The only exceptions MUST note the changes in
- * the 'DynamicStatic' struct.
- */
-struct Curl_one_easy; /* declared and used only in multi.c */
-struct Curl_multi; /* declared and used only in multi.c */
-
-struct UserDefined {
- FILE *err; /* the stderr user data goes here */
- void *debugdata; /* the data that will be passed to fdebug */
- char *errorbuffer; /* store failure messages in here */
- char *proxyuserpwd; /* Proxy <user:password>, if used */
- long proxyport; /* If non-zero, use this port number by default. If the
- proxy string features a ":[port]" that one will override
- this. */
- void *out; /* the fetched file goes here */
- void *in; /* the uploaded file is read from here */
- void *writeheader; /* write the header to this if non-NULL */
- char *set_url; /* what original URL to work on */
- char *proxy; /* proxy to use */
- long use_port; /* which port to use (when not using default) */
- char *userpwd; /* <user:password>, if used */
- long httpauth; /* what kind of HTTP authentication to use (bitmask) */
- long proxyauth; /* what kind of proxy authentication to use (bitmask) */
- char *set_range; /* range, if used. See README for detailed specification
- on this syntax. */
- long followlocation; /* as in HTTP Location: */
- long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
- for infinity */
- char *set_referer; /* custom string */
- bool free_referer; /* set TRUE if 'referer' points to a string we
- allocated */
- char *useragent; /* User-Agent string */
- char *encoding; /* Accept-Encoding string */
- char *postfields; /* if POST, set the fields' values here */
- curl_off_t postfieldsize; /* if POST, this might have a size to use instead
- of strlen(), and then the data *may* be binary
- (contain zero bytes) */
- char *ftpport; /* port to send with the FTP PORT command */
- char *device; /* local network interface/address to use */
- unsigned short localport; /* local port number to bind to */
- int localportrange; /* number of additional port numbers to test in case the
- 'localport' one can't be bind()ed */
- curl_write_callback fwrite; /* function that stores the output */
- curl_write_callback fwrite_header; /* function that stores headers */
- curl_read_callback fread; /* function that reads the input */
- curl_progress_callback fprogress; /* function for progress information */
- curl_debug_callback fdebug; /* function that write informational data */
- curl_ioctl_callback ioctl; /* function for I/O control */
- curl_sockopt_callback fsockopt; /* function for setting socket options */
- void *sockopt_client; /* pointer to pass to the socket options callback */
-
- /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
- /* function to convert from the network encoding: */
- curl_conv_callback convfromnetwork;
- /* function to convert to the network encoding: */
- curl_conv_callback convtonetwork;
- /* function to convert from UTF-8 encoding: */
- curl_conv_callback convfromutf8;
-
- void *progress_client; /* pointer to pass to the progress callback */
- void *ioctl_client; /* pointer to pass to the ioctl callback */
- long timeout; /* in seconds, 0 means no timeout */
- long connecttimeout; /* in seconds, 0 means no timeout */
- long ftp_response_timeout; /* in seconds, 0 means no timeout */
- curl_off_t infilesize; /* size of file to upload, -1 means unknown */
- long low_speed_limit; /* bytes/second */
- long low_speed_time; /* number of seconds */
- curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */
- curl_off_t max_recv_speed; /* high speed limit in bytes/second for download */
- curl_off_t set_resume_from; /* continue [ftp] transfer from here */
- char *cookie; /* HTTP cookie string to send */
- struct curl_slist *headers; /* linked list of extra headers */
- struct curl_httppost *httppost; /* linked list of POST data */
- char *cert; /* certificate */
- char *cert_type; /* format for certificate (default: PEM) */
- char *key; /* private key */
- char *key_type; /* format for private key (default: PEM) */
- char *key_passwd; /* plain text private key password */
- char *cookiejar; /* dump all cookies to this file */
- bool cookiesession; /* new cookie session? */
- bool crlf; /* convert crlf on ftp upload(?) */
- char *ftp_account; /* ftp account data */
- char *ftp_alternative_to_user; /* command to send if USER/PASS fails */
- struct curl_slist *quote; /* after connection is established */
- struct curl_slist *postquote; /* after the transfer */
- struct curl_slist *prequote; /* before the transfer, after type */
- struct curl_slist *source_quote; /* 3rd party quote */
- struct curl_slist *source_prequote; /* in 3rd party transfer mode - before
- the transfer on source host */
- struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
- the transfer on source host */
- struct curl_slist *telnet_options; /* linked list of telnet options */
- curl_TimeCond timecondition; /* kind of time/date comparison */
- time_t timevalue; /* what time to compare with */
- Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
- char *customrequest; /* HTTP/FTP request to use */
- long httpversion; /* when non-zero, a specific HTTP version requested to
- be used in the library's request(s) */
- char *auth_host; /* if set, this is the allocated string to the host name
- * to which to send the authorization data to, and no other
- * host (which location-following otherwise could lead to)
- */
- char *krb4_level; /* what security level */
- struct ssl_config_data ssl; /* user defined SSL stuff */
-
- curl_proxytype proxytype; /* what kind of proxy that is in use */
-
- int dns_cache_timeout; /* DNS cache timeout */
- long buffer_size; /* size of receive buffer to use */
-
- char *private_data; /* Private data */
-
- struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi
- handle, an internal 'Curl_one_easy'
- struct is created and this is a pointer
- to the particular struct associated with
- this SessionHandle */
-
- struct curl_slist *http200aliases; /* linked list of aliases for http200 */
-
- long ip_version;
-
- curl_off_t max_filesize; /* Maximum file size to download */
-
- char *source_url; /* for 3rd party transfer */
- char *source_userpwd; /* for 3rd party transfer */
-
- curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */
-
-/* Here follows boolean settings that define how to behave during
- this session. They are STATIC, set by libcurl users or at least initially
- and they don't change during operations. */
-
- bool printhost; /* printing host name in debug info */
- bool get_filetime;
- bool tunnel_thru_httpproxy;
- bool prefer_ascii; /* ASCII rather than binary */
- bool ftp_append;
- bool ftp_list_only;
- bool ftp_create_missing_dirs;
- bool ftp_use_port;
- bool hide_progress;
- bool http_fail_on_error;
- bool http_follow_location;
- bool http_disable_hostname_check_before_authentication;
- bool include_header; /* include received protocol headers in data output */
- bool http_set_referer;
- bool http_auto_referer; /* set "correct" referer when following location: */
- bool opt_no_body; /* as set with CURLOPT_NO_BODY */
- bool set_port;
- bool upload;
- enum CURL_NETRC_OPTION
- use_netrc; /* defined in include/curl.h */
- char *netrc_file; /* if not NULL, use this instead of trying to find
- $HOME/.netrc */
- bool verbose;
- bool krb4; /* kerberos4 connection requested */
- bool reuse_forbid; /* forbidden to be reused, close after use */
- bool reuse_fresh; /* do not re-use an existing connection */
- bool ftp_use_epsv; /* if EPSV is to be attempted or not */
- bool ftp_use_eprt; /* if EPRT is to be attempted or not */
- bool ftp_use_ccc; /* if CCC is to be attempted or not */
-
- curl_ftpssl ftp_ssl; /* if AUTH TLS is to be attempted etc */
- curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
- bool no_signal; /* do not use any signal/alarm handler */
- bool global_dns_cache; /* subject for future removal */
- bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */
- bool ignorecl; /* ignore content length */
- bool ftp_skip_ip; /* skip the IP address the FTP server passes on to
- us */
- bool connect_only; /* make connection, let application use the socket */
- long ssh_auth_types; /* allowed SSH auth types */
- char *ssh_public_key; /* the path to the public key file for
- authentication */
- char *ssh_private_key; /* the path to the private key file for
- authentication */
-};
-
-struct Names {
- struct curl_hash *hostcache;
- enum {
- HCACHE_NONE, /* not pointing to anything */
- HCACHE_PRIVATE, /* points to our own */
- HCACHE_GLOBAL, /* points to the (shrug) global one */
- HCACHE_MULTI, /* points to a shared one in the multi handle */
- HCACHE_SHARED /* points to a shared one in a shared object */
- } hostcachetype;
-};
-
-/*
- * The 'connectdata' struct MUST have all the connection oriented stuff as we
- * may have several simultaneous connections and connection structs in memory.
- *
- * The 'struct UserDefined' must only contain data that is set once to go for
- * many (perhaps) independent connections. Values that are generated or
- * calculated internally for the "session handle" must be defined within the
- * 'struct UrlState' instead.
- */
-
-struct SessionHandle {
- struct Names dns;
- struct Curl_multi *multi; /* if non-NULL, points to the multi handle
- struct to which this "belongs" */
- struct Curl_share *share; /* Share, handles global variable mutexing */
- struct HandleData reqdata; /* Request-specific data */
- struct UserDefined set; /* values set by the libcurl user */
- struct DynamicStatic change; /* possibly modified userdefined data */
-
- struct CookieInfo *cookies; /* the cookies, read from files and servers */
- struct Progress progress; /* for all the progress meter data */
- struct UrlState state; /* struct for fields used for state info and
- other dynamic purposes */
- struct PureInfo info; /* stats, reports and info data */
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
- iconv_t outbound_cd; /* for translating to the network encoding */
- iconv_t inbound_cd; /* for translating from the network encoding */
- iconv_t utf8_cd; /* for translating to UTF8 */
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
- unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */
-};
-
-#define LIBCURL_NAME "libcurl"
-
-#endif
diff --git a/Utilities/cmcurl/version.c b/Utilities/cmcurl/version.c
deleted file mode 100644
index 9085f7df8..000000000
--- a/Utilities/cmcurl/version.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/***************************************************************************
- * _ _ ____ _
- * Project ___| | | | _ \| |
- * / __| | | | |_) | |
- * | (__| |_| | _ <| |___
- * \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at http://curl.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * $Id$
- ***************************************************************************/
-
-#include "setup.h"
-
-#include <string.h>
-#include <stdio.h>
-
-#include <curl/curl.h>
-#include "urldata.h"
-#include "sslgen.h"
-
-#define _MPRINTF_REPLACE /* use the internal *printf() functions */
-#include <curl/mprintf.h>
-
-#ifdef USE_ARES
-#include <ares_version.h>
-#endif
-
-#ifdef USE_LIBIDN
-#include <stringprep.h>
-#endif
-
-#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
-#include <iconv.h>
-#endif
-
-#ifdef USE_LIBSSH2
-#include <libssh2.h>
-#endif
-
-
-char *curl_version(void)
-{
- static char version[200];
- char *ptr=version;
- size_t len;
- size_t left = sizeof(version);
- strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION );
- ptr=strchr(ptr, '\0');
- left -= strlen(ptr);
-
- len = Curl_ssl_version(ptr, left);
- left -= len;
- ptr += len;
-
-#ifdef HAVE_LIBZ
- len = snprintf(ptr, left, " zlib/%s", zlibVersion());
- left -= len;
- ptr += len;
-#endif
-#ifdef USE_ARES
- /* this function is only present in c-ares, not in the original ares */
- len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
- left -= len;
- ptr += len;
-#endif
-#ifdef USE_LIBIDN
- if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
- len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL));
- left -= len;
- ptr += len;
- }
-#endif
-#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
-#ifdef _LIBICONV_VERSION
- len = snprintf(ptr, left, " iconv/%d.%d",
- _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
-#else
- /* version unknown */
- len = snprintf(ptr, left, " iconv");
-#endif /* _LIBICONV_VERSION */
- left -= len;
- ptr += len;
-#endif
-#ifdef USE_LIBSSH2
- len = snprintf(ptr, left, " libssh2/%s", LIBSSH2_VERSION);
- left -= len;
- ptr += len;
-#endif
-
- return version;
-}
-
-/* data for curl_version_info */
-
-static const char * const protocols[] = {
-#ifndef CURL_DISABLE_TFTP
- "tftp",
-#endif
-#ifndef CURL_DISABLE_FTP
- "ftp",
-#endif
-#ifndef CURL_DISABLE_TELNET
- "telnet",
-#endif
-#ifndef CURL_DISABLE_DICT
- "dict",
-#endif
-#ifndef CURL_DISABLE_LDAP
- "ldap",
-#endif
-#ifndef CURL_DISABLE_HTTP
- "http",
-#endif
-#ifndef CURL_DISABLE_FILE
- "file",
-#endif
-
-#ifdef USE_SSL
-#ifndef CURL_DISABLE_HTTP
- "https",
-#endif
-#ifndef CURL_DISABLE_FTP
- "ftps",
-#endif
-#endif
-
-#ifdef USE_LIBSSH2
- "scp",
- "sftp",
-#endif
-
- NULL
-};
-
-static curl_version_info_data version_info = {
- CURLVERSION_NOW,
- LIBCURL_VERSION,
- LIBCURL_VERSION_NUM,
- OS, /* as found by configure or set by hand at build-time */
- 0 /* features is 0 by default */
-#ifdef ENABLE_IPV6
- | CURL_VERSION_IPV6
-#endif
-#ifdef HAVE_KRB4
- | CURL_VERSION_KERBEROS4
-#endif
-#ifdef USE_SSL
- | CURL_VERSION_SSL
-#endif
-#ifdef USE_NTLM
- | CURL_VERSION_NTLM
-#endif
-#ifdef USE_WINDOWS_SSPI
- | CURL_VERSION_SSPI
-#endif
-#ifdef HAVE_LIBZ
- | CURL_VERSION_LIBZ
-#endif
-#ifdef HAVE_GSSAPI
- | CURL_VERSION_GSSNEGOTIATE
-#endif
-#ifdef CURLDEBUG
- | CURL_VERSION_DEBUG
-#endif
-#ifdef USE_ARES
- | CURL_VERSION_ASYNCHDNS
-#endif
-#ifdef HAVE_SPNEGO
- | CURL_VERSION_SPNEGO
-#endif
-#if defined(ENABLE_64BIT) && (SIZEOF_CURL_OFF_T > 4)
- | CURL_VERSION_LARGEFILE
-#endif
-#if defined(CURL_DOES_CONVERSIONS)
- | CURL_VERSION_CONV
-#endif
- ,
- NULL, /* ssl_version */
- 0, /* ssl_version_num, this is kept at zero */
- NULL, /* zlib_version */
- protocols,
- NULL, /* c-ares version */
- 0, /* c-ares version numerical */
- NULL, /* libidn version */
- 0, /* iconv version */
- NULL, /* ssh lib version */
-};
-
-curl_version_info_data *curl_version_info(CURLversion stamp)
-{
-#ifdef USE_LIBSSH2
- static char ssh_buffer[80];
-#endif
-
-#ifdef USE_SSL
- static char ssl_buffer[80];
- Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
- version_info.ssl_version = ssl_buffer;
-#endif
-
-#ifdef HAVE_LIBZ
- version_info.libz_version = zlibVersion();
- /* libz left NULL if non-existing */
-#endif
-#ifdef USE_ARES
- {
- int aresnum;
- version_info.ares = ares_version(&aresnum);
- version_info.ares_num = aresnum;
- }
-#endif
-#ifdef USE_LIBIDN
- /* This returns a version string if we use the given version or later,
- otherwise it returns NULL */
- version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION);
- if(version_info.libidn)
- version_info.features |= CURL_VERSION_IDN;
-#endif
-
-#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
-#ifdef _LIBICONV_VERSION
- version_info.iconv_ver_num = _LIBICONV_VERSION;
-#else
- /* version unknown */
- version_info.iconv_ver_num = -1;
-#endif /* _LIBICONV_VERSION */
-#endif
-
-#ifdef USE_LIBSSH2
- snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
- version_info.libssh_version = ssh_buffer;
-#endif
-
- (void)stamp; /* avoid compiler warnings, we don't use this */
-
- return &version_info;
-}
diff --git a/Utilities/cmexpat/.NoDartCoverage b/Utilities/cmexpat/.NoDartCoverage
deleted file mode 100644
index 3c9972938..000000000
--- a/Utilities/cmexpat/.NoDartCoverage
+++ /dev/null
@@ -1 +0,0 @@
-# do not do coverage in this directory
diff --git a/Utilities/cmexpat/.gitattributes b/Utilities/cmexpat/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmexpat/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmexpat/CMakeLists.txt b/Utilities/cmexpat/CMakeLists.txt
index 51ba413e5..470fcba99 100644
--- a/Utilities/cmexpat/CMakeLists.txt
+++ b/Utilities/cmexpat/CMakeLists.txt
@@ -1,34 +1,26 @@
-PROJECT(CMEXPAT)
+# Disable warnings to avoid changing 3rd party code.
+IF(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+ENDIF()
-SET(expat_SRCS
- xmlparse.c
- xmltok.c
- xmlrole.c
-)
+include(ConfigureChecks.cmake)
+if(NOT WIN32)
+ add_definitions(-DXML_DEV_URANDOM)
+endif()
-INCLUDE(${CMAKE_ROOT}/Modules/TestBigEndian.cmake)
-TEST_BIG_ENDIAN(CMEXPAT_BIGENDIAN)
-
-INCLUDE_DIRECTORIES(
- "${CMEXPAT_BINARY_DIR}/.."
+include_directories(
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${CMAKE_CURRENT_SOURCE_DIR}/lib
)
-IF(WIN32)
- IF(NOT BUILD_SHARED_LIBS)
- SET (CM_EXPAT_STATIC 1)
- ENDIF(NOT BUILD_SHARED_LIBS)
-ENDIF(WIN32)
-
-CONFIGURE_FILE(${CMEXPAT_SOURCE_DIR}/expatConfig.h.in
- ${CMEXPAT_BINARY_DIR}/expatConfig.h)
-CONFIGURE_FILE(${CMEXPAT_SOURCE_DIR}/expatDllConfig.h.in
- ${CMEXPAT_BINARY_DIR}/expatDllConfig.h)
-CONFIGURE_FILE(${CMEXPAT_SOURCE_DIR}/.NoDartCoverage
- ${CMEXPAT_BINARY_DIR}/.NoDartCoverage)
-CONFIGURE_FILE(${CMEXPAT_SOURCE_DIR}/cm_expat_mangle.h
- ${CMEXPAT_BINARY_DIR}/cm_expat_mangle.h)
-CONFIGURE_FILE(${CMEXPAT_SOURCE_DIR}/expat.h
- ${CMEXPAT_BINARY_DIR}/expat.h)
-
-ADD_LIBRARY(cmexpat ${expat_SRCS})
-INSTALL(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmexpat)
+add_library(cmexpat STATIC
+ lib/loadlibrary.c
+ lib/xmlparse.c
+ lib/xmlrole.c
+ lib/xmltok.c
+ lib/xmltok_impl.c
+ lib/xmltok_ns.c
+ )
diff --git a/Utilities/cmexpat/COPYING b/Utilities/cmexpat/COPYING
index fc97b02d9..8d288f0f2 100644
--- a/Utilities/cmexpat/COPYING
+++ b/Utilities/cmexpat/COPYING
@@ -1,5 +1,5 @@
-Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
- and Clark Cooper
+Copyright (c) 1998-2000 Thai Open Source Software Center Ltd and Clark Cooper
+Copyright (c) 2001-2017 Expat maintainers
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/Utilities/cmexpat/ConfigureChecks.cmake b/Utilities/cmexpat/ConfigureChecks.cmake
new file mode 100644
index 000000000..057cfa58d
--- /dev/null
+++ b/Utilities/cmexpat/ConfigureChecks.cmake
@@ -0,0 +1,44 @@
+include(CheckIncludeFile)
+include(CheckIncludeFiles)
+include(CheckFunctionExists)
+include(CheckSymbolExists)
+include(TestBigEndian)
+
+check_include_file("dlfcn.h" HAVE_DLFCN_H)
+check_include_file("fcntl.h" HAVE_FCNTL_H)
+check_include_file("inttypes.h" HAVE_INTTYPES_H)
+check_include_file("memory.h" HAVE_MEMORY_H)
+check_include_file("stdint.h" HAVE_STDINT_H)
+check_include_file("stdlib.h" HAVE_STDLIB_H)
+check_include_file("strings.h" HAVE_STRINGS_H)
+check_include_file("string.h" HAVE_STRING_H)
+check_include_file("sys/stat.h" HAVE_SYS_STAT_H)
+check_include_file("sys/types.h" HAVE_SYS_TYPES_H)
+check_include_file("unistd.h" HAVE_UNISTD_H)
+
+check_function_exists("getpagesize" HAVE_GETPAGESIZE)
+check_function_exists("bcopy" HAVE_BCOPY)
+check_symbol_exists("memmove" "string.h" HAVE_MEMMOVE)
+check_function_exists("mmap" HAVE_MMAP)
+
+#/* Define to 1 if you have the ANSI C header files. */
+check_include_files("stdlib.h;stdarg.h;string.h;float.h" STDC_HEADERS)
+
+test_big_endian(WORDS_BIGENDIAN)
+#/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+if(WORDS_BIGENDIAN)
+ set(BYTEORDER 4321)
+else(WORDS_BIGENDIAN)
+ set(BYTEORDER 1234)
+endif(WORDS_BIGENDIAN)
+
+if(HAVE_SYS_TYPES_H)
+ check_symbol_exists("off_t" "sys/types.h" OFF_T)
+ check_symbol_exists("size_t" "sys/types.h" SIZE_T)
+else(HAVE_SYS_TYPES_H)
+ set(OFF_T "long")
+ set(SIZE_T "unsigned")
+endif(HAVE_SYS_TYPES_H)
+
+configure_file(expat_config.h.cmake "${CMAKE_CURRENT_BINARY_DIR}/expat_config.h")
+add_definitions(-DHAVE_EXPAT_CONFIG_H)
diff --git a/Utilities/cmexpat/README.md b/Utilities/cmexpat/README.md
new file mode 100644
index 000000000..0a1777e7e
--- /dev/null
+++ b/Utilities/cmexpat/README.md
@@ -0,0 +1,126 @@
+# Expat, Release 2.2.3
+
+This is Expat, a C library for parsing XML, started by
+[James Clark](https://en.wikipedia.org/wiki/James_Clark_(programmer)) in 1997.
+Expat is a stream-oriented XML parser. This means that you register
+handlers with the parser before starting the parse. These handlers
+are called when the parser discovers the associated structures in the
+document being parsed. A start tag is an example of the kind of
+structures for which you may register handlers.
+
+Windows users should use the
+[`expat_win32` package](https://sourceforge.net/projects/expat/files/expat_win32/),
+which includes both precompiled libraries and executables, and source code for
+developers.
+
+Expat is [free software](https://www.gnu.org/philosophy/free-sw.en.html).
+You may copy, distribute, and modify it under the terms of the License
+contained in the file
+[`COPYING`](https://github.com/libexpat/libexpat/blob/master/expat/COPYING)
+distributed with this package.
+This license is the same as the MIT/X Consortium license.
+
+If you are building Expat from a check-out from the
+[Git repository](https://github.com/libexpat/libexpat/),
+you need to run a script that generates the configure script using the
+GNU autoconf and libtool tools. To do this, you need to have
+autoconf 2.58 or newer. Run the script like this:
+
+```console
+./buildconf.sh
+```
+
+Once this has been done, follow the same instructions as for building
+from a source distribution.
+
+To build Expat from a source distribution, you first run the
+configuration shell script in the top level distribution directory:
+
+```console
+./configure
+```
+
+There are many options which you may provide to configure (which you
+can discover by running configure with the `--help` option). But the
+one of most interest is the one that sets the installation directory.
+By default, the configure script will set things up to install
+libexpat into `/usr/local/lib`, `expat.h` into `/usr/local/include`, and
+`xmlwf` into `/usr/local/bin`. If, for example, you'd prefer to install
+into `/home/me/mystuff/lib`, `/home/me/mystuff/include`, and
+`/home/me/mystuff/bin`, you can tell `configure` about that with:
+
+```console
+./configure --prefix=/home/me/mystuff
+```
+
+Another interesting option is to enable 64-bit integer support for
+line and column numbers and the over-all byte index:
+
+```console
+./configure CPPFLAGS=-DXML_LARGE_SIZE
+```
+
+However, such a modification would be a breaking change to the ABI
+and is therefore not recommended for general use &mdash; e.g. as part of
+a Linux distribution &mdash; but rather for builds with special requirements.
+
+After running the configure script, the `make` command will build
+things and `make install` will install things into their proper
+location. Have a look at the `Makefile` to learn about additional
+`make` options. Note that you need to have write permission into
+the directories into which things will be installed.
+
+If you are interested in building Expat to provide document
+information in UTF-16 encoding rather than the default UTF-8, follow
+these instructions (after having run `make distclean`):
+
+1. For UTF-16 output as unsigned short (and version/error strings as char),
+ run:<br/>
+ `./configure CPPFLAGS=-DXML_UNICODE`<br/>
+ For UTF-16 output as `wchar_t` (incl. version/error strings), run:<br/>
+ `./configure CFLAGS="-g -O2 -fshort-wchar" CPPFLAGS=-DXML_UNICODE_WCHAR_T`
+ <br/>Note: The latter requires libc compiled with `-fshort-wchar`, as well.
+
+1. Edit `Makefile`, changing:<br/>
+ `LIBRARY = libexpat.la`<br/>
+ to:<br/>
+ `LIBRARY = libexpatw.la`<br/>
+ (Note the additional "w" in the library name.)
+
+1. Run `make buildlib` (which builds the library only).
+ Or, to save step 2, run `make buildlib LIBRARY=libexpatw.la`.
+
+1. Run `make installlib` (which installs the library only).
+ Or, if step 2 was omitted, run `make installlib LIBRARY=libexpatw.la`.
+
+Using `DESTDIR` or `INSTALL_ROOT` is enabled, with `INSTALL_ROOT` being the
+default value for `DESTDIR`, and the rest of the make file using only
+`DESTDIR`. It works as follows:
+
+```console
+make install DESTDIR=/path/to/image
+```
+
+overrides the in-makefile set `DESTDIR`, while both
+
+```console
+INSTALL_ROOT=/path/to/image make install
+make install INSTALL_ROOT=/path/to/image
+```
+
+use `DESTDIR=$(INSTALL_ROOT)`, even if `DESTDIR` eventually is defined in the
+environment, because variable-setting priority is
+1. commandline
+2. in-makefile
+3. environment
+
+Note: This only applies to the Expat library itself, building UTF-16 versions
+of xmlwf and the tests is currently not supported.
+
+When using Expat with a project using autoconf for configuration, you
+can use the probing macro in `conftools/expat.m4` to determine how to
+include Expat. See the comments at the top of that file for more
+information.
+
+A reference manual is available in the file `doc/reference.html` in this
+distribution.
diff --git a/Utilities/cmexpat/ascii.h b/Utilities/cmexpat/ascii.h
deleted file mode 100644
index 6376b1f31..000000000
--- a/Utilities/cmexpat/ascii.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#define ASCII_A 0x41
-#define ASCII_B 0x42
-#define ASCII_C 0x43
-#define ASCII_D 0x44
-#define ASCII_E 0x45
-#define ASCII_F 0x46
-#define ASCII_G 0x47
-#define ASCII_H 0x48
-#define ASCII_I 0x49
-#define ASCII_J 0x4A
-#define ASCII_K 0x4B
-#define ASCII_L 0x4C
-#define ASCII_M 0x4D
-#define ASCII_N 0x4E
-#define ASCII_O 0x4F
-#define ASCII_P 0x50
-#define ASCII_Q 0x51
-#define ASCII_R 0x52
-#define ASCII_S 0x53
-#define ASCII_T 0x54
-#define ASCII_U 0x55
-#define ASCII_V 0x56
-#define ASCII_W 0x57
-#define ASCII_X 0x58
-#define ASCII_Y 0x59
-#define ASCII_Z 0x5A
-
-#define ASCII_a 0x61
-#define ASCII_b 0x62
-#define ASCII_c 0x63
-#define ASCII_d 0x64
-#define ASCII_e 0x65
-#define ASCII_f 0x66
-#define ASCII_g 0x67
-#define ASCII_h 0x68
-#define ASCII_i 0x69
-#define ASCII_j 0x6A
-#define ASCII_k 0x6B
-#define ASCII_l 0x6C
-#define ASCII_m 0x6D
-#define ASCII_n 0x6E
-#define ASCII_o 0x6F
-#define ASCII_p 0x70
-#define ASCII_q 0x71
-#define ASCII_r 0x72
-#define ASCII_s 0x73
-#define ASCII_t 0x74
-#define ASCII_u 0x75
-#define ASCII_v 0x76
-#define ASCII_w 0x77
-#define ASCII_x 0x78
-#define ASCII_y 0x79
-#define ASCII_z 0x7A
-
-#define ASCII_0 0x30
-#define ASCII_1 0x31
-#define ASCII_2 0x32
-#define ASCII_3 0x33
-#define ASCII_4 0x34
-#define ASCII_5 0x35
-#define ASCII_6 0x36
-#define ASCII_7 0x37
-#define ASCII_8 0x38
-#define ASCII_9 0x39
-
-#define ASCII_TAB 0x09
-#define ASCII_SPACE 0x20
-#define ASCII_EXCL 0x21
-#define ASCII_QUOT 0x22
-#define ASCII_AMP 0x26
-#define ASCII_APOS 0x27
-#define ASCII_MINUS 0x2D
-#define ASCII_PERIOD 0x2E
-#define ASCII_COLON 0x3A
-#define ASCII_SEMI 0x3B
-#define ASCII_LT 0x3C
-#define ASCII_EQUALS 0x3D
-#define ASCII_GT 0x3E
-#define ASCII_LSQB 0x5B
-#define ASCII_RSQB 0x5D
-#define ASCII_UNDERSCORE 0x5F
diff --git a/Utilities/cmexpat/asciitab.h b/Utilities/cmexpat/asciitab.h
deleted file mode 100644
index eb445cc52..000000000
--- a/Utilities/cmexpat/asciitab.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/Utilities/cmexpat/cm_expat_mangle.h b/Utilities/cmexpat/cm_expat_mangle.h
deleted file mode 100644
index 82276a56d..000000000
--- a/Utilities/cmexpat/cm_expat_mangle.h
+++ /dev/null
@@ -1,87 +0,0 @@
-#ifndef cm_expat_mangle_h
-#define cm_expat_mangle_h
-
-/*
-
-This header file mangles all symbols exported from the expat library.
-It is included in all files while building the expat library. Due to
-namespace pollution, no expat headers should be included in .h files in
-CMake.
-
-The following command was used to obtain the symbol list:
-
-nm libcmexpat.a |grep " T "
-
-*/
-
-#define XML_DefaultCurrent cm_expat_XML_DefaultCurrent
-#define XML_ErrorString cm_expat_XML_ErrorString
-#define XML_ExpatVersion cm_expat_XML_ExpatVersion
-#define XML_ExpatVersionInfo cm_expat_XML_ExpatVersionInfo
-#define XML_ExternalEntityParserCreate cm_expat_XML_ExternalEntityParserCreate
-#define XML_GetBase cm_expat_XML_GetBase
-#define XML_GetBuffer cm_expat_XML_GetBuffer
-#define XML_GetCurrentByteCount cm_expat_XML_GetCurrentByteCount
-#define XML_GetCurrentByteIndex cm_expat_XML_GetCurrentByteIndex
-#define XML_GetCurrentColumnNumber cm_expat_XML_GetCurrentColumnNumber
-#define XML_GetCurrentLineNumber cm_expat_XML_GetCurrentLineNumber
-#define XML_GetErrorCode cm_expat_XML_GetErrorCode
-#define XML_GetIdAttributeIndex cm_expat_XML_GetIdAttributeIndex
-#define XML_GetInputContext cm_expat_XML_GetInputContext
-#define XML_GetSpecifiedAttributeCount cm_expat_XML_GetSpecifiedAttributeCount
-#define XML_Parse cm_expat_XML_Parse
-#define XML_ParseBuffer cm_expat_XML_ParseBuffer
-#define XML_ParserCreate cm_expat_XML_ParserCreate
-#define XML_ParserCreateNS cm_expat_XML_ParserCreateNS
-#define XML_ParserCreate_MM cm_expat_XML_ParserCreate_MM
-#define XML_ParserFree cm_expat_XML_ParserFree
-#define XML_SetAttlistDeclHandler cm_expat_XML_SetAttlistDeclHandler
-#define XML_SetBase cm_expat_XML_SetBase
-#define XML_SetCdataSectionHandler cm_expat_XML_SetCdataSectionHandler
-#define XML_SetCharacterDataHandler cm_expat_XML_SetCharacterDataHandler
-#define XML_SetCommentHandler cm_expat_XML_SetCommentHandler
-#define XML_SetDefaultHandler cm_expat_XML_SetDefaultHandler
-#define XML_SetDefaultHandlerExpand cm_expat_XML_SetDefaultHandlerExpand
-#define XML_SetDoctypeDeclHandler cm_expat_XML_SetDoctypeDeclHandler
-#define XML_SetElementDeclHandler cm_expat_XML_SetElementDeclHandler
-#define XML_SetElementHandler cm_expat_XML_SetElementHandler
-#define XML_SetEncoding cm_expat_XML_SetEncoding
-#define XML_SetEndCdataSectionHandler cm_expat_XML_SetEndCdataSectionHandler
-#define XML_SetEndDoctypeDeclHandler cm_expat_XML_SetEndDoctypeDeclHandler
-#define XML_SetEndElementHandler cm_expat_XML_SetEndElementHandler
-#define XML_SetEndNamespaceDeclHandler cm_expat_XML_SetEndNamespaceDeclHandler
-#define XML_SetEntityDeclHandler cm_expat_XML_SetEntityDeclHandler
-#define XML_SetExternalEntityRefHandler cm_expat_XML_SetExternalEntityRefHandler
-#define XML_SetExternalEntityRefHandlerArg cm_expat_XML_SetExternalEntityRefHandlerArg
-#define XML_SetNamespaceDeclHandler cm_expat_XML_SetNamespaceDeclHandler
-#define XML_SetNotStandaloneHandler cm_expat_XML_SetNotStandaloneHandler
-#define XML_SetNotationDeclHandler cm_expat_XML_SetNotationDeclHandler
-#define XML_SetParamEntityParsing cm_expat_XML_SetParamEntityParsing
-#define XML_SetProcessingInstructionHandler cm_expat_XML_SetProcessingInstructionHandler
-#define XML_SetReturnNSTriplet cm_expat_XML_SetReturnNSTriplet
-#define XML_SetStartCdataSectionHandler cm_expat_XML_SetStartCdataSectionHandler
-#define XML_SetStartDoctypeDeclHandler cm_expat_XML_SetStartDoctypeDeclHandler
-#define XML_SetStartElementHandler cm_expat_XML_SetStartElementHandler
-#define XML_SetStartNamespaceDeclHandler cm_expat_XML_SetStartNamespaceDeclHandler
-#define XML_SetUnknownEncodingHandler cm_expat_XML_SetUnknownEncodingHandler
-#define XML_SetUnparsedEntityDeclHandler cm_expat_XML_SetUnparsedEntityDeclHandler
-#define XML_SetUserData cm_expat_XML_SetUserData
-#define XML_SetXmlDeclHandler cm_expat_XML_SetXmlDeclHandler
-#define XML_UseParserAsHandlerArg cm_expat_XML_UseParserAsHandlerArg
-#define XmlGetUtf16InternalEncoding cm_expat_XmlGetUtf16InternalEncoding
-#define XmlGetUtf16InternalEncodingNS cm_expat_XmlGetUtf16InternalEncodingNS
-#define XmlGetUtf8InternalEncoding cm_expat_XmlGetUtf8InternalEncoding
-#define XmlGetUtf8InternalEncodingNS cm_expat_XmlGetUtf8InternalEncodingNS
-#define XmlInitEncoding cm_expat_XmlInitEncoding
-#define XmlInitEncodingNS cm_expat_XmlInitEncodingNS
-#define XmlInitUnknownEncoding cm_expat_XmlInitUnknownEncoding
-#define XmlInitUnknownEncodingNS cm_expat_XmlInitUnknownEncodingNS
-#define XmlParseXmlDecl cm_expat_XmlParseXmlDecl
-#define XmlParseXmlDeclNS cm_expat_XmlParseXmlDeclNS
-#define XmlSizeOfUnknownEncoding cm_expat_XmlSizeOfUnknownEncoding
-#define XmlUtf16Encode cm_expat_XmlUtf16Encode
-#define XmlUtf8Encode cm_expat_XmlUtf8Encode
-#define XmlPrologStateInit cm_expat_XmlPrologStateInit
-#define XmlPrologStateInitExternalEntity cm_expat_XmlPrologStateInitExternalEntity
-
-#endif
diff --git a/Utilities/cmexpat/expat.h b/Utilities/cmexpat/expat.h
deleted file mode 100644
index 86e58a1e5..000000000
--- a/Utilities/cmexpat/expat.h
+++ /dev/null
@@ -1,740 +0,0 @@
-#include "cm_expat_mangle.h"
-/*
-Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#ifndef XmlParse_INCLUDED
-#define XmlParse_INCLUDED 1
-
-#include <stdlib.h>
-
-#include <cmexpat/expatDllConfig.h>
-
-#if defined(_WIN32) && !defined(CM_EXPAT_STATIC)
-# if defined(cmexpat_EXPORTS)
-# define XMLPARSEAPI(type) __declspec( dllexport ) type __cdecl
-# else
-# define XMLPARSEAPI(type) __declspec( dllimport ) type __cdecl
-# endif
-#else
-# define XMLPARSEAPI(type) type
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef void *XML_Parser;
-
-/* Information is UTF-8 encoded. */
-typedef char XML_Char;
-typedef char XML_LChar;
-
-enum XML_Content_Type {
- XML_CTYPE_EMPTY = 1,
- XML_CTYPE_ANY,
- XML_CTYPE_MIXED,
- XML_CTYPE_NAME,
- XML_CTYPE_CHOICE,
- XML_CTYPE_SEQ
-};
-
-enum XML_Content_Quant {
- XML_CQUANT_NONE,
- XML_CQUANT_OPT,
- XML_CQUANT_REP,
- XML_CQUANT_PLUS
-};
-
-/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
- XML_CQUANT_NONE, and the other fields will be zero or NULL.
- If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
- numchildren will contain number of elements that may be mixed in
- and children point to an array of XML_Content cells that will be
- all of XML_CTYPE_NAME type with no quantification.
-
- If type == XML_CTYPE_NAME, then the name points to the name, and
- the numchildren field will be zero and children will be NULL. The
- quant fields indicates any quantifiers placed on the name.
-
- CHOICE and SEQ will have name NULL, the number of children in
- numchildren and children will point, recursively, to an array
- of XML_Content cells.
-
- The EMPTY, ANY, and MIXED types will only occur at top level.
-*/
-
-typedef struct XML_cp XML_Content;
-
-struct XML_cp {
- enum XML_Content_Type type;
- enum XML_Content_Quant quant;
- XML_Char * name;
- unsigned int numchildren;
- XML_Content * children;
-};
-
-
-/* This is called for an element declaration. See above for
- description of the model argument. It's the caller's responsibility
- to free model when finished with it.
-*/
-
-typedef void (*XML_ElementDeclHandler) (void *userData,
- const XML_Char *name,
- XML_Content *model);
-
-XMLPARSEAPI(void)
-XML_SetElementDeclHandler(XML_Parser parser,
- XML_ElementDeclHandler eldecl);
-
-/*
- The Attlist declaration handler is called for *each* attribute. So
- a single Attlist declaration with multiple attributes declared will
- generate multiple calls to this handler. The "default" parameter
- may be NULL in the case of the "#IMPLIED" or "#REQUIRED" keyword.
- The "isrequired" parameter will be true and the default value will
- be NULL in the case of "#REQUIRED". If "isrequired" is true and
- default is non-NULL, then this is a "#FIXED" default.
- */
-
-typedef void (*XML_AttlistDeclHandler) (void *userData,
- const XML_Char *elname,
- const XML_Char *attname,
- const XML_Char *att_type,
- const XML_Char *dflt,
- int isrequired);
-
-XMLPARSEAPI(void)
-XML_SetAttlistDeclHandler(XML_Parser parser,
- XML_AttlistDeclHandler attdecl);
-
-
- /* The XML declaration handler is called for *both* XML declarations and
- text declarations. The way to distinguish is that the version parameter
- will be null for text declarations. The encoding parameter may be null
- for XML declarations. The standalone parameter will be -1, 0, or 1
- indicating respectively that there was no standalone parameter in
- the declaration, that it was given as no, or that it was given as yes.
- */
-
-typedef void (*XML_XmlDeclHandler) (void *userData,
- const XML_Char *version,
- const XML_Char *encoding,
- int standalone);
-
-XMLPARSEAPI(void)
-XML_SetXmlDeclHandler(XML_Parser parser,
- XML_XmlDeclHandler xmldecl);
-
-
-typedef struct {
- void *(*malloc_fcn)(size_t size);
- void *(*realloc_fcn)(void *ptr, size_t size);
- void (*free_fcn)(void *ptr);
-} XML_Memory_Handling_Suite;
-
-/* Constructs a new parser; encoding is the encoding specified by the
-external protocol or null if there is none specified. */
-
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreate(const XML_Char *encoding);
-
-/* Constructs a new parser and namespace processor. Element type
-names and attribute names that belong to a namespace will be expanded;
-unprefixed attribute names are never expanded; unprefixed element type
-names are expanded only if there is a default namespace. The expanded
-name is the concatenation of the namespace URI, the namespace
-separator character, and the local part of the name. If the namespace
-separator is '\0' then the namespace URI and the local part will be
-concatenated without any separator. When a namespace is not declared,
-the name and prefix will be passed through without expansion. */
-
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
-
-
-/* Constructs a new parser using the memory management suit referred to
- by memsuite. If memsuite is NULL, then use the standard library memory
- suite. If namespaceSeparator is non-NULL it creates a parser with
- namespace processing as described above. The character pointed at
- will serve as the namespace separator.
-
- All further memory operations used for the created parser will come from
- the given suite.
-*/
-
-XMLPARSEAPI(XML_Parser)
-XML_ParserCreate_MM(const XML_Char *encoding,
- const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *namespaceSeparator);
-
-/* atts is array of name/value pairs, terminated by 0;
- names and values are 0 terminated. */
-
-typedef void (*XML_StartElementHandler)(void *userData,
- const XML_Char *name,
- const XML_Char **atts);
-
-typedef void (*XML_EndElementHandler)(void *userData,
- const XML_Char *name);
-
-
-/* s is not 0 terminated. */
-typedef void (*XML_CharacterDataHandler)(void *userData,
- const XML_Char *s,
- int len);
-
-/* target and data are 0 terminated */
-typedef void (*XML_ProcessingInstructionHandler)(void *userData,
- const XML_Char *target,
- const XML_Char *data);
-
-/* data is 0 terminated */
-typedef void (*XML_CommentHandler)(void *userData, const XML_Char *data);
-
-typedef void (*XML_StartCdataSectionHandler)(void *userData);
-typedef void (*XML_EndCdataSectionHandler)(void *userData);
-
-/* This is called for any characters in the XML document for
-which there is no applicable handler. This includes both
-characters that are part of markup which is of a kind that is
-not reported (comments, markup declarations), or characters
-that are part of a construct which could be reported but
-for which no handler has been supplied. The characters are passed
-exactly as they were in the XML document except that
-they will be encoded in UTF-8. Line boundaries are not normalized.
-Note that a byte order mark character is not passed to the default handler.
-There are no guarantees about how characters are divided between calls
-to the default handler: for example, a comment might be split between
-multiple calls. */
-
-typedef void (*XML_DefaultHandler)(void *userData,
- const XML_Char *s,
- int len);
-
-/* This is called for the start of the DOCTYPE declaration, before
- any DTD or internal subset is parsed. */
-
-typedef void (*XML_StartDoctypeDeclHandler)(void *userData,
- const XML_Char *doctypeName,
- const XML_Char *sysid,
- const XML_Char *pubid,
- int has_internal_subset);
-
-/* This is called for the start of the DOCTYPE declaration when the
-closing > is encountered, but after processing any external subset. */
-typedef void (*XML_EndDoctypeDeclHandler)(void *userData);
-
-/* This is called for entity declarations. The is_parameter_entity
- argument will be non-zero if the entity is a parameter entity, zero
- otherwise.
-
- For internal entities (<!ENTITY foo "bar">), value will
- be non-null and systemId, publicID, and notationName will be null.
- The value string is NOT null terminated; the length is provided in
- the value_length argument. Since it is legal to have zero-length
- values, do not use this argument to test for internal entities.
-
- For external entities, value will be null and systemId will be non-null.
- The publicId argument will be null unless a public identifier was
- provided. The notationName argument will have a non-null value only
- for unparsed entity declarations.
-*/
-
-typedef void (*XML_EntityDeclHandler) (void *userData,
- const XML_Char *entityName,
- int is_parameter_entity,
- const XML_Char *value,
- int value_length,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
-
-XMLPARSEAPI(void)
-XML_SetEntityDeclHandler(XML_Parser parser,
- XML_EntityDeclHandler handler);
-
-/* OBSOLETE -- OBSOLETE -- OBSOLETE
- This handler has been superceded by the EntityDeclHandler above.
- It is provided here for backward compatibility.
-This is called for a declaration of an unparsed (NDATA)
-entity. The base argument is whatever was set by XML_SetBase.
-The entityName, systemId and notationName arguments will never be null.
-The other arguments may be. */
-
-typedef void (*XML_UnparsedEntityDeclHandler)(void *userData,
- const XML_Char *entityName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId,
- const XML_Char *notationName);
-
-/* This is called for a declaration of notation.
-The base argument is whatever was set by XML_SetBase.
-The notationName will never be null. The other arguments can be. */
-
-typedef void (*XML_NotationDeclHandler)(void *userData,
- const XML_Char *notationName,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
-
-/* When namespace processing is enabled, these are called once for
-each namespace declaration. The call to the start and end element
-handlers occur between the calls to the start and end namespace
-declaration handlers. For an xmlns attribute, prefix will be null.
-For an xmlns="" attribute, uri will be null. */
-
-typedef void (*XML_StartNamespaceDeclHandler)(void *userData,
- const XML_Char *prefix,
- const XML_Char *uri);
-
-typedef void (*XML_EndNamespaceDeclHandler)(void *userData,
- const XML_Char *prefix);
-
-/* This is called if the document is not standalone (it has an
-external subset or a reference to a parameter entity, but does not
-have standalone="yes"). If this handler returns 0, then processing
-will not continue, and the parser will return a
-XML_ERROR_NOT_STANDALONE error. */
-
-typedef int (*XML_NotStandaloneHandler)(void *userData);
-
-/* This is called for a reference to an external parsed general entity.
-The referenced entity is not automatically parsed.
-The application can parse it immediately or later using
-XML_ExternalEntityParserCreate.
-The parser argument is the parser parsing the entity containing the reference;
-it can be passed as the parser argument to XML_ExternalEntityParserCreate.
-The systemId argument is the system identifier as specified in the entity
-declaration; it will not be null.
-The base argument is the system identifier that should be used as the base for
-resolving systemId if systemId was relative; this is set by XML_SetBase;
-it may be null.
-The publicId argument is the public identifier as specified in the entity
-declaration, or null if none was specified; the whitespace in the public
-identifier will have been normalized as required by the XML spec.
-The context argument specifies the parsing context in the format
-expected by the context argument to
-XML_ExternalEntityParserCreate; context is valid only until the handler
-returns, so if the referenced entity is to be parsed later, it must be copied.
-The handler should return 0 if processing should not continue because of
-a fatal error in the handling of the external entity.
-In this case the calling parser will return an
-XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
-Note that unlike other handlers the first argument is the parser, not
-userData. */
-
-typedef int (*XML_ExternalEntityRefHandler)(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *base,
- const XML_Char *systemId,
- const XML_Char *publicId);
-
-/* This structure is filled in by the XML_UnknownEncodingHandler
-to provide information to the parser about encodings that are unknown
-to the parser.
-The map[b] member gives information about byte sequences
-whose first byte is b.
-If map[b] is c where c is >= 0, then b by itself encodes the Unicode scalar
-value c.
-If map[b] is -1, then the byte sequence is malformed.
-If map[b] is -n, where n >= 2, then b is the first byte of an n-byte
-sequence that encodes a single Unicode scalar value.
-The data member will be passed as the first argument to the convert function.
-The convert function is used to convert multibyte sequences;
-s will point to a n-byte sequence where map[(unsigned char)*s] == -n.
-The convert function must return the Unicode scalar value
-represented by this byte sequence or -1 if the byte sequence is malformed.
-The convert function may be null if the encoding is a single-byte encoding,
-that is if map[b] >= -1 for all bytes b.
-When the parser is finished with the encoding, then if release is not null,
-it will call release passing it the data member;
-once release has been called, the convert function will not be called again.
-
-Expat places certain restrictions on the encodings that are supported
-using this mechanism.
-
-1. Every ASCII character that can appear in a well-formed XML document,
-other than the characters
-
- $@\^`{}~
-
-must be represented by a single byte, and that byte must be the
-same byte that represents that character in ASCII.
-
-2. No character may require more than 4 bytes to encode.
-
-3. All characters encoded must have Unicode scalar values <= 0xFFFF, (i.e.,
-characters that would be encoded by surrogates in UTF-16 are not
-allowed). Note that this restriction doesn't apply to the built-in
-support for UTF-8 and UTF-16.
-
-4. No Unicode character may be encoded by more than one distinct sequence
-of bytes. */
-
-typedef struct {
- int map[256];
- void *data;
- int (*convert)(void *data, const char *s);
- void (*release)(void *data);
-} XML_Encoding;
-
-/* This is called for an encoding that is unknown to the parser.
-The encodingHandlerData argument is that which was passed as the
-second argument to XML_SetUnknownEncodingHandler.
-The name argument gives the name of the encoding as specified in
-the encoding declaration.
-If the callback can provide information about the encoding,
-it must fill in the XML_Encoding structure, and return 1.
-Otherwise it must return 0.
-If info does not describe a suitable encoding,
-then the parser will return an XML_UNKNOWN_ENCODING error. */
-
-typedef int (*XML_UnknownEncodingHandler)(void *encodingHandlerData,
- const XML_Char *name,
- XML_Encoding *info);
-
-XMLPARSEAPI(void)
-XML_SetElementHandler(XML_Parser parser,
- XML_StartElementHandler start,
- XML_EndElementHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartElementHandler(XML_Parser, XML_StartElementHandler);
-
-XMLPARSEAPI(void)
-XML_SetEndElementHandler(XML_Parser, XML_EndElementHandler);
-
-XMLPARSEAPI(void)
-XML_SetCharacterDataHandler(XML_Parser parser,
- XML_CharacterDataHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetProcessingInstructionHandler(XML_Parser parser,
- XML_ProcessingInstructionHandler handler);
-XMLPARSEAPI(void)
-XML_SetCommentHandler(XML_Parser parser,
- XML_CommentHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start,
- XML_EndCdataSectionHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndCdataSectionHandler(XML_Parser parser,
- XML_EndCdataSectionHandler end);
-
-/* This sets the default handler and also inhibits expansion of
-internal entities. The entity reference will be passed to the default
-handler. */
-
-XMLPARSEAPI(void)
-XML_SetDefaultHandler(XML_Parser parser,
- XML_DefaultHandler handler);
-
-/* This sets the default handler but does not inhibit expansion of
-internal entities. The entity reference will not be passed to the
-default handler. */
-
-XMLPARSEAPI(void)
-XML_SetDefaultHandlerExpand(XML_Parser parser,
- XML_DefaultHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start,
- XML_EndDoctypeDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndDoctypeDeclHandler(XML_Parser parser,
- XML_EndDoctypeDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
- XML_UnparsedEntityDeclHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetNotationDeclHandler(XML_Parser parser,
- XML_NotationDeclHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start,
- XML_EndNamespaceDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetStartNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start);
-
-XMLPARSEAPI(void)
-XML_SetEndNamespaceDeclHandler(XML_Parser parser,
- XML_EndNamespaceDeclHandler end);
-
-XMLPARSEAPI(void)
-XML_SetNotStandaloneHandler(XML_Parser parser,
- XML_NotStandaloneHandler handler);
-
-XMLPARSEAPI(void)
-XML_SetExternalEntityRefHandler(XML_Parser parser,
- XML_ExternalEntityRefHandler handler);
-
-/* If a non-null value for arg is specified here, then it will be passed
-as the first argument to the external entity ref handler instead
-of the parser object. */
-XMLPARSEAPI(void)
-XML_SetExternalEntityRefHandlerArg(XML_Parser, void *arg);
-
-XMLPARSEAPI(void)
-XML_SetUnknownEncodingHandler(XML_Parser parser,
- XML_UnknownEncodingHandler handler,
- void *encodingHandlerData);
-
-/* This can be called within a handler for a start element, end element,
-processing instruction or character data. It causes the corresponding
-markup to be passed to the default handler. */
-XMLPARSEAPI(void)
-XML_DefaultCurrent(XML_Parser parser);
-
-/* If do_nst is non-zero, and namespace processing is in effect, and
- a name has a prefix (i.e. an explicit namespace qualifier) then
- that name is returned as a triplet in a single
- string separated by the separator character specified when the parser
- was created: URI + sep + local_name + sep + prefix.
-
- If do_nst is zero, then namespace information is returned in the
- default manner (URI + sep + local_name) whether or not the names
- has a prefix.
-*/
-
-XMLPARSEAPI(void)
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
-
-/* This value is passed as the userData argument to callbacks. */
-XMLPARSEAPI(void)
-XML_SetUserData(XML_Parser parser, void *userData);
-
-/* Returns the last value set by XML_SetUserData or null. */
-#define XML_GetUserData(parser) (*(void **)(parser))
-
-/* This is equivalent to supplying an encoding argument
-to XML_ParserCreate. It must not be called after XML_Parse
-or XML_ParseBuffer. */
-
-XMLPARSEAPI(int)
-XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
-
-/* If this function is called, then the parser will be passed
-as the first argument to callbacks instead of userData.
-The userData will still be accessible using XML_GetUserData. */
-
-XMLPARSEAPI(void)
-XML_UseParserAsHandlerArg(XML_Parser parser);
-
-/* Sets the base to be used for resolving relative URIs in system
-identifiers in declarations. Resolving relative identifiers is left
-to the application: this value will be passed through as the base
-argument to the XML_ExternalEntityRefHandler, XML_NotationDeclHandler
-and XML_UnparsedEntityDeclHandler. The base argument will be copied.
-Returns zero if out of memory, non-zero otherwise. */
-
-XMLPARSEAPI(int)
-XML_SetBase(XML_Parser parser, const XML_Char *base);
-
-XMLPARSEAPI(const XML_Char *)
-XML_GetBase(XML_Parser parser);
-
-/* Returns the number of the attribute/value pairs passed in last call
-to the XML_StartElementHandler that were specified in the start-tag
-rather than defaulted. Each attribute/value pair counts as 2; thus
-this correspondds to an index into the atts array passed to the
-XML_StartElementHandler. */
-
-XMLPARSEAPI(int)
-XML_GetSpecifiedAttributeCount(XML_Parser parser);
-
-/* Returns the index of the ID attribute passed in the last call to
-XML_StartElementHandler, or -1 if there is no ID attribute. Each
-attribute/value pair counts as 2; thus this correspondds to an index
-into the atts array passed to the XML_StartElementHandler. */
-
-XMLPARSEAPI(int)
-XML_GetIdAttributeIndex(XML_Parser parser);
-
-/* Parses some input. Returns 0 if a fatal error is detected.
-The last call to XML_Parse must have isFinal true;
-len may be zero for this call (or any other). */
-XMLPARSEAPI(int)
-XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
-
-XMLPARSEAPI(void *)
-XML_GetBuffer(XML_Parser parser, int len);
-
-XMLPARSEAPI(int)
-XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
-
-/* Creates an XML_Parser object that can parse an external general
-entity; context is a '\0'-terminated string specifying the parse
-context; encoding is a '\0'-terminated string giving the name of the
-externally specified encoding, or null if there is no externally
-specified encoding. The context string consists of a sequence of
-tokens separated by formfeeds (\f); a token consisting of a name
-specifies that the general entity of the name is open; a token of the
-form prefix=uri specifies the namespace for a particular prefix; a
-token of the form =uri specifies the default namespace. This can be
-called at any point after the first call to an
-ExternalEntityRefHandler so longer as the parser has not yet been
-freed. The new parser is completely independent and may safely be
-used in a separate thread. The handlers and userData are initialized
-from the parser argument. Returns 0 if out of memory. Otherwise
-returns a new XML_Parser object. */
-XMLPARSEAPI(XML_Parser)
-XML_ExternalEntityParserCreate(XML_Parser parser,
- const XML_Char *context,
- const XML_Char *encoding);
-
-enum XML_ParamEntityParsing {
- XML_PARAM_ENTITY_PARSING_NEVER,
- XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
- XML_PARAM_ENTITY_PARSING_ALWAYS
-};
-
-/* Controls parsing of parameter entities (including the external DTD
-subset). If parsing of parameter entities is enabled, then references
-to external parameter entities (including the external DTD subset)
-will be passed to the handler set with
-XML_SetExternalEntityRefHandler. The context passed will be 0.
-Unlike external general entities, external parameter entities can only
-be parsed synchronously. If the external parameter entity is to be
-parsed, it must be parsed during the call to the external entity ref
-handler: the complete sequence of XML_ExternalEntityParserCreate,
-XML_Parse/XML_ParseBuffer and XML_ParserFree calls must be made during
-this call. After XML_ExternalEntityParserCreate has been called to
-create the parser for the external parameter entity (context must be 0
-for this call), it is illegal to make any calls on the old parser
-until XML_ParserFree has been called on the newly created parser. If
-the library has been compiled without support for parameter entity
-parsing (ie without XML_DTD being defined), then
-XML_SetParamEntityParsing will return 0 if parsing of parameter
-entities is requested; otherwise it will return non-zero. */
-
-XMLPARSEAPI(int)
-XML_SetParamEntityParsing(XML_Parser parser,
- enum XML_ParamEntityParsing parsing);
-
-enum XML_Error {
- XML_ERROR_NONE,
- XML_ERROR_NO_MEMORY,
- XML_ERROR_SYNTAX,
- XML_ERROR_NO_ELEMENTS,
- XML_ERROR_INVALID_TOKEN,
- XML_ERROR_UNCLOSED_TOKEN,
- XML_ERROR_PARTIAL_CHAR,
- XML_ERROR_TAG_MISMATCH,
- XML_ERROR_DUPLICATE_ATTRIBUTE,
- XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
- XML_ERROR_PARAM_ENTITY_REF,
- XML_ERROR_UNDEFINED_ENTITY,
- XML_ERROR_RECURSIVE_ENTITY_REF,
- XML_ERROR_ASYNC_ENTITY,
- XML_ERROR_BAD_CHAR_REF,
- XML_ERROR_BINARY_ENTITY_REF,
- XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
- XML_ERROR_MISPLACED_XML_PI,
- XML_ERROR_UNKNOWN_ENCODING,
- XML_ERROR_INCORRECT_ENCODING,
- XML_ERROR_UNCLOSED_CDATA_SECTION,
- XML_ERROR_EXTERNAL_ENTITY_HANDLING,
- XML_ERROR_NOT_STANDALONE,
- XML_ERROR_UNEXPECTED_STATE
-};
-
-/* If XML_Parse or XML_ParseBuffer have returned 0, then XML_GetErrorCode
-returns information about the error. */
-
-XMLPARSEAPI(enum XML_Error)
-XML_GetErrorCode(XML_Parser parser);
-
-/* These functions return information about the current parse location.
-They may be called when XML_Parse or XML_ParseBuffer return 0;
-in this case the location is the location of the character at which
-the error was detected.
-They may also be called from any other callback called to report
-some parse event; in this the location is the location of the first
-of the sequence of characters that generated the event. */
-
-XMLPARSEAPI(int) XML_GetCurrentLineNumber(XML_Parser parser);
-XMLPARSEAPI(int) XML_GetCurrentColumnNumber(XML_Parser parser);
-XMLPARSEAPI(long) XML_GetCurrentByteIndex(XML_Parser parser);
-
-/* Return the number of bytes in the current event.
-Returns 0 if the event is in an internal entity. */
-
-XMLPARSEAPI(int)
-XML_GetCurrentByteCount(XML_Parser parser);
-
-/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
- the integer pointed to by offset to the offset within this buffer
- of the current parse position, and sets the integer pointed to by size
- to the size of this buffer (the number of input bytes). Otherwise
- returns a null pointer. Also returns a null pointer if a parse isn't
- active.
-
- NOTE: The character pointer returned should not be used outside
- the handler that makes the call. */
-
-XMLPARSEAPI(const char *)
-XML_GetInputContext(XML_Parser parser,
- int *offset,
- int *size);
-
-/* For backwards compatibility with previous versions. */
-#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
-#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
-#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
-
-/* Frees memory used by the parser. */
-XMLPARSEAPI(void)
-XML_ParserFree(XML_Parser parser);
-
-/* Returns a string describing the error. */
-XMLPARSEAPI(const XML_LChar *)
-XML_ErrorString(int code);
-
-/* Return a string containing the version number of this expat */
-XMLPARSEAPI(const XML_LChar *)
-XML_ExpatVersion(void);
-
-typedef struct {
- int major;
- int minor;
- int micro;
-} XML_Expat_Version;
-
-/* Return an XML_Expat_Version structure containing numeric version
- number information for this version of expat */
-
-XMLPARSEAPI(XML_Expat_Version)
-XML_ExpatVersionInfo(void);
-
-#define XML_MAJOR_VERSION 1
-#define XML_MINOR_VERSION 95
-#define XML_MICRO_VERSION 2
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not XmlParse_INCLUDED */
diff --git a/Utilities/cmexpat/expatConfig.h.in b/Utilities/cmexpat/expatConfig.h.in
deleted file mode 100644
index 8f9669a59..000000000
--- a/Utilities/cmexpat/expatConfig.h.in
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "cm_expat_mangle.h"
-#if defined(_WIN32) || defined(WIN32)
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#undef WIN32_LEAN_AND_MEAN
-#include <memory.h>
-#include <string.h>
-#define XML_BYTE_ORDER 12
-
-#else
-
-#cmakedefine CMEXPAT_BIGENDIAN
-#ifdef CMEXPAT_BIGENDIAN
-# define XML_BYTE_ORDER 21
-#else
-# define XML_BYTE_ORDER 12
-#endif
-
-#endif
-
-#define XML_NS
-#define XML_DTD
-#define XML_CONTEXT_BYTES 1024
-
-#if defined ( _MSC_VER )
-#pragma warning ( disable : 4100 )
-#pragma warning ( disable : 4127 )
-#pragma warning ( disable : 4244 )
-#pragma warning ( disable : 4251 )
-#pragma warning ( disable : 4305 )
-#pragma warning ( disable : 4309 )
-#pragma warning ( disable : 4702 )
-#pragma warning ( disable : 4706 )
-#pragma warning ( disable : 4786 )
-#pragma warning ( disable : 4057 )
-#pragma warning ( disable : 4189 )
-#pragma warning ( disable : 4505 )
-#endif
-
-#define VERSION "1.95.2"
-
-#define cmExpatUnused(x) (void)x
diff --git a/Utilities/cmexpat/expatDllConfig.h.in b/Utilities/cmexpat/expatDllConfig.h.in
deleted file mode 100644
index eaaf4b018..000000000
--- a/Utilities/cmexpat/expatDllConfig.h.in
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _expatDllConfig_h
-#define _expatDllConfig_h
-
-#cmakedefine CM_EXPAT_STATIC
-
-#endif
diff --git a/Utilities/cmexpat/expat_config.h.cmake b/Utilities/cmexpat/expat_config.h.cmake
new file mode 100644
index 000000000..ad540d604
--- /dev/null
+++ b/Utilities/cmexpat/expat_config.h.cmake
@@ -0,0 +1,76 @@
+/* expat_config.h.in. Generated from configure.in by autoheader. */
+
+/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
+#cmakedefine BYTEORDER @BYTEORDER@
+
+/* Define to 1 if you have the `bcopy' function. */
+#cmakedefine HAVE_BCOPY
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#cmakedefine HAVE_DLFCN_H
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#cmakedefine HAVE_FCNTL_H
+
+/* Define to 1 if you have the `getpagesize' function. */
+#cmakedefine HAVE_GETPAGESIZE
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H
+
+/* Define to 1 if you have the `memmove' function. */
+#cmakedefine HAVE_MEMMOVE
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H
+
+/* Define to 1 if you have a working `mmap' system call. */
+#cmakedefine HAVE_MMAP
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#cmakedefine HAVE_STDLIB_H
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#cmakedefine HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#cmakedefine HAVE_SYS_TYPES_H
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#cmakedefine HAVE_UNISTD_H
+
+/* Define to 1 if you have the ANSI C header files. */
+#cmakedefine STDC_HEADERS
+
+/* whether byteorder is bigendian */
+#cmakedefine WORDS_BIGENDIAN
+
+/* Define to specify how much context to retain around the current parse
+ point. */
+#define XML_CONTEXT_BYTES 1024
+
+/* Define to make parameter entity parsing functionality available. */
+/* #undef XML_DTD */
+
+/* Define to make XML Namespaces functionality available. */
+/* #undef XML_NS */
+
+/* Define to __FUNCTION__ or "" if `__func__' does not conform to ANSI C. */
+#ifdef _MSC_VER
+# define __func__ __FUNCTION__
+#endif
+
+/* Define to `long' if <sys/types.h> does not define. */
+#cmakedefine off_t @OFF_T@
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#cmakedefine size_t @SIZE_T@
diff --git a/Utilities/cmexpat/iasciitab.h b/Utilities/cmexpat/iasciitab.h
deleted file mode 100644
index 55dbc398b..000000000
--- a/Utilities/cmexpat/iasciitab.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
-/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
-/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
-/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
-/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
-/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
-/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
-/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
-/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
-/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
-/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
-/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
-/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
-/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
-/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/Utilities/cmexpat/latin1tab.h b/Utilities/cmexpat/latin1tab.h
deleted file mode 100644
index 178b1d186..000000000
--- a/Utilities/cmexpat/latin1tab.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
-/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
-/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
-/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
-/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
-/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/Utilities/cmexpat/lib/ascii.h b/Utilities/cmexpat/lib/ascii.h
new file mode 100644
index 000000000..d10530b09
--- /dev/null
+++ b/Utilities/cmexpat/lib/ascii.h
@@ -0,0 +1,92 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#define ASCII_A 0x41
+#define ASCII_B 0x42
+#define ASCII_C 0x43
+#define ASCII_D 0x44
+#define ASCII_E 0x45
+#define ASCII_F 0x46
+#define ASCII_G 0x47
+#define ASCII_H 0x48
+#define ASCII_I 0x49
+#define ASCII_J 0x4A
+#define ASCII_K 0x4B
+#define ASCII_L 0x4C
+#define ASCII_M 0x4D
+#define ASCII_N 0x4E
+#define ASCII_O 0x4F
+#define ASCII_P 0x50
+#define ASCII_Q 0x51
+#define ASCII_R 0x52
+#define ASCII_S 0x53
+#define ASCII_T 0x54
+#define ASCII_U 0x55
+#define ASCII_V 0x56
+#define ASCII_W 0x57
+#define ASCII_X 0x58
+#define ASCII_Y 0x59
+#define ASCII_Z 0x5A
+
+#define ASCII_a 0x61
+#define ASCII_b 0x62
+#define ASCII_c 0x63
+#define ASCII_d 0x64
+#define ASCII_e 0x65
+#define ASCII_f 0x66
+#define ASCII_g 0x67
+#define ASCII_h 0x68
+#define ASCII_i 0x69
+#define ASCII_j 0x6A
+#define ASCII_k 0x6B
+#define ASCII_l 0x6C
+#define ASCII_m 0x6D
+#define ASCII_n 0x6E
+#define ASCII_o 0x6F
+#define ASCII_p 0x70
+#define ASCII_q 0x71
+#define ASCII_r 0x72
+#define ASCII_s 0x73
+#define ASCII_t 0x74
+#define ASCII_u 0x75
+#define ASCII_v 0x76
+#define ASCII_w 0x77
+#define ASCII_x 0x78
+#define ASCII_y 0x79
+#define ASCII_z 0x7A
+
+#define ASCII_0 0x30
+#define ASCII_1 0x31
+#define ASCII_2 0x32
+#define ASCII_3 0x33
+#define ASCII_4 0x34
+#define ASCII_5 0x35
+#define ASCII_6 0x36
+#define ASCII_7 0x37
+#define ASCII_8 0x38
+#define ASCII_9 0x39
+
+#define ASCII_TAB 0x09
+#define ASCII_SPACE 0x20
+#define ASCII_EXCL 0x21
+#define ASCII_QUOT 0x22
+#define ASCII_AMP 0x26
+#define ASCII_APOS 0x27
+#define ASCII_MINUS 0x2D
+#define ASCII_PERIOD 0x2E
+#define ASCII_COLON 0x3A
+#define ASCII_SEMI 0x3B
+#define ASCII_LT 0x3C
+#define ASCII_EQUALS 0x3D
+#define ASCII_GT 0x3E
+#define ASCII_LSQB 0x5B
+#define ASCII_RSQB 0x5D
+#define ASCII_UNDERSCORE 0x5F
+#define ASCII_LPAREN 0x28
+#define ASCII_RPAREN 0x29
+#define ASCII_FF 0x0C
+#define ASCII_SLASH 0x2F
+#define ASCII_HASH 0x23
+#define ASCII_PIPE 0x7C
+#define ASCII_COMMA 0x2C
diff --git a/Utilities/cmexpat/lib/asciitab.h b/Utilities/cmexpat/lib/asciitab.h
new file mode 100644
index 000000000..79a15c28c
--- /dev/null
+++ b/Utilities/cmexpat/lib/asciitab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_CR, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/Utilities/cmexpat/lib/expat.h b/Utilities/cmexpat/lib/expat.h
new file mode 100644
index 000000000..7e5bbb7e3
--- /dev/null
+++ b/Utilities/cmexpat/lib/expat.h
@@ -0,0 +1,1057 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_INCLUDED
+#define Expat_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XML_SetProcessingInstructionHandler XML_SetProcessingInstrHandler
+#define XML_SetUnparsedEntityDeclHandler XML_SetUnparsedEntDeclHandler
+#define XML_SetStartNamespaceDeclHandler XML_SetStartNamespcDeclHandler
+#define XML_SetExternalEntityRefHandlerArg XML_SetExternalEntRefHandlerArg
+#endif
+
+#include <stdlib.h>
+#include "expat_external.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct XML_ParserStruct;
+typedef struct XML_ParserStruct *XML_Parser;
+
+typedef unsigned char XML_Bool;
+#define XML_TRUE ((XML_Bool) 1)
+#define XML_FALSE ((XML_Bool) 0)
+
+/* The XML_Status enum gives the possible return values for several
+ API functions. The preprocessor #defines are included so this
+ stanza can be added to code that still needs to support older
+ versions of Expat 1.95.x:
+
+ #ifndef XML_STATUS_OK
+ #define XML_STATUS_OK 1
+ #define XML_STATUS_ERROR 0
+ #endif
+
+ Otherwise, the #define hackery is quite ugly and would have been
+ dropped.
+*/
+enum XML_Status {
+ XML_STATUS_ERROR = 0,
+#define XML_STATUS_ERROR XML_STATUS_ERROR
+ XML_STATUS_OK = 1,
+#define XML_STATUS_OK XML_STATUS_OK
+ XML_STATUS_SUSPENDED = 2
+#define XML_STATUS_SUSPENDED XML_STATUS_SUSPENDED
+};
+
+enum XML_Error {
+ XML_ERROR_NONE,
+ XML_ERROR_NO_MEMORY,
+ XML_ERROR_SYNTAX,
+ XML_ERROR_NO_ELEMENTS,
+ XML_ERROR_INVALID_TOKEN,
+ XML_ERROR_UNCLOSED_TOKEN,
+ XML_ERROR_PARTIAL_CHAR,
+ XML_ERROR_TAG_MISMATCH,
+ XML_ERROR_DUPLICATE_ATTRIBUTE,
+ XML_ERROR_JUNK_AFTER_DOC_ELEMENT,
+ XML_ERROR_PARAM_ENTITY_REF,
+ XML_ERROR_UNDEFINED_ENTITY,
+ XML_ERROR_RECURSIVE_ENTITY_REF,
+ XML_ERROR_ASYNC_ENTITY,
+ XML_ERROR_BAD_CHAR_REF,
+ XML_ERROR_BINARY_ENTITY_REF,
+ XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF,
+ XML_ERROR_MISPLACED_XML_PI,
+ XML_ERROR_UNKNOWN_ENCODING,
+ XML_ERROR_INCORRECT_ENCODING,
+ XML_ERROR_UNCLOSED_CDATA_SECTION,
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING,
+ XML_ERROR_NOT_STANDALONE,
+ XML_ERROR_UNEXPECTED_STATE,
+ XML_ERROR_ENTITY_DECLARED_IN_PE,
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD,
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING,
+ /* Added in 1.95.7. */
+ XML_ERROR_UNBOUND_PREFIX,
+ /* Added in 1.95.8. */
+ XML_ERROR_UNDECLARING_PREFIX,
+ XML_ERROR_INCOMPLETE_PE,
+ XML_ERROR_XML_DECL,
+ XML_ERROR_TEXT_DECL,
+ XML_ERROR_PUBLICID,
+ XML_ERROR_SUSPENDED,
+ XML_ERROR_NOT_SUSPENDED,
+ XML_ERROR_ABORTED,
+ XML_ERROR_FINISHED,
+ XML_ERROR_SUSPEND_PE,
+ /* Added in 2.0. */
+ XML_ERROR_RESERVED_PREFIX_XML,
+ XML_ERROR_RESERVED_PREFIX_XMLNS,
+ XML_ERROR_RESERVED_NAMESPACE_URI,
+ /* Added in 2.2.1. */
+ XML_ERROR_INVALID_ARGUMENT
+};
+
+enum XML_Content_Type {
+ XML_CTYPE_EMPTY = 1,
+ XML_CTYPE_ANY,
+ XML_CTYPE_MIXED,
+ XML_CTYPE_NAME,
+ XML_CTYPE_CHOICE,
+ XML_CTYPE_SEQ
+};
+
+enum XML_Content_Quant {
+ XML_CQUANT_NONE,
+ XML_CQUANT_OPT,
+ XML_CQUANT_REP,
+ XML_CQUANT_PLUS
+};
+
+/* If type == XML_CTYPE_EMPTY or XML_CTYPE_ANY, then quant will be
+ XML_CQUANT_NONE, and the other fields will be zero or NULL.
+ If type == XML_CTYPE_MIXED, then quant will be NONE or REP and
+ numchildren will contain number of elements that may be mixed in
+ and children point to an array of XML_Content cells that will be
+ all of XML_CTYPE_NAME type with no quantification.
+
+ If type == XML_CTYPE_NAME, then the name points to the name, and
+ the numchildren field will be zero and children will be NULL. The
+ quant fields indicates any quantifiers placed on the name.
+
+ CHOICE and SEQ will have name NULL, the number of children in
+ numchildren and children will point, recursively, to an array
+ of XML_Content cells.
+
+ The EMPTY, ANY, and MIXED types will only occur at top level.
+*/
+
+typedef struct XML_cp XML_Content;
+
+struct XML_cp {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ XML_Char * name;
+ unsigned int numchildren;
+ XML_Content * children;
+};
+
+
+/* This is called for an element declaration. See above for
+ description of the model argument. It's the caller's responsibility
+ to free model when finished with it.
+*/
+typedef void (XMLCALL *XML_ElementDeclHandler) (void *userData,
+ const XML_Char *name,
+ XML_Content *model);
+
+XMLPARSEAPI(void)
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl);
+
+/* The Attlist declaration handler is called for *each* attribute. So
+ a single Attlist declaration with multiple attributes declared will
+ generate multiple calls to this handler. The "default" parameter
+ may be NULL in the case of the "#IMPLIED" or "#REQUIRED"
+ keyword. The "isrequired" parameter will be true and the default
+ value will be NULL in the case of "#REQUIRED". If "isrequired" is
+ true and default is non-NULL, then this is a "#FIXED" default.
+*/
+typedef void (XMLCALL *XML_AttlistDeclHandler) (
+ void *userData,
+ const XML_Char *elname,
+ const XML_Char *attname,
+ const XML_Char *att_type,
+ const XML_Char *dflt,
+ int isrequired);
+
+XMLPARSEAPI(void)
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl);
+
+/* The XML declaration handler is called for *both* XML declarations
+ and text declarations. The way to distinguish is that the version
+ parameter will be NULL for text declarations. The encoding
+ parameter may be NULL for XML declarations. The standalone
+ parameter will be -1, 0, or 1 indicating respectively that there
+ was no standalone parameter in the declaration, that it was given
+ as no, or that it was given as yes.
+*/
+typedef void (XMLCALL *XML_XmlDeclHandler) (void *userData,
+ const XML_Char *version,
+ const XML_Char *encoding,
+ int standalone);
+
+XMLPARSEAPI(void)
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler xmldecl);
+
+
+typedef struct {
+ void *(*malloc_fcn)(size_t size);
+ void *(*realloc_fcn)(void *ptr, size_t size);
+ void (*free_fcn)(void *ptr);
+} XML_Memory_Handling_Suite;
+
+/* Constructs a new parser; encoding is the encoding specified by the
+ external protocol or NULL if there is none specified.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate(const XML_Char *encoding);
+
+/* Constructs a new parser and namespace processor. Element type
+ names and attribute names that belong to a namespace will be
+ expanded; unprefixed attribute names are never expanded; unprefixed
+ element type names are expanded only if there is a default
+ namespace. The expanded name is the concatenation of the namespace
+ URI, the namespace separator character, and the local part of the
+ name. If the namespace separator is '\0' then the namespace URI
+ and the local part will be concatenated without any separator.
+ It is a programming error to use the separator '\0' with namespace
+ triplets (see XML_SetReturnNSTriplet).
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreateNS(const XML_Char *encoding, XML_Char namespaceSeparator);
+
+
+/* Constructs a new parser using the memory management suite referred to
+ by memsuite. If memsuite is NULL, then use the standard library memory
+ suite. If namespaceSeparator is non-NULL it creates a parser with
+ namespace processing as described above. The character pointed at
+ will serve as the namespace separator.
+
+ All further memory operations used for the created parser will come from
+ the given suite.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ParserCreate_MM(const XML_Char *encoding,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *namespaceSeparator);
+
+/* Prepare a parser object to be re-used. This is particularly
+ valuable when memory allocation overhead is disproportionatly high,
+ such as when a large number of small documnents need to be parsed.
+ All handlers are cleared from the parser, except for the
+ unknownEncodingHandler. The parser's external state is re-initialized
+ except for the values of ns and ns_triplets.
+
+ Added in Expat 1.95.3.
+*/
+XMLPARSEAPI(XML_Bool)
+XML_ParserReset(XML_Parser parser, const XML_Char *encoding);
+
+/* atts is array of name/value pairs, terminated by 0;
+ names and values are 0 terminated.
+*/
+typedef void (XMLCALL *XML_StartElementHandler) (void *userData,
+ const XML_Char *name,
+ const XML_Char **atts);
+
+typedef void (XMLCALL *XML_EndElementHandler) (void *userData,
+ const XML_Char *name);
+
+
+/* s is not 0 terminated. */
+typedef void (XMLCALL *XML_CharacterDataHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* target and data are 0 terminated */
+typedef void (XMLCALL *XML_ProcessingInstructionHandler) (
+ void *userData,
+ const XML_Char *target,
+ const XML_Char *data);
+
+/* data is 0 terminated */
+typedef void (XMLCALL *XML_CommentHandler) (void *userData,
+ const XML_Char *data);
+
+typedef void (XMLCALL *XML_StartCdataSectionHandler) (void *userData);
+typedef void (XMLCALL *XML_EndCdataSectionHandler) (void *userData);
+
+/* This is called for any characters in the XML document for which
+ there is no applicable handler. This includes both characters that
+ are part of markup which is of a kind that is not reported
+ (comments, markup declarations), or characters that are part of a
+ construct which could be reported but for which no handler has been
+ supplied. The characters are passed exactly as they were in the XML
+ document except that they will be encoded in UTF-8 or UTF-16.
+ Line boundaries are not normalized. Note that a byte order mark
+ character is not passed to the default handler. There are no
+ guarantees about how characters are divided between calls to the
+ default handler: for example, a comment might be split between
+ multiple calls.
+*/
+typedef void (XMLCALL *XML_DefaultHandler) (void *userData,
+ const XML_Char *s,
+ int len);
+
+/* This is called for the start of the DOCTYPE declaration, before
+ any DTD or internal subset is parsed.
+*/
+typedef void (XMLCALL *XML_StartDoctypeDeclHandler) (
+ void *userData,
+ const XML_Char *doctypeName,
+ const XML_Char *sysid,
+ const XML_Char *pubid,
+ int has_internal_subset);
+
+/* This is called for the start of the DOCTYPE declaration when the
+ closing > is encountered, but after processing any external
+ subset.
+*/
+typedef void (XMLCALL *XML_EndDoctypeDeclHandler)(void *userData);
+
+/* This is called for entity declarations. The is_parameter_entity
+ argument will be non-zero if the entity is a parameter entity, zero
+ otherwise.
+
+ For internal entities (<!ENTITY foo "bar">), value will
+ be non-NULL and systemId, publicID, and notationName will be NULL.
+ The value string is NOT nul-terminated; the length is provided in
+ the value_length argument. Since it is legal to have zero-length
+ values, do not use this argument to test for internal entities.
+
+ For external entities, value will be NULL and systemId will be
+ non-NULL. The publicId argument will be NULL unless a public
+ identifier was provided. The notationName argument will have a
+ non-NULL value only for unparsed entity declarations.
+
+ Note that is_parameter_entity can't be changed to XML_Bool, since
+ that would break binary compatibility.
+*/
+typedef void (XMLCALL *XML_EntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity,
+ const XML_Char *value,
+ int value_length,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+XMLPARSEAPI(void)
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler);
+
+/* OBSOLETE -- OBSOLETE -- OBSOLETE
+ This handler has been superseded by the EntityDeclHandler above.
+ It is provided here for backward compatibility.
+
+ This is called for a declaration of an unparsed (NDATA) entity.
+ The base argument is whatever was set by XML_SetBase. The
+ entityName, systemId and notationName arguments will never be
+ NULL. The other arguments may be.
+*/
+typedef void (XMLCALL *XML_UnparsedEntityDeclHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId,
+ const XML_Char *notationName);
+
+/* This is called for a declaration of notation. The base argument is
+ whatever was set by XML_SetBase. The notationName will never be
+ NULL. The other arguments can be.
+*/
+typedef void (XMLCALL *XML_NotationDeclHandler) (
+ void *userData,
+ const XML_Char *notationName,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* When namespace processing is enabled, these are called once for
+ each namespace declaration. The call to the start and end element
+ handlers occur between the calls to the start and end namespace
+ declaration handlers. For an xmlns attribute, prefix will be
+ NULL. For an xmlns="" attribute, uri will be NULL.
+*/
+typedef void (XMLCALL *XML_StartNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix,
+ const XML_Char *uri);
+
+typedef void (XMLCALL *XML_EndNamespaceDeclHandler) (
+ void *userData,
+ const XML_Char *prefix);
+
+/* This is called if the document is not standalone, that is, it has an
+ external subset or a reference to a parameter entity, but does not
+ have standalone="yes". If this handler returns XML_STATUS_ERROR,
+ then processing will not continue, and the parser will return a
+ XML_ERROR_NOT_STANDALONE error.
+ If parameter entity parsing is enabled, then in addition to the
+ conditions above this handler will only be called if the referenced
+ entity was actually read.
+*/
+typedef int (XMLCALL *XML_NotStandaloneHandler) (void *userData);
+
+/* This is called for a reference to an external parsed general
+ entity. The referenced entity is not automatically parsed. The
+ application can parse it immediately or later using
+ XML_ExternalEntityParserCreate.
+
+ The parser argument is the parser parsing the entity containing the
+ reference; it can be passed as the parser argument to
+ XML_ExternalEntityParserCreate. The systemId argument is the
+ system identifier as specified in the entity declaration; it will
+ not be NULL.
+
+ The base argument is the system identifier that should be used as
+ the base for resolving systemId if systemId was relative; this is
+ set by XML_SetBase; it may be NULL.
+
+ The publicId argument is the public identifier as specified in the
+ entity declaration, or NULL if none was specified; the whitespace
+ in the public identifier will have been normalized as required by
+ the XML spec.
+
+ The context argument specifies the parsing context in the format
+ expected by the context argument to XML_ExternalEntityParserCreate;
+ context is valid only until the handler returns, so if the
+ referenced entity is to be parsed later, it must be copied.
+ context is NULL only when the entity is a parameter entity.
+
+ The handler should return XML_STATUS_ERROR if processing should not
+ continue because of a fatal error in the handling of the external
+ entity. In this case the calling parser will return an
+ XML_ERROR_EXTERNAL_ENTITY_HANDLING error.
+
+ Note that unlike other handlers the first argument is the parser,
+ not userData.
+*/
+typedef int (XMLCALL *XML_ExternalEntityRefHandler) (
+ XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *base,
+ const XML_Char *systemId,
+ const XML_Char *publicId);
+
+/* This is called in two situations:
+ 1) An entity reference is encountered for which no declaration
+ has been read *and* this is not an error.
+ 2) An internal entity reference is read, but not expanded, because
+ XML_SetDefaultHandler has been called.
+ Note: skipped parameter entities in declarations and skipped general
+ entities in attribute values cannot be reported, because
+ the event would be out of sync with the reporting of the
+ declarations or attribute values
+*/
+typedef void (XMLCALL *XML_SkippedEntityHandler) (
+ void *userData,
+ const XML_Char *entityName,
+ int is_parameter_entity);
+
+/* This structure is filled in by the XML_UnknownEncodingHandler to
+ provide information to the parser about encodings that are unknown
+ to the parser.
+
+ The map[b] member gives information about byte sequences whose
+ first byte is b.
+
+ If map[b] is c where c is >= 0, then b by itself encodes the
+ Unicode scalar value c.
+
+ If map[b] is -1, then the byte sequence is malformed.
+
+ If map[b] is -n, where n >= 2, then b is the first byte of an
+ n-byte sequence that encodes a single Unicode scalar value.
+
+ The data member will be passed as the first argument to the convert
+ function.
+
+ The convert function is used to convert multibyte sequences; s will
+ point to a n-byte sequence where map[(unsigned char)*s] == -n. The
+ convert function must return the Unicode scalar value represented
+ by this byte sequence or -1 if the byte sequence is malformed.
+
+ The convert function may be NULL if the encoding is a single-byte
+ encoding, that is if map[b] >= -1 for all bytes b.
+
+ When the parser is finished with the encoding, then if release is
+ not NULL, it will call release passing it the data member; once
+ release has been called, the convert function will not be called
+ again.
+
+ Expat places certain restrictions on the encodings that are supported
+ using this mechanism.
+
+ 1. Every ASCII character that can appear in a well-formed XML document,
+ other than the characters
+
+ $@\^`{}~
+
+ must be represented by a single byte, and that byte must be the
+ same byte that represents that character in ASCII.
+
+ 2. No character may require more than 4 bytes to encode.
+
+ 3. All characters encoded must have Unicode scalar values <=
+ 0xFFFF, (i.e., characters that would be encoded by surrogates in
+ UTF-16 are not allowed). Note that this restriction doesn't
+ apply to the built-in support for UTF-8 and UTF-16.
+
+ 4. No Unicode character may be encoded by more than one distinct
+ sequence of bytes.
+*/
+typedef struct {
+ int map[256];
+ void *data;
+ int (XMLCALL *convert)(void *data, const char *s);
+ void (XMLCALL *release)(void *data);
+} XML_Encoding;
+
+/* This is called for an encoding that is unknown to the parser.
+
+ The encodingHandlerData argument is that which was passed as the
+ second argument to XML_SetUnknownEncodingHandler.
+
+ The name argument gives the name of the encoding as specified in
+ the encoding declaration.
+
+ If the callback can provide information about the encoding, it must
+ fill in the XML_Encoding structure, and return XML_STATUS_OK.
+ Otherwise it must return XML_STATUS_ERROR.
+
+ If info does not describe a suitable encoding, then the parser will
+ return an XML_UNKNOWN_ENCODING error.
+*/
+typedef int (XMLCALL *XML_UnknownEncodingHandler) (
+ void *encodingHandlerData,
+ const XML_Char *name,
+ XML_Encoding *info);
+
+XMLPARSEAPI(void)
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler);
+XMLPARSEAPI(void)
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end);
+
+/* This sets the default handler and also inhibits expansion of
+ internal entities. These entity references will be passed to the
+ default handler, or to the skipped entity handler, if one is set.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+/* This sets the default handler but does not inhibit expansion of
+ internal entities. The entity reference will not be passed to the
+ default handler.
+*/
+XMLPARSEAPI(void)
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start);
+
+XMLPARSEAPI(void)
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end);
+
+XMLPARSEAPI(void)
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler);
+
+/* If a non-NULL value for arg is specified here, then it will be
+ passed as the first argument to the external entity ref handler
+ instead of the parser object.
+*/
+XMLPARSEAPI(void)
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser,
+ void *arg);
+
+XMLPARSEAPI(void)
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler);
+
+XMLPARSEAPI(void)
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *encodingHandlerData);
+
+/* This can be called within a handler for a start element, end
+ element, processing instruction or character data. It causes the
+ corresponding markup to be passed to the default handler.
+*/
+XMLPARSEAPI(void)
+XML_DefaultCurrent(XML_Parser parser);
+
+/* If do_nst is non-zero, and namespace processing is in effect, and
+ a name has a prefix (i.e. an explicit namespace qualifier) then
+ that name is returned as a triplet in a single string separated by
+ the separator character specified when the parser was created: URI
+ + sep + local_name + sep + prefix.
+
+ If do_nst is zero, then namespace information is returned in the
+ default manner (URI + sep + local_name) whether or not the name
+ has a prefix.
+
+ Note: Calling XML_SetReturnNSTriplet after XML_Parse or
+ XML_ParseBuffer has no effect.
+*/
+
+XMLPARSEAPI(void)
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst);
+
+/* This value is passed as the userData argument to callbacks. */
+XMLPARSEAPI(void)
+XML_SetUserData(XML_Parser parser, void *userData);
+
+/* Returns the last value set by XML_SetUserData or NULL. */
+#define XML_GetUserData(parser) (*(void **)(parser))
+
+/* This is equivalent to supplying an encoding argument to
+ XML_ParserCreate. On success XML_SetEncoding returns non-zero,
+ zero otherwise.
+ Note: Calling XML_SetEncoding after XML_Parse or XML_ParseBuffer
+ has no effect and returns XML_STATUS_ERROR.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetEncoding(XML_Parser parser, const XML_Char *encoding);
+
+/* If this function is called, then the parser will be passed as the
+ first argument to callbacks instead of userData. The userData will
+ still be accessible using XML_GetUserData.
+*/
+XMLPARSEAPI(void)
+XML_UseParserAsHandlerArg(XML_Parser parser);
+
+/* If useDTD == XML_TRUE is passed to this function, then the parser
+ will assume that there is an external subset, even if none is
+ specified in the document. In such a case the parser will call the
+ externalEntityRefHandler with a value of NULL for the systemId
+ argument (the publicId and context arguments will be NULL as well).
+ Note: For the purpose of checking WFC: Entity Declared, passing
+ useDTD == XML_TRUE will make the parser behave as if the document
+ had a DTD with an external subset.
+ Note: If this function is called, then this must be done before
+ the first call to XML_Parse or XML_ParseBuffer, since it will
+ have no effect after that. Returns
+ XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING.
+ Note: If the document does not have a DOCTYPE declaration at all,
+ then startDoctypeDeclHandler and endDoctypeDeclHandler will not
+ be called, despite an external subset being parsed.
+ Note: If XML_DTD is not defined when Expat is compiled, returns
+ XML_ERROR_FEATURE_REQUIRES_XML_DTD.
+ Note: If parser == NULL, returns XML_ERROR_INVALID_ARGUMENT.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD);
+
+
+/* Sets the base to be used for resolving relative URIs in system
+ identifiers in declarations. Resolving relative identifiers is
+ left to the application: this value will be passed through as the
+ base argument to the XML_ExternalEntityRefHandler,
+ XML_NotationDeclHandler and XML_UnparsedEntityDeclHandler. The base
+ argument will be copied. Returns XML_STATUS_ERROR if out of memory,
+ XML_STATUS_OK otherwise.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_SetBase(XML_Parser parser, const XML_Char *base);
+
+XMLPARSEAPI(const XML_Char *)
+XML_GetBase(XML_Parser parser);
+
+/* Returns the number of the attribute/value pairs passed in last call
+ to the XML_StartElementHandler that were specified in the start-tag
+ rather than defaulted. Each attribute/value pair counts as 2; thus
+ this correspondds to an index into the atts array passed to the
+ XML_StartElementHandler. Returns -1 if parser == NULL.
+*/
+XMLPARSEAPI(int)
+XML_GetSpecifiedAttributeCount(XML_Parser parser);
+
+/* Returns the index of the ID attribute passed in the last call to
+ XML_StartElementHandler, or -1 if there is no ID attribute or
+ parser == NULL. Each attribute/value pair counts as 2; thus this
+ correspondds to an index into the atts array passed to the
+ XML_StartElementHandler.
+*/
+XMLPARSEAPI(int)
+XML_GetIdAttributeIndex(XML_Parser parser);
+
+#ifdef XML_ATTR_INFO
+/* Source file byte offsets for the start and end of attribute names and values.
+ The value indices are exclusive of surrounding quotes; thus in a UTF-8 source
+ file an attribute value of "blah" will yield:
+ info->valueEnd - info->valueStart = 4 bytes.
+*/
+typedef struct {
+ XML_Index nameStart; /* Offset to beginning of the attribute name. */
+ XML_Index nameEnd; /* Offset after the attribute name's last byte. */
+ XML_Index valueStart; /* Offset to beginning of the attribute value. */
+ XML_Index valueEnd; /* Offset after the attribute value's last byte. */
+} XML_AttrInfo;
+
+/* Returns an array of XML_AttrInfo structures for the attribute/value pairs
+ passed in last call to the XML_StartElementHandler that were specified
+ in the start-tag rather than defaulted. Each attribute/value pair counts
+ as 1; thus the number of entries in the array is
+ XML_GetSpecifiedAttributeCount(parser) / 2.
+*/
+XMLPARSEAPI(const XML_AttrInfo *)
+XML_GetAttributeInfo(XML_Parser parser);
+#endif
+
+/* Parses some input. Returns XML_STATUS_ERROR if a fatal error is
+ detected. The last call to XML_Parse must have isFinal true; len
+ may be zero for this call (or any other).
+
+ Though the return values for these functions has always been
+ described as a Boolean value, the implementation, at least for the
+ 1.95.x series, has always returned exactly one of the XML_Status
+ values.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);
+
+XMLPARSEAPI(void *)
+XML_GetBuffer(XML_Parser parser, int len);
+
+XMLPARSEAPI(enum XML_Status)
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal);
+
+/* Stops parsing, causing XML_Parse() or XML_ParseBuffer() to return.
+ Must be called from within a call-back handler, except when aborting
+ (resumable = 0) an already suspended parser. Some call-backs may
+ still follow because they would otherwise get lost. Examples:
+ - endElementHandler() for empty elements when stopped in
+ startElementHandler(),
+ - endNameSpaceDeclHandler() when stopped in endElementHandler(),
+ and possibly others.
+
+ Can be called from most handlers, including DTD related call-backs,
+ except when parsing an external parameter entity and resumable != 0.
+ Returns XML_STATUS_OK when successful, XML_STATUS_ERROR otherwise.
+ Possible error codes:
+ - XML_ERROR_SUSPENDED: when suspending an already suspended parser.
+ - XML_ERROR_FINISHED: when the parser has already finished.
+ - XML_ERROR_SUSPEND_PE: when suspending while parsing an external PE.
+
+ When resumable != 0 (true) then parsing is suspended, that is,
+ XML_Parse() and XML_ParseBuffer() return XML_STATUS_SUSPENDED.
+ Otherwise, parsing is aborted, that is, XML_Parse() and XML_ParseBuffer()
+ return XML_STATUS_ERROR with error code XML_ERROR_ABORTED.
+
+ *Note*:
+ This will be applied to the current parser instance only, that is, if
+ there is a parent parser then it will continue parsing when the
+ externalEntityRefHandler() returns. It is up to the implementation of
+ the externalEntityRefHandler() to call XML_StopParser() on the parent
+ parser (recursively), if one wants to stop parsing altogether.
+
+ When suspended, parsing can be resumed by calling XML_ResumeParser().
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_StopParser(XML_Parser parser, XML_Bool resumable);
+
+/* Resumes parsing after it has been suspended with XML_StopParser().
+ Must not be called from within a handler call-back. Returns same
+ status codes as XML_Parse() or XML_ParseBuffer().
+ Additional error code XML_ERROR_NOT_SUSPENDED possible.
+
+ *Note*:
+ This must be called on the most deeply nested child parser instance
+ first, and on its parent parser only after the child parser has finished,
+ to be applied recursively until the document entity's parser is restarted.
+ That is, the parent parser will not resume by itself and it is up to the
+ application to call XML_ResumeParser() on it at the appropriate moment.
+*/
+XMLPARSEAPI(enum XML_Status)
+XML_ResumeParser(XML_Parser parser);
+
+enum XML_Parsing {
+ XML_INITIALIZED,
+ XML_PARSING,
+ XML_FINISHED,
+ XML_SUSPENDED
+};
+
+typedef struct {
+ enum XML_Parsing parsing;
+ XML_Bool finalBuffer;
+} XML_ParsingStatus;
+
+/* Returns status of parser with respect to being initialized, parsing,
+ finished, or suspended and processing the final buffer.
+ XXX XML_Parse() and XML_ParseBuffer() should return XML_ParsingStatus,
+ XXX with XML_FINISHED_OK or XML_FINISHED_ERROR replacing XML_FINISHED
+*/
+XMLPARSEAPI(void)
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status);
+
+/* Creates an XML_Parser object that can parse an external general
+ entity; context is a '\0'-terminated string specifying the parse
+ context; encoding is a '\0'-terminated string giving the name of
+ the externally specified encoding, or NULL if there is no
+ externally specified encoding. The context string consists of a
+ sequence of tokens separated by formfeeds (\f); a token consisting
+ of a name specifies that the general entity of the name is open; a
+ token of the form prefix=uri specifies the namespace for a
+ particular prefix; a token of the form =uri specifies the default
+ namespace. This can be called at any point after the first call to
+ an ExternalEntityRefHandler so longer as the parser has not yet
+ been freed. The new parser is completely independent and may
+ safely be used in a separate thread. The handlers and userData are
+ initialized from the parser argument. Returns NULL if out of memory.
+ Otherwise returns a new XML_Parser object.
+*/
+XMLPARSEAPI(XML_Parser)
+XML_ExternalEntityParserCreate(XML_Parser parser,
+ const XML_Char *context,
+ const XML_Char *encoding);
+
+enum XML_ParamEntityParsing {
+ XML_PARAM_ENTITY_PARSING_NEVER,
+ XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE,
+ XML_PARAM_ENTITY_PARSING_ALWAYS
+};
+
+/* Controls parsing of parameter entities (including the external DTD
+ subset). If parsing of parameter entities is enabled, then
+ references to external parameter entities (including the external
+ DTD subset) will be passed to the handler set with
+ XML_SetExternalEntityRefHandler. The context passed will be 0.
+
+ Unlike external general entities, external parameter entities can
+ only be parsed synchronously. If the external parameter entity is
+ to be parsed, it must be parsed during the call to the external
+ entity ref handler: the complete sequence of
+ XML_ExternalEntityParserCreate, XML_Parse/XML_ParseBuffer and
+ XML_ParserFree calls must be made during this call. After
+ XML_ExternalEntityParserCreate has been called to create the parser
+ for the external parameter entity (context must be 0 for this
+ call), it is illegal to make any calls on the old parser until
+ XML_ParserFree has been called on the newly created parser.
+ If the library has been compiled without support for parameter
+ entity parsing (ie without XML_DTD being defined), then
+ XML_SetParamEntityParsing will return 0 if parsing of parameter
+ entities is requested; otherwise it will return non-zero.
+ Note: If XML_SetParamEntityParsing is called after XML_Parse or
+ XML_ParseBuffer, then it has no effect and will always return 0.
+ Note: If parser == NULL, the function will do nothing and return 0.
+*/
+XMLPARSEAPI(int)
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing parsing);
+
+/* Sets the hash salt to use for internal hash calculations.
+ Helps in preventing DoS attacks based on predicting hash
+ function behavior. This must be called before parsing is started.
+ Returns 1 if successful, 0 when called after parsing has started.
+ Note: If parser == NULL, the function will do nothing and return 0.
+*/
+XMLPARSEAPI(int)
+XML_SetHashSalt(XML_Parser parser,
+ unsigned long hash_salt);
+
+/* If XML_Parse or XML_ParseBuffer have returned XML_STATUS_ERROR, then
+ XML_GetErrorCode returns information about the error.
+*/
+XMLPARSEAPI(enum XML_Error)
+XML_GetErrorCode(XML_Parser parser);
+
+/* These functions return information about the current parse
+ location. They may be called from any callback called to report
+ some parse event; in this case the location is the location of the
+ first of the sequence of characters that generated the event. When
+ called from callbacks generated by declarations in the document
+ prologue, the location identified isn't as neatly defined, but will
+ be within the relevant markup. When called outside of the callback
+ functions, the position indicated will be just past the last parse
+ event (regardless of whether there was an associated callback).
+
+ They may also be called after returning from a call to XML_Parse
+ or XML_ParseBuffer. If the return value is XML_STATUS_ERROR then
+ the location is the location of the character at which the error
+ was detected; otherwise the location is the location of the last
+ parse event, as described above.
+
+ Note: XML_GetCurrentLineNumber and XML_GetCurrentColumnNumber
+ return 0 to indicate an error.
+ Note: XML_GetCurrentByteIndex returns -1 to indicate an error.
+*/
+XMLPARSEAPI(XML_Size) XML_GetCurrentLineNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Size) XML_GetCurrentColumnNumber(XML_Parser parser);
+XMLPARSEAPI(XML_Index) XML_GetCurrentByteIndex(XML_Parser parser);
+
+/* Return the number of bytes in the current event.
+ Returns 0 if the event is in an internal entity.
+*/
+XMLPARSEAPI(int)
+XML_GetCurrentByteCount(XML_Parser parser);
+
+/* If XML_CONTEXT_BYTES is defined, returns the input buffer, sets
+ the integer pointed to by offset to the offset within this buffer
+ of the current parse position, and sets the integer pointed to by size
+ to the size of this buffer (the number of input bytes). Otherwise
+ returns a NULL pointer. Also returns a NULL pointer if a parse isn't
+ active.
+
+ NOTE: The character pointer returned should not be used outside
+ the handler that makes the call.
+*/
+XMLPARSEAPI(const char *)
+XML_GetInputContext(XML_Parser parser,
+ int *offset,
+ int *size);
+
+/* For backwards compatibility with previous versions. */
+#define XML_GetErrorLineNumber XML_GetCurrentLineNumber
+#define XML_GetErrorColumnNumber XML_GetCurrentColumnNumber
+#define XML_GetErrorByteIndex XML_GetCurrentByteIndex
+
+/* Frees the content model passed to the element declaration handler */
+XMLPARSEAPI(void)
+XML_FreeContentModel(XML_Parser parser, XML_Content *model);
+
+/* Exposing the memory handling functions used in Expat */
+XMLPARSEAPI(void *)
+XML_ATTR_MALLOC
+XML_ATTR_ALLOC_SIZE(2)
+XML_MemMalloc(XML_Parser parser, size_t size);
+
+XMLPARSEAPI(void *)
+XML_ATTR_ALLOC_SIZE(3)
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size);
+
+XMLPARSEAPI(void)
+XML_MemFree(XML_Parser parser, void *ptr);
+
+/* Frees memory used by the parser. */
+XMLPARSEAPI(void)
+XML_ParserFree(XML_Parser parser);
+
+/* Returns a string describing the error. */
+XMLPARSEAPI(const XML_LChar *)
+XML_ErrorString(enum XML_Error code);
+
+/* Return a string containing the version number of this expat */
+XMLPARSEAPI(const XML_LChar *)
+XML_ExpatVersion(void);
+
+typedef struct {
+ int major;
+ int minor;
+ int micro;
+} XML_Expat_Version;
+
+/* Return an XML_Expat_Version structure containing numeric version
+ number information for this version of expat.
+*/
+XMLPARSEAPI(XML_Expat_Version)
+XML_ExpatVersionInfo(void);
+
+/* Added in Expat 1.95.5. */
+enum XML_FeatureEnum {
+ XML_FEATURE_END = 0,
+ XML_FEATURE_UNICODE,
+ XML_FEATURE_UNICODE_WCHAR_T,
+ XML_FEATURE_DTD,
+ XML_FEATURE_CONTEXT_BYTES,
+ XML_FEATURE_MIN_SIZE,
+ XML_FEATURE_SIZEOF_XML_CHAR,
+ XML_FEATURE_SIZEOF_XML_LCHAR,
+ XML_FEATURE_NS,
+ XML_FEATURE_LARGE_SIZE,
+ XML_FEATURE_ATTR_INFO
+ /* Additional features must be added to the end of this enum. */
+};
+
+typedef struct {
+ enum XML_FeatureEnum feature;
+ const XML_LChar *name;
+ long int value;
+} XML_Feature;
+
+XMLPARSEAPI(const XML_Feature *)
+XML_GetFeatureList(void);
+
+
+/* Expat follows the semantic versioning convention.
+ See http://semver.org.
+*/
+#define XML_MAJOR_VERSION 2
+#define XML_MINOR_VERSION 2
+#define XML_MICRO_VERSION 3
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_INCLUDED */
diff --git a/Utilities/cmexpat/lib/expat_external.h b/Utilities/cmexpat/lib/expat_external.h
new file mode 100644
index 000000000..d60eeccfb
--- /dev/null
+++ b/Utilities/cmexpat/lib/expat_external.h
@@ -0,0 +1,134 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef Expat_External_INCLUDED
+#define Expat_External_INCLUDED 1
+
+/* External API definitions */
+
+#if defined(_MSC_EXTENSIONS) && !defined(__BEOS__) && !defined(__CYGWIN__)
+#define XML_USE_MSC_EXTENSIONS 1
+#endif
+
+/* Expat tries very hard to make the API boundary very specifically
+ defined. There are two macros defined to control this boundary;
+ each of these can be defined before including this header to
+ achieve some different behavior, but doing so it not recommended or
+ tested frequently.
+
+ XMLCALL - The calling convention to use for all calls across the
+ "library boundary." This will default to cdecl, and
+ try really hard to tell the compiler that's what we
+ want.
+
+ XMLIMPORT - Whatever magic is needed to note that a function is
+ to be imported from a dynamically loaded library
+ (.dll, .so, or .sl, depending on your platform).
+
+ The XMLCALL macro was added in Expat 1.95.7. The only one which is
+ expected to be directly useful in client code is XMLCALL.
+
+ Note that on at least some Unix versions, the Expat library must be
+ compiled with the cdecl calling convention as the default since
+ system headers may assume the cdecl convention.
+*/
+#ifndef XMLCALL
+#if defined(_MSC_VER)
+#define XMLCALL __cdecl
+#elif defined(__GNUC__) && defined(__i386) && !defined(__INTEL_COMPILER)
+#define XMLCALL __attribute__((cdecl))
+#else
+/* For any platform which uses this definition and supports more than
+ one calling convention, we need to extend this definition to
+ declare the convention used on that platform, if it's possible to
+ do so.
+
+ If this is the case for your platform, please file a bug report
+ with information on how to identify your platform via the C
+ pre-processor and how to specify the same calling convention as the
+ platform's malloc() implementation.
+*/
+#define XMLCALL
+#endif
+#endif /* not defined XMLCALL */
+
+/* Build within CMake hard-codes use of a static library. */
+#define XML_STATIC
+
+#if !defined(XML_STATIC) && !defined(XMLIMPORT)
+#ifndef XML_BUILDING_EXPAT
+/* using Expat from an application */
+
+#ifdef XML_USE_MSC_EXTENSIONS
+#define XMLIMPORT __declspec(dllimport)
+#endif
+
+#endif
+#endif /* not defined XML_STATIC */
+
+#if !defined(XMLIMPORT) && defined(__GNUC__) && (__GNUC__ >= 4)
+#define XMLIMPORT __attribute__ ((visibility ("default")))
+#endif
+
+/* If we didn't define it above, define it away: */
+#ifndef XMLIMPORT
+#define XMLIMPORT
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
+#define XML_ATTR_MALLOC __attribute__((__malloc__))
+#else
+#define XML_ATTR_MALLOC
+#endif
+
+#if defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+#define XML_ATTR_ALLOC_SIZE(x) __attribute__((__alloc_size__(x)))
+#else
+#define XML_ATTR_ALLOC_SIZE(x)
+#endif
+
+#define XMLPARSEAPI(type) XMLIMPORT type XMLCALL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef XML_UNICODE_WCHAR_T
+# define XML_UNICODE
+# if defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ != 2)
+# error "sizeof(wchar_t) != 2; Need -fshort-wchar for both Expat and libc"
+# endif
+#endif
+
+#ifdef XML_UNICODE /* Information is UTF-16 encoded. */
+#ifdef XML_UNICODE_WCHAR_T
+typedef wchar_t XML_Char;
+typedef wchar_t XML_LChar;
+#else
+typedef unsigned short XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE_WCHAR_T */
+#else /* Information is UTF-8 encoded. */
+typedef char XML_Char;
+typedef char XML_LChar;
+#endif /* XML_UNICODE */
+
+#ifdef XML_LARGE_SIZE /* Use large integers for file/stream positions. */
+#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
+typedef __int64 XML_Index;
+typedef unsigned __int64 XML_Size;
+#else
+typedef long long XML_Index;
+typedef unsigned long long XML_Size;
+#endif
+#else
+typedef long XML_Index;
+typedef unsigned long XML_Size;
+#endif /* XML_LARGE_SIZE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not Expat_External_INCLUDED */
diff --git a/Utilities/cmexpat/lib/iasciitab.h b/Utilities/cmexpat/lib/iasciitab.h
new file mode 100644
index 000000000..24a1d5ccc
--- /dev/null
+++ b/Utilities/cmexpat/lib/iasciitab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
+/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x04 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x08 */ BT_NONXML, BT_S, BT_LF, BT_NONXML,
+/* 0x0C */ BT_NONXML, BT_S, BT_NONXML, BT_NONXML,
+/* 0x10 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x14 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x18 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x1C */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0x20 */ BT_S, BT_EXCL, BT_QUOT, BT_NUM,
+/* 0x24 */ BT_OTHER, BT_PERCNT, BT_AMP, BT_APOS,
+/* 0x28 */ BT_LPAR, BT_RPAR, BT_AST, BT_PLUS,
+/* 0x2C */ BT_COMMA, BT_MINUS, BT_NAME, BT_SOL,
+/* 0x30 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x34 */ BT_DIGIT, BT_DIGIT, BT_DIGIT, BT_DIGIT,
+/* 0x38 */ BT_DIGIT, BT_DIGIT, BT_COLON, BT_SEMI,
+/* 0x3C */ BT_LT, BT_EQUALS, BT_GT, BT_QUEST,
+/* 0x40 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x44 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x48 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x4C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x50 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x54 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x58 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_LSQB,
+/* 0x5C */ BT_OTHER, BT_RSQB, BT_OTHER, BT_NMSTRT,
+/* 0x60 */ BT_OTHER, BT_HEX, BT_HEX, BT_HEX,
+/* 0x64 */ BT_HEX, BT_HEX, BT_HEX, BT_NMSTRT,
+/* 0x68 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x6C */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x70 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x74 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0x78 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0x7C */ BT_VERBAR, BT_OTHER, BT_OTHER, BT_OTHER,
diff --git a/Utilities/cmexpat/lib/internal.h b/Utilities/cmexpat/lib/internal.h
new file mode 100644
index 000000000..94cb98e15
--- /dev/null
+++ b/Utilities/cmexpat/lib/internal.h
@@ -0,0 +1,95 @@
+/* internal.h
+
+ Internal definitions used by Expat. This is not needed to compile
+ client code.
+
+ The following calling convention macros are defined for frequently
+ called functions:
+
+ FASTCALL - Used for those internal functions that have a simple
+ body and a low number of arguments and local variables.
+
+ PTRCALL - Used for functions called though function pointers.
+
+ PTRFASTCALL - Like PTRCALL, but for low number of arguments.
+
+ inline - Used for selected internal functions for which inlining
+ may improve performance on some platforms.
+
+ Note: Use of these macros is based on judgement, not hard rules,
+ and therefore subject to change.
+*/
+
+#if defined(__GNUC__) && defined(__i386__) && !defined(__MINGW32__)
+/* We'll use this version by default only where we know it helps.
+
+ regparm() generates warnings on Solaris boxes. See SF bug #692878.
+
+ Instability reported with egcs on a RedHat Linux 7.3.
+ Let's comment out:
+ #define FASTCALL __attribute__((stdcall, regparm(3)))
+ and let's try this:
+*/
+#define FASTCALL __attribute__((regparm(3)))
+#define PTRFASTCALL __attribute__((regparm(3)))
+#endif
+
+/* Using __fastcall seems to have an unexpected negative effect under
+ MS VC++, especially for function pointers, so we won't use it for
+ now on that platform. It may be reconsidered for a future release
+ if it can be made more effective.
+ Likely reason: __fastcall on Windows is like stdcall, therefore
+ the compiler cannot perform stack optimizations for call clusters.
+*/
+
+/* Make sure all of these are defined if they aren't already. */
+
+#ifndef FASTCALL
+#define FASTCALL
+#endif
+
+#ifndef PTRCALL
+#define PTRCALL
+#endif
+
+#ifndef PTRFASTCALL
+#define PTRFASTCALL
+#endif
+
+#ifndef XML_MIN_SIZE
+#if !defined(__cplusplus) && !defined(inline)
+#ifdef __GNUC__
+#define inline __inline
+#endif /* __GNUC__ */
+#endif
+#endif /* XML_MIN_SIZE */
+
+#ifdef __cplusplus
+#define inline inline
+#else
+#ifndef inline
+#define inline
+#endif
+#endif
+
+#ifndef UNUSED_P
+# ifdef __GNUC__
+# define UNUSED_P(p) UNUSED_ ## p __attribute__((__unused__))
+# else
+# define UNUSED_P(p) UNUSED_ ## p
+# endif
+#endif
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef);
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/Utilities/cmexpat/lib/latin1tab.h b/Utilities/cmexpat/lib/latin1tab.h
new file mode 100644
index 000000000..53c25d76b
--- /dev/null
+++ b/Utilities/cmexpat/lib/latin1tab.h
@@ -0,0 +1,36 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x84 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x88 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x8C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x90 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x94 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x98 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0x9C */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA4 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xA8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xAC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB0 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xB4 */ BT_OTHER, BT_NMSTRT, BT_OTHER, BT_NAME,
+/* 0xB8 */ BT_OTHER, BT_OTHER, BT_NMSTRT, BT_OTHER,
+/* 0xBC */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
+/* 0xC0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xC8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xCC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xD4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xD8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xDC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xE8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xEC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF0 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xF4 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_OTHER,
+/* 0xF8 */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
+/* 0xFC */ BT_NMSTRT, BT_NMSTRT, BT_NMSTRT, BT_NMSTRT,
diff --git a/Utilities/cmexpat/lib/loadlibrary.c b/Utilities/cmexpat/lib/loadlibrary.c
new file mode 100644
index 000000000..ffce86839
--- /dev/null
+++ b/Utilities/cmexpat/lib/loadlibrary.c
@@ -0,0 +1,141 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016 - 2017, Steve Holme, <steve_holme@hotmail.com>.
+ *
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
+ * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
+ * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Except as contained in this notice, the name of a copyright holder shall
+ * not be used in advertising or otherwise to promote the sale, use or other
+ * dealings in this Software without prior written authorization of the
+ * copyright holder.
+ *
+ ***************************************************************************/
+
+#if defined(_WIN32)
+
+#include <windows.h>
+#include <tchar.h>
+
+
+HMODULE _Expat_LoadLibrary(LPCTSTR filename);
+
+
+#if !defined(LOAD_WITH_ALTERED_SEARCH_PATH)
+#define LOAD_WITH_ALTERED_SEARCH_PATH 0x00000008
+#endif
+
+#if !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+#define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
+#endif
+
+/* We use our own typedef here since some headers might lack these */
+typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
+
+/* See function definitions in winbase.h */
+#ifdef UNICODE
+# ifdef _WIN32_WCE
+# define LOADLIBARYEX L"LoadLibraryExW"
+# else
+# define LOADLIBARYEX "LoadLibraryExW"
+# endif
+#else
+# define LOADLIBARYEX "LoadLibraryExA"
+#endif
+
+
+/*
+ * _Expat_LoadLibrary()
+ *
+ * This is used to dynamically load DLLs using the most secure method available
+ * for the version of Windows that we are running on.
+ *
+ * Parameters:
+ *
+ * filename [in] - The filename or full path of the DLL to load. If only the
+ * filename is passed then the DLL will be loaded from the
+ * Windows system directory.
+ *
+ * Returns the handle of the module on success; otherwise NULL.
+ */
+HMODULE _Expat_LoadLibrary(LPCTSTR filename)
+{
+ HMODULE hModule = NULL;
+ LOADLIBRARYEX_FN pLoadLibraryEx = NULL;
+
+ /* Get a handle to kernel32 so we can access it's functions at runtime */
+ HMODULE hKernel32 = GetModuleHandle(TEXT("kernel32"));
+ if(!hKernel32)
+ return NULL;
+
+ /* Attempt to find LoadLibraryEx() which is only available on Windows 2000
+ and above */
+ pLoadLibraryEx = (LOADLIBRARYEX_FN) GetProcAddress(hKernel32, LOADLIBARYEX);
+
+ /* Detect if there's already a path in the filename and load the library if
+ there is. Note: Both back slashes and forward slashes have been supported
+ since the earlier days of DOS at an API level although they are not
+ supported by command prompt */
+ if(_tcspbrk(filename, TEXT("\\/"))) {
+ /** !checksrc! disable BANNEDFUNC 1 **/
+ hModule = pLoadLibraryEx ?
+ pLoadLibraryEx(filename, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+ LoadLibrary(filename);
+ }
+ /* Detect if KB2533623 is installed, as LOAD_LIBARY_SEARCH_SYSTEM32 is only
+ supported on Windows Vista, Windows Server 2008, Windows 7 and Windows
+ Server 2008 R2 with this patch or natively on Windows 8 and above */
+ else if(pLoadLibraryEx && GetProcAddress(hKernel32, "AddDllDirectory")) {
+ /* Load the DLL from the Windows system directory */
+ hModule = pLoadLibraryEx(filename, NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
+ }
+ else {
+ /* Attempt to get the Windows system path */
+ UINT systemdirlen = GetSystemDirectory(NULL, 0);
+ if(systemdirlen) {
+ /* Allocate space for the full DLL path (Room for the null terminator
+ is included in systemdirlen) */
+ size_t filenamelen = _tcslen(filename);
+ TCHAR *path = malloc(sizeof(TCHAR) * (systemdirlen + 1 + filenamelen));
+ if(path && GetSystemDirectory(path, systemdirlen)) {
+ /* Calculate the full DLL path */
+ _tcscpy(path + _tcslen(path), TEXT("\\"));
+ _tcscpy(path + _tcslen(path), filename);
+
+ /* Load the DLL from the Windows system directory */
+ /** !checksrc! disable BANNEDFUNC 1 **/
+ hModule = pLoadLibraryEx ?
+ pLoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) :
+ LoadLibrary(path);
+
+ }
+ free(path);
+ }
+ }
+
+ return hModule;
+}
+
+#else /* defined(_WIN32) */
+
+/* ISO C requires a translation unit to contain at least one declaration
+ [-Wempty-translation-unit] */
+typedef int _TRANSLATION_UNIT_LOAD_LIBRARY_C_NOT_EMTPY;
+
+#endif /* defined(_WIN32) */
diff --git a/Utilities/cmexpat/nametab.h b/Utilities/cmexpat/lib/nametab.h
index b05e62c77..b05e62c77 100644
--- a/Utilities/cmexpat/nametab.h
+++ b/Utilities/cmexpat/lib/nametab.h
diff --git a/Utilities/cmexpat/lib/siphash.h b/Utilities/cmexpat/lib/siphash.h
new file mode 100644
index 000000000..1684b251d
--- /dev/null
+++ b/Utilities/cmexpat/lib/siphash.h
@@ -0,0 +1,377 @@
+/* ==========================================================================
+ * siphash.h - SipHash-2-4 in a single header file
+ * --------------------------------------------------------------------------
+ * Derived by William Ahern from the reference implementation[1] published[2]
+ * by Jean-Philippe Aumasson and Daniel J. Berstein.
+ * Minimal changes by Sebastian Pipping and Victor Stinner on top, see below.
+ * Licensed under the CC0 Public Domain Dedication license.
+ *
+ * 1. https://www.131002.net/siphash/siphash24.c
+ * 2. https://www.131002.net/siphash/
+ * --------------------------------------------------------------------------
+ * HISTORY:
+ *
+ * 2017-07-25 (Vadim Zeitlin)
+ * - Fix use of SIPHASH_MAIN macro
+ *
+ * 2017-07-05 (Sebastian Pipping)
+ * - Use _SIP_ULL macro to not require a C++11 compiler if compiled as C++
+ * - Add const qualifiers at two places
+ * - Ensure <=80 characters line length (assuming tab width 4)
+ *
+ * 2017-06-23 (Victor Stinner)
+ * - Address Win64 compile warnings
+ *
+ * 2017-06-18 (Sebastian Pipping)
+ * - Clarify license note in the header
+ * - Address C89 issues:
+ * - Stop using inline keyword (and let compiler decide)
+ * - Replace _Bool by int
+ * - Turn macro siphash24 into a function
+ * - Address invalid conversion (void pointer) by explicit cast
+ * - Address lack of stdint.h for Visual Studio 2003 to 2008
+ * - Always expose sip24_valid (for self-tests)
+ *
+ * 2012-11-04 - Born. (William Ahern)
+ * --------------------------------------------------------------------------
+ * USAGE:
+ *
+ * SipHash-2-4 takes as input two 64-bit words as the key, some number of
+ * message bytes, and outputs a 64-bit word as the message digest. This
+ * implementation employs two data structures: a struct sipkey for
+ * representing the key, and a struct siphash for representing the hash
+ * state.
+ *
+ * For converting a 16-byte unsigned char array to a key, use either the
+ * macro sip_keyof or the routine sip_tokey. The former instantiates a
+ * compound literal key, while the latter requires a key object as a
+ * parameter.
+ *
+ * unsigned char secret[16];
+ * arc4random_buf(secret, sizeof secret);
+ * struct sipkey *key = sip_keyof(secret);
+ *
+ * For hashing a message, use either the convenience macro siphash24 or the
+ * routines sip24_init, sip24_update, and sip24_final.
+ *
+ * struct siphash state;
+ * void *msg;
+ * size_t len;
+ * uint64_t hash;
+ *
+ * sip24_init(&state, key);
+ * sip24_update(&state, msg, len);
+ * hash = sip24_final(&state);
+ *
+ * or
+ *
+ * hash = siphash24(msg, len, key);
+ *
+ * To convert the 64-bit hash value to a canonical 8-byte little-endian
+ * binary representation, use either the macro sip_binof or the routine
+ * sip_tobin. The former instantiates and returns a compound literal array,
+ * while the latter requires an array object as a parameter.
+ * --------------------------------------------------------------------------
+ * NOTES:
+ *
+ * o Neither sip_keyof, sip_binof, nor siphash24 will work with compilers
+ * lacking compound literal support. Instead, you must use the lower-level
+ * interfaces which take as parameters the temporary state objects.
+ *
+ * o Uppercase macros may evaluate parameters more than once. Lowercase
+ * macros should not exhibit any such side effects.
+ * ==========================================================================
+ */
+#ifndef SIPHASH_H
+#define SIPHASH_H
+
+#include <stddef.h> /* size_t */
+
+#include <cm_kwiml.h>
+
+#ifndef KWIML_INT_HAVE_UINT64_T
+# define uint64_t KWIML_INT_uint64_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT32_T
+# define uint32_t KWIML_INT_uint32_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT8_T
+# define uint8_t KWIML_INT_uint8_t
+#endif
+
+
+/*
+ * Workaround to not require a C++11 compiler for using ULL suffix
+ * if this code is included and compiled as C++; related GCC warning is:
+ * warning: use of C++11 long long integer constant [-Wlong-long]
+ */
+#define _SIP_ULL(high, low) (((uint64_t)high << 32) | low)
+
+
+#define SIP_ROTL(x, b) (uint64_t)(((x) << (b)) | ( (x) >> (64 - (b))))
+
+#define SIP_U32TO8_LE(p, v) \
+ (p)[0] = (uint8_t)((v) >> 0); (p)[1] = (uint8_t)((v) >> 8); \
+ (p)[2] = (uint8_t)((v) >> 16); (p)[3] = (uint8_t)((v) >> 24);
+
+#define SIP_U64TO8_LE(p, v) \
+ SIP_U32TO8_LE((p) + 0, (uint32_t)((v) >> 0)); \
+ SIP_U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
+
+#define SIP_U8TO64_LE(p) \
+ (((uint64_t)((p)[0]) << 0) | \
+ ((uint64_t)((p)[1]) << 8) | \
+ ((uint64_t)((p)[2]) << 16) | \
+ ((uint64_t)((p)[3]) << 24) | \
+ ((uint64_t)((p)[4]) << 32) | \
+ ((uint64_t)((p)[5]) << 40) | \
+ ((uint64_t)((p)[6]) << 48) | \
+ ((uint64_t)((p)[7]) << 56))
+
+
+#define SIPHASH_INITIALIZER { 0, 0, 0, 0, { 0 }, 0, 0 }
+
+struct siphash {
+ uint64_t v0, v1, v2, v3;
+
+ unsigned char buf[8], *p;
+ uint64_t c;
+}; /* struct siphash */
+
+
+#define SIP_KEYLEN 16
+
+struct sipkey {
+ uint64_t k[2];
+}; /* struct sipkey */
+
+#define sip_keyof(k) sip_tokey(&(struct sipkey){ { 0 } }, (k))
+
+static struct sipkey *sip_tokey(struct sipkey *key, const void *src) {
+ key->k[0] = SIP_U8TO64_LE((const unsigned char *)src);
+ key->k[1] = SIP_U8TO64_LE((const unsigned char *)src + 8);
+ return key;
+} /* sip_tokey() */
+
+
+#define sip_binof(v) sip_tobin((unsigned char[8]){ 0 }, (v))
+
+static void *sip_tobin(void *dst, uint64_t u64) {
+ SIP_U64TO8_LE((unsigned char *)dst, u64);
+ return dst;
+} /* sip_tobin() */
+
+
+static void sip_round(struct siphash *H, const int rounds) {
+ int i;
+
+ for (i = 0; i < rounds; i++) {
+ H->v0 += H->v1;
+ H->v1 = SIP_ROTL(H->v1, 13);
+ H->v1 ^= H->v0;
+ H->v0 = SIP_ROTL(H->v0, 32);
+
+ H->v2 += H->v3;
+ H->v3 = SIP_ROTL(H->v3, 16);
+ H->v3 ^= H->v2;
+
+ H->v0 += H->v3;
+ H->v3 = SIP_ROTL(H->v3, 21);
+ H->v3 ^= H->v0;
+
+ H->v2 += H->v1;
+ H->v1 = SIP_ROTL(H->v1, 17);
+ H->v1 ^= H->v2;
+ H->v2 = SIP_ROTL(H->v2, 32);
+ }
+} /* sip_round() */
+
+
+static struct siphash *sip24_init(struct siphash *H,
+ const struct sipkey *key) {
+ H->v0 = _SIP_ULL(0x736f6d65U, 0x70736575U) ^ key->k[0];
+ H->v1 = _SIP_ULL(0x646f7261U, 0x6e646f6dU) ^ key->k[1];
+ H->v2 = _SIP_ULL(0x6c796765U, 0x6e657261U) ^ key->k[0];
+ H->v3 = _SIP_ULL(0x74656462U, 0x79746573U) ^ key->k[1];
+
+ H->p = H->buf;
+ H->c = 0;
+
+ return H;
+} /* sip24_init() */
+
+
+#define sip_endof(a) (&(a)[sizeof (a) / sizeof *(a)])
+
+static struct siphash *sip24_update(struct siphash *H, const void *src,
+ size_t len) {
+ const unsigned char *p = (const unsigned char *)src, *pe = p + len;
+ uint64_t m;
+
+ do {
+ while (p < pe && H->p < sip_endof(H->buf))
+ *H->p++ = *p++;
+
+ if (H->p < sip_endof(H->buf))
+ break;
+
+ m = SIP_U8TO64_LE(H->buf);
+ H->v3 ^= m;
+ sip_round(H, 2);
+ H->v0 ^= m;
+
+ H->p = H->buf;
+ H->c += 8;
+ } while (p < pe);
+
+ return H;
+} /* sip24_update() */
+
+
+static uint64_t sip24_final(struct siphash *H) {
+ const char left = (char)(H->p - H->buf);
+ uint64_t b = (H->c + left) << 56;
+
+ switch (left) {
+ case 7: b |= (uint64_t)H->buf[6] << 48;
+ case 6: b |= (uint64_t)H->buf[5] << 40;
+ case 5: b |= (uint64_t)H->buf[4] << 32;
+ case 4: b |= (uint64_t)H->buf[3] << 24;
+ case 3: b |= (uint64_t)H->buf[2] << 16;
+ case 2: b |= (uint64_t)H->buf[1] << 8;
+ case 1: b |= (uint64_t)H->buf[0] << 0;
+ case 0: break;
+ }
+
+ H->v3 ^= b;
+ sip_round(H, 2);
+ H->v0 ^= b;
+ H->v2 ^= 0xff;
+ sip_round(H, 4);
+
+ return H->v0 ^ H->v1 ^ H->v2 ^ H->v3;
+} /* sip24_final() */
+
+
+static uint64_t siphash24(const void *src, size_t len,
+ const struct sipkey *key) {
+ struct siphash state = SIPHASH_INITIALIZER;
+ return sip24_final(sip24_update(sip24_init(&state, key), src, len));
+} /* siphash24() */
+
+
+/*
+ * SipHash-2-4 output with
+ * k = 00 01 02 ...
+ * and
+ * in = (empty string)
+ * in = 00 (1 byte)
+ * in = 00 01 (2 bytes)
+ * in = 00 01 02 (3 bytes)
+ * ...
+ * in = 00 01 02 ... 3e (63 bytes)
+ */
+static int sip24_valid(void) {
+ static const unsigned char vectors[64][8] = {
+ { 0x31, 0x0e, 0x0e, 0xdd, 0x47, 0xdb, 0x6f, 0x72, },
+ { 0xfd, 0x67, 0xdc, 0x93, 0xc5, 0x39, 0xf8, 0x74, },
+ { 0x5a, 0x4f, 0xa9, 0xd9, 0x09, 0x80, 0x6c, 0x0d, },
+ { 0x2d, 0x7e, 0xfb, 0xd7, 0x96, 0x66, 0x67, 0x85, },
+ { 0xb7, 0x87, 0x71, 0x27, 0xe0, 0x94, 0x27, 0xcf, },
+ { 0x8d, 0xa6, 0x99, 0xcd, 0x64, 0x55, 0x76, 0x18, },
+ { 0xce, 0xe3, 0xfe, 0x58, 0x6e, 0x46, 0xc9, 0xcb, },
+ { 0x37, 0xd1, 0x01, 0x8b, 0xf5, 0x00, 0x02, 0xab, },
+ { 0x62, 0x24, 0x93, 0x9a, 0x79, 0xf5, 0xf5, 0x93, },
+ { 0xb0, 0xe4, 0xa9, 0x0b, 0xdf, 0x82, 0x00, 0x9e, },
+ { 0xf3, 0xb9, 0xdd, 0x94, 0xc5, 0xbb, 0x5d, 0x7a, },
+ { 0xa7, 0xad, 0x6b, 0x22, 0x46, 0x2f, 0xb3, 0xf4, },
+ { 0xfb, 0xe5, 0x0e, 0x86, 0xbc, 0x8f, 0x1e, 0x75, },
+ { 0x90, 0x3d, 0x84, 0xc0, 0x27, 0x56, 0xea, 0x14, },
+ { 0xee, 0xf2, 0x7a, 0x8e, 0x90, 0xca, 0x23, 0xf7, },
+ { 0xe5, 0x45, 0xbe, 0x49, 0x61, 0xca, 0x29, 0xa1, },
+ { 0xdb, 0x9b, 0xc2, 0x57, 0x7f, 0xcc, 0x2a, 0x3f, },
+ { 0x94, 0x47, 0xbe, 0x2c, 0xf5, 0xe9, 0x9a, 0x69, },
+ { 0x9c, 0xd3, 0x8d, 0x96, 0xf0, 0xb3, 0xc1, 0x4b, },
+ { 0xbd, 0x61, 0x79, 0xa7, 0x1d, 0xc9, 0x6d, 0xbb, },
+ { 0x98, 0xee, 0xa2, 0x1a, 0xf2, 0x5c, 0xd6, 0xbe, },
+ { 0xc7, 0x67, 0x3b, 0x2e, 0xb0, 0xcb, 0xf2, 0xd0, },
+ { 0x88, 0x3e, 0xa3, 0xe3, 0x95, 0x67, 0x53, 0x93, },
+ { 0xc8, 0xce, 0x5c, 0xcd, 0x8c, 0x03, 0x0c, 0xa8, },
+ { 0x94, 0xaf, 0x49, 0xf6, 0xc6, 0x50, 0xad, 0xb8, },
+ { 0xea, 0xb8, 0x85, 0x8a, 0xde, 0x92, 0xe1, 0xbc, },
+ { 0xf3, 0x15, 0xbb, 0x5b, 0xb8, 0x35, 0xd8, 0x17, },
+ { 0xad, 0xcf, 0x6b, 0x07, 0x63, 0x61, 0x2e, 0x2f, },
+ { 0xa5, 0xc9, 0x1d, 0xa7, 0xac, 0xaa, 0x4d, 0xde, },
+ { 0x71, 0x65, 0x95, 0x87, 0x66, 0x50, 0xa2, 0xa6, },
+ { 0x28, 0xef, 0x49, 0x5c, 0x53, 0xa3, 0x87, 0xad, },
+ { 0x42, 0xc3, 0x41, 0xd8, 0xfa, 0x92, 0xd8, 0x32, },
+ { 0xce, 0x7c, 0xf2, 0x72, 0x2f, 0x51, 0x27, 0x71, },
+ { 0xe3, 0x78, 0x59, 0xf9, 0x46, 0x23, 0xf3, 0xa7, },
+ { 0x38, 0x12, 0x05, 0xbb, 0x1a, 0xb0, 0xe0, 0x12, },
+ { 0xae, 0x97, 0xa1, 0x0f, 0xd4, 0x34, 0xe0, 0x15, },
+ { 0xb4, 0xa3, 0x15, 0x08, 0xbe, 0xff, 0x4d, 0x31, },
+ { 0x81, 0x39, 0x62, 0x29, 0xf0, 0x90, 0x79, 0x02, },
+ { 0x4d, 0x0c, 0xf4, 0x9e, 0xe5, 0xd4, 0xdc, 0xca, },
+ { 0x5c, 0x73, 0x33, 0x6a, 0x76, 0xd8, 0xbf, 0x9a, },
+ { 0xd0, 0xa7, 0x04, 0x53, 0x6b, 0xa9, 0x3e, 0x0e, },
+ { 0x92, 0x59, 0x58, 0xfc, 0xd6, 0x42, 0x0c, 0xad, },
+ { 0xa9, 0x15, 0xc2, 0x9b, 0xc8, 0x06, 0x73, 0x18, },
+ { 0x95, 0x2b, 0x79, 0xf3, 0xbc, 0x0a, 0xa6, 0xd4, },
+ { 0xf2, 0x1d, 0xf2, 0xe4, 0x1d, 0x45, 0x35, 0xf9, },
+ { 0x87, 0x57, 0x75, 0x19, 0x04, 0x8f, 0x53, 0xa9, },
+ { 0x10, 0xa5, 0x6c, 0xf5, 0xdf, 0xcd, 0x9a, 0xdb, },
+ { 0xeb, 0x75, 0x09, 0x5c, 0xcd, 0x98, 0x6c, 0xd0, },
+ { 0x51, 0xa9, 0xcb, 0x9e, 0xcb, 0xa3, 0x12, 0xe6, },
+ { 0x96, 0xaf, 0xad, 0xfc, 0x2c, 0xe6, 0x66, 0xc7, },
+ { 0x72, 0xfe, 0x52, 0x97, 0x5a, 0x43, 0x64, 0xee, },
+ { 0x5a, 0x16, 0x45, 0xb2, 0x76, 0xd5, 0x92, 0xa1, },
+ { 0xb2, 0x74, 0xcb, 0x8e, 0xbf, 0x87, 0x87, 0x0a, },
+ { 0x6f, 0x9b, 0xb4, 0x20, 0x3d, 0xe7, 0xb3, 0x81, },
+ { 0xea, 0xec, 0xb2, 0xa3, 0x0b, 0x22, 0xa8, 0x7f, },
+ { 0x99, 0x24, 0xa4, 0x3c, 0xc1, 0x31, 0x57, 0x24, },
+ { 0xbd, 0x83, 0x8d, 0x3a, 0xaf, 0xbf, 0x8d, 0xb7, },
+ { 0x0b, 0x1a, 0x2a, 0x32, 0x65, 0xd5, 0x1a, 0xea, },
+ { 0x13, 0x50, 0x79, 0xa3, 0x23, 0x1c, 0xe6, 0x60, },
+ { 0x93, 0x2b, 0x28, 0x46, 0xe4, 0xd7, 0x06, 0x66, },
+ { 0xe1, 0x91, 0x5f, 0x5c, 0xb1, 0xec, 0xa4, 0x6c, },
+ { 0xf3, 0x25, 0x96, 0x5c, 0xa1, 0x6d, 0x62, 0x9f, },
+ { 0x57, 0x5f, 0xf2, 0x8e, 0x60, 0x38, 0x1b, 0xe5, },
+ { 0x72, 0x45, 0x06, 0xeb, 0x4c, 0x32, 0x8a, 0x95, }
+ };
+ unsigned char in[64];
+ struct sipkey k;
+ size_t i;
+
+ sip_tokey(&k, "\000\001\002\003\004\005\006\007\010\011"
+ "\012\013\014\015\016\017");
+
+ for (i = 0; i < sizeof in; ++i) {
+ in[i] = (unsigned char)i;
+
+ if (siphash24(in, i, &k) != SIP_U8TO64_LE(vectors[i]))
+ return 0;
+ }
+
+ return 1;
+} /* sip24_valid() */
+
+
+#ifdef SIPHASH_MAIN
+
+#include <stdio.h>
+
+int main(void) {
+ const int ok = sip24_valid();
+
+ if (ok)
+ puts("OK");
+ else
+ puts("FAIL");
+
+ return !ok;
+} /* main() */
+
+#endif /* SIPHASH_MAIN */
+
+
+#endif /* SIPHASH_H */
diff --git a/Utilities/cmexpat/lib/utf8tab.h b/Utilities/cmexpat/lib/utf8tab.h
new file mode 100644
index 000000000..7bb3e7760
--- /dev/null
+++ b/Utilities/cmexpat/lib/utf8tab.h
@@ -0,0 +1,37 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+
+/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
+/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
+/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
+/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
+/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
+/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/Utilities/cmexpat/lib/winconfig.h b/Utilities/cmexpat/lib/winconfig.h
new file mode 100644
index 000000000..c9dbfea85
--- /dev/null
+++ b/Utilities/cmexpat/lib/winconfig.h
@@ -0,0 +1,44 @@
+/*================================================================
+** Copyright 2000, Clark Cooper
+** All rights reserved.
+**
+** This is free software. You are permitted to copy, distribute, or modify
+** it under the terms of the MIT/X license (contained in the COPYING file
+** with this distribution.)
+*/
+
+#ifndef WINCONFIG_H
+#define WINCONFIG_H
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <memory.h>
+#include <string.h>
+
+
+#if defined(HAVE_EXPAT_CONFIG_H) /* e.g. MinGW */
+# include <expat_config.h>
+#else /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+
+#define XML_NS 1
+#define XML_DTD 1
+#define XML_CONTEXT_BYTES 1024
+
+/* we will assume all Windows platforms are little endian */
+#define BYTEORDER 1234
+
+/* Windows has memmove() available. */
+#define HAVE_MEMMOVE
+
+
+#endif /* !defined(HAVE_EXPAT_CONFIG_H) */
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+# pragma warning(disable:4311) /* pointer truncation */
+#endif
+
+#endif /* ndef WINCONFIG_H */
diff --git a/Utilities/cmexpat/lib/xmlparse.c b/Utilities/cmexpat/lib/xmlparse.c
new file mode 100644
index 000000000..b703e61a0
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmlparse.c
@@ -0,0 +1,7215 @@
+/* Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+
+ 101bfd65d1ff3d1511cf6671e6aae65f82cd97df6f4da137d46d510731830ad9 (2.2.3+)
+*/
+
+#if !defined(_GNU_SOURCE)
+# define _GNU_SOURCE 1 /* syscall prototype */
+#endif
+
+#include <stddef.h>
+#include <string.h> /* memset(), memcpy() */
+#include <assert.h>
+#include <limits.h> /* UINT_MAX */
+#include <stdio.h> /* fprintf */
+#include <stdlib.h> /* getenv */
+
+#ifdef _WIN32
+#define getpid GetCurrentProcessId
+#else
+#include <sys/time.h> /* gettimeofday() */
+#include <sys/types.h> /* getpid() */
+#include <unistd.h> /* getpid() */
+#include <fcntl.h> /* O_RDONLY */
+#include <errno.h>
+#endif
+
+#define XML_BUILDING_EXPAT 1
+
+#ifdef _WIN32
+#include "winconfig.h"
+#elif defined(HAVE_EXPAT_CONFIG_H)
+#include <expat_config.h>
+#endif /* ndef _WIN32 */
+
+#include "ascii.h"
+#include "expat.h"
+#include "siphash.h"
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+# if defined(HAVE_GETRANDOM)
+# include <sys/random.h> /* getrandom */
+# else
+# include <unistd.h> /* syscall */
+# include <sys/syscall.h> /* SYS_getrandom */
+# endif
+# if ! defined(GRND_NONBLOCK)
+# define GRND_NONBLOCK 0x0001
+# endif /* defined(GRND_NONBLOCK) */
+#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+#if defined(HAVE_LIBBSD) \
+ && (defined(HAVE_ARC4RANDOM_BUF) || defined(HAVE_ARC4RANDOM))
+# include <bsd/stdlib.h>
+#endif
+
+#if defined(_WIN32) && !defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
+# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
+#endif
+
+#if !defined(HAVE_GETRANDOM) && !defined(HAVE_SYSCALL_GETRANDOM) \
+ && !defined(HAVE_ARC4RANDOM_BUF) && !defined(HAVE_ARC4RANDOM) \
+ && !defined(XML_DEV_URANDOM) \
+ && !defined(_WIN32) \
+ && !defined(XML_POOR_ENTROPY)
+# error \
+ You do not have support for any sources of high quality entropy \
+ enabled. For end user security, that is probably not what you want. \
+ \
+ Your options include: \
+ * Linux + glibc >=2.25 (getrandom): HAVE_GETRANDOM, \
+ * Linux + glibc <2.25 (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
+ * BSD / macOS >=10.7 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
+ * BSD / macOS <10.7 (arc4random): HAVE_ARC4RANDOM, \
+ * libbsd (arc4random_buf): HAVE_ARC4RANDOM_BUF + HAVE_LIBBSD, \
+ * libbsd (arc4random): HAVE_ARC4RANDOM + HAVE_LIBBSD, \
+ * Linux / BSD / macOS (/dev/urandom): XML_DEV_URANDOM \
+ * Windows (RtlGenRandom): _WIN32. \
+ \
+ If insist on not using any of these, bypass this error by defining \
+ XML_POOR_ENTROPY; you have been warned. \
+ \
+ For CMake, one way to pass the define is: \
+ cmake -DCMAKE_C_FLAGS="-pipe -O2 -DHAVE_SYSCALL_GETRANDOM" . \
+ \
+ If you have reasons to patch this detection code away or need changes \
+ to the build system, please open a bug. Thank you!
+#endif
+
+
+#ifdef XML_UNICODE
+#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
+#define XmlConvert XmlUtf16Convert
+#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
+#define XmlEncode XmlUtf16Encode
+/* Using pointer subtraction to convert to integer type. */
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((char *)(s) - (char *)NULL) & 1))
+typedef unsigned short ICHAR;
+#else
+#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
+#define XmlConvert XmlUtf8Convert
+#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
+#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
+#define XmlEncode XmlUtf8Encode
+#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
+typedef char ICHAR;
+#endif
+
+
+#ifndef XML_NS
+
+#define XmlInitEncodingNS XmlInitEncoding
+#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
+#undef XmlGetInternalEncodingNS
+#define XmlGetInternalEncodingNS XmlGetInternalEncoding
+#define XmlParseXmlDeclNS XmlParseXmlDecl
+
+#endif
+
+#ifdef XML_UNICODE
+
+#ifdef XML_UNICODE_WCHAR_T
+#define XML_T(x) (const wchar_t)x
+#define XML_L(x) L ## x
+#else
+#define XML_T(x) (const unsigned short)x
+#define XML_L(x) x
+#endif
+
+#else
+
+#define XML_T(x) x
+#define XML_L(x) x
+
+#endif
+
+/* Round up n to be a multiple of sz, where sz is a power of 2. */
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
+
+/* Handle the case where memmove() doesn't exist. */
+#ifndef HAVE_MEMMOVE
+#ifdef HAVE_BCOPY
+#define memmove(d,s,l) bcopy((s),(d),(l))
+#else
+#error memmove does not exist on this platform, nor is a substitute available
+#endif /* HAVE_BCOPY */
+#endif /* HAVE_MEMMOVE */
+
+#include "internal.h"
+#include "xmltok.h"
+#include "xmlrole.h"
+
+typedef const XML_Char *KEY;
+
+typedef struct {
+ KEY name;
+} NAMED;
+
+typedef struct {
+ NAMED **v;
+ unsigned char power;
+ size_t size;
+ size_t used;
+ const XML_Memory_Handling_Suite *mem;
+} HASH_TABLE;
+
+static size_t
+keylen(KEY s);
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key);
+
+/* For probing (after a collision) we need a step size relative prime
+ to the hash table size, which is a power of 2. We use double-hashing,
+ since we can calculate a second hash value cheaply by taking those bits
+ of the first hash value that were discarded (masked out) when the table
+ index was calculated: index = hash & mask, where mask = table->size - 1.
+ We limit the maximum step size to table->size / 4 (mask >> 2) and make
+ it odd, since odd numbers are always relative prime to a power of 2.
+*/
+#define SECOND_HASH(hash, mask, power) \
+ ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
+#define PROBE_STEP(hash, mask, power) \
+ ((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
+
+typedef struct {
+ NAMED **p;
+ NAMED **end;
+} HASH_TABLE_ITER;
+
+#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
+#define INIT_DATA_BUF_SIZE 1024
+#define INIT_ATTS_SIZE 16
+#define INIT_ATTS_VERSION 0xFFFFFFFF
+#define INIT_BLOCK_SIZE 1024
+#define INIT_BUFFER_SIZE 1024
+
+#define EXPAND_SPARE 24
+
+typedef struct binding {
+ struct prefix *prefix;
+ struct binding *nextTagBinding;
+ struct binding *prevPrefixBinding;
+ const struct attribute_id *attId;
+ XML_Char *uri;
+ int uriLen;
+ int uriAlloc;
+} BINDING;
+
+typedef struct prefix {
+ const XML_Char *name;
+ BINDING *binding;
+} PREFIX;
+
+typedef struct {
+ const XML_Char *str;
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ int strLen;
+ int uriLen;
+ int prefixLen;
+} TAG_NAME;
+
+/* TAG represents an open element.
+ The name of the element is stored in both the document and API
+ encodings. The memory buffer 'buf' is a separately-allocated
+ memory area which stores the name. During the XML_Parse()/
+ XMLParseBuffer() when the element is open, the memory for the 'raw'
+ version of the name (in the document encoding) is shared with the
+ document buffer. If the element is open across calls to
+ XML_Parse()/XML_ParseBuffer(), the buffer is re-allocated to
+ contain the 'raw' name as well.
+
+ A parser re-uses these structures, maintaining a list of allocated
+ TAG objects in a free list.
+*/
+typedef struct tag {
+ struct tag *parent; /* parent of this element */
+ const char *rawName; /* tagName in the original encoding */
+ int rawNameLength;
+ TAG_NAME name; /* tagName in the API encoding */
+ char *buf; /* buffer for name components */
+ char *bufEnd; /* end of the buffer */
+ BINDING *bindings;
+} TAG;
+
+typedef struct {
+ const XML_Char *name;
+ const XML_Char *textPtr;
+ int textLen; /* length in XML_Chars */
+ int processed; /* # of processed bytes - when suspended */
+ const XML_Char *systemId;
+ const XML_Char *base;
+ const XML_Char *publicId;
+ const XML_Char *notation;
+ XML_Bool open;
+ XML_Bool is_param;
+ XML_Bool is_internal; /* true if declared in internal subset outside PE */
+} ENTITY;
+
+typedef struct {
+ enum XML_Content_Type type;
+ enum XML_Content_Quant quant;
+ const XML_Char * name;
+ int firstchild;
+ int lastchild;
+ int childcnt;
+ int nextsib;
+} CONTENT_SCAFFOLD;
+
+#define INIT_SCAFFOLD_ELEMENTS 32
+
+typedef struct block {
+ struct block *next;
+ int size;
+ XML_Char s[1];
+} BLOCK;
+
+typedef struct {
+ BLOCK *blocks;
+ BLOCK *freeBlocks;
+ const XML_Char *end;
+ XML_Char *ptr;
+ XML_Char *start;
+ const XML_Memory_Handling_Suite *mem;
+} STRING_POOL;
+
+/* The XML_Char before the name is used to determine whether
+ an attribute has been specified. */
+typedef struct attribute_id {
+ XML_Char *name;
+ PREFIX *prefix;
+ XML_Bool maybeTokenized;
+ XML_Bool xmlns;
+} ATTRIBUTE_ID;
+
+typedef struct {
+ const ATTRIBUTE_ID *id;
+ XML_Bool isCdata;
+ const XML_Char *value;
+} DEFAULT_ATTRIBUTE;
+
+typedef struct {
+ unsigned long version;
+ unsigned long hash;
+ const XML_Char *uriName;
+} NS_ATT;
+
+typedef struct {
+ const XML_Char *name;
+ PREFIX *prefix;
+ const ATTRIBUTE_ID *idAtt;
+ int nDefaultAtts;
+ int allocDefaultAtts;
+ DEFAULT_ATTRIBUTE *defaultAtts;
+} ELEMENT_TYPE;
+
+typedef struct {
+ HASH_TABLE generalEntities;
+ HASH_TABLE elementTypes;
+ HASH_TABLE attributeIds;
+ HASH_TABLE prefixes;
+ STRING_POOL pool;
+ STRING_POOL entityValuePool;
+ /* false once a parameter entity reference has been skipped */
+ XML_Bool keepProcessing;
+ /* true once an internal or external PE reference has been encountered;
+ this includes the reference to an external subset */
+ XML_Bool hasParamEntityRefs;
+ XML_Bool standalone;
+#ifdef XML_DTD
+ /* indicates if external PE has been read */
+ XML_Bool paramEntityRead;
+ HASH_TABLE paramEntities;
+#endif /* XML_DTD */
+ PREFIX defaultPrefix;
+ /* === scaffolding for building content model === */
+ XML_Bool in_eldecl;
+ CONTENT_SCAFFOLD *scaffold;
+ unsigned contentStringLen;
+ unsigned scaffSize;
+ unsigned scaffCount;
+ int scaffLevel;
+ int *scaffIndex;
+} DTD;
+
+typedef struct open_internal_entity {
+ const char *internalEventPtr;
+ const char *internalEventEndPtr;
+ struct open_internal_entity *next;
+ ENTITY *entity;
+ int startTagLevel;
+ XML_Bool betweenDecl; /* WFC: PE Between Declarations */
+} OPEN_INTERNAL_ENTITY;
+
+typedef enum XML_Error PTRCALL Processor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr);
+
+static Processor prologProcessor;
+static Processor prologInitProcessor;
+static Processor contentProcessor;
+static Processor cdataSectionProcessor;
+#ifdef XML_DTD
+static Processor ignoreSectionProcessor;
+static Processor externalParEntProcessor;
+static Processor externalParEntInitProcessor;
+static Processor entityValueProcessor;
+static Processor entityValueInitProcessor;
+#endif /* XML_DTD */
+static Processor epilogProcessor;
+static Processor errorProcessor;
+static Processor externalEntityInitProcessor;
+static Processor externalEntityInitProcessor2;
+static Processor externalEntityInitProcessor3;
+static Processor externalEntityContentProcessor;
+static Processor internalEntityProcessor;
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next);
+static enum XML_Error
+initializeEncoding(XML_Parser parser);
+static enum XML_Error
+doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
+ const char *end, int tok, const char *next, const char **nextPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl);
+static enum XML_Error
+doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
+ const char *start, const char *end, const char **endPtr,
+ XML_Bool haveMore);
+static enum XML_Error
+doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#ifdef XML_DTD
+static enum XML_Error
+doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr,
+ const char *end, const char **nextPtr, XML_Bool haveMore);
+#endif /* XML_DTD */
+
+static void
+freeBindings(XML_Parser parser, BINDING *bindings);
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *, const char *s,
+ TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr);
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *dfltValue, XML_Parser parser);
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *, XML_Bool isCdata,
+ const char *, const char *, STRING_POOL *);
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
+static enum XML_Error
+storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end);
+static int
+reportComment(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc, const char *start,
+ const char *end);
+
+static const XML_Char * getContext(XML_Parser parser);
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context);
+
+static void FASTCALL normalizePublicId(XML_Char *s);
+
+static DTD * dtdCreate(const XML_Memory_Handling_Suite *ms);
+/* do not call if parentParser != NULL */
+static void dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms);
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms);
+static int
+dtdCopy(XML_Parser oldParser,
+ DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms);
+static int
+copyEntityTable(XML_Parser oldParser,
+ HASH_TABLE *, STRING_POOL *, const HASH_TABLE *);
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize);
+static void FASTCALL
+hashTableInit(HASH_TABLE *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL hashTableClear(HASH_TABLE *);
+static void FASTCALL hashTableDestroy(HASH_TABLE *);
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
+static NAMED * FASTCALL hashTableIterNext(HASH_TABLE_ITER *);
+
+static void FASTCALL
+poolInit(STRING_POOL *, const XML_Memory_Handling_Suite *ms);
+static void FASTCALL poolClear(STRING_POOL *);
+static void FASTCALL poolDestroy(STRING_POOL *);
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end);
+static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s);
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s);
+
+static int FASTCALL nextScaffoldPart(XML_Parser parser);
+static XML_Content * build_model(XML_Parser parser);
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser, const ENCODING *enc,
+ const char *ptr, const char *end);
+
+static XML_Char *copyString(const XML_Char *s,
+ const XML_Memory_Handling_Suite *memsuite);
+
+static unsigned long generate_hash_secret_salt(XML_Parser parser);
+static XML_Bool startParsing(XML_Parser parser);
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd);
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName);
+
+#define poolStart(pool) ((pool)->start)
+#define poolEnd(pool) ((pool)->ptr)
+#define poolLength(pool) ((pool)->ptr - (pool)->start)
+#define poolChop(pool) ((void)--(pool->ptr))
+#define poolLastChar(pool) (((pool)->ptr)[-1])
+#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
+#define poolFinish(pool) ((pool)->start = (pool)->ptr)
+#define poolAppendChar(pool, c) \
+ (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
+ ? 0 \
+ : ((*((pool)->ptr)++ = c), 1))
+
+struct XML_ParserStruct {
+ /* The first member must be userData so that the XML_GetUserData
+ macro works. */
+ void *m_userData;
+ void *m_handlerArg;
+ char *m_buffer;
+ const XML_Memory_Handling_Suite m_mem;
+ /* first character to be parsed */
+ const char *m_bufferPtr;
+ /* past last character to be parsed */
+ char *m_bufferEnd;
+ /* allocated end of buffer */
+ const char *m_bufferLim;
+ XML_Index m_parseEndByteIndex;
+ const char *m_parseEndPtr;
+ XML_Char *m_dataBuf;
+ XML_Char *m_dataBufEnd;
+ XML_StartElementHandler m_startElementHandler;
+ XML_EndElementHandler m_endElementHandler;
+ XML_CharacterDataHandler m_characterDataHandler;
+ XML_ProcessingInstructionHandler m_processingInstructionHandler;
+ XML_CommentHandler m_commentHandler;
+ XML_StartCdataSectionHandler m_startCdataSectionHandler;
+ XML_EndCdataSectionHandler m_endCdataSectionHandler;
+ XML_DefaultHandler m_defaultHandler;
+ XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
+ XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
+ XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
+ XML_NotationDeclHandler m_notationDeclHandler;
+ XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
+ XML_NotStandaloneHandler m_notStandaloneHandler;
+ XML_ExternalEntityRefHandler m_externalEntityRefHandler;
+ XML_Parser m_externalEntityRefHandlerArg;
+ XML_SkippedEntityHandler m_skippedEntityHandler;
+ XML_UnknownEncodingHandler m_unknownEncodingHandler;
+ XML_ElementDeclHandler m_elementDeclHandler;
+ XML_AttlistDeclHandler m_attlistDeclHandler;
+ XML_EntityDeclHandler m_entityDeclHandler;
+ XML_XmlDeclHandler m_xmlDeclHandler;
+ const ENCODING *m_encoding;
+ INIT_ENCODING m_initEncoding;
+ const ENCODING *m_internalEncoding;
+ const XML_Char *m_protocolEncodingName;
+ XML_Bool m_ns;
+ XML_Bool m_ns_triplets;
+ void *m_unknownEncodingMem;
+ void *m_unknownEncodingData;
+ void *m_unknownEncodingHandlerData;
+ void (XMLCALL *m_unknownEncodingRelease)(void *);
+ PROLOG_STATE m_prologState;
+ Processor *m_processor;
+ enum XML_Error m_errorCode;
+ const char *m_eventPtr;
+ const char *m_eventEndPtr;
+ const char *m_positionPtr;
+ OPEN_INTERNAL_ENTITY *m_openInternalEntities;
+ OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
+ XML_Bool m_defaultExpandInternalEntities;
+ int m_tagLevel;
+ ENTITY *m_declEntity;
+ const XML_Char *m_doctypeName;
+ const XML_Char *m_doctypeSysid;
+ const XML_Char *m_doctypePubid;
+ const XML_Char *m_declAttributeType;
+ const XML_Char *m_declNotationName;
+ const XML_Char *m_declNotationPublicId;
+ ELEMENT_TYPE *m_declElementType;
+ ATTRIBUTE_ID *m_declAttributeId;
+ XML_Bool m_declAttributeIsCdata;
+ XML_Bool m_declAttributeIsId;
+ DTD *m_dtd;
+ const XML_Char *m_curBase;
+ TAG *m_tagStack;
+ TAG *m_freeTagList;
+ BINDING *m_inheritedBindings;
+ BINDING *m_freeBindingList;
+ int m_attsSize;
+ int m_nSpecifiedAtts;
+ int m_idAttIndex;
+ ATTRIBUTE *m_atts;
+ NS_ATT *m_nsAtts;
+ unsigned long m_nsAttsVersion;
+ unsigned char m_nsAttsPower;
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *m_attInfo;
+#endif
+ POSITION m_position;
+ STRING_POOL m_tempPool;
+ STRING_POOL m_temp2Pool;
+ char *m_groupConnector;
+ unsigned int m_groupSize;
+ XML_Char m_namespaceSeparator;
+ XML_Parser m_parentParser;
+ XML_ParsingStatus m_parsingStatus;
+#ifdef XML_DTD
+ XML_Bool m_isParamEntity;
+ XML_Bool m_useForeignDTD;
+ enum XML_ParamEntityParsing m_paramEntityParsing;
+#endif
+ unsigned long m_hash_secret_salt;
+};
+
+#define MALLOC(s) (parser->m_mem.malloc_fcn((s)))
+#define REALLOC(p,s) (parser->m_mem.realloc_fcn((p),(s)))
+#define FREE(p) (parser->m_mem.free_fcn((p)))
+
+#define userData (parser->m_userData)
+#define handlerArg (parser->m_handlerArg)
+#define startElementHandler (parser->m_startElementHandler)
+#define endElementHandler (parser->m_endElementHandler)
+#define characterDataHandler (parser->m_characterDataHandler)
+#define processingInstructionHandler \
+ (parser->m_processingInstructionHandler)
+#define commentHandler (parser->m_commentHandler)
+#define startCdataSectionHandler \
+ (parser->m_startCdataSectionHandler)
+#define endCdataSectionHandler (parser->m_endCdataSectionHandler)
+#define defaultHandler (parser->m_defaultHandler)
+#define startDoctypeDeclHandler (parser->m_startDoctypeDeclHandler)
+#define endDoctypeDeclHandler (parser->m_endDoctypeDeclHandler)
+#define unparsedEntityDeclHandler \
+ (parser->m_unparsedEntityDeclHandler)
+#define notationDeclHandler (parser->m_notationDeclHandler)
+#define startNamespaceDeclHandler \
+ (parser->m_startNamespaceDeclHandler)
+#define endNamespaceDeclHandler (parser->m_endNamespaceDeclHandler)
+#define notStandaloneHandler (parser->m_notStandaloneHandler)
+#define externalEntityRefHandler \
+ (parser->m_externalEntityRefHandler)
+#define externalEntityRefHandlerArg \
+ (parser->m_externalEntityRefHandlerArg)
+#define internalEntityRefHandler \
+ (parser->m_internalEntityRefHandler)
+#define skippedEntityHandler (parser->m_skippedEntityHandler)
+#define unknownEncodingHandler (parser->m_unknownEncodingHandler)
+#define elementDeclHandler (parser->m_elementDeclHandler)
+#define attlistDeclHandler (parser->m_attlistDeclHandler)
+#define entityDeclHandler (parser->m_entityDeclHandler)
+#define xmlDeclHandler (parser->m_xmlDeclHandler)
+#define encoding (parser->m_encoding)
+#define initEncoding (parser->m_initEncoding)
+#define internalEncoding (parser->m_internalEncoding)
+#define unknownEncodingMem (parser->m_unknownEncodingMem)
+#define unknownEncodingData (parser->m_unknownEncodingData)
+#define unknownEncodingHandlerData \
+ (parser->m_unknownEncodingHandlerData)
+#define unknownEncodingRelease (parser->m_unknownEncodingRelease)
+#define protocolEncodingName (parser->m_protocolEncodingName)
+#define ns (parser->m_ns)
+#define ns_triplets (parser->m_ns_triplets)
+#define prologState (parser->m_prologState)
+#define processor (parser->m_processor)
+#define errorCode (parser->m_errorCode)
+#define eventPtr (parser->m_eventPtr)
+#define eventEndPtr (parser->m_eventEndPtr)
+#define positionPtr (parser->m_positionPtr)
+#define position (parser->m_position)
+#define openInternalEntities (parser->m_openInternalEntities)
+#define freeInternalEntities (parser->m_freeInternalEntities)
+#define defaultExpandInternalEntities \
+ (parser->m_defaultExpandInternalEntities)
+#define tagLevel (parser->m_tagLevel)
+#define buffer (parser->m_buffer)
+#define bufferPtr (parser->m_bufferPtr)
+#define bufferEnd (parser->m_bufferEnd)
+#define parseEndByteIndex (parser->m_parseEndByteIndex)
+#define parseEndPtr (parser->m_parseEndPtr)
+#define bufferLim (parser->m_bufferLim)
+#define dataBuf (parser->m_dataBuf)
+#define dataBufEnd (parser->m_dataBufEnd)
+#define _dtd (parser->m_dtd)
+#define curBase (parser->m_curBase)
+#define declEntity (parser->m_declEntity)
+#define doctypeName (parser->m_doctypeName)
+#define doctypeSysid (parser->m_doctypeSysid)
+#define doctypePubid (parser->m_doctypePubid)
+#define declAttributeType (parser->m_declAttributeType)
+#define declNotationName (parser->m_declNotationName)
+#define declNotationPublicId (parser->m_declNotationPublicId)
+#define declElementType (parser->m_declElementType)
+#define declAttributeId (parser->m_declAttributeId)
+#define declAttributeIsCdata (parser->m_declAttributeIsCdata)
+#define declAttributeIsId (parser->m_declAttributeIsId)
+#define freeTagList (parser->m_freeTagList)
+#define freeBindingList (parser->m_freeBindingList)
+#define inheritedBindings (parser->m_inheritedBindings)
+#define tagStack (parser->m_tagStack)
+#define atts (parser->m_atts)
+#define attsSize (parser->m_attsSize)
+#define nSpecifiedAtts (parser->m_nSpecifiedAtts)
+#define idAttIndex (parser->m_idAttIndex)
+#define nsAtts (parser->m_nsAtts)
+#define nsAttsVersion (parser->m_nsAttsVersion)
+#define nsAttsPower (parser->m_nsAttsPower)
+#define attInfo (parser->m_attInfo)
+#define tempPool (parser->m_tempPool)
+#define temp2Pool (parser->m_temp2Pool)
+#define groupConnector (parser->m_groupConnector)
+#define groupSize (parser->m_groupSize)
+#define namespaceSeparator (parser->m_namespaceSeparator)
+#define parentParser (parser->m_parentParser)
+#define ps_parsing (parser->m_parsingStatus.parsing)
+#define ps_finalBuffer (parser->m_parsingStatus.finalBuffer)
+#ifdef XML_DTD
+#define isParamEntity (parser->m_isParamEntity)
+#define useForeignDTD (parser->m_useForeignDTD)
+#define paramEntityParsing (parser->m_paramEntityParsing)
+#endif /* XML_DTD */
+#define hash_secret_salt (parser->m_hash_secret_salt)
+
+XML_Parser XMLCALL
+XML_ParserCreate(const XML_Char *encodingName)
+{
+ return XML_ParserCreate_MM(encodingName, NULL, NULL);
+}
+
+XML_Parser XMLCALL
+XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
+{
+ XML_Char tmp[2];
+ *tmp = nsSep;
+ return XML_ParserCreate_MM(encodingName, NULL, tmp);
+}
+
+static const XML_Char implicitContext[] = {
+ ASCII_x, ASCII_m, ASCII_l, ASCII_EQUALS, ASCII_h, ASCII_t, ASCII_t, ASCII_p,
+ ASCII_COLON, ASCII_SLASH, ASCII_SLASH, ASCII_w, ASCII_w, ASCII_w,
+ ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g,
+ ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L, ASCII_SLASH, ASCII_1, ASCII_9,
+ ASCII_9, ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m, ASCII_e,
+ ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e, '\0'
+};
+
+
+#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+
+/* Obtain entropy on Linux 3.17+ */
+static int
+writeRandomBytes_getrandom_nonblock(void * target, size_t count) {
+ int success = 0; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+ const unsigned int getrandomFlags = GRND_NONBLOCK;
+
+ do {
+ void * const currentTarget = (void*)((char*)target + bytesWrittenTotal);
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ const int bytesWrittenMore =
+#if defined(HAVE_GETRANDOM)
+ getrandom(currentTarget, bytesToWrite, getrandomFlags);
+#else
+ syscall(SYS_getrandom, currentTarget, bytesToWrite, getrandomFlags);
+#endif
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = 1;
+ }
+ } while (! success && (errno == EINTR));
+
+ return success;
+}
+
+#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
+
+
+#if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
+
+/* Extract entropy from /dev/urandom */
+static int
+writeRandomBytes_dev_urandom(void * target, size_t count) {
+ int success = 0; /* full count bytes written? */
+ size_t bytesWrittenTotal = 0;
+
+ const int fd = open("/dev/urandom", O_RDONLY);
+ if (fd < 0) {
+ return 0;
+ }
+
+ do {
+ void * const currentTarget = (void*)((char*)target + bytesWrittenTotal);
+ const size_t bytesToWrite = count - bytesWrittenTotal;
+
+ const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite);
+
+ if (bytesWrittenMore > 0) {
+ bytesWrittenTotal += bytesWrittenMore;
+ if (bytesWrittenTotal >= count)
+ success = 1;
+ }
+ } while (! success && (errno == EINTR));
+
+ close(fd);
+ return success;
+}
+
+#endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+
+
+#if defined(HAVE_ARC4RANDOM)
+
+static void
+writeRandomBytes_arc4random(void * target, size_t count) {
+ size_t bytesWrittenTotal = 0;
+
+ while (bytesWrittenTotal < count) {
+ const uint32_t random32 = arc4random();
+ size_t i = 0;
+
+ for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
+ i++, bytesWrittenTotal++) {
+ const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
+ ((uint8_t *)target)[bytesWrittenTotal] = random8;
+ }
+ }
+}
+
+#endif /* defined(HAVE_ARC4RANDOM) */
+
+
+#ifdef _WIN32
+
+typedef BOOLEAN (APIENTRY *RTLGENRANDOM_FUNC)(PVOID, ULONG);
+HMODULE _Expat_LoadLibrary(LPCTSTR filename); /* see loadlibrary.c */
+
+/* Obtain entropy on Windows XP / Windows Server 2003 and later.
+ * Hint on RtlGenRandom and the following article from libsodium.
+ *
+ * Michael Howard: Cryptographically Secure Random number on Windows without using CryptoAPI
+ * https://blogs.msdn.microsoft.com/michael_howard/2005/01/14/cryptographically-secure-random-number-on-windows-without-using-cryptoapi/
+ */
+static int
+writeRandomBytes_RtlGenRandom(void * target, size_t count) {
+ int success = 0; /* full count bytes written? */
+ const HMODULE advapi32 = _Expat_LoadLibrary(TEXT("ADVAPI32.DLL"));
+
+ if (advapi32) {
+ const RTLGENRANDOM_FUNC RtlGenRandom
+ = (RTLGENRANDOM_FUNC)GetProcAddress(advapi32, "SystemFunction036");
+ if (RtlGenRandom) {
+ if (RtlGenRandom((PVOID)target, (ULONG)count) == TRUE) {
+ success = 1;
+ }
+ }
+ FreeLibrary(advapi32);
+ }
+
+ return success;
+}
+
+#endif /* _WIN32 */
+
+
+#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
+
+static unsigned long
+gather_time_entropy(void)
+{
+#ifdef _WIN32
+ FILETIME ft;
+ GetSystemTimeAsFileTime(&ft); /* never fails */
+ return ft.dwHighDateTime ^ ft.dwLowDateTime;
+#else
+ struct timeval tv;
+ int gettimeofday_res;
+
+ gettimeofday_res = gettimeofday(&tv, NULL);
+
+#if defined(NDEBUG)
+ (void)gettimeofday_res;
+#else
+ assert (gettimeofday_res == 0);
+#endif /* defined(NDEBUG) */
+
+ /* Microseconds time is <20 bits entropy */
+ return tv.tv_usec;
+#endif
+}
+
+#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
+
+
+static unsigned long
+ENTROPY_DEBUG(const char * label, unsigned long entropy) {
+ const char * const EXPAT_ENTROPY_DEBUG = getenv("EXPAT_ENTROPY_DEBUG");
+ if (EXPAT_ENTROPY_DEBUG && ! strcmp(EXPAT_ENTROPY_DEBUG, "1")) {
+ fprintf(stderr, "Entropy: %s --> 0x%0*lx (%lu bytes)\n",
+ label,
+ (int)sizeof(entropy) * 2, entropy,
+ (unsigned long)sizeof(entropy));
+ }
+ return entropy;
+}
+
+static unsigned long
+generate_hash_secret_salt(XML_Parser parser)
+{
+ unsigned long entropy;
+ (void)parser;
+#if defined(HAVE_ARC4RANDOM_BUF)
+ arc4random_buf(&entropy, sizeof(entropy));
+ return ENTROPY_DEBUG("arc4random_buf", entropy);
+#elif defined(HAVE_ARC4RANDOM)
+ writeRandomBytes_arc4random((void *)&entropy, sizeof(entropy));
+ return ENTROPY_DEBUG("arc4random", entropy);
+#else
+ /* Try high quality providers first .. */
+#ifdef _WIN32
+ if (writeRandomBytes_RtlGenRandom((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("RtlGenRandom", entropy);
+ }
+#elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
+ if (writeRandomBytes_getrandom_nonblock((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("getrandom", entropy);
+ }
+#endif
+#if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
+ if (writeRandomBytes_dev_urandom((void *)&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("/dev/urandom", entropy);
+ }
+#endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
+ /* .. and self-made low quality for backup: */
+
+ /* Process ID is 0 bits entropy if attacker has local access */
+ entropy = gather_time_entropy() ^ getpid();
+
+ /* Factors are 2^31-1 and 2^61-1 (Mersenne primes M31 and M61) */
+ if (sizeof(unsigned long) == 4) {
+ return ENTROPY_DEBUG("fallback(4)", entropy * 2147483647);
+ } else {
+ return ENTROPY_DEBUG("fallback(8)",
+ entropy * (unsigned long)2305843009213693951ULL);
+ }
+#endif
+}
+
+static unsigned long
+get_hash_secret_salt(XML_Parser parser) {
+ if (parser->m_parentParser != NULL)
+ return get_hash_secret_salt(parser->m_parentParser);
+ return parser->m_hash_secret_salt;
+}
+
+static XML_Bool /* only valid for root parser */
+startParsing(XML_Parser parser)
+{
+ /* hash functions must be initialized before setContext() is called */
+ if (hash_secret_salt == 0)
+ hash_secret_salt = generate_hash_secret_salt(parser);
+ if (ns) {
+ /* implicit context only set for root parser, since child
+ parsers (i.e. external entity parsers) will inherit it
+ */
+ return setContext(parser, implicitContext);
+ }
+ return XML_TRUE;
+}
+
+XML_Parser XMLCALL
+XML_ParserCreate_MM(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep)
+{
+ return parserCreate(encodingName, memsuite, nameSep, NULL);
+}
+
+static XML_Parser
+parserCreate(const XML_Char *encodingName,
+ const XML_Memory_Handling_Suite *memsuite,
+ const XML_Char *nameSep,
+ DTD *dtd)
+{
+ XML_Parser parser;
+
+ if (memsuite) {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)
+ memsuite->malloc_fcn(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = memsuite->malloc_fcn;
+ mtemp->realloc_fcn = memsuite->realloc_fcn;
+ mtemp->free_fcn = memsuite->free_fcn;
+ }
+ }
+ else {
+ XML_Memory_Handling_Suite *mtemp;
+ parser = (XML_Parser)malloc(sizeof(struct XML_ParserStruct));
+ if (parser != NULL) {
+ mtemp = (XML_Memory_Handling_Suite *)&(parser->m_mem);
+ mtemp->malloc_fcn = malloc;
+ mtemp->realloc_fcn = realloc;
+ mtemp->free_fcn = free;
+ }
+ }
+
+ if (!parser)
+ return parser;
+
+ buffer = NULL;
+ bufferLim = NULL;
+
+ attsSize = INIT_ATTS_SIZE;
+ atts = (ATTRIBUTE *)MALLOC(attsSize * sizeof(ATTRIBUTE));
+ if (atts == NULL) {
+ FREE(parser);
+ return NULL;
+ }
+#ifdef XML_ATTR_INFO
+ attInfo = (XML_AttrInfo*)MALLOC(attsSize * sizeof(XML_AttrInfo));
+ if (attInfo == NULL) {
+ FREE(atts);
+ FREE(parser);
+ return NULL;
+ }
+#endif
+ dataBuf = (XML_Char *)MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
+ if (dataBuf == NULL) {
+ FREE(atts);
+#ifdef XML_ATTR_INFO
+ FREE(attInfo);
+#endif
+ FREE(parser);
+ return NULL;
+ }
+ dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
+
+ if (dtd)
+ _dtd = dtd;
+ else {
+ _dtd = dtdCreate(&parser->m_mem);
+ if (_dtd == NULL) {
+ FREE(dataBuf);
+ FREE(atts);
+#ifdef XML_ATTR_INFO
+ FREE(attInfo);
+#endif
+ FREE(parser);
+ return NULL;
+ }
+ }
+
+ freeBindingList = NULL;
+ freeTagList = NULL;
+ freeInternalEntities = NULL;
+
+ groupSize = 0;
+ groupConnector = NULL;
+
+ unknownEncodingHandler = NULL;
+ unknownEncodingHandlerData = NULL;
+
+ namespaceSeparator = ASCII_EXCL;
+ ns = XML_FALSE;
+ ns_triplets = XML_FALSE;
+
+ nsAtts = NULL;
+ nsAttsVersion = 0;
+ nsAttsPower = 0;
+
+ protocolEncodingName = NULL;
+
+ poolInit(&tempPool, &(parser->m_mem));
+ poolInit(&temp2Pool, &(parser->m_mem));
+ parserInit(parser, encodingName);
+
+ if (encodingName && !protocolEncodingName) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+
+ if (nameSep) {
+ ns = XML_TRUE;
+ internalEncoding = XmlGetInternalEncodingNS();
+ namespaceSeparator = *nameSep;
+ }
+ else {
+ internalEncoding = XmlGetInternalEncoding();
+ }
+
+ return parser;
+}
+
+static void
+parserInit(XML_Parser parser, const XML_Char *encodingName)
+{
+ processor = prologInitProcessor;
+ XmlPrologStateInit(&prologState);
+ if (encodingName != NULL) {
+ protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ }
+ curBase = NULL;
+ XmlInitEncoding(&initEncoding, &encoding, 0);
+ userData = NULL;
+ handlerArg = NULL;
+ startElementHandler = NULL;
+ endElementHandler = NULL;
+ characterDataHandler = NULL;
+ processingInstructionHandler = NULL;
+ commentHandler = NULL;
+ startCdataSectionHandler = NULL;
+ endCdataSectionHandler = NULL;
+ defaultHandler = NULL;
+ startDoctypeDeclHandler = NULL;
+ endDoctypeDeclHandler = NULL;
+ unparsedEntityDeclHandler = NULL;
+ notationDeclHandler = NULL;
+ startNamespaceDeclHandler = NULL;
+ endNamespaceDeclHandler = NULL;
+ notStandaloneHandler = NULL;
+ externalEntityRefHandler = NULL;
+ externalEntityRefHandlerArg = parser;
+ skippedEntityHandler = NULL;
+ elementDeclHandler = NULL;
+ attlistDeclHandler = NULL;
+ entityDeclHandler = NULL;
+ xmlDeclHandler = NULL;
+ bufferPtr = buffer;
+ bufferEnd = buffer;
+ parseEndByteIndex = 0;
+ parseEndPtr = NULL;
+ declElementType = NULL;
+ declAttributeId = NULL;
+ declEntity = NULL;
+ doctypeName = NULL;
+ doctypeSysid = NULL;
+ doctypePubid = NULL;
+ declAttributeType = NULL;
+ declNotationName = NULL;
+ declNotationPublicId = NULL;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeIsId = XML_FALSE;
+ memset(&position, 0, sizeof(POSITION));
+ errorCode = XML_ERROR_NONE;
+ eventPtr = NULL;
+ eventEndPtr = NULL;
+ positionPtr = NULL;
+ openInternalEntities = NULL;
+ defaultExpandInternalEntities = XML_TRUE;
+ tagLevel = 0;
+ tagStack = NULL;
+ inheritedBindings = NULL;
+ nSpecifiedAtts = 0;
+ unknownEncodingMem = NULL;
+ unknownEncodingRelease = NULL;
+ unknownEncodingData = NULL;
+ parentParser = NULL;
+ ps_parsing = XML_INITIALIZED;
+#ifdef XML_DTD
+ isParamEntity = XML_FALSE;
+ useForeignDTD = XML_FALSE;
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+ hash_secret_salt = 0;
+}
+
+/* moves list of bindings to freeBindingList */
+static void FASTCALL
+moveToFreeBindingList(XML_Parser parser, BINDING *bindings)
+{
+ while (bindings) {
+ BINDING *b = bindings;
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ }
+}
+
+XML_Bool XMLCALL
+XML_ParserReset(XML_Parser parser, const XML_Char *encodingName)
+{
+ TAG *tStk;
+ OPEN_INTERNAL_ENTITY *openEntityList;
+
+ if (parser == NULL)
+ return XML_FALSE;
+
+ if (parentParser)
+ return XML_FALSE;
+ /* move tagStack to freeTagList */
+ tStk = tagStack;
+ while (tStk) {
+ TAG *tag = tStk;
+ tStk = tStk->parent;
+ tag->parent = freeTagList;
+ moveToFreeBindingList(parser, tag->bindings);
+ tag->bindings = NULL;
+ freeTagList = tag;
+ }
+ /* move openInternalEntities to freeInternalEntities */
+ openEntityList = openInternalEntities;
+ while (openEntityList) {
+ OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
+ openEntityList = openEntity->next;
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ moveToFreeBindingList(parser, inheritedBindings);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ poolClear(&tempPool);
+ poolClear(&temp2Pool);
+ FREE((void *)protocolEncodingName);
+ protocolEncodingName = NULL;
+ parserInit(parser, encodingName);
+ dtdReset(_dtd, &parser->m_mem);
+ return XML_TRUE;
+}
+
+enum XML_Status XMLCALL
+XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ /* Block after XML_Parse()/XML_ParseBuffer() has been called.
+ XXX There's no way for the caller to determine which of the
+ XXX possible error cases caused the XML_STATUS_ERROR return.
+ */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_STATUS_ERROR;
+
+ /* Get rid of any previous encoding name */
+ FREE((void *)protocolEncodingName);
+
+ if (encodingName == NULL)
+ /* No new encoding name */
+ protocolEncodingName = NULL;
+ else {
+ /* Copy the new encoding name into allocated memory */
+ protocolEncodingName = copyString(encodingName, &(parser->m_mem));
+ if (!protocolEncodingName)
+ return XML_STATUS_ERROR;
+ }
+ return XML_STATUS_OK;
+}
+
+XML_Parser XMLCALL
+XML_ExternalEntityParserCreate(XML_Parser oldParser,
+ const XML_Char *context,
+ const XML_Char *encodingName)
+{
+ XML_Parser parser = oldParser;
+ DTD *newDtd = NULL;
+ DTD *oldDtd;
+ XML_StartElementHandler oldStartElementHandler;
+ XML_EndElementHandler oldEndElementHandler;
+ XML_CharacterDataHandler oldCharacterDataHandler;
+ XML_ProcessingInstructionHandler oldProcessingInstructionHandler;
+ XML_CommentHandler oldCommentHandler;
+ XML_StartCdataSectionHandler oldStartCdataSectionHandler;
+ XML_EndCdataSectionHandler oldEndCdataSectionHandler;
+ XML_DefaultHandler oldDefaultHandler;
+ XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler;
+ XML_NotationDeclHandler oldNotationDeclHandler;
+ XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler;
+ XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler;
+ XML_NotStandaloneHandler oldNotStandaloneHandler;
+ XML_ExternalEntityRefHandler oldExternalEntityRefHandler;
+ XML_SkippedEntityHandler oldSkippedEntityHandler;
+ XML_UnknownEncodingHandler oldUnknownEncodingHandler;
+ XML_ElementDeclHandler oldElementDeclHandler;
+ XML_AttlistDeclHandler oldAttlistDeclHandler;
+ XML_EntityDeclHandler oldEntityDeclHandler;
+ XML_XmlDeclHandler oldXmlDeclHandler;
+ ELEMENT_TYPE * oldDeclElementType;
+
+ void *oldUserData;
+ void *oldHandlerArg;
+ XML_Bool oldDefaultExpandInternalEntities;
+ XML_Parser oldExternalEntityRefHandlerArg;
+#ifdef XML_DTD
+ enum XML_ParamEntityParsing oldParamEntityParsing;
+ int oldInEntityValue;
+#endif
+ XML_Bool oldns_triplets;
+ /* Note that the new parser shares the same hash secret as the old
+ parser, so that dtdCopy and copyEntityTable can lookup values
+ from hash tables associated with either parser without us having
+ to worry which hash secrets each table has.
+ */
+ unsigned long oldhash_secret_salt;
+
+ /* Validate the oldParser parameter before we pull everything out of it */
+ if (oldParser == NULL)
+ return NULL;
+
+ /* Stash the original parser contents on the stack */
+ oldDtd = _dtd;
+ oldStartElementHandler = startElementHandler;
+ oldEndElementHandler = endElementHandler;
+ oldCharacterDataHandler = characterDataHandler;
+ oldProcessingInstructionHandler = processingInstructionHandler;
+ oldCommentHandler = commentHandler;
+ oldStartCdataSectionHandler = startCdataSectionHandler;
+ oldEndCdataSectionHandler = endCdataSectionHandler;
+ oldDefaultHandler = defaultHandler;
+ oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
+ oldNotationDeclHandler = notationDeclHandler;
+ oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
+ oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
+ oldNotStandaloneHandler = notStandaloneHandler;
+ oldExternalEntityRefHandler = externalEntityRefHandler;
+ oldSkippedEntityHandler = skippedEntityHandler;
+ oldUnknownEncodingHandler = unknownEncodingHandler;
+ oldElementDeclHandler = elementDeclHandler;
+ oldAttlistDeclHandler = attlistDeclHandler;
+ oldEntityDeclHandler = entityDeclHandler;
+ oldXmlDeclHandler = xmlDeclHandler;
+ oldDeclElementType = declElementType;
+
+ oldUserData = userData;
+ oldHandlerArg = handlerArg;
+ oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
+ oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
+#ifdef XML_DTD
+ oldParamEntityParsing = paramEntityParsing;
+ oldInEntityValue = prologState.inEntityValue;
+#endif
+ oldns_triplets = ns_triplets;
+ /* Note that the new parser shares the same hash secret as the old
+ parser, so that dtdCopy and copyEntityTable can lookup values
+ from hash tables associated with either parser without us having
+ to worry which hash secrets each table has.
+ */
+ oldhash_secret_salt = hash_secret_salt;
+
+#ifdef XML_DTD
+ if (!context)
+ newDtd = oldDtd;
+#endif /* XML_DTD */
+
+ /* Note that the magical uses of the pre-processor to make field
+ access look more like C++ require that `parser' be overwritten
+ here. This makes this function more painful to follow than it
+ would be otherwise.
+ */
+ if (ns) {
+ XML_Char tmp[2];
+ *tmp = namespaceSeparator;
+ parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
+ }
+ else {
+ parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
+ }
+
+ if (!parser)
+ return NULL;
+
+ startElementHandler = oldStartElementHandler;
+ endElementHandler = oldEndElementHandler;
+ characterDataHandler = oldCharacterDataHandler;
+ processingInstructionHandler = oldProcessingInstructionHandler;
+ commentHandler = oldCommentHandler;
+ startCdataSectionHandler = oldStartCdataSectionHandler;
+ endCdataSectionHandler = oldEndCdataSectionHandler;
+ defaultHandler = oldDefaultHandler;
+ unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
+ notationDeclHandler = oldNotationDeclHandler;
+ startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
+ endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
+ notStandaloneHandler = oldNotStandaloneHandler;
+ externalEntityRefHandler = oldExternalEntityRefHandler;
+ skippedEntityHandler = oldSkippedEntityHandler;
+ unknownEncodingHandler = oldUnknownEncodingHandler;
+ elementDeclHandler = oldElementDeclHandler;
+ attlistDeclHandler = oldAttlistDeclHandler;
+ entityDeclHandler = oldEntityDeclHandler;
+ xmlDeclHandler = oldXmlDeclHandler;
+ declElementType = oldDeclElementType;
+ userData = oldUserData;
+ if (oldUserData == oldHandlerArg)
+ handlerArg = userData;
+ else
+ handlerArg = parser;
+ if (oldExternalEntityRefHandlerArg != oldParser)
+ externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
+ defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
+ ns_triplets = oldns_triplets;
+ hash_secret_salt = oldhash_secret_salt;
+ parentParser = oldParser;
+#ifdef XML_DTD
+ paramEntityParsing = oldParamEntityParsing;
+ prologState.inEntityValue = oldInEntityValue;
+ if (context) {
+#endif /* XML_DTD */
+ if (!dtdCopy(oldParser, _dtd, oldDtd, &parser->m_mem)
+ || !setContext(parser, context)) {
+ XML_ParserFree(parser);
+ return NULL;
+ }
+ processor = externalEntityInitProcessor;
+#ifdef XML_DTD
+ }
+ else {
+ /* The DTD instance referenced by _dtd is shared between the document's
+ root parser and external PE parsers, therefore one does not need to
+ call setContext. In addition, one also *must* not call setContext,
+ because this would overwrite existing prefix->binding pointers in
+ _dtd with ones that get destroyed with the external PE parser.
+ This would leave those prefixes with dangling pointers.
+ */
+ isParamEntity = XML_TRUE;
+ XmlPrologStateInitExternalEntity(&prologState);
+ processor = externalParEntInitProcessor;
+ }
+#endif /* XML_DTD */
+ return parser;
+}
+
+static void FASTCALL
+destroyBindings(BINDING *bindings, XML_Parser parser)
+{
+ for (;;) {
+ BINDING *b = bindings;
+ if (!b)
+ break;
+ bindings = b->nextTagBinding;
+ FREE(b->uri);
+ FREE(b);
+ }
+}
+
+void XMLCALL
+XML_ParserFree(XML_Parser parser)
+{
+ TAG *tagList;
+ OPEN_INTERNAL_ENTITY *entityList;
+ if (parser == NULL)
+ return;
+ /* free tagStack and freeTagList */
+ tagList = tagStack;
+ for (;;) {
+ TAG *p;
+ if (tagList == NULL) {
+ if (freeTagList == NULL)
+ break;
+ tagList = freeTagList;
+ freeTagList = NULL;
+ }
+ p = tagList;
+ tagList = tagList->parent;
+ FREE(p->buf);
+ destroyBindings(p->bindings, parser);
+ FREE(p);
+ }
+ /* free openInternalEntities and freeInternalEntities */
+ entityList = openInternalEntities;
+ for (;;) {
+ OPEN_INTERNAL_ENTITY *openEntity;
+ if (entityList == NULL) {
+ if (freeInternalEntities == NULL)
+ break;
+ entityList = freeInternalEntities;
+ freeInternalEntities = NULL;
+ }
+ openEntity = entityList;
+ entityList = entityList->next;
+ FREE(openEntity);
+ }
+
+ destroyBindings(freeBindingList, parser);
+ destroyBindings(inheritedBindings, parser);
+ poolDestroy(&tempPool);
+ poolDestroy(&temp2Pool);
+ FREE((void *)protocolEncodingName);
+#ifdef XML_DTD
+ /* external parameter entity parsers share the DTD structure
+ parser->m_dtd with the root parser, so we must not destroy it
+ */
+ if (!isParamEntity && _dtd)
+#else
+ if (_dtd)
+#endif /* XML_DTD */
+ dtdDestroy(_dtd, (XML_Bool)!parentParser, &parser->m_mem);
+ FREE((void *)atts);
+#ifdef XML_ATTR_INFO
+ FREE((void *)attInfo);
+#endif
+ FREE(groupConnector);
+ FREE(buffer);
+ FREE(dataBuf);
+ FREE(nsAtts);
+ FREE(unknownEncodingMem);
+ if (unknownEncodingRelease)
+ unknownEncodingRelease(unknownEncodingData);
+ FREE(parser);
+}
+
+void XMLCALL
+XML_UseParserAsHandlerArg(XML_Parser parser)
+{
+ if (parser != NULL)
+ handlerArg = parser;
+}
+
+enum XML_Error XMLCALL
+XML_UseForeignDTD(XML_Parser parser, XML_Bool useDTD)
+{
+ if (parser == NULL)
+ return XML_ERROR_INVALID_ARGUMENT;
+#ifdef XML_DTD
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING;
+ useForeignDTD = useDTD;
+ return XML_ERROR_NONE;
+#else
+ return XML_ERROR_FEATURE_REQUIRES_XML_DTD;
+#endif
+}
+
+void XMLCALL
+XML_SetReturnNSTriplet(XML_Parser parser, int do_nst)
+{
+ if (parser == NULL)
+ return;
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return;
+ ns_triplets = do_nst ? XML_TRUE : XML_FALSE;
+}
+
+void XMLCALL
+XML_SetUserData(XML_Parser parser, void *p)
+{
+ if (parser == NULL)
+ return;
+ if (handlerArg == userData)
+ handlerArg = userData = p;
+ else
+ userData = p;
+}
+
+enum XML_Status XMLCALL
+XML_SetBase(XML_Parser parser, const XML_Char *p)
+{
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ if (p) {
+ p = poolCopyString(&_dtd->pool, p);
+ if (!p)
+ return XML_STATUS_ERROR;
+ curBase = p;
+ }
+ else
+ curBase = NULL;
+ return XML_STATUS_OK;
+}
+
+const XML_Char * XMLCALL
+XML_GetBase(XML_Parser parser)
+{
+ if (parser == NULL)
+ return NULL;
+ return curBase;
+}
+
+int XMLCALL
+XML_GetSpecifiedAttributeCount(XML_Parser parser)
+{
+ if (parser == NULL)
+ return -1;
+ return nSpecifiedAtts;
+}
+
+int XMLCALL
+XML_GetIdAttributeIndex(XML_Parser parser)
+{
+ if (parser == NULL)
+ return -1;
+ return idAttIndex;
+}
+
+#ifdef XML_ATTR_INFO
+const XML_AttrInfo * XMLCALL
+XML_GetAttributeInfo(XML_Parser parser)
+{
+ if (parser == NULL)
+ return NULL;
+ return attInfo;
+}
+#endif
+
+void XMLCALL
+XML_SetElementHandler(XML_Parser parser,
+ XML_StartElementHandler start,
+ XML_EndElementHandler end)
+{
+ if (parser == NULL)
+ return;
+ startElementHandler = start;
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetStartElementHandler(XML_Parser parser,
+ XML_StartElementHandler start) {
+ if (parser != NULL)
+ startElementHandler = start;
+}
+
+void XMLCALL
+XML_SetEndElementHandler(XML_Parser parser,
+ XML_EndElementHandler end) {
+ if (parser != NULL)
+ endElementHandler = end;
+}
+
+void XMLCALL
+XML_SetCharacterDataHandler(XML_Parser parser,
+ XML_CharacterDataHandler handler)
+{
+ if (parser != NULL)
+ characterDataHandler = handler;
+}
+
+void XMLCALL
+XML_SetProcessingInstructionHandler(XML_Parser parser,
+ XML_ProcessingInstructionHandler handler)
+{
+ if (parser != NULL)
+ processingInstructionHandler = handler;
+}
+
+void XMLCALL
+XML_SetCommentHandler(XML_Parser parser,
+ XML_CommentHandler handler)
+{
+ if (parser != NULL)
+ commentHandler = handler;
+}
+
+void XMLCALL
+XML_SetCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start,
+ XML_EndCdataSectionHandler end)
+{
+ if (parser == NULL)
+ return;
+ startCdataSectionHandler = start;
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetStartCdataSectionHandler(XML_Parser parser,
+ XML_StartCdataSectionHandler start) {
+ if (parser != NULL)
+ startCdataSectionHandler = start;
+}
+
+void XMLCALL
+XML_SetEndCdataSectionHandler(XML_Parser parser,
+ XML_EndCdataSectionHandler end) {
+ if (parser != NULL)
+ endCdataSectionHandler = end;
+}
+
+void XMLCALL
+XML_SetDefaultHandler(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ if (parser == NULL)
+ return;
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_FALSE;
+}
+
+void XMLCALL
+XML_SetDefaultHandlerExpand(XML_Parser parser,
+ XML_DefaultHandler handler)
+{
+ if (parser == NULL)
+ return;
+ defaultHandler = handler;
+ defaultExpandInternalEntities = XML_TRUE;
+}
+
+void XMLCALL
+XML_SetDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start,
+ XML_EndDoctypeDeclHandler end)
+{
+ if (parser == NULL)
+ return;
+ startDoctypeDeclHandler = start;
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartDoctypeDeclHandler(XML_Parser parser,
+ XML_StartDoctypeDeclHandler start) {
+ if (parser != NULL)
+ startDoctypeDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndDoctypeDeclHandler(XML_Parser parser,
+ XML_EndDoctypeDeclHandler end) {
+ if (parser != NULL)
+ endDoctypeDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
+ XML_UnparsedEntityDeclHandler handler)
+{
+ if (parser != NULL)
+ unparsedEntityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNotationDeclHandler(XML_Parser parser,
+ XML_NotationDeclHandler handler)
+{
+ if (parser != NULL)
+ notationDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start,
+ XML_EndNamespaceDeclHandler end)
+{
+ if (parser == NULL)
+ return;
+ startNamespaceDeclHandler = start;
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetStartNamespaceDeclHandler(XML_Parser parser,
+ XML_StartNamespaceDeclHandler start) {
+ if (parser != NULL)
+ startNamespaceDeclHandler = start;
+}
+
+void XMLCALL
+XML_SetEndNamespaceDeclHandler(XML_Parser parser,
+ XML_EndNamespaceDeclHandler end) {
+ if (parser != NULL)
+ endNamespaceDeclHandler = end;
+}
+
+void XMLCALL
+XML_SetNotStandaloneHandler(XML_Parser parser,
+ XML_NotStandaloneHandler handler)
+{
+ if (parser != NULL)
+ notStandaloneHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandler(XML_Parser parser,
+ XML_ExternalEntityRefHandler handler)
+{
+ if (parser != NULL)
+ externalEntityRefHandler = handler;
+}
+
+void XMLCALL
+XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
+{
+ if (parser == NULL)
+ return;
+ if (arg)
+ externalEntityRefHandlerArg = (XML_Parser)arg;
+ else
+ externalEntityRefHandlerArg = parser;
+}
+
+void XMLCALL
+XML_SetSkippedEntityHandler(XML_Parser parser,
+ XML_SkippedEntityHandler handler)
+{
+ if (parser != NULL)
+ skippedEntityHandler = handler;
+}
+
+void XMLCALL
+XML_SetUnknownEncodingHandler(XML_Parser parser,
+ XML_UnknownEncodingHandler handler,
+ void *data)
+{
+ if (parser == NULL)
+ return;
+ unknownEncodingHandler = handler;
+ unknownEncodingHandlerData = data;
+}
+
+void XMLCALL
+XML_SetElementDeclHandler(XML_Parser parser,
+ XML_ElementDeclHandler eldecl)
+{
+ if (parser != NULL)
+ elementDeclHandler = eldecl;
+}
+
+void XMLCALL
+XML_SetAttlistDeclHandler(XML_Parser parser,
+ XML_AttlistDeclHandler attdecl)
+{
+ if (parser != NULL)
+ attlistDeclHandler = attdecl;
+}
+
+void XMLCALL
+XML_SetEntityDeclHandler(XML_Parser parser,
+ XML_EntityDeclHandler handler)
+{
+ if (parser != NULL)
+ entityDeclHandler = handler;
+}
+
+void XMLCALL
+XML_SetXmlDeclHandler(XML_Parser parser,
+ XML_XmlDeclHandler handler) {
+ if (parser != NULL)
+ xmlDeclHandler = handler;
+}
+
+int XMLCALL
+XML_SetParamEntityParsing(XML_Parser parser,
+ enum XML_ParamEntityParsing peParsing)
+{
+ if (parser == NULL)
+ return 0;
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return 0;
+#ifdef XML_DTD
+ paramEntityParsing = peParsing;
+ return 1;
+#else
+ return peParsing == XML_PARAM_ENTITY_PARSING_NEVER;
+#endif
+}
+
+int XMLCALL
+XML_SetHashSalt(XML_Parser parser,
+ unsigned long hash_salt)
+{
+ if (parser == NULL)
+ return 0;
+ if (parser->m_parentParser)
+ return XML_SetHashSalt(parser->m_parentParser, hash_salt);
+ /* block after XML_Parse()/XML_ParseBuffer() has been called */
+ if (ps_parsing == XML_PARSING || ps_parsing == XML_SUSPENDED)
+ return 0;
+ hash_secret_salt = hash_salt;
+ return 1;
+}
+
+enum XML_Status XMLCALL
+XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
+{
+ if ((parser == NULL) || (len < 0) || ((s == NULL) && (len != 0))) {
+ if (parser != NULL)
+ parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
+ return XML_STATUS_ERROR;
+ }
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ case XML_INITIALIZED:
+ if (parentParser == NULL && !startParsing(parser)) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return XML_STATUS_ERROR;
+ }
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ if (len == 0) {
+ ps_finalBuffer = (XML_Bool)isFinal;
+ if (!isFinal)
+ return XML_STATUS_OK;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+
+ /* If data are left over from last buffer, and we now know that these
+ data are the final chunk of input, then we have to check them again
+ to detect errors based on that fact.
+ */
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode == XML_ERROR_NONE) {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ /* It is hard to be certain, but it seems that this case
+ * cannot occur. This code is cleaning up a previous parse
+ * with no new data (since len == 0). Changing the parsing
+ * state requires getting to execute a handler function, and
+ * there doesn't seem to be an opportunity for that while in
+ * this circumstance.
+ *
+ * Given the uncertainty, we retain the code but exclude it
+ * from coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return XML_STATUS_SUSPENDED;
+ /* LCOV_EXCL_STOP */
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ ps_parsing = XML_FINISHED;
+ /* fall through */
+ default:
+ return XML_STATUS_OK;
+ }
+ }
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+#ifndef XML_CONTEXT_BYTES
+ else if (bufferPtr == bufferEnd) {
+ const char *end;
+ int nLeftOver;
+ enum XML_Status result;
+ /* Detect overflow (a+b > MAX <==> b > MAX-a) */
+ if (len > ((XML_Size)-1) / 2 - parseEndByteIndex) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = NULL;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ parseEndByteIndex += len;
+ positionPtr = s;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, s, parseEndPtr = s + len, &end);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return XML_STATUS_OK;
+ }
+ /* fall through */
+ default:
+ result = XML_STATUS_OK;
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, end, &position);
+ nLeftOver = s + len - end;
+ if (nLeftOver) {
+ if (buffer == NULL || nLeftOver > bufferLim - buffer) {
+ /* avoid _signed_ integer overflow */
+ char *temp = NULL;
+ const int bytesToAllocate = (int)((unsigned)len * 2U);
+ if (bytesToAllocate > 0) {
+ temp = (buffer == NULL
+ ? (char *)MALLOC(bytesToAllocate)
+ : (char *)REALLOC(buffer, bytesToAllocate));
+ }
+ if (temp == NULL) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ eventPtr = eventEndPtr = NULL;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ buffer = temp;
+ bufferLim = buffer + bytesToAllocate;
+ }
+ memcpy(buffer, end, nLeftOver);
+ }
+ bufferPtr = buffer;
+ bufferEnd = buffer + nLeftOver;
+ positionPtr = bufferPtr;
+ parseEndPtr = bufferEnd;
+ eventPtr = bufferPtr;
+ eventEndPtr = bufferPtr;
+ return result;
+ }
+#endif /* not defined XML_CONTEXT_BYTES */
+ else {
+ void *buff = XML_GetBuffer(parser, len);
+ if (buff == NULL)
+ return XML_STATUS_ERROR;
+ else {
+ memcpy(buff, s, len);
+ return XML_ParseBuffer(parser, len, isFinal);
+ }
+ }
+}
+
+enum XML_Status XMLCALL
+XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
+{
+ const char *start;
+ enum XML_Status result = XML_STATUS_OK;
+
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ case XML_INITIALIZED:
+ if (parentParser == NULL && !startParsing(parser)) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return XML_STATUS_ERROR;
+ }
+ default:
+ ps_parsing = XML_PARSING;
+ }
+
+ start = bufferPtr;
+ positionPtr = start;
+ bufferEnd += len;
+ parseEndPtr = bufferEnd;
+ parseEndByteIndex += len;
+ ps_finalBuffer = (XML_Bool)isFinal;
+
+ errorCode = processor(parser, start, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (isFinal) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ; /* should not happen */
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void * XMLCALL
+XML_GetBuffer(XML_Parser parser, int len)
+{
+ if (parser == NULL)
+ return NULL;
+ if (len < 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ errorCode = XML_ERROR_SUSPENDED;
+ return NULL;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return NULL;
+ default: ;
+ }
+
+ if (len > bufferLim - bufferEnd) {
+#ifdef XML_CONTEXT_BYTES
+ int keep;
+#endif /* defined XML_CONTEXT_BYTES */
+ /* Do not invoke signed arithmetic overflow: */
+ int neededSize = (int) ((unsigned)len + (unsigned)(bufferEnd - bufferPtr));
+ if (neededSize < 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+#ifdef XML_CONTEXT_BYTES
+ keep = (int)(bufferPtr - buffer);
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ neededSize += keep;
+#endif /* defined XML_CONTEXT_BYTES */
+ if (neededSize <= bufferLim - buffer) {
+#ifdef XML_CONTEXT_BYTES
+ if (keep < bufferPtr - buffer) {
+ int offset = (int)(bufferPtr - buffer) - keep;
+ memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
+ bufferEnd -= offset;
+ bufferPtr -= offset;
+ }
+#else
+ memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
+ bufferEnd = buffer + (bufferEnd - bufferPtr);
+ bufferPtr = buffer;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ else {
+ char *newBuf;
+ int bufferSize = (int)(bufferLim - bufferPtr);
+ if (bufferSize == 0)
+ bufferSize = INIT_BUFFER_SIZE;
+ do {
+ /* Do not invoke signed arithmetic overflow: */
+ bufferSize = (int) (2U * (unsigned) bufferSize);
+ } while (bufferSize < neededSize && bufferSize > 0);
+ if (bufferSize <= 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+ newBuf = (char *)MALLOC(bufferSize);
+ if (newBuf == 0) {
+ errorCode = XML_ERROR_NO_MEMORY;
+ return NULL;
+ }
+ bufferLim = newBuf + bufferSize;
+#ifdef XML_CONTEXT_BYTES
+ if (bufferPtr) {
+ int keep = (int)(bufferPtr - buffer);
+ if (keep > XML_CONTEXT_BYTES)
+ keep = XML_CONTEXT_BYTES;
+ memcpy(newBuf, &bufferPtr[-keep], bufferEnd - bufferPtr + keep);
+ FREE(buffer);
+ buffer = newBuf;
+ bufferEnd = buffer + (bufferEnd - bufferPtr) + keep;
+ bufferPtr = buffer + keep;
+ }
+ else {
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+ }
+#else
+ if (bufferPtr) {
+ memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
+ FREE(buffer);
+ }
+ bufferEnd = newBuf + (bufferEnd - bufferPtr);
+ bufferPtr = buffer = newBuf;
+#endif /* not defined XML_CONTEXT_BYTES */
+ }
+ eventPtr = eventEndPtr = NULL;
+ positionPtr = NULL;
+ }
+ return bufferEnd;
+}
+
+enum XML_Status XMLCALL
+XML_StopParser(XML_Parser parser, XML_Bool resumable)
+{
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ if (resumable) {
+ errorCode = XML_ERROR_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_FINISHED;
+ break;
+ case XML_FINISHED:
+ errorCode = XML_ERROR_FINISHED;
+ return XML_STATUS_ERROR;
+ default:
+ if (resumable) {
+#ifdef XML_DTD
+ if (isParamEntity) {
+ errorCode = XML_ERROR_SUSPEND_PE;
+ return XML_STATUS_ERROR;
+ }
+#endif
+ ps_parsing = XML_SUSPENDED;
+ }
+ else
+ ps_parsing = XML_FINISHED;
+ }
+ return XML_STATUS_OK;
+}
+
+enum XML_Status XMLCALL
+XML_ResumeParser(XML_Parser parser)
+{
+ enum XML_Status result = XML_STATUS_OK;
+
+ if (parser == NULL)
+ return XML_STATUS_ERROR;
+ if (ps_parsing != XML_SUSPENDED) {
+ errorCode = XML_ERROR_NOT_SUSPENDED;
+ return XML_STATUS_ERROR;
+ }
+ ps_parsing = XML_PARSING;
+
+ errorCode = processor(parser, bufferPtr, parseEndPtr, &bufferPtr);
+
+ if (errorCode != XML_ERROR_NONE) {
+ eventEndPtr = eventPtr;
+ processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+ else {
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ result = XML_STATUS_SUSPENDED;
+ break;
+ case XML_INITIALIZED:
+ case XML_PARSING:
+ if (ps_finalBuffer) {
+ ps_parsing = XML_FINISHED;
+ return result;
+ }
+ default: ;
+ }
+ }
+
+ XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
+ positionPtr = bufferPtr;
+ return result;
+}
+
+void XMLCALL
+XML_GetParsingStatus(XML_Parser parser, XML_ParsingStatus *status)
+{
+ if (parser == NULL)
+ return;
+ assert(status != NULL);
+ *status = parser->m_parsingStatus;
+}
+
+enum XML_Error XMLCALL
+XML_GetErrorCode(XML_Parser parser)
+{
+ if (parser == NULL)
+ return XML_ERROR_INVALID_ARGUMENT;
+ return errorCode;
+}
+
+XML_Index XMLCALL
+XML_GetCurrentByteIndex(XML_Parser parser)
+{
+ if (parser == NULL)
+ return -1;
+ if (eventPtr)
+ return (XML_Index)(parseEndByteIndex - (parseEndPtr - eventPtr));
+ return -1;
+}
+
+int XMLCALL
+XML_GetCurrentByteCount(XML_Parser parser)
+{
+ if (parser == NULL)
+ return 0;
+ if (eventEndPtr && eventPtr)
+ return (int)(eventEndPtr - eventPtr);
+ return 0;
+}
+
+const char * XMLCALL
+XML_GetInputContext(XML_Parser parser, int *offset, int *size)
+{
+#ifdef XML_CONTEXT_BYTES
+ if (parser == NULL)
+ return NULL;
+ if (eventPtr && buffer) {
+ if (offset != NULL)
+ *offset = (int)(eventPtr - buffer);
+ if (size != NULL)
+ *size = (int)(bufferEnd - buffer);
+ return buffer;
+ }
+#else
+ (void)parser;
+ (void)offset;
+ (void)size;
+#endif /* defined XML_CONTEXT_BYTES */
+ return (char *) 0;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentLineNumber(XML_Parser parser)
+{
+ if (parser == NULL)
+ return 0;
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.lineNumber + 1;
+}
+
+XML_Size XMLCALL
+XML_GetCurrentColumnNumber(XML_Parser parser)
+{
+ if (parser == NULL)
+ return 0;
+ if (eventPtr && eventPtr >= positionPtr) {
+ XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
+ positionPtr = eventPtr;
+ }
+ return position.columnNumber;
+}
+
+void XMLCALL
+XML_FreeContentModel(XML_Parser parser, XML_Content *model)
+{
+ if (parser != NULL)
+ FREE(model);
+}
+
+void * XMLCALL
+XML_MemMalloc(XML_Parser parser, size_t size)
+{
+ if (parser == NULL)
+ return NULL;
+ return MALLOC(size);
+}
+
+void * XMLCALL
+XML_MemRealloc(XML_Parser parser, void *ptr, size_t size)
+{
+ if (parser == NULL)
+ return NULL;
+ return REALLOC(ptr, size);
+}
+
+void XMLCALL
+XML_MemFree(XML_Parser parser, void *ptr)
+{
+ if (parser != NULL)
+ FREE(ptr);
+}
+
+void XMLCALL
+XML_DefaultCurrent(XML_Parser parser)
+{
+ if (parser == NULL)
+ return;
+ if (defaultHandler) {
+ if (openInternalEntities)
+ reportDefault(parser,
+ internalEncoding,
+ openInternalEntities->internalEventPtr,
+ openInternalEntities->internalEventEndPtr);
+ else
+ reportDefault(parser, encoding, eventPtr, eventEndPtr);
+ }
+}
+
+const XML_LChar * XMLCALL
+XML_ErrorString(enum XML_Error code)
+{
+ static const XML_LChar* const message[] = {
+ 0,
+ XML_L("out of memory"),
+ XML_L("syntax error"),
+ XML_L("no element found"),
+ XML_L("not well-formed (invalid token)"),
+ XML_L("unclosed token"),
+ XML_L("partial character"),
+ XML_L("mismatched tag"),
+ XML_L("duplicate attribute"),
+ XML_L("junk after document element"),
+ XML_L("illegal parameter entity reference"),
+ XML_L("undefined entity"),
+ XML_L("recursive entity reference"),
+ XML_L("asynchronous entity"),
+ XML_L("reference to invalid character number"),
+ XML_L("reference to binary entity"),
+ XML_L("reference to external entity in attribute"),
+ XML_L("XML or text declaration not at start of entity"),
+ XML_L("unknown encoding"),
+ XML_L("encoding specified in XML declaration is incorrect"),
+ XML_L("unclosed CDATA section"),
+ XML_L("error in processing external entity reference"),
+ XML_L("document is not standalone"),
+ XML_L("unexpected parser state - please send a bug report"),
+ XML_L("entity declared in parameter entity"),
+ XML_L("requested feature requires XML_DTD support in Expat"),
+ XML_L("cannot change setting once parsing has begun"),
+ XML_L("unbound prefix"),
+ XML_L("must not undeclare prefix"),
+ XML_L("incomplete markup in parameter entity"),
+ XML_L("XML declaration not well-formed"),
+ XML_L("text declaration not well-formed"),
+ XML_L("illegal character(s) in public id"),
+ XML_L("parser suspended"),
+ XML_L("parser not suspended"),
+ XML_L("parsing aborted"),
+ XML_L("parsing finished"),
+ XML_L("cannot suspend in external parameter entity"),
+ XML_L("reserved prefix (xml) must not be undeclared or bound to another namespace name"),
+ XML_L("reserved prefix (xmlns) must not be declared or undeclared"),
+ XML_L("prefix must not be bound to one of the reserved namespace names")
+ };
+ if (code > 0 && code < sizeof(message)/sizeof(message[0]))
+ return message[code];
+ return NULL;
+}
+
+const XML_LChar * XMLCALL
+XML_ExpatVersion(void) {
+
+ /* V1 is used to string-ize the version number. However, it would
+ string-ize the actual version macro *names* unless we get them
+ substituted before being passed to V1. CPP is defined to expand
+ a macro, then rescan for more expansions. Thus, we use V2 to expand
+ the version macros, then CPP will expand the resulting V1() macro
+ with the correct numerals. */
+ /* ### I'm assuming cpp is portable in this respect... */
+
+#define V1(a,b,c) XML_L(#a)XML_L(".")XML_L(#b)XML_L(".")XML_L(#c)
+#define V2(a,b,c) XML_L("expat_")V1(a,b,c)
+
+ return V2(XML_MAJOR_VERSION, XML_MINOR_VERSION, XML_MICRO_VERSION);
+
+#undef V1
+#undef V2
+}
+
+XML_Expat_Version XMLCALL
+XML_ExpatVersionInfo(void)
+{
+ XML_Expat_Version version;
+
+ version.major = XML_MAJOR_VERSION;
+ version.minor = XML_MINOR_VERSION;
+ version.micro = XML_MICRO_VERSION;
+
+ return version;
+}
+
+const XML_Feature * XMLCALL
+XML_GetFeatureList(void)
+{
+ static const XML_Feature features[] = {
+ {XML_FEATURE_SIZEOF_XML_CHAR, XML_L("sizeof(XML_Char)"),
+ sizeof(XML_Char)},
+ {XML_FEATURE_SIZEOF_XML_LCHAR, XML_L("sizeof(XML_LChar)"),
+ sizeof(XML_LChar)},
+#ifdef XML_UNICODE
+ {XML_FEATURE_UNICODE, XML_L("XML_UNICODE"), 0},
+#endif
+#ifdef XML_UNICODE_WCHAR_T
+ {XML_FEATURE_UNICODE_WCHAR_T, XML_L("XML_UNICODE_WCHAR_T"), 0},
+#endif
+#ifdef XML_DTD
+ {XML_FEATURE_DTD, XML_L("XML_DTD"), 0},
+#endif
+#ifdef XML_CONTEXT_BYTES
+ {XML_FEATURE_CONTEXT_BYTES, XML_L("XML_CONTEXT_BYTES"),
+ XML_CONTEXT_BYTES},
+#endif
+#ifdef XML_MIN_SIZE
+ {XML_FEATURE_MIN_SIZE, XML_L("XML_MIN_SIZE"), 0},
+#endif
+#ifdef XML_NS
+ {XML_FEATURE_NS, XML_L("XML_NS"), 0},
+#endif
+#ifdef XML_LARGE_SIZE
+ {XML_FEATURE_LARGE_SIZE, XML_L("XML_LARGE_SIZE"), 0},
+#endif
+#ifdef XML_ATTR_INFO
+ {XML_FEATURE_ATTR_INFO, XML_L("XML_ATTR_INFO"), 0},
+#endif
+ {XML_FEATURE_END, NULL, 0}
+ };
+
+ return features;
+}
+
+/* Initially tag->rawName always points into the parse buffer;
+ for those TAG instances opened while the current parse buffer was
+ processed, and not yet closed, we need to store tag->rawName in a more
+ permanent location, since the parse buffer is about to be discarded.
+*/
+static XML_Bool
+storeRawNames(XML_Parser parser)
+{
+ TAG *tag = tagStack;
+ while (tag) {
+ int bufSize;
+ int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+ char *rawNameBuf = tag->buf + nameLen;
+ /* Stop if already stored. Since tagStack is a stack, we can stop
+ at the first entry that has already been copied; everything
+ below it in the stack is already been accounted for in a
+ previous call to this function.
+ */
+ if (tag->rawName == rawNameBuf)
+ break;
+ /* For re-use purposes we need to ensure that the
+ size of tag->buf is a multiple of sizeof(XML_Char).
+ */
+ bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+ if (bufSize > tag->bufEnd - tag->buf) {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_FALSE;
+ /* if tag->name.str points to tag->buf (only when namespace
+ processing is off) then we have to update it
+ */
+ if (tag->name.str == (XML_Char *)tag->buf)
+ tag->name.str = (XML_Char *)temp;
+ /* if tag->name.localPart is set (when namespace processing is on)
+ then update it as well, since it will always point into tag->buf
+ */
+ if (tag->name.localPart)
+ tag->name.localPart = (XML_Char *)temp + (tag->name.localPart -
+ (XML_Char *)tag->buf);
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ rawNameBuf = temp + nameLen;
+ }
+ memcpy(rawNameBuf, tag->rawName, tag->rawNameLength);
+ tag->rawName = rawNameBuf;
+ tag = tag->parent;
+ }
+ return XML_TRUE;
+}
+
+static enum XML_Error PTRCALL
+contentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 0, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = externalEntityInitProcessor2;
+ return externalEntityInitProcessor2(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor2(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(encoding, start, end, &next);
+ switch (tok) {
+ case XML_TOK_BOM:
+ /* If we are at the end of the buffer, this would cause the next stage,
+ i.e. externalEntityInitProcessor3, to pass control directly to
+ doContent (by detecting XML_TOK_NONE) without processing any xml text
+ declaration - causing the error XML_ERROR_MISPLACED_XML_PI in doContent.
+ */
+ if (next == end && !ps_finalBuffer) {
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ }
+ start = next;
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ eventPtr = start;
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityInitProcessor3;
+ return externalEntityInitProcessor3(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityInitProcessor3(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ int tok;
+ const char *next = start; /* XmlContentTok doesn't always set the last arg */
+ eventPtr = start;
+ tok = XmlContentTok(encoding, start, end, &next);
+ eventEndPtr = next;
+
+ switch (tok) {
+ case XML_TOK_XML_DECL:
+ {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 1, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *endPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ start = next;
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *endPtr = start;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ }
+ processor = externalEntityContentProcessor;
+ tagLevel = 1;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+}
+
+static enum XML_Error PTRCALL
+externalEntityContentProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doContent(parser, 1, encoding, start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result == XML_ERROR_NONE) {
+ if (!storeRawNames(parser))
+ return XML_ERROR_NO_MEMORY;
+ }
+ return result;
+}
+
+static enum XML_Error
+doContent(XML_Parser parser,
+ int startTagLevel,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+
+ for (;;) {
+ const char *next = s; /* XmlContentTok doesn't always set the last arg */
+ int tok = XmlContentTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_TRAILING_CR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ *eventEndPP = end;
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0)
+ return XML_ERROR_NO_ELEMENTS;
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (startTagLevel > 0) {
+ if (tagLevel != startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_NO_ELEMENTS;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (characterDataHandler)
+ characterDataHandler(handlerArg, &ch, 1);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity or default handler.
+ */
+ if (!dtd->hasParamEntityRefs || dtd->standalone) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->notation)
+ return XML_ERROR_BINARY_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ if (!defaultExpandInternalEntities) {
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, entity->name, 0);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ result = processInternalEntity(parser, entity, XML_FALSE);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ else if (externalEntityRefHandler) {
+ const XML_Char *context;
+ entity->open = XML_TRUE;
+ context = getContext(parser);
+ entity->open = XML_FALSE;
+ if (!context)
+ return XML_ERROR_NO_MEMORY;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ context,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ poolDiscard(&tempPool);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ }
+ case XML_TOK_START_TAG_NO_ATTS:
+ /* fall through */
+ case XML_TOK_START_TAG_WITH_ATTS:
+ {
+ TAG *tag;
+ enum XML_Error result;
+ XML_Char *toPtr;
+ if (freeTagList) {
+ tag = freeTagList;
+ freeTagList = freeTagList->parent;
+ }
+ else {
+ tag = (TAG *)MALLOC(sizeof(TAG));
+ if (!tag)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = (char *)MALLOC(INIT_TAG_BUF_SIZE);
+ if (!tag->buf) {
+ FREE(tag);
+ return XML_ERROR_NO_MEMORY;
+ }
+ tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
+ }
+ tag->bindings = NULL;
+ tag->parent = tagStack;
+ tagStack = tag;
+ tag->name.localPart = NULL;
+ tag->name.prefix = NULL;
+ tag->rawName = s + enc->minBytesPerChar;
+ tag->rawNameLength = XmlNameLength(enc, tag->rawName);
+ ++tagLevel;
+ {
+ const char *rawNameEnd = tag->rawName + tag->rawNameLength;
+ const char *fromPtr = tag->rawName;
+ toPtr = (XML_Char *)tag->buf;
+ for (;;) {
+ int bufSize;
+ int convLen;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc,
+ &fromPtr, rawNameEnd,
+ (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
+ convLen = (int)(toPtr - (XML_Char *)tag->buf);
+ if ((fromPtr >= rawNameEnd) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
+ tag->name.strLen = convLen;
+ break;
+ }
+ bufSize = (int)(tag->bufEnd - tag->buf) << 1;
+ {
+ char *temp = (char *)REALLOC(tag->buf, bufSize);
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ tag->buf = temp;
+ tag->bufEnd = temp + bufSize;
+ toPtr = (XML_Char *)temp + convLen;
+ }
+ }
+ }
+ tag->name.str = (XML_Char *)tag->buf;
+ *toPtr = XML_T('\0');
+ result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
+ if (result)
+ return result;
+ if (startElementHandler)
+ startElementHandler(handlerArg, tag->name.str,
+ (const XML_Char **)atts);
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ break;
+ }
+ case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
+ /* fall through */
+ case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
+ {
+ const char *rawName = s + enc->minBytesPerChar;
+ enum XML_Error result;
+ BINDING *bindings = NULL;
+ XML_Bool noElmHandlers = XML_TRUE;
+ TAG_NAME name;
+ name.str = poolStoreString(&tempPool, enc, rawName,
+ rawName + XmlNameLength(enc, rawName));
+ if (!name.str)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ result = storeAtts(parser, enc, s, &name, &bindings);
+ if (result != XML_ERROR_NONE) {
+ freeBindings(parser, bindings);
+ return result;
+ }
+ poolFinish(&tempPool);
+ if (startElementHandler) {
+ startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
+ noElmHandlers = XML_FALSE;
+ }
+ if (endElementHandler) {
+ if (startElementHandler)
+ *eventPP = *eventEndPP;
+ endElementHandler(handlerArg, name.str);
+ noElmHandlers = XML_FALSE;
+ }
+ if (noElmHandlers && defaultHandler)
+ reportDefault(parser, enc, s, next);
+ poolClear(&tempPool);
+ freeBindings(parser, bindings);
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ break;
+ case XML_TOK_END_TAG:
+ if (tagLevel == startTagLevel)
+ return XML_ERROR_ASYNC_ENTITY;
+ else {
+ int len;
+ const char *rawName;
+ TAG *tag = tagStack;
+ tagStack = tag->parent;
+ tag->parent = freeTagList;
+ freeTagList = tag;
+ rawName = s + enc->minBytesPerChar*2;
+ len = XmlNameLength(enc, rawName);
+ if (len != tag->rawNameLength
+ || memcmp(tag->rawName, rawName, len) != 0) {
+ *eventPP = rawName;
+ return XML_ERROR_TAG_MISMATCH;
+ }
+ --tagLevel;
+ if (endElementHandler) {
+ const XML_Char *localPart;
+ const XML_Char *prefix;
+ XML_Char *uri;
+ localPart = tag->name.localPart;
+ if (ns && localPart) {
+ /* localPart and prefix may have been overwritten in
+ tag->name.str, since this points to the binding->uri
+ buffer which gets re-used; so we have to add them again
+ */
+ uri = (XML_Char *)tag->name.str + tag->name.uriLen;
+ /* don't need to check for space - already done in storeAtts() */
+ while (*localPart) *uri++ = *localPart++;
+ prefix = (XML_Char *)tag->name.prefix;
+ if (ns_triplets && prefix) {
+ *uri++ = namespaceSeparator;
+ while (*prefix) *uri++ = *prefix++;
+ }
+ *uri = XML_T('\0');
+ }
+ endElementHandler(handlerArg, tag->name.str);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ while (tag->bindings) {
+ BINDING *b = tag->bindings;
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+ tag->bindings = tag->bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+ if (tagLevel == 0)
+ return epilogProcessor(parser, next, end, nextPtr);
+ }
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ int n = XmlCharRefNumber(enc, s);
+ if (n < 0)
+ return XML_ERROR_BAD_CHAR_REF;
+ if (characterDataHandler) {
+ XML_Char buf[XML_ENCODE_MAX];
+ characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_CDATA_SECT_OPEN:
+ {
+ enum XML_Error result;
+ if (startCdataSectionHandler)
+ startCdataSectionHandler(handlerArg);
+#if 0
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the
+ transformation and writes the characters out escaping them as
+ necessary. This case will fail to work if we leave out the
+ following two lines (because & and < inside CDATA sections will
+ be incorrectly escaped).
+
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this.
+ */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ result = doCdataSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = cdataSectionProcessor;
+ return result;
+ }
+ }
+ break;
+ case XML_TOK_TRAILING_RSQB:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ if (characterDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ characterDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ }
+ else
+ characterDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)end - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, end);
+ /* We are at the end of the final buffer, should we check for
+ XML_SUSPENDED, XML_FINISHED?
+ */
+ if (startTagLevel == 0) {
+ *eventPP = end;
+ return XML_ERROR_NO_ELEMENTS;
+ }
+ if (tagLevel != startTagLevel) {
+ *eventPP = end;
+ return XML_ERROR_ASYNC_ENTITY;
+ }
+ *nextPtr = end;
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_CHARS:
+ {
+ XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ charDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ charDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ default:
+ /* All of the tokens produced by XmlContentTok() have their own
+ * explicit cases, so this default is not strictly necessary.
+ * However it is a useful safety net, so we retain the code and
+ * simply exclude it from the coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ /* LCOV_EXCL_STOP */
+ }
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+/* This function does not call free() on the allocated memory, merely
+ * moving it to the parser's freeBindingList where it can be freed or
+ * reused as appropriate.
+ */
+static void
+freeBindings(XML_Parser parser, BINDING *bindings)
+{
+ while (bindings) {
+ BINDING *b = bindings;
+
+ /* startNamespaceDeclHandler will have been called for this
+ * binding in addBindings(), so call the end handler now.
+ */
+ if (endNamespaceDeclHandler)
+ endNamespaceDeclHandler(handlerArg, b->prefix->name);
+
+ bindings = bindings->nextTagBinding;
+ b->nextTagBinding = freeBindingList;
+ freeBindingList = b;
+ b->prefix->binding = b->prevPrefixBinding;
+ }
+}
+
+/* Precondition: all arguments must be non-NULL;
+ Purpose:
+ - normalize attributes
+ - check attributes for well-formedness
+ - generate namespace aware attribute names (URI, prefix)
+ - build list of attributes for startElementHandler
+ - default attributes
+ - process namespace declarations (check and report them)
+ - generate namespace aware element name (URI, prefix)
+*/
+static enum XML_Error
+storeAtts(XML_Parser parser, const ENCODING *enc,
+ const char *attStr, TAG_NAME *tagNamePtr,
+ BINDING **bindingsPtr)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ELEMENT_TYPE *elementType;
+ int nDefaultAtts;
+ const XML_Char **appAtts; /* the attribute list for the application */
+ int attIndex = 0;
+ int prefixLen;
+ int i;
+ int n;
+ XML_Char *uri;
+ int nPrefixes = 0;
+ BINDING *binding;
+ const XML_Char *localPart;
+
+ /* lookup the element type name */
+ elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str,0);
+ if (!elementType) {
+ const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ elementType = (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, name,
+ sizeof(ELEMENT_TYPE));
+ if (!elementType)
+ return XML_ERROR_NO_MEMORY;
+ if (ns && !setElementTypePrefix(parser, elementType))
+ return XML_ERROR_NO_MEMORY;
+ }
+ nDefaultAtts = elementType->nDefaultAtts;
+
+ /* get the attributes from the tokenizer */
+ n = XmlGetAttributes(enc, attStr, attsSize, atts);
+ if (n + nDefaultAtts > attsSize) {
+ int oldAttsSize = attsSize;
+ ATTRIBUTE *temp;
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *temp2;
+#endif
+ attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
+ temp = (ATTRIBUTE *)REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
+ if (temp == NULL) {
+ attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+ atts = temp;
+#ifdef XML_ATTR_INFO
+ temp2 = (XML_AttrInfo *)REALLOC((void *)attInfo, attsSize * sizeof(XML_AttrInfo));
+ if (temp2 == NULL) {
+ attsSize = oldAttsSize;
+ return XML_ERROR_NO_MEMORY;
+ }
+ attInfo = temp2;
+#endif
+ if (n > oldAttsSize)
+ XmlGetAttributes(enc, attStr, n, atts);
+ }
+
+ appAtts = (const XML_Char **)atts;
+ for (i = 0; i < n; i++) {
+ ATTRIBUTE *currAtt = &atts[i];
+#ifdef XML_ATTR_INFO
+ XML_AttrInfo *currAttInfo = &attInfo[i];
+#endif
+ /* add the name and value to the attribute list */
+ ATTRIBUTE_ID *attId = getAttributeId(parser, enc, currAtt->name,
+ currAtt->name
+ + XmlNameLength(enc, currAtt->name));
+ if (!attId)
+ return XML_ERROR_NO_MEMORY;
+#ifdef XML_ATTR_INFO
+ currAttInfo->nameStart = parseEndByteIndex - (parseEndPtr - currAtt->name);
+ currAttInfo->nameEnd = currAttInfo->nameStart +
+ XmlNameLength(enc, currAtt->name);
+ currAttInfo->valueStart = parseEndByteIndex -
+ (parseEndPtr - currAtt->valuePtr);
+ currAttInfo->valueEnd = parseEndByteIndex - (parseEndPtr - currAtt->valueEnd);
+#endif
+ /* Detect duplicate attributes by their QNames. This does not work when
+ namespace processing is turned on and different prefixes for the same
+ namespace are used. For this case we have a check further down.
+ */
+ if ((attId->name)[-1]) {
+ if (enc == encoding)
+ eventPtr = atts[i].name;
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ (attId->name)[-1] = 1;
+ appAtts[attIndex++] = attId->name;
+ if (!atts[i].normalized) {
+ enum XML_Error result;
+ XML_Bool isCdata = XML_TRUE;
+
+ /* figure out whether declared as other than CDATA */
+ if (attId->maybeTokenized) {
+ int j;
+ for (j = 0; j < nDefaultAtts; j++) {
+ if (attId == elementType->defaultAtts[j].id) {
+ isCdata = elementType->defaultAtts[j].isCdata;
+ break;
+ }
+ }
+ }
+
+ /* normalize the attribute value */
+ result = storeAttributeValue(parser, enc, isCdata,
+ atts[i].valuePtr, atts[i].valueEnd,
+ &tempPool);
+ if (result)
+ return result;
+ appAtts[attIndex] = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ }
+ else {
+ /* the value did not need normalizing */
+ appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr,
+ atts[i].valueEnd);
+ if (appAtts[attIndex] == 0)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ }
+ /* handle prefixed attribute names */
+ if (attId->prefix) {
+ if (attId->xmlns) {
+ /* deal with namespace declarations here */
+ enum XML_Error result = addBinding(parser, attId->prefix, attId,
+ appAtts[attIndex], bindingsPtr);
+ if (result)
+ return result;
+ --attIndex;
+ }
+ else {
+ /* deal with other prefixed names later */
+ attIndex++;
+ nPrefixes++;
+ (attId->name)[-1] = 2;
+ }
+ }
+ else
+ attIndex++;
+ }
+
+ /* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
+ nSpecifiedAtts = attIndex;
+ if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
+ for (i = 0; i < attIndex; i += 2)
+ if (appAtts[i] == elementType->idAtt->name) {
+ idAttIndex = i;
+ break;
+ }
+ }
+ else
+ idAttIndex = -1;
+
+ /* do attribute defaulting */
+ for (i = 0; i < nDefaultAtts; i++) {
+ const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
+ if (!(da->id->name)[-1] && da->value) {
+ if (da->id->prefix) {
+ if (da->id->xmlns) {
+ enum XML_Error result = addBinding(parser, da->id->prefix, da->id,
+ da->value, bindingsPtr);
+ if (result)
+ return result;
+ }
+ else {
+ (da->id->name)[-1] = 2;
+ nPrefixes++;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ else {
+ (da->id->name)[-1] = 1;
+ appAtts[attIndex++] = da->id->name;
+ appAtts[attIndex++] = da->value;
+ }
+ }
+ }
+ appAtts[attIndex] = 0;
+
+ /* expand prefixed attribute names, check for duplicates,
+ and clear flags that say whether attributes were specified */
+ i = 0;
+ if (nPrefixes) {
+ int j; /* hash table index */
+ unsigned long version = nsAttsVersion;
+ int nsAttsSize = (int)1 << nsAttsPower;
+ unsigned char oldNsAttsPower = nsAttsPower;
+ /* size of hash table must be at least 2 * (# of prefixed attributes) */
+ if ((nPrefixes << 1) >> nsAttsPower) { /* true for nsAttsPower = 0 */
+ NS_ATT *temp;
+ /* hash table size must also be a power of 2 and >= 8 */
+ while (nPrefixes >> nsAttsPower++);
+ if (nsAttsPower < 3)
+ nsAttsPower = 3;
+ nsAttsSize = (int)1 << nsAttsPower;
+ temp = (NS_ATT *)REALLOC(nsAtts, nsAttsSize * sizeof(NS_ATT));
+ if (!temp) {
+ /* Restore actual size of memory in nsAtts */
+ nsAttsPower = oldNsAttsPower;
+ return XML_ERROR_NO_MEMORY;
+ }
+ nsAtts = temp;
+ version = 0; /* force re-initialization of nsAtts hash table */
+ }
+ /* using a version flag saves us from initializing nsAtts every time */
+ if (!version) { /* initialize version flags when version wraps around */
+ version = INIT_ATTS_VERSION;
+ for (j = nsAttsSize; j != 0; )
+ nsAtts[--j].version = version;
+ }
+ nsAttsVersion = --version;
+
+ /* expand prefixed names and check for duplicates */
+ for (; i < attIndex; i += 2) {
+ const XML_Char *s = appAtts[i];
+ if (s[-1] == 2) { /* prefixed */
+ ATTRIBUTE_ID *id;
+ const BINDING *b;
+ unsigned long uriHash;
+ struct siphash sip_state;
+ struct sipkey sip_key;
+
+ copy_salt_to_sipkey(parser, &sip_key);
+ sip24_init(&sip_state, &sip_key);
+
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+ if (!id || !id->prefix) {
+ /* This code is walking through the appAtts array, dealing
+ * with (in this case) a prefixed attribute name. To be in
+ * the array, the attribute must have already been bound, so
+ * has to have passed through the hash table lookup once
+ * already. That implies that an entry for it already
+ * exists, so the lookup above will return a pointer to
+ * already allocated memory. There is no opportunaity for
+ * the allocator to fail, so the condition above cannot be
+ * fulfilled.
+ *
+ * Since it is difficult to be certain that the above
+ * analysis is complete, we retain the test and merely
+ * remove the code from coverage tests.
+ */
+ return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
+ }
+ b = id->prefix->binding;
+ if (!b)
+ return XML_ERROR_UNBOUND_PREFIX;
+
+ for (j = 0; j < b->uriLen; j++) {
+ const XML_Char c = b->uri[j];
+ if (!poolAppendChar(&tempPool, c))
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
+
+ while (*s++ != XML_T(ASCII_COLON))
+ ;
+
+ sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
+
+ do { /* copies null terminator */
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ } while (*s++);
+
+ uriHash = (unsigned long)sip24_final(&sip_state);
+
+ { /* Check hash table for duplicate of expanded name (uriName).
+ Derived from code in lookup(parser, HASH_TABLE *table, ...).
+ */
+ unsigned char step = 0;
+ unsigned long mask = nsAttsSize - 1;
+ j = uriHash & mask; /* index into hash table */
+ while (nsAtts[j].version == version) {
+ /* for speed we compare stored hash values first */
+ if (uriHash == nsAtts[j].hash) {
+ const XML_Char *s1 = poolStart(&tempPool);
+ const XML_Char *s2 = nsAtts[j].uriName;
+ /* s1 is null terminated, but not s2 */
+ for (; *s1 == *s2 && *s1 != 0; s1++, s2++);
+ if (*s1 == 0)
+ return XML_ERROR_DUPLICATE_ATTRIBUTE;
+ }
+ if (!step)
+ step = PROBE_STEP(uriHash, mask, nsAttsPower);
+ j < step ? (j += nsAttsSize - step) : (j -= step);
+ }
+ }
+
+ if (ns_triplets) { /* append namespace separator and prefix */
+ tempPool.ptr[-1] = namespaceSeparator;
+ s = b->prefix->name;
+ do {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_ERROR_NO_MEMORY;
+ } while (*s++);
+ }
+
+ /* store expanded name in attribute list */
+ s = poolStart(&tempPool);
+ poolFinish(&tempPool);
+ appAtts[i] = s;
+
+ /* fill empty slot with new version, uriName and hash value */
+ nsAtts[j].version = version;
+ nsAtts[j].hash = uriHash;
+ nsAtts[j].uriName = s;
+
+ if (!--nPrefixes) {
+ i += 2;
+ break;
+ }
+ }
+ else /* not prefixed */
+ ((XML_Char *)s)[-1] = 0; /* clear flag */
+ }
+ }
+ /* clear flags for the remaining attributes */
+ for (; i < attIndex; i += 2)
+ ((XML_Char *)(appAtts[i]))[-1] = 0;
+ for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
+ binding->attId->name[-1] = 0;
+
+ if (!ns)
+ return XML_ERROR_NONE;
+
+ /* expand the element type name */
+ if (elementType->prefix) {
+ binding = elementType->prefix->binding;
+ if (!binding)
+ return XML_ERROR_UNBOUND_PREFIX;
+ localPart = tagNamePtr->str;
+ while (*localPart++ != XML_T(ASCII_COLON))
+ ;
+ }
+ else if (dtd->defaultPrefix.binding) {
+ binding = dtd->defaultPrefix.binding;
+ localPart = tagNamePtr->str;
+ }
+ else
+ return XML_ERROR_NONE;
+ prefixLen = 0;
+ if (ns_triplets && binding->prefix->name) {
+ for (; binding->prefix->name[prefixLen++];)
+ ; /* prefixLen includes null terminator */
+ }
+ tagNamePtr->localPart = localPart;
+ tagNamePtr->uriLen = binding->uriLen;
+ tagNamePtr->prefix = binding->prefix->name;
+ tagNamePtr->prefixLen = prefixLen;
+ for (i = 0; localPart[i++];)
+ ; /* i includes null terminator */
+ n = i + binding->uriLen + prefixLen;
+ if (n > binding->uriAlloc) {
+ TAG *p;
+ uri = (XML_Char *)MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
+ if (!uri)
+ return XML_ERROR_NO_MEMORY;
+ binding->uriAlloc = n + EXPAND_SPARE;
+ memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
+ for (p = tagStack; p; p = p->parent)
+ if (p->name.str == binding->uri)
+ p->name.str = uri;
+ FREE(binding->uri);
+ binding->uri = uri;
+ }
+ /* if namespaceSeparator != '\0' then uri includes it already */
+ uri = binding->uri + binding->uriLen;
+ memcpy(uri, localPart, i * sizeof(XML_Char));
+ /* we always have a namespace separator between localPart and prefix */
+ if (prefixLen) {
+ uri += i - 1;
+ *uri = namespaceSeparator; /* replace null terminator */
+ memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
+ }
+ tagNamePtr->str = binding->uri;
+ return XML_ERROR_NONE;
+}
+
+/* addBinding() overwrites the value of prefix->binding without checking.
+ Therefore one must keep track of the old value outside of addBinding().
+*/
+static enum XML_Error
+addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
+ const XML_Char *uri, BINDING **bindingsPtr)
+{
+ static const XML_Char xmlNamespace[] = {
+ ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+ ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+ ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_X, ASCII_M, ASCII_L,
+ ASCII_SLASH, ASCII_1, ASCII_9, ASCII_9, ASCII_8, ASCII_SLASH,
+ ASCII_n, ASCII_a, ASCII_m, ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
+ ASCII_e, '\0'
+ };
+ static const int xmlLen =
+ (int)sizeof(xmlNamespace)/sizeof(XML_Char) - 1;
+ static const XML_Char xmlnsNamespace[] = {
+ ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH, ASCII_SLASH,
+ ASCII_w, ASCII_w, ASCII_w, ASCII_PERIOD, ASCII_w, ASCII_3, ASCII_PERIOD,
+ ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH, ASCII_2, ASCII_0, ASCII_0,
+ ASCII_0, ASCII_SLASH, ASCII_x, ASCII_m, ASCII_l, ASCII_n, ASCII_s,
+ ASCII_SLASH, '\0'
+ };
+ static const int xmlnsLen =
+ (int)sizeof(xmlnsNamespace)/sizeof(XML_Char) - 1;
+
+ XML_Bool mustBeXML = XML_FALSE;
+ XML_Bool isXML = XML_TRUE;
+ XML_Bool isXMLNS = XML_TRUE;
+
+ BINDING *b;
+ int len;
+
+ /* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
+ if (*uri == XML_T('\0') && prefix->name)
+ return XML_ERROR_UNDECLARING_PREFIX;
+
+ if (prefix->name
+ && prefix->name[0] == XML_T(ASCII_x)
+ && prefix->name[1] == XML_T(ASCII_m)
+ && prefix->name[2] == XML_T(ASCII_l)) {
+
+ /* Not allowed to bind xmlns */
+ if (prefix->name[3] == XML_T(ASCII_n)
+ && prefix->name[4] == XML_T(ASCII_s)
+ && prefix->name[5] == XML_T('\0'))
+ return XML_ERROR_RESERVED_PREFIX_XMLNS;
+
+ if (prefix->name[3] == XML_T('\0'))
+ mustBeXML = XML_TRUE;
+ }
+
+ for (len = 0; uri[len]; len++) {
+ if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
+ isXML = XML_FALSE;
+
+ if (!mustBeXML && isXMLNS
+ && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
+ isXMLNS = XML_FALSE;
+ }
+ isXML = isXML && len == xmlLen;
+ isXMLNS = isXMLNS && len == xmlnsLen;
+
+ if (mustBeXML != isXML)
+ return mustBeXML ? XML_ERROR_RESERVED_PREFIX_XML
+ : XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (isXMLNS)
+ return XML_ERROR_RESERVED_NAMESPACE_URI;
+
+ if (namespaceSeparator)
+ len++;
+ if (freeBindingList) {
+ b = freeBindingList;
+ if (len > b->uriAlloc) {
+ XML_Char *temp = (XML_Char *)REALLOC(b->uri,
+ sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = temp;
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ freeBindingList = b->nextTagBinding;
+ }
+ else {
+ b = (BINDING *)MALLOC(sizeof(BINDING));
+ if (!b)
+ return XML_ERROR_NO_MEMORY;
+ b->uri = (XML_Char *)MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
+ if (!b->uri) {
+ FREE(b);
+ return XML_ERROR_NO_MEMORY;
+ }
+ b->uriAlloc = len + EXPAND_SPARE;
+ }
+ b->uriLen = len;
+ memcpy(b->uri, uri, len * sizeof(XML_Char));
+ if (namespaceSeparator)
+ b->uri[len - 1] = namespaceSeparator;
+ b->prefix = prefix;
+ b->attId = attId;
+ b->prevPrefixBinding = prefix->binding;
+ /* NULL binding when default namespace undeclared */
+ if (*uri == XML_T('\0') && prefix == &_dtd->defaultPrefix)
+ prefix->binding = NULL;
+ else
+ prefix->binding = b;
+ b->nextTagBinding = *bindingsPtr;
+ *bindingsPtr = b;
+ /* if attId == NULL then we are not starting a namespace scope */
+ if (attId && startNamespaceDeclHandler)
+ startNamespaceDeclHandler(handlerArg, prefix->name,
+ prefix->binding ? uri : 0);
+ return XML_ERROR_NONE;
+}
+
+/* The idea here is to avoid using stack for each CDATA section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+cdataSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doCdataSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ if (parentParser) { /* we are parsing an external entity */
+ processor = externalEntityContentProcessor;
+ return externalEntityContentProcessor(parser, start, end, endPtr);
+ }
+ else {
+ processor = contentProcessor;
+ return contentProcessor(parser, start, end, endPtr);
+ }
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null if the section is closed, and to null if
+ the section is not yet closed.
+*/
+static enum XML_Error
+doCdataSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+
+ for (;;) {
+ const char *next;
+ int tok = XmlCdataSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_CDATA_SECT_CLOSE:
+ if (endCdataSectionHandler)
+ endCdataSectionHandler(handlerArg);
+#if 0
+ /* see comment under XML_TOK_CDATA_SECT_OPEN */
+ else if (characterDataHandler)
+ characterDataHandler(handlerArg, dataBuf, 0);
+#endif
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_DATA_NEWLINE:
+ if (characterDataHandler) {
+ XML_Char c = 0xA;
+ characterDataHandler(handlerArg, &c, 1);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ break;
+ case XML_TOK_DATA_CHARS:
+ {
+ XML_CharacterDataHandler charDataHandler = characterDataHandler;
+ if (charDataHandler) {
+ if (MUST_CONVERT(enc, s)) {
+ for (;;) {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = next;
+ charDataHandler(handlerArg, dataBuf,
+ (int)(dataPtr - (ICHAR *)dataBuf));
+ if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+ break;
+ *eventPP = s;
+ }
+ }
+ else
+ charDataHandler(handlerArg,
+ (XML_Char *)s,
+ (int)((XML_Char *)next - (XML_Char *)s));
+ }
+ else if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ }
+ break;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_CDATA_SECTION;
+ default:
+ /* Every token returned by XmlCdataSectionTok() has its own
+ * explicit case, so this default case will never be executed.
+ * We retain it as a safety net and exclude it from the coverage
+ * statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
+ }
+
+ *eventPP = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+ /* not reached */
+}
+
+#ifdef XML_DTD
+
+/* The idea here is to avoid using stack for each IGNORE section when
+ the whole file is parsed with one call.
+*/
+static enum XML_Error PTRCALL
+ignoreSectionProcessor(XML_Parser parser,
+ const char *start,
+ const char *end,
+ const char **endPtr)
+{
+ enum XML_Error result = doIgnoreSection(parser, encoding, &start, end,
+ endPtr, (XML_Bool)!ps_finalBuffer);
+ if (result != XML_ERROR_NONE)
+ return result;
+ if (start) {
+ processor = prologProcessor;
+ return prologProcessor(parser, start, end, endPtr);
+ }
+ return result;
+}
+
+/* startPtr gets set to non-null is the section is closed, and to null
+ if the section is not yet closed.
+*/
+static enum XML_Error
+doIgnoreSection(XML_Parser parser,
+ const ENCODING *enc,
+ const char **startPtr,
+ const char *end,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+ const char *next;
+ int tok;
+ const char *s = *startPtr;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ *eventPP = s;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ /* It's not entirely clear, but it seems the following two lines
+ * of code cannot be executed. The only occasions on which 'enc'
+ * is not 'parser->m_encoding' are when this function is called
+ * from the internal entity processing, and IGNORE sections are an
+ * error in internal entities.
+ *
+ * Since it really isn't clear that this is true, we keep the code
+ * and just remove it from our coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ /* LCOV_EXCL_STOP */
+ }
+ *eventPP = s;
+ *startPtr = NULL;
+ tok = XmlIgnoreSectionTok(enc, s, end, &next);
+ *eventEndPP = next;
+ switch (tok) {
+ case XML_TOK_IGNORE_SECT:
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ *startPtr = next;
+ *nextPtr = next;
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ else
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_PARTIAL:
+ case XML_TOK_NONE:
+ if (haveMore) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
+ default:
+ /* All of the tokens that XmlIgnoreSectionTok() returns have
+ * explicit cases to handle them, so this default case is never
+ * executed. We keep it as a safety net anyway, and remove it
+ * from our test coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ *eventPP = next;
+ return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
+ }
+ /* not reached */
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error
+initializeEncoding(XML_Parser parser)
+{
+ const char *s;
+#ifdef XML_UNICODE
+ char encodingBuf[128];
+ /* See comments abount `protoclEncodingName` in parserInit() */
+ if (!protocolEncodingName)
+ s = NULL;
+ else {
+ int i;
+ for (i = 0; protocolEncodingName[i]; i++) {
+ if (i == sizeof(encodingBuf) - 1
+ || (protocolEncodingName[i] & ~0x7f) != 0) {
+ encodingBuf[0] = '\0';
+ break;
+ }
+ encodingBuf[i] = (char)protocolEncodingName[i];
+ }
+ encodingBuf[i] = '\0';
+ s = encodingBuf;
+ }
+#else
+ s = protocolEncodingName;
+#endif
+ if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
+ return XML_ERROR_NONE;
+ return handleUnknownEncoding(parser, protocolEncodingName);
+}
+
+static enum XML_Error
+processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
+ const char *s, const char *next)
+{
+ const char *encodingName = NULL;
+ const XML_Char *storedEncName = NULL;
+ const ENCODING *newEncoding = NULL;
+ const char *version = NULL;
+ const char *versionend;
+ const XML_Char *storedversion = NULL;
+ int standalone = -1;
+ if (!(ns
+ ? XmlParseXmlDeclNS
+ : XmlParseXmlDecl)(isGeneralTextEntity,
+ encoding,
+ s,
+ next,
+ &eventPtr,
+ &version,
+ &versionend,
+ &encodingName,
+ &newEncoding,
+ &standalone)) {
+ if (isGeneralTextEntity)
+ return XML_ERROR_TEXT_DECL;
+ else
+ return XML_ERROR_XML_DECL;
+ }
+ if (!isGeneralTextEntity && standalone == 1) {
+ _dtd->standalone = XML_TRUE;
+#ifdef XML_DTD
+ if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
+ paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
+#endif /* XML_DTD */
+ }
+ if (xmlDeclHandler) {
+ if (encodingName != NULL) {
+ storedEncName = poolStoreString(&temp2Pool,
+ encoding,
+ encodingName,
+ encodingName
+ + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&temp2Pool);
+ }
+ if (version) {
+ storedversion = poolStoreString(&temp2Pool,
+ encoding,
+ version,
+ versionend - encoding->minBytesPerChar);
+ if (!storedversion)
+ return XML_ERROR_NO_MEMORY;
+ }
+ xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
+ }
+ else if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ if (protocolEncodingName == NULL) {
+ if (newEncoding) {
+ /* Check that the specified encoding does not conflict with what
+ * the parser has already deduced. Do we have the same number
+ * of bytes in the smallest representation of a character? If
+ * this is UTF-16, is it the same endianness?
+ */
+ if (newEncoding->minBytesPerChar != encoding->minBytesPerChar
+ || (newEncoding->minBytesPerChar == 2 &&
+ newEncoding != encoding)) {
+ eventPtr = encodingName;
+ return XML_ERROR_INCORRECT_ENCODING;
+ }
+ encoding = newEncoding;
+ }
+ else if (encodingName) {
+ enum XML_Error result;
+ if (!storedEncName) {
+ storedEncName = poolStoreString(
+ &temp2Pool, encoding, encodingName,
+ encodingName + XmlNameLength(encoding, encodingName));
+ if (!storedEncName)
+ return XML_ERROR_NO_MEMORY;
+ }
+ result = handleUnknownEncoding(parser, storedEncName);
+ poolClear(&temp2Pool);
+ if (result == XML_ERROR_UNKNOWN_ENCODING)
+ eventPtr = encodingName;
+ return result;
+ }
+ }
+
+ if (storedEncName || storedversion)
+ poolClear(&temp2Pool);
+
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
+{
+ if (unknownEncodingHandler) {
+ XML_Encoding info;
+ int i;
+ for (i = 0; i < 256; i++)
+ info.map[i] = -1;
+ info.convert = NULL;
+ info.data = NULL;
+ info.release = NULL;
+ if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName,
+ &info)) {
+ ENCODING *enc;
+ unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
+ if (!unknownEncodingMem) {
+ if (info.release)
+ info.release(info.data);
+ return XML_ERROR_NO_MEMORY;
+ }
+ enc = (ns
+ ? XmlInitUnknownEncodingNS
+ : XmlInitUnknownEncoding)(unknownEncodingMem,
+ info.map,
+ info.convert,
+ info.data);
+ if (enc) {
+ unknownEncodingData = info.data;
+ unknownEncodingRelease = info.release;
+ encoding = enc;
+ return XML_ERROR_NONE;
+ }
+ }
+ if (info.release != NULL)
+ info.release(info.data);
+ }
+ return XML_ERROR_UNKNOWN_ENCODING;
+}
+
+static enum XML_Error PTRCALL
+prologInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+ processor = prologProcessor;
+ return prologProcessor(parser, s, end, nextPtr);
+}
+
+#ifdef XML_DTD
+
+static enum XML_Error PTRCALL
+externalParEntInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ enum XML_Error result = initializeEncoding(parser);
+ if (result != XML_ERROR_NONE)
+ return result;
+
+ /* we know now that XML_Parse(Buffer) has been called,
+ so we consider the external parameter entity read */
+ _dtd->paramEntityRead = XML_TRUE;
+
+ if (prologState.inEntityValue) {
+ processor = entityValueInitProcessor;
+ return entityValueInitProcessor(parser, s, end, nextPtr);
+ }
+ else {
+ processor = externalParEntProcessor;
+ return externalParEntProcessor(parser, s, end, nextPtr);
+ }
+}
+
+static enum XML_Error PTRCALL
+entityValueInitProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ int tok;
+ const char *start = s;
+ const char *next = start;
+ eventPtr = start;
+
+ for (;;) {
+ tok = XmlPrologTok(encoding, start, end, &next);
+ eventEndPtr = next;
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, encoding, s, end);
+ }
+ else if (tok == XML_TOK_XML_DECL) {
+ enum XML_Error result;
+ result = processXmlDecl(parser, 0, start, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ /* At this point, ps_parsing cannot be XML_SUSPENDED. For that
+ * to happen, a parameter entity parsing handler must have
+ * attempted to suspend the parser, which fails and raises an
+ * error. The parser can be aborted, but can't be suspended.
+ */
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ *nextPtr = next;
+ /* stop scanning for text declaration - we found one */
+ processor = entityValueProcessor;
+ return entityValueProcessor(parser, next, end, nextPtr);
+ }
+ /* If we are at the end of the buffer, this would cause XmlPrologTok to
+ return XML_TOK_NONE on the next call, which would then cause the
+ function to exit with *nextPtr set to s - that is what we want for other
+ tokens, but not for the BOM - we would rather like to skip it;
+ then, when this routine is entered the next time, XmlPrologTok will
+ return XML_TOK_INVALID, since the BOM is still in the buffer
+ */
+ else if (tok == XML_TOK_BOM && next == end && !ps_finalBuffer) {
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ }
+ /* If we get this token, we have the start of what might be a
+ normal tag, but not a declaration (i.e. it doesn't begin with
+ "<!"). In a DTD context, that isn't legal.
+ */
+ else if (tok == XML_TOK_INSTANCE_START) {
+ *nextPtr = next;
+ return XML_ERROR_SYNTAX;
+ }
+ start = next;
+ eventPtr = start;
+ }
+}
+
+static enum XML_Error PTRCALL
+externalParEntProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok;
+
+ tok = XmlPrologTok(encoding, s, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ }
+ /* This would cause the next stage, i.e. doProlog to be passed XML_TOK_BOM.
+ However, when parsing an external subset, doProlog will not accept a BOM
+ as valid, and report a syntax error, so we have to skip the BOM
+ */
+ else if (tok == XML_TOK_BOM) {
+ s = next;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ }
+
+ processor = prologProcessor;
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error PTRCALL
+entityValueProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *start = s;
+ const char *next = s;
+ const ENCODING *enc = encoding;
+ int tok;
+
+ for (;;) {
+ tok = XmlPrologTok(enc, start, end, &next);
+ if (tok <= 0) {
+ if (!ps_finalBuffer && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case XML_TOK_NONE: /* start == end */
+ default:
+ break;
+ }
+ /* found end of entity value - can store it now */
+ return storeEntityValue(parser, enc, s, end);
+ }
+ start = next;
+ }
+}
+
+#endif /* XML_DTD */
+
+static enum XML_Error PTRCALL
+prologProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ const char *next = s;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+}
+
+static enum XML_Error
+doProlog(XML_Parser parser,
+ const ENCODING *enc,
+ const char *s,
+ const char *end,
+ int tok,
+ const char *next,
+ const char **nextPtr,
+ XML_Bool haveMore)
+{
+#ifdef XML_DTD
+ static const XML_Char externalSubsetName[] = { ASCII_HASH , '\0' };
+#endif /* XML_DTD */
+ static const XML_Char atypeCDATA[] =
+ { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+ static const XML_Char atypeID[] = { ASCII_I, ASCII_D, '\0' };
+ static const XML_Char atypeIDREF[] =
+ { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+ static const XML_Char atypeIDREFS[] =
+ { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+ static const XML_Char atypeENTITY[] =
+ { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+ static const XML_Char atypeENTITIES[] = { ASCII_E, ASCII_N,
+ ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
+ static const XML_Char atypeNMTOKEN[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+ static const XML_Char atypeNMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T,
+ ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
+ static const XML_Char notationPrefix[] = { ASCII_N, ASCII_O, ASCII_T,
+ ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, ASCII_LPAREN, '\0' };
+ static const XML_Char enumValueSep[] = { ASCII_PIPE, '\0' };
+ static const XML_Char enumValueStart[] = { ASCII_LPAREN, '\0' };
+
+ /* save one level of indirection */
+ DTD * const dtd = _dtd;
+
+ const char **eventPP;
+ const char **eventEndPP;
+ enum XML_Content_Quant quant;
+
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ }
+
+ for (;;) {
+ int role;
+ XML_Bool handleDefault = XML_TRUE;
+ *eventPP = s;
+ *eventEndPP = next;
+ if (tok <= 0) {
+ if (haveMore && tok != XML_TOK_INVALID) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ switch (tok) {
+ case XML_TOK_INVALID:
+ *eventPP = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ return XML_ERROR_PARTIAL_CHAR;
+ case -XML_TOK_PROLOG_S:
+ tok = -tok;
+ break;
+ case XML_TOK_NONE:
+#ifdef XML_DTD
+ /* for internal PE NOT referenced between declarations */
+ if (enc != encoding && !openInternalEntities->betweenDecl) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ /* WFC: PE Between Declarations - must check that PE contains
+ complete markup, not only for external PEs, but also for
+ internal PEs if the reference occurs between declarations.
+ */
+ if (isParamEntity || enc != encoding) {
+ if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
+ == XML_ROLE_ERROR)
+ return XML_ERROR_INCOMPLETE_PE;
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+#endif /* XML_DTD */
+ return XML_ERROR_NO_ELEMENTS;
+ default:
+ tok = -tok;
+ next = end;
+ break;
+ }
+ }
+ role = XmlTokenRole(&prologState, tok, s, next, enc);
+ switch (role) {
+ case XML_ROLE_XML_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 0, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NAME:
+ if (startDoctypeDeclHandler) {
+ doctypeName = poolStoreString(&tempPool, enc, s, next);
+ if (!doctypeName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ doctypePubid = NULL;
+ handleDefault = XML_FALSE;
+ }
+ doctypeSysid = NULL; /* always initialize to NULL */
+ break;
+ case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
+ if (startDoctypeDeclHandler) {
+ startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
+ doctypePubid, 1);
+ doctypeName = NULL;
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+#ifdef XML_DTD
+ case XML_ROLE_TEXT_DECL:
+ {
+ enum XML_Error result = processXmlDecl(parser, 1, s, next);
+ if (result != XML_ERROR_NONE)
+ return result;
+ enc = encoding;
+ handleDefault = XML_FALSE;
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_DOCTYPE_PUBLIC_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+ declEntity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ XML_Char *pubId;
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ pubId = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!pubId)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(pubId);
+ poolFinish(&tempPool);
+ doctypePubid = pubId;
+ handleDefault = XML_FALSE;
+ goto alreadyChecked;
+ }
+ /* fall through */
+ case XML_ROLE_ENTITY_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ alreadyChecked:
+ if (dtd->keepProcessing && declEntity) {
+ XML_Char *tem = poolStoreString(&dtd->pool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declEntity->publicId = tem;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_CLOSE:
+ if (doctypeName) {
+ startDoctypeDeclHandler(handlerArg, doctypeName,
+ doctypeSysid, doctypePubid, 0);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ /* doctypeSysid will be non-NULL in the case of a previous
+ XML_ROLE_DOCTYPE_SYSTEM_ID, even if startDoctypeDeclHandler
+ was not set, indicating an external subset
+ */
+#ifdef XML_DTD
+ if (doctypeSysid || useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity) {
+ /* The external subset name "#" will have already been
+ * inserted into the hash table at the start of the
+ * external entity parsing, so no allocation will happen
+ * and lookup() cannot fail.
+ */
+ return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
+ }
+ if (useForeignDTD)
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else if (!doctypeSysid)
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ useForeignDTD = XML_FALSE;
+ }
+#endif /* XML_DTD */
+ if (endDoctypeDeclHandler) {
+ endDoctypeDeclHandler(handlerArg);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_INSTANCE_START:
+#ifdef XML_DTD
+ /* if there is no DOCTYPE declaration then now is the
+ last chance to read the foreign DTD
+ */
+ if (useForeignDTD) {
+ XML_Bool hadParamEntityRefs = dtd->hasParamEntityRefs;
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (paramEntityParsing && externalEntityRefHandler) {
+ ENTITY *entity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!entity)
+ return XML_ERROR_NO_MEMORY;
+ entity->base = curBase;
+ dtd->paramEntityRead = XML_FALSE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId))
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ if (dtd->paramEntityRead) {
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ }
+ /* if we didn't read the foreign DTD then this means that there
+ is no external subset and we must reset dtd->hasParamEntityRefs
+ */
+ else
+ dtd->hasParamEntityRefs = hadParamEntityRefs;
+ /* end of DTD - no need to update dtd->keepProcessing */
+ }
+ }
+#endif /* XML_DTD */
+ processor = contentProcessor;
+ return contentProcessor(parser, s, end, nextPtr);
+ case XML_ROLE_ATTLIST_ELEMENT_NAME:
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_NAME:
+ declAttributeId = getAttributeId(parser, enc, s, next);
+ if (!declAttributeId)
+ return XML_ERROR_NO_MEMORY;
+ declAttributeIsCdata = XML_FALSE;
+ declAttributeType = NULL;
+ declAttributeIsId = XML_FALSE;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
+ declAttributeIsCdata = XML_TRUE;
+ declAttributeType = atypeCDATA;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ID:
+ declAttributeIsId = XML_TRUE;
+ declAttributeType = atypeID;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
+ declAttributeType = atypeIDREF;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
+ declAttributeType = atypeIDREFS;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
+ declAttributeType = atypeENTITY;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
+ declAttributeType = atypeENTITIES;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
+ declAttributeType = atypeNMTOKEN;
+ goto checkAttListDeclHandler;
+ case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
+ declAttributeType = atypeNMTOKENS;
+ checkAttListDeclHandler:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
+ case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
+ if (dtd->keepProcessing && attlistDeclHandler) {
+ const XML_Char *prefix;
+ if (declAttributeType) {
+ prefix = enumValueSep;
+ }
+ else {
+ prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
+ ? notationPrefix
+ : enumValueStart);
+ }
+ if (!poolAppendString(&tempPool, prefix))
+ return XML_ERROR_NO_MEMORY;
+ if (!poolAppend(&tempPool, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
+ case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, declAttributeIsId,
+ 0, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T(ASCII_LPAREN)
+ || (*declAttributeType == XML_T(ASCII_N)
+ && declAttributeType[1] == XML_T(ASCII_O))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
+ case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
+ if (dtd->keepProcessing) {
+ const XML_Char *attVal;
+ enum XML_Error result =
+ storeAttributeValue(parser, enc, declAttributeIsCdata,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar,
+ &dtd->pool);
+ if (result)
+ return result;
+ attVal = poolStart(&dtd->pool);
+ poolFinish(&dtd->pool);
+ /* ID attributes aren't allowed to have a default */
+ if (!defineAttribute(declElementType, declAttributeId,
+ declAttributeIsCdata, XML_FALSE, attVal, parser))
+ return XML_ERROR_NO_MEMORY;
+ if (attlistDeclHandler && declAttributeType) {
+ if (*declAttributeType == XML_T(ASCII_LPAREN)
+ || (*declAttributeType == XML_T(ASCII_N)
+ && declAttributeType[1] == XML_T(ASCII_O))) {
+ /* Enumerated or Notation type */
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_RPAREN))
+ || !poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ declAttributeType = tempPool.start;
+ poolFinish(&tempPool);
+ }
+ *eventEndPP = s;
+ attlistDeclHandler(handlerArg, declElementType->name,
+ declAttributeId->name, declAttributeType,
+ attVal,
+ role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+ poolClear(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_ENTITY_VALUE:
+ if (dtd->keepProcessing) {
+ enum XML_Error result = storeEntityValue(parser, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (declEntity) {
+ declEntity->textPtr = poolStart(&dtd->entityValuePool);
+ declEntity->textLen = (int)(poolLength(&dtd->entityValuePool));
+ poolFinish(&dtd->entityValuePool);
+ if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ declEntity->textPtr,
+ declEntity->textLen,
+ curBase, 0, 0, 0);
+ handleDefault = XML_FALSE;
+ }
+ }
+ else
+ poolDiscard(&dtd->entityValuePool);
+ if (result != XML_ERROR_NONE)
+ return result;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_SYSTEM_ID:
+#ifdef XML_DTD
+ useForeignDTD = XML_FALSE;
+#endif /* XML_DTD */
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (startDoctypeDeclHandler) {
+ doctypeSysid = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (doctypeSysid == NULL)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+#ifdef XML_DTD
+ else
+ /* use externalSubsetName to make doctypeSysid non-NULL
+ for the case where no startDoctypeDeclHandler is set */
+ doctypeSysid = externalSubsetName;
+#endif /* XML_DTD */
+ if (!dtd->standalone
+#ifdef XML_DTD
+ && !paramEntityParsing
+#endif /* XML_DTD */
+ && notStandaloneHandler
+ && !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+#ifndef XML_DTD
+ break;
+#else /* XML_DTD */
+ if (!declEntity) {
+ declEntity = (ENTITY *)lookup(parser,
+ &dtd->paramEntities,
+ externalSubsetName,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->publicId = NULL;
+ }
+ /* fall through */
+#endif /* XML_DTD */
+ case XML_ROLE_ENTITY_SYSTEM_ID:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->systemId = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!declEntity->systemId)
+ return XML_ERROR_NO_MEMORY;
+ declEntity->base = curBase;
+ poolFinish(&dtd->pool);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_COMPLETE:
+ if (dtd->keepProcessing && declEntity && entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->is_param,
+ 0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ 0);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_ENTITY_NOTATION_NAME:
+ if (dtd->keepProcessing && declEntity) {
+ declEntity->notation = poolStoreString(&dtd->pool, enc, s, next);
+ if (!declEntity->notation)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&dtd->pool);
+ if (unparsedEntityDeclHandler) {
+ *eventEndPP = s;
+ unparsedEntityDeclHandler(handlerArg,
+ declEntity->name,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ else if (entityDeclHandler) {
+ *eventEndPP = s;
+ entityDeclHandler(handlerArg,
+ declEntity->name,
+ 0,0,0,
+ declEntity->base,
+ declEntity->systemId,
+ declEntity->publicId,
+ declEntity->notation);
+ handleDefault = XML_FALSE;
+ }
+ }
+ break;
+ case XML_ROLE_GENERAL_ENTITY_NAME:
+ {
+ if (XmlPredefinedEntityName(enc, s, next)) {
+ declEntity = NULL;
+ break;
+ }
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(parser, &dtd->generalEntities, name,
+ sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_FALSE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ }
+ break;
+ case XML_ROLE_PARAM_ENTITY_NAME:
+#ifdef XML_DTD
+ if (dtd->keepProcessing) {
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, s, next);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ declEntity = (ENTITY *)lookup(parser, &dtd->paramEntities,
+ name, sizeof(ENTITY));
+ if (!declEntity)
+ return XML_ERROR_NO_MEMORY;
+ if (declEntity->name != name) {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+ else {
+ poolFinish(&dtd->pool);
+ declEntity->publicId = NULL;
+ declEntity->is_param = XML_TRUE;
+ /* if we have a parent parser or are reading an internal parameter
+ entity, then the entity declaration is not considered "internal"
+ */
+ declEntity->is_internal = !(parentParser || openInternalEntities);
+ if (entityDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ }
+ else {
+ poolDiscard(&dtd->pool);
+ declEntity = NULL;
+ }
+#else /* not XML_DTD */
+ declEntity = NULL;
+#endif /* XML_DTD */
+ break;
+ case XML_ROLE_NOTATION_NAME:
+ declNotationPublicId = NULL;
+ declNotationName = NULL;
+ if (notationDeclHandler) {
+ declNotationName = poolStoreString(&tempPool, enc, s, next);
+ if (!declNotationName)
+ return XML_ERROR_NO_MEMORY;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_PUBLIC_ID:
+ if (!XmlIsPublicId(enc, s, next, eventPP))
+ return XML_ERROR_PUBLICID;
+ if (declNotationName) { /* means notationDeclHandler != NULL */
+ XML_Char *tem = poolStoreString(&tempPool,
+ enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!tem)
+ return XML_ERROR_NO_MEMORY;
+ normalizePublicId(tem);
+ declNotationPublicId = tem;
+ poolFinish(&tempPool);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_NOTATION_SYSTEM_ID:
+ if (declNotationName && notationDeclHandler) {
+ const XML_Char *systemId
+ = poolStoreString(&tempPool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!systemId)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ systemId,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_NOTATION_NO_SYSTEM_ID:
+ if (declNotationPublicId && notationDeclHandler) {
+ *eventEndPP = s;
+ notationDeclHandler(handlerArg,
+ declNotationName,
+ curBase,
+ 0,
+ declNotationPublicId);
+ handleDefault = XML_FALSE;
+ }
+ poolClear(&tempPool);
+ break;
+ case XML_ROLE_ERROR:
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+ /* PE references in internal subset are
+ not allowed within declarations. */
+ return XML_ERROR_PARAM_ENTITY_REF;
+ case XML_TOK_XML_DECL:
+ return XML_ERROR_MISPLACED_XML_PI;
+ default:
+ return XML_ERROR_SYNTAX;
+ }
+#ifdef XML_DTD
+ case XML_ROLE_IGNORE_SECT:
+ {
+ enum XML_Error result;
+ if (defaultHandler)
+ reportDefault(parser, enc, s, next);
+ handleDefault = XML_FALSE;
+ result = doIgnoreSection(parser, enc, &next, end, nextPtr, haveMore);
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (!next) {
+ processor = ignoreSectionProcessor;
+ return result;
+ }
+ }
+ break;
+#endif /* XML_DTD */
+ case XML_ROLE_GROUP_OPEN:
+ if (prologState.level >= groupSize) {
+ if (groupSize) {
+ char *temp = (char *)REALLOC(groupConnector, groupSize *= 2);
+ if (temp == NULL) {
+ groupSize /= 2;
+ return XML_ERROR_NO_MEMORY;
+ }
+ groupConnector = temp;
+ if (dtd->scaffIndex) {
+ int *temp = (int *)REALLOC(dtd->scaffIndex,
+ groupSize * sizeof(int));
+ if (temp == NULL)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex = temp;
+ }
+ }
+ else {
+ groupConnector = (char *)MALLOC(groupSize = 32);
+ if (!groupConnector) {
+ groupSize = 0;
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ }
+ groupConnector[prologState.level] = 0;
+ if (dtd->in_eldecl) {
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffIndex[dtd->scaffLevel] = myindex;
+ dtd->scaffLevel++;
+ dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+ case XML_ROLE_GROUP_SEQUENCE:
+ if (groupConnector[prologState.level] == ASCII_PIPE)
+ return XML_ERROR_SYNTAX;
+ groupConnector[prologState.level] = ASCII_COMMA;
+ if (dtd->in_eldecl && elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_GROUP_CHOICE:
+ if (groupConnector[prologState.level] == ASCII_COMMA)
+ return XML_ERROR_SYNTAX;
+ if (dtd->in_eldecl
+ && !groupConnector[prologState.level]
+ && (dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ != XML_CTYPE_MIXED)
+ ) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_CHOICE;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ groupConnector[prologState.level] = ASCII_PIPE;
+ break;
+ case XML_ROLE_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ case XML_ROLE_INNER_PARAM_ENTITY_REF:
+ dtd->hasParamEntityRefs = XML_TRUE;
+ if (!paramEntityParsing)
+ dtd->keepProcessing = dtd->standalone;
+ else {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&dtd->pool, enc,
+ s + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+ poolDiscard(&dtd->pool);
+ /* first, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal,
+ otherwise call the skipped entity handler
+ */
+ if (prologState.documentEntity &&
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs)) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal) {
+ /* It's hard to exhaustively search the code to be sure,
+ * but there doesn't seem to be a way of executing the
+ * following line. There are two cases:
+ *
+ * If 'standalone' is false, the DTD must have no
+ * parameter entities or we wouldn't have passed the outer
+ * 'if' statement. That measn the only entity in the hash
+ * table is the external subset name "#" which cannot be
+ * given as a parameter entity name in XML syntax, so the
+ * lookup must have returned NULL and we don't even reach
+ * the test for an internal entity.
+ *
+ * If 'standalone' is true, it does not seem to be
+ * possible to create entities taking this code path that
+ * are not internal entities, so fail the test above.
+ *
+ * Because this analysis is very uncertain, the code is
+ * being left in place and merely removed from the
+ * coverage test statistics.
+ */
+ return XML_ERROR_ENTITY_DECLARED_IN_PE; /* LCOV_EXCL_LINE */
+ }
+ }
+ else if (!entity) {
+ dtd->keepProcessing = dtd->standalone;
+ /* cannot report skipped entities in declarations */
+ if ((role == XML_ROLE_PARAM_ENTITY_REF) && skippedEntityHandler) {
+ skippedEntityHandler(handlerArg, name, 1);
+ handleDefault = XML_FALSE;
+ }
+ break;
+ }
+ if (entity->open)
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ if (entity->textPtr) {
+ enum XML_Error result;
+ XML_Bool betweenDecl =
+ (role == XML_ROLE_PARAM_ENTITY_REF ? XML_TRUE : XML_FALSE);
+ result = processInternalEntity(parser, entity, betweenDecl);
+ if (result != XML_ERROR_NONE)
+ return result;
+ handleDefault = XML_FALSE;
+ break;
+ }
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ }
+ entity->open = XML_FALSE;
+ handleDefault = XML_FALSE;
+ if (!dtd->paramEntityRead) {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+ else {
+ dtd->keepProcessing = dtd->standalone;
+ break;
+ }
+ }
+#endif /* XML_DTD */
+ if (!dtd->standalone &&
+ notStandaloneHandler &&
+ !notStandaloneHandler(handlerArg))
+ return XML_ERROR_NOT_STANDALONE;
+ break;
+
+ /* Element declaration stuff */
+
+ case XML_ROLE_ELEMENT_NAME:
+ if (elementDeclHandler) {
+ declElementType = getElementType(parser, enc, s, next);
+ if (!declElementType)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffLevel = 0;
+ dtd->scaffCount = 0;
+ dtd->in_eldecl = XML_TRUE;
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ANY:
+ case XML_ROLE_CONTENT_EMPTY:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler) {
+ XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
+ if (!content)
+ return XML_ERROR_NO_MEMORY;
+ content->quant = XML_CQUANT_NONE;
+ content->name = NULL;
+ content->numchildren = 0;
+ content->children = NULL;
+ content->type = ((role == XML_ROLE_CONTENT_ANY) ?
+ XML_CTYPE_ANY :
+ XML_CTYPE_EMPTY);
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, content);
+ handleDefault = XML_FALSE;
+ }
+ dtd->in_eldecl = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_PCDATA:
+ if (dtd->in_eldecl) {
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel - 1]].type
+ = XML_CTYPE_MIXED;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_CONTENT_ELEMENT:
+ quant = XML_CQUANT_NONE;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_OPT:
+ quant = XML_CQUANT_OPT;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_REP:
+ quant = XML_CQUANT_REP;
+ goto elementContent;
+ case XML_ROLE_CONTENT_ELEMENT_PLUS:
+ quant = XML_CQUANT_PLUS;
+ elementContent:
+ if (dtd->in_eldecl) {
+ ELEMENT_TYPE *el;
+ const XML_Char *name;
+ int nameLen;
+ const char *nxt = (quant == XML_CQUANT_NONE
+ ? next
+ : next - enc->minBytesPerChar);
+ int myindex = nextScaffoldPart(parser);
+ if (myindex < 0)
+ return XML_ERROR_NO_MEMORY;
+ dtd->scaffold[myindex].type = XML_CTYPE_NAME;
+ dtd->scaffold[myindex].quant = quant;
+ el = getElementType(parser, enc, s, nxt);
+ if (!el)
+ return XML_ERROR_NO_MEMORY;
+ name = el->name;
+ dtd->scaffold[myindex].name = name;
+ nameLen = 0;
+ for (; name[nameLen++]; );
+ dtd->contentStringLen += nameLen;
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ }
+ break;
+
+ case XML_ROLE_GROUP_CLOSE:
+ quant = XML_CQUANT_NONE;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_OPT:
+ quant = XML_CQUANT_OPT;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_REP:
+ quant = XML_CQUANT_REP;
+ goto closeGroup;
+ case XML_ROLE_GROUP_CLOSE_PLUS:
+ quant = XML_CQUANT_PLUS;
+ closeGroup:
+ if (dtd->in_eldecl) {
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ dtd->scaffLevel--;
+ dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel]].quant = quant;
+ if (dtd->scaffLevel == 0) {
+ if (!handleDefault) {
+ XML_Content *model = build_model(parser);
+ if (!model)
+ return XML_ERROR_NO_MEMORY;
+ *eventEndPP = s;
+ elementDeclHandler(handlerArg, declElementType->name, model);
+ }
+ dtd->in_eldecl = XML_FALSE;
+ dtd->contentStringLen = 0;
+ }
+ }
+ break;
+ /* End element declaration stuff */
+
+ case XML_ROLE_PI:
+ if (!reportProcessingInstruction(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_COMMENT:
+ if (!reportComment(parser, enc, s, next))
+ return XML_ERROR_NO_MEMORY;
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NONE:
+ switch (tok) {
+ case XML_TOK_BOM:
+ handleDefault = XML_FALSE;
+ break;
+ }
+ break;
+ case XML_ROLE_DOCTYPE_NONE:
+ if (startDoctypeDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ENTITY_NONE:
+ if (dtd->keepProcessing && entityDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_NOTATION_NONE:
+ if (notationDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ATTLIST_NONE:
+ if (dtd->keepProcessing && attlistDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ case XML_ROLE_ELEMENT_NONE:
+ if (elementDeclHandler)
+ handleDefault = XML_FALSE;
+ break;
+ } /* end of big switch */
+
+ if (handleDefault && defaultHandler)
+ reportDefault(parser, enc, s, next);
+
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default:
+ s = next;
+ tok = XmlPrologTok(enc, s, end, &next);
+ }
+ }
+ /* not reached */
+}
+
+static enum XML_Error PTRCALL
+epilogProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ processor = epilogProcessor;
+ eventPtr = s;
+ for (;;) {
+ const char *next = NULL;
+ int tok = XmlPrologTok(encoding, s, end, &next);
+ eventEndPtr = next;
+ switch (tok) {
+ /* report partial linebreak - it might be the last token */
+ case -XML_TOK_PROLOG_S:
+ if (defaultHandler) {
+ reportDefault(parser, encoding, s, next);
+ if (ps_parsing == XML_FINISHED)
+ return XML_ERROR_ABORTED;
+ }
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_TOK_NONE:
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ case XML_TOK_PROLOG_S:
+ if (defaultHandler)
+ reportDefault(parser, encoding, s, next);
+ break;
+ case XML_TOK_PI:
+ if (!reportProcessingInstruction(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_COMMENT:
+ if (!reportComment(parser, encoding, s, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_INVALID:
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_UNCLOSED_TOKEN;
+ case XML_TOK_PARTIAL_CHAR:
+ if (!ps_finalBuffer) {
+ *nextPtr = s;
+ return XML_ERROR_NONE;
+ }
+ return XML_ERROR_PARTIAL_CHAR;
+ default:
+ return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
+ }
+ eventPtr = s = next;
+ switch (ps_parsing) {
+ case XML_SUSPENDED:
+ *nextPtr = next;
+ return XML_ERROR_NONE;
+ case XML_FINISHED:
+ return XML_ERROR_ABORTED;
+ default: ;
+ }
+ }
+}
+
+static enum XML_Error
+processInternalEntity(XML_Parser parser, ENTITY *entity,
+ XML_Bool betweenDecl)
+{
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity;
+
+ if (freeInternalEntities) {
+ openEntity = freeInternalEntities;
+ freeInternalEntities = openEntity->next;
+ }
+ else {
+ openEntity = (OPEN_INTERNAL_ENTITY *)MALLOC(sizeof(OPEN_INTERNAL_ENTITY));
+ if (!openEntity)
+ return XML_ERROR_NO_MEMORY;
+ }
+ entity->open = XML_TRUE;
+ entity->processed = 0;
+ openEntity->next = openInternalEntities;
+ openInternalEntities = openEntity;
+ openEntity->entity = entity;
+ openEntity->startTagLevel = tagLevel;
+ openEntity->betweenDecl = betweenDecl;
+ openEntity->internalEventPtr = NULL;
+ openEntity->internalEventEndPtr = NULL;
+ textStart = (char *)entity->textPtr;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ next = textStart;
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, tagLevel, internalEncoding, textStart,
+ textEnd, &next, XML_FALSE);
+
+ if (result == XML_ERROR_NONE) {
+ if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - textStart);
+ processor = internalEntityProcessor;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+ }
+ return result;
+}
+
+static enum XML_Error PTRCALL
+internalEntityProcessor(XML_Parser parser,
+ const char *s,
+ const char *end,
+ const char **nextPtr)
+{
+ ENTITY *entity;
+ const char *textStart, *textEnd;
+ const char *next;
+ enum XML_Error result;
+ OPEN_INTERNAL_ENTITY *openEntity = openInternalEntities;
+ if (!openEntity)
+ return XML_ERROR_UNEXPECTED_STATE;
+
+ entity = openEntity->entity;
+ textStart = ((char *)entity->textPtr) + entity->processed;
+ textEnd = (char *)(entity->textPtr + entity->textLen);
+ /* Set a safe default value in case 'next' does not get set */
+ next = textStart;
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok = XmlPrologTok(internalEncoding, textStart, textEnd, &next);
+ result = doProlog(parser, internalEncoding, textStart, textEnd, tok,
+ next, &next, XML_FALSE);
+ }
+ else
+#endif /* XML_DTD */
+ result = doContent(parser, openEntity->startTagLevel, internalEncoding,
+ textStart, textEnd, &next, XML_FALSE);
+
+ if (result != XML_ERROR_NONE)
+ return result;
+ else if (textEnd != next && ps_parsing == XML_SUSPENDED) {
+ entity->processed = (int)(next - (char *)entity->textPtr);
+ return result;
+ }
+ else {
+ entity->open = XML_FALSE;
+ openInternalEntities = openEntity->next;
+ /* put openEntity back in list of free instances */
+ openEntity->next = freeInternalEntities;
+ freeInternalEntities = openEntity;
+ }
+
+#ifdef XML_DTD
+ if (entity->is_param) {
+ int tok;
+ processor = prologProcessor;
+ tok = XmlPrologTok(encoding, s, end, &next);
+ return doProlog(parser, encoding, s, end, tok, next, nextPtr,
+ (XML_Bool)!ps_finalBuffer);
+ }
+ else
+#endif /* XML_DTD */
+ {
+ processor = contentProcessor;
+ /* see externalEntityContentProcessor vs contentProcessor */
+ return doContent(parser, parentParser ? 1 : 0, encoding, s, end,
+ nextPtr, (XML_Bool)!ps_finalBuffer);
+ }
+}
+
+static enum XML_Error PTRCALL
+errorProcessor(XML_Parser parser,
+ const char *UNUSED_P(s),
+ const char *UNUSED_P(end),
+ const char **UNUSED_P(nextPtr))
+{
+ return errorCode;
+}
+
+static enum XML_Error
+storeAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr,
+ end, pool);
+ if (result)
+ return result;
+ if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
+ poolChop(pool);
+ if (!poolAppendChar(pool, XML_T('\0')))
+ return XML_ERROR_NO_MEMORY;
+ return XML_ERROR_NONE;
+}
+
+static enum XML_Error
+appendAttributeValue(XML_Parser parser, const ENCODING *enc, XML_Bool isCdata,
+ const char *ptr, const char *end,
+ STRING_POOL *pool)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ for (;;) {
+ const char *next;
+ int tok = XmlAttributeValueTok(enc, ptr, end, &next);
+ switch (tok) {
+ case XML_TOK_NONE:
+ return XML_ERROR_NONE;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_INVALID_TOKEN;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, ptr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BAD_CHAR_REF;
+ }
+ if (!isCdata
+ && n == 0x20 /* space */
+ && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ n = XmlEncode(n, (ICHAR *)buf);
+ /* The XmlEncode() functions can never return 0 here. That
+ * error return happens if the code point passed in is either
+ * negative or greater than or equal to 0x110000. The
+ * XmlCharRefNumber() functions will all return a number
+ * strictly less than 0x110000 or a negative value if an error
+ * occurred. The negative value is intercepted above, so
+ * XmlEncode() is never passed a value it might return an
+ * error for.
+ */
+ for (i = 0; i < n; i++) {
+ if (!poolAppendChar(pool, buf[i]))
+ return XML_ERROR_NO_MEMORY;
+ }
+ }
+ break;
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, ptr, next))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = ptr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_ATTRIBUTE_VALUE_S:
+ case XML_TOK_DATA_NEWLINE:
+ if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
+ break;
+ if (!poolAppendChar(pool, 0x20))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ case XML_TOK_ENTITY_REF:
+ {
+ const XML_Char *name;
+ ENTITY *entity;
+ char checkEntityDecl;
+ XML_Char ch = (XML_Char) XmlPredefinedEntityName(enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (ch) {
+ if (!poolAppendChar(pool, ch))
+ return XML_ERROR_NO_MEMORY;
+ break;
+ }
+ name = poolStoreString(&temp2Pool, enc,
+ ptr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name)
+ return XML_ERROR_NO_MEMORY;
+ entity = (ENTITY *)lookup(parser, &dtd->generalEntities, name, 0);
+ poolDiscard(&temp2Pool);
+ /* First, determine if a check for an existing declaration is needed;
+ if yes, check that the entity exists, and that it is internal.
+ */
+ if (pool == &dtd->pool) /* are we called from prolog? */
+ checkEntityDecl =
+#ifdef XML_DTD
+ prologState.documentEntity &&
+#endif /* XML_DTD */
+ (dtd->standalone
+ ? !openInternalEntities
+ : !dtd->hasParamEntityRefs);
+ else /* if (pool == &tempPool): we are called from content */
+ checkEntityDecl = !dtd->hasParamEntityRefs || dtd->standalone;
+ if (checkEntityDecl) {
+ if (!entity)
+ return XML_ERROR_UNDEFINED_ENTITY;
+ else if (!entity->is_internal)
+ return XML_ERROR_ENTITY_DECLARED_IN_PE;
+ }
+ else if (!entity) {
+ /* Cannot report skipped entity here - see comments on
+ skippedEntityHandler.
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ /* Cannot call the default handler because this would be
+ out of sync with the call to the startElementHandler.
+ if ((pool == &tempPool) && defaultHandler)
+ reportDefault(parser, enc, ptr, next);
+ */
+ break;
+ }
+ if (entity->open) {
+ if (enc == encoding) {
+ /* It does not appear that this line can be executed.
+ *
+ * The "if (entity->open)" check catches recursive entity
+ * definitions. In order to be called with an open
+ * entity, it must have gone through this code before and
+ * been through the recursive call to
+ * appendAttributeValue() some lines below. That call
+ * sets the local encoding ("enc") to the parser's
+ * internal encoding (internal_utf8 or internal_utf16),
+ * which can never be the same as the principle encoding.
+ * It doesn't appear there is another code path that gets
+ * here with entity->open being TRUE.
+ *
+ * Since it is not certain that this logic is watertight,
+ * we keep the line and merely exclude it from coverage
+ * tests.
+ */
+ eventPtr = ptr; /* LCOV_EXCL_LINE */
+ }
+ return XML_ERROR_RECURSIVE_ENTITY_REF;
+ }
+ if (entity->notation) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_BINARY_ENTITY_REF;
+ }
+ if (!entity->textPtr) {
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
+ }
+ else {
+ enum XML_Error result;
+ const XML_Char *textEnd = entity->textPtr + entity->textLen;
+ entity->open = XML_TRUE;
+ result = appendAttributeValue(parser, internalEncoding, isCdata,
+ (char *)entity->textPtr,
+ (char *)textEnd, pool);
+ entity->open = XML_FALSE;
+ if (result)
+ return result;
+ }
+ }
+ break;
+ default:
+ /* The only token returned by XmlAttributeValueTok() that does
+ * not have an explicit case here is XML_TOK_PARTIAL_CHAR.
+ * Getting that would require an entity name to contain an
+ * incomplete XML character (e.g. \xE2\x82); however previous
+ * tokenisers will have already recognised and rejected such
+ * names before XmlAttributeValueTok() gets a look-in. This
+ * default case should be retained as a safety net, but the code
+ * excluded from coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+ if (enc == encoding)
+ eventPtr = ptr;
+ return XML_ERROR_UNEXPECTED_STATE;
+ /* LCOV_EXCL_STOP */
+ }
+ ptr = next;
+ }
+ /* not reached */
+}
+
+static enum XML_Error
+storeEntityValue(XML_Parser parser,
+ const ENCODING *enc,
+ const char *entityTextPtr,
+ const char *entityTextEnd)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ STRING_POOL *pool = &(dtd->entityValuePool);
+ enum XML_Error result = XML_ERROR_NONE;
+#ifdef XML_DTD
+ int oldInEntityValue = prologState.inEntityValue;
+ prologState.inEntityValue = 1;
+#endif /* XML_DTD */
+ /* never return Null for the value argument in EntityDeclHandler,
+ since this would indicate an external entity; therefore we
+ have to make sure that entityValuePool.start is not null */
+ if (!pool->blocks) {
+ if (!poolGrow(pool))
+ return XML_ERROR_NO_MEMORY;
+ }
+
+ for (;;) {
+ const char *next;
+ int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
+ switch (tok) {
+ case XML_TOK_PARAM_ENTITY_REF:
+#ifdef XML_DTD
+ if (isParamEntity || enc != encoding) {
+ const XML_Char *name;
+ ENTITY *entity;
+ name = poolStoreString(&tempPool, enc,
+ entityTextPtr + enc->minBytesPerChar,
+ next - enc->minBytesPerChar);
+ if (!name) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ entity = (ENTITY *)lookup(parser, &dtd->paramEntities, name, 0);
+ poolDiscard(&tempPool);
+ if (!entity) {
+ /* not a well-formedness error - see XML 1.0: WFC Entity Declared */
+ /* cannot report skipped entity here - see comments on
+ skippedEntityHandler
+ if (skippedEntityHandler)
+ skippedEntityHandler(handlerArg, name, 0);
+ */
+ dtd->keepProcessing = dtd->standalone;
+ goto endEntityValue;
+ }
+ if (entity->open) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_RECURSIVE_ENTITY_REF;
+ goto endEntityValue;
+ }
+ if (entity->systemId) {
+ if (externalEntityRefHandler) {
+ dtd->paramEntityRead = XML_FALSE;
+ entity->open = XML_TRUE;
+ if (!externalEntityRefHandler(externalEntityRefHandlerArg,
+ 0,
+ entity->base,
+ entity->systemId,
+ entity->publicId)) {
+ entity->open = XML_FALSE;
+ result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
+ goto endEntityValue;
+ }
+ entity->open = XML_FALSE;
+ if (!dtd->paramEntityRead)
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else
+ dtd->keepProcessing = dtd->standalone;
+ }
+ else {
+ entity->open = XML_TRUE;
+ result = storeEntityValue(parser,
+ internalEncoding,
+ (char *)entity->textPtr,
+ (char *)(entity->textPtr
+ + entity->textLen));
+ entity->open = XML_FALSE;
+ if (result)
+ goto endEntityValue;
+ }
+ break;
+ }
+#endif /* XML_DTD */
+ /* In the internal subset, PE references are not legal
+ within markup declarations, e.g entity values in this case. */
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_PARAM_ENTITY_REF;
+ goto endEntityValue;
+ case XML_TOK_NONE:
+ result = XML_ERROR_NONE;
+ goto endEntityValue;
+ case XML_TOK_ENTITY_REF:
+ case XML_TOK_DATA_CHARS:
+ if (!poolAppend(pool, enc, entityTextPtr, next)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ break;
+ case XML_TOK_TRAILING_CR:
+ next = entityTextPtr + enc->minBytesPerChar;
+ /* fall through */
+ case XML_TOK_DATA_NEWLINE:
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = 0xA;
+ break;
+ case XML_TOK_CHAR_REF:
+ {
+ XML_Char buf[XML_ENCODE_MAX];
+ int i;
+ int n = XmlCharRefNumber(enc, entityTextPtr);
+ if (n < 0) {
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_BAD_CHAR_REF;
+ goto endEntityValue;
+ }
+ n = XmlEncode(n, (ICHAR *)buf);
+ /* The XmlEncode() functions can never return 0 here. That
+ * error return happens if the code point passed in is either
+ * negative or greater than or equal to 0x110000. The
+ * XmlCharRefNumber() functions will all return a number
+ * strictly less than 0x110000 or a negative value if an error
+ * occurred. The negative value is intercepted above, so
+ * XmlEncode() is never passed a value it might return an
+ * error for.
+ */
+ for (i = 0; i < n; i++) {
+ if (pool->end == pool->ptr && !poolGrow(pool)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
+ }
+ *(pool->ptr)++ = buf[i];
+ }
+ }
+ break;
+ case XML_TOK_PARTIAL:
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ case XML_TOK_INVALID:
+ if (enc == encoding)
+ eventPtr = next;
+ result = XML_ERROR_INVALID_TOKEN;
+ goto endEntityValue;
+ default:
+ /* This default case should be unnecessary -- all the tokens
+ * that XmlEntityValueTok() can return have their own explicit
+ * cases -- but should be retained for safety. We do however
+ * exclude it from the coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ if (enc == encoding)
+ eventPtr = entityTextPtr;
+ result = XML_ERROR_UNEXPECTED_STATE;
+ goto endEntityValue;
+ /* LCOV_EXCL_STOP */
+ }
+ entityTextPtr = next;
+ }
+endEntityValue:
+#ifdef XML_DTD
+ prologState.inEntityValue = oldInEntityValue;
+#endif /* XML_DTD */
+ return result;
+}
+
+static void FASTCALL
+normalizeLines(XML_Char *s)
+{
+ XML_Char *p;
+ for (;; s++) {
+ if (*s == XML_T('\0'))
+ return;
+ if (*s == 0xD)
+ break;
+ }
+ p = s;
+ do {
+ if (*s == 0xD) {
+ *p++ = 0xA;
+ if (*++s == 0xA)
+ s++;
+ }
+ else
+ *p++ = *s++;
+ } while (*s);
+ *p = XML_T('\0');
+}
+
+static int
+reportProcessingInstruction(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ const XML_Char *target;
+ XML_Char *data;
+ const char *tem;
+ if (!processingInstructionHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ start += enc->minBytesPerChar * 2;
+ tem = start + XmlNameLength(enc, start);
+ target = poolStoreString(&tempPool, enc, start, tem);
+ if (!target)
+ return 0;
+ poolFinish(&tempPool);
+ data = poolStoreString(&tempPool, enc,
+ XmlSkipS(enc, tem),
+ end - enc->minBytesPerChar*2);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ processingInstructionHandler(handlerArg, target, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static int
+reportComment(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ XML_Char *data;
+ if (!commentHandler) {
+ if (defaultHandler)
+ reportDefault(parser, enc, start, end);
+ return 1;
+ }
+ data = poolStoreString(&tempPool,
+ enc,
+ start + enc->minBytesPerChar * 4,
+ end - enc->minBytesPerChar * 3);
+ if (!data)
+ return 0;
+ normalizeLines(data);
+ commentHandler(handlerArg, data);
+ poolClear(&tempPool);
+ return 1;
+}
+
+static void
+reportDefault(XML_Parser parser, const ENCODING *enc,
+ const char *s, const char *end)
+{
+ if (MUST_CONVERT(enc, s)) {
+ enum XML_Convert_Result convert_res;
+ const char **eventPP;
+ const char **eventEndPP;
+ if (enc == encoding) {
+ eventPP = &eventPtr;
+ eventEndPP = &eventEndPtr;
+ }
+ else {
+ /* To get here, two things must be true; the parser must be
+ * using a character encoding that is not the same as the
+ * encoding passed in, and the encoding passed in must need
+ * conversion to the internal format (UTF-8 unless XML_UNICODE
+ * is defined). The only occasions on which the encoding passed
+ * in is not the same as the parser's encoding are when it is
+ * the internal encoding (e.g. a previously defined parameter
+ * entity, already converted to internal format). This by
+ * definition doesn't need conversion, so the whole branch never
+ * gets executed.
+ *
+ * For safety's sake we don't delete these lines and merely
+ * exclude them from coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+ eventPP = &(openInternalEntities->internalEventPtr);
+ eventEndPP = &(openInternalEntities->internalEventEndPtr);
+ /* LCOV_EXCL_STOP */
+ }
+ do {
+ ICHAR *dataPtr = (ICHAR *)dataBuf;
+ convert_res = XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
+ *eventEndPP = s;
+ defaultHandler(handlerArg, dataBuf, (int)(dataPtr - (ICHAR *)dataBuf));
+ *eventPP = s;
+ } while ((convert_res != XML_CONVERT_COMPLETED) && (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
+ }
+ else
+ defaultHandler(handlerArg, (XML_Char *)s, (int)((XML_Char *)end - (XML_Char *)s));
+}
+
+
+static int
+defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata,
+ XML_Bool isId, const XML_Char *value, XML_Parser parser)
+{
+ DEFAULT_ATTRIBUTE *att;
+ if (value || isId) {
+ /* The handling of default attributes gets messed up if we have
+ a default which duplicates a non-default. */
+ int i;
+ for (i = 0; i < type->nDefaultAtts; i++)
+ if (attId == type->defaultAtts[i].id)
+ return 1;
+ if (isId && !type->idAtt && !attId->xmlns)
+ type->idAtt = attId;
+ }
+ if (type->nDefaultAtts == type->allocDefaultAtts) {
+ if (type->allocDefaultAtts == 0) {
+ type->allocDefaultAtts = 8;
+ type->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(type->allocDefaultAtts
+ * sizeof(DEFAULT_ATTRIBUTE));
+ if (!type->defaultAtts)
+ return 0;
+ }
+ else {
+ DEFAULT_ATTRIBUTE *temp;
+ int count = type->allocDefaultAtts * 2;
+ temp = (DEFAULT_ATTRIBUTE *)
+ REALLOC(type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ if (temp == NULL)
+ return 0;
+ type->allocDefaultAtts = count;
+ type->defaultAtts = temp;
+ }
+ }
+ att = type->defaultAtts + type->nDefaultAtts;
+ att->id = attId;
+ att->value = value;
+ att->isCdata = isCdata;
+ if (!isCdata)
+ attId->maybeTokenized = XML_TRUE;
+ type->nDefaultAtts += 1;
+ return 1;
+}
+
+static int
+setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name;
+ for (name = elementType->name; *name; name++) {
+ if (*name == XML_T(ASCII_COLON)) {
+ PREFIX *prefix;
+ const XML_Char *s;
+ for (s = elementType->name; s != name; s++) {
+ if (!poolAppendChar(&dtd->pool, *s))
+ return 0;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return 0;
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return 0;
+ if (prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ elementType->prefix = prefix;
+
+ }
+ }
+ return 1;
+}
+
+static ATTRIBUTE_ID *
+getAttributeId(XML_Parser parser, const ENCODING *enc,
+ const char *start, const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ ATTRIBUTE_ID *id;
+ const XML_Char *name;
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ name = poolStoreString(&dtd->pool, enc, start, end);
+ if (!name)
+ return NULL;
+ /* skip quotation mark - its storage will be re-used (like in name[-1]) */
+ ++name;
+ id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, name, sizeof(ATTRIBUTE_ID));
+ if (!id)
+ return NULL;
+ if (id->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!ns)
+ ;
+ else if (name[0] == XML_T(ASCII_x)
+ && name[1] == XML_T(ASCII_m)
+ && name[2] == XML_T(ASCII_l)
+ && name[3] == XML_T(ASCII_n)
+ && name[4] == XML_T(ASCII_s)
+ && (name[5] == XML_T('\0') || name[5] == XML_T(ASCII_COLON))) {
+ if (name[5] == XML_T('\0'))
+ id->prefix = &dtd->defaultPrefix;
+ else
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, name + 6, sizeof(PREFIX));
+ id->xmlns = XML_TRUE;
+ }
+ else {
+ int i;
+ for (i = 0; name[i]; i++) {
+ /* attributes without prefix are *not* in the default namespace */
+ if (name[i] == XML_T(ASCII_COLON)) {
+ int j;
+ for (j = 0; j < i; j++) {
+ if (!poolAppendChar(&dtd->pool, name[j]))
+ return NULL;
+ }
+ if (!poolAppendChar(&dtd->pool, XML_T('\0')))
+ return NULL;
+ id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&dtd->pool),
+ sizeof(PREFIX));
+ if (!id->prefix)
+ return NULL;
+ if (id->prefix->name == poolStart(&dtd->pool))
+ poolFinish(&dtd->pool);
+ else
+ poolDiscard(&dtd->pool);
+ break;
+ }
+ }
+ }
+ }
+ return id;
+}
+
+#define CONTEXT_SEP XML_T(ASCII_FF)
+
+static const XML_Char *
+getContext(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ HASH_TABLE_ITER iter;
+ XML_Bool needSep = XML_FALSE;
+
+ if (dtd->defaultPrefix.binding) {
+ int i;
+ int len;
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ return NULL;
+ len = dtd->defaultPrefix.binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++) {
+ if (!poolAppendChar(&tempPool, dtd->defaultPrefix.binding->uri[i])) {
+ /* Because of memory caching, I don't believe this line can be
+ * executed.
+ *
+ * This is part of a loop copying the default prefix binding
+ * URI into the parser's temporary string pool. Previously,
+ * that URI was copied into the same string pool, with a
+ * terminating NUL character, as part of setContext(). When
+ * the pool was cleared, that leaves a block definitely big
+ * enough to hold the URI on the free block list of the pool.
+ * The URI copy in getContext() therefore cannot run out of
+ * memory.
+ *
+ * If the pool is used between the setContext() and
+ * getContext() calls, the worst it can do is leave a bigger
+ * block on the front of the free list. Given that this is
+ * all somewhat inobvious and program logic can be changed, we
+ * don't delete the line but we do exclude it from the test
+ * coverage statistics.
+ */
+ return NULL; /* LCOV_EXCL_LINE */
+ }
+ }
+ needSep = XML_TRUE;
+ }
+
+ hashTableIterInit(&iter, &(dtd->prefixes));
+ for (;;) {
+ int i;
+ int len;
+ const XML_Char *s;
+ PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
+ if (!prefix)
+ break;
+ if (!prefix->binding) {
+ /* This test appears to be (justifiable) paranoia. There does
+ * not seem to be a way of injecting a prefix without a binding
+ * that doesn't get errored long before this function is called.
+ * The test should remain for safety's sake, so we instead
+ * exclude the following line from the coverage statistics.
+ */
+ continue; /* LCOV_EXCL_LINE */
+ }
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = prefix->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return NULL;
+ if (!poolAppendChar(&tempPool, XML_T(ASCII_EQUALS)))
+ return NULL;
+ len = prefix->binding->uriLen;
+ if (namespaceSeparator)
+ len--;
+ for (i = 0; i < len; i++)
+ if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
+ return NULL;
+ needSep = XML_TRUE;
+ }
+
+
+ hashTableIterInit(&iter, &(dtd->generalEntities));
+ for (;;) {
+ const XML_Char *s;
+ ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (!e->open)
+ continue;
+ if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
+ return NULL;
+ for (s = e->name; *s; s++)
+ if (!poolAppendChar(&tempPool, *s))
+ return 0;
+ needSep = XML_TRUE;
+ }
+
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return NULL;
+ return tempPool.start;
+}
+
+static XML_Bool
+setContext(XML_Parser parser, const XML_Char *context)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *s = context;
+
+ while (*context != XML_T('\0')) {
+ if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
+ ENTITY *e;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ e = (ENTITY *)lookup(parser, &dtd->generalEntities, poolStart(&tempPool), 0);
+ if (e)
+ e->open = XML_TRUE;
+ if (*s != XML_T('\0'))
+ s++;
+ context = s;
+ poolDiscard(&tempPool);
+ }
+ else if (*s == XML_T(ASCII_EQUALS)) {
+ PREFIX *prefix;
+ if (poolLength(&tempPool) == 0)
+ prefix = &dtd->defaultPrefix;
+ else {
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ prefix = (PREFIX *)lookup(parser, &dtd->prefixes, poolStart(&tempPool),
+ sizeof(PREFIX));
+ if (!prefix)
+ return XML_FALSE;
+ if (prefix->name == poolStart(&tempPool)) {
+ prefix->name = poolCopyString(&dtd->pool, prefix->name);
+ if (!prefix->name)
+ return XML_FALSE;
+ }
+ poolDiscard(&tempPool);
+ }
+ for (context = s + 1;
+ *context != CONTEXT_SEP && *context != XML_T('\0');
+ context++)
+ if (!poolAppendChar(&tempPool, *context))
+ return XML_FALSE;
+ if (!poolAppendChar(&tempPool, XML_T('\0')))
+ return XML_FALSE;
+ if (addBinding(parser, prefix, NULL, poolStart(&tempPool),
+ &inheritedBindings) != XML_ERROR_NONE)
+ return XML_FALSE;
+ poolDiscard(&tempPool);
+ if (*context != XML_T('\0'))
+ ++context;
+ s = context;
+ }
+ else {
+ if (!poolAppendChar(&tempPool, *s))
+ return XML_FALSE;
+ s++;
+ }
+ }
+ return XML_TRUE;
+}
+
+static void FASTCALL
+normalizePublicId(XML_Char *publicId)
+{
+ XML_Char *p = publicId;
+ XML_Char *s;
+ for (s = publicId; *s; s++) {
+ switch (*s) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ if (p != publicId && p[-1] != 0x20)
+ *p++ = 0x20;
+ break;
+ default:
+ *p++ = *s;
+ }
+ }
+ if (p != publicId && p[-1] == 0x20)
+ --p;
+ *p = XML_T('\0');
+}
+
+static DTD *
+dtdCreate(const XML_Memory_Handling_Suite *ms)
+{
+ DTD *p = (DTD *)ms->malloc_fcn(sizeof(DTD));
+ if (p == NULL)
+ return p;
+ poolInit(&(p->pool), ms);
+ poolInit(&(p->entityValuePool), ms);
+ hashTableInit(&(p->generalEntities), ms);
+ hashTableInit(&(p->elementTypes), ms);
+ hashTableInit(&(p->attributeIds), ms);
+ hashTableInit(&(p->prefixes), ms);
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableInit(&(p->paramEntities), ms);
+#endif /* XML_DTD */
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+ p->scaffIndex = NULL;
+ p->scaffold = NULL;
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+ return p;
+}
+
+static void
+dtdReset(DTD *p, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableClear(&(p->generalEntities));
+#ifdef XML_DTD
+ p->paramEntityRead = XML_FALSE;
+ hashTableClear(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableClear(&(p->elementTypes));
+ hashTableClear(&(p->attributeIds));
+ hashTableClear(&(p->prefixes));
+ poolClear(&(p->pool));
+ poolClear(&(p->entityValuePool));
+ p->defaultPrefix.name = NULL;
+ p->defaultPrefix.binding = NULL;
+
+ p->in_eldecl = XML_FALSE;
+
+ ms->free_fcn(p->scaffIndex);
+ p->scaffIndex = NULL;
+ ms->free_fcn(p->scaffold);
+ p->scaffold = NULL;
+
+ p->scaffLevel = 0;
+ p->scaffSize = 0;
+ p->scaffCount = 0;
+ p->contentStringLen = 0;
+
+ p->keepProcessing = XML_TRUE;
+ p->hasParamEntityRefs = XML_FALSE;
+ p->standalone = XML_FALSE;
+}
+
+static void
+dtdDestroy(DTD *p, XML_Bool isDocEntity, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+ hashTableIterInit(&iter, &(p->elementTypes));
+ for (;;) {
+ ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!e)
+ break;
+ if (e->allocDefaultAtts != 0)
+ ms->free_fcn(e->defaultAtts);
+ }
+ hashTableDestroy(&(p->generalEntities));
+#ifdef XML_DTD
+ hashTableDestroy(&(p->paramEntities));
+#endif /* XML_DTD */
+ hashTableDestroy(&(p->elementTypes));
+ hashTableDestroy(&(p->attributeIds));
+ hashTableDestroy(&(p->prefixes));
+ poolDestroy(&(p->pool));
+ poolDestroy(&(p->entityValuePool));
+ if (isDocEntity) {
+ ms->free_fcn(p->scaffIndex);
+ ms->free_fcn(p->scaffold);
+ }
+ ms->free_fcn(p);
+}
+
+/* Do a deep copy of the DTD. Return 0 for out of memory, non-zero otherwise.
+ The new DTD has already been initialized.
+*/
+static int
+dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, const XML_Memory_Handling_Suite *ms)
+{
+ HASH_TABLE_ITER iter;
+
+ /* Copy the prefix table. */
+
+ hashTableIterInit(&iter, &(oldDtd->prefixes));
+ for (;;) {
+ const XML_Char *name;
+ const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
+ if (!oldP)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldP->name);
+ if (!name)
+ return 0;
+ if (!lookup(oldParser, &(newDtd->prefixes), name, sizeof(PREFIX)))
+ return 0;
+ }
+
+ hashTableIterInit(&iter, &(oldDtd->attributeIds));
+
+ /* Copy the attribute id table. */
+
+ for (;;) {
+ ATTRIBUTE_ID *newA;
+ const XML_Char *name;
+ const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
+
+ if (!oldA)
+ break;
+ /* Remember to allocate the scratch byte before the name. */
+ if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
+ return 0;
+ name = poolCopyString(&(newDtd->pool), oldA->name);
+ if (!name)
+ return 0;
+ ++name;
+ newA = (ATTRIBUTE_ID *)lookup(oldParser, &(newDtd->attributeIds), name,
+ sizeof(ATTRIBUTE_ID));
+ if (!newA)
+ return 0;
+ newA->maybeTokenized = oldA->maybeTokenized;
+ if (oldA->prefix) {
+ newA->xmlns = oldA->xmlns;
+ if (oldA->prefix == &oldDtd->defaultPrefix)
+ newA->prefix = &newDtd->defaultPrefix;
+ else
+ newA->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+ oldA->prefix->name, 0);
+ }
+ }
+
+ /* Copy the element type table. */
+
+ hashTableIterInit(&iter, &(oldDtd->elementTypes));
+
+ for (;;) {
+ int i;
+ ELEMENT_TYPE *newE;
+ const XML_Char *name;
+ const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(&(newDtd->pool), oldE->name);
+ if (!name)
+ return 0;
+ newE = (ELEMENT_TYPE *)lookup(oldParser, &(newDtd->elementTypes), name,
+ sizeof(ELEMENT_TYPE));
+ if (!newE)
+ return 0;
+ if (oldE->nDefaultAtts) {
+ newE->defaultAtts = (DEFAULT_ATTRIBUTE *)
+ ms->malloc_fcn(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
+ if (!newE->defaultAtts) {
+ return 0;
+ }
+ }
+ if (oldE->idAtt)
+ newE->idAtt = (ATTRIBUTE_ID *)
+ lookup(oldParser, &(newDtd->attributeIds), oldE->idAtt->name, 0);
+ newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
+ if (oldE->prefix)
+ newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
+ oldE->prefix->name, 0);
+ for (i = 0; i < newE->nDefaultAtts; i++) {
+ newE->defaultAtts[i].id = (ATTRIBUTE_ID *)
+ lookup(oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
+ if (oldE->defaultAtts[i].value) {
+ newE->defaultAtts[i].value
+ = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
+ if (!newE->defaultAtts[i].value)
+ return 0;
+ }
+ else
+ newE->defaultAtts[i].value = NULL;
+ }
+ }
+
+ /* Copy the entity tables. */
+ if (!copyEntityTable(oldParser,
+ &(newDtd->generalEntities),
+ &(newDtd->pool),
+ &(oldDtd->generalEntities)))
+ return 0;
+
+#ifdef XML_DTD
+ if (!copyEntityTable(oldParser,
+ &(newDtd->paramEntities),
+ &(newDtd->pool),
+ &(oldDtd->paramEntities)))
+ return 0;
+ newDtd->paramEntityRead = oldDtd->paramEntityRead;
+#endif /* XML_DTD */
+
+ newDtd->keepProcessing = oldDtd->keepProcessing;
+ newDtd->hasParamEntityRefs = oldDtd->hasParamEntityRefs;
+ newDtd->standalone = oldDtd->standalone;
+
+ /* Don't want deep copying for scaffolding */
+ newDtd->in_eldecl = oldDtd->in_eldecl;
+ newDtd->scaffold = oldDtd->scaffold;
+ newDtd->contentStringLen = oldDtd->contentStringLen;
+ newDtd->scaffSize = oldDtd->scaffSize;
+ newDtd->scaffLevel = oldDtd->scaffLevel;
+ newDtd->scaffIndex = oldDtd->scaffIndex;
+
+ return 1;
+} /* End dtdCopy */
+
+static int
+copyEntityTable(XML_Parser oldParser,
+ HASH_TABLE *newTable,
+ STRING_POOL *newPool,
+ const HASH_TABLE *oldTable)
+{
+ HASH_TABLE_ITER iter;
+ const XML_Char *cachedOldBase = NULL;
+ const XML_Char *cachedNewBase = NULL;
+
+ hashTableIterInit(&iter, oldTable);
+
+ for (;;) {
+ ENTITY *newE;
+ const XML_Char *name;
+ const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
+ if (!oldE)
+ break;
+ name = poolCopyString(newPool, oldE->name);
+ if (!name)
+ return 0;
+ newE = (ENTITY *)lookup(oldParser, newTable, name, sizeof(ENTITY));
+ if (!newE)
+ return 0;
+ if (oldE->systemId) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
+ if (!tem)
+ return 0;
+ newE->systemId = tem;
+ if (oldE->base) {
+ if (oldE->base == cachedOldBase)
+ newE->base = cachedNewBase;
+ else {
+ cachedOldBase = oldE->base;
+ tem = poolCopyString(newPool, cachedOldBase);
+ if (!tem)
+ return 0;
+ cachedNewBase = newE->base = tem;
+ }
+ }
+ if (oldE->publicId) {
+ tem = poolCopyString(newPool, oldE->publicId);
+ if (!tem)
+ return 0;
+ newE->publicId = tem;
+ }
+ }
+ else {
+ const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr,
+ oldE->textLen);
+ if (!tem)
+ return 0;
+ newE->textPtr = tem;
+ newE->textLen = oldE->textLen;
+ }
+ if (oldE->notation) {
+ const XML_Char *tem = poolCopyString(newPool, oldE->notation);
+ if (!tem)
+ return 0;
+ newE->notation = tem;
+ }
+ newE->is_param = oldE->is_param;
+ newE->is_internal = oldE->is_internal;
+ }
+ return 1;
+}
+
+#define INIT_POWER 6
+
+static XML_Bool FASTCALL
+keyeq(KEY s1, KEY s2)
+{
+ for (; *s1 == *s2; s1++, s2++)
+ if (*s1 == 0)
+ return XML_TRUE;
+ return XML_FALSE;
+}
+
+static size_t
+keylen(KEY s)
+{
+ size_t len = 0;
+ for (; *s; s++, len++);
+ return len;
+}
+
+static void
+copy_salt_to_sipkey(XML_Parser parser, struct sipkey * key)
+{
+ key->k[0] = 0;
+ key->k[1] = get_hash_secret_salt(parser);
+}
+
+static unsigned long FASTCALL
+hash(XML_Parser parser, KEY s)
+{
+ struct siphash state;
+ struct sipkey key;
+ (void)sip_tobin;
+ (void)sip24_valid;
+ copy_salt_to_sipkey(parser, &key);
+ sip24_init(&state, &key);
+ sip24_update(&state, s, keylen(s) * sizeof(XML_Char));
+ return (unsigned long)sip24_final(&state);
+}
+
+static NAMED *
+lookup(XML_Parser parser, HASH_TABLE *table, KEY name, size_t createSize)
+{
+ size_t i;
+ if (table->size == 0) {
+ size_t tsize;
+ if (!createSize)
+ return NULL;
+ table->power = INIT_POWER;
+ /* table->size is a power of 2 */
+ table->size = (size_t)1 << INIT_POWER;
+ tsize = table->size * sizeof(NAMED *);
+ table->v = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!table->v) {
+ table->size = 0;
+ return NULL;
+ }
+ memset(table->v, 0, tsize);
+ i = hash(parser, name) & ((unsigned long)table->size - 1);
+ }
+ else {
+ unsigned long h = hash(parser, name);
+ unsigned long mask = (unsigned long)table->size - 1;
+ unsigned char step = 0;
+ i = h & mask;
+ while (table->v[i]) {
+ if (keyeq(name, table->v[i]->name))
+ return table->v[i];
+ if (!step)
+ step = PROBE_STEP(h, mask, table->power);
+ i < step ? (i += table->size - step) : (i -= step);
+ }
+ if (!createSize)
+ return NULL;
+
+ /* check for overflow (table is half full) */
+ if (table->used >> (table->power - 1)) {
+ unsigned char newPower = table->power + 1;
+ size_t newSize = (size_t)1 << newPower;
+ unsigned long newMask = (unsigned long)newSize - 1;
+ size_t tsize = newSize * sizeof(NAMED *);
+ NAMED **newV = (NAMED **)table->mem->malloc_fcn(tsize);
+ if (!newV)
+ return NULL;
+ memset(newV, 0, tsize);
+ for (i = 0; i < table->size; i++)
+ if (table->v[i]) {
+ unsigned long newHash = hash(parser, table->v[i]->name);
+ size_t j = newHash & newMask;
+ step = 0;
+ while (newV[j]) {
+ if (!step)
+ step = PROBE_STEP(newHash, newMask, newPower);
+ j < step ? (j += newSize - step) : (j -= step);
+ }
+ newV[j] = table->v[i];
+ }
+ table->mem->free_fcn(table->v);
+ table->v = newV;
+ table->power = newPower;
+ table->size = newSize;
+ i = h & newMask;
+ step = 0;
+ while (table->v[i]) {
+ if (!step)
+ step = PROBE_STEP(h, newMask, newPower);
+ i < step ? (i += newSize - step) : (i -= step);
+ }
+ }
+ }
+ table->v[i] = (NAMED *)table->mem->malloc_fcn(createSize);
+ if (!table->v[i])
+ return NULL;
+ memset(table->v[i], 0, createSize);
+ table->v[i]->name = name;
+ (table->used)++;
+ return table->v[i];
+}
+
+static void FASTCALL
+hashTableClear(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++) {
+ table->mem->free_fcn(table->v[i]);
+ table->v[i] = NULL;
+ }
+ table->used = 0;
+}
+
+static void FASTCALL
+hashTableDestroy(HASH_TABLE *table)
+{
+ size_t i;
+ for (i = 0; i < table->size; i++)
+ table->mem->free_fcn(table->v[i]);
+ table->mem->free_fcn(table->v);
+}
+
+static void FASTCALL
+hashTableInit(HASH_TABLE *p, const XML_Memory_Handling_Suite *ms)
+{
+ p->power = 0;
+ p->size = 0;
+ p->used = 0;
+ p->v = NULL;
+ p->mem = ms;
+}
+
+static void FASTCALL
+hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
+{
+ iter->p = table->v;
+ iter->end = iter->p + table->size;
+}
+
+static NAMED * FASTCALL
+hashTableIterNext(HASH_TABLE_ITER *iter)
+{
+ while (iter->p != iter->end) {
+ NAMED *tem = *(iter->p)++;
+ if (tem)
+ return tem;
+ }
+ return NULL;
+}
+
+static void FASTCALL
+poolInit(STRING_POOL *pool, const XML_Memory_Handling_Suite *ms)
+{
+ pool->blocks = NULL;
+ pool->freeBlocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+ pool->mem = ms;
+}
+
+static void FASTCALL
+poolClear(STRING_POOL *pool)
+{
+ if (!pool->freeBlocks)
+ pool->freeBlocks = pool->blocks;
+ else {
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ p->next = pool->freeBlocks;
+ pool->freeBlocks = p;
+ p = tem;
+ }
+ }
+ pool->blocks = NULL;
+ pool->start = NULL;
+ pool->ptr = NULL;
+ pool->end = NULL;
+}
+
+static void FASTCALL
+poolDestroy(STRING_POOL *pool)
+{
+ BLOCK *p = pool->blocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+ p = pool->freeBlocks;
+ while (p) {
+ BLOCK *tem = p->next;
+ pool->mem->free_fcn(p);
+ p = tem;
+ }
+}
+
+static XML_Char *
+poolAppend(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!pool->ptr && !poolGrow(pool))
+ return NULL;
+ for (;;) {
+ const enum XML_Convert_Result convert_res = XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
+ if ((convert_res == XML_CONVERT_COMPLETED) || (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
+ break;
+ if (!poolGrow(pool))
+ return NULL;
+ }
+ return pool->start;
+}
+
+static const XML_Char * FASTCALL
+poolCopyString(STRING_POOL *pool, const XML_Char *s)
+{
+ do {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ } while (*s++);
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char *
+poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
+{
+ if (!pool->ptr && !poolGrow(pool)) {
+ /* The following line is unreachable given the current usage of
+ * poolCopyStringN(). Currently it is called from exactly one
+ * place to copy the text of a simple general entity. By that
+ * point, the name of the entity is already stored in the pool, so
+ * pool->ptr cannot be NULL.
+ *
+ * If poolCopyStringN() is used elsewhere as it well might be,
+ * this line may well become executable again. Regardless, this
+ * sort of check shouldn't be removed lightly, so we just exclude
+ * it from the coverage statistics.
+ */
+ return NULL; /* LCOV_EXCL_LINE */
+ }
+ for (; n > 0; --n, s++) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ }
+ s = pool->start;
+ poolFinish(pool);
+ return s;
+}
+
+static const XML_Char * FASTCALL
+poolAppendString(STRING_POOL *pool, const XML_Char *s)
+{
+ while (*s) {
+ if (!poolAppendChar(pool, *s))
+ return NULL;
+ s++;
+ }
+ return pool->start;
+}
+
+static XML_Char *
+poolStoreString(STRING_POOL *pool, const ENCODING *enc,
+ const char *ptr, const char *end)
+{
+ if (!poolAppend(pool, enc, ptr, end))
+ return NULL;
+ if (pool->ptr == pool->end && !poolGrow(pool))
+ return NULL;
+ *(pool->ptr)++ = 0;
+ return pool->start;
+}
+
+static size_t
+poolBytesToAllocateFor(int blockSize)
+{
+ /* Unprotected math would be:
+ ** return offsetof(BLOCK, s) + blockSize * sizeof(XML_Char);
+ **
+ ** Detect overflow, avoiding _signed_ overflow undefined behavior
+ ** For a + b * c we check b * c in isolation first, so that addition of a
+ ** on top has no chance of making us accept a small non-negative number
+ */
+ const size_t stretch = sizeof(XML_Char); /* can be 4 bytes */
+
+ if (blockSize <= 0)
+ return 0;
+
+ if (blockSize > (int)(INT_MAX / stretch))
+ return 0;
+
+ {
+ const int stretchedBlockSize = blockSize * (int)stretch;
+ const int bytesToAllocate = (int)(
+ offsetof(BLOCK, s) + (unsigned)stretchedBlockSize);
+ if (bytesToAllocate < 0)
+ return 0;
+
+ return (size_t)bytesToAllocate;
+ }
+}
+
+static XML_Bool FASTCALL
+poolGrow(STRING_POOL *pool)
+{
+ if (pool->freeBlocks) {
+ if (pool->start == 0) {
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = pool->freeBlocks->next;
+ pool->blocks->next = NULL;
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ pool->ptr = pool->start;
+ return XML_TRUE;
+ }
+ if (pool->end - pool->start < pool->freeBlocks->size) {
+ BLOCK *tem = pool->freeBlocks->next;
+ pool->freeBlocks->next = pool->blocks;
+ pool->blocks = pool->freeBlocks;
+ pool->freeBlocks = tem;
+ memcpy(pool->blocks->s, pool->start,
+ (pool->end - pool->start) * sizeof(XML_Char));
+ pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + pool->blocks->size;
+ return XML_TRUE;
+ }
+ }
+ if (pool->blocks && pool->start == pool->blocks->s) {
+ BLOCK *temp;
+ int blockSize = (int)((unsigned)(pool->end - pool->start)*2U);
+ size_t bytesToAllocate;
+
+ // NOTE: Needs to be calculated prior to calling `realloc`
+ // to avoid dangling pointers:
+ const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
+
+ if (blockSize < 0) {
+ /* This condition traps a situation where either more than
+ * INT_MAX/2 bytes have already been allocated. This isn't
+ * readily testable, since it is unlikely that an average
+ * machine will have that much memory, so we exclude it from the
+ * coverage statistics.
+ */
+ return XML_FALSE; /* LCOV_EXCL_LINE */
+ }
+
+ bytesToAllocate = poolBytesToAllocateFor(blockSize);
+ if (bytesToAllocate == 0)
+ return XML_FALSE;
+
+ temp = (BLOCK *)
+ pool->mem->realloc_fcn(pool->blocks, (unsigned)bytesToAllocate);
+ if (temp == NULL)
+ return XML_FALSE;
+ pool->blocks = temp;
+ pool->blocks->size = blockSize;
+ pool->ptr = pool->blocks->s + offsetInsideBlock;
+ pool->start = pool->blocks->s;
+ pool->end = pool->start + blockSize;
+ }
+ else {
+ BLOCK *tem;
+ int blockSize = (int)(pool->end - pool->start);
+ size_t bytesToAllocate;
+
+ if (blockSize < 0) {
+ /* This condition traps a situation where either more than
+ * INT_MAX bytes have already been allocated (which is prevented
+ * by various pieces of program logic, not least this one, never
+ * mind the unlikelihood of actually having that much memory) or
+ * the pool control fields have been corrupted (which could
+ * conceivably happen in an extremely buggy user handler
+ * function). Either way it isn't readily testable, so we
+ * exclude it from the coverage statistics.
+ */
+ return XML_FALSE; /* LCOV_EXCL_LINE */
+ }
+
+ if (blockSize < INIT_BLOCK_SIZE)
+ blockSize = INIT_BLOCK_SIZE;
+ else {
+ /* Detect overflow, avoiding _signed_ overflow undefined behavior */
+ if ((int)((unsigned)blockSize * 2U) < 0) {
+ return XML_FALSE;
+ }
+ blockSize *= 2;
+ }
+
+ bytesToAllocate = poolBytesToAllocateFor(blockSize);
+ if (bytesToAllocate == 0)
+ return XML_FALSE;
+
+ tem = (BLOCK *)pool->mem->malloc_fcn(bytesToAllocate);
+ if (!tem)
+ return XML_FALSE;
+ tem->size = blockSize;
+ tem->next = pool->blocks;
+ pool->blocks = tem;
+ if (pool->ptr != pool->start)
+ memcpy(tem->s, pool->start,
+ (pool->ptr - pool->start) * sizeof(XML_Char));
+ pool->ptr = tem->s + (pool->ptr - pool->start);
+ pool->start = tem->s;
+ pool->end = tem->s + blockSize;
+ }
+ return XML_TRUE;
+}
+
+static int FASTCALL
+nextScaffoldPart(XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ CONTENT_SCAFFOLD * me;
+ int next;
+
+ if (!dtd->scaffIndex) {
+ dtd->scaffIndex = (int *)MALLOC(groupSize * sizeof(int));
+ if (!dtd->scaffIndex)
+ return -1;
+ dtd->scaffIndex[0] = 0;
+ }
+
+ if (dtd->scaffCount >= dtd->scaffSize) {
+ CONTENT_SCAFFOLD *temp;
+ if (dtd->scaffold) {
+ temp = (CONTENT_SCAFFOLD *)
+ REALLOC(dtd->scaffold, dtd->scaffSize * 2 * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize *= 2;
+ }
+ else {
+ temp = (CONTENT_SCAFFOLD *)MALLOC(INIT_SCAFFOLD_ELEMENTS
+ * sizeof(CONTENT_SCAFFOLD));
+ if (temp == NULL)
+ return -1;
+ dtd->scaffSize = INIT_SCAFFOLD_ELEMENTS;
+ }
+ dtd->scaffold = temp;
+ }
+ next = dtd->scaffCount++;
+ me = &dtd->scaffold[next];
+ if (dtd->scaffLevel) {
+ CONTENT_SCAFFOLD *parent = &dtd->scaffold[dtd->scaffIndex[dtd->scaffLevel-1]];
+ if (parent->lastchild) {
+ dtd->scaffold[parent->lastchild].nextsib = next;
+ }
+ if (!parent->childcnt)
+ parent->firstchild = next;
+ parent->lastchild = next;
+ parent->childcnt++;
+ }
+ me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
+ return next;
+}
+
+static void
+build_node(XML_Parser parser,
+ int src_node,
+ XML_Content *dest,
+ XML_Content **contpos,
+ XML_Char **strpos)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ dest->type = dtd->scaffold[src_node].type;
+ dest->quant = dtd->scaffold[src_node].quant;
+ if (dest->type == XML_CTYPE_NAME) {
+ const XML_Char *src;
+ dest->name = *strpos;
+ src = dtd->scaffold[src_node].name;
+ for (;;) {
+ *(*strpos)++ = *src;
+ if (!*src)
+ break;
+ src++;
+ }
+ dest->numchildren = 0;
+ dest->children = NULL;
+ }
+ else {
+ unsigned int i;
+ int cn;
+ dest->numchildren = dtd->scaffold[src_node].childcnt;
+ dest->children = *contpos;
+ *contpos += dest->numchildren;
+ for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+ i < dest->numchildren;
+ i++, cn = dtd->scaffold[cn].nextsib) {
+ build_node(parser, cn, &(dest->children[i]), contpos, strpos);
+ }
+ dest->name = NULL;
+ }
+}
+
+static XML_Content *
+build_model (XML_Parser parser)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ XML_Content *ret;
+ XML_Content *cpos;
+ XML_Char * str;
+ int allocsize = (dtd->scaffCount * sizeof(XML_Content)
+ + (dtd->contentStringLen * sizeof(XML_Char)));
+
+ ret = (XML_Content *)MALLOC(allocsize);
+ if (!ret)
+ return NULL;
+
+ str = (XML_Char *) (&ret[dtd->scaffCount]);
+ cpos = &ret[1];
+
+ build_node(parser, 0, ret, &cpos, &str);
+ return ret;
+}
+
+static ELEMENT_TYPE *
+getElementType(XML_Parser parser,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end)
+{
+ DTD * const dtd = _dtd; /* save one level of indirection */
+ const XML_Char *name = poolStoreString(&dtd->pool, enc, ptr, end);
+ ELEMENT_TYPE *ret;
+
+ if (!name)
+ return NULL;
+ ret = (ELEMENT_TYPE *) lookup(parser, &dtd->elementTypes, name, sizeof(ELEMENT_TYPE));
+ if (!ret)
+ return NULL;
+ if (ret->name != name)
+ poolDiscard(&dtd->pool);
+ else {
+ poolFinish(&dtd->pool);
+ if (!setElementTypePrefix(parser, ret))
+ return NULL;
+ }
+ return ret;
+}
+
+static XML_Char *
+copyString(const XML_Char *s,
+ const XML_Memory_Handling_Suite *memsuite)
+{
+ int charsRequired = 0;
+ XML_Char *result;
+
+ /* First determine how long the string is */
+ while (s[charsRequired] != 0) {
+ charsRequired++;
+ }
+ /* Include the terminator */
+ charsRequired++;
+
+ /* Now allocate space for the copy */
+ result = memsuite->malloc_fcn(charsRequired * sizeof(XML_Char));
+ if (result == NULL)
+ return NULL;
+ /* Copy the original into place */
+ memcpy(result, s, charsRequired * sizeof(XML_Char));
+ return result;
+}
diff --git a/Utilities/cmexpat/lib/xmlrole.c b/Utilities/cmexpat/lib/xmlrole.c
new file mode 100644
index 000000000..c809ee514
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmlrole.c
@@ -0,0 +1,1358 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include "winconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef _WIN32 */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmlrole.h"
+#include "ascii.h"
+
+/* Doesn't check:
+
+ that ,| are not mixed in a model group
+ content of literals
+
+*/
+
+static const char KW_ANY[] = {
+ ASCII_A, ASCII_N, ASCII_Y, '\0' };
+static const char KW_ATTLIST[] = {
+ ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
+static const char KW_CDATA[] = {
+ ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_DOCTYPE[] = {
+ ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
+static const char KW_ELEMENT[] = {
+ ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
+static const char KW_EMPTY[] = {
+ ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
+static const char KW_ENTITIES[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S,
+ '\0' };
+static const char KW_ENTITY[] = {
+ ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
+static const char KW_FIXED[] = {
+ ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
+static const char KW_ID[] = {
+ ASCII_I, ASCII_D, '\0' };
+static const char KW_IDREF[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
+static const char KW_IDREFS[] = {
+ ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
+#ifdef XML_DTD
+static const char KW_IGNORE[] = {
+ ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
+#endif
+static const char KW_IMPLIED[] = {
+ ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
+#ifdef XML_DTD
+static const char KW_INCLUDE[] = {
+ ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
+#endif
+static const char KW_NDATA[] = {
+ ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_NMTOKEN[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
+static const char KW_NMTOKENS[] = {
+ ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S,
+ '\0' };
+static const char KW_NOTATION[] =
+ { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N,
+ '\0' };
+static const char KW_PCDATA[] = {
+ ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
+static const char KW_PUBLIC[] = {
+ ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
+static const char KW_REQUIRED[] = {
+ ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D,
+ '\0' };
+static const char KW_SYSTEM[] = {
+ ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
+
+#ifndef MIN_BYTES_PER_CHAR
+#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
+#endif
+
+#ifdef XML_DTD
+#define setTopLevel(state) \
+ ((state)->handler = ((state)->documentEntity \
+ ? internalSubset \
+ : externalSubset1))
+#else /* not XML_DTD */
+#define setTopLevel(state) ((state)->handler = internalSubset)
+#endif /* not XML_DTD */
+
+typedef int PTRCALL PROLOG_HANDLER(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+
+static PROLOG_HANDLER
+ prolog0, prolog1, prolog2,
+ doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
+ internalSubset,
+ entity0, entity1, entity2, entity3, entity4, entity5, entity6,
+ entity7, entity8, entity9, entity10,
+ notation0, notation1, notation2, notation3, notation4,
+ attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
+ attlist7, attlist8, attlist9,
+ element0, element1, element2, element3, element4, element5, element6,
+ element7,
+#ifdef XML_DTD
+ externalSubset0, externalSubset1,
+ condSect0, condSect1, condSect2,
+#endif /* XML_DTD */
+ declClose,
+ error;
+
+static int FASTCALL common(PROLOG_STATE *state, int tok);
+
+static int PTRCALL
+prolog0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ state->handler = prolog1;
+ return XML_ROLE_NONE;
+ case XML_TOK_XML_DECL:
+ state->handler = prolog1;
+ return XML_ROLE_XML_DECL;
+ case XML_TOK_PI:
+ state->handler = prolog1;
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ state->handler = prolog1;
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_BOM:
+ /* This case can never arise. To reach this role function, the
+ * parse must have passed through prolog0 and therefore have had
+ * some form of input, even if only a space. At that point, a
+ * byte order mark is no longer a valid character (though
+ * technically it should be interpreted as a non-breaking space),
+ * so will be rejected by the tokenizing stages.
+ */
+ return XML_ROLE_NONE; /* LCOV_EXCL_LINE */
+ case XML_TOK_DECL_OPEN:
+ if (!XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_DOCTYPE))
+ break;
+ state->handler = doctype0;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+prolog2(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_INSTANCE_START:
+ state->handler = error;
+ return XML_ROLE_INSTANCE_START;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype0(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = doctype1;
+ return XML_ROLE_DOCTYPE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = doctype2;
+ return XML_ROLE_DOCTYPE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype2(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype3;
+ return XML_ROLE_DOCTYPE_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype3(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = doctype4;
+ return XML_ROLE_DOCTYPE_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype4(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = internalSubset;
+ return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+doctype5(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_DECL_CLOSE:
+ state->handler = prolog2;
+ return XML_ROLE_DOCTYPE_CLOSE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+internalSubset(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_DECL_OPEN:
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ENTITY)) {
+ state->handler = entity0;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ATTLIST)) {
+ state->handler = attlist0;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_ELEMENT)) {
+ state->handler = element0;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + 2 * MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_NOTATION)) {
+ state->handler = notation0;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ case XML_TOK_PI:
+ return XML_ROLE_PI;
+ case XML_TOK_COMMENT:
+ return XML_ROLE_COMMENT;
+ case XML_TOK_PARAM_ENTITY_REF:
+ return XML_ROLE_PARAM_ENTITY_REF;
+ case XML_TOK_CLOSE_BRACKET:
+ state->handler = doctype5;
+ return XML_ROLE_DOCTYPE_NONE;
+ case XML_TOK_NONE:
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+externalSubset0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ state->handler = externalSubset1;
+ if (tok == XML_TOK_XML_DECL)
+ return XML_ROLE_TEXT_DECL;
+ return externalSubset1(state, tok, ptr, end, enc);
+}
+
+static int PTRCALL
+externalSubset1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_COND_SECT_OPEN:
+ state->handler = condSect0;
+ return XML_ROLE_NONE;
+ case XML_TOK_COND_SECT_CLOSE:
+ if (state->includeLevel == 0)
+ break;
+ state->includeLevel -= 1;
+ return XML_ROLE_NONE;
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_CLOSE_BRACKET:
+ break;
+ case XML_TOK_NONE:
+ if (state->includeLevel)
+ break;
+ return XML_ROLE_NONE;
+ default:
+ return internalSubset(state, tok, ptr, end, enc);
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+entity0(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_PERCENT:
+ state->handler = entity1;
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity2;
+ return XML_ROLE_GENERAL_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity1(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = entity7;
+ return XML_ROLE_PARAM_ENTITY_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity3;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity3(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity4;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity4(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity5;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity5(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
+ state->handler = entity6;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity6(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity7(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = entity8;
+ return XML_ROLE_ENTITY_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ENTITY_NONE;
+ return XML_ROLE_ENTITY_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity8(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity9;
+ return XML_ROLE_ENTITY_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity9(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = entity10;
+ return XML_ROLE_ENTITY_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+entity10(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ENTITY_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ENTITY_COMPLETE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation0(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ state->handler = notation1;
+ return XML_ROLE_NOTATION_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
+ state->handler = notation3;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
+ state->handler = notation2;
+ return XML_ROLE_NOTATION_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation2(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = notation4;
+ return XML_ROLE_NOTATION_PUBLIC_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation3(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+notation4(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NOTATION_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_NOTATION_NONE;
+ return XML_ROLE_NOTATION_SYSTEM_ID;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_NOTATION_NO_SYSTEM_ID;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist0(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist1;
+ return XML_ROLE_ATTLIST_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist1(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist2;
+ return XML_ROLE_ATTRIBUTE_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ {
+ static const char * const types[] = {
+ KW_CDATA,
+ KW_ID,
+ KW_IDREF,
+ KW_IDREFS,
+ KW_ENTITY,
+ KW_ENTITIES,
+ KW_NMTOKEN,
+ KW_NMTOKENS,
+ };
+ int i;
+ for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
+ if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
+ state->handler = attlist8;
+ return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
+ state->handler = attlist5;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist3(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NMTOKEN:
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = attlist4;
+ return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist4(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist3;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist5(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist6(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_NAME:
+ state->handler = attlist7;
+ return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist7(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = attlist8;
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_OR:
+ state->handler = attlist6;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ return common(state, tok);
+}
+
+/* default value */
+static int PTRCALL
+attlist8(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_IMPLIED)) {
+ state->handler = attlist1;
+ return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_REQUIRED)) {
+ state->handler = attlist1;
+ return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
+ }
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_FIXED)) {
+ state->handler = attlist9;
+ return XML_ROLE_ATTLIST_NONE;
+ }
+ break;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+attlist9(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ATTLIST_NONE;
+ case XML_TOK_LITERAL:
+ state->handler = attlist1;
+ return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element0(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element1;
+ return XML_ROLE_ELEMENT_NAME;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element1(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_EMPTY;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_CONTENT_ANY;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->handler = element2;
+ state->level = 1;
+ return XML_ROLE_GROUP_OPEN;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element2(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_POUND_NAME:
+ if (XmlNameMatchesAscii(enc,
+ ptr + MIN_BYTES_PER_CHAR(enc),
+ end,
+ KW_PCDATA)) {
+ state->handler = element3;
+ return XML_ROLE_CONTENT_PCDATA;
+ }
+ break;
+ case XML_TOK_OPEN_PAREN:
+ state->level = 2;
+ state->handler = element6;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element3(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element4(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element5;
+ return XML_ROLE_CONTENT_ELEMENT;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element5(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_OR:
+ state->handler = element4;
+ return XML_ROLE_ELEMENT_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element6(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_OPEN_PAREN:
+ state->level += 1;
+ return XML_ROLE_GROUP_OPEN;
+ case XML_TOK_NAME:
+ case XML_TOK_PREFIXED_NAME:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT;
+ case XML_TOK_NAME_QUESTION:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_OPT;
+ case XML_TOK_NAME_ASTERISK:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_REP;
+ case XML_TOK_NAME_PLUS:
+ state->handler = element7;
+ return XML_ROLE_CONTENT_ELEMENT_PLUS;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+element7(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_ELEMENT_NONE;
+ case XML_TOK_CLOSE_PAREN:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE;
+ case XML_TOK_CLOSE_PAREN_ASTERISK:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_REP;
+ case XML_TOK_CLOSE_PAREN_QUESTION:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_OPT;
+ case XML_TOK_CLOSE_PAREN_PLUS:
+ state->level -= 1;
+ if (state->level == 0) {
+ state->handler = declClose;
+ state->role_none = XML_ROLE_ELEMENT_NONE;
+ }
+ return XML_ROLE_GROUP_CLOSE_PLUS;
+ case XML_TOK_COMMA:
+ state->handler = element6;
+ return XML_ROLE_GROUP_SEQUENCE;
+ case XML_TOK_OR:
+ state->handler = element6;
+ return XML_ROLE_GROUP_CHOICE;
+ }
+ return common(state, tok);
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+condSect0(PROLOG_STATE *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc)
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_NAME:
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
+ state->handler = condSect1;
+ return XML_ROLE_NONE;
+ }
+ if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
+ state->handler = condSect2;
+ return XML_ROLE_NONE;
+ }
+ break;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect1(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ state->includeLevel += 1;
+ return XML_ROLE_NONE;
+ }
+ return common(state, tok);
+}
+
+static int PTRCALL
+condSect2(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return XML_ROLE_NONE;
+ case XML_TOK_OPEN_BRACKET:
+ state->handler = externalSubset1;
+ return XML_ROLE_IGNORE_SECT;
+ }
+ return common(state, tok);
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+declClose(PROLOG_STATE *state,
+ int tok,
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ switch (tok) {
+ case XML_TOK_PROLOG_S:
+ return state->role_none;
+ case XML_TOK_DECL_CLOSE:
+ setTopLevel(state);
+ return state->role_none;
+ }
+ return common(state, tok);
+}
+
+/* This function will only be invoked if the internal logic of the
+ * parser has broken down. It is used in two cases:
+ *
+ * 1: When the XML prolog has been finished. At this point the
+ * processor (the parser level above these role handlers) should
+ * switch from prologProcessor to contentProcessor and reinitialise
+ * the handler function.
+ *
+ * 2: When an error has been detected (via common() below). At this
+ * point again the processor should be switched to errorProcessor,
+ * which will never call a handler.
+ *
+ * The result of this is that error() can only be called if the
+ * processor switch failed to happen, which is an internal error and
+ * therefore we shouldn't be able to provoke it simply by using the
+ * library. It is a necessary backstop, however, so we merely exclude
+ * it from the coverage statistics.
+ *
+ * LCOV_EXCL_START
+ */
+static int PTRCALL
+error(PROLOG_STATE *UNUSED_P(state),
+ int UNUSED_P(tok),
+ const char *UNUSED_P(ptr),
+ const char *UNUSED_P(end),
+ const ENCODING *UNUSED_P(enc))
+{
+ return XML_ROLE_NONE;
+}
+/* LCOV_EXCL_STOP */
+
+static int FASTCALL
+common(PROLOG_STATE *state, int tok)
+{
+#ifdef XML_DTD
+ if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
+ return XML_ROLE_INNER_PARAM_ENTITY_REF;
+#endif
+ state->handler = error;
+ return XML_ROLE_ERROR;
+}
+
+void
+XmlPrologStateInit(PROLOG_STATE *state)
+{
+ state->handler = prolog0;
+#ifdef XML_DTD
+ state->documentEntity = 1;
+ state->includeLevel = 0;
+ state->inEntityValue = 0;
+#endif /* XML_DTD */
+}
+
+#ifdef XML_DTD
+
+void
+XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
+{
+ state->handler = externalSubset0;
+ state->documentEntity = 0;
+ state->includeLevel = 0;
+}
+
+#endif /* XML_DTD */
diff --git a/Utilities/cmexpat/lib/xmlrole.h b/Utilities/cmexpat/lib/xmlrole.h
new file mode 100644
index 000000000..4dd9f06f9
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmlrole.h
@@ -0,0 +1,114 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlRole_INCLUDED
+#define XmlRole_INCLUDED 1
+
+#ifdef __VMS
+/* 0 1 2 3 0 1 2 3
+ 1234567890123456789012345678901 1234567890123456789012345678901 */
+#define XmlPrologStateInitExternalEntity XmlPrologStateInitExternalEnt
+#endif
+
+#include "xmltok.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum {
+ XML_ROLE_ERROR = -1,
+ XML_ROLE_NONE = 0,
+ XML_ROLE_XML_DECL,
+ XML_ROLE_INSTANCE_START,
+ XML_ROLE_DOCTYPE_NONE,
+ XML_ROLE_DOCTYPE_NAME,
+ XML_ROLE_DOCTYPE_SYSTEM_ID,
+ XML_ROLE_DOCTYPE_PUBLIC_ID,
+ XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
+ XML_ROLE_DOCTYPE_CLOSE,
+ XML_ROLE_GENERAL_ENTITY_NAME,
+ XML_ROLE_PARAM_ENTITY_NAME,
+ XML_ROLE_ENTITY_NONE,
+ XML_ROLE_ENTITY_VALUE,
+ XML_ROLE_ENTITY_SYSTEM_ID,
+ XML_ROLE_ENTITY_PUBLIC_ID,
+ XML_ROLE_ENTITY_COMPLETE,
+ XML_ROLE_ENTITY_NOTATION_NAME,
+ XML_ROLE_NOTATION_NONE,
+ XML_ROLE_NOTATION_NAME,
+ XML_ROLE_NOTATION_SYSTEM_ID,
+ XML_ROLE_NOTATION_NO_SYSTEM_ID,
+ XML_ROLE_NOTATION_PUBLIC_ID,
+ XML_ROLE_ATTRIBUTE_NAME,
+ XML_ROLE_ATTRIBUTE_TYPE_CDATA,
+ XML_ROLE_ATTRIBUTE_TYPE_ID,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREF,
+ XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
+ XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
+ XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
+ XML_ROLE_ATTRIBUTE_ENUM_VALUE,
+ XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
+ XML_ROLE_ATTLIST_NONE,
+ XML_ROLE_ATTLIST_ELEMENT_NAME,
+ XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
+ XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
+ XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
+ XML_ROLE_FIXED_ATTRIBUTE_VALUE,
+ XML_ROLE_ELEMENT_NONE,
+ XML_ROLE_ELEMENT_NAME,
+ XML_ROLE_CONTENT_ANY,
+ XML_ROLE_CONTENT_EMPTY,
+ XML_ROLE_CONTENT_PCDATA,
+ XML_ROLE_GROUP_OPEN,
+ XML_ROLE_GROUP_CLOSE,
+ XML_ROLE_GROUP_CLOSE_REP,
+ XML_ROLE_GROUP_CLOSE_OPT,
+ XML_ROLE_GROUP_CLOSE_PLUS,
+ XML_ROLE_GROUP_CHOICE,
+ XML_ROLE_GROUP_SEQUENCE,
+ XML_ROLE_CONTENT_ELEMENT,
+ XML_ROLE_CONTENT_ELEMENT_REP,
+ XML_ROLE_CONTENT_ELEMENT_OPT,
+ XML_ROLE_CONTENT_ELEMENT_PLUS,
+ XML_ROLE_PI,
+ XML_ROLE_COMMENT,
+#ifdef XML_DTD
+ XML_ROLE_TEXT_DECL,
+ XML_ROLE_IGNORE_SECT,
+ XML_ROLE_INNER_PARAM_ENTITY_REF,
+#endif /* XML_DTD */
+ XML_ROLE_PARAM_ENTITY_REF
+};
+
+typedef struct prolog_state {
+ int (PTRCALL *handler) (struct prolog_state *state,
+ int tok,
+ const char *ptr,
+ const char *end,
+ const ENCODING *enc);
+ unsigned level;
+ int role_none;
+#ifdef XML_DTD
+ unsigned includeLevel;
+ int documentEntity;
+ int inEntityValue;
+#endif /* XML_DTD */
+} PROLOG_STATE;
+
+void XmlPrologStateInit(PROLOG_STATE *);
+#ifdef XML_DTD
+void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
+#endif /* XML_DTD */
+
+#define XmlTokenRole(state, tok, ptr, end, enc) \
+ (((state)->handler)(state, tok, ptr, end, enc))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlRole_INCLUDED */
diff --git a/Utilities/cmexpat/lib/xmltok.c b/Utilities/cmexpat/lib/xmltok.c
new file mode 100644
index 000000000..db4a5c8ca
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmltok.c
@@ -0,0 +1,1754 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include "winconfig.h"
+#else
+#ifdef HAVE_EXPAT_CONFIG_H
+#include <expat_config.h>
+#endif
+#endif /* ndef _WIN32 */
+
+#include "expat_external.h"
+#include "internal.h"
+#include "xmltok.h"
+#include "nametab.h"
+
+#ifdef XML_DTD
+#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
+#else
+#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
+#endif
+
+#define VTABLE1 \
+ { PREFIX(prologTok), PREFIX(contentTok), \
+ PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
+ { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
+ PREFIX(sameName), \
+ PREFIX(nameMatchesAscii), \
+ PREFIX(nameLength), \
+ PREFIX(skipS), \
+ PREFIX(getAtts), \
+ PREFIX(charRefNumber), \
+ PREFIX(predefinedEntityName), \
+ PREFIX(updatePosition), \
+ PREFIX(isPublicId)
+
+#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
+
+#define UCS2_GET_NAMING(pages, hi, lo) \
+ (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1u << ((lo) & 0x1F)))
+
+/* A 2 byte UTF-8 representation splits the characters 11 bits between
+ the bottom 5 and 6 bits of the bytes. We need 8 bits to index into
+ pages, 3 bits to add to that index and 5 bits to generate the mask.
+*/
+#define UTF8_GET_NAMING2(pages, byte) \
+ (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
+ + ((((byte)[0]) & 3) << 1) \
+ + ((((byte)[1]) >> 5) & 1)] \
+ & (1u << (((byte)[1]) & 0x1F)))
+
+/* A 3 byte UTF-8 representation splits the characters 16 bits between
+ the bottom 4, 6 and 6 bits of the bytes. We need 8 bits to index
+ into pages, 3 bits to add to that index and 5 bits to generate the
+ mask.
+*/
+#define UTF8_GET_NAMING3(pages, byte) \
+ (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
+ + ((((byte)[1]) >> 2) & 0xF)] \
+ << 3) \
+ + ((((byte)[1]) & 3) << 1) \
+ + ((((byte)[2]) >> 5) & 1)] \
+ & (1u << (((byte)[2]) & 0x1F)))
+
+#define UTF8_GET_NAMING(pages, p, n) \
+ ((n) == 2 \
+ ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
+ : ((n) == 3 \
+ ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
+ : 0))
+
+/* Detection of invalid UTF-8 sequences is based on Table 3.1B
+ of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
+ with the additional restriction of not allowing the Unicode
+ code points 0xFFFF and 0xFFFE (sequences EF,BF,BF and EF,BF,BE).
+ Implementation details:
+ (A & 0x80) == 0 means A < 0x80
+ and
+ (A & 0xC0) == 0xC0 means A > 0xBF
+*/
+
+#define UTF8_INVALID2(p) \
+ ((*p) < 0xC2 || ((p)[1] & 0x80) == 0 || ((p)[1] & 0xC0) == 0xC0)
+
+#define UTF8_INVALID3(p) \
+ (((p)[2] & 0x80) == 0 \
+ || \
+ ((*p) == 0xEF && (p)[1] == 0xBF \
+ ? \
+ (p)[2] > 0xBD \
+ : \
+ ((p)[2] & 0xC0) == 0xC0) \
+ || \
+ ((*p) == 0xE0 \
+ ? \
+ (p)[1] < 0xA0 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xED ? (p)[1] > 0x9F : ((p)[1] & 0xC0) == 0xC0)))
+
+#define UTF8_INVALID4(p) \
+ (((p)[3] & 0x80) == 0 || ((p)[3] & 0xC0) == 0xC0 \
+ || \
+ ((p)[2] & 0x80) == 0 || ((p)[2] & 0xC0) == 0xC0 \
+ || \
+ ((*p) == 0xF0 \
+ ? \
+ (p)[1] < 0x90 || ((p)[1] & 0xC0) == 0xC0 \
+ : \
+ ((p)[1] & 0x80) == 0 \
+ || \
+ ((*p) == 0xF4 ? (p)[1] > 0x8F : ((p)[1] & 0xC0) == 0xC0)))
+
+static int PTRFASTCALL
+isNever(const ENCODING *UNUSED_P(enc), const char *UNUSED_P(p))
+{
+ return 0;
+}
+
+static int PTRFASTCALL
+utf8_isName2(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isName3(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
+}
+
+#define utf8_isName4 isNever
+
+static int PTRFASTCALL
+utf8_isNmstrt2(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isNmstrt3(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
+}
+
+#define utf8_isNmstrt4 isNever
+
+static int PTRFASTCALL
+utf8_isInvalid2(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_INVALID2((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid3(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_INVALID3((const unsigned char *)p);
+}
+
+static int PTRFASTCALL
+utf8_isInvalid4(const ENCODING *UNUSED_P(enc), const char *p)
+{
+ return UTF8_INVALID4((const unsigned char *)p);
+}
+
+struct normal_encoding {
+ ENCODING enc;
+ unsigned char type[256];
+#ifdef XML_MIN_SIZE
+ int (PTRFASTCALL *byteType)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNameMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrtMin)(const ENCODING *, const char *);
+ int (PTRFASTCALL *byteToAscii)(const ENCODING *, const char *);
+ int (PTRCALL *charMatches)(const ENCODING *, const char *, int);
+#endif /* XML_MIN_SIZE */
+ int (PTRFASTCALL *isName2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isName4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isNmstrt4)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid2)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid3)(const ENCODING *, const char *);
+ int (PTRFASTCALL *isInvalid4)(const ENCODING *, const char *);
+};
+
+#define AS_NORMAL_ENCODING(enc) ((const struct normal_encoding *) (enc))
+
+#ifdef XML_MIN_SIZE
+
+#define STANDARD_VTABLE(E) \
+ E ## byteType, \
+ E ## isNameMin, \
+ E ## isNmstrtMin, \
+ E ## byteToAscii, \
+ E ## charMatches,
+
+#else
+
+#define STANDARD_VTABLE(E) /* as nothing */
+
+#endif
+
+#define NORMAL_VTABLE(E) \
+ E ## isName2, \
+ E ## isName3, \
+ E ## isName4, \
+ E ## isNmstrt2, \
+ E ## isNmstrt3, \
+ E ## isNmstrt4, \
+ E ## isInvalid2, \
+ E ## isInvalid3, \
+ E ## isInvalid4
+
+#define NULL_VTABLE \
+ /* isName2 */ NULL, \
+ /* isName3 */ NULL, \
+ /* isName4 */ NULL, \
+ /* isNmstrt2 */ NULL, \
+ /* isNmstrt3 */ NULL, \
+ /* isNmstrt4 */ NULL, \
+ /* isInvalid2 */ NULL, \
+ /* isInvalid3 */ NULL, \
+ /* isInvalid4 */ NULL
+
+static int FASTCALL checkCharRefNumber(int);
+
+#include "xmltok_impl.h"
+#include "ascii.h"
+
+#ifdef XML_MIN_SIZE
+#define sb_isNameMin isNever
+#define sb_isNmstrtMin isNever
+#endif
+
+#ifdef XML_MIN_SIZE
+#define MINBPC(enc) ((enc)->minBytesPerChar)
+#else
+/* minimum bytes per character */
+#define MINBPC(enc) 1
+#endif
+
+#define SB_BYTE_TYPE(enc, p) \
+ (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
+
+#ifdef XML_MIN_SIZE
+static int PTRFASTCALL
+sb_byteType(const ENCODING *enc, const char *p)
+{
+ return SB_BYTE_TYPE(enc, p);
+}
+#define BYTE_TYPE(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteType(enc, p))
+#else
+#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define BYTE_TO_ASCII(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->byteToAscii(enc, p))
+static int PTRFASTCALL
+sb_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return *p;
+}
+#else
+#define BYTE_TO_ASCII(enc, p) (*(p))
+#endif
+
+#define IS_NAME_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isName ## n(enc, p))
+#define IS_NMSTRT_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrt ## n(enc, p))
+#define IS_INVALID_CHAR(enc, p, n) \
+ (AS_NORMAL_ENCODING(enc)->isInvalid ## n(enc, p))
+
+#ifdef XML_MIN_SIZE
+#define IS_NAME_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNameMin(enc, p))
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ (AS_NORMAL_ENCODING(enc)->isNmstrtMin(enc, p))
+#else
+#define IS_NAME_CHAR_MINBPC(enc, p) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
+#endif
+
+#ifdef XML_MIN_SIZE
+#define CHAR_MATCHES(enc, p, c) \
+ (AS_NORMAL_ENCODING(enc)->charMatches(enc, p, c))
+static int PTRCALL
+sb_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return *p == c;
+}
+#else
+/* c is an ASCII character */
+#define CHAR_MATCHES(enc, p, c) (*(p) == c)
+#endif
+
+#define PREFIX(ident) normal_ ## ident
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
+ UTF8_cval1 = 0x00,
+ UTF8_cval2 = 0xc0,
+ UTF8_cval3 = 0xe0,
+ UTF8_cval4 = 0xf0
+};
+
+void
+align_limit_to_full_utf8_characters(const char * from, const char ** fromLimRef)
+{
+ const char * fromLim = *fromLimRef;
+ size_t walked = 0;
+ for (; fromLim > from; fromLim--, walked++) {
+ const unsigned char prev = (unsigned char)fromLim[-1];
+ if ((prev & 0xf8u) == 0xf0u) { /* 4-byte character, lead by 0b11110xxx byte */
+ if (walked + 1 >= 4) {
+ fromLim += 4 - 1;
+ break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0xf0u) == 0xe0u) { /* 3-byte character, lead by 0b1110xxxx byte */
+ if (walked + 1 >= 3) {
+ fromLim += 3 - 1;
+ break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0xe0u) == 0xc0u) { /* 2-byte character, lead by 0b110xxxxx byte */
+ if (walked + 1 >= 2) {
+ fromLim += 2 - 1;
+ break;
+ } else {
+ walked = 0;
+ }
+ } else if ((prev & 0x80u) == 0x00u) { /* 1-byte character, matching 0b0xxxxxxx */
+ break;
+ }
+ }
+ *fromLimRef = fromLim;
+}
+
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf8(const ENCODING *UNUSED_P(enc),
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ char *to;
+ const char *from;
+ const char *fromLimInitial = fromLim;
+
+ /* Avoid copying partial characters. */
+ align_limit_to_full_utf8_characters(*fromP, &fromLim);
+
+ for (to = *toP, from = *fromP; (from < fromLim) && (to < toLim); from++, to++)
+ *to = *from;
+ *fromP = from;
+ *toP = to;
+
+ if (fromLim < fromLimInitial)
+ return XML_CONVERT_INPUT_INCOMPLETE;
+ else if ((to == toLim) && (from < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
+}
+
+static enum XML_Convert_Result PTRCALL
+utf8_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ enum XML_Convert_Result res = XML_CONVERT_COMPLETED;
+ unsigned short *to = *toP;
+ const char *from = *fromP;
+ while (from < fromLim && to < toLim) {
+ switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
+ case BT_LEAD2:
+ if (fromLim - from < 2) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
+ *to++ = (unsigned short)(((from[0] & 0x1f) << 6) | (from[1] & 0x3f));
+ from += 2;
+ break;
+ case BT_LEAD3:
+ if (fromLim - from < 3) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
+ *to++ = (unsigned short)(((from[0] & 0xf) << 12)
+ | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f));
+ from += 3;
+ break;
+ case BT_LEAD4:
+ {
+ unsigned long n;
+ if (toLim - to < 2) {
+ res = XML_CONVERT_OUTPUT_EXHAUSTED;
+ goto after;
+ }
+ if (fromLim - from < 4) {
+ res = XML_CONVERT_INPUT_INCOMPLETE;
+ goto after;
+ }
+ n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12)
+ | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
+ n -= 0x10000;
+ to[0] = (unsigned short)((n >> 10) | 0xD800);
+ to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
+ to += 2;
+ from += 4;
+ }
+ break;
+ default:
+ *to++ = *from++;
+ break;
+ }
+ }
+ if (from < fromLim)
+ res = XML_CONVERT_OUTPUT_EXHAUSTED;
+after:
+ *fromP = from;
+ *toP = to;
+ return res;
+}
+
+#ifdef XML_NS
+static const struct normal_encoding utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+#endif
+
+static const struct normal_encoding utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_utf8_encoding_ns = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#include "iasciitab.h"
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+#endif
+
+static const struct normal_encoding internal_utf8_encoding = {
+ { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "utf8tab.h"
+ },
+ STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
+};
+
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf8(const ENCODING *UNUSED_P(enc),
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ for (;;) {
+ unsigned char c;
+ if (*fromP == fromLim)
+ return XML_CONVERT_COMPLETED;
+ c = (unsigned char)**fromP;
+ if (c & 0x80) {
+ if (toLim - *toP < 2)
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ *(*toP)++ = (char)((c >> 6) | UTF8_cval2);
+ *(*toP)++ = (char)((c & 0x3f) | 0x80);
+ (*fromP)++;
+ }
+ else {
+ if (*toP == toLim)
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ *(*toP)++ = *(*fromP)++;
+ }
+ }
+}
+
+static enum XML_Convert_Result PTRCALL
+latin1_toUtf16(const ENCODING *UNUSED_P(enc),
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ while (*fromP < fromLim && *toP < toLim)
+ *(*toP)++ = (unsigned char)*(*fromP)++;
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding latin1_encoding_ns = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding latin1_encoding = {
+ { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE
+};
+
+static enum XML_Convert_Result PTRCALL
+ascii_toUtf8(const ENCODING *UNUSED_P(enc),
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ while (*fromP < fromLim && *toP < toLim)
+ *(*toP)++ = *(*fromP)++;
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
+}
+
+#ifdef XML_NS
+
+static const struct normal_encoding ascii_encoding_ns = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#include "asciitab.h"
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding ascii_encoding = {
+ { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+/* BT_NONXML == 0 */
+ },
+ STANDARD_VTABLE(sb_) NULL_VTABLE
+};
+
+static int PTRFASTCALL
+unicode_byte_type(char hi, char lo)
+{
+ switch ((unsigned char)hi) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ return BT_LEAD4;
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return BT_TRAIL;
+ case 0xFF:
+ switch ((unsigned char)lo) {
+ case 0xFF:
+ case 0xFE:
+ return BT_NONXML;
+ }
+ break;
+ }
+ return BT_NONASCII;
+}
+
+#define DEFINE_UTF16_TO_UTF8(E) \
+static enum XML_Convert_Result PTRCALL \
+E ## toUtf8(const ENCODING *UNUSED_P(enc), \
+ const char **fromP, const char *fromLim, \
+ char **toP, const char *toLim) \
+{ \
+ const char *from = *fromP; \
+ fromLim = from + (((fromLim - from) >> 1) << 1); /* shrink to even */ \
+ for (; from < fromLim; from += 2) { \
+ int plane; \
+ unsigned char lo2; \
+ unsigned char lo = GET_LO(from); \
+ unsigned char hi = GET_HI(from); \
+ switch (hi) { \
+ case 0: \
+ if (lo < 0x80) { \
+ if (*toP == toLim) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ *(*toP)++ = lo; \
+ break; \
+ } \
+ /* fall through */ \
+ case 0x1: case 0x2: case 0x3: \
+ case 0x4: case 0x5: case 0x6: case 0x7: \
+ if (toLim - *toP < 2) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ default: \
+ if (toLim - *toP < 3) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
+ *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
+ *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
+ *(*toP)++ = ((lo & 0x3f) | 0x80); \
+ break; \
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
+ if (toLim - *toP < 4) { \
+ *fromP = from; \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ } \
+ if (fromLim - from < 4) { \
+ *fromP = from; \
+ return XML_CONVERT_INPUT_INCOMPLETE; \
+ } \
+ plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
+ *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
+ *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
+ from += 2; \
+ lo2 = GET_LO(from); \
+ *(*toP)++ = (((lo & 0x3) << 4) \
+ | ((GET_HI(from) & 0x3) << 2) \
+ | (lo2 >> 6) \
+ | 0x80); \
+ *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
+ break; \
+ } \
+ } \
+ *fromP = from; \
+ if (from < fromLim) \
+ return XML_CONVERT_INPUT_INCOMPLETE; \
+ else \
+ return XML_CONVERT_COMPLETED; \
+}
+
+#define DEFINE_UTF16_TO_UTF16(E) \
+static enum XML_Convert_Result PTRCALL \
+E ## toUtf16(const ENCODING *UNUSED_P(enc), \
+ const char **fromP, const char *fromLim, \
+ unsigned short **toP, const unsigned short *toLim) \
+{ \
+ enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
+ fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \
+ /* Avoid copying first half only of surrogate */ \
+ if (fromLim - *fromP > ((toLim - *toP) << 1) \
+ && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
+ fromLim -= 2; \
+ res = XML_CONVERT_INPUT_INCOMPLETE; \
+ } \
+ for (; *fromP < fromLim && *toP < toLim; *fromP += 2) \
+ *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
+ if ((*toP == toLim) && (*fromP < fromLim)) \
+ return XML_CONVERT_OUTPUT_EXHAUSTED; \
+ else \
+ return res; \
+}
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[0])
+#define GET_HI(ptr) ((unsigned char)(ptr)[1])
+
+DEFINE_UTF16_TO_UTF8(little2_)
+DEFINE_UTF16_TO_UTF16(little2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define SET2(ptr, ch) \
+ (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
+#define GET_LO(ptr) ((unsigned char)(ptr)[1])
+#define GET_HI(ptr) ((unsigned char)(ptr)[0])
+
+DEFINE_UTF16_TO_UTF8(big2_)
+DEFINE_UTF16_TO_UTF16(big2_)
+
+#undef SET2
+#undef GET_LO
+#undef GET_HI
+
+#define LITTLE2_BYTE_TYPE(enc, p) \
+ ((p)[1] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
+ : unicode_byte_type((p)[1], (p)[0]))
+#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
+#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
+#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
+#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+little2_byteType(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+little2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+little2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return LITTLE2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+little2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+little2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) little2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding little2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding little2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 1234
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE
+};
+
+#if BYTEORDER != 4321
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_little2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding internal_little2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(little2_) NULL_VTABLE
+};
+
+#endif
+
+
+#define BIG2_BYTE_TYPE(enc, p) \
+ ((p)[0] == 0 \
+ ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
+ : unicode_byte_type((p)[0], (p)[1]))
+#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
+#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
+#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
+#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
+ UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
+
+#ifdef XML_MIN_SIZE
+
+static int PTRFASTCALL
+big2_byteType(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TYPE(enc, p);
+}
+
+static int PTRFASTCALL
+big2_byteToAscii(const ENCODING *enc, const char *p)
+{
+ return BIG2_BYTE_TO_ASCII(enc, p);
+}
+
+static int PTRCALL
+big2_charMatches(const ENCODING *enc, const char *p, int c)
+{
+ return BIG2_CHAR_MATCHES(enc, p, c);
+}
+
+static int PTRFASTCALL
+big2_isNameMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
+}
+
+static int PTRFASTCALL
+big2_isNmstrtMin(const ENCODING *enc, const char *p)
+{
+ return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
+}
+
+#undef VTABLE
+#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
+
+#else /* not XML_MIN_SIZE */
+
+#undef PREFIX
+#define PREFIX(ident) big2_ ## ident
+#define MINBPC(enc) 2
+/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
+#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
+#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
+#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
+#define IS_NAME_CHAR(enc, p, n) 0
+#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
+#define IS_NMSTRT_CHAR(enc, p, n) (0)
+#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
+
+#define XML_TOK_IMPL_C
+#include "xmltok_impl.c"
+#undef XML_TOK_IMPL_C
+
+#undef MINBPC
+#undef BYTE_TYPE
+#undef BYTE_TO_ASCII
+#undef CHAR_MATCHES
+#undef IS_NAME_CHAR
+#undef IS_NAME_CHAR_MINBPC
+#undef IS_NMSTRT_CHAR
+#undef IS_NMSTRT_CHAR_MINBPC
+#undef IS_INVALID_CHAR
+
+#endif /* not XML_MIN_SIZE */
+
+#ifdef XML_NS
+
+static const struct normal_encoding big2_encoding_ns = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#include "asciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding big2_encoding = {
+ { VTABLE, 2, 0,
+#if BYTEORDER == 4321
+ 1
+#else
+ 0
+#endif
+ },
+ {
+#define BT_COLON BT_NMSTRT
+#include "asciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE
+};
+
+#if BYTEORDER != 1234
+
+#ifdef XML_NS
+
+static const struct normal_encoding internal_big2_encoding_ns = {
+ { VTABLE, 2, 0, 1 },
+ {
+#include "iasciitab.h"
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE
+};
+
+#endif
+
+static const struct normal_encoding internal_big2_encoding = {
+ { VTABLE, 2, 0, 1 },
+ {
+#define BT_COLON BT_NMSTRT
+#include "iasciitab.h"
+#undef BT_COLON
+#include "latin1tab.h"
+ },
+ STANDARD_VTABLE(big2_) NULL_VTABLE
+};
+
+#endif
+
+#undef PREFIX
+
+static int FASTCALL
+streqci(const char *s1, const char *s2)
+{
+ for (;;) {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if (ASCII_a <= c1 && c1 <= ASCII_z)
+ c1 += ASCII_A - ASCII_a;
+ if (ASCII_a <= c2 && c2 <= ASCII_z)
+ /* The following line will never get executed. streqci() is
+ * only called from two places, both of which guarantee to put
+ * upper-case strings into s2.
+ */
+ c2 += ASCII_A - ASCII_a; /* LCOV_EXCL_LINE */
+ if (c1 != c2)
+ return 0;
+ if (!c1)
+ break;
+ }
+ return 1;
+}
+
+static void PTRCALL
+initUpdatePosition(const ENCODING *UNUSED_P(enc), const char *ptr,
+ const char *end, POSITION *pos)
+{
+ normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
+}
+
+static int
+toAscii(const ENCODING *enc, const char *ptr, const char *end)
+{
+ char buf[1];
+ char *p = buf;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
+ if (p == buf)
+ return -1;
+ else
+ return buf[0];
+}
+
+static int FASTCALL
+isSpace(int c)
+{
+ switch (c) {
+ case 0x20:
+ case 0xD:
+ case 0xA:
+ case 0x9:
+ return 1;
+ }
+ return 0;
+}
+
+/* Return 1 if there's just optional white space or there's an S
+ followed by name=val.
+*/
+static int
+parsePseudoAttribute(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **namePtr,
+ const char **nameEndPtr,
+ const char **valPtr,
+ const char **nextTokPtr)
+{
+ int c;
+ char open;
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ if (!isSpace(toAscii(enc, ptr, end))) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(toAscii(enc, ptr, end)));
+ if (ptr == end) {
+ *namePtr = NULL;
+ return 1;
+ }
+ *namePtr = ptr;
+ for (;;) {
+ c = toAscii(enc, ptr, end);
+ if (c == -1) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ if (c == ASCII_EQUALS) {
+ *nameEndPtr = ptr;
+ break;
+ }
+ if (isSpace(c)) {
+ *nameEndPtr = ptr;
+ do {
+ ptr += enc->minBytesPerChar;
+ } while (isSpace(c = toAscii(enc, ptr, end)));
+ if (c != ASCII_EQUALS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ ptr += enc->minBytesPerChar;
+ }
+ if (ptr == *namePtr) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ while (isSpace(c)) {
+ ptr += enc->minBytesPerChar;
+ c = toAscii(enc, ptr, end);
+ }
+ if (c != ASCII_QUOT && c != ASCII_APOS) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ open = (char)c;
+ ptr += enc->minBytesPerChar;
+ *valPtr = ptr;
+ for (;; ptr += enc->minBytesPerChar) {
+ c = toAscii(enc, ptr, end);
+ if (c == open)
+ break;
+ if (!(ASCII_a <= c && c <= ASCII_z)
+ && !(ASCII_A <= c && c <= ASCII_Z)
+ && !(ASCII_0 <= c && c <= ASCII_9)
+ && c != ASCII_PERIOD
+ && c != ASCII_MINUS
+ && c != ASCII_UNDERSCORE) {
+ *nextTokPtr = ptr;
+ return 0;
+ }
+ }
+ *nextTokPtr = ptr + enc->minBytesPerChar;
+ return 1;
+}
+
+static const char KW_version[] = {
+ ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
+};
+
+static const char KW_encoding[] = {
+ ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
+};
+
+static const char KW_standalone[] = {
+ ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o,
+ ASCII_n, ASCII_e, '\0'
+};
+
+static const char KW_yes[] = {
+ ASCII_y, ASCII_e, ASCII_s, '\0'
+};
+
+static const char KW_no[] = {
+ ASCII_n, ASCII_o, '\0'
+};
+
+static int
+doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
+ const char *,
+ const char *),
+ int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ const char *val = NULL;
+ const char *name = NULL;
+ const char *nameEnd = NULL;
+ ptr += 5 * enc->minBytesPerChar;
+ end -= 2 * enc->minBytesPerChar;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)
+ || !name) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
+ if (!isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ }
+ else {
+ if (versionPtr)
+ *versionPtr = val;
+ if (versionEndPtr)
+ *versionEndPtr = ptr;
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name) {
+ if (isGeneralTextEntity) {
+ /* a TextDecl must have an EncodingDecl */
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+ }
+ }
+ if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
+ int c = toAscii(enc, val, end);
+ if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
+ *badPtr = val;
+ return 0;
+ }
+ if (encodingName)
+ *encodingName = val;
+ if (encoding)
+ *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
+ if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ if (!name)
+ return 1;
+ }
+ if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone)
+ || isGeneralTextEntity) {
+ *badPtr = name;
+ return 0;
+ }
+ if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
+ if (standalone)
+ *standalone = 1;
+ }
+ else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
+ if (standalone)
+ *standalone = 0;
+ }
+ else {
+ *badPtr = val;
+ return 0;
+ }
+ while (isSpace(toAscii(enc, ptr, end)))
+ ptr += enc->minBytesPerChar;
+ if (ptr != end) {
+ *badPtr = ptr;
+ return 0;
+ }
+ return 1;
+}
+
+static int FASTCALL
+checkCharRefNumber(int result)
+{
+ switch (result >> 8) {
+ case 0xD8: case 0xD9: case 0xDA: case 0xDB:
+ case 0xDC: case 0xDD: case 0xDE: case 0xDF:
+ return -1;
+ case 0:
+ if (latin1_encoding.type[result] == BT_NONXML)
+ return -1;
+ break;
+ case 0xFF:
+ if (result == 0xFFFE || result == 0xFFFF)
+ return -1;
+ break;
+ }
+ return result;
+}
+
+int FASTCALL
+XmlUtf8Encode(int c, char *buf)
+{
+ enum {
+ /* minN is minimum legal resulting value for N byte sequence */
+ min2 = 0x80,
+ min3 = 0x800,
+ min4 = 0x10000
+ };
+
+ if (c < 0)
+ return 0; /* LCOV_EXCL_LINE: this case is always eliminated beforehand */
+ if (c < min2) {
+ buf[0] = (char)(c | UTF8_cval1);
+ return 1;
+ }
+ if (c < min3) {
+ buf[0] = (char)((c >> 6) | UTF8_cval2);
+ buf[1] = (char)((c & 0x3f) | 0x80);
+ return 2;
+ }
+ if (c < min4) {
+ buf[0] = (char)((c >> 12) | UTF8_cval3);
+ buf[1] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[2] = (char)((c & 0x3f) | 0x80);
+ return 3;
+ }
+ if (c < 0x110000) {
+ buf[0] = (char)((c >> 18) | UTF8_cval4);
+ buf[1] = (char)(((c >> 12) & 0x3f) | 0x80);
+ buf[2] = (char)(((c >> 6) & 0x3f) | 0x80);
+ buf[3] = (char)((c & 0x3f) | 0x80);
+ return 4;
+ }
+ return 0; /* LCOV_EXCL_LINE: this case too is eliminated before calling */
+}
+
+int FASTCALL
+XmlUtf16Encode(int charNum, unsigned short *buf)
+{
+ if (charNum < 0)
+ return 0;
+ if (charNum < 0x10000) {
+ buf[0] = (unsigned short)charNum;
+ return 1;
+ }
+ if (charNum < 0x110000) {
+ charNum -= 0x10000;
+ buf[0] = (unsigned short)((charNum >> 10) + 0xD800);
+ buf[1] = (unsigned short)((charNum & 0x3FF) + 0xDC00);
+ return 2;
+ }
+ return 0;
+}
+
+struct unknown_encoding {
+ struct normal_encoding normal;
+ CONVERTER convert;
+ void *userData;
+ unsigned short utf16[256];
+ char utf8[256][4];
+};
+
+#define AS_UNKNOWN_ENCODING(enc) ((const struct unknown_encoding *) (enc))
+
+int
+XmlSizeOfUnknownEncoding(void)
+{
+ return sizeof(struct unknown_encoding);
+}
+
+static int PTRFASTCALL
+unknown_isName(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isNmstrt(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ if (c & ~0xFFFF)
+ return 0;
+ return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
+}
+
+static int PTRFASTCALL
+unknown_isInvalid(const ENCODING *enc, const char *p)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ int c = uenc->convert(uenc->userData, p);
+ return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
+}
+
+static enum XML_Convert_Result PTRCALL
+unknown_toUtf8(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ char **toP, const char *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ char buf[XML_UTF8_ENCODE_MAX];
+ for (;;) {
+ const char *utf8;
+ int n;
+ if (*fromP == fromLim)
+ return XML_CONVERT_COMPLETED;
+ utf8 = uenc->utf8[(unsigned char)**fromP];
+ n = *utf8++;
+ if (n == 0) {
+ int c = uenc->convert(uenc->userData, *fromP);
+ n = XmlUtf8Encode(c, buf);
+ if (n > toLim - *toP)
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ utf8 = buf;
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else {
+ if (n > toLim - *toP)
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ (*fromP)++;
+ }
+ do {
+ *(*toP)++ = *utf8++;
+ } while (--n != 0);
+ }
+}
+
+static enum XML_Convert_Result PTRCALL
+unknown_toUtf16(const ENCODING *enc,
+ const char **fromP, const char *fromLim,
+ unsigned short **toP, const unsigned short *toLim)
+{
+ const struct unknown_encoding *uenc = AS_UNKNOWN_ENCODING(enc);
+ while (*fromP < fromLim && *toP < toLim) {
+ unsigned short c = uenc->utf16[(unsigned char)**fromP];
+ if (c == 0) {
+ c = (unsigned short)
+ uenc->convert(uenc->userData, *fromP);
+ *fromP += (AS_NORMAL_ENCODING(enc)->type[(unsigned char)**fromP]
+ - (BT_LEAD2 - 2));
+ }
+ else
+ (*fromP)++;
+ *(*toP)++ = c;
+ }
+
+ if ((*toP == toLim) && (*fromP < fromLim))
+ return XML_CONVERT_OUTPUT_EXHAUSTED;
+ else
+ return XML_CONVERT_COMPLETED;
+}
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ int i;
+ struct unknown_encoding *e = (struct unknown_encoding *)mem;
+ for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
+ ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
+ for (i = 0; i < 128; i++)
+ if (latin1_encoding.type[i] != BT_OTHER
+ && latin1_encoding.type[i] != BT_NONXML
+ && table[i] != i)
+ return 0;
+ for (i = 0; i < 256; i++) {
+ int c = table[i];
+ if (c == -1) {
+ e->normal.type[i] = BT_MALFORM;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else if (c < 0) {
+ if (c < -4)
+ return 0;
+ /* Multi-byte sequences need a converter function */
+ if (!convert)
+ return 0;
+ e->normal.type[i] = (unsigned char)(BT_LEAD2 - (c + 2));
+ e->utf8[i][0] = 0;
+ e->utf16[i] = 0;
+ }
+ else if (c < 0x80) {
+ if (latin1_encoding.type[c] != BT_OTHER
+ && latin1_encoding.type[c] != BT_NONXML
+ && c != i)
+ return 0;
+ e->normal.type[i] = latin1_encoding.type[c];
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = (char)c;
+ e->utf16[i] = (unsigned short)(c == 0 ? 0xFFFF : c);
+ }
+ else if (checkCharRefNumber(c) < 0) {
+ e->normal.type[i] = BT_NONXML;
+ /* This shouldn't really get used. */
+ e->utf16[i] = 0xFFFF;
+ e->utf8[i][0] = 1;
+ e->utf8[i][1] = 0;
+ }
+ else {
+ if (c > 0xFFFF)
+ return 0;
+ if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NMSTRT;
+ else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
+ e->normal.type[i] = BT_NAME;
+ else
+ e->normal.type[i] = BT_OTHER;
+ e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
+ e->utf16[i] = (unsigned short)c;
+ }
+ }
+ e->userData = userData;
+ e->convert = convert;
+ if (convert) {
+ e->normal.isName2 = unknown_isName;
+ e->normal.isName3 = unknown_isName;
+ e->normal.isName4 = unknown_isName;
+ e->normal.isNmstrt2 = unknown_isNmstrt;
+ e->normal.isNmstrt3 = unknown_isNmstrt;
+ e->normal.isNmstrt4 = unknown_isNmstrt;
+ e->normal.isInvalid2 = unknown_isInvalid;
+ e->normal.isInvalid3 = unknown_isInvalid;
+ e->normal.isInvalid4 = unknown_isInvalid;
+ }
+ e->normal.enc.utf8Convert = unknown_toUtf8;
+ e->normal.enc.utf16Convert = unknown_toUtf16;
+ return &(e->normal.enc);
+}
+
+/* If this enumeration is changed, getEncodingIndex and encodings
+must also be changed. */
+enum {
+ UNKNOWN_ENC = -1,
+ ISO_8859_1_ENC = 0,
+ US_ASCII_ENC,
+ UTF_8_ENC,
+ UTF_16_ENC,
+ UTF_16BE_ENC,
+ UTF_16LE_ENC,
+ /* must match encodingNames up to here */
+ NO_ENC
+};
+
+static const char KW_ISO_8859_1[] = {
+ ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9,
+ ASCII_MINUS, ASCII_1, '\0'
+};
+static const char KW_US_ASCII[] = {
+ ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I,
+ '\0'
+};
+static const char KW_UTF_8[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
+};
+static const char KW_UTF_16[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
+};
+static const char KW_UTF_16BE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E,
+ '\0'
+};
+static const char KW_UTF_16LE[] = {
+ ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E,
+ '\0'
+};
+
+static int FASTCALL
+getEncodingIndex(const char *name)
+{
+ static const char * const encodingNames[] = {
+ KW_ISO_8859_1,
+ KW_US_ASCII,
+ KW_UTF_8,
+ KW_UTF_16,
+ KW_UTF_16BE,
+ KW_UTF_16LE,
+ };
+ int i;
+ if (name == NULL)
+ return NO_ENC;
+ for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
+ if (streqci(name, encodingNames[i]))
+ return i;
+ return UNKNOWN_ENC;
+}
+
+/* For binary compatibility, we store the index of the encoding
+ specified at initialization in the isUtf16 member.
+*/
+
+#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
+#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
+
+/* This is what detects the encoding. encodingTable maps from
+ encoding indices to encodings; INIT_ENC_INDEX(enc) is the index of
+ the external (protocol) specified encoding; state is
+ XML_CONTENT_STATE if we're parsing an external text entity, and
+ XML_PROLOG_STATE otherwise.
+*/
+
+
+static int
+initScan(const ENCODING * const *encodingTable,
+ const INIT_ENCODING *enc,
+ int state,
+ const char *ptr,
+ const char *end,
+ const char **nextTokPtr)
+{
+ const ENCODING **encPtr;
+
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ encPtr = enc->encPtr;
+ if (ptr + 1 == end) {
+ /* only a single byte available for auto-detection */
+#ifndef XML_DTD /* FIXME */
+ /* a well-formed document entity must have more than one byte */
+ if (state != XML_CONTENT_STATE)
+ return XML_TOK_PARTIAL;
+#endif
+ /* so we're parsing an external text entity... */
+ /* if UTF-16 was externally specified, then we need at least 2 bytes */
+ switch (INIT_ENC_INDEX(enc)) {
+ case UTF_16_ENC:
+ case UTF_16LE_ENC:
+ case UTF_16BE_ENC:
+ return XML_TOK_PARTIAL;
+ }
+ switch ((unsigned char)*ptr) {
+ case 0xFE:
+ case 0xFF:
+ case 0xEF: /* possibly first byte of UTF-8 BOM */
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ /* fall through */
+ case 0x00:
+ case 0x3C:
+ return XML_TOK_PARTIAL;
+ }
+ }
+ else {
+ switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
+ case 0xFEFF:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XML_TOK_BOM;
+ /* 00 3C is handled in the default case */
+ case 0x3C00:
+ if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
+ || INIT_ENC_INDEX(enc) == UTF_16_ENC)
+ && state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ case 0xFFFE:
+ if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
+ && state == XML_CONTENT_STATE)
+ break;
+ *nextTokPtr = ptr + 2;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XML_TOK_BOM;
+ case 0xEFBB:
+ /* Maybe a UTF-8 BOM (EF BB BF) */
+ /* If there's an explicitly specified (external) encoding
+ of ISO-8859-1 or some flavour of UTF-16
+ and this is an external text entity,
+ don't look for the BOM,
+ because it might be a legal data.
+ */
+ if (state == XML_CONTENT_STATE) {
+ int e = INIT_ENC_INDEX(enc);
+ if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC
+ || e == UTF_16LE_ENC || e == UTF_16_ENC)
+ break;
+ }
+ if (ptr + 2 == end)
+ return XML_TOK_PARTIAL;
+ if ((unsigned char)ptr[2] == 0xBF) {
+ *nextTokPtr = ptr + 3;
+ *encPtr = encodingTable[UTF_8_ENC];
+ return XML_TOK_BOM;
+ }
+ break;
+ default:
+ if (ptr[0] == '\0') {
+ /* 0 isn't a legal data character. Furthermore a document
+ entity can only start with ASCII characters. So the only
+ way this can fail to be big-endian UTF-16 if it it's an
+ external parsed general entity that's labelled as
+ UTF-16LE.
+ */
+ if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
+ break;
+ *encPtr = encodingTable[UTF_16BE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ else if (ptr[1] == '\0') {
+ /* We could recover here in the case:
+ - parsing an external entity
+ - second byte is 0
+ - no externally specified encoding
+ - no encoding declaration
+ by assuming UTF-16LE. But we don't, because this would mean when
+ presented just with a single byte, we couldn't reliably determine
+ whether we needed further bytes.
+ */
+ if (state == XML_CONTENT_STATE)
+ break;
+ *encPtr = encodingTable[UTF_16LE_ENC];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+ }
+ break;
+ }
+ }
+ *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
+ return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
+}
+
+
+#define NS(x) x
+#define ns(x) x
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+#undef NS
+#undef ns
+
+#ifdef XML_NS
+
+#define NS(x) x ## NS
+#define ns(x) x ## _ns
+
+#define XML_TOK_NS_C
+#include "xmltok_ns.c"
+#undef XML_TOK_NS_C
+
+#undef NS
+#undef ns
+
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData)
+{
+ ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
+ if (enc)
+ ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
+ return enc;
+}
+
+#endif /* XML_NS */
diff --git a/Utilities/cmexpat/lib/xmltok.h b/Utilities/cmexpat/lib/xmltok.h
new file mode 100644
index 000000000..752007e8b
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmltok.h
@@ -0,0 +1,322 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+#ifndef XmlTok_INCLUDED
+#define XmlTok_INCLUDED 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The following token may be returned by XmlContentTok */
+#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be
+ start of illegal ]]> sequence */
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_NONE -4 /* The string to be scanned is empty */
+#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
+ might be part of CRLF sequence */
+#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
+#define XML_TOK_PARTIAL -1 /* only part of a token */
+#define XML_TOK_INVALID 0
+
+/* The following tokens are returned by XmlContentTok; some are also
+ returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok.
+*/
+#define XML_TOK_START_TAG_WITH_ATTS 1
+#define XML_TOK_START_TAG_NO_ATTS 2
+#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
+#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
+#define XML_TOK_END_TAG 5
+#define XML_TOK_DATA_CHARS 6
+#define XML_TOK_DATA_NEWLINE 7
+#define XML_TOK_CDATA_SECT_OPEN 8
+#define XML_TOK_ENTITY_REF 9
+#define XML_TOK_CHAR_REF 10 /* numeric character reference */
+
+/* The following tokens may be returned by both XmlPrologTok and
+ XmlContentTok.
+*/
+#define XML_TOK_PI 11 /* processing instruction */
+#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
+#define XML_TOK_COMMENT 13
+#define XML_TOK_BOM 14 /* Byte order mark */
+
+/* The following tokens are returned only by XmlPrologTok */
+#define XML_TOK_PROLOG_S 15
+#define XML_TOK_DECL_OPEN 16 /* <!foo */
+#define XML_TOK_DECL_CLOSE 17 /* > */
+#define XML_TOK_NAME 18
+#define XML_TOK_NMTOKEN 19
+#define XML_TOK_POUND_NAME 20 /* #name */
+#define XML_TOK_OR 21 /* | */
+#define XML_TOK_PERCENT 22
+#define XML_TOK_OPEN_PAREN 23
+#define XML_TOK_CLOSE_PAREN 24
+#define XML_TOK_OPEN_BRACKET 25
+#define XML_TOK_CLOSE_BRACKET 26
+#define XML_TOK_LITERAL 27
+#define XML_TOK_PARAM_ENTITY_REF 28
+#define XML_TOK_INSTANCE_START 29
+
+/* The following occur only in element type declarations */
+#define XML_TOK_NAME_QUESTION 30 /* name? */
+#define XML_TOK_NAME_ASTERISK 31 /* name* */
+#define XML_TOK_NAME_PLUS 32 /* name+ */
+#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
+#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
+#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
+#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
+#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
+#define XML_TOK_COMMA 38
+
+/* The following token is returned only by XmlAttributeValueTok */
+#define XML_TOK_ATTRIBUTE_VALUE_S 39
+
+/* The following token is returned only by XmlCdataSectionTok */
+#define XML_TOK_CDATA_SECT_CLOSE 40
+
+/* With namespace processing this is returned by XmlPrologTok for a
+ name with a colon.
+*/
+#define XML_TOK_PREFIXED_NAME 41
+
+#ifdef XML_DTD
+#define XML_TOK_IGNORE_SECT 42
+#endif /* XML_DTD */
+
+#ifdef XML_DTD
+#define XML_N_STATES 4
+#else /* not XML_DTD */
+#define XML_N_STATES 3
+#endif /* not XML_DTD */
+
+#define XML_PROLOG_STATE 0
+#define XML_CONTENT_STATE 1
+#define XML_CDATA_SECTION_STATE 2
+#ifdef XML_DTD
+#define XML_IGNORE_SECTION_STATE 3
+#endif /* XML_DTD */
+
+#define XML_N_LITERAL_TYPES 2
+#define XML_ATTRIBUTE_VALUE_LITERAL 0
+#define XML_ENTITY_VALUE_LITERAL 1
+
+/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
+#define XML_UTF8_ENCODE_MAX 4
+/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
+#define XML_UTF16_ENCODE_MAX 2
+
+typedef struct position {
+ /* first line and first column are 0 not 1 */
+ XML_Size lineNumber;
+ XML_Size columnNumber;
+} POSITION;
+
+typedef struct {
+ const char *name;
+ const char *valuePtr;
+ const char *valueEnd;
+ char normalized;
+} ATTRIBUTE;
+
+struct encoding;
+typedef struct encoding ENCODING;
+
+typedef int (PTRCALL *SCANNER)(const ENCODING *,
+ const char *,
+ const char *,
+ const char **);
+
+enum XML_Convert_Result {
+ XML_CONVERT_COMPLETED = 0,
+ XML_CONVERT_INPUT_INCOMPLETE = 1,
+ XML_CONVERT_OUTPUT_EXHAUSTED = 2 /* and therefore potentially input remaining as well */
+};
+
+struct encoding {
+ SCANNER scanners[XML_N_STATES];
+ SCANNER literalScanners[XML_N_LITERAL_TYPES];
+ int (PTRCALL *sameName)(const ENCODING *,
+ const char *,
+ const char *);
+ int (PTRCALL *nameMatchesAscii)(const ENCODING *,
+ const char *,
+ const char *,
+ const char *);
+ int (PTRFASTCALL *nameLength)(const ENCODING *, const char *);
+ const char *(PTRFASTCALL *skipS)(const ENCODING *, const char *);
+ int (PTRCALL *getAtts)(const ENCODING *enc,
+ const char *ptr,
+ int attsMax,
+ ATTRIBUTE *atts);
+ int (PTRFASTCALL *charRefNumber)(const ENCODING *enc, const char *ptr);
+ int (PTRCALL *predefinedEntityName)(const ENCODING *,
+ const char *,
+ const char *);
+ void (PTRCALL *updatePosition)(const ENCODING *,
+ const char *ptr,
+ const char *end,
+ POSITION *);
+ int (PTRCALL *isPublicId)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr);
+ enum XML_Convert_Result (PTRCALL *utf8Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ char **toP,
+ const char *toLim);
+ enum XML_Convert_Result (PTRCALL *utf16Convert)(const ENCODING *enc,
+ const char **fromP,
+ const char *fromLim,
+ unsigned short **toP,
+ const unsigned short *toLim);
+ int minBytesPerChar;
+ char isUtf8;
+ char isUtf16;
+};
+
+/* Scan the string starting at ptr until the end of the next complete
+ token, but do not scan past eptr. Return an integer giving the
+ type of token.
+
+ Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
+
+ Return XML_TOK_PARTIAL when the string does not contain a complete
+ token; nextTokPtr will not be set.
+
+ Return XML_TOK_INVALID when the string does not start a valid
+ token; nextTokPtr will be set to point to the character which made
+ the token invalid.
+
+ Otherwise the string starts with a valid token; nextTokPtr will be
+ set to point to the character following the end of that token.
+
+ Each data character counts as a single token, but adjacent data
+ characters may be returned together. Similarly for characters in
+ the prolog outside literals, comments and processing instructions.
+*/
+
+
+#define XmlTok(enc, state, ptr, end, nextTokPtr) \
+ (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
+
+#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
+
+#define XmlContentTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
+
+#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
+
+#ifdef XML_DTD
+
+#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
+ XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
+
+#endif /* XML_DTD */
+
+/* This is used for performing a 2nd-level tokenization on the content
+ of a literal that has already been returned by XmlTok.
+*/
+#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
+ (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
+
+#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
+ XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
+
+#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
+
+#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
+ (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
+
+#define XmlNameLength(enc, ptr) \
+ (((enc)->nameLength)(enc, ptr))
+
+#define XmlSkipS(enc, ptr) \
+ (((enc)->skipS)(enc, ptr))
+
+#define XmlGetAttributes(enc, ptr, attsMax, atts) \
+ (((enc)->getAtts)(enc, ptr, attsMax, atts))
+
+#define XmlCharRefNumber(enc, ptr) \
+ (((enc)->charRefNumber)(enc, ptr))
+
+#define XmlPredefinedEntityName(enc, ptr, end) \
+ (((enc)->predefinedEntityName)(enc, ptr, end))
+
+#define XmlUpdatePosition(enc, ptr, end, pos) \
+ (((enc)->updatePosition)(enc, ptr, end, pos))
+
+#define XmlIsPublicId(enc, ptr, end, badPtr) \
+ (((enc)->isPublicId)(enc, ptr, end, badPtr))
+
+#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
+
+#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
+ (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
+
+typedef struct {
+ ENCODING initEnc;
+ const ENCODING **encPtr;
+} INIT_ENCODING;
+
+int XmlParseXmlDecl(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncoding(void);
+const ENCODING *XmlGetUtf16InternalEncoding(void);
+int FASTCALL XmlUtf8Encode(int charNumber, char *buf);
+int FASTCALL XmlUtf16Encode(int charNumber, unsigned short *buf);
+int XmlSizeOfUnknownEncoding(void);
+
+
+typedef int (XMLCALL *CONVERTER) (void *userData, const char *p);
+
+ENCODING *
+XmlInitUnknownEncoding(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+
+int XmlParseXmlDeclNS(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingNamePtr,
+ const ENCODING **namedEncodingPtr,
+ int *standalonePtr);
+
+int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
+const ENCODING *XmlGetUtf8InternalEncodingNS(void);
+const ENCODING *XmlGetUtf16InternalEncodingNS(void);
+ENCODING *
+XmlInitUnknownEncodingNS(void *mem,
+ int *table,
+ CONVERTER convert,
+ void *userData);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XmlTok_INCLUDED */
diff --git a/Utilities/cmexpat/lib/xmltok_impl.c b/Utilities/cmexpat/lib/xmltok_impl.c
new file mode 100644
index 000000000..4fa1ff679
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmltok_impl.c
@@ -0,0 +1,1806 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_IMPL_C
+
+#ifndef IS_INVALID_CHAR
+#define IS_INVALID_CHAR(enc, ptr, n) (0)
+#endif
+
+#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_INVALID_CHAR(enc, ptr, n)) { \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define INVALID_CASES(ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
+ INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
+ case BT_NONXML: \
+ case BT_MALFORM: \
+ case BT_TRAIL: \
+ *(nextTokPtr) = (ptr); \
+ return XML_TOK_INVALID;
+
+#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NAME_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ case BT_DIGIT: \
+ case BT_NAME: \
+ case BT_MINUS: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
+
+#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ ptr += n; \
+ break;
+
+#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
+ case BT_NONASCII: \
+ if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID; \
+ } \
+ case BT_NMSTRT: \
+ case BT_HEX: \
+ ptr += MINBPC(enc); \
+ break; \
+ CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
+ CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
+
+#ifndef PREFIX
+#define PREFIX(ident) ident
+#endif
+
+
+#define HAS_CHARS(enc, ptr, end, count) \
+ (end - ptr >= count * MINBPC(enc))
+
+#define HAS_CHAR(enc, ptr, end) \
+ HAS_CHARS(enc, ptr, end, 1)
+
+#define REQUIRE_CHARS(enc, ptr, end, count) \
+ { \
+ if (! HAS_CHARS(enc, ptr, end, count)) { \
+ return XML_TOK_PARTIAL; \
+ } \
+ }
+
+#define REQUIRE_CHAR(enc, ptr, end) \
+ REQUIRE_CHARS(enc, ptr, end, 1)
+
+
+/* ptr points to character following "<!-" */
+
+static int PTRCALL
+PREFIX(scanComment)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (HAS_CHAR(enc, ptr, end)) {
+ if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_MINUS:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMENT;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<!" */
+
+static int PTRCALL
+PREFIX(scanDecl)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COND_SECT_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_PERCNT:
+ REQUIRE_CHARS(enc, ptr, end, 2);
+ /* don't allow <!ENTITY% foo "whatever"> */
+ switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
+ case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* fall through */
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DECL_OPEN;
+ case BT_NMSTRT:
+ case BT_HEX:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(checkPiTarget)(const ENCODING *UNUSED_P(enc), const char *ptr,
+ const char *end, int *tokPtr)
+{
+ int upper = 0;
+ *tokPtr = XML_TOK_PI;
+ if (end - ptr != MINBPC(enc)*3)
+ return 1;
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_x:
+ break;
+ case ASCII_X:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_m:
+ break;
+ case ASCII_M:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ ptr += MINBPC(enc);
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ break;
+ case ASCII_L:
+ upper = 1;
+ break;
+ default:
+ return 1;
+ }
+ if (upper)
+ return 0;
+ *tokPtr = XML_TOK_XML_DECL;
+ return 1;
+}
+
+/* ptr points to character following "<?" */
+
+static int PTRCALL
+PREFIX(scanPi)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int tok;
+ const char *target = ptr;
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUEST:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+ case BT_QUEST:
+ if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return tok;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanCdataSection)(const ENCODING *UNUSED_P(enc), const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A,
+ ASCII_T, ASCII_A, ASCII_LSQB };
+ int i;
+ /* CDATA[ */
+ REQUIRE_CHARS(enc, ptr, end, 6);
+ for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
+ if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CDATA_SECT_OPEN;
+}
+
+static int PTRCALL
+PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CDATA_SECT_CLOSE;
+ case BT_CR:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ case BT_RSQB:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "</" */
+
+static int PTRCALL
+PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ break;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+#ifdef XML_NS
+ case BT_COLON:
+ /* no need to check qname syntax here,
+ since end-tag must match exactly */
+ ptr += MINBPC(enc);
+ break;
+#endif
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_END_TAG;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#X" */
+
+static int PTRCALL
+PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&#" */
+
+static int PTRCALL
+PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ if (HAS_CHAR(enc, ptr, end)) {
+ if (CHAR_MATCHES(enc, ptr, ASCII_x))
+ return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ for (ptr += MINBPC(enc); HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ break;
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CHAR_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "&" */
+
+static int PTRCALL
+PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_NUM:
+ return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following first character of attribute name */
+
+static int PTRCALL
+PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon = 0;
+#endif
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ for (;;) {
+ int t;
+
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ t = BYTE_TYPE(enc, ptr);
+ if (t == BT_EQUALS)
+ break;
+ switch (t) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_EQUALS:
+ {
+ int open;
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ for (;;) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ open = BYTE_TYPE(enc, ptr);
+ if (open == BT_QUOT || open == BT_APOS)
+ break;
+ switch (open) {
+ case BT_S:
+ case BT_LF:
+ case BT_CR:
+ break;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ ptr += MINBPC(enc);
+ /* in attribute value */
+ for (;;) {
+ int t;
+ REQUIRE_CHAR(enc, ptr, end);
+ t = BYTE_TYPE(enc, ptr);
+ if (t == open)
+ break;
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_AMP:
+ {
+ int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
+ if (tok <= 0) {
+ if (tok == XML_TOK_INVALID)
+ *nextTokPtr = ptr;
+ return tok;
+ }
+ break;
+ }
+ case BT_LT:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S:
+ case BT_CR:
+ case BT_LF:
+ break;
+ case BT_SOL:
+ goto sol;
+ case BT_GT:
+ goto gt;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ /* ptr points to closing quote */
+ for (;;) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_CR: case BT_LF:
+ continue;
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_WITH_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+ }
+ break;
+ }
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+/* ptr points to character following "<" */
+
+static int PTRCALL
+PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+#ifdef XML_NS
+ int hadColon;
+#endif
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_EXCL:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_MINUS:
+ return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LSQB:
+ return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_SOL:
+ return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+#ifdef XML_NS
+ hadColon = 0;
+#endif
+ /* we have a start-tag */
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+#ifdef XML_NS
+ case BT_COLON:
+ if (hadColon) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ hadColon = 1;
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ break;
+#endif
+ case BT_S: case BT_CR: case BT_LF:
+ {
+ ptr += MINBPC(enc);
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT:
+ goto gt;
+ case BT_SOL:
+ goto sol;
+ case BT_S: case BT_CR: case BT_LF:
+ ptr += MINBPC(enc);
+ continue;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
+ }
+ return XML_TOK_PARTIAL;
+ }
+ case BT_GT:
+ gt:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_START_TAG_NO_ATTS;
+ case BT_SOL:
+ sol:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LT:
+ return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_AMP:
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_CR:
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ case BT_LF:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
+ break;
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return XML_TOK_TRAILING_RSQB;
+ if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr -= MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ INVALID_CASES(ptr, nextTokPtr)
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
+ *nextTokPtr = ptr; \
+ return XML_TOK_DATA_CHARS; \
+ } \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_RSQB:
+ if (HAS_CHARS(enc, ptr, end, 2)) {
+ if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ if (HAS_CHARS(enc, ptr, end, 3)) {
+ if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
+ ptr += MINBPC(enc);
+ break;
+ }
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_INVALID;
+ }
+ }
+ /* fall through */
+ case BT_AMP:
+ case BT_LT:
+ case BT_NONXML:
+ case BT_MALFORM:
+ case BT_TRAIL:
+ case BT_CR:
+ case BT_LF:
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+/* ptr points to character following "%" */
+
+static int PTRCALL
+PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
+ *nextTokPtr = ptr;
+ return XML_TOK_PERCENT;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_SEMI:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_PARAM_ENTITY_REF;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_POUND_NAME;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -XML_TOK_POUND_NAME;
+}
+
+static int PTRCALL
+PREFIX(scanLit)(int open, const ENCODING *enc,
+ const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ while (HAS_CHAR(enc, ptr, end)) {
+ int t = BYTE_TYPE(enc, ptr);
+ switch (t) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_QUOT:
+ case BT_APOS:
+ ptr += MINBPC(enc);
+ if (t != open)
+ break;
+ if (! HAS_CHAR(enc, ptr, end))
+ return -XML_TOK_LITERAL;
+ *nextTokPtr = ptr;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_CR: case BT_LF:
+ case BT_GT: case BT_PERCNT: case BT_LSQB:
+ return XML_TOK_LITERAL;
+ default:
+ return XML_TOK_INVALID;
+ }
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+static int PTRCALL
+PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ int tok;
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ if (n == 0)
+ return XML_TOK_PARTIAL;
+ end = ptr + n;
+ }
+ }
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_QUOT:
+ return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_APOS:
+ return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_LT:
+ {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_EXCL:
+ return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_QUEST:
+ return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_NMSTRT:
+ case BT_HEX:
+ case BT_NONASCII:
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ *nextTokPtr = ptr - MINBPC(enc);
+ return XML_TOK_INSTANCE_START;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ case BT_CR:
+ if (ptr + MINBPC(enc) == end) {
+ *nextTokPtr = end;
+ /* indicate that this might be part of a CR/LF pair */
+ return -XML_TOK_PROLOG_S;
+ }
+ /* fall through */
+ case BT_S: case BT_LF:
+ for (;;) {
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ break;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_S: case BT_LF:
+ break;
+ case BT_CR:
+ /* don't split CR/LF pair */
+ if (ptr + MINBPC(enc) != end)
+ break;
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_PROLOG_S;
+ case BT_PERCNT:
+ return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ case BT_COMMA:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_COMMA;
+ case BT_LSQB:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_BRACKET;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return -XML_TOK_CLOSE_BRACKET;
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ REQUIRE_CHARS(enc, ptr, end, 2);
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
+ *nextTokPtr = ptr + 2*MINBPC(enc);
+ return XML_TOK_COND_SECT_CLOSE;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_BRACKET;
+ case BT_LPAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OPEN_PAREN;
+ case BT_RPAR:
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return -XML_TOK_CLOSE_PAREN;
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_AST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_ASTERISK;
+ case BT_QUEST:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_QUESTION;
+ case BT_PLUS:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_CLOSE_PAREN_PLUS;
+ case BT_CR: case BT_LF: case BT_S:
+ case BT_GT: case BT_COMMA: case BT_VERBAR:
+ case BT_RPAR:
+ *nextTokPtr = ptr;
+ return XML_TOK_CLOSE_PAREN;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_VERBAR:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_OR;
+ case BT_GT:
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DECL_CLOSE;
+ case BT_NUM:
+ return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (end - ptr < n) \
+ return XML_TOK_PARTIAL_CHAR; \
+ if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NAME; \
+ break; \
+ } \
+ if (IS_NAME_CHAR(enc, ptr, n)) { \
+ ptr += n; \
+ tok = XML_TOK_NMTOKEN; \
+ break; \
+ } \
+ *nextTokPtr = ptr; \
+ return XML_TOK_INVALID;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NMSTRT:
+ case BT_HEX:
+ tok = XML_TOK_NAME;
+ ptr += MINBPC(enc);
+ break;
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ tok = XML_TOK_NMTOKEN;
+ ptr += MINBPC(enc);
+ break;
+ case BT_NONASCII:
+ if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NAME;
+ break;
+ }
+ if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
+ ptr += MINBPC(enc);
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ /* fall through */
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ case BT_GT: case BT_RPAR: case BT_COMMA:
+ case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
+ case BT_S: case BT_CR: case BT_LF:
+ *nextTokPtr = ptr;
+ return tok;
+#ifdef XML_NS
+ case BT_COLON:
+ ptr += MINBPC(enc);
+ switch (tok) {
+ case XML_TOK_NAME:
+ REQUIRE_CHAR(enc, ptr, end);
+ tok = XML_TOK_PREFIXED_NAME;
+ switch (BYTE_TYPE(enc, ptr)) {
+ CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
+ default:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+ case XML_TOK_PREFIXED_NAME:
+ tok = XML_TOK_NMTOKEN;
+ break;
+ }
+ break;
+#endif
+ case BT_PLUS:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_PLUS;
+ case BT_AST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_ASTERISK;
+ case BT_QUEST:
+ if (tok == XML_TOK_NMTOKEN) {
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_NAME_QUESTION;
+ default:
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ }
+ }
+ return -tok;
+}
+
+static int PTRCALL
+PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ else if (! HAS_CHAR(enc, ptr, end)) {
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
+ * already been eliminated from the input. Retaining the paranoia
+ * check is still valuable, however.
+ */
+ return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */
+ }
+ start = ptr;
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LT:
+ /* this is for inside entity references */
+ *nextTokPtr = ptr;
+ return XML_TOK_INVALID;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_S:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_ATTRIBUTE_VALUE_S;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+static int PTRCALL
+PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ const char *start;
+ if (ptr >= end)
+ return XML_TOK_NONE;
+ else if (! HAS_CHAR(enc, ptr, end)) {
+ /* This line cannot be executed. The incoming data has already
+ * been tokenized once, so incomplete characters like this have
+ * already been eliminated from the input. Retaining the paranoia
+ * check is still valuable, however.
+ */
+ return XML_TOK_PARTIAL; /* LCOV_EXCL_LINE */
+ }
+ start = ptr;
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_AMP:
+ if (ptr == start)
+ return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_PERCNT:
+ if (ptr == start) {
+ int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
+ end, nextTokPtr);
+ return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_LF:
+ if (ptr == start) {
+ *nextTokPtr = ptr + MINBPC(enc);
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ case BT_CR:
+ if (ptr == start) {
+ ptr += MINBPC(enc);
+ if (! HAS_CHAR(enc, ptr, end))
+ return XML_TOK_TRAILING_CR;
+ if (BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_NEWLINE;
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ *nextTokPtr = ptr;
+ return XML_TOK_DATA_CHARS;
+}
+
+#ifdef XML_DTD
+
+static int PTRCALL
+PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr,
+ const char *end, const char **nextTokPtr)
+{
+ int level = 0;
+ if (MINBPC(enc) > 1) {
+ size_t n = end - ptr;
+ if (n & (MINBPC(enc) - 1)) {
+ n &= ~(MINBPC(enc) - 1);
+ end = ptr + n;
+ }
+ }
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ INVALID_CASES(ptr, nextTokPtr)
+ case BT_LT:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
+ ++level;
+ ptr += MINBPC(enc);
+ }
+ }
+ break;
+ case BT_RSQB:
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
+ ptr += MINBPC(enc);
+ REQUIRE_CHAR(enc, ptr, end);
+ if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
+ ptr += MINBPC(enc);
+ if (level == 0) {
+ *nextTokPtr = ptr;
+ return XML_TOK_IGNORE_SECT;
+ }
+ --level;
+ }
+ }
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ }
+ return XML_TOK_PARTIAL;
+}
+
+#endif /* XML_DTD */
+
+static int PTRCALL
+PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **badPtr)
+{
+ ptr += MINBPC(enc);
+ end -= MINBPC(enc);
+ for (; HAS_CHAR(enc, ptr, end); ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_DIGIT:
+ case BT_HEX:
+ case BT_MINUS:
+ case BT_APOS:
+ case BT_LPAR:
+ case BT_RPAR:
+ case BT_PLUS:
+ case BT_COMMA:
+ case BT_SOL:
+ case BT_EQUALS:
+ case BT_QUEST:
+ case BT_CR:
+ case BT_LF:
+ case BT_SEMI:
+ case BT_EXCL:
+ case BT_AST:
+ case BT_PERCNT:
+ case BT_NUM:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ break;
+ case BT_S:
+ if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ case BT_NAME:
+ case BT_NMSTRT:
+ if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
+ break;
+ default:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case 0x24: /* $ */
+ case 0x40: /* @ */
+ break;
+ default:
+ *badPtr = ptr;
+ return 0;
+ }
+ break;
+ }
+ }
+ return 1;
+}
+
+/* This must only be called for a well-formed start-tag or empty
+ element tag. Returns the number of attributes. Pointers to the
+ first attsMax attributes are stored in atts.
+*/
+
+static int PTRCALL
+PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
+ int attsMax, ATTRIBUTE *atts)
+{
+ enum { other, inName, inValue } state = inName;
+ int nAtts = 0;
+ int open = 0; /* defined when state == inValue;
+ initialization just to shut up compilers */
+
+ for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define START_NAME \
+ if (state == other) { \
+ if (nAtts < attsMax) { \
+ atts[nAtts].name = ptr; \
+ atts[nAtts].normalized = 1; \
+ } \
+ state = inName; \
+ }
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+ case BT_HEX:
+ START_NAME
+ break;
+#undef START_NAME
+ case BT_QUOT:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_QUOT;
+ }
+ else if (open == BT_QUOT) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_APOS:
+ if (state != inValue) {
+ if (nAtts < attsMax)
+ atts[nAtts].valuePtr = ptr + MINBPC(enc);
+ state = inValue;
+ open = BT_APOS;
+ }
+ else if (open == BT_APOS) {
+ state = other;
+ if (nAtts < attsMax)
+ atts[nAtts].valueEnd = ptr;
+ nAtts++;
+ }
+ break;
+ case BT_AMP:
+ if (nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_S:
+ if (state == inName)
+ state = other;
+ else if (state == inValue
+ && nAtts < attsMax
+ && atts[nAtts].normalized
+ && (ptr == atts[nAtts].valuePtr
+ || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
+ || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
+ || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_CR: case BT_LF:
+ /* This case ensures that the first attribute name is counted
+ Apart from that we could just change state on the quote. */
+ if (state == inName)
+ state = other;
+ else if (state == inValue && nAtts < attsMax)
+ atts[nAtts].normalized = 0;
+ break;
+ case BT_GT:
+ case BT_SOL:
+ if (state != inValue)
+ return nAtts;
+ break;
+ default:
+ break;
+ }
+ }
+ /* not reached */
+}
+
+static int PTRFASTCALL
+PREFIX(charRefNumber)(const ENCODING *UNUSED_P(enc), const char *ptr)
+{
+ int result = 0;
+ /* skip &# */
+ ptr += 2*MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
+ for (ptr += MINBPC(enc);
+ !CHAR_MATCHES(enc, ptr, ASCII_SEMI);
+ ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ switch (c) {
+ case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
+ case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
+ result <<= 4;
+ result |= (c - ASCII_0);
+ break;
+ case ASCII_A: case ASCII_B: case ASCII_C:
+ case ASCII_D: case ASCII_E: case ASCII_F:
+ result <<= 4;
+ result += 10 + (c - ASCII_A);
+ break;
+ case ASCII_a: case ASCII_b: case ASCII_c:
+ case ASCII_d: case ASCII_e: case ASCII_f:
+ result <<= 4;
+ result += 10 + (c - ASCII_a);
+ break;
+ }
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ else {
+ for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
+ int c = BYTE_TO_ASCII(enc, ptr);
+ result *= 10;
+ result += (c - ASCII_0);
+ if (result >= 0x110000)
+ return -1;
+ }
+ }
+ return checkCharRefNumber(result);
+}
+
+static int PTRCALL
+PREFIX(predefinedEntityName)(const ENCODING *UNUSED_P(enc), const char *ptr,
+ const char *end)
+{
+ switch ((end - ptr)/MINBPC(enc)) {
+ case 2:
+ if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_l:
+ return ASCII_LT;
+ case ASCII_g:
+ return ASCII_GT;
+ }
+ }
+ break;
+ case 3:
+ if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p))
+ return ASCII_AMP;
+ }
+ }
+ break;
+ case 4:
+ switch (BYTE_TO_ASCII(enc, ptr)) {
+ case ASCII_q:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_t))
+ return ASCII_QUOT;
+ }
+ }
+ break;
+ case ASCII_a:
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
+ ptr += MINBPC(enc);
+ if (CHAR_MATCHES(enc, ptr, ASCII_s))
+ return ASCII_APOS;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+/* This function does not appear to be called from anywhere within the
+ * library code. It is used via the macro XmlSameName(), which is
+ * defined but never used. Since it appears in the encoding function
+ * table, removing it is not a thing to be undertaken lightly. For
+ * the moment, we simply exclude it from coverage tests.
+ *
+ * LCOV_EXCL_START
+ */
+static int PTRCALL
+PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr1)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ if (*ptr1++ != *ptr2++) \
+ return 0;
+ LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
+#undef LEAD_CASE
+ /* fall through */
+ if (*ptr1++ != *ptr2++)
+ return 0;
+ break;
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 1) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 2) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ if (MINBPC(enc) > 3) {
+ if (*ptr2++ != *ptr1++)
+ return 0;
+ }
+ }
+ }
+ break;
+ default:
+ if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
+ return 1;
+ switch (BYTE_TYPE(enc, ptr2)) {
+ case BT_LEAD2:
+ case BT_LEAD3:
+ case BT_LEAD4:
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ return 0;
+ default:
+ return 1;
+ }
+ }
+ }
+ /* not reached */
+}
+/* LCOV_EXCL_STOP */
+
+static int PTRCALL
+PREFIX(nameMatchesAscii)(const ENCODING *UNUSED_P(enc), const char *ptr1,
+ const char *end1, const char *ptr2)
+{
+ for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
+ if (end1 - ptr1 < MINBPC(enc)) {
+ /* This line cannot be executed. THe incoming data has already
+ * been tokenized once, so imcomplete characters like this have
+ * already been eliminated from the input. Retaining the
+ * paranoia check is still valuable, however.
+ */
+ return 0; /* LCOV_EXCL_LINE */
+ }
+ if (!CHAR_MATCHES(enc, ptr1, *ptr2))
+ return 0;
+ }
+ return ptr1 == end1;
+}
+
+static int PTRFASTCALL
+PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
+{
+ const char *start = ptr;
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: ptr += n; break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_NONASCII:
+ case BT_NMSTRT:
+#ifdef XML_NS
+ case BT_COLON:
+#endif
+ case BT_HEX:
+ case BT_DIGIT:
+ case BT_NAME:
+ case BT_MINUS:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return (int)(ptr - start);
+ }
+ }
+}
+
+static const char * PTRFASTCALL
+PREFIX(skipS)(const ENCODING *enc, const char *ptr)
+{
+ for (;;) {
+ switch (BYTE_TYPE(enc, ptr)) {
+ case BT_LF:
+ case BT_CR:
+ case BT_S:
+ ptr += MINBPC(enc);
+ break;
+ default:
+ return ptr;
+ }
+ }
+}
+
+static void PTRCALL
+PREFIX(updatePosition)(const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ POSITION *pos)
+{
+ while (HAS_CHAR(enc, ptr, end)) {
+ switch (BYTE_TYPE(enc, ptr)) {
+#define LEAD_CASE(n) \
+ case BT_LEAD ## n: \
+ ptr += n; \
+ break;
+ LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
+#undef LEAD_CASE
+ case BT_LF:
+ pos->columnNumber = (XML_Size)-1;
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ break;
+ case BT_CR:
+ pos->lineNumber++;
+ ptr += MINBPC(enc);
+ if (HAS_CHAR(enc, ptr, end) && BYTE_TYPE(enc, ptr) == BT_LF)
+ ptr += MINBPC(enc);
+ pos->columnNumber = (XML_Size)-1;
+ break;
+ default:
+ ptr += MINBPC(enc);
+ break;
+ }
+ pos->columnNumber++;
+ }
+}
+
+#undef DO_LEAD_CASE
+#undef MULTIBYTE_CASES
+#undef INVALID_CASES
+#undef CHECK_NAME_CASE
+#undef CHECK_NAME_CASES
+#undef CHECK_NMSTRT_CASE
+#undef CHECK_NMSTRT_CASES
+
+#endif /* XML_TOK_IMPL_C */
diff --git a/Utilities/cmexpat/xmltok_impl.h b/Utilities/cmexpat/lib/xmltok_impl.h
index da0ea60a6..da0ea60a6 100644
--- a/Utilities/cmexpat/xmltok_impl.h
+++ b/Utilities/cmexpat/lib/xmltok_impl.h
diff --git a/Utilities/cmexpat/lib/xmltok_ns.c b/Utilities/cmexpat/lib/xmltok_ns.c
new file mode 100644
index 000000000..c3b88fdf4
--- /dev/null
+++ b/Utilities/cmexpat/lib/xmltok_ns.c
@@ -0,0 +1,115 @@
+/* Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
+ See the file COPYING for copying permission.
+*/
+
+/* This file is included! */
+#ifdef XML_TOK_NS_C
+
+const ENCODING *
+NS(XmlGetUtf8InternalEncoding)(void)
+{
+ return &ns(internal_utf8_encoding).enc;
+}
+
+const ENCODING *
+NS(XmlGetUtf16InternalEncoding)(void)
+{
+#if BYTEORDER == 1234
+ return &ns(internal_little2_encoding).enc;
+#elif BYTEORDER == 4321
+ return &ns(internal_big2_encoding).enc;
+#else
+ const short n = 1;
+ return (*(const char *)&n
+ ? &ns(internal_little2_encoding).enc
+ : &ns(internal_big2_encoding).enc);
+#endif
+}
+
+static const ENCODING * const NS(encodings)[] = {
+ &ns(latin1_encoding).enc,
+ &ns(ascii_encoding).enc,
+ &ns(utf8_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(big2_encoding).enc,
+ &ns(little2_encoding).enc,
+ &ns(utf8_encoding).enc /* NO_ENC */
+};
+
+static int PTRCALL
+NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_PROLOG_STATE, ptr, end, nextTokPtr);
+}
+
+static int PTRCALL
+NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
+ const char **nextTokPtr)
+{
+ return initScan(NS(encodings), (const INIT_ENCODING *)enc,
+ XML_CONTENT_STATE, ptr, end, nextTokPtr);
+}
+
+int
+NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr,
+ const char *name)
+{
+ int i = getEncodingIndex(name);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ SET_INIT_ENC_INDEX(p, i);
+ p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
+ p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
+ p->initEnc.updatePosition = initUpdatePosition;
+ p->encPtr = encPtr;
+ *encPtr = &(p->initEnc);
+ return 1;
+}
+
+static const ENCODING *
+NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
+{
+#define ENCODING_MAX 128
+ char buf[ENCODING_MAX];
+ char *p = buf;
+ int i;
+ XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
+ if (ptr != end)
+ return 0;
+ *p = 0;
+ if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
+ return enc;
+ i = getEncodingIndex(buf);
+ if (i == UNKNOWN_ENC)
+ return 0;
+ return NS(encodings)[i];
+}
+
+int
+NS(XmlParseXmlDecl)(int isGeneralTextEntity,
+ const ENCODING *enc,
+ const char *ptr,
+ const char *end,
+ const char **badPtr,
+ const char **versionPtr,
+ const char **versionEndPtr,
+ const char **encodingName,
+ const ENCODING **encoding,
+ int *standalone)
+{
+ return doParseXmlDecl(NS(findEncoding),
+ isGeneralTextEntity,
+ enc,
+ ptr,
+ end,
+ badPtr,
+ versionPtr,
+ versionEndPtr,
+ encodingName,
+ encoding,
+ standalone);
+}
+
+#endif /* XML_TOK_NS_C */
diff --git a/Utilities/cmexpat/utf8tab.h b/Utilities/cmexpat/utf8tab.h
deleted file mode 100644
index 9e3b6b83e..000000000
--- a/Utilities/cmexpat/utf8tab.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-
-/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x84 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x88 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x8C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x90 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x94 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x98 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0x9C */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xA8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xAC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB0 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB4 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xB8 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xBC */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
-/* 0xC0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xC8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xCC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD0 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD4 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xD8 */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xDC */ BT_LEAD2, BT_LEAD2, BT_LEAD2, BT_LEAD2,
-/* 0xE0 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE4 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xE8 */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xEC */ BT_LEAD3, BT_LEAD3, BT_LEAD3, BT_LEAD3,
-/* 0xF0 */ BT_LEAD4, BT_LEAD4, BT_LEAD4, BT_LEAD4,
-/* 0xF4 */ BT_LEAD4, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xF8 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
-/* 0xFC */ BT_NONXML, BT_NONXML, BT_MALFORM, BT_MALFORM,
diff --git a/Utilities/cmexpat/xmlparse.c b/Utilities/cmexpat/xmlparse.c
deleted file mode 100644
index 29ea3d3d7..000000000
--- a/Utilities/cmexpat/xmlparse.c
+++ /dev/null
@@ -1,4622 +0,0 @@
-/*
-Copyright (c) 1998, 1999, 2000 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#include <cmexpat/expatConfig.h>
-#include <cmexpat/expat.h>
-
-#include <stddef.h>
-#include <string.h>
-
-#ifdef XML_UNICODE
-#define XML_ENCODE_MAX XML_UTF16_ENCODE_MAX
-#define XmlConvert XmlUtf16Convert
-#define XmlGetInternalEncoding XmlGetUtf16InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf16InternalEncodingNS
-#define XmlEncode XmlUtf16Encode
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf16 || (((unsigned long)s) & 1))
-typedef unsigned short ICHAR;
-#else
-#define XML_ENCODE_MAX XML_UTF8_ENCODE_MAX
-#define XmlConvert XmlUtf8Convert
-#define XmlGetInternalEncoding XmlGetUtf8InternalEncoding
-#define XmlGetInternalEncodingNS XmlGetUtf8InternalEncodingNS
-#define XmlEncode XmlUtf8Encode
-#define MUST_CONVERT(enc, s) (!(enc)->isUtf8)
-typedef char ICHAR;
-#endif
-
-
-#ifndef XML_NS
-
-#define XmlInitEncodingNS XmlInitEncoding
-#define XmlInitUnknownEncodingNS XmlInitUnknownEncoding
-#undef XmlGetInternalEncodingNS
-#define XmlGetInternalEncodingNS XmlGetInternalEncoding
-#define XmlParseXmlDeclNS XmlParseXmlDecl
-
-#endif
-
-#ifdef XML_UNICODE_WCHAR_T
-#define XML_T(x) L ## x
-#else
-#define XML_T(x) x
-#endif
-
-/* Round up n to be a multiple of sz, where sz is a power of 2. */
-#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
-
-#include "xmltok.h"
-#include "xmlrole.h"
-
-typedef const XML_Char *KEY;
-
-typedef struct {
- KEY name;
-} NAMED;
-
-typedef struct {
- NAMED **v;
- size_t size;
- size_t used;
- size_t usedLim;
- XML_Memory_Handling_Suite *mem;
-} HASH_TABLE;
-
-typedef struct {
- NAMED **p;
- NAMED **end;
-} HASH_TABLE_ITER;
-
-#define INIT_TAG_BUF_SIZE 32 /* must be a multiple of sizeof(XML_Char) */
-#define INIT_DATA_BUF_SIZE 1024
-#define INIT_ATTS_SIZE 16
-#define INIT_BLOCK_SIZE 1024
-#define INIT_BUFFER_SIZE 1024
-
-#define EXPAND_SPARE 24
-
-typedef struct binding {
- struct prefix *prefix;
- struct binding *nextTagBinding;
- struct binding *prevPrefixBinding;
- const struct attribute_id *attId;
- XML_Char *uri;
- int uriLen;
- int uriAlloc;
-} BINDING;
-
-typedef struct prefix {
- const XML_Char *name;
- BINDING *binding;
-} PREFIX;
-
-typedef struct {
- const XML_Char *str;
- const XML_Char *localPart;
- int uriLen;
-} TAG_NAME;
-
-typedef struct tag {
- struct tag *parent;
- const char *rawName;
- int rawNameLength;
- TAG_NAME name;
- char *buf;
- char *bufEnd;
- BINDING *bindings;
-} TAG;
-
-typedef struct {
- const XML_Char *name;
- const XML_Char *textPtr;
- int textLen;
- const XML_Char *systemId;
- const XML_Char *base;
- const XML_Char *publicId;
- const XML_Char *notation;
- char open;
- char is_param;
-} ENTITY;
-
-typedef struct {
- enum XML_Content_Type type;
- enum XML_Content_Quant quant;
- const XML_Char * name;
- int firstchild;
- int lastchild;
- int childcnt;
- int nextsib;
-} CONTENT_SCAFFOLD;
-
-typedef struct block {
- struct block *next;
- int size;
- XML_Char s[1];
-} BLOCK;
-
-typedef struct {
- BLOCK *blocks;
- BLOCK *freeBlocks;
- const XML_Char *end;
- XML_Char *ptr;
- XML_Char *start;
- XML_Memory_Handling_Suite *mem;
-} STRING_POOL;
-
-/* The XML_Char before the name is used to determine whether
-an attribute has been specified. */
-typedef struct attribute_id {
- XML_Char *name;
- PREFIX *prefix;
- char maybeTokenized;
- char xmlns;
-} ATTRIBUTE_ID;
-
-typedef struct {
- const ATTRIBUTE_ID *id;
- char isCdata;
- const XML_Char *value;
-} DEFAULT_ATTRIBUTE;
-
-typedef struct {
- const XML_Char *name;
- PREFIX *prefix;
- const ATTRIBUTE_ID *idAtt;
- int nDefaultAtts;
- int allocDefaultAtts;
- DEFAULT_ATTRIBUTE *defaultAtts;
-} ELEMENT_TYPE;
-
-typedef struct {
- HASH_TABLE generalEntities;
- HASH_TABLE elementTypes;
- HASH_TABLE attributeIds;
- HASH_TABLE prefixes;
- STRING_POOL pool;
- int complete;
- int standalone;
-#ifdef XML_DTD
- HASH_TABLE paramEntities;
-#endif /* XML_DTD */
- PREFIX defaultPrefix;
- /* === scaffolding for building content model === */
- int in_eldecl;
- CONTENT_SCAFFOLD *scaffold;
- unsigned contentStringLen;
- unsigned scaffSize;
- unsigned scaffCount;
- int scaffLevel;
- int *scaffIndex;
-} DTD;
-
-typedef struct open_internal_entity {
- const char *internalEventPtr;
- const char *internalEventEndPtr;
- struct open_internal_entity *next;
- ENTITY *entity;
-} OPEN_INTERNAL_ENTITY;
-
-typedef enum XML_Error Processor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr);
-
-static Processor prologProcessor;
-static Processor prologInitProcessor;
-static Processor contentProcessor;
-static Processor cdataSectionProcessor;
-#ifdef XML_DTD
-static Processor ignoreSectionProcessor;
-#endif /* XML_DTD */
-static Processor epilogProcessor;
-static Processor errorProcessor;
-static Processor externalEntityInitProcessor;
-static Processor externalEntityInitProcessor2;
-static Processor externalEntityInitProcessor3;
-static Processor externalEntityContentProcessor;
-
-static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName);
-static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity, const char *, const char *);
-static enum XML_Error
-initializeEncoding(XML_Parser parser);
-static enum XML_Error
-doProlog(XML_Parser parser, const ENCODING *enc, const char *s,
- const char *end, int tok, const char *next, const char **nextPtr);
-static enum XML_Error
-processInternalParamEntity(XML_Parser parser, ENTITY *entity);
-static enum XML_Error
-doContent(XML_Parser parser, int startTagLevel, const ENCODING *enc,
- const char *start, const char *end, const char **endPtr);
-static enum XML_Error
-doCdataSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
-#ifdef XML_DTD
-static enum XML_Error
-doIgnoreSection(XML_Parser parser, const ENCODING *, const char **startPtr, const char *end, const char **nextPtr);
-#endif /* XML_DTD */
-static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *, const char *s,
- TAG_NAME *tagNamePtr, BINDING **bindingsPtr);
-static
-int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr);
-
-static int
-defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *,
- int isCdata, int isId, const XML_Char *dfltValue,
- XML_Parser parser);
-
-static enum XML_Error
-storeAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *,
- STRING_POOL *);
-static enum XML_Error
-appendAttributeValue(XML_Parser parser, const ENCODING *, int isCdata, const char *, const char *,
- STRING_POOL *);
-static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
-static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *);
-static enum XML_Error
-storeEntityValue(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
-static int
-reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
-static int
-reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
-static void
-reportDefault(XML_Parser parser, const ENCODING *enc, const char *start, const char *end);
-
-static const XML_Char *getContext(XML_Parser parser);
-static int setContext(XML_Parser parser, const XML_Char *context);
-static void normalizePublicId(XML_Char *s);
-static int dtdInit(DTD *, XML_Parser parser);
-
-static void dtdDestroy(DTD *, XML_Parser parser);
-
-static int dtdCopy(DTD *newDtd, const DTD *oldDtd, XML_Parser parser);
-
-static int copyEntityTable(HASH_TABLE *, STRING_POOL *, const HASH_TABLE *,
- XML_Parser parser);
-
-#ifdef XML_DTD
-static void dtdSwap(DTD *, DTD *);
-#endif /* XML_DTD */
-
-static NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize);
-
-static void hashTableInit(HASH_TABLE *, XML_Memory_Handling_Suite *ms);
-
-static void hashTableDestroy(HASH_TABLE *);
-static void hashTableIterInit(HASH_TABLE_ITER *, const HASH_TABLE *);
-static NAMED *hashTableIterNext(HASH_TABLE_ITER *);
-static void poolInit(STRING_POOL *, XML_Memory_Handling_Suite *ms);
-static void poolClear(STRING_POOL *);
-static void poolDestroy(STRING_POOL *);
-static XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end);
-static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end);
-
-static int poolGrow(STRING_POOL *pool);
-
-static int nextScaffoldPart(XML_Parser parser);
-static XML_Content *build_model(XML_Parser parser);
-
-static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s);
-static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n);
-static const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s);
-static ELEMENT_TYPE * getElementType(XML_Parser Paraser,
- const ENCODING *enc,
- const char *ptr,
- const char *end);
-
-#define poolStart(pool) ((pool)->start)
-#define poolEnd(pool) ((pool)->ptr)
-#define poolLength(pool) ((pool)->ptr - (pool)->start)
-#define poolChop(pool) ((void)--(pool->ptr))
-#define poolLastChar(pool) (((pool)->ptr)[-1])
-#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
-#define poolFinish(pool) ((pool)->start = (pool)->ptr)
-#define poolAppendChar(pool, c) \
- (((pool)->ptr == (pool)->end && !poolGrow(pool)) \
- ? 0 \
- : ((*((pool)->ptr)++ = c), 1))
-
-typedef struct {
- /* The first member must be userData so that the XML_GetUserData macro works. */
- void *m_userData;
- void *m_handlerArg;
- char *m_buffer;
- XML_Memory_Handling_Suite m_mem;
- /* first character to be parsed */
- const char *m_bufferPtr;
- /* past last character to be parsed */
- char *m_bufferEnd;
- /* allocated end of buffer */
- const char *m_bufferLim;
- long m_parseEndByteIndex;
- const char *m_parseEndPtr;
- XML_Char *m_dataBuf;
- XML_Char *m_dataBufEnd;
- XML_StartElementHandler m_startElementHandler;
- XML_EndElementHandler m_endElementHandler;
- XML_CharacterDataHandler m_characterDataHandler;
- XML_ProcessingInstructionHandler m_processingInstructionHandler;
- XML_CommentHandler m_commentHandler;
- XML_StartCdataSectionHandler m_startCdataSectionHandler;
- XML_EndCdataSectionHandler m_endCdataSectionHandler;
- XML_DefaultHandler m_defaultHandler;
- XML_StartDoctypeDeclHandler m_startDoctypeDeclHandler;
- XML_EndDoctypeDeclHandler m_endDoctypeDeclHandler;
- XML_UnparsedEntityDeclHandler m_unparsedEntityDeclHandler;
- XML_NotationDeclHandler m_notationDeclHandler;
- XML_StartNamespaceDeclHandler m_startNamespaceDeclHandler;
- XML_EndNamespaceDeclHandler m_endNamespaceDeclHandler;
- XML_NotStandaloneHandler m_notStandaloneHandler;
- XML_ExternalEntityRefHandler m_externalEntityRefHandler;
- void *m_externalEntityRefHandlerArg;
- XML_UnknownEncodingHandler m_unknownEncodingHandler;
- XML_ElementDeclHandler m_elementDeclHandler;
- XML_AttlistDeclHandler m_attlistDeclHandler;
- XML_EntityDeclHandler m_entityDeclHandler;
- XML_XmlDeclHandler m_xmlDeclHandler;
- const ENCODING *m_encoding;
- INIT_ENCODING m_initEncoding;
- const ENCODING *m_internalEncoding;
- const XML_Char *m_protocolEncodingName;
- int m_ns;
- int m_ns_triplets;
- void *m_unknownEncodingMem;
- void *m_unknownEncodingData;
- void *m_unknownEncodingHandlerData;
- void (*m_unknownEncodingRelease)(void *);
- PROLOG_STATE m_prologState;
- Processor *m_processor;
- enum XML_Error m_errorCode;
- const char *m_eventPtr;
- const char *m_eventEndPtr;
- const char *m_positionPtr;
- OPEN_INTERNAL_ENTITY *m_openInternalEntities;
- int m_defaultExpandInternalEntities;
- int m_tagLevel;
- ENTITY *m_declEntity;
- const XML_Char *m_doctypeName;
- const XML_Char *m_doctypeSysid;
- const XML_Char *m_doctypePubid;
- const XML_Char *m_declAttributeType;
- const XML_Char *m_declNotationName;
- const XML_Char *m_declNotationPublicId;
- ELEMENT_TYPE *m_declElementType;
- ATTRIBUTE_ID *m_declAttributeId;
- char m_declAttributeIsCdata;
- char m_declAttributeIsId;
- DTD m_dtd;
- const XML_Char *m_curBase;
- TAG *m_tagStack;
- TAG *m_freeTagList;
- BINDING *m_inheritedBindings;
- BINDING *m_freeBindingList;
- int m_attsSize;
- int m_nSpecifiedAtts;
- int m_idAttIndex;
- ATTRIBUTE *m_atts;
- POSITION m_position;
- STRING_POOL m_tempPool;
- STRING_POOL m_temp2Pool;
- char *m_groupConnector;
- unsigned m_groupSize;
- int m_hadExternalDoctype;
- XML_Char m_namespaceSeparator;
-#ifdef XML_DTD
- enum XML_ParamEntityParsing m_paramEntityParsing;
- XML_Parser m_parentParser;
-#endif
-} Parser;
-
-#define MALLOC(s) (((Parser *)parser)->m_mem.malloc_fcn((s)))
-#define REALLOC(p,s) (((Parser *)parser)->m_mem.realloc_fcn((p),(s)))
-#define FREE(p) (((Parser *)parser)->m_mem.free_fcn((p)))
-
-#define userData (((Parser *)parser)->m_userData)
-#define handlerArg (((Parser *)parser)->m_handlerArg)
-#define startElementHandler (((Parser *)parser)->m_startElementHandler)
-#define endElementHandler (((Parser *)parser)->m_endElementHandler)
-#define characterDataHandler (((Parser *)parser)->m_characterDataHandler)
-#define processingInstructionHandler (((Parser *)parser)->m_processingInstructionHandler)
-#define commentHandler (((Parser *)parser)->m_commentHandler)
-#define startCdataSectionHandler (((Parser *)parser)->m_startCdataSectionHandler)
-#define endCdataSectionHandler (((Parser *)parser)->m_endCdataSectionHandler)
-#define defaultHandler (((Parser *)parser)->m_defaultHandler)
-#define startDoctypeDeclHandler (((Parser *)parser)->m_startDoctypeDeclHandler)
-#define endDoctypeDeclHandler (((Parser *)parser)->m_endDoctypeDeclHandler)
-#define unparsedEntityDeclHandler (((Parser *)parser)->m_unparsedEntityDeclHandler)
-#define notationDeclHandler (((Parser *)parser)->m_notationDeclHandler)
-#define startNamespaceDeclHandler (((Parser *)parser)->m_startNamespaceDeclHandler)
-#define endNamespaceDeclHandler (((Parser *)parser)->m_endNamespaceDeclHandler)
-#define notStandaloneHandler (((Parser *)parser)->m_notStandaloneHandler)
-#define externalEntityRefHandler (((Parser *)parser)->m_externalEntityRefHandler)
-#define externalEntityRefHandlerArg (((Parser *)parser)->m_externalEntityRefHandlerArg)
-#define internalEntityRefHandler (((Parser *)parser)->m_internalEntityRefHandler)
-#define unknownEncodingHandler (((Parser *)parser)->m_unknownEncodingHandler)
-#define elementDeclHandler (((Parser *)parser)->m_elementDeclHandler)
-#define attlistDeclHandler (((Parser *)parser)->m_attlistDeclHandler)
-#define entityDeclHandler (((Parser *)parser)->m_entityDeclHandler)
-#define xmlDeclHandler (((Parser *)parser)->m_xmlDeclHandler)
-#define encoding (((Parser *)parser)->m_encoding)
-#define initEncoding (((Parser *)parser)->m_initEncoding)
-#define internalEncoding (((Parser *)parser)->m_internalEncoding)
-#define unknownEncodingMem (((Parser *)parser)->m_unknownEncodingMem)
-#define unknownEncodingData (((Parser *)parser)->m_unknownEncodingData)
-#define unknownEncodingHandlerData \
- (((Parser *)parser)->m_unknownEncodingHandlerData)
-#define unknownEncodingRelease (((Parser *)parser)->m_unknownEncodingRelease)
-#define protocolEncodingName (((Parser *)parser)->m_protocolEncodingName)
-#define ns (((Parser *)parser)->m_ns)
-#define ns_triplets (((Parser *)parser)->m_ns_triplets)
-#define prologState (((Parser *)parser)->m_prologState)
-#define processor (((Parser *)parser)->m_processor)
-#define errorCode (((Parser *)parser)->m_errorCode)
-#define eventPtr (((Parser *)parser)->m_eventPtr)
-#define eventEndPtr (((Parser *)parser)->m_eventEndPtr)
-#define positionPtr (((Parser *)parser)->m_positionPtr)
-#define position (((Parser *)parser)->m_position)
-#define openInternalEntities (((Parser *)parser)->m_openInternalEntities)
-#define defaultExpandInternalEntities (((Parser *)parser)->m_defaultExpandInternalEntities)
-#define tagLevel (((Parser *)parser)->m_tagLevel)
-#define buffer (((Parser *)parser)->m_buffer)
-#define bufferPtr (((Parser *)parser)->m_bufferPtr)
-#define bufferEnd (((Parser *)parser)->m_bufferEnd)
-#define parseEndByteIndex (((Parser *)parser)->m_parseEndByteIndex)
-#define parseEndPtr (((Parser *)parser)->m_parseEndPtr)
-#define bufferLim (((Parser *)parser)->m_bufferLim)
-#define dataBuf (((Parser *)parser)->m_dataBuf)
-#define dataBufEnd (((Parser *)parser)->m_dataBufEnd)
-#define dtd (((Parser *)parser)->m_dtd)
-#define curBase (((Parser *)parser)->m_curBase)
-#define declEntity (((Parser *)parser)->m_declEntity)
-#define doctypeName (((Parser *)parser)->m_doctypeName)
-#define doctypeSysid (((Parser *)parser)->m_doctypeSysid)
-#define doctypePubid (((Parser *)parser)->m_doctypePubid)
-#define declAttributeType (((Parser *)parser)->m_declAttributeType)
-#define declNotationName (((Parser *)parser)->m_declNotationName)
-#define declNotationPublicId (((Parser *)parser)->m_declNotationPublicId)
-#define declElementType (((Parser *)parser)->m_declElementType)
-#define declAttributeId (((Parser *)parser)->m_declAttributeId)
-#define declAttributeIsCdata (((Parser *)parser)->m_declAttributeIsCdata)
-#define declAttributeIsId (((Parser *)parser)->m_declAttributeIsId)
-#define freeTagList (((Parser *)parser)->m_freeTagList)
-#define freeBindingList (((Parser *)parser)->m_freeBindingList)
-#define inheritedBindings (((Parser *)parser)->m_inheritedBindings)
-#define tagStack (((Parser *)parser)->m_tagStack)
-#define atts (((Parser *)parser)->m_atts)
-#define attsSize (((Parser *)parser)->m_attsSize)
-#define nSpecifiedAtts (((Parser *)parser)->m_nSpecifiedAtts)
-#define idAttIndex (((Parser *)parser)->m_idAttIndex)
-#define tempPool (((Parser *)parser)->m_tempPool)
-#define temp2Pool (((Parser *)parser)->m_temp2Pool)
-#define groupConnector (((Parser *)parser)->m_groupConnector)
-#define groupSize (((Parser *)parser)->m_groupSize)
-#define hadExternalDoctype (((Parser *)parser)->m_hadExternalDoctype)
-#define namespaceSeparator (((Parser *)parser)->m_namespaceSeparator)
-#ifdef XML_DTD
-#define parentParser (((Parser *)parser)->m_parentParser)
-#define paramEntityParsing (((Parser *)parser)->m_paramEntityParsing)
-#endif /* XML_DTD */
-
-#ifdef COMPILED_FROM_DSP
-BOOL WINAPI DllMain(HINSTANCE h, DWORD r, LPVOID p) {
- return TRUE;
-}
-#endif /* def COMPILED_FROM_DSP */
-
-#ifdef _MSC_VER
-#ifdef _DEBUG
-Parser *asParser(XML_Parser parser)
-{
- return parser;
-}
-#endif
-#endif
-
-XML_Parser XML_ParserCreate(const XML_Char *encodingName)
-{
- return XML_ParserCreate_MM(encodingName, NULL, NULL);
-}
-
-XML_Parser XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep)
-{
- XML_Char tmp[2];
- *tmp = nsSep;
- return XML_ParserCreate_MM(encodingName, NULL, tmp);
-}
-
-XML_Parser
-XML_ParserCreate_MM(const XML_Char *encodingName,
- const XML_Memory_Handling_Suite *memsuite,
- const XML_Char *nameSep) {
-
- XML_Parser parser;
- static
- const XML_Char implicitContext[] = {
- XML_T('x'), XML_T('m'), XML_T('l'), XML_T('='),
- XML_T('h'), XML_T('t'), XML_T('t'), XML_T('p'), XML_T(':'),
- XML_T('/'), XML_T('/'), XML_T('w'), XML_T('w'), XML_T('w'),
- XML_T('.'), XML_T('w'), XML_T('3'),
- XML_T('.'), XML_T('o'), XML_T('r'), XML_T('g'),
- XML_T('/'), XML_T('X'), XML_T('M'), XML_T('L'),
- XML_T('/'), XML_T('1'), XML_T('9'), XML_T('9'), XML_T('8'),
- XML_T('/'), XML_T('n'), XML_T('a'), XML_T('m'), XML_T('e'),
- XML_T('s'), XML_T('p'), XML_T('a'), XML_T('c'), XML_T('e'),
- XML_T('\0')
- };
-
-
- if (memsuite) {
- XML_Memory_Handling_Suite *mtemp;
- parser = memsuite->malloc_fcn(sizeof(Parser));
- mtemp = &(((Parser *) parser)->m_mem);
- mtemp->malloc_fcn = memsuite->malloc_fcn;
- mtemp->realloc_fcn = memsuite->realloc_fcn;
- mtemp->free_fcn = memsuite->free_fcn;
- }
- else {
- XML_Memory_Handling_Suite *mtemp;
- parser = malloc(sizeof(Parser));
- mtemp = &(((Parser *) parser)->m_mem);
- mtemp->malloc_fcn = malloc;
- mtemp->realloc_fcn = realloc;
- mtemp->free_fcn = free;
- }
-
- if (!parser)
- return parser;
- processor = prologInitProcessor;
- XmlPrologStateInit(&prologState);
- userData = 0;
- handlerArg = 0;
- startElementHandler = 0;
- endElementHandler = 0;
- characterDataHandler = 0;
- processingInstructionHandler = 0;
- commentHandler = 0;
- startCdataSectionHandler = 0;
- endCdataSectionHandler = 0;
- defaultHandler = 0;
- startDoctypeDeclHandler = 0;
- endDoctypeDeclHandler = 0;
- unparsedEntityDeclHandler = 0;
- notationDeclHandler = 0;
- startNamespaceDeclHandler = 0;
- endNamespaceDeclHandler = 0;
- notStandaloneHandler = 0;
- externalEntityRefHandler = 0;
- externalEntityRefHandlerArg = parser;
- unknownEncodingHandler = 0;
- elementDeclHandler = 0;
- attlistDeclHandler = 0;
- entityDeclHandler = 0;
- xmlDeclHandler = 0;
- buffer = 0;
- bufferPtr = 0;
- bufferEnd = 0;
- parseEndByteIndex = 0;
- parseEndPtr = 0;
- bufferLim = 0;
- declElementType = 0;
- declAttributeId = 0;
- declEntity = 0;
- doctypeName = 0;
- doctypeSysid = 0;
- doctypePubid = 0;
- declAttributeType = 0;
- declNotationName = 0;
- declNotationPublicId = 0;
- memset(&position, 0, sizeof(POSITION));
- errorCode = XML_ERROR_NONE;
- eventPtr = 0;
- eventEndPtr = 0;
- positionPtr = 0;
- openInternalEntities = 0;
- tagLevel = 0;
- tagStack = 0;
- freeTagList = 0;
- freeBindingList = 0;
- inheritedBindings = 0;
- attsSize = INIT_ATTS_SIZE;
- atts = MALLOC(attsSize * sizeof(ATTRIBUTE));
- nSpecifiedAtts = 0;
- dataBuf = MALLOC(INIT_DATA_BUF_SIZE * sizeof(XML_Char));
- groupSize = 0;
- groupConnector = 0;
- hadExternalDoctype = 0;
- unknownEncodingMem = 0;
- unknownEncodingRelease = 0;
- unknownEncodingData = 0;
- unknownEncodingHandlerData = 0;
- namespaceSeparator = '!';
-#ifdef XML_DTD
- parentParser = 0;
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
-#endif
- ns = 0;
- ns_triplets = 0;
- poolInit(&tempPool, &(((Parser *) parser)->m_mem));
- poolInit(&temp2Pool, &(((Parser *) parser)->m_mem));
- protocolEncodingName = encodingName ? poolCopyString(&tempPool, encodingName) : 0;
- curBase = 0;
- if (!dtdInit(&dtd, parser) || !atts || !dataBuf
- || (encodingName && !protocolEncodingName)) {
- XML_ParserFree(parser);
- return 0;
- }
- dataBufEnd = dataBuf + INIT_DATA_BUF_SIZE;
-
- if (nameSep) {
- XmlInitEncodingNS(&initEncoding, &encoding, 0);
- ns = 1;
- internalEncoding = XmlGetInternalEncodingNS();
- namespaceSeparator = *nameSep;
-
- if (! setContext(parser, implicitContext)) {
- XML_ParserFree(parser);
- return 0;
- }
- }
- else {
- XmlInitEncoding(&initEncoding, &encoding, 0);
- internalEncoding = XmlGetInternalEncoding();
- }
-
- return parser;
-} /* End XML_ParserCreate_MM */
-
-int XML_SetEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
- if (!encodingName)
- protocolEncodingName = 0;
- else {
- protocolEncodingName = poolCopyString(&tempPool, encodingName);
- if (!protocolEncodingName)
- return 0;
- }
- return 1;
-}
-
-XML_Parser XML_ExternalEntityParserCreate(XML_Parser oldParser,
- const XML_Char *context,
- const XML_Char *encodingName)
-{
- XML_Parser parser = oldParser;
- DTD *oldDtd = &dtd;
- XML_StartElementHandler oldStartElementHandler = startElementHandler;
- XML_EndElementHandler oldEndElementHandler = endElementHandler;
- XML_CharacterDataHandler oldCharacterDataHandler = characterDataHandler;
- XML_ProcessingInstructionHandler oldProcessingInstructionHandler = processingInstructionHandler;
- XML_CommentHandler oldCommentHandler = commentHandler;
- XML_StartCdataSectionHandler oldStartCdataSectionHandler = startCdataSectionHandler;
- XML_EndCdataSectionHandler oldEndCdataSectionHandler = endCdataSectionHandler;
- XML_DefaultHandler oldDefaultHandler = defaultHandler;
- XML_UnparsedEntityDeclHandler oldUnparsedEntityDeclHandler = unparsedEntityDeclHandler;
- XML_NotationDeclHandler oldNotationDeclHandler = notationDeclHandler;
- XML_StartNamespaceDeclHandler oldStartNamespaceDeclHandler = startNamespaceDeclHandler;
- XML_EndNamespaceDeclHandler oldEndNamespaceDeclHandler = endNamespaceDeclHandler;
- XML_NotStandaloneHandler oldNotStandaloneHandler = notStandaloneHandler;
- XML_ExternalEntityRefHandler oldExternalEntityRefHandler = externalEntityRefHandler;
- XML_UnknownEncodingHandler oldUnknownEncodingHandler = unknownEncodingHandler;
- XML_ElementDeclHandler oldElementDeclHandler = elementDeclHandler;
- XML_AttlistDeclHandler oldAttlistDeclHandler = attlistDeclHandler;
- XML_EntityDeclHandler oldEntityDeclHandler = entityDeclHandler;
- XML_XmlDeclHandler oldXmlDeclHandler = xmlDeclHandler;
- ELEMENT_TYPE * oldDeclElementType = declElementType;
-
- void *oldUserData = userData;
- void *oldHandlerArg = handlerArg;
- int oldDefaultExpandInternalEntities = defaultExpandInternalEntities;
- void *oldExternalEntityRefHandlerArg = externalEntityRefHandlerArg;
-#ifdef XML_DTD
- enum XML_ParamEntityParsing oldParamEntityParsing = paramEntityParsing;
-#endif
- int oldns_triplets = ns_triplets;
-
- if (ns) {
- XML_Char tmp[2];
-
- *tmp = namespaceSeparator;
- parser = XML_ParserCreate_MM(encodingName, &((Parser *)parser)->m_mem,
- tmp);
- }
- else {
- parser = XML_ParserCreate_MM(encodingName, &((Parser *)parser)->m_mem,
- NULL);
- }
-
- if (!parser)
- return 0;
-
- startElementHandler = oldStartElementHandler;
- endElementHandler = oldEndElementHandler;
- characterDataHandler = oldCharacterDataHandler;
- processingInstructionHandler = oldProcessingInstructionHandler;
- commentHandler = oldCommentHandler;
- startCdataSectionHandler = oldStartCdataSectionHandler;
- endCdataSectionHandler = oldEndCdataSectionHandler;
- defaultHandler = oldDefaultHandler;
- unparsedEntityDeclHandler = oldUnparsedEntityDeclHandler;
- notationDeclHandler = oldNotationDeclHandler;
- startNamespaceDeclHandler = oldStartNamespaceDeclHandler;
- endNamespaceDeclHandler = oldEndNamespaceDeclHandler;
- notStandaloneHandler = oldNotStandaloneHandler;
- externalEntityRefHandler = oldExternalEntityRefHandler;
- unknownEncodingHandler = oldUnknownEncodingHandler;
- elementDeclHandler = oldElementDeclHandler;
- attlistDeclHandler = oldAttlistDeclHandler;
- entityDeclHandler = oldEntityDeclHandler;
- xmlDeclHandler = oldXmlDeclHandler;
- declElementType = oldDeclElementType;
- userData = oldUserData;
- if (oldUserData == oldHandlerArg)
- handlerArg = userData;
- else
- handlerArg = parser;
- if (oldExternalEntityRefHandlerArg != oldParser)
- externalEntityRefHandlerArg = oldExternalEntityRefHandlerArg;
- defaultExpandInternalEntities = oldDefaultExpandInternalEntities;
- ns_triplets = oldns_triplets;
-#ifdef XML_DTD
- paramEntityParsing = oldParamEntityParsing;
- if (context) {
-#endif /* XML_DTD */
- if (!dtdCopy(&dtd, oldDtd, parser) || !setContext(parser, context)) {
- XML_ParserFree(parser);
- return 0;
- }
- processor = externalEntityInitProcessor;
-#ifdef XML_DTD
- }
- else {
- dtdSwap(&dtd, oldDtd);
- parentParser = oldParser;
- XmlPrologStateInitExternalEntity(&prologState);
- dtd.complete = 1;
- hadExternalDoctype = 1;
- }
-#endif /* XML_DTD */
- return parser;
-}
-
-static
-void destroyBindings(BINDING *bindings, XML_Parser parser)
-{
- for (;;) {
- BINDING *b = bindings;
- if (!b)
- break;
- bindings = b->nextTagBinding;
- FREE(b->uri);
- FREE(b);
- }
-}
-
-void XML_ParserFree(XML_Parser parser)
-{
- for (;;) {
- TAG *p;
- if (tagStack == 0) {
- if (freeTagList == 0)
- break;
- tagStack = freeTagList;
- freeTagList = 0;
- }
- p = tagStack;
- tagStack = tagStack->parent;
- FREE(p->buf);
- destroyBindings(p->bindings, parser);
- FREE(p);
- }
- destroyBindings(freeBindingList, parser);
- destroyBindings(inheritedBindings, parser);
- poolDestroy(&tempPool);
- poolDestroy(&temp2Pool);
-#ifdef XML_DTD
- if (parentParser) {
- if (hadExternalDoctype)
- dtd.complete = 0;
- dtdSwap(&dtd, &((Parser *)parentParser)->m_dtd);
- }
-#endif /* XML_DTD */
- dtdDestroy(&dtd, parser);
- FREE((void *)atts);
- if (groupConnector)
- FREE(groupConnector);
- if (buffer)
- FREE(buffer);
- FREE(dataBuf);
- if (unknownEncodingMem)
- FREE(unknownEncodingMem);
- if (unknownEncodingRelease)
- unknownEncodingRelease(unknownEncodingData);
- FREE(parser);
-}
-
-void XML_UseParserAsHandlerArg(XML_Parser parser)
-{
- handlerArg = parser;
-}
-
-void
-XML_SetReturnNSTriplet(XML_Parser parser, int do_nst) {
- ns_triplets = do_nst;
-}
-
-void XML_SetUserData(XML_Parser parser, void *p)
-{
- if (handlerArg == userData)
- handlerArg = userData = p;
- else
- userData = p;
-}
-
-int XML_SetBase(XML_Parser parser, const XML_Char *p)
-{
- if (p) {
- p = poolCopyString(&dtd.pool, p);
- if (!p)
- return 0;
- curBase = p;
- }
- else
- curBase = 0;
- return 1;
-}
-
-const XML_Char *XML_GetBase(XML_Parser parser)
-{
- return curBase;
-}
-
-int XML_GetSpecifiedAttributeCount(XML_Parser parser)
-{
- return nSpecifiedAtts;
-}
-
-int XML_GetIdAttributeIndex(XML_Parser parser)
-{
- return idAttIndex;
-}
-
-void XML_SetElementHandler(XML_Parser parser,
- XML_StartElementHandler start,
- XML_EndElementHandler end)
-{
- startElementHandler = start;
- endElementHandler = end;
-}
-
-void XML_SetStartElementHandler(XML_Parser parser,
- XML_StartElementHandler start) {
- startElementHandler = start;
-}
-
-void XML_SetEndElementHandler(XML_Parser parser,
- XML_EndElementHandler end) {
- endElementHandler = end;
-}
-
-void XML_SetCharacterDataHandler(XML_Parser parser,
- XML_CharacterDataHandler handler)
-{
- characterDataHandler = handler;
-}
-
-void XML_SetProcessingInstructionHandler(XML_Parser parser,
- XML_ProcessingInstructionHandler handler)
-{
- processingInstructionHandler = handler;
-}
-
-void XML_SetCommentHandler(XML_Parser parser,
- XML_CommentHandler handler)
-{
- commentHandler = handler;
-}
-
-void XML_SetCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start,
- XML_EndCdataSectionHandler end)
-{
- startCdataSectionHandler = start;
- endCdataSectionHandler = end;
-}
-
-void XML_SetStartCdataSectionHandler(XML_Parser parser,
- XML_StartCdataSectionHandler start) {
- startCdataSectionHandler = start;
-}
-
-void XML_SetEndCdataSectionHandler(XML_Parser parser,
- XML_EndCdataSectionHandler end) {
- endCdataSectionHandler = end;
-}
-
-void XML_SetDefaultHandler(XML_Parser parser,
- XML_DefaultHandler handler)
-{
- defaultHandler = handler;
- defaultExpandInternalEntities = 0;
-}
-
-void XML_SetDefaultHandlerExpand(XML_Parser parser,
- XML_DefaultHandler handler)
-{
- defaultHandler = handler;
- defaultExpandInternalEntities = 1;
-}
-
-void XML_SetDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start,
- XML_EndDoctypeDeclHandler end)
-{
- startDoctypeDeclHandler = start;
- endDoctypeDeclHandler = end;
-}
-
-void XML_SetStartDoctypeDeclHandler(XML_Parser parser,
- XML_StartDoctypeDeclHandler start) {
- startDoctypeDeclHandler = start;
-}
-
-void XML_SetEndDoctypeDeclHandler(XML_Parser parser,
- XML_EndDoctypeDeclHandler end) {
- endDoctypeDeclHandler = end;
-}
-
-void XML_SetUnparsedEntityDeclHandler(XML_Parser parser,
- XML_UnparsedEntityDeclHandler handler)
-{
- unparsedEntityDeclHandler = handler;
-}
-
-void XML_SetNotationDeclHandler(XML_Parser parser,
- XML_NotationDeclHandler handler)
-{
- notationDeclHandler = handler;
-}
-
-void XML_SetNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start,
- XML_EndNamespaceDeclHandler end)
-{
- startNamespaceDeclHandler = start;
- endNamespaceDeclHandler = end;
-}
-
-void XML_SetStartNamespaceDeclHandler(XML_Parser parser,
- XML_StartNamespaceDeclHandler start) {
- startNamespaceDeclHandler = start;
-}
-
-void XML_SetEndNamespaceDeclHandler(XML_Parser parser,
- XML_EndNamespaceDeclHandler end) {
- endNamespaceDeclHandler = end;
-}
-
-
-void XML_SetNotStandaloneHandler(XML_Parser parser,
- XML_NotStandaloneHandler handler)
-{
- notStandaloneHandler = handler;
-}
-
-void XML_SetExternalEntityRefHandler(XML_Parser parser,
- XML_ExternalEntityRefHandler handler)
-{
- externalEntityRefHandler = handler;
-}
-
-void XML_SetExternalEntityRefHandlerArg(XML_Parser parser, void *arg)
-{
- if (arg)
- externalEntityRefHandlerArg = arg;
- else
- externalEntityRefHandlerArg = parser;
-}
-
-void XML_SetUnknownEncodingHandler(XML_Parser parser,
- XML_UnknownEncodingHandler handler,
- void *data)
-{
- unknownEncodingHandler = handler;
- unknownEncodingHandlerData = data;
-}
-
-void XML_SetElementDeclHandler(XML_Parser parser,
- XML_ElementDeclHandler eldecl)
-{
- elementDeclHandler = eldecl;
-}
-
-void XML_SetAttlistDeclHandler(XML_Parser parser,
- XML_AttlistDeclHandler attdecl)
-{
- attlistDeclHandler = attdecl;
-}
-
-void XML_SetEntityDeclHandler(XML_Parser parser,
- XML_EntityDeclHandler handler)
-{
- entityDeclHandler = handler;
-}
-
-void XML_SetXmlDeclHandler(XML_Parser parser,
- XML_XmlDeclHandler handler) {
- xmlDeclHandler = handler;
-}
-
-int XML_SetParamEntityParsing(XML_Parser parser,
- enum XML_ParamEntityParsing parsing)
-{
-#ifdef XML_DTD
- paramEntityParsing = parsing;
- return 1;
-#else
- return parsing == XML_PARAM_ENTITY_PARSING_NEVER;
-#endif
-}
-
-int XML_Parse(XML_Parser parser, const char *s, int len, int isFinal)
-{
- if (len == 0) {
- if (!isFinal)
- return 1;
- positionPtr = bufferPtr;
- errorCode = processor(parser, bufferPtr, parseEndPtr = bufferEnd, 0);
- if (errorCode == XML_ERROR_NONE)
- return 1;
- eventEndPtr = eventPtr;
- processor = errorProcessor;
- return 0;
- }
-#ifndef XML_CONTEXT_BYTES
- else if (bufferPtr == bufferEnd) {
- const char *end;
- int nLeftOver;
- parseEndByteIndex += len;
- positionPtr = s;
- if (isFinal) {
- errorCode = processor(parser, s, parseEndPtr = s + len, 0);
- if (errorCode == XML_ERROR_NONE)
- return 1;
- eventEndPtr = eventPtr;
- processor = errorProcessor;
- return 0;
- }
- errorCode = processor(parser, s, parseEndPtr = s + len, &end);
- if (errorCode != XML_ERROR_NONE) {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
- return 0;
- }
- XmlUpdatePosition(encoding, positionPtr, end, &position);
- nLeftOver = s + len - end;
- if (nLeftOver) {
- if (buffer == 0 || nLeftOver > bufferLim - buffer) {
- /* FIXME avoid integer overflow */
- buffer = buffer == 0 ? MALLOC(len * 2) : REALLOC(buffer, len * 2);
- /* FIXME storage leak if realloc fails */
- if (!buffer) {
- errorCode = XML_ERROR_NO_MEMORY;
- eventPtr = eventEndPtr = 0;
- processor = errorProcessor;
- return 0;
- }
- bufferLim = buffer + len * 2;
- }
- memcpy(buffer, end, nLeftOver);
- bufferPtr = buffer;
- bufferEnd = buffer + nLeftOver;
- }
- return 1;
- }
-#endif /* not defined XML_CONTEXT_BYTES */
- else {
- memcpy(XML_GetBuffer(parser, len), s, len);
- return XML_ParseBuffer(parser, len, isFinal);
- }
-}
-
-int XML_ParseBuffer(XML_Parser parser, int len, int isFinal)
-{
- const char *start = bufferPtr;
- positionPtr = start;
- bufferEnd += len;
- parseEndByteIndex += len;
- errorCode = processor(parser, start, parseEndPtr = bufferEnd,
- isFinal ? (const char **)0 : &bufferPtr);
- if (errorCode == XML_ERROR_NONE) {
- if (!isFinal)
- XmlUpdatePosition(encoding, positionPtr, bufferPtr, &position);
- return 1;
- }
- else {
- eventEndPtr = eventPtr;
- processor = errorProcessor;
- return 0;
- }
-}
-
-void *XML_GetBuffer(XML_Parser parser, int len)
-{
- if (len > bufferLim - bufferEnd) {
- /* FIXME avoid integer overflow */
- int neededSize = len + (bufferEnd - bufferPtr);
-#ifdef XML_CONTEXT_BYTES
- int keep = bufferPtr - buffer;
-
- if (keep > XML_CONTEXT_BYTES)
- keep = XML_CONTEXT_BYTES;
- neededSize += keep;
-#endif /* defined XML_CONTEXT_BYTES */
- if (neededSize <= bufferLim - buffer) {
-#ifdef XML_CONTEXT_BYTES
- if (keep < bufferPtr - buffer) {
- int offset = (bufferPtr - buffer) - keep;
- memmove(buffer, &buffer[offset], bufferEnd - bufferPtr + keep);
- bufferEnd -= offset;
- bufferPtr -= offset;
- }
-#else
- memmove(buffer, bufferPtr, bufferEnd - bufferPtr);
- bufferEnd = buffer + (bufferEnd - bufferPtr);
- bufferPtr = buffer;
-#endif /* not defined XML_CONTEXT_BYTES */
- }
- else {
- char *newBuf;
- int bufferSize = bufferLim - bufferPtr;
- if (bufferSize == 0)
- bufferSize = INIT_BUFFER_SIZE;
- do {
- bufferSize *= 2;
- } while (bufferSize < neededSize);
- newBuf = MALLOC(bufferSize);
- if (newBuf == 0) {
- errorCode = XML_ERROR_NO_MEMORY;
- return 0;
- }
- bufferLim = newBuf + bufferSize;
-#ifdef XML_CONTEXT_BYTES
- if (bufferPtr) {
- int xmKeep = bufferPtr - buffer;
- if (xmKeep > XML_CONTEXT_BYTES)
- xmKeep = XML_CONTEXT_BYTES;
- memcpy(newBuf, &bufferPtr[-xmKeep], bufferEnd - bufferPtr + xmKeep);
- FREE(buffer);
- buffer = newBuf;
- bufferEnd = buffer + (bufferEnd - bufferPtr) + xmKeep;
- bufferPtr = buffer + xmKeep;
- }
- else {
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
- }
-#else
- if (bufferPtr) {
- memcpy(newBuf, bufferPtr, bufferEnd - bufferPtr);
- FREE(buffer);
- }
- bufferEnd = newBuf + (bufferEnd - bufferPtr);
- bufferPtr = buffer = newBuf;
-#endif /* not defined XML_CONTEXT_BYTES */
- }
- }
- return bufferEnd;
-}
-
-enum XML_Error XML_GetErrorCode(XML_Parser parser)
-{
- return errorCode;
-}
-
-long XML_GetCurrentByteIndex(XML_Parser parser)
-{
- if (eventPtr)
- return parseEndByteIndex - (parseEndPtr - eventPtr);
- return -1;
-}
-
-int XML_GetCurrentByteCount(XML_Parser parser)
-{
- if (eventEndPtr && eventPtr)
- return eventEndPtr - eventPtr;
- return 0;
-}
-
-const char * XML_GetInputContext(XML_Parser parser, int *offset, int *size)
-{
-#ifdef XML_CONTEXT_BYTES
- if (eventPtr && buffer) {
- *offset = eventPtr - buffer;
- *size = bufferEnd - buffer;
- return buffer;
- }
-#endif /* defined XML_CONTEXT_BYTES */
- return (char *) 0;
-}
-
-int XML_GetCurrentLineNumber(XML_Parser parser)
-{
- if (eventPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
- }
- return position.lineNumber + 1;
-}
-
-int XML_GetCurrentColumnNumber(XML_Parser parser)
-{
- if (eventPtr) {
- XmlUpdatePosition(encoding, positionPtr, eventPtr, &position);
- positionPtr = eventPtr;
- }
- return position.columnNumber;
-}
-
-void XML_DefaultCurrent(XML_Parser parser)
-{
- if (defaultHandler) {
- if (openInternalEntities)
- reportDefault(parser,
- internalEncoding,
- openInternalEntities->internalEventPtr,
- openInternalEntities->internalEventEndPtr);
- else
- reportDefault(parser, encoding, eventPtr, eventEndPtr);
- }
-}
-
-const XML_LChar *XML_ErrorString(int code)
-{
- static const XML_LChar *message[] = {
- 0,
- XML_T("out of memory"),
- XML_T("syntax error"),
- XML_T("no element found"),
- XML_T("not well-formed (invalid token)"),
- XML_T("unclosed token"),
- XML_T("unclosed token"),
- XML_T("mismatched tag"),
- XML_T("duplicate attribute"),
- XML_T("junk after document element"),
- XML_T("illegal parameter entity reference"),
- XML_T("undefined entity"),
- XML_T("recursive entity reference"),
- XML_T("asynchronous entity"),
- XML_T("reference to invalid character number"),
- XML_T("reference to binary entity"),
- XML_T("reference to external entity in attribute"),
- XML_T("xml processing instruction not at start of external entity"),
- XML_T("unknown encoding"),
- XML_T("encoding specified in XML declaration is incorrect"),
- XML_T("unclosed CDATA section"),
- XML_T("error in processing external entity reference"),
- XML_T("document is not standalone"),
- XML_T("unexpected parser state - please send a bug report")
- };
- if (code > 0 && code < (int)(sizeof(message)/sizeof(message[0])))
- return message[code];
- return 0;
-}
-
-const XML_LChar *
-XML_ExpatVersion(void) {
- return VERSION;
-}
-
-XML_Expat_Version
-XML_ExpatVersionInfo(void) {
- XML_Expat_Version version;
-
- version.major = XML_MAJOR_VERSION;
- version.minor = XML_MINOR_VERSION;
- version.micro = XML_MICRO_VERSION;
-
- return version;
-}
-
-static
-enum XML_Error contentProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- return doContent(parser, 0, encoding, start, end, endPtr);
-}
-
-static
-enum XML_Error externalEntityInitProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = initializeEncoding(parser);
- if (result != XML_ERROR_NONE)
- return result;
- processor = externalEntityInitProcessor2;
- return externalEntityInitProcessor2(parser, start, end, endPtr);
-}
-
-static
-enum XML_Error externalEntityInitProcessor2(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- const char *next;
- int tok = XmlContentTok(encoding, start, end, &next);
- switch (tok) {
- case XML_TOK_BOM:
- start = next;
- break;
- case XML_TOK_PARTIAL:
- if (endPtr) {
- *endPtr = start;
- return XML_ERROR_NONE;
- }
- eventPtr = start;
- return XML_ERROR_UNCLOSED_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (endPtr) {
- *endPtr = start;
- return XML_ERROR_NONE;
- }
- eventPtr = start;
- return XML_ERROR_PARTIAL_CHAR;
- }
- processor = externalEntityInitProcessor3;
- return externalEntityInitProcessor3(parser, start, end, endPtr);
-}
-
-static
-enum XML_Error externalEntityInitProcessor3(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- const char *next;
- int tok = XmlContentTok(encoding, start, end, &next);
- switch (tok) {
- case XML_TOK_XML_DECL:
- {
- enum XML_Error result = processXmlDecl(parser, 1, start, next);
- if (result != XML_ERROR_NONE)
- return result;
- start = next;
- }
- break;
- case XML_TOK_PARTIAL:
- if (endPtr) {
- *endPtr = start;
- return XML_ERROR_NONE;
- }
- eventPtr = start;
- return XML_ERROR_UNCLOSED_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (endPtr) {
- *endPtr = start;
- return XML_ERROR_NONE;
- }
- eventPtr = start;
- return XML_ERROR_PARTIAL_CHAR;
- }
- processor = externalEntityContentProcessor;
- tagLevel = 1;
- return doContent(parser, 1, encoding, start, end, endPtr);
-}
-
-static
-enum XML_Error externalEntityContentProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- return doContent(parser, 1, encoding, start, end, endPtr);
-}
-
-static enum XML_Error
-doContent(XML_Parser parser,
- int startTagLevel,
- const ENCODING *enc,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- const char **eventPP;
- const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
- }
- *eventPP = s;
- for (;;) {
- const char *next = s; /* XmlContentTok doesn't always set the last arg */
- int tok = XmlContentTok(enc, s, end, &next);
- *eventEndPP = next;
- switch (tok) {
- case XML_TOK_TRAILING_CR:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- *eventEndPP = end;
- if (characterDataHandler) {
- XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, end);
- if (startTagLevel == 0)
- return XML_ERROR_NO_ELEMENTS;
- if (tagLevel != startTagLevel)
- return XML_ERROR_ASYNC_ENTITY;
- return XML_ERROR_NONE;
- case XML_TOK_NONE:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- if (startTagLevel > 0) {
- if (tagLevel != startTagLevel)
- return XML_ERROR_ASYNC_ENTITY;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_NO_ELEMENTS;
- case XML_TOK_INVALID:
- *eventPP = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_UNCLOSED_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_ENTITY_REF:
- {
- const XML_Char *name;
- ENTITY *entity;
- XML_Char ch = XmlPredefinedEntityName(enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (ch) {
- if (characterDataHandler)
- characterDataHandler(handlerArg, &ch, 1);
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
- name = poolStoreString(&dtd.pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0);
- poolDiscard(&dtd.pool);
- if (!entity) {
- if (dtd.complete || dtd.standalone)
- return XML_ERROR_UNDEFINED_ENTITY;
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
- if (entity->open)
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- if (entity->notation)
- return XML_ERROR_BINARY_ENTITY_REF;
- if (entity) {
- if (entity->textPtr) {
- enum XML_Error result;
- OPEN_INTERNAL_ENTITY openEntity;
- if (defaultHandler && !defaultExpandInternalEntities) {
- reportDefault(parser, enc, s, next);
- break;
- }
- entity->open = 1;
- openEntity.next = openInternalEntities;
- openInternalEntities = &openEntity;
- openEntity.entity = entity;
- openEntity.internalEventPtr = 0;
- openEntity.internalEventEndPtr = 0;
- result = doContent(parser,
- tagLevel,
- internalEncoding,
- (char *)entity->textPtr,
- (char *)(entity->textPtr + entity->textLen),
- 0);
- entity->open = 0;
- openInternalEntities = openEntity.next;
- if (result)
- return result;
- }
- else if (externalEntityRefHandler) {
- const XML_Char *context;
- entity->open = 1;
- context = getContext(parser);
- entity->open = 0;
- if (!context)
- return XML_ERROR_NO_MEMORY;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- context,
- entity->base,
- entity->systemId,
- entity->publicId))
- return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- poolDiscard(&tempPool);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- }
- break;
- }
- case XML_TOK_START_TAG_WITH_ATTS:
- if (!startElementHandler) {
- enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
- if (result)
- return result;
- }
- /* fall through */
- case XML_TOK_START_TAG_NO_ATTS:
- {
- TAG *tag;
- if (freeTagList) {
- tag = freeTagList;
- freeTagList = freeTagList->parent;
- }
- else {
- tag = MALLOC(sizeof(TAG));
- if (!tag)
- return XML_ERROR_NO_MEMORY;
- tag->buf = MALLOC(INIT_TAG_BUF_SIZE);
- if (!tag->buf)
- return XML_ERROR_NO_MEMORY;
- tag->bufEnd = tag->buf + INIT_TAG_BUF_SIZE;
- }
- tag->bindings = 0;
- tag->parent = tagStack;
- tagStack = tag;
- tag->name.localPart = 0;
- tag->rawName = s + enc->minBytesPerChar;
- tag->rawNameLength = XmlNameLength(enc, tag->rawName);
- if (nextPtr) {
- /* Need to guarantee that:
- tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)) <= tag->bufEnd - sizeof(XML_Char) */
- if (tag->rawNameLength + (int)(sizeof(XML_Char) - 1) + (int)sizeof(XML_Char) > tag->bufEnd - tag->buf) {
- int bufSize = tag->rawNameLength * 4;
- bufSize = ROUND_UP(bufSize, sizeof(XML_Char));
- tag->buf = REALLOC(tag->buf, bufSize);
- if (!tag->buf)
- return XML_ERROR_NO_MEMORY;
- tag->bufEnd = tag->buf + bufSize;
- }
- memcpy(tag->buf, tag->rawName, tag->rawNameLength);
- tag->rawName = tag->buf;
- }
- ++tagLevel;
- if (startElementHandler) {
- enum XML_Error result;
- XML_Char *toPtr;
- for (;;) {
- const char *rawNameEnd = tag->rawName + tag->rawNameLength;
- const char *fromPtr = tag->rawName;
- int bufSize;
- if (nextPtr)
- toPtr = (XML_Char *)(tag->buf + ROUND_UP(tag->rawNameLength, sizeof(XML_Char)));
- else
- toPtr = (XML_Char *)tag->buf;
- tag->name.str = toPtr;
- XmlConvert(enc,
- &fromPtr, rawNameEnd,
- (ICHAR **)&toPtr, (ICHAR *)tag->bufEnd - 1);
- if (fromPtr == rawNameEnd)
- break;
- bufSize = (tag->bufEnd - tag->buf) << 1;
- tag->buf = REALLOC(tag->buf, bufSize);
- if (!tag->buf)
- return XML_ERROR_NO_MEMORY;
- tag->bufEnd = tag->buf + bufSize;
- if (nextPtr)
- tag->rawName = tag->buf;
- }
- *toPtr = XML_T('\0');
- result = storeAtts(parser, enc, s, &(tag->name), &(tag->bindings));
- if (result)
- return result;
- startElementHandler(handlerArg, tag->name.str, (const XML_Char **)atts);
- poolClear(&tempPool);
- }
- else {
- tag->name.str = 0;
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- }
- break;
- }
- case XML_TOK_EMPTY_ELEMENT_WITH_ATTS:
- if (!startElementHandler) {
- enum XML_Error result = storeAtts(parser, enc, s, 0, 0);
- if (result)
- return result;
- }
- /* fall through */
- case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
- if (startElementHandler || endElementHandler) {
- const char *rawName = s + enc->minBytesPerChar;
- enum XML_Error result;
- BINDING *bindings = 0;
- TAG_NAME name;
- name.str = poolStoreString(&tempPool, enc, rawName,
- rawName + XmlNameLength(enc, rawName));
- if (!name.str)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- result = storeAtts(parser, enc, s, &name, &bindings);
- if (result)
- return result;
- poolFinish(&tempPool);
- if (startElementHandler)
- startElementHandler(handlerArg, name.str, (const XML_Char **)atts);
- if (endElementHandler) {
- if (startElementHandler)
- *eventPP = *eventEndPP;
- endElementHandler(handlerArg, name.str);
- }
- poolClear(&tempPool);
- while (bindings) {
- BINDING *b = bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
- bindings = bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
- b->prefix->binding = b->prevPrefixBinding;
- }
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
- break;
- case XML_TOK_END_TAG:
- if (tagLevel == startTagLevel)
- return XML_ERROR_ASYNC_ENTITY;
- else {
- int len;
- const char *rawName;
- TAG *tag = tagStack;
- tagStack = tag->parent;
- tag->parent = freeTagList;
- freeTagList = tag;
- rawName = s + enc->minBytesPerChar*2;
- len = XmlNameLength(enc, rawName);
- if (len != tag->rawNameLength
- || memcmp(tag->rawName, rawName, len) != 0) {
- *eventPP = rawName;
- return XML_ERROR_TAG_MISMATCH;
- }
- --tagLevel;
- if (endElementHandler && tag->name.str) {
- if (tag->name.localPart) {
- XML_Char *to = (XML_Char *)tag->name.str + tag->name.uriLen;
- const XML_Char *from = tag->name.localPart;
- while ((*to++ = *from++) != 0)
- ;
- }
- endElementHandler(handlerArg, tag->name.str);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- while (tag->bindings) {
- BINDING *b = tag->bindings;
- if (endNamespaceDeclHandler)
- endNamespaceDeclHandler(handlerArg, b->prefix->name);
- tag->bindings = tag->bindings->nextTagBinding;
- b->nextTagBinding = freeBindingList;
- freeBindingList = b;
- b->prefix->binding = b->prevPrefixBinding;
- }
- if (tagLevel == 0)
- return epilogProcessor(parser, next, end, nextPtr);
- }
- break;
- case XML_TOK_CHAR_REF:
- {
- int n = XmlCharRefNumber(enc, s);
- if (n < 0)
- return XML_ERROR_BAD_CHAR_REF;
- if (characterDataHandler) {
- XML_Char buf[XML_ENCODE_MAX];
- characterDataHandler(handlerArg, buf, XmlEncode(n, (ICHAR *)buf));
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- }
- break;
- case XML_TOK_XML_DECL:
- return XML_ERROR_MISPLACED_XML_PI;
- case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
- XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- case XML_TOK_CDATA_SECT_OPEN:
- {
- enum XML_Error result;
- if (startCdataSectionHandler)
- startCdataSectionHandler(handlerArg);
-#if 0
- /* Suppose you doing a transformation on a document that involves
- changing only the character data. You set up a defaultHandler
- and a characterDataHandler. The defaultHandler simply copies
- characters through. The characterDataHandler does the transformation
- and writes the characters out escaping them as necessary. This case
- will fail to work if we leave out the following two lines (because &
- and < inside CDATA sections will be incorrectly escaped).
-
- However, now we have a start/endCdataSectionHandler, so it seems
- easier to let the user deal with this. */
-
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- result = doCdataSection(parser, enc, &next, end, nextPtr);
- if (!next) {
- processor = cdataSectionProcessor;
- return result;
- }
- }
- break;
- case XML_TOK_TRAILING_RSQB:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- if (characterDataHandler) {
- if (MUST_CONVERT(enc, s)) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
- characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
- }
- else
- characterDataHandler(handlerArg,
- (XML_Char *)s,
- (XML_Char *)end - (XML_Char *)s);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, end);
- if (startTagLevel == 0) {
- *eventPP = end;
- return XML_ERROR_NO_ELEMENTS;
- }
- if (tagLevel != startTagLevel) {
- *eventPP = end;
- return XML_ERROR_ASYNC_ENTITY;
- }
- return XML_ERROR_NONE;
- case XML_TOK_DATA_CHARS:
- if (characterDataHandler) {
- if (MUST_CONVERT(enc, s)) {
- for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
- *eventEndPP = s;
- characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
- if (s == next)
- break;
- *eventPP = s;
- }
- }
- else
- characterDataHandler(handlerArg,
- (XML_Char *)s,
- (XML_Char *)next - (XML_Char *)s);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, enc, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_COMMENT:
- if (!reportComment(parser, enc, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- default:
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- }
- *eventPP = s = next;
- }
- /* not reached */
-}
-
-/* If tagNamePtr is non-null, build a real list of attributes,
-otherwise just check the attributes for well-formedness. */
-
-static enum XML_Error storeAtts(XML_Parser parser, const ENCODING *enc,
- const char *attStr, TAG_NAME *tagNamePtr,
- BINDING **bindingsPtr)
-{
- ELEMENT_TYPE *elementType = 0;
- int nDefaultAtts = 0;
- const XML_Char **appAtts; /* the attribute list to pass to the application */
- int attIndex = 0;
- int i;
- int n;
- int nPrefixes = 0;
- BINDING *binding;
- const XML_Char *localPart;
-
- /* lookup the element type name */
- if (tagNamePtr) {
- elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str,0);
- if (!elementType) {
- tagNamePtr->str = poolCopyString(&dtd.pool, tagNamePtr->str);
- if (!tagNamePtr->str)
- return XML_ERROR_NO_MEMORY;
- elementType = (ELEMENT_TYPE *)lookup(&dtd.elementTypes, tagNamePtr->str, sizeof(ELEMENT_TYPE));
- if (!elementType)
- return XML_ERROR_NO_MEMORY;
- if (ns && !setElementTypePrefix(parser, elementType))
- return XML_ERROR_NO_MEMORY;
- }
- nDefaultAtts = elementType->nDefaultAtts;
- }
- /* get the attributes from the tokenizer */
- n = XmlGetAttributes(enc, attStr, attsSize, atts);
- if (n + nDefaultAtts > attsSize) {
- int oldAttsSize = attsSize;
- attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
- atts = REALLOC((void *)atts, attsSize * sizeof(ATTRIBUTE));
- if (!atts)
- return XML_ERROR_NO_MEMORY;
- if (n > oldAttsSize)
- XmlGetAttributes(enc, attStr, n, atts);
- }
- appAtts = (const XML_Char **)atts;
- for (i = 0; i < n; i++) {
- /* add the name and value to the attribute list */
- ATTRIBUTE_ID *attId = getAttributeId(parser, enc, atts[i].name,
- atts[i].name
- + XmlNameLength(enc, atts[i].name));
- if (!attId)
- return XML_ERROR_NO_MEMORY;
- /* detect duplicate attributes */
- if ((attId->name)[-1]) {
- if (enc == encoding)
- eventPtr = atts[i].name;
- return XML_ERROR_DUPLICATE_ATTRIBUTE;
- }
- (attId->name)[-1] = 1;
- appAtts[attIndex++] = attId->name;
- if (!atts[i].normalized) {
- enum XML_Error result;
- int isCdata = 1;
-
- /* figure out whether declared as other than CDATA */
- if (attId->maybeTokenized) {
- int j;
- for (j = 0; j < nDefaultAtts; j++) {
- if (attId == elementType->defaultAtts[j].id) {
- isCdata = elementType->defaultAtts[j].isCdata;
- break;
- }
- }
- }
-
- /* normalize the attribute value */
- result = storeAttributeValue(parser, enc, isCdata,
- atts[i].valuePtr, atts[i].valueEnd,
- &tempPool);
- if (result)
- return result;
- if (tagNamePtr) {
- appAtts[attIndex] = poolStart(&tempPool);
- poolFinish(&tempPool);
- }
- else
- poolDiscard(&tempPool);
- }
- else if (tagNamePtr) {
- /* the value did not need normalizing */
- appAtts[attIndex] = poolStoreString(&tempPool, enc, atts[i].valuePtr, atts[i].valueEnd);
- if (appAtts[attIndex] == 0)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- }
- /* handle prefixed attribute names */
- if (attId->prefix && tagNamePtr) {
- if (attId->xmlns) {
- /* deal with namespace declarations here */
- if (!addBinding(parser, attId->prefix, attId, appAtts[attIndex], bindingsPtr))
- return XML_ERROR_NO_MEMORY;
- --attIndex;
- }
- else {
- /* deal with other prefixed names later */
- attIndex++;
- nPrefixes++;
- (attId->name)[-1] = 2;
- }
- }
- else
- attIndex++;
- }
- if (tagNamePtr) {
- int j;
- nSpecifiedAtts = attIndex;
- if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
- for (i = 0; i < attIndex; i += 2)
- if (appAtts[i] == elementType->idAtt->name) {
- idAttIndex = i;
- break;
- }
- }
- else
- idAttIndex = -1;
- /* do attribute defaulting */
- for (j = 0; j < nDefaultAtts; j++) {
- const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + j;
- if (!(da->id->name)[-1] && da->value) {
- if (da->id->prefix) {
- if (da->id->xmlns) {
- if (!addBinding(parser, da->id->prefix, da->id, da->value, bindingsPtr))
- return XML_ERROR_NO_MEMORY;
- }
- else {
- (da->id->name)[-1] = 2;
- nPrefixes++;
- appAtts[attIndex++] = da->id->name;
- appAtts[attIndex++] = da->value;
- }
- }
- else {
- (da->id->name)[-1] = 1;
- appAtts[attIndex++] = da->id->name;
- appAtts[attIndex++] = da->value;
- }
- }
- }
- appAtts[attIndex] = 0;
- }
- i = 0;
- if (nPrefixes) {
- /* expand prefixed attribute names */
- for (; i < attIndex; i += 2) {
- if (appAtts[i][-1] == 2) {
- ATTRIBUTE_ID *id;
- ((XML_Char *)(appAtts[i]))[-1] = 0;
- id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, appAtts[i], 0);
- if (id->prefix->binding) {
- int j;
- const BINDING *b = id->prefix->binding;
- const XML_Char *s = appAtts[i];
- for (j = 0; j < b->uriLen; j++) {
- if (!poolAppendChar(&tempPool, b->uri[j]))
- return XML_ERROR_NO_MEMORY;
- }
- while (*s++ != ':')
- ;
- do {
- if (!poolAppendChar(&tempPool, *s))
- return XML_ERROR_NO_MEMORY;
- } while (*s++);
- if (ns_triplets) {
- tempPool.ptr[-1] = namespaceSeparator;
- s = b->prefix->name;
- do {
- if (!poolAppendChar(&tempPool, *s))
- return XML_ERROR_NO_MEMORY;
- } while (*s++);
- }
-
- appAtts[i] = poolStart(&tempPool);
- poolFinish(&tempPool);
- }
- if (!--nPrefixes)
- break;
- }
- else
- ((XML_Char *)(appAtts[i]))[-1] = 0;
- }
- }
- /* clear the flags that say whether attributes were specified */
- for (; i < attIndex; i += 2)
- ((XML_Char *)(appAtts[i]))[-1] = 0;
- if (!tagNamePtr)
- return XML_ERROR_NONE;
- for (binding = *bindingsPtr; binding; binding = binding->nextTagBinding)
- binding->attId->name[-1] = 0;
- /* expand the element type name */
- if (elementType->prefix) {
- binding = elementType->prefix->binding;
- if (!binding)
- return XML_ERROR_NONE;
- localPart = tagNamePtr->str;
- while (*localPart++ != XML_T(':'))
- ;
- }
- else if (dtd.defaultPrefix.binding) {
- binding = dtd.defaultPrefix.binding;
- localPart = tagNamePtr->str;
- }
- else
- return XML_ERROR_NONE;
- tagNamePtr->localPart = localPart;
- tagNamePtr->uriLen = binding->uriLen;
- for (i = 0; localPart[i++];)
- ;
- n = i + binding->uriLen;
- if (n > binding->uriAlloc) {
- TAG *p;
- XML_Char *uri = MALLOC((n + EXPAND_SPARE) * sizeof(XML_Char));
- if (!uri)
- return XML_ERROR_NO_MEMORY;
- binding->uriAlloc = n + EXPAND_SPARE;
- memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
- for (p = tagStack; p; p = p->parent)
- if (p->name.str == binding->uri)
- p->name.str = uri;
- FREE(binding->uri);
- binding->uri = uri;
- }
- memcpy(binding->uri + binding->uriLen, localPart, i * sizeof(XML_Char));
- tagNamePtr->str = binding->uri;
- return XML_ERROR_NONE;
-}
-
-static
-int addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId, const XML_Char *uri, BINDING **bindingsPtr)
-{
- BINDING *b;
- int len;
- for (len = 0; uri[len]; len++)
- ;
- if (namespaceSeparator)
- len++;
- if (freeBindingList) {
- b = freeBindingList;
- if (len > b->uriAlloc) {
- b->uri = REALLOC(b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
- if (!b->uri)
- return 0;
- b->uriAlloc = len + EXPAND_SPARE;
- }
- freeBindingList = b->nextTagBinding;
- }
- else {
- b = MALLOC(sizeof(BINDING));
- if (!b)
- return 0;
- b->uri = MALLOC(sizeof(XML_Char) * (len + EXPAND_SPARE));
- if (!b->uri) {
- FREE(b);
- return 0;
- }
- b->uriAlloc = len + EXPAND_SPARE;
- }
- b->uriLen = len;
- memcpy(b->uri, uri, len * sizeof(XML_Char));
- if (namespaceSeparator)
- b->uri[len - 1] = namespaceSeparator;
- b->prefix = prefix;
- b->attId = attId;
- b->prevPrefixBinding = prefix->binding;
- if (*uri == XML_T('\0') && prefix == &dtd.defaultPrefix)
- prefix->binding = 0;
- else
- prefix->binding = b;
- b->nextTagBinding = *bindingsPtr;
- *bindingsPtr = b;
- if (startNamespaceDeclHandler)
- startNamespaceDeclHandler(handlerArg, prefix->name,
- prefix->binding ? uri : 0);
- return 1;
-}
-
-/* The idea here is to avoid using stack for each CDATA section when
-the whole file is parsed with one call. */
-
-static
-enum XML_Error cdataSectionProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doCdataSection(parser, encoding, &start, end, endPtr);
- if (start) {
- processor = contentProcessor;
- return contentProcessor(parser, start, end, endPtr);
- }
- return result;
-}
-
-/* startPtr gets set to non-null is the section is closed, and to null if
-the section is not yet closed. */
-
-static
-enum XML_Error doCdataSection(XML_Parser parser,
- const ENCODING *enc,
- const char **startPtr,
- const char *end,
- const char **nextPtr)
-{
- const char *s = *startPtr;
- const char **eventPP;
- const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- *eventPP = s;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
- }
- *eventPP = s;
- *startPtr = 0;
- for (;;) {
- const char *next;
- int tok = XmlCdataSectionTok(enc, s, end, &next);
- *eventEndPP = next;
- switch (tok) {
- case XML_TOK_CDATA_SECT_CLOSE:
- if (endCdataSectionHandler)
- endCdataSectionHandler(handlerArg);
-#if 0
- /* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if (characterDataHandler)
- characterDataHandler(handlerArg, dataBuf, 0);
-#endif
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- *startPtr = next;
- return XML_ERROR_NONE;
- case XML_TOK_DATA_NEWLINE:
- if (characterDataHandler) {
- XML_Char c = 0xA;
- characterDataHandler(handlerArg, &c, 1);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- case XML_TOK_DATA_CHARS:
- if (characterDataHandler) {
- if (MUST_CONVERT(enc, s)) {
- for (;;) {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, next, &dataPtr, (ICHAR *)dataBufEnd);
- *eventEndPP = next;
- characterDataHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
- if (s == next)
- break;
- *eventPP = s;
- }
- }
- else
- characterDataHandler(handlerArg,
- (XML_Char *)s,
- (XML_Char *)next - (XML_Char *)s);
- }
- else if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
- case XML_TOK_INVALID:
- *eventPP = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_PARTIAL:
- case XML_TOK_NONE:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_UNCLOSED_CDATA_SECTION;
- default:
- *eventPP = next;
- return XML_ERROR_UNEXPECTED_STATE;
- }
- *eventPP = s = next;
- }
- /* not reached */
-}
-
-#ifdef XML_DTD
-
-/* The idea here is to avoid using stack for each IGNORE section when
-the whole file is parsed with one call. */
-
-static
-enum XML_Error ignoreSectionProcessor(XML_Parser parser,
- const char *start,
- const char *end,
- const char **endPtr)
-{
- enum XML_Error result = doIgnoreSection(parser, encoding, &start, end, endPtr);
- if (start) {
- processor = prologProcessor;
- return prologProcessor(parser, start, end, endPtr);
- }
- return result;
-}
-
-/* startPtr gets set to non-null is the section is closed, and to null if
-the section is not yet closed. */
-
-static
-enum XML_Error doIgnoreSection(XML_Parser parser,
- const ENCODING *enc,
- const char **startPtr,
- const char *end,
- const char **nextPtr)
-{
- const char *next;
- int tok;
- const char *s = *startPtr;
- const char **eventPP;
- const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- *eventPP = s;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
- }
- *eventPP = s;
- *startPtr = 0;
- tok = XmlIgnoreSectionTok(enc, s, end, &next);
- *eventEndPP = next;
- switch (tok) {
- case XML_TOK_IGNORE_SECT:
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- *startPtr = next;
- return XML_ERROR_NONE;
- case XML_TOK_INVALID:
- *eventPP = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_PARTIAL:
- case XML_TOK_NONE:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_SYNTAX; /* XML_ERROR_UNCLOSED_IGNORE_SECTION */
- default:
- *eventPP = next;
- return XML_ERROR_UNEXPECTED_STATE;
- }
- /* not reached */
-}
-
-#endif /* XML_DTD */
-
-static enum XML_Error
-initializeEncoding(XML_Parser parser)
-{
- const char *s;
-#ifdef XML_UNICODE
- char encodingBuf[128];
- if (!protocolEncodingName)
- s = 0;
- else {
- int i;
- for (i = 0; protocolEncodingName[i]; i++) {
- if (i == sizeof(encodingBuf) - 1
- || (protocolEncodingName[i] & ~0x7f) != 0) {
- encodingBuf[0] = '\0';
- break;
- }
- encodingBuf[i] = (char)protocolEncodingName[i];
- }
- encodingBuf[i] = '\0';
- s = encodingBuf;
- }
-#else
- s = protocolEncodingName;
-#endif
- if ((ns ? XmlInitEncodingNS : XmlInitEncoding)(&initEncoding, &encoding, s))
- return XML_ERROR_NONE;
- return handleUnknownEncoding(parser, protocolEncodingName);
-}
-
-static enum XML_Error
-processXmlDecl(XML_Parser parser, int isGeneralTextEntity,
- const char *s, const char *next)
-{
- const char *encodingName = 0;
- const char *storedEncName = 0;
- const ENCODING *newEncoding = 0;
- const char *version = 0;
- const char *versionend;
- const char *storedversion = 0;
- int standalone = -1;
- if (!(ns
- ? XmlParseXmlDeclNS
- : XmlParseXmlDecl)(isGeneralTextEntity,
- encoding,
- s,
- next,
- &eventPtr,
- &version,
- &versionend,
- &encodingName,
- &newEncoding,
- &standalone))
- return XML_ERROR_SYNTAX;
- if (!isGeneralTextEntity && standalone == 1) {
- dtd.standalone = 1;
-#ifdef XML_DTD
- if (paramEntityParsing == XML_PARAM_ENTITY_PARSING_UNLESS_STANDALONE)
- paramEntityParsing = XML_PARAM_ENTITY_PARSING_NEVER;
-#endif /* XML_DTD */
- }
- if (xmlDeclHandler) {
- if (encodingName) {
- storedEncName = poolStoreString(&temp2Pool,
- encoding,
- encodingName,
- encodingName
- + XmlNameLength(encoding, encodingName));
- if (! storedEncName)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&temp2Pool);
- }
- if (version) {
- storedversion = poolStoreString(&temp2Pool,
- encoding,
- version,
- versionend - encoding->minBytesPerChar);
- if (! storedversion)
- return XML_ERROR_NO_MEMORY;
- }
- xmlDeclHandler(handlerArg, storedversion, storedEncName, standalone);
- }
- else if (defaultHandler)
- reportDefault(parser, encoding, s, next);
- if (!protocolEncodingName) {
- if (newEncoding) {
- if (newEncoding->minBytesPerChar != encoding->minBytesPerChar) {
- eventPtr = encodingName;
- return XML_ERROR_INCORRECT_ENCODING;
- }
- encoding = newEncoding;
- }
- else if (encodingName) {
- enum XML_Error result;
- if (! storedEncName) {
- storedEncName = poolStoreString(&temp2Pool,
- encoding,
- encodingName,
- encodingName
- + XmlNameLength(encoding, encodingName));
- if (! storedEncName)
- return XML_ERROR_NO_MEMORY;
- }
- result = handleUnknownEncoding(parser, storedEncName);
- poolClear(&tempPool);
- if (result == XML_ERROR_UNKNOWN_ENCODING)
- eventPtr = encodingName;
- return result;
- }
- }
-
- if (storedEncName || storedversion)
- poolClear(&temp2Pool);
-
- return XML_ERROR_NONE;
-}
-
-static enum XML_Error
-handleUnknownEncoding(XML_Parser parser, const XML_Char *encodingName)
-{
- if (unknownEncodingHandler) {
- XML_Encoding info;
- int i;
- for (i = 0; i < 256; i++)
- info.map[i] = -1;
- info.convert = 0;
- info.data = 0;
- info.release = 0;
- if (unknownEncodingHandler(unknownEncodingHandlerData, encodingName, &info)) {
- ENCODING *enc;
- unknownEncodingMem = MALLOC(XmlSizeOfUnknownEncoding());
- if (!unknownEncodingMem) {
- if (info.release)
- info.release(info.data);
- return XML_ERROR_NO_MEMORY;
- }
- enc = (ns
- ? XmlInitUnknownEncodingNS
- : XmlInitUnknownEncoding)(unknownEncodingMem,
- info.map,
- info.convert,
- info.data);
- if (enc) {
- unknownEncodingData = info.data;
- unknownEncodingRelease = info.release;
- encoding = enc;
- return XML_ERROR_NONE;
- }
- }
- if (info.release)
- info.release(info.data);
- }
- return XML_ERROR_UNKNOWN_ENCODING;
-}
-
-static enum XML_Error
-prologInitProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- enum XML_Error result = initializeEncoding(parser);
- if (result != XML_ERROR_NONE)
- return result;
- processor = prologProcessor;
- return prologProcessor(parser, s, end, nextPtr);
-}
-
-static enum XML_Error
-prologProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- const char *next;
- int tok = XmlPrologTok(encoding, s, end, &next);
- return doProlog(parser, encoding, s, end, tok, next, nextPtr);
-}
-
-static enum XML_Error
-doProlog(XML_Parser parser,
- const ENCODING *enc,
- const char *s,
- const char *end,
- int tok,
- const char *next,
- const char **nextPtr)
-{
-#ifdef XML_DTD
- static const XML_Char externalSubsetName[] = { '#' , '\0' };
-#endif /* XML_DTD */
-
- const char **eventPP;
- const char **eventEndPP;
- enum XML_Content_Quant quant;
-
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
- }
- for (;;) {
- int role;
- *eventPP = s;
- *eventEndPP = next;
- if (tok <= 0) {
- if (nextPtr != 0 && tok != XML_TOK_INVALID) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- switch (tok) {
- case XML_TOK_INVALID:
- *eventPP = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL:
- return XML_ERROR_UNCLOSED_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- return XML_ERROR_PARTIAL_CHAR;
- case XML_TOK_NONE:
-#ifdef XML_DTD
- if (enc != encoding)
- return XML_ERROR_NONE;
- if (parentParser) {
- if (XmlTokenRole(&prologState, XML_TOK_NONE, end, end, enc)
- == XML_ROLE_ERROR)
- return XML_ERROR_SYNTAX;
- hadExternalDoctype = 0;
- return XML_ERROR_NONE;
- }
-#endif /* XML_DTD */
- return XML_ERROR_NO_ELEMENTS;
- default:
- tok = -tok;
- next = end;
- break;
- }
- }
- role = XmlTokenRole(&prologState, tok, s, next, enc);
- switch (role) {
- case XML_ROLE_XML_DECL:
- {
- enum XML_Error result = processXmlDecl(parser, 0, s, next);
- if (result != XML_ERROR_NONE)
- return result;
- enc = encoding;
- }
- break;
- case XML_ROLE_DOCTYPE_NAME:
- if (startDoctypeDeclHandler) {
- doctypeName = poolStoreString(&tempPool, enc, s, next);
- if (! doctypeName)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- doctypeSysid = 0;
- doctypePubid = 0;
- }
- break;
- case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
- if (startDoctypeDeclHandler) {
- startDoctypeDeclHandler(handlerArg, doctypeName, doctypeSysid,
- doctypePubid, 1);
- doctypeName = 0;
- poolClear(&tempPool);
- }
- break;
-#ifdef XML_DTD
- case XML_ROLE_TEXT_DECL:
- {
- enum XML_Error result = processXmlDecl(parser, 1, s, next);
- if (result != XML_ERROR_NONE)
- return result;
- enc = encoding;
- }
- break;
-#endif /* XML_DTD */
- case XML_ROLE_DOCTYPE_PUBLIC_ID:
- if (startDoctypeDeclHandler) {
- doctypePubid = poolStoreString(&tempPool, enc, s + 1, next - 1);
- if (! doctypePubid)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- }
-#ifdef XML_DTD
- declEntity = (ENTITY *)lookup(&dtd.paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- if (!declEntity)
- return XML_ERROR_NO_MEMORY;
-#endif /* XML_DTD */
- /* fall through */
- case XML_ROLE_ENTITY_PUBLIC_ID:
- if (!XmlIsPublicId(enc, s, next, eventPP))
- return XML_ERROR_SYNTAX;
- if (declEntity) {
- XML_Char *tem = poolStoreString(&dtd.pool,
- enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!tem)
- return XML_ERROR_NO_MEMORY;
- normalizePublicId(tem);
- declEntity->publicId = tem;
- poolFinish(&dtd.pool);
- }
- break;
- case XML_ROLE_DOCTYPE_CLOSE:
- if (doctypeName) {
- startDoctypeDeclHandler(handlerArg, doctypeName,
- doctypeSysid, doctypePubid, 0);
- poolClear(&tempPool);
- }
- if (dtd.complete && hadExternalDoctype) {
- dtd.complete = 0;
-#ifdef XML_DTD
- if (paramEntityParsing && externalEntityRefHandler) {
- ENTITY *entity = (ENTITY *)lookup(&dtd.paramEntities,
- externalSubsetName,
- 0);
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId))
- return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- }
-#endif /* XML_DTD */
- if (!dtd.complete
- && !dtd.standalone
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
- return XML_ERROR_NOT_STANDALONE;
- }
- if (endDoctypeDeclHandler)
- endDoctypeDeclHandler(handlerArg);
- break;
- case XML_ROLE_INSTANCE_START:
- processor = contentProcessor;
- return contentProcessor(parser, s, end, nextPtr);
- case XML_ROLE_ATTLIST_ELEMENT_NAME:
- declElementType = getElementType(parser, enc, s, next);
- if (!declElementType)
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_ROLE_ATTRIBUTE_NAME:
- declAttributeId = getAttributeId(parser, enc, s, next);
- if (!declAttributeId)
- return XML_ERROR_NO_MEMORY;
- declAttributeIsCdata = 0;
- declAttributeType = 0;
- declAttributeIsId = 0;
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_CDATA:
- declAttributeIsCdata = 1;
- declAttributeType = "CDATA";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_ID:
- declAttributeIsId = 1;
- declAttributeType = "ID";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_IDREF:
- declAttributeType = "IDREF";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_IDREFS:
- declAttributeType = "IDREFS";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_ENTITY:
- declAttributeType = "ENTITY";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_ENTITIES:
- declAttributeType = "ENTITIES";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN:
- declAttributeType = "NMTOKEN";
- break;
- case XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS:
- declAttributeType = "NMTOKENS";
- break;
-
- case XML_ROLE_ATTRIBUTE_ENUM_VALUE:
- case XML_ROLE_ATTRIBUTE_NOTATION_VALUE:
- if (attlistDeclHandler)
- {
- char *prefix;
- if (declAttributeType) {
- prefix = "|";
- }
- else {
- prefix = (role == XML_ROLE_ATTRIBUTE_NOTATION_VALUE
- ? "NOTATION("
- : "(");
- }
- if (! poolAppendString(&tempPool, prefix))
- return XML_ERROR_NO_MEMORY;
- if (! poolAppend(&tempPool, enc, s, next))
- return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- }
- break;
- case XML_ROLE_IMPLIED_ATTRIBUTE_VALUE:
- case XML_ROLE_REQUIRED_ATTRIBUTE_VALUE:
- if (dtd.complete
- && !defineAttribute(declElementType, declAttributeId,
- declAttributeIsCdata, declAttributeIsId, 0,
- parser))
- return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == '('
- || (*declAttributeType == 'N' && declAttributeType[1] == 'O')) {
- /* Enumerated or Notation type */
- if (! poolAppendChar(&tempPool, ')')
- || ! poolAppendChar(&tempPool, '\0'))
- return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
- }
- *eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
- 0, role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
- }
- break;
- case XML_ROLE_DEFAULT_ATTRIBUTE_VALUE:
- case XML_ROLE_FIXED_ATTRIBUTE_VALUE:
- {
- const XML_Char *attVal;
- enum XML_Error result
- = storeAttributeValue(parser, enc, declAttributeIsCdata,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar,
- &dtd.pool);
- if (result)
- return result;
- attVal = poolStart(&dtd.pool);
- poolFinish(&dtd.pool);
- if (dtd.complete
- /* ID attributes aren't allowed to have a default */
- && !defineAttribute(declElementType, declAttributeId, declAttributeIsCdata, 0, attVal, parser))
- return XML_ERROR_NO_MEMORY;
- if (attlistDeclHandler && declAttributeType) {
- if (*declAttributeType == '('
- || (*declAttributeType == 'N' && declAttributeType[1] == 'O')) {
- /* Enumerated or Notation type */
- if (! poolAppendChar(&tempPool, ')')
- || ! poolAppendChar(&tempPool, '\0'))
- return XML_ERROR_NO_MEMORY;
- declAttributeType = tempPool.start;
- poolFinish(&tempPool);
- }
- *eventEndPP = s;
- attlistDeclHandler(handlerArg, declElementType->name,
- declAttributeId->name, declAttributeType,
- attVal,
- role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
- poolClear(&tempPool);
- }
- break;
- }
- case XML_ROLE_ENTITY_VALUE:
- {
- enum XML_Error result = storeEntityValue(parser, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (declEntity) {
- declEntity->textPtr = poolStart(&dtd.pool);
- declEntity->textLen = poolLength(&dtd.pool);
- poolFinish(&dtd.pool);
- if (entityDeclHandler) {
- *eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->is_param,
- declEntity->textPtr,
- declEntity->textLen,
- curBase, 0, 0, 0);
- }
- }
- else
- poolDiscard(&dtd.pool);
- if (result != XML_ERROR_NONE)
- return result;
- }
- break;
- case XML_ROLE_DOCTYPE_SYSTEM_ID:
- if (startDoctypeDeclHandler) {
- doctypeSysid = poolStoreString(&tempPool, enc, s + 1, next - 1);
- if (! doctypeSysid)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- }
- if (!dtd.standalone
-#ifdef XML_DTD
- && !paramEntityParsing
-#endif /* XML_DTD */
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
- return XML_ERROR_NOT_STANDALONE;
- hadExternalDoctype = 1;
-#ifndef XML_DTD
- break;
-#else /* XML_DTD */
- if (!declEntity) {
- declEntity = (ENTITY *)lookup(&dtd.paramEntities,
- externalSubsetName,
- sizeof(ENTITY));
- declEntity->publicId = 0;
- if (!declEntity)
- return XML_ERROR_NO_MEMORY;
- }
- /* fall through */
-#endif /* XML_DTD */
- case XML_ROLE_ENTITY_SYSTEM_ID:
- if (declEntity) {
- declEntity->systemId = poolStoreString(&dtd.pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!declEntity->systemId)
- return XML_ERROR_NO_MEMORY;
- declEntity->base = curBase;
- poolFinish(&dtd.pool);
- }
- break;
- case XML_ROLE_ENTITY_COMPLETE:
- if (declEntity && entityDeclHandler) {
- *eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- 0,0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- 0);
- }
- break;
- case XML_ROLE_ENTITY_NOTATION_NAME:
- if (declEntity) {
- declEntity->notation = poolStoreString(&dtd.pool, enc, s, next);
- if (!declEntity->notation)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&dtd.pool);
- if (unparsedEntityDeclHandler) {
- *eventEndPP = s;
- unparsedEntityDeclHandler(handlerArg,
- declEntity->name,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
- }
- else if (entityDeclHandler) {
- *eventEndPP = s;
- entityDeclHandler(handlerArg,
- declEntity->name,
- 0,0,0,
- declEntity->base,
- declEntity->systemId,
- declEntity->publicId,
- declEntity->notation);
- }
- }
- break;
- case XML_ROLE_GENERAL_ENTITY_NAME:
- {
- const XML_Char *name;
- if (XmlPredefinedEntityName(enc, s, next)) {
- declEntity = 0;
- break;
- }
- name = poolStoreString(&dtd.pool, enc, s, next);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- if (dtd.complete) {
- declEntity = (ENTITY *)lookup(&dtd.generalEntities, name, sizeof(ENTITY));
- if (!declEntity)
- return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
- poolDiscard(&dtd.pool);
- declEntity = 0;
- }
- else {
- poolFinish(&dtd.pool);
- declEntity->publicId = 0;
- declEntity->is_param = 0;
- }
- }
- else {
- poolDiscard(&dtd.pool);
- declEntity = 0;
- }
- }
- break;
- case XML_ROLE_PARAM_ENTITY_NAME:
-#ifdef XML_DTD
- if (dtd.complete) {
- const XML_Char *name = poolStoreString(&dtd.pool, enc, s, next);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- declEntity = (ENTITY *)lookup(&dtd.paramEntities,
- name, sizeof(ENTITY));
- if (!declEntity)
- return XML_ERROR_NO_MEMORY;
- if (declEntity->name != name) {
- poolDiscard(&dtd.pool);
- declEntity = 0;
- }
- else {
- poolFinish(&dtd.pool);
- declEntity->publicId = 0;
- declEntity->is_param = 1;
- }
- }
-#else /* not XML_DTD */
- declEntity = 0;
-#endif /* not XML_DTD */
- break;
- case XML_ROLE_NOTATION_NAME:
- declNotationPublicId = 0;
- declNotationName = 0;
- if (notationDeclHandler) {
- declNotationName = poolStoreString(&tempPool, enc, s, next);
- if (!declNotationName)
- return XML_ERROR_NO_MEMORY;
- poolFinish(&tempPool);
- }
- break;
- case XML_ROLE_NOTATION_PUBLIC_ID:
- if (!XmlIsPublicId(enc, s, next, eventPP))
- return XML_ERROR_SYNTAX;
- if (declNotationName) {
- XML_Char *tem = poolStoreString(&tempPool,
- enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!tem)
- return XML_ERROR_NO_MEMORY;
- normalizePublicId(tem);
- declNotationPublicId = tem;
- poolFinish(&tempPool);
- }
- break;
- case XML_ROLE_NOTATION_SYSTEM_ID:
- if (declNotationName && notationDeclHandler) {
- const XML_Char *systemId
- = poolStoreString(&tempPool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!systemId)
- return XML_ERROR_NO_MEMORY;
- *eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
- systemId,
- declNotationPublicId);
- }
- poolClear(&tempPool);
- break;
- case XML_ROLE_NOTATION_NO_SYSTEM_ID:
- if (declNotationPublicId && notationDeclHandler) {
- *eventEndPP = s;
- notationDeclHandler(handlerArg,
- declNotationName,
- curBase,
- 0,
- declNotationPublicId);
- }
- poolClear(&tempPool);
- break;
- case XML_ROLE_ERROR:
- switch (tok) {
- case XML_TOK_PARAM_ENTITY_REF:
- return XML_ERROR_PARAM_ENTITY_REF;
- case XML_TOK_XML_DECL:
- return XML_ERROR_MISPLACED_XML_PI;
- default:
- return XML_ERROR_SYNTAX;
- }
-#ifdef XML_DTD
- case XML_ROLE_IGNORE_SECT:
- {
- enum XML_Error result;
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- result = doIgnoreSection(parser, enc, &next, end, nextPtr);
- if (!next) {
- processor = ignoreSectionProcessor;
- return result;
- }
- }
- break;
-#endif /* XML_DTD */
- case XML_ROLE_GROUP_OPEN:
- if (prologState.level >= groupSize) {
- if (groupSize) {
- groupConnector = REALLOC(groupConnector, groupSize *= 2);
- if (dtd.scaffIndex)
- dtd.scaffIndex = REALLOC(dtd.scaffIndex, groupSize * sizeof(int));
- }
- else
- groupConnector = MALLOC(groupSize = 32);
- if (!groupConnector)
- return XML_ERROR_NO_MEMORY;
- }
- groupConnector[prologState.level] = 0;
- if (dtd.in_eldecl) {
- int myindex = nextScaffoldPart(parser);
- if (myindex < 0)
- return XML_ERROR_NO_MEMORY;
- dtd.scaffIndex[dtd.scaffLevel] = myindex;
- dtd.scaffLevel++;
- dtd.scaffold[myindex].type = XML_CTYPE_SEQ;
- }
- break;
- case XML_ROLE_GROUP_SEQUENCE:
- if (groupConnector[prologState.level] == '|')
- return XML_ERROR_SYNTAX;
- groupConnector[prologState.level] = ',';
- break;
- case XML_ROLE_GROUP_CHOICE:
- if (groupConnector[prologState.level] == ',')
- return XML_ERROR_SYNTAX;
- if (dtd.in_eldecl
- && ! groupConnector[prologState.level]
- && dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type != XML_CTYPE_MIXED
- ) {
- dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type = XML_CTYPE_CHOICE;
- }
- groupConnector[prologState.level] = '|';
- break;
- case XML_ROLE_PARAM_ENTITY_REF:
-#ifdef XML_DTD
- case XML_ROLE_INNER_PARAM_ENTITY_REF:
- if (paramEntityParsing
- && (dtd.complete || role == XML_ROLE_INNER_PARAM_ENTITY_REF)) {
- const XML_Char *name;
- ENTITY *entity;
- name = poolStoreString(&dtd.pool, enc,
- s + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0);
- poolDiscard(&dtd.pool);
- if (!entity) {
- /* FIXME what to do if !dtd.complete? */
- return XML_ERROR_UNDEFINED_ENTITY;
- }
- if (entity->open)
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- if (entity->textPtr) {
- enum XML_Error result;
- result = processInternalParamEntity(parser, entity);
- if (result != XML_ERROR_NONE)
- return result;
- break;
- }
- if (role == XML_ROLE_INNER_PARAM_ENTITY_REF)
- return XML_ERROR_PARAM_ENTITY_REF;
- if (externalEntityRefHandler) {
- dtd.complete = 0;
- entity->open = 1;
- if (!externalEntityRefHandler(externalEntityRefHandlerArg,
- 0,
- entity->base,
- entity->systemId,
- entity->publicId)) {
- entity->open = 0;
- return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
- }
- entity->open = 0;
- if (dtd.complete)
- break;
- }
- }
-#endif /* XML_DTD */
- if (!dtd.standalone
- && notStandaloneHandler
- && !notStandaloneHandler(handlerArg))
- return XML_ERROR_NOT_STANDALONE;
- dtd.complete = 0;
- if (defaultHandler)
- reportDefault(parser, enc, s, next);
- break;
-
- /* Element declaration stuff */
-
- case XML_ROLE_ELEMENT_NAME:
- if (elementDeclHandler) {
- declElementType = getElementType(parser, enc, s, next);
- if (! declElementType)
- return XML_ERROR_NO_MEMORY;
- dtd.scaffLevel = 0;
- dtd.scaffCount = 0;
- dtd.in_eldecl = 1;
- }
- break;
-
- case XML_ROLE_CONTENT_ANY:
- case XML_ROLE_CONTENT_EMPTY:
- if (dtd.in_eldecl) {
- if (elementDeclHandler) {
- XML_Content * content = (XML_Content *) MALLOC(sizeof(XML_Content));
- if (! content)
- return XML_ERROR_NO_MEMORY;
- content->quant = XML_CQUANT_NONE;
- content->name = 0;
- content->numchildren = 0;
- content->children = 0;
- content->type = ((role == XML_ROLE_CONTENT_ANY) ?
- XML_CTYPE_ANY :
- XML_CTYPE_EMPTY);
- *eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, content);
- }
- dtd.in_eldecl = 0;
- }
- break;
-
- case XML_ROLE_CONTENT_PCDATA:
- if (dtd.in_eldecl) {
- dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]].type = XML_CTYPE_MIXED;
- }
- break;
-
- case XML_ROLE_CONTENT_ELEMENT:
- quant = XML_CQUANT_NONE;
- goto elementContent;
- case XML_ROLE_CONTENT_ELEMENT_OPT:
- quant = XML_CQUANT_OPT;
- goto elementContent;
- case XML_ROLE_CONTENT_ELEMENT_REP:
- quant = XML_CQUANT_REP;
- goto elementContent;
- case XML_ROLE_CONTENT_ELEMENT_PLUS:
- quant = XML_CQUANT_PLUS;
- elementContent:
- if (dtd.in_eldecl)
- {
- ELEMENT_TYPE *el;
- const char *nxt = quant == XML_CQUANT_NONE ? next : next - 1;
- int myindex = nextScaffoldPart(parser);
- if (myindex < 0)
- return XML_ERROR_NO_MEMORY;
- dtd.scaffold[myindex].type = XML_CTYPE_NAME;
- dtd.scaffold[myindex].quant = quant;
- el = getElementType(parser, enc, s, nxt);
- if (! el)
- return XML_ERROR_NO_MEMORY;
- dtd.scaffold[myindex].name = el->name;
- dtd.contentStringLen += nxt - s + 1;
- }
- break;
-
- case XML_ROLE_GROUP_CLOSE:
- quant = XML_CQUANT_NONE;
- goto closeGroup;
- case XML_ROLE_GROUP_CLOSE_OPT:
- quant = XML_CQUANT_OPT;
- goto closeGroup;
- case XML_ROLE_GROUP_CLOSE_REP:
- quant = XML_CQUANT_REP;
- goto closeGroup;
- case XML_ROLE_GROUP_CLOSE_PLUS:
- quant = XML_CQUANT_PLUS;
- closeGroup:
- if (dtd.in_eldecl) {
- dtd.scaffLevel--;
- dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel]].quant = quant;
- if (dtd.scaffLevel == 0) {
- if (elementDeclHandler) {
- XML_Content *model = build_model(parser);
- if (! model)
- return XML_ERROR_NO_MEMORY;
- *eventEndPP = s;
- elementDeclHandler(handlerArg, declElementType->name, model);
- }
- dtd.in_eldecl = 0;
- dtd.contentStringLen = 0;
- }
- }
- break;
- /* End element declaration stuff */
-
- case XML_ROLE_NONE:
- switch (tok) {
- case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, enc, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_COMMENT:
- if (!reportComment(parser, enc, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- }
- break;
- }
- if (defaultHandler) {
- switch (tok) {
- case XML_TOK_PI:
- case XML_TOK_COMMENT:
- case XML_TOK_BOM:
- case XML_TOK_XML_DECL:
-#ifdef XML_DTD
- case XML_TOK_IGNORE_SECT:
-#endif /* XML_DTD */
- case XML_TOK_PARAM_ENTITY_REF:
- break;
- default:
-#ifdef XML_DTD
- if (role != XML_ROLE_IGNORE_SECT)
-#endif /* XML_DTD */
- reportDefault(parser, enc, s, next);
- }
- }
- s = next;
- tok = XmlPrologTok(enc, s, end, &next);
- }
- /* not reached */
-}
-
-static
-enum XML_Error epilogProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- processor = epilogProcessor;
- eventPtr = s;
- for (;;) {
- const char *next;
- int tok = XmlPrologTok(encoding, s, end, &next);
- eventEndPtr = next;
- switch (tok) {
- case -XML_TOK_PROLOG_S:
- if (defaultHandler) {
- eventEndPtr = end;
- reportDefault(parser, encoding, s, end);
- }
- /* fall through */
- case XML_TOK_NONE:
- if (nextPtr)
- *nextPtr = end;
- return XML_ERROR_NONE;
- case XML_TOK_PROLOG_S:
- if (defaultHandler)
- reportDefault(parser, encoding, s, next);
- break;
- case XML_TOK_PI:
- if (!reportProcessingInstruction(parser, encoding, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_COMMENT:
- if (!reportComment(parser, encoding, s, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_INVALID:
- eventPtr = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_UNCLOSED_TOKEN;
- case XML_TOK_PARTIAL_CHAR:
- if (nextPtr) {
- *nextPtr = s;
- return XML_ERROR_NONE;
- }
- return XML_ERROR_PARTIAL_CHAR;
- default:
- return XML_ERROR_JUNK_AFTER_DOC_ELEMENT;
- }
- eventPtr = s = next;
- }
-}
-
-#ifdef XML_DTD
-
-static enum XML_Error
-processInternalParamEntity(XML_Parser parser, ENTITY *entity)
-{
- const char *s, *end, *next;
- int tok;
- enum XML_Error result;
- OPEN_INTERNAL_ENTITY openEntity;
- entity->open = 1;
- openEntity.next = openInternalEntities;
- openInternalEntities = &openEntity;
- openEntity.entity = entity;
- openEntity.internalEventPtr = 0;
- openEntity.internalEventEndPtr = 0;
- s = (char *)entity->textPtr;
- end = (char *)(entity->textPtr + entity->textLen);
- tok = XmlPrologTok(internalEncoding, s, end, &next);
- result = doProlog(parser, internalEncoding, s, end, tok, next, 0);
- entity->open = 0;
- openInternalEntities = openEntity.next;
- return result;
-}
-
-#endif /* XML_DTD */
-
-static
-enum XML_Error errorProcessor(XML_Parser parser,
- const char *s,
- const char *end,
- const char **nextPtr)
-{
- cmExpatUnused(s);
- cmExpatUnused(end);
- cmExpatUnused(nextPtr);
- return errorCode;
-}
-
-static enum XML_Error
-storeAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata,
- const char *ptr, const char *end,
- STRING_POOL *pool)
-{
- enum XML_Error result = appendAttributeValue(parser, enc, isCdata, ptr, end, pool);
- if (result)
- return result;
- if (!isCdata && poolLength(pool) && poolLastChar(pool) == 0x20)
- poolChop(pool);
- if (!poolAppendChar(pool, XML_T('\0')))
- return XML_ERROR_NO_MEMORY;
- return XML_ERROR_NONE;
-}
-
-static enum XML_Error
-appendAttributeValue(XML_Parser parser, const ENCODING *enc, int isCdata,
- const char *ptr, const char *end,
- STRING_POOL *pool)
-{
- for (;;) {
- const char *next;
- int tok = XmlAttributeValueTok(enc, ptr, end, &next);
- switch (tok) {
- case XML_TOK_NONE:
- return XML_ERROR_NONE;
- case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_CHAR_REF:
- {
- XML_Char buf[XML_ENCODE_MAX];
- int i;
- int n = XmlCharRefNumber(enc, ptr);
- if (n < 0) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- if (!isCdata
- && n == 0x20 /* space */
- && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
- break;
- n = XmlEncode(n, (ICHAR *)buf);
- if (!n) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- for (i = 0; i < n; i++) {
- if (!poolAppendChar(pool, buf[i]))
- return XML_ERROR_NO_MEMORY;
- }
- }
- break;
- case XML_TOK_DATA_CHARS:
- if (!poolAppend(pool, enc, ptr, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_TRAILING_CR:
- next = ptr + enc->minBytesPerChar;
- /* fall through */
- case XML_TOK_ATTRIBUTE_VALUE_S:
- case XML_TOK_DATA_NEWLINE:
- if (!isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
- break;
- if (!poolAppendChar(pool, 0x20))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_ENTITY_REF:
- {
- const XML_Char *name;
- ENTITY *entity;
- XML_Char ch = XmlPredefinedEntityName(enc,
- ptr + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (ch) {
- if (!poolAppendChar(pool, ch))
- return XML_ERROR_NO_MEMORY;
- break;
- }
- name = poolStoreString(&temp2Pool, enc,
- ptr + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(&dtd.generalEntities, name, 0);
- poolDiscard(&temp2Pool);
- if (!entity) {
- if (dtd.complete) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_UNDEFINED_ENTITY;
- }
- }
- else if (entity->open) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- }
- else if (entity->notation) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_BINARY_ENTITY_REF;
- }
- else if (!entity->textPtr) {
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF;
- }
- else {
- enum XML_Error result;
- const XML_Char *textEnd = entity->textPtr + entity->textLen;
- entity->open = 1;
- result = appendAttributeValue(parser, internalEncoding, isCdata, (char *)entity->textPtr, (char *)textEnd, pool);
- entity->open = 0;
- if (result)
- return result;
- }
- }
- break;
- default:
- if (enc == encoding)
- eventPtr = ptr;
- return XML_ERROR_UNEXPECTED_STATE;
- }
- ptr = next;
- }
- /* not reached */
-}
-
-static
-enum XML_Error storeEntityValue(XML_Parser parser,
- const ENCODING *enc,
- const char *entityTextPtr,
- const char *entityTextEnd)
-{
- STRING_POOL *pool = &(dtd.pool);
- for (;;) {
- const char *next;
- int tok = XmlEntityValueTok(enc, entityTextPtr, entityTextEnd, &next);
- switch (tok) {
- case XML_TOK_PARAM_ENTITY_REF:
-#ifdef XML_DTD
- if (parentParser || enc != encoding) {
- enum XML_Error result;
- const XML_Char *name;
- ENTITY *entity;
- name = poolStoreString(&tempPool, enc,
- entityTextPtr + enc->minBytesPerChar,
- next - enc->minBytesPerChar);
- if (!name)
- return XML_ERROR_NO_MEMORY;
- entity = (ENTITY *)lookup(&dtd.paramEntities, name, 0);
- poolDiscard(&tempPool);
- if (!entity) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_UNDEFINED_ENTITY;
- }
- if (entity->open) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_RECURSIVE_ENTITY_REF;
- }
- if (entity->systemId) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_PARAM_ENTITY_REF;
- }
- entity->open = 1;
- result = storeEntityValue(parser,
- internalEncoding,
- (char *)entity->textPtr,
- (char *)(entity->textPtr + entity->textLen));
- entity->open = 0;
- if (result)
- return result;
- break;
- }
-#endif /* XML_DTD */
- eventPtr = entityTextPtr;
- return XML_ERROR_SYNTAX;
- case XML_TOK_NONE:
- return XML_ERROR_NONE;
- case XML_TOK_ENTITY_REF:
- case XML_TOK_DATA_CHARS:
- if (!poolAppend(pool, enc, entityTextPtr, next))
- return XML_ERROR_NO_MEMORY;
- break;
- case XML_TOK_TRAILING_CR:
- next = entityTextPtr + enc->minBytesPerChar;
- /* fall through */
- case XML_TOK_DATA_NEWLINE:
- if (pool->end == pool->ptr && !poolGrow(pool))
- return XML_ERROR_NO_MEMORY;
- *(pool->ptr)++ = 0xA;
- break;
- case XML_TOK_CHAR_REF:
- {
- XML_Char buf[XML_ENCODE_MAX];
- int i;
- int n = XmlCharRefNumber(enc, entityTextPtr);
- if (n < 0) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- n = XmlEncode(n, (ICHAR *)buf);
- if (!n) {
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_BAD_CHAR_REF;
- }
- for (i = 0; i < n; i++) {
- if (pool->end == pool->ptr && !poolGrow(pool))
- return XML_ERROR_NO_MEMORY;
- *(pool->ptr)++ = buf[i];
- }
- }
- break;
- case XML_TOK_PARTIAL:
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_INVALID_TOKEN;
- case XML_TOK_INVALID:
- if (enc == encoding)
- eventPtr = next;
- return XML_ERROR_INVALID_TOKEN;
- default:
- if (enc == encoding)
- eventPtr = entityTextPtr;
- return XML_ERROR_UNEXPECTED_STATE;
- }
- entityTextPtr = next;
- }
- /* not reached */
-}
-
-static void
-normalizeLines(XML_Char *s)
-{
- XML_Char *p;
- for (;; s++) {
- if (*s == XML_T('\0'))
- return;
- if (*s == 0xD)
- break;
- }
- p = s;
- do {
- if (*s == 0xD) {
- *p++ = 0xA;
- if (*++s == 0xA)
- s++;
- }
- else
- *p++ = *s++;
- } while (*s);
- *p = XML_T('\0');
-}
-
-static int
-reportProcessingInstruction(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
-{
- const XML_Char *target;
- XML_Char *data;
- const char *tem;
- if (!processingInstructionHandler) {
- if (defaultHandler)
- reportDefault(parser, enc, start, end);
- return 1;
- }
- start += enc->minBytesPerChar * 2;
- tem = start + XmlNameLength(enc, start);
- target = poolStoreString(&tempPool, enc, start, tem);
- if (!target)
- return 0;
- poolFinish(&tempPool);
- data = poolStoreString(&tempPool, enc,
- XmlSkipS(enc, tem),
- end - enc->minBytesPerChar*2);
- if (!data)
- return 0;
- normalizeLines(data);
- processingInstructionHandler(handlerArg, target, data);
- poolClear(&tempPool);
- return 1;
-}
-
-static int
-reportComment(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
-{
- XML_Char *data;
- if (!commentHandler) {
- if (defaultHandler)
- reportDefault(parser, enc, start, end);
- return 1;
- }
- data = poolStoreString(&tempPool,
- enc,
- start + enc->minBytesPerChar * 4,
- end - enc->minBytesPerChar * 3);
- if (!data)
- return 0;
- normalizeLines(data);
- commentHandler(handlerArg, data);
- poolClear(&tempPool);
- return 1;
-}
-
-static void
-reportDefault(XML_Parser parser, const ENCODING *enc, const char *s, const char *end)
-{
- if (MUST_CONVERT(enc, s)) {
- const char **eventPP;
- const char **eventEndPP;
- if (enc == encoding) {
- eventPP = &eventPtr;
- eventEndPP = &eventEndPtr;
- }
- else {
- eventPP = &(openInternalEntities->internalEventPtr);
- eventEndPP = &(openInternalEntities->internalEventEndPtr);
- }
- do {
- ICHAR *dataPtr = (ICHAR *)dataBuf;
- XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)dataBufEnd);
- *eventEndPP = s;
- defaultHandler(handlerArg, dataBuf, dataPtr - (ICHAR *)dataBuf);
- *eventPP = s;
- } while (s != end);
- }
- else
- defaultHandler(handlerArg, (XML_Char *)s, (XML_Char *)end - (XML_Char *)s);
-}
-
-
-static int
-defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, int isCdata,
- int isId, const XML_Char *value, XML_Parser parser)
-{
- DEFAULT_ATTRIBUTE *att;
- if (value || isId) {
- /* The handling of default attributes gets messed up if we have
- a default which duplicates a non-default. */
- int i;
- for (i = 0; i < type->nDefaultAtts; i++)
- if (attId == type->defaultAtts[i].id)
- return 1;
- if (isId && !type->idAtt && !attId->xmlns)
- type->idAtt = attId;
- }
- if (type->nDefaultAtts == type->allocDefaultAtts) {
- if (type->allocDefaultAtts == 0) {
- type->allocDefaultAtts = 8;
- type->defaultAtts = MALLOC(type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE));
- }
- else {
- type->allocDefaultAtts *= 2;
- type->defaultAtts = REALLOC(type->defaultAtts,
- type->allocDefaultAtts*sizeof(DEFAULT_ATTRIBUTE));
- }
- if (!type->defaultAtts)
- return 0;
- }
- att = type->defaultAtts + type->nDefaultAtts;
- att->id = attId;
- att->value = value;
- att->isCdata = isCdata;
- if (!isCdata)
- attId->maybeTokenized = 1;
- type->nDefaultAtts += 1;
- return 1;
-}
-
-static int setElementTypePrefix(XML_Parser parser, ELEMENT_TYPE *elementType)
-{
- const XML_Char *name;
- for (name = elementType->name; *name; name++) {
- if (*name == XML_T(':')) {
- PREFIX *prefix;
- const XML_Char *s;
- for (s = elementType->name; s != name; s++) {
- if (!poolAppendChar(&dtd.pool, *s))
- return 0;
- }
- if (!poolAppendChar(&dtd.pool, XML_T('\0')))
- return 0;
- prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
- if (!prefix)
- return 0;
- if (prefix->name == poolStart(&dtd.pool))
- poolFinish(&dtd.pool);
- else
- poolDiscard(&dtd.pool);
- elementType->prefix = prefix;
-
- }
- }
- return 1;
-}
-
-static ATTRIBUTE_ID *
-getAttributeId(XML_Parser parser, const ENCODING *enc, const char *start, const char *end)
-{
- ATTRIBUTE_ID *id;
- const XML_Char *name;
- if (!poolAppendChar(&dtd.pool, XML_T('\0')))
- return 0;
- name = poolStoreString(&dtd.pool, enc, start, end);
- if (!name)
- return 0;
- ++name;
- id = (ATTRIBUTE_ID *)lookup(&dtd.attributeIds, name, sizeof(ATTRIBUTE_ID));
- if (!id)
- return 0;
- if (id->name != name)
- poolDiscard(&dtd.pool);
- else {
- poolFinish(&dtd.pool);
- if (!ns)
- ;
- else if (name[0] == 'x'
- && name[1] == 'm'
- && name[2] == 'l'
- && name[3] == 'n'
- && name[4] == 's'
- && (name[5] == XML_T('\0') || name[5] == XML_T(':'))) {
- if (name[5] == '\0')
- id->prefix = &dtd.defaultPrefix;
- else
- id->prefix = (PREFIX *)lookup(&dtd.prefixes, name + 6, sizeof(PREFIX));
- id->xmlns = 1;
- }
- else {
- int i;
- for (i = 0; name[i]; i++) {
- if (name[i] == XML_T(':')) {
- int j;
- for (j = 0; j < i; j++) {
- if (!poolAppendChar(&dtd.pool, name[j]))
- return 0;
- }
- if (!poolAppendChar(&dtd.pool, XML_T('\0')))
- return 0;
- id->prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&dtd.pool), sizeof(PREFIX));
- if (id->prefix->name == poolStart(&dtd.pool))
- poolFinish(&dtd.pool);
- else
- poolDiscard(&dtd.pool);
- break;
- }
- }
- }
- }
- return id;
-}
-
-#define CONTEXT_SEP XML_T('\f')
-
-static
-const XML_Char *getContext(XML_Parser parser)
-{
- HASH_TABLE_ITER iter;
- int needSep = 0;
-
- if (dtd.defaultPrefix.binding) {
- int i;
- int len;
- if (!poolAppendChar(&tempPool, XML_T('=')))
- return 0;
- len = dtd.defaultPrefix.binding->uriLen;
- if (namespaceSeparator != XML_T('\0'))
- len--;
- for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, dtd.defaultPrefix.binding->uri[i]))
- return 0;
- needSep = 1;
- }
-
- hashTableIterInit(&iter, &(dtd.prefixes));
- for (;;) {
- int i;
- int len;
- const XML_Char *s;
- PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
- if (!prefix)
- break;
- if (!prefix->binding)
- continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
- return 0;
- for (s = prefix->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
- return 0;
- if (!poolAppendChar(&tempPool, XML_T('=')))
- return 0;
- len = prefix->binding->uriLen;
- if (namespaceSeparator != XML_T('\0'))
- len--;
- for (i = 0; i < len; i++)
- if (!poolAppendChar(&tempPool, prefix->binding->uri[i]))
- return 0;
- needSep = 1;
- }
-
-
- hashTableIterInit(&iter, &(dtd.generalEntities));
- for (;;) {
- const XML_Char *s;
- ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
- if (!e)
- break;
- if (!e->open)
- continue;
- if (needSep && !poolAppendChar(&tempPool, CONTEXT_SEP))
- return 0;
- for (s = e->name; *s; s++)
- if (!poolAppendChar(&tempPool, *s))
- return 0;
- needSep = 1;
- }
-
- if (!poolAppendChar(&tempPool, XML_T('\0')))
- return 0;
- return tempPool.start;
-}
-
-static
-int setContext(XML_Parser parser, const XML_Char *context)
-{
- const XML_Char *s = context;
-
- while (*context != XML_T('\0')) {
- if (*s == CONTEXT_SEP || *s == XML_T('\0')) {
- ENTITY *e;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
- return 0;
- e = (ENTITY *)lookup(&dtd.generalEntities, poolStart(&tempPool), 0);
- if (e)
- e->open = 1;
- if (*s != XML_T('\0'))
- s++;
- context = s;
- poolDiscard(&tempPool);
- }
- else if (*s == '=') {
- PREFIX *prefix;
- if (poolLength(&tempPool) == 0)
- prefix = &dtd.defaultPrefix;
- else {
- if (!poolAppendChar(&tempPool, XML_T('\0')))
- return 0;
- prefix = (PREFIX *)lookup(&dtd.prefixes, poolStart(&tempPool), sizeof(PREFIX));
- if (!prefix)
- return 0;
- if (prefix->name == poolStart(&tempPool)) {
- prefix->name = poolCopyString(&dtd.pool, prefix->name);
- if (!prefix->name)
- return 0;
- }
- poolDiscard(&tempPool);
- }
- for (context = s + 1; *context != CONTEXT_SEP && *context != XML_T('\0'); context++)
- if (!poolAppendChar(&tempPool, *context))
- return 0;
- if (!poolAppendChar(&tempPool, XML_T('\0')))
- return 0;
- if (!addBinding(parser, prefix, 0, poolStart(&tempPool), &inheritedBindings))
- return 0;
- poolDiscard(&tempPool);
- if (*context != XML_T('\0'))
- ++context;
- s = context;
- }
- else {
- if (!poolAppendChar(&tempPool, *s))
- return 0;
- s++;
- }
- }
- return 1;
-}
-
-
-static
-void normalizePublicId(XML_Char *publicId)
-{
- XML_Char *p = publicId;
- XML_Char *s;
- for (s = publicId; *s; s++) {
- switch (*s) {
- case 0x20:
- case 0xD:
- case 0xA:
- if (p != publicId && p[-1] != 0x20)
- *p++ = 0x20;
- break;
- default:
- *p++ = *s;
- }
- }
- if (p != publicId && p[-1] == 0x20)
- --p;
- *p = XML_T('\0');
-}
-
-static int dtdInit(DTD *p, XML_Parser parser)
-{
- XML_Memory_Handling_Suite *ms = &((Parser *) parser)->m_mem;
- poolInit(&(p->pool), ms);
- hashTableInit(&(p->generalEntities), ms);
- hashTableInit(&(p->elementTypes), ms);
- hashTableInit(&(p->attributeIds), ms);
- hashTableInit(&(p->prefixes), ms);
- p->complete = 1;
- p->standalone = 0;
-#ifdef XML_DTD
- hashTableInit(&(p->paramEntities), ms);
-#endif /* XML_DTD */
- p->defaultPrefix.name = 0;
- p->defaultPrefix.binding = 0;
-
- p->in_eldecl = 0;
- p->scaffIndex = 0;
- p->scaffLevel = 0;
- p->scaffold = 0;
- p->contentStringLen = 0;
- p->scaffSize = 0;
- p->scaffCount = 0;
-
- return 1;
-}
-
-#ifdef XML_DTD
-
-static void dtdSwap(DTD *p1, DTD *p2)
-{
- DTD tem;
- memcpy(&tem, p1, sizeof(DTD));
- memcpy(p1, p2, sizeof(DTD));
- memcpy(p2, &tem, sizeof(DTD));
-}
-
-#endif /* XML_DTD */
-
-static void dtdDestroy(DTD *p, XML_Parser parser)
-{
- HASH_TABLE_ITER iter;
- hashTableIterInit(&iter, &(p->elementTypes));
- for (;;) {
- ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
- if (!e)
- break;
- if (e->allocDefaultAtts != 0)
- FREE(e->defaultAtts);
- }
- hashTableDestroy(&(p->generalEntities));
-#ifdef XML_DTD
- hashTableDestroy(&(p->paramEntities));
-#endif /* XML_DTD */
- hashTableDestroy(&(p->elementTypes));
- hashTableDestroy(&(p->attributeIds));
- hashTableDestroy(&(p->prefixes));
- poolDestroy(&(p->pool));
- if (p->scaffIndex)
- FREE(p->scaffIndex);
- if (p->scaffold)
- FREE(p->scaffold);
-}
-
-/* Do a deep copy of the DTD. Return 0 for out of memory; non-zero otherwise.
-The new DTD has already been initialized. */
-
-static int dtdCopy(DTD *newDtd, const DTD *oldDtd, XML_Parser parser)
-{
- HASH_TABLE_ITER iter;
-
- /* Copy the prefix table. */
-
- hashTableIterInit(&iter, &(oldDtd->prefixes));
- for (;;) {
- const XML_Char *name;
- const PREFIX *oldP = (PREFIX *)hashTableIterNext(&iter);
- if (!oldP)
- break;
- name = poolCopyString(&(newDtd->pool), oldP->name);
- if (!name)
- return 0;
- if (!lookup(&(newDtd->prefixes), name, sizeof(PREFIX)))
- return 0;
- }
-
- hashTableIterInit(&iter, &(oldDtd->attributeIds));
-
- /* Copy the attribute id table. */
-
- for (;;) {
- ATTRIBUTE_ID *newA;
- const XML_Char *name;
- const ATTRIBUTE_ID *oldA = (ATTRIBUTE_ID *)hashTableIterNext(&iter);
-
- if (!oldA)
- break;
- /* Remember to allocate the scratch byte before the name. */
- if (!poolAppendChar(&(newDtd->pool), XML_T('\0')))
- return 0;
- name = poolCopyString(&(newDtd->pool), oldA->name);
- if (!name)
- return 0;
- ++name;
- newA = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), name, sizeof(ATTRIBUTE_ID));
- if (!newA)
- return 0;
- newA->maybeTokenized = oldA->maybeTokenized;
- if (oldA->prefix) {
- newA->xmlns = oldA->xmlns;
- if (oldA->prefix == &oldDtd->defaultPrefix)
- newA->prefix = &newDtd->defaultPrefix;
- else
- newA->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldA->prefix->name, 0);
- }
- }
-
- /* Copy the element type table. */
-
- hashTableIterInit(&iter, &(oldDtd->elementTypes));
-
- for (;;) {
- int i;
- ELEMENT_TYPE *newE;
- const XML_Char *name;
- const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
- if (!oldE)
- break;
- name = poolCopyString(&(newDtd->pool), oldE->name);
- if (!name)
- return 0;
- newE = (ELEMENT_TYPE *)lookup(&(newDtd->elementTypes), name, sizeof(ELEMENT_TYPE));
- if (!newE)
- return 0;
- if (oldE->nDefaultAtts) {
- newE->defaultAtts = (DEFAULT_ATTRIBUTE *)MALLOC(oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
- if (!newE->defaultAtts)
- return 0;
- }
- if (oldE->idAtt)
- newE->idAtt = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->idAtt->name, 0);
- newE->allocDefaultAtts = newE->nDefaultAtts = oldE->nDefaultAtts;
- if (oldE->prefix)
- newE->prefix = (PREFIX *)lookup(&(newDtd->prefixes), oldE->prefix->name, 0);
- for (i = 0; i < newE->nDefaultAtts; i++) {
- newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(&(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
- newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
- if (oldE->defaultAtts[i].value) {
- newE->defaultAtts[i].value = poolCopyString(&(newDtd->pool), oldE->defaultAtts[i].value);
- if (!newE->defaultAtts[i].value)
- return 0;
- }
- else
- newE->defaultAtts[i].value = 0;
- }
- }
-
- /* Copy the entity tables. */
- if (!copyEntityTable(&(newDtd->generalEntities),
- &(newDtd->pool),
- &(oldDtd->generalEntities), parser))
- return 0;
-
-#ifdef XML_DTD
- if (!copyEntityTable(&(newDtd->paramEntities),
- &(newDtd->pool),
- &(oldDtd->paramEntities), parser))
- return 0;
-#endif /* XML_DTD */
-
- newDtd->complete = oldDtd->complete;
- newDtd->standalone = oldDtd->standalone;
-
- /* Don't want deep copying for scaffolding */
- newDtd->in_eldecl = oldDtd->in_eldecl;
- newDtd->scaffold = oldDtd->scaffold;
- newDtd->contentStringLen = oldDtd->contentStringLen;
- newDtd->scaffSize = oldDtd->scaffSize;
- newDtd->scaffLevel = oldDtd->scaffLevel;
- newDtd->scaffIndex = oldDtd->scaffIndex;
-
- return 1;
-} /* End dtdCopy */
-
-static int copyEntityTable(HASH_TABLE *newTable,
- STRING_POOL *newPool,
- const HASH_TABLE *oldTable,
- XML_Parser parser)
-{
- HASH_TABLE_ITER iter;
- const XML_Char *cachedOldBase = 0;
- const XML_Char *cachedNewBase = 0;
- cmExpatUnused(parser);
-
- hashTableIterInit(&iter, oldTable);
-
- for (;;) {
- ENTITY *newE;
- const XML_Char *name;
- const ENTITY *oldE = (ENTITY *)hashTableIterNext(&iter);
- if (!oldE)
- break;
- name = poolCopyString(newPool, oldE->name);
- if (!name)
- return 0;
- newE = (ENTITY *)lookup(newTable, name, sizeof(ENTITY));
- if (!newE)
- return 0;
- if (oldE->systemId) {
- const XML_Char *tem = poolCopyString(newPool, oldE->systemId);
- if (!tem)
- return 0;
- newE->systemId = tem;
- if (oldE->base) {
- if (oldE->base == cachedOldBase)
- newE->base = cachedNewBase;
- else {
- cachedOldBase = oldE->base;
- tem = poolCopyString(newPool, cachedOldBase);
- if (!tem)
- return 0;
- cachedNewBase = newE->base = tem;
- }
- }
- }
- else {
- const XML_Char *tem = poolCopyStringN(newPool, oldE->textPtr, oldE->textLen);
- if (!tem)
- return 0;
- newE->textPtr = tem;
- newE->textLen = oldE->textLen;
- }
- if (oldE->notation) {
- const XML_Char *tem = poolCopyString(newPool, oldE->notation);
- if (!tem)
- return 0;
- newE->notation = tem;
- }
- }
- return 1;
-}
-
-#define INIT_SIZE 64
-
-static
-int keyeq(KEY s1, KEY s2)
-{
- for (; *s1 == *s2; s1++, s2++)
- if (*s1 == 0)
- return 1;
- return 0;
-}
-
-static
-unsigned long hash(KEY s)
-{
- unsigned long h = 0;
- while (*s)
- h = (h << 5) + h + (unsigned char)*s++;
- return h;
-}
-
-static
-NAMED *lookup(HASH_TABLE *table, KEY name, size_t createSize)
-{
- size_t i;
- if (table->size == 0) {
- size_t tsize;
-
- if (!createSize)
- return 0;
- tsize = INIT_SIZE * sizeof(NAMED *);
- table->v = table->mem->malloc_fcn(tsize);
- if (!table->v)
- return 0;
- memset(table->v, 0, tsize);
- table->size = INIT_SIZE;
- table->usedLim = INIT_SIZE / 2;
- i = hash(name) & (table->size - 1);
- }
- else {
- unsigned long h = hash(name);
- for (i = h & (table->size - 1);
- table->v[i];
- i == 0 ? i = table->size - 1 : --i) {
- if (keyeq(name, table->v[i]->name))
- return table->v[i];
- }
- if (!createSize)
- return 0;
- if (table->used == table->usedLim) {
- /* check for overflow */
- size_t newSize = table->size * 2;
- size_t tsize = newSize * sizeof(NAMED *);
- NAMED **newV = table->mem->malloc_fcn(tsize);
- if (!newV)
- return 0;
- memset(newV, 0, tsize);
- for (i = 0; i < table->size; i++)
- if (table->v[i]) {
- size_t j;
- for (j = hash(table->v[i]->name) & (newSize - 1);
- newV[j];
- j == 0 ? j = newSize - 1 : --j)
- ;
- newV[j] = table->v[i];
- }
- table->mem->free_fcn(table->v);
- table->v = newV;
- table->size = newSize;
- table->usedLim = newSize/2;
- for (i = h & (table->size - 1);
- table->v[i];
- i == 0 ? i = table->size - 1 : --i)
- ;
- }
- }
- table->v[i] = table->mem->malloc_fcn(createSize);
- if (!table->v[i])
- return 0;
- memset(table->v[i], 0, createSize);
- table->v[i]->name = name;
- (table->used)++;
- return table->v[i];
-}
-
-static
-void hashTableDestroy(HASH_TABLE *table)
-{
- size_t i;
- for (i = 0; i < table->size; i++) {
- NAMED *p = table->v[i];
- if (p)
- table->mem->free_fcn(p);
- }
- if (table->v)
- table->mem->free_fcn(table->v);
-}
-
-static
-void hashTableInit(HASH_TABLE *p, XML_Memory_Handling_Suite *ms)
-{
- p->size = 0;
- p->usedLim = 0;
- p->used = 0;
- p->v = 0;
- p->mem = ms;
-}
-
-static
-void hashTableIterInit(HASH_TABLE_ITER *iter, const HASH_TABLE *table)
-{
- iter->p = table->v;
- iter->end = iter->p + table->size;
-}
-
-static
-NAMED *hashTableIterNext(HASH_TABLE_ITER *iter)
-{
- while (iter->p != iter->end) {
- NAMED *tem = *(iter->p)++;
- if (tem)
- return tem;
- }
- return 0;
-}
-
-
-static
-void poolInit(STRING_POOL *pool, XML_Memory_Handling_Suite *ms)
-{
- pool->blocks = 0;
- pool->freeBlocks = 0;
- pool->start = 0;
- pool->ptr = 0;
- pool->end = 0;
- pool->mem = ms;
-}
-
-static
-void poolClear(STRING_POOL *pool)
-{
- if (!pool->freeBlocks)
- pool->freeBlocks = pool->blocks;
- else {
- BLOCK *p = pool->blocks;
- while (p) {
- BLOCK *tem = p->next;
- p->next = pool->freeBlocks;
- pool->freeBlocks = p;
- p = tem;
- }
- }
- pool->blocks = 0;
- pool->start = 0;
- pool->ptr = 0;
- pool->end = 0;
-}
-
-static
-void poolDestroy(STRING_POOL *pool)
-{
- BLOCK *p = pool->blocks;
- while (p) {
- BLOCK *tem = p->next;
- pool->mem->free_fcn(p);
- p = tem;
- }
- pool->blocks = 0;
- p = pool->freeBlocks;
- while (p) {
- BLOCK *tem = p->next;
- pool->mem->free_fcn(p);
- p = tem;
- }
- pool->freeBlocks = 0;
- pool->ptr = 0;
- pool->start = 0;
- pool->end = 0;
-}
-
-static
-XML_Char *poolAppend(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end)
-{
- if (!pool->ptr && !poolGrow(pool))
- return 0;
- for (;;) {
- XmlConvert(enc, &ptr, end, (ICHAR **)&(pool->ptr), (ICHAR *)pool->end);
- if (ptr == end)
- break;
- if (!poolGrow(pool))
- return 0;
- }
- return pool->start;
-}
-
-static const XML_Char *poolCopyString(STRING_POOL *pool, const XML_Char *s)
-{
- do {
- if (!poolAppendChar(pool, *s))
- return 0;
- } while (*s++);
- s = pool->start;
- poolFinish(pool);
- return s;
-}
-
-static const XML_Char *poolCopyStringN(STRING_POOL *pool, const XML_Char *s, int n)
-{
- if (!pool->ptr && !poolGrow(pool))
- return 0;
- for (; n > 0; --n, s++) {
- if (!poolAppendChar(pool, *s))
- return 0;
-
- }
- s = pool->start;
- poolFinish(pool);
- return s;
-}
-
-static
-const XML_Char *poolAppendString(STRING_POOL *pool, const XML_Char *s)
-{
- while (*s) {
- if (!poolAppendChar(pool, *s))
- return 0;
- s++;
- }
- return pool->start;
-} /* End poolAppendString */
-
-static
-XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
- const char *ptr, const char *end)
-{
- if (!poolAppend(pool, enc, ptr, end))
- return 0;
- if (pool->ptr == pool->end && !poolGrow(pool))
- return 0;
- *(pool->ptr)++ = 0;
- return pool->start;
-}
-
-static
-int poolGrow(STRING_POOL *pool)
-{
- if (pool->freeBlocks) {
- if (pool->start == 0) {
- pool->blocks = pool->freeBlocks;
- pool->freeBlocks = pool->freeBlocks->next;
- pool->blocks->next = 0;
- pool->start = pool->blocks->s;
- pool->end = pool->start + pool->blocks->size;
- pool->ptr = pool->start;
- return 1;
- }
- if (pool->end - pool->start < pool->freeBlocks->size) {
- BLOCK *tem = pool->freeBlocks->next;
- pool->freeBlocks->next = pool->blocks;
- pool->blocks = pool->freeBlocks;
- pool->freeBlocks = tem;
- memcpy(pool->blocks->s, pool->start, (pool->end - pool->start) * sizeof(XML_Char));
- pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
- pool->start = pool->blocks->s;
- pool->end = pool->start + pool->blocks->size;
- return 1;
- }
- }
- if (pool->blocks && pool->start == pool->blocks->s) {
- int blockSize = (pool->end - pool->start)*2;
- pool->blocks = pool->mem->realloc_fcn(pool->blocks, offsetof(BLOCK, s) + blockSize * sizeof(XML_Char));
- if (!pool->blocks)
- return 0;
- pool->blocks->size = blockSize;
- pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
- pool->start = pool->blocks->s;
- pool->end = pool->start + blockSize;
- }
- else {
- BLOCK *tem;
- int blockSize = pool->end - pool->start;
- if (blockSize < INIT_BLOCK_SIZE)
- blockSize = INIT_BLOCK_SIZE;
- else
- blockSize *= 2;
- tem = pool->mem->malloc_fcn(offsetof(BLOCK, s) + blockSize * sizeof(XML_Char));
- if (!tem)
- return 0;
- tem->size = blockSize;
- tem->next = pool->blocks;
- pool->blocks = tem;
- if (pool->ptr != pool->start)
- memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
- pool->ptr = tem->s + (pool->ptr - pool->start);
- pool->start = tem->s;
- pool->end = tem->s + blockSize;
- }
- return 1;
-}
-
-static int
-nextScaffoldPart(XML_Parser parser)
-{
- CONTENT_SCAFFOLD * me;
- int next;
-
- if (! dtd.scaffIndex) {
- dtd.scaffIndex = MALLOC(groupSize * sizeof(int));
- if (! dtd.scaffIndex)
- return -1;
- dtd.scaffIndex[0] = 0;
- }
-
- if (dtd.scaffCount >= dtd.scaffSize) {
- if (dtd.scaffold) {
- dtd.scaffSize *= 2;
- dtd.scaffold = (CONTENT_SCAFFOLD *) REALLOC(dtd.scaffold,
- dtd.scaffSize * sizeof(CONTENT_SCAFFOLD));
- }
- else {
- dtd.scaffSize = 32;
- dtd.scaffold = (CONTENT_SCAFFOLD *) MALLOC(dtd.scaffSize * sizeof(CONTENT_SCAFFOLD));
- }
- if (! dtd.scaffold)
- return -1;
- }
- next = dtd.scaffCount++;
- me = &dtd.scaffold[next];
- if (dtd.scaffLevel) {
- CONTENT_SCAFFOLD *parent = &dtd.scaffold[dtd.scaffIndex[dtd.scaffLevel - 1]];
- if (parent->lastchild) {
- dtd.scaffold[parent->lastchild].nextsib = next;
- }
- if (! parent->childcnt)
- parent->firstchild = next;
- parent->lastchild = next;
- parent->childcnt++;
- }
- me->firstchild = me->lastchild = me->childcnt = me->nextsib = 0;
- return next;
-} /* End nextScaffoldPart */
-
-static void
-build_node (XML_Parser parser,
- int src_node,
- XML_Content *dest,
- XML_Content **contpos,
- char **strpos)
-{
- dest->type = dtd.scaffold[src_node].type;
- dest->quant = dtd.scaffold[src_node].quant;
- if (dest->type == XML_CTYPE_NAME) {
- const char *src;
- dest->name = *strpos;
- src = dtd.scaffold[src_node].name;
- for (;;) {
- *(*strpos)++ = *src;
- if (! *src)
- break;
- src++;
- }
- dest->numchildren = 0;
- dest->children = 0;
- }
- else {
- unsigned int i;
- int cn;
- dest->numchildren = dtd.scaffold[src_node].childcnt;
- dest->children = *contpos;
- *contpos += dest->numchildren;
- for (i = 0, cn = dtd.scaffold[src_node].firstchild;
- i < dest->numchildren;
- i++, cn = dtd.scaffold[cn].nextsib) {
- build_node(parser, cn, &(dest->children[i]), contpos, strpos);
- }
- dest->name = 0;
- }
-} /* End build_node */
-
-static XML_Content *
-build_model (XML_Parser parser)
-{
- XML_Content *ret;
- XML_Content *cpos;
- char * str;
- int allocsize = dtd.scaffCount * sizeof(XML_Content) + dtd.contentStringLen;
-
- ret = MALLOC(allocsize);
- if (! ret)
- return 0;
-
- str = (char *) (&ret[dtd.scaffCount]);
- cpos = &ret[1];
-
- build_node(parser, 0, ret, &cpos, &str);
- return ret;
-} /* End build_model */
-
-static ELEMENT_TYPE *
-getElementType(XML_Parser parser,
- const ENCODING *enc,
- const char *ptr,
- const char *end)
-{
- const XML_Char *name = poolStoreString(&dtd.pool, enc, ptr, end);
- ELEMENT_TYPE *ret;
-
- if (! name)
- return 0;
- ret = (ELEMENT_TYPE *) lookup(&dtd.elementTypes, name, sizeof(ELEMENT_TYPE));
- if (! ret)
- return 0;
- if (ret->name != name)
- poolDiscard(&dtd.pool);
- else {
- poolFinish(&dtd.pool);
- if (!setElementTypePrefix(parser, ret))
- return 0;
- }
- return ret;
-} /* End getElementType */
diff --git a/Utilities/cmexpat/xmlrole.c b/Utilities/cmexpat/xmlrole.c
deleted file mode 100644
index 289964ca5..000000000
--- a/Utilities/cmexpat/xmlrole.c
+++ /dev/null
@@ -1,1401 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-static char RCSId[]
- = "$Header$";
-const char* cm_expat_GetXMLRole_RCSId()
-{
- /* Avoid warning about unused static without removing RCSId from original. */
- return RCSId;
-}
-
-#include <cmexpat/expatConfig.h>
-
-#include "xmlrole.h"
-#include "ascii.h"
-
-/* Doesn't check:
-
- that ,| are not mixed in a model group
- content of literals
-
-*/
-
-static const char KW_ANY[] = { ASCII_A, ASCII_N, ASCII_Y, '\0' };
-static const char KW_ATTLIST[] = { ASCII_A, ASCII_T, ASCII_T, ASCII_L, ASCII_I, ASCII_S, ASCII_T, '\0' };
-static const char KW_CDATA[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_DOCTYPE[] = { ASCII_D, ASCII_O, ASCII_C, ASCII_T, ASCII_Y, ASCII_P, ASCII_E, '\0' };
-static const char KW_ELEMENT[] = { ASCII_E, ASCII_L, ASCII_E, ASCII_M, ASCII_E, ASCII_N, ASCII_T, '\0' };
-static const char KW_EMPTY[] = { ASCII_E, ASCII_M, ASCII_P, ASCII_T, ASCII_Y, '\0' };
-static const char KW_ENTITIES[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_I, ASCII_E, ASCII_S, '\0' };
-static const char KW_ENTITY[] = { ASCII_E, ASCII_N, ASCII_T, ASCII_I, ASCII_T, ASCII_Y, '\0' };
-static const char KW_FIXED[] = { ASCII_F, ASCII_I, ASCII_X, ASCII_E, ASCII_D, '\0' };
-static const char KW_ID[] = { ASCII_I, ASCII_D, '\0' };
-static const char KW_IDREF[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, '\0' };
-static const char KW_IDREFS[] = { ASCII_I, ASCII_D, ASCII_R, ASCII_E, ASCII_F, ASCII_S, '\0' };
-static const char KW_IGNORE[] = { ASCII_I, ASCII_G, ASCII_N, ASCII_O, ASCII_R, ASCII_E, '\0' };
-static const char KW_IMPLIED[] = { ASCII_I, ASCII_M, ASCII_P, ASCII_L, ASCII_I, ASCII_E, ASCII_D, '\0' };
-static const char KW_INCLUDE[] = { ASCII_I, ASCII_N, ASCII_C, ASCII_L, ASCII_U, ASCII_D, ASCII_E, '\0' };
-static const char KW_NDATA[] = { ASCII_N, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_NMTOKEN[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, '\0' };
-static const char KW_NMTOKENS[] = { ASCII_N, ASCII_M, ASCII_T, ASCII_O, ASCII_K, ASCII_E, ASCII_N, ASCII_S, '\0' };
-static const char KW_NOTATION[] = { ASCII_N, ASCII_O, ASCII_T, ASCII_A, ASCII_T, ASCII_I, ASCII_O, ASCII_N, '\0' };
-static const char KW_PCDATA[] = { ASCII_P, ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, '\0' };
-static const char KW_PUBLIC[] = { ASCII_P, ASCII_U, ASCII_B, ASCII_L, ASCII_I, ASCII_C, '\0' };
-static const char KW_REQUIRED[] = { ASCII_R, ASCII_E, ASCII_Q, ASCII_U, ASCII_I, ASCII_R, ASCII_E, ASCII_D, '\0' };
-static const char KW_SYSTEM[] = { ASCII_S, ASCII_Y, ASCII_S, ASCII_T, ASCII_E, ASCII_M, '\0' };
-
-#ifndef MIN_BYTES_PER_CHAR
-#define MIN_BYTES_PER_CHAR(enc) ((enc)->minBytesPerChar)
-#endif
-
-#ifdef XML_DTD
-#define setTopLevel(state) \
- ((state)->handler = ((state)->documentEntity \
- ? internalSubset \
- : externalSubset1))
-#else /* not XML_DTD */
-#define setTopLevel(state) ((state)->handler = internalSubset)
-#endif /* not XML_DTD */
-
-typedef int PROLOG_HANDLER(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc);
-
-static PROLOG_HANDLER
- prolog0, prolog1, prolog2,
- doctype0, doctype1, doctype2, doctype3, doctype4, doctype5,
- internalSubset,
- entity0, entity1, entity2, entity3, entity4, entity5, entity6,
- entity7, entity8, entity9,
- notation0, notation1, notation2, notation3, notation4,
- attlist0, attlist1, attlist2, attlist3, attlist4, attlist5, attlist6,
- attlist7, attlist8, attlist9,
- element0, element1, element2, element3, element4, element5, element6,
- element7,
-#ifdef XML_DTD
- externalSubset0, externalSubset1,
- condSect0, condSect1, condSect2,
-#endif /* XML_DTD */
- declClose,
- error;
-
-static
-int common(PROLOG_STATE *state, int tok);
-
-static
-int prolog0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- state->handler = prolog1;
- return XML_ROLE_NONE;
- case XML_TOK_XML_DECL:
- state->handler = prolog1;
- return XML_ROLE_XML_DECL;
- case XML_TOK_PI:
- state->handler = prolog1;
- return XML_ROLE_NONE;
- case XML_TOK_COMMENT:
- state->handler = prolog1;
- case XML_TOK_BOM:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_OPEN:
- if (!XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_DOCTYPE))
- break;
- state->handler = doctype0;
- return XML_ROLE_NONE;
- case XML_TOK_INSTANCE_START:
- state->handler = error;
- return XML_ROLE_INSTANCE_START;
- }
- return common(state, tok);
-}
-
-static
-int prolog1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_PI:
- case XML_TOK_COMMENT:
- case XML_TOK_BOM:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_OPEN:
- if (!XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_DOCTYPE))
- break;
- state->handler = doctype0;
- return XML_ROLE_NONE;
- case XML_TOK_INSTANCE_START:
- state->handler = error;
- return XML_ROLE_INSTANCE_START;
- }
- return common(state, tok);
-}
-
-static
-int prolog2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_PI:
- case XML_TOK_COMMENT:
- return XML_ROLE_NONE;
- case XML_TOK_INSTANCE_START:
- state->handler = error;
- return XML_ROLE_INSTANCE_START;
- }
- return common(state, tok);
-}
-
-static
-int doctype0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = doctype1;
- return XML_ROLE_DOCTYPE_NAME;
- }
- return common(state, tok);
-}
-
-static
-int doctype1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_BRACKET:
- state->handler = internalSubset;
- return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
- case XML_TOK_DECL_CLOSE:
- state->handler = prolog2;
- return XML_ROLE_DOCTYPE_CLOSE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
- state->handler = doctype3;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
- state->handler = doctype2;
- return XML_ROLE_NONE;
- }
- break;
- }
- return common(state, tok);
-}
-
-static
-int doctype2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = doctype3;
- return XML_ROLE_DOCTYPE_PUBLIC_ID;
- }
- return common(state, tok);
-}
-
-static
-int doctype3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = doctype4;
- return XML_ROLE_DOCTYPE_SYSTEM_ID;
- }
- return common(state, tok);
-}
-
-static
-int doctype4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_BRACKET:
- state->handler = internalSubset;
- return XML_ROLE_DOCTYPE_INTERNAL_SUBSET;
- case XML_TOK_DECL_CLOSE:
- state->handler = prolog2;
- return XML_ROLE_DOCTYPE_CLOSE;
- }
- return common(state, tok);
-}
-
-static
-int doctype5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_CLOSE:
- state->handler = prolog2;
- return XML_ROLE_DOCTYPE_CLOSE;
- }
- return common(state, tok);
-}
-
-static
-int internalSubset(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_OPEN:
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_ENTITY)) {
- state->handler = entity0;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_ATTLIST)) {
- state->handler = attlist0;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_ELEMENT)) {
- state->handler = element0;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc,
- ptr + 2 * MIN_BYTES_PER_CHAR(enc),
- end,
- KW_NOTATION)) {
- state->handler = notation0;
- return XML_ROLE_NONE;
- }
- break;
- case XML_TOK_PI:
- case XML_TOK_COMMENT:
- return XML_ROLE_NONE;
- case XML_TOK_PARAM_ENTITY_REF:
- return XML_ROLE_PARAM_ENTITY_REF;
- case XML_TOK_CLOSE_BRACKET:
- state->handler = doctype5;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-#ifdef XML_DTD
-
-static
-int externalSubset0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- state->handler = externalSubset1;
- if (tok == XML_TOK_XML_DECL)
- return XML_ROLE_TEXT_DECL;
- return externalSubset1(state, tok, ptr, end, enc);
-}
-
-static
-int externalSubset1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_COND_SECT_OPEN:
- state->handler = condSect0;
- return XML_ROLE_NONE;
- case XML_TOK_COND_SECT_CLOSE:
- if (state->includeLevel == 0)
- break;
- state->includeLevel -= 1;
- return XML_ROLE_NONE;
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_BRACKET:
- break;
- case XML_TOK_NONE:
- if (state->includeLevel)
- break;
- return XML_ROLE_NONE;
- default:
- return internalSubset(state, tok, ptr, end, enc);
- }
- return common(state, tok);
-}
-
-#endif /* XML_DTD */
-
-static
-int entity0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_PERCENT:
- state->handler = entity1;
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- state->handler = entity2;
- return XML_ROLE_GENERAL_ENTITY_NAME;
- }
- return common(state, tok);
-}
-
-static
-int entity1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- state->handler = entity7;
- return XML_ROLE_PARAM_ENTITY_NAME;
- }
- return common(state, tok);
-}
-
-static
-int entity2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
- state->handler = entity4;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
- state->handler = entity3;
- return XML_ROLE_NONE;
- }
- break;
- case XML_TOK_LITERAL:
- state->handler = declClose;
- return XML_ROLE_ENTITY_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int entity3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = entity4;
- return XML_ROLE_ENTITY_PUBLIC_ID;
- }
- return common(state, tok);
-}
-
-
-static
-int entity4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = entity5;
- return XML_ROLE_ENTITY_SYSTEM_ID;
- }
- return common(state, tok);
-}
-
-static
-int entity5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_CLOSE:
- setTopLevel(state);
- return XML_ROLE_ENTITY_COMPLETE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_NDATA)) {
- state->handler = entity6;
- return XML_ROLE_NONE;
- }
- break;
- }
- return common(state, tok);
-}
-
-static
-int entity6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- state->handler = declClose;
- return XML_ROLE_ENTITY_NOTATION_NAME;
- }
- return common(state, tok);
-}
-
-static
-int entity7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
- state->handler = entity9;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
- state->handler = entity8;
- return XML_ROLE_NONE;
- }
- break;
- case XML_TOK_LITERAL:
- state->handler = declClose;
- return XML_ROLE_ENTITY_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int entity8(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = entity9;
- return XML_ROLE_ENTITY_PUBLIC_ID;
- }
- return common(state, tok);
-}
-
-static
-int entity9(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = declClose;
- return XML_ROLE_ENTITY_SYSTEM_ID;
- }
- return common(state, tok);
-}
-
-static
-int notation0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- state->handler = notation1;
- return XML_ROLE_NOTATION_NAME;
- }
- return common(state, tok);
-}
-
-static
-int notation1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_SYSTEM)) {
- state->handler = notation3;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_PUBLIC)) {
- state->handler = notation2;
- return XML_ROLE_NONE;
- }
- break;
- }
- return common(state, tok);
-}
-
-static
-int notation2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = notation4;
- return XML_ROLE_NOTATION_PUBLIC_ID;
- }
- return common(state, tok);
-}
-
-static
-int notation3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = declClose;
- return XML_ROLE_NOTATION_SYSTEM_ID;
- }
- return common(state, tok);
-}
-
-static
-int notation4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = declClose;
- return XML_ROLE_NOTATION_SYSTEM_ID;
- case XML_TOK_DECL_CLOSE:
- setTopLevel(state);
- return XML_ROLE_NOTATION_NO_SYSTEM_ID;
- }
- return common(state, tok);
-}
-
-static
-int attlist0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = attlist1;
- return XML_ROLE_ATTLIST_ELEMENT_NAME;
- }
- return common(state, tok);
-}
-
-static
-int attlist1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_CLOSE:
- setTopLevel(state);
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = attlist2;
- return XML_ROLE_ATTRIBUTE_NAME;
- }
- return common(state, tok);
-}
-
-static
-int attlist2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- {
- static const char *types[] = {
- KW_CDATA,
- KW_ID,
- KW_IDREF,
- KW_IDREFS,
- KW_ENTITY,
- KW_ENTITIES,
- KW_NMTOKEN,
- KW_NMTOKENS,
- };
- int i;
- for (i = 0; i < (int)(sizeof(types)/sizeof(types[0])); i++)
- if (XmlNameMatchesAscii(enc, ptr, end, types[i])) {
- state->handler = attlist8;
- return XML_ROLE_ATTRIBUTE_TYPE_CDATA + i;
- }
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_NOTATION)) {
- state->handler = attlist5;
- return XML_ROLE_NONE;
- }
- break;
- case XML_TOK_OPEN_PAREN:
- state->handler = attlist3;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-static
-int attlist3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NMTOKEN:
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = attlist4;
- return XML_ROLE_ATTRIBUTE_ENUM_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int attlist4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_PAREN:
- state->handler = attlist8;
- return XML_ROLE_NONE;
- case XML_TOK_OR:
- state->handler = attlist3;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-static
-int attlist5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_PAREN:
- state->handler = attlist6;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-
-static
-int attlist6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- state->handler = attlist7;
- return XML_ROLE_ATTRIBUTE_NOTATION_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int attlist7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_PAREN:
- state->handler = attlist8;
- return XML_ROLE_NONE;
- case XML_TOK_OR:
- state->handler = attlist6;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-/* default value */
-static
-int attlist8(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_POUND_NAME:
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
- KW_IMPLIED)) {
- state->handler = attlist1;
- return XML_ROLE_IMPLIED_ATTRIBUTE_VALUE;
- }
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
- KW_REQUIRED)) {
- state->handler = attlist1;
- return XML_ROLE_REQUIRED_ATTRIBUTE_VALUE;
- }
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
- KW_FIXED)) {
- state->handler = attlist9;
- return XML_ROLE_NONE;
- }
- break;
- case XML_TOK_LITERAL:
- state->handler = attlist1;
- return XML_ROLE_DEFAULT_ATTRIBUTE_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int attlist9(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_LITERAL:
- state->handler = attlist1;
- return XML_ROLE_FIXED_ATTRIBUTE_VALUE;
- }
- return common(state, tok);
-}
-
-static
-int element0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = element1;
- return XML_ROLE_ELEMENT_NAME;
- }
- return common(state, tok);
-}
-
-static
-int element1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_EMPTY)) {
- state->handler = declClose;
- return XML_ROLE_CONTENT_EMPTY;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_ANY)) {
- state->handler = declClose;
- return XML_ROLE_CONTENT_ANY;
- }
- break;
- case XML_TOK_OPEN_PAREN:
- state->handler = element2;
- state->level = 1;
- return XML_ROLE_GROUP_OPEN;
- }
- return common(state, tok);
-}
-
-static
-int element2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_POUND_NAME:
- if (XmlNameMatchesAscii(enc,
- ptr + MIN_BYTES_PER_CHAR(enc),
- end,
- KW_PCDATA)) {
- state->handler = element3;
- return XML_ROLE_CONTENT_PCDATA;
- }
- break;
- case XML_TOK_OPEN_PAREN:
- state->level = 2;
- state->handler = element6;
- return XML_ROLE_GROUP_OPEN;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT;
- case XML_TOK_NAME_QUESTION:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_OPT;
- case XML_TOK_NAME_ASTERISK:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_REP;
- case XML_TOK_NAME_PLUS:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_PLUS;
- }
- return common(state, tok);
-}
-
-static
-int element3(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_PAREN:
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE;
- case XML_TOK_CLOSE_PAREN_ASTERISK:
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE_REP;
- case XML_TOK_OR:
- state->handler = element4;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-static
-int element4(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = element5;
- return XML_ROLE_CONTENT_ELEMENT;
- }
- return common(state, tok);
-}
-
-static
-int element5(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_PAREN_ASTERISK:
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE_REP;
- case XML_TOK_OR:
- state->handler = element4;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-static
-int element6(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_PAREN:
- state->level += 1;
- return XML_ROLE_GROUP_OPEN;
- case XML_TOK_NAME:
- case XML_TOK_PREFIXED_NAME:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT;
- case XML_TOK_NAME_QUESTION:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_OPT;
- case XML_TOK_NAME_ASTERISK:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_REP;
- case XML_TOK_NAME_PLUS:
- state->handler = element7;
- return XML_ROLE_CONTENT_ELEMENT_PLUS;
- }
- return common(state, tok);
-}
-
-static
-int element7(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_CLOSE_PAREN:
- state->level -= 1;
- if (state->level == 0)
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE;
- case XML_TOK_CLOSE_PAREN_ASTERISK:
- state->level -= 1;
- if (state->level == 0)
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE_REP;
- case XML_TOK_CLOSE_PAREN_QUESTION:
- state->level -= 1;
- if (state->level == 0)
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE_OPT;
- case XML_TOK_CLOSE_PAREN_PLUS:
- state->level -= 1;
- if (state->level == 0)
- state->handler = declClose;
- return XML_ROLE_GROUP_CLOSE_PLUS;
- case XML_TOK_COMMA:
- state->handler = element6;
- return XML_ROLE_GROUP_SEQUENCE;
- case XML_TOK_OR:
- state->handler = element6;
- return XML_ROLE_GROUP_CHOICE;
- }
- return common(state, tok);
-}
-
-#ifdef XML_DTD
-
-static
-int condSect0(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_NAME:
- if (XmlNameMatchesAscii(enc, ptr, end, KW_INCLUDE)) {
- state->handler = condSect1;
- return XML_ROLE_NONE;
- }
- if (XmlNameMatchesAscii(enc, ptr, end, KW_IGNORE)) {
- state->handler = condSect2;
- return XML_ROLE_NONE;
- }
- break;
- }
- return common(state, tok);
-}
-
-static
-int condSect1(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_BRACKET:
- state->handler = externalSubset1;
- state->includeLevel += 1;
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-static
-int condSect2(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_OPEN_BRACKET:
- state->handler = externalSubset1;
- return XML_ROLE_IGNORE_SECT;
- }
- return common(state, tok);
-}
-
-#endif /* XML_DTD */
-
-static
-int declClose(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_PROLOG_S:
- return XML_ROLE_NONE;
- case XML_TOK_DECL_CLOSE:
- setTopLevel(state);
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-
-#if 0
-
-static
-int ignore(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- switch (tok) {
- case XML_TOK_DECL_CLOSE:
- state->handler = internalSubset;
- return 0;
- default:
- return XML_ROLE_NONE;
- }
- return common(state, tok);
-}
-#endif
-
-static
-int error(PROLOG_STATE *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc)
-{
- cmExpatUnused(state);
- cmExpatUnused(tok);
- cmExpatUnused(ptr);
- cmExpatUnused(end);
- cmExpatUnused(enc);
- return XML_ROLE_NONE;
-}
-
-static
-int common(PROLOG_STATE *state, int tok)
-{
-#ifdef XML_DTD
- if (!state->documentEntity && tok == XML_TOK_PARAM_ENTITY_REF)
- return XML_ROLE_INNER_PARAM_ENTITY_REF;
-#endif
- state->handler = error;
- return XML_ROLE_ERROR;
-}
-
-void XmlPrologStateInit(PROLOG_STATE *state)
-{
- state->handler = prolog0;
-#ifdef XML_DTD
- state->documentEntity = 1;
- state->includeLevel = 0;
-#endif /* XML_DTD */
-}
-
-#ifdef XML_DTD
-
-void XmlPrologStateInitExternalEntity(PROLOG_STATE *state)
-{
- state->handler = externalSubset0;
- state->documentEntity = 0;
- state->includeLevel = 0;
-}
-
-#endif /* XML_DTD */
diff --git a/Utilities/cmexpat/xmlrole.h b/Utilities/cmexpat/xmlrole.h
deleted file mode 100644
index 6f2579306..000000000
--- a/Utilities/cmexpat/xmlrole.h
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#ifndef XmlRole_INCLUDED
-#define XmlRole_INCLUDED 1
-
-#include "xmltok.h"
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum {
- XML_ROLE_ERROR = -1,
- XML_ROLE_NONE = 0,
- XML_ROLE_XML_DECL,
- XML_ROLE_INSTANCE_START,
- XML_ROLE_DOCTYPE_NAME,
- XML_ROLE_DOCTYPE_SYSTEM_ID,
- XML_ROLE_DOCTYPE_PUBLIC_ID,
- XML_ROLE_DOCTYPE_INTERNAL_SUBSET,
- XML_ROLE_DOCTYPE_CLOSE,
- XML_ROLE_GENERAL_ENTITY_NAME,
- XML_ROLE_PARAM_ENTITY_NAME,
- XML_ROLE_ENTITY_VALUE,
- XML_ROLE_ENTITY_SYSTEM_ID,
- XML_ROLE_ENTITY_PUBLIC_ID,
- XML_ROLE_ENTITY_COMPLETE,
- XML_ROLE_ENTITY_NOTATION_NAME,
- XML_ROLE_NOTATION_NAME,
- XML_ROLE_NOTATION_SYSTEM_ID,
- XML_ROLE_NOTATION_NO_SYSTEM_ID,
- XML_ROLE_NOTATION_PUBLIC_ID,
- XML_ROLE_ATTRIBUTE_NAME,
- XML_ROLE_ATTRIBUTE_TYPE_CDATA,
- XML_ROLE_ATTRIBUTE_TYPE_ID,
- XML_ROLE_ATTRIBUTE_TYPE_IDREF,
- XML_ROLE_ATTRIBUTE_TYPE_IDREFS,
- XML_ROLE_ATTRIBUTE_TYPE_ENTITY,
- XML_ROLE_ATTRIBUTE_TYPE_ENTITIES,
- XML_ROLE_ATTRIBUTE_TYPE_NMTOKEN,
- XML_ROLE_ATTRIBUTE_TYPE_NMTOKENS,
- XML_ROLE_ATTRIBUTE_ENUM_VALUE,
- XML_ROLE_ATTRIBUTE_NOTATION_VALUE,
- XML_ROLE_ATTLIST_ELEMENT_NAME,
- XML_ROLE_IMPLIED_ATTRIBUTE_VALUE,
- XML_ROLE_REQUIRED_ATTRIBUTE_VALUE,
- XML_ROLE_DEFAULT_ATTRIBUTE_VALUE,
- XML_ROLE_FIXED_ATTRIBUTE_VALUE,
- XML_ROLE_ELEMENT_NAME,
- XML_ROLE_CONTENT_ANY,
- XML_ROLE_CONTENT_EMPTY,
- XML_ROLE_CONTENT_PCDATA,
- XML_ROLE_GROUP_OPEN,
- XML_ROLE_GROUP_CLOSE,
- XML_ROLE_GROUP_CLOSE_REP,
- XML_ROLE_GROUP_CLOSE_OPT,
- XML_ROLE_GROUP_CLOSE_PLUS,
- XML_ROLE_GROUP_CHOICE,
- XML_ROLE_GROUP_SEQUENCE,
- XML_ROLE_CONTENT_ELEMENT,
- XML_ROLE_CONTENT_ELEMENT_REP,
- XML_ROLE_CONTENT_ELEMENT_OPT,
- XML_ROLE_CONTENT_ELEMENT_PLUS,
-#ifdef XML_DTD
- XML_ROLE_TEXT_DECL,
- XML_ROLE_IGNORE_SECT,
- XML_ROLE_INNER_PARAM_ENTITY_REF,
-#endif /* XML_DTD */
- XML_ROLE_PARAM_ENTITY_REF
-};
-
-typedef struct prolog_state {
- int (*handler)(struct prolog_state *state,
- int tok,
- const char *ptr,
- const char *end,
- const ENCODING *enc);
- unsigned level;
-#ifdef XML_DTD
- unsigned includeLevel;
- int documentEntity;
-#endif /* XML_DTD */
-} PROLOG_STATE;
-
-void XmlPrologStateInit(PROLOG_STATE *);
-#ifdef XML_DTD
-void XmlPrologStateInitExternalEntity(PROLOG_STATE *);
-#endif /* XML_DTD */
-
-#define XmlTokenRole(state, tok, ptr, end, enc) \
- (((state)->handler)(state, tok, ptr, end, enc))
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not XmlRole_INCLUDED */
diff --git a/Utilities/cmexpat/xmltok.c b/Utilities/cmexpat/xmltok.c
deleted file mode 100644
index 8ee9c7519..000000000
--- a/Utilities/cmexpat/xmltok.c
+++ /dev/null
@@ -1,1584 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#include <cmexpat/expatConfig.h>
-
-#include "xmltok.h"
-#include "nametab.h"
-
-#if defined(__BORLANDC__)
-#pragma warn -8008 // Disable "condition is always true" warning.
-#pragma warn -8066 // Disable "unreachable code" warning.
-#endif
-
-#ifdef XML_DTD
-#define IGNORE_SECTION_TOK_VTABLE , PREFIX(ignoreSectionTok)
-#else
-#define IGNORE_SECTION_TOK_VTABLE /* as nothing */
-#endif
-
-#define VTABLE1 \
- { PREFIX(prologTok), PREFIX(contentTok), \
- PREFIX(cdataSectionTok) IGNORE_SECTION_TOK_VTABLE }, \
- { PREFIX(attributeValueTok), PREFIX(entityValueTok) }, \
- PREFIX(sameName), \
- PREFIX(nameMatchesAscii), \
- PREFIX(nameLength), \
- PREFIX(skipS), \
- PREFIX(getAtts), \
- PREFIX(charRefNumber), \
- PREFIX(predefinedEntityName), \
- PREFIX(updatePosition), \
- PREFIX(isPublicId)
-
-#define VTABLE VTABLE1, PREFIX(toUtf8), PREFIX(toUtf16)
-
-#define UCS2_GET_NAMING(pages, hi, lo) \
- (namingBitmap[(pages[hi] << 3) + ((lo) >> 5)] & (1 << ((lo) & 0x1F)))
-
-/* A 2 byte UTF-8 representation splits the characters 11 bits
-between the bottom 5 and 6 bits of the bytes.
-We need 8 bits to index into pages, 3 bits to add to that index and
-5 bits to generate the mask. */
-#define UTF8_GET_NAMING2(pages, byte) \
- (namingBitmap[((pages)[(((byte)[0]) >> 2) & 7] << 3) \
- + ((((byte)[0]) & 3) << 1) \
- + ((((byte)[1]) >> 5) & 1)] \
- & (1 << (((byte)[1]) & 0x1F)))
-
-/* A 3 byte UTF-8 representation splits the characters 16 bits
-between the bottom 4, 6 and 6 bits of the bytes.
-We need 8 bits to index into pages, 3 bits to add to that index and
-5 bits to generate the mask. */
-#define UTF8_GET_NAMING3(pages, byte) \
- (namingBitmap[((pages)[((((byte)[0]) & 0xF) << 4) \
- + ((((byte)[1]) >> 2) & 0xF)] \
- << 3) \
- + ((((byte)[1]) & 3) << 1) \
- + ((((byte)[2]) >> 5) & 1)] \
- & (1 << (((byte)[2]) & 0x1F)))
-
-#define UTF8_GET_NAMING(pages, p, n) \
- ((n) == 2 \
- ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p)) \
- : ((n) == 3 \
- ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) \
- : 0))
-
-#define UTF8_INVALID3(p) \
- ((*p) == 0xED \
- ? (((p)[1] & 0x20) != 0) \
- : ((*p) == 0xEF \
- ? ((p)[1] == 0xBF && ((p)[2] == 0xBF || (p)[2] == 0xBE)) \
- : 0))
-
-#define UTF8_INVALID4(p) ((*p) == 0xF4 && ((p)[1] & 0x30) != 0)
-
-static
-int isNever(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- cmExpatUnused(p);
- return 0;
-}
-
-static
-int utf8_isName2(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_GET_NAMING2(namePages, (const unsigned char *)p);
-}
-
-static
-int utf8_isName3(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_GET_NAMING3(namePages, (const unsigned char *)p);
-}
-
-#define utf8_isName4 isNever
-
-static
-int utf8_isNmstrt2(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_GET_NAMING2(nmstrtPages, (const unsigned char *)p);
-}
-
-static
-int utf8_isNmstrt3(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_GET_NAMING3(nmstrtPages, (const unsigned char *)p);
-}
-
-#define utf8_isNmstrt4 isNever
-
-#define utf8_isInvalid2 isNever
-
-static
-int utf8_isInvalid3(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_INVALID3((const unsigned char *)p);
-}
-
-static
-int utf8_isInvalid4(const ENCODING *enc, const char *p)
-{
- cmExpatUnused(enc);
- return UTF8_INVALID4((const unsigned char *)p);
-}
-
-struct normal_encoding {
- ENCODING enc;
- unsigned char type[256];
-#ifdef XML_MIN_SIZE
- int (*byteType)(const ENCODING *, const char *);
- int (*isNameMin)(const ENCODING *, const char *);
- int (*isNmstrtMin)(const ENCODING *, const char *);
- int (*byteToAscii)(const ENCODING *, const char *);
- int (*charMatches)(const ENCODING *, const char *, int);
-#endif /* XML_MIN_SIZE */
- int (*isName2)(const ENCODING *, const char *);
- int (*isName3)(const ENCODING *, const char *);
- int (*isName4)(const ENCODING *, const char *);
- int (*isNmstrt2)(const ENCODING *, const char *);
- int (*isNmstrt3)(const ENCODING *, const char *);
- int (*isNmstrt4)(const ENCODING *, const char *);
- int (*isInvalid2)(const ENCODING *, const char *);
- int (*isInvalid3)(const ENCODING *, const char *);
- int (*isInvalid4)(const ENCODING *, const char *);
-};
-
-#ifdef XML_MIN_SIZE
-
-#define STANDARD_VTABLE(E) \
- E ## byteType, \
- E ## isNameMin, \
- E ## isNmstrtMin, \
- E ## byteToAscii, \
- E ## charMatches,
-
-#else
-
-#define STANDARD_VTABLE(E) /* as nothing */
-
-#endif
-
-#define NORMAL_VTABLE(E) \
- E ## isName2, \
- E ## isName3, \
- E ## isName4, \
- E ## isNmstrt2, \
- E ## isNmstrt3, \
- E ## isNmstrt4, \
- E ## isInvalid2, \
- E ## isInvalid3, \
- E ## isInvalid4
-
-#define EMPTY_VTABLE(E) 0, 0, 0, 0, 0, 0, 0, 0, 0
-
-static int checkCharRefNumber(int);
-
-#include "xmltok_impl.h"
-#include "ascii.h"
-
-#ifdef XML_MIN_SIZE
-#define sb_isNameMin isNever
-#define sb_isNmstrtMin isNever
-#endif
-
-#ifdef XML_MIN_SIZE
-#define MINBPC(enc) ((enc)->minBytesPerChar)
-#else
-/* minimum bytes per character */
-#define MINBPC(enc) 1
-#endif
-
-#define SB_BYTE_TYPE(enc, p) \
- (((struct normal_encoding *)(enc))->type[(unsigned char)*(p)])
-
-#ifdef XML_MIN_SIZE
-static
-int sb_byteType(const ENCODING *enc, const char *p)
-{
- return SB_BYTE_TYPE(enc, p);
-}
-#define BYTE_TYPE(enc, p) \
- (((const struct normal_encoding *)(enc))->byteType(enc, p))
-#else
-#define BYTE_TYPE(enc, p) SB_BYTE_TYPE(enc, p)
-#endif
-
-#ifdef XML_MIN_SIZE
-#define BYTE_TO_ASCII(enc, p) \
- (((const struct normal_encoding *)(enc))->byteToAscii(enc, p))
-static
-int sb_byteToAscii(const ENCODING *enc, const char *p)
-{
- return *p;
-}
-#else
-#define BYTE_TO_ASCII(enc, p) (*(p))
-#endif
-
-#define IS_NAME_CHAR(enc, p, n) \
- (((const struct normal_encoding *)(enc))->isName ## n(enc, p))
-#define IS_NMSTRT_CHAR(enc, p, n) \
- (((const struct normal_encoding *)(enc))->isNmstrt ## n(enc, p))
-#define IS_INVALID_CHAR(enc, p, n) \
- (((const struct normal_encoding *)(enc))->isInvalid ## n(enc, p))
-
-#ifdef XML_MIN_SIZE
-#define IS_NAME_CHAR_MINBPC(enc, p) \
- (((const struct normal_encoding *)(enc))->isNameMin(enc, p))
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) \
- (((const struct normal_encoding *)(enc))->isNmstrtMin(enc, p))
-#else
-#define IS_NAME_CHAR_MINBPC(enc, p) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) (0)
-#endif
-
-#ifdef XML_MIN_SIZE
-#define CHAR_MATCHES(enc, p, c) \
- (((const struct normal_encoding *)(enc))->charMatches(enc, p, c))
-static
-int sb_charMatches(const ENCODING *enc, const char *p, int c)
-{
- return *p == c;
-}
-#else
-/* c is an ASCII character */
-#define CHAR_MATCHES(enc, p, c) (*(p) == c)
-#endif
-
-#define PREFIX(ident) normal_ ## ident
-#include "xmltok_impl.c"
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-enum { /* UTF8_cvalN is value of masked first byte of N byte sequence */
- UTF8_cval1 = 0x00,
- UTF8_cval2 = 0xc0,
- UTF8_cval3 = 0xe0,
- UTF8_cval4 = 0xf0
-};
-
-static
-void utf8_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- char *to;
- const char *from;
- cmExpatUnused(enc);
- if (fromLim - *fromP > toLim - *toP) {
- /* Avoid copying partial characters. */
- for (fromLim = *fromP + (toLim - *toP); fromLim > *fromP; fromLim--)
- if (((unsigned char)fromLim[-1] & 0xc0) != 0x80)
- break;
- }
- for (to = *toP, from = *fromP; from != fromLim; from++, to++)
- *to = *from;
- *fromP = from;
- *toP = to;
-}
-
-static
-void utf8_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
- unsigned short *to = *toP;
- const char *from = *fromP;
- while (from != fromLim && to != toLim) {
- switch (((struct normal_encoding *)enc)->type[(unsigned char)*from]) {
- case BT_LEAD2:
- *to++ = ((from[0] & 0x1f) << 6) | (from[1] & 0x3f);
- from += 2;
- break;
- case BT_LEAD3:
- *to++ = ((from[0] & 0xf) << 12) | ((from[1] & 0x3f) << 6) | (from[2] & 0x3f);
- from += 3;
- break;
- case BT_LEAD4:
- {
- unsigned long n;
- if (to + 1 == toLim)
- break;
- n = ((from[0] & 0x7) << 18) | ((from[1] & 0x3f) << 12) | ((from[2] & 0x3f) << 6) | (from[3] & 0x3f);
- n -= 0x10000;
- to[0] = (unsigned short)((n >> 10) | 0xD800);
- to[1] = (unsigned short)((n & 0x3FF) | 0xDC00);
- to += 2;
- from += 4;
- }
- break;
- default:
- *to++ = *from++;
- break;
- }
- }
- *fromP = from;
- *toP = to;
-}
-
-#ifdef XML_NS
-static const struct normal_encoding utf8_encoding_ns = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#include "asciitab.h"
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-#endif
-
-static const struct normal_encoding utf8_encoding = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_utf8_encoding_ns = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#include "iasciitab.h"
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-#endif
-
-static const struct normal_encoding internal_utf8_encoding = {
- { VTABLE1, utf8_toUtf8, utf8_toUtf16, 1, 1, 0 },
- {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "utf8tab.h"
- },
- STANDARD_VTABLE(sb_) NORMAL_VTABLE(utf8_)
-};
-
-static
-void latin1_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- cmExpatUnused(enc);
- for (;;) {
- unsigned char c;
- if (*fromP == fromLim)
- break;
- c = (unsigned char)**fromP;
- if (c & 0x80) {
- if (toLim - *toP < 2)
- break;
- *(*toP)++ = ((c >> 6) | UTF8_cval2);
- *(*toP)++ = ((c & 0x3f) | 0x80);
- (*fromP)++;
- }
- else {
- if (*toP == toLim)
- break;
- *(*toP)++ = *(*fromP)++;
- }
- }
-}
-
-static
-void latin1_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
- cmExpatUnused(enc);
- while (*fromP != fromLim && *toP != toLim)
- *(*toP)++ = (unsigned char)*(*fromP)++;
-}
-
-#ifdef XML_NS
-
-static const struct normal_encoding latin1_encoding_ns = {
- { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_)
-};
-
-#endif
-
-static const struct normal_encoding latin1_encoding = {
- { VTABLE1, latin1_toUtf8, latin1_toUtf16, 1, 0, 0 },
- {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_)
-};
-
-static
-void ascii_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- cmExpatUnused(enc);
- while (*fromP != fromLim && *toP != toLim)
- *(*toP)++ = *(*fromP)++;
-}
-
-#ifdef XML_NS
-
-static const struct normal_encoding ascii_encoding_ns = {
- { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
- {
-#include "asciitab.h"
-/* BT_NONXML == 0 */
- },
- STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_)
-};
-
-#endif
-
-static const struct normal_encoding ascii_encoding = {
- { VTABLE1, ascii_toUtf8, latin1_toUtf16, 1, 1, 0 },
- {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-/* BT_NONXML == 0 */
- },
- STANDARD_VTABLE(sb_) EMPTY_VTABLE(sb_)
-};
-
-static int unicode_byte_type(char hi, char lo)
-{
- switch ((unsigned char)hi) {
- case 0xD8: case 0xD9: case 0xDA: case 0xDB:
- return BT_LEAD4;
- case 0xDC: case 0xDD: case 0xDE: case 0xDF:
- return BT_TRAIL;
- case 0xFF:
- switch ((unsigned char)lo) {
- case 0xFF:
- case 0xFE:
- return BT_NONXML;
- }
- break;
- }
- return BT_NONASCII;
-}
-
-#define DEFINE_UTF16_TO_UTF8(E) \
-static \
-void E ## toUtf8(const ENCODING *enc, \
- const char **fromP, const char *fromLim, \
- char **toP, const char *toLim) \
-{ \
- const char *from; \
- cmExpatUnused(enc);\
- for (from = *fromP; from != fromLim; from += 2) { \
- int plane; \
- unsigned char lo2; \
- unsigned char lo = GET_LO(from); \
- unsigned char hi = GET_HI(from); \
- switch (hi) { \
- case 0: \
- if (lo < 0x80) { \
- if (*toP == toLim) { \
- *fromP = from; \
- return; \
- } \
- *(*toP)++ = lo; \
- break; \
- } \
- /* fall through */ \
- case 0x1: case 0x2: case 0x3: \
- case 0x4: case 0x5: case 0x6: case 0x7: \
- if (toLim - *toP < 2) { \
- *fromP = from; \
- return; \
- } \
- *(*toP)++ = ((lo >> 6) | (hi << 2) | UTF8_cval2); \
- *(*toP)++ = ((lo & 0x3f) | 0x80); \
- break; \
- default: \
- if (toLim - *toP < 3) { \
- *fromP = from; \
- return; \
- } \
- /* 16 bits divided 4, 6, 6 amongst 3 bytes */ \
- *(*toP)++ = ((hi >> 4) | UTF8_cval3); \
- *(*toP)++ = (((hi & 0xf) << 2) | (lo >> 6) | 0x80); \
- *(*toP)++ = ((lo & 0x3f) | 0x80); \
- break; \
- case 0xD8: case 0xD9: case 0xDA: case 0xDB: \
- if (toLim - *toP < 4) { \
- *fromP = from; \
- return; \
- } \
- plane = (((hi & 0x3) << 2) | ((lo >> 6) & 0x3)) + 1; \
- *(*toP)++ = ((plane >> 2) | UTF8_cval4); \
- *(*toP)++ = (((lo >> 2) & 0xF) | ((plane & 0x3) << 4) | 0x80); \
- from += 2; \
- lo2 = GET_LO(from); \
- *(*toP)++ = (((lo & 0x3) << 4) \
- | ((GET_HI(from) & 0x3) << 2) \
- | (lo2 >> 6) \
- | 0x80); \
- *(*toP)++ = ((lo2 & 0x3f) | 0x80); \
- break; \
- } \
- } \
- *fromP = from; \
-}
-
-#define DEFINE_UTF16_TO_UTF16(E) \
-static \
-void E ## toUtf16(const ENCODING *enc, \
- const char **fromP, const char *fromLim, \
- unsigned short **toP, const unsigned short *toLim) \
-{ \
- cmExpatUnused(enc);\
- /* Avoid copying first half only of surrogate */ \
- if (fromLim - *fromP > ((toLim - *toP) << 1) \
- && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) \
- fromLim -= 2; \
- for (; *fromP != fromLim && *toP != toLim; *fromP += 2) \
- *(*toP)++ = (GET_HI(*fromP) << 8) | GET_LO(*fromP); \
-}
-
-#define SET2(ptr, ch) \
- (((ptr)[0] = ((ch) & 0xff)), ((ptr)[1] = ((ch) >> 8)))
-#define GET_LO(ptr) ((unsigned char)(ptr)[0])
-#define GET_HI(ptr) ((unsigned char)(ptr)[1])
-
-DEFINE_UTF16_TO_UTF8(little2_)
-DEFINE_UTF16_TO_UTF16(little2_)
-
-#undef SET2
-#undef GET_LO
-#undef GET_HI
-
-#define SET2(ptr, ch) \
- (((ptr)[0] = ((ch) >> 8)), ((ptr)[1] = ((ch) & 0xFF)))
-#define GET_LO(ptr) ((unsigned char)(ptr)[1])
-#define GET_HI(ptr) ((unsigned char)(ptr)[0])
-
-DEFINE_UTF16_TO_UTF8(big2_)
-DEFINE_UTF16_TO_UTF16(big2_)
-
-#undef SET2
-#undef GET_LO
-#undef GET_HI
-
-#define LITTLE2_BYTE_TYPE(enc, p) \
- ((p)[1] == 0 \
- ? ((struct normal_encoding *)(enc))->type[(unsigned char)*(p)] \
- : unicode_byte_type((p)[1], (p)[0]))
-#define LITTLE2_BYTE_TO_ASCII(enc, p) ((p)[1] == 0 ? (p)[0] : -1)
-#define LITTLE2_CHAR_MATCHES(enc, p, c) ((p)[1] == 0 && (p)[0] == c)
-#define LITTLE2_IS_NAME_CHAR_MINBPC(enc, p) \
- UCS2_GET_NAMING(namePages, (unsigned char)p[1], (unsigned char)p[0])
-#define LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
- UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[1], (unsigned char)p[0])
-
-#ifdef XML_MIN_SIZE
-
-static
-int little2_byteType(const ENCODING *enc, const char *p)
-{
- return LITTLE2_BYTE_TYPE(enc, p);
-}
-
-static
-int little2_byteToAscii(const ENCODING *enc, const char *p)
-{
- return LITTLE2_BYTE_TO_ASCII(enc, p);
-}
-
-static
-int little2_charMatches(const ENCODING *enc, const char *p, int c)
-{
- return LITTLE2_CHAR_MATCHES(enc, p, c);
-}
-
-static
-int little2_isNameMin(const ENCODING *enc, const char *p)
-{
- return LITTLE2_IS_NAME_CHAR_MINBPC(enc, p);
-}
-
-static
-int little2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
- return LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p);
-}
-
-#undef VTABLE
-#define VTABLE VTABLE1, little2_toUtf8, little2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-#undef PREFIX
-#define PREFIX(ident) little2_ ## ident
-#define MINBPC(enc) 2
-/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) LITTLE2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) LITTLE2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) LITTLE2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) LITTLE2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) LITTLE2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#include "xmltok_impl.c"
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-#endif /* not XML_MIN_SIZE */
-
-#ifdef XML_NS
-
-static const struct normal_encoding little2_encoding_ns = {
- { VTABLE, 2, 0,
-#if XML_BYTE_ORDER == 12
- 1
-#else
- 0
-#endif
- },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_)
-};
-
-#endif
-
-static const struct normal_encoding little2_encoding = {
- { VTABLE, 2, 0,
-#if XML_BYTE_ORDER == 12
- 1
-#else
- 0
-#endif
- },
- {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_)
-};
-
-#if XML_BYTE_ORDER != 21
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_little2_encoding_ns = {
- { VTABLE, 2, 0, 1 },
- {
-#include "iasciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_)
-};
-
-#endif
-
-static const struct normal_encoding internal_little2_encoding = {
- { VTABLE, 2, 0, 1 },
- {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(little2_) EMPTY_VTABLE(little2_)
-};
-
-#endif
-
-
-#define BIG2_BYTE_TYPE(enc, p) \
- ((p)[0] == 0 \
- ? ((struct normal_encoding *)(enc))->type[(unsigned char)(p)[1]] \
- : unicode_byte_type((p)[0], (p)[1]))
-#define BIG2_BYTE_TO_ASCII(enc, p) ((p)[0] == 0 ? (p)[1] : -1)
-#define BIG2_CHAR_MATCHES(enc, p, c) ((p)[0] == 0 && (p)[1] == c)
-#define BIG2_IS_NAME_CHAR_MINBPC(enc, p) \
- UCS2_GET_NAMING(namePages, (unsigned char)p[0], (unsigned char)p[1])
-#define BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p) \
- UCS2_GET_NAMING(nmstrtPages, (unsigned char)p[0], (unsigned char)p[1])
-
-#ifdef XML_MIN_SIZE
-
-static
-int big2_byteType(const ENCODING *enc, const char *p)
-{
- return BIG2_BYTE_TYPE(enc, p);
-}
-
-static
-int big2_byteToAscii(const ENCODING *enc, const char *p)
-{
- return BIG2_BYTE_TO_ASCII(enc, p);
-}
-
-static
-int big2_charMatches(const ENCODING *enc, const char *p, int c)
-{
- return BIG2_CHAR_MATCHES(enc, p, c);
-}
-
-static
-int big2_isNameMin(const ENCODING *enc, const char *p)
-{
- return BIG2_IS_NAME_CHAR_MINBPC(enc, p);
-}
-
-static
-int big2_isNmstrtMin(const ENCODING *enc, const char *p)
-{
- return BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p);
-}
-
-#undef VTABLE
-#define VTABLE VTABLE1, big2_toUtf8, big2_toUtf16
-
-#else /* not XML_MIN_SIZE */
-
-#undef PREFIX
-#define PREFIX(ident) big2_ ## ident
-#define MINBPC(enc) 2
-/* CHAR_MATCHES is guaranteed to have MINBPC bytes available. */
-#define BYTE_TYPE(enc, p) BIG2_BYTE_TYPE(enc, p)
-#define BYTE_TO_ASCII(enc, p) BIG2_BYTE_TO_ASCII(enc, p)
-#define CHAR_MATCHES(enc, p, c) BIG2_CHAR_MATCHES(enc, p, c)
-#define IS_NAME_CHAR(enc, p, n) 0
-#define IS_NAME_CHAR_MINBPC(enc, p) BIG2_IS_NAME_CHAR_MINBPC(enc, p)
-#define IS_NMSTRT_CHAR(enc, p, n) (0)
-#define IS_NMSTRT_CHAR_MINBPC(enc, p) BIG2_IS_NMSTRT_CHAR_MINBPC(enc, p)
-
-#include "xmltok_impl.c"
-
-#undef MINBPC
-#undef BYTE_TYPE
-#undef BYTE_TO_ASCII
-#undef CHAR_MATCHES
-#undef IS_NAME_CHAR
-#undef IS_NAME_CHAR_MINBPC
-#undef IS_NMSTRT_CHAR
-#undef IS_NMSTRT_CHAR_MINBPC
-#undef IS_INVALID_CHAR
-
-#endif /* not XML_MIN_SIZE */
-
-#ifdef XML_NS
-
-static const struct normal_encoding big2_encoding_ns = {
- { VTABLE, 2, 0,
-#if XML_BYTE_ORDER == 21
- 1
-#else
- 0
-#endif
- },
- {
-#include "asciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_)
-};
-
-#endif
-
-static const struct normal_encoding big2_encoding = {
- { VTABLE, 2, 0,
-#if XML_BYTE_ORDER == 21
- 1
-#else
- 0
-#endif
- },
- {
-#define BT_COLON BT_NMSTRT
-#include "asciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_)
-};
-
-#if XML_BYTE_ORDER != 12
-
-#ifdef XML_NS
-
-static const struct normal_encoding internal_big2_encoding_ns = {
- { VTABLE, 2, 0, 1 },
- {
-#include "iasciitab.h"
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_)
-};
-
-#endif
-
-static const struct normal_encoding internal_big2_encoding = {
- { VTABLE, 2, 0, 1 },
- {
-#define BT_COLON BT_NMSTRT
-#include "iasciitab.h"
-#undef BT_COLON
-#include "latin1tab.h"
- },
- STANDARD_VTABLE(big2_) EMPTY_VTABLE(big2_)
-};
-
-#endif
-
-#undef PREFIX
-
-static
-int streqci(const char *s1, const char *s2)
-{
- for (;;) {
- char c1 = *s1++;
- char c2 = *s2++;
- if (ASCII_a <= c1 && c1 <= ASCII_z)
- c1 += ASCII_A - ASCII_a;
- if (ASCII_a <= c2 && c2 <= ASCII_z)
- c2 += ASCII_A - ASCII_a;
- if (c1 != c2)
- return 0;
- if (!c1)
- break;
- }
- return 1;
-}
-
-static
-void initUpdatePosition(const ENCODING *enc, const char *ptr,
- const char *end, POSITION *pos)
-{
- cmExpatUnused(enc);
- normal_updatePosition(&utf8_encoding.enc, ptr, end, pos);
-}
-
-static
-int toAscii(const ENCODING *enc, const char *ptr, const char *end)
-{
- char buf[1];
- char *p = buf;
- XmlUtf8Convert(enc, &ptr, end, &p, p + 1);
- if (p == buf)
- return -1;
- else
- return buf[0];
-}
-
-static
-int isSpace(int c)
-{
- switch (c) {
- case 0x20:
- case 0xD:
- case 0xA:
- case 0x9:
- return 1;
- }
- return 0;
-}
-
-/* Return 1 if there's just optional white space
-or there's an S followed by name=val. */
-static
-int parsePseudoAttribute(const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **namePtr,
- const char **nameEndPtr,
- const char **valPtr,
- const char **nextTokPtr)
-{
- int c;
- char open;
- if (ptr == end) {
- *namePtr = 0;
- return 1;
- }
- if (!isSpace(toAscii(enc, ptr, end))) {
- *nextTokPtr = ptr;
- return 0;
- }
- do {
- ptr += enc->minBytesPerChar;
- } while (isSpace(toAscii(enc, ptr, end)));
- if (ptr == end) {
- *namePtr = 0;
- return 1;
- }
- *namePtr = ptr;
- for (;;) {
- c = toAscii(enc, ptr, end);
- if (c == -1) {
- *nextTokPtr = ptr;
- return 0;
- }
- if (c == ASCII_EQUALS) {
- *nameEndPtr = ptr;
- break;
- }
- if (isSpace(c)) {
- *nameEndPtr = ptr;
- do {
- ptr += enc->minBytesPerChar;
- } while (isSpace(c = toAscii(enc, ptr, end)));
- if (c != ASCII_EQUALS) {
- *nextTokPtr = ptr;
- return 0;
- }
- break;
- }
- ptr += enc->minBytesPerChar;
- }
- if (ptr == *namePtr) {
- *nextTokPtr = ptr;
- return 0;
- }
- ptr += enc->minBytesPerChar;
- c = toAscii(enc, ptr, end);
- while (isSpace(c)) {
- ptr += enc->minBytesPerChar;
- c = toAscii(enc, ptr, end);
- }
- if (c != ASCII_QUOT && c != ASCII_APOS) {
- *nextTokPtr = ptr;
- return 0;
- }
- open = c;
- ptr += enc->minBytesPerChar;
- *valPtr = ptr;
- for (;; ptr += enc->minBytesPerChar) {
- c = toAscii(enc, ptr, end);
- if (c == open)
- break;
- if (!(ASCII_a <= c && c <= ASCII_z)
- && !(ASCII_A <= c && c <= ASCII_Z)
- && !(ASCII_0 <= c && c <= ASCII_9)
- && c != ASCII_PERIOD
- && c != ASCII_MINUS
- && c != ASCII_UNDERSCORE) {
- *nextTokPtr = ptr;
- return 0;
- }
- }
- *nextTokPtr = ptr + enc->minBytesPerChar;
- return 1;
-}
-
-static const char KW_version[] = {
- ASCII_v, ASCII_e, ASCII_r, ASCII_s, ASCII_i, ASCII_o, ASCII_n, '\0'
-};
-
-static const char KW_encoding[] = {
- ASCII_e, ASCII_n, ASCII_c, ASCII_o, ASCII_d, ASCII_i, ASCII_n, ASCII_g, '\0'
-};
-
-static const char KW_standalone[] = {
- ASCII_s, ASCII_t, ASCII_a, ASCII_n, ASCII_d, ASCII_a, ASCII_l, ASCII_o, ASCII_n, ASCII_e, '\0'
-};
-
-static const char KW_yes[] = {
- ASCII_y, ASCII_e, ASCII_s, '\0'
-};
-
-static const char KW_no[] = {
- ASCII_n, ASCII_o, '\0'
-};
-
-static
-int doParseXmlDecl(const ENCODING *(*encodingFinder)(const ENCODING *,
- const char *,
- const char *),
- int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingName,
- const ENCODING **encoding,
- int *standalone)
-{
- const char *val = 0;
- const char *name = 0;
- const char *nameEnd = 0;
- ptr += 5 * enc->minBytesPerChar;
- end -= 2 * enc->minBytesPerChar;
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr) || !name) {
- *badPtr = ptr;
- return 0;
- }
- if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_version)) {
- if (!isGeneralTextEntity) {
- *badPtr = name;
- return 0;
- }
- }
- else {
- if (versionPtr)
- *versionPtr = val;
- if (versionEndPtr)
- *versionEndPtr = ptr;
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
- *badPtr = ptr;
- return 0;
- }
- if (!name) {
- if (isGeneralTextEntity) {
- /* a TextDecl must have an EncodingDecl */
- *badPtr = ptr;
- return 0;
- }
- return 1;
- }
- }
- if (XmlNameMatchesAscii(enc, name, nameEnd, KW_encoding)) {
- int c = toAscii(enc, val, end);
- if (!(ASCII_a <= c && c <= ASCII_z) && !(ASCII_A <= c && c <= ASCII_Z)) {
- *badPtr = val;
- return 0;
- }
- if (encodingName)
- *encodingName = val;
- if (encoding)
- *encoding = encodingFinder(enc, val, ptr - enc->minBytesPerChar);
- if (!parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
- *badPtr = ptr;
- return 0;
- }
- if (!name)
- return 1;
- }
- if (!XmlNameMatchesAscii(enc, name, nameEnd, KW_standalone) || isGeneralTextEntity) {
- *badPtr = name;
- return 0;
- }
- if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_yes)) {
- if (standalone)
- *standalone = 1;
- }
- else if (XmlNameMatchesAscii(enc, val, ptr - enc->minBytesPerChar, KW_no)) {
- if (standalone)
- *standalone = 0;
- }
- else {
- *badPtr = val;
- return 0;
- }
- while (isSpace(toAscii(enc, ptr, end)))
- ptr += enc->minBytesPerChar;
- if (ptr != end) {
- *badPtr = ptr;
- return 0;
- }
- return 1;
-}
-
-static
-int checkCharRefNumber(int result)
-{
- switch (result >> 8) {
- case 0xD8: case 0xD9: case 0xDA: case 0xDB:
- case 0xDC: case 0xDD: case 0xDE: case 0xDF:
- return -1;
- case 0:
- if (latin1_encoding.type[result] == BT_NONXML)
- return -1;
- break;
- case 0xFF:
- if (result == 0xFFFE || result == 0xFFFF)
- return -1;
- break;
- }
- return result;
-}
-
-int XmlUtf8Encode(int c, char *buf)
-{
- enum {
- /* minN is minimum legal resulting value for N byte sequence */
- min2 = 0x80,
- min3 = 0x800,
- min4 = 0x10000
- };
-
- if (c < 0)
- return 0;
- if (c < min2) {
- buf[0] = (c | UTF8_cval1);
- return 1;
- }
- if (c < min3) {
- buf[0] = ((c >> 6) | UTF8_cval2);
- buf[1] = ((c & 0x3f) | 0x80);
- return 2;
- }
- if (c < min4) {
- buf[0] = ((c >> 12) | UTF8_cval3);
- buf[1] = (((c >> 6) & 0x3f) | 0x80);
- buf[2] = ((c & 0x3f) | 0x80);
- return 3;
- }
- if (c < 0x110000) {
- buf[0] = ((c >> 18) | UTF8_cval4);
- buf[1] = (((c >> 12) & 0x3f) | 0x80);
- buf[2] = (((c >> 6) & 0x3f) | 0x80);
- buf[3] = ((c & 0x3f) | 0x80);
- return 4;
- }
- return 0;
-}
-
-int XmlUtf16Encode(int charNum, unsigned short *buf)
-{
- if (charNum < 0)
- return 0;
- if (charNum < 0x10000) {
- buf[0] = charNum;
- return 1;
- }
- if (charNum < 0x110000) {
- charNum -= 0x10000;
- buf[0] = (charNum >> 10) + 0xD800;
- buf[1] = (charNum & 0x3FF) + 0xDC00;
- return 2;
- }
- return 0;
-}
-
-struct unknown_encoding {
- struct normal_encoding normal;
- int (*convert)(void *userData, const char *p);
- void *userData;
- unsigned short utf16[256];
- char utf8[256][4];
-};
-
-int XmlSizeOfUnknownEncoding(void)
-{
- return sizeof(struct unknown_encoding);
-}
-
-static
-int unknown_isName(const ENCODING *enc, const char *p)
-{
- int c = ((const struct unknown_encoding *)enc)
- ->convert(((const struct unknown_encoding *)enc)->userData, p);
- if (c & ~0xFFFF)
- return 0;
- return UCS2_GET_NAMING(namePages, c >> 8, c & 0xFF);
-}
-
-static
-int unknown_isNmstrt(const ENCODING *enc, const char *p)
-{
- int c = ((const struct unknown_encoding *)enc)
- ->convert(((const struct unknown_encoding *)enc)->userData, p);
- if (c & ~0xFFFF)
- return 0;
- return UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xFF);
-}
-
-static
-int unknown_isInvalid(const ENCODING *enc, const char *p)
-{
- int c = ((const struct unknown_encoding *)enc)
- ->convert(((const struct unknown_encoding *)enc)->userData, p);
- return (c & ~0xFFFF) || checkCharRefNumber(c) < 0;
-}
-
-static
-void unknown_toUtf8(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- char **toP, const char *toLim)
-{
- char buf[XML_UTF8_ENCODE_MAX];
- for (;;) {
- const char *utf8;
- int n;
- if (*fromP == fromLim)
- break;
- utf8 = ((const struct unknown_encoding *)enc)->utf8[(unsigned char)**fromP];
- n = *utf8++;
- if (n == 0) {
- int c = ((const struct unknown_encoding *)enc)
- ->convert(((const struct unknown_encoding *)enc)->userData, *fromP);
- n = XmlUtf8Encode(c, buf);
- if (n > toLim - *toP)
- break;
- utf8 = buf;
- *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP]
- - (BT_LEAD2 - 2);
- }
- else {
- if (n > toLim - *toP)
- break;
- (*fromP)++;
- }
- do {
- *(*toP)++ = *utf8++;
- } while (--n != 0);
- }
-}
-
-static
-void unknown_toUtf16(const ENCODING *enc,
- const char **fromP, const char *fromLim,
- unsigned short **toP, const unsigned short *toLim)
-{
- while (*fromP != fromLim && *toP != toLim) {
- unsigned short c
- = ((const struct unknown_encoding *)enc)->utf16[(unsigned char)**fromP];
- if (c == 0) {
- c = (unsigned short)((const struct unknown_encoding *)enc)
- ->convert(((const struct unknown_encoding *)enc)->userData, *fromP);
- *fromP += ((const struct normal_encoding *)enc)->type[(unsigned char)**fromP]
- - (BT_LEAD2 - 2);
- }
- else
- (*fromP)++;
- *(*toP)++ = c;
- }
-}
-
-ENCODING *
-XmlInitUnknownEncoding(void *mem,
- int *table,
- int (*convert)(void *userData, const char *p),
- void *userData)
-{
- int i;
- struct unknown_encoding *e = mem;
- for (i = 0; i < (int)sizeof(struct normal_encoding); i++)
- ((char *)mem)[i] = ((char *)&latin1_encoding)[i];
- for (i = 0; i < 128; i++)
- if (latin1_encoding.type[i] != BT_OTHER
- && latin1_encoding.type[i] != BT_NONXML
- && table[i] != i)
- return 0;
- for (i = 0; i < 256; i++) {
- int c = table[i];
- if (c == -1) {
- e->normal.type[i] = BT_MALFORM;
- /* This shouldn't really get used. */
- e->utf16[i] = 0xFFFF;
- e->utf8[i][0] = 1;
- e->utf8[i][1] = 0;
- }
- else if (c < 0) {
- if (c < -4)
- return 0;
- e->normal.type[i] = BT_LEAD2 - (c + 2);
- e->utf8[i][0] = 0;
- e->utf16[i] = 0;
- }
- else if (c < 0x80) {
- if (latin1_encoding.type[c] != BT_OTHER
- && latin1_encoding.type[c] != BT_NONXML
- && c != i)
- return 0;
- e->normal.type[i] = latin1_encoding.type[c];
- e->utf8[i][0] = 1;
- e->utf8[i][1] = (char)c;
- e->utf16[i] = c == 0 ? 0xFFFF : c;
- }
- else if (checkCharRefNumber(c) < 0) {
- e->normal.type[i] = BT_NONXML;
- /* This shouldn't really get used. */
- e->utf16[i] = 0xFFFF;
- e->utf8[i][0] = 1;
- e->utf8[i][1] = 0;
- }
- else {
- if (c > 0xFFFF)
- return 0;
- if (UCS2_GET_NAMING(nmstrtPages, c >> 8, c & 0xff))
- e->normal.type[i] = BT_NMSTRT;
- else if (UCS2_GET_NAMING(namePages, c >> 8, c & 0xff))
- e->normal.type[i] = BT_NAME;
- else
- e->normal.type[i] = BT_OTHER;
- e->utf8[i][0] = (char)XmlUtf8Encode(c, e->utf8[i] + 1);
- e->utf16[i] = c;
- }
- }
- e->userData = userData;
- e->convert = convert;
- if (convert) {
- e->normal.isName2 = unknown_isName;
- e->normal.isName3 = unknown_isName;
- e->normal.isName4 = unknown_isName;
- e->normal.isNmstrt2 = unknown_isNmstrt;
- e->normal.isNmstrt3 = unknown_isNmstrt;
- e->normal.isNmstrt4 = unknown_isNmstrt;
- e->normal.isInvalid2 = unknown_isInvalid;
- e->normal.isInvalid3 = unknown_isInvalid;
- e->normal.isInvalid4 = unknown_isInvalid;
- }
- e->normal.enc.utf8Convert = unknown_toUtf8;
- e->normal.enc.utf16Convert = unknown_toUtf16;
- return &(e->normal.enc);
-}
-
-/* If this enumeration is changed, getEncodingIndex and encodings
-must also be changed. */
-enum {
- UNKNOWN_ENC = -1,
- ISO_8859_1_ENC = 0,
- US_ASCII_ENC,
- UTF_8_ENC,
- UTF_16_ENC,
- UTF_16BE_ENC,
- UTF_16LE_ENC,
- /* must match encodingNames up to here */
- NO_ENC
-};
-
-static const char KW_ISO_8859_1[] = {
- ASCII_I, ASCII_S, ASCII_O, ASCII_MINUS, ASCII_8, ASCII_8, ASCII_5, ASCII_9, ASCII_MINUS, ASCII_1, '\0'
-};
-static const char KW_US_ASCII[] = {
- ASCII_U, ASCII_S, ASCII_MINUS, ASCII_A, ASCII_S, ASCII_C, ASCII_I, ASCII_I, '\0'
-};
-static const char KW_UTF_8[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_8, '\0'
-};
-static const char KW_UTF_16[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, '\0'
-};
-static const char KW_UTF_16BE[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_B, ASCII_E, '\0'
-};
-static const char KW_UTF_16LE[] = {
- ASCII_U, ASCII_T, ASCII_F, ASCII_MINUS, ASCII_1, ASCII_6, ASCII_L, ASCII_E, '\0'
-};
-
-static
-int getEncodingIndex(const char *name)
-{
- static const char *encodingNames[] = {
- KW_ISO_8859_1,
- KW_US_ASCII,
- KW_UTF_8,
- KW_UTF_16,
- KW_UTF_16BE,
- KW_UTF_16LE,
- };
- int i;
- if (name == 0)
- return NO_ENC;
- for (i = 0; i < (int)(sizeof(encodingNames)/sizeof(encodingNames[0])); i++)
- if (streqci(name, encodingNames[i]))
- return i;
- return UNKNOWN_ENC;
-}
-
-/* For binary compatibility, we store the index of the encoding specified
-at initialization in the isUtf16 member. */
-
-#define INIT_ENC_INDEX(enc) ((int)(enc)->initEnc.isUtf16)
-#define SET_INIT_ENC_INDEX(enc, i) ((enc)->initEnc.isUtf16 = (char)i)
-
-/* This is what detects the encoding.
-encodingTable maps from encoding indices to encodings;
-INIT_ENC_INDEX(enc) is the index of the external (protocol) specified encoding;
-state is XML_CONTENT_STATE if we're parsing an external text entity,
-and XML_PROLOG_STATE otherwise.
-*/
-
-
-static
-int initScan(const ENCODING **encodingTable,
- const INIT_ENCODING *enc,
- int state,
- const char *ptr,
- const char *end,
- const char **nextTokPtr)
-{
- const ENCODING **encPtr;
-
- if (ptr == end)
- return XML_TOK_NONE;
- encPtr = enc->encPtr;
- if (ptr + 1 == end) {
- /* only a single byte available for auto-detection */
-#ifndef XML_DTD /* FIXME */
- /* a well-formed document entity must have more than one byte */
- if (state != XML_CONTENT_STATE)
- return XML_TOK_PARTIAL;
-#endif
- /* so we're parsing an external text entity... */
- /* if UTF-16 was externally specified, then we need at least 2 bytes */
- switch (INIT_ENC_INDEX(enc)) {
- case UTF_16_ENC:
- case UTF_16LE_ENC:
- case UTF_16BE_ENC:
- return XML_TOK_PARTIAL;
- }
- switch ((unsigned char)*ptr) {
- case 0xFE:
- case 0xFF:
- case 0xEF: /* possibly first byte of UTF-8 BOM */
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
- break;
- /* fall through */
- case 0x00:
- case 0x3C:
- return XML_TOK_PARTIAL;
- }
- }
- else {
- switch (((unsigned char)ptr[0] << 8) | (unsigned char)ptr[1]) {
- case 0xFEFF:
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
- break;
- *nextTokPtr = ptr + 2;
- *encPtr = encodingTable[UTF_16BE_ENC];
- return XML_TOK_BOM;
- /* 00 3C is handled in the default case */
- case 0x3C00:
- if ((INIT_ENC_INDEX(enc) == UTF_16BE_ENC
- || INIT_ENC_INDEX(enc) == UTF_16_ENC)
- && state == XML_CONTENT_STATE)
- break;
- *encPtr = encodingTable[UTF_16LE_ENC];
- return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
- case 0xFFFE:
- if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC
- && state == XML_CONTENT_STATE)
- break;
- *nextTokPtr = ptr + 2;
- *encPtr = encodingTable[UTF_16LE_ENC];
- return XML_TOK_BOM;
- case 0xEFBB:
- /* Maybe a UTF-8 BOM (EF BB BF) */
- /* If there's an explicitly specified (external) encoding
- of ISO-8859-1 or some flavour of UTF-16
- and this is an external text entity,
- don't look for the BOM,
- because it might be a legal data. */
- if (state == XML_CONTENT_STATE) {
- int e = INIT_ENC_INDEX(enc);
- if (e == ISO_8859_1_ENC || e == UTF_16BE_ENC || e == UTF_16LE_ENC || e == UTF_16_ENC)
- break;
- }
- if (ptr + 2 == end)
- return XML_TOK_PARTIAL;
- if ((unsigned char)ptr[2] == 0xBF) {
- *nextTokPtr = ptr + 3;
- *encPtr = encodingTable[UTF_8_ENC];
- return XML_TOK_BOM;
- }
- break;
- default:
- if (ptr[0] == '\0') {
- /* 0 isn't a legal data character. Furthermore a document entity can only
- start with ASCII characters. So the only way this can fail to be big-endian
- UTF-16 if it it's an external parsed general entity that's labelled as
- UTF-16LE. */
- if (state == XML_CONTENT_STATE && INIT_ENC_INDEX(enc) == UTF_16LE_ENC)
- break;
- *encPtr = encodingTable[UTF_16BE_ENC];
- return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
- }
- else if (ptr[1] == '\0') {
- /* We could recover here in the case:
- - parsing an external entity
- - second byte is 0
- - no externally specified encoding
- - no encoding declaration
- by assuming UTF-16LE. But we don't, because this would mean when
- presented just with a single byte, we couldn't reliably determine
- whether we needed further bytes. */
- if (state == XML_CONTENT_STATE)
- break;
- *encPtr = encodingTable[UTF_16LE_ENC];
- return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
- }
- break;
- }
- }
- *encPtr = encodingTable[INIT_ENC_INDEX(enc)];
- return XmlTok(*encPtr, state, ptr, end, nextTokPtr);
-}
-
-
-#define NS(x) x
-#define ns(x) x
-#include "xmltok_ns.c"
-#undef NS
-#undef ns
-
-#ifdef XML_NS
-
-#define NS(x) x ## NS
-#define ns(x) x ## _ns
-
-#include "xmltok_ns.c"
-
-#undef NS
-#undef ns
-
-ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
- int *table,
- int (*convert)(void *userData, const char *p),
- void *userData)
-{
- ENCODING *enc = XmlInitUnknownEncoding(mem, table, convert, userData);
- if (enc)
- ((struct normal_encoding *)enc)->type[ASCII_COLON] = BT_COLON;
- return enc;
-}
-
-#endif /* XML_NS */
diff --git a/Utilities/cmexpat/xmltok.h b/Utilities/cmexpat/xmltok.h
deleted file mode 100644
index cdf49b2cb..000000000
--- a/Utilities/cmexpat/xmltok.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#ifndef XmlTok_INCLUDED
-#define XmlTok_INCLUDED 1
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* The following token may be returned by XmlContentTok */
-#define XML_TOK_TRAILING_RSQB -5 /* ] or ]] at the end of the scan; might be start of
- illegal ]]> sequence */
-/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */
-#define XML_TOK_NONE -4 /* The string to be scanned is empty */
-#define XML_TOK_TRAILING_CR -3 /* A CR at the end of the scan;
- might be part of CRLF sequence */
-#define XML_TOK_PARTIAL_CHAR -2 /* only part of a multibyte sequence */
-#define XML_TOK_PARTIAL -1 /* only part of a token */
-#define XML_TOK_INVALID 0
-
-/* The following tokens are returned by XmlContentTok; some are also
- returned by XmlAttributeValueTok, XmlEntityTok, XmlCdataSectionTok */
-
-#define XML_TOK_START_TAG_WITH_ATTS 1
-#define XML_TOK_START_TAG_NO_ATTS 2
-#define XML_TOK_EMPTY_ELEMENT_WITH_ATTS 3 /* empty element tag <e/> */
-#define XML_TOK_EMPTY_ELEMENT_NO_ATTS 4
-#define XML_TOK_END_TAG 5
-#define XML_TOK_DATA_CHARS 6
-#define XML_TOK_DATA_NEWLINE 7
-#define XML_TOK_CDATA_SECT_OPEN 8
-#define XML_TOK_ENTITY_REF 9
-#define XML_TOK_CHAR_REF 10 /* numeric character reference */
-
-/* The following tokens may be returned by both XmlPrologTok and XmlContentTok */
-#define XML_TOK_PI 11 /* processing instruction */
-#define XML_TOK_XML_DECL 12 /* XML decl or text decl */
-#define XML_TOK_COMMENT 13
-#define XML_TOK_BOM 14 /* Byte order mark */
-
-/* The following tokens are returned only by XmlPrologTok */
-#define XML_TOK_PROLOG_S 15
-#define XML_TOK_DECL_OPEN 16 /* <!foo */
-#define XML_TOK_DECL_CLOSE 17 /* > */
-#define XML_TOK_NAME 18
-#define XML_TOK_NMTOKEN 19
-#define XML_TOK_POUND_NAME 20 /* #name */
-#define XML_TOK_OR 21 /* | */
-#define XML_TOK_PERCENT 22
-#define XML_TOK_OPEN_PAREN 23
-#define XML_TOK_CLOSE_PAREN 24
-#define XML_TOK_OPEN_BRACKET 25
-#define XML_TOK_CLOSE_BRACKET 26
-#define XML_TOK_LITERAL 27
-#define XML_TOK_PARAM_ENTITY_REF 28
-#define XML_TOK_INSTANCE_START 29
-
-/* The following occur only in element type declarations */
-#define XML_TOK_NAME_QUESTION 30 /* name? */
-#define XML_TOK_NAME_ASTERISK 31 /* name* */
-#define XML_TOK_NAME_PLUS 32 /* name+ */
-#define XML_TOK_COND_SECT_OPEN 33 /* <![ */
-#define XML_TOK_COND_SECT_CLOSE 34 /* ]]> */
-#define XML_TOK_CLOSE_PAREN_QUESTION 35 /* )? */
-#define XML_TOK_CLOSE_PAREN_ASTERISK 36 /* )* */
-#define XML_TOK_CLOSE_PAREN_PLUS 37 /* )+ */
-#define XML_TOK_COMMA 38
-
-/* The following token is returned only by XmlAttributeValueTok */
-#define XML_TOK_ATTRIBUTE_VALUE_S 39
-
-/* The following token is returned only by XmlCdataSectionTok */
-#define XML_TOK_CDATA_SECT_CLOSE 40
-
-/* With namespace processing this is returned by XmlPrologTok
- for a name with a colon. */
-#define XML_TOK_PREFIXED_NAME 41
-
-#ifdef XML_DTD
-#define XML_TOK_IGNORE_SECT 42
-#endif /* XML_DTD */
-
-#ifdef XML_DTD
-#define XML_N_STATES 4
-#else /* not XML_DTD */
-#define XML_N_STATES 3
-#endif /* not XML_DTD */
-
-#define XML_PROLOG_STATE 0
-#define XML_CONTENT_STATE 1
-#define XML_CDATA_SECTION_STATE 2
-#ifdef XML_DTD
-#define XML_IGNORE_SECTION_STATE 3
-#endif /* XML_DTD */
-
-#define XML_N_LITERAL_TYPES 2
-#define XML_ATTRIBUTE_VALUE_LITERAL 0
-#define XML_ENTITY_VALUE_LITERAL 1
-
-/* The size of the buffer passed to XmlUtf8Encode must be at least this. */
-#define XML_UTF8_ENCODE_MAX 4
-/* The size of the buffer passed to XmlUtf16Encode must be at least this. */
-#define XML_UTF16_ENCODE_MAX 2
-
-typedef struct position {
- /* first line and first column are 0 not 1 */
- unsigned long lineNumber;
- unsigned long columnNumber;
-} POSITION;
-
-typedef struct {
- const char *name;
- const char *valuePtr;
- const char *valueEnd;
- char normalized;
-} ATTRIBUTE;
-
-struct encoding;
-typedef struct encoding ENCODING;
-
-struct encoding {
- int (*scanners[XML_N_STATES])(const ENCODING *,
- const char *,
- const char *,
- const char **);
- int (*literalScanners[XML_N_LITERAL_TYPES])(const ENCODING *,
- const char *,
- const char *,
- const char **);
- int (*sameName)(const ENCODING *,
- const char *, const char *);
- int (*nameMatchesAscii)(const ENCODING *,
- const char *, const char *, const char *);
- int (*nameLength)(const ENCODING *, const char *);
- const char *(*skipS)(const ENCODING *, const char *);
- int (*getAtts)(const ENCODING *enc, const char *ptr,
- int attsMax, ATTRIBUTE *atts);
- int (*charRefNumber)(const ENCODING *enc, const char *ptr);
- int (*predefinedEntityName)(const ENCODING *, const char *, const char *);
- void (*updatePosition)(const ENCODING *,
- const char *ptr,
- const char *end,
- POSITION *);
- int (*isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
- const char **badPtr);
- void (*utf8Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim,
- char **toP,
- const char *toLim);
- void (*utf16Convert)(const ENCODING *enc,
- const char **fromP,
- const char *fromLim,
- unsigned short **toP,
- const unsigned short *toLim);
- int minBytesPerChar;
- char isUtf8;
- char isUtf16;
-};
-
-/*
-Scan the string starting at ptr until the end of the next complete token,
-but do not scan past eptr. Return an integer giving the type of token.
-
-Return XML_TOK_NONE when ptr == eptr; nextTokPtr will not be set.
-
-Return XML_TOK_PARTIAL when the string does not contain a complete token;
-nextTokPtr will not be set.
-
-Return XML_TOK_INVALID when the string does not start a valid token; nextTokPtr
-will be set to point to the character which made the token invalid.
-
-Otherwise the string starts with a valid token; nextTokPtr will be set to point
-to the character following the end of that token.
-
-Each data character counts as a single token, but adjacent data characters
-may be returned together. Similarly for characters in the prolog outside
-literals, comments and processing instructions.
-*/
-
-
-#define XmlTok(enc, state, ptr, end, nextTokPtr) \
- (((enc)->scanners[state])(enc, ptr, end, nextTokPtr))
-
-#define XmlPrologTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_PROLOG_STATE, ptr, end, nextTokPtr)
-
-#define XmlContentTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_CONTENT_STATE, ptr, end, nextTokPtr)
-
-#define XmlCdataSectionTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_CDATA_SECTION_STATE, ptr, end, nextTokPtr)
-
-#ifdef XML_DTD
-
-#define XmlIgnoreSectionTok(enc, ptr, end, nextTokPtr) \
- XmlTok(enc, XML_IGNORE_SECTION_STATE, ptr, end, nextTokPtr)
-
-#endif /* XML_DTD */
-
-/* This is used for performing a 2nd-level tokenization on
-the content of a literal that has already been returned by XmlTok. */
-
-#define XmlLiteralTok(enc, literalType, ptr, end, nextTokPtr) \
- (((enc)->literalScanners[literalType])(enc, ptr, end, nextTokPtr))
-
-#define XmlAttributeValueTok(enc, ptr, end, nextTokPtr) \
- XmlLiteralTok(enc, XML_ATTRIBUTE_VALUE_LITERAL, ptr, end, nextTokPtr)
-
-#define XmlEntityValueTok(enc, ptr, end, nextTokPtr) \
- XmlLiteralTok(enc, XML_ENTITY_VALUE_LITERAL, ptr, end, nextTokPtr)
-
-#define XmlSameName(enc, ptr1, ptr2) (((enc)->sameName)(enc, ptr1, ptr2))
-
-#define XmlNameMatchesAscii(enc, ptr1, end1, ptr2) \
- (((enc)->nameMatchesAscii)(enc, ptr1, end1, ptr2))
-
-#define XmlNameLength(enc, ptr) \
- (((enc)->nameLength)(enc, ptr))
-
-#define XmlSkipS(enc, ptr) \
- (((enc)->skipS)(enc, ptr))
-
-#define XmlGetAttributes(enc, ptr, attsMax, atts) \
- (((enc)->getAtts)(enc, ptr, attsMax, atts))
-
-#define XmlCharRefNumber(enc, ptr) \
- (((enc)->charRefNumber)(enc, ptr))
-
-#define XmlPredefinedEntityName(enc, ptr, end) \
- (((enc)->predefinedEntityName)(enc, ptr, end))
-
-#define XmlUpdatePosition(enc, ptr, end, pos) \
- (((enc)->updatePosition)(enc, ptr, end, pos))
-
-#define XmlIsPublicId(enc, ptr, end, badPtr) \
- (((enc)->isPublicId)(enc, ptr, end, badPtr))
-
-#define XmlUtf8Convert(enc, fromP, fromLim, toP, toLim) \
- (((enc)->utf8Convert)(enc, fromP, fromLim, toP, toLim))
-
-#define XmlUtf16Convert(enc, fromP, fromLim, toP, toLim) \
- (((enc)->utf16Convert)(enc, fromP, fromLim, toP, toLim))
-
-typedef struct {
- ENCODING initEnc;
- const ENCODING **encPtr;
-} INIT_ENCODING;
-
-int XmlParseXmlDecl(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingNamePtr,
- const ENCODING **namedEncodingPtr,
- int *standalonePtr);
-
-int XmlInitEncoding(INIT_ENCODING *, const ENCODING **, const char *name);
-const ENCODING *XmlGetUtf8InternalEncoding(void);
-const ENCODING *XmlGetUtf16InternalEncoding(void);
-int XmlUtf8Encode(int charNumber, char *buf);
-int XmlUtf16Encode(int charNumber, unsigned short *buf);
-
-int XmlSizeOfUnknownEncoding(void);
-ENCODING *
-XmlInitUnknownEncoding(void *mem,
- int *table,
- int (*conv)(void *userData, const char *p),
- void *userData);
-
-int XmlParseXmlDeclNS(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingNamePtr,
- const ENCODING **namedEncodingPtr,
- int *standalonePtr);
-int XmlInitEncodingNS(INIT_ENCODING *, const ENCODING **, const char *name);
-const ENCODING *XmlGetUtf8InternalEncodingNS(void);
-const ENCODING *XmlGetUtf16InternalEncodingNS(void);
-ENCODING *
-XmlInitUnknownEncodingNS(void *mem,
- int *table,
- int (*conv)(void *userData, const char *p),
- void *userData);
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* not XmlTok_INCLUDED */
diff --git a/Utilities/cmexpat/xmltok_impl.c b/Utilities/cmexpat/xmltok_impl.c
deleted file mode 100644
index 6e0be9551..000000000
--- a/Utilities/cmexpat/xmltok_impl.c
+++ /dev/null
@@ -1,1775 +0,0 @@
-/*
-Copyright (c) 1998, 1999 Thai Open Source Software Center Ltd
-See the file COPYING for copying permission.
-*/
-
-#ifndef IS_INVALID_CHAR
-#define IS_INVALID_CHAR(enc, ptr, n) (0)
-#endif
-
-#ifndef INVALID_LEAD_CASE
-#define INVALID_LEAD_CASE(n, ptr, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (IS_INVALID_CHAR(enc, ptr, n)) { \
- *(nextTokPtr) = (ptr); \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
-#endif
-
-#define INVALID_CASES(ptr, nextTokPtr) \
- INVALID_LEAD_CASE(2, ptr, nextTokPtr) \
- INVALID_LEAD_CASE(3, ptr, nextTokPtr) \
- INVALID_LEAD_CASE(4, ptr, nextTokPtr) \
- case BT_NONXML: \
- case BT_MALFORM: \
- case BT_TRAIL: \
- *(nextTokPtr) = (ptr); \
- return XML_TOK_INVALID;
-
-#define CHECK_NAME_CASE(n, enc, ptr, end, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (!IS_NAME_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
-
-#define CHECK_NAME_CASES(enc, ptr, end, nextTokPtr) \
- case BT_NONASCII: \
- if (!IS_NAME_CHAR_MINBPC(enc, ptr)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- case BT_NMSTRT: \
- case BT_HEX: \
- case BT_DIGIT: \
- case BT_NAME: \
- case BT_MINUS: \
- ptr += MINBPC(enc); \
- break; \
- CHECK_NAME_CASE(2, enc, ptr, end, nextTokPtr) \
- CHECK_NAME_CASE(3, enc, ptr, end, nextTokPtr) \
- CHECK_NAME_CASE(4, enc, ptr, end, nextTokPtr)
-
-#define CHECK_NMSTRT_CASE(n, enc, ptr, end, nextTokPtr) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (!IS_NMSTRT_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- ptr += n; \
- break;
-
-#define CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr) \
- case BT_NONASCII: \
- if (!IS_NMSTRT_CHAR_MINBPC(enc, ptr)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID; \
- } \
- case BT_NMSTRT: \
- case BT_HEX: \
- ptr += MINBPC(enc); \
- break; \
- CHECK_NMSTRT_CASE(2, enc, ptr, end, nextTokPtr) \
- CHECK_NMSTRT_CASE(3, enc, ptr, end, nextTokPtr) \
- CHECK_NMSTRT_CASE(4, enc, ptr, end, nextTokPtr)
-
-#ifndef PREFIX
-#define PREFIX(ident) ident
-#endif
-
-/* ptr points to character following "<!-" */
-
-static
-int PREFIX(scanComment)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr != end) {
- if (!CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- ptr += MINBPC(enc);
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
- case BT_MINUS:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_MINUS)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_COMMENT;
- }
- break;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "<!" */
-
-static
-int PREFIX(scanDecl)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_MINUS:
- return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_LSQB:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_COND_SECT_OPEN;
- case BT_NMSTRT:
- case BT_HEX:
- ptr += MINBPC(enc);
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_PERCNT:
- if (ptr + MINBPC(enc) == end)
- return XML_TOK_PARTIAL;
- /* don't allow <!ENTITY% foo "whatever"> */
- switch (BYTE_TYPE(enc, ptr + MINBPC(enc))) {
- case BT_S: case BT_CR: case BT_LF: case BT_PERCNT:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- /* fall through */
- case BT_S: case BT_CR: case BT_LF:
- *nextTokPtr = ptr;
- return XML_TOK_DECL_OPEN;
- case BT_NMSTRT:
- case BT_HEX:
- ptr += MINBPC(enc);
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-static
-int PREFIX(checkPiTarget)(const ENCODING *enc, const char *ptr, const char *end, int *tokPtr)
-{
- int upper = 0;
- cmExpatUnused(enc);
- *tokPtr = XML_TOK_PI;
- if (end - ptr != MINBPC(enc)*3)
- return 1;
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case ASCII_x:
- break;
- case ASCII_X:
- upper = 1;
- break;
- default:
- return 1;
- }
- ptr += MINBPC(enc);
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case ASCII_m:
- break;
- case ASCII_M:
- upper = 1;
- break;
- default:
- return 1;
- }
- ptr += MINBPC(enc);
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case ASCII_l:
- break;
- case ASCII_L:
- upper = 1;
- break;
- default:
- return 1;
- }
- if (upper)
- return 0;
- *tokPtr = XML_TOK_XML_DECL;
- return 1;
-}
-
-/* ptr points to character following "<?" */
-
-static
-int PREFIX(scanPi)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- int tok;
- const char *target = ptr;
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- ptr += MINBPC(enc);
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
- case BT_QUEST:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr + MINBPC(enc);
- return tok;
- }
- break;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- return XML_TOK_PARTIAL;
- case BT_QUEST:
- if (!PREFIX(checkPiTarget)(enc, target, ptr, &tok)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr + MINBPC(enc);
- return tok;
- }
- /* fall through */
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-
-static
-int PREFIX(scanCdataSection)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- static const char CDATA_LSQB[] = { ASCII_C, ASCII_D, ASCII_A, ASCII_T, ASCII_A, ASCII_LSQB };
- int i;
- cmExpatUnused(enc);
- /* CDATA[ */
- if (end - ptr < 6 * MINBPC(enc))
- return XML_TOK_PARTIAL;
- for (i = 0; i < 6; i++, ptr += MINBPC(enc)) {
- if (!CHAR_MATCHES(enc, ptr, CDATA_LSQB[i])) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_CDATA_SECT_OPEN;
-}
-
-static
-int PREFIX(cdataSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_NONE;
- if (MINBPC(enc) > 1) {
- size_t n = end - ptr;
- if (n & (MINBPC(enc) - 1)) {
- n &= ~(MINBPC(enc) - 1);
- if (n == 0)
- return XML_TOK_PARTIAL;
- end = ptr + n;
- }
- }
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_RSQB:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
- break;
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- ptr -= MINBPC(enc);
- break;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CDATA_SECT_CLOSE;
- case BT_CR:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (BYTE_TYPE(enc, ptr) == BT_LF)
- ptr += MINBPC(enc);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_NEWLINE;
- case BT_LF:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_DATA_NEWLINE;
- INVALID_CASES(ptr, nextTokPtr)
- default:
- ptr += MINBPC(enc);
- break;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_DATA_CHARS; \
- } \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_NONXML:
- case BT_MALFORM:
- case BT_TRAIL:
- case BT_CR:
- case BT_LF:
- case BT_RSQB:
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
-}
-
-/* ptr points to character following "</" */
-
-static
-int PREFIX(scanEndTag)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_CR: case BT_LF:
- break;
- case BT_GT:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_END_TAG;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-#ifdef XML_NS
- case BT_COLON:
- /* no need to check qname syntax here, since end-tag must match exactly */
- ptr += MINBPC(enc);
- break;
-#endif
- case BT_GT:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_END_TAG;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&#X" */
-
-static
-int PREFIX(scanHexCharRef)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_DIGIT:
- case BT_HEX:
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_DIGIT:
- case BT_HEX:
- break;
- case BT_SEMI:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CHAR_REF;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&#" */
-
-static
-int PREFIX(scanCharRef)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr != end) {
- if (CHAR_MATCHES(enc, ptr, ASCII_x))
- return PREFIX(scanHexCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_DIGIT:
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- for (ptr += MINBPC(enc); ptr != end; ptr += MINBPC(enc)) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_DIGIT:
- break;
- case BT_SEMI:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CHAR_REF;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "&" */
-
-static
-int PREFIX(scanRef)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_NUM:
- return PREFIX(scanCharRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_SEMI:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_ENTITY_REF;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following first character of attribute name */
-
-static
-int PREFIX(scanAtts)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
-#ifdef XML_NS
- int hadColon = 0;
-#endif
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
- case BT_COLON:
- if (hadColon) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- hadColon = 1;
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- break;
-#endif
- case BT_S: case BT_CR: case BT_LF:
- for (;;) {
- int t;
-
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- t = BYTE_TYPE(enc, ptr);
- if (t == BT_EQUALS)
- break;
- switch (t) {
- case BT_S:
- case BT_LF:
- case BT_CR:
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- /* fall through */
- case BT_EQUALS:
- {
- int open;
-#ifdef XML_NS
- hadColon = 0;
-#endif
- for (;;) {
-
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- open = BYTE_TYPE(enc, ptr);
- if (open == BT_QUOT || open == BT_APOS)
- break;
- switch (open) {
- case BT_S:
- case BT_LF:
- case BT_CR:
- break;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- ptr += MINBPC(enc);
- /* in attribute value */
- for (;;) {
- int t;
- if (ptr == end)
- return XML_TOK_PARTIAL;
- t = BYTE_TYPE(enc, ptr);
- if (t == open)
- break;
- switch (t) {
- INVALID_CASES(ptr, nextTokPtr)
- case BT_AMP:
- {
- int tok = PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, &ptr);
- if (tok <= 0) {
- if (tok == XML_TOK_INVALID)
- *nextTokPtr = ptr;
- return tok;
- }
- break;
- }
- case BT_LT:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_S:
- case BT_CR:
- case BT_LF:
- break;
- case BT_SOL:
- goto sol;
- case BT_GT:
- goto gt;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- /* ptr points to closing quote */
- for (;;) {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_CR: case BT_LF:
- continue;
- case BT_GT:
- gt:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_START_TAG_WITH_ATTS;
- case BT_SOL:
- sol:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_EMPTY_ELEMENT_WITH_ATTS;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- break;
- }
- break;
- }
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-/* ptr points to character following "<" */
-
-static
-int PREFIX(scanLt)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
-#ifdef XML_NS
- int hadColon;
-#endif
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_EXCL:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_MINUS:
- return PREFIX(scanComment)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_LSQB:
- return PREFIX(scanCdataSection)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- }
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- case BT_QUEST:
- return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_SOL:
- return PREFIX(scanEndTag)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
-#ifdef XML_NS
- hadColon = 0;
-#endif
- /* we have a start-tag */
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
-#ifdef XML_NS
- case BT_COLON:
- if (hadColon) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- hadColon = 1;
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- break;
-#endif
- case BT_S: case BT_CR: case BT_LF:
- {
- ptr += MINBPC(enc);
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_GT:
- goto gt;
- case BT_SOL:
- goto sol;
- case BT_S: case BT_CR: case BT_LF:
- ptr += MINBPC(enc);
- continue;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- return PREFIX(scanAtts)(enc, ptr, end, nextTokPtr);
- }
- return XML_TOK_PARTIAL;
- }
- case BT_GT:
- gt:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_START_TAG_NO_ATTS;
- case BT_SOL:
- sol:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_EMPTY_ELEMENT_NO_ATTS;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-static
-int PREFIX(contentTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_NONE;
- if (MINBPC(enc) > 1) {
- size_t n = end - ptr;
- if (n & (MINBPC(enc) - 1)) {
- n &= ~(MINBPC(enc) - 1);
- if (n == 0)
- return XML_TOK_PARTIAL;
- end = ptr + n;
- }
- }
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_LT:
- return PREFIX(scanLt)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_AMP:
- return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_CR:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_TRAILING_CR;
- if (BYTE_TYPE(enc, ptr) == BT_LF)
- ptr += MINBPC(enc);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_NEWLINE;
- case BT_LF:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_DATA_NEWLINE;
- case BT_RSQB:
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_TRAILING_RSQB;
- if (!CHAR_MATCHES(enc, ptr, ASCII_RSQB))
- break;
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_TRAILING_RSQB;
- if (!CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- ptr -= MINBPC(enc);
- break;
- }
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- INVALID_CASES(ptr, nextTokPtr)
- default:
- ptr += MINBPC(enc);
- break;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n || IS_INVALID_CHAR(enc, ptr, n)) { \
- *nextTokPtr = ptr; \
- return XML_TOK_DATA_CHARS; \
- } \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_RSQB:
- if (ptr + MINBPC(enc) != end) {
- if (!CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_RSQB)) {
- ptr += MINBPC(enc);
- break;
- }
- if (ptr + 2*MINBPC(enc) != end) {
- if (!CHAR_MATCHES(enc, ptr + 2*MINBPC(enc), ASCII_GT)) {
- ptr += MINBPC(enc);
- break;
- }
- *nextTokPtr = ptr + 2*MINBPC(enc);
- return XML_TOK_INVALID;
- }
- }
- /* fall through */
- case BT_AMP:
- case BT_LT:
- case BT_NONXML:
- case BT_MALFORM:
- case BT_TRAIL:
- case BT_CR:
- case BT_LF:
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
-}
-
-/* ptr points to character following "%" */
-
-static
-int PREFIX(scanPercent)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- case BT_S: case BT_LF: case BT_CR: case BT_PERCNT:
- *nextTokPtr = ptr;
- return XML_TOK_PERCENT;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_SEMI:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_PARAM_ENTITY_REF;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-static
-int PREFIX(scanPoundName)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NMSTRT_CASES(enc, ptr, end, nextTokPtr)
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_CR: case BT_LF: case BT_S:
- case BT_RPAR: case BT_GT: case BT_PERCNT: case BT_VERBAR:
- *nextTokPtr = ptr;
- return XML_TOK_POUND_NAME;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return -XML_TOK_POUND_NAME;
-}
-
-static
-int PREFIX(scanLit)(int open, const ENCODING *enc,
- const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- while (ptr != end) {
- int t = BYTE_TYPE(enc, ptr);
- switch (t) {
- INVALID_CASES(ptr, nextTokPtr)
- case BT_QUOT:
- case BT_APOS:
- ptr += MINBPC(enc);
- if (t != open)
- break;
- if (ptr == end)
- return -XML_TOK_LITERAL;
- *nextTokPtr = ptr;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_CR: case BT_LF:
- case BT_GT: case BT_PERCNT: case BT_LSQB:
- return XML_TOK_LITERAL;
- default:
- return XML_TOK_INVALID;
- }
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-static
-int PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- int tok;
- if (ptr == end)
- return XML_TOK_NONE;
- if (MINBPC(enc) > 1) {
- size_t n = end - ptr;
- if (n & (MINBPC(enc) - 1)) {
- n &= ~(MINBPC(enc) - 1);
- if (n == 0)
- return XML_TOK_PARTIAL;
- end = ptr + n;
- }
- }
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_QUOT:
- return PREFIX(scanLit)(BT_QUOT, enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_APOS:
- return PREFIX(scanLit)(BT_APOS, enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_LT:
- {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_PARTIAL;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_EXCL:
- return PREFIX(scanDecl)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_QUEST:
- return PREFIX(scanPi)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_NMSTRT:
- case BT_HEX:
- case BT_NONASCII:
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- *nextTokPtr = ptr - MINBPC(enc);
- return XML_TOK_INSTANCE_START;
- }
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- case BT_CR:
- if (ptr + MINBPC(enc) == end)
- return -XML_TOK_PROLOG_S;
- /* fall through */
- case BT_S: case BT_LF:
- for (;;) {
- ptr += MINBPC(enc);
- if (ptr == end)
- break;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_S: case BT_LF:
- break;
- case BT_CR:
- /* don't split CR/LF pair */
- if (ptr + MINBPC(enc) != end)
- break;
- /* fall through */
- default:
- *nextTokPtr = ptr;
- return XML_TOK_PROLOG_S;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_PROLOG_S;
- case BT_PERCNT:
- return PREFIX(scanPercent)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- case BT_COMMA:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_COMMA;
- case BT_LSQB:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_OPEN_BRACKET;
- case BT_RSQB:
- ptr += MINBPC(enc);
- if (ptr == end)
- return -XML_TOK_CLOSE_BRACKET;
- if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
- if (ptr + MINBPC(enc) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_GT)) {
- *nextTokPtr = ptr + 2*MINBPC(enc);
- return XML_TOK_COND_SECT_CLOSE;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_CLOSE_BRACKET;
- case BT_LPAR:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_OPEN_PAREN;
- case BT_RPAR:
- ptr += MINBPC(enc);
- if (ptr == end)
- return -XML_TOK_CLOSE_PAREN;
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_AST:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CLOSE_PAREN_ASTERISK;
- case BT_QUEST:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CLOSE_PAREN_QUESTION;
- case BT_PLUS:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_CLOSE_PAREN_PLUS;
- case BT_CR: case BT_LF: case BT_S:
- case BT_GT: case BT_COMMA: case BT_VERBAR:
- case BT_RPAR:
- *nextTokPtr = ptr;
- return XML_TOK_CLOSE_PAREN;
- }
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- case BT_VERBAR:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_OR;
- case BT_GT:
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_DECL_CLOSE;
- case BT_NUM:
- return PREFIX(scanPoundName)(enc, ptr + MINBPC(enc), end, nextTokPtr);
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (end - ptr < n) \
- return XML_TOK_PARTIAL_CHAR; \
- if (IS_NMSTRT_CHAR(enc, ptr, n)) { \
- ptr += n; \
- tok = XML_TOK_NAME; \
- break; \
- } \
- if (IS_NAME_CHAR(enc, ptr, n)) { \
- ptr += n; \
- tok = XML_TOK_NMTOKEN; \
- break; \
- } \
- *nextTokPtr = ptr; \
- return XML_TOK_INVALID;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_NMSTRT:
- case BT_HEX:
- tok = XML_TOK_NAME;
- ptr += MINBPC(enc);
- break;
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- tok = XML_TOK_NMTOKEN;
- ptr += MINBPC(enc);
- break;
- case BT_NONASCII:
- if (IS_NMSTRT_CHAR_MINBPC(enc, ptr)) {
- ptr += MINBPC(enc);
- tok = XML_TOK_NAME;
- break;
- }
- if (IS_NAME_CHAR_MINBPC(enc, ptr)) {
- ptr += MINBPC(enc);
- tok = XML_TOK_NMTOKEN;
- break;
- }
- /* fall through */
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- case BT_GT: case BT_RPAR: case BT_COMMA:
- case BT_VERBAR: case BT_LSQB: case BT_PERCNT:
- case BT_S: case BT_CR: case BT_LF:
- *nextTokPtr = ptr;
- return tok;
-#ifdef XML_NS
- case BT_COLON:
- ptr += MINBPC(enc);
- switch (tok) {
- case XML_TOK_NAME:
- if (ptr == end)
- return XML_TOK_PARTIAL;
- tok = XML_TOK_PREFIXED_NAME;
- switch (BYTE_TYPE(enc, ptr)) {
- CHECK_NAME_CASES(enc, ptr, end, nextTokPtr)
- default:
- tok = XML_TOK_NMTOKEN;
- break;
- }
- break;
- case XML_TOK_PREFIXED_NAME:
- tok = XML_TOK_NMTOKEN;
- break;
- }
- break;
-#endif
- case BT_PLUS:
- if (tok == XML_TOK_NMTOKEN) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_NAME_PLUS;
- case BT_AST:
- if (tok == XML_TOK_NMTOKEN) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_NAME_ASTERISK;
- case BT_QUEST:
- if (tok == XML_TOK_NMTOKEN) {
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_NAME_QUESTION;
- default:
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- }
- }
- return -tok;
-}
-
-static
-int PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- const char *start;
- if (ptr == end)
- return XML_TOK_NONE;
- start = ptr;
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_AMP:
- if (ptr == start)
- return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_LT:
- /* this is for inside entity references */
- *nextTokPtr = ptr;
- return XML_TOK_INVALID;
- case BT_LF:
- if (ptr == start) {
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_DATA_NEWLINE;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_CR:
- if (ptr == start) {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_TRAILING_CR;
- if (BYTE_TYPE(enc, ptr) == BT_LF)
- ptr += MINBPC(enc);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_NEWLINE;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_S:
- if (ptr == start) {
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_ATTRIBUTE_VALUE_S;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
-}
-
-static
-int PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- const char *start;
- if (ptr == end)
- return XML_TOK_NONE;
- start = ptr;
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_AMP:
- if (ptr == start)
- return PREFIX(scanRef)(enc, ptr + MINBPC(enc), end, nextTokPtr);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_PERCNT:
- if (ptr == start) {
- int tok = PREFIX(scanPercent)(enc, ptr + MINBPC(enc),
- end, nextTokPtr);
- return (tok == XML_TOK_PERCENT) ? XML_TOK_INVALID : tok;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_LF:
- if (ptr == start) {
- *nextTokPtr = ptr + MINBPC(enc);
- return XML_TOK_DATA_NEWLINE;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- case BT_CR:
- if (ptr == start) {
- ptr += MINBPC(enc);
- if (ptr == end)
- return XML_TOK_TRAILING_CR;
- if (BYTE_TYPE(enc, ptr) == BT_LF)
- ptr += MINBPC(enc);
- *nextTokPtr = ptr;
- return XML_TOK_DATA_NEWLINE;
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- *nextTokPtr = ptr;
- return XML_TOK_DATA_CHARS;
-}
-
-#ifdef XML_DTD
-
-static
-int PREFIX(ignoreSectionTok)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- int level = 0;
- if (MINBPC(enc) > 1) {
- size_t n = end - ptr;
- if (n & (MINBPC(enc) - 1)) {
- n &= ~(MINBPC(enc) - 1);
- end = ptr + n;
- }
- }
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
- INVALID_CASES(ptr, nextTokPtr)
- case BT_LT:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_EXCL)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_LSQB)) {
- ++level;
- ptr += MINBPC(enc);
- }
- }
- break;
- case BT_RSQB:
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_RSQB)) {
- if ((ptr += MINBPC(enc)) == end)
- return XML_TOK_PARTIAL;
- if (CHAR_MATCHES(enc, ptr, ASCII_GT)) {
- ptr += MINBPC(enc);
- if (level == 0) {
- *nextTokPtr = ptr;
- return XML_TOK_IGNORE_SECT;
- }
- --level;
- }
- }
- break;
- default:
- ptr += MINBPC(enc);
- break;
- }
- }
- return XML_TOK_PARTIAL;
-}
-
-#endif /* XML_DTD */
-
-static
-int PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
- const char **badPtr)
-{
- ptr += MINBPC(enc);
- end -= MINBPC(enc);
- for (; ptr != end; ptr += MINBPC(enc)) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_DIGIT:
- case BT_HEX:
- case BT_MINUS:
- case BT_APOS:
- case BT_LPAR:
- case BT_RPAR:
- case BT_PLUS:
- case BT_COMMA:
- case BT_SOL:
- case BT_EQUALS:
- case BT_QUEST:
- case BT_CR:
- case BT_LF:
- case BT_SEMI:
- case BT_EXCL:
- case BT_AST:
- case BT_PERCNT:
- case BT_NUM:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- break;
- case BT_S:
- if (CHAR_MATCHES(enc, ptr, ASCII_TAB)) {
- *badPtr = ptr;
- return 0;
- }
- break;
- case BT_NAME:
- case BT_NMSTRT:
- if (!(BYTE_TO_ASCII(enc, ptr) & ~0x7f))
- break;
- default:
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case 0x24: /* $ */
- case 0x40: /* @ */
- break;
- default:
- *badPtr = ptr;
- return 0;
- }
- break;
- }
- }
- return 1;
-}
-
-/* This must only be called for a well-formed start-tag or empty element tag.
-Returns the number of attributes. Pointers to the first attsMax attributes
-are stored in atts. */
-
-static
-int PREFIX(getAtts)(const ENCODING *enc, const char *ptr,
- int attsMax, ATTRIBUTE *atts)
-{
- enum { other, inName, inValue } state = inName;
- int nAtts = 0;
- int open = 0; /* defined when state == inValue;
- initialization just to shut up compilers */
-
- for (ptr += MINBPC(enc);; ptr += MINBPC(enc)) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define START_NAME \
- if (state == other) { \
- if (nAtts < attsMax) { \
- atts[nAtts].name = ptr; \
- atts[nAtts].normalized = 1; \
- } \
- state = inName; \
- }
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: START_NAME ptr += (n - MINBPC(enc)); break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_NONASCII:
- case BT_NMSTRT:
- case BT_HEX:
- START_NAME
- break;
-#undef START_NAME
- case BT_QUOT:
- if (state != inValue) {
- if (nAtts < attsMax)
- atts[nAtts].valuePtr = ptr + MINBPC(enc);
- state = inValue;
- open = BT_QUOT;
- }
- else if (open == BT_QUOT) {
- state = other;
- if (nAtts < attsMax)
- atts[nAtts].valueEnd = ptr;
- nAtts++;
- }
- break;
- case BT_APOS:
- if (state != inValue) {
- if (nAtts < attsMax)
- atts[nAtts].valuePtr = ptr + MINBPC(enc);
- state = inValue;
- open = BT_APOS;
- }
- else if (open == BT_APOS) {
- state = other;
- if (nAtts < attsMax)
- atts[nAtts].valueEnd = ptr;
- nAtts++;
- }
- break;
- case BT_AMP:
- if (nAtts < attsMax)
- atts[nAtts].normalized = 0;
- break;
- case BT_S:
- if (state == inName)
- state = other;
- else if (state == inValue
- && nAtts < attsMax
- && atts[nAtts].normalized
- && (ptr == atts[nAtts].valuePtr
- || BYTE_TO_ASCII(enc, ptr) != ASCII_SPACE
- || BYTE_TO_ASCII(enc, ptr + MINBPC(enc)) == ASCII_SPACE
- || BYTE_TYPE(enc, ptr + MINBPC(enc)) == open))
- atts[nAtts].normalized = 0;
- break;
- case BT_CR: case BT_LF:
- /* This case ensures that the first attribute name is counted
- Apart from that we could just change state on the quote. */
- if (state == inName)
- state = other;
- else if (state == inValue && nAtts < attsMax)
- atts[nAtts].normalized = 0;
- break;
- case BT_GT:
- case BT_SOL:
- if (state != inValue)
- return nAtts;
- break;
- default:
- break;
- }
- }
- /* not reached */
-}
-
-static
-int PREFIX(charRefNumber)(const ENCODING *enc, const char *ptr)
-{
- int result = 0;
- cmExpatUnused(enc);
- /* skip &# */
- ptr += 2*MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_x)) {
- for (ptr += MINBPC(enc); !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
- int c = BYTE_TO_ASCII(enc, ptr);
- switch (c) {
- case ASCII_0: case ASCII_1: case ASCII_2: case ASCII_3: case ASCII_4:
- case ASCII_5: case ASCII_6: case ASCII_7: case ASCII_8: case ASCII_9:
- result <<= 4;
- result |= (c - ASCII_0);
- break;
- case ASCII_A: case ASCII_B: case ASCII_C: case ASCII_D: case ASCII_E: case ASCII_F:
- result <<= 4;
- result += 10 + (c - ASCII_A);
- break;
- case ASCII_a: case ASCII_b: case ASCII_c: case ASCII_d: case ASCII_e: case ASCII_f:
- result <<= 4;
- result += 10 + (c - ASCII_a);
- break;
- }
- if (result >= 0x110000)
- return -1;
- }
- }
- else {
- for (; !CHAR_MATCHES(enc, ptr, ASCII_SEMI); ptr += MINBPC(enc)) {
- int c = BYTE_TO_ASCII(enc, ptr);
- result *= 10;
- result += (c - ASCII_0);
- if (result >= 0x110000)
- return -1;
- }
- }
- return checkCharRefNumber(result);
-}
-
-static
-int PREFIX(predefinedEntityName)(const ENCODING *enc, const char *ptr, const char *end)
-{
- cmExpatUnused(enc);
- switch ((end - ptr)/MINBPC(enc)) {
- case 2:
- if (CHAR_MATCHES(enc, ptr + MINBPC(enc), ASCII_t)) {
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case ASCII_l:
- return ASCII_LT;
- case ASCII_g:
- return ASCII_GT;
- }
- }
- break;
- case 3:
- if (CHAR_MATCHES(enc, ptr, ASCII_a)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_m)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_p))
- return ASCII_AMP;
- }
- }
- break;
- case 4:
- switch (BYTE_TO_ASCII(enc, ptr)) {
- case ASCII_q:
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_u)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_t))
- return ASCII_QUOT;
- }
- }
- break;
- case ASCII_a:
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_p)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_o)) {
- ptr += MINBPC(enc);
- if (CHAR_MATCHES(enc, ptr, ASCII_s))
- return ASCII_APOS;
- }
- }
- break;
- }
- }
- return 0;
-}
-
-static
-int PREFIX(sameName)(const ENCODING *enc, const char *ptr1, const char *ptr2)
-{
- for (;;) {
- switch (BYTE_TYPE(enc, ptr1)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- if (*ptr1++ != *ptr2++) \
- return 0;
- LEAD_CASE(4) LEAD_CASE(3) LEAD_CASE(2)
-#undef LEAD_CASE
- /* fall through */
- if (*ptr1++ != *ptr2++)
- return 0;
- break;
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 1) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 2) {
- if (*ptr2++ != *ptr1++)
- return 0;
- if (MINBPC(enc) > 3) {
- if (*ptr2++ != *ptr1++)
- return 0;
- }
- }
- }
- break;
- default:
- if (MINBPC(enc) == 1 && *ptr1 == *ptr2)
- return 1;
- switch (BYTE_TYPE(enc, ptr2)) {
- case BT_LEAD2:
- case BT_LEAD3:
- case BT_LEAD4:
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- return 0;
- default:
- return 1;
- }
- }
- }
- /* not reached */
-}
-
-static
-int PREFIX(nameMatchesAscii)(const ENCODING *enc, const char *ptr1,
- const char *end1, const char *ptr2)
-{
- cmExpatUnused(enc);
- for (; *ptr2; ptr1 += MINBPC(enc), ptr2++) {
- if (ptr1 == end1)
- return 0;
- if (!CHAR_MATCHES(enc, ptr1, *ptr2))
- return 0;
- }
- return ptr1 == end1;
-}
-
-static
-int PREFIX(nameLength)(const ENCODING *enc, const char *ptr)
-{
- const char *start = ptr;
- for (;;) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: ptr += n; break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_NONASCII:
- case BT_NMSTRT:
-#ifdef XML_NS
- case BT_COLON:
-#endif
- case BT_HEX:
- case BT_DIGIT:
- case BT_NAME:
- case BT_MINUS:
- ptr += MINBPC(enc);
- break;
- default:
- return ptr - start;
- }
- }
-}
-
-static
-const char *PREFIX(skipS)(const ENCODING *enc, const char *ptr)
-{
- for (;;) {
- switch (BYTE_TYPE(enc, ptr)) {
- case BT_LF:
- case BT_CR:
- case BT_S:
- ptr += MINBPC(enc);
- break;
- default:
- return ptr;
- }
- }
-}
-
-static
-void PREFIX(updatePosition)(const ENCODING *enc,
- const char *ptr,
- const char *end,
- POSITION *pos)
-{
- while (ptr != end) {
- switch (BYTE_TYPE(enc, ptr)) {
-#define LEAD_CASE(n) \
- case BT_LEAD ## n: \
- ptr += n; \
- break;
- LEAD_CASE(2) LEAD_CASE(3) LEAD_CASE(4)
-#undef LEAD_CASE
- case BT_LF:
- pos->columnNumber = (unsigned)-1;
- pos->lineNumber++;
- ptr += MINBPC(enc);
- break;
- case BT_CR:
- pos->lineNumber++;
- ptr += MINBPC(enc);
- if (ptr != end && BYTE_TYPE(enc, ptr) == BT_LF)
- ptr += MINBPC(enc);
- pos->columnNumber = (unsigned)-1;
- break;
- default:
- ptr += MINBPC(enc);
- break;
- }
- pos->columnNumber++;
- }
-}
-
-#undef DO_LEAD_CASE
-#undef MULTIBYTE_CASES
-#undef INVALID_CASES
-#undef CHECK_NAME_CASE
-#undef CHECK_NAME_CASES
-#undef CHECK_NMSTRT_CASE
-#undef CHECK_NMSTRT_CASES
diff --git a/Utilities/cmexpat/xmltok_ns.c b/Utilities/cmexpat/xmltok_ns.c
deleted file mode 100644
index fa78adffc..000000000
--- a/Utilities/cmexpat/xmltok_ns.c
+++ /dev/null
@@ -1,98 +0,0 @@
-const ENCODING *NS(XmlGetUtf8InternalEncoding)(void)
-{
- return &ns(internal_utf8_encoding).enc;
-}
-
-const ENCODING *NS(XmlGetUtf16InternalEncoding)(void)
-{
-#if XML_BYTE_ORDER == 12
- return &ns(internal_little2_encoding).enc;
-#elif XML_BYTE_ORDER == 21
- return &ns(internal_big2_encoding).enc;
-#else
- const short n = 1;
- return *(const char *)&n ? &ns(internal_little2_encoding).enc : &ns(internal_big2_encoding).enc;
-#endif
-}
-
-static
-const ENCODING *NS(encodings)[] = {
- &ns(latin1_encoding).enc,
- &ns(ascii_encoding).enc,
- &ns(utf8_encoding).enc,
- &ns(big2_encoding).enc,
- &ns(big2_encoding).enc,
- &ns(little2_encoding).enc,
- &ns(utf8_encoding).enc /* NO_ENC */
-};
-
-static
-int NS(initScanProlog)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_PROLOG_STATE, ptr, end, nextTokPtr);
-}
-
-static
-int NS(initScanContent)(const ENCODING *enc, const char *ptr, const char *end,
- const char **nextTokPtr)
-{
- return initScan(NS(encodings), (const INIT_ENCODING *)enc, XML_CONTENT_STATE, ptr, end, nextTokPtr);
-}
-
-int NS(XmlInitEncoding)(INIT_ENCODING *p, const ENCODING **encPtr, const char *name)
-{
- int i = getEncodingIndex(name);
- if (i == UNKNOWN_ENC)
- return 0;
- SET_INIT_ENC_INDEX(p, i);
- p->initEnc.scanners[XML_PROLOG_STATE] = NS(initScanProlog);
- p->initEnc.scanners[XML_CONTENT_STATE] = NS(initScanContent);
- p->initEnc.updatePosition = initUpdatePosition;
- p->encPtr = encPtr;
- *encPtr = &(p->initEnc);
- return 1;
-}
-
-static
-const ENCODING *NS(findEncoding)(const ENCODING *enc, const char *ptr, const char *end)
-{
-#define ENCODING_MAX 128
- char buf[ENCODING_MAX];
- char *p = buf;
- int i;
- XmlUtf8Convert(enc, &ptr, end, &p, p + ENCODING_MAX - 1);
- if (ptr != end)
- return 0;
- *p = 0;
- if (streqci(buf, KW_UTF_16) && enc->minBytesPerChar == 2)
- return enc;
- i = getEncodingIndex(buf);
- if (i == UNKNOWN_ENC)
- return 0;
- return NS(encodings)[i];
-}
-
-int NS(XmlParseXmlDecl)(int isGeneralTextEntity,
- const ENCODING *enc,
- const char *ptr,
- const char *end,
- const char **badPtr,
- const char **versionPtr,
- const char **versionEndPtr,
- const char **encodingName,
- const ENCODING **encoding,
- int *standalone)
-{
- return doParseXmlDecl(NS(findEncoding),
- isGeneralTextEntity,
- enc,
- ptr,
- end,
- badPtr,
- versionPtr,
- versionEndPtr,
- encodingName,
- encoding,
- standalone);
-}
diff --git a/Utilities/cmjsoncpp/.gitattributes b/Utilities/cmjsoncpp/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmjsoncpp/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmjsoncpp/CMakeLists.txt b/Utilities/cmjsoncpp/CMakeLists.txt
new file mode 100644
index 000000000..bc9076e8e
--- /dev/null
+++ b/Utilities/cmjsoncpp/CMakeLists.txt
@@ -0,0 +1,27 @@
+project(JsonCpp CXX)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_CXX_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w")
+elseif(CMAKE_CXX_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -woffall")
+endif()
+
+set(JSONCPP_SOURCES
+ src/lib_json/json_batchallocator.h
+ src/lib_json/json_reader.cpp
+ src/lib_json/json_tool.h
+ src/lib_json/json_value.cpp
+ src/lib_json/json_valueiterator.inl
+ src/lib_json/json_writer.cpp
+ )
+
+include_directories(
+ ${JsonCpp_SOURCE_DIR}/include
+ ${KWSYS_HEADER_ROOT}
+ )
+
+add_library(cmjsoncpp ${JSONCPP_SOURCES})
+target_link_libraries(cmjsoncpp ${CMake_KWIML_LIBRARIES})
+set_property(TARGET cmjsoncpp PROPERTY CXX_INCLUDE_WHAT_YOU_USE "")
diff --git a/Utilities/cmjsoncpp/LICENSE b/Utilities/cmjsoncpp/LICENSE
new file mode 100644
index 000000000..ca2bfe1a0
--- /dev/null
+++ b/Utilities/cmjsoncpp/LICENSE
@@ -0,0 +1,55 @@
+The JsonCpp library's source code, including accompanying documentation,
+tests and demonstration applications, are licensed under the following
+conditions...
+
+The author (Baptiste Lepilleur) explicitly disclaims copyright in all
+jurisdictions which recognize such a disclaimer. In such jurisdictions,
+this software is released into the Public Domain.
+
+In jurisdictions which do not recognize Public Domain property (e.g. Germany as of
+2010), this software is Copyright (c) 2007-2010 by Baptiste Lepilleur, and is
+released under the terms of the MIT License (see below).
+
+In jurisdictions which recognize Public Domain property, the user of this
+software may choose to accept it either as 1) Public Domain, 2) under the
+conditions of the MIT License (see below), or 3) under the terms of dual
+Public Domain/MIT License conditions described here, as they choose.
+
+The MIT License is about as close to Public Domain as a license can get, and is
+described in clear, concise terms at:
+
+ http://en.wikipedia.org/wiki/MIT_License
+
+The full text of the MIT License follows:
+
+========================================================================
+Copyright (c) 2007-2010 Baptiste Lepilleur
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use, copy,
+modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+========================================================================
+(END LICENSE TEXT)
+
+The MIT license is compatible with both the GPL and commercial
+software, affording one all of the rights of Public Domain with the
+minor nuisance of being required to keep the above copyright notice
+and license text in the source code. Note also that by accepting the
+Public Domain "license" you can re-license your copy using whatever
+license you like.
diff --git a/Utilities/cmjsoncpp/README-CMake.txt b/Utilities/cmjsoncpp/README-CMake.txt
new file mode 100644
index 000000000..bf74094dd
--- /dev/null
+++ b/Utilities/cmjsoncpp/README-CMake.txt
@@ -0,0 +1,66 @@
+The Utilities/cmjsoncpp directory contains a reduced distribution
+of the jsoncpp source tree with only the library source code and
+CMake build system. It is not a submodule; the actual content is part
+of our source tree and changes can be made and committed directly.
+
+We update from upstream using Git's "subtree" merge strategy. A
+special branch contains commits of upstream jsoncpp snapshots and
+nothing else. No Git ref points explicitly to the head of this
+branch, but it is merged into our history.
+
+Update jsoncpp from upstream as follows. Create a local branch to
+explicitly reference the upstream snapshot branch head:
+
+ git branch jsoncpp-upstream 53f6ccb0
+
+Use a temporary directory to checkout the branch:
+
+ mkdir jsoncpp-tmp
+ cd jsoncpp-tmp
+ git init
+ git pull .. jsoncpp-upstream
+ rm -rf *
+
+Now place the (reduced) jsoncpp content in this directory. See
+instructions shown by
+
+ git log 53f6ccb0
+
+for help extracting the content from the upstream svn repo. Then run
+the following commands to commit the new version. Substitute the
+appropriate date and version number:
+
+ git add --all
+
+ GIT_AUTHOR_NAME='JsonCpp Upstream' \
+ GIT_AUTHOR_EMAIL='kwrobot@kitware.com' \
+ GIT_AUTHOR_DATE='Thu Nov 20 08:45:58 2014 -0600' \
+ git commit -m 'JsonCpp 1.0.0 (reduced)' &&
+ git commit --amend
+
+Edit the commit message to describe the procedure used to obtain the
+content. Then push the changes back up to the main local repository:
+
+ git push .. HEAD:jsoncpp-upstream
+ cd ..
+ rm -rf jsoncpp-tmp
+
+Create a topic in the main repository on which to perform the update:
+
+ git checkout -b update-jsoncpp master
+
+Merge the jsoncpp-upstream branch as a subtree:
+
+ git merge -s recursive -X subtree=Utilities/cmjsoncpp \
+ jsoncpp-upstream
+
+If there are conflicts, resolve them and commit. Build and test the
+tree. Commit any additional changes needed to succeed.
+
+Finally, run
+
+ git rev-parse --short=8 jsoncpp-upstream
+
+to get the commit from which the jsoncpp-upstream branch must be started
+on the next update. Edit the "git branch jsoncpp-upstream" line above to
+record it, and commit this file.
diff --git a/Utilities/cmjsoncpp/include/json/assertions.h b/Utilities/cmjsoncpp/include/json/assertions.h
new file mode 100644
index 000000000..37a3ff553
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/assertions.h
@@ -0,0 +1,41 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_ASSERTIONS_H_INCLUDED
+#define CPPTL_JSON_ASSERTIONS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+#include <stdlib.h>
+
+#if JSON_USE_EXCEPTION
+#include <stdexcept>
+#define JSON_ASSERT(condition) \
+ assert(condition); // @todo <= change this into an exception throw
+#define JSON_FAIL_MESSAGE(message) throw std::runtime_error(message);
+#else // JSON_USE_EXCEPTION
+#define JSON_ASSERT(condition) assert(condition);
+
+// The call to assert() will show the failure message in debug builds. In
+// release bugs we write to invalid memory in order to crash hard, so that a
+// debugger or crash reporter gets the chance to take over. We still call exit()
+// afterward in order to tell the compiler that this macro doesn't return.
+#define JSON_FAIL_MESSAGE(message) \
+ { \
+ assert(false&& message); \
+ strcpy(reinterpret_cast<char*>(666), message); \
+ exit(123); \
+ }
+
+#endif
+
+#define JSON_ASSERT_MESSAGE(condition, message) \
+ if (!(condition)) { \
+ JSON_FAIL_MESSAGE(message) \
+ }
+
+#endif // CPPTL_JSON_ASSERTIONS_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/config.h b/Utilities/cmjsoncpp/include/json/config.h
new file mode 100644
index 000000000..6847ceba8
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/config.h
@@ -0,0 +1,119 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_CONFIG_H_INCLUDED
+#define JSON_CONFIG_H_INCLUDED
+
+// Include KWSys Large File Support configuration.
+#include <cmsys/Configure.h>
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+#endif
+
+/// If defined, indicates that json library is embedded in CppTL library.
+//# define JSON_IN_CPPTL 1
+
+/// If defined, indicates that json may leverage CppTL library
+//# define JSON_USE_CPPTL 1
+/// If defined, indicates that cpptl vector based map should be used instead of
+/// std::map
+/// as Value container.
+//# define JSON_USE_CPPTL_SMALLMAP 1
+/// If defined, indicates that Json specific container should be used
+/// (hash table & simple deque container with customizable allocator).
+/// THIS FEATURE IS STILL EXPERIMENTAL! There is know bugs: See #3177332
+//# define JSON_VALUE_USE_INTERNAL_MAP 1
+/// Force usage of standard new/malloc based allocator instead of memory pool
+/// based allocator.
+/// The memory pools allocator used optimization (initializing Value and
+/// ValueInternalLink
+/// as if it was a POD) that may cause some validation tool to report errors.
+/// Only has effects if JSON_VALUE_USE_INTERNAL_MAP is defined.
+//# define JSON_USE_SIMPLE_INTERNAL_ALLOCATOR 1
+
+// If non-zero, the library uses exceptions to report bad input instead of C
+// assertion macros. The default is to use exceptions.
+#ifndef JSON_USE_EXCEPTION
+#define JSON_USE_EXCEPTION 1
+#endif
+
+/// If defined, indicates that the source file is amalgated
+/// to prevent private header inclusion.
+/// Remarks: it is automatically defined in the generated amalgated header.
+// #define JSON_IS_AMALGAMATION
+
+#ifdef JSON_IN_CPPTL
+#include <cpptl/config.h>
+#ifndef JSON_USE_CPPTL
+#define JSON_USE_CPPTL 1
+#endif
+#endif
+
+#ifdef JSON_IN_CPPTL
+#define JSON_API CPPTL_API
+#elif defined(JSON_DLL_BUILD)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllexport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#elif defined(JSON_DLL)
+#if defined(_MSC_VER)
+#define JSON_API __declspec(dllimport)
+#define JSONCPP_DISABLE_DLL_INTERFACE_WARNING
+#endif // if defined(_MSC_VER)
+#endif // ifdef JSON_IN_CPPTL
+#if !defined(JSON_API)
+#define JSON_API
+#endif
+
+// If JSON_NO_INT64 is defined, then Json only support C++ "int" type for
+// integer
+// Storages, and 64 bits integer support is disabled.
+// #define JSON_NO_INT64 1
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC 6
+// Microsoft Visual Studio 6 only support conversion from __int64 to double
+// (no conversion from unsigned __int64).
+#define JSON_USE_INT64_DOUBLE_CONVERSION 1
+// Disable warning 4786 for VS6 caused by STL (identifier was truncated to '255'
+// characters in the debug information)
+// All projects I've ever seen with VS6 were using this globally (not bothering
+// with pragma push/pop).
+#pragma warning(disable : 4786)
+#endif // if defined(_MSC_VER) && _MSC_VER < 1200 // MSVC 6
+
+#if defined(_MSC_VER) && _MSC_VER >= 1500 // MSVC 2008
+/// Indicates that the following function is deprecated.
+#define JSONCPP_DEPRECATED(message) __declspec(deprecated(message))
+#endif
+
+#if !defined(JSONCPP_DEPRECATED)
+#define JSONCPP_DEPRECATED(message)
+#endif // if !defined(JSONCPP_DEPRECATED)
+
+namespace Json {
+typedef int Int;
+typedef unsigned int UInt;
+#if defined(JSON_NO_INT64)
+typedef int LargestInt;
+typedef unsigned int LargestUInt;
+#undef JSON_HAS_INT64
+#else // if defined(JSON_NO_INT64)
+// For Microsoft Visual use specific types as long long is not supported
+#if defined(_MSC_VER) // Microsoft Visual Studio
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else // if defined(_MSC_VER) // Other platforms, use long long
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif // if defined(_MSC_VER)
+typedef Int64 LargestInt;
+typedef UInt64 LargestUInt;
+#define JSON_HAS_INT64
+#endif // if defined(JSON_NO_INT64)
+} // end namespace Json
+
+#endif // JSON_CONFIG_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/features.h b/Utilities/cmjsoncpp/include/json/features.h
new file mode 100644
index 000000000..1bb7bb614
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/features.h
@@ -0,0 +1,57 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_FEATURES_H_INCLUDED
+#define CPPTL_JSON_FEATURES_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+/** \brief Configuration passed to reader and writer.
+ * This configuration object can be used to force the Reader or Writer
+ * to behave in a standard conforming way.
+ */
+class JSON_API Features {
+public:
+ /** \brief A configuration that allows all features and assumes all strings
+ * are UTF-8.
+ * - C & C++ comments are allowed
+ * - Root object can be any JSON value
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features all();
+
+ /** \brief A configuration that is strictly compatible with the JSON
+ * specification.
+ * - Comments are forbidden.
+ * - Root object must be either an array or an object value.
+ * - Assumes Value strings are encoded in UTF-8
+ */
+ static Features strictMode();
+
+ /** \brief Initialize the configuration like JsonConfig::allFeatures;
+ */
+ Features();
+
+ /// \c true if comments are allowed. Default: \c true.
+ bool allowComments_;
+
+ /// \c true if root must be either an array or an object value. Default: \c
+ /// false.
+ bool strictRoot_;
+
+ /// \c true if dropped null placeholders are allowed. Default: \c false.
+ bool allowDroppedNullPlaceholders_;
+
+ /// \c true if numeric object key are allowed. Default: \c false.
+ bool allowNumericKeys_;
+};
+
+} // namespace Json
+
+#endif // CPPTL_JSON_FEATURES_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/forwards.h b/Utilities/cmjsoncpp/include/json/forwards.h
new file mode 100644
index 000000000..84a26cd2f
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/forwards.h
@@ -0,0 +1,43 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_FORWARDS_H_INCLUDED
+#define JSON_FORWARDS_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "config.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// writer.h
+class FastWriter;
+class StyledWriter;
+
+// reader.h
+class Reader;
+
+// features.h
+class Features;
+
+// value.h
+typedef unsigned int ArrayIndex;
+class StaticString;
+class Path;
+class PathArgument;
+class Value;
+class ValueIteratorBase;
+class ValueIterator;
+class ValueConstIterator;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+class ValueMapAllocator;
+class ValueInternalLink;
+class ValueInternalArray;
+class ValueInternalMap;
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+} // namespace Json
+
+#endif // JSON_FORWARDS_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/json.h b/Utilities/cmjsoncpp/include/json/json.h
new file mode 100644
index 000000000..f89bc6270
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/json.h
@@ -0,0 +1,14 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_JSON_H_INCLUDED
+#define JSON_JSON_H_INCLUDED
+
+#include "value.h"
+#include "reader.h"
+#include "writer.h"
+#include "features.h"
+
+#endif // JSON_JSON_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/reader.h b/Utilities/cmjsoncpp/include/json/reader.h
new file mode 100644
index 000000000..95237d168
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/reader.h
@@ -0,0 +1,274 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_READER_H_INCLUDED
+#define CPPTL_JSON_READER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "features.h"
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <deque>
+#include <iosfwd>
+#include <stack>
+#include <string>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+/** \brief Unserialize a <a HREF="http://www.json.org">JSON</a> document into a
+ *Value.
+ *
+ */
+class JSON_API Reader {
+public:
+ typedef char Char;
+ typedef const Char* Location;
+
+ /** \brief An error tagged with where in the JSON text it was encountered.
+ *
+ * The offsets give the [start, limit) range of bytes within the text. Note
+ * that this is bytes, not codepoints.
+ *
+ */
+ struct StructuredError {
+ size_t offset_start;
+ size_t offset_limit;
+ std::string message;
+ };
+
+ /** \brief Constructs a Reader allowing all features
+ * for parsing.
+ */
+ Reader();
+
+ /** \brief Constructs a Reader allowing the specified feature set
+ * for parsing.
+ */
+ Reader(const Features& features);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ * document.
+ * \param document UTF-8 encoded string containing the document to read.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ * back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ * Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ * error occurred.
+ */
+ bool
+ parse(const std::string& document, Value& root, bool collectComments = true);
+
+ /** \brief Read a Value from a <a HREF="http://www.json.org">JSON</a>
+ document.
+ * \param beginDoc Pointer on the beginning of the UTF-8 encoded string of the
+ document to read.
+ * \param endDoc Pointer on the end of the UTF-8 encoded string of the
+ document to read.
+ \ Must be >= beginDoc.
+ * \param root [out] Contains the root value of the document if it was
+ * successfully parsed.
+ * \param collectComments \c true to collect comment and allow writing them
+ back during
+ * serialization, \c false to discard comments.
+ * This parameter is ignored if
+ Features::allowComments_
+ * is \c false.
+ * \return \c true if the document was successfully parsed, \c false if an
+ error occurred.
+ */
+ bool parse(const char* beginDoc,
+ const char* endDoc,
+ Value& root,
+ bool collectComments = true);
+
+ /// \brief Parse from input stream.
+ /// \see Json::operator>>(std::istream&, Json::Value&).
+ bool parse(std::istream& is, Value& root, bool collectComments = true);
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ */
+ std::string getFormatedErrorMessages() const;
+
+ /** \brief Returns a user friendly string that list errors in the parsed
+ * document.
+ * \return Formatted error message with the list of errors with their location
+ * in
+ * the parsed document. An empty string is returned if no error
+ * occurred
+ * during parsing.
+ */
+ std::string getFormattedErrorMessages() const;
+
+ /** \brief Returns a vector of structured erros encounted while parsing.
+ * \return A (possibly empty) vector of StructuredError objects. Currently
+ * only one error can be returned, but the caller should tolerate
+ * multiple
+ * errors. This can occur if the parser recovers from a non-fatal
+ * parse error and then encounters additional errors.
+ */
+ std::vector<StructuredError> getStructuredErrors() const;
+
+ /** \brief Add a semantic error message.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \return \c true if the error was successfully added, \c false if the
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value& value, const std::string& message);
+
+ /** \brief Add a semantic error message with extra context.
+ * \param value JSON Value location associated with the error
+ * \param message The error message.
+ * \param extra Additional JSON Value location to contextualize the error
+ * \return \c true if the error was successfully added, \c false if either
+ * Value offset exceeds the document size.
+ */
+ bool pushError(const Value& value, const std::string& message, const Value& extra);
+
+ /** \brief Return whether there are any errors.
+ * \return \c true if there are no errors to report \c false if
+ * errors have occurred.
+ */
+ bool good() const;
+
+private:
+ enum TokenType {
+ tokenEndOfStream = 0,
+ tokenObjectBegin,
+ tokenObjectEnd,
+ tokenArrayBegin,
+ tokenArrayEnd,
+ tokenString,
+ tokenNumber,
+ tokenTrue,
+ tokenFalse,
+ tokenNull,
+ tokenArraySeparator,
+ tokenMemberSeparator,
+ tokenComment,
+ tokenError
+ };
+
+ class Token {
+ public:
+ TokenType type_;
+ Location start_;
+ Location end_;
+ };
+
+ class ErrorInfo {
+ public:
+ Token token_;
+ std::string message_;
+ Location extra_;
+ };
+
+ typedef std::deque<ErrorInfo> Errors;
+
+ bool expectToken(TokenType type, Token& token, const char* message);
+ bool readToken(Token& token);
+ void skipSpaces();
+ bool match(Location pattern, int patternLength);
+ bool readComment();
+ bool readCStyleComment();
+ bool readCppStyleComment();
+ bool readString();
+ void readNumber();
+ bool readValue();
+ bool readObject(Token& token);
+ bool readArray(Token& token);
+ bool decodeNumber(Token& token);
+ bool decodeNumber(Token& token, Value& decoded);
+ bool decodeString(Token& token);
+ bool decodeString(Token& token, std::string& decoded);
+ bool decodeDouble(Token& token);
+ bool decodeDouble(Token& token, Value& decoded);
+ bool decodeUnicodeCodePoint(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode);
+ bool decodeUnicodeEscapeSequence(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode);
+ bool addError(const std::string& message, Token& token, Location extra = 0);
+ bool recoverFromError(TokenType skipUntilToken);
+ bool addErrorAndRecover(const std::string& message,
+ Token& token,
+ TokenType skipUntilToken);
+ void skipUntilSpace();
+ Value& currentValue();
+ Char getNextChar();
+ void
+ getLocationLineAndColumn(Location location, int& line, int& column) const;
+ std::string getLocationLineAndColumn(Location location) const;
+ void addComment(Location begin, Location end, CommentPlacement placement);
+ void skipCommentTokens(Token& token);
+
+ typedef std::stack<Value*> Nodes;
+ Nodes nodes_;
+ Errors errors_;
+ std::string document_;
+ Location begin_;
+ Location end_;
+ Location current_;
+ Location lastValueEnd_;
+ Value* lastValue_;
+ std::string commentsBefore_;
+ Features features_;
+ bool collectComments_;
+};
+
+/** \brief Read from 'sin' into 'root'.
+
+ Always keep comments from the input JSON.
+
+ This can be used to read a file into a particular sub-object.
+ For example:
+ \code
+ Json::Value root;
+ cin >> root["dir"]["file"];
+ cout << root;
+ \endcode
+ Result:
+ \verbatim
+ {
+ "dir": {
+ "file": {
+ // The input stream JSON would be nested here.
+ }
+ }
+ }
+ \endverbatim
+ \throw std::exception on parse error.
+ \see Json::operator<<()
+*/
+JSON_API std::istream& operator>>(std::istream&, Value&);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_READER_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/value.h b/Utilities/cmjsoncpp/include/json/value.h
new file mode 100644
index 000000000..197a85614
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/value.h
@@ -0,0 +1,1088 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef CPPTL_JSON_H_INCLUDED
+#define CPPTL_JSON_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "forwards.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <string>
+#include <vector>
+
+#ifndef JSON_USE_CPPTL_SMALLMAP
+#include <map>
+#else
+#include <cpptl/smallmap.h>
+#endif
+#ifdef JSON_USE_CPPTL
+#include <cpptl/forwards.h>
+#endif
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+/** \brief JSON (JavaScript Object Notation).
+ */
+namespace Json {
+
+/** \brief Type of the value held by a Value object.
+ */
+enum ValueType {
+ nullValue = 0, ///< 'null' value
+ intValue, ///< signed integer value
+ uintValue, ///< unsigned integer value
+ realValue, ///< double value
+ stringValue, ///< UTF-8 string value
+ booleanValue, ///< bool value
+ arrayValue, ///< array value (ordered list)
+ objectValue ///< object value (collection of name/value pairs).
+};
+
+enum CommentPlacement {
+ commentBefore = 0, ///< a comment placed on the line before a value
+ commentAfterOnSameLine, ///< a comment just after a value on the same line
+ commentAfter, ///< a comment on the line after a value (only make sense for
+ /// root value)
+ numberOfCommentPlacement
+};
+
+//# ifdef JSON_USE_CPPTL
+// typedef CppTL::AnyEnumerator<const char *> EnumMemberNames;
+// typedef CppTL::AnyEnumerator<const Value &> EnumValues;
+//# endif
+
+/** \brief Lightweight wrapper to tag static string.
+ *
+ * Value constructor and objectValue member assignement takes advantage of the
+ * StaticString and avoid the cost of string duplication when storing the
+ * string or the member name.
+ *
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+class JSON_API StaticString {
+public:
+ explicit StaticString(const char* czstring) : str_(czstring) {}
+
+ operator const char*() const { return str_; }
+
+ const char* c_str() const { return str_; }
+
+private:
+ const char* str_;
+};
+
+/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
+ *
+ * This class is a discriminated union wrapper that can represents a:
+ * - signed integer [range: Value::minInt - Value::maxInt]
+ * - unsigned integer (range: 0 - Value::maxUInt)
+ * - double
+ * - UTF-8 string
+ * - boolean
+ * - 'null'
+ * - an ordered list of Value
+ * - collection of name/value pairs (javascript object)
+ *
+ * The type of the held value is represented by a #ValueType and
+ * can be obtained using type().
+ *
+ * values of an #objectValue or #arrayValue can be accessed using operator[]()
+ *methods.
+ * Non const methods will automatically create the a #nullValue element
+ * if it does not exist.
+ * The sequence of an #arrayValue will be automatically resize and initialized
+ * with #nullValue. resize() can be used to enlarge or truncate an #arrayValue.
+ *
+ * The get() methods can be used to obtanis default value in the case the
+ *required element
+ * does not exist.
+ *
+ * It is possible to iterate over the list of a #objectValue values using
+ * the getMemberNames() method.
+ */
+class JSON_API Value {
+ friend class ValueIteratorBase;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ friend class ValueInternalLink;
+ friend class ValueInternalMap;
+#endif
+public:
+ typedef std::vector<std::string> Members;
+ typedef ValueIterator iterator;
+ typedef ValueConstIterator const_iterator;
+ typedef Json::UInt UInt;
+ typedef Json::Int Int;
+#if defined(JSON_HAS_INT64)
+ typedef Json::UInt64 UInt64;
+ typedef Json::Int64 Int64;
+#endif // defined(JSON_HAS_INT64)
+ typedef Json::LargestInt LargestInt;
+ typedef Json::LargestUInt LargestUInt;
+ typedef Json::ArrayIndex ArrayIndex;
+
+ static const Value& null;
+ /// Minimum signed integer value that can be stored in a Json::Value.
+ static const LargestInt minLargestInt;
+ /// Maximum signed integer value that can be stored in a Json::Value.
+ static const LargestInt maxLargestInt;
+ /// Maximum unsigned integer value that can be stored in a Json::Value.
+ static const LargestUInt maxLargestUInt;
+
+ /// Minimum signed int value that can be stored in a Json::Value.
+ static const Int minInt;
+ /// Maximum signed int value that can be stored in a Json::Value.
+ static const Int maxInt;
+ /// Maximum unsigned int value that can be stored in a Json::Value.
+ static const UInt maxUInt;
+
+#if defined(JSON_HAS_INT64)
+ /// Minimum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 minInt64;
+ /// Maximum signed 64 bits int value that can be stored in a Json::Value.
+ static const Int64 maxInt64;
+ /// Maximum unsigned 64 bits int value that can be stored in a Json::Value.
+ static const UInt64 maxUInt64;
+#endif // defined(JSON_HAS_INT64)
+
+private:
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ class CZString {
+ public:
+ enum DuplicationPolicy {
+ noDuplication = 0,
+ duplicate,
+ duplicateOnCopy
+ };
+ CZString(ArrayIndex index);
+ CZString(const char* cstr, DuplicationPolicy allocate);
+ CZString(const CZString& other);
+ ~CZString();
+ CZString& operator=(CZString other);
+ bool operator<(const CZString& other) const;
+ bool operator==(const CZString& other) const;
+ ArrayIndex index() const;
+ const char* c_str() const;
+ bool isStaticString() const;
+
+ private:
+ void swap(CZString& other);
+ const char* cstr_;
+ ArrayIndex index_;
+ };
+
+public:
+#ifndef JSON_USE_CPPTL_SMALLMAP
+ typedef std::map<CZString, Value> ObjectValues;
+#else
+ typedef CppTL::SmallMap<CZString, Value> ObjectValues;
+#endif // ifndef JSON_USE_CPPTL_SMALLMAP
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+public:
+ /** \brief Create a default Value of the given type.
+
+ This is a very useful constructor.
+ To create an empty array, pass arrayValue.
+ To create an empty object, pass objectValue.
+ Another Value can then be set to this one by assignment.
+This is useful since clear() and resize() will not alter types.
+
+ Examples:
+\code
+Json::Value null_value; // null
+Json::Value arr_value(Json::arrayValue); // []
+Json::Value obj_value(Json::objectValue); // {}
+\endcode
+ */
+ Value(ValueType type = nullValue);
+ Value(Int value);
+ Value(UInt value);
+#if defined(JSON_HAS_INT64)
+ Value(Int64 value);
+ Value(UInt64 value);
+#endif // if defined(JSON_HAS_INT64)
+ Value(double value);
+ Value(const char* value);
+ Value(const char* beginValue, const char* endValue);
+ /** \brief Constructs a value from a static string.
+
+ * Like other value string constructor but do not duplicate the string for
+ * internal storage. The given string must remain alive after the call to this
+ * constructor.
+ * Example of usage:
+ * \code
+ * Json::Value aValue( StaticString("some text") );
+ * \endcode
+ */
+ Value(const StaticString& value);
+ Value(const std::string& value);
+#ifdef JSON_USE_CPPTL
+ Value(const CppTL::ConstString& value);
+#endif
+ Value(bool value);
+ Value(const Value& other);
+ ~Value();
+
+ Value& operator=(Value other);
+ /// Swap values.
+ /// \note Currently, comments are intentionally not swapped, for
+ /// both logic and efficiency.
+ void swap(Value& other);
+
+ ValueType type() const;
+
+ bool operator<(const Value& other) const;
+ bool operator<=(const Value& other) const;
+ bool operator>=(const Value& other) const;
+ bool operator>(const Value& other) const;
+
+ bool operator==(const Value& other) const;
+ bool operator!=(const Value& other) const;
+
+ int compare(const Value& other) const;
+
+ const char* asCString() const;
+ std::string asString() const;
+#ifdef JSON_USE_CPPTL
+ CppTL::ConstString asConstString() const;
+#endif
+ Int asInt() const;
+ UInt asUInt() const;
+#if defined(JSON_HAS_INT64)
+ Int64 asInt64() const;
+ UInt64 asUInt64() const;
+#endif // if defined(JSON_HAS_INT64)
+ LargestInt asLargestInt() const;
+ LargestUInt asLargestUInt() const;
+ float asFloat() const;
+ double asDouble() const;
+ bool asBool() const;
+
+ bool isNull() const;
+ bool isBool() const;
+ bool isInt() const;
+ bool isInt64() const;
+ bool isUInt() const;
+ bool isUInt64() const;
+ bool isIntegral() const;
+ bool isDouble() const;
+ bool isNumeric() const;
+ bool isString() const;
+ bool isArray() const;
+ bool isObject() const;
+
+ bool isConvertibleTo(ValueType other) const;
+
+ /// Number of values in array or object
+ ArrayIndex size() const;
+
+ /// \brief Return true if empty array, empty object, or null;
+ /// otherwise, false.
+ bool empty() const;
+
+ /// Return isNull()
+ bool operator!() const;
+
+ /// Remove all object members and array elements.
+ /// \pre type() is arrayValue, objectValue, or nullValue
+ /// \post type() is unchanged
+ void clear();
+
+ /// Resize the array to size elements.
+ /// New elements are initialized to null.
+ /// May only be called on nullValue or arrayValue.
+ /// \pre type() is arrayValue or nullValue
+ /// \post type() is arrayValue
+ void resize(ArrayIndex size);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value& operator[](ArrayIndex index);
+
+ /// Access an array element (zero based index ).
+ /// If the array contains less than index element, then null value are
+ /// inserted
+ /// in the array so that its size is index+1.
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ Value& operator[](int index);
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value& operator[](ArrayIndex index) const;
+
+ /// Access an array element (zero based index )
+ /// (You may need to say 'value[0u]' to get your compiler to distinguish
+ /// this from the operator[] which takes a string.)
+ const Value& operator[](int index) const;
+
+ /// If the array contains at least index+1 elements, returns the element
+ /// value,
+ /// otherwise returns defaultValue.
+ Value get(ArrayIndex index, const Value& defaultValue) const;
+ /// Return true if index < size().
+ bool isValidIndex(ArrayIndex index) const;
+ /// \brief Append value to array at the end.
+ ///
+ /// Equivalent to jsonvalue[jsonvalue.size()] = value;
+ Value& append(const Value& value);
+
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const char* key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const char* key) const;
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const std::string& key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const std::string& key) const;
+ /** \brief Access an object value by name, create a null member if it does not
+ exist.
+
+ * If the object as no entry for that name, then the member name used to store
+ * the new entry is not duplicated.
+ * Example of use:
+ * \code
+ * Json::Value object;
+ * static const StaticString code("code");
+ * object[code] = 1234;
+ * \endcode
+ */
+ Value& operator[](const StaticString& key);
+#ifdef JSON_USE_CPPTL
+ /// Access an object value by name, create a null member if it does not exist.
+ Value& operator[](const CppTL::ConstString& key);
+ /// Access an object value by name, returns null if there is no member with
+ /// that name.
+ const Value& operator[](const CppTL::ConstString& key) const;
+#endif
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const char* key, const Value& defaultValue) const;
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const std::string& key, const Value& defaultValue) const;
+#ifdef JSON_USE_CPPTL
+ /// Return the member named key if it exist, defaultValue otherwise.
+ Value get(const CppTL::ConstString& key, const Value& defaultValue) const;
+#endif
+ /// \brief Remove and return the named member.
+ ///
+ /// Do nothing if it did not exist.
+ /// \return the removed Value, or null.
+ /// \pre type() is objectValue or nullValue
+ /// \post type() is unchanged
+ Value removeMember(const char* key);
+ /// Same as removeMember(const char*)
+ Value removeMember(const std::string& key);
+
+ /// Return true if the object has a member named key.
+ bool isMember(const char* key) const;
+ /// Return true if the object has a member named key.
+ bool isMember(const std::string& key) const;
+#ifdef JSON_USE_CPPTL
+ /// Return true if the object has a member named key.
+ bool isMember(const CppTL::ConstString& key) const;
+#endif
+
+ /// \brief Return a list of the member names.
+ ///
+ /// If null, return an empty list.
+ /// \pre type() is objectValue or nullValue
+ /// \post if type() was nullValue, it remains nullValue
+ Members getMemberNames() const;
+
+ //# ifdef JSON_USE_CPPTL
+ // EnumMemberNames enumMemberNames() const;
+ // EnumValues enumValues() const;
+ //# endif
+
+ /// Comments must be //... or /* ... */
+ void setComment(const char* comment, CommentPlacement placement);
+ /// Comments must be //... or /* ... */
+ void setComment(const std::string& comment, CommentPlacement placement);
+ bool hasComment(CommentPlacement placement) const;
+ /// Include delimiters and embedded newlines.
+ std::string getComment(CommentPlacement placement) const;
+
+ std::string toStyledString() const;
+
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ iterator begin();
+ iterator end();
+
+ // Accessors for the [start, limit) range of bytes within the JSON text from
+ // which this value was parsed, if any.
+ void setOffsetStart(size_t start);
+ void setOffsetLimit(size_t limit);
+ size_t getOffsetStart() const;
+ size_t getOffsetLimit() const;
+
+private:
+ void initBasic(ValueType type, bool allocated = false);
+
+ Value& resolveReference(const char* key, bool isStatic);
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ inline bool isItemAvailable() const { return itemIsUsed_ == 0; }
+
+ inline void setItemUsed(bool isUsed = true) { itemIsUsed_ = isUsed ? 1 : 0; }
+
+ inline bool isMemberNameStatic() const { return memberNameIsStatic_ == 0; }
+
+ inline void setMemberNameIsStatic(bool isStatic) {
+ memberNameIsStatic_ = isStatic ? 1 : 0;
+ }
+#endif // # ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+private:
+ struct CommentInfo {
+ CommentInfo();
+ ~CommentInfo();
+
+ void setComment(const char* text);
+
+ char* comment_;
+ };
+
+ // struct MemberNamesTransform
+ //{
+ // typedef const char *result_type;
+ // const char *operator()( const CZString &name ) const
+ // {
+ // return name.c_str();
+ // }
+ //};
+
+ union ValueHolder {
+ LargestInt int_;
+ LargestUInt uint_;
+ double real_;
+ bool bool_;
+ char* string_;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ ValueInternalArray* array_;
+ ValueInternalMap* map_;
+#else
+ ObjectValues* map_;
+#endif
+ } value_;
+ ValueType type_ : 8;
+ int allocated_ : 1; // Notes: if declared as bool, bitfield is useless.
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ unsigned int itemIsUsed_ : 1; // used by the ValueInternalMap container.
+ int memberNameIsStatic_ : 1; // used by the ValueInternalMap container.
+#endif
+ CommentInfo* comments_;
+
+ // [start, limit) byte offsets in the source JSON text from which this Value
+ // was extracted.
+ size_t start_;
+ size_t limit_;
+};
+
+/** \brief Experimental and untested: represents an element of the "path" to
+ * access a node.
+ */
+class JSON_API PathArgument {
+public:
+ friend class Path;
+
+ PathArgument();
+ PathArgument(ArrayIndex index);
+ PathArgument(const char* key);
+ PathArgument(const std::string& key);
+
+private:
+ enum Kind {
+ kindNone = 0,
+ kindIndex,
+ kindKey
+ };
+ std::string key_;
+ ArrayIndex index_;
+ Kind kind_;
+};
+
+/** \brief Experimental and untested: represents a "path" to access a node.
+ *
+ * Syntax:
+ * - "." => root node
+ * - ".[n]" => elements at index 'n' of root node (an array value)
+ * - ".name" => member named 'name' of root node (an object value)
+ * - ".name1.name2.name3"
+ * - ".[0][1][2].name1[3]"
+ * - ".%" => member name is provided as parameter
+ * - ".[%]" => index is provied as parameter
+ */
+class JSON_API Path {
+public:
+ Path(const std::string& path,
+ const PathArgument& a1 = PathArgument(),
+ const PathArgument& a2 = PathArgument(),
+ const PathArgument& a3 = PathArgument(),
+ const PathArgument& a4 = PathArgument(),
+ const PathArgument& a5 = PathArgument());
+
+ const Value& resolve(const Value& root) const;
+ Value resolve(const Value& root, const Value& defaultValue) const;
+ /// Creates the "path" to access the specified node and returns a reference on
+ /// the node.
+ Value& make(Value& root) const;
+
+private:
+ typedef std::vector<const PathArgument*> InArgs;
+ typedef std::vector<PathArgument> Args;
+
+ void makePath(const std::string& path, const InArgs& in);
+ void addPathInArg(const std::string& path,
+ const InArgs& in,
+ InArgs::const_iterator& itInArg,
+ PathArgument::Kind kind);
+ void invalidPath(const std::string& path, int location);
+
+ Args args_;
+};
+
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+/** \brief Allocator to customize Value internal map.
+ * Below is an example of a simple implementation (default implementation
+ actually
+ * use memory pool for speed).
+ * \code
+ class DefaultValueMapAllocator : public ValueMapAllocator
+ {
+ public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap *newMap()
+ {
+ return new ValueInternalMap();
+ }
+
+ virtual ValueInternalMap *newMapCopy( const ValueInternalMap &other )
+ {
+ return new ValueInternalMap( other );
+ }
+
+ virtual void destructMap( ValueInternalMap *map )
+ {
+ delete map;
+ }
+
+ virtual ValueInternalLink *allocateMapBuckets( unsigned int size )
+ {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets( ValueInternalLink *links )
+ {
+ delete [] links;
+ }
+
+ virtual ValueInternalLink *allocateMapLink()
+ {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink( ValueInternalLink *link )
+ {
+ delete link;
+ }
+ };
+ * \endcode
+ */
+class JSON_API ValueMapAllocator {
+public:
+ virtual ~ValueMapAllocator();
+ virtual ValueInternalMap* newMap() = 0;
+ virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) = 0;
+ virtual void destructMap(ValueInternalMap* map) = 0;
+ virtual ValueInternalLink* allocateMapBuckets(unsigned int size) = 0;
+ virtual void releaseMapBuckets(ValueInternalLink* links) = 0;
+ virtual ValueInternalLink* allocateMapLink() = 0;
+ virtual void releaseMapLink(ValueInternalLink* link) = 0;
+};
+
+/** \brief ValueInternalMap hash-map bucket chain link (for internal use only).
+ * \internal previous_ & next_ allows for bidirectional traversal.
+ */
+class JSON_API ValueInternalLink {
+public:
+ enum {
+ itemPerLink = 6
+ }; // sizeof(ValueInternalLink) = 128 on 32 bits architecture.
+ enum InternalFlags {
+ flagAvailable = 0,
+ flagUsed = 1
+ };
+
+ ValueInternalLink();
+
+ ~ValueInternalLink();
+
+ Value items_[itemPerLink];
+ char* keys_[itemPerLink];
+ ValueInternalLink* previous_;
+ ValueInternalLink* next_;
+};
+
+/** \brief A linked page based hash-table implementation used internally by
+ *Value.
+ * \internal ValueInternalMap is a tradional bucket based hash-table, with a
+ *linked
+ * list in each bucket to handle collision. There is an addional twist in that
+ * each node of the collision linked list is a page containing a fixed amount of
+ * value. This provides a better compromise between memory usage and speed.
+ *
+ * Each bucket is made up of a chained list of ValueInternalLink. The last
+ * link of a given bucket can be found in the 'previous_' field of the following
+ *bucket.
+ * The last link of the last bucket is stored in tailLink_ as it has no
+ *following bucket.
+ * Only the last link of a bucket may contains 'available' item. The last link
+ *always
+ * contains at least one element unless is it the bucket one very first link.
+ */
+class JSON_API ValueInternalMap {
+ friend class ValueIteratorBase;
+ friend class Value;
+
+public:
+ typedef unsigned int HashKey;
+ typedef unsigned int BucketIndex;
+
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState {
+ IteratorState() : map_(0), link_(0), itemIndex_(0), bucketIndex_(0) {}
+ ValueInternalMap* map_;
+ ValueInternalLink* link_;
+ BucketIndex itemIndex_;
+ BucketIndex bucketIndex_;
+ };
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalMap();
+ ValueInternalMap(const ValueInternalMap& other);
+ ValueInternalMap& operator=(ValueInternalMap other);
+ ~ValueInternalMap();
+
+ void swap(ValueInternalMap& other);
+
+ BucketIndex size() const;
+
+ void clear();
+
+ bool reserveDelta(BucketIndex growth);
+
+ bool reserve(BucketIndex newItemCount);
+
+ const Value* find(const char* key) const;
+
+ Value* find(const char* key);
+
+ Value& resolveReference(const char* key, bool isStatic);
+
+ void remove(const char* key);
+
+ void doActualRemove(ValueInternalLink* link,
+ BucketIndex index,
+ BucketIndex bucketIndex);
+
+ ValueInternalLink*& getLastLinkInBucket(BucketIndex bucketIndex);
+
+ Value& setNewItem(const char* key,
+ bool isStatic,
+ ValueInternalLink* link,
+ BucketIndex index);
+
+ Value& unsafeAdd(const char* key, bool isStatic, HashKey hashedKey);
+
+ HashKey hash(const char* key) const;
+
+ int compare(const ValueInternalMap& other) const;
+
+private:
+ void makeBeginIterator(IteratorState& it) const;
+ void makeEndIterator(IteratorState& it) const;
+ static bool equals(const IteratorState& x, const IteratorState& other);
+ static void increment(IteratorState& iterator);
+ static void incrementBucket(IteratorState& iterator);
+ static void decrement(IteratorState& iterator);
+ static const char* key(const IteratorState& iterator);
+ static const char* key(const IteratorState& iterator, bool& isStatic);
+ static Value& value(const IteratorState& iterator);
+ static int distance(const IteratorState& x, const IteratorState& y);
+
+private:
+ ValueInternalLink* buckets_;
+ ValueInternalLink* tailLink_;
+ BucketIndex bucketsSize_;
+ BucketIndex itemCount_;
+};
+
+/** \brief A simplified deque implementation used internally by Value.
+* \internal
+* It is based on a list of fixed "page", each page contains a fixed number of
+*items.
+* Instead of using a linked-list, a array of pointer is used for fast item
+*look-up.
+* Look-up for an element is as follow:
+* - compute page index: pageIndex = itemIndex / itemsPerPage
+* - look-up item in page: pages_[pageIndex][itemIndex % itemsPerPage]
+*
+* Insertion is amortized constant time (only the array containing the index of
+*pointers
+* need to be reallocated when items are appended).
+*/
+class JSON_API ValueInternalArray {
+ friend class Value;
+ friend class ValueIteratorBase;
+
+public:
+ enum {
+ itemsPerPage = 8
+ }; // should be a power of 2 for fast divide and modulo.
+ typedef Value::ArrayIndex ArrayIndex;
+ typedef unsigned int PageIndex;
+
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+ struct IteratorState // Must be a POD
+ {
+ IteratorState() : array_(0), currentPageIndex_(0), currentItemIndex_(0) {}
+ ValueInternalArray* array_;
+ Value** currentPageIndex_;
+ unsigned int currentItemIndex_;
+ };
+#endif // ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+ ValueInternalArray();
+ ValueInternalArray(const ValueInternalArray& other);
+ ValueInternalArray& operator=(ValueInternalArray other);
+ ~ValueInternalArray();
+ void swap(ValueInternalArray& other);
+
+ void clear();
+ void resize(ArrayIndex newSize);
+
+ Value& resolveReference(ArrayIndex index);
+
+ Value* find(ArrayIndex index) const;
+
+ ArrayIndex size() const;
+
+ int compare(const ValueInternalArray& other) const;
+
+private:
+ static bool equals(const IteratorState& x, const IteratorState& other);
+ static void increment(IteratorState& iterator);
+ static void decrement(IteratorState& iterator);
+ static Value& dereference(const IteratorState& iterator);
+ static Value& unsafeDereference(const IteratorState& iterator);
+ static int distance(const IteratorState& x, const IteratorState& y);
+ static ArrayIndex indexOf(const IteratorState& iterator);
+ void makeBeginIterator(IteratorState& it) const;
+ void makeEndIterator(IteratorState& it) const;
+ void makeIterator(IteratorState& it, ArrayIndex index) const;
+
+ void makeIndexValid(ArrayIndex index);
+
+ Value** pages_;
+ ArrayIndex size_;
+ PageIndex pageCount_;
+};
+
+/** \brief Experimental: do not use. Allocator to customize Value internal
+array.
+ * Below is an example of a simple implementation (actual implementation use
+ * memory pool).
+ \code
+class DefaultValueArrayAllocator : public ValueArrayAllocator
+{
+public: // overridden from ValueArrayAllocator
+virtual ~DefaultValueArrayAllocator()
+{
+}
+
+virtual ValueInternalArray *newArray()
+{
+ return new ValueInternalArray();
+}
+
+virtual ValueInternalArray *newArrayCopy( const ValueInternalArray &other )
+{
+ return new ValueInternalArray( other );
+}
+
+virtual void destruct( ValueInternalArray *array )
+{
+ delete array;
+}
+
+virtual void reallocateArrayPageIndex( Value **&indexes,
+ ValueInternalArray::PageIndex
+&indexCount,
+ ValueInternalArray::PageIndex
+minNewIndexCount )
+{
+ ValueInternalArray::PageIndex newIndexCount = (indexCount*3)/2 + 1;
+ if ( minNewIndexCount > newIndexCount )
+ newIndexCount = minNewIndexCount;
+ void *newIndexes = realloc( indexes, sizeof(Value*) * newIndexCount );
+ if ( !newIndexes )
+ throw std::bad_alloc();
+ indexCount = newIndexCount;
+ indexes = static_cast<Value **>( newIndexes );
+}
+virtual void releaseArrayPageIndex( Value **indexes,
+ ValueInternalArray::PageIndex indexCount )
+{
+ if ( indexes )
+ free( indexes );
+}
+
+virtual Value *allocateArrayPage()
+{
+ return static_cast<Value *>( malloc( sizeof(Value) *
+ValueInternalArray::itemsPerPage ) );
+}
+
+virtual void releaseArrayPage( Value *value )
+{
+ if ( value )
+ free( value );
+}
+};
+ \endcode
+ */
+class JSON_API ValueArrayAllocator {
+public:
+ virtual ~ValueArrayAllocator();
+ virtual ValueInternalArray* newArray() = 0;
+ virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) = 0;
+ virtual void destructArray(ValueInternalArray* array) = 0;
+ /** \brief Reallocate array page index.
+ * Reallocates an array of pointer on each page.
+ * \param indexes [input] pointer on the current index. May be \c NULL.
+ * [output] pointer on the new index of at least
+ * \a minNewIndexCount pages.
+ * \param indexCount [input] current number of pages in the index.
+ * [output] number of page the reallocated index can handle.
+ * \b MUST be >= \a minNewIndexCount.
+ * \param minNewIndexCount Minimum number of page the new index must be able
+ * to
+ * handle.
+ */
+ virtual void
+ reallocateArrayPageIndex(Value**& indexes,
+ ValueInternalArray::PageIndex& indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount) = 0;
+ virtual void
+ releaseArrayPageIndex(Value** indexes,
+ ValueInternalArray::PageIndex indexCount) = 0;
+ virtual Value* allocateArrayPage() = 0;
+ virtual void releaseArrayPage(Value* value) = 0;
+};
+#endif // #ifdef JSON_VALUE_USE_INTERNAL_MAP
+
+/** \brief base class for Value iterators.
+ *
+ */
+class JSON_API ValueIteratorBase {
+public:
+ typedef std::bidirectional_iterator_tag iterator_category;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef ValueIteratorBase SelfType;
+
+ ValueIteratorBase();
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIteratorBase(const Value::ObjectValues::iterator& current);
+#else
+ ValueIteratorBase(const ValueInternalArray::IteratorState& state);
+ ValueIteratorBase(const ValueInternalMap::IteratorState& state);
+#endif
+
+ bool operator==(const SelfType& other) const { return isEqual(other); }
+
+ bool operator!=(const SelfType& other) const { return !isEqual(other); }
+
+ difference_type operator-(const SelfType& other) const {
+ return computeDistance(other);
+ }
+
+ /// Return either the index or the member name of the referenced value as a
+ /// Value.
+ Value key() const;
+
+ /// Return the index of the referenced Value. -1 if it is not an arrayValue.
+ UInt index() const;
+
+ /// Return the member name of the referenced Value. "" if it is not an
+ /// objectValue.
+ const char* memberName() const;
+
+protected:
+ Value& deref() const;
+
+ void increment();
+
+ void decrement();
+
+ difference_type computeDistance(const SelfType& other) const;
+
+ bool isEqual(const SelfType& other) const;
+
+ void copy(const SelfType& other);
+
+private:
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ Value::ObjectValues::iterator current_;
+ // Indicates that iterator is for a null value.
+ bool isNull_;
+#else
+ union {
+ ValueInternalArray::IteratorState array_;
+ ValueInternalMap::IteratorState map_;
+ } iterator_;
+ bool isArray_;
+#endif
+};
+
+/** \brief const iterator for object and array value.
+ *
+ */
+class JSON_API ValueConstIterator : public ValueIteratorBase {
+ friend class Value;
+
+public:
+ typedef const Value value_type;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef const Value& reference;
+ typedef const Value* pointer;
+ typedef ValueConstIterator SelfType;
+
+ ValueConstIterator();
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueConstIterator(const Value::ObjectValues::iterator& current);
+#else
+ ValueConstIterator(const ValueInternalArray::IteratorState& state);
+ ValueConstIterator(const ValueInternalMap::IteratorState& state);
+#endif
+public:
+ SelfType& operator=(const ValueIteratorBase& other);
+
+ SelfType operator++(int) {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int) {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType& operator--() {
+ decrement();
+ return *this;
+ }
+
+ SelfType& operator++() {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+/** \brief Iterator for object and array value.
+ */
+class JSON_API ValueIterator : public ValueIteratorBase {
+ friend class Value;
+
+public:
+ typedef Value value_type;
+ typedef unsigned int size_t;
+ typedef int difference_type;
+ typedef Value& reference;
+ typedef Value* pointer;
+ typedef ValueIterator SelfType;
+
+ ValueIterator();
+ ValueIterator(const ValueConstIterator& other);
+ ValueIterator(const ValueIterator& other);
+
+private:
+/*! \internal Use by Value to create an iterator.
+ */
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ explicit ValueIterator(const Value::ObjectValues::iterator& current);
+#else
+ ValueIterator(const ValueInternalArray::IteratorState& state);
+ ValueIterator(const ValueInternalMap::IteratorState& state);
+#endif
+public:
+ SelfType& operator=(const SelfType& other);
+
+ SelfType operator++(int) {
+ SelfType temp(*this);
+ ++*this;
+ return temp;
+ }
+
+ SelfType operator--(int) {
+ SelfType temp(*this);
+ --*this;
+ return temp;
+ }
+
+ SelfType& operator--() {
+ decrement();
+ return *this;
+ }
+
+ SelfType& operator++() {
+ increment();
+ return *this;
+ }
+
+ reference operator*() const { return deref(); }
+
+ pointer operator->() const { return &deref(); }
+};
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // CPPTL_JSON_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/version.h b/Utilities/cmjsoncpp/include/json/version.h
new file mode 100644
index 000000000..6fe06824d
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/version.h
@@ -0,0 +1,14 @@
+// DO NOT EDIT. This file is generated by CMake from "version"
+// and "version.h.in" files.
+// Run CMake configure step to update it.
+#ifndef JSON_VERSION_H_INCLUDED
+# define JSON_VERSION_H_INCLUDED
+
+# define JSONCPP_VERSION_STRING "1.0.0"
+# define JSONCPP_VERSION_MAJOR 1
+# define JSONCPP_VERSION_MINOR 0
+# define JSONCPP_VERSION_PATCH 0
+# define JSONCPP_VERSION_QUALIFIER
+# define JSONCPP_VERSION_HEXA ((JSONCPP_VERSION_MAJOR << 24) | (JSONCPP_VERSION_MINOR << 16) | (JSONCPP_VERSION_PATCH << 8))
+
+#endif // JSON_VERSION_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/include/json/writer.h b/Utilities/cmjsoncpp/include/json/writer.h
new file mode 100644
index 000000000..10863b078
--- /dev/null
+++ b/Utilities/cmjsoncpp/include/json/writer.h
@@ -0,0 +1,213 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSON_WRITER_H_INCLUDED
+#define JSON_WRITER_H_INCLUDED
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include "value.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <iosfwd>
+#include <vector>
+#include <string>
+
+// Disable warning C4251: <data member>: <type> needs to have dll-interface to
+// be used by...
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(push)
+#pragma warning(disable : 4251)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+namespace Json {
+
+class Value;
+
+/** \brief Abstract class for writers.
+ */
+class JSON_API Writer {
+public:
+ virtual ~Writer();
+
+ virtual std::string write(const Value& root) = 0;
+};
+
+/** \brief Outputs a Value in <a HREF="http://www.json.org">JSON</a> format
+ *without formatting (not human friendly).
+ *
+ * The JSON document is written in a single line. It is not intended for 'human'
+ *consumption,
+ * but may be usefull to support feature such as RPC where bandwith is limited.
+ * \sa Reader, Value
+ */
+class JSON_API FastWriter : public Writer {
+public:
+ FastWriter();
+ virtual ~FastWriter() {}
+
+ void enableYAMLCompatibility();
+
+ /** \brief Drop the "null" string from the writer's output for nullValues.
+ * Strictly speaking, this is not valid JSON. But when the output is being
+ * fed to a browser's Javascript, it makes for smaller output and the
+ * browser can handle the output just fine.
+ */
+ void dropNullPlaceholders();
+
+ void omitEndingLineFeed();
+
+public: // overridden from Writer
+ virtual std::string write(const Value& root);
+
+private:
+ void writeValue(const Value& value);
+
+ std::string document_;
+ bool yamlCompatiblityEnabled_;
+ bool dropNullPlaceholders_;
+ bool omitEndingLineFeed_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ *human friendly way.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ *line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ *types,
+ * and all the values fit on one lines, then print the array on a single
+ *line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ *#CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledWriter : public Writer {
+public:
+ StyledWriter();
+ virtual ~StyledWriter() {}
+
+public: // overridden from Writer
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param root Value to serialize.
+ * \return String containing the JSON document that represents the root value.
+ */
+ virtual std::string write(const Value& root);
+
+private:
+ void writeValue(const Value& value);
+ void writeArrayValue(const Value& value);
+ bool isMultineArray(const Value& value);
+ void pushValue(const std::string& value);
+ void writeIndent();
+ void writeWithIndent(const std::string& value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value& root);
+ void writeCommentAfterValueOnSameLine(const Value& root);
+ bool hasCommentForValue(const Value& value);
+ static std::string normalizeEOL(const std::string& text);
+
+ typedef std::vector<std::string> ChildValues;
+
+ ChildValues childValues_;
+ std::string document_;
+ std::string indentString_;
+ int rightMargin_;
+ int indentSize_;
+ bool addChildValues_;
+};
+
+/** \brief Writes a Value in <a HREF="http://www.json.org">JSON</a> format in a
+ human friendly way,
+ to a stream rather than to a string.
+ *
+ * The rules for line break and indent are as follow:
+ * - Object value:
+ * - if empty then print {} without indent and line break
+ * - if not empty the print '{', line break & indent, print one value per
+ line
+ * and then unindent and line break and print '}'.
+ * - Array value:
+ * - if empty then print [] without indent and line break
+ * - if the array contains no object value, empty array or some other value
+ types,
+ * and all the values fit on one lines, then print the array on a single
+ line.
+ * - otherwise, it the values do not fit on one line, or the array contains
+ * object or non empty array, then print one value per line.
+ *
+ * If the Value have comments then they are outputed according to their
+ #CommentPlacement.
+ *
+ * \sa Reader, Value, Value::setComment()
+ */
+class JSON_API StyledStreamWriter {
+public:
+ StyledStreamWriter(std::string indentation = "\t");
+ ~StyledStreamWriter() {}
+
+public:
+ /** \brief Serialize a Value in <a HREF="http://www.json.org">JSON</a> format.
+ * \param out Stream to write to. (Can be ostringstream, e.g.)
+ * \param root Value to serialize.
+ * \note There is no point in deriving from Writer, since write() should not
+ * return a value.
+ */
+ void write(std::ostream& out, const Value& root);
+
+private:
+ void writeValue(const Value& value);
+ void writeArrayValue(const Value& value);
+ bool isMultineArray(const Value& value);
+ void pushValue(const std::string& value);
+ void writeIndent();
+ void writeWithIndent(const std::string& value);
+ void indent();
+ void unindent();
+ void writeCommentBeforeValue(const Value& root);
+ void writeCommentAfterValueOnSameLine(const Value& root);
+ bool hasCommentForValue(const Value& value);
+ static std::string normalizeEOL(const std::string& text);
+
+ typedef std::vector<std::string> ChildValues;
+
+ ChildValues childValues_;
+ std::ostream* document_;
+ std::string indentString_;
+ int rightMargin_;
+ std::string indentation_;
+ bool addChildValues_;
+};
+
+#if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(Int value);
+std::string JSON_API valueToString(UInt value);
+#endif // if defined(JSON_HAS_INT64)
+std::string JSON_API valueToString(LargestInt value);
+std::string JSON_API valueToString(LargestUInt value);
+std::string JSON_API valueToString(double value);
+std::string JSON_API valueToString(bool value);
+std::string JSON_API valueToQuotedString(const char* value);
+
+/// \brief Output using the StyledStreamWriter.
+/// \see Json::operator>>()
+JSON_API std::ostream& operator<<(std::ostream&, const Value& root);
+
+} // namespace Json
+
+#if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+#pragma warning(pop)
+#endif // if defined(JSONCPP_DISABLE_DLL_INTERFACE_WARNING)
+
+#endif // JSON_WRITER_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h b/Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h
new file mode 100644
index 000000000..2fbef7a86
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_batchallocator.h
@@ -0,0 +1,121 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef JSONCPP_BATCHALLOCATOR_H_INCLUDED
+#define JSONCPP_BATCHALLOCATOR_H_INCLUDED
+
+#include <stdlib.h>
+#include <assert.h>
+
+#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
+
+namespace Json {
+
+/* Fast memory allocator.
+ *
+ * This memory allocator allocates memory for a batch of object (specified by
+ * the page size, the number of object in each page).
+ *
+ * It does not allow the destruction of a single object. All the allocated
+ * objects can be destroyed at once. The memory can be either released or reused
+ * for future allocation.
+ *
+ * The in-place new operator must be used to construct the object using the
+ * pointer returned by allocate.
+ */
+template <typename AllocatedType, const unsigned int objectPerAllocation>
+class BatchAllocator {
+public:
+ BatchAllocator(unsigned int objectsPerPage = 255)
+ : freeHead_(0), objectsPerPage_(objectsPerPage) {
+ // printf( "Size: %d => %s\n", sizeof(AllocatedType),
+ // typeid(AllocatedType).name() );
+ assert(sizeof(AllocatedType) * objectPerAllocation >=
+ sizeof(AllocatedType*)); // We must be able to store a slist in the
+ // object free space.
+ assert(objectsPerPage >= 16);
+ batches_ = allocateBatch(0); // allocated a dummy page
+ currentBatch_ = batches_;
+ }
+
+ ~BatchAllocator() {
+ for (BatchInfo* batch = batches_; batch;) {
+ BatchInfo* nextBatch = batch->next_;
+ free(batch);
+ batch = nextBatch;
+ }
+ }
+
+ /// allocate space for an array of objectPerAllocation object.
+ /// @warning it is the responsability of the caller to call objects
+ /// constructors.
+ AllocatedType* allocate() {
+ if (freeHead_) // returns node from free list.
+ {
+ AllocatedType* object = freeHead_;
+ freeHead_ = *(AllocatedType**)object;
+ return object;
+ }
+ if (currentBatch_->used_ == currentBatch_->end_) {
+ currentBatch_ = currentBatch_->next_;
+ while (currentBatch_ && currentBatch_->used_ == currentBatch_->end_)
+ currentBatch_ = currentBatch_->next_;
+
+ if (!currentBatch_) // no free batch found, allocate a new one
+ {
+ currentBatch_ = allocateBatch(objectsPerPage_);
+ currentBatch_->next_ = batches_; // insert at the head of the list
+ batches_ = currentBatch_;
+ }
+ }
+ AllocatedType* allocated = currentBatch_->used_;
+ currentBatch_->used_ += objectPerAllocation;
+ return allocated;
+ }
+
+ /// Release the object.
+ /// @warning it is the responsability of the caller to actually destruct the
+ /// object.
+ void release(AllocatedType* object) {
+ assert(object != 0);
+ *(AllocatedType**)object = freeHead_;
+ freeHead_ = object;
+ }
+
+private:
+ struct BatchInfo {
+ BatchInfo* next_;
+ AllocatedType* used_;
+ AllocatedType* end_;
+ AllocatedType buffer_[objectPerAllocation];
+ };
+
+ // disabled copy constructor and assignement operator.
+ BatchAllocator(const BatchAllocator&);
+ void operator=(const BatchAllocator&);
+
+ static BatchInfo* allocateBatch(unsigned int objectsPerPage) {
+ const unsigned int mallocSize =
+ sizeof(BatchInfo) - sizeof(AllocatedType) * objectPerAllocation +
+ sizeof(AllocatedType) * objectPerAllocation * objectsPerPage;
+ BatchInfo* batch = static_cast<BatchInfo*>(malloc(mallocSize));
+ batch->next_ = 0;
+ batch->used_ = batch->buffer_;
+ batch->end_ = batch->buffer_ + objectsPerPage;
+ return batch;
+ }
+
+ BatchInfo* batches_;
+ BatchInfo* currentBatch_;
+ /// Head of a single linked list within the allocated space of freeed object
+ AllocatedType* freeHead_;
+ unsigned int objectsPerPage_;
+};
+
+} // namespace Json
+
+#endif // ifndef JSONCPP_DOC_INCLUDE_IMPLEMENTATION
+
+#endif // JSONCPP_BATCHALLOCATOR_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl b/Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl
new file mode 100644
index 000000000..9ee15e9db
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_internalarray.inl
@@ -0,0 +1,360 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueArrayAllocator::~ValueArrayAllocator() {}
+
+// //////////////////////////////////////////////////////////////////
+// class DefaultValueArrayAllocator
+// //////////////////////////////////////////////////////////////////
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueArrayAllocator : public ValueArrayAllocator {
+public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator() {}
+
+ virtual ValueInternalArray* newArray() { return new ValueInternalArray(); }
+
+ virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
+ return new ValueInternalArray(other);
+ }
+
+ virtual void destructArray(ValueInternalArray* array) { delete array; }
+
+ virtual void
+ reallocateArrayPageIndex(Value**& indexes,
+ ValueInternalArray::PageIndex& indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount) {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
+ if (minNewIndexCount > newIndexCount)
+ newIndexCount = minNewIndexCount;
+ void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
+ JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+ indexCount = newIndexCount;
+ indexes = static_cast<Value**>(newIndexes);
+ }
+ virtual void releaseArrayPageIndex(Value** indexes,
+ ValueInternalArray::PageIndex indexCount) {
+ if (indexes)
+ free(indexes);
+ }
+
+ virtual Value* allocateArrayPage() {
+ return static_cast<Value*>(
+ malloc(sizeof(Value) * ValueInternalArray::itemsPerPage));
+ }
+
+ virtual void releaseArrayPage(Value* value) {
+ if (value)
+ free(value);
+ }
+};
+
+#else // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueArrayAllocator : public ValueArrayAllocator {
+public: // overridden from ValueArrayAllocator
+ virtual ~DefaultValueArrayAllocator() {}
+
+ virtual ValueInternalArray* newArray() {
+ ValueInternalArray* array = arraysAllocator_.allocate();
+ new (array) ValueInternalArray(); // placement new
+ return array;
+ }
+
+ virtual ValueInternalArray* newArrayCopy(const ValueInternalArray& other) {
+ ValueInternalArray* array = arraysAllocator_.allocate();
+ new (array) ValueInternalArray(other); // placement new
+ return array;
+ }
+
+ virtual void destructArray(ValueInternalArray* array) {
+ if (array) {
+ array->~ValueInternalArray();
+ arraysAllocator_.release(array);
+ }
+ }
+
+ virtual void
+ reallocateArrayPageIndex(Value**& indexes,
+ ValueInternalArray::PageIndex& indexCount,
+ ValueInternalArray::PageIndex minNewIndexCount) {
+ ValueInternalArray::PageIndex newIndexCount = (indexCount * 3) / 2 + 1;
+ if (minNewIndexCount > newIndexCount)
+ newIndexCount = minNewIndexCount;
+ void* newIndexes = realloc(indexes, sizeof(Value*) * newIndexCount);
+ JSON_ASSERT_MESSAGE(newIndexes, "Couldn't realloc.");
+ indexCount = newIndexCount;
+ indexes = static_cast<Value**>(newIndexes);
+ }
+ virtual void releaseArrayPageIndex(Value** indexes,
+ ValueInternalArray::PageIndex indexCount) {
+ if (indexes)
+ free(indexes);
+ }
+
+ virtual Value* allocateArrayPage() {
+ return static_cast<Value*>(pagesAllocator_.allocate());
+ }
+
+ virtual void releaseArrayPage(Value* value) {
+ if (value)
+ pagesAllocator_.release(value);
+ }
+
+private:
+ BatchAllocator<ValueInternalArray, 1> arraysAllocator_;
+ BatchAllocator<Value, ValueInternalArray::itemsPerPage> pagesAllocator_;
+};
+#endif // #ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+
+static ValueArrayAllocator*& arrayAllocator() {
+ static DefaultValueArrayAllocator defaultAllocator;
+ static ValueArrayAllocator* arrayAllocator = &defaultAllocator;
+ return arrayAllocator;
+}
+
+static struct DummyArrayAllocatorInitializer {
+ DummyArrayAllocatorInitializer() {
+ arrayAllocator(); // ensure arrayAllocator() statics are initialized before
+ // main().
+ }
+} dummyArrayAllocatorInitializer;
+
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalArray
+// //////////////////////////////////////////////////////////////////
+bool ValueInternalArray::equals(const IteratorState& x,
+ const IteratorState& other) {
+ return x.array_ == other.array_ &&
+ x.currentItemIndex_ == other.currentItemIndex_ &&
+ x.currentPageIndex_ == other.currentPageIndex_;
+}
+
+void ValueInternalArray::increment(IteratorState& it) {
+ JSON_ASSERT_MESSAGE(
+ it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
+ it.currentItemIndex_ !=
+ it.array_->size_,
+ "ValueInternalArray::increment(): moving iterator beyond end");
+ ++(it.currentItemIndex_);
+ if (it.currentItemIndex_ == itemsPerPage) {
+ it.currentItemIndex_ = 0;
+ ++(it.currentPageIndex_);
+ }
+}
+
+void ValueInternalArray::decrement(IteratorState& it) {
+ JSON_ASSERT_MESSAGE(
+ it.array_ && it.currentPageIndex_ == it.array_->pages_ &&
+ it.currentItemIndex_ == 0,
+ "ValueInternalArray::decrement(): moving iterator beyond end");
+ if (it.currentItemIndex_ == 0) {
+ it.currentItemIndex_ = itemsPerPage - 1;
+ --(it.currentPageIndex_);
+ } else {
+ --(it.currentItemIndex_);
+ }
+}
+
+Value& ValueInternalArray::unsafeDereference(const IteratorState& it) {
+ return (*(it.currentPageIndex_))[it.currentItemIndex_];
+}
+
+Value& ValueInternalArray::dereference(const IteratorState& it) {
+ JSON_ASSERT_MESSAGE(
+ it.array_ && (it.currentPageIndex_ - it.array_->pages_) * itemsPerPage +
+ it.currentItemIndex_ <
+ it.array_->size_,
+ "ValueInternalArray::dereference(): dereferencing invalid iterator");
+ return unsafeDereference(it);
+}
+
+void ValueInternalArray::makeBeginIterator(IteratorState& it) const {
+ it.array_ = const_cast<ValueInternalArray*>(this);
+ it.currentItemIndex_ = 0;
+ it.currentPageIndex_ = pages_;
+}
+
+void ValueInternalArray::makeIterator(IteratorState& it,
+ ArrayIndex index) const {
+ it.array_ = const_cast<ValueInternalArray*>(this);
+ it.currentItemIndex_ = index % itemsPerPage;
+ it.currentPageIndex_ = pages_ + index / itemsPerPage;
+}
+
+void ValueInternalArray::makeEndIterator(IteratorState& it) const {
+ makeIterator(it, size_);
+}
+
+ValueInternalArray::ValueInternalArray() : pages_(0), size_(0), pageCount_(0) {}
+
+ValueInternalArray::ValueInternalArray(const ValueInternalArray& other)
+ : pages_(0), size_(other.size_), pageCount_(0) {
+ PageIndex minNewPages = other.size_ / itemsPerPage;
+ arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
+ JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
+ "ValueInternalArray::reserve(): bad reallocation");
+ IteratorState itOther;
+ other.makeBeginIterator(itOther);
+ Value* value;
+ for (ArrayIndex index = 0; index < size_; ++index, increment(itOther)) {
+ if (index % itemsPerPage == 0) {
+ PageIndex pageIndex = index / itemsPerPage;
+ value = arrayAllocator()->allocateArrayPage();
+ pages_[pageIndex] = value;
+ }
+ new (value) Value(dereference(itOther));
+ }
+}
+
+ValueInternalArray& ValueInternalArray::operator=(ValueInternalArray other) {
+ swap(other);
+ return *this;
+}
+
+ValueInternalArray::~ValueInternalArray() {
+ // destroy all constructed items
+ IteratorState it;
+ IteratorState itEnd;
+ makeBeginIterator(it);
+ makeEndIterator(itEnd);
+ for (; !equals(it, itEnd); increment(it)) {
+ Value* value = &dereference(it);
+ value->~Value();
+ }
+ // release all pages
+ PageIndex lastPageIndex = size_ / itemsPerPage;
+ for (PageIndex pageIndex = 0; pageIndex < lastPageIndex; ++pageIndex)
+ arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
+ // release pages index
+ arrayAllocator()->releaseArrayPageIndex(pages_, pageCount_);
+}
+
+void ValueInternalArray::swap(ValueInternalArray& other) {
+ Value** tempPages = pages_;
+ pages_ = other.pages_;
+ other.pages_ = tempPages;
+ ArrayIndex tempSize = size_;
+ size_ = other.size_;
+ other.size_ = tempSize;
+ PageIndex tempPageCount = pageCount_;
+ pageCount_ = other.pageCount_;
+ other.pageCount_ = tempPageCount;
+}
+
+void ValueInternalArray::clear() {
+ ValueInternalArray dummy;
+ swap(dummy);
+}
+
+void ValueInternalArray::resize(ArrayIndex newSize) {
+ if (newSize == 0)
+ clear();
+ else if (newSize < size_) {
+ IteratorState it;
+ IteratorState itEnd;
+ makeIterator(it, newSize);
+ makeIterator(itEnd, size_);
+ for (; !equals(it, itEnd); increment(it)) {
+ Value* value = &dereference(it);
+ value->~Value();
+ }
+ PageIndex pageIndex = (newSize + itemsPerPage - 1) / itemsPerPage;
+ PageIndex lastPageIndex = size_ / itemsPerPage;
+ for (; pageIndex < lastPageIndex; ++pageIndex)
+ arrayAllocator()->releaseArrayPage(pages_[pageIndex]);
+ size_ = newSize;
+ } else if (newSize > size_)
+ resolveReference(newSize);
+}
+
+void ValueInternalArray::makeIndexValid(ArrayIndex index) {
+ // Need to enlarge page index ?
+ if (index >= pageCount_ * itemsPerPage) {
+ PageIndex minNewPages = (index + 1) / itemsPerPage;
+ arrayAllocator()->reallocateArrayPageIndex(pages_, pageCount_, minNewPages);
+ JSON_ASSERT_MESSAGE(pageCount_ >= minNewPages,
+ "ValueInternalArray::reserve(): bad reallocation");
+ }
+
+ // Need to allocate new pages ?
+ ArrayIndex nextPageIndex = (size_ % itemsPerPage) != 0
+ ? size_ - (size_ % itemsPerPage) + itemsPerPage
+ : size_;
+ if (nextPageIndex <= index) {
+ PageIndex pageIndex = nextPageIndex / itemsPerPage;
+ PageIndex pageToAllocate = (index - nextPageIndex) / itemsPerPage + 1;
+ for (; pageToAllocate-- > 0; ++pageIndex)
+ pages_[pageIndex] = arrayAllocator()->allocateArrayPage();
+ }
+
+ // Initialize all new entries
+ IteratorState it;
+ IteratorState itEnd;
+ makeIterator(it, size_);
+ size_ = index + 1;
+ makeIterator(itEnd, size_);
+ for (; !equals(it, itEnd); increment(it)) {
+ Value* value = &dereference(it);
+ new (value) Value(); // Construct a default value using placement new
+ }
+}
+
+Value& ValueInternalArray::resolveReference(ArrayIndex index) {
+ if (index >= size_)
+ makeIndexValid(index);
+ return pages_[index / itemsPerPage][index % itemsPerPage];
+}
+
+Value* ValueInternalArray::find(ArrayIndex index) const {
+ if (index >= size_)
+ return 0;
+ return &(pages_[index / itemsPerPage][index % itemsPerPage]);
+}
+
+ValueInternalArray::ArrayIndex ValueInternalArray::size() const {
+ return size_;
+}
+
+int ValueInternalArray::distance(const IteratorState& x,
+ const IteratorState& y) {
+ return indexOf(y) - indexOf(x);
+}
+
+ValueInternalArray::ArrayIndex
+ValueInternalArray::indexOf(const IteratorState& iterator) {
+ if (!iterator.array_)
+ return ArrayIndex(-1);
+ return ArrayIndex((iterator.currentPageIndex_ - iterator.array_->pages_) *
+ itemsPerPage +
+ iterator.currentItemIndex_);
+}
+
+int ValueInternalArray::compare(const ValueInternalArray& other) const {
+ int sizeDiff(size_ - other.size_);
+ if (sizeDiff != 0)
+ return sizeDiff;
+
+ for (ArrayIndex index = 0; index < size_; ++index) {
+ int diff = pages_[index / itemsPerPage][index % itemsPerPage].compare(
+ other.pages_[index / itemsPerPage][index % itemsPerPage]);
+ if (diff != 0)
+ return diff;
+ }
+ return 0;
+}
+
+} // namespace Json
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl b/Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl
new file mode 100644
index 000000000..ef3f3302d
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_internalmap.inl
@@ -0,0 +1,473 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueInternalMap
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/** \internal MUST be safely initialized using memset( this, 0,
+ * sizeof(ValueInternalLink) );
+ * This optimization is used by the fast allocator.
+ */
+ValueInternalLink::ValueInternalLink() : previous_(0), next_(0) {}
+
+ValueInternalLink::~ValueInternalLink() {
+ for (int index = 0; index < itemPerLink; ++index) {
+ if (!items_[index].isItemAvailable()) {
+ if (!items_[index].isMemberNameStatic())
+ free(keys_[index]);
+ } else
+ break;
+ }
+}
+
+ValueMapAllocator::~ValueMapAllocator() {}
+
+#ifdef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+class DefaultValueMapAllocator : public ValueMapAllocator {
+public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap* newMap() { return new ValueInternalMap(); }
+
+ virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
+ return new ValueInternalMap(other);
+ }
+
+ virtual void destructMap(ValueInternalMap* map) { delete map; }
+
+ virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
+
+ virtual ValueInternalLink* allocateMapLink() {
+ return new ValueInternalLink();
+ }
+
+ virtual void releaseMapLink(ValueInternalLink* link) { delete link; }
+};
+#else
+/// @todo make this thread-safe (lock when accessign batch allocator)
+class DefaultValueMapAllocator : public ValueMapAllocator {
+public: // overridden from ValueMapAllocator
+ virtual ValueInternalMap* newMap() {
+ ValueInternalMap* map = mapsAllocator_.allocate();
+ new (map) ValueInternalMap(); // placement new
+ return map;
+ }
+
+ virtual ValueInternalMap* newMapCopy(const ValueInternalMap& other) {
+ ValueInternalMap* map = mapsAllocator_.allocate();
+ new (map) ValueInternalMap(other); // placement new
+ return map;
+ }
+
+ virtual void destructMap(ValueInternalMap* map) {
+ if (map) {
+ map->~ValueInternalMap();
+ mapsAllocator_.release(map);
+ }
+ }
+
+ virtual ValueInternalLink* allocateMapBuckets(unsigned int size) {
+ return new ValueInternalLink[size];
+ }
+
+ virtual void releaseMapBuckets(ValueInternalLink* links) { delete[] links; }
+
+ virtual ValueInternalLink* allocateMapLink() {
+ ValueInternalLink* link = linksAllocator_.allocate();
+ memset(link, 0, sizeof(ValueInternalLink));
+ return link;
+ }
+
+ virtual void releaseMapLink(ValueInternalLink* link) {
+ link->~ValueInternalLink();
+ linksAllocator_.release(link);
+ }
+
+private:
+ BatchAllocator<ValueInternalMap, 1> mapsAllocator_;
+ BatchAllocator<ValueInternalLink, 1> linksAllocator_;
+};
+#endif
+
+static ValueMapAllocator*& mapAllocator() {
+ static DefaultValueMapAllocator defaultAllocator;
+ static ValueMapAllocator* mapAllocator = &defaultAllocator;
+ return mapAllocator;
+}
+
+static struct DummyMapAllocatorInitializer {
+ DummyMapAllocatorInitializer() {
+ mapAllocator(); // ensure mapAllocator() statics are initialized before
+ // main().
+ }
+} dummyMapAllocatorInitializer;
+
+// h(K) = value * K >> w ; with w = 32 & K prime w.r.t. 2^32.
+
+/*
+use linked list hash map.
+buckets array is a container.
+linked list element contains 6 key/values. (memory = (16+4) * 6 + 4 = 124)
+value have extra state: valid, available, deleted
+*/
+
+ValueInternalMap::ValueInternalMap()
+ : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {}
+
+ValueInternalMap::ValueInternalMap(const ValueInternalMap& other)
+ : buckets_(0), tailLink_(0), bucketsSize_(0), itemCount_(0) {
+ reserve(other.itemCount_);
+ IteratorState it;
+ IteratorState itEnd;
+ other.makeBeginIterator(it);
+ other.makeEndIterator(itEnd);
+ for (; !equals(it, itEnd); increment(it)) {
+ bool isStatic;
+ const char* memberName = key(it, isStatic);
+ const Value& aValue = value(it);
+ resolveReference(memberName, isStatic) = aValue;
+ }
+}
+
+ValueInternalMap& ValueInternalMap::operator=(ValueInternalMap other) {
+ swap(other);
+ return *this;
+}
+
+ValueInternalMap::~ValueInternalMap() {
+ if (buckets_) {
+ for (BucketIndex bucketIndex = 0; bucketIndex < bucketsSize_;
+ ++bucketIndex) {
+ ValueInternalLink* link = buckets_[bucketIndex].next_;
+ while (link) {
+ ValueInternalLink* linkToRelease = link;
+ link = link->next_;
+ mapAllocator()->releaseMapLink(linkToRelease);
+ }
+ }
+ mapAllocator()->releaseMapBuckets(buckets_);
+ }
+}
+
+void ValueInternalMap::swap(ValueInternalMap& other) {
+ ValueInternalLink* tempBuckets = buckets_;
+ buckets_ = other.buckets_;
+ other.buckets_ = tempBuckets;
+ ValueInternalLink* tempTailLink = tailLink_;
+ tailLink_ = other.tailLink_;
+ other.tailLink_ = tempTailLink;
+ BucketIndex tempBucketsSize = bucketsSize_;
+ bucketsSize_ = other.bucketsSize_;
+ other.bucketsSize_ = tempBucketsSize;
+ BucketIndex tempItemCount = itemCount_;
+ itemCount_ = other.itemCount_;
+ other.itemCount_ = tempItemCount;
+}
+
+void ValueInternalMap::clear() {
+ ValueInternalMap dummy;
+ swap(dummy);
+}
+
+ValueInternalMap::BucketIndex ValueInternalMap::size() const {
+ return itemCount_;
+}
+
+bool ValueInternalMap::reserveDelta(BucketIndex growth) {
+ return reserve(itemCount_ + growth);
+}
+
+bool ValueInternalMap::reserve(BucketIndex newItemCount) {
+ if (!buckets_ && newItemCount > 0) {
+ buckets_ = mapAllocator()->allocateMapBuckets(1);
+ bucketsSize_ = 1;
+ tailLink_ = &buckets_[0];
+ }
+ // BucketIndex idealBucketCount = (newItemCount +
+ // ValueInternalLink::itemPerLink) / ValueInternalLink::itemPerLink;
+ return true;
+}
+
+const Value* ValueInternalMap::find(const char* key) const {
+ if (!bucketsSize_)
+ return 0;
+ HashKey hashedKey = hash(key);
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for (const ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
+ current = current->next_) {
+ for (BucketIndex index = 0; index < ValueInternalLink::itemPerLink;
+ ++index) {
+ if (current->items_[index].isItemAvailable())
+ return 0;
+ if (strcmp(key, current->keys_[index]) == 0)
+ return &current->items_[index];
+ }
+ }
+ return 0;
+}
+
+Value* ValueInternalMap::find(const char* key) {
+ const ValueInternalMap* constThis = this;
+ return const_cast<Value*>(constThis->find(key));
+}
+
+Value& ValueInternalMap::resolveReference(const char* key, bool isStatic) {
+ HashKey hashedKey = hash(key);
+ if (bucketsSize_) {
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ ValueInternalLink** previous = 0;
+ BucketIndex index;
+ for (ValueInternalLink* current = &buckets_[bucketIndex]; current != 0;
+ previous = &current->next_, current = current->next_) {
+ for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
+ if (current->items_[index].isItemAvailable())
+ return setNewItem(key, isStatic, current, index);
+ if (strcmp(key, current->keys_[index]) == 0)
+ return current->items_[index];
+ }
+ }
+ }
+
+ reserveDelta(1);
+ return unsafeAdd(key, isStatic, hashedKey);
+}
+
+void ValueInternalMap::remove(const char* key) {
+ HashKey hashedKey = hash(key);
+ if (!bucketsSize_)
+ return;
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ for (ValueInternalLink* link = &buckets_[bucketIndex]; link != 0;
+ link = link->next_) {
+ BucketIndex index;
+ for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
+ if (link->items_[index].isItemAvailable())
+ return;
+ if (strcmp(key, link->keys_[index]) == 0) {
+ doActualRemove(link, index, bucketIndex);
+ return;
+ }
+ }
+ }
+}
+
+void ValueInternalMap::doActualRemove(ValueInternalLink* link,
+ BucketIndex index,
+ BucketIndex bucketIndex) {
+ // find last item of the bucket and swap it with the 'removed' one.
+ // set removed items flags to 'available'.
+ // if last page only contains 'available' items, then desallocate it (it's
+ // empty)
+ ValueInternalLink*& lastLink = getLastLinkInBucket(index);
+ BucketIndex lastItemIndex = 1; // a link can never be empty, so start at 1
+ for (; lastItemIndex < ValueInternalLink::itemPerLink;
+ ++lastItemIndex) // may be optimized with dicotomic search
+ {
+ if (lastLink->items_[lastItemIndex].isItemAvailable())
+ break;
+ }
+
+ BucketIndex lastUsedIndex = lastItemIndex - 1;
+ Value* valueToDelete = &link->items_[index];
+ Value* valueToPreserve = &lastLink->items_[lastUsedIndex];
+ if (valueToDelete != valueToPreserve)
+ valueToDelete->swap(*valueToPreserve);
+ if (lastUsedIndex == 0) // page is now empty
+ { // remove it from bucket linked list and delete it.
+ ValueInternalLink* linkPreviousToLast = lastLink->previous_;
+ if (linkPreviousToLast != 0) // can not deleted bucket link.
+ {
+ mapAllocator()->releaseMapLink(lastLink);
+ linkPreviousToLast->next_ = 0;
+ lastLink = linkPreviousToLast;
+ }
+ } else {
+ Value dummy;
+ valueToPreserve->swap(dummy); // restore deleted to default Value.
+ valueToPreserve->setItemUsed(false);
+ }
+ --itemCount_;
+}
+
+ValueInternalLink*&
+ValueInternalMap::getLastLinkInBucket(BucketIndex bucketIndex) {
+ if (bucketIndex == bucketsSize_ - 1)
+ return tailLink_;
+ ValueInternalLink*& previous = buckets_[bucketIndex + 1].previous_;
+ if (!previous)
+ previous = &buckets_[bucketIndex];
+ return previous;
+}
+
+Value& ValueInternalMap::setNewItem(const char* key,
+ bool isStatic,
+ ValueInternalLink* link,
+ BucketIndex index) {
+ char* duplicatedKey = makeMemberName(key);
+ ++itemCount_;
+ link->keys_[index] = duplicatedKey;
+ link->items_[index].setItemUsed();
+ link->items_[index].setMemberNameIsStatic(isStatic);
+ return link->items_[index]; // items already default constructed.
+}
+
+Value&
+ValueInternalMap::unsafeAdd(const char* key, bool isStatic, HashKey hashedKey) {
+ JSON_ASSERT_MESSAGE(bucketsSize_ > 0,
+ "ValueInternalMap::unsafeAdd(): internal logic error.");
+ BucketIndex bucketIndex = hashedKey % bucketsSize_;
+ ValueInternalLink*& previousLink = getLastLinkInBucket(bucketIndex);
+ ValueInternalLink* link = previousLink;
+ BucketIndex index;
+ for (index = 0; index < ValueInternalLink::itemPerLink; ++index) {
+ if (link->items_[index].isItemAvailable())
+ break;
+ }
+ if (index == ValueInternalLink::itemPerLink) // need to add a new page
+ {
+ ValueInternalLink* newLink = mapAllocator()->allocateMapLink();
+ index = 0;
+ link->next_ = newLink;
+ previousLink = newLink;
+ link = newLink;
+ }
+ return setNewItem(key, isStatic, link, index);
+}
+
+ValueInternalMap::HashKey ValueInternalMap::hash(const char* key) const {
+ HashKey hash = 0;
+ while (*key)
+ hash += *key++ * 37;
+ return hash;
+}
+
+int ValueInternalMap::compare(const ValueInternalMap& other) const {
+ int sizeDiff(itemCount_ - other.itemCount_);
+ if (sizeDiff != 0)
+ return sizeDiff;
+ // Strict order guaranty is required. Compare all keys FIRST, then compare
+ // values.
+ IteratorState it;
+ IteratorState itEnd;
+ makeBeginIterator(it);
+ makeEndIterator(itEnd);
+ for (; !equals(it, itEnd); increment(it)) {
+ if (!other.find(key(it)))
+ return 1;
+ }
+
+ // All keys are equals, let's compare values
+ makeBeginIterator(it);
+ for (; !equals(it, itEnd); increment(it)) {
+ const Value* otherValue = other.find(key(it));
+ int valueDiff = value(it).compare(*otherValue);
+ if (valueDiff != 0)
+ return valueDiff;
+ }
+ return 0;
+}
+
+void ValueInternalMap::makeBeginIterator(IteratorState& it) const {
+ it.map_ = const_cast<ValueInternalMap*>(this);
+ it.bucketIndex_ = 0;
+ it.itemIndex_ = 0;
+ it.link_ = buckets_;
+}
+
+void ValueInternalMap::makeEndIterator(IteratorState& it) const {
+ it.map_ = const_cast<ValueInternalMap*>(this);
+ it.bucketIndex_ = bucketsSize_;
+ it.itemIndex_ = 0;
+ it.link_ = 0;
+}
+
+bool ValueInternalMap::equals(const IteratorState& x,
+ const IteratorState& other) {
+ return x.map_ == other.map_ && x.bucketIndex_ == other.bucketIndex_ &&
+ x.link_ == other.link_ && x.itemIndex_ == other.itemIndex_;
+}
+
+void ValueInternalMap::incrementBucket(IteratorState& iterator) {
+ ++iterator.bucketIndex_;
+ JSON_ASSERT_MESSAGE(
+ iterator.bucketIndex_ <= iterator.map_->bucketsSize_,
+ "ValueInternalMap::increment(): attempting to iterate beyond end.");
+ if (iterator.bucketIndex_ == iterator.map_->bucketsSize_)
+ iterator.link_ = 0;
+ else
+ iterator.link_ = &(iterator.map_->buckets_[iterator.bucketIndex_]);
+ iterator.itemIndex_ = 0;
+}
+
+void ValueInternalMap::increment(IteratorState& iterator) {
+ JSON_ASSERT_MESSAGE(iterator.map_,
+ "Attempting to iterator using invalid iterator.");
+ ++iterator.itemIndex_;
+ if (iterator.itemIndex_ == ValueInternalLink::itemPerLink) {
+ JSON_ASSERT_MESSAGE(
+ iterator.link_ != 0,
+ "ValueInternalMap::increment(): attempting to iterate beyond end.");
+ iterator.link_ = iterator.link_->next_;
+ if (iterator.link_ == 0)
+ incrementBucket(iterator);
+ } else if (iterator.link_->items_[iterator.itemIndex_].isItemAvailable()) {
+ incrementBucket(iterator);
+ }
+}
+
+void ValueInternalMap::decrement(IteratorState& iterator) {
+ if (iterator.itemIndex_ == 0) {
+ JSON_ASSERT_MESSAGE(iterator.map_,
+ "Attempting to iterate using invalid iterator.");
+ if (iterator.link_ == &iterator.map_->buckets_[iterator.bucketIndex_]) {
+ JSON_ASSERT_MESSAGE(iterator.bucketIndex_ > 0,
+ "Attempting to iterate beyond beginning.");
+ --(iterator.bucketIndex_);
+ }
+ iterator.link_ = iterator.link_->previous_;
+ iterator.itemIndex_ = ValueInternalLink::itemPerLink - 1;
+ }
+}
+
+const char* ValueInternalMap::key(const IteratorState& iterator) {
+ JSON_ASSERT_MESSAGE(iterator.link_,
+ "Attempting to iterate using invalid iterator.");
+ return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+const char* ValueInternalMap::key(const IteratorState& iterator,
+ bool& isStatic) {
+ JSON_ASSERT_MESSAGE(iterator.link_,
+ "Attempting to iterate using invalid iterator.");
+ isStatic = iterator.link_->items_[iterator.itemIndex_].isMemberNameStatic();
+ return iterator.link_->keys_[iterator.itemIndex_];
+}
+
+Value& ValueInternalMap::value(const IteratorState& iterator) {
+ JSON_ASSERT_MESSAGE(iterator.link_,
+ "Attempting to iterate using invalid iterator.");
+ return iterator.link_->items_[iterator.itemIndex_];
+}
+
+int ValueInternalMap::distance(const IteratorState& x, const IteratorState& y) {
+ int offset = 0;
+ IteratorState it = x;
+ while (!equals(it, y))
+ increment(it);
+ return offset;
+}
+
+} // namespace Json
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp b/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
new file mode 100644
index 000000000..7b338285c
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_reader.cpp
@@ -0,0 +1,885 @@
+// Copyright 2007-2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/reader.h>
+#include <json/value.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include <istream>
+
+#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
+#define snprintf _snprintf
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+// Implementation of class Features
+// ////////////////////////////////
+
+Features::Features()
+ : allowComments_(true), strictRoot_(false),
+ allowDroppedNullPlaceholders_(false), allowNumericKeys_(false) {}
+
+Features Features::all() { return Features(); }
+
+Features Features::strictMode() {
+ Features features;
+ features.allowComments_ = false;
+ features.strictRoot_ = true;
+ features.allowDroppedNullPlaceholders_ = false;
+ features.allowNumericKeys_ = false;
+ return features;
+}
+
+// Implementation of class Reader
+// ////////////////////////////////
+
+static inline bool in(Reader::Char c,
+ Reader::Char c1,
+ Reader::Char c2,
+ Reader::Char c3,
+ Reader::Char c4) {
+ return c == c1 || c == c2 || c == c3 || c == c4;
+}
+
+static inline bool in(Reader::Char c,
+ Reader::Char c1,
+ Reader::Char c2,
+ Reader::Char c3,
+ Reader::Char c4,
+ Reader::Char c5) {
+ return c == c1 || c == c2 || c == c3 || c == c4 || c == c5;
+}
+
+static bool containsNewLine(Reader::Location begin, Reader::Location end) {
+ for (; begin < end; ++begin)
+ if (*begin == '\n' || *begin == '\r')
+ return true;
+ return false;
+}
+
+// Class Reader
+// //////////////////////////////////////////////////////////////////
+
+Reader::Reader()
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+ lastValue_(), commentsBefore_(), features_(Features::all()),
+ collectComments_() {}
+
+Reader::Reader(const Features& features)
+ : errors_(), document_(), begin_(), end_(), current_(), lastValueEnd_(),
+ lastValue_(), commentsBefore_(), features_(features), collectComments_() {
+}
+
+bool
+Reader::parse(const std::string& document, Value& root, bool collectComments) {
+ document_ = document;
+ const char* begin = document_.c_str();
+ const char* end = begin + document_.length();
+ return parse(begin, end, root, collectComments);
+}
+
+bool Reader::parse(std::istream& sin, Value& root, bool collectComments) {
+ // std::istream_iterator<char> begin(sin);
+ // std::istream_iterator<char> end;
+ // Those would allow streamed input from a file, if parse() were a
+ // template function.
+
+ // Since std::string is reference-counted, this at least does not
+ // create an extra copy.
+ std::string doc;
+ std::getline(sin, doc, (char)EOF);
+ return parse(doc, root, collectComments);
+}
+
+bool Reader::parse(const char* beginDoc,
+ const char* endDoc,
+ Value& root,
+ bool collectComments) {
+ if (!features_.allowComments_) {
+ collectComments = false;
+ }
+
+ begin_ = beginDoc;
+ end_ = endDoc;
+ collectComments_ = collectComments;
+ current_ = begin_;
+ lastValueEnd_ = 0;
+ lastValue_ = 0;
+ commentsBefore_ = "";
+ errors_.clear();
+ while (!nodes_.empty())
+ nodes_.pop();
+ nodes_.push(&root);
+
+ bool successful = readValue();
+ Token token;
+ skipCommentTokens(token);
+ if (collectComments_ && !commentsBefore_.empty())
+ root.setComment(commentsBefore_, commentAfter);
+ if (features_.strictRoot_) {
+ if (!root.isArray() && !root.isObject()) {
+ // Set error location to start of doc, ideally should be first token found
+ // in doc
+ token.type_ = tokenError;
+ token.start_ = beginDoc;
+ token.end_ = endDoc;
+ addError(
+ "A valid JSON document must be either an array or an object value.",
+ token);
+ return false;
+ }
+ }
+ return successful;
+}
+
+bool Reader::readValue() {
+ Token token;
+ skipCommentTokens(token);
+ bool successful = true;
+
+ if (collectComments_ && !commentsBefore_.empty()) {
+ // Remove newline characters at the end of the comments
+ size_t lastNonNewline = commentsBefore_.find_last_not_of("\r\n");
+ if (lastNonNewline != std::string::npos) {
+ commentsBefore_.erase(lastNonNewline + 1);
+ } else {
+ commentsBefore_.clear();
+ }
+
+ currentValue().setComment(commentsBefore_, commentBefore);
+ commentsBefore_ = "";
+ }
+
+ switch (token.type_) {
+ case tokenObjectBegin:
+ successful = readObject(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenArrayBegin:
+ successful = readArray(token);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ case tokenNumber:
+ successful = decodeNumber(token);
+ break;
+ case tokenString:
+ successful = decodeString(token);
+ break;
+ case tokenTrue:
+ currentValue() = true;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenFalse:
+ currentValue() = false;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenNull:
+ currentValue() = Value();
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ break;
+ case tokenArraySeparator:
+ if (features_.allowDroppedNullPlaceholders_) {
+ // "Un-read" the current token and mark the current value as a null
+ // token.
+ current_--;
+ currentValue() = Value();
+ currentValue().setOffsetStart(current_ - begin_ - 1);
+ currentValue().setOffsetLimit(current_ - begin_);
+ break;
+ }
+ // Else, fall through...
+ default:
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return addError("Syntax error: value, object or array expected.", token);
+ }
+
+ if (collectComments_) {
+ lastValueEnd_ = current_;
+ lastValue_ = &currentValue();
+ }
+
+ return successful;
+}
+
+void Reader::skipCommentTokens(Token& token) {
+ if (features_.allowComments_) {
+ do {
+ readToken(token);
+ } while (token.type_ == tokenComment);
+ } else {
+ readToken(token);
+ }
+}
+
+bool Reader::expectToken(TokenType type, Token& token, const char* message) {
+ readToken(token);
+ if (token.type_ != type)
+ return addError(message, token);
+ return true;
+}
+
+bool Reader::readToken(Token& token) {
+ skipSpaces();
+ token.start_ = current_;
+ Char c = getNextChar();
+ bool ok = true;
+ switch (c) {
+ case '{':
+ token.type_ = tokenObjectBegin;
+ break;
+ case '}':
+ token.type_ = tokenObjectEnd;
+ break;
+ case '[':
+ token.type_ = tokenArrayBegin;
+ break;
+ case ']':
+ token.type_ = tokenArrayEnd;
+ break;
+ case '"':
+ token.type_ = tokenString;
+ ok = readString();
+ break;
+ case '/':
+ token.type_ = tokenComment;
+ ok = readComment();
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '-':
+ token.type_ = tokenNumber;
+ readNumber();
+ break;
+ case 't':
+ token.type_ = tokenTrue;
+ ok = match("rue", 3);
+ break;
+ case 'f':
+ token.type_ = tokenFalse;
+ ok = match("alse", 4);
+ break;
+ case 'n':
+ token.type_ = tokenNull;
+ ok = match("ull", 3);
+ break;
+ case ',':
+ token.type_ = tokenArraySeparator;
+ break;
+ case ':':
+ token.type_ = tokenMemberSeparator;
+ break;
+ case 0:
+ token.type_ = tokenEndOfStream;
+ break;
+ default:
+ ok = false;
+ break;
+ }
+ if (!ok)
+ token.type_ = tokenError;
+ token.end_ = current_;
+ return true;
+}
+
+void Reader::skipSpaces() {
+ while (current_ != end_) {
+ Char c = *current_;
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ ++current_;
+ else
+ break;
+ }
+}
+
+bool Reader::match(Location pattern, int patternLength) {
+ if (end_ - current_ < patternLength)
+ return false;
+ int index = patternLength;
+ while (index--)
+ if (current_[index] != pattern[index])
+ return false;
+ current_ += patternLength;
+ return true;
+}
+
+bool Reader::readComment() {
+ Location commentBegin = current_ - 1;
+ Char c = getNextChar();
+ bool successful = false;
+ if (c == '*')
+ successful = readCStyleComment();
+ else if (c == '/')
+ successful = readCppStyleComment();
+ if (!successful)
+ return false;
+
+ if (collectComments_) {
+ CommentPlacement placement = commentBefore;
+ if (lastValueEnd_ && !containsNewLine(lastValueEnd_, commentBegin)) {
+ if (c != '*' || !containsNewLine(commentBegin, current_))
+ placement = commentAfterOnSameLine;
+ }
+
+ addComment(commentBegin, current_, placement);
+ }
+ return true;
+}
+
+void
+Reader::addComment(Location begin, Location end, CommentPlacement placement) {
+ assert(collectComments_);
+ if (placement == commentAfterOnSameLine) {
+ assert(lastValue_ != 0);
+ lastValue_->setComment(std::string(begin, end), placement);
+ } else {
+ commentsBefore_ += std::string(begin, end);
+ }
+}
+
+bool Reader::readCStyleComment() {
+ while (current_ != end_) {
+ Char c = getNextChar();
+ if (c == '*' && *current_ == '/')
+ break;
+ }
+ return getNextChar() == '/';
+}
+
+bool Reader::readCppStyleComment() {
+ while (current_ != end_) {
+ Char c = getNextChar();
+ if (c == '\r' || c == '\n')
+ break;
+ }
+ return true;
+}
+
+void Reader::readNumber() {
+ while (current_ != end_) {
+ if (!(*current_ >= '0' && *current_ <= '9') &&
+ !in(*current_, '.', 'e', 'E', '+', '-'))
+ break;
+ ++current_;
+ }
+}
+
+bool Reader::readString() {
+ Char c = 0;
+ while (current_ != end_) {
+ c = getNextChar();
+ if (c == '\\')
+ getNextChar();
+ else if (c == '"')
+ break;
+ }
+ return c == '"';
+}
+
+bool Reader::readObject(Token& tokenStart) {
+ Token tokenName;
+ std::string name;
+ currentValue() = Value(objectValue);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ while (readToken(tokenName)) {
+ bool initialTokenOk = true;
+ while (tokenName.type_ == tokenComment && initialTokenOk)
+ initialTokenOk = readToken(tokenName);
+ if (!initialTokenOk)
+ break;
+ if (tokenName.type_ == tokenObjectEnd && name.empty()) // empty object
+ return true;
+ name = "";
+ if (tokenName.type_ == tokenString) {
+ if (!decodeString(tokenName, name))
+ return recoverFromError(tokenObjectEnd);
+ } else if (tokenName.type_ == tokenNumber && features_.allowNumericKeys_) {
+ Value numberName;
+ if (!decodeNumber(tokenName, numberName))
+ return recoverFromError(tokenObjectEnd);
+ name = numberName.asString();
+ } else {
+ break;
+ }
+
+ Token colon;
+ if (!readToken(colon) || colon.type_ != tokenMemberSeparator) {
+ return addErrorAndRecover(
+ "Missing ':' after object member name", colon, tokenObjectEnd);
+ }
+ Value& value = currentValue()[name];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenObjectEnd);
+
+ Token comma;
+ if (!readToken(comma) ||
+ (comma.type_ != tokenObjectEnd && comma.type_ != tokenArraySeparator &&
+ comma.type_ != tokenComment)) {
+ return addErrorAndRecover(
+ "Missing ',' or '}' in object declaration", comma, tokenObjectEnd);
+ }
+ bool finalizeTokenOk = true;
+ while (comma.type_ == tokenComment && finalizeTokenOk)
+ finalizeTokenOk = readToken(comma);
+ if (comma.type_ == tokenObjectEnd)
+ return true;
+ }
+ return addErrorAndRecover(
+ "Missing '}' or object member name", tokenName, tokenObjectEnd);
+}
+
+bool Reader::readArray(Token& tokenStart) {
+ currentValue() = Value(arrayValue);
+ currentValue().setOffsetStart(tokenStart.start_ - begin_);
+ skipSpaces();
+ if (*current_ == ']') // empty array
+ {
+ Token endArray;
+ readToken(endArray);
+ return true;
+ }
+ int index = 0;
+ for (;;) {
+ Value& value = currentValue()[index++];
+ nodes_.push(&value);
+ bool ok = readValue();
+ nodes_.pop();
+ if (!ok) // error already set
+ return recoverFromError(tokenArrayEnd);
+
+ Token token;
+ // Accept Comment after last item in the array.
+ ok = readToken(token);
+ while (token.type_ == tokenComment && ok) {
+ ok = readToken(token);
+ }
+ bool badTokenType =
+ (token.type_ != tokenArraySeparator && token.type_ != tokenArrayEnd);
+ if (!ok || badTokenType) {
+ return addErrorAndRecover(
+ "Missing ',' or ']' in array declaration", token, tokenArrayEnd);
+ }
+ if (token.type_ == tokenArrayEnd)
+ break;
+ }
+ return true;
+}
+
+bool Reader::decodeNumber(Token& token) {
+ Value decoded;
+ if (!decodeNumber(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeNumber(Token& token, Value& decoded) {
+ bool isDouble = false;
+ for (Location inspect = token.start_; inspect != token.end_; ++inspect) {
+ isDouble = isDouble || in(*inspect, '.', 'e', 'E', '+') ||
+ (*inspect == '-' && inspect != token.start_);
+ }
+ if (isDouble)
+ return decodeDouble(token, decoded);
+ // Attempts to parse the number as an integer. If the number is
+ // larger than the maximum supported value of an integer then
+ // we decode the number as a double.
+ Location current = token.start_;
+ bool isNegative = *current == '-';
+ if (isNegative)
+ ++current;
+ Value::LargestUInt maxIntegerValue =
+ isNegative ? Value::LargestUInt(-Value::minLargestInt)
+ : Value::maxLargestUInt;
+ Value::LargestUInt threshold = maxIntegerValue / 10;
+ Value::LargestUInt value = 0;
+ while (current < token.end_) {
+ Char c = *current++;
+ if (c < '0' || c > '9')
+ return addError("'" + std::string(token.start_, token.end_) +
+ "' is not a number.",
+ token);
+ Value::UInt digit(static_cast<Value::UInt>(c - '0'));
+ if (value >= threshold) {
+ // We've hit or exceeded the max value divided by 10 (rounded down). If
+ // a) we've only just touched the limit, b) this is the last digit, and
+ // c) it's small enough to fit in that rounding delta, we're okay.
+ // Otherwise treat this number as a double to avoid overflow.
+ if (value > threshold || current != token.end_ ||
+ digit > maxIntegerValue % 10) {
+ return decodeDouble(token, decoded);
+ }
+ }
+ value = value * 10 + digit;
+ }
+ if (isNegative)
+ decoded = -Value::LargestInt(value);
+ else if (value <= Value::LargestUInt(Value::maxInt))
+ decoded = Value::LargestInt(value);
+ else
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeDouble(Token& token) {
+ Value decoded;
+ if (!decodeDouble(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeDouble(Token& token, Value& decoded) {
+ double value = 0;
+ const int bufferSize = 32;
+ int count;
+ int length = int(token.end_ - token.start_);
+
+ // Sanity check to avoid buffer overflow exploits.
+ if (length < 0) {
+ return addError("Unable to parse token length", token);
+ }
+
+ // Avoid using a string constant for the format control string given to
+ // sscanf, as this can cause hard to debug crashes on OS X. See here for more
+ // info:
+ //
+ // http://developer.apple.com/library/mac/#DOCUMENTATION/DeveloperTools/gcc-4.0.1/gcc/Incompatibilities.html
+ char format[] = "%lf";
+
+ if (length <= bufferSize) {
+ Char buffer[bufferSize + 1];
+ memcpy(buffer, token.start_, length);
+ buffer[length] = 0;
+ count = sscanf(buffer, format, &value);
+ } else {
+ std::string buffer(token.start_, token.end_);
+ count = sscanf(buffer.c_str(), format, &value);
+ }
+
+ if (count != 1)
+ return addError("'" + std::string(token.start_, token.end_) +
+ "' is not a number.",
+ token);
+ decoded = value;
+ return true;
+}
+
+bool Reader::decodeString(Token& token) {
+ std::string decoded;
+ if (!decodeString(token, decoded))
+ return false;
+ currentValue() = decoded;
+ currentValue().setOffsetStart(token.start_ - begin_);
+ currentValue().setOffsetLimit(token.end_ - begin_);
+ return true;
+}
+
+bool Reader::decodeString(Token& token, std::string& decoded) {
+ decoded.reserve(token.end_ - token.start_ - 2);
+ Location current = token.start_ + 1; // skip '"'
+ Location end = token.end_ - 1; // do not include '"'
+ while (current != end) {
+ Char c = *current++;
+ if (c == '"')
+ break;
+ else if (c == '\\') {
+ if (current == end)
+ return addError("Empty escape sequence in string", token, current);
+ Char escape = *current++;
+ switch (escape) {
+ case '"':
+ decoded += '"';
+ break;
+ case '/':
+ decoded += '/';
+ break;
+ case '\\':
+ decoded += '\\';
+ break;
+ case 'b':
+ decoded += '\b';
+ break;
+ case 'f':
+ decoded += '\f';
+ break;
+ case 'n':
+ decoded += '\n';
+ break;
+ case 'r':
+ decoded += '\r';
+ break;
+ case 't':
+ decoded += '\t';
+ break;
+ case 'u': {
+ unsigned int unicode;
+ if (!decodeUnicodeCodePoint(token, current, end, unicode))
+ return false;
+ decoded += codePointToUTF8(unicode);
+ } break;
+ default:
+ return addError("Bad escape sequence in string", token, current);
+ }
+ } else {
+ decoded += c;
+ }
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeCodePoint(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode) {
+
+ if (!decodeUnicodeEscapeSequence(token, current, end, unicode))
+ return false;
+ if (unicode >= 0xD800 && unicode <= 0xDBFF) {
+ // surrogate pairs
+ if (end - current < 6)
+ return addError(
+ "additional six characters expected to parse unicode surrogate pair.",
+ token,
+ current);
+ unsigned int surrogatePair;
+ if (*(current++) == '\\' && *(current++) == 'u') {
+ if (decodeUnicodeEscapeSequence(token, current, end, surrogatePair)) {
+ unicode = 0x10000 + ((unicode & 0x3FF) << 10) + (surrogatePair & 0x3FF);
+ } else
+ return false;
+ } else
+ return addError("expecting another \\u token to begin the second half of "
+ "a unicode surrogate pair",
+ token,
+ current);
+ }
+ return true;
+}
+
+bool Reader::decodeUnicodeEscapeSequence(Token& token,
+ Location& current,
+ Location end,
+ unsigned int& unicode) {
+ if (end - current < 4)
+ return addError(
+ "Bad unicode escape sequence in string: four digits expected.",
+ token,
+ current);
+ unicode = 0;
+ for (int index = 0; index < 4; ++index) {
+ Char c = *current++;
+ unicode *= 16;
+ if (c >= '0' && c <= '9')
+ unicode += c - '0';
+ else if (c >= 'a' && c <= 'f')
+ unicode += c - 'a' + 10;
+ else if (c >= 'A' && c <= 'F')
+ unicode += c - 'A' + 10;
+ else
+ return addError(
+ "Bad unicode escape sequence in string: hexadecimal digit expected.",
+ token,
+ current);
+ }
+ return true;
+}
+
+bool
+Reader::addError(const std::string& message, Token& token, Location extra) {
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = extra;
+ errors_.push_back(info);
+ return false;
+}
+
+bool Reader::recoverFromError(TokenType skipUntilToken) {
+ int errorCount = int(errors_.size());
+ Token skip;
+ for (;;) {
+ if (!readToken(skip))
+ errors_.resize(errorCount); // discard errors caused by recovery
+ if (skip.type_ == skipUntilToken || skip.type_ == tokenEndOfStream)
+ break;
+ }
+ errors_.resize(errorCount);
+ return false;
+}
+
+bool Reader::addErrorAndRecover(const std::string& message,
+ Token& token,
+ TokenType skipUntilToken) {
+ addError(message, token);
+ return recoverFromError(skipUntilToken);
+}
+
+Value& Reader::currentValue() { return *(nodes_.top()); }
+
+Reader::Char Reader::getNextChar() {
+ if (current_ == end_)
+ return 0;
+ return *current_++;
+}
+
+void Reader::getLocationLineAndColumn(Location location,
+ int& line,
+ int& column) const {
+ Location current = begin_;
+ Location lastLineStart = current;
+ line = 0;
+ while (current < location && current != end_) {
+ Char c = *current++;
+ if (c == '\r') {
+ if (*current == '\n')
+ ++current;
+ lastLineStart = current;
+ ++line;
+ } else if (c == '\n') {
+ lastLineStart = current;
+ ++line;
+ }
+ }
+ // column & line start at 1
+ column = int(location - lastLineStart) + 1;
+ ++line;
+}
+
+std::string Reader::getLocationLineAndColumn(Location location) const {
+ int line, column;
+ getLocationLineAndColumn(location, line, column);
+ char buffer[18 + 16 + 16 + 1];
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__)
+#if defined(WINCE)
+ _snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#else
+ sprintf_s(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#endif
+#else
+ snprintf(buffer, sizeof(buffer), "Line %d, Column %d", line, column);
+#endif
+ return buffer;
+}
+
+// Deprecated. Preserved for backward compatibility
+std::string Reader::getFormatedErrorMessages() const {
+ return getFormattedErrorMessages();
+}
+
+std::string Reader::getFormattedErrorMessages() const {
+ std::string formattedMessage;
+ for (Errors::const_iterator itError = errors_.begin();
+ itError != errors_.end();
+ ++itError) {
+ const ErrorInfo& error = *itError;
+ formattedMessage +=
+ "* " + getLocationLineAndColumn(error.token_.start_) + "\n";
+ formattedMessage += " " + error.message_ + "\n";
+ if (error.extra_)
+ formattedMessage +=
+ "See " + getLocationLineAndColumn(error.extra_) + " for detail.\n";
+ }
+ return formattedMessage;
+}
+
+std::vector<Reader::StructuredError> Reader::getStructuredErrors() const {
+ std::vector<Reader::StructuredError> allErrors;
+ for (Errors::const_iterator itError = errors_.begin();
+ itError != errors_.end();
+ ++itError) {
+ const ErrorInfo& error = *itError;
+ Reader::StructuredError structured;
+ structured.offset_start = error.token_.start_ - begin_;
+ structured.offset_limit = error.token_.end_ - begin_;
+ structured.message = error.message_;
+ allErrors.push_back(structured);
+ }
+ return allErrors;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message) {
+ size_t length = end_ - begin_;
+ if(value.getOffsetStart() > length
+ || value.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = end_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = 0;
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::pushError(const Value& value, const std::string& message, const Value& extra) {
+ size_t length = end_ - begin_;
+ if(value.getOffsetStart() > length
+ || value.getOffsetLimit() > length
+ || extra.getOffsetLimit() > length)
+ return false;
+ Token token;
+ token.type_ = tokenError;
+ token.start_ = begin_ + value.getOffsetStart();
+ token.end_ = begin_ + value.getOffsetLimit();
+ ErrorInfo info;
+ info.token_ = token;
+ info.message_ = message;
+ info.extra_ = begin_ + extra.getOffsetStart();
+ errors_.push_back(info);
+ return true;
+}
+
+bool Reader::good() const {
+ return !errors_.size();
+}
+
+std::istream& operator>>(std::istream& sin, Value& root) {
+ Json::Reader reader;
+ bool ok = reader.parse(sin, root, true);
+ if (!ok) {
+ fprintf(stderr,
+ "Error from reader: %s",
+ reader.getFormattedErrorMessages().c_str());
+
+ JSON_FAIL_MESSAGE("reader error");
+ }
+ return sin;
+}
+
+} // namespace Json
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_tool.h b/Utilities/cmjsoncpp/src/lib_json/json_tool.h
new file mode 100644
index 000000000..f9b61c38c
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_tool.h
@@ -0,0 +1,87 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#ifndef LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+#define LIB_JSONCPP_JSON_TOOL_H_INCLUDED
+
+/* This header provides common string manipulation support, such as UTF-8,
+ * portable conversion from/to string...
+ *
+ * It is an internal header that must not be exposed.
+ */
+
+namespace Json {
+
+/// Converts a unicode code-point to UTF-8.
+static inline std::string codePointToUTF8(unsigned int cp) {
+ std::string result;
+
+ // based on description from http://en.wikipedia.org/wiki/UTF-8
+
+ if (cp <= 0x7f) {
+ result.resize(1);
+ result[0] = static_cast<char>(cp);
+ } else if (cp <= 0x7FF) {
+ result.resize(2);
+ result[1] = static_cast<char>(0x80 | (0x3f & cp));
+ result[0] = static_cast<char>(0xC0 | (0x1f & (cp >> 6)));
+ } else if (cp <= 0xFFFF) {
+ result.resize(3);
+ result[2] = static_cast<char>(0x80 | (0x3f & cp));
+ result[1] = 0x80 | static_cast<char>((0x3f & (cp >> 6)));
+ result[0] = 0xE0 | static_cast<char>((0xf & (cp >> 12)));
+ } else if (cp <= 0x10FFFF) {
+ result.resize(4);
+ result[3] = static_cast<char>(0x80 | (0x3f & cp));
+ result[2] = static_cast<char>(0x80 | (0x3f & (cp >> 6)));
+ result[1] = static_cast<char>(0x80 | (0x3f & (cp >> 12)));
+ result[0] = static_cast<char>(0xF0 | (0x7 & (cp >> 18)));
+ }
+
+ return result;
+}
+
+/// Returns true if ch is a control character (in range [0,32[).
+static inline bool isControlCharacter(char ch) { return ch > 0 && ch <= 0x1F; }
+
+enum {
+ /// Constant that specify the size of the buffer that must be passed to
+ /// uintToString.
+ uintToStringBufferSize = 3 * sizeof(LargestUInt) + 1
+};
+
+// Defines a char buffer for use with uintToString().
+typedef char UIntToStringBuffer[uintToStringBufferSize];
+
+/** Converts an unsigned integer to string.
+ * @param value Unsigned interger to convert to string
+ * @param current Input/Output string buffer.
+ * Must have at least uintToStringBufferSize chars free.
+ */
+static inline void uintToString(LargestUInt value, char*& current) {
+ *--current = 0;
+ do {
+ *--current = char(value % 10) + '0';
+ value /= 10;
+ } while (value != 0);
+}
+
+/** Change ',' to '.' everywhere in buffer.
+ *
+ * We had a sophisticated way, but it did not work in WinCE.
+ * @see https://github.com/open-source-parsers/jsoncpp/pull/9
+ */
+static inline void fixNumericLocale(char* begin, char* end) {
+ while (begin < end) {
+ if (*begin == ',') {
+ *begin = '.';
+ }
+ ++begin;
+ }
+}
+
+} // namespace Json {
+
+#endif // LIB_JSONCPP_JSON_TOOL_H_INCLUDED
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_value.cpp b/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
new file mode 100644
index 000000000..478afe102
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_value.cpp
@@ -0,0 +1,1482 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/assertions.h>
+#include <json/value.h>
+#include <json/writer.h>
+#ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#include "json_batchallocator.h"
+#endif // #ifndef JSON_USE_SIMPLE_INTERNAL_ALLOCATOR
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <math.h>
+#include <sstream>
+#include <utility>
+#include <string.h>
+#include <assert.h>
+#ifdef JSON_USE_CPPTL
+#include <cpptl/conststring.h>
+#endif
+#include <cstddef> // size_t
+
+#define JSON_ASSERT_UNREACHABLE assert(false)
+
+namespace Json {
+
+// This is a walkaround to avoid the static initialization of Value::null.
+// kNull must be word-aligned to avoid crashing on ARM. We use an alignment of
+// 8 (instead of 4) as a bit of future-proofing.
+#if defined(__ARMEL__)
+#define ALIGNAS(byte_alignment) __attribute__((aligned(byte_alignment)))
+#else
+#define ALIGNAS(byte_alignment)
+#endif
+static const unsigned char ALIGNAS(8) kNull[sizeof(Value)] = { 0 };
+const unsigned char& kNullRef = kNull[0];
+const Value& Value::null = reinterpret_cast<const Value&>(kNullRef);
+
+const Int Value::minInt = Int(~(UInt(-1) / 2));
+const Int Value::maxInt = Int(UInt(-1) / 2);
+const UInt Value::maxUInt = UInt(-1);
+#if defined(JSON_HAS_INT64)
+const Int64 Value::minInt64 = Int64(~(UInt64(-1) / 2));
+const Int64 Value::maxInt64 = Int64(UInt64(-1) / 2);
+const UInt64 Value::maxUInt64 = UInt64(-1);
+// The constant is hard-coded because some compiler have trouble
+// converting Value::maxUInt64 to a double correctly (AIX/xlC).
+// Assumes that UInt64 is a 64 bits integer.
+static const double maxUInt64AsDouble = 18446744073709551615.0;
+#endif // defined(JSON_HAS_INT64)
+const LargestInt Value::minLargestInt = LargestInt(~(LargestUInt(-1) / 2));
+const LargestInt Value::maxLargestInt = LargestInt(LargestUInt(-1) / 2);
+const LargestUInt Value::maxLargestUInt = LargestUInt(-1);
+
+/// Unknown size marker
+static const unsigned int unknown = (unsigned)-1;
+
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+ return d >= min && d <= max;
+}
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+static inline double integerToDouble(Json::UInt64 value) {
+ return static_cast<double>(Int64(value / 2)) * 2.0 + Int64(value & 1);
+}
+
+template <typename T> static inline double integerToDouble(T value) {
+ return static_cast<double>(value);
+}
+
+template <typename T, typename U>
+static inline bool InRange(double d, T min, U max) {
+ return d >= integerToDouble(min) && d <= integerToDouble(max);
+}
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+
+/** Duplicates the specified string value.
+ * @param value Pointer to the string to duplicate. Must be zero-terminated if
+ * length is "unknown".
+ * @param length Length of the value. if equals to unknown, then it will be
+ * computed using strlen(value).
+ * @return Pointer on the duplicate instance of string.
+ */
+static inline char* duplicateStringValue(const char* value,
+ unsigned int length = unknown) {
+ if (length == unknown)
+ length = (unsigned int)strlen(value);
+
+ // Avoid an integer overflow in the call to malloc below by limiting length
+ // to a sane value.
+ if (length >= (unsigned)Value::maxInt)
+ length = Value::maxInt - 1;
+
+ char* newString = static_cast<char*>(malloc(length + 1));
+ JSON_ASSERT_MESSAGE(newString != 0,
+ "in Json::Value::duplicateStringValue(): "
+ "Failed to allocate string value buffer");
+ memcpy(newString, value, length);
+ newString[length] = 0;
+ return newString;
+}
+
+/** Free the string duplicated by duplicateStringValue().
+ */
+static inline void releaseStringValue(char* value) { free(value); }
+
+} // namespace Json
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// ValueInternals...
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#if !defined(JSON_IS_AMALGAMATION)
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+#include "json_internalarray.inl"
+#include "json_internalmap.inl"
+#endif // JSON_VALUE_USE_INTERNAL_MAP
+
+#include "json_valueiterator.inl"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CommentInfo
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+Value::CommentInfo::CommentInfo() : comment_(0) {}
+
+Value::CommentInfo::~CommentInfo() {
+ if (comment_)
+ releaseStringValue(comment_);
+}
+
+void Value::CommentInfo::setComment(const char* text) {
+ if (comment_)
+ releaseStringValue(comment_);
+ JSON_ASSERT(text != 0);
+ JSON_ASSERT_MESSAGE(
+ text[0] == '\0' || text[0] == '/',
+ "in Json::Value::setComment(): Comments must start with /");
+ // It seems that /**/ style comments are acceptable as well.
+ comment_ = duplicateStringValue(text);
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::CZString
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// Notes: index_ indicates if the string was allocated when
+// a string is stored.
+
+Value::CZString::CZString(ArrayIndex index) : cstr_(0), index_(index) {}
+
+Value::CZString::CZString(const char* cstr, DuplicationPolicy allocate)
+ : cstr_(allocate == duplicate ? duplicateStringValue(cstr) : cstr),
+ index_(allocate) {}
+
+Value::CZString::CZString(const CZString& other)
+ : cstr_(other.index_ != noDuplication && other.cstr_ != 0
+ ? duplicateStringValue(other.cstr_)
+ : other.cstr_),
+ index_(other.cstr_
+ ? static_cast<ArrayIndex>(other.index_ == noDuplication
+ ? noDuplication : duplicate)
+ : other.index_) {}
+
+Value::CZString::~CZString() {
+ if (cstr_ && index_ == duplicate)
+ releaseStringValue(const_cast<char*>(cstr_));
+}
+
+void Value::CZString::swap(CZString& other) {
+ std::swap(cstr_, other.cstr_);
+ std::swap(index_, other.index_);
+}
+
+Value::CZString& Value::CZString::operator=(CZString other) {
+ swap(other);
+ return *this;
+}
+
+bool Value::CZString::operator<(const CZString& other) const {
+ if (cstr_) {
+ assert(other.cstr_);
+ return strcmp(cstr_, other.cstr_) < 0;
+ }
+ return index_ < other.index_;
+}
+
+bool Value::CZString::operator==(const CZString& other) const {
+ if (cstr_) {
+ assert(other.cstr_);
+ return strcmp(cstr_, other.cstr_) == 0;
+ }
+ return index_ == other.index_;
+}
+
+ArrayIndex Value::CZString::index() const { return index_; }
+
+const char* Value::CZString::c_str() const { return cstr_; }
+
+bool Value::CZString::isStaticString() const { return index_ == noDuplication; }
+
+#endif // ifndef JSON_VALUE_USE_INTERNAL_MAP
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class Value::Value
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+/*! \internal Default constructor initialization must be equivalent to:
+ * memset( this, 0, sizeof(Value) )
+ * This optimization is used in ValueInternalMap fast allocator.
+ */
+Value::Value(ValueType type) {
+ initBasic(type);
+ switch (type) {
+ case nullValue:
+ break;
+ case intValue:
+ case uintValue:
+ value_.int_ = 0;
+ break;
+ case realValue:
+ value_.real_ = 0.0;
+ break;
+ case stringValue:
+ value_.string_ = 0;
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues();
+ break;
+#else
+ case arrayValue:
+ value_.array_ = arrayAllocator()->newArray();
+ break;
+ case objectValue:
+ value_.map_ = mapAllocator()->newMap();
+ break;
+#endif
+ case booleanValue:
+ value_.bool_ = false;
+ break;
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+}
+
+Value::Value(Int value) {
+ initBasic(intValue);
+ value_.int_ = value;
+}
+
+Value::Value(UInt value) {
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#if defined(JSON_HAS_INT64)
+Value::Value(Int64 value) {
+ initBasic(intValue);
+ value_.int_ = value;
+}
+Value::Value(UInt64 value) {
+ initBasic(uintValue);
+ value_.uint_ = value;
+}
+#endif // defined(JSON_HAS_INT64)
+
+Value::Value(double value) {
+ initBasic(realValue);
+ value_.real_ = value;
+}
+
+Value::Value(const char* value) {
+ initBasic(stringValue, true);
+ value_.string_ = duplicateStringValue(value);
+}
+
+Value::Value(const char* beginValue, const char* endValue) {
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateStringValue(beginValue, (unsigned int)(endValue - beginValue));
+}
+
+Value::Value(const std::string& value) {
+ initBasic(stringValue, true);
+ value_.string_ =
+ duplicateStringValue(value.c_str(), (unsigned int)value.length());
+}
+
+Value::Value(const StaticString& value) {
+ initBasic(stringValue);
+ value_.string_ = const_cast<char*>(value.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value::Value(const CppTL::ConstString& value) {
+ initBasic(stringValue, true);
+ value_.string_ = duplicateStringValue(value, value.length());
+}
+#endif
+
+Value::Value(bool value) {
+ initBasic(booleanValue);
+ value_.bool_ = value;
+}
+
+Value::Value(const Value& other)
+ : type_(other.type_), allocated_(false)
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ ,
+ itemIsUsed_(0)
+#endif
+ ,
+ comments_(0), start_(other.start_), limit_(other.limit_) {
+ switch (type_) {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ value_ = other.value_;
+ break;
+ case stringValue:
+ if (other.value_.string_) {
+ value_.string_ = duplicateStringValue(other.value_.string_);
+ allocated_ = true;
+ } else {
+ value_.string_ = 0;
+ allocated_ = false;
+ }
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_ = new ObjectValues(*other.value_.map_);
+ break;
+#else
+ case arrayValue:
+ value_.array_ = arrayAllocator()->newArrayCopy(*other.value_.array_);
+ break;
+ case objectValue:
+ value_.map_ = mapAllocator()->newMapCopy(*other.value_.map_);
+ break;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ if (other.comments_) {
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ for (int comment = 0; comment < numberOfCommentPlacement; ++comment) {
+ const CommentInfo& otherComment = other.comments_[comment];
+ if (otherComment.comment_)
+ comments_[comment].setComment(otherComment.comment_);
+ }
+ }
+}
+
+Value::~Value() {
+ switch (type_) {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ break;
+ case stringValue:
+ if (allocated_)
+ releaseStringValue(value_.string_);
+ break;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ delete value_.map_;
+ break;
+#else
+ case arrayValue:
+ arrayAllocator()->destructArray(value_.array_);
+ break;
+ case objectValue:
+ mapAllocator()->destructMap(value_.map_);
+ break;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+
+ if (comments_)
+ delete[] comments_;
+}
+
+Value& Value::operator=(Value other) {
+ swap(other);
+ return *this;
+}
+
+void Value::swap(Value& other) {
+ ValueType temp = type_;
+ type_ = other.type_;
+ other.type_ = temp;
+ std::swap(value_, other.value_);
+ int temp2 = allocated_;
+ allocated_ = other.allocated_;
+ other.allocated_ = temp2;
+ std::swap(start_, other.start_);
+ std::swap(limit_, other.limit_);
+}
+
+ValueType Value::type() const { return type_; }
+
+int Value::compare(const Value& other) const {
+ if (*this < other)
+ return -1;
+ if (*this > other)
+ return 1;
+ return 0;
+}
+
+bool Value::operator<(const Value& other) const {
+ int typeDelta = type_ - other.type_;
+ if (typeDelta)
+ return typeDelta < 0 ? true : false;
+ switch (type_) {
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ < other.value_.int_;
+ case uintValue:
+ return value_.uint_ < other.value_.uint_;
+ case realValue:
+ return value_.real_ < other.value_.real_;
+ case booleanValue:
+ return value_.bool_ < other.value_.bool_;
+ case stringValue:
+ return (value_.string_ == 0 && other.value_.string_) ||
+ (other.value_.string_ && value_.string_ &&
+ strcmp(value_.string_, other.value_.string_) < 0);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue: {
+ int delta = int(value_.map_->size() - other.value_.map_->size());
+ if (delta)
+ return delta < 0;
+ return (*value_.map_) < (*other.value_.map_);
+ }
+#else
+ case arrayValue:
+ return value_.array_->compare(*(other.value_.array_)) < 0;
+ case objectValue:
+ return value_.map_->compare(*(other.value_.map_)) < 0;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable
+}
+
+bool Value::operator<=(const Value& other) const { return !(other < *this); }
+
+bool Value::operator>=(const Value& other) const { return !(*this < other); }
+
+bool Value::operator>(const Value& other) const { return other < *this; }
+
+bool Value::operator==(const Value& other) const {
+ // if ( type_ != other.type_ )
+ // GCC 2.95.3 says:
+ // attempt to take address of bit-field structure member `Json::Value::type_'
+ // Beats me, but a temp solves the problem.
+ int temp = other.type_;
+ if (type_ != temp)
+ return false;
+ switch (type_) {
+ case nullValue:
+ return true;
+ case intValue:
+ return value_.int_ == other.value_.int_;
+ case uintValue:
+ return value_.uint_ == other.value_.uint_;
+ case realValue:
+ return value_.real_ == other.value_.real_;
+ case booleanValue:
+ return value_.bool_ == other.value_.bool_;
+ case stringValue:
+ return (value_.string_ == other.value_.string_) ||
+ (other.value_.string_ && value_.string_ &&
+ strcmp(value_.string_, other.value_.string_) == 0);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ return value_.map_->size() == other.value_.map_->size() &&
+ (*value_.map_) == (*other.value_.map_);
+#else
+ case arrayValue:
+ return value_.array_->compare(*(other.value_.array_)) == 0;
+ case objectValue:
+ return value_.map_->compare(*(other.value_.map_)) == 0;
+#endif
+ default:
+ JSON_ASSERT_UNREACHABLE;
+ }
+ return false; // unreachable
+}
+
+bool Value::operator!=(const Value& other) const { return !(*this == other); }
+
+const char* Value::asCString() const {
+ JSON_ASSERT_MESSAGE(type_ == stringValue,
+ "in Json::Value::asCString(): requires stringValue");
+ return value_.string_;
+}
+
+std::string Value::asString() const {
+ switch (type_) {
+ case nullValue:
+ return "";
+ case stringValue:
+ return value_.string_ ? value_.string_ : "";
+ case booleanValue:
+ return value_.bool_ ? "true" : "false";
+ case intValue:
+ return valueToString(value_.int_);
+ case uintValue:
+ return valueToString(value_.uint_);
+ case realValue:
+ return valueToString(value_.real_);
+ default:
+ JSON_FAIL_MESSAGE("Type is not convertible to string");
+ }
+}
+
+#ifdef JSON_USE_CPPTL
+CppTL::ConstString Value::asConstString() const {
+ return CppTL::ConstString(asString().c_str());
+}
+#endif
+
+Value::Int Value::asInt() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestInt out of Int range");
+ return Int(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt(), "LargestUInt out of Int range");
+ return Int(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt, maxInt),
+ "double out of Int range");
+ return Int(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int.");
+}
+
+Value::UInt Value::asUInt() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestInt out of UInt range");
+ return UInt(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isUInt(), "LargestUInt out of UInt range");
+ return UInt(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt),
+ "double out of UInt range");
+ return UInt(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt.");
+}
+
+#if defined(JSON_HAS_INT64)
+
+Value::Int64 Value::asInt64() const {
+ switch (type_) {
+ case intValue:
+ return Int64(value_.int_);
+ case uintValue:
+ JSON_ASSERT_MESSAGE(isInt64(), "LargestUInt out of Int64 range");
+ return Int64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, minInt64, maxInt64),
+ "double out of Int64 range");
+ return Int64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to Int64.");
+}
+
+Value::UInt64 Value::asUInt64() const {
+ switch (type_) {
+ case intValue:
+ JSON_ASSERT_MESSAGE(isUInt64(), "LargestInt out of UInt64 range");
+ return UInt64(value_.int_);
+ case uintValue:
+ return UInt64(value_.uint_);
+ case realValue:
+ JSON_ASSERT_MESSAGE(InRange(value_.real_, 0, maxUInt64),
+ "double out of UInt64 range");
+ return UInt64(value_.real_);
+ case nullValue:
+ return 0;
+ case booleanValue:
+ return value_.bool_ ? 1 : 0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to UInt64.");
+}
+#endif // if defined(JSON_HAS_INT64)
+
+LargestInt Value::asLargestInt() const {
+#if defined(JSON_NO_INT64)
+ return asInt();
+#else
+ return asInt64();
+#endif
+}
+
+LargestUInt Value::asLargestUInt() const {
+#if defined(JSON_NO_INT64)
+ return asUInt();
+#else
+ return asUInt64();
+#endif
+}
+
+double Value::asDouble() const {
+ switch (type_) {
+ case intValue:
+ return static_cast<double>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<double>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return value_.real_;
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0 : 0.0;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to double.");
+}
+
+float Value::asFloat() const {
+ switch (type_) {
+ case intValue:
+ return static_cast<float>(value_.int_);
+ case uintValue:
+#if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return static_cast<float>(value_.uint_);
+#else // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ return integerToDouble(value_.uint_);
+#endif // if !defined(JSON_USE_INT64_DOUBLE_CONVERSION)
+ case realValue:
+ return static_cast<float>(value_.real_);
+ case nullValue:
+ return 0.0;
+ case booleanValue:
+ return value_.bool_ ? 1.0f : 0.0f;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to float.");
+}
+
+bool Value::asBool() const {
+ switch (type_) {
+ case booleanValue:
+ return value_.bool_;
+ case nullValue:
+ return false;
+ case intValue:
+ return value_.int_ ? true : false;
+ case uintValue:
+ return value_.uint_ ? true : false;
+ case realValue:
+ return value_.real_ ? true : false;
+ default:
+ break;
+ }
+ JSON_FAIL_MESSAGE("Value is not convertible to bool.");
+}
+
+bool Value::isConvertibleTo(ValueType other) const {
+ switch (other) {
+ case nullValue:
+ return (isNumeric() && asDouble() == 0.0) ||
+ (type_ == booleanValue && value_.bool_ == false) ||
+ (type_ == stringValue && asString() == "") ||
+ (type_ == arrayValue && value_.map_->size() == 0) ||
+ (type_ == objectValue && value_.map_->size() == 0) ||
+ type_ == nullValue;
+ case intValue:
+ return isInt() ||
+ (type_ == realValue && InRange(value_.real_, minInt, maxInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case uintValue:
+ return isUInt() ||
+ (type_ == realValue && InRange(value_.real_, 0, maxUInt)) ||
+ type_ == booleanValue || type_ == nullValue;
+ case realValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case booleanValue:
+ return isNumeric() || type_ == booleanValue || type_ == nullValue;
+ case stringValue:
+ return isNumeric() || type_ == booleanValue || type_ == stringValue ||
+ type_ == nullValue;
+ case arrayValue:
+ return type_ == arrayValue || type_ == nullValue;
+ case objectValue:
+ return type_ == objectValue || type_ == nullValue;
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return false;
+}
+
+/// Number of values in array or object
+ArrayIndex Value::size() const {
+ switch (type_) {
+ case nullValue:
+ case intValue:
+ case uintValue:
+ case realValue:
+ case booleanValue:
+ case stringValue:
+ return 0;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue: // size of the array is highest index + 1
+ if (!value_.map_->empty()) {
+ ObjectValues::const_iterator itLast = value_.map_->end();
+ --itLast;
+ return (*itLast).first.index() + 1;
+ }
+ return 0;
+ case objectValue:
+ return ArrayIndex(value_.map_->size());
+#else
+ case arrayValue:
+ return Int(value_.array_->size());
+ case objectValue:
+ return Int(value_.map_->size());
+#endif
+ }
+ JSON_ASSERT_UNREACHABLE;
+ return 0; // unreachable;
+}
+
+bool Value::empty() const {
+ if (isNull() || isArray() || isObject())
+ return size() == 0u;
+ else
+ return false;
+}
+
+bool Value::operator!() const { return isNull(); }
+
+void Value::clear() {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue ||
+ type_ == objectValue,
+ "in Json::Value::clear(): requires complex value");
+ start_ = 0;
+ limit_ = 0;
+ switch (type_) {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ case objectValue:
+ value_.map_->clear();
+ break;
+#else
+ case arrayValue:
+ value_.array_->clear();
+ break;
+ case objectValue:
+ value_.map_->clear();
+ break;
+#endif
+ default:
+ break;
+ }
+}
+
+void Value::resize(ArrayIndex newSize) {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::resize(): requires arrayValue");
+ if (type_ == nullValue)
+ *this = Value(arrayValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ArrayIndex oldSize = size();
+ if (newSize == 0)
+ clear();
+ else if (newSize > oldSize)
+ (*this)[newSize - 1];
+ else {
+ for (ArrayIndex index = newSize; index < oldSize; ++index) {
+ value_.map_->erase(index);
+ }
+ assert(size() == newSize);
+ }
+#else
+ value_.array_->resize(newSize);
+#endif
+}
+
+Value& Value::operator[](ArrayIndex index) {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex): requires arrayValue");
+ if (type_ == nullValue)
+ *this = Value(arrayValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString key(index);
+ ObjectValues::iterator it = value_.map_->lower_bound(key);
+ if (it != value_.map_->end() && (*it).first == key)
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue(key, null);
+ it = value_.map_->insert(it, defaultValue);
+ return (*it).second;
+#else
+ return value_.array_->resolveReference(index);
+#endif
+}
+
+Value& Value::operator[](int index) {
+ JSON_ASSERT_MESSAGE(
+ index >= 0,
+ "in Json::Value::operator[](int index): index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+const Value& Value::operator[](ArrayIndex index) const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == arrayValue,
+ "in Json::Value::operator[](ArrayIndex)const: requires arrayValue");
+ if (type_ == nullValue)
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString key(index);
+ ObjectValues::const_iterator it = value_.map_->find(key);
+ if (it == value_.map_->end())
+ return null;
+ return (*it).second;
+#else
+ Value* value = value_.array_->find(index);
+ return value ? *value : null;
+#endif
+}
+
+const Value& Value::operator[](int index) const {
+ JSON_ASSERT_MESSAGE(
+ index >= 0,
+ "in Json::Value::operator[](int index) const: index cannot be negative");
+ return (*this)[ArrayIndex(index)];
+}
+
+Value& Value::operator[](const char* key) {
+ return resolveReference(key, false);
+}
+
+void Value::initBasic(ValueType type, bool allocated) {
+ type_ = type;
+ allocated_ = allocated;
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ itemIsUsed_ = 0;
+#endif
+ comments_ = 0;
+ start_ = 0;
+ limit_ = 0;
+}
+
+Value& Value::resolveReference(const char* key, bool isStatic) {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::resolveReference(): requires objectValue");
+ if (type_ == nullValue)
+ *this = Value(objectValue);
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey(
+ key, isStatic ? CZString::noDuplication : CZString::duplicateOnCopy);
+ ObjectValues::iterator it = value_.map_->lower_bound(actualKey);
+ if (it != value_.map_->end() && (*it).first == actualKey)
+ return (*it).second;
+
+ ObjectValues::value_type defaultValue(actualKey, null);
+ it = value_.map_->insert(it, defaultValue);
+ Value& value = (*it).second;
+ return value;
+#else
+ return value_.map_->resolveReference(key, isStatic);
+#endif
+}
+
+Value Value::get(ArrayIndex index, const Value& defaultValue) const {
+ const Value* value = &((*this)[index]);
+ return value == &null ? defaultValue : *value;
+}
+
+bool Value::isValidIndex(ArrayIndex index) const { return index < size(); }
+
+const Value& Value::operator[](const char* key) const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::operator[](char const*)const: requires objectValue");
+ if (type_ == nullValue)
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey(key, CZString::noDuplication);
+ ObjectValues::const_iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return null;
+ return (*it).second;
+#else
+ const Value* value = value_.map_->find(key);
+ return value ? *value : null;
+#endif
+}
+
+Value& Value::operator[](const std::string& key) {
+ return (*this)[key.c_str()];
+}
+
+const Value& Value::operator[](const std::string& key) const {
+ return (*this)[key.c_str()];
+}
+
+Value& Value::operator[](const StaticString& key) {
+ return resolveReference(key, true);
+}
+
+#ifdef JSON_USE_CPPTL
+Value& Value::operator[](const CppTL::ConstString& key) {
+ return (*this)[key.c_str()];
+}
+
+const Value& Value::operator[](const CppTL::ConstString& key) const {
+ return (*this)[key.c_str()];
+}
+#endif
+
+Value& Value::append(const Value& value) { return (*this)[size()] = value; }
+
+Value Value::get(const char* key, const Value& defaultValue) const {
+ const Value* value = &((*this)[key]);
+ return value == &null ? defaultValue : *value;
+}
+
+Value Value::get(const std::string& key, const Value& defaultValue) const {
+ return get(key.c_str(), defaultValue);
+}
+
+Value Value::removeMember(const char* key) {
+ JSON_ASSERT_MESSAGE(type_ == nullValue || type_ == objectValue,
+ "in Json::Value::removeMember(): requires objectValue");
+ if (type_ == nullValue)
+ return null;
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ CZString actualKey(key, CZString::noDuplication);
+ ObjectValues::iterator it = value_.map_->find(actualKey);
+ if (it == value_.map_->end())
+ return null;
+ Value old(it->second);
+ value_.map_->erase(it);
+ return old;
+#else
+ Value* value = value_.map_->find(key);
+ if (value) {
+ Value old(*value);
+ value_.map_.remove(key);
+ return old;
+ } else {
+ return null;
+ }
+#endif
+}
+
+Value Value::removeMember(const std::string& key) {
+ return removeMember(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+Value Value::get(const CppTL::ConstString& key,
+ const Value& defaultValue) const {
+ return get(key.c_str(), defaultValue);
+}
+#endif
+
+bool Value::isMember(const char* key) const {
+ const Value* value = &((*this)[key]);
+ return value != &null;
+}
+
+bool Value::isMember(const std::string& key) const {
+ return isMember(key.c_str());
+}
+
+#ifdef JSON_USE_CPPTL
+bool Value::isMember(const CppTL::ConstString& key) const {
+ return isMember(key.c_str());
+}
+#endif
+
+Value::Members Value::getMemberNames() const {
+ JSON_ASSERT_MESSAGE(
+ type_ == nullValue || type_ == objectValue,
+ "in Json::Value::getMemberNames(), value must be objectValue");
+ if (type_ == nullValue)
+ return Value::Members();
+ Members members;
+ members.reserve(value_.map_->size());
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ObjectValues::const_iterator it = value_.map_->begin();
+ ObjectValues::const_iterator itEnd = value_.map_->end();
+ for (; it != itEnd; ++it)
+ members.push_back(std::string((*it).first.c_str()));
+#else
+ ValueInternalMap::IteratorState it;
+ ValueInternalMap::IteratorState itEnd;
+ value_.map_->makeBeginIterator(it);
+ value_.map_->makeEndIterator(itEnd);
+ for (; !ValueInternalMap::equals(it, itEnd); ValueInternalMap::increment(it))
+ members.push_back(std::string(ValueInternalMap::key(it)));
+#endif
+ return members;
+}
+//
+//# ifdef JSON_USE_CPPTL
+// EnumMemberNames
+// Value::enumMemberNames() const
+//{
+// if ( type_ == objectValue )
+// {
+// return CppTL::Enum::any( CppTL::Enum::transform(
+// CppTL::Enum::keys( *(value_.map_), CppTL::Type<const CZString &>() ),
+// MemberNamesTransform() ) );
+// }
+// return EnumMemberNames();
+//}
+//
+//
+// EnumValues
+// Value::enumValues() const
+//{
+// if ( type_ == objectValue || type_ == arrayValue )
+// return CppTL::Enum::anyValues( *(value_.map_),
+// CppTL::Type<const Value &>() );
+// return EnumValues();
+//}
+//
+//# endif
+
+static bool IsIntegral(double d) {
+ double integral_part;
+ return modf(d, &integral_part) == 0.0;
+}
+
+bool Value::isNull() const { return type_ == nullValue; }
+
+bool Value::isBool() const { return type_ == booleanValue; }
+
+bool Value::isInt() const {
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= minInt && value_.int_ <= maxInt;
+ case uintValue:
+ return value_.uint_ <= UInt(maxInt);
+ case realValue:
+ return value_.real_ >= minInt && value_.real_ <= maxInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isUInt() const {
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= 0 && LargestUInt(value_.int_) <= LargestUInt(maxUInt);
+ case uintValue:
+ return value_.uint_ <= maxUInt;
+ case realValue:
+ return value_.real_ >= 0 && value_.real_ <= maxUInt &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+ return false;
+}
+
+bool Value::isInt64() const {
+#if defined(JSON_HAS_INT64)
+ switch (type_) {
+ case intValue:
+ return true;
+ case uintValue:
+ return value_.uint_ <= UInt64(maxInt64);
+ case realValue:
+ // Note that maxInt64 (= 2^63 - 1) is not exactly representable as a
+ // double, so double(maxInt64) will be rounded up to 2^63. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= double(minInt64) &&
+ value_.real_ < double(maxInt64) && IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isUInt64() const {
+#if defined(JSON_HAS_INT64)
+ switch (type_) {
+ case intValue:
+ return value_.int_ >= 0;
+ case uintValue:
+ return true;
+ case realValue:
+ // Note that maxUInt64 (= 2^64 - 1) is not exactly representable as a
+ // double, so double(maxUInt64) will be rounded up to 2^64. Therefore we
+ // require the value to be strictly less than the limit.
+ return value_.real_ >= 0 && value_.real_ < maxUInt64AsDouble &&
+ IsIntegral(value_.real_);
+ default:
+ break;
+ }
+#endif // JSON_HAS_INT64
+ return false;
+}
+
+bool Value::isIntegral() const {
+#if defined(JSON_HAS_INT64)
+ return isInt64() || isUInt64();
+#else
+ return isInt() || isUInt();
+#endif
+}
+
+bool Value::isDouble() const { return type_ == realValue || isIntegral(); }
+
+bool Value::isNumeric() const { return isIntegral() || isDouble(); }
+
+bool Value::isString() const { return type_ == stringValue; }
+
+bool Value::isArray() const { return type_ == arrayValue; }
+
+bool Value::isObject() const { return type_ == objectValue; }
+
+void Value::setComment(const char* comment, CommentPlacement placement) {
+ if (!comments_)
+ comments_ = new CommentInfo[numberOfCommentPlacement];
+ comments_[placement].setComment(comment);
+}
+
+void Value::setComment(const std::string& comment, CommentPlacement placement) {
+ setComment(comment.c_str(), placement);
+}
+
+bool Value::hasComment(CommentPlacement placement) const {
+ return comments_ != 0 && comments_[placement].comment_ != 0;
+}
+
+std::string Value::getComment(CommentPlacement placement) const {
+ if (hasComment(placement))
+ return comments_[placement].comment_;
+ return "";
+}
+
+void Value::setOffsetStart(size_t start) { start_ = start; }
+
+void Value::setOffsetLimit(size_t limit) { limit_ = limit; }
+
+size_t Value::getOffsetStart() const { return start_; }
+
+size_t Value::getOffsetLimit() const { return limit_; }
+
+std::string Value::toStyledString() const {
+ StyledWriter writer;
+ return writer.write(*this);
+}
+
+Value::const_iterator Value::begin() const {
+ switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if (value_.array_) {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeBeginIterator(it);
+ return const_iterator(it);
+ }
+ break;
+ case objectValue:
+ if (value_.map_) {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeBeginIterator(it);
+ return const_iterator(it);
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return const_iterator(value_.map_->begin());
+ break;
+#endif
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+Value::const_iterator Value::end() const {
+ switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if (value_.array_) {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeEndIterator(it);
+ return const_iterator(it);
+ }
+ break;
+ case objectValue:
+ if (value_.map_) {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeEndIterator(it);
+ return const_iterator(it);
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return const_iterator(value_.map_->end());
+ break;
+#endif
+ default:
+ break;
+ }
+ return const_iterator();
+}
+
+Value::iterator Value::begin() {
+ switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if (value_.array_) {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeBeginIterator(it);
+ return iterator(it);
+ }
+ break;
+ case objectValue:
+ if (value_.map_) {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeBeginIterator(it);
+ return iterator(it);
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return iterator(value_.map_->begin());
+ break;
+#endif
+ default:
+ break;
+ }
+ return iterator();
+}
+
+Value::iterator Value::end() {
+ switch (type_) {
+#ifdef JSON_VALUE_USE_INTERNAL_MAP
+ case arrayValue:
+ if (value_.array_) {
+ ValueInternalArray::IteratorState it;
+ value_.array_->makeEndIterator(it);
+ return iterator(it);
+ }
+ break;
+ case objectValue:
+ if (value_.map_) {
+ ValueInternalMap::IteratorState it;
+ value_.map_->makeEndIterator(it);
+ return iterator(it);
+ }
+ break;
+#else
+ case arrayValue:
+ case objectValue:
+ if (value_.map_)
+ return iterator(value_.map_->end());
+ break;
+#endif
+ default:
+ break;
+ }
+ return iterator();
+}
+
+// class PathArgument
+// //////////////////////////////////////////////////////////////////
+
+PathArgument::PathArgument() : key_(), index_(), kind_(kindNone) {}
+
+PathArgument::PathArgument(ArrayIndex index)
+ : key_(), index_(index), kind_(kindIndex) {}
+
+PathArgument::PathArgument(const char* key)
+ : key_(key), index_(), kind_(kindKey) {}
+
+PathArgument::PathArgument(const std::string& key)
+ : key_(key.c_str()), index_(), kind_(kindKey) {}
+
+// class Path
+// //////////////////////////////////////////////////////////////////
+
+Path::Path(const std::string& path,
+ const PathArgument& a1,
+ const PathArgument& a2,
+ const PathArgument& a3,
+ const PathArgument& a4,
+ const PathArgument& a5) {
+ InArgs in;
+ in.push_back(&a1);
+ in.push_back(&a2);
+ in.push_back(&a3);
+ in.push_back(&a4);
+ in.push_back(&a5);
+ makePath(path, in);
+}
+
+void Path::makePath(const std::string& path, const InArgs& in) {
+ const char* current = path.c_str();
+ const char* end = current + path.length();
+ InArgs::const_iterator itInArg = in.begin();
+ while (current != end) {
+ if (*current == '[') {
+ ++current;
+ if (*current == '%')
+ addPathInArg(path, in, itInArg, PathArgument::kindIndex);
+ else {
+ ArrayIndex index = 0;
+ for (; current != end && *current >= '0' && *current <= '9'; ++current)
+ index = index * 10 + ArrayIndex(*current - '0');
+ args_.push_back(index);
+ }
+ if (current == end || *current++ != ']')
+ invalidPath(path, int(current - path.c_str()));
+ } else if (*current == '%') {
+ addPathInArg(path, in, itInArg, PathArgument::kindKey);
+ ++current;
+ } else if (*current == '.') {
+ ++current;
+ } else {
+ const char* beginName = current;
+ while (current != end && !strchr("[.", *current))
+ ++current;
+ args_.push_back(std::string(beginName, current));
+ }
+ }
+}
+
+void Path::addPathInArg(const std::string& /*path*/,
+ const InArgs& in,
+ InArgs::const_iterator& itInArg,
+ PathArgument::Kind kind) {
+ if (itInArg == in.end()) {
+ // Error: missing argument %d
+ } else if ((*itInArg)->kind_ != kind) {
+ // Error: bad argument type
+ } else {
+ args_.push_back(**itInArg);
+ }
+}
+
+void Path::invalidPath(const std::string& /*path*/, int /*location*/) {
+ // Error: invalid path.
+}
+
+const Value& Path::resolve(const Value& root) const {
+ const Value* node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+ const PathArgument& arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex) {
+ if (!node->isArray() || !node->isValidIndex(arg.index_)) {
+ // Error: unable to resolve path (array value expected at position...
+ }
+ node = &((*node)[arg.index_]);
+ } else if (arg.kind_ == PathArgument::kindKey) {
+ if (!node->isObject()) {
+ // Error: unable to resolve path (object value expected at position...)
+ }
+ node = &((*node)[arg.key_]);
+ if (node == &Value::null) {
+ // Error: unable to resolve path (object has no member named '' at
+ // position...)
+ }
+ }
+ }
+ return *node;
+}
+
+Value Path::resolve(const Value& root, const Value& defaultValue) const {
+ const Value* node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+ const PathArgument& arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex) {
+ if (!node->isArray() || !node->isValidIndex(arg.index_))
+ return defaultValue;
+ node = &((*node)[arg.index_]);
+ } else if (arg.kind_ == PathArgument::kindKey) {
+ if (!node->isObject())
+ return defaultValue;
+ node = &((*node)[arg.key_]);
+ if (node == &Value::null)
+ return defaultValue;
+ }
+ }
+ return *node;
+}
+
+Value& Path::make(Value& root) const {
+ Value* node = &root;
+ for (Args::const_iterator it = args_.begin(); it != args_.end(); ++it) {
+ const PathArgument& arg = *it;
+ if (arg.kind_ == PathArgument::kindIndex) {
+ if (!node->isArray()) {
+ // Error: node is not an array at position ...
+ }
+ node = &((*node)[arg.index_]);
+ } else if (arg.kind_ == PathArgument::kindKey) {
+ if (!node->isObject()) {
+ // Error: node is not an object at position...
+ }
+ node = &((*node)[arg.key_]);
+ }
+ }
+ return *node;
+}
+
+} // namespace Json
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl b/Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
new file mode 100644
index 000000000..a9f7df63a
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_valueiterator.inl
@@ -0,0 +1,241 @@
+// Copyright 2007-2010 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+// included by json_value.cpp
+
+namespace Json {
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIteratorBase
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIteratorBase::ValueIteratorBase()
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ : current_(), isNull_(true) {
+}
+#else
+ : isArray_(true), isNull_(true) {
+ iterator_.array_ = ValueInternalArray::IteratorState();
+}
+#endif
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIteratorBase::ValueIteratorBase(
+ const Value::ObjectValues::iterator& current)
+ : current_(current), isNull_(false) {}
+#else
+ValueIteratorBase::ValueIteratorBase(
+ const ValueInternalArray::IteratorState& state)
+ : isArray_(true) {
+ iterator_.array_ = state;
+}
+
+ValueIteratorBase::ValueIteratorBase(
+ const ValueInternalMap::IteratorState& state)
+ : isArray_(false) {
+ iterator_.map_ = state;
+}
+#endif
+
+Value& ValueIteratorBase::deref() const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ return current_->second;
+#else
+ if (isArray_)
+ return ValueInternalArray::dereference(iterator_.array_);
+ return ValueInternalMap::value(iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::increment() {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ ++current_;
+#else
+ if (isArray_)
+ ValueInternalArray::increment(iterator_.array_);
+ ValueInternalMap::increment(iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::decrement() {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ --current_;
+#else
+ if (isArray_)
+ ValueInternalArray::decrement(iterator_.array_);
+ ValueInternalMap::decrement(iterator_.map_);
+#endif
+}
+
+ValueIteratorBase::difference_type
+ValueIteratorBase::computeDistance(const SelfType& other) const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+#ifdef JSON_USE_CPPTL_SMALLMAP
+ return current_ - other.current_;
+#else
+ // Iterator for null value are initialized using the default
+ // constructor, which initialize current_ to the default
+ // std::map::iterator. As begin() and end() are two instance
+ // of the default std::map::iterator, they can not be compared.
+ // To allow this, we handle this comparison specifically.
+ if (isNull_ && other.isNull_) {
+ return 0;
+ }
+
+ // Usage of std::distance is not portable (does not compile with Sun Studio 12
+ // RogueWave STL,
+ // which is the one used by default).
+ // Using a portable hand-made version for non random iterator instead:
+ // return difference_type( std::distance( current_, other.current_ ) );
+ difference_type myDistance = 0;
+ for (Value::ObjectValues::iterator it = current_; it != other.current_;
+ ++it) {
+ ++myDistance;
+ }
+ return myDistance;
+#endif
+#else
+ if (isArray_)
+ return ValueInternalArray::distance(iterator_.array_,
+ other.iterator_.array_);
+ return ValueInternalMap::distance(iterator_.map_, other.iterator_.map_);
+#endif
+}
+
+bool ValueIteratorBase::isEqual(const SelfType& other) const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ if (isNull_) {
+ return other.isNull_;
+ }
+ return current_ == other.current_;
+#else
+ if (isArray_)
+ return ValueInternalArray::equals(iterator_.array_, other.iterator_.array_);
+ return ValueInternalMap::equals(iterator_.map_, other.iterator_.map_);
+#endif
+}
+
+void ValueIteratorBase::copy(const SelfType& other) {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ current_ = other.current_;
+ isNull_ = other.isNull_;
+#else
+ if (isArray_)
+ iterator_.array_ = other.iterator_.array_;
+ iterator_.map_ = other.iterator_.map_;
+#endif
+}
+
+Value ValueIteratorBase::key() const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const Value::CZString czstring = (*current_).first;
+ if (czstring.c_str()) {
+ if (czstring.isStaticString())
+ return Value(StaticString(czstring.c_str()));
+ return Value(czstring.c_str());
+ }
+ return Value(czstring.index());
+#else
+ if (isArray_)
+ return Value(ValueInternalArray::indexOf(iterator_.array_));
+ bool isStatic;
+ const char* memberName = ValueInternalMap::key(iterator_.map_, isStatic);
+ if (isStatic)
+ return Value(StaticString(memberName));
+ return Value(memberName);
+#endif
+}
+
+UInt ValueIteratorBase::index() const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const Value::CZString czstring = (*current_).first;
+ if (!czstring.c_str())
+ return czstring.index();
+ return Value::UInt(-1);
+#else
+ if (isArray_)
+ return Value::UInt(ValueInternalArray::indexOf(iterator_.array_));
+ return Value::UInt(-1);
+#endif
+}
+
+const char* ValueIteratorBase::memberName() const {
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ const char* name = (*current_).first.c_str();
+ return name ? name : "";
+#else
+ if (!isArray_)
+ return ValueInternalMap::key(iterator_.map_);
+ return "";
+#endif
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueConstIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueConstIterator::ValueConstIterator() {}
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueConstIterator::ValueConstIterator(
+ const Value::ObjectValues::iterator& current)
+ : ValueIteratorBase(current) {}
+#else
+ValueConstIterator::ValueConstIterator(
+ const ValueInternalArray::IteratorState& state)
+ : ValueIteratorBase(state) {}
+
+ValueConstIterator::ValueConstIterator(
+ const ValueInternalMap::IteratorState& state)
+ : ValueIteratorBase(state) {}
+#endif
+
+ValueConstIterator& ValueConstIterator::
+operator=(const ValueIteratorBase& other) {
+ copy(other);
+ return *this;
+}
+
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// class ValueIterator
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+// //////////////////////////////////////////////////////////////////
+
+ValueIterator::ValueIterator() {}
+
+#ifndef JSON_VALUE_USE_INTERNAL_MAP
+ValueIterator::ValueIterator(const Value::ObjectValues::iterator& current)
+ : ValueIteratorBase(current) {}
+#else
+ValueIterator::ValueIterator(const ValueInternalArray::IteratorState& state)
+ : ValueIteratorBase(state) {}
+
+ValueIterator::ValueIterator(const ValueInternalMap::IteratorState& state)
+ : ValueIteratorBase(state) {}
+#endif
+
+ValueIterator::ValueIterator(const ValueConstIterator& other)
+ : ValueIteratorBase(other) {}
+
+ValueIterator::ValueIterator(const ValueIterator& other)
+ : ValueIteratorBase(other) {}
+
+ValueIterator& ValueIterator::operator=(const SelfType& other) {
+ copy(other);
+ return *this;
+}
+
+} // namespace Json
diff --git a/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
new file mode 100644
index 000000000..e3f4e53cf
--- /dev/null
+++ b/Utilities/cmjsoncpp/src/lib_json/json_writer.cpp
@@ -0,0 +1,724 @@
+// Copyright 2011 Baptiste Lepilleur
+// Distributed under MIT license, or public domain if desired and
+// recognized in your jurisdiction.
+// See file LICENSE for detail or copy at http://jsoncpp.sourceforge.net/LICENSE
+
+#if !defined(JSON_IS_AMALGAMATION)
+#include <json/writer.h>
+#include "json_tool.h"
+#endif // if !defined(JSON_IS_AMALGAMATION)
+#include <utility>
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <sstream>
+#include <iomanip>
+#include <math.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1500 // VC++ 8.0 and below
+#include <float.h>
+#define isfinite _finite
+#define snprintf _snprintf
+#endif
+
+// Solaris
+#if defined(__sun)
+# include <ieeefp.h>
+# if !defined(isfinite)
+# define isfinite finite
+# endif
+#endif
+
+// AIX
+#if defined(_AIX)
+# if !defined(isfinite)
+# define isfinite finite
+# endif
+#endif
+
+// HP-UX
+#if defined(__hpux)
+# if !defined(isfinite)
+# if defined(__ia64) && !defined(finite)
+# define isfinite(x) ((sizeof(x) == sizeof(float) ? \
+ _Isfinitef(x) : _Isfinite(x)))
+# else
+# define isfinite finite
+# endif
+# endif
+#endif
+
+// Ancient glibc
+#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 2
+# if !defined(isfinite)
+# define isfinite __finite
+# endif
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400 // VC++ 8.0
+// Disable warning about strdup being deprecated.
+#pragma warning(disable : 4996)
+#endif
+
+namespace Json {
+
+static bool containsControlCharacter(const char* str) {
+ while (*str) {
+ if (isControlCharacter(*(str++)))
+ return true;
+ }
+ return false;
+}
+
+std::string valueToString(LargestInt value) {
+ UIntToStringBuffer buffer;
+ char* current = buffer + sizeof(buffer);
+ bool isNegative = value < 0;
+ if (isNegative)
+ value = -value;
+ uintToString(LargestUInt(value), current);
+ if (isNegative)
+ *--current = '-';
+ assert(current >= buffer);
+ return current;
+}
+
+std::string valueToString(LargestUInt value) {
+ UIntToStringBuffer buffer;
+ char* current = buffer + sizeof(buffer);
+ uintToString(value, current);
+ assert(current >= buffer);
+ return current;
+}
+
+#if defined(JSON_HAS_INT64)
+
+std::string valueToString(Int value) {
+ return valueToString(LargestInt(value));
+}
+
+std::string valueToString(UInt value) {
+ return valueToString(LargestUInt(value));
+}
+
+#endif // # if defined(JSON_HAS_INT64)
+
+std::string valueToString(double value) {
+ // Allocate a buffer that is more than large enough to store the 16 digits of
+ // precision requested below.
+ char buffer[32];
+ int len = -1;
+
+// Print into the buffer. We need not request the alternative representation
+// that always has a decimal point because JSON doesn't distingish the
+// concepts of reals and integers.
+#if defined(_MSC_VER) && defined(__STDC_SECURE_LIB__) // Use secure version with
+ // visual studio 2005 to
+ // avoid warning.
+#if defined(WINCE)
+ len = _snprintf(buffer, sizeof(buffer), "%.16g", value);
+#else
+ len = sprintf_s(buffer, sizeof(buffer), "%.16g", value);
+#endif
+#else
+ if (isfinite(value)) {
+ len = snprintf(buffer, sizeof(buffer), "%.16g", value);
+ } else {
+ // IEEE standard states that NaN values will not compare to themselves
+ if (value != value) {
+ len = snprintf(buffer, sizeof(buffer), "null");
+ } else if (value < 0) {
+ len = snprintf(buffer, sizeof(buffer), "-1e+9999");
+ } else {
+ len = snprintf(buffer, sizeof(buffer), "1e+9999");
+ }
+ // For those, we do not need to call fixNumLoc, but it is fast.
+ }
+#endif
+ assert(len >= 0);
+ fixNumericLocale(buffer, buffer + len);
+ return buffer;
+}
+
+std::string valueToString(bool value) { return value ? "true" : "false"; }
+
+std::string valueToQuotedString(const char* value) {
+ if (value == NULL)
+ return "";
+ // Not sure how to handle unicode...
+ if (strpbrk(value, "\"\\\b\f\n\r\t") == NULL &&
+ !containsControlCharacter(value))
+ return std::string("\"") + value + "\"";
+ // We have to walk value and escape any special characters.
+ // Appending to std::string is not efficient, but this should be rare.
+ // (Note: forward slashes are *not* rare, but I am not escaping them.)
+ std::string::size_type maxsize =
+ strlen(value) * 2 + 3; // allescaped+quotes+NULL
+ std::string result;
+ result.reserve(maxsize); // to avoid lots of mallocs
+ result += "\"";
+ for (const char* c = value; *c != 0; ++c) {
+ switch (*c) {
+ case '\"':
+ result += "\\\"";
+ break;
+ case '\\':
+ result += "\\\\";
+ break;
+ case '\b':
+ result += "\\b";
+ break;
+ case '\f':
+ result += "\\f";
+ break;
+ case '\n':
+ result += "\\n";
+ break;
+ case '\r':
+ result += "\\r";
+ break;
+ case '\t':
+ result += "\\t";
+ break;
+ // case '/':
+ // Even though \/ is considered a legal escape in JSON, a bare
+ // slash is also legal, so I see no reason to escape it.
+ // (I hope I am not misunderstanding something.
+ // blep notes: actually escaping \/ may be useful in javascript to avoid </
+ // sequence.
+ // Should add a flag to allow this compatibility mode and prevent this
+ // sequence from occurring.
+ default:
+ if (isControlCharacter(*c)) {
+ std::ostringstream oss;
+ oss << "\\u" << std::hex << std::uppercase << std::setfill('0')
+ << std::setw(4) << static_cast<int>(*c);
+ result += oss.str();
+ } else {
+ result += *c;
+ }
+ break;
+ }
+ }
+ result += "\"";
+ return result;
+}
+
+// Class Writer
+// //////////////////////////////////////////////////////////////////
+Writer::~Writer() {}
+
+// Class FastWriter
+// //////////////////////////////////////////////////////////////////
+
+FastWriter::FastWriter()
+ : yamlCompatiblityEnabled_(false), dropNullPlaceholders_(false),
+ omitEndingLineFeed_(false) {}
+
+void FastWriter::enableYAMLCompatibility() { yamlCompatiblityEnabled_ = true; }
+
+void FastWriter::dropNullPlaceholders() { dropNullPlaceholders_ = true; }
+
+void FastWriter::omitEndingLineFeed() { omitEndingLineFeed_ = true; }
+
+std::string FastWriter::write(const Value& root) {
+ document_ = "";
+ writeValue(root);
+ if (!omitEndingLineFeed_)
+ document_ += "\n";
+ return document_;
+}
+
+void FastWriter::writeValue(const Value& value) {
+ switch (value.type()) {
+ case nullValue:
+ if (!dropNullPlaceholders_)
+ document_ += "null";
+ break;
+ case intValue:
+ document_ += valueToString(value.asLargestInt());
+ break;
+ case uintValue:
+ document_ += valueToString(value.asLargestUInt());
+ break;
+ case realValue:
+ document_ += valueToString(value.asDouble());
+ break;
+ case stringValue:
+ document_ += valueToQuotedString(value.asCString());
+ break;
+ case booleanValue:
+ document_ += valueToString(value.asBool());
+ break;
+ case arrayValue: {
+ document_ += '[';
+ int size = value.size();
+ for (int index = 0; index < size; ++index) {
+ if (index > 0)
+ document_ += ',';
+ writeValue(value[index]);
+ }
+ document_ += ']';
+ } break;
+ case objectValue: {
+ Value::Members members(value.getMemberNames());
+ document_ += '{';
+ for (Value::Members::iterator it = members.begin(); it != members.end();
+ ++it) {
+ const std::string& name = *it;
+ if (it != members.begin())
+ document_ += ',';
+ document_ += valueToQuotedString(name.c_str());
+ document_ += yamlCompatiblityEnabled_ ? ": " : ":";
+ writeValue(value[name]);
+ }
+ document_ += '}';
+ } break;
+ }
+}
+
+// Class StyledWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledWriter::StyledWriter()
+ : rightMargin_(74), indentSize_(3), addChildValues_() {}
+
+std::string StyledWriter::write(const Value& root) {
+ document_ = "";
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue(root);
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ document_ += "\n";
+ return document_;
+}
+
+void StyledWriter::writeValue(const Value& value) {
+ switch (value.type()) {
+ case nullValue:
+ pushValue("null");
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ break;
+ case realValue:
+ pushValue(valueToString(value.asDouble()));
+ break;
+ case stringValue:
+ pushValue(valueToQuotedString(value.asCString()));
+ break;
+ case booleanValue:
+ pushValue(valueToString(value.asBool()));
+ break;
+ case arrayValue:
+ writeArrayValue(value);
+ break;
+ case objectValue: {
+ Value::Members members(value.getMemberNames());
+ if (members.empty())
+ pushValue("{}");
+ else {
+ writeWithIndent("{");
+ indent();
+ Value::Members::iterator it = members.begin();
+ for (;;) {
+ const std::string& name = *it;
+ const Value& childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ document_ += " : ";
+ writeValue(childValue);
+ if (++it == members.end()) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ } break;
+ }
+}
+
+void StyledWriter::writeArrayValue(const Value& value) {
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine) {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;) {
+ const Value& childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else {
+ writeIndent();
+ writeValue(childValue);
+ }
+ if (++index == size) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ document_ += ',';
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ } else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ document_ += "[ ";
+ for (unsigned index = 0; index < size; ++index) {
+ if (index > 0)
+ document_ += ", ";
+ document_ += childValues_[index];
+ }
+ document_ += " ]";
+ }
+ }
+}
+
+bool StyledWriter::isMultineArray(const Value& value) {
+ int size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (int index = 0; index < size && !isMultiLine; ++index) {
+ const Value& childValue = value[index];
+ isMultiLine =
+ isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (int index = 0; index < size; ++index) {
+ writeValue(value[index]);
+ lineLength += int(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void StyledWriter::pushValue(const std::string& value) {
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ document_ += value;
+}
+
+void StyledWriter::writeIndent() {
+ if (!document_.empty()) {
+ char last = document_[document_.length() - 1];
+ if (last == ' ') // already indented
+ return;
+ if (last != '\n') // Comments may add new-line
+ document_ += '\n';
+ }
+ document_ += indentString_;
+}
+
+void StyledWriter::writeWithIndent(const std::string& value) {
+ writeIndent();
+ document_ += value;
+}
+
+void StyledWriter::indent() { indentString_ += std::string(indentSize_, ' '); }
+
+void StyledWriter::unindent() {
+ assert(int(indentString_.size()) >= indentSize_);
+ indentString_.resize(indentString_.size() - indentSize_);
+}
+
+void StyledWriter::writeCommentBeforeValue(const Value& root) {
+ if (!root.hasComment(commentBefore))
+ return;
+
+ document_ += "\n";
+ writeIndent();
+ std::string normalizedComment = normalizeEOL(root.getComment(commentBefore));
+ std::string::const_iterator iter = normalizedComment.begin();
+ while (iter != normalizedComment.end()) {
+ document_ += *iter;
+ if (*iter == '\n' && *(iter + 1) == '/')
+ writeIndent();
+ ++iter;
+ }
+
+ // Comments are stripped of newlines, so add one here
+ document_ += "\n";
+}
+
+void StyledWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+ if (root.hasComment(commentAfterOnSameLine))
+ document_ += " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+ if (root.hasComment(commentAfter)) {
+ document_ += "\n";
+ document_ += normalizeEOL(root.getComment(commentAfter));
+ document_ += "\n";
+ }
+}
+
+bool StyledWriter::hasCommentForValue(const Value& value) {
+ return value.hasComment(commentBefore) ||
+ value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+std::string StyledWriter::normalizeEOL(const std::string& text) {
+ std::string normalized;
+ normalized.reserve(text.length());
+ const char* begin = text.c_str();
+ const char* end = begin + text.length();
+ const char* current = begin;
+ while (current != end) {
+ char c = *current++;
+ if (c == '\r') // mac or dos EOL
+ {
+ if (*current == '\n') // convert dos EOL
+ ++current;
+ normalized += '\n';
+ } else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+// Class StyledStreamWriter
+// //////////////////////////////////////////////////////////////////
+
+StyledStreamWriter::StyledStreamWriter(std::string indentation)
+ : document_(NULL), rightMargin_(74), indentation_(indentation),
+ addChildValues_() {}
+
+void StyledStreamWriter::write(std::ostream& out, const Value& root) {
+ document_ = &out;
+ addChildValues_ = false;
+ indentString_ = "";
+ writeCommentBeforeValue(root);
+ writeValue(root);
+ writeCommentAfterValueOnSameLine(root);
+ *document_ << "\n";
+ document_ = NULL; // Forget the stream, for safety.
+}
+
+void StyledStreamWriter::writeValue(const Value& value) {
+ switch (value.type()) {
+ case nullValue:
+ pushValue("null");
+ break;
+ case intValue:
+ pushValue(valueToString(value.asLargestInt()));
+ break;
+ case uintValue:
+ pushValue(valueToString(value.asLargestUInt()));
+ break;
+ case realValue:
+ pushValue(valueToString(value.asDouble()));
+ break;
+ case stringValue:
+ pushValue(valueToQuotedString(value.asCString()));
+ break;
+ case booleanValue:
+ pushValue(valueToString(value.asBool()));
+ break;
+ case arrayValue:
+ writeArrayValue(value);
+ break;
+ case objectValue: {
+ Value::Members members(value.getMemberNames());
+ if (members.empty())
+ pushValue("{}");
+ else {
+ writeWithIndent("{");
+ indent();
+ Value::Members::iterator it = members.begin();
+ for (;;) {
+ const std::string& name = *it;
+ const Value& childValue = value[name];
+ writeCommentBeforeValue(childValue);
+ writeWithIndent(valueToQuotedString(name.c_str()));
+ *document_ << " : ";
+ writeValue(childValue);
+ if (++it == members.end()) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("}");
+ }
+ } break;
+ }
+}
+
+void StyledStreamWriter::writeArrayValue(const Value& value) {
+ unsigned size = value.size();
+ if (size == 0)
+ pushValue("[]");
+ else {
+ bool isArrayMultiLine = isMultineArray(value);
+ if (isArrayMultiLine) {
+ writeWithIndent("[");
+ indent();
+ bool hasChildValue = !childValues_.empty();
+ unsigned index = 0;
+ for (;;) {
+ const Value& childValue = value[index];
+ writeCommentBeforeValue(childValue);
+ if (hasChildValue)
+ writeWithIndent(childValues_[index]);
+ else {
+ writeIndent();
+ writeValue(childValue);
+ }
+ if (++index == size) {
+ writeCommentAfterValueOnSameLine(childValue);
+ break;
+ }
+ *document_ << ",";
+ writeCommentAfterValueOnSameLine(childValue);
+ }
+ unindent();
+ writeWithIndent("]");
+ } else // output on a single line
+ {
+ assert(childValues_.size() == size);
+ *document_ << "[ ";
+ for (unsigned index = 0; index < size; ++index) {
+ if (index > 0)
+ *document_ << ", ";
+ *document_ << childValues_[index];
+ }
+ *document_ << " ]";
+ }
+ }
+}
+
+bool StyledStreamWriter::isMultineArray(const Value& value) {
+ int size = value.size();
+ bool isMultiLine = size * 3 >= rightMargin_;
+ childValues_.clear();
+ for (int index = 0; index < size && !isMultiLine; ++index) {
+ const Value& childValue = value[index];
+ isMultiLine =
+ isMultiLine || ((childValue.isArray() || childValue.isObject()) &&
+ childValue.size() > 0);
+ }
+ if (!isMultiLine) // check if line length > max line length
+ {
+ childValues_.reserve(size);
+ addChildValues_ = true;
+ int lineLength = 4 + (size - 1) * 2; // '[ ' + ', '*n + ' ]'
+ for (int index = 0; index < size; ++index) {
+ writeValue(value[index]);
+ lineLength += int(childValues_[index].length());
+ }
+ addChildValues_ = false;
+ isMultiLine = isMultiLine || lineLength >= rightMargin_;
+ }
+ return isMultiLine;
+}
+
+void StyledStreamWriter::pushValue(const std::string& value) {
+ if (addChildValues_)
+ childValues_.push_back(value);
+ else
+ *document_ << value;
+}
+
+void StyledStreamWriter::writeIndent() {
+ /*
+ Some comments in this method would have been nice. ;-)
+
+ if ( !document_.empty() )
+ {
+ char last = document_[document_.length()-1];
+ if ( last == ' ' ) // already indented
+ return;
+ if ( last != '\n' ) // Comments may add new-line
+ *document_ << '\n';
+ }
+ */
+ *document_ << '\n' << indentString_;
+}
+
+void StyledStreamWriter::writeWithIndent(const std::string& value) {
+ writeIndent();
+ *document_ << value;
+}
+
+void StyledStreamWriter::indent() { indentString_ += indentation_; }
+
+void StyledStreamWriter::unindent() {
+ assert(indentString_.size() >= indentation_.size());
+ indentString_.resize(indentString_.size() - indentation_.size());
+}
+
+void StyledStreamWriter::writeCommentBeforeValue(const Value& root) {
+ if (!root.hasComment(commentBefore))
+ return;
+ *document_ << normalizeEOL(root.getComment(commentBefore));
+ *document_ << "\n";
+}
+
+void StyledStreamWriter::writeCommentAfterValueOnSameLine(const Value& root) {
+ if (root.hasComment(commentAfterOnSameLine))
+ *document_ << " " + normalizeEOL(root.getComment(commentAfterOnSameLine));
+
+ if (root.hasComment(commentAfter)) {
+ *document_ << "\n";
+ *document_ << normalizeEOL(root.getComment(commentAfter));
+ *document_ << "\n";
+ }
+}
+
+bool StyledStreamWriter::hasCommentForValue(const Value& value) {
+ return value.hasComment(commentBefore) ||
+ value.hasComment(commentAfterOnSameLine) ||
+ value.hasComment(commentAfter);
+}
+
+std::string StyledStreamWriter::normalizeEOL(const std::string& text) {
+ std::string normalized;
+ normalized.reserve(text.length());
+ const char* begin = text.c_str();
+ const char* end = begin + text.length();
+ const char* current = begin;
+ while (current != end) {
+ char c = *current++;
+ if (c == '\r') // mac or dos EOL
+ {
+ if (*current == '\n') // convert dos EOL
+ ++current;
+ normalized += '\n';
+ } else // handle unix EOL & other char
+ normalized += c;
+ }
+ return normalized;
+}
+
+std::ostream& operator<<(std::ostream& sout, const Value& root) {
+ Json::StyledStreamWriter writer;
+ writer.write(sout, root);
+ return sout;
+}
+
+} // namespace Json
diff --git a/Utilities/cmlibarchive/.gitattributes b/Utilities/cmlibarchive/.gitattributes
index be7062b6e..562b12e16 100644
--- a/Utilities/cmlibarchive/.gitattributes
+++ b/Utilities/cmlibarchive/.gitattributes
@@ -1,2 +1 @@
-*.h whitespace=indent-with-non-tab,-blank-at-eol
-*.c whitespace=indent-with-non-tab,-blank-at-eol
+* -whitespace
diff --git a/Utilities/cmlibarchive/CMakeLists.txt b/Utilities/cmlibarchive/CMakeLists.txt
index 8ef0e89d6..bfe6b131e 100644
--- a/Utilities/cmlibarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/CMakeLists.txt
@@ -8,19 +8,22 @@ 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)
+# Enable @rpath in the install name.
+# detail in "cmake --help-policy CMP0042"
+SET(CMAKE_MACOSX_RPATH ON)
#
# 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})
+ "^([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})
+ "^[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})
+ "^[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})
+ "^[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})
@@ -28,11 +31,12 @@ 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(BSDCAT_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.7 == interface version 9 = 2 + 7
# libarchive 2.8 == interface version 10 = 2 + 8
# libarchive 2.9 == interface version 11 = 2 + 9
# libarchive 3.0 == interface version 12
@@ -55,13 +59,11 @@ SET(CMAKE_REQUIRED_LIBRARIES)
SET(CMAKE_REQUIRED_FLAGS)
# Disable warnings to avoid changing 3rd party code.
-IF("${CMAKE_C_COMPILER_ID}" MATCHES
- "^(GNU|Clang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+IF(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
-ELSEIF("${CMAKE_C_COMPILER_ID}" MATCHES "^(PathScale)$")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
-ELSEIF(BORLAND)
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w-")
ENDIF()
# Enable CTest/CDash support
@@ -69,19 +71,31 @@ include(CTest)
OPTION(ENABLE_NETTLE "Enable use of Nettle" ON)
OPTION(ENABLE_OPENSSL "Enable use of OpenSSL" ON)
+OPTION(ENABLE_LZO "Enable the use of the system LZO library if found" OFF)
+OPTION(ENABLE_LZMA "Enable the use of the system LZMA library if found" ON)
+
+OPTION(ENABLE_ZLIB "Enable the use of the system ZLIB library if found" ON)
+OPTION(ENABLE_BZip2 "Enable the use of the system BZip2 library if found" ON)
+OPTION(ENABLE_LIBXML2 "Enable the use of the system libxml2 library if found" ON)
+OPTION(ENABLE_EXPAT "Enable the use of the system EXPAT library if found" ON)
+OPTION(ENABLE_PCREPOSIX "Enable the use of the system PCREPOSIX library if found" ON)
+OPTION(ENABLE_LibGCC "Enable the use of the system LibGCC library if found" ON)
+# CNG is used for encrypt/decrypt Zip archives on Windows.
+OPTION(ENABLE_CNG "Enable the use of CNG(Crypto Next Generation)" 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})
+ #ELSEIF(WINDOWS_VERSION STREQUAL "WINXP")
+ SET(NTDDI_VERSION 0x05010000)
+ SET(_WIN32_WINNT 0x0501)
+ SET(WINVER 0x0501)
ENDIF(WIN32)
+set(HAVE_PTHREAD_H 0) # no threads in CMake
+
IF("${CMAKE_C_PLATFORM_ID}" MATCHES "^(HP-UX)$")
ADD_DEFINITIONS(-D_XOPEN_SOURCE=500) # Ask wchar.h for mbstate_t
ENDIF()
@@ -95,7 +109,7 @@ INCLUDE(CheckHeaderDirent)
INCLUDE(CheckIncludeFile)
INCLUDE(CheckIncludeFiles)
INCLUDE(CheckLibraryExists)
-INCLUDE(CheckStructMember)
+INCLUDE(CheckStructHasMember)
INCLUDE(CheckSymbolExists)
INCLUDE(CheckTypeExists)
INCLUDE(CheckTypeSize)
@@ -186,11 +200,11 @@ IF(DEFINED __GNUWIN32PATH AND EXISTS "${__GNUWIN32PATH}")
# 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.
+ # If compiling error occurred 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 */
@@ -204,7 +218,11 @@ SET(ADDITIONAL_LIBS "")
#
# Find ZLIB
#
-FIND_PACKAGE(ZLIB)
+IF(ENABLE_ZLIB)
+ FIND_PACKAGE(ZLIB)
+ELSE()
+ SET(ZLIB_FOUND FALSE) # Override cached value
+ENDIF()
IF(ZLIB_FOUND)
SET(HAVE_LIBZ 1)
SET(HAVE_ZLIB_H 1)
@@ -239,7 +257,11 @@ ENDIF(ZLIB_FOUND)
#
# Find BZip2
#
-FIND_PACKAGE(BZip2)
+IF(ENABLE_BZip2)
+ FIND_PACKAGE(BZip2)
+ELSE()
+ SET(BZIP2_FOUND FALSE) # Override cached value
+ENDIF()
IF(BZIP2_FOUND)
SET(HAVE_LIBBZ2 1)
SET(HAVE_BZLIB_H 1)
@@ -259,43 +281,55 @@ IF(BZIP2_FOUND)
ENDIF(BZIP2_FOUND)
MARK_AS_ADVANCED(CLEAR BZIP2_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR BZIP2_LIBRARIES)
-IF(0) # CMake does not need LZMA or LZO2 support in libarchive
+
+
#
# Find LZMA
#
-FIND_PACKAGE(LZMA)
-IF(LZMA_FOUND)
+IF(ENABLE_LZMA)
+ FIND_PACKAGE(LibLZMA)
+ELSE()
+ SET(LIBZMA_FOUND FALSE) # Override cached value
+ENDIF()
+
+IF(LIBLZMA_FOUND)
SET(HAVE_LIBLZMA 1)
SET(HAVE_LZMA_H 1)
- INCLUDE_DIRECTORIES(${LZMA_INCLUDE_DIR})
- LIST(APPEND ADDITIONAL_LIBS ${LZMA_LIBRARIES})
- # Test if a macro is needed for the library.
- TRY_MACRO_FOR_LIBRARY(
- "${LZMA_INCLUDE_DIR}" "${LZMA_LIBRARIES}"
- COMPILES
- "#include <lzma.h>\nint main() {return (int)lzma_version_number(); }"
- "WITHOUT_LZMA_API_STATIC;LZMA_API_STATIC")
- IF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
+ INCLUDE_DIRECTORIES(${LIBLZMA_INCLUDE_DIRS})
+ LIST(APPEND ADDITIONAL_LIBS ${LIBLZMA_LIBRARIES})
+ IF(CMAKE_USE_SYSTEM_LIBLZMA)
+ # Test if a macro is needed for the library.
+ TRY_MACRO_FOR_LIBRARY(
+ "${LIBLZMA_INCLUDE_DIRS}" "${LIBLZMA_LIBRARIES}"
+ COMPILES
+ "#include <lzma.h>\nint main() {return (int)lzma_version_number(); }"
+ "WITHOUT_LZMA_API_STATIC;LZMA_API_STATIC")
+ IF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
+ ADD_DEFINITIONS(-DLZMA_API_STATIC)
+ ENDIF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
+ ELSE()
ADD_DEFINITIONS(-DLZMA_API_STATIC)
- ENDIF(NOT WITHOUT_LZMA_API_STATIC AND LZMA_API_STATIC)
-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()
+ELSE(LIBLZMA_FOUND)
+# LZMA not found and will not be used.
+ENDIF(LIBLZMA_FOUND)
+IF(0) # CMake does not need LZO2 support in libarchive
#
# Find LZO2
#
-IF (LZO2_INCLUDE_DIR)
- # Already in cache, be silent
- SET(LZO2_FIND_QUIETLY TRUE)
-ENDIF (LZO2_INCLUDE_DIR)
-
-FIND_PATH(LZO2_INCLUDE_DIR lzo/lzoconf.h)
-FIND_LIBRARY(LZO2_LIBRARY NAMES lzo2 liblzo2)
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO2 DEFAULT_MSG LZO2_LIBRARY LZO2_INCLUDE_DIR)
+IF(ENABLE_LZO)
+ IF (LZO2_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(LZO2_FIND_QUIETLY TRUE)
+ ENDIF (LZO2_INCLUDE_DIR)
+
+ FIND_PATH(LZO2_INCLUDE_DIR lzo/lzoconf.h)
+ FIND_LIBRARY(LZO2_LIBRARY NAMES lzo2 liblzo2)
+ INCLUDE(FindPackageHandleStandardArgs)
+ FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZO2 DEFAULT_MSG LZO2_LIBRARY LZO2_INCLUDE_DIR)
+ELSE(ENABLE_LZO)
+ SET(LIBZMA_FOUND FALSE) # Override cached value
+ENDIF(ENABLE_LZO)
IF(LZO2_FOUND)
SET(HAVE_LIBLZO2 1)
SET(HAVE_LZO_LZOCONF_H 1)
@@ -309,6 +343,35 @@ ENDIF(LZO2_FOUND)
MARK_AS_ADVANCED(CLEAR LZO2_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR LZO2_LIBRARY)
ENDIF()
+IF(0) # CMake does not need LZ4 support in libarchive
+#
+# Find LZ4
+#
+IF (LZ4_INCLUDE_DIR)
+ # Already in cache, be silent
+ SET(LZ4_FIND_QUIETLY TRUE)
+ENDIF (LZ4_INCLUDE_DIR)
+
+FIND_PATH(LZ4_INCLUDE_DIR lz4.h)
+FIND_LIBRARY(LZ4_LIBRARY NAMES lz4 liblz4)
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZ4 DEFAULT_MSG LZ4_LIBRARY LZ4_INCLUDE_DIR)
+IF(LZ4_FOUND)
+ SET(HAVE_LIBLZ4 1)
+ SET(HAVE_LZ4_H 1)
+ CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
+ SET(CMAKE_REQUIRED_INCLUDES ${LZ4_INCLUDE_DIR})
+ CHECK_INCLUDE_FILES("lz4hc.h" HAVE_LZ4HC_H)
+ CMAKE_POP_CHECK_STATE() # Restore the state of the variables
+ INCLUDE_DIRECTORIES(${LZ4_INCLUDE_DIR})
+ LIST(APPEND ADDITIONAL_LIBS ${LZ4_LIBRARY})
+ #
+ # TODO: test for static library.
+ #
+ENDIF(LZ4_FOUND)
+MARK_AS_ADVANCED(CLEAR LZ4_INCLUDE_DIR)
+MARK_AS_ADVANCED(CLEAR LZ4_LIBRARY)
+ENDIF()
#
# Check headers
@@ -327,7 +390,11 @@ ENDMACRO (LA_CHECK_INCLUDE_FILE)
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)
+IF(ENABLE_ACL)
+ LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H)
+ELSE(ENABLE_ACL)
+ SET(HAVE_ACL_LIBACL_H FALSE)
+ENDIF(ENABLE_ACL)
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)
@@ -348,13 +415,20 @@ 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)
+
+CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
+#include <linux/fs.h>
+int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
+
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("pthread.h" HAVE_PTHREAD_H)
LA_CHECK_INCLUDE_FILE("pwd.h" HAVE_PWD_H)
+LA_CHECK_INCLUDE_FILE("readpassphrase.h" HAVE_READPASSPHRASE_H)
LA_CHECK_INCLUDE_FILE("regex.h" HAVE_REGEX_H)
LA_CHECK_INCLUDE_FILE("signal.h" HAVE_SIGNAL_H)
LA_CHECK_INCLUDE_FILE("spawn.h" HAVE_SPAWN_H)
@@ -385,7 +459,12 @@ 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.
+IF(ENABLE_CNG)
+ LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H)
+ELSE(ENABLE_CNG)
+ UNSET(HAVE_BCRYPT_H CACHE)
+ENDIF(ENABLE_CNG)
+# Following files need windows.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)
@@ -411,11 +490,17 @@ IF(ENABLE_NETTLE)
FIND_PACKAGE(Nettle)
IF(NETTLE_FOUND)
SET(HAVE_LIBNETTLE 1)
- SET(HAVE_NETTLE_MD5_H 1)
- SET(HAVE_NETTLE_RIPEMD160_H 1)
- SET(HAVE_NETTLE_SHA_H 1)
- INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
LIST(APPEND ADDITIONAL_LIBS ${NETTLE_LIBRARIES})
+ INCLUDE_DIRECTORIES(${NETTLE_INCLUDE_DIR})
+
+ LIST(APPEND CMAKE_REQUIRED_INCLUDES ${NETTLE_INCLUDE_DIR})
+ LA_CHECK_INCLUDE_FILE("nettle/aes.h" HAVE_NETTLE_AES_H)
+ LA_CHECK_INCLUDE_FILE("nettle/hmac.h" HAVE_NETTLE_HMAC_H)
+ LA_CHECK_INCLUDE_FILE("nettle/md5.h" HAVE_NETTLE_MD5_H)
+ LA_CHECK_INCLUDE_FILE("nettle/pbkdf2.h" HAVE_NETTLE_PBKDF2_H)
+ LA_CHECK_INCLUDE_FILE("nettle/ripemd160.h" HAVE_NETTLE_RIPEMD160_H)
+ LA_CHECK_INCLUDE_FILE("nettle/sha.h" HAVE_NETTLE_SHA_H)
+
ENDIF(NETTLE_FOUND)
MARK_AS_ADVANCED(CLEAR NETTLE_INCLUDE_DIR)
MARK_AS_ADVANCED(CLEAR NETTLE_LIBRARIES)
@@ -427,6 +512,10 @@ ENDIF(ENABLE_NETTLE)
#
IF(ENABLE_OPENSSL AND NOT CMAKE_SYSTEM_NAME MATCHES "Darwin")
FIND_PACKAGE(OpenSSL)
+ IF(OPENSSL_FOUND)
+ SET(HAVE_LIBCRYPTO 1)
+ INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
+ ENDIF(OPENSSL_FOUND)
ELSE()
SET(OPENSSL_FOUND FALSE) # Override cached value
ENDIF()
@@ -445,7 +534,7 @@ ENDIF(NOT OPENSSL_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
+# platforms, just see if archive_digest.c can compile and link against
# required libraries.
#
MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
@@ -484,7 +573,7 @@ MACRO(CHECK_CRYPTO ALGORITHMS IMPLEMENTATION)
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h)
FILE(READ "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/confdefs.h"
CONFDEFS_H)
- FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_crypto.c"
+ FILE(READ "${CMAKE_CURRENT_SOURCE_DIR}/libarchive/archive_digest.c"
ARCHIVE_CRYPTO_C)
SET(SOURCE "${CONFDEFS_H}
@@ -510,16 +599,10 @@ main(int argc, char **argv)
FILE(WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c" "${SOURCE}")
MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}")
- IF(CMAKE_REQUIRED_LINKER_FLAGS)
- SET(CHECK_CRYPTO_ADD_LINKER_FLAGS
- "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
- ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
- SET(CHECK_CRYPTO_ADD_LINKER_FLAGS)
- ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
TRY_COMPILE(ARCHIVE_CRYPTO_${ALGORITHM}_${IMPLEMENTATION}
${CMAKE_BINARY_DIR}
${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/check_crypto_md.c
- CMAKE_FLAGS ${CHECK_CRYPTO_ADD_LINKER_FLAGS}
+ CMAKE_FLAGS
"${TRY_CRYPTO_REQUIRED_LIBS}"
"${TRY_CRYPTO_REQUIRED_INCLUDES}"
OUTPUT_VARIABLE OUTPUT)
@@ -604,16 +687,10 @@ main(int argc, char **argv)
FILE(WRITE "${SOURCE_FILE}" "${SOURCE}")
MESSAGE(STATUS "Checking support for ARCHIVE_CRYPTO_${CRYPTO}_WIN")
- IF(CMAKE_REQUIRED_LINKER_FLAGS)
- SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS
- "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_REQUIRED_LINKER_FLAGS}")
- ELSE(CMAKE_REQUIRED_LINKER_FLAGS)
- SET(CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS)
- ENDIF(CMAKE_REQUIRED_LINKER_FLAGS)
TRY_COMPILE(ARCHIVE_CRYPTO_${CRYPTO}_WIN
${CMAKE_BINARY_DIR}
${SOURCE_FILE}
- CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive" ${CHECK_CRYPTO_WIN_ADD_LINKER_FLAGS}
+ CMAKE_FLAGS "-DINCLUDE_DIRECTORIES:STRING=${CMAKE_BINARY_DIR};${CMAKE_CURRENT_SOURCE_DIR}/libarchive"
OUTPUT_VARIABLE OUTPUT)
IF (ARCHIVE_CRYPTO_${CRYPTO}_WIN)
@@ -646,14 +723,18 @@ ENDMACRO(CHECK_CRYPTO_WIN CRYPTO_LIST)
MACRO(CHECK_ICONV LIB TRY_ICONV_CONST)
IF(NOT HAVE_ICONV)
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
- IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+ IF (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
+ CMAKE_C_COMPILER_ID STREQUAL "Clang")
#
# During checking iconv proto type, we should use -Werror to avoid the
# success of iconv detection with a warnig which success is a miss
# detection. So this needs for all build mode(even it's a release mode).
#
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
- ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+ ENDIF ()
+ IF (CMAKE_C_COMPILER_ID STREQUAL "XL")
+ SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -qhalt=w -qflag=w:w")
+ ENDIF ()
IF (MSVC)
# NOTE: /WX option is the same as gcc's -Werror option.
SET(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} /WX")
@@ -777,7 +858,11 @@ IF(0) # CMake does not need XML support in libarchive
#
# Find Libxml2
#
-FIND_PACKAGE(LibXml2)
+IF(ENABLE_LIBXML2)
+ FIND_PACKAGE(LibXml2)
+ELSE()
+ SET(LIBXML2_FOUND FALSE)
+ENDIF()
IF(LIBXML2_FOUND)
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
INCLUDE_DIRECTORIES(${LIBXML2_INCLUDE_DIR})
@@ -802,7 +887,11 @@ ELSE(LIBXML2_FOUND)
#
# Find Expat
#
- FIND_PACKAGE(EXPAT)
+ IF(ENABLE_EXPAT)
+ FIND_PACKAGE(EXPAT)
+ ELSE()
+ SET(EXPAT_FOUND FALSE)
+ ENDIF()
IF(EXPAT_FOUND)
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
INCLUDE_DIRECTORIES(${EXPAT_INCLUDE_DIR})
@@ -820,15 +909,17 @@ ENDIF()
# Check functions
#
CMAKE_PUSH_CHECK_STATE() # Save the state of the variables
-IF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+IF (CMAKE_C_COMPILER_ID STREQUAL "GNU" OR
+ CMAKE_C_COMPILER_ID STREQUAL "Clang")
#
# 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(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fno-builtin")
-ENDIF ("CMAKE_C_COMPILER_ID" MATCHES "^GNU$")
+ENDIF ()
CHECK_SYMBOL_EXISTS(_CrtSetReportMode "crtdbg.h" HAVE__CrtSetReportMode)
+CHECK_FUNCTION_EXISTS_GLIBC(arc4random_buf HAVE_ARC4RANDOM_BUF)
CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
@@ -876,6 +967,7 @@ CHECK_FUNCTION_EXISTS_GLIBC(pipe HAVE_PIPE)
CHECK_FUNCTION_EXISTS_GLIBC(poll HAVE_POLL)
CHECK_FUNCTION_EXISTS_GLIBC(posix_spawnp HAVE_POSIX_SPAWNP)
CHECK_FUNCTION_EXISTS_GLIBC(readlink HAVE_READLINK)
+CHECK_FUNCTION_EXISTS_GLIBC(readpassphrase HAVE_READPASSPHRASE)
CHECK_FUNCTION_EXISTS_GLIBC(select HAVE_SELECT)
CHECK_FUNCTION_EXISTS_GLIBC(setenv HAVE_SETENV)
CHECK_FUNCTION_EXISTS_GLIBC(setlocale HAVE_SETLOCALE)
@@ -914,9 +1006,18 @@ CHECK_FUNCTION_EXISTS(strftime HAVE_STRFTIME)
CHECK_FUNCTION_EXISTS(vprintf HAVE_VPRINTF)
CHECK_FUNCTION_EXISTS(wmemcmp HAVE_WMEMCMP)
CHECK_FUNCTION_EXISTS(wmemcpy HAVE_WMEMCPY)
+CHECK_FUNCTION_EXISTS(wmemmove HAVE_WMEMMOVE)
CMAKE_POP_CHECK_STATE() # Restore the state of the variables
+CHECK_C_SOURCE_COMPILES(
+ "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct vfsconf v; return sizeof(v);}"
+ HAVE_STRUCT_VFSCONF)
+
+CHECK_C_SOURCE_COMPILES(
+ "#include <sys/types.h>\n#include <sys/mount.h>\nint main(void) { struct xvfsconf v; return sizeof(v);}"
+ HAVE_STRUCT_XVFSCONF)
+
# Make sure we have the POSIX version of readdir_r, not the
# older 2-argument version.
CHECK_C_SOURCE_COMPILES(
@@ -942,6 +1043,10 @@ CHECK_C_SOURCE_COMPILES(
"#include <sys/sysmacros.h>\nint main() { return major(256); }"
MAJOR_IN_SYSMACROS)
+CHECK_C_SOURCE_COMPILES(
+ "#include <lzma.h>\n#if LZMA_VERSION < 50020000\n#error unsupported\n#endif\nint main(void){lzma_stream_encoder_mt(0, 0); return 0;}"
+ HAVE_LZMA_STREAM_ENCODER_MT)
+
IF(HAVE_STRERROR_R)
SET(HAVE_DECL_STRERROR_R 1)
ENDIF(HAVE_STRERROR_R)
@@ -959,10 +1064,15 @@ 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(INT32_MAX "${headers}" HAVE_DECL_INT32_MAX)
+CHECK_SYMBOL_EXISTS(INT32_MIN "${headers}" HAVE_DECL_INT32_MIN)
CHECK_SYMBOL_EXISTS(INT64_MAX "${headers}" HAVE_DECL_INT64_MAX)
CHECK_SYMBOL_EXISTS(INT64_MIN "${headers}" HAVE_DECL_INT64_MIN)
+CHECK_SYMBOL_EXISTS(INTMAX_MAX "${headers}" HAVE_DECL_INTMAX_MAX)
+CHECK_SYMBOL_EXISTS(INTMAX_MIN "${headers}" HAVE_DECL_INTMAX_MIN)
CHECK_SYMBOL_EXISTS(UINT32_MAX "${headers}" HAVE_DECL_UINT32_MAX)
CHECK_SYMBOL_EXISTS(UINT64_MAX "${headers}" HAVE_DECL_UINT64_MAX)
+CHECK_SYMBOL_EXISTS(UINTMAX_MAX "${headers}" HAVE_DECL_UINTMAX_MAX)
CHECK_SYMBOL_EXISTS(SIZE_MAX "${headers}" HAVE_DECL_SIZE_MAX)
CHECK_SYMBOL_EXISTS(SSIZE_MAX "limits.h" HAVE_DECL_SSIZE_MAX)
@@ -970,47 +1080,47 @@ 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
+CHECK_STRUCT_HAS_MEMBER("struct tm" tm_gmtoff
"time.h" HAVE_STRUCT_TM_TM_GMTOFF)
-CHECK_STRUCT_MEMBER("struct tm" __tm_gmtoff
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_MEMBER("struct stat" st_umtime
"sys/types.h;sys/stat.h" HAVE_STRUCT_STAT_ST_UMTIME)
-CHECK_STRUCT_MEMBER("struct stat" st_mtime_usec
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+CHECK_STRUCT_HAS_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
+ CHECK_STRUCT_HAS_MEMBER("struct statvfs" f_iosize
"sys/types.h;sys/statvfs.h" HAVE_STRUCT_STATVFS_F_IOSIZE)
ENDIF()
#
#
-CHECK_STRUCT_MEMBER("struct tm" tm_sec
+CHECK_STRUCT_HAS_MEMBER("struct tm" tm_sec
"sys/types.h;sys/time.h;time.h" TIME_WITH_SYS_TIME)
#
@@ -1030,13 +1140,13 @@ 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(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(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)
@@ -1230,16 +1340,36 @@ IF(ENABLE_ACL)
# 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_fd_np HAVE_ACL_GET_FD_NP)
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)
CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
+ CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "${INCLUDES}" HAVE_ACL_TYPE_NFS4)
# 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)
+ CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
+#include <sys/acl.h>
+int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED)
+
+ # Solaris and derivates ACLs
+ CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC)
+ IF(HAVE_LIBSEC)
+ SET(CMAKE_REQUIRED_LIBRARIES "sec")
+ FIND_LIBRARY(SEC_LIBRARY NAMES sec)
+ LIST(APPEND ADDITIONAL_LIBS ${SEC_LIBRARY})
+ ENDIF(HAVE_LIBSEC)
+ #
+ CHECK_TYPE_EXISTS(aclent_t "${INCLUDES}" HAVE_ACLENT_T)
+ CHECK_TYPE_EXISTS(ace_t "${INCLUDES}" HAVE_ACE_T)
+ CHECK_FUNCTION_EXISTS(acl_get HAVE_FACL_GET)
+ CHECK_FUNCTION_EXISTS(facl_get HAVE_FACL_GET)
+ CHECK_FUNCTION_EXISTS(acl_set HAVE_FACL_SET)
+ CHECK_FUNCTION_EXISTS(facl_set HAVE_FACL_SET)
ELSE(ENABLE_ACL)
# If someone runs cmake, then disables ACL support, we need
# to forcibly override the cached values for these.
@@ -1254,7 +1384,15 @@ ELSE(ENABLE_ACL)
SET(HAVE_ACL_SET_FD FALSE)
SET(HAVE_ACL_SET_FD_NP FALSE)
SET(HAVE_ACL_SET_FILE FALSE)
+ SET(HAVE_ACL_TYPE_NFS4 FALSE)
SET(HAVE_ACL_USER FALSE)
+ SET(HAVE_ACL_TYPE_EXTENDED FALSE)
+ SET(HAVE_ACL_GET FALSE)
+ SET(HAVE_ACLENT_T FALSE)
+ SET(HAVE_ACE_T FALSE)
+ SET(HAVE_FACL_GET FALSE)
+ SET(HAVE_ACL_SET FALSE)
+ SET(HAVE_FACL_SET FALSE)
ENDIF(ENABLE_ACL)
#
diff --git a/Utilities/cmlibarchive/COPYING b/Utilities/cmlibarchive/COPYING
index b25880600..93952b77a 100644
--- a/Utilities/cmlibarchive/COPYING
+++ b/Utilities/cmlibarchive/COPYING
@@ -17,12 +17,11 @@ the actual statements in the files are controlling.
files for details:
libarchive/archive_entry.c
libarchive/archive_read_support_filter_compress.c
- libarchive/archive_write_set_filter_compress.c
+ libarchive/archive_write_add_filter_compress.c
libarchive/mtree.5
- tar/matching.c
* The following source files are in the public domain:
- tar/getdate.c
+ libarchive/archive_getdate.c
* The build files---including Makefiles, configure scripts,
and auxiliary scripts used as part of the compile process---have
diff --git a/Utilities/cmlibarchive/README-CMake.txt b/Utilities/cmlibarchive/README-CMake.txt
deleted file mode 100644
index ab105f064..000000000
--- a/Utilities/cmlibarchive/README-CMake.txt
+++ /dev/null
@@ -1,66 +0,0 @@
-The Utilities/cmlibarchive directory contains a reduced distribution
-of the libarchive source tree with only the library source code and
-CMake build system. It is not a submodule; the actual content is part
-of our source tree and changes can be made and committed directly.
-
-We update from upstream using Git's "subtree" merge strategy. A
-special branch contains commits of upstream libarchive snapshots and
-nothing else. No Git ref points explicitly to the head of this
-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 35df7c8b
-
-Use a temporary directory to checkout the branch:
-
- mkdir libarchive-tmp
- cd libarchive-tmp
- git init
- git pull .. libarchive-upstream
- rm -rf *
-
-Now place the (reduced) libarchive content in this directory. See
-instructions shown by
-
- git log 35df7c8b
-
-for help extracting the content from the upstream svn repo. Then run
-the following commands to commit the new version. Substitute the
-appropriate date and version number:
-
- git add --all
-
- GIT_AUTHOR_NAME='LibArchive Upstream' \
- GIT_AUTHOR_EMAIL='libarchive-discuss@googlegroups.com' \
- GIT_AUTHOR_DATE='2013-02-09 12:17:57 -0500' \
- git commit -m 'libarchive 3.1.2 (reduced)' &&
- git commit --amend
-
-Edit the commit message to describe the procedure used to obtain the
-content. Then push the changes back up to the main local repository:
-
- git push .. HEAD:libarchive-upstream
- cd ..
- rm -rf libarchive-tmp
-
-Create a topic in the main repository on which to perform the update:
-
- git checkout -b update-libarchive master
-
-Merge the libarchive-upstream branch as a subtree:
-
- git merge -s recursive -X subtree=Utilities/cmlibarchive \
- libarchive-upstream
-
-If there are conflicts, resolve them and commit. Build and test the
-tree. Commit any additional changes needed to succeed.
-
-Finally, run
-
- git rev-parse --short=8 libarchive-upstream
-
-to get the commit from which the libarchive-upstream branch must be started
-on the next update. Edit the "git branch libarchive-upstream" line above to
-record it, and commit this file.
diff --git a/Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake b/Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake
index 0670df97f..84cc881e3 100644
--- a/Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake
+++ b/Utilities/cmlibarchive/build/cmake/CheckFuncs.cmake
@@ -31,7 +31,7 @@ MACRO (CHECK_FUNCTION_EXISTS_GLIBC _FUNC _FUNCVAR)
SET(CHECK_STUB_FUNC_1 "__stub_${_FUNC}")
SET(CHECK_STUB_FUNC_2 "__stub___${_FUNC}")
CONFIGURE_FILE( ${_selfdir_CheckFunctionExistsGlibc}/CheckFuncs_stub.c.in
- ${CMAKE_CURRENT_BINARY_DIR}/cmake.tmp/CheckFuncs_stub.c IMMEDIATE)
+ ${CMAKE_CURRENT_BINARY_DIR}/cmake.tmp/CheckFuncs_stub.c)
TRY_COMPILE(__stub
${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}/cmake.tmp/CheckFuncs_stub.c
diff --git a/Utilities/cmlibarchive/build/cmake/CheckStructMember.cmake b/Utilities/cmlibarchive/build/cmake/CheckStructMember.cmake
deleted file mode 100644
index 05ddb3a11..000000000
--- a/Utilities/cmlibarchive/build/cmake/CheckStructMember.cmake
+++ /dev/null
@@ -1,43 +0,0 @@
-# - Check if the given struct or class has the specified member variable
-# CHECK_STRUCT_MEMBER (STRUCT MEMBER HEADER VARIABLE)
-#
-# STRUCT - the name of the struct or class you are interested in
-# MEMBER - the member which existence you want to check
-# HEADER - the header(s) where the prototype should be declared
-# VARIABLE - variable to store the result
-#
-# The following variables may be set before calling this macro to
-# modify the way the check is run:
-#
-# CMAKE_REQUIRED_FLAGS = string of compile command line flags
-# CMAKE_REQUIRED_DEFINITIONS = list of macros to define (-DFOO=bar)
-# CMAKE_REQUIRED_INCLUDES = list of include directories
-
-# Copyright (c) 2006, Alexander Neundorf, <neundorf@kde.org>
-#
-# Redistribution and use is allowed according to the terms of the BSD license.
-# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
-
-
-INCLUDE(CheckCSourceCompiles)
-
-MACRO (CHECK_STRUCT_MEMBER _STRUCT _MEMBER _HEADER _RESULT)
- SET(_INCLUDE_FILES)
- FOREACH (it ${_HEADER})
- SET(_INCLUDE_FILES "${_INCLUDE_FILES}#include <${it}>\n")
- ENDFOREACH (it)
-
- SET(_CHECK_STRUCT_MEMBER_SOURCE_CODE "
-${_INCLUDE_FILES}
-int main()
-{
- static ${_STRUCT} tmp;
- if (sizeof(tmp.${_MEMBER}))
- return 0;
- return 0;
-}
-")
- CHECK_C_SOURCE_COMPILES("${_CHECK_STRUCT_MEMBER_SOURCE_CODE}" ${_RESULT})
-
-ENDMACRO (CHECK_STRUCT_MEMBER)
-
diff --git a/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake b/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake
new file mode 100644
index 000000000..fc8529a57
--- /dev/null
+++ b/Utilities/cmlibarchive/build/cmake/CreatePkgConfigFile.cmake
@@ -0,0 +1,33 @@
+# - Generate a libarchive.pc like autotools for pkg-config
+#
+
+# Set the required variables (we use the same input file as autotools)
+SET(prefix ${CMAKE_INSTALL_PREFIX})
+SET(exec_prefix \${prefix})
+SET(libdir \${exec_prefix}/lib)
+SET(includedir \${prefix}/include)
+# Now, this is not particularly pretty, nor is it terribly accurate...
+# Loop over all our additional libs
+FOREACH(mylib ${ADDITIONAL_LIBS})
+ # Extract the filename from the absolute path
+ GET_FILENAME_COMPONENT(mylib_name ${mylib} NAME_WE)
+ # Strip the lib prefix
+ STRING(REGEX REPLACE "^lib" "" mylib_name ${mylib_name})
+ # Append it to our LIBS string
+ SET(LIBS "${LIBS} -l${mylib_name}")
+ENDFOREACH()
+# libxml2 is easier, since it's already using pkg-config
+FOREACH(mylib ${PC_LIBXML_STATIC_LDFLAGS})
+ SET(LIBS "${LIBS} ${mylib}")
+ENDFOREACH()
+# FIXME: The order of the libraries doesn't take dependencies into account,
+# thus there's a good chance it'll make some binutils versions unhappy...
+# This only affects Libs.private (looked up for static builds) though.
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc.in
+ ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+ @ONLY)
+# And install it, of course ;).
+IF(ENABLE_INSTALL)
+ INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/build/pkgconfig/libarchive.pc
+ DESTINATION "lib/pkgconfig")
+ENDIF()
diff --git a/Utilities/cmlibarchive/build/cmake/FindLZMA.cmake b/Utilities/cmlibarchive/build/cmake/FindLZMA.cmake
deleted file mode 100644
index 0b46b2cdd..000000000
--- a/Utilities/cmlibarchive/build/cmake/FindLZMA.cmake
+++ /dev/null
@@ -1,48 +0,0 @@
-# - Find lzma and lzmadec
-# Find the native LZMA includes and library
-#
-# LZMA_INCLUDE_DIR - where to find lzma.h, etc.
-# LZMA_LIBRARIES - List of libraries when using liblzma.
-# LZMA_FOUND - True if liblzma found.
-# LZMADEC_INCLUDE_DIR - where to find lzmadec.h, etc.
-# LZMADEC_LIBRARIES - List of libraries when using liblzmadec.
-# LZMADEC_FOUND - True if liblzmadec found.
-
-IF (LZMA_INCLUDE_DIR)
- # Already in cache, be silent
- SET(LZMA_FIND_QUIETLY TRUE)
-ENDIF (LZMA_INCLUDE_DIR)
-
-FIND_PATH(LZMA_INCLUDE_DIR lzma.h)
-FIND_LIBRARY(LZMA_LIBRARY NAMES lzma liblzma)
-
-# handle the QUIETLY and REQUIRED arguments and set LZMA_FOUND to TRUE if
-# all listed variables are TRUE
-INCLUDE(FindPackageHandleStandardArgs)
-FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMA DEFAULT_MSG LZMA_LIBRARY LZMA_INCLUDE_DIR)
-
-IF(LZMA_FOUND)
- SET( LZMA_LIBRARIES ${LZMA_LIBRARY} )
-ELSE(LZMA_FOUND)
- SET( LZMA_LIBRARIES )
-
- IF (LZMADEC_INCLUDE_DIR)
- # Already in cache, be silent
- SET(LZMADEC_FIND_QUIETLY TRUE)
- ENDIF (LZMADEC_INCLUDE_DIR)
-
- FIND_PATH(LZMADEC_INCLUDE_DIR lzmadec.h)
- FIND_LIBRARY(LZMADEC_LIBRARY NAMES lzmadec )
-
- # handle the QUIETLY and REQUIRED arguments and set LZMADEC_FOUND to TRUE if
- # all listed variables are TRUE
- INCLUDE(FindPackageHandleStandardArgs)
- FIND_PACKAGE_HANDLE_STANDARD_ARGS(LZMADEC DEFAULT_MSG LZMADEC_LIBRARY
- LZMADEC_INCLUDE_DIR)
-
- IF(LZMADEC_FOUND)
- SET( LZMADEC_LIBRARIES ${LZMADEC_LIBRARY} )
- ELSE(LZMADEC_FOUND)
- SET( LZMADEC_LIBRARIES )
- ENDIF(LZMADEC_FOUND)
-ENDIF(LZMA_FOUND)
diff --git a/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake b/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake
new file mode 100644
index 000000000..297b886cc
--- /dev/null
+++ b/Utilities/cmlibarchive/build/cmake/LibarchiveCodeCoverage.cmake
@@ -0,0 +1,68 @@
+#################################################################
+# Adds a build target called "coverage" for code coverage.
+#
+# This compiles the code using special GCC flags, run the tests,
+# and then generates a nice HTML output. This new "coverage" make
+# target will only be available if you build using GCC in Debug
+# mode. If any of the required programs (lcov and genhtml) were
+# not found, a FATAL_ERROR message is printed.
+#
+# If not already done, this code will set ENABLE_TEST to ON.
+#
+# To build the code coverage and open it in your browser do this:
+#
+# mkdir debug
+# cd debug
+# cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_COVERAGE=ON ..
+# make -j4
+# make coverage
+# xdg-open coverage/index.html
+#################################################################
+
+# Find programs we need
+FIND_PROGRAM(LCOV_EXECUTABLE lcov DOC "Full path to lcov executable")
+FIND_PROGRAM(GENHTML_EXECUTABLE genhtml DOC "Full path to genhtml executable")
+MARK_AS_ADVANCED(LCOV_EXECUTABLE GENHTML_EXECUTABLE)
+
+# Check, compiler, build types and programs are available
+IF(NOT CMAKE_COMPILER_IS_GNUCC)
+MESSAGE(FATAL_ERROR "Coverage can only be built on GCC")
+ELSEIF(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+MESSAGE(FATAL_ERROR "Coverage can only be built in Debug mode")
+ELSEIF(NOT LCOV_EXECUTABLE)
+MESSAGE(FATAL_ERROR "lcov executable not found")
+ELSEIF(NOT GENHTML_EXECUTABLE)
+MESSAGE(FATAL_ERROR "genhtml executable not found")
+ENDIF(NOT CMAKE_COMPILER_IS_GNUCC)
+
+# Enable testing if not already done
+SET(ENABLE_TEST ON)
+
+#################################################################
+# Set special compiler and linker flags for test coverage
+#################################################################
+# 0. Enable debug: -g
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g")
+# 1. Disable optimizations: -O0
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0")
+# 2. Enable all kind of warnings:
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -W")
+# 3. Enable special coverage flag (HINT: --coverage is a synonym for -fprofile-arcs -ftest-coverage)
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage")
+SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage")
+SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage")
+#################################################################
+
+ADD_CUSTOM_TARGET(coverage
+COMMAND ${CMAKE_COMMAND} -E echo "Beginning test coverage. Output is written to coverage.log."
+COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-1/5: Reset all execution counts to zero"
+COMMAND ${LCOV_EXECUTABLE} --directory . --zerocounters > coverage.log 2>&1
+COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-2/5: Run testrunner"
+COMMAND ${CMAKE_CTEST_COMMAND} >> coverage.log 2>&1
+COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-3/5: Collect coverage data"
+COMMAND ${LCOV_EXECUTABLE} --capture --directory . --output-file "./coverage.info" >> coverage.log 2>&1
+COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-4/5: Generate HTML from coverage data"
+COMMAND ${GENHTML_EXECUTABLE} "coverage.info" --title="libarchive-${LIBARCHIVE_VERSION_STRING}" --show-details --legend --output-directory "./coverage" >> coverage.log 2>&1
+COMMAND ${CMAKE_COMMAND} -E echo "COVERAGE-STEP-5/5: Open test coverage HTML output in browser: xdg-open ./coverage/index.html"
+COMMENT "Runs testrunner and generates coverage output (formats: .info and .html)")
+
diff --git a/Utilities/cmlibarchive/build/cmake/config.h.in b/Utilities/cmlibarchive/build/cmake/config.h.in
index 750ae660a..55e04b9af 100644
--- a/Utilities/cmlibarchive/build/cmake/config.h.in
+++ b/Utilities/cmlibarchive/build/cmake/config.h.in
@@ -66,7 +66,7 @@ typedef long long int64_t;
* Similarly for int32_t
*/
#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4
-typedef long int32_t;
+typedef int int32_t;
#define HAVE_INT32_T
#endif
@@ -173,8 +173,6 @@ typedef unsigned char uint8_t;
/* Define intmax_t and uintmax_t if they are not already defined. */
#if !defined(HAVE_INTMAX_T)
typedef int64_t intmax_t;
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
#endif
#if !defined(HAVE_UINTMAX_T)
@@ -292,9 +290,15 @@ typedef uint64_t uintmax_t;
/* Version number of bsdtar */
#cmakedefine BSDTAR_VERSION_STRING "${BSDTAR_VERSION_STRING}"
+/* Version number of bsdcat */
+#cmakedefine BSDCAT_VERSION_STRING "${BSDCAT_VERSION_STRING}"
+
/* Define to 1 if you have the `acl_create_entry' function. */
#cmakedefine HAVE_ACL_CREATE_ENTRY 1
+/* Define to 1 if you have the `acl_get_fd_np' function. */
+#cmakedefine HAVE_ACL_GET_FD_NP 1
+
/* Define to 1 if you have the `acl_get_link' function. */
#cmakedefine HAVE_ACL_GET_LINK 1
@@ -325,12 +329,24 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `acl_set_file' function. */
#cmakedefine HAVE_ACL_SET_FILE 1
+/* True for FreeBSD with NFSv4 ACL support */
+#cmakedefine HAVE_ACL_TYPE_NFS4 1
+
+/* True for MacOS ACL support */
+#cmakedefine HAVE_ACL_TYPE_EXTENDED 1
+
/* True for systems with POSIX ACL support */
#cmakedefine HAVE_ACL_USER 1
+/* Define to 1 if you have the `arc4random_buf' function. */
+#cmakedefine HAVE_ARC4RANDOM_BUF 1
+
/* Define to 1 if you have the <attr/xattr.h> header file. */
#cmakedefine HAVE_ATTR_XATTR_H 1
+/* Define to 1 if you have the <Bcrypt.h> header file. */
+#cmakedefine HAVE_BCRYPT_H 1
+
/* Define to 1 if you have the <bsdxml.h> header file. */
#cmakedefine HAVE_BSDXML_H 1
@@ -358,6 +374,14 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `cygwin_conv_path' function. */
#cmakedefine HAVE_CYGWIN_CONV_PATH 1
+/* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you
+ don't. */
+#cmakedefine HAVE_DECL_INT32_MAX 1
+
+/* Define to 1 if you have the declaration of `INT32_MIN', and to 0 if you
+ don't. */
+#cmakedefine HAVE_DECL_INT32_MIN 1
+
/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you
don't. */
#cmakedefine HAVE_DECL_INT64_MAX 1
@@ -366,6 +390,14 @@ typedef uint64_t uintmax_t;
don't. */
#cmakedefine HAVE_DECL_INT64_MIN 1
+/* Define to 1 if you have the declaration of `INTMAX_MAX', and to 0 if you
+ don't. */
+#cmakedefine HAVE_DECL_INTMAX_MAX 1
+
+/* Define to 1 if you have the declaration of `INTMAX_MIN', and to 0 if you
+ don't. */
+#cmakedefine HAVE_DECL_INTMAX_MIN 1
+
/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you
don't. */
#cmakedefine HAVE_DECL_SIZE_MAX 1
@@ -386,6 +418,10 @@ typedef uint64_t uintmax_t;
don't. */
#cmakedefine HAVE_DECL_UINT64_MAX 1
+/* Define to 1 if you have the declaration of `UINTMAX_MAX', and to 0 if you
+ don't. */
+#cmakedefine HAVE_DECL_UINTMAX_MAX 1
+
/* Define to 1 if you have the <direct.h> header file. */
#cmakedefine HAVE_DIRECT_H 1
@@ -579,12 +615,21 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `bz2' library (-lbz2). */
#cmakedefine HAVE_LIBBZ2 1
+/* Define to 1 if you have the `charset' library (-lcharset). */
+#cmakedefine HAVE_LIBCHARSET 1
+
+/* Define to 1 if you have the `crypto' library (-lcrypto). */
+#cmakedefine HAVE_LIBCRYPTO 1
+
/* Define to 1 if you have the `expat' library (-lexpat). */
#cmakedefine HAVE_LIBEXPAT 1
/* Define to 1 if you have the `gcc' library (-lgcc). */
#cmakedefine HAVE_LIBGCC 1
+/* Define to 1 if you have the `lz4' library (-llz4). */
+#cmakedefine HAVE_LIBLZ4 1
+
/* Define to 1 if you have the `lzma' library (-llzma). */
#cmakedefine HAVE_LIBLZMA 1
@@ -679,12 +724,21 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `lutimes' function. */
#cmakedefine HAVE_LUTIMES 1
+/* Define to 1 if you have the <lz4hc.h> header file. */
+#cmakedefine HAVE_LZ4HC_H 1
+
+/* Define to 1 if you have the <lz4.h> header file. */
+#cmakedefine HAVE_LZ4_H 1
+
/* Define to 1 if you have the <lzmadec.h> header file. */
#cmakedefine HAVE_LZMADEC_H 1
/* Define to 1 if you have the <lzma.h> header file. */
#cmakedefine HAVE_LZMA_H 1
+/* Define to 1 if you have a working `lzma_stream_encoder_mt' function. */
+#cmakedefine HAVE_LZMA_STREAM_ENCODER_MT 1
+
/* Define to 1 if you have the <lzo/lzo1x.h> header file. */
#cmakedefine HAVE_LZO_LZO1X_H 1
@@ -715,9 +769,18 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
#cmakedefine HAVE_NDIR_H 1
+/* Define to 1 if you have the <nettle/aes.h> header file. */
+#cmakedefine HAVE_NETTLE_AES_H 1
+
+/* Define to 1 if you have the <nettle/hmac.h> header file. */
+#cmakedefine HAVE_NETTLE_HMAC_H 1
+
/* Define to 1 if you have the <nettle/md5.h> header file. */
#cmakedefine HAVE_NETTLE_MD5_H 1
+/* Define to 1 if you have the <nettle/pbkdf2.h> header file. */
+#cmakedefine HAVE_NETTLE_PBKDF2_H 1
+
/* Define to 1 if you have the <nettle/ripemd160.h> header file. */
#cmakedefine HAVE_NETTLE_RIPEMD160_H 1
@@ -739,6 +802,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `pipe' function. */
#cmakedefine HAVE_PIPE 1
+/* Define to 1 if you have the `PKCS5_PBKDF2_HMAC_SHA1' function. */
+#cmakedefine HAVE_PKCS5_PBKDF2_HMAC_SHA1 1
+
/* Define to 1 if you have the `poll' function. */
#cmakedefine HAVE_POLL 1
@@ -751,6 +817,9 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the <process.h> header file. */
#cmakedefine HAVE_PROCESS_H 1
+/* Define to 1 if you have the <pthread.h> header file. */
+#cmakedefine HAVE_PTHREAD_H 1
+
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H 1
@@ -763,6 +832,12 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `readlinkat' function. */
#cmakedefine HAVE_READLINKAT 1
+/* Define to 1 if you have the `readpassphrase' function. */
+#cmakedefine HAVE_READPASSPHRASE 1
+
+/* Define to 1 if you have the <readpassphrase.h> header file. */
+#cmakedefine HAVE_READPASSPHRASE_H 1
+
/* Define to 1 if you have the <regex.h> header file. */
#cmakedefine HAVE_REGEX_H 1
@@ -866,6 +941,12 @@ typedef uint64_t uintmax_t;
/* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */
#cmakedefine HAVE_STRUCT_TM___TM_GMTOFF 1
+/* Define to 1 if you have `struct vfsconf'. */
+#cmakedefine HAVE_STRUCT_VFSCONF 1
+
+/* Define to 1 if you have `struct xvfsconf'. */
+#cmakedefine HAVE_STRUCT_XVFSCONF 1
+
/* Define to 1 if you have the `symlink' function. */
#cmakedefine HAVE_SYMLINK 1
@@ -1018,9 +1099,15 @@ typedef uint64_t uintmax_t;
/* Define to 1 if you have the `wmemcpy' function. */
#cmakedefine HAVE_WMEMCPY 1
+/* Define to 1 if you have the `wmemmove' function. */
+#cmakedefine HAVE_WMEMMOVE 1
+
/* Define to 1 if you have a working EXT2_IOC_GETFLAGS */
#cmakedefine HAVE_WORKING_EXT2_IOC_GETFLAGS 1
+/* Define to 1 if you have a working FS_IOC_GETFLAGS */
+#cmakedefine HAVE_WORKING_FS_IOC_GETFLAGS 1
+
/* Define to 1 if you have the <zlib.h> header file. */
#cmakedefine HAVE_ZLIB_H 1
@@ -1111,9 +1198,18 @@ typedef uint64_t uintmax_t;
/* Define for large files, on AIX-style hosts. */
#cmakedefine _LARGE_FILES ${_LARGE_FILES}
-/* Define for Windows to use Windows 2000+ APIs. */
+/* Define to control Windows SDK version */
+#ifndef NTDDI_VERSION
+#cmakedefine NTDDI_VERSION ${NTDDI_VERSION}
+#endif // NTDDI_VERSION
+
+#ifndef _WIN32_WINNT
#cmakedefine _WIN32_WINNT ${_WIN32_WINNT}
+#endif // _WIN32_WINNT
+
+#ifndef WINVER
#cmakedefine WINVER ${WINVER}
+#endif // WINVER
/* Define to empty if `const' does not conform to ANSI C. */
#cmakedefine const ${const}
diff --git a/Utilities/cmlibarchive/build/version b/Utilities/cmlibarchive/build/version
index 937b126a2..ef8345726 100644
--- a/Utilities/cmlibarchive/build/version
+++ b/Utilities/cmlibarchive/build/version
@@ -1 +1 @@
-3001002
+3003001
diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
index 42781bc3c..d412c80dc 100644
--- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt
+++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt
@@ -18,8 +18,10 @@ SET(libarchive_SOURCES
archive_cmdline.c
archive_cmdline_private.h
archive_crc32.h
- archive_crypto.c
- archive_crypto_private.h
+ archive_cryptor.c
+ archive_cryptor_private.h
+ archive_digest.c
+ archive_digest_private.h
archive_endian.h
archive_entry.c
archive_entry.h
@@ -32,9 +34,16 @@ SET(libarchive_SOURCES
archive_entry_strmode.c
archive_entry_xattr.c
archive_getdate.c
+ archive_getdate.h
+ archive_hmac.c
+ archive_hmac_private.h
archive_match.c
+ archive_openssl_evp_private.h
+ archive_openssl_hmac_private.h
archive_options.c
archive_options_private.h
+ archive_pack_dev.h
+ archive_pack_dev.c
archive_pathmatch.c
archive_pathmatch.h
archive_platform.h
@@ -42,9 +51,12 @@ SET(libarchive_SOURCES
archive_ppmd7.c
archive_ppmd7_private.h
archive_private.h
+ archive_random.c
+ archive_random_private.h
archive_rb.c
archive_rb.h
archive_read.c
+ archive_read_add_passphrase.c
archive_read_append_filter.c
archive_read_data_into_fd.c
archive_read_disk_entry_from_file.c
@@ -52,6 +64,7 @@ SET(libarchive_SOURCES
archive_read_disk_private.h
archive_read_disk_set_standard_lookup.c
archive_read_extract.c
+ archive_read_extract2.c
archive_read_open_fd.c
archive_read_open_file.c
archive_read_open_filename.c
@@ -65,6 +78,7 @@ SET(libarchive_SOURCES
archive_read_support_filter_gzip.c
archive_read_support_filter_grzip.c
archive_read_support_filter_lrzip.c
+ archive_read_support_filter_lz4.c
archive_read_support_filter_lzop.c
archive_read_support_filter_none.c
archive_read_support_filter_program.c
@@ -84,6 +98,7 @@ SET(libarchive_SOURCES
archive_read_support_format_rar.c
archive_read_support_format_raw.c
archive_read_support_format_tar.c
+ archive_read_support_format_warc.c
archive_read_support_format_xar.c
archive_read_support_format_zip.c
archive_string.c
@@ -110,6 +125,7 @@ SET(libarchive_SOURCES
archive_write_add_filter_grzip.c
archive_write_add_filter_gzip.c
archive_write_add_filter_lrzip.c
+ archive_write_add_filter_lz4.c
archive_write_add_filter_lzop.c
archive_write_add_filter_none.c
archive_write_add_filter_program.c
@@ -121,18 +137,24 @@ SET(libarchive_SOURCES
archive_write_set_format_by_name.c
archive_write_set_format_cpio.c
archive_write_set_format_cpio_newc.c
+ archive_write_set_format_filter_by_ext.c
archive_write_set_format_gnutar.c
archive_write_set_format_iso9660.c
archive_write_set_format_mtree.c
archive_write_set_format_pax.c
+ archive_write_set_format_raw.c
archive_write_set_format_shar.c
archive_write_set_format_ustar.c
archive_write_set_format_v7tar.c
+ archive_write_set_format_warc.c
archive_write_set_format_xar.c
archive_write_set_format_zip.c
archive_write_set_options.c
+ archive_write_set_passphrase.c
+ archive_xxhash.h
filter_fork_posix.c
filter_fork.h
+ xxhash.c
)
# Man pages
@@ -145,14 +167,34 @@ SET(libarchive_MANS
archive_entry_stat.3
archive_entry_time.3
archive_read.3
+ archive_read_add_passphrase.3
+ archive_read_data.3
archive_read_disk.3
+ archive_read_extract.3
+ archive_read_filter.3
+ archive_read_format.3
+ archive_read_free.3
+ archive_read_header.3
+ archive_read_new.3
+ archive_read_open.3
archive_read_set_options.3
archive_util.3
archive_write.3
+ archive_write_blocksize.3
+ archive_write_data.3
archive_write_disk.3
+ archive_write_filter.3
+ archive_write_finish_entry.3
+ archive_write_format.3
+ archive_write_free.3
+ archive_write_header.3
+ archive_write_new.3
+ archive_write_open.3
archive_write_set_options.3
+ archive_write_set_passphrase.3
cpio.5
libarchive.3
+ libarchive_changes.3
libarchive_internals.3
libarchive-formats.5
mtree.5
diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h
index 1a1d32a6d..cfb5c48b2 100644
--- a/Utilities/cmlibarchive/libarchive/archive.h
+++ b/Utilities/cmlibarchive/libarchive/archive.h
@@ -28,9 +28,20 @@
#ifndef ARCHIVE_H_INCLUDED
#define ARCHIVE_H_INCLUDED
+/*
+ * 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_NUMBER >= 2012108.
+ */
+/* Note: Compiler will complain if this does not match archive_entry.h! */
+#define ARCHIVE_VERSION_NUMBER 3003001
+
#include <sys/stat.h>
#include <stddef.h> /* for wchar_t */
#include <stdio.h> /* For FILE * */
+#include <time.h> /* For time_t */
/*
* Note: archive.h is for use outside of libarchive; the configuration
@@ -45,32 +56,49 @@
# 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_
+/* Get appropriate definitions of 64-bit integer */
+#if !defined(__LA_INT64_T_DEFINED)
+/* Older code relied on the __LA_INT64_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
+# endif
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
+# include <unistd.h> /* ssize_t */
+# if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+# else
+typedef int64_t la_int64_t;
+# endif
+# endif
#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
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
# endif
-#else
-# include <unistd.h> /* ssize_t, uid_t, and gid_t */
-# if defined(_SCO_DS) || defined(__osf__)
-# define __LA_INT64_T long long
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+# elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+# else
+typedef long la_ssize_t;
+# endif
# else
-# define __LA_INT64_T int64_t
+# include <unistd.h> /* ssize_t */
+typedef ssize_t la_ssize_t;
# endif
-# define __LA_SSIZE_T ssize_t
+#endif
+
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
#endif
/*
@@ -119,24 +147,34 @@ extern "C" {
* 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_NUMBER >= 2012108.
- */
-/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3001002
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_STRING "libarchive 3.1.2"
+#define ARCHIVE_VERSION_ONLY_STRING "3.3.1"
+#define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
__LA_DECL const char * archive_version_string(void);
+/*
+ * Detailed textual name/version of the library and its dependencies.
+ * This has the form:
+ * "libarchive x.y.z zlib/a.b.c liblzma/d.e.f ... etc ..."
+ * the list of libraries described here will vary depending on how
+ * libarchive was compiled.
+ */
+__LA_DECL const char * archive_version_details(void);
+
+/*
+ * Returns NULL if libarchive was compiled without the associated library.
+ * Otherwise, returns the version number that libarchive was compiled
+ * against.
+ */
+__LA_DECL const char * archive_zlib_version(void);
+__LA_DECL const char * archive_liblzma_version(void);
+__LA_DECL const char * archive_bzlib_version(void);
+__LA_DECL const char * archive_liblz4_version(void);
+
/* Declare our basic types. */
struct archive;
struct archive_entry;
@@ -177,7 +215,7 @@ struct archive_entry;
*/
/* Returns pointer and size of next block of data from archive. */
-typedef __LA_SSIZE_T archive_read_callback(struct 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.
@@ -185,18 +223,18 @@ typedef __LA_SSIZE_T archive_read_callback(struct archive *,
* 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);
+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);
+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 *,
+typedef la_ssize_t archive_write_callback(struct archive *,
void *_client_data,
const void *_buffer, size_t _length);
@@ -212,6 +250,13 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
void *_client_data2);
/*
+ * Returns a passphrase used for encryption or decryption, NULL on nothing
+ * to do and give it up.
+ */
+typedef const char *archive_passphrase_callback(struct archive *,
+ void *_client_data);
+
+/*
* Codes to identify various stream filters.
*/
#define ARCHIVE_FILTER_NONE 0
@@ -227,6 +272,7 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
#define ARCHIVE_FILTER_LRZIP 10
#define ARCHIVE_FILTER_LZOP 11
#define ARCHIVE_FILTER_GRZIP 12
+#define ARCHIVE_FILTER_LZ4 13
#if ARCHIVE_VERSION_NUMBER < 4000000
#define ARCHIVE_COMPRESSION_NONE ARCHIVE_FILTER_NONE
@@ -288,6 +334,31 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
#define ARCHIVE_FORMAT_CAB 0xC0000
#define ARCHIVE_FORMAT_RAR 0xD0000
#define ARCHIVE_FORMAT_7ZIP 0xE0000
+#define ARCHIVE_FORMAT_WARC 0xF0000
+
+/*
+ * Codes returned by archive_read_format_capabilities().
+ *
+ * This list can be extended with values between 0 and 0xffff.
+ * The original purpose of this list was to let different archive
+ * format readers expose their general capabilities in terms of
+ * encryption.
+ */
+#define ARCHIVE_READ_FORMAT_CAPS_NONE (0) /* no special capabilities */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA (1<<0) /* reader can detect encrypted data */
+#define ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA (1<<1) /* reader can detect encryptable metadata (pathname, mtime, etc.) */
+
+/*
+ * Codes returned by archive_read_has_encrypted_entries().
+ *
+ * In case the archive does not support encryption detection at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned. If the reader
+ * for some other reason (e.g. not enough bytes read) cannot say if
+ * there are encrypted entries, ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW
+ * is returned.
+ */
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED -2
+#define ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW -1
/*-
* Basic outline for reading an archive:
@@ -299,7 +370,7 @@ typedef int archive_switch_callback(struct archive *, void *_client_data1,
* 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.
+ * 5) Call archive_read_free to end processing.
*/
__LA_DECL struct archive *archive_read_new(void);
@@ -346,6 +417,7 @@ __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_grzip(struct archive *);
__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lz4(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_lzop(struct archive *);
@@ -373,8 +445,17 @@ __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_warc(struct archive *);
__LA_DECL int archive_read_support_format_xar(struct archive *);
+/* archive_read_support_format_zip() enables both streamable and seekable
+ * zip readers. */
__LA_DECL int archive_read_support_format_zip(struct archive *);
+/* Reads Zip archives as stream from beginning to end. Doesn't
+ * correctly handle SFX ZIP files or ZIP archives that have been modified
+ * in-place. */
+__LA_DECL int archive_read_support_format_zip_streamable(struct archive *);
+/* Reads starting from central directory; requires seekable input. */
+__LA_DECL int archive_read_support_format_zip_seekable(struct archive *);
/* Functions to manually set the format and filters to be used. This is
* useful to bypass the bidding process when the format and filters to use
@@ -445,9 +526,9 @@ __LA_DECL int archive_read_open_file(struct archive *,
const char *_filename, size_t _block_size) __LA_DEPRECATED;
/* Read an archive that's stored in memory. */
__LA_DECL int archive_read_open_memory(struct archive *,
- void * buff, size_t size);
+ const 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,
+__LA_DECL int archive_read_open_memory2(struct archive *a, const 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,
@@ -468,14 +549,40 @@ __LA_DECL int archive_read_next_header2(struct archive *,
* Retrieve the byte offset in UNCOMPRESSED data where last-read
* header started.
*/
-__LA_DECL __LA_INT64_T archive_read_header_position(struct archive *);
+__LA_DECL la_int64_t archive_read_header_position(struct archive *);
+
+/*
+ * Returns 1 if the archive contains at least one encrypted entry.
+ * If the archive format not support encryption at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
+ * If for any other reason (e.g. not enough data read so far)
+ * we cannot say whether there are encrypted entries, then
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
+ * In general, this function will return values below zero when the
+ * reader is uncertain or totally incapable of encryption support.
+ * When this function returns 0 you can be sure that the reader
+ * supports encryption detection but no encrypted entries have
+ * been found yet.
+ *
+ * NOTE: If the metadata/header of an archive is also encrypted, you
+ * cannot rely on the number of encrypted entries. That is why this
+ * function does not return the number of encrypted entries but#
+ * just shows that there are some.
+ */
+__LA_DECL int archive_read_has_encrypted_entries(struct archive *);
+
+/*
+ * Returns a bitmask of capabilities that are supported by the archive format reader.
+ * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.
+ */
+__LA_DECL int archive_read_format_capabilities(struct archive *);
/* Read data from the body of an entry. Similar to read(2). */
-__LA_DECL __LA_SSIZE_T archive_read_data(struct archive *,
+__LA_DECL la_ssize_t archive_read_data(struct archive *,
void *, size_t);
/* Seek within the body of an entry. Similar to lseek(2). */
-__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
+__LA_DECL la_int64_t archive_seek_data(struct archive *, la_int64_t, int);
/*
* A zero-copy version of archive_read_data that also exposes the file offset
@@ -484,7 +591,7 @@ __LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
* 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);
+ const void **buff, size_t *size, la_int64_t *offset);
/*-
* Some convenience functions that are built on archive_read_data:
@@ -514,6 +621,14 @@ __LA_DECL int archive_read_set_option(struct archive *_a,
__LA_DECL int archive_read_set_options(struct archive *_a,
const char *opts);
+/*
+ * Add a decryption passphrase.
+ */
+__LA_DECL int archive_read_add_passphrase(struct archive *, const char *);
+__LA_DECL int archive_read_set_passphrase_callback(struct archive *,
+ void *client_data, archive_passphrase_callback *);
+
+
/*-
* Convenience function to recreate the current entry (whose header
* has just been read) on disk.
@@ -566,6 +681,10 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
/* Default: Do not use HFS+ compression if it was not compressed. */
/* This has no effect except on Mac OS v10.6 or later. */
#define ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED (0x8000)
+/* Default: Do not reject entries with absolute paths */
+#define ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS (0x10000)
+/* Default: Do not clear no-change flags when unlinking object */
+#define ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS (0x20000)
__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
@@ -577,7 +696,7 @@ __LA_DECL void archive_read_extract_set_progress_callback(struct archive *,
/* 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);
+ la_int64_t, la_int64_t);
/* Close the file and release most resources. */
__LA_DECL int archive_read_close(struct archive *);
@@ -616,7 +735,7 @@ __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);
+ la_int64_t, la_int64_t);
#if ARCHIVE_VERSION_NUMBER < 4000000
__LA_DECL int archive_write_set_compression_bzip2(struct archive *)
@@ -647,6 +766,7 @@ __LA_DECL int archive_write_add_filter_compress(struct archive *);
__LA_DECL int archive_write_add_filter_grzip(struct archive *);
__LA_DECL int archive_write_add_filter_gzip(struct archive *);
__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lz4(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_lzop(struct archive *);
@@ -674,12 +794,16 @@ __LA_DECL int archive_write_set_format_mtree_classic(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_raw(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_v7tar(struct archive *);
+__LA_DECL int archive_write_set_format_warc(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_set_format_filter_by_ext(struct archive *a, const char *filename);
+__LA_DECL int archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext);
__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
__LA_DECL int archive_write_open(struct archive *, void *,
@@ -704,12 +828,12 @@ __LA_DECL int archive_write_open_memory(struct archive *,
*/
__LA_DECL int archive_write_header(struct archive *,
struct archive_entry *);
-__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *,
+__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 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 *);
@@ -744,6 +868,13 @@ __LA_DECL int archive_write_set_option(struct archive *_a,
__LA_DECL int archive_write_set_options(struct archive *_a,
const char *opts);
+/*
+ * Set a encryption passphrase.
+ */
+__LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p);
+__LA_DECL int archive_write_set_passphrase_callback(struct archive *,
+ void *client_data, archive_passphrase_callback *);
+
/*-
* ARCHIVE_WRITE_DISK API
*
@@ -763,7 +894,7 @@ __LA_DECL int archive_write_set_options(struct archive *_a,
__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);
+ 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 *,
@@ -793,14 +924,14 @@ __LA_DECL int archive_write_disk_set_standard_lookup(struct archive *);
*/
__LA_DECL int archive_write_disk_set_group_lookup(struct archive *,
void * /* private_data */,
- __LA_INT64_T (*)(void *, const char *, __LA_INT64_T),
+ 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),
+ 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);
+__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
@@ -821,19 +952,19 @@ __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);
+__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),
+ 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),
+ 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 *);
@@ -850,12 +981,12 @@ __LA_DECL int archive_read_disk_can_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. */
+/* Request that the access time of the entry visited by traversal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/*
* Set behavior. The "flags" argument selects optional behavior.
*/
-/* Request that the access time of the entry visited by travesal be restored.
+/* Request that the access time of the entry visited by traversal be restored.
* This is the same as archive_read_disk_set_atime_restored. */
#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001)
/* Default: Do not skip an entry which has nodump flags. */
@@ -863,8 +994,14 @@ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
/* Default: Skip a mac resource fork file whose prefix is "._" because of
* using copyfile. */
#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004)
-/* Default: Do not traverse mount points. */
+/* Default: Traverse mount points. */
#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008)
+/* Default: Xattrs are read from disk. */
+#define ARCHIVE_READDISK_NO_XATTR (0x0010)
+/* Default: ACLs are read from disk. */
+#define ARCHIVE_READDISK_NO_ACL (0x0020)
+/* Default: File flags are read from disk. */
+#define ARCHIVE_READDISK_NO_FFLAGS (0x0040)
__LA_DECL int archive_read_disk_set_behavior(struct archive *,
int flags);
@@ -883,6 +1020,10 @@ __LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,
int (*_metadata_filter_func)(struct archive *, void *,
struct archive_entry *), void *_client_data);
+/* Simplified cleanup interface;
+ * This calls archive_read_free() or archive_write_free() as needed. */
+__LA_DECL int archive_free(struct archive *);
+
/*
* Accessor functions to read/set various information in
* the struct archive object:
@@ -893,7 +1034,7 @@ __LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,
* 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 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);
@@ -901,10 +1042,10 @@ __LA_DECL const char * archive_filter_name(struct archive *, int);
/* 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 *)
+__LA_DECL la_int64_t archive_position_compressed(struct archive *)
__LA_DEPRECATED;
/* 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 *)
+__LA_DECL la_int64_t archive_position_uncompressed(struct archive *)
__LA_DEPRECATED;
/* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
__LA_DECL const char *archive_compression_name(struct archive *)
@@ -984,7 +1125,7 @@ __LA_DECL int archive_match_time_excluded(struct archive *,
/*
* Flags to tell a matching type of time stamps. These are used for
- * following functinos.
+ * following functions.
*/
/* Time flag: mtime to be tested. */
#define ARCHIVE_MATCH_MTIME (0x0100)
@@ -1004,7 +1145,7 @@ __LA_DECL int archive_match_include_date(struct archive *, int _flag,
const char *_datestr);
__LA_DECL int archive_match_include_date_w(struct archive *, int _flag,
const wchar_t *_datestr);
-/* Set inclusion time by a particluar file. */
+/* Set inclusion time by a particular file. */
__LA_DECL int archive_match_include_file_time(struct archive *,
int _flag, const char *_pathname);
__LA_DECL int archive_match_include_file_time_w(struct archive *,
@@ -1020,8 +1161,8 @@ __LA_DECL int archive_match_exclude_entry(struct archive *,
__LA_DECL int archive_match_owner_excluded(struct archive *,
struct archive_entry *);
/* Add inclusion uid, gid, uname and gname. */
-__LA_DECL int archive_match_include_uid(struct archive *, __LA_INT64_T);
-__LA_DECL int archive_match_include_gid(struct archive *, __LA_INT64_T);
+__LA_DECL int archive_match_include_uid(struct archive *, la_int64_t);
+__LA_DECL int archive_match_include_gid(struct archive *, la_int64_t);
__LA_DECL int archive_match_include_uname(struct archive *, const char *);
__LA_DECL int archive_match_include_uname_w(struct archive *,
const wchar_t *);
@@ -1029,6 +1170,10 @@ __LA_DECL int archive_match_include_gname(struct archive *, const char *);
__LA_DECL int archive_match_include_gname_w(struct archive *,
const wchar_t *);
+/* Utility functions */
+/* Convenience function to sort a NULL terminated list of strings */
+__LA_DECL int archive_utility_string_sort(char **);
+
#ifdef __cplusplus
}
#endif
@@ -1036,9 +1181,4 @@ __LA_DECL int archive_match_include_gname_w(struct archive *,
/* These are meaningless outside of this header. */
#undef __LA_DECL
-/* 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 --git a/Utilities/cmlibarchive/libarchive/archive_acl.c b/Utilities/cmlibarchive/libarchive/archive_acl.c
index bf4b61040..b8b6b6364 100644
--- a/Utilities/cmlibarchive/libarchive/archive_acl.c
+++ b/Utilities/cmlibarchive/libarchive/archive_acl.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2010 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,25 +56,77 @@ static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
static int archive_acl_add_entry_len_l(struct archive_acl *acl,
int type, int permset, int tag, int id, const char *name,
size_t len, struct archive_string_conv *sc);
+static int archive_acl_text_want_type(struct archive_acl *acl, int flags);
+static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type,
+ int flags, int wide, struct archive *a,
+ struct archive_string_conv *sc);
static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
+static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,
+ int *result);
+static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end,
+ int *result);
static void next_field_w(const wchar_t **wp, const wchar_t **start,
const wchar_t **end, wchar_t *sep);
-static int prefix_w(const wchar_t *start, const wchar_t *end,
- const wchar_t *test);
-static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
- const wchar_t *wname, int perm, int id);
+static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, const wchar_t *wname, int perm, int id);
static void append_id_w(wchar_t **wp, int id);
static int isint(const char *start, const char *end, int *result);
static int ismode(const char *start, const char *end, int *result);
+static int is_nfs4_flags(const char *start, const char *end,
+ int *result);
+static int is_nfs4_perms(const char *start, const char *end,
+ int *result);
static void next_field(const char **p, const char **start,
const char **end, char *sep);
-static int prefix_c(const char *start, const char *end,
- const char *test);
-static void append_entry(char **p, const char *prefix, int tag,
- const char *name, int perm, int id);
+static void append_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id);
static void append_id(char **p, int id);
+static const struct {
+ const int perm;
+ const char c;
+ const wchar_t wc;
+} nfsv4_acl_perm_map[] = {
+ { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r',
+ L'r' },
+ { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w',
+ L'w' },
+ { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' },
+ { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
+ 'p', L'p' },
+ { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' },
+ { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' },
+ { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' },
+ { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' },
+ { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' },
+ { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' },
+ { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' },
+ { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' },
+ { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' },
+ { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' }
+};
+
+static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) /
+ sizeof(nfsv4_acl_perm_map[0]));
+
+static const struct {
+ const int perm;
+ const char c;
+ const wchar_t wc;
+} nfsv4_acl_flag_map[] = {
+ { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' },
+ { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' }
+};
+
+static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) /
+ sizeof(nfsv4_acl_flag_map[0]));
+
void
archive_acl_clear(struct archive_acl *acl)
{
@@ -94,6 +147,7 @@ archive_acl_clear(struct archive_acl *acl)
acl->acl_text = NULL;
}
acl->acl_p = NULL;
+ acl->acl_types = 0;
acl->acl_state = 0; /* Not counting. */
}
@@ -279,23 +333,31 @@ acl_new_entry(struct archive_acl *acl,
acl->acl_text = NULL;
}
- /* If there's a matching entry already in the list, overwrite it. */
+ /*
+ * If there's a matching entry already in the list, overwrite it.
+ * NFSv4 entries may be repeated and are not overwritten.
+ *
+ * TODO: compare names of no id is provided (needs more rework)
+ */
ap = acl->acl_head;
aq = NULL;
while (ap != NULL) {
- if (ap->type == type && ap->tag == tag && ap->id == id) {
- ap->permset = permset;
- return (ap);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) &&
+ ap->type == type && ap->tag == tag && ap->id == id) {
+ if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER &&
+ tag != ARCHIVE_ENTRY_ACL_GROUP)) {
+ ap->permset = permset;
+ return (ap);
+ }
}
aq = ap;
ap = ap->next;
}
/* Add a new entry to the end of the list. */
- ap = (struct archive_acl_entry *)malloc(sizeof(*ap));
+ ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap));
if (ap == NULL)
return (NULL);
- memset(ap, 0, sizeof(*ap));
if (aq == NULL)
acl->acl_head = ap;
else
@@ -331,6 +393,15 @@ archive_acl_count(struct archive_acl *acl, int want_type)
}
/*
+ * Return a bitmask of stored ACL types in an ACL list
+ */
+int
+archive_acl_types(struct archive_acl *acl)
+{
+ return (acl->acl_types);
+}
+
+/*
* Prepare for reading entries from the ACL data. Returns a count
* of entries matching "want_type", or zero if there are no
* non-extended ACL entries of that type.
@@ -366,8 +437,8 @@ archive_acl_reset(struct archive_acl *acl, int want_type)
* standard permissions and include them in the returned list.
*/
int
-archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *type,
- int *permset, int *tag, int *id, const char **name)
+archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type,
+ int *type, int *permset, int *tag, int *id, const char **name)
{
*name = NULL;
*id = -1;
@@ -432,130 +503,273 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int
}
/*
- * Generate a text version of the ACL. The flags parameter controls
- * the style of the generated ACL.
+ * Determine what type of ACL do we want
*/
-const wchar_t *
-archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
+static int
+archive_acl_text_want_type(struct archive_acl *acl, int flags)
{
- int count;
- size_t length;
- const wchar_t *wname;
- const wchar_t *prefix;
- wchar_t separator;
- struct archive_acl_entry *ap;
- int id, r;
- wchar_t *wp;
+ int want_type;
- if (acl->acl_text_w != NULL) {
- free (acl->acl_text_w);
- acl->acl_text_w = NULL;
+ /* Check if ACL is NFSv4 */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ /* NFSv4 should never mix with POSIX.1e */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ return (0);
+ else
+ return (ARCHIVE_ENTRY_ACL_TYPE_NFS4);
}
- separator = L',';
+ /* Now deal with POSIX.1e ACLs */
+
+ want_type = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+
+ /* By default we want both access and default ACLs */
+ if (want_type == 0)
+ return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E);
+
+ return (want_type);
+}
+
+/*
+ * Calculate ACL text string length
+ */
+static ssize_t
+archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
+ int wide, struct archive *a, struct archive_string_conv *sc) {
+ struct archive_acl_entry *ap;
+ const char *name;
+ const wchar_t *wname;
+ int count, idlen, tmp, r;
+ ssize_t length;
+ size_t len;
+
count = 0;
length = 0;
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & flags) != 0) {
- count++;
- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
- (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
- length += 8; /* "default:" */
- length += 5; /* tag name */
- length += 1; /* colon */
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0 && wname != NULL)
- length += wcslen(wname);
- else if (r < 0 && errno == ENOMEM)
- return (NULL);
- else
- length += sizeof(uid_t) * 3 + 1;
- length ++; /* colon */
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ count++;
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0
+ && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ length += 8; /* "default:" */
+ switch (ap->tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "owner@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ length += 4; /* "user", "mask" */
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "group@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ length += 5; /* "group", "other" */
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ length += 9; /* "everyone@" */
+ break;
+ }
+ length += 1; /* colon after tag */
+ if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (wide) {
+ r = archive_mstring_get_wcs(a, &ap->name,
+ &wname);
+ if (r == 0 && wname != NULL)
+ length += wcslen(wname);
+ else if (r < 0 && errno == ENOMEM)
+ return (0);
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ } else {
+ r = archive_mstring_get_mbs_l(&ap->name, &name,
+ &len, sc);
+ if (r != 0)
+ return (0);
+ if (len > 0 && name != NULL)
+ length += len;
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ }
+ length += 1; /* colon after user or group name */
+ } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)
+ length += 1; /* 2nd colon empty user,group or other */
+
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)
+ && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER
+ || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {
+ /* Solaris has no colon after other: and mask: */
+ length = length - 1;
+ }
+
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* rwxpdDaARWcCos:fdinSFI:deny */
+ length += 27;
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)
+ length += 1; /* allow, alarm, audit */
+ } else
length += 3; /* rwx */
+
+ if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {
length += 1; /* colon */
- length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
- length ++; /* newline */
+ /* ID digit count */
+ idlen = 1;
+ tmp = ap->id;
+ while (tmp > 9) {
+ tmp = tmp / 10;
+ idlen++;
+ }
+ length += idlen;
}
- ap = ap->next;
+ length ++; /* entry separator */
}
- if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
- length += 10; /* "user::rwx\n" */
- length += 11; /* "group::rwx\n" */
- length += 11; /* "other::rwx\n" */
- }
+ /* Add filemode-mapping access entries to the length */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {
+ /* "user::rwx\ngroup::rwx\nother:rwx\n" */
+ length += 31;
+ } else {
+ /* "user::rwx\ngroup::rwx\nother::rwx\n" */
+ length += 32;
+ }
+ } else if (count == 0)
+ return (0);
+
+ /* The terminating character is included in count */
+ return (length);
+}
+
+/*
+ * Generate a wide text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+wchar_t *
+archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
+ struct archive *a)
+{
+ int count;
+ ssize_t length;
+ size_t len;
+ const wchar_t *wname;
+ const wchar_t *prefix;
+ wchar_t separator;
+ struct archive_acl_entry *ap;
+ int id, r, want_type;
+ wchar_t *wp, *ws;
+
+ want_type = archive_acl_text_want_type(acl, flags);
+
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
+ return (NULL);
+
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);
- if (count == 0)
+ if (length == 0)
return (NULL);
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = L',';
+ else
+ separator = L'\n';
+
/* Now, allocate the string and actually populate it. */
- wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
- if (wp == NULL)
+ wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t));
+ if (wp == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
count += 3;
-
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0) {
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, NULL, ap->tag, wname,
- ap->permset, id);
- count++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
}
-
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
prefix = L"default:";
else
prefix = NULL;
- ap = acl->acl_head;
- count = 0;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0) {
- if (count > 0)
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, prefix, ap->tag,
- wname, ap->permset, id);
- count ++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 0) {
+ if (count > 0)
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, prefix, ap->type, ap->tag, flags,
+ wname, ap->permset, id);
+ count++;
+ } else if (r < 0 && errno == ENOMEM)
+ return (NULL);
}
- return (acl->acl_text_w);
-}
+ /* Add terminating character */
+ *wp++ = L'\0';
+
+ len = wcslen(ws);
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (ws);
+}
static void
append_id_w(wchar_t **wp, int id)
@@ -568,9 +782,11 @@ append_id_w(wchar_t **wp, int id)
}
static void
-append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
- const wchar_t *wname, int perm, int id)
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, const wchar_t *wname, int perm, int id)
{
+ int i;
+
if (prefix != NULL) {
wcscpy(*wp, prefix);
*wp += wcslen(*wp);
@@ -579,6 +795,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
wcscpy(*wp, L"user");
@@ -586,6 +806,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
wcscpy(*wp, L"group");
@@ -600,153 +824,184 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
wname = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ wcscpy(*wp, L"everyone@");
+ wname = NULL;
+ id = -1;
+ break;
}
*wp += wcslen(*wp);
*(*wp)++ = L':';
- if (wname != NULL) {
- wcscpy(*wp, wname);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (wname != NULL) {
+ wcscpy(*wp, wname);
+ *wp += wcslen(*wp);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id_w(wp, id);
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*wp)++ = L':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+ *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+ *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ } else {
+ /* NFSv4 ACL perms */
+ for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
+ if (perm & nfsv4_acl_perm_map[i].perm)
+ *(*wp)++ = nfsv4_acl_perm_map[i].wc;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*wp)++ = L'-';
+ }
+ *(*wp)++ = L':';
+ for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
+ if (perm & nfsv4_acl_flag_map[i].perm)
+ *(*wp)++ = nfsv4_acl_flag_map[i].wc;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*wp)++ = L'-';
+ }
+ *(*wp)++ = L':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ wcscpy(*wp, L"allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ wcscpy(*wp, L"deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ wcscpy(*wp, L"audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ wcscpy(*wp, L"alarm");
+ break;
+ default:
+ break;
+ }
*wp += wcslen(*wp);
- } else if (tag == ARCHIVE_ENTRY_ACL_USER
- || tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id_w(wp, id);
- id = -1;
}
- *(*wp)++ = L':';
- *(*wp)++ = (perm & 0444) ? L'r' : L'-';
- *(*wp)++ = (perm & 0222) ? L'w' : L'-';
- *(*wp)++ = (perm & 0111) ? L'x' : L'-';
if (id != -1) {
*(*wp)++ = L':';
append_id_w(wp, id);
}
- **wp = L'\0';
}
-int
-archive_acl_text_l(struct archive_acl *acl, int flags,
- const char **acl_text, size_t *acl_text_len,
+/*
+ * Generate a text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+char *
+archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
struct archive_string_conv *sc)
{
int count;
- size_t length;
+ ssize_t length;
+ size_t len;
const char *name;
const char *prefix;
char separator;
struct archive_acl_entry *ap;
- size_t len;
- int id, r;
- char *p;
+ int id, r, want_type;
+ char *p, *s;
- if (acl->acl_text != NULL) {
- free (acl->acl_text);
- acl->acl_text = NULL;
- }
+ want_type = archive_acl_text_want_type(acl, flags);
- *acl_text = NULL;
- if (acl_text_len != NULL)
- *acl_text_len = 0;
- separator = ',';
- count = 0;
- length = 0;
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & flags) != 0) {
- count++;
- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
- (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
- length += 8; /* "default:" */
- length += 5; /* tag name */
- length += 1; /* colon */
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- if (len > 0 && name != NULL)
- length += len;
- else
- length += sizeof(uid_t) * 3 + 1;
- length ++; /* colon */
- length += 3; /* rwx */
- length += 1; /* colon */
- length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
- length ++; /* newline */
- }
- ap = ap->next;
- }
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
+ return (NULL);
- if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
- length += 10; /* "user::rwx\n" */
- length += 11; /* "group::rwx\n" */
- length += 11; /* "other::rwx\n" */
- }
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
- if (count == 0)
- return (0);
+ length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);
+
+ if (length == 0)
+ return (NULL);
+
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = ',';
+ else
+ separator = '\n';
/* Now, allocate the string and actually populate it. */
- p = acl->acl_text = (char *)malloc(length);
- if (p == NULL)
- return (-1);
+ p = s = (char *)malloc(length * sizeof(char));
+ if (p == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
count += 3;
-
- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) == 0)
- continue;
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- *p++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry(&p, NULL, ap->tag, name,
- ap->permset, id);
- count++;
- }
}
-
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
prefix = "default:";
else
prefix = NULL;
- count = 0;
- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) == 0)
- continue;
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- if (count > 0)
- *p++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry(&p, prefix, ap->tag,
- name, ap->permset, id);
- count ++;
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (NULL);
+ if (count > 0)
+ *p++ = separator;
+ if (name == NULL ||
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
+ id = ap->id;
+ } else {
+ id = -1;
}
+ append_entry(&p, prefix, ap->type, ap->tag, flags, name,
+ ap->permset, id);
+ count++;
}
- *acl_text = acl->acl_text;
- if (acl_text_len != NULL)
- *acl_text_len = strlen(acl->acl_text);
- return (0);
+ /* Add terminating character */
+ *p++ = '\0';
+
+ len = strlen(s);
+
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (s);
}
static void
@@ -760,9 +1015,11 @@ append_id(char **p, int id)
}
static void
-append_entry(char **p, const char *prefix, int tag,
- const char *name, int perm, int id)
+append_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id)
{
+ int i;
+
if (prefix != NULL) {
strcpy(*p, prefix);
*p += strlen(*p);
@@ -771,6 +1028,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
strcpy(*p, "user");
@@ -778,6 +1039,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
strcpy(*p, "group");
@@ -792,48 +1057,120 @@ append_entry(char **p, const char *prefix, int tag,
name = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ strcpy(*p, "everyone@");
+ name = NULL;
+ id = -1;
+ break;
}
*p += strlen(*p);
*(*p)++ = ':';
- if (name != NULL) {
- strcpy(*p, name);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (name != NULL) {
+ strcpy(*p, name);
+ *p += strlen(*p);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id(p, id);
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0)
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*p)++ = ':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*p)++ = (perm & 0444) ? 'r' : '-';
+ *(*p)++ = (perm & 0222) ? 'w' : '-';
+ *(*p)++ = (perm & 0111) ? 'x' : '-';
+ } else {
+ /* NFSv4 ACL perms */
+ for (i = 0; i < nfsv4_acl_perm_map_size; i++) {
+ if (perm & nfsv4_acl_perm_map[i].perm)
+ *(*p)++ = nfsv4_acl_perm_map[i].c;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*p)++ = '-';
+ }
+ *(*p)++ = ':';
+ for (i = 0; i < nfsv4_acl_flag_map_size; i++) {
+ if (perm & nfsv4_acl_flag_map[i].perm)
+ *(*p)++ = nfsv4_acl_flag_map[i].c;
+ else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0)
+ *(*p)++ = '-';
+ }
+ *(*p)++ = ':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ strcpy(*p, "allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ strcpy(*p, "deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ strcpy(*p, "audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ strcpy(*p, "alarm");
+ break;
+ }
*p += strlen(*p);
- } else if (tag == ARCHIVE_ENTRY_ACL_USER
- || tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id(p, id);
- id = -1;
}
- *(*p)++ = ':';
- *(*p)++ = (perm & 0444) ? 'r' : '-';
- *(*p)++ = (perm & 0222) ? 'w' : '-';
- *(*p)++ = (perm & 0111) ? 'x' : '-';
if (id != -1) {
*(*p)++ = ':';
append_id(p, id);
}
- **p = '\0';
}
/*
- * Parse a textual ACL. This automatically recognizes and supports
- * extensions described above. The 'type' argument is used to
- * indicate the type that should be used for any entries not
- * explicitly marked as "default:".
+ * Parse a wide ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_w(struct archive_acl *acl,
- const wchar_t *text, int default_type)
+archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
+ int want_type)
{
struct {
const wchar_t *start;
const wchar_t *end;
- } field[4], name;
+ } field[6], name;
+
+ const wchar_t *s, *st;
- int fields, n;
- int type, tag, permset, id;
+ int numfields, fields, n, r, sol, ret;
+ int type, types, tag, permset, id;
+ size_t len;
wchar_t sep;
- while (text != NULL && *text != L'\0') {
+ ret = ARCHIVE_OK;
+ types = 0;
+
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ while (text != NULL && *text != L'\0') {
/*
* Parse the fields out of the next entry,
* advance 'text' to start of next entry.
@@ -842,7 +1179,7 @@ archive_acl_parse_w(struct archive_acl *acl,
do {
const wchar_t *start, *end;
next_field_w(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -850,78 +1187,210 @@ archive_acl_parse_w(struct archive_acl *acl,
} while (sep == L':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
- /* Check for a numeric ID in field 1 or 3. */
- id = -1;
- isint_w(field[1].start, field[1].end, &id);
- /* Field 3 is optional. */
- if (id == -1 && fields > 3)
- isint_w(field[3].start, field[3].end, &id);
-
- /*
- * Solaris extension: "defaultuser::rwx" is the
- * default ACL corresponding to "user::rwx", etc.
- */
- if (field[0].end - field[0].start > 7
- && wmemcmp(field[0].start, L"default", 7) == 0) {
- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
- field[0].start += 7;
- } else
- type = default_type;
+ if (field[0].start != NULL && *(field[0].start) == L'#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ sol = 0;
+ id = -1;
+ permset = 0;
name.start = name.end = NULL;
- if (prefix_w(field[0].start, field[0].end, L"user")) {
- if (!ismode_w(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_USER;
- name = field[1];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == L'd' && (len == 1 || (len >= 7
+ && wmemcmp((s + 1), L"efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 1;
} else
- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix_w(field[0].start, field[0].end, L"group")) {
- if (!ismode_w(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_GROUP;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint_w(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > n+3)
+ isint_w(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case L'u':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case L'g':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case L'o':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case L'm':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode_w(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ sol = 1;
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /*
+ * Without "default:" we expect mode in field 2
+ * Exception: Solaris other and mask fields
+ */
+ if (permset == 0 && !ismode_w(field[n + 2 - sol].start,
+ field[n + 2 - sol].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (wmemcmp(s, L"user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (wmemcmp(s, L"group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (wmemcmp(s, L"owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (wmemcmp(s, L"group@", len) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (wmemcmp(s, L"everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
+ isint_w(name.start, name.end, &id);
} else
- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix_w(field[0].start, field[0].end, L"other")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode_w(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "other:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode_w(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "other::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode_w(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "mask:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode_w(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "mask::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_MASK;
- } else
- return (ARCHIVE_WARN);
+ n = 0;
+
+ if (!is_nfs4_perms_w(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags_w(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (wmemcmp(s, L"deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (wmemcmp(s, L"allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (wmemcmp(s, L"audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (wmemcmp(s, L"alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint_w(field[4 + n].start, field[4 + n].end, &id);
+ }
/* Add entry to the internal list. */
- archive_acl_add_entry_w_len(acl, type, permset,
+ r = archive_acl_add_entry_w_len(acl, type, permset,
tag, id, name.start, name.end - name.start);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ if (r != ARCHIVE_OK)
+ ret = ARCHIVE_WARN;
+ types |= type;
}
- return (ARCHIVE_OK);
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
+ return (ret);
}
/*
@@ -967,16 +1436,122 @@ ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
*permset = 0;
while (p < end) {
switch (*p++) {
- case 'r': case 'R':
+ case L'r': case L'R':
*permset |= ARCHIVE_ENTRY_ACL_READ;
break;
- case 'w': case 'W':
+ case L'w': case L'W':
*permset |= ARCHIVE_ENTRY_ACL_WRITE;
break;
- case 'x': case 'X':
+ case L'x': case L'X':
*permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
break;
- case '-':
+ case L'-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p = start;
+
+ while (p < end) {
+ switch (*p++) {
+ case L'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case L'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case L'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case L'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case L'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case L'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case L'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case L'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case L'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case L'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case L'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case L'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case L's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case L'-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p = start;
+
+ while (p < end) {
+ switch(*p++) {
+ case L'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case L'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case L'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case L'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case L'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case L'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ break;
+ case L'-':
break;
default:
return (0);
@@ -1023,46 +1598,48 @@ next_field_w(const wchar_t **wp, const wchar_t **start,
}
/*
- * Return true if the characters [start...end) are a prefix of 'test'.
- * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
- */
-static int
-prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
-{
- if (start == end)
- return (0);
-
- if (*start++ != *test++)
- return (0);
-
- while (start < end && *start++ == *test++)
- ;
-
- if (start < end)
- return (0);
-
- return (1);
-}
-
-/*
- * Parse a textual ACL. This automatically recognizes and supports
- * extensions described above. The 'type' argument is used to
- * indicate the type that should be used for any entries not
- * explicitly marked as "default:".
+ * Parse an ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_l(struct archive_acl *acl,
- const char *text, int default_type, struct archive_string_conv *sc)
+archive_acl_from_text_l(struct archive_acl *acl, const char *text,
+ int want_type, struct archive_string_conv *sc)
{
struct {
const char *start;
const char *end;
- } field[4], name;
+ } field[6], name;
- int fields, n, r, ret = ARCHIVE_OK;
- int type, tag, permset, id;
+ const char *s, *st;
+ int numfields, fields, n, r, sol, ret;
+ int type, types, tag, permset, id;
+ size_t len;
char sep;
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ ret = ARCHIVE_OK;
+ types = 0;
+
while (text != NULL && *text != '\0') {
/*
* Parse the fields out of the next entry,
@@ -1072,7 +1649,7 @@ archive_acl_parse_l(struct archive_acl *acl,
do {
const char *start, *end;
next_field(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -1080,72 +1657,197 @@ archive_acl_parse_l(struct archive_acl *acl,
} while (sep == ':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
- /* Check for a numeric ID in field 1 or 3. */
- id = -1;
- isint(field[1].start, field[1].end, &id);
- /* Field 3 is optional. */
- if (id == -1 && fields > 3)
- isint(field[3].start, field[3].end, &id);
-
- /*
- * Solaris extension: "defaultuser::rwx" is the
- * default ACL corresponding to "user::rwx", etc.
- */
- if (field[0].end - field[0].start > 7
- && memcmp(field[0].start, "default", 7) == 0) {
- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
- field[0].start += 7;
- } else
- type = default_type;
+ if (field[0].start != NULL && *(field[0].start) == '#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ sol = 0;
+ id = -1;
+ permset = 0;
name.start = name.end = NULL;
- if (prefix_c(field[0].start, field[0].end, "user")) {
- if (!ismode(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_USER;
- name = field[1];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == 'd' && (len == 1 || (len >= 7
+ && memcmp((s + 1), "efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 1;
} else
- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix_c(field[0].start, field[0].end, "group")) {
- if (!ismode(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_GROUP;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > (n + 3))
+ isint(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case 'u':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case 'g':
+ if (len == 1 || (len == 5
+ && memcmp(st, "roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 'o':
+ if (len == 1 || (len == 5
+ && memcmp(st, "ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case 'm':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ sol = 1;
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /*
+ * Without "default:" we expect mode in field 3
+ * Exception: Solaris other and mask fields
+ */
+ if (permset == 0 && !ismode(field[n + 2 - sol].start,
+ field[n + 2 - sol].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (memcmp(s, "user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (memcmp(s, "group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (memcmp(s, "owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (memcmp(s, "group@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (memcmp(s, "everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ break;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
+ isint(name.start, name.end, &id);
} else
- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix_c(field[0].start, field[0].end, "other")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "other:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "other::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else if (prefix_c(field[0].start, field[0].end, "mask")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "mask:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "mask::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_MASK;
- } else
- return (ARCHIVE_WARN);
+ n = 0;
+
+ if (!is_nfs4_perms(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (memcmp(s, "deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (memcmp(s, "allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (memcmp(s, "audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (memcmp(s, "alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint(field[4 + n].start, field[4 + n].end,
+ &id);
+ }
/* Add entry to the internal list. */
r = archive_acl_add_entry_len_l(acl, type, permset,
@@ -1154,7 +1856,12 @@ archive_acl_parse_l(struct archive_acl *acl,
return (r);
if (r != ARCHIVE_OK)
ret = ARCHIVE_WARN;
+ types |= type;
}
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
return (ret);
}
@@ -1220,6 +1927,112 @@ ismode(const char *start, const char *end, int *permset)
}
/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms(const char *start, const char *end, int *permset)
+{
+ const char *p = start;
+
+ while (p < end) {
+ switch (*p++) {
+ case 'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case 'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case 'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case 'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case 'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case 'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case 'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case 'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case 'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case 'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case 'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case 'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case 's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case '-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags(const char *start, const char *end, int *permset)
+{
+ const char *p = start;
+
+ while (p < end) {
+ switch(*p++) {
+ case 'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case 'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case 'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case 'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case 'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case 'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ break;
+ case '-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
* Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
* to point to just after the separator. *start points to the first
* character of the matched text and *end just after the last
@@ -1254,25 +2067,3 @@ next_field(const char **p, const char **start,
if (**p != '\0')
(*p)++;
}
-
-/*
- * Return true if the characters [start...end) are a prefix of 'test'.
- * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
- */
-static int
-prefix_c(const char *start, const char *end, const char *test)
-{
- if (start == end)
- return (0);
-
- if (*start++ != *test++)
- return (0);
-
- while (start < end && *start++ == *test++)
- ;
-
- if (start < end)
- return (0);
-
- return (1);
-}
diff --git a/Utilities/cmlibarchive/libarchive/archive_acl_private.h b/Utilities/cmlibarchive/libarchive/archive_acl_private.h
index 1421adbf8..ef0b0234c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_acl_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_acl_private.h
@@ -56,6 +56,7 @@ struct archive_acl {
void archive_acl_clear(struct archive_acl *);
void archive_acl_copy(struct archive_acl *, struct archive_acl *);
int archive_acl_count(struct archive_acl *, int);
+int archive_acl_types(struct archive_acl *);
int archive_acl_reset(struct archive_acl *, int);
int archive_acl_next(struct archive *, struct archive_acl *, int,
int *, int *, int *, int *, const char **);
@@ -66,22 +67,17 @@ int archive_acl_add_entry_w_len(struct archive_acl *,
int archive_acl_add_entry_len(struct archive_acl *,
int, int, int, int, const char *, size_t);
-const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
-int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
+wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int,
+ struct archive *);
+char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int,
struct archive_string_conv *);
/*
- * Private ACL parser. This is private because it handles some
- * very weird formats that clients should not be messing with.
- * Clients should only deal with their platform-native formats.
- * Because of the need to support many formats cleanly, new arguments
- * are likely to get added on a regular basis. Clients who try to use
- * this interface are likely to be surprised when it changes.
+ * ACL text parser.
*/
-int archive_acl_parse_w(struct archive_acl *,
- const wchar_t *, int /* type */);
-int archive_acl_parse_l(struct archive_acl *,
- const char *, int /* type */,
- struct archive_string_conv *);
+int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */,
+ int /* type */);
+int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,
+ int /* type */, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff --git a/Utilities/cmlibarchive/libarchive/archive_crypto.c b/Utilities/cmlibarchive/libarchive/archive_crypto.c
deleted file mode 100644
index 85aba3ae2..000000000
--- a/Utilities/cmlibarchive/libarchive/archive_crypto.c
+++ /dev/null
@@ -1,1429 +0,0 @@
-/*-
-* Copyright (c) 2003-2007 Tim Kientzle
-* Copyright (c) 2011 Andres Mejia
-* Copyright (c) 2011 Michihiro NAKAJIMA
-* All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#include "archive_platform.h"
-
-#include "archive.h"
-#include "archive_crypto_private.h"
-
-/* In particular, force the configure probe to break if it tries
- * to test a combination of OpenSSL and libmd. */
-#if defined(ARCHIVE_CRYPTO_OPENSSL) && defined(ARCHIVE_CRYPTO_LIBMD)
-#error Cannot use both OpenSSL and libmd.
-#endif
-
-/*
- * Message digest functions for Windows platform.
- */
-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA512_WIN)
-
-/*
- * Initialize a Message digest.
- */
-static int
-win_crypto_init(Digest_CTX *ctx, ALG_ID algId)
-{
-
- ctx->valid = 0;
- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
- PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
- if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
- return (ARCHIVE_FAILED);
- if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
- PROV_RSA_FULL, CRYPT_NEWKEYSET))
- return (ARCHIVE_FAILED);
- }
-
- if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
- CryptReleaseContext(ctx->cryptProv, 0);
- return (ARCHIVE_FAILED);
- }
-
- ctx->valid = 1;
- return (ARCHIVE_OK);
-}
-
-/*
- * Update a Message digest.
- */
-static int
-win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
-{
-
- if (!ctx->valid)
- return (ARCHIVE_FAILED);
-
- CryptHashData(ctx->hash,
- (unsigned char *)(uintptr_t)buf,
- (DWORD)len, 0);
- return (ARCHIVE_OK);
-}
-
-static int
-win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
-{
- DWORD siglen = (DWORD)bufsize;
-
- if (!ctx->valid)
- return (ARCHIVE_FAILED);
-
- CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
- CryptDestroyHash(ctx->hash);
- CryptReleaseContext(ctx->cryptProv, 0);
- ctx->valid = 0;
- return (ARCHIVE_OK);
-}
-
-#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
-
-
-/* MD5 implementations */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
-
-static int
-__archive_libc_md5init(archive_md5_ctx *ctx)
-{
- MD5Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- MD5Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_md5final(archive_md5_ctx *ctx, void *md)
-{
- MD5Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
-
-static int
-__archive_libmd_md5init(archive_md5_ctx *ctx)
-{
- MD5Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- MD5Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
-{
- MD5Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
-
-static int
-__archive_libsystem_md5init(archive_md5_ctx *ctx)
-{
- CC_MD5_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- CC_MD5_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
-{
- CC_MD5_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
-
-static int
-__archive_nettle_md5init(archive_md5_ctx *ctx)
-{
- md5_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- md5_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
-{
- md5_digest(ctx, MD5_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
-
-static int
-__archive_openssl_md5init(archive_md5_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_md5());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
-{
- /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
- * this is meant to cope with that. Real fix is probably to fix
- * archive_write_set_format_xar.c
- */
- if (ctx->digest)
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
-
-static int
-__archive_windowsapi_md5init(archive_md5_ctx *ctx)
-{
- return (win_crypto_init(ctx, CALG_MD5));
-}
-
-static int
-__archive_windowsapi_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- return (win_crypto_Update(ctx, indata, insize));
-}
-
-static int
-__archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
-{
- return (win_crypto_Final(md, 16, ctx));
-}
-
-#else
-
-static int
-__archive_stub_md5init(archive_md5_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_md5final(archive_md5_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* RIPEMD160 implementations */
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
-
-static int
-__archive_libc_ripemd160init(archive_rmd160_ctx *ctx)
-{
- RMD160Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
- size_t insize)
-{
- RMD160Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
-{
- RMD160Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
-
-static int
-__archive_libmd_ripemd160init(archive_rmd160_ctx *ctx)
-{
- RIPEMD160_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
- size_t insize)
-{
- RIPEMD160_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
-{
- RIPEMD160_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
-
-static int
-__archive_nettle_ripemd160init(archive_rmd160_ctx *ctx)
-{
- ripemd160_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
- size_t insize)
-{
- ripemd160_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
-{
- ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
-
-static int
-__archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_ripemd160());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
-{
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#else
-
-static int
-__archive_stub_ripemd160init(archive_rmd160_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* SHA1 implementations */
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
-
-static int
-__archive_libc_sha1init(archive_sha1_ctx *ctx)
-{
- SHA1Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA1Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- SHA1Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
-
-static int
-__archive_libmd_sha1init(archive_sha1_ctx *ctx)
-{
- SHA1_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA1_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- SHA1_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
-
-static int
-__archive_libsystem_sha1init(archive_sha1_ctx *ctx)
-{
- CC_SHA1_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- CC_SHA1_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- CC_SHA1_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
-
-static int
-__archive_nettle_sha1init(archive_sha1_ctx *ctx)
-{
- sha1_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- sha1_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
-
-static int
-__archive_openssl_sha1init(archive_sha1_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_sha1());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
- * this is meant to cope with that. Real fix is probably to fix
- * archive_write_set_format_xar.c
- */
- if (ctx->digest)
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
-
-static int
-__archive_windowsapi_sha1init(archive_sha1_ctx *ctx)
-{
- return (win_crypto_init(ctx, CALG_SHA1));
-}
-
-static int
-__archive_windowsapi_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- return (win_crypto_Update(ctx, indata, insize));
-}
-
-static int
-__archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- return (win_crypto_Final(md, 20, ctx));
-}
-
-#else
-
-static int
-__archive_stub_sha1init(archive_sha1_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* SHA256 implementations */
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
-
-static int
-__archive_libc_sha256init(archive_sha256_ctx *ctx)
-{
- SHA256_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA256_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- SHA256_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
-
-static int
-__archive_libc2_sha256init(archive_sha256_ctx *ctx)
-{
- SHA256Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA256Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- SHA256Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
-
-static int
-__archive_libc3_sha256init(archive_sha256_ctx *ctx)
-{
- SHA256Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA256Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- SHA256Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
-
-static int
-__archive_libmd_sha256init(archive_sha256_ctx *ctx)
-{
- SHA256_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA256_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- SHA256_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
-
-static int
-__archive_libsystem_sha256init(archive_sha256_ctx *ctx)
-{
- CC_SHA256_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- CC_SHA256_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- CC_SHA256_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
-
-static int
-__archive_nettle_sha256init(archive_sha256_ctx *ctx)
-{
- sha256_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- sha256_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
-
-static int
-__archive_openssl_sha256init(archive_sha256_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_sha256());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
-
-static int
-__archive_windowsapi_sha256init(archive_sha256_ctx *ctx)
-{
- return (win_crypto_init(ctx, CALG_SHA_256));
-}
-
-static int
-__archive_windowsapi_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- return (win_crypto_Update(ctx, indata, insize));
-}
-
-static int
-__archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- return (win_crypto_Final(md, 32, ctx));
-}
-
-#else
-
-static int
-__archive_stub_sha256init(archive_sha256_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* SHA384 implementations */
-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
-
-static int
-__archive_libc_sha384init(archive_sha384_ctx *ctx)
-{
- SHA384_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA384_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- SHA384_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
-
-static int
-__archive_libc2_sha384init(archive_sha384_ctx *ctx)
-{
- SHA384Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA384Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- SHA384Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
-
-static int
-__archive_libc3_sha384init(archive_sha384_ctx *ctx)
-{
- SHA384Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA384Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- SHA384Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
-
-static int
-__archive_libsystem_sha384init(archive_sha384_ctx *ctx)
-{
- CC_SHA384_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- CC_SHA384_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- CC_SHA384_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
-
-static int
-__archive_nettle_sha384init(archive_sha384_ctx *ctx)
-{
- sha384_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- sha384_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
-
-static int
-__archive_openssl_sha384init(archive_sha384_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_sha384());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
-
-static int
-__archive_windowsapi_sha384init(archive_sha384_ctx *ctx)
-{
- return (win_crypto_init(ctx, CALG_SHA_384));
-}
-
-static int
-__archive_windowsapi_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- return (win_crypto_Update(ctx, indata, insize));
-}
-
-static int
-__archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- return (win_crypto_Final(md, 48, ctx));
-}
-
-#else
-
-static int
-__archive_stub_sha384init(archive_sha384_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* SHA512 implementations */
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
-
-static int
-__archive_libc_sha512init(archive_sha512_ctx *ctx)
-{
- SHA512_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA512_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- SHA512_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
-
-static int
-__archive_libc2_sha512init(archive_sha512_ctx *ctx)
-{
- SHA512Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA512Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- SHA512Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
-
-static int
-__archive_libc3_sha512init(archive_sha512_ctx *ctx)
-{
- SHA512Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA512Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- SHA512Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
-
-static int
-__archive_libmd_sha512init(archive_sha512_ctx *ctx)
-{
- SHA512_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- SHA512_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- SHA512_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
-
-static int
-__archive_libsystem_sha512init(archive_sha512_ctx *ctx)
-{
- CC_SHA512_Init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- CC_SHA512_Update(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- CC_SHA512_Final(md, ctx);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
-
-static int
-__archive_nettle_sha512init(archive_sha512_ctx *ctx)
-{
- sha512_init(ctx);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- sha512_update(ctx, insize, indata);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
-
-static int
-__archive_openssl_sha512init(archive_sha512_ctx *ctx)
-{
- EVP_DigestInit(ctx, EVP_sha512());
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- EVP_DigestUpdate(ctx, indata, insize);
- return (ARCHIVE_OK);
-}
-
-static int
-__archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- EVP_DigestFinal(ctx, md, NULL);
- return (ARCHIVE_OK);
-}
-
-#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
-
-static int
-__archive_windowsapi_sha512init(archive_sha512_ctx *ctx)
-{
- return (win_crypto_init(ctx, CALG_SHA_512));
-}
-
-static int
-__archive_windowsapi_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- return (win_crypto_Update(ctx, indata, insize));
-}
-
-static int
-__archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- return (win_crypto_Final(md, 64, ctx));
-}
-
-#else
-
-static int
-__archive_stub_sha512init(archive_sha512_ctx *ctx)
-{
- (void)ctx; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
- size_t insize)
-{
- (void)ctx; /* UNUSED */
- (void)indata; /* UNUSED */
- (void)insize; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-static int
-__archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
-{
- (void)ctx; /* UNUSED */
- (void)md; /* UNUSED */
- return (ARCHIVE_FAILED);
-}
-
-#endif
-
-/* NOTE: Crypto functions are set based on availability and by the following
- * order of preference.
- * 1. libc
- * 2. libc2
- * 3. libc3
- * 4. libSystem
- * 5. Nettle
- * 6. OpenSSL
- * 7. libmd
- * 8. Windows API
- */
-const struct archive_crypto __archive_crypto =
-{
-/* MD5 */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
- &__archive_libc_md5init,
- &__archive_libc_md5update,
- &__archive_libc_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
- &__archive_libmd_md5init,
- &__archive_libmd_md5update,
- &__archive_libmd_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
- &__archive_libsystem_md5init,
- &__archive_libsystem_md5update,
- &__archive_libsystem_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
- &__archive_nettle_md5init,
- &__archive_nettle_md5update,
- &__archive_nettle_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
- &__archive_openssl_md5init,
- &__archive_openssl_md5update,
- &__archive_openssl_md5final,
-#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
- &__archive_windowsapi_md5init,
- &__archive_windowsapi_md5update,
- &__archive_windowsapi_md5final,
-#elif !defined(ARCHIVE_MD5_COMPILE_TEST)
- &__archive_stub_md5init,
- &__archive_stub_md5update,
- &__archive_stub_md5final,
-#endif
-
-/* RIPEMD160 */
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
- &__archive_libc_ripemd160init,
- &__archive_libc_ripemd160update,
- &__archive_libc_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
- &__archive_libmd_ripemd160init,
- &__archive_libmd_ripemd160update,
- &__archive_libmd_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
- &__archive_nettle_ripemd160init,
- &__archive_nettle_ripemd160update,
- &__archive_nettle_ripemd160final,
-#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
- &__archive_openssl_ripemd160init,
- &__archive_openssl_ripemd160update,
- &__archive_openssl_ripemd160final,
-#elif !defined(ARCHIVE_RMD160_COMPILE_TEST)
- &__archive_stub_ripemd160init,
- &__archive_stub_ripemd160update,
- &__archive_stub_ripemd160final,
-#endif
-
-/* SHA1 */
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
- &__archive_libc_sha1init,
- &__archive_libc_sha1update,
- &__archive_libc_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
- &__archive_libmd_sha1init,
- &__archive_libmd_sha1update,
- &__archive_libmd_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
- &__archive_libsystem_sha1init,
- &__archive_libsystem_sha1update,
- &__archive_libsystem_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
- &__archive_nettle_sha1init,
- &__archive_nettle_sha1update,
- &__archive_nettle_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
- &__archive_openssl_sha1init,
- &__archive_openssl_sha1update,
- &__archive_openssl_sha1final,
-#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
- &__archive_windowsapi_sha1init,
- &__archive_windowsapi_sha1update,
- &__archive_windowsapi_sha1final,
-#elif !defined(ARCHIVE_SHA1_COMPILE_TEST)
- &__archive_stub_sha1init,
- &__archive_stub_sha1update,
- &__archive_stub_sha1final,
-#endif
-
-/* SHA256 */
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
- &__archive_libc_sha256init,
- &__archive_libc_sha256update,
- &__archive_libc_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
- &__archive_libc2_sha256init,
- &__archive_libc2_sha256update,
- &__archive_libc2_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
- &__archive_libc3_sha256init,
- &__archive_libc3_sha256update,
- &__archive_libc3_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
- &__archive_libmd_sha256init,
- &__archive_libmd_sha256update,
- &__archive_libmd_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
- &__archive_libsystem_sha256init,
- &__archive_libsystem_sha256update,
- &__archive_libsystem_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
- &__archive_nettle_sha256init,
- &__archive_nettle_sha256update,
- &__archive_nettle_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
- &__archive_openssl_sha256init,
- &__archive_openssl_sha256update,
- &__archive_openssl_sha256final,
-#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
- &__archive_windowsapi_sha256init,
- &__archive_windowsapi_sha256update,
- &__archive_windowsapi_sha256final,
-#elif !defined(ARCHIVE_SHA256_COMPILE_TEST)
- &__archive_stub_sha256init,
- &__archive_stub_sha256update,
- &__archive_stub_sha256final,
-#endif
-
-/* SHA384 */
-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
- &__archive_libc_sha384init,
- &__archive_libc_sha384update,
- &__archive_libc_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
- &__archive_libc2_sha384init,
- &__archive_libc2_sha384update,
- &__archive_libc2_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
- &__archive_libc3_sha384init,
- &__archive_libc3_sha384update,
- &__archive_libc3_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
- &__archive_libsystem_sha384init,
- &__archive_libsystem_sha384update,
- &__archive_libsystem_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
- &__archive_nettle_sha384init,
- &__archive_nettle_sha384update,
- &__archive_nettle_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
- &__archive_openssl_sha384init,
- &__archive_openssl_sha384update,
- &__archive_openssl_sha384final,
-#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
- &__archive_windowsapi_sha384init,
- &__archive_windowsapi_sha384update,
- &__archive_windowsapi_sha384final,
-#elif !defined(ARCHIVE_SHA384_COMPILE_TEST)
- &__archive_stub_sha384init,
- &__archive_stub_sha384update,
- &__archive_stub_sha384final,
-#endif
-
-/* SHA512 */
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
- &__archive_libc_sha512init,
- &__archive_libc_sha512update,
- &__archive_libc_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
- &__archive_libc2_sha512init,
- &__archive_libc2_sha512update,
- &__archive_libc2_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
- &__archive_libc3_sha512init,
- &__archive_libc3_sha512update,
- &__archive_libc3_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
- &__archive_libmd_sha512init,
- &__archive_libmd_sha512update,
- &__archive_libmd_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
- &__archive_libsystem_sha512init,
- &__archive_libsystem_sha512update,
- &__archive_libsystem_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
- &__archive_nettle_sha512init,
- &__archive_nettle_sha512update,
- &__archive_nettle_sha512final,
-#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
- &__archive_openssl_sha512init,
- &__archive_openssl_sha512update,
- &__archive_openssl_sha512final
-#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
- &__archive_windowsapi_sha512init,
- &__archive_windowsapi_sha512update,
- &__archive_windowsapi_sha512final
-#elif !defined(ARCHIVE_SHA512_COMPILE_TEST)
- &__archive_stub_sha512init,
- &__archive_stub_sha512update,
- &__archive_stub_sha512final
-#endif
-};
diff --git a/Utilities/cmlibarchive/libarchive/archive_crypto_private.h b/Utilities/cmlibarchive/libarchive/archive_crypto_private.h
deleted file mode 100644
index f8b1fb3c3..000000000
--- a/Utilities/cmlibarchive/libarchive/archive_crypto_private.h
+++ /dev/null
@@ -1,376 +0,0 @@
-/*-
-* Copyright (c) 2003-2007 Tim Kientzle
-* Copyright (c) 2011 Andres Mejia
-* All rights reserved.
-*
-* Redistribution and use in source and binary forms, with or without
-* modification, are permitted provided that the following conditions
-* are met:
-* 1. Redistributions of source code must retain the above copyright
-* notice, this list of conditions and the following disclaimer.
-* 2. Redistributions in binary form must reproduce the above copyright
-* notice, this list of conditions and the following disclaimer in the
-* documentation and/or other materials provided with the distribution.
-*
-* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef __LIBARCHIVE_BUILD
-#error This header is only to be used internally to libarchive.
-#endif
-
-#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
-#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
-
-/*
- * Crypto support in various Operating Systems:
- *
- * NetBSD:
- * - MD5 and SHA1 in libc: without _ after algorithm name
- * - SHA2 in libc: with _ after algorithm name
- *
- * OpenBSD:
- * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
- * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
- *
- * DragonFly and FreeBSD:
- * - MD5 libmd: without _ after algorithm name
- * - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name
- *
- * Mac OS X (10.4 and later):
- * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
- *
- * OpenSSL:
- * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
- *
- * Windows:
- * - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API
- */
-
-/* libc crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
-#include <md5.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
-#include <rmd160.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
-#include <sha1.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
-#include <sha2.h>
-#endif
-
-/* libmd crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
-#define ARCHIVE_CRYPTO_LIBMD 1
-#endif
-
-#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)
-#include <md5.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
-#include <ripemd.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
-#include <sha.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
-#include <sha256.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
-#include <sha512.h>
-#endif
-
-/* libSystem crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
-#include <CommonCrypto/CommonDigest.h>
-#endif
-
-/* Nettle crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
-#include <nettle/md5.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
-#include <nettle/ripemd160.h>
-#endif
-#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
-#include <nettle/sha.h>
-#endif
-
-/* OpenSSL crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
-#define ARCHIVE_CRYPTO_OPENSSL 1
-#include <openssl/evp.h>
-#endif
-
-/* Windows crypto headers */
-#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
- defined(ARCHIVE_CRYPTO_SHA512_WIN)
-#include <wincrypt.h>
-typedef struct {
- int valid;
- HCRYPTPROV cryptProv;
- HCRYPTHASH hash;
-} Digest_CTX;
-#endif
-
-/* typedefs */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
-typedef MD5_CTX archive_md5_ctx;
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
-typedef MD5_CTX archive_md5_ctx;
-#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
-typedef CC_MD5_CTX archive_md5_ctx;
-#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
-typedef struct md5_ctx archive_md5_ctx;
-#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
-typedef EVP_MD_CTX archive_md5_ctx;
-#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
-typedef Digest_CTX archive_md5_ctx;
-#else
-typedef unsigned char archive_md5_ctx;
-#endif
-
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
-typedef RMD160_CTX archive_rmd160_ctx;
-#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
-typedef RIPEMD160_CTX archive_rmd160_ctx;
-#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
-typedef struct ripemd160_ctx archive_rmd160_ctx;
-#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
-typedef EVP_MD_CTX archive_rmd160_ctx;
-#else
-typedef unsigned char archive_rmd160_ctx;
-#endif
-
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
-typedef SHA1_CTX archive_sha1_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
-typedef SHA1_CTX archive_sha1_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
-typedef CC_SHA1_CTX archive_sha1_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
-typedef struct sha1_ctx archive_sha1_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
-typedef EVP_MD_CTX archive_sha1_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
-typedef Digest_CTX archive_sha1_ctx;
-#else
-typedef unsigned char archive_sha1_ctx;
-#endif
-
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
-typedef SHA256_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
-typedef SHA256_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
-typedef SHA2_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
-typedef SHA256_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
-typedef CC_SHA256_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
-typedef struct sha256_ctx archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
-typedef EVP_MD_CTX archive_sha256_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
-typedef Digest_CTX archive_sha256_ctx;
-#else
-typedef unsigned char archive_sha256_ctx;
-#endif
-
-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
-typedef SHA384_CTX archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
-typedef SHA384_CTX archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
-typedef SHA2_CTX archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
-typedef CC_SHA512_CTX archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
-typedef struct sha384_ctx archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
-typedef EVP_MD_CTX archive_sha384_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
-typedef Digest_CTX archive_sha384_ctx;
-#else
-typedef unsigned char archive_sha384_ctx;
-#endif
-
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
-typedef SHA512_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
-typedef SHA512_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
-typedef SHA2_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
-typedef SHA512_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
-typedef CC_SHA512_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
-typedef struct sha512_ctx archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
-typedef EVP_MD_CTX archive_sha512_ctx;
-#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
-typedef Digest_CTX archive_sha512_ctx;
-#else
-typedef unsigned char archive_sha512_ctx;
-#endif
-
-/* defines */
-#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\
- defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \
- defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_MD5_WIN)
-#define ARCHIVE_HAS_MD5
-#endif
-#define archive_md5_init(ctx)\
- __archive_crypto.md5init(ctx)
-#define archive_md5_final(ctx, md)\
- __archive_crypto.md5final(ctx, md)
-#define archive_md5_update(ctx, buf, n)\
- __archive_crypto.md5update(ctx, buf, n)
-
-#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
- defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
-#define ARCHIVE_HAS_RMD160
-#endif
-#define archive_rmd160_init(ctx)\
- __archive_crypto.rmd160init(ctx)
-#define archive_rmd160_final(ctx, md)\
- __archive_crypto.rmd160final(ctx, md)
-#define archive_rmd160_update(ctx, buf, n)\
- __archive_crypto.rmd160update(ctx, buf, n)
-
-#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \
- defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA1_WIN)
-#define ARCHIVE_HAS_SHA1
-#endif
-#define archive_sha1_init(ctx)\
- __archive_crypto.sha1init(ctx)
-#define archive_sha1_final(ctx, md)\
- __archive_crypto.sha1final(ctx, md)
-#define archive_sha1_update(ctx, buf, n)\
- __archive_crypto.sha1update(ctx, buf, n)
-
-#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA256_WIN)
-#define ARCHIVE_HAS_SHA256
-#endif
-#define archive_sha256_init(ctx)\
- __archive_crypto.sha256init(ctx)
-#define archive_sha256_final(ctx, md)\
- __archive_crypto.sha256final(ctx, md)
-#define archive_sha256_update(ctx, buf, n)\
- __archive_crypto.sha256update(ctx, buf, n)
-
-#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
- defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA384_WIN)
-#define ARCHIVE_HAS_SHA384
-#endif
-#define archive_sha384_init(ctx)\
- __archive_crypto.sha384init(ctx)
-#define archive_sha384_final(ctx, md)\
- __archive_crypto.sha384final(ctx, md)
-#define archive_sha384_update(ctx, buf, n)\
- __archive_crypto.sha384update(ctx, buf, n)
-
-#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\
- defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\
- defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\
- defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
- defined(ARCHIVE_CRYPTO_SHA512_WIN)
-#define ARCHIVE_HAS_SHA512
-#endif
-#define archive_sha512_init(ctx)\
- __archive_crypto.sha512init(ctx)
-#define archive_sha512_final(ctx, md)\
- __archive_crypto.sha512final(ctx, md)
-#define archive_sha512_update(ctx, buf, n)\
- __archive_crypto.sha512update(ctx, buf, n)
-
-/* Minimal interface to crypto functionality for internal use in libarchive */
-struct archive_crypto
-{
- /* Message Digest */
- int (*md5init)(archive_md5_ctx *ctx);
- int (*md5update)(archive_md5_ctx *, const void *, size_t);
- int (*md5final)(archive_md5_ctx *, void *);
- int (*rmd160init)(archive_rmd160_ctx *);
- int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);
- int (*rmd160final)(archive_rmd160_ctx *, void *);
- int (*sha1init)(archive_sha1_ctx *);
- int (*sha1update)(archive_sha1_ctx *, const void *, size_t);
- int (*sha1final)(archive_sha1_ctx *, void *);
- int (*sha256init)(archive_sha256_ctx *);
- int (*sha256update)(archive_sha256_ctx *, const void *, size_t);
- int (*sha256final)(archive_sha256_ctx *, void *);
- int (*sha384init)(archive_sha384_ctx *);
- int (*sha384update)(archive_sha384_ctx *, const void *, size_t);
- int (*sha384final)(archive_sha384_ctx *, void *);
- int (*sha512init)(archive_sha512_ctx *);
- int (*sha512update)(archive_sha512_ctx *, const void *, size_t);
- int (*sha512final)(archive_sha512_ctx *, void *);
-};
-
-extern const struct archive_crypto __archive_crypto;
-
-#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor.c b/Utilities/cmlibarchive/libarchive/archive_cryptor.c
new file mode 100644
index 000000000..ced52fd70
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c
@@ -0,0 +1,450 @@
+/*-
+* Copyright (c) 2014 Michihiro NAKAJIMA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "archive.h"
+#include "archive_cryptor_private.h"
+
+/*
+ * On systems that do not support any recognized crypto libraries,
+ * this file will normally define no usable symbols.
+ *
+ * But some compilers and linkers choke on empty object files, so
+ * define a public symbol that will always exist. This could
+ * be removed someday if this file gains another always-present
+ * symbol definition.
+ */
+int __libarchive_cryptor_build_hack(void) {
+ return 0;
+}
+
+#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
+
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len)
+{
+ CCKeyDerivationPBKDF(kCCPBKDF2, (const char *)pw,
+ pw_len, salt, salt_len, kCCPRFHmacAlgSHA1, rounds,
+ derived_key, derived_key_len);
+ return 0;
+}
+
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+#ifdef _MSC_VER
+#pragma comment(lib, "Bcrypt.lib")
+#endif
+
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len)
+{
+ NTSTATUS status;
+ BCRYPT_ALG_HANDLE hAlg;
+
+ status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,
+ MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);
+ if (!BCRYPT_SUCCESS(status))
+ return -1;
+
+ status = BCryptDeriveKeyPBKDF2(hAlg,
+ (PUCHAR)(uintptr_t)pw, (ULONG)pw_len,
+ (PUCHAR)(uintptr_t)salt, (ULONG)salt_len, rounds,
+ (PUCHAR)derived_key, (ULONG)derived_key_len, 0);
+
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+
+ return (BCRYPT_SUCCESS(status)) ? 0: -1;
+}
+
+#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_PBKDF2_H)
+
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len) {
+ pbkdf2_hmac_sha1((unsigned)pw_len, (const uint8_t *)pw, rounds,
+ salt_len, salt, derived_key_len, derived_key);
+ return 0;
+}
+
+#elif defined(HAVE_LIBCRYPTO) && defined(HAVE_PKCS5_PBKDF2_HMAC_SHA1)
+
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len) {
+
+ PKCS5_PBKDF2_HMAC_SHA1(pw, pw_len, salt, salt_len, rounds,
+ derived_key_len, derived_key);
+ return 0;
+}
+
+#else
+
+/* Stub */
+static int
+pbkdf2_sha1(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len) {
+ (void)pw; /* UNUSED */
+ (void)pw_len; /* UNUSED */
+ (void)salt; /* UNUSED */
+ (void)salt_len; /* UNUSED */
+ (void)rounds; /* UNUSED */
+ (void)derived_key; /* UNUSED */
+ (void)derived_key_len; /* UNUSED */
+ return -1; /* UNSUPPORTED */
+}
+
+#endif
+
+#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
+# if MAC_OS_X_VERSION_MAX_ALLOWED < 1090
+# define kCCAlgorithmAES kCCAlgorithmAES128
+# endif
+
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ CCCryptorStatus r;
+
+ ctx->key_len = key_len;
+ memcpy(ctx->key, key, key_len);
+ memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ ctx->encr_pos = AES_BLOCK_SIZE;
+ r = CCCryptorCreateWithMode(kCCEncrypt, kCCModeECB, kCCAlgorithmAES,
+ ccNoPadding, NULL, key, key_len, NULL, 0, 0, 0, &ctx->ctx);
+ return (r == kCCSuccess)? 0: -1;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+ CCCryptorRef ref = ctx->ctx;
+ CCCryptorStatus r;
+
+ r = CCCryptorReset(ref, NULL);
+ if (r != kCCSuccess)
+ return -1;
+ r = CCCryptorUpdate(ref, ctx->nonce, AES_BLOCK_SIZE, ctx->encr_buf,
+ AES_BLOCK_SIZE, NULL);
+ return (r == kCCSuccess)? 0: -1;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+ memset(ctx->key, 0, ctx->key_len);
+ memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ return 0;
+}
+
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ BCRYPT_ALG_HANDLE hAlg;
+ BCRYPT_KEY_HANDLE hKey;
+ DWORD keyObj_len, aes_key_len;
+ PBYTE keyObj;
+ ULONG result;
+ NTSTATUS status;
+ BCRYPT_KEY_LENGTHS_STRUCT key_lengths;
+
+ ctx->hAlg = NULL;
+ ctx->hKey = NULL;
+ ctx->keyObj = NULL;
+ switch (key_len) {
+ case 16: aes_key_len = 128; break;
+ case 24: aes_key_len = 192; break;
+ case 32: aes_key_len = 256; break;
+ default: return -1;
+ }
+ status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_AES_ALGORITHM,
+ MS_PRIMITIVE_PROVIDER, 0);
+ if (!BCRYPT_SUCCESS(status))
+ return -1;
+ status = BCryptGetProperty(hAlg, BCRYPT_KEY_LENGTHS, (PUCHAR)&key_lengths,
+ sizeof(key_lengths), &result, 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ if (key_lengths.dwMinLength > aes_key_len
+ || key_lengths.dwMaxLength < aes_key_len) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ status = BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PUCHAR)&keyObj_len,
+ sizeof(keyObj_len), &result, 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ keyObj = (PBYTE)HeapAlloc(GetProcessHeap(), 0, keyObj_len);
+ if (keyObj == NULL) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ status = BCryptSetProperty(hAlg, BCRYPT_CHAINING_MODE,
+ (PUCHAR)BCRYPT_CHAIN_MODE_ECB, sizeof(BCRYPT_CHAIN_MODE_ECB), 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ HeapFree(GetProcessHeap(), 0, keyObj);
+ return -1;
+ }
+ status = BCryptGenerateSymmetricKey(hAlg, &hKey,
+ keyObj, keyObj_len,
+ (PUCHAR)(uintptr_t)key, (ULONG)key_len, 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ HeapFree(GetProcessHeap(), 0, keyObj);
+ return -1;
+ }
+
+ ctx->hAlg = hAlg;
+ ctx->hKey = hKey;
+ ctx->keyObj = keyObj;
+ ctx->keyObj_len = keyObj_len;
+ ctx->encr_pos = AES_BLOCK_SIZE;
+
+ return 0;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+ NTSTATUS status;
+ ULONG result;
+
+ status = BCryptEncrypt(ctx->hKey, (PUCHAR)ctx->nonce, AES_BLOCK_SIZE,
+ NULL, NULL, 0, (PUCHAR)ctx->encr_buf, AES_BLOCK_SIZE,
+ &result, 0);
+ return BCRYPT_SUCCESS(status) ? 0 : -1;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+
+ if (ctx->hAlg != NULL) {
+ BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+ ctx->hAlg = NULL;
+ BCryptDestroyKey(ctx->hKey);
+ ctx->hKey = NULL;
+ HeapFree(GetProcessHeap(), 0, ctx->keyObj);
+ ctx->keyObj = NULL;
+ }
+ memset(ctx, 0, sizeof(*ctx));
+ return 0;
+}
+
+#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_AES_H)
+
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ ctx->key_len = key_len;
+ memcpy(ctx->key, key, key_len);
+ memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ ctx->encr_pos = AES_BLOCK_SIZE;
+ memset(&ctx->ctx, 0, sizeof(ctx->ctx));
+ return 0;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+ aes_set_encrypt_key(&ctx->ctx, ctx->key_len, ctx->key);
+ aes_encrypt(&ctx->ctx, AES_BLOCK_SIZE, ctx->encr_buf, ctx->nonce);
+ return 0;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+ return 0;
+}
+
+#elif defined(HAVE_LIBCRYPTO)
+
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ if ((ctx->ctx = EVP_CIPHER_CTX_new()) == NULL)
+ return -1;
+
+ switch (key_len) {
+ case 16: ctx->type = EVP_aes_128_ecb(); break;
+ case 24: ctx->type = EVP_aes_192_ecb(); break;
+ case 32: ctx->type = EVP_aes_256_ecb(); break;
+ default: ctx->type = NULL; return -1;
+ }
+
+ ctx->key_len = key_len;
+ memcpy(ctx->key, key, key_len);
+ memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ ctx->encr_pos = AES_BLOCK_SIZE;
+ EVP_CIPHER_CTX_init(ctx->ctx);
+ return 0;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+ int outl = 0;
+ int r;
+
+ r = EVP_EncryptInit_ex(ctx->ctx, ctx->type, NULL, ctx->key, NULL);
+ if (r == 0)
+ return -1;
+ r = EVP_EncryptUpdate(ctx->ctx, ctx->encr_buf, &outl, ctx->nonce,
+ AES_BLOCK_SIZE);
+ if (r == 0 || outl != AES_BLOCK_SIZE)
+ return -1;
+ return 0;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+ EVP_CIPHER_CTX_free(ctx->ctx);
+ memset(ctx->key, 0, ctx->key_len);
+ memset(ctx->nonce, 0, sizeof(ctx->nonce));
+ return 0;
+}
+
+#else
+
+#define ARCHIVE_CRYPTOR_STUB
+/* Stub */
+static int
+aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ (void)ctx; /* UNUSED */
+ (void)key; /* UNUSED */
+ (void)key_len; /* UNUSED */
+ return -1;
+}
+
+static int
+aes_ctr_encrypt_counter(archive_crypto_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return -1;
+}
+
+static int
+aes_ctr_release(archive_crypto_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return 0;
+}
+
+#endif
+
+#ifdef ARCHIVE_CRYPTOR_STUB
+static int
+aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,
+ size_t in_len, uint8_t * const out, size_t *out_len)
+{
+ (void)ctx; /* UNUSED */
+ (void)in; /* UNUSED */
+ (void)in_len; /* UNUSED */
+ (void)out; /* UNUSED */
+ (void)out_len; /* UNUSED */
+ aes_ctr_encrypt_counter(ctx); /* UNUSED */ /* Fix unused function warning */
+ return -1;
+}
+
+#else
+static void
+aes_ctr_increase_counter(archive_crypto_ctx *ctx)
+{
+ uint8_t *const nonce = ctx->nonce;
+ int j;
+
+ for (j = 0; j < 8; j++) {
+ if (++nonce[j])
+ break;
+ }
+}
+
+static int
+aes_ctr_update(archive_crypto_ctx *ctx, const uint8_t * const in,
+ size_t in_len, uint8_t * const out, size_t *out_len)
+{
+ uint8_t *const ebuf = ctx->encr_buf;
+ unsigned pos = ctx->encr_pos;
+ unsigned max = (unsigned)((in_len < *out_len)? in_len: *out_len);
+ unsigned i;
+
+ for (i = 0; i < max; ) {
+ if (pos == AES_BLOCK_SIZE) {
+ aes_ctr_increase_counter(ctx);
+ if (aes_ctr_encrypt_counter(ctx) != 0)
+ return -1;
+ while (max -i >= AES_BLOCK_SIZE) {
+ for (pos = 0; pos < AES_BLOCK_SIZE; pos++)
+ out[i+pos] = in[i+pos] ^ ebuf[pos];
+ i += AES_BLOCK_SIZE;
+ aes_ctr_increase_counter(ctx);
+ if (aes_ctr_encrypt_counter(ctx) != 0)
+ return -1;
+ }
+ pos = 0;
+ if (i >= max)
+ break;
+ }
+ out[i] = in[i] ^ ebuf[pos++];
+ i++;
+ }
+ ctx->encr_pos = pos;
+ *out_len = i;
+
+ return 0;
+}
+#endif /* ARCHIVE_CRYPTOR_STUB */
+
+
+const struct archive_cryptor __archive_cryptor =
+{
+ &pbkdf2_sha1,
+ &aes_ctr_init,
+ &aes_ctr_update,
+ &aes_ctr_release,
+ &aes_ctr_init,
+ &aes_ctr_update,
+ &aes_ctr_release,
+};
diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
new file mode 100644
index 000000000..0ca544b57
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_cryptor_private.h
@@ -0,0 +1,163 @@
+/*-
+* Copyright (c) 2014 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.
+*/
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_CRYPTOR_PRIVATE_H_INCLUDED
+#define ARCHIVE_CRYPTOR_PRIVATE_H_INCLUDED
+
+/*
+ * On systems that do not support any recognized crypto libraries,
+ * the archive_cryptor.c file will normally define no usable symbols.
+ *
+ * But some compilers and linkers choke on empty object files, so
+ * define a public symbol that will always exist. This could
+ * be removed someday if this file gains another always-present
+ * symbol definition.
+ */
+int __libarchive_cryptor_build_hack(void);
+
+#ifdef __APPLE__
+# include <AvailabilityMacros.h>
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1080
+# define ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
+# endif
+#endif
+
+#ifdef ARCHIVE_CRYPTOR_USE_Apple_CommonCrypto
+#include <CommonCrypto/CommonCryptor.h>
+#include <CommonCrypto/CommonKeyDerivation.h>
+#define AES_BLOCK_SIZE 16
+#define AES_MAX_KEY_SIZE kCCKeySizeAES256
+
+typedef struct {
+ CCCryptorRef ctx;
+ uint8_t key[AES_MAX_KEY_SIZE];
+ unsigned key_len;
+ uint8_t nonce[AES_BLOCK_SIZE];
+ uint8_t encr_buf[AES_BLOCK_SIZE];
+ unsigned encr_pos;
+} archive_crypto_ctx;
+
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+#include <Bcrypt.h>
+
+/* Common in other bcrypt implementations, but missing from VS2008. */
+#ifndef BCRYPT_SUCCESS
+#define BCRYPT_SUCCESS(r) ((NTSTATUS)(r) == STATUS_SUCCESS)
+#endif
+
+#define AES_MAX_KEY_SIZE 32
+#define AES_BLOCK_SIZE 16
+typedef struct {
+ BCRYPT_ALG_HANDLE hAlg;
+ BCRYPT_KEY_HANDLE hKey;
+ PBYTE keyObj;
+ DWORD keyObj_len;
+ uint8_t nonce[AES_BLOCK_SIZE];
+ uint8_t encr_buf[AES_BLOCK_SIZE];
+ unsigned encr_pos;
+} archive_crypto_ctx;
+
+#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_AES_H)
+#if defined(HAVE_NETTLE_PBKDF2_H)
+#include <nettle/pbkdf2.h>
+#endif
+#include <nettle/aes.h>
+
+typedef struct {
+ struct aes_ctx ctx;
+ uint8_t key[AES_MAX_KEY_SIZE];
+ unsigned key_len;
+ uint8_t nonce[AES_BLOCK_SIZE];
+ uint8_t encr_buf[AES_BLOCK_SIZE];
+ unsigned encr_pos;
+} archive_crypto_ctx;
+
+#elif defined(HAVE_LIBCRYPTO)
+#include "archive_openssl_evp_private.h"
+#define AES_BLOCK_SIZE 16
+#define AES_MAX_KEY_SIZE 32
+
+typedef struct {
+ EVP_CIPHER_CTX *ctx;
+ const EVP_CIPHER *type;
+ uint8_t key[AES_MAX_KEY_SIZE];
+ unsigned key_len;
+ uint8_t nonce[AES_BLOCK_SIZE];
+ uint8_t encr_buf[AES_BLOCK_SIZE];
+ unsigned encr_pos;
+} archive_crypto_ctx;
+
+#else
+
+#define AES_BLOCK_SIZE 16
+#define AES_MAX_KEY_SIZE 32
+typedef int archive_crypto_ctx;
+
+#endif
+
+/* defines */
+#define archive_pbkdf2_sha1(pw, pw_len, salt, salt_len, rounds, dk, dk_len)\
+ __archive_cryptor.pbkdf2sha1(pw, pw_len, salt, salt_len, rounds, dk, dk_len)
+
+#define archive_decrypto_aes_ctr_init(ctx, key, key_len) \
+ __archive_cryptor.decrypto_aes_ctr_init(ctx, key, key_len)
+#define archive_decrypto_aes_ctr_update(ctx, in, in_len, out, out_len) \
+ __archive_cryptor.decrypto_aes_ctr_update(ctx, in, in_len, out, out_len)
+#define archive_decrypto_aes_ctr_release(ctx) \
+ __archive_cryptor.decrypto_aes_ctr_release(ctx)
+
+#define archive_encrypto_aes_ctr_init(ctx, key, key_len) \
+ __archive_cryptor.encrypto_aes_ctr_init(ctx, key, key_len)
+#define archive_encrypto_aes_ctr_update(ctx, in, in_len, out, out_len) \
+ __archive_cryptor.encrypto_aes_ctr_update(ctx, in, in_len, out, out_len)
+#define archive_encrypto_aes_ctr_release(ctx) \
+ __archive_cryptor.encrypto_aes_ctr_release(ctx)
+
+/* Minimal interface to cryptographic functionality for internal use in
+ * libarchive */
+struct archive_cryptor
+{
+ /* PKCS5 PBKDF2 HMAC-SHA1 */
+ int (*pbkdf2sha1)(const char *pw, size_t pw_len, const uint8_t *salt,
+ size_t salt_len, unsigned rounds, uint8_t *derived_key,
+ size_t derived_key_len);
+ /* AES CTR mode(little endian version) */
+ int (*decrypto_aes_ctr_init)(archive_crypto_ctx *, const uint8_t *, size_t);
+ int (*decrypto_aes_ctr_update)(archive_crypto_ctx *, const uint8_t *,
+ size_t, uint8_t *, size_t *);
+ int (*decrypto_aes_ctr_release)(archive_crypto_ctx *);
+ int (*encrypto_aes_ctr_init)(archive_crypto_ctx *, const uint8_t *, size_t);
+ int (*encrypto_aes_ctr_update)(archive_crypto_ctx *, const uint8_t *,
+ size_t, uint8_t *, size_t *);
+ int (*encrypto_aes_ctr_release)(archive_crypto_ctx *);
+};
+
+extern const struct archive_cryptor __archive_cryptor;
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_digest.c b/Utilities/cmlibarchive/libarchive/archive_digest.c
new file mode 100644
index 000000000..415392303
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_digest.c
@@ -0,0 +1,1463 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* Copyright (c) 2011 Michihiro NAKAJIMA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#include "archive.h"
+#include "archive_digest_private.h"
+
+/* In particular, force the configure probe to break if it tries
+ * to test a combination of OpenSSL and libmd. */
+#if defined(ARCHIVE_CRYPTO_OPENSSL) && defined(ARCHIVE_CRYPTO_LIBMD)
+#error Cannot use both OpenSSL and libmd.
+#endif
+
+/*
+ * Message digest functions for Windows platform.
+ */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+/*
+ * Initialize a Message digest.
+ */
+static int
+win_crypto_init(Digest_CTX *ctx, ALG_ID algId)
+{
+
+ ctx->valid = 0;
+ if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ if (GetLastError() != (DWORD)NTE_BAD_KEYSET)
+ return (ARCHIVE_FAILED);
+ if (!CryptAcquireContext(&ctx->cryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_NEWKEYSET))
+ return (ARCHIVE_FAILED);
+ }
+
+ if (!CryptCreateHash(ctx->cryptProv, algId, 0, 0, &ctx->hash)) {
+ CryptReleaseContext(ctx->cryptProv, 0);
+ return (ARCHIVE_FAILED);
+ }
+
+ ctx->valid = 1;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Update a Message digest.
+ */
+static int
+win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
+{
+
+ if (!ctx->valid)
+ return (ARCHIVE_FAILED);
+
+ CryptHashData(ctx->hash,
+ (unsigned char *)(uintptr_t)buf,
+ (DWORD)len, 0);
+ return (ARCHIVE_OK);
+}
+
+static int
+win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
+{
+ DWORD siglen = (DWORD)bufsize;
+
+ if (!ctx->valid)
+ return (ARCHIVE_FAILED);
+
+ CryptGetHashParam(ctx->hash, HP_HASHVAL, buf, &siglen, 0);
+ CryptDestroyHash(ctx->hash);
+ CryptReleaseContext(ctx->cryptProv, 0);
+ ctx->valid = 0;
+ return (ARCHIVE_OK);
+}
+
+#endif /* defined(ARCHIVE_CRYPTO_*_WIN) */
+
+
+/* MD5 implementations */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+
+static int
+__archive_libc_md5init(archive_md5_ctx *ctx)
+{
+ MD5Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ MD5Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_md5final(archive_md5_ctx *ctx, void *md)
+{
+ MD5Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+
+static int
+__archive_libmd_md5init(archive_md5_ctx *ctx)
+{
+ MD5Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ MD5Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_md5final(archive_md5_ctx *ctx, void *md)
+{
+ MD5Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+
+static int
+__archive_libsystem_md5init(archive_md5_ctx *ctx)
+{
+ CC_MD5_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_MD5_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_md5final(archive_md5_ctx *ctx, void *md)
+{
+ CC_MD5_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+
+static int
+__archive_nettle_md5init(archive_md5_ctx *ctx)
+{
+ md5_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ md5_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_md5final(archive_md5_ctx *ctx, void *md)
+{
+ md5_digest(ctx, MD5_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+
+static int
+__archive_openssl_md5init(archive_md5_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_md5());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_md5final(archive_md5_ctx *ctx, void *md)
+{
+ /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+ * this is meant to cope with that. Real fix is probably to fix
+ * archive_write_set_format_xar.c
+ */
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+
+static int
+__archive_windowsapi_md5init(archive_md5_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_MD5));
+}
+
+static int
+__archive_windowsapi_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_md5final(archive_md5_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 16, ctx));
+}
+
+#else
+
+static int
+__archive_stub_md5init(archive_md5_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5update(archive_md5_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_md5final(archive_md5_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* RIPEMD160 implementations */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+
+static int
+__archive_libc_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ RMD160Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ RMD160Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ RMD160Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+
+static int
+__archive_libmd_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ RIPEMD160_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ RIPEMD160_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ RIPEMD160_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+
+static int
+__archive_nettle_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ ripemd160_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ ripemd160_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ ripemd160_digest(ctx, RIPEMD160_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+
+static int
+__archive_openssl_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_ripemd160());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#else
+
+static int
+__archive_stub_ripemd160init(archive_rmd160_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160update(archive_rmd160_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_ripemd160final(archive_rmd160_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA1 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+
+static int
+__archive_libc_sha1init(archive_sha1_ctx *ctx)
+{
+ SHA1Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA1Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ SHA1Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+
+static int
+__archive_libmd_sha1init(archive_sha1_ctx *ctx)
+{
+ SHA1_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA1_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ SHA1_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha1init(archive_sha1_ctx *ctx)
+{
+ CC_SHA1_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA1_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ CC_SHA1_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+
+static int
+__archive_nettle_sha1init(archive_sha1_ctx *ctx)
+{
+ sha1_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha1_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ sha1_digest(ctx, SHA1_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+
+static int
+__archive_openssl_sha1init(archive_sha1_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_sha1());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ /* HACK: archive_write_set_format_xar.c is finalizing empty contexts, so
+ * this is meant to cope with that. Real fix is probably to fix
+ * archive_write_set_format_xar.c
+ */
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+
+static int
+__archive_windowsapi_sha1init(archive_sha1_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA1));
+}
+
+static int
+__archive_windowsapi_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 20, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha1init(archive_sha1_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1update(archive_sha1_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha1final(archive_sha1_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA256 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+
+static int
+__archive_libc_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+
+static int
+__archive_libc2_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+
+static int
+__archive_libc3_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+
+static int
+__archive_libmd_sha256init(archive_sha256_ctx *ctx)
+{
+ SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha256init(archive_sha256_ctx *ctx)
+{
+ CC_SHA256_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA256_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ CC_SHA256_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+
+static int
+__archive_nettle_sha256init(archive_sha256_ctx *ctx)
+{
+ sha256_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha256_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ sha256_digest(ctx, SHA256_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+
+static int
+__archive_openssl_sha256init(archive_sha256_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_sha256());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+
+static int
+__archive_windowsapi_sha256init(archive_sha256_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_256));
+}
+
+static int
+__archive_windowsapi_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 32, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha256init(archive_sha256_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256update(archive_sha256_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha256final(archive_sha256_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA384 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+
+static int
+__archive_libc_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+
+static int
+__archive_libc2_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+
+static int
+__archive_libc3_sha384init(archive_sha384_ctx *ctx)
+{
+ SHA384Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA384Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ SHA384Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha384init(archive_sha384_ctx *ctx)
+{
+ CC_SHA384_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA384_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ CC_SHA384_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+
+static int
+__archive_nettle_sha384init(archive_sha384_ctx *ctx)
+{
+ sha384_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha384_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ sha384_digest(ctx, SHA384_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+
+static int
+__archive_openssl_sha384init(archive_sha384_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_sha384());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+
+static int
+__archive_windowsapi_sha384init(archive_sha384_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_384));
+}
+
+static int
+__archive_windowsapi_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 48, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha384init(archive_sha384_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384update(archive_sha384_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha384final(archive_sha384_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* SHA512 implementations */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+
+static int
+__archive_libc_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+
+static int
+__archive_libc2_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc2_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+
+static int
+__archive_libc3_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libc3_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+
+static int
+__archive_libmd_sha512init(archive_sha512_ctx *ctx)
+{
+ SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libmd_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+
+static int
+__archive_libsystem_sha512init(archive_sha512_ctx *ctx)
+{
+ CC_SHA512_Init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ CC_SHA512_Update(ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_libsystem_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ CC_SHA512_Final(md, ctx);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+
+static int
+__archive_nettle_sha512init(archive_sha512_ctx *ctx)
+{
+ sha512_init(ctx);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ sha512_update(ctx, insize, indata);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_nettle_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ sha512_digest(ctx, SHA512_DIGEST_SIZE, md);
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+
+static int
+__archive_openssl_sha512init(archive_sha512_ctx *ctx)
+{
+ if ((*ctx = EVP_MD_CTX_new()) == NULL)
+ return (ARCHIVE_FAILED);
+ EVP_DigestInit(*ctx, EVP_sha512());
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ EVP_DigestUpdate(*ctx, indata, insize);
+ return (ARCHIVE_OK);
+}
+
+static int
+__archive_openssl_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ if (*ctx) {
+ EVP_DigestFinal(*ctx, md, NULL);
+ EVP_MD_CTX_free(*ctx);
+ *ctx = NULL;
+ }
+ return (ARCHIVE_OK);
+}
+
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+
+static int
+__archive_windowsapi_sha512init(archive_sha512_ctx *ctx)
+{
+ return (win_crypto_init(ctx, CALG_SHA_512));
+}
+
+static int
+__archive_windowsapi_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ return (win_crypto_Update(ctx, indata, insize));
+}
+
+static int
+__archive_windowsapi_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ return (win_crypto_Final(md, 64, ctx));
+}
+
+#else
+
+static int
+__archive_stub_sha512init(archive_sha512_ctx *ctx)
+{
+ (void)ctx; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512update(archive_sha512_ctx *ctx, const void *indata,
+ size_t insize)
+{
+ (void)ctx; /* UNUSED */
+ (void)indata; /* UNUSED */
+ (void)insize; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+static int
+__archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
+{
+ (void)ctx; /* UNUSED */
+ (void)md; /* UNUSED */
+ return (ARCHIVE_FAILED);
+}
+
+#endif
+
+/* NOTE: Message Digest functions are set based on availability and by the
+ * following order of preference.
+ * 1. libc
+ * 2. libc2
+ * 3. libc3
+ * 4. libSystem
+ * 5. Nettle
+ * 6. OpenSSL
+ * 7. libmd
+ * 8. Windows API
+ */
+const struct archive_digest __archive_digest =
+{
+/* MD5 */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+ &__archive_libc_md5init,
+ &__archive_libc_md5update,
+ &__archive_libc_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+ &__archive_libmd_md5init,
+ &__archive_libmd_md5update,
+ &__archive_libmd_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+ &__archive_libsystem_md5init,
+ &__archive_libsystem_md5update,
+ &__archive_libsystem_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+ &__archive_nettle_md5init,
+ &__archive_nettle_md5update,
+ &__archive_nettle_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+ &__archive_openssl_md5init,
+ &__archive_openssl_md5update,
+ &__archive_openssl_md5final,
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+ &__archive_windowsapi_md5init,
+ &__archive_windowsapi_md5update,
+ &__archive_windowsapi_md5final,
+#elif !defined(ARCHIVE_MD5_COMPILE_TEST)
+ &__archive_stub_md5init,
+ &__archive_stub_md5update,
+ &__archive_stub_md5final,
+#endif
+
+/* RIPEMD160 */
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+ &__archive_libc_ripemd160init,
+ &__archive_libc_ripemd160update,
+ &__archive_libc_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+ &__archive_libmd_ripemd160init,
+ &__archive_libmd_ripemd160update,
+ &__archive_libmd_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+ &__archive_nettle_ripemd160init,
+ &__archive_nettle_ripemd160update,
+ &__archive_nettle_ripemd160final,
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+ &__archive_openssl_ripemd160init,
+ &__archive_openssl_ripemd160update,
+ &__archive_openssl_ripemd160final,
+#elif !defined(ARCHIVE_RMD160_COMPILE_TEST)
+ &__archive_stub_ripemd160init,
+ &__archive_stub_ripemd160update,
+ &__archive_stub_ripemd160final,
+#endif
+
+/* SHA1 */
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+ &__archive_libc_sha1init,
+ &__archive_libc_sha1update,
+ &__archive_libc_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+ &__archive_libmd_sha1init,
+ &__archive_libmd_sha1update,
+ &__archive_libmd_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+ &__archive_libsystem_sha1init,
+ &__archive_libsystem_sha1update,
+ &__archive_libsystem_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+ &__archive_nettle_sha1init,
+ &__archive_nettle_sha1update,
+ &__archive_nettle_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+ &__archive_openssl_sha1init,
+ &__archive_openssl_sha1update,
+ &__archive_openssl_sha1final,
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+ &__archive_windowsapi_sha1init,
+ &__archive_windowsapi_sha1update,
+ &__archive_windowsapi_sha1final,
+#elif !defined(ARCHIVE_SHA1_COMPILE_TEST)
+ &__archive_stub_sha1init,
+ &__archive_stub_sha1update,
+ &__archive_stub_sha1final,
+#endif
+
+/* SHA256 */
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+ &__archive_libc_sha256init,
+ &__archive_libc_sha256update,
+ &__archive_libc_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+ &__archive_libc2_sha256init,
+ &__archive_libc2_sha256update,
+ &__archive_libc2_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+ &__archive_libc3_sha256init,
+ &__archive_libc3_sha256update,
+ &__archive_libc3_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+ &__archive_libmd_sha256init,
+ &__archive_libmd_sha256update,
+ &__archive_libmd_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+ &__archive_libsystem_sha256init,
+ &__archive_libsystem_sha256update,
+ &__archive_libsystem_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+ &__archive_nettle_sha256init,
+ &__archive_nettle_sha256update,
+ &__archive_nettle_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+ &__archive_openssl_sha256init,
+ &__archive_openssl_sha256update,
+ &__archive_openssl_sha256final,
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+ &__archive_windowsapi_sha256init,
+ &__archive_windowsapi_sha256update,
+ &__archive_windowsapi_sha256final,
+#elif !defined(ARCHIVE_SHA256_COMPILE_TEST)
+ &__archive_stub_sha256init,
+ &__archive_stub_sha256update,
+ &__archive_stub_sha256final,
+#endif
+
+/* SHA384 */
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+ &__archive_libc_sha384init,
+ &__archive_libc_sha384update,
+ &__archive_libc_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+ &__archive_libc2_sha384init,
+ &__archive_libc2_sha384update,
+ &__archive_libc2_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+ &__archive_libc3_sha384init,
+ &__archive_libc3_sha384update,
+ &__archive_libc3_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+ &__archive_libsystem_sha384init,
+ &__archive_libsystem_sha384update,
+ &__archive_libsystem_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+ &__archive_nettle_sha384init,
+ &__archive_nettle_sha384update,
+ &__archive_nettle_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+ &__archive_openssl_sha384init,
+ &__archive_openssl_sha384update,
+ &__archive_openssl_sha384final,
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+ &__archive_windowsapi_sha384init,
+ &__archive_windowsapi_sha384update,
+ &__archive_windowsapi_sha384final,
+#elif !defined(ARCHIVE_SHA384_COMPILE_TEST)
+ &__archive_stub_sha384init,
+ &__archive_stub_sha384update,
+ &__archive_stub_sha384final,
+#endif
+
+/* SHA512 */
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+ &__archive_libc_sha512init,
+ &__archive_libc_sha512update,
+ &__archive_libc_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+ &__archive_libc2_sha512init,
+ &__archive_libc2_sha512update,
+ &__archive_libc2_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+ &__archive_libc3_sha512init,
+ &__archive_libc3_sha512update,
+ &__archive_libc3_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+ &__archive_libmd_sha512init,
+ &__archive_libmd_sha512update,
+ &__archive_libmd_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+ &__archive_libsystem_sha512init,
+ &__archive_libsystem_sha512update,
+ &__archive_libsystem_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+ &__archive_nettle_sha512init,
+ &__archive_nettle_sha512update,
+ &__archive_nettle_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+ &__archive_openssl_sha512init,
+ &__archive_openssl_sha512update,
+ &__archive_openssl_sha512final
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+ &__archive_windowsapi_sha512init,
+ &__archive_windowsapi_sha512update,
+ &__archive_windowsapi_sha512final
+#elif !defined(ARCHIVE_SHA512_COMPILE_TEST)
+ &__archive_stub_sha512init,
+ &__archive_stub_sha512update,
+ &__archive_stub_sha512final
+#endif
+};
diff --git a/Utilities/cmlibarchive/libarchive/archive_digest_private.h b/Utilities/cmlibarchive/libarchive/archive_digest_private.h
new file mode 100644
index 000000000..b4fd6ca22
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_digest_private.h
@@ -0,0 +1,377 @@
+/*-
+* Copyright (c) 2003-2007 Tim Kientzle
+* Copyright (c) 2011 Andres Mejia
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+#define ARCHIVE_CRYPTO_PRIVATE_H_INCLUDED
+
+/*
+ * Crypto support in various Operating Systems:
+ *
+ * NetBSD:
+ * - MD5 and SHA1 in libc: without _ after algorithm name
+ * - SHA2 in libc: with _ after algorithm name
+ *
+ * OpenBSD:
+ * - MD5, SHA1 and SHA2 in libc: without _ after algorithm name
+ * - OpenBSD 4.4 and earlier have SHA2 in libc with _ after algorithm name
+ *
+ * DragonFly and FreeBSD:
+ * - MD5 libmd: without _ after algorithm name
+ * - SHA1, SHA256 and SHA512 in libmd: with _ after algorithm name
+ *
+ * Mac OS X (10.4 and later):
+ * - MD5, SHA1 and SHA2 in libSystem: with CC_ prefix and _ after algorithm name
+ *
+ * OpenSSL:
+ * - MD5, SHA1 and SHA2 in libcrypto: with _ after algorithm name
+ *
+ * Windows:
+ * - MD5, SHA1 and SHA2 in archive_crypto.c using Windows crypto API
+ */
+
+/* libc crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+#include <rmd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+#include <sha1.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+#include <sha2.h>
+#endif
+
+/* libmd crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#define ARCHIVE_CRYPTO_LIBMD 1
+#endif
+
+#if defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+#include <md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+#include <ripemd.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+#include <sha.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+#include <sha256.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+#include <sha512.h>
+#endif
+
+/* libSystem crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+#include <CommonCrypto/CommonDigest.h>
+#endif
+
+/* Nettle crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+#include <nettle/md5.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+#include <nettle/ripemd160.h>
+#endif
+#if defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+#include <nettle/sha.h>
+#endif
+
+/* OpenSSL crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+#define ARCHIVE_CRYPTO_OPENSSL 1
+#include "archive_openssl_evp_private.h"
+#endif
+
+/* Windows crypto headers */
+#if defined(ARCHIVE_CRYPTO_MD5_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#include <windows.h>
+#include <wincrypt.h>
+typedef struct {
+ int valid;
+ HCRYPTPROV cryptProv;
+ HCRYPTHASH hash;
+} Digest_CTX;
+#endif
+
+/* typedefs */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBMD)
+typedef MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM)
+typedef CC_MD5_CTX archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_NETTLE)
+typedef struct md5_ctx archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_OPENSSL)
+typedef EVP_MD_CTX *archive_md5_ctx;
+#elif defined(ARCHIVE_CRYPTO_MD5_WIN)
+typedef Digest_CTX archive_md5_ctx;
+#else
+typedef unsigned char archive_md5_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC)
+typedef RMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_LIBMD)
+typedef RIPEMD160_CTX archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_NETTLE)
+typedef struct ripemd160_ctx archive_rmd160_ctx;
+#elif defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+typedef EVP_MD_CTX *archive_rmd160_ctx;
+#else
+typedef unsigned char archive_rmd160_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBMD)
+typedef SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM)
+typedef CC_SHA1_CTX archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_NETTLE)
+typedef struct sha1_ctx archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_OPENSSL)
+typedef EVP_MD_CTX *archive_sha1_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA1_WIN)
+typedef Digest_CTX archive_sha1_ctx;
+#else
+typedef unsigned char archive_sha1_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC2)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBC3)
+typedef SHA2_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBMD)
+typedef SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM)
+typedef CC_SHA256_CTX archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_NETTLE)
+typedef struct sha256_ctx archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_OPENSSL)
+typedef EVP_MD_CTX *archive_sha256_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA256_WIN)
+typedef Digest_CTX archive_sha256_ctx;
+#else
+typedef unsigned char archive_sha256_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC2)
+typedef SHA384_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBC3)
+typedef SHA2_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_NETTLE)
+typedef struct sha384_ctx archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_OPENSSL)
+typedef EVP_MD_CTX *archive_sha384_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA384_WIN)
+typedef Digest_CTX archive_sha384_ctx;
+#else
+typedef unsigned char archive_sha384_ctx;
+#endif
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC2)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBC3)
+typedef SHA2_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBMD)
+typedef SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM)
+typedef CC_SHA512_CTX archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_NETTLE)
+typedef struct sha512_ctx archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_OPENSSL)
+typedef EVP_MD_CTX *archive_sha512_ctx;
+#elif defined(ARCHIVE_CRYPTO_SHA512_WIN)
+typedef Digest_CTX archive_sha512_ctx;
+#else
+typedef unsigned char archive_sha512_ctx;
+#endif
+
+/* defines */
+#if defined(ARCHIVE_CRYPTO_MD5_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_MD5_LIBMD) || \
+ defined(ARCHIVE_CRYPTO_MD5_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_MD5_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_MD5_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_MD5_WIN)
+#define ARCHIVE_HAS_MD5
+#endif
+#define archive_md5_init(ctx)\
+ __archive_digest.md5init(ctx)
+#define archive_md5_final(ctx, md)\
+ __archive_digest.md5final(ctx, md)
+#define archive_md5_update(ctx, buf, n)\
+ __archive_digest.md5update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_RMD160_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_RMD160_OPENSSL)
+#define ARCHIVE_HAS_RMD160
+#endif
+#define archive_rmd160_init(ctx)\
+ __archive_digest.rmd160init(ctx)
+#define archive_rmd160_final(ctx, md)\
+ __archive_digest.rmd160final(ctx, md)
+#define archive_rmd160_update(ctx, buf, n)\
+ __archive_digest.rmd160update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA1_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_LIBMD) || \
+ defined(ARCHIVE_CRYPTO_SHA1_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA1_WIN)
+#define ARCHIVE_HAS_SHA1
+#endif
+#define archive_sha1_init(ctx)\
+ __archive_digest.sha1init(ctx)
+#define archive_sha1_final(ctx, md)\
+ __archive_digest.sha1final(ctx, md)
+#define archive_sha1_update(ctx, buf, n)\
+ __archive_digest.sha1update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA256_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA256_WIN)
+#define ARCHIVE_HAS_SHA256
+#endif
+#define archive_sha256_init(ctx)\
+ __archive_digest.sha256init(ctx)
+#define archive_sha256_final(ctx, md)\
+ __archive_digest.sha256final(ctx, md)
+#define archive_sha256_update(ctx, buf, n)\
+ __archive_digest.sha256update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA384_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA384_WIN)
+#define ARCHIVE_HAS_SHA384
+#endif
+#define archive_sha384_init(ctx)\
+ __archive_digest.sha384init(ctx)
+#define archive_sha384_final(ctx, md)\
+ __archive_digest.sha384final(ctx, md)
+#define archive_sha384_update(ctx, buf, n)\
+ __archive_digest.sha384update(ctx, buf, n)
+
+#if defined(ARCHIVE_CRYPTO_SHA512_LIBC) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC2) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBC3) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBMD) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_LIBSYSTEM) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_NETTLE) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_OPENSSL) ||\
+ defined(ARCHIVE_CRYPTO_SHA512_WIN)
+#define ARCHIVE_HAS_SHA512
+#endif
+#define archive_sha512_init(ctx)\
+ __archive_digest.sha512init(ctx)
+#define archive_sha512_final(ctx, md)\
+ __archive_digest.sha512final(ctx, md)
+#define archive_sha512_update(ctx, buf, n)\
+ __archive_digest.sha512update(ctx, buf, n)
+
+/* Minimal interface to digest functionality for internal use in libarchive */
+struct archive_digest
+{
+ /* Message Digest */
+ int (*md5init)(archive_md5_ctx *ctx);
+ int (*md5update)(archive_md5_ctx *, const void *, size_t);
+ int (*md5final)(archive_md5_ctx *, void *);
+ int (*rmd160init)(archive_rmd160_ctx *);
+ int (*rmd160update)(archive_rmd160_ctx *, const void *, size_t);
+ int (*rmd160final)(archive_rmd160_ctx *, void *);
+ int (*sha1init)(archive_sha1_ctx *);
+ int (*sha1update)(archive_sha1_ctx *, const void *, size_t);
+ int (*sha1final)(archive_sha1_ctx *, void *);
+ int (*sha256init)(archive_sha256_ctx *);
+ int (*sha256update)(archive_sha256_ctx *, const void *, size_t);
+ int (*sha256final)(archive_sha256_ctx *, void *);
+ int (*sha384init)(archive_sha384_ctx *);
+ int (*sha384update)(archive_sha384_ctx *, const void *, size_t);
+ int (*sha384final)(archive_sha384_ctx *, void *);
+ int (*sha512init)(archive_sha512_ctx *);
+ int (*sha512update)(archive_sha512_ctx *, const void *, size_t);
+ int (*sha512final)(archive_sha512_ctx *, void *);
+};
+
+extern const struct archive_digest __archive_digest;
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.3 b/Utilities/cmlibarchive/libarchive/archive_entry.3
index f77f385f2..f5e22af85 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.3
@@ -131,11 +131,11 @@ be discarded in favor of the new data.
.\" .Sh RETURN VALUES
.\" .Sh ERRORS
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_paths 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3
+.Xr libarchive 3 ,
.Sh HISTORY
The
.Nm libarchive
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.c b/Utilities/cmlibarchive/libarchive/archive_entry.c
index 386e51d47..10eff11b2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -201,6 +202,9 @@ archive_entry_clone(struct archive_entry *entry)
entry2->ae_set = entry->ae_set;
archive_mstring_copy(&entry2->ae_uname, &entry->ae_uname);
+ /* Copy encryption status */
+ entry2->encryption = entry->encryption;
+
/* Copy ACL data over. */
archive_acl_copy(&entry2->acl, &entry->acl);
@@ -245,10 +249,9 @@ archive_entry_new2(struct archive *a)
{
struct archive_entry *entry;
- entry = (struct archive_entry *)malloc(sizeof(*entry));
+ entry = (struct archive_entry *)calloc(1, sizeof(*entry));
if (entry == NULL)
return (NULL);
- memset(entry, 0, sizeof(*entry));
entry->archive = a;
return (entry);
}
@@ -415,6 +418,18 @@ archive_entry_gname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_gname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(entry->archive, &entry->ae_gname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
+
const wchar_t *
archive_entry_gname_w(struct archive_entry *entry)
{
@@ -447,6 +462,20 @@ archive_entry_hardlink(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_hardlink_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_hardlink, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_hardlink_w(struct archive_entry *entry)
{
@@ -533,6 +562,18 @@ archive_entry_pathname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_pathname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_pathname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_pathname_w(struct archive_entry *entry)
{
@@ -634,6 +675,20 @@ archive_entry_symlink(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_symlink_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_utf8(
+ entry->archive, &entry->ae_symlink, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_symlink_w(struct archive_entry *entry)
{
@@ -677,6 +732,17 @@ archive_entry_uname(struct archive_entry *entry)
return (NULL);
}
+const char *
+archive_entry_uname_utf8(struct archive_entry *entry)
+{
+ const char *p;
+ if (archive_mstring_get_utf8(entry->archive, &entry->ae_uname, &p) == 0)
+ return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+}
+
const wchar_t *
archive_entry_uname_w(struct archive_entry *entry)
{
@@ -695,6 +761,24 @@ _archive_entry_uname_l(struct archive_entry *entry,
return (archive_mstring_get_mbs_l(&entry->ae_uname, p, len, sc));
}
+int
+archive_entry_is_data_encrypted(struct archive_entry *entry)
+{
+ return ((entry->encryption & AE_ENCRYPTION_DATA) == AE_ENCRYPTION_DATA);
+}
+
+int
+archive_entry_is_metadata_encrypted(struct archive_entry *entry)
+{
+ return ((entry->encryption & AE_ENCRYPTION_METADATA) == AE_ENCRYPTION_METADATA);
+}
+
+int
+archive_entry_is_encrypted(struct archive_entry *entry)
+{
+ return (entry->encryption & (AE_ENCRYPTION_DATA|AE_ENCRYPTION_METADATA));
+}
+
/*
* Functions to set archive_entry properties.
*/
@@ -748,6 +832,12 @@ archive_entry_set_gname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_gname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_gname, name);
+}
+
+void
archive_entry_copy_gname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_gname, name);
@@ -804,6 +894,16 @@ archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
}
void
+archive_entry_set_hardlink_utf8(struct archive_entry *entry, const char *target)
+{
+ archive_mstring_copy_utf8(&entry->ae_hardlink, target);
+ if (target != NULL)
+ entry->ae_set |= AE_SET_HARDLINK;
+ else
+ entry->ae_set &= ~AE_SET_HARDLINK;
+}
+
+void
archive_entry_copy_hardlink(struct archive_entry *entry, const char *target)
{
archive_mstring_copy_mbs(&entry->ae_hardlink, target);
@@ -941,6 +1041,15 @@ archive_entry_set_link(struct archive_entry *entry, const char *target)
archive_mstring_copy_mbs(&entry->ae_hardlink, target);
}
+void
+archive_entry_set_link_utf8(struct archive_entry *entry, const char *target)
+{
+ if (entry->ae_set & AE_SET_SYMLINK)
+ archive_mstring_copy_utf8(&entry->ae_symlink, target);
+ else
+ archive_mstring_copy_utf8(&entry->ae_hardlink, target);
+}
+
/* Set symlink if symlink is already set, else set hardlink. */
void
archive_entry_copy_link(struct archive_entry *entry, const char *target)
@@ -1031,6 +1140,12 @@ archive_entry_set_pathname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_pathname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_pathname, name);
+}
+
+void
archive_entry_copy_pathname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_pathname, name);
@@ -1131,6 +1246,16 @@ archive_entry_set_symlink(struct archive_entry *entry, const char *linkname)
}
void
+archive_entry_set_symlink_utf8(struct archive_entry *entry, const char *linkname)
+{
+ archive_mstring_copy_utf8(&entry->ae_symlink, linkname);
+ if (linkname != NULL)
+ entry->ae_set |= AE_SET_SYMLINK;
+ else
+ entry->ae_set &= ~AE_SET_SYMLINK;
+}
+
+void
archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname)
{
archive_mstring_copy_mbs(&entry->ae_symlink, linkname);
@@ -1194,6 +1319,12 @@ archive_entry_set_uname(struct archive_entry *entry, const char *name)
}
void
+archive_entry_set_uname_utf8(struct archive_entry *entry, const char *name)
+{
+ archive_mstring_copy_utf8(&entry->ae_uname, name);
+}
+
+void
archive_entry_copy_uname(struct archive_entry *entry, const char *name)
{
archive_mstring_copy_mbs(&entry->ae_uname, name);
@@ -1216,6 +1347,26 @@ archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name)
return (0);
}
+void
+archive_entry_set_is_data_encrypted(struct archive_entry *entry, char is_encrypted)
+{
+ if (is_encrypted) {
+ entry->encryption |= AE_ENCRYPTION_DATA;
+ } else {
+ entry->encryption &= ~AE_ENCRYPTION_DATA;
+ }
+}
+
+void
+archive_entry_set_is_metadata_encrypted(struct archive_entry *entry, char is_encrypted)
+{
+ if (is_encrypted) {
+ entry->encryption |= AE_ENCRYPTION_METADATA;
+ } else {
+ entry->encryption &= ~AE_ENCRYPTION_METADATA;
+ }
+}
+
int
_archive_entry_copy_uname_l(struct archive_entry *entry,
const char *name, size_t len, struct archive_string_conv *sc)
@@ -1291,6 +1442,15 @@ archive_entry_acl_add_entry_w(struct archive_entry *entry,
}
/*
+ * Return a bitmask of ACL types in an archive entry ACL list
+ */
+int
+archive_entry_acl_types(struct archive_entry *entry)
+{
+ return (archive_acl_types(&entry->acl));
+}
+
+/*
* Return a count of entries matching "want_type".
*/
int
@@ -1327,34 +1487,121 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
}
/*
- * Generate a text version of the ACL. The flags parameter controls
+ * Generate a text version of the ACL. The flags parameter controls
* the style of the generated ACL.
*/
+wchar_t *
+archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_w(&entry->acl, len, flags,
+ entry->archive));
+}
+
+char *
+archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
+}
+
+char *
+_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
+ int flags, struct archive_string_conv *sc)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
+}
+
+/*
+ * ACL text parser.
+ */
+int
+archive_entry_acl_from_text_w(struct archive_entry *entry,
+ const wchar_t *wtext, int type)
+{
+ return (archive_acl_from_text_w(&entry->acl, wtext, type));
+}
+
+int
+archive_entry_acl_from_text(struct archive_entry *entry,
+ const char *text, int type)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
+}
+
+int
+_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
+ int type, struct archive_string_conv *sc)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, sc));
+}
+
+/* Deprecated */
+static int
+archive_entry_acl_text_compat(int *flags)
+{
+ if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
+ return (1);
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
+
+ return (0);
+}
+
+/* Deprecated */
const wchar_t *
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
{
- const wchar_t *r;
- r = archive_acl_text_w(entry->archive, &entry->acl, flags);
- if (r == NULL && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (r);
+ if (entry->acl.acl_text_w != NULL) {
+ free(entry->acl.acl_text_w);
+ entry->acl.acl_text_w = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
+ NULL, flags, entry->archive);
+ return (entry->acl.acl_text_w);
}
+/* Deprecated */
const char *
archive_entry_acl_text(struct archive_entry *entry, int flags)
{
- const char *p;
- if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
- && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (p);
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
+ flags, NULL);
+
+ return (entry->acl.acl_text);
}
+/* Deprecated */
int
_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
const char **acl_text, size_t *len, struct archive_string_conv *sc)
{
- return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc));
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
+ (ssize_t *)len, flags, sc);
+
+ *acl_text = entry->acl.acl_text;
+
+ return (0);
}
/*
@@ -1402,7 +1649,10 @@ static struct flag {
{ "nosappnd", L"nosappnd", SF_APPEND, 0 },
{ "nosappend", L"nosappend", SF_APPEND, 0 },
#endif
-#ifdef EXT2_APPEND_FL /* 'a' */
+#if defined(FS_APPEND_FL) /* 'a' */
+ { "nosappnd", L"nosappnd", FS_APPEND_FL, 0 },
+ { "nosappend", L"nosappend", FS_APPEND_FL, 0 },
+#elif defined(EXT2_APPEND_FL) /* 'a' */
{ "nosappnd", L"nosappnd", EXT2_APPEND_FL, 0 },
{ "nosappend", L"nosappend", EXT2_APPEND_FL, 0 },
#endif
@@ -1415,7 +1665,11 @@ static struct flag {
{ "noschange", L"noschange", SF_IMMUTABLE, 0 },
{ "nosimmutable", L"nosimmutable", SF_IMMUTABLE, 0 },
#endif
-#ifdef EXT2_IMMUTABLE_FL /* 'i' */
+#if defined(FS_IMMUTABLE_FL) /* 'i' */
+ { "noschg", L"noschg", FS_IMMUTABLE_FL, 0 },
+ { "noschange", L"noschange", FS_IMMUTABLE_FL, 0 },
+ { "nosimmutable", L"nosimmutable", FS_IMMUTABLE_FL, 0 },
+#elif defined(EXT2_IMMUTABLE_FL) /* 'i' */
{ "noschg", L"noschg", EXT2_IMMUTABLE_FL, 0 },
{ "noschange", L"noschange", EXT2_IMMUTABLE_FL, 0 },
{ "nosimmutable", L"nosimmutable", EXT2_IMMUTABLE_FL, 0 },
@@ -1439,7 +1693,9 @@ static struct flag {
#ifdef UF_NODUMP
{ "nodump", L"nodump", 0, UF_NODUMP},
#endif
-#ifdef EXT2_NODUMP_FL /* 'd' */
+#if defined(FS_NODUMP_FL) /* 'd' */
+ { "nodump", L"nodump", 0, FS_NODUMP_FL},
+#elif defined(EXT2_NODUMP_FL) /* 'd' */
{ "nodump", L"nodump", 0, EXT2_NODUMP_FL},
#endif
#ifdef UF_OPAQUE
@@ -1452,65 +1708,124 @@ static struct flag {
#ifdef UF_COMPRESSED
{ "nocompressed",L"nocompressed", UF_COMPRESSED, 0 },
#endif
-#ifdef EXT2_UNRM_FL
+#if defined(FS_UNRM_FL)
+ { "nouunlink", L"nouunlink", FS_UNRM_FL, 0},
+#elif defined(EXT2_UNRM_FL)
{ "nouunlink", L"nouunlink", EXT2_UNRM_FL, 0},
#endif
-#ifdef EXT2_BTREE_FL
+#if defined(FS_BTREE_FL)
+ { "nobtree", L"nobtree", FS_BTREE_FL, 0 },
+#elif defined(EXT2_BTREE_FL)
{ "nobtree", L"nobtree", EXT2_BTREE_FL, 0 },
#endif
-#ifdef EXT2_ECOMPR_FL
+#if defined(FS_ECOMPR_FL)
+ { "nocomperr", L"nocomperr", FS_ECOMPR_FL, 0 },
+#elif defined(EXT2_ECOMPR_FL)
{ "nocomperr", L"nocomperr", EXT2_ECOMPR_FL, 0 },
#endif
-#ifdef EXT2_COMPR_FL /* 'c' */
+#if defined(FS_COMPR_FL) /* 'c' */
+ { "nocompress", L"nocompress", FS_COMPR_FL, 0 },
+#elif defined(EXT2_COMPR_FL) /* 'c' */
{ "nocompress", L"nocompress", EXT2_COMPR_FL, 0 },
#endif
-#ifdef EXT2_NOATIME_FL /* 'A' */
+#if defined(FS_NOATIME_FL) /* 'A' */
+ { "noatime", L"noatime", 0, FS_NOATIME_FL},
+#elif defined(EXT2_NOATIME_FL) /* 'A' */
{ "noatime", L"noatime", 0, EXT2_NOATIME_FL},
#endif
-#ifdef EXT2_DIRTY_FL
+#if defined(FS_DIRTY_FL)
+ { "nocompdirty",L"nocompdirty", FS_DIRTY_FL, 0},
+#elif defined(EXT2_DIRTY_FL)
{ "nocompdirty",L"nocompdirty", EXT2_DIRTY_FL, 0},
#endif
-#ifdef EXT2_COMPRBLK_FL
-#ifdef EXT2_NOCOMPR_FL
+#if defined(FS_COMPRBLK_FL)
+#if defined(FS_NOCOMPR_FL)
+ { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, FS_NOCOMPR_FL},
+#else
+ { "nocomprblk", L"nocomprblk", FS_COMPRBLK_FL, 0},
+#endif
+#elif defined(EXT2_COMPRBLK_FL)
+#if defined(EXT2_NOCOMPR_FL)
{ "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
#else
{ "nocomprblk", L"nocomprblk", EXT2_COMPRBLK_FL, 0},
#endif
#endif
-#ifdef EXT2_DIRSYNC_FL
+#if defined(FS_DIRSYNC_FL)
+ { "nodirsync", L"nodirsync", FS_DIRSYNC_FL, 0},
+#elif defined(EXT2_DIRSYNC_FL)
{ "nodirsync", L"nodirsync", EXT2_DIRSYNC_FL, 0},
#endif
-#ifdef EXT2_INDEX_FL
+#if defined(FS_INDEX_FL)
+ { "nohashidx", L"nohashidx", FS_INDEX_FL, 0},
+#elif defined(EXT2_INDEX_FL)
{ "nohashidx", L"nohashidx", EXT2_INDEX_FL, 0},
#endif
-#ifdef EXT2_IMAGIC_FL
+#if defined(FS_IMAGIC_FL)
+ { "noimagic", L"noimagic", FS_IMAGIC_FL, 0},
+#elif defined(EXT2_IMAGIC_FL)
{ "noimagic", L"noimagic", EXT2_IMAGIC_FL, 0},
#endif
-#ifdef EXT3_JOURNAL_DATA_FL
+#if defined(FS_JOURNAL_DATA_FL)
+ { "nojournal", L"nojournal", FS_JOURNAL_DATA_FL, 0},
+#elif defined(EXT3_JOURNAL_DATA_FL)
{ "nojournal", L"nojournal", EXT3_JOURNAL_DATA_FL, 0},
#endif
-#ifdef EXT2_SECRM_FL
+#if defined(FS_SECRM_FL)
+ { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL, 0},
+#elif defined(EXT2_SECRM_FL)
{ "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL, 0},
#endif
-#ifdef EXT2_SYNC_FL
+#if defined(FS_SYNC_FL)
+ { "nosync", L"nosync", FS_SYNC_FL, 0},
+#elif defined(EXT2_SYNC_FL)
{ "nosync", L"nosync", EXT2_SYNC_FL, 0},
#endif
-#ifdef EXT2_NOTAIL_FL
+#if defined(FS_NOTAIL_FL)
+ { "notail", L"notail", 0, FS_NOTAIL_FL},
+#elif defined(EXT2_NOTAIL_FL)
{ "notail", L"notail", 0, EXT2_NOTAIL_FL},
#endif
-#ifdef EXT2_TOPDIR_FL
+#if defined(FS_TOPDIR_FL)
+ { "notopdir", L"notopdir", FS_TOPDIR_FL, 0},
+#elif defined(EXT2_TOPDIR_FL)
{ "notopdir", L"notopdir", EXT2_TOPDIR_FL, 0},
#endif
-#ifdef EXT2_RESERVED_FL
+#ifdef FS_ENCRYPT_FL
+ { "noencrypt", L"noencrypt", FS_ENCRYPT_FL, 0},
+#endif
+#ifdef FS_HUGE_FILE_FL
+ { "nohugefile", L"nohugefile", FS_HUGE_FILE_FL, 0},
+#endif
+#ifdef FS_EXTENT_FL
+ { "noextent", L"noextent", FS_EXTENT_FL, 0},
+#endif
+#ifdef FS_EA_INODE_FL
+ { "noeainode", L"noeainode", FS_EA_INODE_FL, 0},
+#endif
+#ifdef FS_EOFBLOCKS_FL
+ { "noeofblocks",L"noeofblocks", FS_EOFBLOCKS_FL, 0},
+#endif
+#ifdef FS_NOCOW_FL
+ { "nocow", L"nocow", FS_NOCOW_FL, 0},
+#endif
+#ifdef FS_INLINE_DATA_FL
+ { "noinlinedata",L"noinlinedata", FS_INLINE_DATA_FL, 0},
+#endif
+#ifdef FS_PROJINHERIT_FL
+ { "noprojinherit",L"noprojinherit", FS_PROJINHERIT_FL, 0},
+#endif
+#if defined(FS_RESERVED_FL)
+ { "noreserved", L"noreserved", FS_RESERVED_FL, 0},
+#elif defined(EXT2_RESERVED_FL)
{ "noreserved", L"noreserved", EXT2_RESERVED_FL, 0},
#endif
-
{ NULL, NULL, 0, 0 }
};
@@ -1588,19 +1903,23 @@ ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
while (*start == '\t' || *start == ' ' || *start == ',')
start++;
while (*start != '\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != '\0' && *end != '\t' &&
*end != ' ' && *end != ',')
end++;
+ length = end - start;
for (flag = flags; flag->name != NULL; flag++) {
- if (memcmp(start, flag->name, end - start) == 0) {
+ size_t flag_length = strlen(flag->name);
+ if (length == flag_length
+ && memcmp(start, flag->name, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (memcmp(start, flag->name + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && memcmp(start, flag->name + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
@@ -1652,19 +1971,23 @@ ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
while (*start == L'\t' || *start == L' ' || *start == L',')
start++;
while (*start != L'\0') {
+ size_t length;
/* Locate end of token. */
end = start;
while (*end != L'\0' && *end != L'\t' &&
*end != L' ' && *end != L',')
end++;
+ length = end - start;
for (flag = flags; flag->wname != NULL; flag++) {
- if (wmemcmp(start, flag->wname, end - start) == 0) {
+ size_t flag_length = wcslen(flag->wname);
+ if (length == flag_length
+ && wmemcmp(start, flag->wname, length) == 0) {
/* Matched "noXXXX", so reverse the sense. */
clear |= flag->set;
set |= flag->clear;
break;
- } else if (wmemcmp(start, flag->wname + 2, end - start)
- == 0) {
+ } else if (length == flag_length - 2
+ && wmemcmp(start, flag->wname + 2, length) == 0) {
/* Matched "XXXX", so don't reverse. */
set |= flag->set;
clear |= flag->clear;
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h
index 85ea885f7..6e0225b04 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2008 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,7 +30,7 @@
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3001002
+#define ARCHIVE_VERSION_NUMBER 3003001
/*
* Note: archive_entry.h is for use outside of libarchive; the
@@ -48,14 +49,41 @@
#endif
/* Get a suitable 64-bit integer type. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-# define __LA_INT64_T __int64
-#else
+#if !defined(__LA_INT64_T_DEFINED)
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_INT64_T la_int64_t
+# endif
+#define __LA_INT64_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+typedef __int64 la_int64_t;
+# else
#include <unistd.h>
-# if defined(_SCO_DS) || defined(__osf__)
-# define __LA_INT64_T long long
+# if defined(_SCO_DS) || defined(__osf__)
+typedef long long la_int64_t;
+# else
+typedef int64_t la_int64_t;
+# endif
+# endif
+#endif
+
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+# if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+# elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+# else
+typedef long la_ssize_t;
+# endif
# else
-# define __LA_INT64_T int64_t
+# include <unistd.h> /* ssize_t */
+typedef ssize_t la_ssize_t;
# endif
#endif
@@ -63,12 +91,17 @@
#if ARCHIVE_VERSION_NUMBER >= 3999000
/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */
# define __LA_MODE_T int
-#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) && !defined(__WATCOMC__)
# define __LA_MODE_T unsigned short
#else
# define __LA_MODE_T mode_t
#endif
+/* Large file support for Android */
+#ifdef __ANDROID__
+#include "android_lf.h"
+#endif
+
/*
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
* .lib. The default here assumes you're building a DLL. Only
@@ -93,6 +126,9 @@
# define __LA_DECL
#endif
+/* CMake uses some deprecated APIs to build with old libarchive versions. */
+#define __LA_DEPRECATED
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -206,13 +242,15 @@ __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 la_int64_t archive_entry_gid(struct archive_entry *);
__LA_DECL const char *archive_entry_gname(struct archive_entry *);
+__LA_DECL const char *archive_entry_gname_utf8(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 char *archive_entry_hardlink_utf8(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 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 *);
@@ -220,6 +258,7 @@ __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 char *archive_entry_pathname_utf8(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 *);
@@ -227,14 +266,19 @@ __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 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 char *archive_entry_symlink_utf8(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 la_int64_t archive_entry_uid(struct archive_entry *);
__LA_DECL const char *archive_entry_uname(struct archive_entry *);
+__LA_DECL const char *archive_entry_uname_utf8(struct archive_entry *);
__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
+__LA_DECL int archive_entry_is_data_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_metadata_encrypted(struct archive_entry *);
+__LA_DECL int archive_entry_is_encrypted(struct archive_entry *);
/*
* Set fields in an archive_entry.
@@ -248,7 +292,7 @@ __LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *);
__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 *);
+__LA_DECL void archive_entry_copy_bhfi(struct archive_entry *, struct _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 *);
@@ -266,18 +310,21 @@ __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_gid(struct archive_entry *, la_int64_t);
__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_gname_utf8(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_set_hardlink_utf8(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_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_set_link_utf8(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 *);
@@ -286,6 +333,7 @@ __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_set_pathname_utf8(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 *);
@@ -293,19 +341,23 @@ __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_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_set_symlink_utf8(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_uid(struct archive_entry *, la_int64_t);
__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *);
+__LA_DECL void archive_entry_set_uname_utf8(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 *);
+__LA_DECL void archive_entry_set_is_data_encrypted(struct archive_entry *, char is_encrypted);
+__LA_DECL void archive_entry_set_is_metadata_encrypted(struct archive_entry *, char is_encrypted);
/*
* Routines to bulk copy fields to/from a platform-native "struct
* stat." Libarchive used to just store a struct stat inside of each
@@ -393,6 +445,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
/*
* Inheritance values (NFS4 ACLs only); included in permset.
*/
+#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000
#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
@@ -406,15 +459,16 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
| 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)
+ | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \
+ | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)
/* 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_ACCESS 0x00000100 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* 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 \
@@ -465,21 +519,51 @@ __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type
* Construct a text-format ACL. The flags argument is a bitmask that
* can include any of the following:
*
+ * Flags only for archive entries with POSIX.1e ACL:
* 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.
+ * default ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and
+ * "mask" entries.
+ *
+ * Flags only for archive entries with NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for
+ * unset permissions and flags in NFSv4 ACL permission and flag fields
+ *
+ * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ * each ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma
+ * instead of newline.
*/
-#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
-#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001
+#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002
+#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004
+#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008
+#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010
+
+__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
+ la_ssize_t * /* len */, int /* flags */);
+__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
+ la_ssize_t * /* len */, int /* flags */);
+__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
+ const wchar_t * /* wtext */, int /* type */);
+__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
+ const char * /* text */, int /* type */);
+
+/* Deprecated constants */
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+
+/* Deprecated functions */
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __LA_DEPRECATED;
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __LA_DEPRECATED;
+
+/* Return bitmask of ACL types in an archive entry */
+__LA_DECL int archive_entry_acl_types(struct archive_entry *);
/* Return a count of entries matching 'want_type' */
__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */);
@@ -514,7 +598,7 @@ __LA_DECL int archive_entry_xattr_next(struct archive_entry *,
__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 */);
+ la_int64_t /* offset */, la_int64_t /* length */);
/*
* To retrieve the xattr list, first "reset", then repeatedly ask for the
@@ -524,7 +608,7 @@ __LA_DECL void archive_entry_sparse_add_entry(struct archive_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 */);
+ la_int64_t * /* offset */, la_int64_t * /* length */);
/*
* Utility to match up hardlinks.
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_acl.3 b/Utilities/cmlibarchive/libarchive/archive_entry_acl.3
index f5c337733..c5115f727 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_acl.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_acl.3
@@ -1,4 +1,5 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" Copyright (c) 2016 Martin Matuska
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -22,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 2, 2012
+.Dd February 15, 2017
.Dt ARCHIVE_ENTRY_ACL 3
.Os
.Sh NAME
@@ -30,10 +31,14 @@
.Nm archive_entry_acl_add_entry_w ,
.Nm archive_entry_acl_clear ,
.Nm archive_entry_acl_count ,
+.Nm archive_entry_acl_from_text ,
+.Nm archive_entry_acl_from_text_w,
.Nm archive_entry_acl_next ,
.Nm archive_entry_acl_next_w ,
.Nm archive_entry_acl_reset ,
-.Nm archive_entry_acl_text_w
+.Nm archive_entry_acl_to_text ,
+.Nm archive_entry_acl_to_text_w ,
+.Nm archive_entry_acl_types
.Nd functions for manipulating Access Control Lists in archive entry descriptions
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
@@ -62,6 +67,18 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
.Ft int
+.Fo archive_entry_acl_from_text
+.Fa "struct archive_entry *a"
+.Fa "const char *text"
+.Fa "int type"
+.Fc
+.Ft int
+.Fo archive_entry_acl_from_text_w
+.Fa "struct archive_entry *a"
+.Fa "const wchar_t *text"
+.Fa "int type"
+.Fc
+.Ft int
.Fo archive_entry_acl_next
.Fa "struct archive_entry *a"
.Fa "int type"
@@ -83,31 +100,48 @@ Streaming Archive Library (libarchive, -larchive)
.Fc
.Ft int
.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
-.Ft const wchar_t *
-.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
+.Ft char *
+.Fo archive_entry_acl_to_text
+.Fa "struct archive_entry *a"
+.Fa "ssize_t *len_p"
+.Fa "int flags"
+.Fc
+.Ft wchar_t *
+.Fo archive_entry_acl_to_text_w
+.Fa "struct archive_entry *a"
+.Fa "ssize_t *len_p"
+.Fa "int flags"
+.Fc
+.Ft int
+.Fn archive_entry_acl_types "struct archive_entry *a"
.\" enum?
.Sh DESCRIPTION
-An
-.Dq Access Control List
-is a generalisation of the classic Unix permission system.
+The
+.Dq Access Control Lists (ACLs)
+extend the standard Unix perssion model.
The ACL interface of
.Nm libarchive
-is derived from the POSIX.1e draft, but restricted to simplify dealing
-with practical implementations in various Operating Systems and archive formats.
-.Pp
-An ACL consists of a number of independent entries.
+supports both POSIX.1e and NFSv4 style ACLs. Use of ACLs is restricted by
+various levels of ACL support in operating systems, file systems and archive
+formats.
+.Ss POSIX.1e Access Control Lists
+A POSIX.1e ACL consists of a number of independent entries.
Each entry specifies the permission set as bitmask of basic permissions.
-Valid permissions are:
+Valid permissions in the
+.Fa permset
+are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
-.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
-.It Dv ARCHIVE_ENTRY_ACL_WRITE
-.It Dv ARCHIVE_ENTRY_ACL_READ
+.It Dv ARCHIVE_ENTRY_ACL_READ ( Sy r )
+.It Dv ARCHIVE_ENTRY_ACL_WRITE ( Sy w )
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x )
.El
The permissions correspond to the normal Unix permissions.
.Pp
-The tag specifies the principal to which the permission applies.
+The
+.Fa tag
+specifies the principal to which the permission applies.
Valid values are:
-.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
.It Dv ARCHIVE_ENTRY_ACL_USER
The user specified by the name field.
.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
@@ -119,8 +153,9 @@ The group who owns the file.
.It Dv ARCHIVE_ENTRY_ACL_MASK
The maximum permissions to be obtained via group permissions.
.It Dv ARCHIVE_ENTRY_ACL_OTHER
-Any principal who doesn't have a user or group entry.
+Any principal who is not file owner or a member of the owning group.
.El
+.Pp
The principals
.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
@@ -129,19 +164,123 @@ and
are equivalent to user, group and other in the classic Unix permission
model and specify non-extended ACL entries.
.Pp
-All files have an access ACL
+All files with have an access ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
This specifies the permissions required for access to the file itself.
Directories have an additional ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
which controls the initial access ACL for newly created directory entries.
+.Ss NFSv4 Access Control Lists
+A NFSv4 ACL consists of multiple individual entries called Access Control
+Entries (ACEs).
+.Pp
+There are four possible types of a NFSv4 ACE:
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYE_ALLOW"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW
+Allow principal to perform actions requiring given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY
+Prevent principal from performing actions requiring given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT
+Log access attempts by principal which require given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM
+Trigger a system alarm on access attempts by principal which require given
+permissions.
+.El
+.Pp
+The
+.Fa tag
+specifies the principal to which the permission applies.
+Valid values are:
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.It Dv ARCHIVE_ENTRY_ACL_USER
+The user specified by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
+The owner of the file.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP
+The group specied by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+The group who owns the file.
+.It Dv ARCHIVE_ENTRY_ACL_EVERYONE
+Any principal who is not file owner or a member of the owning group.
+.El
+.Pp
+Entries with the
+.Dv ARCHIVE_ENTRY_ACL_USER
+or
+.Dv ARCHIVE_ENTRY_ACL_GROUP
+tag store the user and group name in the
+.Fa name
+string and optionally the user or group ID in the
+.Fa qualifier
+integer.
+.Pp
+NFSv4 ACE permissions and flags are stored in the same
+.Fa permset
+bitfield. Some permissions share the same constant and permission character but
+have different effect on directories than on files. The following ACE
+permissions are supported:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_READ_DATA ( Sy r )
+Read data (file).
+.It Dv ARCHIVE_ENTRY_ACL_LIST_DIRECTORY ( Sy r )
+List entries (directory).
+.It ARCHIVE_ENTRY_ACL_WRITE_DATA ( Sy w )
+Write data (file).
+.It ARCHIVE_ENTRY_ACL_ADD_FILE ( Sy w )
+Create files (directory).
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x )
+Execute file or change into a directory.
+.It Dv ARCHIVE_ENTRY_ACL_APPEND_DATA ( Sy p )
+Append data (file).
+.It Dv ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY ( Sy p )
+Create subdirectories (directory).
+.It Dv ARCHIVE_ENTRY_ACL_DELETE_CHILD ( Sy D )
+Remove files and subdirectories inside a directory.
+.It Dv ARCHIVE_ENTRY_ACL_DELETE ( Sy d )
+Remove file or directory.
+.It Dv ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES ( Sy a )
+Read file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES ( Sy A )
+Write file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS ( Sy R )
+Read named file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS ( Sy W )
+Write named file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_READ_ACL ( Sy c )
+Read file or directory ACL.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_ACL ( Sy C )
+Write file or directory ACL.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_OWNER ( Sy o )
+Change owner of a file or directory.
+.It Dv ARCHIVE_ENTRY_ACL_SYNCHRONIZE ( Sy s )
+Use synchronous I/O.
+.El
.Pp
+The following NFSv4 ACL inheritance flags are supported:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT ( Sy f )
+Inherit parent directory ACE to files.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT ( Sy d )
+Inherit parent directory ACE to subdirectories.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY ( Sy i )
+Only inherit, do not apply the permission on the directory itself.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT ( Sy n )
+Do not propagate inherit flags. Only first-level entries inherit ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS ( Sy S )
+Trigger alarm or audit on succesful access.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS ( Sy F )
+Trigger alarm or audit on failed access.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERITED ( Sy I )
+Mark that ACE was inherited.
+.El
+.Ss Functions
.Fn archive_entry_acl_add_entry
and
.Fn archive_entry_acl_add_entry_w
add a single ACL entry.
For the access ACL and non-extended principals, the classic Unix permissions
-are updated.
+are updated. An archive enry cannot contain both POSIX.1e and NFSv4 ACL
+entries.
.Pp
.Fn archive_entry_acl_clear
removes all ACL entries and resets the enumeration pointer.
@@ -150,14 +289,58 @@ removes all ACL entries and resets the enumeration pointer.
counts the ACL entries that have the given type mask.
.Fa type
can be the bitwise-or of
-.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
-and
-.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
-If
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+.El
+for POSIX.1e ACLs and
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_ALLOW"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM
+.El
+for NFSv4 ACLs. For POSIX.1e ACLs if
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
is included and at least one extended ACL entry is found,
the three non-extened ACLs are added.
.Pp
+.Fn archive_entry_acl_from_text
+and
+.Fn archive_entry_acl_from_text_w
+add new
+.Pq or merge with existing
+ACL entries from
+.Pq wide
+text. The argument
+.Fa type
+may take one of the following values:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4
+.El
+Supports all formats that can be created with
+.Fn archive_entry_acl_to_text
+or respective
+.Fn archive_entry_acl_to_text_w .
+Existing ACL entries are preserved. To get a clean new ACL from text
+.Fn archive_entry_acl_clear
+must be called first. Entries prefixed with
+.Dq default:
+are treated as
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+unless
+.Fa type
+is
+.Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4 .
+Invalid entries, non-parseable ACL entries and entries beginning with
+the
+.Sq #
+character
+.Pq comments
+are skipped.
+.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
@@ -179,29 +362,81 @@ or set using
Otherwise, the function returns the same value as
.Fn archive_entry_acl_count .
.Pp
-.Fn archive_entry_acl_text_w
-converts the ACL entries for the given type mask into a wide string.
-In addition to the normal type flags,
-.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+.Fn archive_entry_acl_to_text
and
-.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
-can be specified to further customize the result.
-The returned long string is valid until the next call to
-.Fn archive_entry_acl_clear ,
-.Fn archive_entry_acl_add_entry ,
-.Fn archive_entry_acl_add_entry_w
+.Fn archive_entry_acl_to_text_w
+convert the ACL entries for the given type into a
+.Pq wide
+string of ACL entries separated by newline. If the the pointer
+.Fa len_p
+is not NULL, then the function shall return the length of the string
+.Pq not including the NULL terminator
+in the location pointed to by
+.Fa len_p .
+The
+.Fa flag
+argument is a bitwise-or.
+.Pp
+The following flags are effective only on POSIX.1e ACL:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+Output access ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+Output POSIX.1e default ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+Prefix each default ACL entry with the word
+.Dq default: .
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_SOLARIS
+The mask and other ACLs don not contain a double colon.
+.El
+.Pp
+The following flags are effecive only on NFSv4 ACL:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_COMPACT
+Do not output minus characters for unset permissions and flags in NFSv4 ACL
+permission and flag fields.
+.El
+.Pp
+The following flags are effective on both POSIX.1e and NFSv4 ACL:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+Add an additional colon-separated field containing the user or group id.
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
+Separate ACL entries with comma instead of newline.
+.El
+.Pp
+If the archive entry contains NFSv4 ACLs, all types of NFSv4 ACLs are returned.
+It the entry contains POSIX.1e ACLs and none of the flags
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
or
-.Fn archive_entry_acl_text_w .
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+are specified, both access and default entries are returned and default entries
+are prefixed with
+.Dq default: .
+.Pp
+.Fn archive_entry_acl_types
+get ACL entry types contained in an archive entry's ACL. As POSIX.1e and NFSv4
+ACL entries cannot be mixed, this function is a very efficient way to detect if
+an ACL already contains POSIX.1e or NFSv4 ACL entries.
.Sh RETURN VALUES
.Fn archive_entry_acl_count
and
.Fn archive_entry_acl_reset
returns the number of ACL entries that match the given type mask.
-If the type mask includes
+For POSIX.1e ACLS if the type mask includes
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and at least one extended ACL entry exists, the three classic Unix
permissions are counted.
.Pp
+.Fn archive_entry_acl_from_text
+and
+.Fn archive_entry_acl_from_text_w
+return
+.Dv ARCHIVE_OK
+if all entries were successfully parsed and
+.Dv ARCHIVE_WARN
+if one or more entries were invalid or non-parseable.
+.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
@@ -216,20 +451,16 @@ if
.Fn archive_entry_acl_reset
has not been called first.
.Pp
-.Fn archive_entry_text_w
-returns a wide string representation of the ACL entrise matching the
-given type mask.
-The returned long string is valid until the next call to
-.Fn archive_entry_acl_clear ,
-.Fn archive_entry_acl_add_entry ,
-.Fn archive_entry_acl_add_entry_w
-or
-.Fn archive_entry_acl_text_w .
+.Fn archive_entry_acl_to_text
+returns a string representing the ACL entries matching the given type and
+flags on success or NULL on error.
+.Pp
+.Fn archive_entry_acl_to_text_w
+returns a wide string representing the ACL entries matching the given type
+and flags on success or NULL on error.
+.Pp
+.Fn archive_entry_acl_types
+returns a bitmask of ACL entry types or 0 if archive entry has no ACL entries.
.Sh SEE ALSO
-.Xr archive 3 ,
-.Xr archive_entry 3
-.Sh BUGS
-.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
-and
-.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
-are not documented.
+.Xr archive_entry 3 ,
+.Xr libarchive 3
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c b/Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c
index 37d4d6edb..ac83868e8 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_copy_stat.c
@@ -44,6 +44,10 @@ archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec);
archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec);
archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec);
+#elif HAVE_STRUCT_STAT_ST_MTIME_NSEC
+ archive_entry_set_atime(entry, st->st_atime, st->st_atime_nsec);
+ archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime, st->st_mtime_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
archive_entry_set_atime(entry, st->st_atime, st->st_atime_n);
archive_entry_set_ctime(entry, st->st_ctime, st->st_ctime_n);
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_locale.h b/Utilities/cmlibarchive/libarchive/archive_entry_locale.h
index 02e024ae2..44550c51e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_locale.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_locale.h
@@ -63,9 +63,13 @@ int _archive_entry_uname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_acl_text_l _archive_entry_acl_text_l
int _archive_entry_acl_text_l(struct archive_entry *, int,
- const char **, size_t *, struct archive_string_conv *);
-
-
+const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED;
+#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l
+char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,
+ struct archive_string_conv *);
+#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l
+int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text,
+ int type, struct archive_string_conv *);
#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
int _archive_entry_copy_gname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_paths.3 b/Utilities/cmlibarchive/libarchive/archive_entry_paths.3
index 51c8b8c8e..fd22cf7e2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_paths.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_paths.3
@@ -149,5 +149,5 @@ It doesn't have a corresponding get accessor function.
is an alias for
.Fn archive_entry_copy_XXX .
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry 3
+.Xr libarchive 3 ,
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_perms.3 b/Utilities/cmlibarchive/libarchive/archive_entry_perms.3
index 5b7b5d955..340c5ea72 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_perms.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_perms.3
@@ -194,11 +194,11 @@ every name that is recognized.
.Xr strtofflags 3 ,
which stops parsing at the first unrecognized name.)
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_read_disk 3 ,
.Xr archive_write_disk 3
+.Xr libarchive 3 ,
.Sh BUGS
The platform types
.Vt uid_t
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_private.h b/Utilities/cmlibarchive/libarchive/archive_entry_private.h
index e3547c3e3..c69233e68 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_private.h
@@ -154,6 +154,11 @@ struct archive_entry {
/* Not used within libarchive; useful for some clients. */
struct archive_mstring ae_sourcepath; /* Path this entry is sourced from. */
+#define AE_ENCRYPTION_NONE 0
+#define AE_ENCRYPTION_DATA 1
+#define AE_ENCRYPTION_METADATA 2
+ char encryption;
+
void *mac_metadata;
size_t mac_metadata_size;
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c b/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c
index 10c54474a..fed74f512 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_sparse.c
@@ -58,7 +58,7 @@ archive_entry_sparse_add_entry(struct archive_entry *entry,
if (offset < 0 || length < 0)
/* Invalid value */
return;
- if (offset + length < 0 ||
+ if (offset > INT64_MAX - length ||
offset + length > archive_entry_size(entry))
/* A value of "length" parameter is too large. */
return;
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_stat.3 b/Utilities/cmlibarchive/libarchive/archive_entry_stat.3
index 84a4ea12a..26611e4c6 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_stat.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_stat.3
@@ -226,7 +226,7 @@ and
are used by
.Xr archive_entry_linkify 3
to find hardlinks.
-The pair of device and inode is suppossed to identify hardlinked files.
+The pair of device and inode is supposed to identify hardlinked files.
.Pp
The device major and minor number can be obtained independently using
.Fn archive_entry_devmajor
@@ -267,8 +267,8 @@ platforms.
Some archive formats use the combined form, while other formats use
the split form.
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry_acl 3 ,
.Xr archive_entry_perms 3 ,
.Xr archive_entry_time 3 ,
+.Xr libarchive 3 ,
.Xr stat 2
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c b/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c
index 16cb3f7bb..af2517a32 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c
@@ -80,7 +80,7 @@ archive_entry_strmode(struct archive_entry *entry)
if (mode & 0001) bp[9] = 't';
else bp[9] = 'T';
}
- if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS))
+ if (archive_entry_acl_types(entry) != 0)
bp[10] = '+';
return (bp);
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_time.3 b/Utilities/cmlibarchive/libarchive/archive_entry_time.3
index 17c658a65..186452159 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_time.3
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_time.3
@@ -113,8 +113,8 @@ The current state can be queried using
.Fn XXX_is_set .
Unset time fields have a second and nanosecond field of 0.
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry 3
+.Xr libarchive 3 ,
.Sh HISTORY
The
.Nm libarchive
diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_xattr.c b/Utilities/cmlibarchive/libarchive/archive_entry_xattr.c
index a3efe7ca8..5fe726b99 100644
--- a/Utilities/cmlibarchive/libarchive/archive_entry_xattr.c
+++ b/Utilities/cmlibarchive/libarchive/archive_entry_xattr.c
@@ -91,14 +91,12 @@ archive_entry_xattr_add_entry(struct archive_entry *entry,
{
struct ae_xattr *xp;
- for (xp = entry->xattr_head; xp != NULL; xp = xp->next)
- ;
-
if ((xp = (struct ae_xattr *)malloc(sizeof(struct ae_xattr))) == NULL)
- /* XXX Error XXX */
- return;
+ __archive_errx(1, "Out of memory");
+
+ if ((xp->name = strdup(name)) == NULL)
+ __archive_errx(1, "Out of memory");
- xp->name = strdup(name);
if ((xp->value = malloc(size)) != NULL) {
memcpy(xp->value, value, size);
xp->size = size;
diff --git a/Utilities/cmlibarchive/libarchive/archive_getdate.c b/Utilities/cmlibarchive/libarchive/archive_getdate.c
index f8b5a28d5..beb0cba2e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_getdate.c
+++ b/Utilities/cmlibarchive/libarchive/archive_getdate.c
@@ -38,8 +38,8 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <time.h>
-/* This file defines a single public function. */
-time_t __archive_get_date(time_t now, char *);
+#define __LIBARCHIVE_BUILD 1
+#include "archive_getdate.h"
/* Basic time units. */
#define EPOCH 1970
@@ -369,8 +369,8 @@ relunitphrase(struct gdstate *gds)
&& gds->tokenp[1].token == tSEC_UNIT) {
/* "1 day" */
gds->HaveRel++;
- gds->RelSeconds += gds->tokenp[1].value * gds->tokenp[2].value;
- gds->tokenp += 3;
+ gds->RelSeconds += gds->tokenp[0].value * gds->tokenp[1].value;
+ gds->tokenp += 2;
return 1;
}
if (gds->tokenp[0].token == '-'
@@ -403,7 +403,7 @@ relunitphrase(struct gdstate *gds)
/* "now", "tomorrow" */
gds->HaveRel++;
gds->RelSeconds += gds->tokenp[0].value;
- ++gds->tokenp;
+ gds->tokenp += 1;
return 1;
}
if (gds->tokenp[0].token == tMONTH_UNIT) {
@@ -782,7 +782,7 @@ RelativeMonth(time_t Start, time_t Timezone, time_t RelMonth)
* Tokenizer.
*/
static int
-nexttoken(char **in, time_t *value)
+nexttoken(const char **in, time_t *value)
{
char c;
char buff[64];
@@ -809,7 +809,7 @@ nexttoken(char **in, time_t *value)
/* Try the next token in the word table first. */
/* This allows us to match "2nd", for example. */
{
- char *src = *in;
+ const char *src = *in;
const struct LEXICON *tp;
unsigned i = 0;
@@ -894,7 +894,7 @@ difftm (struct tm *a, struct tm *b)
* TODO: tokens[] array should be dynamically sized.
*/
time_t
-__archive_get_date(time_t now, char *p)
+__archive_get_date(time_t now, const char *p)
{
struct token tokens[256];
struct gdstate _gds;
@@ -1022,10 +1022,11 @@ int
main(int argc, char **argv)
{
time_t d;
+ time_t now = time(NULL);
while (*++argv != NULL) {
(void)printf("Input: %s\n", *argv);
- d = get_date(*argv);
+ d = get_date(now, *argv);
if (d == -1)
(void)printf("Bad format - couldn't convert.\n");
else
diff --git a/Utilities/cmlibarchive/libarchive/archive_getdate.h b/Utilities/cmlibarchive/libarchive/archive_getdate.h
new file mode 100644
index 000000000..666ff5ff7
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_getdate.h
@@ -0,0 +1,39 @@
+/*-
+ * Copyright (c) 2003-2015 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_GETDATE_H_INCLUDED
+#define ARCHIVE_GETDATE_H_INCLUDED
+
+#include <time.h>
+
+time_t __archive_get_date(time_t now, const char *);
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_hmac.c b/Utilities/cmlibarchive/libarchive/archive_hmac.c
new file mode 100644
index 000000000..f29965577
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_hmac.c
@@ -0,0 +1,254 @@
+/*-
+* Copyright (c) 2014 Michihiro NAKAJIMA
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+*
+* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "archive_platform.h"
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include "archive.h"
+#include "archive_hmac_private.h"
+
+/*
+ * On systems that do not support any recognized crypto libraries,
+ * the archive_hmac.c file is expected to define no usable symbols.
+ *
+ * But some compilers and linkers choke on empty object files, so
+ * define a public symbol that will always exist. This could
+ * be removed someday if this file gains another always-present
+ * symbol definition.
+ */
+int __libarchive_hmac_build_hack(void) {
+ return 0;
+}
+
+
+#ifdef ARCHIVE_HMAC_USE_Apple_CommonCrypto
+
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ CCHmacInit(ctx, kCCHmacAlgSHA1, key, key_len);
+ return 0;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+ size_t data_len)
+{
+ CCHmacUpdate(ctx, data, data_len);
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+ CCHmacFinal(ctx, out);
+ *out_len = 20;
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+
+#ifndef BCRYPT_HASH_REUSABLE_FLAG
+# define BCRYPT_HASH_REUSABLE_FLAG 0x00000020
+#endif
+
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ BCRYPT_ALG_HANDLE hAlg;
+ BCRYPT_HASH_HANDLE hHash;
+ DWORD hash_len;
+ PBYTE hash;
+ ULONG result;
+ NTSTATUS status;
+
+ ctx->hAlg = NULL;
+ status = BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA1_ALGORITHM,
+ MS_PRIMITIVE_PROVIDER, BCRYPT_ALG_HANDLE_HMAC_FLAG);
+ if (!BCRYPT_SUCCESS(status))
+ return -1;
+ status = BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PUCHAR)&hash_len,
+ sizeof(hash_len), &result, 0);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ hash = (PBYTE)HeapAlloc(GetProcessHeap(), 0, hash_len);
+ if (hash == NULL) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ return -1;
+ }
+ status = BCryptCreateHash(hAlg, &hHash, NULL, 0,
+ (PUCHAR)key, (ULONG)key_len, BCRYPT_HASH_REUSABLE_FLAG);
+ if (!BCRYPT_SUCCESS(status)) {
+ BCryptCloseAlgorithmProvider(hAlg, 0);
+ HeapFree(GetProcessHeap(), 0, hash);
+ return -1;
+ }
+
+ ctx->hAlg = hAlg;
+ ctx->hHash = hHash;
+ ctx->hash_len = hash_len;
+ ctx->hash = hash;
+
+ return 0;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+ size_t data_len)
+{
+ BCryptHashData(ctx->hHash, (PUCHAR)(uintptr_t)data, (ULONG)data_len, 0);
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+ BCryptFinishHash(ctx->hHash, ctx->hash, ctx->hash_len, 0);
+ if (ctx->hash_len == *out_len)
+ memcpy(out, ctx->hash, *out_len);
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+ if (ctx->hAlg != NULL) {
+ BCryptCloseAlgorithmProvider(ctx->hAlg, 0);
+ HeapFree(GetProcessHeap(), 0, ctx->hash);
+ ctx->hAlg = NULL;
+ }
+}
+
+#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_HMAC_H)
+
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ hmac_sha1_set_key(ctx, key_len, key);
+ return 0;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+ size_t data_len)
+{
+ hmac_sha1_update(ctx, data_len, data);
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+ hmac_sha1_digest(ctx, (unsigned)*out_len, out);
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+#elif defined(HAVE_LIBCRYPTO)
+
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ *ctx = HMAC_CTX_new();
+ if (*ctx == NULL)
+ return -1;
+ HMAC_Init_ex(*ctx, key, key_len, EVP_sha1(), NULL);
+ return 0;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+ size_t data_len)
+{
+ HMAC_Update(*ctx, data, data_len);
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+ unsigned int len = (unsigned int)*out_len;
+ HMAC_Final(*ctx, out, &len);
+ *out_len = len;
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+ HMAC_CTX_free(*ctx);
+ *ctx = NULL;
+}
+
+#else
+
+/* Stub */
+static int
+__hmac_sha1_init(archive_hmac_sha1_ctx *ctx, const uint8_t *key, size_t key_len)
+{
+ (void)ctx;/* UNUSED */
+ (void)key;/* UNUSED */
+ (void)key_len;/* UNUSED */
+ return -1;
+}
+
+static void
+__hmac_sha1_update(archive_hmac_sha1_ctx *ctx, const uint8_t *data,
+ size_t data_len)
+{
+ (void)ctx;/* UNUSED */
+ (void)data;/* UNUSED */
+ (void)data_len;/* UNUSED */
+}
+
+static void
+__hmac_sha1_final(archive_hmac_sha1_ctx *ctx, uint8_t *out, size_t *out_len)
+{
+ (void)ctx;/* UNUSED */
+ (void)out;/* UNUSED */
+ (void)out_len;/* UNUSED */
+}
+
+static void
+__hmac_sha1_cleanup(archive_hmac_sha1_ctx *ctx)
+{
+ (void)ctx;/* UNUSED */
+}
+
+#endif
+
+const struct archive_hmac __archive_hmac = {
+ &__hmac_sha1_init,
+ &__hmac_sha1_update,
+ &__hmac_sha1_final,
+ &__hmac_sha1_cleanup,
+};
diff --git a/Utilities/cmlibarchive/libarchive/archive_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
new file mode 100644
index 000000000..eb45c4ef2
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_hmac_private.h
@@ -0,0 +1,106 @@
+/*-
+* Copyright (c) 2014 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.
+*/
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_HMAC_PRIVATE_H_INCLUDED
+#define ARCHIVE_HMAC_PRIVATE_H_INCLUDED
+
+/*
+ * On systems that do not support any recognized crypto libraries,
+ * the archive_hmac.c file is expected to define no usable symbols.
+ *
+ * But some compilers and linkers choke on empty object files, so
+ * define a public symbol that will always exist. This could
+ * be removed someday if this file gains another always-present
+ * symbol definition.
+ */
+int __libarchive_hmac_build_hack(void);
+
+#ifdef __APPLE__
+# include <AvailabilityMacros.h>
+# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
+# define ARCHIVE_HMAC_USE_Apple_CommonCrypto
+# endif
+#endif
+
+#ifdef ARCHIVE_HMAC_USE_Apple_CommonCrypto
+#include <CommonCrypto/CommonHMAC.h>
+
+typedef CCHmacContext archive_hmac_sha1_ctx;
+
+#elif defined(_WIN32) && !defined(__CYGWIN__) && defined(HAVE_BCRYPT_H)
+#include <bcrypt.h>
+
+typedef struct {
+ BCRYPT_ALG_HANDLE hAlg;
+ BCRYPT_HASH_HANDLE hHash;
+ DWORD hash_len;
+ PBYTE hash;
+
+} archive_hmac_sha1_ctx;
+
+#elif defined(HAVE_LIBNETTLE) && defined(HAVE_NETTLE_HMAC_H)
+#include <nettle/hmac.h>
+
+typedef struct hmac_sha1_ctx archive_hmac_sha1_ctx;
+
+#elif defined(HAVE_LIBCRYPTO)
+#include "archive_openssl_hmac_private.h"
+
+typedef HMAC_CTX* archive_hmac_sha1_ctx;
+
+#else
+
+typedef int archive_hmac_sha1_ctx;
+
+#endif
+
+
+/* HMAC */
+#define archive_hmac_sha1_init(ctx, key, key_len)\
+ __archive_hmac.__hmac_sha1_init(ctx, key, key_len)
+#define archive_hmac_sha1_update(ctx, data, data_len)\
+ __archive_hmac.__hmac_sha1_update(ctx, data, data_len)
+#define archive_hmac_sha1_final(ctx, out, out_len)\
+ __archive_hmac.__hmac_sha1_final(ctx, out, out_len)
+#define archive_hmac_sha1_cleanup(ctx)\
+ __archive_hmac.__hmac_sha1_cleanup(ctx)
+
+
+struct archive_hmac {
+ /* HMAC */
+ int (*__hmac_sha1_init)(archive_hmac_sha1_ctx *, const uint8_t *,
+ size_t);
+ void (*__hmac_sha1_update)(archive_hmac_sha1_ctx *, const uint8_t *,
+ size_t);
+ void (*__hmac_sha1_final)(archive_hmac_sha1_ctx *, uint8_t *, size_t *);
+ void (*__hmac_sha1_cleanup)(archive_hmac_sha1_ctx *);
+};
+
+extern const struct archive_hmac __archive_hmac;
+#endif /* ARCHIVE_HMAC_PRIVATE_H_INCLUDED */
diff --git a/Utilities/cmlibarchive/libarchive/archive_match.c b/Utilities/cmlibarchive/libarchive/archive_match.c
index 6b6be9cb2..be72066ea 100644
--- a/Utilities/cmlibarchive/libarchive/archive_match.c
+++ b/Utilities/cmlibarchive/libarchive/archive_match.c
@@ -40,6 +40,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
#include "archive_entry.h"
+#include "archive_getdate.h"
#include "archive_pathmatch.h"
#include "archive_rb.h"
#include "archive_string.h"
@@ -184,7 +185,6 @@ static int time_excluded(struct archive_match *,
struct archive_entry *);
static int validate_time_flag(struct archive *, int, const char *);
-time_t __archive_get_date(time_t now, const char *);
#define get_date __archive_get_date
static const struct archive_rb_tree_ops rb_ops_mbs = {
@@ -471,7 +471,7 @@ archive_match_path_excluded(struct archive *_a,
}
/*
- * Utilty functions to get statistic information for inclusion patterns.
+ * Utility functions to get statistic information for inclusion patterns.
*/
int
archive_match_path_unmatched_inclusions(struct archive *_a)
@@ -580,6 +580,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
return (ARCHIVE_FATAL);
}
r = archive_read_support_format_raw(ar);
+ r = archive_read_support_format_empty(ar);
if (r != ARCHIVE_OK) {
archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
@@ -596,9 +597,13 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
}
r = archive_read_next_header(ar, &ae);
if (r != ARCHIVE_OK) {
- archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
- return (r);
+ if (r == ARCHIVE_EOF) {
+ return (ARCHIVE_OK);
+ } else {
+ archive_copy_error(&(a->archive), ar);
+ return (r);
+ }
}
archive_string_init(&as);
@@ -650,7 +655,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
}
}
- /* If something error happend, report it immediately. */
+ /* If an error occurred, report it immediately. */
if (r < ARCHIVE_OK) {
archive_copy_error(&(a->archive), ar);
archive_read_free(ar);
@@ -1152,7 +1157,7 @@ set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
{
/* NOTE: stat() on Windows cannot handle nano seconds. */
HANDLE h;
- WIN32_FIND_DATA d;
+ WIN32_FIND_DATAA d;
if (path == NULL || *path == '\0') {
archive_set_error(&(a->archive), EINVAL, "pathname is empty");
@@ -1265,7 +1270,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
#endif /* _WIN32 && !__CYGWIN__ */
/*
- * Call back funtions for archive_rb.
+ * Call back functions for archive_rb.
*/
static int
cmp_node_mbs(const struct archive_rb_node *n1,
@@ -1400,7 +1405,7 @@ add_entry(struct archive_match *a, int flag,
&(a->exclusion_tree), pathname);
/*
- * We always overwrite comparison condision.
+ * We always overwrite comparison condition.
* If you do not want to overwrite it, you should not
* call archive_match_exclude_entry(). We cannot know
* what behavior you really expect since overwriting
@@ -1476,7 +1481,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
if (nsec == a->older_ctime_nsec &&
(a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
== 0)
- return (1); /* Eeual, skip it. */
+ return (1); /* Equal, skip it. */
}
}
if (a->newer_mtime_filter) {
@@ -1508,7 +1513,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
}
}
- /* If there is no excluson list, include the file. */
+ /* If there is no exclusion list, include the file. */
if (a->exclusion_entry_list.count == 0)
return (0);
@@ -1695,7 +1700,7 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
break;
}
- /* Add oowner id. */
+ /* Add owner id. */
if (i == ids->count)
ids->ids[ids->count++] = id;
else if (ids->ids[i] != id) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
new file mode 100644
index 000000000..43a3ccc52
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
+#define ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
+
+#include <openssl/evp.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memset */
+static inline EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *)calloc(1, sizeof(EVP_MD_CTX));
+ return ctx;
+}
+
+static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ EVP_MD_CTX_cleanup(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+#endif
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
new file mode 100644
index 000000000..2deeb5f55
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
+#define ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
+
+#include <openssl/hmac.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memset */
+static inline HMAC_CTX *HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx = (HMAC_CTX *)calloc(1, sizeof(HMAC_CTX));
+ return ctx;
+}
+
+static inline void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ HMAC_CTX_cleanup(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+#endif
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_options.c b/Utilities/cmlibarchive/libarchive/archive_options.c
index 220ebd417..6496025a5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_options.c
+++ b/Utilities/cmlibarchive/libarchive/archive_options.c
@@ -26,6 +26,10 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
#include "archive_options_private.h"
static const char *
@@ -42,9 +46,9 @@ _archive_set_option(struct archive *a,
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
- mp = m != NULL && m[0] != '\0' ? m : NULL;
- op = o != NULL && o[0] != '\0' ? o : NULL;
- vp = v != NULL && v[0] != '\0' ? v : NULL;
+ mp = (m != NULL && m[0] != '\0') ? m : NULL;
+ op = (o != NULL && o[0] != '\0') ? o : NULL;
+ vp = (v != NULL && v[0] != '\0') ? v : NULL;
if (op == NULL && vp == NULL)
return (ARCHIVE_OK);
@@ -105,8 +109,11 @@ _archive_set_options(struct archive *a, const char *options,
if (options == NULL || options[0] == '\0')
return ARCHIVE_OK;
- data = (char *)malloc(strlen(options) + 1);
- strcpy(data, options);
+ if ((data = strdup(options)) == NULL) {
+ archive_set_error(a,
+ ENOMEM, "Out of memory adding file to list");
+ return (ARCHIVE_FATAL);
+ }
s = (const char *)data;
do {
diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.c b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
new file mode 100644
index 000000000..6b7b4726d
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.c
@@ -0,0 +1,329 @@
+/* $NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Originally from NetBSD's mknod(8) source. */
+
+#include "archive_platform.h"
+
+#if HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+#if !defined(lint)
+__RCSID("$NetBSD$");
+#endif /* not lint */
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive_pack_dev.h"
+
+static pack_t pack_netbsd;
+static pack_t pack_freebsd;
+static pack_t pack_8_8;
+static pack_t pack_12_20;
+static pack_t pack_14_18;
+static pack_t pack_8_24;
+static pack_t pack_bsdos;
+static int compare_format(const void *, const void *);
+
+static const char iMajorError[] = "invalid major number";
+static const char iMinorError[] = "invalid minor number";
+static const char tooManyFields[] = "too many fields for format";
+
+/* This is blatantly stolen from libarchive/archive_entry.c,
+ * in an attempt to get this to play nice on MinGW... */
+#if !defined(HAVE_MAJOR) && !defined(major)
+/* Replacement for major/minor/makedev. */
+#define major(x) ((int)(0x00ff & ((x) >> 8)))
+#define minor(x) ((int)(0xffff00ff & (x)))
+#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
+#endif
+
+/* Play games to come up with a suitable makedev() definition. */
+#ifdef __QNXNTO__
+/* QNX. <sigh> */
+#include <sys/netmgr.h>
+#define apd_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
+#elif defined makedev
+/* There's a "makedev" macro. */
+#define apd_makedev(maj, min) makedev((maj), (min))
+#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
+/* Windows. <sigh> */
+#define apd_makedev(maj, min) mkdev((maj), (min))
+#else
+/* There's a "makedev" function. */
+#define apd_makedev(maj, min) makedev((maj), (min))
+#endif
+
+/* exported */
+dev_t
+pack_native(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = apd_makedev(numbers[0], numbers[1]);
+ if ((unsigned long)major(dev) != numbers[0])
+ *error = iMajorError;
+ else if ((unsigned long)minor(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+static dev_t
+pack_netbsd(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_netbsd(numbers[0], numbers[1]);
+ if ((unsigned long)major_netbsd(dev) != numbers[0])
+ *error = iMajorError;
+ else if ((unsigned long)minor_netbsd(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))
+#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0xffff00ff)))
+
+static dev_t
+pack_freebsd(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_freebsd(numbers[0], numbers[1]);
+ if ((unsigned long)major_freebsd(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_freebsd(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0x000000ff)))
+
+static dev_t
+pack_8_8(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_8_8(numbers[0], numbers[1]);
+ if ((unsigned long)major_8_8(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_8_8(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))
+#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 0) & 0x000fffff)))
+
+static dev_t
+pack_12_20(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if ((unsigned long)major_12_20(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_12_20(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))
+#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))
+#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \
+ (((y) << 0) & 0x0003ffff)))
+
+static dev_t
+pack_14_18(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_14_18(numbers[0], numbers[1]);
+ if ((unsigned long)major_14_18(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_14_18(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))
+#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))
+#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \
+ (((y) << 0) & 0x00ffffff)))
+
+static dev_t
+pack_8_24(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_8_24(numbers[0], numbers[1]);
+ if ((unsigned long)major_8_24(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_8_24(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))
+#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 8) & 0x000fff00) | \
+ (((z) << 0) & 0x000000ff)))
+
+static dev_t
+pack_bsdos(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if ((unsigned long)major_12_20(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_12_20(dev) != numbers[1])
+ *error = iMinorError;
+ } else if (n == 3) {
+ dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
+ if ((unsigned long)major_12_12_8(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)unit_12_12_8(dev) != numbers[1])
+ *error = "invalid unit number";
+ if ((unsigned long)subunit_12_12_8(dev) != numbers[2])
+ *error = "invalid subunit number";
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+ /* list of formats and pack functions */
+ /* this list must be sorted lexically */
+static struct format {
+ const char *name;
+ pack_t *pack;
+} formats[] = {
+ {"386bsd", pack_8_8},
+ {"4bsd", pack_8_8},
+ {"bsdos", pack_bsdos},
+ {"freebsd", pack_freebsd},
+ {"hpux", pack_8_24},
+ {"isc", pack_8_8},
+ {"linux", pack_8_8},
+ {"native", pack_native},
+ {"netbsd", pack_netbsd},
+ {"osf1", pack_12_20},
+ {"sco", pack_8_8},
+ {"solaris", pack_14_18},
+ {"sunos", pack_8_8},
+ {"svr3", pack_8_8},
+ {"svr4", pack_14_18},
+ {"ultrix", pack_8_8},
+};
+
+static int
+compare_format(const void *key, const void *element)
+{
+ const char *name;
+ const struct format *format;
+
+ name = key;
+ format = element;
+
+ return (strcmp(name, format->name));
+}
+
+
+pack_t *
+pack_find(const char *name)
+{
+ struct format *format;
+
+ format = bsearch(name, formats,
+ sizeof(formats)/sizeof(formats[0]),
+ sizeof(formats[0]), compare_format);
+ if (format == 0)
+ return (NULL);
+ return (format->pack);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_pack_dev.h b/Utilities/cmlibarchive/libarchive/archive_pack_dev.h
new file mode 100644
index 000000000..749fd3d2c
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_pack_dev.h
@@ -0,0 +1,49 @@
+/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Originally from NetBSD's mknod(8) source. */
+
+#ifndef _PACK_DEV_H
+#define _PACK_DEV_H
+
+typedef dev_t pack_t(int, unsigned long [], const char **);
+
+pack_t *pack_find(const char *);
+pack_t pack_native;
+
+#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
+#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
+ (((x) & 0x000000ff) >> 0)))
+#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
+ (((y) << 12) & 0xfff00000) | \
+ (((y) << 0) & 0x000000ff)))
+
+#endif /* _PACK_DEV_H */
diff --git a/Utilities/cmlibarchive/libarchive/archive_pathmatch.c b/Utilities/cmlibarchive/libarchive/archive_pathmatch.c
index 505252a18..619e2b622 100644
--- a/Utilities/cmlibarchive/libarchive/archive_pathmatch.c
+++ b/Utilities/cmlibarchive/libarchive/archive_pathmatch.c
@@ -394,8 +394,8 @@ __archive_pathmatch(const char *p, const char *s, int flags)
if (*p == '/' && *s != '/')
return (0);
- /* Certain patterns and file names anchor implicitly. */
- if (*p == '*' || *p == '/' || *p == '/') {
+ /* Certain patterns anchor implicitly. */
+ if (*p == '*' || *p == '/') {
while (*p == '/')
++p;
while (*s == '/')
@@ -434,8 +434,8 @@ __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
if (*p == L'/' && *s != L'/')
return (0);
- /* Certain patterns and file names anchor implicitly. */
- if (*p == L'*' || *p == L'/' || *p == L'/') {
+ /* Certain patterns anchor implicitly. */
+ if (*p == L'*' || *p == L'/') {
while (*p == L'/')
++p;
while (*s == L'/')
diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h
index cdd9c7c86..47d144b05 100644
--- a/Utilities/cmlibarchive/libarchive/archive_platform.h
+++ b/Utilities/cmlibarchive/libarchive/archive_platform.h
@@ -66,15 +66,18 @@
* headers as required.
*/
-/* Get a real definition for __FBSDID if we can */
+/* Get a real definition for __FBSDID or __RCSID if we can */
#if HAVE_SYS_CDEFS_H
#include <sys/cdefs.h>
#endif
-/* If not, define it so as to avoid dangling semicolons. */
+/* If not, define them so as to avoid dangling semicolons. */
#ifndef __FBSDID
#define __FBSDID(a) struct _undefined_hack
#endif
+#ifndef __RCSID
+#define __RCSID(a) struct _undefined_hack
+#endif
/* Old glibc mbsnrtowcs fails assertions in our use case. */
#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
@@ -119,6 +122,12 @@
#if !HAVE_DECL_UINT32_MAX
#define UINT32_MAX (~(uint32_t)0)
#endif
+#if !HAVE_DECL_INT32_MAX
+#define INT32_MAX ((int32_t)(UINT32_MAX >> 1))
+#endif
+#if !HAVE_DECL_INT32_MIN
+#define INT32_MIN ((int32_t)(~INT32_MAX))
+#endif
#if !HAVE_DECL_UINT64_MAX
#define UINT64_MAX (~(uint64_t)0)
#endif
@@ -128,14 +137,40 @@
#if !HAVE_DECL_INT64_MIN
#define INT64_MIN ((int64_t)(~INT64_MAX))
#endif
+#if !HAVE_DECL_UINTMAX_MAX
+#define UINTMAX_MAX (~(uintmax_t)0)
+#endif
+#if !HAVE_DECL_INTMAX_MAX
+#define INTMAX_MAX ((intmax_t)(UINTMAX_MAX >> 1))
+#endif
+#if !HAVE_DECL_INTMAX_MIN
+#define INTMAX_MIN ((intmax_t)(~INTMAX_MAX))
+#endif
/*
* If this platform has <sys/acl.h>, acl_create(), acl_init(),
* acl_set_file(), and ACL_USER, we assume it has the rest of the
* POSIX.1e draft functions used in archive_read_extract.c.
*/
-#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER
+#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
+#if HAVE_ACL_USER
#define HAVE_POSIX_ACL 1
+#elif HAVE_ACL_TYPE_EXTENDED
+#define HAVE_DARWIN_ACL 1
+#endif
+#endif
+
+/*
+ * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
+ * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions
+ */
+#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T
+#define HAVE_SUN_ACL 1
+#endif
+
+/* Define if platform supports NFSv4 ACLs */
+#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+#define HAVE_NFS4_ACL 1
#endif
/*
@@ -146,6 +181,15 @@
#define CAN_RESTORE_METADATA_FD
#endif
+/*
+ * glibc 2.24 deprecates readdir_r
+ */
+#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24))
+#define USE_READDIR_R 1
+#else
+#undef USE_READDIR_R
+#endif
+
/* Set up defaults for internal error codes. */
#ifndef ARCHIVE_ERRNO_FILE_FORMAT
#if HAVE_EFTYPE
diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd7.c b/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
index fe0b0318c..1aed922db 100644
--- a/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
+++ b/Utilities/cmlibarchive/libarchive/archive_ppmd7.c
@@ -126,6 +126,11 @@ static Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
{
if (p->Base == 0 || p->Size != size)
{
+ /* RestartModel() below assumes that p->Size >= UNIT_SIZE
+ (see the calculation of m->MinContext). */
+ if (size < UNIT_SIZE) {
+ return False;
+ }
Ppmd7_Free(p, alloc);
p->AlignOffset =
#ifdef PPMD_32BIT
diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
index 3a6b9eb41..06c99e828 100644
--- a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h
@@ -19,7 +19,7 @@ If you need the compatibility with original PPMd var.H, you can use external Ran
#define PPMD7_MAX_ORDER 64
#define PPMD7_MIN_MEM_SIZE (1 << 11)
-#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3)
struct CPpmd7_Context_;
diff --git a/Utilities/cmlibarchive/libarchive/archive_private.h b/Utilities/cmlibarchive/libarchive/archive_private.h
index 30d472fcd..4b4be9796 100644
--- a/Utilities/cmlibarchive/libarchive/archive_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_private.h
@@ -119,6 +119,23 @@ struct archive {
unsigned current_codepage; /* Current ACP(ANSI CodePage). */
unsigned current_oemcp; /* Current OEMCP(OEM CodePage). */
struct archive_string_conv *sconv;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ int64_t read_data_offset;
+ int64_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /*
+ * Used by formats/filters to determine the amount of data
+ * requested from a call to archive_read_data(). This is only
+ * useful when the format/filter has seek support.
+ */
+ char read_data_is_posix_read;
+ size_t read_data_requested;
};
/* Check magic value and state; return(ARCHIVE_FATAL) if it isn't valid. */
@@ -139,6 +156,8 @@ int __archive_mktemp(const char *tmpdir);
int __archive_clean(struct archive *);
+void __archive_reset_read_data(struct archive *);
+
#define err_combine(a,b) ((a) < (b) ? (a) : (b))
#if defined(__BORLANDC__) || (defined(_MSC_VER) && _MSC_VER <= 1300)
diff --git a/Utilities/cmlibarchive/libarchive/archive_random.c b/Utilities/cmlibarchive/libarchive/archive_random.c
new file mode 100644
index 000000000..90ee7c626
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_random.c
@@ -0,0 +1,269 @@
+/*-
+ * Copyright (c) 2014 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_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+#ifdef HAVE_FCNTL
+#include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
+
+static void arc4random_buf(void *, size_t);
+
+#endif /* HAVE_ARC4RANDOM_BUF */
+
+#include "archive.h"
+#include "archive_random_private.h"
+
+#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
+#include <wincrypt.h>
+#endif
+
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#endif
+
+/*
+ * Random number generator function.
+ * This simply calls arc4random_buf function if the platform provides it.
+ */
+
+int
+archive_random(void *buf, size_t nbytes)
+{
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ HCRYPTPROV hProv;
+ BOOL success;
+
+ success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT);
+ if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) {
+ success = CryptAcquireContext(&hProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_NEWKEYSET);
+ }
+ if (success) {
+ success = CryptGenRandom(hProv, (DWORD)nbytes, (BYTE*)buf);
+ CryptReleaseContext(hProv, 0);
+ if (success)
+ return ARCHIVE_OK;
+ }
+ /* TODO: Does this case really happen? */
+ return ARCHIVE_FAILED;
+#else
+ arc4random_buf(buf, nbytes);
+ return ARCHIVE_OK;
+#endif
+}
+
+#if !defined(HAVE_ARC4RANDOM_BUF) && (!defined(_WIN32) || defined(__CYGWIN__))
+
+/* $OpenBSD: arc4random.c,v 1.24 2013/06/11 16:59:50 deraadt Exp $ */
+/*
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Arc4 random number generator for OpenBSD.
+ *
+ * This code is derived from section 17.1 of Applied Cryptography,
+ * second edition, which describes a stream cipher allegedly
+ * compatible with RSA Labs "RC4" cipher (the actual description of
+ * which is a trade secret). The same algorithm is used as a stream
+ * cipher called "arcfour" in Tatu Ylonen's ssh package.
+ *
+ * RC4 is a registered trademark of RSA Laboratories.
+ */
+
+#ifdef __GNUC__
+#define inline __inline
+#else /* !__GNUC__ */
+#define inline
+#endif /* !__GNUC__ */
+
+struct arc4_stream {
+ uint8_t i;
+ uint8_t j;
+ uint8_t s[256];
+};
+
+#define RANDOMDEV "/dev/urandom"
+#define KEYSIZE 128
+#ifdef HAVE_PTHREAD_H
+static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
+#define _ARC4_LOCK() pthread_mutex_lock(&arc4random_mtx);
+#define _ARC4_UNLOCK() pthread_mutex_unlock(&arc4random_mtx);
+#else
+#define _ARC4_LOCK()
+#define _ARC4_UNLOCK()
+#endif
+
+static int rs_initialized;
+static struct arc4_stream rs;
+static pid_t arc4_stir_pid;
+static int arc4_count;
+
+static inline uint8_t arc4_getbyte(void);
+static void arc4_stir(void);
+
+static inline void
+arc4_init(void)
+{
+ int n;
+
+ for (n = 0; n < 256; n++)
+ rs.s[n] = n;
+ rs.i = 0;
+ rs.j = 0;
+}
+
+static inline void
+arc4_addrandom(u_char *dat, int datlen)
+{
+ int n;
+ uint8_t si;
+
+ rs.i--;
+ for (n = 0; n < 256; n++) {
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si + dat[n % datlen]);
+ rs.s[rs.i] = rs.s[rs.j];
+ rs.s[rs.j] = si;
+ }
+ rs.j = rs.i;
+}
+
+static void
+arc4_stir(void)
+{
+ int done, fd, i;
+ struct {
+ struct timeval tv;
+ pid_t pid;
+ u_char rnd[KEYSIZE];
+ } rdat;
+
+ if (!rs_initialized) {
+ arc4_init();
+ rs_initialized = 1;
+ }
+ done = 0;
+ fd = open(RANDOMDEV, O_RDONLY | O_CLOEXEC, 0);
+ if (fd >= 0) {
+ if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
+ done = 1;
+ (void)close(fd);
+ }
+ if (!done) {
+ (void)gettimeofday(&rdat.tv, NULL);
+ rdat.pid = getpid();
+ /* We'll just take whatever was on the stack too... */
+ }
+
+ arc4_addrandom((u_char *)&rdat, KEYSIZE);
+
+ /*
+ * Discard early keystream, as per recommendations in:
+ * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
+ */
+ for (i = 0; i < 3072; i++)
+ (void)arc4_getbyte();
+ arc4_count = 1600000;
+}
+
+static void
+arc4_stir_if_needed(void)
+{
+ pid_t pid = getpid();
+
+ if (arc4_count <= 0 || !rs_initialized || arc4_stir_pid != pid) {
+ arc4_stir_pid = pid;
+ arc4_stir();
+ }
+}
+
+static inline uint8_t
+arc4_getbyte(void)
+{
+ uint8_t si, sj;
+
+ rs.i = (rs.i + 1);
+ si = rs.s[rs.i];
+ rs.j = (rs.j + si);
+ sj = rs.s[rs.j];
+ rs.s[rs.i] = sj;
+ rs.s[rs.j] = si;
+ return (rs.s[(si + sj) & 0xff]);
+}
+
+static void
+arc4random_buf(void *_buf, size_t n)
+{
+ u_char *buf = (u_char *)_buf;
+ _ARC4_LOCK();
+ arc4_stir_if_needed();
+ while (n--) {
+ if (--arc4_count <= 0)
+ arc4_stir();
+ buf[n] = arc4_getbyte();
+ }
+ _ARC4_UNLOCK();
+}
+
+#endif /* !HAVE_ARC4RANDOM_BUF */
diff --git a/Utilities/cmlibarchive/libarchive/archive_random_private.h b/Utilities/cmlibarchive/libarchive/archive_random_private.h
new file mode 100644
index 000000000..c414779f8
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_random_private.h
@@ -0,0 +1,36 @@
+/*-
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_RANDOM_PRIVATE_H_INCLUDED
+#define ARCHIVE_RANDOM_PRIVATE_H_INCLUDED
+
+/* Random number generator. */
+int archive_random(void *buf, size_t nbytes);
+
+#endif /* ARCHIVE_RANDOM_PRIVATE_H_INCLUDED */
diff --git a/Utilities/cmlibarchive/libarchive/archive_rb.c b/Utilities/cmlibarchive/libarchive/archive_rb.c
index 5b5da2034..cf58ac335 100644
--- a/Utilities/cmlibarchive/libarchive/archive_rb.c
+++ b/Utilities/cmlibarchive/libarchive/archive_rb.c
@@ -312,7 +312,7 @@ __archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt,
father = RB_FATHER(self);
if (RB_BLACK_P(father)) {
/*
- * If our greatgrandpa is black, we're done.
+ * If our great-grandpa is black, we're done.
*/
return;
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read.3 b/Utilities/cmlibarchive/libarchive/archive_read.3
index a29cc1ea6..d37e7327c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read.3
@@ -130,7 +130,7 @@ which provides a slightly more efficient interface.
You may prefer to use the higher-level
.Fn archive_read_data_skip ,
which reads and discards the data for this entry,
-.Fn archive_read_data_to_file ,
+.Fn archive_read_data_into_fd ,
which copies the data to the provided file descriptor, or
.Fn archive_read_extract ,
which recreates the specified entry on disk and copies data
@@ -186,7 +186,7 @@ list_archive(const char *name)
free(mydata);
}
-ssize_t
+la_ssize_t
myread(struct archive *a, void *client_data, const void **buff)
{
struct mydata *mydata = client_data;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read.c b/Utilities/cmlibarchive/libarchive/archive_read.c
index 796d37d06..d1fecebfd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read.c
@@ -57,6 +57,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
static int choose_filters(struct archive_read *);
static int choose_format(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);
@@ -101,16 +102,17 @@ archive_read_new(void)
{
struct archive_read *a;
- a = (struct archive_read *)malloc(sizeof(*a));
+ a = (struct archive_read *)calloc(1, 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();
+ a->passphrases.last = &a->passphrases.first;
+
return (&a->archive);
}
@@ -194,10 +196,12 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
ask = skip_limit;
get = (self->archive->client.skipper)
(&self->archive->archive, self->data, ask);
- if (get == 0)
+ total += get;
+ if (get == 0 || get == request)
return (total);
+ if (get > request)
+ return ARCHIVE_FATAL;
request -= get;
- total += get;
}
} else if (self->archive->client.seeker != NULL
&& request > 64 * 1024) {
@@ -230,8 +234,11 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
* other libarchive code that assumes a successful forward
* seek means it can also seek backwards.
*/
- if (self->archive->client.seeker == NULL)
+ if (self->archive->client.seeker == NULL) {
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "Current client reader does not support seeking a device");
return (ARCHIVE_FAILED);
+ }
return (self->archive->client.seeker)(&self->archive->archive,
self->data, offset, whence);
}
@@ -454,7 +461,7 @@ archive_read_open1(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter, *tmp;
- int slot, e;
+ int slot, e = ARCHIVE_OK;
unsigned int i;
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
@@ -522,7 +529,7 @@ archive_read_open1(struct archive *_a)
{
slot = choose_format(a);
if (slot < 0) {
- __archive_read_close_filters(a);
+ close_filters(a);
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
@@ -541,16 +548,20 @@ archive_read_open1(struct archive *_a)
* it wants to handle this stream. Repeat until we've finished
* building the pipeline.
*/
+
+/* We won't build a filter pipeline with more stages than this. */
+#define MAX_NUMBER_FILTERS 25
+
static int
choose_filters(struct archive_read *a)
{
- int number_bidders, i, bid, best_bid;
+ int number_bidders, i, bid, best_bid, number_filters;
struct archive_read_filter_bidder *bidder, *best_bidder;
struct archive_read_filter *filter;
ssize_t avail;
int r;
- for (;;) {
+ for (number_filters = 0; number_filters < MAX_NUMBER_FILTERS; ++number_filters) {
number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
best_bid = 0;
@@ -572,7 +583,6 @@ choose_filters(struct archive_read *a)
/* Verify the filter by asking it for some data. */
__archive_read_filter_ahead(a->filter, 1, &avail);
if (avail < 0) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
@@ -591,11 +601,13 @@ choose_filters(struct archive_read *a)
a->filter = filter;
r = (best_bidder->init)(a->filter);
if (r != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
}
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Input requires too many filters for decoding");
+ return (ARCHIVE_FATAL);
}
/*
@@ -658,16 +670,14 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
- a->read_data_output_offset = 0;
- a->read_data_remaining = 0;
- a->read_data_is_posix_read = 0;
- a->read_data_requested = 0;
+ __archive_reset_read_data(&a->archive);
+
a->data_start_node = a->client.cursor;
/* EOF always wins; otherwise return the worst error. */
return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
}
-int
+static int
_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
{
int ret;
@@ -747,6 +757,59 @@ archive_read_header_position(struct archive *_a)
}
/*
+ * Returns 1 if the archive contains at least one encrypted entry.
+ * If the archive format not support encryption at all
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED is returned.
+ * If for any other reason (e.g. not enough data read so far)
+ * we cannot say whether there are encrypted entries, then
+ * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned.
+ * In general, this function will return values below zero when the
+ * reader is uncertain or totally incapable of encryption support.
+ * When this function returns 0 you can be sure that the reader
+ * supports encryption detection but no encrypted entries have
+ * been found yet.
+ *
+ * NOTE: If the metadata/header of an archive is also encrypted, you
+ * cannot rely on the number of encrypted entries. That is why this
+ * function does not return the number of encrypted entries but#
+ * just shows that there are some.
+ */
+int
+archive_read_has_encrypted_entries(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ int format_supports_encryption = archive_read_format_capabilities(_a)
+ & (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+
+ if (!_a || !format_supports_encryption) {
+ /* Format in general doesn't support encryption */
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_UNSUPPORTED;
+ }
+
+ /* A reader potentially has read enough data now. */
+ if (a->format && a->format->has_encrypted_entries) {
+ return (a->format->has_encrypted_entries)(a);
+ }
+
+ /* For any other reason we cannot say how many entries are there. */
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+}
+
+/*
+ * Returns a bitmask of capabilities that are supported by the archive format reader.
+ * If the reader has no special capabilities, ARCHIVE_READ_FORMAT_CAPS_NONE is returned.
+ */
+int
+archive_read_format_capabilities(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ if (a && a->format && a->format->format_capabilties) {
+ return (a->format->format_capabilties)(a);
+ }
+ return ARCHIVE_READ_FORMAT_CAPS_NONE;
+}
+
+/*
* 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
@@ -760,7 +823,7 @@ archive_read_header_position(struct archive *_a)
ssize_t
archive_read_data(struct archive *_a, void *buff, size_t s)
{
- struct archive_read *a = (struct archive_read *)_a;
+ struct archive *a = (struct archive *)_a;
char *dest;
const void *read_buf;
size_t bytes_read;
@@ -775,7 +838,7 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
read_buf = a->read_data_block;
a->read_data_is_posix_read = 1;
a->read_data_requested = s;
- r = _archive_read_data_block(&a->archive, &read_buf,
+ r = archive_read_data_block(a, &read_buf,
&a->read_data_remaining, &a->read_data_offset);
a->read_data_block = read_buf;
if (r == ARCHIVE_EOF)
@@ -790,7 +853,7 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
}
if (a->read_data_offset < a->read_data_output_offset) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
"Encountered out-of-order sparse blocks");
return (ARCHIVE_RETRY);
}
@@ -834,6 +897,21 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
}
/*
+ * Reset the read_data_* variables, used for starting a new entry.
+ */
+void __archive_reset_read_data(struct archive * a)
+{
+ a->read_data_output_offset = 0;
+ a->read_data_remaining = 0;
+ a->read_data_is_posix_read = 0;
+ a->read_data_requested = 0;
+
+ /* extra resets, from rar.c */
+ a->read_data_block = NULL;
+ a->read_data_offset = 0;
+}
+
+/*
* Skip over all remaining data in this entry.
*/
int
@@ -900,15 +978,15 @@ _archive_read_data_block(struct archive *_a,
if (a->format->read_data == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
- "No format_read_data_block function registered");
+ "No format->read_data function registered");
return (ARCHIVE_FATAL);
}
return (a->format->read_data)(a, buff, size, offset);
}
-int
-__archive_read_close_filters(struct archive_read *a)
+static int
+close_filters(struct archive_read *a)
{
struct archive_read_filter *f = a->filter;
int r = ARCHIVE_OK;
@@ -931,6 +1009,9 @@ __archive_read_close_filters(struct archive_read *a)
void
__archive_read_free_filters(struct archive_read *a)
{
+ /* Make sure filters are closed and their buffers are freed */
+ close_filters(a);
+
while (a->filter != NULL) {
struct archive_read_filter *t = a->filter->upstream;
free(a->filter);
@@ -973,7 +1054,7 @@ _archive_read_close(struct archive *_a)
/* TODO: Clean up the formatters. */
/* Release the filter objects. */
- r1 = __archive_read_close_filters(a);
+ r1 = close_filters(a);
if (r1 < r)
r = r1;
@@ -987,6 +1068,7 @@ static int
_archive_read_free(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_passphrase *p;
int i, n;
int slots;
int r = ARCHIVE_OK;
@@ -1024,9 +1106,20 @@ _archive_read_free(struct archive *_a)
}
}
+ /* Release passphrase list. */
+ p = a->passphrases.first;
+ while (p != NULL) {
+ struct archive_read_passphrase *np = p->next;
+
+ /* A passphrase should be cleaned. */
+ memset(p->passphrase, 0, strlen(p->passphrase));
+ free(p->passphrase);
+ free(p);
+ p = np;
+ }
+
archive_string_free(&a->archive.error_string);
- if (a->entry)
- archive_entry_free(a->entry);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a->client.dataset);
@@ -1094,7 +1187,9 @@ __archive_read_register_format(struct archive_read *a,
int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
int (*read_data_skip)(struct archive_read *),
int64_t (*seek_data)(struct archive_read *, int64_t, int),
- int (*cleanup)(struct archive_read *))
+ int (*cleanup)(struct archive_read *),
+ int (*format_capabilities)(struct archive_read *),
+ int (*has_encrypted_entries)(struct archive_read *))
{
int i, number_slots;
@@ -1117,6 +1212,8 @@ __archive_read_register_format(struct archive_read *a,
a->formats[i].cleanup = cleanup;
a->formats[i].data = format_data;
a->formats[i].name = name;
+ a->formats[i].format_capabilties = format_capabilities;
+ a->formats[i].has_encrypted_entries = has_encrypted_entries;
return (ARCHIVE_OK);
}
}
@@ -1394,6 +1491,8 @@ __archive_read_filter_consume(struct archive_read_filter * filter,
{
int64_t skipped;
+ if (request < 0)
+ return ARCHIVE_FATAL;
if (request == 0)
return 0;
@@ -1557,10 +1656,9 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
client->dataset[++cursor].begin_position = r;
}
offset -= client->dataset[cursor].begin_position;
- if (offset < 0)
- offset = 0;
- else if (offset > client->dataset[cursor].total_size - 1)
- offset = client->dataset[cursor].total_size - 1;
+ if (offset < 0
+ || offset > client->dataset[cursor].total_size)
+ return ARCHIVE_FATAL;
if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
return r;
break;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.3 b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.3
new file mode 100644
index 000000000..8b242ea79
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 2014 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 AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 14, 2014
+.Dt ARCHIVE_READ_ADD_PASSPHRASE 3
+.Os
+.Sh NAME
+.Nm archive_read_add_passphrase ,
+.Nm archive_read_set_passphrase_callback
+.Nd functions for reading encrypted archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_read_add_passphrase
+.Fa "struct archive *"
+.Fa "const char *passphrase"
+.Fc
+.Ft int
+.Fo archive_read_set_passphrase_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_passphrase_callback *"
+.Fc
+.Sh DESCRIPTION
+.Bl -tag -width indent
+.It Fn archive_read_add_passphrase
+Register passphrases for reading an encryption archive.
+If
+.Ar passphrase
+is
+.Dv NULL
+or empty, this function will do nothing and
+.Cm ARCHIVE_FAILED
+will be returned.
+Otherwise,
+.Cm ARCHIVE_OK
+will be returned.
+.It Fn archive_read_set_passphrase_callback
+Register callback function that will be invoked to get a passphrase
+for decrption after trying all passphrases registered by the
+.Fn archive_read_add_passphrase
+function failed.
+.El
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_set_options 3
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c
new file mode 100644
index 000000000..cf821b5d4
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c
@@ -0,0 +1,186 @@
+/*-
+ * Copyright (c) 2014 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 "archive_read_private.h"
+
+static void
+add_passphrase_to_tail(struct archive_read *a,
+ struct archive_read_passphrase *p)
+{
+ *a->passphrases.last = p;
+ a->passphrases.last = &p->next;
+ p->next = NULL;
+}
+
+static struct archive_read_passphrase *
+remove_passphrases_from_head(struct archive_read *a)
+{
+ struct archive_read_passphrase *p;
+
+ p = a->passphrases.first;
+ if (p != NULL)
+ a->passphrases.first = p->next;
+ return (p);
+}
+
+static void
+insert_passphrase_to_head(struct archive_read *a,
+ struct archive_read_passphrase *p)
+{
+ p->next = a->passphrases.first;
+ a->passphrases.first = p;
+}
+
+static struct archive_read_passphrase *
+new_read_passphrase(struct archive_read *a, const char *passphrase)
+{
+ struct archive_read_passphrase *p;
+
+ p = malloc(sizeof(*p));
+ if (p == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ return (NULL);
+ }
+ p->passphrase = strdup(passphrase);
+ if (p->passphrase == NULL) {
+ free(p);
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ return (NULL);
+ }
+ return (p);
+}
+
+int
+archive_read_add_passphrase(struct archive *_a, const char *passphrase)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_passphrase *p;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_read_add_passphrase");
+
+ if (passphrase == NULL || passphrase[0] == '\0') {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Empty passphrase is unacceptable");
+ return (ARCHIVE_FAILED);
+ }
+
+ p = new_read_passphrase(a, passphrase);
+ if (p == NULL)
+ return (ARCHIVE_FATAL);
+ add_passphrase_to_tail(a, p);
+
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_set_passphrase_callback(struct archive *_a, void *client_data,
+ archive_passphrase_callback *cb)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_read_set_passphrase_callback");
+
+ a->passphrases.callback = cb;
+ a->passphrases.client_data = client_data;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Call this in advance when you start to get a passphrase for decryption
+ * for a entry.
+ */
+void
+__archive_read_reset_passphrase(struct archive_read *a)
+{
+
+ a->passphrases.candidate = -1;
+}
+
+/*
+ * Get a passphrase for decryption.
+ */
+const char *
+__archive_read_next_passphrase(struct archive_read *a)
+{
+ struct archive_read_passphrase *p;
+ const char *passphrase;
+
+ if (a->passphrases.candidate < 0) {
+ /* Count out how many passphrases we have. */
+ int cnt = 0;
+
+ for (p = a->passphrases.first; p != NULL; p = p->next)
+ cnt++;
+ a->passphrases.candidate = cnt;
+ p = a->passphrases.first;
+ } else if (a->passphrases.candidate > 1) {
+ /* Rotate a passphrase list. */
+ a->passphrases.candidate--;
+ p = remove_passphrases_from_head(a);
+ add_passphrase_to_tail(a, p);
+ /* Pick a new passphrase candidate up. */
+ p = a->passphrases.first;
+ } else if (a->passphrases.candidate == 1) {
+ /* This case is that all candidates failed to decrypt. */
+ a->passphrases.candidate = 0;
+ if (a->passphrases.first->next != NULL) {
+ /* Rotate a passphrase list. */
+ p = remove_passphrases_from_head(a);
+ add_passphrase_to_tail(a, p);
+ }
+ p = NULL;
+ } else /* There is no passphrase candidate. */
+ p = NULL;
+
+ if (p != NULL)
+ passphrase = p->passphrase;
+ else if (a->passphrases.callback != NULL) {
+ /* Get a passphrase through a call-back function
+ * since we tried all passphrases out or we don't
+ * have it. */
+ passphrase = a->passphrases.callback(&a->archive,
+ a->passphrases.client_data);
+ if (passphrase != NULL) {
+ p = new_read_passphrase(a, passphrase);
+ if (p == NULL)
+ return (NULL);
+ insert_passphrase_to_head(a, p);
+ a->passphrases.candidate = 1;
+ }
+ } else
+ passphrase = NULL;
+
+ return (passphrase);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
index 017d7c68a..5e4d16307 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c
@@ -43,7 +43,7 @@ archive_read_append_filter(struct archive *_a, int code)
struct archive_read_filter *filter;
struct archive_read *a = (struct archive_read *)_a;
- r1 = r2 = (ARCHIVE_OK);
+ r2 = (ARCHIVE_OK);
switch (code)
{
case ARCHIVE_FILTER_NONE:
@@ -85,6 +85,10 @@ archive_read_append_filter(struct archive *_a, int code)
strcpy(str, "rpm");
r1 = archive_read_support_filter_rpm(_a);
break;
+ case ARCHIVE_FILTER_LZ4:
+ strcpy(str, "lz4");
+ r1 = archive_read_support_filter_lz4(_a);
+ break;
case ARCHIVE_FILTER_LZIP:
strcpy(str, "lzip");
r1 = archive_read_support_filter_lzip(_a);
@@ -129,7 +133,6 @@ archive_read_append_filter(struct archive *_a, int code)
a->filter = filter;
r2 = (bidder->init)(a->filter);
if (r2 != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
@@ -187,7 +190,6 @@ archive_read_append_filter_program_signature(struct archive *_a,
a->filter = filter;
r = (bidder->init)(a->filter);
if (r != ARCHIVE_OK) {
- __archive_read_close_filters(a);
__archive_read_free_filters(a);
return (ARCHIVE_FATAL);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_data.3 b/Utilities/cmlibarchive/libarchive/archive_read_data.3
index bf0578ce3..c1bc15d7c 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_data.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_data.3
@@ -37,7 +37,7 @@
Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
-.Ft ssize_t
+.Ft la_ssize_t
.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
.Ft int
.Fo archive_read_data_block
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk.3 b/Utilities/cmlibarchive/libarchive/archive_read_disk.3
index 525dc59cb..2a5c1305e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 2, 2012
+.Dd December 30, 2016
.Dt ARCHIVE_READ_DISK 3
.Os
.Sh NAME
@@ -54,9 +54,9 @@ Streaming Archive Library (libarchive, -larchive)
.Fn archive_read_disk_set_symlink_physical "struct archive *"
.Ft int
.Fn archive_read_disk_set_symlink_hybrid "struct archive *"
-.Ft int
+.Ft const char *
.Fn archive_read_disk_gname "struct archive *" "gid_t"
-.Ft int
+.Ft const char *
.Fn archive_read_disk_uname "struct archive *" "uid_t"
.Ft int
.Fo archive_read_disk_set_gname_lookup
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
index e984aaadb..b2f1d17d9 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2009 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -37,6 +38,11 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#ifdef HAVE_SYS_ACL_H
#include <sys/acl.h>
#endif
+#ifdef HAVE_DARWIN_ACL
+#include <membership.h>
+#include <grp.h>
+#include <pwd.h>
+#endif
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif
@@ -117,6 +123,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#define ACL_GET_PERM acl_get_perm_np
#endif
+/* NFSv4 platform ACL type */
+#if HAVE_SUN_ACL
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T
+#elif HAVE_DARWIN_ACL
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+#elif HAVE_ACL_TYPE_NFS4
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4
+#endif
+
static int setup_acls(struct archive_read_disk *,
struct archive_entry *, int *fd);
static int setup_mac_metadata(struct archive_read_disk *,
@@ -125,6 +140,10 @@ static int setup_xattrs(struct archive_read_disk *,
struct archive_entry *, int *fd);
static int setup_sparse(struct archive_read_disk *,
struct archive_entry *, int *fd);
+#if defined(HAVE_LINUX_FIEMAP_H)
+static int setup_sparse_fiemap(struct archive_read_disk *,
+ struct archive_entry *, int *fd);
+#endif
int
archive_read_disk_entry_from_file(struct archive *_a,
@@ -184,15 +203,17 @@ archive_read_disk_entry_from_file(struct archive *_a,
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
/* On FreeBSD, we get flags for free with the stat. */
/* TODO: Does this belong in copy_stat()? */
- if (st->st_flags != 0)
+ if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
archive_entry_set_fflags(entry, st->st_flags, 0);
#endif
-#if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
/* Linux requires an extra ioctl to pull the flags. Although
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
- if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
+ if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
+ (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
if (fd < 0) {
if (a->tree != NULL)
fd = a->open_on_current_dir(a->tree, path,
@@ -204,7 +225,13 @@ archive_read_disk_entry_from_file(struct archive *_a,
}
if (fd >= 0) {
int stflags;
- r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+ r = ioctl(fd,
+#if defined(FS_IOC_GETFLAGS)
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
+ &stflags);
if (r == 0 && stflags != 0)
archive_entry_set_fflags(entry, stflags, 0);
}
@@ -250,11 +277,15 @@ archive_read_disk_entry_from_file(struct archive *_a,
}
#endif /* HAVE_READLINK || HAVE_READLINKAT */
- r = setup_acls(a, entry, &fd);
- r1 = setup_xattrs(a, entry, &fd);
- if (r1 < r)
- r = r1;
- if (a->enable_copyfile) {
+ r = 0;
+ if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
+ r = setup_acls(a, entry, &fd);
+ if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
+ r1 = setup_xattrs(a, entry, &fd);
+ if (r1 < r)
+ r = r1;
+ }
+ if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
r1 = setup_mac_metadata(a, entry, &fd);
if (r1 < r)
r = r1;
@@ -300,20 +331,17 @@ setup_mac_metadata(struct archive_read_disk *a,
name = archive_entry_sourcepath(entry);
if (name == NULL)
name = archive_entry_pathname(entry);
+ else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't change dir to read extended attributes");
+ return (ARCHIVE_FAILED);
+ }
if (name == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Can't open file to read extended attributes: No name");
return (ARCHIVE_WARN);
}
- if (a->tree != NULL) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't change dir");
- return (ARCHIVE_FAILED);
- }
- }
-
/* Short-circuit if there's nothing to do. */
have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
if (have_attrs == -1) {
@@ -398,33 +426,87 @@ setup_mac_metadata(struct archive_read_disk *a,
}
#endif
+#if HAVE_DARWIN_ACL
+static int translate_guid(struct archive *, acl_entry_t,
+ int *, int *, const char **);
+
+static void add_trivial_nfs4_acl(struct archive_entry *);
+#endif
+
+#if HAVE_SUN_ACL
+static int
+sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
+#endif
-#if defined(HAVE_POSIX_ACL) && defined(ACL_TYPE_NFS4)
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
static int translate_acl(struct archive_read_disk *a,
- struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
+ struct archive_entry *entry,
+#if HAVE_SUN_ACL
+ acl_t *acl,
+#else
+ acl_t acl,
+#endif
+ int archive_entry_acl_type);
static int
setup_acls(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
const char *accpath;
- acl_t acl;
-#if HAVE_ACL_IS_TRIVIAL_NP
- int r;
+#if HAVE_SUN_ACL
+ acl_t *acl;
+#else
+ acl_t acl;
#endif
+ int r;
+
+ accpath = NULL;
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
+#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
+ if (*fd < 0)
+#else
+ /* For default ACLs on Linux we need reachable accpath */
+ if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
+#endif
+ {
+ accpath = archive_entry_sourcepath(entry);
+ if (accpath == NULL || (a->tree != NULL &&
+ a->tree_enter_working_dir(a->tree) != 0))
+ accpath = archive_entry_pathname(entry);
+ if (accpath == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Couldn't determine file path to read ACLs");
+ return (ARCHIVE_WARN);
+ }
+ if (a->tree != NULL &&
+#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
+ *fd < 0 &&
+#endif
+ (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)) {
+ *fd = a->open_on_current_dir(a->tree,
+ accpath, O_RDONLY | O_NONBLOCK);
+ }
+ }
archive_entry_acl_clear(entry);
- /* Try NFS4 ACL first. */
+ acl = NULL;
+
+#if HAVE_NFS4_ACL
+ /* Try NFSv4 ACL first. */
if (*fd >= 0)
+#if HAVE_SUN_ACL
+ /* Solaris reads both POSIX.1e and NFSv4 ACL here */
+ facl_get(*fd, 0, &acl);
+#elif HAVE_ACL_GET_FD_NP
+ acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
+#else
acl = acl_get_fd(*fd);
+#endif
#if HAVE_ACL_GET_LINK_NP
else if (!a->follow_symlinks)
- acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
+ acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
#else
else if ((!a->follow_symlinks)
&& (archive_entry_filetype(entry) == AE_IFLNK))
@@ -433,20 +515,62 @@ setup_acls(struct archive_read_disk *a,
acl = NULL;
#endif
else
- acl = acl_get_file(accpath, ACL_TYPE_NFS4);
-#if HAVE_ACL_IS_TRIVIAL_NP
+#if HAVE_SUN_ACL
+ /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
+ acl_get(accpath, 0, &acl);
+#else
+ acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
+#endif
+
+
+#if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL
/* Ignore "trivial" ACLs that just mirror the file mode. */
- acl_is_trivial_np(acl, &r);
- if (r) {
- acl_free(acl);
- acl = NULL;
- }
+ if (acl != NULL) {
+#if HAVE_SUN_ACL
+ if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
+ &r) == 0 && r == 1)
+#elif HAVE_ACL_IS_TRIVIAL_NP
+ if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
#endif
+ {
+ acl_free(acl);
+ acl = NULL;
+ /*
+ * Simultaneous NFSv4 and POSIX.1e ACLs for the same
+ * entry are not allowed, so we should return here
+ */
+ return (ARCHIVE_OK);
+ }
+ }
+#endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
if (acl != NULL) {
- translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
acl_free(acl);
- return (ARCHIVE_OK);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't translate "
+#if !HAVE_SUN_ACL
+ "NFSv4 "
+#endif
+ "ACLs");
+ }
+#if HAVE_DARWIN_ACL
+ /*
+ * Because Mac OS doesn't support owner@, group@ and everyone@
+ * ACLs we need to add NFSv4 ACLs mirroring the file mode to
+ * the archive entry. Otherwise extraction on non-Mac platforms
+ * would lead to an invalid file mode.
+ */
+ if ((archive_entry_acl_types(entry) &
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
+ add_trivial_nfs4_acl(entry);
+#endif
+ return (r);
}
+#endif /* HAVE_NFS4_ACL */
+
+#if HAVE_POSIX_ACL
+ /* This code path is skipped on MacOS and Solaris */
/* Retrieve access ACL from file. */
if (*fd >= 0)
@@ -463,81 +587,609 @@ setup_acls(struct archive_read_disk *a,
#endif
else
acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
+
+#if HAVE_ACL_IS_TRIVIAL_NP
+ /* Ignore "trivial" ACLs that just mirror the file mode. */
+ if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
+ if (r) {
+ acl_free(acl);
+ acl = NULL;
+ }
+ }
+#endif
+
if (acl != NULL) {
- translate_acl(a, entry, acl,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
acl_free(acl);
+ acl = NULL;
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't translate access ACLs");
+ return (r);
+ }
}
/* Only directories can have default ACLs. */
if (S_ISDIR(archive_entry_mode(entry))) {
+#if HAVE_ACL_GET_FD_NP
+ if (*fd >= 0)
+ acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
+ else
+#endif
acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
if (acl != NULL) {
- translate_acl(a, entry, acl,
+ r = translate_acl(a, entry, acl,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
acl_free(acl);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't translate default ACLs");
+ return (r);
+ }
}
}
+#endif /* HAVE_POSIX_ACL */
return (ARCHIVE_OK);
}
/*
- * Translate system ACL into libarchive internal structure.
+ * Translate system ACL permissions into libarchive internal structure
*/
-
-static struct {
- int archive_perm;
- int platform_perm;
+static const struct {
+ const int archive_perm;
+ const int platform_perm;
} acl_perm_map[] = {
- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
- {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
- {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
+#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#else /* POSIX.1e ACL permissions */
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+ {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#endif
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
};
-static struct {
- int archive_inherit;
- int platform_inherit;
+#if HAVE_NFS4_ACL
+/*
+ * Translate system NFSv4 inheritance flags into libarchive internal structure
+ */
+static const struct {
+ const int archive_inherit;
+ const int platform_inherit;
} acl_inherit_map[] = {
- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+#if HAVE_SUN_ACL /* Solaris ACL inheritance flags */
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
+#else /* FreeBSD NFSv4 ACL inheritance flags */
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
+ {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
};
+#endif /* HAVE_NFS4_ACL */
+
+#if HAVE_DARWIN_ACL
+static int translate_guid(struct archive *a, acl_entry_t acl_entry,
+ int *ae_id, int *ae_tag, const char **ae_name)
+{
+ void *q;
+ uid_t ugid;
+ int r, idtype;
+ struct passwd *pwd;
+ struct group *grp;
+
+ q = acl_get_qualifier(acl_entry);
+ if (q == NULL)
+ return (1);
+ r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
+ if (r != 0) {
+ acl_free(q);
+ return (1);
+ }
+ if (idtype == ID_TYPE_UID) {
+ *ae_tag = ARCHIVE_ENTRY_ACL_USER;
+ pwd = getpwuuid(q);
+ if (pwd == NULL) {
+ *ae_id = ugid;
+ *ae_name = NULL;
+ } else {
+ *ae_id = pwd->pw_uid;
+ *ae_name = archive_read_disk_uname(a, *ae_id);
+ }
+ } else if (idtype == ID_TYPE_GID) {
+ *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+ grp = getgruuid(q);
+ if (grp == NULL) {
+ *ae_id = ugid;
+ *ae_name = NULL;
+ } else {
+ *ae_id = grp->gr_gid;
+ *ae_name = archive_read_disk_gname(a, *ae_id);
+ }
+ } else
+ r = 1;
+
+ acl_free(q);
+ return (r);
+}
+
+/*
+ * Add trivial NFSv4 ACL entries from mode
+ */
+static void
+add_trivial_nfs4_acl(struct archive_entry *entry)
+{
+ mode_t mode;
+ int i;
+ const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
+ const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
+ const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+ ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_WRITE_ACL |
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+
+ struct {
+ const int type;
+ const int tag;
+ int permset;
+ } tacl_entry[] = {
+ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
+ {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
+ {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
+ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
+ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
+ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
+ };
+
+ mode = archive_entry_mode(entry);
+
+ /* Permissions for everyone@ */
+ if (mode & 0004)
+ tacl_entry[5].permset |= rperm;
+ if (mode & 0002)
+ tacl_entry[5].permset |= wperm;
+ if (mode & 0001)
+ tacl_entry[5].permset |= eperm;
+
+ /* Permissions for group@ */
+ if (mode & 0040)
+ tacl_entry[4].permset |= rperm;
+ else if (mode & 0004)
+ tacl_entry[2].permset |= rperm;
+ if (mode & 0020)
+ tacl_entry[4].permset |= wperm;
+ else if (mode & 0002)
+ tacl_entry[2].permset |= wperm;
+ if (mode & 0010)
+ tacl_entry[4].permset |= eperm;
+ else if (mode & 0001)
+ tacl_entry[2].permset |= eperm;
+
+ /* Permissions for owner@ */
+ if (mode & 0400) {
+ tacl_entry[3].permset |= rperm;
+ if (!(mode & 0040) && (mode & 0004))
+ tacl_entry[0].permset |= rperm;
+ } else if ((mode & 0040) || (mode & 0004))
+ tacl_entry[1].permset |= rperm;
+ if (mode & 0200) {
+ tacl_entry[3].permset |= wperm;
+ if (!(mode & 0020) && (mode & 0002))
+ tacl_entry[0].permset |= wperm;
+ } else if ((mode & 0020) || (mode & 0002))
+ tacl_entry[1].permset |= wperm;
+ if (mode & 0100) {
+ tacl_entry[3].permset |= eperm;
+ if (!(mode & 0010) && (mode & 0001))
+ tacl_entry[0].permset |= eperm;
+ } else if ((mode & 0010) || (mode & 0001))
+ tacl_entry[1].permset |= eperm;
+
+ for (i = 0; i < 6; i++) {
+ if (tacl_entry[i].permset != 0) {
+ archive_entry_acl_add_entry(entry,
+ tacl_entry[i].type, tacl_entry[i].permset,
+ tacl_entry[i].tag, -1, NULL);
+ }
+ }
+
+ return;
+}
+#elif HAVE_SUN_ACL
+/*
+ * Check if acl is trivial
+ * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
+ */
+static int
+sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
+{
+ int i, p;
+ const uint32_t rperm = ACE_READ_DATA;
+ const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
+ const uint32_t eperm = ACE_EXECUTE;
+ const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
+ ACE_READ_ACL | ACE_SYNCHRONIZE;
+ const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
+ ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
+
+ ace_t *ace;
+ ace_t tace[6];
+
+ if (acl == NULL || trivialp == NULL)
+ return (-1);
+
+ *trivialp = 0;
+
+ /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
+ if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
+ return (0);
+
+ /*
+ * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
+ * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
+ * including mask.
+ */
+ if (acl->acl_type == ACLENT_T) {
+ if (acl->acl_cnt == 4)
+ *trivialp = 1;
+ return (0);
+ }
+ if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
+ return (-1);
+
+ /*
+ * Continue with checking NFSv4 ACLs
+ *
+ * Create list of trivial ace's to be compared
+ */
+
+ /* owner@ allow pre */
+ tace[0].a_flags = ACE_OWNER;
+ tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ tace[0].a_access_mask = 0;
+
+ /* owner@ deny */
+ tace[1].a_flags = ACE_OWNER;
+ tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+ tace[1].a_access_mask = 0;
+
+ /* group@ deny */
+ tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
+ tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+ tace[2].a_access_mask = 0;
+
+ /* owner@ allow */
+ tace[3].a_flags = ACE_OWNER;
+ tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ tace[3].a_access_mask = ownset;
+
+ /* group@ allow */
+ tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
+ tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ tace[4].a_access_mask = pubset;
+
+ /* everyone@ allow */
+ tace[5].a_flags = ACE_EVERYONE;
+ tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ tace[5].a_access_mask = pubset;
+
+ /* Permissions for everyone@ */
+ if (mode & 0004)
+ tace[5].a_access_mask |= rperm;
+ if (mode & 0002)
+ tace[5].a_access_mask |= wperm;
+ if (mode & 0001)
+ tace[5].a_access_mask |= eperm;
+
+ /* Permissions for group@ */
+ if (mode & 0040)
+ tace[4].a_access_mask |= rperm;
+ else if (mode & 0004)
+ tace[2].a_access_mask |= rperm;
+ if (mode & 0020)
+ tace[4].a_access_mask |= wperm;
+ else if (mode & 0002)
+ tace[2].a_access_mask |= wperm;
+ if (mode & 0010)
+ tace[4].a_access_mask |= eperm;
+ else if (mode & 0001)
+ tace[2].a_access_mask |= eperm;
+
+ /* Permissions for owner@ */
+ if (mode & 0400) {
+ tace[3].a_access_mask |= rperm;
+ if (!(mode & 0040) && (mode & 0004))
+ tace[0].a_access_mask |= rperm;
+ } else if ((mode & 0040) || (mode & 0004))
+ tace[1].a_access_mask |= rperm;
+ if (mode & 0200) {
+ tace[3].a_access_mask |= wperm;
+ if (!(mode & 0020) && (mode & 0002))
+ tace[0].a_access_mask |= wperm;
+ } else if ((mode & 0020) || (mode & 0002))
+ tace[1].a_access_mask |= wperm;
+ if (mode & 0100) {
+ tace[3].a_access_mask |= eperm;
+ if (!(mode & 0010) && (mode & 0001))
+ tace[0].a_access_mask |= eperm;
+ } else if ((mode & 0010) || (mode & 0001))
+ tace[1].a_access_mask |= eperm;
+
+ /* Check if the acl count matches */
+ p = 3;
+ for (i = 0; i < 3; i++) {
+ if (tace[i].a_access_mask != 0)
+ p++;
+ }
+ if (acl->acl_cnt != p)
+ return (0);
+
+ p = 0;
+ for (i = 0; i < 6; i++) {
+ if (tace[i].a_access_mask != 0) {
+ ace = &((ace_t *)acl->acl_aclp)[p];
+ /*
+ * Illumos added ACE_DELETE_CHILD to write perms for
+ * directories. We have to check against that, too.
+ */
+ if (ace->a_flags != tace[i].a_flags ||
+ ace->a_type != tace[i].a_type ||
+ (ace->a_access_mask != tace[i].a_access_mask &&
+ ((acl->acl_flags & ACL_IS_DIR) == 0 ||
+ (tace[i].a_access_mask & wperm) == 0 ||
+ ace->a_access_mask !=
+ (tace[i].a_access_mask | ACE_DELETE_CHILD))))
+ return (0);
+ p++;
+ }
+ }
+
+ *trivialp = 1;
+ return (0);
+}
+#endif /* HAVE_SUN_ACL */
+
+#if HAVE_SUN_ACL
+/*
+ * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
+ */
+static int
+translate_acl(struct archive_read_disk *a,
+ struct archive_entry *entry, acl_t *acl, int default_entry_acl_type)
+{
+ int e, i;
+ int ae_id, ae_tag, ae_perm;
+ int entry_acl_type;
+ const char *ae_name;
+ aclent_t *aclent;
+ ace_t *ace;
+
+ (void)default_entry_acl_type;
+
+ if (acl->acl_cnt <= 0)
+ return (ARCHIVE_OK);
+
+ for (e = 0; e < acl->acl_cnt; e++) {
+ ae_name = NULL;
+ ae_tag = 0;
+ ae_perm = 0;
+
+ if (acl->acl_type == ACE_T) {
+ ace = &((ace_t *)acl->acl_aclp)[e];
+ ae_id = ace->a_who;
+
+ switch(ace->a_type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ break;
+ case ACE_ACCESS_DENIED_ACE_TYPE:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ break;
+ case ACE_SYSTEM_AUDIT_ACE_TYPE:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ break;
+ case ACE_SYSTEM_ALARM_ACE_TYPE:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ break;
+ default:
+ /* Unknown entry type, skip */
+ continue;
+ }
+
+ if ((ace->a_flags & ACE_OWNER) != 0)
+ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if ((ace->a_flags & ACE_GROUP) != 0)
+ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ else if ((ace->a_flags & ACE_EVERYONE) != 0)
+ ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
+ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+ ae_name = archive_read_disk_gname(&a->archive,
+ ae_id);
+ } else {
+ ae_tag = ARCHIVE_ENTRY_ACL_USER;
+ ae_name = archive_read_disk_uname(&a->archive,
+ ae_id);
+ }
+
+ for (i = 0; i < (int)(sizeof(acl_inherit_map) /
+ sizeof(acl_inherit_map[0])); ++i) {
+ if ((ace->a_flags &
+ acl_inherit_map[i].platform_inherit) != 0)
+ ae_perm |=
+ acl_inherit_map[i].archive_inherit;
+ }
+
+ for (i = 0; i < (int)(sizeof(acl_perm_map) /
+ sizeof(acl_perm_map[0])); ++i) {
+ if ((ace->a_access_mask &
+ acl_perm_map[i].platform_perm) != 0)
+ ae_perm |=
+ acl_perm_map[i].archive_perm;
+ }
+ } else {
+ aclent = &((aclent_t *)acl->acl_aclp)[e];
+ if ((aclent->a_type & ACL_DEFAULT) != 0)
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ else
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ ae_id = aclent->a_id;
+
+ switch(aclent->a_type) {
+ case DEF_USER:
+ case USER:
+ ae_name = archive_read_disk_uname(&a->archive,
+ ae_id);
+ ae_tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case DEF_GROUP:
+ case GROUP:
+ ae_name = archive_read_disk_gname(&a->archive,
+ ae_id);
+ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case DEF_CLASS_OBJ:
+ case CLASS_OBJ:
+ ae_tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ case DEF_USER_OBJ:
+ case USER_OBJ:
+ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case DEF_GROUP_OBJ:
+ case GROUP_OBJ:
+ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case DEF_OTHER_OBJ:
+ case OTHER_OBJ:
+ ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ default:
+ /* Unknown tag type, skip */
+ continue;
+ }
+
+ if ((aclent->a_perm & 1) != 0)
+ ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ if ((aclent->a_perm & 2) != 0)
+ ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
+ if ((aclent->a_perm & 4) != 0)
+ ae_perm |= ARCHIVE_ENTRY_ACL_READ;
+ } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */
+
+ archive_entry_acl_add_entry(entry, entry_acl_type,
+ ae_perm, ae_tag, ae_id, ae_name);
+ }
+ return (ARCHIVE_OK);
+}
+#else /* !HAVE_SUN_ACL */
+/*
+ * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
+ * MacOS (NFSv4 only) ACLs into libarchive internal structure
+ */
static int
translate_acl(struct archive_read_disk *a,
struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
{
acl_tag_t acl_tag;
+#if HAVE_ACL_TYPE_NFS4
acl_entry_type_t acl_type;
+ int brand;
+#endif
+#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
acl_flagset_t acl_flagset;
+#endif
acl_entry_t acl_entry;
acl_permset_t acl_permset;
- int brand, i, r, entry_acl_type;
- int s, ae_id, ae_tag, ae_perm;
+ int i, entry_acl_type;
+ int r, s, ae_id, ae_tag, ae_perm;
+#if !HAVE_DARWIN_ACL
+ void *q;
+#endif
const char *ae_name;
-
+#if HAVE_ACL_TYPE_NFS4
// FreeBSD "brands" ACLs as POSIX.1e or NFSv4
// Make sure the "brand" on this ACL is consistent
// with the default_entry_acl_type bits provided.
- acl_get_brand_np(acl, &brand);
+ if (acl_get_brand_np(acl, &brand) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Failed to read ACL brand");
+ return (ARCHIVE_WARN);
+ }
switch (brand) {
case ACL_BRAND_POSIX:
switch (default_entry_acl_type) {
@@ -545,39 +1197,67 @@ translate_acl(struct archive_read_disk *a,
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
break;
default:
- // XXX set warning message?
- return ARCHIVE_FAILED;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid ACL entry type for POSIX.1e ACL");
+ return (ARCHIVE_WARN);
}
break;
case ACL_BRAND_NFS4:
if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
- // XXX set warning message?
- return ARCHIVE_FAILED;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid ACL entry type for NFSv4 ACL");
+ return (ARCHIVE_WARN);
}
break;
default:
- // XXX set warning message?
- return ARCHIVE_FAILED;
- break;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL brand");
+ return (ARCHIVE_WARN);
}
-
+#endif
s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
- while (s == 1) {
+ if (s == -1) {
+ archive_set_error(&a->archive, errno,
+ "Failed to get first ACL entry");
+ return (ARCHIVE_WARN);
+ }
+
+#if HAVE_DARWIN_ACL
+ while (s == 0)
+#else /* FreeBSD, Linux */
+ while (s == 1)
+#endif
+ {
ae_id = -1;
ae_name = NULL;
ae_perm = 0;
- acl_get_tag_type(acl_entry, &acl_tag);
+ if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Failed to get ACL tag type");
+ return (ARCHIVE_WARN);
+ }
switch (acl_tag) {
+#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
case ACL_USER:
- ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
- ae_name = archive_read_disk_uname(&a->archive, ae_id);
+ q = acl_get_qualifier(acl_entry);
+ if (q != NULL) {
+ ae_id = (int)*(uid_t *)q;
+ acl_free(q);
+ ae_name = archive_read_disk_uname(&a->archive,
+ ae_id);
+ }
ae_tag = ARCHIVE_ENTRY_ACL_USER;
break;
case ACL_GROUP:
- ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
- ae_name = archive_read_disk_gname(&a->archive, ae_id);
+ q = acl_get_qualifier(acl_entry);
+ if (q != NULL) {
+ ae_id = (int)*(gid_t *)q;
+ acl_free(q);
+ ae_name = archive_read_disk_gname(&a->archive,
+ ae_id);
+ }
ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
break;
case ACL_MASK:
@@ -592,21 +1272,52 @@ translate_acl(struct archive_read_disk *a,
case ACL_OTHER:
ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
break;
+#if HAVE_ACL_TYPE_NFS4
case ACL_EVERYONE:
ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
break;
+#endif
+#else /* HAVE_DARWIN_ACL */
+ case ACL_EXTENDED_ALLOW:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ r = translate_guid(&a->archive, acl_entry, &ae_id,
+ &ae_tag, &ae_name);
+ break;
+ case ACL_EXTENDED_DENY:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ r = translate_guid(&a->archive, acl_entry, &ae_id,
+ &ae_tag, &ae_name);
+ break;
+#endif /* HAVE_DARWIN_ACL */
default:
/* Skip types that libarchive can't support. */
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
continue;
}
- // XXX acl type maps to allow/deny/audit/YYYY bits
- // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for
- // non-NFSv4 ACLs
+#if HAVE_DARWIN_ACL
+ /* Skip if translate_guid() above failed */
+ if (r != 0) {
+ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+ continue;
+ }
+#endif
+
+#if !HAVE_DARWIN_ACL
+ // XXX acl_type maps to allow/deny/audit/YYYY bits
entry_acl_type = default_entry_acl_type;
- r = acl_get_entry_type_np(acl_entry, &acl_type);
- if (r == 0) {
+#endif
+#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+ if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+#if HAVE_ACL_TYPE_NFS4
+ /*
+ * acl_get_entry_type_np() fails with non-NFSv4 ACLs
+ */
+ if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
+ archive_set_error(&a->archive, errno, "Failed "
+ "to get ACL type from a NFSv4 ACL entry");
+ return (ARCHIVE_WARN);
+ }
switch (acl_type) {
case ACL_ENTRY_TYPE_ALLOW:
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
@@ -620,28 +1331,54 @@ translate_acl(struct archive_read_disk *a,
case ACL_ENTRY_TYPE_ALARM:
entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
break;
+ default:
+ archive_set_error(&a->archive, errno,
+ "Invalid NFSv4 ACL entry type");
+ return (ARCHIVE_WARN);
}
- }
+#endif /* HAVE_ACL_TYPE_NFS4 */
- /*
- * Libarchive stores "flag" (NFSv4 inheritance bits)
- * in the ae_perm bitmap.
- */
- acl_get_flagset_np(acl_entry, &acl_flagset);
- for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
- if (acl_get_flag_np(acl_flagset,
- acl_inherit_map[i].platform_inherit))
- ae_perm |= acl_inherit_map[i].archive_inherit;
-
- }
+ /*
+ * Libarchive stores "flag" (NFSv4 inheritance bits)
+ * in the ae_perm bitmap.
+ *
+ * acl_get_flagset_np() fails with non-NFSv4 ACLs
+ */
+ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Failed to get flagset from a NFSv4 ACL entry");
+ return (ARCHIVE_WARN);
+ }
+ for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+ r = acl_get_flag_np(acl_flagset,
+ acl_inherit_map[i].platform_inherit);
+ if (r == -1) {
+ archive_set_error(&a->archive, errno,
+ "Failed to check flag in a NFSv4 "
+ "ACL flagset");
+ return (ARCHIVE_WARN);
+ } else if (r)
+ ae_perm |= acl_inherit_map[i].archive_inherit;
+ }
+ }
+#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
- acl_get_permset(acl_entry, &acl_permset);
- for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Failed to get ACL permission set");
+ return (ARCHIVE_WARN);
+ }
+ for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
/*
* acl_get_perm() is spelled differently on different
* platforms; see above.
*/
- if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
+ r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
+ if (r == -1) {
+ archive_set_error(&a->archive, errno,
+ "Failed to check permission in an ACL permission set");
+ return (ARCHIVE_WARN);
+ } else if (r)
ae_perm |= acl_perm_map[i].archive_perm;
}
@@ -650,10 +1387,18 @@ translate_acl(struct archive_read_disk *a,
ae_id, ae_name);
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+#if !HAVE_DARWIN_ACL
+ if (s == -1) {
+ archive_set_error(&a->archive, errno,
+ "Failed to get next ACL entry");
+ return (ARCHIVE_WARN);
+ }
+#endif
}
return (ARCHIVE_OK);
}
-#else
+#endif /* !HAVE_SUN_ACL */
+#else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
static int
setup_acls(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
@@ -663,7 +1408,7 @@ setup_acls(struct archive_read_disk *a,
(void)fd; /* UNUSED */
return (ARCHIVE_OK);
}
-#endif
+#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
#if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
@@ -683,15 +1428,10 @@ setup_acls(struct archive_read_disk *a,
static int
setup_xattr(struct archive_read_disk *a,
- struct archive_entry *entry, const char *name, int fd)
+ struct archive_entry *entry, const char *name, int fd, const char *accpath)
{
ssize_t size;
void *value = NULL;
- const char *accpath;
-
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
#if HAVE_FGETXATTR
if (fd >= 0)
@@ -756,21 +1496,23 @@ setup_xattrs(struct archive_read_disk *a,
const char *path;
ssize_t list_size;
- path = archive_entry_sourcepath(entry);
- if (path == NULL)
- path = archive_entry_pathname(entry);
+ path = NULL;
- if (*fd < 0 && a->tree != NULL) {
- if (a->follow_symlinks ||
- archive_entry_filetype(entry) != AE_IFLNK)
- *fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't access %s", path);
- return (ARCHIVE_FAILED);
- }
+ if (*fd < 0) {
+ path = archive_entry_sourcepath(entry);
+ if (path == NULL || (a->tree != NULL &&
+ a->tree_enter_working_dir(a->tree) != 0))
+ path = archive_entry_pathname(entry);
+ if (path == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Couldn't determine file path to read "
+ "extended attributes");
+ return (ARCHIVE_WARN);
+ }
+ if (a->tree != NULL && (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)) {
+ *fd = a->open_on_current_dir(a->tree,
+ path, O_RDONLY | O_NONBLOCK);
}
}
@@ -833,7 +1575,7 @@ setup_xattrs(struct archive_read_disk *a,
if (strncmp(p, "system.", 7) == 0 ||
strncmp(p, "xfsroot.", 8) == 0)
continue;
- setup_xattr(a, entry, p, *fd);
+ setup_xattr(a, entry, p, *fd, path);
}
free(list);
@@ -854,19 +1596,16 @@ setup_xattrs(struct archive_read_disk *a,
*/
static int
setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
- int namespace, const char *name, const char *fullname, int fd);
+ int namespace, const char *name, const char *fullname, int fd,
+ const char *path);
static int
setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
- int namespace, const char *name, const char *fullname, int fd)
+ int namespace, const char *name, const char *fullname, int fd,
+ const char *accpath)
{
ssize_t size;
void *value = NULL;
- const char *accpath;
-
- accpath = archive_entry_sourcepath(entry);
- if (accpath == NULL)
- accpath = archive_entry_pathname(entry);
if (fd >= 0)
size = extattr_get_fd(fd, namespace, name, NULL, 0);
@@ -916,21 +1655,23 @@ setup_xattrs(struct archive_read_disk *a,
const char *path;
int namespace = EXTATTR_NAMESPACE_USER;
- path = archive_entry_sourcepath(entry);
- if (path == NULL)
- path = archive_entry_pathname(entry);
+ path = NULL;
- if (*fd < 0 && a->tree != NULL) {
- if (a->follow_symlinks ||
- archive_entry_filetype(entry) != AE_IFLNK)
- *fd = a->open_on_current_dir(a->tree, path,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- if (a->tree_enter_working_dir(a->tree) != 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't access %s", path);
- return (ARCHIVE_FAILED);
- }
+ if (*fd < 0) {
+ path = archive_entry_sourcepath(entry);
+ if (path == NULL || (a->tree != NULL &&
+ a->tree_enter_working_dir(a->tree) != 0))
+ path = archive_entry_pathname(entry);
+ if (path == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Couldn't determine file path to read "
+ "extended attributes");
+ return (ARCHIVE_WARN);
+ }
+ if (a->tree != NULL && (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)) {
+ *fd = a->open_on_current_dir(a->tree,
+ path, O_RDONLY | O_NONBLOCK);
}
}
@@ -980,7 +1721,7 @@ setup_xattrs(struct archive_read_disk *a,
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
- setup_xattr(a, entry, namespace, name, buff, *fd);
+ setup_xattr(a, entry, namespace, name, buff, *fd, path);
p += 1 + len;
}
@@ -1008,7 +1749,7 @@ setup_xattrs(struct archive_read_disk *a,
#if defined(HAVE_LINUX_FIEMAP_H)
/*
- * Linux sparse interface.
+ * Linux FIEMAP sparse interface.
*
* The FIEMAP ioctl returns an "extent" for each physical allocation
* on disk. We need to process those to generate a more compact list
@@ -1023,14 +1764,14 @@ setup_xattrs(struct archive_read_disk *a,
*/
static int
-setup_sparse(struct archive_read_disk *a,
+setup_sparse_fiemap(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
char buff[4096];
struct fiemap *fm;
struct fiemap_extent *fe;
int64_t size;
- int count, do_fiemap;
+ int count, do_fiemap, iters;
int exit_sts = ARCHIVE_OK;
if (archive_entry_filetype(entry) != AE_IFREG
@@ -1067,18 +1808,23 @@ setup_sparse(struct archive_read_disk *a,
fm->fm_extent_count = count;
do_fiemap = 1;
size = archive_entry_size(entry);
- for (;;) {
+ for (iters = 0; ; ++iters) {
int i, r;
r = ioctl(*fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
/* When something error happens, it is better we
* should return ARCHIVE_OK because an earlier
- * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */
- goto exit_setup_sparse;
+ * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */
+ goto exit_setup_sparse_fiemap;
}
- if (fm->fm_mapped_extents == 0)
+ if (fm->fm_mapped_extents == 0) {
+ if (iters == 0) {
+ /* Fully sparse file; insert a zero-length "data" entry */
+ archive_entry_sparse_add_entry(entry, 0, 0);
+ }
break;
+ }
fe = fm->fm_extents;
for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
@@ -1105,14 +1851,24 @@ setup_sparse(struct archive_read_disk *a,
} else
break;
}
-exit_setup_sparse:
+exit_setup_sparse_fiemap:
return (exit_sts);
}
-#elif defined(SEEK_HOLE) && defined(SEEK_DATA) && defined(_PC_MIN_HOLE_SIZE)
+#if !defined(SEEK_HOLE) || !defined(SEEK_DATA)
+static int
+setup_sparse(struct archive_read_disk *a,
+ struct archive_entry *entry, int *fd)
+{
+ return setup_sparse_fiemap(a, entry, fd);
+}
+#endif
+#endif /* defined(HAVE_LINUX_FIEMAP_H) */
+
+#if defined(SEEK_HOLE) && defined(SEEK_DATA)
/*
- * FreeBSD and Solaris sparse interface.
+ * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris)
*/
static int
@@ -1120,9 +1876,10 @@ setup_sparse(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
int64_t size;
- off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
- off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
+ off_t initial_off;
+ off_t off_s, off_e;
int exit_sts = ARCHIVE_OK;
+ int check_fully_sparse = 0;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_size(entry) <= 0
@@ -1146,8 +1903,10 @@ setup_sparse(struct archive_read_disk *a,
}
if (*fd >= 0) {
+#ifdef _PC_MIN_HOLE_SIZE
if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
+#endif
initial_off = lseek(*fd, 0, SEEK_CUR);
if (initial_off != 0)
lseek(*fd, 0, SEEK_SET);
@@ -1158,8 +1917,10 @@ setup_sparse(struct archive_read_disk *a,
if (path == NULL)
path = archive_entry_pathname(entry);
+#ifdef _PC_MIN_HOLE_SIZE
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
+#endif
*fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
if (*fd < 0) {
archive_set_error(&a->archive, errno,
@@ -1170,13 +1931,32 @@ setup_sparse(struct archive_read_disk *a,
initial_off = 0;
}
+#ifndef _PC_MIN_HOLE_SIZE
+ /* Check if the underlying filesystem supports seek hole */
+ off_s = lseek(*fd, 0, SEEK_HOLE);
+ if (off_s < 0)
+#if defined(HAVE_LINUX_FIEMAP_H)
+ return setup_sparse_fiemap(a, entry, fd);
+#else
+ goto exit_setup_sparse;
+#endif
+ else if (off_s > 0)
+ lseek(*fd, 0, SEEK_SET);
+#endif
+
off_s = 0;
size = archive_entry_size(entry);
while (off_s < size) {
off_s = lseek(*fd, off_s, SEEK_DATA);
if (off_s == (off_t)-1) {
- if (errno == ENXIO)
- break;/* no more hole */
+ if (errno == ENXIO) {
+ /* no more hole */
+ if (archive_entry_sparse_count(entry) == 0) {
+ /* Potentially a fully-sparse file. */
+ check_fully_sparse = 1;
+ }
+ break;
+ }
archive_set_error(&a->archive, errno,
"lseek(SEEK_HOLE) failed");
exit_sts = ARCHIVE_FAILED;
@@ -1195,17 +1975,25 @@ setup_sparse(struct archive_read_disk *a,
goto exit_setup_sparse;
}
if (off_s == 0 && off_e == size)
- break;/* This is not spase. */
+ break;/* This is not sparse. */
archive_entry_sparse_add_entry(entry, off_s,
off_e - off_s);
off_s = off_e;
}
+
+ if (check_fully_sparse) {
+ if (lseek(*fd, 0, SEEK_HOLE) == 0 &&
+ lseek(*fd, 0, SEEK_END) == size) {
+ /* Fully sparse file; insert a zero-length "data" entry */
+ archive_entry_sparse_add_entry(entry, 0, 0);
+ }
+ }
exit_setup_sparse:
lseek(*fd, initial_off, SEEK_SET);
return (exit_sts);
}
-#else
+#elif !defined(HAVE_LINUX_FIEMAP_H)
/*
* Generic (stub) sparse support.
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
index a13dbbf81..6961ae6a4 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c
@@ -165,7 +165,7 @@ struct filesystem {
int synthetic;
int remote;
int noatime;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
size_t name_max;
#endif
long incr_xfer_size;
@@ -200,7 +200,7 @@ struct tree {
DIR *d;
#define INVALID_DIR_HANDLE NULL
struct dirent *de;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
struct dirent *dirent;
size_t dirent_allocated;
#endif
@@ -244,7 +244,7 @@ struct tree {
int initial_filesystem_id;
int current_filesystem_id;
int max_filesystem_id;
- int allocated_filesytem;
+ int allocated_filesystem;
int entry_fd;
int entry_eof;
@@ -356,6 +356,8 @@ static int _archive_read_free(struct archive *);
static int _archive_read_close(struct archive *);
static int _archive_read_data_block(struct archive *,
const void **, size_t *, int64_t *);
+static int _archive_read_next_header(struct archive *,
+ struct archive_entry **);
static int _archive_read_next_header2(struct archive *,
struct archive_entry *);
static const char *trivial_lookup_gname(void *, int64_t gid);
@@ -377,6 +379,7 @@ archive_read_disk_vtable(void)
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
av.archive_read_data_block = _archive_read_data_block;
+ av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
inited = 1;
}
@@ -459,10 +462,10 @@ archive_read_disk_new(void)
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
+ a->entry = archive_entry_new2(&a->archive);
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
- a->enable_copyfile = 1;
- a->traverse_mount_points = 1;
+ a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
a->open_on_current_dir = open_on_current_dir;
a->tree_current_dir_fd = tree_current_dir_fd;
a->tree_enter_working_dir = tree_enter_working_dir;
@@ -491,6 +494,7 @@ _archive_read_free(struct archive *_a)
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a);
@@ -558,25 +562,19 @@ archive_read_disk_set_symlink_hybrid(struct archive *_a)
int
archive_read_disk_set_atime_restored(struct archive *_a)
{
-#ifndef HAVE_UTIMES
- static int warning_done = 0;
-#endif
struct archive_read_disk *a = (struct archive_read_disk *)_a;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
#ifdef HAVE_UTIMES
- a->restore_time = 1;
+ a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
if (a->tree != NULL)
a->tree->flags |= needsRestoreTimes;
return (ARCHIVE_OK);
#else
- if (warning_done)
- /* Warning was already emitted; suppress further warnings. */
- return (ARCHIVE_OK);
-
+ /* Display warning and unset flag */
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Cannot restore access time on this system");
- warning_done = 1;
+ a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME;
return (ARCHIVE_WARN);
#endif
}
@@ -590,25 +588,14 @@ archive_read_disk_set_behavior(struct archive *_a, int flags)
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+ a->flags = flags;
+
if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
r = archive_read_disk_set_atime_restored(_a);
else {
- a->restore_time = 0;
if (a->tree != NULL)
a->tree->flags &= ~needsRestoreTimes;
}
- if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
- a->honor_nodump = 1;
- else
- a->honor_nodump = 0;
- if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
- a->enable_copyfile = 1;
- else
- a->enable_copyfile = 0;
- if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
- a->traverse_mount_points = 0;
- else
- a->traverse_mount_points = 1;
return (r);
}
@@ -666,7 +653,7 @@ setup_suitable_read_buffer(struct archive_read_disk *a)
asize = cf->min_xfer_size;
/* Increase a buffer size up to 64K bytes in
- * a proper incremant size. */
+ * a proper increment size. */
while (asize < 1024*64)
asize += incr;
/* Take a margin to adjust to the filesystem
@@ -708,6 +695,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
int r;
ssize_t bytes;
size_t buffbytes;
+ int empty_sparse_region = 0;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
"archive_read_data_block");
@@ -789,6 +777,9 @@ _archive_read_data_block(struct archive *_a, const void **buff,
if ((int64_t)buffbytes > t->current_sparse->length)
buffbytes = t->current_sparse->length;
+ if (t->current_sparse->length == 0)
+ empty_sparse_region = 1;
+
/*
* Skip hole.
* TODO: Should we consider t->current_filesystem->xfer_align?
@@ -819,7 +810,11 @@ _archive_read_data_block(struct archive *_a, const void **buff,
}
} else
bytes = 0;
- if (bytes == 0) {
+ /*
+ * Return an EOF unless we've read a leading empty sparse region, which
+ * is used to represent fully-sparse files.
+ */
+ if (bytes == 0 && !empty_sparse_region) {
/* Get EOF */
t->entry_eof = 1;
r = ARCHIVE_EOF;
@@ -901,7 +896,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
} while (lst == NULL);
#ifdef __APPLE__
- if (a->enable_copyfile) {
+ if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
/* If we're using copyfile(), ignore "._XXX" files. */
const char *bname = strrchr(tree_current_path(t), '/');
if (bname == NULL)
@@ -921,7 +916,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_path_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -972,9 +967,9 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
if (t->initial_filesystem_id == -1)
t->initial_filesystem_id = t->current_filesystem_id;
- if (!a->traverse_mount_points) {
+ if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
if (t->initial_filesystem_id != t->current_filesystem_id)
- return (ARCHIVE_RETRY);
+ descend = 0;
}
t->descend = descend;
@@ -982,12 +977,14 @@ next_entry(struct archive_read_disk *a, struct tree *t,
* Honor nodump flag.
* If the file is marked with nodump flag, do not return this entry.
*/
- if (a->honor_nodump) {
+ if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) {
#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
if (st->st_flags & UF_NODUMP)
return (ARCHIVE_RETRY);
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
- defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \
+ defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \
+ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
int stflags;
@@ -996,9 +993,18 @@ next_entry(struct archive_read_disk *a, struct tree *t,
O_RDONLY | O_NONBLOCK | O_CLOEXEC);
__archive_ensure_cloexec_flag(t->entry_fd);
if (t->entry_fd >= 0) {
- r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
+ r = ioctl(t->entry_fd,
+#ifdef FS_IOC_GETFLAGS
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
&stflags);
+#ifdef FS_NODUMP_FL
+ if (r == 0 && (stflags & FS_NODUMP_FL) != 0)
+#else
if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)
+#endif
return (ARCHIVE_RETRY);
}
}
@@ -1009,7 +1015,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
/* Save the times to be restored. This must be in before
* calling archive_read_disk_descend() or any chance of it,
- * especially, invokng a callback. */
+ * especially, invoking a callback. */
t->restore_time.mtime = archive_entry_mtime(entry);
t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
t->restore_time.atime = archive_entry_atime(entry);
@@ -1024,7 +1030,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_time_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -1050,7 +1056,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_owner_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -1081,6 +1087,17 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
static int
+_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
+{
+ int ret;
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ *entryp = NULL;
+ ret = _archive_read_next_header2(_a, a->entry);
+ *entryp = a->entry;
+ return ret;
+}
+
+static int
_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -1148,6 +1165,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
+ __archive_reset_read_data(&a->archive);
return (r);
}
@@ -1311,10 +1329,11 @@ _archive_read_disk_open(struct archive *_a, const char *pathname)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->tree != NULL)
- a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+ a->tree = tree_reopen(a->tree, pathname,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
else
a->tree = tree_open(pathname, a->symlink_mode,
- a->restore_time);
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
if (a->tree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
@@ -1353,7 +1372,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
for (i = 0; i < t->max_filesystem_id; i++) {
if (t->filesystem_table[i].dev == dev) {
- /* There is the filesytem ID we've already generated. */
+ /* There is the filesystem ID we've already generated. */
t->current_filesystem_id = i;
t->current_filesystem = &(t->filesystem_table[i]);
return (ARCHIVE_OK);
@@ -1361,10 +1380,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
}
/*
- * This is the new filesytem which we have to generate a new ID for.
+ * This is the new filesystem which we have to generate a new ID for.
*/
fid = t->max_filesystem_id++;
- if (t->max_filesystem_id > t->allocated_filesytem) {
+ if (t->max_filesystem_id > t->allocated_filesystem) {
size_t s;
void *p;
@@ -1377,7 +1396,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
return (ARCHIVE_FATAL);
}
t->filesystem_table = (struct filesystem *)p;
- t->allocated_filesytem = s;
+ t->allocated_filesystem = s;
}
t->current_filesystem_id = fid;
t->current_filesystem = &(t->filesystem_table[fid]);
@@ -1475,7 +1494,20 @@ setup_current_filesystem(struct archive_read_disk *a)
struct tree *t = a->tree;
struct statfs sfs;
#if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC)
+/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make
+ * this accurate; some platforms have both and we need the one that's
+ * used by getvfsbyname()
+ *
+ * Then the following would become:
+ * #if defined(GETVFSBYNAME_ARG_TYPE)
+ * GETVFSBYNAME_ARG_TYPE vfc;
+ * #endif
+ */
+# if defined(HAVE_STRUCT_XVFSCONF)
struct xvfsconf vfc;
+# else
+ struct vfsconf vfc;
+# endif
#endif
int r, xr = 0;
#if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
@@ -1550,11 +1582,12 @@ setup_current_filesystem(struct archive_read_disk *a)
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
#if defined(HAVE_STRUCT_STATFS_F_NAMEMAX)
t->current_filesystem->name_max = sfs.f_namemax;
#else
+# if defined(_PC_NAME_MAX)
/* Mac OS X does not have f_namemax in struct statfs. */
if (tree_current_is_symblic_link_target(t)) {
if (tree_enter_working_dir(t) != 0) {
@@ -1564,12 +1597,15 @@ setup_current_filesystem(struct archive_read_disk *a)
nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
} else
nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
+# else
+ nm = -1;
+# endif
if (nm == -1)
t->current_filesystem->name_max = NAME_MAX;
else
t->current_filesystem->name_max = nm;
#endif
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -1610,7 +1646,7 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "statvfs failed");
return (ARCHIVE_FAILED);
} else if (xr == 1) {
- /* Usuall come here unless NetBSD supports _PC_REC_XFER_ALIGN
+ /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN
* for pathconf() function. */
t->current_filesystem->xfer_align = sfs.f_frsize;
t->current_filesystem->max_xfer_size = -1;
@@ -1660,7 +1696,9 @@ setup_current_filesystem(struct archive_read_disk *a)
{
struct tree *t = a->tree;
struct statfs sfs;
+#if defined(HAVE_STATVFS)
struct statvfs svfs;
+#endif
int r, vr = 0, xr = 0;
if (tree_current_is_symblic_link_target(t)) {
@@ -1677,7 +1715,9 @@ setup_current_filesystem(struct archive_read_disk *a)
"openat failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_FSTATVFS)
vr = fstatvfs(fd, &svfs);/* for f_flag, mount flags */
+#endif
r = fstatfs(fd, &sfs);
if (r == 0)
xr = get_xfer_size(t, fd, NULL);
@@ -1687,14 +1727,18 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "fchdir failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_STATVFS)
vr = statvfs(tree_current_access_path(t), &svfs);
+#endif
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
#endif
} else {
#ifdef HAVE_FSTATFS
+#if defined(HAVE_FSTATVFS)
vr = fstatvfs(tree_current_dir_fd(t), &svfs);
+#endif
r = fstatfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
@@ -1703,7 +1747,9 @@ setup_current_filesystem(struct archive_read_disk *a)
archive_set_error(&a->archive, errno, "fchdir failed");
return (ARCHIVE_FAILED);
}
+#if defined(HAVE_STATVFS)
vr = statvfs(".", &svfs);
+#endif
r = statfs(".", &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, ".");
@@ -1716,10 +1762,17 @@ setup_current_filesystem(struct archive_read_disk *a)
return (ARCHIVE_FAILED);
} else if (xr == 1) {
/* pathconf(_PC_REX_*) operations are not supported. */
+#if defined(HAVE_STATVFS)
t->current_filesystem->xfer_align = svfs.f_frsize;
t->current_filesystem->max_xfer_size = -1;
t->current_filesystem->min_xfer_size = svfs.f_bsize;
t->current_filesystem->incr_xfer_size = svfs.f_bsize;
+#else
+ t->current_filesystem->xfer_align = sfs.f_frsize;
+ t->current_filesystem->max_xfer_size = -1;
+ t->current_filesystem->min_xfer_size = sfs.f_bsize;
+ t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+#endif
}
switch (sfs.f_type) {
case AFS_SUPER_MAGIC:
@@ -1744,13 +1797,17 @@ setup_current_filesystem(struct archive_read_disk *a)
}
#if defined(ST_NOATIME)
+#if defined(HAVE_STATVFS)
if (svfs.f_flag & ST_NOATIME)
+#else
+ if (sfs.f_flag & ST_NOATIME)
+#endif
t->current_filesystem->noatime = 1;
else
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
t->current_filesystem->name_max = sfs.f_namelen;
#endif
@@ -1834,7 +1891,7 @@ setup_current_filesystem(struct archive_read_disk *a)
#endif
t->current_filesystem->noatime = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
t->current_filesystem->name_max = sfs.f_namemax;
#endif
@@ -1851,7 +1908,7 @@ static int
setup_current_filesystem(struct archive_read_disk *a)
{
struct tree *t = a->tree;
-#if defined(_PC_NAME_MAX) && defined(HAVE_READDIR_R)
+#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R)
long nm;
#endif
t->current_filesystem->synthetic = -1;/* Not supported */
@@ -1863,7 +1920,7 @@ setup_current_filesystem(struct archive_read_disk *a)
t->current_filesystem->min_xfer_size = -1;
t->current_filesystem->incr_xfer_size = -1;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
/* Set maximum filename length. */
# if defined(_PC_NAME_MAX)
if (tree_current_is_symblic_link_target(t)) {
@@ -1877,7 +1934,7 @@ setup_current_filesystem(struct archive_read_disk *a)
if (nm == -1)
# endif /* _PC_NAME_MAX */
/*
- * Some sysmtes (HP-UX or others?) incorrectly defined
+ * Some systems (HP-UX or others?) incorrectly defined
* NAME_MAX macro to be a smaller value.
*/
# if defined(NAME_MAX) && NAME_MAX >= 255
@@ -1891,7 +1948,7 @@ setup_current_filesystem(struct archive_read_disk *a)
else
t->current_filesystem->name_max = nm;
# endif /* _PC_NAME_MAX */
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
return (ARCHIVE_OK);
}
@@ -1973,7 +2030,7 @@ tree_dup(int fd)
static volatile int can_dupfd_cloexec = 1;
if (can_dupfd_cloexec) {
- new_fd = fcntl(fd, F_DUPFD_CLOEXEC);
+ new_fd = fcntl(fd, F_DUPFD_CLOEXEC, 0);
if (new_fd != -1)
return (new_fd);
/* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,
@@ -1996,8 +2053,7 @@ tree_push(struct tree *t, const char *path, int filesystem_id,
{
struct tree_entry *te;
- te = malloc(sizeof(*te));
- memset(te, 0, sizeof(*te));
+ te = calloc(1, sizeof(*te));
te->next = t->stack;
te->parent = t->current;
if (te->parent)
@@ -2055,9 +2111,8 @@ tree_open(const char *path, int symlink_mode, int restore_time)
{
struct tree *t;
- if ((t = malloc(sizeof(*t))) == NULL)
+ if ((t = calloc(1, sizeof(*t))) == NULL)
return (NULL);
- memset(t, 0, sizeof(*t));
archive_string_init(&t->path);
archive_string_ensure(&t->path, 31);
t->initial_symlink_mode = symlink_mode;
@@ -2067,7 +2122,7 @@ tree_open(const char *path, int symlink_mode, int restore_time)
static struct tree *
tree_reopen(struct tree *t, const char *path, int restore_time)
{
- t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags = (restore_time != 0)?needsRestoreTimes:0;
t->flags |= onInitialDir;
t->visit_type = 0;
t->tree_errno = 0;
@@ -2299,7 +2354,7 @@ tree_dir_next_posix(struct tree *t)
size_t namelen;
if (t->d == NULL) {
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
size_t dirent_size;
#endif
@@ -2320,7 +2375,7 @@ tree_dir_next_posix(struct tree *t)
t->visit_type = r != 0 ? r : TREE_ERROR_DIR;
return (t->visit_type);
}
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
dirent_size = offsetof(struct dirent, d_name) +
t->filesystem_table[t->current->filesystem_id].name_max + 1;
if (t->dirent == NULL || t->dirent_allocated < dirent_size) {
@@ -2337,11 +2392,11 @@ tree_dir_next_posix(struct tree *t)
}
t->dirent_allocated = dirent_size;
}
-#endif /* HAVE_READDIR_R */
+#endif /* USE_READDIR_R */
}
for (;;) {
errno = 0;
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
r = readdir_r(t->d, t->dirent, &t->de);
#ifdef _AIX
/* Note: According to the man page, return value 9 indicates
@@ -2593,7 +2648,7 @@ tree_free(struct tree *t)
if (t == NULL)
return;
archive_string_free(&t->path);
-#if defined(HAVE_READDIR_R)
+#if defined(USE_READDIR_R)
free(t->dirent);
#endif
free(t->sparse_list);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_private.h b/Utilities/cmlibarchive/libarchive/archive_read_disk_private.h
index e5af16b91..b5a8328b7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_private.h
@@ -39,6 +39,9 @@ struct archive_entry;
struct archive_read_disk {
struct archive archive;
+ /* Reused by archive_read_next_header() */
+ struct archive_entry *entry;
+
/*
* Symlink mode is one of 'L'ogical, 'P'hysical, or 'H'ybrid,
* following an old BSD convention. 'L' follows all symlinks,
@@ -60,14 +63,8 @@ struct archive_read_disk {
int (*tree_current_dir_fd)(struct tree*);
int (*tree_enter_working_dir)(struct tree*);
- /* Set 1 if users request to restore atime . */
- int restore_time;
- /* Set 1 if users request to honor nodump flag . */
- int honor_nodump;
- /* Set 1 if users request to enable mac copyfile. */
- int enable_copyfile;
- /* Set 1 if users request to traverse mount points. */
- int traverse_mount_points;
+ /* Bitfield with ARCHIVE_READDISK_* tunables */
+ int flags;
const char * (*lookup_gname)(void *private, int64_t gid);
void (*cleanup_gname)(void *private);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c
index 3bc52c70d..c7fd2471e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c
@@ -83,7 +83,7 @@ static const char * lookup_uname_helper(struct name_cache *, id_t uid);
* a simple cache to accelerate such lookups---into the archive_read_disk
* object. This is in a separate file because getpwuid()/getgrgid()
* can pull in a LOT of library code (including NIS/LDAP functions, which
- * pull in DNS resolveers, etc). This can easily top 500kB, which makes
+ * pull in DNS resolvers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
@@ -232,6 +232,7 @@ static const char *
lookup_uname_helper(struct name_cache *cache, id_t id)
{
struct passwd *result;
+ (void)cache; /* UNUSED */
result = getpwuid((uid_t)id);
@@ -298,6 +299,7 @@ static const char *
lookup_gname_helper(struct name_cache *cache, id_t id)
{
struct group *result;
+ (void)cache; /* UNUSED */
result = getgrgid((gid_t)id);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
index 9c5420d80..3b903304f 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c
@@ -168,7 +168,7 @@ struct tree {
int initial_filesystem_id;
int current_filesystem_id;
int max_filesystem_id;
- int allocated_filesytem;
+ int allocated_filesystem;
HANDLE entry_fh;
int entry_eof;
@@ -288,6 +288,8 @@ static int _archive_read_free(struct archive *);
static int _archive_read_close(struct archive *);
static int _archive_read_data_block(struct archive *,
const void **, size_t *, int64_t *);
+static int _archive_read_next_header(struct archive *,
+ struct archive_entry **);
static int _archive_read_next_header2(struct archive *,
struct archive_entry *);
static const char *trivial_lookup_gname(void *, int64_t gid);
@@ -310,6 +312,7 @@ archive_read_disk_vtable(void)
av.archive_free = _archive_read_free;
av.archive_close = _archive_read_close;
av.archive_read_data_block = _archive_read_data_block;
+ av.archive_read_next_header = _archive_read_next_header;
av.archive_read_next_header2 = _archive_read_next_header2;
inited = 1;
}
@@ -386,17 +389,16 @@ archive_read_disk_new(void)
{
struct archive_read_disk *a;
- a = (struct archive_read_disk *)malloc(sizeof(*a));
+ a = (struct archive_read_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
+ a->entry = archive_entry_new2(&a->archive);
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
- a->enable_copyfile = 1;
- a->traverse_mount_points = 1;
+ a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
return (&a->archive);
}
@@ -422,6 +424,7 @@ _archive_read_free(struct archive *_a)
if (a->cleanup_uname != NULL && a->lookup_uname_data != NULL)
(a->cleanup_uname)(a->lookup_uname_data);
archive_string_free(&a->archive.error_string);
+ archive_entry_free(a->entry);
a->archive.magic = 0;
free(a);
return (r);
@@ -491,7 +494,7 @@ archive_read_disk_set_atime_restored(struct archive *_a)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
- a->restore_time = 1;
+ a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
if (a->tree != NULL)
a->tree->flags |= needsRestoreTimes;
return (ARCHIVE_OK);
@@ -506,25 +509,14 @@ archive_read_disk_set_behavior(struct archive *_a, int flags)
archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+ a->flags = flags;
+
if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
r = archive_read_disk_set_atime_restored(_a);
else {
- a->restore_time = 0;
if (a->tree != NULL)
a->tree->flags &= ~needsRestoreTimes;
}
- if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
- a->honor_nodump = 1;
- else
- a->honor_nodump = 0;
- if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
- a->enable_copyfile = 1;
- else
- a->enable_copyfile = 0;
- if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
- a->traverse_mount_points = 0;
- else
- a->traverse_mount_points = 1;
return (r);
}
@@ -798,7 +790,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_path_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -848,7 +840,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
if (t->initial_filesystem_id == -1)
t->initial_filesystem_id = t->current_filesystem_id;
- if (!a->traverse_mount_points) {
+ if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
if (t->initial_filesystem_id != t->current_filesystem_id)
return (ARCHIVE_RETRY);
}
@@ -858,7 +850,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
/* Save the times to be restored. This must be in before
* calling archive_read_disk_descend() or any chance of it,
- * especially, invokng a callback. */
+ * especially, invoking a callback. */
t->restore_time.lastWriteTime = st->ftLastWriteTime;
t->restore_time.lastAccessTime = st->ftLastAccessTime;
t->restore_time.filetype = archive_entry_filetype(entry);
@@ -870,7 +862,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_time_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -896,7 +888,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
r = archive_match_owner_excluded(a->matching, entry);
if (r < 0) {
archive_set_error(&(a->archive), errno,
- "Faild : %s", archive_error_string(a->matching));
+ "Failed : %s", archive_error_string(a->matching));
return (r);
}
if (r) {
@@ -929,7 +921,7 @@ next_entry(struct archive_read_disk *a, struct tree *t,
else
flags |= FILE_FLAG_SEQUENTIAL_SCAN;
t->entry_fh = CreateFileW(tree_current_access_path(t),
- GENERIC_READ, 0, NULL, OPEN_EXISTING, flags, NULL);
+ GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, flags, NULL);
if (t->entry_fh == INVALID_HANDLE_VALUE) {
archive_set_error(&a->archive, errno,
"Couldn't open %ls", tree_current_path(a->tree));
@@ -945,6 +937,17 @@ next_entry(struct archive_read_disk *a, struct tree *t,
}
static int
+_archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
+{
+ int ret;
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ *entryp = NULL;
+ ret = _archive_read_next_header2(_a, a->entry);
+ *entryp = a->entry;
+ return ret;
+}
+
+static int
_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
{
struct archive_read_disk *a = (struct archive_read_disk *)_a;
@@ -1000,6 +1003,7 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
break;
}
+ __archive_reset_read_data(&a->archive);
return (r);
}
@@ -1203,9 +1207,11 @@ _archive_read_disk_open_w(struct archive *_a, const wchar_t *pathname)
struct archive_read_disk *a = (struct archive_read_disk *)_a;
if (a->tree != NULL)
- a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+ a->tree = tree_reopen(a->tree, pathname,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
else
- a->tree = tree_open(pathname, a->symlink_mode, a->restore_time);
+ a->tree = tree_open(pathname, a->symlink_mode,
+ a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
if (a->tree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate directory traversal data");
@@ -1244,7 +1250,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
for (i = 0; i < t->max_filesystem_id; i++) {
if (t->filesystem_table[i].dev == dev) {
- /* There is the filesytem ID we've already generated. */
+ /* There is the filesystem ID we've already generated. */
t->current_filesystem_id = i;
t->current_filesystem = &(t->filesystem_table[i]);
return (ARCHIVE_OK);
@@ -1252,10 +1258,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
}
/*
- * There is a new filesytem, we generate a new ID for.
+ * There is a new filesystem, we generate a new ID for.
*/
fid = t->max_filesystem_id++;
- if (t->max_filesystem_id > t->allocated_filesytem) {
+ if (t->max_filesystem_id > t->allocated_filesystem) {
size_t s;
void *p;
@@ -1268,7 +1274,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
return (ARCHIVE_FATAL);
}
t->filesystem_table = (struct filesystem *)p;
- t->allocated_filesytem = (int)s;
+ t->allocated_filesystem = (int)s;
}
t->current_filesystem_id = fid;
t->current_filesystem = &(t->filesystem_table[fid]);
@@ -1385,7 +1391,7 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt)
if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype)
return (0);
- /* Close a file descritor.
+ /* Close a file descriptor.
* It will not be used for SetFileTime() because it has been opened
* by a read only mode.
*/
@@ -1420,8 +1426,7 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path,
{
struct tree_entry *te;
- te = malloc(sizeof(*te));
- memset(te, 0, sizeof(*te));
+ te = calloc(1, sizeof(*te));
te->next = t->stack;
te->parent = t->current;
if (te->parent)
@@ -1490,8 +1495,7 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time)
{
struct tree *t;
- t = malloc(sizeof(*t));
- memset(t, 0, sizeof(*t));
+ t = calloc(1, sizeof(*t));
archive_string_init(&(t->full_path));
archive_string_init(&t->path);
archive_wstring_ensure(&t->path, 15);
@@ -1505,7 +1509,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
struct archive_wstring ws;
wchar_t *pathname, *p, *base;
- t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags = (restore_time != 0)?needsRestoreTimes:0;
t->visit_type = 0;
t->tree_errno = 0;
t->full_path_dir_length = 0;
@@ -1569,7 +1573,7 @@ tree_reopen(struct tree *t, const wchar_t *path, int restore_time)
t->stack->flags = needsFirstVisit;
/*
* Debug flag for Direct IO(No buffering) or Async IO.
- * Those dependant on environment variable switches
+ * Those dependent on environment variable switches
* will be removed until next release.
*/
{
@@ -1851,8 +1855,6 @@ entry_copy_bhfi(struct archive_entry *entry, const wchar_t *path,
break;
case L'C': case L'c':
if (((p[2] == L'M' || p[2] == L'm' ) &&
- (p[3] == L'D' || p[3] == L'd' )) ||
- ((p[2] == L'M' || p[2] == L'm' ) &&
(p[3] == L'D' || p[3] == L'd' )))
mode |= S_IXUSR | S_IXGRP | S_IXOTH;
break;
@@ -1886,7 +1888,7 @@ tree_current_file_information(struct tree *t, BY_HANDLE_FILE_INFORMATION *st,
if (sim_lstat && tree_current_is_physical_link(t))
flag |= FILE_FLAG_OPEN_REPARSE_POINT;
- h = CreateFileW(tree_current_access_path(t), 0, 0, NULL,
+ h = CreateFileW(tree_current_access_path(t), 0, FILE_SHARE_READ, NULL,
OPEN_EXISTING, flag, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
@@ -2115,7 +2117,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
} else
desiredAccess = GENERIC_READ;
- h = CreateFileW(path, desiredAccess, 0, NULL,
+ h = CreateFileW(path, desiredAccess, FILE_SHARE_READ, NULL,
OPEN_EXISTING, flag, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
@@ -2162,7 +2164,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
if (fd >= 0) {
h = (HANDLE)_get_osfhandle(fd);
} else {
- h = CreateFileW(path, GENERIC_READ, 0, NULL,
+ h = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (h == INVALID_HANDLE_VALUE) {
la_dosmaperr(GetLastError());
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_extract.c b/Utilities/cmlibarchive/libarchive/archive_read_extract.c
index 795f2abea..b7973fa8e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_extract.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_extract.c
@@ -26,158 +26,35 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_read_private.h"
-#include "archive_write_disk_private.h"
-
-struct extract {
- struct archive *ad; /* archive_write_disk object */
-
- /* Progress function invoked during extract. */
- void (*extract_progress)(void *);
- void *extract_progress_user_data;
-};
-
-static int archive_read_extract_cleanup(struct archive_read *);
-static int copy_data(struct archive *ar, struct archive *aw);
-static struct extract *get_extract(struct archive_read *);
-
-static struct extract *
-get_extract(struct archive_read *a)
-{
- /* If we haven't initialized, do it now. */
- /* This also sets up a lot of global state. */
- if (a->extract == NULL) {
- a->extract = (struct extract *)malloc(sizeof(*a->extract));
- if (a->extract == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't extract");
- return (NULL);
- }
- memset(a->extract, 0, sizeof(*a->extract));
- a->extract->ad = archive_write_disk_new();
- if (a->extract->ad == NULL) {
- archive_set_error(&a->archive, ENOMEM, "Can't extract");
- return (NULL);
- }
- archive_write_disk_set_standard_lookup(a->extract->ad);
- a->cleanup_archive_extract = archive_read_extract_cleanup;
- }
- return (a->extract);
-}
int
archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
- struct extract *extract;
+ struct archive_read_extract *extract;
+ struct archive_read * a = (struct archive_read *)_a;
- extract = get_extract((struct archive_read *)_a);
+ extract = __archive_read_get_extract(a);
if (extract == NULL)
return (ARCHIVE_FATAL);
- archive_write_disk_set_options(extract->ad, flags);
- return (archive_read_extract2(_a, entry, extract->ad));
-}
-int
-archive_read_extract2(struct archive *_a, struct archive_entry *entry,
- struct archive *ad)
-{
- struct archive_read *a = (struct archive_read *)_a;
- int r, r2;
-
- /* Set up for this particular entry. */
- if (a->skip_file_set)
- archive_write_disk_set_skip_file(ad,
- a->skip_file_dev, a->skip_file_ino);
- r = archive_write_header(ad, entry);
- if (r < ARCHIVE_WARN)
- r = ARCHIVE_WARN;
- if (r != ARCHIVE_OK)
- /* If _write_header failed, copy the error. */
- archive_copy_error(&a->archive, ad);
- else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)
- /* Otherwise, pour data into the entry. */
- r = copy_data(_a, ad);
- r2 = archive_write_finish_entry(ad);
- if (r2 < ARCHIVE_WARN)
- r2 = ARCHIVE_WARN;
- /* Use the first message. */
- if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
- archive_copy_error(&a->archive, ad);
- /* Use the worst error return. */
- if (r2 < r)
- r = r2;
- return (r);
-}
-
-void
-archive_read_extract_set_progress_callback(struct archive *_a,
- void (*progress_func)(void *), void *user_data)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct extract *extract = get_extract(a);
- if (extract != NULL) {
- extract->extract_progress = progress_func;
- extract->extract_progress_user_data = user_data;
- }
-}
-
-static int
-copy_data(struct archive *ar, struct archive *aw)
-{
- int64_t offset;
- const void *buff;
- struct extract *extract;
- size_t size;
- int r;
-
- extract = get_extract((struct archive_read *)ar);
- if (extract == NULL)
- return (ARCHIVE_FATAL);
- for (;;) {
- r = archive_read_data_block(ar, &buff, &size, &offset);
- if (r == ARCHIVE_EOF)
- return (ARCHIVE_OK);
- if (r != ARCHIVE_OK)
- return (r);
- r = (int)archive_write_data_block(aw, buff, size, offset);
- if (r < ARCHIVE_WARN)
- r = ARCHIVE_WARN;
- if (r != ARCHIVE_OK) {
- archive_set_error(ar, archive_errno(aw),
- "%s", archive_error_string(aw));
- return (r);
+ /* If we haven't initialized the archive_write_disk object, do it now. */
+ if (extract->ad == NULL) {
+ extract->ad = archive_write_disk_new();
+ if (extract->ad == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't extract");
+ return (ARCHIVE_FATAL);
}
- if (extract->extract_progress)
- (extract->extract_progress)
- (extract->extract_progress_user_data);
+ archive_write_disk_set_standard_lookup(extract->ad);
}
-}
-/*
- * Cleanup function for archive_extract.
- */
-static int
-archive_read_extract_cleanup(struct archive_read *a)
-{
- int ret = ARCHIVE_OK;
-
- ret = archive_write_free(a->extract->ad);
- free(a->extract);
- a->extract = NULL;
- return (ret);
+ archive_write_disk_set_options(extract->ad, flags);
+ return (archive_read_extract2(&a->archive, entry, extract->ad));
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_extract2.c b/Utilities/cmlibarchive/libarchive/archive_read_extract2.c
new file mode 100644
index 000000000..4febd8ce0
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_extract2.c
@@ -0,0 +1,155 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_extract.c,v 1.61 2008/05/26 17:00:22 kientzle Exp $");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+static int copy_data(struct archive *ar, struct archive *aw);
+static int archive_read_extract_cleanup(struct archive_read *);
+
+
+/* Retrieve an extract object without initialising the associated
+ * archive_write_disk object.
+ */
+struct archive_read_extract *
+__archive_read_get_extract(struct archive_read *a)
+{
+ if (a->extract == NULL) {
+ a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract));
+ if (a->extract == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't extract");
+ return (NULL);
+ }
+ a->cleanup_archive_extract = archive_read_extract_cleanup;
+ }
+ return (a->extract);
+}
+
+/*
+ * Cleanup function for archive_extract.
+ */
+static int
+archive_read_extract_cleanup(struct archive_read *a)
+{
+ int ret = ARCHIVE_OK;
+
+ if (a->extract->ad != NULL) {
+ ret = archive_write_free(a->extract->ad);
+ }
+ free(a->extract);
+ a->extract = NULL;
+ return (ret);
+}
+
+int
+archive_read_extract2(struct archive *_a, struct archive_entry *entry,
+ struct archive *ad)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ int r, r2;
+
+ /* Set up for this particular entry. */
+ if (a->skip_file_set)
+ archive_write_disk_set_skip_file(ad,
+ a->skip_file_dev, a->skip_file_ino);
+ r = archive_write_header(ad, entry);
+ if (r < ARCHIVE_WARN)
+ r = ARCHIVE_WARN;
+ if (r != ARCHIVE_OK)
+ /* If _write_header failed, copy the error. */
+ archive_copy_error(&a->archive, ad);
+ else if (!archive_entry_size_is_set(entry) || archive_entry_size(entry) > 0)
+ /* Otherwise, pour data into the entry. */
+ r = copy_data(_a, ad);
+ r2 = archive_write_finish_entry(ad);
+ if (r2 < ARCHIVE_WARN)
+ r2 = ARCHIVE_WARN;
+ /* Use the first message. */
+ if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
+ archive_copy_error(&a->archive, ad);
+ /* Use the worst error return. */
+ if (r2 < r)
+ r = r2;
+ return (r);
+}
+
+void
+archive_read_extract_set_progress_callback(struct archive *_a,
+ void (*progress_func)(void *), void *user_data)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_extract *extract = __archive_read_get_extract(a);
+ if (extract != NULL) {
+ extract->extract_progress = progress_func;
+ extract->extract_progress_user_data = user_data;
+ }
+}
+
+static int
+copy_data(struct archive *ar, struct archive *aw)
+{
+ int64_t offset;
+ const void *buff;
+ struct archive_read_extract *extract;
+ size_t size;
+ int r;
+
+ extract = __archive_read_get_extract((struct archive_read *)ar);
+ if (extract == NULL)
+ return (ARCHIVE_FATAL);
+ for (;;) {
+ r = archive_read_data_block(ar, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF)
+ return (ARCHIVE_OK);
+ if (r != ARCHIVE_OK)
+ return (r);
+ r = (int)archive_write_data_block(aw, buff, size, offset);
+ if (r < ARCHIVE_WARN)
+ r = ARCHIVE_WARN;
+ if (r < ARCHIVE_OK) {
+ archive_set_error(ar, archive_errno(aw),
+ "%s", archive_error_string(aw));
+ return (r);
+ }
+ if (extract->extract_progress)
+ (extract->extract_progress)
+ (extract->extract_progress_user_data);
+ }
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_filter.3 b/Utilities/cmlibarchive/libarchive/archive_read_filter.3
index 8761127d9..7f020e373 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_filter.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_filter.3
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 2, 2012
+.Dd August 14, 2014
.Dt ARCHIVE_READ_FILTER 3
.Os
.Sh NAME
@@ -32,8 +32,11 @@
.Nm archive_read_support_filter_bzip2 ,
.Nm archive_read_support_filter_compress ,
.Nm archive_read_support_filter_gzip ,
+.Nm archive_read_support_filter_lz4 ,
.Nm archive_read_support_filter_lzma ,
.Nm archive_read_support_filter_none ,
+.Nm archive_read_support_filter_rpm ,
+.Nm archive_read_support_filter_uu ,
.Nm archive_read_support_filter_xz ,
.Nm archive_read_support_filter_program ,
.Nm archive_read_support_filter_program_signature
@@ -50,12 +53,24 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_read_support_filter_compress "struct archive *"
.Ft int
+.Fn archive_read_support_filter_grzip "struct archive *"
+.Ft int
.Fn archive_read_support_filter_gzip "struct archive *"
.Ft int
+.Fn archive_read_support_filter_lrzip "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_lz4 "struct archive *"
+.Ft int
.Fn archive_read_support_filter_lzma "struct archive *"
.Ft int
+.Fn archive_read_support_filter_lzop "struct archive *"
+.Ft int
.Fn archive_read_support_filter_none "struct archive *"
.Ft int
+.Fn archive_read_support_filter_rpm "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_uu "struct archive *"
+.Ft int
.Fn archive_read_support_filter_xz "struct archive *"
.Ft int
.Fo archive_read_support_filter_program
@@ -75,9 +90,15 @@ Streaming Archive Library (libarchive, -larchive)
.It Xo
.Fn archive_read_support_filter_bzip2 ,
.Fn archive_read_support_filter_compress ,
+.Fn archive_read_support_filter_grzip ,
.Fn archive_read_support_filter_gzip ,
+.Fn archive_read_support_filter_lrzip ,
+.Fn archive_read_support_filter_lz4 ,
.Fn archive_read_support_filter_lzma ,
+.Fn archive_read_support_filter_lzop ,
.Fn archive_read_support_filter_none ,
+.Fn archive_read_support_filter_rpm ,
+.Fn archive_read_support_filter_uu ,
.Fn archive_read_support_filter_xz
.Xc
Enables auto-detection code and decompression support for the
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open.3 b/Utilities/cmlibarchive/libarchive/archive_read_open.3
index 30a740bef..4d8272cac 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open.3
@@ -130,14 +130,14 @@ objects can be found in the overview manual page for
The callback functions must match the following prototypes:
.Bl -item -offset indent
.It
-.Ft typedef ssize_t
+.Ft typedef la_ssize_t
.Fo archive_read_callback
.Fa "struct archive *"
.Fa "void *client_data"
.Fa "const void **buffer"
.Fc
.It
-.Ft typedef off_t
+.Ft typedef la_int64_t
.Fo archive_skip_callback
.Fa "struct archive *"
.Fa "void *client_data"
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_fd.c b/Utilities/cmlibarchive/libarchive/archive_read_open_fd.c
index e0f95bf41..f59cd07fe 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open_fd.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open_fd.c
@@ -59,6 +59,7 @@ struct read_fd_data {
static int file_close(struct archive *, void *);
static ssize_t file_read(struct archive *, void *, const void **buff);
+static int64_t file_seek(struct archive *, void *, int64_t request, int);
static int64_t file_skip(struct archive *, void *, int64_t request);
int
@@ -102,6 +103,7 @@ archive_read_open_fd(struct archive *a, int fd, size_t block_size)
archive_read_set_read_callback(a, file_read);
archive_read_set_skip_callback(a, file_skip);
+ archive_read_set_seek_callback(a, file_seek);
archive_read_set_close_callback(a, file_close);
archive_read_set_callback_data(a, mine);
return (archive_read_open1(a));
@@ -170,6 +172,33 @@ file_skip(struct archive *a, void *client_data, int64_t request)
return (-1);
}
+/*
+ * TODO: Store the offset and use it in the read callback.
+ */
+static int64_t
+file_seek(struct archive *a, void *client_data, int64_t request, int whence)
+{
+ struct read_fd_data *mine = (struct read_fd_data *)client_data;
+ int64_t r;
+
+ /* We use off_t here because lseek() is declared that way. */
+ /* See above for notes about when off_t is less than 64 bits. */
+ r = lseek(mine->fd, request, whence);
+ if (r >= 0)
+ return r;
+
+ if (errno == ESPIPE) {
+ archive_set_error(a, errno,
+ "A file descriptor(%d) is not seekable(PIPE)", mine->fd);
+ return (ARCHIVE_FAILED);
+ } else {
+ /* If the input is corrupted or truncated, fail. */
+ archive_set_error(a, errno,
+ "Error seeking in a file descriptor(%d)", mine->fd);
+ return (ARCHIVE_FATAL);
+ }
+}
+
static int
file_close(struct archive *a, void *client_data)
{
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_file.c b/Utilities/cmlibarchive/libarchive/archive_read_open_file.c
index 3a33c258e..bfe933bf3 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open_file.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open_file.c
@@ -83,8 +83,9 @@ archive_read_open_FILE(struct archive *a, FILE *f)
mine->f = f;
/*
* If we can't fstat() the file, it may just be that it's not
- * a file. (FILE * objects can wrap many kinds of I/O
- * streams, some of which don't support fileno()).)
+ * a file. (On some platforms, FILE * objects can wrap I/O
+ * streams that don't support fileno()). As a result, fileno()
+ * should be used cautiously.)
*/
if (fstat(fileno(mine->f), &st) == 0 && S_ISREG(st.st_mode)) {
archive_read_extract_set_skip_file(a, st.st_dev, st.st_ino);
@@ -150,7 +151,10 @@ file_skip(struct archive *a, void *client_data, int64_t request)
skip = max_skip;
}
-#if HAVE_FSEEKO
+#ifdef __ANDROID__
+ /* fileno() isn't safe on all platforms ... see above. */
+ if (lseek(fileno(mine->f), skip, SEEK_CUR) < 0)
+#elif HAVE_FSEEKO
if (fseeko(mine->f, skip, SEEK_CUR) != 0)
#elif HAVE__FSEEKI64
if (_fseeki64(mine->f, skip, SEEK_CUR) != 0)
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
index 622c960c4..86635e219 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c
@@ -178,7 +178,7 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
#else
/*
* POSIX system does not support a wchar_t interface for
- * open() system call, so we have to translate a whcar_t
+ * open() system call, so we have to translate a wchar_t
* filename to multi-byte one and use it.
*/
struct archive_string fn;
@@ -222,7 +222,7 @@ file_open(struct archive *a, void *client_data)
void *buffer;
const char *filename = NULL;
const wchar_t *wfilename = NULL;
- int fd;
+ int fd = -1;
int is_disk_like = 0;
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */
@@ -277,7 +277,7 @@ file_open(struct archive *a, void *client_data)
#else
archive_set_error(a, ARCHIVE_ERRNO_MISC,
"Unexpedted operation in archive_read_open_filename");
- return (ARCHIVE_FATAL);
+ goto fail;
#endif
}
if (fstat(fd, &st) != 0) {
@@ -287,7 +287,7 @@ file_open(struct archive *a, void *client_data)
else
archive_set_error(a, errno, "Can't stat '%s'",
filename);
- return (ARCHIVE_FATAL);
+ goto fail;
}
/*
@@ -356,11 +356,9 @@ file_open(struct archive *a, void *client_data)
mine->block_size = new_block_size;
}
buffer = malloc(mine->block_size);
- if (mine == NULL || buffer == NULL) {
+ if (buffer == NULL) {
archive_set_error(a, ENOMEM, "No memory");
- free(mine);
- free(buffer);
- return (ARCHIVE_FATAL);
+ goto fail;
}
mine->buffer = buffer;
mine->fd = fd;
@@ -372,6 +370,14 @@ file_open(struct archive *a, void *client_data)
mine->use_lseek = 1;
return (ARCHIVE_OK);
+fail:
+ /*
+ * Don't close file descriptors not opened or ones pointing referring
+ * to `FNT_STDIN`.
+ */
+ if (fd != -1 && fd != 0)
+ close(fd);
+ return (ARCHIVE_FATAL);
}
static ssize_t
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c b/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c
index bcc7d6f78..311be4704 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c
@@ -41,9 +41,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_open_memory.c,v 1.6 2007/07/
*/
struct read_memory_data {
- unsigned char *start;
- unsigned char *p;
- unsigned char *end;
+ const unsigned char *start;
+ const unsigned char *p;
+ const unsigned char *end;
ssize_t read_size;
};
@@ -54,7 +54,7 @@ static int64_t memory_read_skip(struct archive *, void *, int64_t request);
static ssize_t memory_read(struct archive *, void *, const void **buff);
int
-archive_read_open_memory(struct archive *a, void *buff, size_t size)
+archive_read_open_memory(struct archive *a, const void *buff, size_t size)
{
return archive_read_open_memory2(a, buff, size, size);
}
@@ -65,18 +65,17 @@ archive_read_open_memory(struct archive *a, void *buff, size_t size)
* test harnesses can exercise block operations inside the library.
*/
int
-archive_read_open_memory2(struct archive *a, void *buff,
+archive_read_open_memory2(struct archive *a, const void *buff,
size_t size, size_t read_size)
{
struct read_memory_data *mine;
- mine = (struct read_memory_data *)malloc(sizeof(*mine));
+ mine = (struct read_memory_data *)calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
return (ARCHIVE_FATAL);
}
- memset(mine, 0, sizeof(*mine));
- mine->start = mine->p = (unsigned char *)buff;
+ mine->start = mine->p = (const unsigned char *)buff;
mine->end = mine->start + size;
mine->read_size = read_size;
archive_read_set_open_callback(a, memory_read_open);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_private.h b/Utilities/cmlibarchive/libarchive/archive_read_private.h
index 8a6c859a8..78546dca3 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_read_private.h
@@ -26,8 +26,10 @@
*/
#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
+#endif
#ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
#define ARCHIVE_READ_PRIVATE_H_INCLUDED
@@ -141,6 +143,18 @@ struct archive_read_client {
int64_t position;
struct archive_read_data_node *dataset;
};
+struct archive_read_passphrase {
+ char *passphrase;
+ struct archive_read_passphrase *next;
+};
+
+struct archive_read_extract {
+ struct archive *ad; /* archive_write_disk object */
+
+ /* Progress function invoked during extract. */
+ void (*extract_progress)(void *);
+ void *extract_progress_user_data;
+};
struct archive_read {
struct archive archive;
@@ -152,28 +166,11 @@ struct archive_read {
int64_t skip_file_dev;
int64_t skip_file_ino;
- /*
- * Used by archive_read_data() to track blocks and copy
- * data to client buffers, filling gaps with zero bytes.
- */
- const char *read_data_block;
- int64_t read_data_offset;
- int64_t read_data_output_offset;
- size_t read_data_remaining;
-
- /*
- * Used by formats/filters to determine the amount of data
- * requested from a call to archive_read_data(). This is only
- * useful when the format/filter has seek support.
- */
- char read_data_is_posix_read;
- size_t read_data_requested;
-
/* Callbacks to open/read/write/close client archive streams. */
struct archive_read_client client;
/* Registered filter bidders. */
- struct archive_read_filter_bidder bidders[14];
+ struct archive_read_filter_bidder bidders[16];
/* Last filter in chain */
struct archive_read_filter *filter;
@@ -207,26 +204,41 @@ struct archive_read {
int (*read_data_skip)(struct archive_read *);
int64_t (*seek_data)(struct archive_read *, int64_t, int);
int (*cleanup)(struct archive_read *);
+ int (*format_capabilties)(struct archive_read *);
+ int (*has_encrypted_entries)(struct archive_read *);
} formats[16];
struct archive_format_descriptor *format; /* Active format. */
/*
* Various information needed by archive_extract.
*/
- struct extract *extract;
+ struct archive_read_extract *extract;
int (*cleanup_archive_extract)(struct archive_read *);
+
+ /*
+ * Decryption passphrase.
+ */
+ struct {
+ struct archive_read_passphrase *first;
+ struct archive_read_passphrase **last;
+ int candidate;
+ archive_passphrase_callback *callback;
+ void *client_data;
+ } passphrases;
};
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 *),
- int64_t (*seek_data)(struct archive_read *, int64_t, int),
- int (*cleanup)(struct archive_read *));
+ 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 *),
+ int64_t (*seek_data)(struct archive_read *, int64_t, int),
+ int (*cleanup)(struct archive_read *),
+ int (*format_capabilities)(struct archive_read *),
+ int (*has_encrypted_entries)(struct archive_read *));
int __archive_read_get_bidder(struct archive_read *a,
struct archive_read_filter_bidder **bidder);
@@ -240,5 +252,12 @@ int64_t __archive_read_consume(struct archive_read *, int64_t);
int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t);
int __archive_read_program(struct archive_read_filter *, const char *);
void __archive_read_free_filters(struct archive_read *);
-int __archive_read_close_filters(struct archive_read *);
+struct archive_read_extract *__archive_read_get_extract(struct archive_read *);
+
+
+/*
+ * Get a decryption passphrase.
+ */
+void __archive_read_reset_passphrase(struct archive_read *a);
+const char * __archive_read_next_passphrase(struct archive_read *a);
#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3 b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3
index 6fe9f90f8..1a251cefe 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.3
+++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.3
@@ -193,6 +193,28 @@ Defaults to enabled, use
.Cm !rockridge
to disable.
.El
+.It Format tar
+.Bl -tag -compact -width indent
+.It Cm compat-2x
+Libarchive 2.x incorrectly encoded Unicode filenames on
+some platforms.
+This option mimics the libarchive 2.x filename handling
+so that such archives can be read correctly.
+.It Cm hdrcharset
+The value is used as a character set name that will be
+used when translating filenames.
+.It Cm mac-ext
+Support Mac OS metadata extension that records data in special
+files beginning with a period and underscore.
+Defaults to enabled on Mac OS, disabled on other platforms.
+Use
+.Cm !mac-ext
+to disable.
+.It Cm read_concatenated_archives
+Ignore zeroed blocks in the archive, which occurs when multiple tar archives
+have been concatenated together. Without this option, only the contents of
+the first concatenated archive would be read.
+.El
.El
.\"
.Sh ERRORS
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c
index 793f8f73e..2e2eea690 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_set_options.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_set_options.c
@@ -76,18 +76,20 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
const char *v)
{
struct archive_read *a = (struct archive_read *)_a;
- struct archive_format_descriptor *format;
size_t i;
- int r, rv = ARCHIVE_WARN;
+ int r, rv = ARCHIVE_WARN, matched_modules = 0;
for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
- format = &a->formats[i];
- if (format == NULL || format->options == NULL ||
- format->name == NULL)
+ struct archive_format_descriptor *format = &a->formats[i];
+
+ if (format->options == NULL || format->name == NULL)
/* This format does not support option. */
continue;
- if (m != NULL && strcmp(format->name, m) != 0)
- continue;
+ if (m != NULL) {
+ if (strcmp(format->name, m) != 0)
+ continue;
+ ++matched_modules;
+ }
a->format = format;
r = format->options(a, o, v);
@@ -96,16 +98,13 @@ archive_set_format_option(struct archive *_a, const char *m, const char *o,
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- if (m != NULL)
- return (r);
-
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the format name didn't match, return a special code for
* _archive_set_option[s]. */
- if (rv == ARCHIVE_WARN && m != NULL)
- rv = ARCHIVE_WARN - 1;
+ if (m != NULL && matched_modules == 0)
+ return ARCHIVE_WARN - 1;
return (rv);
}
@@ -116,7 +115,7 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
- int r, rv = ARCHIVE_WARN;
+ int r, rv = ARCHIVE_WARN, matched_modules = 0;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
@@ -125,24 +124,24 @@ archive_set_filter_option(struct archive *_a, const char *m, const char *o,
if (bidder->options == NULL)
/* This bidder does not support option */
continue;
- if (m != NULL && strcmp(filter->name, m) != 0)
- continue;
+ if (m != NULL) {
+ if (strcmp(filter->name, m) != 0)
+ continue;
+ ++matched_modules;
+ }
r = bidder->options(bidder, o, v);
if (r == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- if (m != NULL)
- return (r);
-
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
/* If the filter name didn't match, return a special code for
* _archive_set_option[s]. */
- if (rv == ARCHIVE_WARN && m != NULL)
- rv = ARCHIVE_WARN - 1;
+ if (m != NULL && matched_modules == 0)
+ return ARCHIVE_WARN - 1;
return (rv);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
index b778cfb79..68c53de41 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_all.c
@@ -69,6 +69,8 @@ archive_read_support_filter_all(struct archive *a)
archive_read_support_filter_lzop(a);
/* The decode code always uses "grzip -d" command-line. */
archive_read_support_filter_grzip(a);
+ /* Lz4 falls back to "lz4 -d" command-line program. */
+ archive_read_support_filter_lz4(a);
/* Note: We always return ARCHIVE_OK here, even if some of the
* above return ARCHIVE_WARN. The intent here is to enable
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c
index 3f5d1f37e..e05132dbf 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_compress.c
@@ -185,19 +185,22 @@ compress_bidder_bid(struct archive_read_filter_bidder *self,
(void)self; /* UNUSED */
- buffer = __archive_read_filter_ahead(filter, 2, &avail);
+ /* Shortest valid compress file is 3 bytes. */
+ buffer = __archive_read_filter_ahead(filter, 3, &avail);
if (buffer == NULL)
return (0);
bits_checked = 0;
+ /* First two bytes are the magic value */
if (buffer[0] != 0x1F || buffer[1] != 0x9D)
return (0);
- bits_checked += 16;
-
- /*
- * TODO: Verify more.
- */
+ /* Third byte holds compression parameters. */
+ if (buffer[2] & 0x20) /* Reserved bit, must be zero. */
+ return (0);
+ if (buffer[2] & 0x40) /* Reserved bit, must be zero. */
+ return (0);
+ bits_checked += 18;
return (bits_checked);
}
@@ -239,7 +242,13 @@ compress_bidder_init(struct archive_read_filter *self)
(void)getbits(self, 8); /* Skip first signature byte. */
(void)getbits(self, 8); /* Skip second signature byte. */
+ /* Get compression parameters. */
code = getbits(self, 8);
+ if ((code & 0x1f) > 16) {
+ archive_set_error(&self->archive->archive, -1,
+ "Invalid compressed data");
+ return (ARCHIVE_FATAL);
+ }
state->maxcode_bits = code & 0x1f;
state->maxcode = (1 << state->maxcode_bits);
state->use_reset_code = code & 0x80;
@@ -368,7 +377,8 @@ next_code(struct archive_read_filter *self)
return (next_code(self));
}
- if (code > state->free_ent) {
+ if (code > state->free_ent
+ || (code == state->free_ent && state->oldcode < 0)) {
/* An invalid code is a fatal error. */
archive_set_error(&(self->archive->archive), -1,
"Invalid compressed data");
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c
new file mode 100644
index 000000000..663e2d3d6
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c
@@ -0,0 +1,742 @@
+/*-
+ * Copyright (c) 2014 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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
+
+#include "archive.h"
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+#include "archive_xxhash.h"
+
+#define LZ4_MAGICNUMBER 0x184d2204
+#define LZ4_SKIPPABLED 0x184d2a50
+#define LZ4_LEGACY 0x184c2102
+
+#if defined(HAVE_LIBLZ4)
+struct private_data {
+ enum { SELECT_STREAM,
+ READ_DEFAULT_STREAM,
+ READ_DEFAULT_BLOCK,
+ READ_LEGACY_STREAM,
+ READ_LEGACY_BLOCK,
+ } stage;
+ struct {
+ unsigned block_independence:1;
+ unsigned block_checksum:3;
+ unsigned stream_size:1;
+ unsigned stream_checksum:1;
+ unsigned preset_dictionary:1;
+ int block_maximum_size;
+ } flags;
+ int64_t stream_size;
+ uint32_t dict_id;
+ char *out_block;
+ size_t out_block_size;
+
+ /* Bytes read but not yet consumed via __archive_read_consume() */
+ size_t unconsumed;
+ size_t decoded_size;
+ void *xxh32_state;
+
+ char valid; /* True = decompressor is initialized */
+ char eof; /* True = found end of compressed data. */
+};
+
+#define LEGACY_BLOCK_SIZE (8 * 1024 * 1024)
+
+/* Lz4 filter */
+static ssize_t lz4_filter_read(struct archive_read_filter *, const void **);
+static int lz4_filter_close(struct archive_read_filter *);
+#endif
+
+/*
+ * Note that we can detect lz4 archives even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better
+ * error messages.) So the bid framework here gets compiled even
+ * if liblz4 is unavailable.
+ */
+static int lz4_reader_bid(struct archive_read_filter_bidder *, struct archive_read_filter *);
+static int lz4_reader_init(struct archive_read_filter *);
+static int lz4_reader_free(struct archive_read_filter_bidder *);
+#if defined(HAVE_LIBLZ4)
+static ssize_t lz4_filter_read_default_stream(struct archive_read_filter *,
+ const void **);
+static ssize_t lz4_filter_read_legacy_stream(struct archive_read_filter *,
+ const void **);
+#endif
+
+int
+archive_read_support_filter_lz4(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct archive_read_filter_bidder *reader;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_filter_lz4");
+
+ if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+
+ reader->data = NULL;
+ reader->name = "lz4";
+ reader->bid = lz4_reader_bid;
+ reader->init = lz4_reader_init;
+ reader->options = NULL;
+ reader->free = lz4_reader_free;
+#if defined(HAVE_LIBLZ4)
+ return (ARCHIVE_OK);
+#else
+ archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+ "Using external lz4 program");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+static int
+lz4_reader_free(struct archive_read_filter_bidder *self){
+ (void)self; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Test whether we can handle this data.
+ *
+ * This logic returns zero if any part of the signature fails. It
+ * also tries to Do The Right Thing if a very short buffer prevents us
+ * from verifying as much as we would like.
+ */
+static int
+lz4_reader_bid(struct archive_read_filter_bidder *self,
+ struct archive_read_filter *filter)
+{
+ const unsigned char *buffer;
+ ssize_t avail;
+ int bits_checked;
+ uint32_t number;
+
+ (void)self; /* UNUSED */
+
+ /* Minimal lz4 archive is 11 bytes. */
+ buffer = __archive_read_filter_ahead(filter, 11, &avail);
+ if (buffer == NULL)
+ return (0);
+
+ /* First four bytes must be LZ4 magic numbers. */
+ bits_checked = 0;
+ if ((number = archive_le32dec(buffer)) == LZ4_MAGICNUMBER) {
+ unsigned char flag, BD;
+
+ bits_checked += 32;
+ /* Next follows a stream descriptor. */
+ /* Descriptor Flags. */
+ flag = buffer[4];
+ /* A version number must be "01". */
+ if (((flag & 0xc0) >> 6) != 1)
+ return (0);
+ /* A reserved bit must be "0". */
+ if (flag & 2)
+ return (0);
+ bits_checked += 8;
+ BD = buffer[5];
+ /* A block maximum size should be more than 3. */
+ if (((BD & 0x70) >> 4) < 4)
+ return (0);
+ /* Reserved bits must be "0". */
+ if (BD & ~0x70)
+ return (0);
+ bits_checked += 8;
+ } else if (number == LZ4_LEGACY) {
+ bits_checked += 32;
+ }
+
+ return (bits_checked);
+}
+
+#if !defined(HAVE_LIBLZ4)
+
+/*
+ * If we don't have the library on this system, we can't actually do the
+ * decompression. We can, however, still detect compressed archives
+ * and emit a useful message.
+ */
+static int
+lz4_reader_init(struct archive_read_filter *self)
+{
+ int r;
+
+ r = __archive_read_program(self, "lz4 -d -q");
+ /* Note: We set the format here even if __archive_read_program()
+ * above fails. We do, after all, know what the format is
+ * even if we weren't able to read it. */
+ self->code = ARCHIVE_FILTER_LZ4;
+ self->name = "lz4";
+ return (r);
+}
+
+
+#else
+
+/*
+ * Setup the callbacks.
+ */
+static int
+lz4_reader_init(struct archive_read_filter *self)
+{
+ struct private_data *state;
+
+ self->code = ARCHIVE_FILTER_LZ4;
+ self->name = "lz4";
+
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ if (state == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for lz4 decompression");
+ return (ARCHIVE_FATAL);
+ }
+
+ self->data = state;
+ state->stage = SELECT_STREAM;
+ self->read = lz4_filter_read;
+ self->skip = NULL; /* not supported */
+ self->close = lz4_filter_close;
+
+ return (ARCHIVE_OK);
+}
+
+static int
+lz4_allocate_out_block(struct archive_read_filter *self)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ size_t out_block_size = state->flags.block_maximum_size;
+ void *out_block;
+
+ if (!state->flags.block_independence)
+ out_block_size += 64 * 1024;
+ if (state->out_block_size < out_block_size) {
+ free(state->out_block);
+ out_block = (unsigned char *)malloc(out_block_size);
+ state->out_block_size = out_block_size;
+ if (out_block == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for lz4 decompression");
+ return (ARCHIVE_FATAL);
+ }
+ state->out_block = out_block;
+ }
+ if (!state->flags.block_independence)
+ memset(state->out_block, 0, 64 * 1024);
+ return (ARCHIVE_OK);
+}
+
+static int
+lz4_allocate_out_block_for_legacy(struct archive_read_filter *self)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ size_t out_block_size = LEGACY_BLOCK_SIZE;
+ void *out_block;
+
+ if (state->out_block_size < out_block_size) {
+ free(state->out_block);
+ out_block = (unsigned char *)malloc(out_block_size);
+ state->out_block_size = out_block_size;
+ if (out_block == NULL) {
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Can't allocate data for lz4 decompression");
+ return (ARCHIVE_FATAL);
+ }
+ state->out_block = out_block;
+ }
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Return the next block of decompressed data.
+ */
+static ssize_t
+lz4_filter_read(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ ssize_t ret;
+
+ if (state->eof) {
+ *p = NULL;
+ return (0);
+ }
+
+ __archive_read_filter_consume(self->upstream, state->unconsumed);
+ state->unconsumed = 0;
+
+ switch (state->stage) {
+ case SELECT_STREAM:
+ break;
+ case READ_DEFAULT_STREAM:
+ case READ_LEGACY_STREAM:
+ /* Reading a lz4 stream already failed. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC, "Invalid sequence.");
+ return (ARCHIVE_FATAL);
+ case READ_DEFAULT_BLOCK:
+ ret = lz4_filter_read_default_stream(self, p);
+ if (ret != 0 || state->stage != SELECT_STREAM)
+ return ret;
+ break;
+ case READ_LEGACY_BLOCK:
+ ret = lz4_filter_read_legacy_stream(self, p);
+ if (ret != 0 || state->stage != SELECT_STREAM)
+ return ret;
+ break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC, "Program error.");
+ return (ARCHIVE_FATAL);
+ break;
+ }
+
+ while (state->stage == SELECT_STREAM) {
+ const char *read_buf;
+
+ /* Read a magic number. */
+ read_buf = __archive_read_filter_ahead(self->upstream, 4,
+ NULL);
+ if (read_buf == NULL) {
+ state->eof = 1;
+ *p = NULL;
+ return (0);
+ }
+ uint32_t number = archive_le32dec(read_buf);
+ __archive_read_filter_consume(self->upstream, 4);
+ if (number == LZ4_MAGICNUMBER)
+ return lz4_filter_read_default_stream(self, p);
+ else if (number == LZ4_LEGACY)
+ return lz4_filter_read_legacy_stream(self, p);
+ else if ((number & ~0xF) == LZ4_SKIPPABLED) {
+ read_buf = __archive_read_filter_ahead(
+ self->upstream, 4, NULL);
+ if (read_buf == NULL) {
+ archive_set_error(
+ &self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Malformed lz4 data");
+ return (ARCHIVE_FATAL);
+ }
+ uint32_t skip_bytes = archive_le32dec(read_buf);
+ __archive_read_filter_consume(self->upstream,
+ 4 + skip_bytes);
+ } else {
+ /* Ignore following unrecognized data. */
+ state->eof = 1;
+ *p = NULL;
+ return (0);
+ }
+ }
+ state->eof = 1;
+ *p = NULL;
+ return (0);
+}
+
+static int
+lz4_filter_read_descriptor(struct archive_read_filter *self)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ const char *read_buf;
+ ssize_t bytes_remaining;
+ ssize_t descriptor_bytes;
+ unsigned char flag, bd;
+ unsigned int chsum, chsum_verifier;
+
+ /* Make sure we have 2 bytes for flags. */
+ read_buf = __archive_read_filter_ahead(self->upstream, 2,
+ &bytes_remaining);
+ if (read_buf == NULL) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ Parse flags.
+ */
+ flag = (unsigned char)read_buf[0];
+ /* Verify version number. */
+ if ((flag & 0xc0) != 1<<6)
+ goto malformed_error;
+ /* A reserved bit must be zero. */
+ if (flag & 0x02)
+ goto malformed_error;
+ state->flags.block_independence = (flag & 0x20) != 0;
+ state->flags.block_checksum = (flag & 0x10)?4:0;
+ state->flags.stream_size = (flag & 0x08) != 0;
+ state->flags.stream_checksum = (flag & 0x04) != 0;
+ state->flags.preset_dictionary = (flag & 0x01) != 0;
+
+ /* BD */
+ bd = (unsigned char)read_buf[1];
+ /* Reserved bits must be zero. */
+ if (bd & 0x8f)
+ goto malformed_error;
+ /* Get a maximum block size. */
+ switch (read_buf[1] >> 4) {
+ case 4: /* 64 KB */
+ state->flags.block_maximum_size = 64 * 1024;
+ break;
+ case 5: /* 256 KB */
+ state->flags.block_maximum_size = 256 * 1024;
+ break;
+ case 6: /* 1 MB */
+ state->flags.block_maximum_size = 1024 * 1024;
+ break;
+ case 7: /* 4 MB */
+ state->flags.block_maximum_size = 4 * 1024 * 1024;
+ break;
+ default:
+ goto malformed_error;
+ }
+
+ /* Read the whole descriptor in a stream block. */
+ descriptor_bytes = 3;
+ if (state->flags.stream_size)
+ descriptor_bytes += 8;
+ if (state->flags.preset_dictionary)
+ descriptor_bytes += 4;
+ if (bytes_remaining < descriptor_bytes) {
+ read_buf = __archive_read_filter_ahead(self->upstream,
+ descriptor_bytes, &bytes_remaining);
+ if (read_buf == NULL) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ /* Check if a descriptor is corrupted */
+ chsum = __archive_xxhash.XXH32(read_buf, (int)descriptor_bytes -1, 0);
+ chsum = (chsum >> 8) & 0xff;
+ chsum_verifier = read_buf[descriptor_bytes-1] & 0xff;
+ if (chsum != chsum_verifier)
+ goto malformed_error;
+
+ __archive_read_filter_consume(self->upstream, descriptor_bytes);
+
+ /* Make sure we have an enough buffer for uncompressed data. */
+ if (lz4_allocate_out_block(self) != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ if (state->flags.stream_checksum)
+ state->xxh32_state = __archive_xxhash.XXH32_init(0);
+
+ state->decoded_size = 0;
+ /* Success */
+ return (ARCHIVE_OK);
+malformed_error:
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "malformed lz4 data");
+ return (ARCHIVE_FATAL);
+}
+
+static ssize_t
+lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ ssize_t compressed_size;
+ const char *read_buf;
+ ssize_t bytes_remaining;
+ int checksum_size;
+ ssize_t uncompressed_size;
+ size_t prefix64k;
+
+ *p = NULL;
+
+ /* Make sure we have 4 bytes for a block size. */
+ read_buf = __archive_read_filter_ahead(self->upstream, 4,
+ &bytes_remaining);
+ if (read_buf == NULL)
+ goto truncated_error;
+ compressed_size = archive_le32dec(read_buf);
+ if ((compressed_size & ~(1 << 31)) > state->flags.block_maximum_size)
+ goto malformed_error;
+ /* A compressed size == 0 means the end of stream blocks. */
+ if (compressed_size == 0) {
+ __archive_read_filter_consume(self->upstream, 4);
+ return 0;
+ }
+
+ checksum_size = state->flags.block_checksum;
+ /* Check if the block is uncompressed. */
+ if (compressed_size & (1 << 31)) {
+ compressed_size &= ~(1 << 31);
+ uncompressed_size = compressed_size;
+ } else
+ uncompressed_size = 0;/* Unknown yet. */
+
+ /*
+ Unfortunately, lz4 decompression API requires a whole block
+ for its decompression speed, so we read a whole block and allocate
+ a huge buffer used for decoded data.
+ */
+ read_buf = __archive_read_filter_ahead(self->upstream,
+ 4 + compressed_size + checksum_size, &bytes_remaining);
+ if (read_buf == NULL)
+ goto truncated_error;
+
+ /* Optional process, checking a block sum. */
+ if (checksum_size) {
+ unsigned int chsum = __archive_xxhash.XXH32(
+ read_buf + 4, (int)compressed_size, 0);
+ unsigned int chsum_block =
+ archive_le32dec(read_buf + 4 + compressed_size);
+ if (chsum != chsum_block)
+ goto malformed_error;
+ }
+
+
+ /* If the block is uncompressed, there is nothing to do. */
+ if (uncompressed_size) {
+ /* Prepare a prefix 64k block for next block. */
+ if (!state->flags.block_independence) {
+ prefix64k = 64 * 1024;
+ if (uncompressed_size < (ssize_t)prefix64k) {
+ memcpy(state->out_block
+ + prefix64k - uncompressed_size,
+ read_buf + 4,
+ uncompressed_size);
+ memset(state->out_block, 0,
+ prefix64k - uncompressed_size);
+ } else {
+ memcpy(state->out_block,
+ read_buf + 4
+ + uncompressed_size - prefix64k,
+ prefix64k);
+ }
+ state->decoded_size = 0;
+ }
+ state->unconsumed = 4 + uncompressed_size + checksum_size;
+ *p = read_buf + 4;
+ return uncompressed_size;
+ }
+
+ /*
+ Decompress a block data.
+ */
+ if (state->flags.block_independence) {
+ prefix64k = 0;
+ uncompressed_size = LZ4_decompress_safe(read_buf + 4,
+ state->out_block, (int)compressed_size,
+ state->flags.block_maximum_size);
+ } else {
+ prefix64k = 64 * 1024;
+ if (state->decoded_size) {
+ if (state->decoded_size < prefix64k) {
+ memmove(state->out_block
+ + prefix64k - state->decoded_size,
+ state->out_block + prefix64k,
+ state->decoded_size);
+ memset(state->out_block, 0,
+ prefix64k - state->decoded_size);
+ } else {
+ memmove(state->out_block,
+ state->out_block + state->decoded_size,
+ prefix64k);
+ }
+ }
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ uncompressed_size = LZ4_decompress_safe_usingDict(
+ read_buf + 4,
+ state->out_block + prefix64k, (int)compressed_size,
+ state->flags.block_maximum_size,
+ state->out_block,
+ prefix64k);
+#else
+ uncompressed_size = LZ4_decompress_safe_withPrefix64k(
+ read_buf + 4,
+ state->out_block + prefix64k, (int)compressed_size,
+ state->flags.block_maximum_size);
+#endif
+ }
+
+ /* Check if an error occurred in the decompression process. */
+ if (uncompressed_size < 0) {
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
+ return (ARCHIVE_FATAL);
+ }
+
+ state->unconsumed = 4 + compressed_size + checksum_size;
+ *p = state->out_block + prefix64k;
+ state->decoded_size = uncompressed_size;
+ return uncompressed_size;
+
+malformed_error:
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "malformed lz4 data");
+ return (ARCHIVE_FATAL);
+truncated_error:
+ archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+ "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+}
+
+static ssize_t
+lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ const char *read_buf;
+ ssize_t bytes_remaining;
+ ssize_t ret;
+
+ if (state->stage == SELECT_STREAM) {
+ state->stage = READ_DEFAULT_STREAM;
+ /* First, read a descriptor. */
+ if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK)
+ return (ret);
+ state->stage = READ_DEFAULT_BLOCK;
+ }
+ /* Decompress a block. */
+ ret = lz4_filter_read_data_block(self, p);
+
+ /* If the end of block is detected, change the filter status
+ to read next stream. */
+ if (ret == 0 && *p == NULL)
+ state->stage = SELECT_STREAM;
+
+ /* Optional process, checking a stream sum. */
+ if (state->flags.stream_checksum) {
+ if (state->stage == SELECT_STREAM) {
+ unsigned int checksum;
+ unsigned int checksum_stream;
+ read_buf = __archive_read_filter_ahead(self->upstream,
+ 4, &bytes_remaining);
+ if (read_buf == NULL) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC, "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+ }
+ checksum = archive_le32dec(read_buf);
+ __archive_read_filter_consume(self->upstream, 4);
+ checksum_stream = __archive_xxhash.XXH32_digest(
+ state->xxh32_state);
+ state->xxh32_state = NULL;
+ if (checksum != checksum_stream) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "lz4 stream cheksum error");
+ return (ARCHIVE_FATAL);
+ }
+ } else if (ret > 0)
+ __archive_xxhash.XXH32_update(state->xxh32_state,
+ *p, (int)ret);
+ }
+ return (ret);
+}
+
+static ssize_t
+lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p)
+{
+ struct private_data *state = (struct private_data *)self->data;
+ int compressed;
+ const char *read_buf;
+ ssize_t ret;
+
+ *p = NULL;
+ ret = lz4_allocate_out_block_for_legacy(self);
+ if (ret != ARCHIVE_OK)
+ return ret;
+
+ /* Make sure we have 4 bytes for a block size. */
+ read_buf = __archive_read_filter_ahead(self->upstream, 4, NULL);
+ if (read_buf == NULL) {
+ if (state->stage == SELECT_STREAM) {
+ state->stage = READ_LEGACY_STREAM;
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+ }
+ state->stage = SELECT_STREAM;
+ return 0;
+ }
+ state->stage = READ_LEGACY_BLOCK;
+ compressed = archive_le32dec(read_buf);
+ if (compressed > LZ4_COMPRESSBOUND(LEGACY_BLOCK_SIZE)) {
+ state->stage = SELECT_STREAM;
+ return 0;
+ }
+
+ /* Make sure we have a whole block. */
+ read_buf = __archive_read_filter_ahead(self->upstream,
+ 4 + compressed, NULL);
+ if (read_buf == NULL) {
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC, "truncated lz4 input");
+ return (ARCHIVE_FATAL);
+ }
+ ret = LZ4_decompress_safe(read_buf + 4, state->out_block,
+ compressed, (int)state->out_block_size);
+ if (ret < 0) {
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC, "lz4 decompression failed");
+ return (ARCHIVE_FATAL);
+ }
+ *p = state->out_block;
+ state->unconsumed = 4 + compressed;
+ return ret;
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+lz4_filter_close(struct archive_read_filter *self)
+{
+ struct private_data *state;
+ int ret = ARCHIVE_OK;
+
+ state = (struct private_data *)self->data;
+ free(state->xxh32_state);
+ free(state->out_block);
+ free(state);
+ return (ret);
+}
+
+#endif /* HAVE_LIBLZ4 */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
index 7958fa50a..4356b82fd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c
@@ -242,10 +242,18 @@ consume_header(struct archive_read_filter *self)
if (version >= 0x940) {
unsigned level = *p++;
- if (method == 1 && level == 0) level = 3;
- if (method == 2 && level == 0) level = 1;
- if (method == 3 && level == 0) level = 9;
- if (level < 1 && level > 9) {
+#if 0
+ unsigned default_level[] = {0, 3, 1, 9};
+#endif
+ if (level == 0)
+ /* Method is 1..3 here due to check above. */
+#if 0 /* Avoid an error Clang Static Analyzer claims
+ "Value stored to 'level' is never read". */
+ level = default_level[method];
+#else
+ ;/* NOP */
+#endif
+ else if (level > 9) {
archive_set_error(&self->archive->archive,
ARCHIVE_ERRNO_MISC, "Invalid level");
return (ARCHIVE_FAILED);
@@ -428,7 +436,7 @@ lzop_filter_read(struct archive_read_filter *self, const void **p)
}
/*
- * Drive lzo uncompresison.
+ * Drive lzo uncompression.
*/
out_size = (lzo_uint)state->uncompressed_size;
r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c
index 66dc2f424..b8bf12886 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c
@@ -430,6 +430,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
&state->child_stdout);
if (child == -1) {
free(state->out_buf);
+ archive_string_free(&state->description);
free(state);
archive_set_error(&self->archive->archive, EINVAL,
"Can't initialize filter; unable to run program \"%s\"",
@@ -441,6 +442,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
if (state->child == NULL) {
child_stop(self, state);
free(state->out_buf);
+ archive_string_free(&state->description);
free(state);
archive_set_error(&self->archive->archive, EINVAL,
"Can't initialize filter; unable to run program \"%s\"",
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c
index 471771b6f..641297990 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c
@@ -312,6 +312,7 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
avail -= len;
if (l == 6) {
+ /* "begin " */
if (!uuchar[*b])
return (0);
/* Get a length of decoded bytes. */
@@ -319,30 +320,14 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
if (l > 45)
/* Normally, maximum length is 45(character 'M'). */
return (0);
- while (l && len-nl > 0) {
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- if (!uuchar[*b++])
- return (0);
- len -= 2;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
- if (l > 0) {
- if (!uuchar[*b++])
- return (0);
- --len;
- --l;
- }
+ if (l > len - nl)
+ return (0); /* Line too short. */
+ while (l) {
+ if (!uuchar[*b++])
+ return (0);
+ --len;
+ --l;
}
- if (len-nl < 0)
- return (0);
if (len-nl == 1 &&
(uuchar[*b] || /* Check sum. */
(*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */
@@ -352,8 +337,8 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self,
b += nl;
if (avail && uuchar[*b])
return (firstline+30);
- }
- if (l == 13) {
+ } else if (l == 13) {
+ /* "begin-base64 " */
while (len-nl > 0) {
if (!base64[*b++])
return (0);
@@ -509,7 +494,14 @@ read_more:
return (ARCHIVE_FATAL);
}
llen = len;
- if (nl == 0) {
+ if ((nl == 0) && (uudecode->state != ST_UUEND)) {
+ if (total == 0 && ravail <= 0) {
+ /* There is nothing more to read, fail */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Missing format data");
+ return (ARCHIVE_FATAL);
+ }
/*
* Save remaining data which does not contain
* NL('\n','\r').
@@ -527,6 +519,7 @@ read_more:
self->upstream, ravail);
goto read_more;
}
+ used += len;
break;
}
switch (uudecode->state) {
@@ -565,7 +558,7 @@ read_more:
"Insufficient compressed data");
return (ARCHIVE_FATAL);
}
- /* Get length of undecoded bytes of curent line. */
+ /* Get length of undecoded bytes of current line. */
l = UUDECODE(*b++);
body--;
if (l > body) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
index 15824b1d0..a18818638 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c
@@ -42,9 +42,7 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#endif
#if HAVE_LZMA_H
-#include <lzma.h>
-#elif HAVE_LZMADEC_H
-#include <lzmadec.h>
+#include <cm_lzma.h>
#endif
#include "archive.h"
@@ -82,19 +80,6 @@ static ssize_t xz_filter_read(struct archive_read_filter *, const void **);
static int xz_filter_close(struct archive_read_filter *);
static int xz_lzma_bidder_init(struct archive_read_filter *);
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-struct private_data {
- lzmadec_stream stream;
- unsigned char *out_block;
- size_t out_block_size;
- int64_t total_out;
- char eof; /* True = found end of compressed data. */
-};
-
-/* Lzma-only filter */
-static ssize_t lzma_filter_read(struct archive_read_filter *, const void **);
-static int lzma_filter_close(struct archive_read_filter *);
#endif
/*
@@ -178,8 +163,6 @@ archive_read_support_filter_lzma(struct archive *_a)
bidder->free = NULL;
#if HAVE_LZMA_H && HAVE_LIBLZMA
return (ARCHIVE_OK);
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
- return (ARCHIVE_OK);
#else
archive_set_error(_a, ARCHIVE_ERRNO_MISC,
"Using external lzma program for lzma decompression");
@@ -310,7 +293,7 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self,
/* Second through fifth bytes are dictionary size, stored in
* little-endian order. The minimum dictionary size is
* 1 << 12(4KiB) which the lzma of LZMA SDK uses with option
- * -d12 and the maxinam dictionary size is 1 << 27(128MiB)
+ * -d12 and the maximum dictionary size is 1 << 27(128MiB)
* which the one uses with option -d27.
* NOTE: A comment of LZMA SDK source code says this dictionary
* range is from 1 << 12 to 1 << 30. */
@@ -601,9 +584,7 @@ lzip_init(struct archive_read_filter *self)
return (ARCHIVE_FATAL);
}
ret = lzma_raw_decoder(&(state->stream), filters);
-#if LZMA_VERSION < 50000030
free(filters[0].options);
-#endif
if (ret != LZMA_OK) {
set_error(self, ret);
return (ARCHIVE_FATAL);
@@ -627,7 +608,7 @@ lzip_tail(struct archive_read_filter *self)
f = __archive_read_filter_ahead(self->upstream, tail, &avail_in);
if (f == NULL && avail_in < 0)
return (ARCHIVE_FATAL);
- if (avail_in < tail) {
+ if (f == NULL || avail_in < tail) {
archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
"Lzip: Remaining data is less bytes");
return (ARCHIVE_FAILED);
@@ -763,175 +744,6 @@ xz_filter_close(struct archive_read_filter *self)
#else
-#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC
-
-/*
- * If we have the older liblzmadec library, then we can handle
- * LZMA streams but not XZ streams.
- */
-
-/*
- * Setup the callbacks.
- */
-static int
-lzma_bidder_init(struct archive_read_filter *self)
-{
- static const size_t out_block_size = 64 * 1024;
- void *out_block;
- struct private_data *state;
- ssize_t ret, avail_in;
-
- self->code = ARCHIVE_FILTER_LZMA;
- self->name = "lzma";
-
- state = (struct private_data *)calloc(sizeof(*state), 1);
- out_block = (unsigned char *)malloc(out_block_size);
- if (state == NULL || out_block == NULL) {
- archive_set_error(&self->archive->archive, ENOMEM,
- "Can't allocate data for lzma decompression");
- free(out_block);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
- self->data = state;
- state->out_block_size = out_block_size;
- state->out_block = out_block;
- self->read = lzma_filter_read;
- self->skip = NULL; /* not supported */
- self->close = lzma_filter_close;
-
- /* Prime the lzma library with 18 bytes of input. */
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 18, &avail_in);
- if (state->stream.next_in == NULL)
- return (ARCHIVE_FATAL);
- state->stream.avail_in = avail_in;
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Initialize compression library. */
- ret = lzmadec_init(&(state->stream));
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- if (ret == LZMADEC_OK)
- return (ARCHIVE_OK);
-
- /* Library setup failed: Clean up. */
- archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing lzma library");
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case LZMADEC_HEADER_ERROR:
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid header");
- break;
- case LZMADEC_MEM_ERROR:
- archive_set_error(&self->archive->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- }
-
- free(state->out_block);
- free(state);
- self->data = NULL;
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Return the next block of decompressed data.
- */
-static ssize_t
-lzma_filter_read(struct archive_read_filter *self, const void **p)
-{
- struct private_data *state;
- size_t decompressed;
- ssize_t avail_in, ret;
-
- state = (struct private_data *)self->data;
-
- /* Empty our output buffer. */
- state->stream.next_out = state->out_block;
- state->stream.avail_out = state->out_block_size;
-
- /* Try to fill the output buffer. */
- while (state->stream.avail_out > 0 && !state->eof) {
- state->stream.next_in = (unsigned char *)(uintptr_t)
- __archive_read_filter_ahead(self->upstream, 1, &avail_in);
- if (state->stream.next_in == NULL && avail_in < 0) {
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "truncated lzma input");
- return (ARCHIVE_FATAL);
- }
- state->stream.avail_in = avail_in;
-
- /* Decompress as much as we can in one pass. */
- ret = lzmadec_decode(&(state->stream), avail_in == 0);
- switch (ret) {
- case LZMADEC_STREAM_END: /* Found end of stream. */
- state->eof = 1;
- /* FALL THROUGH */
- case LZMADEC_OK: /* Decompressor made some progress. */
- __archive_read_filter_consume(self->upstream,
- avail_in - state->stream.avail_in);
- break;
- case LZMADEC_BUF_ERROR: /* Insufficient input data? */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Insufficient compressed data");
- return (ARCHIVE_FATAL);
- default:
- /* Return an error. */
- archive_set_error(&self->archive->archive,
- ARCHIVE_ERRNO_MISC,
- "Lzma decompression failed");
- return (ARCHIVE_FATAL);
- }
- }
-
- decompressed = state->stream.next_out - state->out_block;
- state->total_out += decompressed;
- if (decompressed == 0)
- *p = NULL;
- else
- *p = state->out_block;
- return (decompressed);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-lzma_filter_close(struct archive_read_filter *self)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)self->data;
- ret = ARCHIVE_OK;
- switch (lzmadec_end(&(state->stream))) {
- case LZMADEC_OK:
- break;
- default:
- archive_set_error(&(self->archive->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor",
- self->archive->archive.compression_name);
- ret = ARCHIVE_FATAL;
- }
-
- free(state->out_block);
- free(state);
- return (ret);
-}
-
-#else
-
/*
*
* If we have no suitable library on this system, we can't actually do
@@ -953,9 +765,6 @@ lzma_bidder_init(struct archive_read_filter *self)
return (r);
}
-#endif /* HAVE_LZMADEC_H */
-
-
static int
xz_bidder_init(struct archive_read_filter *self)
{
@@ -984,5 +793,4 @@ lzip_bidder_init(struct archive_read_filter *self)
return (r);
}
-
#endif /* HAVE_LZMA_H */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
index 54ea24590..96774f4e3 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c
@@ -36,7 +36,7 @@ __FBSDID("$FreeBSD$");
#include <cm_bzlib.h>
#endif
#ifdef HAVE_LZMA_H
-#include <lzma.h>
+#include <cm_lzma.h>
#endif
#ifdef HAVE_ZLIB_H
#include <cm_zlib.h>
@@ -69,7 +69,11 @@ __FBSDID("$FreeBSD$");
#define _7Z_BZ2 0x040202
#define _7Z_PPMD 0x030401
#define _7Z_DELTA 0x03
-#define _7Z_CRYPTO 0x06F10701
+#define _7Z_CRYPTO_MAIN_ZIP 0x06F10101 /* Main Zip crypto algo */
+#define _7Z_CRYPTO_RAR_29 0x06F10303 /* Rar29 AES-128 + (modified SHA-1) */
+#define _7Z_CRYPTO_AES_256_SHA_256 0x06F10701 /* AES-256 + SHA-256 */
+
+
#define _7Z_X86 0x03030103
#define _7Z_X86_BCJ2 0x0303011B
#define _7Z_POWERPC 0x03030205
@@ -104,6 +108,7 @@ __FBSDID("$FreeBSD$");
#define kMTime 0x14
#define kAttributes 0x15
#define kEncodedHeader 0x17
+#define kDummy 0x19
struct _7z_digests {
unsigned char *defineds;
@@ -208,7 +213,7 @@ struct _7zip {
int header_is_encoded;
uint64_t header_bytes_remaining;
unsigned long header_crc32;
- /* Header offset to check that reading pointes of the file contens
+ /* Header offset to check that reading points of the file contents
* will not exceed the header. */
uint64_t header_offset;
/* Base offset of the archive file for a seek in case reading SFX. */
@@ -258,22 +263,22 @@ struct _7zip {
/*
* Decompressor controllers.
*/
- /* Decording LZMA1 and LZMA2 data. */
+ /* Decoding LZMA1 and LZMA2 data. */
#ifdef HAVE_LZMA_H
lzma_stream lzstream;
int lzstream_valid;
#endif
- /* Decording bzip2 data. */
+ /* Decoding bzip2 data. */
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
bz_stream bzstream;
int bzstream_valid;
#endif
- /* Decording deflate data. */
+ /* Decoding deflate data. */
#ifdef HAVE_ZLIB_H
z_stream stream;
int stream_valid;
#endif
- /* Decording PPMd data. */
+ /* Decoding PPMd data. */
int ppmd7_stat;
CPpmd7 ppmd7_context;
CPpmd7z_RangeDec range_dec;
@@ -322,8 +327,18 @@ struct _7zip {
struct archive_string_conv *sconv;
char format_name[64];
+
+ /* Custom value that is non-zero if this archive contains encrypted entries. */
+ int has_encrypted_entries;
};
+/* Maximum entry size. This limitation prevents reading intentional
+ * corrupted 7-zip files on assuming there are not so many entries in
+ * the files. */
+#define UMAX_ENTRY ARCHIVE_LITERAL_ULL(100000000)
+
+static int archive_read_format_7zip_has_encrypted_entries(struct archive_read *);
+static int archive_read_support_format_7zip_capabilities(struct archive_read *a);
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 *,
@@ -401,6 +416,13 @@ archive_read_support_format_7zip(struct archive *_a)
return (ARCHIVE_FATAL);
}
+ /*
+ * Until enough data has been read, we cannot tell about
+ * any encrypted entries yet.
+ */
+ zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+
+
r = __archive_read_register_format(a,
zip,
"7zip",
@@ -410,7 +432,9 @@ archive_read_support_format_7zip(struct archive *_a)
archive_read_format_7zip_read_data,
archive_read_format_7zip_read_data_skip,
NULL,
- archive_read_format_7zip_cleanup);
+ archive_read_format_7zip_cleanup,
+ archive_read_support_format_7zip_capabilities,
+ archive_read_format_7zip_has_encrypted_entries);
if (r != ARCHIVE_OK)
free(zip);
@@ -418,6 +442,27 @@ archive_read_support_format_7zip(struct archive *_a)
}
static int
+archive_read_support_format_7zip_capabilities(struct archive_read * a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
+ ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+}
+
+
+static int
+archive_read_format_7zip_has_encrypted_entries(struct archive_read *_a)
+{
+ if (_a && _a->format) {
+ struct _7zip * zip = (struct _7zip *)_a->format->data;
+ if (zip) {
+ return zip->has_encrypted_entries;
+ }
+ }
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+}
+
+static int
archive_read_format_7zip_bid(struct archive_read *a, int best_bid)
{
const char *p;
@@ -476,7 +521,7 @@ check_7zip_header_in_sfx(const char *p)
switch ((unsigned char)p[5]) {
case 0x1C:
if (memcmp(p, _7ZIP_SIGNATURE, 6) != 0)
- return (6);
+ return (6);
/*
* Test the CRC because its extraction code has 7-Zip
* Magic Code, so we should do this in order not to
@@ -484,15 +529,15 @@ check_7zip_header_in_sfx(const char *p)
*/
if (crc32(0, (const unsigned char *)p + 12, 20)
!= archive_le32dec(p + 8))
- return (6);
+ 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);
+ case 0x37: return (5);
+ case 0x7A: return (4);
+ case 0xBC: return (3);
+ case 0xAF: return (2);
+ case 0x27: return (1);
+ default: return (6);
}
}
@@ -507,7 +552,7 @@ skip_sfx(struct archive_read *a, ssize_t bytes_avail)
/*
* 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.
+ * already had enough data.
*/
if (bytes_avail > SFX_MIN_ADDR)
__archive_read_consume(a, SFX_MIN_ADDR);
@@ -568,6 +613,19 @@ archive_read_format_7zip_read_header(struct archive_read *a,
struct _7zip *zip = (struct _7zip *)a->format->data;
struct _7zip_entry *zip_entry;
int r, ret = ARCHIVE_OK;
+ struct _7z_folder *folder = 0;
+ uint64_t fidx = 0;
+
+ /*
+ * It should be sufficient to call archive_read_next_header() for
+ * a reader to determine if an entry is encrypted or not. If the
+ * encryption of an entry is only detectable when calling
+ * archive_read_data(), so be it. We'll do the same check there
+ * as well.
+ */
+ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ zip->has_encrypted_entries = 0;
+ }
a->archive.archive_format = ARCHIVE_FORMAT_7ZIP;
if (a->archive.archive_format_name == NULL)
@@ -588,7 +646,7 @@ archive_read_format_7zip_read_header(struct archive_read *a,
}
zip_entry = zip->entry;
- if (zip->entries_remaining <= 0)
+ if (zip->entries_remaining <= 0 || zip_entry == NULL)
return ARCHIVE_EOF;
--zip->entries_remaining;
@@ -604,6 +662,32 @@ archive_read_format_7zip_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
}
+ /* Figure out if the entry is encrypted by looking at the folder
+ that is associated to the current 7zip entry. If the folder
+ has a coder with a _7Z_CRYPTO codec then the folder is encrypted.
+ Hence the entry must also be encrypted. */
+ if (zip_entry && zip_entry->folderIndex < zip->si.ci.numFolders) {
+ folder = &(zip->si.ci.folders[zip_entry->folderIndex]);
+ for (fidx=0; folder && fidx<folder->numCoders; fidx++) {
+ switch(folder->coders[fidx].codec) {
+ case _7Z_CRYPTO_MAIN_ZIP:
+ case _7Z_CRYPTO_RAR_29:
+ case _7Z_CRYPTO_AES_256_SHA_256: {
+ archive_entry_set_is_data_encrypted(entry, 1);
+ zip->has_encrypted_entries = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Now that we've checked for encryption, if there were still no
+ * encrypted entries found we can say for sure that there are none.
+ */
+ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ zip->has_encrypted_entries = 0;
+ }
+
if (archive_entry_copy_pathname_l(entry,
(const char *)zip_entry->utf16name,
zip_entry->name_len, zip->sconv) != 0) {
@@ -676,7 +760,7 @@ 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
+ /* If there is no symname, handle it as a regular
* file. */
zip_entry->mode &= ~AE_IFMT;
zip_entry->mode |= AE_IFREG;
@@ -707,6 +791,10 @@ archive_read_format_7zip_read_data(struct archive_read *a,
zip = (struct _7zip *)(a->format->data);
+ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ zip->has_encrypted_entries = 0;
+ }
+
if (zip->pack_stream_bytes_unconsumed)
read_consume(a);
@@ -968,10 +1056,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
#endif
{
lzma_options_delta delta_opt;
- lzma_filter filters[LZMA_FILTERS_MAX];
-#if LZMA_VERSION < 50000030
- lzma_filter *ff;
-#endif
+ lzma_filter filters[LZMA_FILTERS_MAX], *ff;
int fi = 0;
if (zip->lzstream_valid) {
@@ -994,7 +1079,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
* 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.
+ * there is no way to do that.
* Discussion about this can be found at XZ Utils forum.
*/
if (coder2 != NULL) {
@@ -1056,9 +1141,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
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, (size_t)coder1->propertiesSize);
if (r != LZMA_OK) {
@@ -1070,9 +1153,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
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);
@@ -1203,6 +1284,17 @@ init_decompression(struct archive_read *a, struct _7zip *zip,
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unexpected codec ID: %lX", zip->codec);
return (ARCHIVE_FAILED);
+ case _7Z_CRYPTO_MAIN_ZIP:
+ case _7Z_CRYPTO_RAR_29:
+ case _7Z_CRYPTO_AES_256_SHA_256:
+ if (a->entry) {
+ archive_entry_set_is_metadata_encrypted(a->entry, 1);
+ archive_entry_set_is_data_encrypted(a->entry, 1);
+ zip->has_encrypted_entries = 1;
+ }
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Crypto codec not supported yet (ID: 0x%lX)", zip->codec);
+ return (ARCHIVE_FAILED);
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Unknown codec ID: %lX", zip->codec);
@@ -1426,7 +1518,7 @@ decompress(struct archive_read *a, struct _7zip *zip,
do {
int sym;
-
+
sym = __archive_ppmd7_functions.Ppmd7_DecodeSymbol(
&(zip->ppmd7_context), &(zip->range_dec.p));
if (sym < 0) {
@@ -1570,7 +1662,7 @@ parse_7zip_uint64(struct archive_read *a, uint64_t *val)
mask >>= 1;
continue;
}
- *val += (avail & (mask -1)) << (8 * i);
+ *val += ((uint64_t)(avail & (mask -1))) << (8 * i);
break;
}
return (0);
@@ -1670,7 +1762,7 @@ read_PackInfo(struct archive_read *a, struct _7z_pack_info *pi)
return (-1);
if (pi->numPackStreams == 0)
return (-1);
- if (1000000 < pi->numPackStreams)
+ if (UMAX_ENTRY < pi->numPackStreams)
return (-1);
/*
@@ -1799,12 +1891,12 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
if (parse_7zip_uint64(
a, &(f->coders[i].numInStreams)) < 0)
return (-1);
- if (1000000 < f->coders[i].numInStreams)
+ if (UMAX_ENTRY < f->coders[i].numInStreams)
return (-1);
if (parse_7zip_uint64(
a, &(f->coders[i].numOutStreams)) < 0)
return (-1);
- if (1000000 < f->coders[i].numOutStreams)
+ if (UMAX_ENTRY < f->coders[i].numOutStreams)
return (-1);
}
@@ -1844,11 +1936,11 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
for (i = 0; i < f->numBindPairs; i++) {
if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
return (-1);
- if (1000000 < f->bindPairs[i].inIndex)
+ if (UMAX_ENTRY < f->bindPairs[i].inIndex)
return (-1);
if (parse_7zip_uint64(a, &(f->bindPairs[i].outIndex)) < 0)
return (-1);
- if (1000000 < f->bindPairs[i].outIndex)
+ if (UMAX_ENTRY < f->bindPairs[i].outIndex)
return (-1);
}
@@ -1874,7 +1966,7 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
for (i = 0; i < f->numPackedStreams; i++) {
if (parse_7zip_uint64(a, &(f->packedStreams[i])) < 0)
return (-1);
- if (1000000 < f->packedStreams[i])
+ if (UMAX_ENTRY < f->packedStreams[i])
return (-1);
}
}
@@ -1916,8 +2008,8 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
*/
if (parse_7zip_uint64(a, &(ci->numFolders)) < 0)
goto failed;
- if (1000000 < ci->numFolders)
- return (-1);
+ if (UMAX_ENTRY < ci->numFolders)
+ return (-1);
/*
* Read External.
@@ -1938,9 +2030,18 @@ read_CodersInfo(struct archive_read *a, struct _7z_coders_info *ci)
case 1:
if (parse_7zip_uint64(a, &(ci->dataStreamIndex)) < 0)
return (-1);
- if (1000000 < ci->dataStreamIndex)
+ if (UMAX_ENTRY < ci->dataStreamIndex)
return (-1);
+ if (ci->numFolders > 0) {
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ goto failed;
+ }
break;
+ default:
+ archive_set_error(&a->archive, -1,
+ "Malformed 7-Zip archive");
+ goto failed;
}
if ((p = header_bytes(a, 1)) == NULL)
@@ -2043,8 +2144,11 @@ read_SubStreamsInfo(struct archive_read *a, struct _7z_substream_info *ss,
for (i = 0; i < numFolders; i++) {
if (parse_7zip_uint64(a, &(f[i].numUnpackStreams)) < 0)
return (-1);
- if (1000000 < f[i].numUnpackStreams)
+ if (UMAX_ENTRY < f[i].numUnpackStreams)
return (-1);
+ if (unpack_streams > SIZE_MAX - UMAX_ENTRY) {
+ return (-1);
+ }
unpack_streams += (size_t)f[i].numUnpackStreams;
}
if ((p = header_bytes(a, 1)) == NULL)
@@ -2292,8 +2396,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if (parse_7zip_uint64(a, &(zip->numFiles)) < 0)
return (-1);
- if (1000000 < zip->numFiles)
- return (-1);
+ if (UMAX_ENTRY < zip->numFiles)
+ return (-1);
zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
if (zip->entries == NULL)
@@ -2320,6 +2424,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
switch (type) {
case kEmptyStream:
+ if (h->emptyStreamBools != NULL)
+ return (-1);
h->emptyStreamBools = calloc((size_t)zip->numFiles,
sizeof(*h->emptyStreamBools));
if (h->emptyStreamBools == NULL)
@@ -2340,6 +2446,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
return (-1);
break;
}
+ if (h->emptyFileBools != NULL)
+ return (-1);
h->emptyFileBools = calloc(empty_streams,
sizeof(*h->emptyFileBools));
if (h->emptyFileBools == NULL)
@@ -2354,6 +2462,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
return (-1);
break;
}
+ if (h->antiBools != NULL)
+ return (-1);
h->antiBools = calloc(empty_streams,
sizeof(*h->antiBools));
if (h->antiBools == NULL)
@@ -2380,6 +2490,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if ((ll & 1) || ll < zip->numFiles * 4)
return (-1);
+ if (zip->entry_names != NULL)
+ return (-1);
zip->entry_names = malloc(ll);
if (zip->entry_names == NULL)
return (-1);
@@ -2432,6 +2544,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
if ((p = header_bytes(a, 2)) == NULL)
return (-1);
allAreDefined = *p;
+ if (h->attrBools != NULL)
+ return (-1);
h->attrBools = calloc((size_t)zip->numFiles,
sizeof(*h->attrBools));
if (h->attrBools == NULL)
@@ -2452,6 +2566,9 @@ read_Header(struct archive_read *a, struct _7z_header_info *h,
}
break;
}
+ case kDummy:
+ if (ll == 0)
+ break;
default:
if (header_bytes(a, ll) == NULL)
return (-1);
@@ -2591,7 +2708,7 @@ read_Times(struct archive_read *a, struct _7z_header_info *h, int type)
if (*p) {
if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
goto failed;
- if (1000000 < h->dataIndex)
+ if (UMAX_ENTRY < h->dataIndex)
goto failed;
}
@@ -2755,6 +2872,7 @@ slurp_central_directory(struct archive_read *a, struct _7zip *zip,
zip->header_crc32 = 0;
zip->header_is_encoded = 0;
zip->header_is_being_read = 1;
+ zip->has_encrypted_entries = 0;
check_header_crc = 1;
if ((p = header_bytes(a, 1)) == NULL) {
@@ -3170,7 +3288,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
return (r);
/*
- * Skip the bytes we alrady has skipped in skip_stream().
+ * Skip the bytes we already has skipped in skip_stream().
*/
while (skip_bytes) {
ssize_t skipped;
@@ -3235,16 +3353,36 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
* 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);
+ switch(folder->coders[i].codec) {
+ case _7Z_CRYPTO_MAIN_ZIP:
+ case _7Z_CRYPTO_RAR_29:
+ case _7Z_CRYPTO_AES_256_SHA_256: {
+ /* For entry that is associated with this folder, mark
+ it as encrypted (data+metadata). */
+ zip->has_encrypted_entries = 1;
+ if (a->entry) {
+ archive_entry_set_is_data_encrypted(a->entry, 1);
+ archive_entry_set_is_metadata_encrypted(a->entry, 1);
+ }
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "The %s is encrypted, "
+ "but currently not supported", cname);
+ return (ARCHIVE_FATAL);
+ }
+ case _7Z_X86_BCJ2: {
+ found_bcj2++;
+ break;
+ }
}
- if (folder->coders[i].codec == _7Z_X86_BCJ2)
- found_bcj2++;
}
+ /* Now that we've checked for encryption, if there were still no
+ * encrypted entries found we can say for sure that there are none.
+ */
+ if (zip->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ zip->has_encrypted_entries = 0;
+ }
+
if ((folder->numCoders > 2 && !found_bcj2) || found_bcj2 > 1) {
archive_set_error(&(a->archive),
ARCHIVE_ERRNO_MISC,
@@ -3368,7 +3506,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
return (ARCHIVE_FATAL);
}
- /* Allocate memory for the decorded data of a sub
+ /* Allocate memory for the decoded data of a sub
* stream. */
b[i] = malloc((size_t)zip->folder_outbytes_remaining);
if (b[i] == NULL) {
@@ -3453,7 +3591,7 @@ skip_stream(struct archive_read *a, size_t skip_bytes)
if (zip->folder_index == 0) {
/*
* Optimization for a list mode.
- * Avoid unncecessary decoding operations.
+ * Avoid unnecessary decoding operations.
*/
zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes
+= skip_bytes;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c
index 53fe6fa39..2127ebd33 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_all.c
@@ -61,6 +61,7 @@ archive_read_support_format_all(struct archive *a)
archive_read_support_format_mtree(a);
archive_read_support_format_tar(a);
archive_read_support_format_xar(a);
+ archive_read_support_format_warc(a);
/*
* Install expensive bidders last. By doing them last, we
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c
index 40be18c0c..b6b9fc3c6 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c
@@ -104,13 +104,12 @@ archive_read_support_format_ar(struct archive *_a)
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_ar");
- ar = (struct ar *)malloc(sizeof(*ar));
+ ar = (struct ar *)calloc(1, sizeof(*ar));
if (ar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate ar data");
return (ARCHIVE_FATAL);
}
- memset(ar, 0, sizeof(*ar));
ar->strtab = NULL;
r = __archive_read_register_format(a,
@@ -122,7 +121,9 @@ archive_read_support_format_ar(struct archive *_a)
archive_read_format_ar_read_data,
archive_read_format_ar_skip,
NULL,
- archive_read_format_ar_cleanup);
+ archive_read_format_ar_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK) {
free(ar);
@@ -178,7 +179,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) {
archive_set_error(&a->archive, EINVAL,
"Incorrect file header signature");
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
/* Copy filename into work buffer. */
@@ -237,8 +238,15 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
* and are not terminated in '/', so we don't trim anything
* that starts with '/'.)
*/
- if (filename[0] != '/' && *p == '/')
+ if (filename[0] != '/' && p > filename && *p == '/') {
*p = '\0';
+ }
+
+ if (p < filename) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Found entry with empty filename");
+ return (ARCHIVE_FATAL);
+ }
/*
* '//' is the GNU filename table.
@@ -251,7 +259,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
archive_entry_set_filetype(entry, AE_IFREG);
/* Get the size of the filename table. */
number = ar_atol10(h + AR_size_offset, AR_size_size);
- if (number > SIZE_MAX) {
+ if (number > SIZE_MAX || number > 1024 * 1024 * 1024) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Filename table too large");
return (ARCHIVE_FATAL);
@@ -260,12 +268,12 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
if (entry_size == 0) {
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
if (ar->strtab != NULL) {
archive_set_error(&a->archive, EINVAL,
"More than one string tables exist");
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
/* Read the filename table into memory. */
@@ -307,13 +315,13 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
* If we can't look up the real name, warn and return
* the entry with the wrong name.
*/
- if (ar->strtab == NULL || number > ar->strtab_size) {
+ if (ar->strtab == NULL || number >= ar->strtab_size) {
archive_set_error(&a->archive, EINVAL,
- "Can't find long filename for entry");
+ "Can't find long filename for GNU/SVR4 archive entry");
archive_entry_copy_pathname(entry, filename);
/* Parse the time, owner, mode, size fields. */
ar_parse_common_header(ar, entry, h);
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]);
@@ -333,16 +341,19 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry,
/* Parse the size of the name, adjust the file size. */
number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3);
- bsd_name_length = (size_t)number;
- /* Guard against the filename + trailing NUL
- * overflowing a size_t and against the filename size
- * being larger than the entire entry. */
- if (number > (uint64_t)(bsd_name_length + 1)
- || (int64_t)bsd_name_length > ar->entry_bytes_remaining) {
+ /* Sanity check the filename length:
+ * = Must be <= SIZE_MAX - 1
+ * = Must be <= 1MB
+ * = Cannot be bigger than the entire entry
+ */
+ if (number > SIZE_MAX - 1
+ || number > 1024 * 1024
+ || (int64_t)number > ar->entry_bytes_remaining) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad input file size");
return (ARCHIVE_FATAL);
}
+ bsd_name_length = (size_t)number;
ar->entry_bytes_remaining -= bsd_name_length;
/* Adjust file size reported to client. */
archive_entry_set_size(entry, ar->entry_bytes_remaining);
@@ -571,7 +582,7 @@ bad_string_table:
"Invalid string table");
free(ar->strtab);
ar->strtab = NULL;
- return (ARCHIVE_WARN);
+ return (ARCHIVE_FATAL);
}
static uint64_t
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
index 4dd38db93..20eb157f2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c
@@ -67,7 +67,7 @@ struct lzx_dec {
/* The length how many bytes we can copy decoded code from
* the window. */
int copy_len;
- /* Translation reversal for x86 proccessor CALL byte sequence(E8).
+ /* Translation reversal for x86 processor CALL byte sequence(E8).
* This is used for LZX only. */
uint32_t translation_size;
char translation;
@@ -383,7 +383,9 @@ archive_read_support_format_cab(struct archive *_a)
archive_read_format_cab_read_data,
archive_read_format_cab_read_data_skip,
NULL,
- archive_read_format_cab_cleanup);
+ archive_read_format_cab_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(cab);
@@ -643,12 +645,13 @@ cab_read_header(struct archive_read *a)
cab = (struct cab *)(a->format->data);
if (cab->found_header == 0 &&
p[0] == 'M' && p[1] == 'Z') {
- /* This is an executable? Must be self-extracting... */
+ /* This is an executable? Must be self-extracting... */
err = cab_skip_sfx(a);
if (err < ARCHIVE_WARN)
return (err);
- if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL)
+ /* Re-read header after processing the SFX. */
+ if ((p = __archive_read_ahead(a, 42, NULL)) == NULL)
return (truncated_error(a));
}
@@ -1492,6 +1495,8 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
/* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
if (mszip > 0) {
+ if (bytes_avail <= 0)
+ goto nomszip;
if (bytes_avail <= mszip) {
if (mszip == 2) {
if (cab->stream.next_in[0] != 0x43)
@@ -1552,7 +1557,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
/*
* Note: I suspect there is a bug in makecab.exe because, in rare
* case, compressed bytes are still remaining regardless we have
- * gotten all uncompressed bytes, which size is recoded in CFDATA,
+ * gotten all uncompressed bytes, which size is recorded in CFDATA,
* as much as we need, and we have to use the garbage so as to
* correctly compute the sum of CFDATA accordingly.
*/
@@ -1739,7 +1744,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail)
}
/*
- * Translation reversal of x86 proccessor CALL byte sequence(E8).
+ * Translation reversal of x86 processor CALL byte sequence(E8).
*/
lzx_translation(&cab->xstrm, cab->uncompressed_buffer,
cfdata->uncompressed_size,
@@ -2268,7 +2273,7 @@ static int
lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br)
{
/*
- * x86 proccessor family can read misaligned data without an access error.
+ * x86 processor family can read misaligned data without an access error.
*/
int n = CACHE_BITS - br->cache_avail;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
index 819f4a4f5..ffd4a8580 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c
@@ -198,7 +198,7 @@ static int archive_read_format_cpio_read_data(struct archive_read *,
static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *);
static int archive_read_format_cpio_skip(struct archive_read *);
-static int be4(const unsigned char *);
+static int64_t be4(const unsigned char *);
static int find_odc_header(struct archive_read *);
static int find_newc_header(struct archive_read *);
static int header_bin_be(struct archive_read *, struct cpio *,
@@ -213,7 +213,7 @@ static int header_afiol(struct archive_read *, struct cpio *,
struct archive_entry *, size_t *, size_t *);
static int is_octal(const char *, size_t);
static int is_hex(const char *, size_t);
-static int le4(const unsigned char *);
+static int64_t le4(const unsigned char *);
static int record_hardlink(struct archive_read *a,
struct cpio *cpio, struct archive_entry *entry);
@@ -243,7 +243,9 @@ archive_read_support_format_cpio(struct archive *_a)
archive_read_format_cpio_read_data,
archive_read_format_cpio_skip,
NULL,
- archive_read_format_cpio_cleanup);
+ archive_read_format_cpio_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(cpio);
@@ -324,7 +326,7 @@ archive_read_format_cpio_options(struct archive_read *a,
cpio = (struct cpio *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
- /* Handle filnames as libarchive 2.x */
+ /* Handle filenames as libarchive 2.x */
cpio->init_default_conversion = (val != NULL)?1:0;
return (ARCHIVE_OK);
} else if (strcmp(key, "hdrcharset") == 0) {
@@ -354,7 +356,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct cpio *cpio;
- const void *h;
+ const void *h, *hl;
struct archive_string_conv *sconv;
size_t namelength;
size_t name_pad;
@@ -399,11 +401,16 @@ archive_read_format_cpio_read_header(struct archive_read *a,
/* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) {
- h = __archive_read_ahead(a,
+ if (cpio->entry_bytes_remaining > 1024 * 1024) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Rejecting malformed cpio archive: symlink contents exceed 1 megabyte");
+ return (ARCHIVE_FATAL);
+ }
+ hl = __archive_read_ahead(a,
(size_t)cpio->entry_bytes_remaining, NULL);
- if (h == NULL)
+ if (hl == NULL)
return (ARCHIVE_FATAL);
- if (archive_entry_copy_symlink_l(entry, (const char *)h,
+ if (archive_entry_copy_symlink_l(entry, (const char *)hl,
(size_t)cpio->entry_bytes_remaining, sconv) != 0) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
@@ -427,7 +434,8 @@ archive_read_format_cpio_read_header(struct archive_read *a,
* header. XXX */
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
- if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
+ if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!",
+ 11) == 0) {
/* TODO: Store file location of start of block. */
archive_clear_error(&a->archive);
return (ARCHIVE_EOF);
@@ -807,8 +815,8 @@ header_odc(struct archive_read *a, struct cpio *cpio,
* NOTE: if a filename suffix is ".z", it is the file gziped by afio.
* it would be nice that we can show uncompressed file size and we can
* uncompressed file contents automatically, unfortunately we have nothing
- * to get a uncompressed file size while reading each header. it means
- * we also cannot uncompressed file contens under the our framework.
+ * to get a uncompressed file size while reading each header. It means
+ * we also cannot uncompress file contents under our framework.
*/
static int
header_afiol(struct archive_read *a, struct cpio *cpio,
@@ -864,8 +872,11 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
/* Read fixed-size portion of header. */
h = __archive_read_ahead(a, bin_header_size, NULL);
- if (h == NULL)
+ if (h == NULL) {
+ archive_set_error(&a->archive, 0,
+ "End of file trying to read next cpio header");
return (ARCHIVE_FATAL);
+ }
/* Parse out binary fields. */
header = (const unsigned char *)h;
@@ -900,8 +911,11 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
/* Read fixed-size portion of header. */
h = __archive_read_ahead(a, bin_header_size, NULL);
- if (h == NULL)
+ if (h == NULL) {
+ archive_set_error(&a->archive, 0,
+ "End of file trying to read next cpio header");
return (ARCHIVE_FATAL);
+ }
/* Parse out binary fields. */
header = (const unsigned char *)h;
@@ -944,17 +958,17 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
return (ARCHIVE_OK);
}
-static int
+static int64_t
le4(const unsigned char *p)
{
- return ((p[0]<<16) + (p[1]<<24) + (p[2]<<0) + (p[3]<<8));
+ return ((p[0] << 16) + (((int64_t)p[1]) << 24) + (p[2] << 0) + (p[3] << 8));
}
-static int
+static int64_t
be4(const unsigned char *p)
{
- return ((p[0]<<24) + (p[1]<<16) + (p[2]<<8) + (p[3]));
+ return ((((int64_t)p[0]) << 24) + (p[1] << 16) + (p[2] << 8) + (p[3]));
}
/*
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c
index 366073820..c641eb9b1 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_empty.c
@@ -54,6 +54,8 @@ archive_read_support_format_empty(struct archive *_a)
archive_read_format_empty_read_data,
NULL,
NULL,
+ NULL,
+ NULL,
NULL);
return (r);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
index 8147461b9..354133005 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c
@@ -322,7 +322,7 @@ struct iso9660 {
struct archive_string pathname;
char seenRockridge; /* Set true if RR extensions are used. */
- char seenSUSP; /* Set true if SUSP is beging used. */
+ char seenSUSP; /* Set true if SUSP is being used. */
char seenJoliet;
unsigned char suspOffset;
@@ -374,7 +374,7 @@ struct iso9660 {
size_t utf16be_path_len;
unsigned char *utf16be_previous_path;
size_t utf16be_previous_path_len;
- /* Null buufer used in bidder to improve its performance. */
+ /* Null buffer used in bidder to improve its performance. */
unsigned char null[2048];
};
@@ -387,7 +387,7 @@ static int archive_read_format_iso9660_read_data(struct archive_read *,
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 const char *build_pathname(struct archive_string *, struct file_info *, int);
static int build_pathname_utf16be(unsigned char *, size_t, size_t *,
struct file_info *);
#if DEBUG
@@ -478,7 +478,9 @@ archive_read_support_format_iso9660(struct archive *_a)
archive_read_format_iso9660_read_data,
archive_read_format_iso9660_read_data_skip,
NULL,
- archive_read_format_iso9660_cleanup);
+ archive_read_format_iso9660_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK) {
free(iso9660);
@@ -1089,7 +1091,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
/* This condition is unlikely; by way of caution. */
vd = &(iso9660->joliet);
- skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+ skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;
skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0)
return ((int)skipsize);
@@ -1127,7 +1129,7 @@ choose_volume(struct archive_read *a, struct iso9660 *iso9660)
&& iso9660->seenJoliet) {
/* Switch reading data from primary to joliet. */
vd = &(iso9660->joliet);
- skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+ skipsize = LOGICAL_BLOCK_SIZE * (int64_t)vd->location;
skipsize -= iso9660->current_position;
skipsize = __archive_read_consume(a, skipsize);
if (skipsize < 0)
@@ -1197,7 +1199,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
archive_string_conversion_from_charset(
&(a->archive), "UTF-16BE", 1);
if (iso9660->sconv_utf16be == NULL)
- /* Coundn't allocate memory */
+ /* Couldn't allocate memory */
return (ARCHIVE_FATAL);
}
if (iso9660->utf16be_path == NULL) {
@@ -1223,6 +1225,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Pathname is too long");
+ return (ARCHIVE_FATAL);
}
r = archive_entry_copy_pathname_l(entry,
@@ -1245,9 +1248,16 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
rd_r = ARCHIVE_WARN;
}
} else {
- archive_string_empty(&iso9660->pathname);
- archive_entry_set_pathname(entry,
- build_pathname(&iso9660->pathname, file));
+ const char *path = build_pathname(&iso9660->pathname, file, 0);
+ if (path == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Pathname is too long");
+ return (ARCHIVE_FATAL);
+ } else {
+ archive_string_empty(&iso9660->pathname);
+ archive_entry_set_pathname(entry, path);
+ }
}
iso9660->entry_bytes_remaining = file->size;
@@ -1742,12 +1752,12 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
const unsigned char *isodirrec)
{
struct iso9660 *iso9660;
- struct file_info *file;
+ struct file_info *file, *filep;
size_t name_len;
const unsigned char *rr_start, *rr_end;
const unsigned char *p;
size_t dr_len;
- uint64_t fsize;
+ uint64_t fsize, offset;
int32_t location;
int flags;
@@ -1791,6 +1801,16 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
return (NULL);
}
+ /* Sanity check that this entry does not create a cycle. */
+ offset = iso9660->logical_block_size * (uint64_t)location;
+ for (filep = parent; filep != NULL; filep = filep->parent) {
+ if (filep->offset == offset) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Directory structure contains loop");
+ 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) {
@@ -1799,7 +1819,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
return (NULL);
}
file->parent = parent;
- file->offset = iso9660->logical_block_size * (uint64_t)location;
+ file->offset = offset;
file->size = fsize;
file->mtime = isodate7(isodirrec + DR_date_offset);
file->ctime = file->atime = file->mtime;
@@ -1844,7 +1864,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
if ((file->utf16be_name = malloc(name_len)) == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for file name");
- return (NULL);
+ goto fail;
}
memcpy(file->utf16be_name, p, name_len);
file->utf16be_bytes = name_len;
@@ -1923,10 +1943,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
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);
- }
+ if (r != ARCHIVE_OK)
+ goto fail;
/*
* A file size of symbolic link files in ISO images
* made by makefs is not zero and its location is
@@ -1970,7 +1988,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge RE");
- return (NULL);
+ goto fail;
}
/*
* Sanity check: file does not have "CL" extension.
@@ -1979,7 +1997,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge RE and CL");
- return (NULL);
+ goto fail;
}
/*
* Sanity check: The file type must be a directory.
@@ -1988,7 +2006,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge RE");
- return (NULL);
+ goto fail;
}
} else if (parent != NULL && parent->rr_moved)
file->rr_moved_has_re_only = 0;
@@ -2002,7 +2020,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge CL");
- return (NULL);
+ goto fail;
}
/*
* Sanity check: The file type must be a regular file.
@@ -2011,7 +2029,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge CL");
- return (NULL);
+ goto fail;
}
parent->subdirs++;
/* Overwrite an offset and a number of this "CL" entry
@@ -2029,7 +2047,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge CL");
- return (NULL);
+ goto fail;
}
}
if (file->cl_offset == file->offset ||
@@ -2037,7 +2055,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
"Invalid Rockridge CL");
- return (NULL);
+ goto fail;
}
}
}
@@ -2068,6 +2086,10 @@ parse_file_info(struct archive_read *a, struct file_info *parent,
#endif
register_file(iso9660, file);
return (file);
+fail:
+ archive_string_free(&file->name);
+ free(file);
+ return (NULL);
}
static int
@@ -2387,7 +2409,7 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660)
return (ARCHIVE_FATAL);
} while (heap->cnt &&
heap->reqs[0].offset == iso9660->current_position);
- /* NOTE: Do not move this consume's code to fron of
+ /* NOTE: Do not move this consume's code to front of
* do-while loop. Registration of nested CE extension
* might cause error because of current position. */
__archive_read_consume(a, step);
@@ -2709,7 +2731,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
if (file == NULL) {
/*
* If directory entries all which are descendant of
- * rr_moved are stil remaning, expose their.
+ * rr_moved are still remaining, expose their.
*/
if (iso9660->re_files.first != NULL &&
iso9660->rr_moved != NULL &&
@@ -2832,7 +2854,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
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. */
+ * is not put back. */
while (iso9660->pending_files.used > 0 &&
(iso9660->pending_files.files[0]->number == -1 ||
iso9660->pending_files.files[0]->number == number)) {
@@ -2840,7 +2862,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660,
/* 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
+ * NOTE: This wrong offset was recorded by
* old mkisofs utility. If ISO images is
* created by latest mkisofs, this does not
* happen.
@@ -3145,29 +3167,39 @@ static time_t
time_from_tm(struct tm *t)
{
#if HAVE_TIMEGM
- /* Use platform timegm() if available. */
- return (timegm(t));
+ /* Use platform timegm() if available. */
+ return (timegm(t));
#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
+ return (_mkgmtime64(t));
#else
- /* Else use direct calculation using POSIX assumptions. */
- /* First, fix up tm_yday based on the year/month/day. */
- if (mktime(t) == (time_t)-1)
- return ((time_t)-1);
- /* 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);
+ /* Else use direct calculation using POSIX assumptions. */
+ /* First, fix up tm_yday based on the year/month/day. */
+ if (mktime(t) == (time_t)-1)
+ return ((time_t)-1);
+ /* 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)
+build_pathname(struct archive_string *as, struct file_info *file, int depth)
{
+ // Plain ISO9660 only allows 8 dir levels; if we get
+ // to 1000, then something is very, very wrong.
+ if (depth > 1000) {
+ return NULL;
+ }
if (file->parent != NULL && archive_strlen(&file->parent->name) > 0) {
- build_pathname(as, file->parent);
+ if (build_pathname(as, file->parent, depth + 1) == NULL) {
+ return NULL;
+ }
archive_strcat(as, "/");
}
if (archive_strlen(&file->name) == 0)
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
index f702949fb..ebd7f2ccb 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2008-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2008-2014 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -82,9 +82,6 @@ struct lzh_dec {
/* The length how many bytes we can copy decoded code from
* the window. */
int copy_len;
- /* The remaining bytes that we have not copied decoded data from
- * the window to an output buffer. */
- int w_remaining;
/*
* Bit stream reader.
@@ -140,10 +137,10 @@ struct lzh_dec {
struct lzh_stream {
const unsigned char *next_in;
- int64_t avail_in;
+ int avail_in;
int64_t total_in;
- unsigned char *next_out;
- int64_t avail_out;
+ const unsigned char *ref_ptr;
+ int avail_out;
int64_t total_out;
struct lzh_dec *ds;
};
@@ -198,9 +195,6 @@ struct lha {
char end_of_entry_cleanup;
char entry_is_compressed;
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
-
char format_name[64];
struct lzh_stream strm;
@@ -214,41 +208,6 @@ struct lha {
#define H_LEVEL_OFFSET 20 /* Header Level. */
#define H_SIZE 22 /* Minimum header size. */
-static const uint16_t crc16tbl[256] = {
- 0x0000,0xC0C1,0xC181,0x0140,0xC301,0x03C0,0x0280,0xC241,
- 0xC601,0x06C0,0x0780,0xC741,0x0500,0xC5C1,0xC481,0x0440,
- 0xCC01,0x0CC0,0x0D80,0xCD41,0x0F00,0xCFC1,0xCE81,0x0E40,
- 0x0A00,0xCAC1,0xCB81,0x0B40,0xC901,0x09C0,0x0880,0xC841,
- 0xD801,0x18C0,0x1980,0xD941,0x1B00,0xDBC1,0xDA81,0x1A40,
- 0x1E00,0xDEC1,0xDF81,0x1F40,0xDD01,0x1DC0,0x1C80,0xDC41,
- 0x1400,0xD4C1,0xD581,0x1540,0xD701,0x17C0,0x1680,0xD641,
- 0xD201,0x12C0,0x1380,0xD341,0x1100,0xD1C1,0xD081,0x1040,
- 0xF001,0x30C0,0x3180,0xF141,0x3300,0xF3C1,0xF281,0x3240,
- 0x3600,0xF6C1,0xF781,0x3740,0xF501,0x35C0,0x3480,0xF441,
- 0x3C00,0xFCC1,0xFD81,0x3D40,0xFF01,0x3FC0,0x3E80,0xFE41,
- 0xFA01,0x3AC0,0x3B80,0xFB41,0x3900,0xF9C1,0xF881,0x3840,
- 0x2800,0xE8C1,0xE981,0x2940,0xEB01,0x2BC0,0x2A80,0xEA41,
- 0xEE01,0x2EC0,0x2F80,0xEF41,0x2D00,0xEDC1,0xEC81,0x2C40,
- 0xE401,0x24C0,0x2580,0xE541,0x2700,0xE7C1,0xE681,0x2640,
- 0x2200,0xE2C1,0xE381,0x2340,0xE101,0x21C0,0x2080,0xE041,
- 0xA001,0x60C0,0x6180,0xA141,0x6300,0xA3C1,0xA281,0x6240,
- 0x6600,0xA6C1,0xA781,0x6740,0xA501,0x65C0,0x6480,0xA441,
- 0x6C00,0xACC1,0xAD81,0x6D40,0xAF01,0x6FC0,0x6E80,0xAE41,
- 0xAA01,0x6AC0,0x6B80,0xAB41,0x6900,0xA9C1,0xA881,0x6840,
- 0x7800,0xB8C1,0xB981,0x7940,0xBB01,0x7BC0,0x7A80,0xBA41,
- 0xBE01,0x7EC0,0x7F80,0xBF41,0x7D00,0xBDC1,0xBC81,0x7C40,
- 0xB401,0x74C0,0x7580,0xB541,0x7700,0xB7C1,0xB681,0x7640,
- 0x7200,0xB2C1,0xB381,0x7340,0xB101,0x71C0,0x7080,0xB041,
- 0x5000,0x90C1,0x9181,0x5140,0x9301,0x53C0,0x5280,0x9241,
- 0x9601,0x56C0,0x5780,0x9741,0x5500,0x95C1,0x9481,0x5440,
- 0x9C01,0x5CC0,0x5D80,0x9D41,0x5F00,0x9FC1,0x9E81,0x5E40,
- 0x5A00,0x9AC1,0x9B81,0x5B40,0x9901,0x59C0,0x5880,0x9841,
- 0x8801,0x48C0,0x4980,0x8941,0x4B00,0x8BC1,0x8A81,0x4A40,
- 0x4E00,0x8EC1,0x8F81,0x4F40,0x8D01,0x4DC0,0x4C80,0x8C41,
- 0x4400,0x84C1,0x8581,0x4540,0x8701,0x47C0,0x4680,0x8641,
- 0x8201,0x42C0,0x4380,0x8341,0x4100,0x81C1,0x8081,0x4040
-};
-
static int archive_read_format_lha_bid(struct archive_read *, int);
static int archive_read_format_lha_options(struct archive_read *,
const char *, const char *);
@@ -279,6 +238,7 @@ static int lha_read_data_none(struct archive_read *, const void **,
size_t *, int64_t *);
static int lha_read_data_lzh(struct archive_read *, const void **,
size_t *, int64_t *);
+static void lha_crc16_init(void);
static uint16_t lha_crc16(uint16_t, const void *, size_t);
static int lzh_decode_init(struct lzh_stream *, const char *);
static void lzh_decode_free(struct lzh_stream *);
@@ -320,7 +280,9 @@ archive_read_support_format_lha(struct archive *_a)
archive_read_format_lha_read_data,
archive_read_format_lha_read_data_skip,
NULL,
- archive_read_format_lha_cleanup);
+ archive_read_format_lha_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(lha);
@@ -518,6 +480,8 @@ archive_read_format_lha_read_header(struct archive_read *a,
const char *signature;
int err;
+ lha_crc16_init();
+
a->archive.archive_format = ARCHIVE_FORMAT_LHA;
if (a->archive.archive_format_name == NULL)
a->archive.archive_format_name = "lha";
@@ -960,6 +924,9 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha)
/* Get a real compressed file size. */
lha->compsize -= extdsize - 2;
+ if (lha->compsize < 0)
+ goto invalid; /* Invalid compressed file size */
+
if (sum_calculated != headersum) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"LHa header sum error");
@@ -1230,13 +1197,15 @@ lha_read_file_extended_header(struct archive_read *a, struct lha *lha,
archive_string_empty(&lha->filename);
break;
}
+ if (extdheader[0] == '\0')
+ goto invalid;
archive_strncpy(&lha->filename,
(const char *)extdheader, datasize);
break;
case EXT_DIRECTORY:
- if (datasize == 0)
+ if (datasize == 0 || extdheader[0] == '\0')
/* no directory name data. exit this case. */
- break;
+ goto invalid;
archive_strncpy(&lha->dirname,
(const char *)extdheader, datasize);
@@ -1376,6 +1345,26 @@ invalid:
}
static int
+lha_end_of_entry(struct archive_read *a)
+{
+ struct lha *lha = (struct lha *)(a->format->data);
+ int r = ARCHIVE_EOF;
+
+ if (!lha->end_of_entry_cleanup) {
+ if ((lha->setflag & CRC_IS_SET) &&
+ lha->crc != lha->entry_crc_calculated) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "LHa data CRC error");
+ r = ARCHIVE_WARN;
+ }
+
+ /* End-of-entry cleanup done. */
+ lha->end_of_entry_cleanup = 1;
+ }
+ return (r);
+}
+
+static int
archive_read_format_lha_read_data(struct archive_read *a,
const void **buff, size_t *size, int64_t *offset)
{
@@ -1388,22 +1377,10 @@ archive_read_format_lha_read_data(struct archive_read *a,
lha->entry_unconsumed = 0;
}
if (lha->end_of_entry) {
- if (!lha->end_of_entry_cleanup) {
- if ((lha->setflag & CRC_IS_SET) &&
- lha->crc != lha->entry_crc_calculated) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "LHa data CRC error");
- return (ARCHIVE_WARN);
- }
-
- /* End-of-entry cleanup done. */
- lha->end_of_entry_cleanup = 1;
- }
*offset = lha->entry_offset;
*size = 0;
*buff = NULL;
- return (ARCHIVE_EOF);
+ return (lha_end_of_entry(a));
}
if (lha->entry_is_compressed)
@@ -1475,18 +1452,6 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
ssize_t bytes_avail;
int r;
- /* If the buffer hasn't been allocated, allocate it now. */
- if (lha->uncompressed_buffer == NULL) {
- lha->uncompressed_buffer_size = 64 * 1024;
- lha->uncompressed_buffer
- = (unsigned char *)malloc(lha->uncompressed_buffer_size);
- if (lha->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "No memory for lzh decompression");
- return (ARCHIVE_FATAL);
- }
- }
-
/* If we haven't yet read any data, initialize the decompressor. */
if (!lha->decompress_init) {
r = lzh_decode_init(&(lha->strm), lha->method);
@@ -1532,12 +1497,9 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
if (bytes_avail > lha->entry_bytes_remaining)
bytes_avail = (ssize_t)lha->entry_bytes_remaining;
- lha->strm.avail_in = bytes_avail;
+ lha->strm.avail_in = (int)bytes_avail;
lha->strm.total_in = 0;
- if (lha->strm.avail_out == 0) {
- lha->strm.next_out = lha->uncompressed_buffer;
- lha->strm.avail_out = lha->uncompressed_buffer_size;
- }
+ lha->strm.avail_out = 0;
r = lzh_decode(&(lha->strm), bytes_avail == lha->entry_bytes_remaining);
switch (r) {
@@ -1554,10 +1516,10 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
lha->entry_unconsumed = lha->strm.total_in;
lha->entry_bytes_remaining -= lha->strm.total_in;
- if (lha->strm.avail_out == 0 || lha->end_of_entry) {
+ if (lha->strm.avail_out) {
*offset = lha->entry_offset;
- *size = lha->strm.next_out - lha->uncompressed_buffer;
- *buff = lha->uncompressed_buffer;
+ *size = lha->strm.avail_out;
+ *buff = lha->strm.ref_ptr;
lha->entry_crc_calculated =
lha_crc16(lha->entry_crc_calculated, *buff, *size);
lha->entry_offset += *size;
@@ -1565,6 +1527,8 @@ lha_read_data_lzh(struct archive_read *a, const void **buff,
*offset = lha->entry_offset;
*size = 0;
*buff = NULL;
+ if (lha->end_of_entry)
+ return (lha_end_of_entry(a));
}
return (ARCHIVE_OK);
}
@@ -1609,7 +1573,6 @@ archive_read_format_lha_cleanup(struct archive_read *a)
struct lha *lha = (struct lha *)(a->format->data);
lzh_decode_free(&(lha->strm));
- free(lha->uncompressed_buffer);
archive_string_free(&(lha->dirname));
archive_string_free(&(lha->filename));
archive_string_free(&(lha->uname));
@@ -1700,50 +1663,94 @@ lha_calcsum(unsigned char sum, const void *pp, int offset, size_t size)
return (sum);
}
-#define CRC16(crc, v) do { \
- (crc) = crc16tbl[((crc) ^ v) & 0xFF] ^ ((crc) >> 8); \
-} while (0)
+static uint16_t crc16tbl[2][256];
+static void
+lha_crc16_init(void)
+{
+ unsigned int i;
+ static int crc16init = 0;
+
+ if (crc16init)
+ return;
+ crc16init = 1;
+
+ for (i = 0; i < 256; i++) {
+ unsigned int j;
+ uint16_t crc = (uint16_t)i;
+ for (j = 8; j; j--)
+ crc = (crc >> 1) ^ ((crc & 1) * 0xA001);
+ crc16tbl[0][i] = crc;
+ }
+
+ for (i = 0; i < 256; i++) {
+ crc16tbl[1][i] = (crc16tbl[0][i] >> 8)
+ ^ crc16tbl[0][crc16tbl[0][i] & 0xff];
+ }
+}
static uint16_t
lha_crc16(uint16_t crc, const void *pp, size_t len)
{
- const unsigned char *buff = (const unsigned char *)pp;
-
- while (len >= 8) {
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- CRC16(crc, *buff++); CRC16(crc, *buff++);
- len -= 8;
+ const unsigned char *p = (const unsigned char *)pp;
+ const uint16_t *buff;
+ const union {
+ uint32_t i;
+ char c[4];
+ } u = { 0x01020304 };
+
+ if (len == 0)
+ return crc;
+
+ /* Process unaligned address. */
+ if (((uintptr_t)p) & (uintptr_t)0x1) {
+ crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];
+ len--;
}
- switch (len) {
- case 7:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 6:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 5:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 4:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 3:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 2:
- CRC16(crc, *buff++);
- /* FALL THROUGH */
- case 1:
- CRC16(crc, *buff);
- /* FALL THROUGH */
- case 0:
- break;
+ buff = (const uint16_t *)p;
+ /*
+ * Modern C compiler such as GCC does not unroll automatically yet
+ * without unrolling pragma, and Clang is so. So we should
+ * unroll this loop for its performance.
+ */
+ for (;len >= 8; len -= 8) {
+ /* This if statement expects compiler optimization will
+ * remove the statement which will not be executed. */
+#undef bswap16
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+#if defined(_MSC_VER) && _MSC_VER >= 1400 /* Visual Studio */
+# define bswap16(x) _byteswap_ushort(x)
+#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4)
+/* GCC 4.8 and later has __builtin_bswap16() */
+# define bswap16(x) __builtin_bswap16(x)
+#elif defined(__clang__) && __has_builtin(__builtin_bswap16)
+/* All clang versions have __builtin_bswap16() */
+# define bswap16(x) __builtin_bswap16(x)
+#else
+# define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8))
+#endif
+#define CRC16W do { \
+ if(u.c[0] == 1) { /* Big endian */ \
+ crc ^= bswap16(*buff); buff++; \
+ } else \
+ crc ^= *buff++; \
+ crc = crc16tbl[1][crc & 0xff] ^ crc16tbl[0][crc >> 8];\
+} while (0)
+ CRC16W;
+ CRC16W;
+ CRC16W;
+ CRC16W;
+#undef CRC16W
+#undef bswap16
}
- return (crc);
-}
+ p = (const unsigned char *)buff;
+ for (;len; len--) {
+ crc = (crc >> 8) ^ crc16tbl[0][(crc ^ *p++) & 0xff];
+ }
+ return crc;
+}
/*
* Initialize LZHUF decoder.
@@ -1782,18 +1789,18 @@ lzh_decode_init(struct lzh_stream *strm, const char *method)
return (ARCHIVE_FAILED);/* Not supported. */
}
ds->error = ARCHIVE_FATAL;
- w_size = ds->w_size;
- ds->w_size = 1U << w_bits;
+ /* Expand a window size up to 128 KiB for decompressing process
+ * performance whatever its original window size is. */
+ ds->w_size = 1U << 17;
ds->w_mask = ds->w_size -1;
- if (ds->w_buff == NULL || w_size != ds->w_size) {
- free(ds->w_buff);
+ if (ds->w_buff == NULL) {
ds->w_buff = malloc(ds->w_size);
if (ds->w_buff == NULL)
return (ARCHIVE_FATAL);
}
- memset(ds->w_buff, 0x20, ds->w_size);
+ w_size = 1U << w_bits;
+ memset(ds->w_buff + ds->w_size - w_size, 0x20, w_size);
ds->w_pos = 0;
- ds->w_remaining = 0;
ds->state = 0;
ds->pos_pt_len_size = w_bits + 1;
ds->pos_pt_len_bits = (w_bits == 15 || w_bits == 16)? 5: 4;
@@ -1880,9 +1887,10 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
int n = CACHE_BITS - br->cache_avail;
for (;;) {
- switch (n >> 3) {
- case 8:
- if (strm->avail_in >= 8) {
+ const int x = n >> 3;
+ if (strm->avail_in >= x) {
+ switch (x) {
+ case 8:
br->cache_buffer =
((uint64_t)strm->next_in[0]) << 56 |
((uint64_t)strm->next_in[1]) << 48 |
@@ -1896,10 +1904,7 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
strm->avail_in -= 8;
br->cache_avail += 8 * 8;
return (1);
- }
- break;
- case 7:
- if (strm->avail_in >= 7) {
+ case 7:
br->cache_buffer =
(br->cache_buffer << 56) |
((uint64_t)strm->next_in[0]) << 48 |
@@ -1913,10 +1918,7 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
strm->avail_in -= 7;
br->cache_avail += 7 * 8;
return (1);
- }
- break;
- case 6:
- if (strm->avail_in >= 6) {
+ case 6:
br->cache_buffer =
(br->cache_buffer << 48) |
((uint64_t)strm->next_in[0]) << 40 |
@@ -1929,14 +1931,13 @@ lzh_br_fillup(struct lzh_stream *strm, struct lzh_br *br)
strm->avail_in -= 6;
br->cache_avail += 6 * 8;
return (1);
+ case 0:
+ /* We have enough compressed data in
+ * the cache buffer.*/
+ return (1);
+ default:
+ break;
}
- break;
- case 0:
- /* We have enough compressed data in
- * the cache buffer.*/
- return (1);
- default:
- break;
}
if (strm->avail_in == 0) {
/* There is not enough compressed data to fill up the
@@ -1991,7 +1992,7 @@ static int
lzh_decode(struct lzh_stream *strm, int last)
{
struct lzh_dec *ds = strm->ds;
- int64_t avail_in;
+ int avail_in;
int r;
if (ds->error)
@@ -2008,35 +2009,12 @@ lzh_decode(struct lzh_stream *strm, int last)
return (r);
}
-static int
-lzh_copy_from_window(struct lzh_stream *strm, struct lzh_dec *ds)
+static void
+lzh_emit_window(struct lzh_stream *strm, size_t s)
{
- size_t copy_bytes;
-
- if (ds->w_remaining == 0 && ds->w_pos > 0) {
- if (ds->w_pos - ds->copy_pos <= strm->avail_out)
- copy_bytes = ds->w_pos - ds->copy_pos;
- else
- copy_bytes = (size_t)strm->avail_out;
- memcpy(strm->next_out,
- ds->w_buff + ds->copy_pos, copy_bytes);
- ds->copy_pos += (int)copy_bytes;
- } else {
- if (ds->w_remaining <= strm->avail_out)
- copy_bytes = ds->w_remaining;
- else
- copy_bytes = (size_t)strm->avail_out;
- memcpy(strm->next_out,
- ds->w_buff + ds->w_size - ds->w_remaining, copy_bytes);
- ds->w_remaining -= (int)copy_bytes;
- }
- strm->next_out += copy_bytes;
- strm->avail_out -= copy_bytes;
- strm->total_out += copy_bytes;
- if (strm->avail_out == 0)
- return (0);
- else
- return (1);
+ strm->ref_ptr = strm->ds->w_buff;
+ strm->avail_out = (int)s;
+ strm->total_out += s;
}
static int
@@ -2071,8 +2049,9 @@ lzh_read_blocks(struct lzh_stream *strm, int last)
goto failed;
}
if (ds->w_pos > 0) {
- if (!lzh_copy_from_window(strm, ds))
- return (ARCHIVE_OK);
+ lzh_emit_window(strm, ds->w_pos);
+ ds->w_pos = 0;
+ return (ARCHIVE_OK);
}
/* End of compressed data; we have completely
* handled all compressed data. */
@@ -2289,10 +2268,6 @@ lzh_decode_blocks(struct lzh_stream *strm, int last)
int lt_max_bits = lt->max_bits, pt_max_bits = pt->max_bits;
int state = ds->state;
- if (ds->w_remaining > 0) {
- if (!lzh_copy_from_window(strm, ds))
- goto next_data;
- }
for (;;) {
switch (state) {
case ST_GET_LITERAL:
@@ -2347,9 +2322,8 @@ lzh_decode_blocks(struct lzh_stream *strm, int last)
w_buff[w_pos] = c;
if (++w_pos >= w_size) {
w_pos = 0;
- ds->w_remaining = w_size;
- if (!lzh_copy_from_window(strm, ds))
- goto next_data;
+ lzh_emit_window(strm, w_size);
+ goto next_data;
}
}
/* 'c' is the length of a match pattern we have
@@ -2427,25 +2401,26 @@ lzh_decode_blocks(struct lzh_stream *strm, int last)
d = w_buff + w_pos;
s = w_buff + copy_pos;
- for (li = 0; li < l; li++)
+ for (li = 0; li < l-1;) {
+ d[li] = s[li];li++;
+ d[li] = s[li];li++;
+ }
+ if (li < l)
d[li] = s[li];
}
- w_pos = (w_pos + l) & w_mask;
- if (w_pos == 0) {
- ds->w_remaining = w_size;
- if (!lzh_copy_from_window(strm, ds)) {
- if (copy_len <= l)
- state = ST_GET_LITERAL;
- else {
- state = ST_COPY_DATA;
- ds->copy_len =
- copy_len - l;
- ds->copy_pos =
- (copy_pos + l)
- & w_mask;
- }
- goto next_data;
+ w_pos += l;
+ if (w_pos == w_size) {
+ w_pos = 0;
+ lzh_emit_window(strm, w_size);
+ if (copy_len <= l)
+ state = ST_GET_LITERAL;
+ else {
+ state = ST_COPY_DATA;
+ ds->copy_len = copy_len - l;
+ ds->copy_pos =
+ (copy_pos + l) & w_mask;
}
+ goto next_data;
}
if (copy_len <= l)
/* A copy of current pattern ended. */
@@ -2505,14 +2480,80 @@ lzh_huffman_free(struct huffman *hf)
free(hf->tree);
}
+static char bitlen_tbl[0x400] = {
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 16, 0
+};
static int
lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)
{
struct lzh_dec *ds = strm->ds;
- struct lzh_br * br = &(ds->br);
+ struct lzh_br *br = &(ds->br);
int c, i;
- for (i = start; i < end;) {
+ for (i = start; i < end; ) {
/*
* bit pattern the number we need
* 000 -> 0
@@ -2528,17 +2569,13 @@ lzh_read_pt_bitlen(struct lzh_stream *strm, int start, int end)
if (!lzh_br_read_ahead(strm, br, 3))
return (i);
if ((c = lzh_br_bits(br, 3)) == 7) {
- int d;
if (!lzh_br_read_ahead(strm, br, 13))
return (i);
- d = lzh_br_bits(br, 13);
- while (d & 0x200) {
- c++;
- d <<= 1;
- }
- if (c > 16)
+ c = bitlen_tbl[lzh_br_bits(br, 13) & 0x3FF];
+ if (c)
+ lzh_br_consume(br, c - 3);
+ else
return (-1);/* Invalid data. */
- lzh_br_consume(br, c - 3);
} else
lzh_br_consume(br, 3);
ds->pt.bitlen[i++] = c;
@@ -2601,7 +2638,7 @@ lzh_make_huffman_table(struct huffman *hf)
}
}
if (maxbits > HTBL_BITS) {
- int htbl_max;
+ unsigned htbl_max;
uint16_t *p;
diffbits = maxbits - HTBL_BITS;
@@ -2645,8 +2682,40 @@ lzh_make_huffman_table(struct huffman *hf)
return (0);/* Invalid */
/* Update the table */
p = &(tbl[ptn]);
- while (--cnt >= 0)
- p[cnt] = (uint16_t)i;
+ if (cnt > 7) {
+ uint16_t *pc;
+
+ cnt -= 8;
+ pc = &p[cnt];
+ pc[0] = (uint16_t)i;
+ pc[1] = (uint16_t)i;
+ pc[2] = (uint16_t)i;
+ pc[3] = (uint16_t)i;
+ pc[4] = (uint16_t)i;
+ pc[5] = (uint16_t)i;
+ pc[6] = (uint16_t)i;
+ pc[7] = (uint16_t)i;
+ if (cnt > 7) {
+ cnt -= 8;
+ memcpy(&p[cnt], pc,
+ 8 * sizeof(uint16_t));
+ pc = &p[cnt];
+ while (cnt > 15) {
+ cnt -= 16;
+ memcpy(&p[cnt], pc,
+ 16 * sizeof(uint16_t));
+ }
+ }
+ if (cnt)
+ memcpy(p, pc, cnt * sizeof(uint16_t));
+ } else {
+ while (cnt > 1) {
+ p[--cnt] = (uint16_t)i;
+ p[--cnt] = (uint16_t)i;
+ }
+ if (cnt)
+ p[--cnt] = (uint16_t)i;
+ }
continue;
}
@@ -2740,7 +2809,7 @@ lzh_decode_huffman(struct huffman *hf, unsigned rbits)
* If it fails, search a huffman tree for.
*/
c = hf->tbl[rbits >> hf->shift_bits];
- if (c < hf->len_avail)
+ if (c < hf->len_avail || hf->len_avail == 0)
return (c);
/* This bit pattern needs to be found out at a huffman tree. */
return (lzh_decode_huffman_tree(hf, rbits, c));
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
index c4e7021a8..4231ff500 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c
@@ -51,6 +51,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#include "archive_private.h"
#include "archive_read_private.h"
#include "archive_string.h"
+#include "archive_pack_dev.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -74,6 +75,8 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011
#define MTREE_HAS_OPTIONAL 0x0800
#define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */
+#define MTREE_HASHTABLE_SIZE 1024
+
struct mtree_option {
struct mtree_option *next;
char *value;
@@ -85,6 +88,8 @@ struct mtree_entry {
char *name;
char full;
char used;
+ unsigned int name_hash;
+ struct mtree_entry *hashtable_next;
};
struct mtree {
@@ -97,17 +102,20 @@ struct mtree {
const char *archive_format_name;
struct mtree_entry *entries;
struct mtree_entry *this_entry;
+ struct mtree_entry *entry_hashtable[MTREE_HASHTABLE_SIZE];
struct archive_string current_dir;
struct archive_string contents_name;
struct archive_entry_linkresolver *resolver;
int64_t cur_size;
+ char checkfs;
};
static int bid_keycmp(const char *, const char *, ssize_t);
static int cleanup(struct archive_read *);
static int detect_form(struct archive_read *, int *);
+static unsigned int hash(const char *);
static int mtree_bid(struct archive_read *, int);
static int parse_file(struct archive_read *, struct archive_entry *,
struct mtree *, struct mtree_entry *, int *);
@@ -137,16 +145,22 @@ get_time_t_max(void)
#if defined(TIME_T_MAX)
return TIME_T_MAX;
#else
- static time_t t;
- time_t a;
- if (t == 0) {
- a = 1;
- while (a > t) {
- t = a;
- a = a * 2 + 1;
+ /* ISO C allows time_t to be a floating-point type,
+ but POSIX requires an integer type. The following
+ should work on any system that follows the POSIX
+ conventions. */
+ if (((time_t)0) < ((time_t)-1)) {
+ /* Time_t is unsigned */
+ return (~(time_t)0);
+ } else {
+ /* Time_t is signed. */
+ /* Assume it's the same as int64_t or int32_t */
+ if (sizeof(time_t) == sizeof(int64_t)) {
+ return (time_t)INT64_MAX;
+ } else {
+ return (time_t)INT32_MAX;
}
}
- return t;
#endif
}
@@ -156,23 +170,43 @@ get_time_t_min(void)
#if defined(TIME_T_MIN)
return TIME_T_MIN;
#else
- /* 't' will hold the minimum value, which will be zero (if
- * time_t is unsigned) or -2^n (if time_t is signed). */
- static int computed;
- static time_t t;
- time_t a;
- if (computed == 0) {
- a = (time_t)-1;
- while (a < t) {
- t = a;
- a = a * 2;
- }
- computed = 1;
+ if (((time_t)0) < ((time_t)-1)) {
+ /* Time_t is unsigned */
+ return (time_t)0;
+ } else {
+ /* Time_t is signed. */
+ if (sizeof(time_t) == sizeof(int64_t)) {
+ return (time_t)INT64_MIN;
+ } else {
+ return (time_t)INT32_MIN;
+ }
}
- return t;
#endif
}
+static int
+archive_read_format_mtree_options(struct archive_read *a,
+ const char *key, const char *val)
+{
+ struct mtree *mtree;
+
+ mtree = (struct mtree *)(a->format->data);
+ if (strcmp(key, "checkfs") == 0) {
+ /* Allows to read information missing from the mtree from the file system */
+ if (val == NULL || val[0] == 0) {
+ mtree->checkfs = 0;
+ } else {
+ mtree->checkfs = 1;
+ }
+ 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 void
free_options(struct mtree_option *head)
{
@@ -195,17 +229,16 @@ archive_read_support_format_mtree(struct archive *_a)
archive_check_magic(_a, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_NEW, "archive_read_support_format_mtree");
- mtree = (struct mtree *)malloc(sizeof(*mtree));
+ mtree = (struct mtree *)calloc(1, sizeof(*mtree));
if (mtree == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate mtree data");
return (ARCHIVE_FATAL);
}
- memset(mtree, 0, sizeof(*mtree));
mtree->fd = -1;
r = __archive_read_register_format(a, mtree, "mtree",
- mtree_bid, NULL, read_header, read_data, skip, NULL, cleanup);
+ mtree_bid, archive_read_format_mtree_options, read_header, read_data, skip, NULL, cleanup, NULL, NULL);
if (r != ARCHIVE_OK)
free(mtree);
@@ -273,6 +306,15 @@ get_line_size(const char *b, ssize_t avail, ssize_t *nlsize)
return (avail);
}
+/*
+ * <---------------- ravail --------------------->
+ * <-- diff ------> <--- avail ----------------->
+ * <---- len ----------->
+ * | Previous lines | line being parsed nl extra |
+ * ^
+ * b
+ *
+ */
static ssize_t
next_line(struct archive_read *a,
const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl)
@@ -311,7 +353,7 @@ next_line(struct archive_read *a,
*b += diff;
*avail -= diff;
tested = len;/* Skip some bytes we already determinated. */
- len = get_line_size(*b, *avail, nl);
+ len = get_line_size(*b + len, *avail - len, nl);
if (len >= 0)
len += tested;
}
@@ -367,7 +409,7 @@ bid_keyword(const char *p, ssize_t len)
"gid", "gname", NULL
};
static const char *keys_il[] = {
- "ignore", "link", NULL
+ "ignore", "inode", "link", NULL
};
static const char *keys_m[] = {
"md5", "md5digest", "mode", NULL
@@ -376,7 +418,7 @@ bid_keyword(const char *p, ssize_t len)
"nlink", "nochange", "optional", NULL
};
static const char *keys_r[] = {
- "rmd160", "rmd160digest", NULL
+ "resdevice", "rmd160", "rmd160digest", NULL
};
static const char *keys_s[] = {
"sha1", "sha1digest",
@@ -507,32 +549,34 @@ bid_entry(const char *p, ssize_t len, ssize_t nl, int *last_is_path)
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* F0 - FF */
};
- ssize_t ll = len;
+ ssize_t ll;
const char *pp = p;
+ const char * const pp_end = pp + len;
*last_is_path = 0;
/*
* Skip the path-name which is quoted.
*/
- while (ll > 0 && *pp != ' ' &&*pp != '\t' && *pp != '\r' &&
- *pp != '\n') {
+ for (;pp < pp_end; ++pp) {
if (!safe_char[*(const unsigned char *)pp]) {
- f = 0;
+ if (*pp != ' ' && *pp != '\t' && *pp != '\r'
+ && *pp != '\n')
+ f = 0;
break;
}
- ++pp;
- --ll;
- ++f;
+ f = 1;
}
+ ll = pp_end - pp;
+
/* If a path-name was not found at the first, try to check
- * a mtree format ``NetBSD's mtree -D'' creates, which
- * places the path-name at the last. */
+ * a mtree format(a.k.a form D) ``NetBSD's mtree -D'' creates,
+ * which places the path-name at the last. */
if (f == 0) {
const char *pb = p + len - nl;
int name_len = 0;
int slash;
- /* Do not accept multi lines for form D. */
+ /* The form D accepts only a single line for an entry. */
if (pb-2 >= p &&
pb[-1] == '\\' && (pb[-2] == ' ' || pb[-2] == '\t'))
return (-1);
@@ -671,13 +715,13 @@ detect_form(struct archive_read *a, int *is_form_d)
}
} else
break;
- } else if (strncmp(p, "/set", 4) == 0) {
+ } else if (len > 4 && strncmp(p, "/set", 4) == 0) {
if (bid_keyword_list(p+4, len-4, 0, 0) <= 0)
break;
/* This line continues. */
if (p[len-nl-1] == '\\')
multiline = 2;
- } else if (strncmp(p, "/unset", 6) == 0) {
+ } else if (len > 6 && strncmp(p, "/unset", 6) == 0) {
if (bid_keyword_list(p+6, len-6, 1, 0) <= 0)
break;
/* This line continues. */
@@ -823,11 +867,12 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
struct mtree_option **global, const char *line, ssize_t line_len,
struct mtree_entry **last_entry, int is_form_d)
{
- struct mtree_entry *entry;
+ struct mtree_entry *entry, *ht_iter;
struct mtree_option *iter;
const char *next, *eq, *name, *end;
- size_t len;
- int r;
+ size_t name_len, len;
+ int r, i;
+ unsigned int ht_idx;
if ((entry = malloc(sizeof(*entry))) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory");
@@ -838,6 +883,8 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
entry->name = NULL;
entry->used = 0;
entry->full = 0;
+ entry->name_hash = 0;
+ entry->hashtable_next = NULL;
/* Add this entry to list. */
if (*last_entry == NULL)
@@ -847,44 +894,59 @@ process_add_entry(struct archive_read *a, struct mtree *mtree,
*last_entry = entry;
if (is_form_d) {
- /*
- * This form places the file name as last parameter.
- */
- name = line + line_len -1;
+ /* Filename is last item on line. */
+ /* Adjust line_len to trim trailing whitespace */
while (line_len > 0) {
- if (*name != '\r' && *name != '\n' &&
- *name != '\t' && *name != ' ')
+ char last_character = line[line_len - 1];
+ if (last_character == '\r'
+ || last_character == '\n'
+ || last_character == '\t'
+ || last_character == ' ') {
+ line_len--;
+ } else {
break;
- name--;
- line_len--;
+ }
}
- len = 0;
- while (line_len > 0) {
- if (*name == '\r' || *name == '\n' ||
- *name == '\t' || *name == ' ') {
- name++;
- break;
+ /* Name starts after the last whitespace separator */
+ name = line;
+ for (i = 0; i < line_len; i++) {
+ if (line[i] == '\r'
+ || line[i] == '\n'
+ || line[i] == '\t'
+ || line[i] == ' ') {
+ name = line + i + 1;
}
- name--;
- line_len--;
- len++;
}
+ name_len = line + line_len - name;
end = name;
} else {
- len = strcspn(line, " \t\r\n");
+ /* Filename is first item on line */
+ name_len = strcspn(line, " \t\r\n");
name = line;
- line += len;
+ line += name_len;
end = line + line_len;
}
+ /* name/name_len is the name within the line. */
+ /* line..end brackets the entire line except the name */
- if ((entry->name = malloc(len + 1)) == NULL) {
+ if ((entry->name = malloc(name_len + 1)) == NULL) {
archive_set_error(&a->archive, errno, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
- memcpy(entry->name, name, len);
- entry->name[len] = '\0';
+ memcpy(entry->name, name, name_len);
+ entry->name[name_len] = '\0';
parse_escapes(entry->name, entry);
+ entry->name_hash = hash(entry->name);
+
+ ht_idx = entry->name_hash % MTREE_HASHTABLE_SIZE;
+ if ((ht_iter = mtree->entry_hashtable[ht_idx]) != NULL) {
+ while (ht_iter->hashtable_next)
+ ht_iter = ht_iter->hashtable_next;
+ ht_iter->hashtable_next = entry;
+ } else {
+ mtree->entry_hashtable[ht_idx] = entry;
+ }
for (iter = *global; iter != NULL; iter = iter->next) {
r = add_option(a, &entry->options, iter->value,
@@ -957,11 +1019,11 @@ read_mtree(struct archive_read *a, struct mtree *mtree)
if (*p != '/') {
r = process_add_entry(a, mtree, &global, p, len,
&last_entry, is_form_d);
- } else if (strncmp(p, "/set", 4) == 0) {
+ } else if (len > 4 && strncmp(p, "/set", 4) == 0) {
if (p[4] != ' ' && p[4] != '\t')
break;
r = process_global_set(a, &global, p);
- } else if (strncmp(p, "/unset", 6) == 0) {
+ } else if (len > 6 && strncmp(p, "/unset", 6) == 0) {
if (p[6] != ' ' && p[6] != '\t')
break;
r = process_global_unset(a, &global, p);
@@ -1031,7 +1093,8 @@ read_header(struct archive_read *a, struct archive_entry *entry)
}
if (!mtree->this_entry->used) {
use_next = 0;
- r = parse_file(a, entry, mtree, mtree->this_entry, &use_next);
+ r = parse_file(a, entry, mtree, mtree->this_entry,
+ &use_next);
if (use_next == 0)
return (r);
}
@@ -1077,9 +1140,10 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
* with pathname canonicalization, which is a very
* tricky subject.)
*/
- for (mp = mentry->next; mp != NULL; mp = mp->next) {
+ for (mp = mentry->hashtable_next; mp != NULL; mp = mp->hashtable_next) {
if (mp->full && !mp->used
- && strcmp(mentry->name, mp->name) == 0) {
+ && mentry->name_hash == mp->name_hash
+ && strcmp(mentry->name, mp->name) == 0) {
/* Later lines override earlier ones. */
mp->used = 1;
r1 = parse_line(a, entry, mtree, mp,
@@ -1103,162 +1167,168 @@ parse_file(struct archive_read *a, struct archive_entry *entry,
mtree->current_dir.length = n;
}
- /*
- * Try to open and stat the file to get the real size
- * and other file info. It would be nice to avoid
- * this here so that getting a listing of an mtree
- * wouldn't require opening every referenced contents
- * file. But then we wouldn't know the actual
- * contents size, so I don't see a really viable way
- * around this. (Also, we may want to someday pull
- * other unspecified info from the contents file on
- * disk.)
- */
- mtree->fd = -1;
- if (archive_strlen(&mtree->contents_name) > 0)
- path = mtree->contents_name.s;
- else
- path = archive_entry_pathname(entry);
-
- if (archive_entry_filetype(entry) == AE_IFREG ||
- archive_entry_filetype(entry) == AE_IFDIR) {
- mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(mtree->fd);
- if (mtree->fd == -1 &&
- (errno != ENOENT ||
- archive_strlen(&mtree->contents_name) > 0)) {
- archive_set_error(&a->archive, errno,
- "Can't open %s", path);
- r = ARCHIVE_WARN;
+ if (mtree->checkfs) {
+ /*
+ * Try to open and stat the file to get the real size
+ * and other file info. It would be nice to avoid
+ * this here so that getting a listing of an mtree
+ * wouldn't require opening every referenced contents
+ * file. But then we wouldn't know the actual
+ * contents size, so I don't see a really viable way
+ * around this. (Also, we may want to someday pull
+ * other unspecified info from the contents file on
+ * disk.)
+ */
+ mtree->fd = -1;
+ if (archive_strlen(&mtree->contents_name) > 0)
+ path = mtree->contents_name.s;
+ else
+ path = archive_entry_pathname(entry);
+
+ if (archive_entry_filetype(entry) == AE_IFREG ||
+ archive_entry_filetype(entry) == AE_IFDIR) {
+ mtree->fd = open(path, O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(mtree->fd);
+ if (mtree->fd == -1 &&
+ (errno != ENOENT ||
+ archive_strlen(&mtree->contents_name) > 0)) {
+ archive_set_error(&a->archive, errno,
+ "Can't open %s", path);
+ r = ARCHIVE_WARN;
+ }
}
- }
- st = &st_storage;
- if (mtree->fd >= 0) {
- if (fstat(mtree->fd, st) == -1) {
- archive_set_error(&a->archive, errno,
- "Could not fstat %s", path);
- r = ARCHIVE_WARN;
- /* If we can't stat it, don't keep it open. */
- close(mtree->fd);
- mtree->fd = -1;
+ st = &st_storage;
+ if (mtree->fd >= 0) {
+ if (fstat(mtree->fd, st) == -1) {
+ archive_set_error(&a->archive, errno,
+ "Could not fstat %s", path);
+ r = ARCHIVE_WARN;
+ /* If we can't stat it, don't keep it open. */
+ close(mtree->fd);
+ mtree->fd = -1;
+ st = NULL;
+ }
+ } else if (lstat(path, st) == -1) {
st = NULL;
}
- } else if (lstat(path, st) == -1) {
- st = NULL;
- }
- /*
- * Check for a mismatch between the type in the specification and
- * the type of the contents object on disk.
- */
- if (st != NULL) {
- if (
- ((st->st_mode & S_IFMT) == S_IFREG &&
- archive_entry_filetype(entry) == AE_IFREG)
+ /*
+ * Check for a mismatch between the type in the specification
+ * and the type of the contents object on disk.
+ */
+ if (st != NULL) {
+ if (((st->st_mode & S_IFMT) == S_IFREG &&
+ archive_entry_filetype(entry) == AE_IFREG)
#ifdef S_IFLNK
- || ((st->st_mode & S_IFMT) == S_IFLNK &&
- archive_entry_filetype(entry) == AE_IFLNK)
+ ||((st->st_mode & S_IFMT) == S_IFLNK &&
+ archive_entry_filetype(entry) == AE_IFLNK)
#endif
#ifdef S_IFSOCK
- || ((st->st_mode & S_IFSOCK) == S_IFSOCK &&
- archive_entry_filetype(entry) == AE_IFSOCK)
+ ||((st->st_mode & S_IFSOCK) == S_IFSOCK &&
+ archive_entry_filetype(entry) == AE_IFSOCK)
#endif
#ifdef S_IFCHR
- || ((st->st_mode & S_IFMT) == S_IFCHR &&
- archive_entry_filetype(entry) == AE_IFCHR)
+ ||((st->st_mode & S_IFMT) == S_IFCHR &&
+ archive_entry_filetype(entry) == AE_IFCHR)
#endif
#ifdef S_IFBLK
- || ((st->st_mode & S_IFMT) == S_IFBLK &&
- archive_entry_filetype(entry) == AE_IFBLK)
+ ||((st->st_mode & S_IFMT) == S_IFBLK &&
+ archive_entry_filetype(entry) == AE_IFBLK)
#endif
- || ((st->st_mode & S_IFMT) == S_IFDIR &&
- archive_entry_filetype(entry) == AE_IFDIR)
+ ||((st->st_mode & S_IFMT) == S_IFDIR &&
+ archive_entry_filetype(entry) == AE_IFDIR)
#ifdef S_IFIFO
- || ((st->st_mode & S_IFMT) == S_IFIFO &&
- archive_entry_filetype(entry) == AE_IFIFO)
+ ||((st->st_mode & S_IFMT) == S_IFIFO &&
+ archive_entry_filetype(entry) == AE_IFIFO)
#endif
- ) {
- /* Types match. */
- } else {
- /* Types don't match; bail out gracefully. */
- if (mtree->fd >= 0)
- close(mtree->fd);
- mtree->fd = -1;
- if (parsed_kws & MTREE_HAS_OPTIONAL) {
- /* It's not an error for an optional entry
- to not match disk. */
- *use_next = 1;
- } else if (r == ARCHIVE_OK) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "mtree specification has different type for %s",
- archive_entry_pathname(entry));
- r = ARCHIVE_WARN;
+ ) {
+ /* Types match. */
+ } else {
+ /* Types don't match; bail out gracefully. */
+ if (mtree->fd >= 0)
+ close(mtree->fd);
+ mtree->fd = -1;
+ if (parsed_kws & MTREE_HAS_OPTIONAL) {
+ /* It's not an error for an optional
+ * entry to not match disk. */
+ *use_next = 1;
+ } else if (r == ARCHIVE_OK) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "mtree specification has different"
+ " type for %s",
+ archive_entry_pathname(entry));
+ r = ARCHIVE_WARN;
+ }
+ return (r);
}
- return r;
}
- }
- /*
- * If there is a contents file on disk, pick some of the metadata
- * from that file. For most of these, we only set it from the contents
- * if it wasn't already parsed from the specification.
- */
- if (st != NULL) {
- if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
- (archive_entry_filetype(entry) == AE_IFCHR ||
- archive_entry_filetype(entry) == AE_IFBLK))
- archive_entry_set_rdev(entry, st->st_rdev);
- if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_gid(entry, st->st_gid);
- if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_uid(entry, st->st_uid);
- if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
+ /*
+ * If there is a contents file on disk, pick some of the
+ * metadata from that file. For most of these, we only
+ * set it from the contents if it wasn't already parsed
+ * from the specification.
+ */
+ if (st != NULL) {
+ if (((parsed_kws & MTREE_HAS_DEVICE) == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) &&
+ (archive_entry_filetype(entry) == AE_IFCHR ||
+ archive_entry_filetype(entry) == AE_IFBLK))
+ archive_entry_set_rdev(entry, st->st_rdev);
+ if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME))
+ == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
+ archive_entry_set_gid(entry, st->st_gid);
+ if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME))
+ == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
+ archive_entry_set_uid(entry, st->st_uid);
+ if ((parsed_kws & MTREE_HAS_MTIME) == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0) {
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtimespec.tv_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime,
+ st->st_mtimespec.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtim.tv_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime,
+ st->st_mtim.tv_nsec);
#elif HAVE_STRUCT_STAT_ST_MTIME_N
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtime_n);
+ archive_entry_set_mtime(entry, st->st_mtime,
+ st->st_mtime_n);
#elif HAVE_STRUCT_STAT_ST_UMTIME
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_umtime*1000);
+ archive_entry_set_mtime(entry, st->st_mtime,
+ st->st_umtime*1000);
#elif HAVE_STRUCT_STAT_ST_MTIME_USEC
- archive_entry_set_mtime(entry, st->st_mtime,
- st->st_mtime_usec*1000);
+ archive_entry_set_mtime(entry, st->st_mtime,
+ st->st_mtime_usec*1000);
#else
- archive_entry_set_mtime(entry, st->st_mtime, 0);
+ archive_entry_set_mtime(entry, st->st_mtime, 0);
#endif
+ }
+ if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
+ archive_entry_set_nlink(entry, st->st_nlink);
+ if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
+ archive_entry_set_perm(entry, st->st_mode);
+ if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
+ (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
+ archive_entry_set_size(entry, st->st_size);
+ archive_entry_set_ino(entry, st->st_ino);
+ archive_entry_set_dev(entry, st->st_dev);
+
+ archive_entry_linkify(mtree->resolver, &entry,
+ &sparse_entry);
+ } else if (parsed_kws & MTREE_HAS_OPTIONAL) {
+ /*
+ * Couldn't open the entry, stat it or the on-disk type
+ * didn't match. If this entry is optional, just
+ * ignore it and read the next header entry.
+ */
+ *use_next = 1;
+ return ARCHIVE_OK;
}
- if ((parsed_kws & MTREE_HAS_NLINK) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_nlink(entry, st->st_nlink);
- if ((parsed_kws & MTREE_HAS_PERM) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_perm(entry, st->st_mode);
- if ((parsed_kws & MTREE_HAS_SIZE) == 0 ||
- (parsed_kws & MTREE_HAS_NOCHANGE) != 0)
- archive_entry_set_size(entry, st->st_size);
- archive_entry_set_ino(entry, st->st_ino);
- archive_entry_set_dev(entry, st->st_dev);
-
- archive_entry_linkify(mtree->resolver, &entry, &sparse_entry);
- } else if (parsed_kws & MTREE_HAS_OPTIONAL) {
- /*
- * Couldn't open the entry, stat it or the on-disk type
- * didn't match. If this entry is optional, just ignore it
- * and read the next header entry.
- */
- *use_next = 1;
- return ARCHIVE_OK;
}
mtree->cur_size = archive_entry_size(entry);
@@ -1292,33 +1362,82 @@ parse_line(struct archive_read *a, struct archive_entry *entry,
/*
* Device entries have one of the following forms:
- * raw dev_t
- * format,major,minor[,subdevice]
- *
- * Just use major and minor, no translation etc is done
- * between formats.
+ * - raw dev_t
+ * - format,major,minor[,subdevice]
+ * When parsing succeeded, `pdev' will contain the appropriate dev_t value.
*/
-static int
-parse_device(struct archive *a, struct archive_entry *entry, char *val)
+
+/* strsep() is not in C90, but strcspn() is. */
+/* Taken from http://unixpapa.com/incnote/string.html */
+static char *
+la_strsep(char **sp, const char *sep)
{
- char *comma1, *comma2;
+ char *p, *s;
+ if (sp == NULL || *sp == NULL || **sp == '\0')
+ return(NULL);
+ s = *sp;
+ p = s + strcspn(s, sep);
+ if (*p != '\0')
+ *p++ = '\0';
+ *sp = p;
+ return(s);
+}
- comma1 = strchr(val, ',');
- if (comma1 == NULL) {
- archive_entry_set_dev(entry, (dev_t)mtree_atol10(&val));
- return (ARCHIVE_OK);
- }
- ++comma1;
- comma2 = strchr(comma1, ',');
- if (comma2 == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
- "Malformed device attribute");
- return (ARCHIVE_WARN);
+static int
+parse_device(dev_t *pdev, struct archive *a, char *val)
+{
+#define MAX_PACK_ARGS 3
+ unsigned long numbers[MAX_PACK_ARGS];
+ char *p, *dev;
+ int argc;
+ pack_t *pack;
+ dev_t result;
+ const char *error = NULL;
+
+ memset(pdev, 0, sizeof(*pdev));
+ if ((dev = strchr(val, ',')) != NULL) {
+ /*
+ * Device's major/minor are given in a specified format.
+ * Decode and pack it accordingly.
+ */
+ *dev++ = '\0';
+ if ((pack = pack_find(val)) == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown format `%s'", val);
+ return ARCHIVE_WARN;
+ }
+ argc = 0;
+ while ((p = la_strsep(&dev, ",")) != NULL) {
+ if (*p == '\0') {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Missing number");
+ return ARCHIVE_WARN;
+ }
+ if (argc >= MAX_PACK_ARGS) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Too many arguments");
+ return ARCHIVE_WARN;
+ }
+ numbers[argc++] = (unsigned long)mtree_atol(&p);
+ }
+ if (argc < 2) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Not enough arguments");
+ return ARCHIVE_WARN;
+ }
+ result = (*pack)(argc, numbers, &error);
+ if (error != NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ "%s", error);
+ return ARCHIVE_WARN;
+ }
+ } else {
+ /* file system raw value. */
+ result = (dev_t)mtree_atol(&val);
}
- ++comma2;
- archive_entry_set_rdevmajor(entry, (dev_t)mtree_atol(&comma1));
- archive_entry_set_rdevminor(entry, (dev_t)mtree_atol(&comma2));
- return (ARCHIVE_OK);
+ *pdev = result;
+ return ARCHIVE_OK;
+#undef MAX_PACK_ARGS
}
/*
@@ -1374,8 +1493,16 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
break;
case 'd':
if (strcmp(key, "device") == 0) {
+ /* stat(2) st_rdev field, e.g. the major/minor IDs
+ * of a char/block special file */
+ int r;
+ dev_t dev;
+
*parsed_kws |= MTREE_HAS_DEVICE;
- return parse_device(&a->archive, entry, val);
+ r = parse_device(&dev, &a->archive, val);
+ if (r == ARCHIVE_OK)
+ archive_entry_set_rdev(entry, dev);
+ return r;
}
case 'f':
if (strcmp(key, "flags") == 0) {
@@ -1394,6 +1521,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
archive_entry_copy_gname(entry, val);
break;
}
+ case 'i':
+ if (strcmp(key, "inode") == 0) {
+ archive_entry_set_ino(entry, mtree_atol10(&val));
+ break;
+ }
case 'l':
if (strcmp(key, "link") == 0) {
archive_entry_copy_symlink(entry, val);
@@ -1423,6 +1555,17 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
break;
}
case 'r':
+ if (strcmp(key, "resdevice") == 0) {
+ /* stat(2) st_dev field, e.g. the device ID where the
+ * inode resides */
+ int r;
+ dev_t dev;
+
+ r = parse_device(&dev, &a->archive, val);
+ if (r == ARCHIVE_OK)
+ archive_entry_set_dev(entry, dev);
+ return r;
+ }
if (strcmp(key, "rmd160") == 0 ||
strcmp(key, "rmd160digest") == 0)
break;
@@ -1455,7 +1598,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
int64_t m;
int64_t my_time_t_max = get_time_t_max();
int64_t my_time_t_min = get_time_t_min();
- long ns;
+ long ns = 0;
*parsed_kws |= MTREE_HAS_MTIME;
m = mtree_atol10(&val);
@@ -1465,8 +1608,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
if (*val == '.') {
++val;
ns = (long)mtree_atol10(&val);
- } else
- ns = 0;
+ if (ns < 0)
+ ns = 0;
+ else if (ns > 999999999)
+ ns = 999999999;
+ }
if (m > my_time_t_max)
m = my_time_t_max;
else if (m < my_time_t_min)
@@ -1483,32 +1629,38 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
case 'c':
if (strcmp(val, "char") == 0) {
- archive_entry_set_filetype(entry, AE_IFCHR);
+ archive_entry_set_filetype(entry,
+ AE_IFCHR);
break;
}
case 'd':
if (strcmp(val, "dir") == 0) {
- archive_entry_set_filetype(entry, AE_IFDIR);
+ archive_entry_set_filetype(entry,
+ AE_IFDIR);
break;
}
case 'f':
if (strcmp(val, "fifo") == 0) {
- archive_entry_set_filetype(entry, AE_IFIFO);
+ archive_entry_set_filetype(entry,
+ AE_IFIFO);
break;
}
if (strcmp(val, "file") == 0) {
- archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_set_filetype(entry,
+ AE_IFREG);
break;
}
case 'l':
if (strcmp(val, "link") == 0) {
- archive_entry_set_filetype(entry, AE_IFLNK);
+ archive_entry_set_filetype(entry,
+ AE_IFLNK);
break;
}
default:
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized file type \"%s\"; assuming \"file\"", val);
+ "Unrecognized file type \"%s\"; "
+ "assuming \"file\"", val);
archive_entry_set_filetype(entry, AE_IFREG);
return (ARCHIVE_WARN);
}
@@ -1535,7 +1687,8 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
}
static int
-read_data(struct archive_read *a, const void **buff, size_t *size, int64_t *offset)
+read_data(struct archive_read *a, const void **buff, size_t *size,
+ int64_t *offset)
{
size_t bytes_to_read;
ssize_t bytes_read;
@@ -1661,6 +1814,10 @@ parse_escapes(char *src, struct mtree_entry *mentry)
c = '\v';
++src;
break;
+ case '\\':
+ c = '\\';
+ ++src;
+ break;
}
}
*dest++ = c;
@@ -1798,14 +1955,14 @@ mtree_atol(char **p)
* point to first character of line.
*/
static ssize_t
-readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limit)
+readline(struct archive_read *a, struct mtree *mtree, char **start,
+ ssize_t limit)
{
ssize_t bytes_read;
ssize_t total_size = 0;
ssize_t find_off = 0;
const void *t;
- const char *s;
- void *p;
+ void *nl;
char *u;
/* Accumulate line in a line buffer. */
@@ -1816,11 +1973,10 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
return (0);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
- s = t; /* Start of line? */
- p = memchr(t, '\n', bytes_read);
- /* If we found '\n', trim the read. */
- if (p != NULL) {
- bytes_read = 1 + ((const char *)p) - s;
+ nl = memchr(t, '\n', bytes_read);
+ /* If we found '\n', trim the read to end exactly there. */
+ if (nl != NULL) {
+ bytes_read = ((const char *)nl) - ((const char *)t) + 1;
}
if (total_size + bytes_read + 1 > limit) {
archive_set_error(&a->archive,
@@ -1834,39 +1990,51 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
"Can't allocate working buffer");
return (ARCHIVE_FATAL);
}
+ /* Append new bytes to string. */
memcpy(mtree->line.s + total_size, t, bytes_read);
__archive_read_consume(a, bytes_read);
total_size += bytes_read;
- /* Null terminate. */
mtree->line.s[total_size] = '\0';
- /* If we found an unescaped '\n', clean up and return. */
+
for (u = mtree->line.s + find_off; *u; ++u) {
if (u[0] == '\n') {
+ /* Ends with unescaped newline. */
*start = mtree->line.s;
return total_size;
- }
- if (u[0] == '#') {
- if (p == NULL)
+ } else if (u[0] == '#') {
+ /* Ends with comment sequence #...\n */
+ if (nl == NULL) {
+ /* But we've not found the \n yet */
break;
- *start = mtree->line.s;
- return total_size;
- }
- if (u[0] != '\\')
- continue;
- if (u[1] == '\\') {
- ++u;
- continue;
- }
- if (u[1] == '\n') {
- memmove(u, u + 1,
- total_size - (u - mtree->line.s) + 1);
- --total_size;
- ++u;
- break;
+ }
+ } else if (u[0] == '\\') {
+ if (u[1] == '\n') {
+ /* Trim escaped newline. */
+ total_size -= 2;
+ mtree->line.s[total_size] = '\0';
+ break;
+ } else if (u[1] != '\0') {
+ /* Skip the two-char escape sequence */
+ ++u;
+ }
}
- if (u[1] == '\0')
- break;
}
find_off = u - mtree->line.s;
}
}
+
+static unsigned int
+hash(const char *p)
+{
+ /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
+ as used by ELF for hashing function names. */
+ unsigned g, h = 0;
+ while (*p != '\0') {
+ h = (h << 4) + *p++;
+ if ((g = h & 0xF0000000) != 0) {
+ h ^= g >> 24;
+ h &= 0x0FFFFFFF;
+ }
+ }
+ return h;
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
index dc1563d9e..658d49d50 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c
@@ -186,6 +186,7 @@ struct huffman_code
{
struct huffman_tree_node *tree;
int numentries;
+ int numallocatedentries;
int minlength;
int maxlength;
int tablesize;
@@ -225,6 +226,7 @@ struct rar
mode_t mode;
char *filename;
char *filename_save;
+ size_t filename_save_size;
size_t filename_allocated;
/* File header optional entries */
@@ -304,8 +306,15 @@ struct rar
ssize_t avail_in;
const unsigned char *next_in;
} br;
+
+ /*
+ * Custom field to denote that this archive contains encrypted entries
+ */
+ int has_encrypted_entries;
};
+static int archive_read_support_format_rar_capabilities(struct archive_read *);
+static int archive_read_format_rar_has_encrypted_entries(struct archive_read *);
static int archive_read_format_rar_bid(struct archive_read *, int);
static int archive_read_format_rar_options(struct archive_read *,
const char *, const char *);
@@ -638,13 +647,18 @@ archive_read_support_format_rar(struct archive *_a)
archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
"archive_read_support_format_rar");
- rar = (struct rar *)malloc(sizeof(*rar));
+ rar = (struct rar *)calloc(sizeof(*rar), 1);
if (rar == NULL)
{
archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data");
return (ARCHIVE_FATAL);
}
- memset(rar, 0, sizeof(*rar));
+
+ /*
+ * Until enough data has been read, we cannot tell about
+ * any encrypted entries yet.
+ */
+ rar->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
r = __archive_read_register_format(a,
rar,
@@ -655,7 +669,9 @@ archive_read_support_format_rar(struct archive *_a)
archive_read_format_rar_read_data,
archive_read_format_rar_read_data_skip,
archive_read_format_rar_seek_data,
- archive_read_format_rar_cleanup);
+ archive_read_format_rar_cleanup,
+ archive_read_support_format_rar_capabilities,
+ archive_read_format_rar_has_encrypted_entries);
if (r != ARCHIVE_OK)
free(rar);
@@ -663,6 +679,27 @@ archive_read_support_format_rar(struct archive *_a)
}
static int
+archive_read_support_format_rar_capabilities(struct archive_read * a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA
+ | ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+}
+
+static int
+archive_read_format_rar_has_encrypted_entries(struct archive_read *_a)
+{
+ if (_a && _a->format) {
+ struct rar * rar = (struct rar *)_a->format->data;
+ if (rar) {
+ return rar->has_encrypted_entries;
+ }
+ }
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+}
+
+
+static int
archive_read_format_rar_bid(struct archive_read *a, int best_bid)
{
const char *p;
@@ -755,7 +792,7 @@ archive_read_format_rar_options(struct archive_read *a,
{
struct rar *rar;
int ret = ARCHIVE_FAILED;
-
+
rar = (struct rar *)(a->format->data);
if (strcmp(key, "hdrcharset") == 0) {
if (val == NULL || val[0] == 0)
@@ -790,6 +827,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
char head_type;
int ret;
unsigned flags;
+ unsigned long crc32_expected;
a->archive.archive_format = ARCHIVE_FORMAT_RAR;
if (a->archive.archive_format_name == NULL)
@@ -797,6 +835,17 @@ archive_read_format_rar_read_header(struct archive_read *a,
rar = (struct rar *)(a->format->data);
+ /*
+ * It should be sufficient to call archive_read_next_header() for
+ * a reader to determine if an entry is encrypted or not. If the
+ * encryption of an entry is only detectable when calling
+ * archive_read_data(), so be it. We'll do the same check there
+ * as well.
+ */
+ if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ rar->has_encrypted_entries = 0;
+ }
+
/* RAR files can be generated without EOF headers, so return ARCHIVE_EOF if
* this fails.
*/
@@ -857,9 +906,14 @@ archive_read_format_rar_read_header(struct archive_read *a,
sizeof(rar->reserved2));
}
+ /* Main header is password encrypted, so we cannot read any
+ file names or any other info about files from the header. */
if (rar->main_flags & MHD_PASSWORD)
{
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_entry_set_is_metadata_encrypted(entry, 1);
+ archive_entry_set_is_data_encrypted(entry, 1);
+ rar->has_encrypted_entries = 1;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"RAR encryption support unavailable.");
return (ARCHIVE_FATAL);
}
@@ -886,36 +940,50 @@ archive_read_format_rar_read_header(struct archive_read *a,
skip = archive_le16dec(p + 5);
if (skip < 7) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
+ "Invalid header size too small");
return (ARCHIVE_FATAL);
}
- if (skip > 7) {
- if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
- return (ARCHIVE_FATAL);
- p = h;
- }
if (flags & HD_ADD_SIZE_PRESENT)
{
if (skip < 7 + 4) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid header size");
+ "Invalid header size too small");
return (ARCHIVE_FATAL);
}
- skip += archive_le32dec(p + 7);
if ((h = __archive_read_ahead(a, skip, NULL)) == NULL)
return (ARCHIVE_FATAL);
p = h;
+ skip += archive_le32dec(p + 7);
}
- crc32_val = crc32(0, (const unsigned char *)p + 2, (unsigned)skip - 2);
- if ((crc32_val & 0xffff) != archive_le16dec(p)) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Header CRC error");
- return (ARCHIVE_FATAL);
+ /* Skip over the 2-byte CRC at the beginning of the header. */
+ crc32_expected = archive_le16dec(p);
+ __archive_read_consume(a, 2);
+ skip -= 2;
+
+ /* Skim the entire header and compute the CRC. */
+ crc32_val = 0;
+ while (skip > 0) {
+ size_t to_read = skip;
+ ssize_t did_read;
+ if (to_read > 32 * 1024) {
+ to_read = 32 * 1024;
+ }
+ if ((h = __archive_read_ahead(a, to_read, &did_read)) == NULL) {
+ return (ARCHIVE_FATAL);
+ }
+ p = h;
+ crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned)did_read);
+ __archive_read_consume(a, did_read);
+ skip -= did_read;
+ }
+ if ((crc32_val & 0xffff) != crc32_expected) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Header CRC error");
+ return (ARCHIVE_FATAL);
}
- __archive_read_consume(a, skip);
if (head_type == ENDARC_HEAD)
- return (ARCHIVE_EOF);
+ return (ARCHIVE_EOF);
break;
case NEWSUB_HEAD:
@@ -938,14 +1006,18 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
struct rar *rar = (struct rar *)(a->format->data);
int ret;
+ if (rar->has_encrypted_entries == ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ rar->has_encrypted_entries = 0;
+ }
+
if (rar->bytes_unconsumed > 0) {
/* Consume as much as the decompressor actually used. */
__archive_read_consume(a, rar->bytes_unconsumed);
rar->bytes_unconsumed = 0;
}
+ *buff = NULL;
if (rar->entry_eof || rar->offset_seek >= rar->unp_size) {
- *buff = NULL;
*size = 0;
*offset = rar->offset;
if (*offset < rar->unp_size)
@@ -957,7 +1029,7 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
{
case COMPRESS_METHOD_STORE:
ret = read_data_stored(a, buff, size, offset);
- break;
+ break;
case COMPRESS_METHOD_FASTEST:
case COMPRESS_METHOD_FAST:
@@ -967,13 +1039,13 @@ archive_read_format_rar_read_data(struct archive_read *a, const void **buff,
ret = read_data_compressed(a, buff, size, offset);
if (ret != ARCHIVE_OK && ret != ARCHIVE_WARN)
__archive_ppmd7_functions.Ppmd7_Free(&rar->ppmd7_context, &g_szalloc);
- break;
+ break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported compression method for RAR file.");
ret = ARCHIVE_FATAL;
- break;
+ break;
}
return (ret);
}
@@ -1145,10 +1217,8 @@ archive_read_format_rar_seek_data(struct archive_read *a, int64_t offset,
ret -= rar->dbo[0].start_offset;
/* Always restart reading the file after a seek */
- a->read_data_block = NULL;
- a->read_data_offset = 0;
- a->read_data_output_offset = 0;
- a->read_data_remaining = 0;
+ __archive_reset_read_data(&a->archive);
+
rar->bytes_unconsumed = 0;
rar->offset = 0;
@@ -1290,9 +1360,14 @@ read_header(struct archive_read *a, struct archive_entry *entry,
if (rar->file_flags & FHD_PASSWORD)
{
+ archive_entry_set_is_data_encrypted(entry, 1);
+ rar->has_encrypted_entries = 1;
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"RAR encryption support unavailable.");
- return (ARCHIVE_FATAL);
+ /* Since it is only the data part itself that is encrypted we can at least
+ extract information about the currently processed entry and don't need
+ to return ARCHIVE_FATAL here. */
+ /*return (ARCHIVE_FATAL);*/
}
if (rar->file_flags & FHD_LARGE)
@@ -1377,7 +1452,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
flagbyte = *(p + offset++);
flagbits = 8;
}
-
+
flagbits -= 2;
switch((flagbyte >> flagbits) & 3)
{
@@ -1469,6 +1544,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
/* Split file in multivolume RAR. No more need to process header. */
if (rar->filename_save &&
+ filename_size == rar->filename_save_size &&
!memcmp(rar->filename, rar->filename_save, filename_size + 1))
{
__archive_read_consume(a, header_size - 7);
@@ -1498,6 +1574,7 @@ read_header(struct archive_read *a, struct archive_entry *entry,
rar->filename_save = (char*)realloc(rar->filename_save,
filename_size + 1);
memcpy(rar->filename_save, rar->filename, filename_size + 1);
+ rar->filename_save_size = filename_size;
/* Set info for seeking */
free(rar->dbo);
@@ -2049,6 +2126,12 @@ parse_codes(struct archive_read *a)
rar->range_dec.Stream = &rar->bytein;
__archive_ppmd7_functions.Ppmd7_Construct(&rar->ppmd7_context);
+ if (rar->dictionary_size == 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid zero dictionary size");
+ return (ARCHIVE_FATAL);
+ }
+
if (!__archive_ppmd7_functions.Ppmd7_Alloc(&rar->ppmd7_context,
rar->dictionary_size, &g_szalloc))
{
@@ -2345,6 +2428,8 @@ create_code(struct archive_read *a, struct huffman_code *code,
{
int i, j, codebits = 0, symbolsleft = numsymbols;
+ code->numentries = 0;
+ code->numallocatedentries = 0;
if (new_node(code) < 0) {
archive_set_error(&a->archive, ENOMEM,
"Unable to allocate memory for node data.");
@@ -2473,11 +2558,17 @@ static int
new_node(struct huffman_code *code)
{
void *new_tree;
-
- new_tree = realloc(code->tree, (code->numentries + 1) * sizeof(*code->tree));
- if (new_tree == NULL)
- return (-1);
- code->tree = (struct huffman_tree_node *)new_tree;
+ if (code->numallocatedentries == code->numentries) {
+ int new_num_entries = 256;
+ if (code->numentries > 0) {
+ new_num_entries = code->numentries * 2;
+ }
+ new_tree = realloc(code->tree, new_num_entries * sizeof(*code->tree));
+ if (new_tree == NULL)
+ return (-1);
+ code->tree = (struct huffman_tree_node *)new_tree;
+ code->numallocatedentries = new_num_entries;
+ }
code->tree[code->numentries].branches[0] = -1;
code->tree[code->numentries].branches[1] = -2;
return 1;
@@ -2611,7 +2702,7 @@ expand(struct archive_read *a, int64_t end)
if ((symbol = read_next_symbol(a, &rar->maincode)) < 0)
return (ARCHIVE_FATAL);
rar->output_last_match = 0;
-
+
if (symbol < 256)
{
lzss_emit_literal(rar, symbol);
@@ -2798,11 +2889,10 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
}
windowoffs = lzss_offset_for_position(&rar->lzss, startpos);
- if(windowoffs + length <= lzss_size(&rar->lzss))
+ if(windowoffs + length <= lzss_size(&rar->lzss)) {
memcpy(&rar->unp_buffer[rar->unp_offset], &rar->lzss.window[windowoffs],
length);
- else
- {
+ } else if (length <= lzss_size(&rar->lzss)) {
firstpart = lzss_size(&rar->lzss) - windowoffs;
if (firstpart < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -2814,9 +2904,14 @@ copy_from_lzss_window(struct archive_read *a, const void **buffer,
&rar->lzss.window[windowoffs], firstpart);
memcpy(&rar->unp_buffer[rar->unp_offset + firstpart],
&rar->lzss.window[0], length - firstpart);
- } else
+ } else {
memcpy(&rar->unp_buffer[rar->unp_offset],
&rar->lzss.window[windowoffs], length);
+ }
+ } else {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Bad RAR file data");
+ return (ARCHIVE_FATAL);
}
rar->unp_offset += length;
if (rar->unp_offset >= rar->unp_buffer_size)
@@ -2834,8 +2929,8 @@ rar_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
int ret;
if (avail)
{
- if (a->read_data_is_posix_read && *avail > (ssize_t)a->read_data_requested)
- *avail = a->read_data_requested;
+ if (a->archive.read_data_is_posix_read && *avail > (ssize_t)a->archive.read_data_requested)
+ *avail = a->archive.read_data_requested;
if (*avail > rar->bytes_remaining)
*avail = (ssize_t)rar->bytes_remaining;
if (*avail < 0)
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c
index 843497878..efa2c6a33 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_raw.c
@@ -78,7 +78,9 @@ archive_read_support_format_raw(struct archive *_a)
archive_read_format_raw_read_data,
archive_read_format_raw_read_data_skip,
NULL,
- archive_read_format_raw_cleanup);
+ archive_read_format_raw_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(info);
return (r);
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
index e9523cb68..bd7f13d52 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -136,6 +137,7 @@ struct tar {
int64_t entry_padding;
int64_t entry_bytes_unconsumed;
int64_t realsize;
+ int sparse_allowed;
struct sparse_block *sparse_list;
struct sparse_block *sparse_last;
int64_t sparse_offset;
@@ -151,6 +153,8 @@ struct tar {
struct archive_string_conv *sconv_default;
int init_default_conversion;
int compat_2x;
+ int process_mac_extensions;
+ int read_concatenated_archives;
};
static int archive_block_is_null(const char *p);
@@ -200,9 +204,14 @@ static int archive_read_format_tar_read_header(struct archive_read *,
struct archive_entry *);
static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_read *, struct tar *,
- struct archive_entry *, char *key, char *value);
+ struct archive_entry *, const char *key, const char *value,
+ size_t value_length);
+static int pax_attribute_acl(struct archive_read *, struct tar *,
+ struct archive_entry *, const char *, int);
+static int pax_attribute_xattr(struct archive_entry *, const char *,
+ const char *);
static int pax_header(struct archive_read *, struct tar *,
- struct archive_entry *, char *attr);
+ struct archive_entry *, struct archive_string *);
static void pax_time(const char *, int64_t *sec, long *nanos);
static ssize_t readline(struct archive_read *, struct tar *, const char **,
ssize_t limit, size_t *);
@@ -241,6 +250,10 @@ archive_read_support_format_tar(struct archive *_a)
ARCHIVE_STATE_NEW, "archive_read_support_format_tar");
tar = (struct tar *)calloc(1, sizeof(*tar));
+#ifdef HAVE_COPYFILE_H
+ /* Set this by default on Mac OS. */
+ tar->process_mac_extensions = 1;
+#endif
if (tar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate tar data");
@@ -254,7 +267,9 @@ archive_read_support_format_tar(struct archive *_a)
archive_read_format_tar_read_data,
archive_read_format_tar_skip,
NULL,
- archive_read_format_tar_cleanup);
+ archive_read_format_tar_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(tar);
@@ -285,6 +300,57 @@ archive_read_format_tar_cleanup(struct archive_read *a)
return (ARCHIVE_OK);
}
+/*
+ * Validate number field
+ *
+ * This has to be pretty lenient in order to accommodate the enormous
+ * variety of tar writers in the world:
+ * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading
+ * zeros and allows fields to be terminated with space or null characters
+ * = Many writers use different termination (in particular, libarchive
+ * omits terminator bytes to squeeze one or two more digits)
+ * = Many writers pad with space and omit leading zeros
+ * = GNU tar and star write base-256 values if numbers are too
+ * big to be represented in octal
+ *
+ * Examples of specific tar headers that we should support:
+ * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two
+ * null bytes, pads size with spaces and other numeric fields with zeroes
+ * = plexus-archiver prior to 2.6.3 (before switching to commons-compress)
+ * may have uid and gid fields filled with spaces without any octal digits
+ * at all and pads all numeric fields with spaces
+ *
+ * This should tolerate all variants in use. It will reject a field
+ * where the writer just left garbage after a trailing NUL.
+ */
+static int
+validate_number_field(const char* p_field, size_t i_size)
+{
+ unsigned char marker = (unsigned char)p_field[0];
+ if (marker == 128 || marker == 255 || marker == 0) {
+ /* Base-256 marker, there's nothing we can check. */
+ return 1;
+ } else {
+ /* Must be octal */
+ size_t i = 0;
+ /* Skip any leading spaces */
+ while (i < i_size && p_field[i] == ' ') {
+ ++i;
+ }
+ /* Skip octal digits. */
+ while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') {
+ ++i;
+ }
+ /* Any remaining characters must be space or NUL padding. */
+ while (i < i_size) {
+ if (p_field[i] != ' ' && p_field[i] != 0) {
+ return 0;
+ }
+ ++i;
+ }
+ return 1;
+ }
+}
static int
archive_read_format_tar_bid(struct archive_read *a, int best_bid)
@@ -337,23 +403,19 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid)
return (0);
bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */
- /* Sanity check: Look at first byte of mode field. */
- switch (255 & (unsigned)header->mode[0]) {
- case 0: case 255:
- /* Base-256 value: No further verification possible! */
- break;
- case ' ': /* Not recommended, but not illegal, either. */
- break;
- case '0': case '1': case '2': case '3':
- case '4': case '5': case '6': case '7':
- /* Octal Value. */
- /* TODO: Check format of remainder of this field. */
- break;
- default:
- /* Not a valid mode; bail out here. */
- return (0);
+ /*
+ * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields.
+ */
+ if (bid > 0 && (
+ validate_number_field(header->mode, sizeof(header->mode)) == 0
+ || validate_number_field(header->uid, sizeof(header->uid)) == 0
+ || validate_number_field(header->gid, sizeof(header->gid)) == 0
+ || validate_number_field(header->mtime, sizeof(header->mtime)) == 0
+ || validate_number_field(header->size, sizeof(header->size)) == 0
+ || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0
+ || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) {
+ bid = 0;
}
- /* TODO: Sanity test uid/gid/size/mtime/rdevmajor/rdevminor fields. */
return (bid);
}
@@ -367,8 +429,8 @@ archive_read_format_tar_options(struct archive_read *a,
tar = (struct tar *)(a->format->data);
if (strcmp(key, "compat-2x") == 0) {
- /* Handle UTF-8 filnames as libarchive 2.x */
- tar->compat_2x = (val != NULL)?1:0;
+ /* Handle UTF-8 filenames as libarchive 2.x */
+ tar->compat_2x = (val != NULL && val[0] != 0);
tar->init_default_conversion = tar->compat_2x;
return (ARCHIVE_OK);
} else if (strcmp(key, "hdrcharset") == 0) {
@@ -385,6 +447,12 @@ archive_read_format_tar_options(struct archive_read *a,
ret = ARCHIVE_FATAL;
}
return (ret);
+ } else if (strcmp(key, "mac-ext") == 0) {
+ tar->process_mac_extensions = (val != NULL && val[0] != 0);
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "read_concatenated_archives") == 0) {
+ tar->read_concatenated_archives = (val != NULL && val[0] != 0);
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -397,7 +465,7 @@ archive_read_format_tar_options(struct archive_read *a,
* how much unconsumed data we have floating around, and to consume
* anything outstanding since we're going to do read_aheads
*/
-static void
+static void
tar_flush_unconsumed(struct archive_read *a, size_t *unconsumed)
{
if (*unconsumed) {
@@ -442,6 +510,7 @@ archive_read_format_tar_read_header(struct archive_read *a,
static int default_dev;
struct tar *tar;
const char *p;
+ const wchar_t *wp;
int r;
size_t l, unconsumed = 0;
@@ -492,27 +561,22 @@ archive_read_format_tar_read_header(struct archive_read *a,
}
}
- if (r == ARCHIVE_OK) {
+ if (r == ARCHIVE_OK && archive_entry_filetype(entry) == AE_IFREG) {
/*
* "Regular" entry with trailing '/' is really
* directory: This is needed for certain old tar
* variants and even for some broken newer ones.
*/
- const wchar_t *wp;
- wp = archive_entry_pathname_w(entry);
- if (wp != NULL) {
+ if ((wp = archive_entry_pathname_w(entry)) != NULL) {
l = wcslen(wp);
- if (archive_entry_filetype(entry) == AE_IFREG
- && wp[l-1] == L'/')
+ if (l > 0 && wp[l - 1] == L'/') {
archive_entry_set_filetype(entry, AE_IFDIR);
- } else {
- p = archive_entry_pathname(entry);
- if (p == NULL)
- return (ARCHIVE_FAILED);
+ }
+ } else if ((p = archive_entry_pathname(entry)) != NULL) {
l = strlen(p);
- if (archive_entry_filetype(entry) == AE_IFREG
- && p[l-1] == '/')
+ if (l > 0 && p[l - 1] == '/') {
archive_entry_set_filetype(entry, AE_IFDIR);
+ }
}
}
return (r);
@@ -585,13 +649,27 @@ static int
archive_read_format_tar_skip(struct archive_read *a)
{
int64_t bytes_skipped;
+ int64_t request;
+ struct sparse_block *p;
struct tar* tar;
tar = (struct tar *)(a->format->data);
- bytes_skipped = __archive_read_consume(a,
- tar->entry_bytes_remaining + tar->entry_padding +
- tar->entry_bytes_unconsumed);
+ /* Do not consume the hole of a sparse file. */
+ request = 0;
+ for (p = tar->sparse_list; p != NULL; p = p->next) {
+ if (!p->hole) {
+ if (p->remaining >= INT64_MAX - request) {
+ return ARCHIVE_FATAL;
+ }
+ request += p->remaining;
+ }
+ }
+ if (request > tar->entry_bytes_remaining)
+ request = tar->entry_bytes_remaining;
+ request += tar->entry_padding + tar->entry_bytes_unconsumed;
+
+ bytes_skipped = __archive_read_consume(a, request);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
@@ -619,36 +697,50 @@ tar_read_header(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
const struct archive_entry_header_gnutar *gnuheader;
- tar_flush_unconsumed(a, unconsumed);
+ /* Loop until we find a workable header record. */
+ for (;;) {
+ tar_flush_unconsumed(a, unconsumed);
- /* Read 512-byte header record */
- h = __archive_read_ahead(a, 512, &bytes);
- if (bytes < 0)
- return ((int)bytes);
- if (bytes == 0) { /* EOF at a block boundary. */
- /* Some writers do omit the block of nulls. <sigh> */
- return (ARCHIVE_EOF);
- }
- if (bytes < 512) { /* Short block at EOF; this is bad. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated tar archive");
- return (ARCHIVE_FATAL);
- }
- *unconsumed = 512;
+ /* Read 512-byte header record */
+ h = __archive_read_ahead(a, 512, &bytes);
+ if (bytes < 0)
+ return ((int)bytes);
+ if (bytes == 0) { /* EOF at a block boundary. */
+ /* Some writers do omit the block of nulls. <sigh> */
+ return (ARCHIVE_EOF);
+ }
+ if (bytes < 512) { /* Short block at EOF; this is bad. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated tar archive");
+ return (ARCHIVE_FATAL);
+ }
+ *unconsumed = 512;
- /* Check for end-of-archive mark. */
- if (h[0] == 0 && archive_block_is_null(h)) {
- /* Try to consume a second all-null record, as well. */
- tar_flush_unconsumed(a, unconsumed);
- h = __archive_read_ahead(a, 512, NULL);
- if (h != NULL)
- __archive_read_consume(a, 512);
- archive_clear_error(&a->archive);
+ /* Header is workable if it's not an end-of-archive mark. */
+ if (h[0] != 0 || !archive_block_is_null(h))
+ break;
+
+ /* Ensure format is set for archives with only null blocks. */
if (a->archive.archive_format_name == NULL) {
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
a->archive.archive_format_name = "tar";
}
- return (ARCHIVE_EOF);
+
+ if (!tar->read_concatenated_archives) {
+ /* Try to consume a second all-null record, as well. */
+ tar_flush_unconsumed(a, unconsumed);
+ h = __archive_read_ahead(a, 512, NULL);
+ if (h != NULL && h[0] == 0 && archive_block_is_null(h))
+ __archive_read_consume(a, 512);
+ archive_clear_error(&a->archive);
+ return (ARCHIVE_EOF);
+ }
+
+ /*
+ * We're reading concatenated archives, ignore this block and
+ * loop to get the next.
+ */
}
/*
@@ -683,6 +775,8 @@ tar_read_header(struct archive_read *a, struct tar *tar,
a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_global(a, tar, entry, h, unconsumed);
+ if (err == ARCHIVE_EOF)
+ return (err);
break;
case 'K': /* Long link name (GNU tar, others) */
err = header_longlink(a, tar, entry, h, unconsumed);
@@ -735,9 +829,9 @@ tar_read_header(struct archive_read *a, struct tar *tar,
* extensions for both the AppleDouble extension entry and the
* regular entry.
*/
- /* TODO: Should this be disabled on non-Mac platforms? */
if ((err == ARCHIVE_WARN || err == ARCHIVE_OK) &&
- tar->header_recursion_depth == 0) {
+ tar->header_recursion_depth == 0 &&
+ tar->process_mac_extensions) {
int err2 = read_mac_metadata_blob(a, tar, entry, h, unconsumed);
if (err2 < err)
err = err2;
@@ -753,9 +847,9 @@ tar_read_header(struct archive_read *a, struct tar *tar,
tar->sparse_gnu_pending = 0;
/* Read initial sparse map. */
bytes_read = gnu_sparse_10_read(a, tar, unconsumed);
- tar->entry_bytes_remaining -= bytes_read;
if (bytes_read < 0)
return ((int)bytes_read);
+ tar->entry_bytes_remaining -= bytes_read;
} else {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
@@ -780,12 +874,20 @@ checksum(struct archive_read *a, const void *h)
{
const unsigned char *bytes;
const struct archive_entry_header_ustar *header;
- int check, i, sum;
+ int check, sum;
+ size_t i;
(void)a; /* UNUSED */
bytes = (const unsigned char *)h;
header = (const struct archive_entry_header_ustar *)h;
+ /* Checksum field must hold an octal number */
+ for (i = 0; i < sizeof(header->checksum); ++i) {
+ char c = header->checksum[i];
+ if (c != ' ' && c != '\0' && (c < '0' || c > '7'))
+ return 0;
+ }
+
/*
* Test the checksum. Note that POSIX specifies _unsigned_
* bytes for this calculation.
@@ -842,7 +944,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
{
const struct archive_entry_header_ustar *header;
size_t size;
- int err;
+ int err, acl_type;
int64_t type;
char *acl, *p;
@@ -887,11 +989,12 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
switch ((int)type & ~0777777) {
case 01000000:
/* POSIX.1e ACL */
+ acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
break;
case 03000000:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Solaris NFSv4 ACLs not supported");
- return (ARCHIVE_WARN);
+ /* NFSv4 ACL */
+ acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4;
+ break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Malformed Solaris ACL attribute (unsupported type %o)",
@@ -920,8 +1023,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
archive_strncpy(&(tar->localname), acl, p - acl);
- err = archive_acl_parse_l(archive_entry_acl(entry),
- tar->localname.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, tar->sconv_acl);
+ err = archive_acl_from_text_l(archive_entry_acl(entry),
+ tar->localname.s, acl_type, tar->sconv_acl);
if (err != ARCHIVE_OK) {
if (errno == ENOMEM) {
archive_set_error(&a->archive, ENOMEM,
@@ -1080,8 +1183,15 @@ header_common(struct archive_read *a, struct tar *tar,
if (tar->entry_bytes_remaining < 0) {
tar->entry_bytes_remaining = 0;
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Tar entry has negative size?");
- err = ARCHIVE_WARN;
+ "Tar entry has negative size");
+ return (ARCHIVE_FATAL);
+ }
+ if (tar->entry_bytes_remaining == INT64_MAX) {
+ /* Note: tar_atol returns INT64_MAX on overflow */
+ tar->entry_bytes_remaining = 0;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Tar entry size overflow");
+ return (ARCHIVE_FATAL);
}
tar->realsize = tar->entry_bytes_remaining;
archive_entry_set_size(entry, tar->entry_bytes_remaining);
@@ -1216,6 +1326,14 @@ header_common(struct archive_read *a, struct tar *tar,
* sparse information in the extended area.
*/
/* FALLTHROUGH */
+ case '0':
+ /*
+ * Enable sparse file "read" support only for regular
+ * files and explicit GNU sparse files. However, we
+ * don't allow non-standard file types to be sparse.
+ */
+ tar->sparse_allowed = 1;
+ /* FALLTHROUGH */
default: /* Regular file and non-standard types */
/*
* Per POSIX: non-recognized types should always be
@@ -1277,7 +1395,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
if (wp[0] == '/' && wp[1] != L'\0')
wname = wp + 1;
}
- /*
+ /*
* If last path element starts with "._", then
* this is a Mac extension.
*/
@@ -1292,7 +1410,7 @@ read_mac_metadata_blob(struct archive_read *a, struct tar *tar,
if (p[0] == '/' && p[1] != '\0')
name = p + 1;
}
- /*
+ /*
* If last path element starts with "._", then
* this is a Mac extension.
*/
@@ -1367,7 +1485,7 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
* and then skip any fields in the standard header that were
* defined in the pax header.
*/
- err2 = pax_header(a, tar, entry, tar->pax_header.s);
+ err2 = pax_header(a, tar, entry, &tar->pax_header);
err = err_combine(err, err2);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (err);
@@ -1448,16 +1566,17 @@ header_ustar(struct archive_read *a, struct tar *tar,
*/
static int
pax_header(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, char *attr)
+ struct archive_entry *entry, struct archive_string *in_as)
{
- size_t attr_length, l, line_length;
+ size_t attr_length, l, line_length, value_length;
char *p;
char *key, *value;
struct archive_string *as;
struct archive_string_conv *sconv;
int err, err2;
+ char *attr = in_as->s;
- attr_length = strlen(attr);
+ attr_length = in_as->length;
tar->pax_hdrcharset_binary = 0;
archive_string_empty(&(tar->entry_gname));
archive_string_empty(&(tar->entry_linkpath));
@@ -1522,11 +1641,13 @@ pax_header(struct archive_read *a, struct tar *tar,
}
*p = '\0';
- /* Identify null-terminated 'value' portion. */
value = p + 1;
+ /* Some values may be binary data */
+ value_length = attr + line_length - 1 - value;
+
/* Identify this attribute and set it in the entry. */
- err2 = pax_attribute(a, tar, entry, key, value);
+ err2 = pax_attribute(a, tar, entry, key, value, value_length);
if (err2 == ARCHIVE_FATAL)
return (err2);
err = err_combine(err, err2);
@@ -1616,7 +1737,7 @@ pax_header(struct archive_read *a, struct tar *tar,
static int
pax_attribute_xattr(struct archive_entry *entry,
- char *name, char *value)
+ const char *name, const char *value)
{
char *name_decoded;
void *value_decoded;
@@ -1647,6 +1768,66 @@ pax_attribute_xattr(struct archive_entry *entry,
return 0;
}
+static int
+pax_attribute_schily_xattr(struct archive_entry *entry,
+ const char *name, const char *value, size_t value_length)
+{
+ if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0)
+ return 1;
+
+ name += 13;
+
+ archive_entry_xattr_add_entry(entry, name, value, value_length);
+
+ return 0;
+}
+
+static int
+pax_attribute_acl(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const char *value, int type)
+{
+ int r;
+ const char* errstr;
+
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ errstr = "SCHILY.acl.access";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ errstr = "SCHILY.acl.default";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ errstr = "SCHILY.acl.ace";
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL type: %d", type);
+ return(ARCHIVE_FATAL);
+ }
+
+ if (tar->sconv_acl == NULL) {
+ tar->sconv_acl =
+ archive_string_conversion_from_charset(
+ &(a->archive), "UTF-8", 1);
+ if (tar->sconv_acl == NULL)
+ return (ARCHIVE_FATAL);
+ }
+
+ r = archive_acl_from_text_l(archive_entry_acl(entry), value, type,
+ tar->sconv_acl);
+ if (r != ARCHIVE_OK) {
+ if (r == ARCHIVE_FATAL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "%s %s", "Can't allocate memory for ",
+ errstr);
+ return (r);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
+ }
+ return (r);
+}
+
/*
* Parse a single key=value attribute. key/value pointers are
* assumed to point into reasonably long-lived storage.
@@ -1662,7 +1843,7 @@ pax_attribute_xattr(struct archive_entry *entry,
*/
static int
pax_attribute(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, char *key, char *value)
+ struct archive_entry *entry, const char *key, const char *value, size_t value_length)
{
int64_t s;
long n;
@@ -1673,6 +1854,14 @@ pax_attribute(struct archive_read *a, struct tar *tar,
* NULL pointer to strlen(). */
switch (key[0]) {
case 'G':
+ /* Reject GNU.sparse.* headers on non-regular files. */
+ if (strncmp(key, "GNU.sparse", 10) == 0 &&
+ !tar->sparse_allowed) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Non-regular file cannot be sparse");
+ return (ARCHIVE_FATAL);
+ }
+
/* GNU "0.0" sparse pax format. */
if (strcmp(key, "GNU.sparse.numblocks") == 0) {
tar->sparse_offset = -1;
@@ -1755,53 +1944,20 @@ pax_attribute(struct archive_read *a, struct tar *tar,
case 'S':
/* We support some keys used by the "star" archiver */
if (strcmp(key, "SCHILY.acl.access") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.access");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.access");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.acl.default") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.default");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.default");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+ if (r == ARCHIVE_FATAL)
+ return (r);
+ } else if (strcmp(key, "SCHILY.acl.ace") == 0) {
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.devmajor") == 0) {
archive_entry_set_rdevmajor(entry,
(dev_t)tar_atol10(value, strlen(value)));
@@ -1822,6 +1978,9 @@ pax_attribute(struct archive_read *a, struct tar *tar,
} else if (strcmp(key, "SCHILY.realsize") == 0) {
tar->realsize = tar_atol10(value, strlen(value));
archive_entry_set_size(entry, tar->realsize);
+ } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) {
+ pax_attribute_schily_xattr(entry, key, value,
+ value_length);
} else if (strcmp(key, "SUN.holesdata") == 0) {
/* A Solaris extension for sparse. */
r = solaris_sparse_parse(a, tar, entry, value);
@@ -2068,17 +2227,20 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar,
{
struct sparse_block *p;
- p = (struct sparse_block *)malloc(sizeof(*p));
+ p = (struct sparse_block *)calloc(1, sizeof(*p));
if (p == NULL) {
archive_set_error(&a->archive, ENOMEM, "Out of memory");
return (ARCHIVE_FATAL);
}
- memset(p, 0, sizeof(*p));
if (tar->sparse_last != NULL)
tar->sparse_last->next = p;
else
tar->sparse_list = p;
tar->sparse_last = p;
+ if (remaining < 0 || offset < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed sparse map data");
+ return (ARCHIVE_FATAL);
+ }
p->offset = offset;
p->remaining = remaining;
return (ARCHIVE_OK);
@@ -2325,6 +2487,9 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed)
tar_flush_unconsumed(a, unconsumed);
bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining);
to_skip = 0x1ff & -bytes_read;
+ /* Fail if tar->entry_bytes_remaing would get negative */
+ if (to_skip > remaining)
+ return (ARCHIVE_FATAL);
if (to_skip != __archive_read_consume(a, to_skip))
return (ARCHIVE_FATAL);
return ((ssize_t)(bytes_read + to_skip));
@@ -2412,14 +2577,15 @@ tar_atol(const char *p, size_t char_cnt)
static int64_t
tar_atol_base_n(const char *p, size_t char_cnt, int base)
{
- int64_t l, limit, last_digit_limit;
+ int64_t l, maxval, limit, last_digit_limit;
int digit, sign;
+ maxval = INT64_MAX;
limit = INT64_MAX / base;
last_digit_limit = INT64_MAX % base;
/* the pointer will not be dereferenced if char_cnt is zero
- * due to the way the && operator is evaulated.
+ * due to the way the && operator is evaluated.
*/
while (char_cnt != 0 && (*p == ' ' || *p == '\t')) {
p++;
@@ -2431,6 +2597,10 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
sign = -1;
p++;
char_cnt--;
+
+ maxval = INT64_MIN;
+ limit = -(INT64_MIN / base);
+ last_digit_limit = INT64_MIN % base;
}
l = 0;
@@ -2438,8 +2608,7 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base)
digit = *p - '0';
while (digit >= 0 && digit < base && char_cnt != 0) {
if (l>limit || (l == limit && digit > last_digit_limit)) {
- l = INT64_MAX; /* Truncate on overflow. */
- break;
+ return maxval; /* Truncate on overflow. */
}
l = (l * base) + digit;
digit = *++p - '0';
@@ -2462,36 +2631,56 @@ tar_atol10(const char *p, size_t char_cnt)
}
/*
- * Parse a base-256 integer. This is just a straight signed binary
- * value in big-endian order, except that the high-order bit is
- * ignored.
+ * Parse a base-256 integer. This is just a variable-length
+ * twos-complement signed binary value in big-endian order, except
+ * that the high-order bit is ignored. The values here can be up to
+ * 12 bytes, so we need to be careful about overflowing 64-bit
+ * (8-byte) integers.
+ *
+ * This code unashamedly assumes that the local machine uses 8-bit
+ * bytes and twos-complement arithmetic.
*/
static int64_t
tar_atol256(const char *_p, size_t char_cnt)
{
- int64_t l, upper_limit, lower_limit;
+ uint64_t l;
const unsigned char *p = (const unsigned char *)_p;
+ unsigned char c, neg;
+
+ /* Extend 7-bit 2s-comp to 8-bit 2s-comp, decide sign. */
+ c = *p;
+ if (c & 0x40) {
+ neg = 0xff;
+ c |= 0x80;
+ l = ~ARCHIVE_LITERAL_ULL(0);
+ } else {
+ neg = 0;
+ c &= 0x7f;
+ l = 0;
+ }
- upper_limit = INT64_MAX / 256;
- lower_limit = INT64_MIN / 256;
+ /* If more than 8 bytes, check that we can ignore
+ * high-order bits without overflow. */
+ while (char_cnt > sizeof(int64_t)) {
+ --char_cnt;
+ if (c != neg)
+ return neg ? INT64_MIN : INT64_MAX;
+ c = *++p;
+ }
- /* Pad with 1 or 0 bits, depending on sign. */
- if ((0x40 & *p) == 0x40)
- l = (int64_t)-1;
- else
- l = 0;
- l = (l << 6) | (0x3f & *p++);
+ /* c is first byte that fits; if sign mismatch, return overflow */
+ if ((c ^ neg) & 0x80) {
+ return neg ? INT64_MIN : INT64_MAX;
+ }
+
+ /* Accumulate remaining bytes. */
while (--char_cnt > 0) {
- if (l > upper_limit) {
- l = INT64_MAX; /* Truncate on overflow */
- break;
- } else if (l < lower_limit) {
- l = INT64_MIN;
- break;
- }
- l = (l << 8) | (0xff & (int64_t)*p++);
+ l = (l << 8) | c;
+ c = *++p;
}
- return (l);
+ l = (l << 8) | c;
+ /* Return signed twos-complement value. */
+ return (int64_t)(l);
}
/*
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c
new file mode 100644
index 000000000..b16246514
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c
@@ -0,0 +1,824 @@
+/*-
+ * Copyright (c) 2014 Sebastian Freundt
+ * 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$");
+
+/**
+ * WARC is standardised by ISO TC46/SC4/WG12 and currently available as
+ * ISO 28500:2009.
+ * For the purposes of this file we used the final draft from:
+ * http://bibnum.bnf.fr/warc/WARC_ISO_28500_version1_latestdraft.pdf
+ *
+ * Todo:
+ * [ ] real-world warcs can contain resources at endpoints ending in /
+ * e.g. http://bibnum.bnf.fr/warc/
+ * if you're lucky their response contains a Content-Location: header
+ * pointing to a unix-compliant filename, in the example above it's
+ * Content-Location: http://bibnum.bnf.fr/warc/index.html
+ * however, that's not mandated and github for example doesn't follow
+ * this convention.
+ * We need a set of archive options to control what to do with
+ * entries like these, at the moment care is taken to skip them.
+ *
+ **/
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+typedef enum {
+ WT_NONE,
+ /* warcinfo */
+ WT_INFO,
+ /* metadata */
+ WT_META,
+ /* resource */
+ WT_RSRC,
+ /* request, unsupported */
+ WT_REQ,
+ /* response, unsupported */
+ WT_RSP,
+ /* revisit, unsupported */
+ WT_RVIS,
+ /* conversion, unsupported */
+ WT_CONV,
+ /* continuation, unsupported at the moment */
+ WT_CONT,
+ /* invalid type */
+ LAST_WT
+} warc_type_t;
+
+typedef struct {
+ size_t len;
+ const char *str;
+} warc_string_t;
+
+typedef struct {
+ size_t len;
+ char *str;
+} warc_strbuf_t;
+
+struct warc_s {
+ /* content length ahead */
+ size_t cntlen;
+ /* and how much we've processed so far */
+ size_t cntoff;
+ /* and how much we need to consume between calls */
+ size_t unconsumed;
+
+ /* string pool */
+ warc_strbuf_t pool;
+ /* previous version */
+ unsigned int pver;
+ /* stringified format name */
+ struct archive_string sver;
+};
+
+static int _warc_bid(struct archive_read *a, int);
+static int _warc_cleanup(struct archive_read *a);
+static int _warc_read(struct archive_read*, const void**, size_t*, int64_t*);
+static int _warc_skip(struct archive_read *a);
+static int _warc_rdhdr(struct archive_read *a, struct archive_entry *e);
+
+/* private routines */
+static unsigned int _warc_rdver(const char buf[10], size_t bsz);
+static unsigned int _warc_rdtyp(const char *buf, size_t bsz);
+static warc_string_t _warc_rduri(const char *buf, size_t bsz);
+static ssize_t _warc_rdlen(const char *buf, size_t bsz);
+static time_t _warc_rdrtm(const char *buf, size_t bsz);
+static time_t _warc_rdmtm(const char *buf, size_t bsz);
+static const char *_warc_find_eoh(const char *buf, size_t bsz);
+static const char *_warc_find_eol(const char *buf, size_t bsz);
+
+int
+archive_read_support_format_warc(struct archive *_a)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct warc_s *w;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_warc");
+
+ if ((w = calloc(1, sizeof(*w))) == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate warc data");
+ return (ARCHIVE_FATAL);
+ }
+
+ r = __archive_read_register_format(
+ a, w, "warc",
+ _warc_bid, NULL, _warc_rdhdr, _warc_read,
+ _warc_skip, NULL, _warc_cleanup, NULL, NULL);
+
+ if (r != ARCHIVE_OK) {
+ free(w);
+ return (r);
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_cleanup(struct archive_read *a)
+{
+ struct warc_s *w = a->format->data;
+
+ if (w->pool.len > 0U) {
+ free(w->pool.str);
+ }
+ archive_string_free(&w->sver);
+ free(w);
+ a->format->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_bid(struct archive_read *a, int best_bid)
+{
+ const char *hdr;
+ ssize_t nrd;
+ unsigned int ver;
+
+ (void)best_bid; /* UNUSED */
+
+ /* check first line of file, it should be a record already */
+ if ((hdr = __archive_read_ahead(a, 12U, &nrd)) == NULL) {
+ /* no idea what to do */
+ return -1;
+ } else if (nrd < 12) {
+ /* nah, not for us, our magic cookie is at least 12 bytes */
+ return -1;
+ }
+
+ /* otherwise snarf the record's version number */
+ ver = _warc_rdver(hdr, nrd);
+ if (ver < 1200U || ver > 10000U) {
+ /* we only support WARC 0.12 to 1.0 */
+ return -1;
+ }
+
+ /* otherwise be confident */
+ return (64);
+}
+
+static int
+_warc_rdhdr(struct archive_read *a, struct archive_entry *entry)
+{
+#define HDR_PROBE_LEN (12U)
+ struct warc_s *w = a->format->data;
+ unsigned int ver;
+ const char *buf;
+ ssize_t nrd;
+ const char *eoh;
+ /* for the file name, saves some strndup()'ing */
+ warc_string_t fnam;
+ /* warc record type, not that we really use it a lot */
+ warc_type_t ftyp;
+ /* content-length+error monad */
+ ssize_t cntlen;
+ /* record time is the WARC-Date time we reinterpret it as ctime */
+ time_t rtime;
+ /* mtime is the Last-Modified time which will be the entry's mtime */
+ time_t mtime;
+
+start_over:
+ /* just use read_ahead() they keep track of unconsumed
+ * bits and bobs for us; no need to put an extra shift in
+ * and reproduce that functionality here */
+ buf = __archive_read_ahead(a, HDR_PROBE_LEN, &nrd);
+
+ if (nrd < 0) {
+ /* no good */
+ archive_set_error(
+ &a->archive, ARCHIVE_ERRNO_MISC,
+ "Bad record header");
+ return (ARCHIVE_FATAL);
+ } else if (buf == NULL) {
+ /* there should be room for at least WARC/bla\r\n
+ * must be EOF therefore */
+ return (ARCHIVE_EOF);
+ }
+ /* looks good so far, try and find the end of the header now */
+ eoh = _warc_find_eoh(buf, nrd);
+ if (eoh == NULL) {
+ /* still no good, the header end might be beyond the
+ * probe we've requested, but then again who'd cram
+ * so much stuff into the header *and* be 28500-compliant */
+ archive_set_error(
+ &a->archive, ARCHIVE_ERRNO_MISC,
+ "Bad record header");
+ return (ARCHIVE_FATAL);
+ }
+ ver = _warc_rdver(buf, eoh - buf);
+ /* we currently support WARC 0.12 to 1.0 */
+ if (ver == 0U) {
+ archive_set_error(
+ &a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid record version");
+ return (ARCHIVE_FATAL);
+ } else if (ver < 1200U || ver > 10000U) {
+ archive_set_error(
+ &a->archive, ARCHIVE_ERRNO_MISC,
+ "Unsupported record version: %u.%u",
+ ver / 10000, (ver % 10000) / 100);
+ return (ARCHIVE_FATAL);
+ }
+ cntlen = _warc_rdlen(buf, eoh - buf);
+ if (cntlen < 0) {
+ /* nightmare! the specs say content-length is mandatory
+ * so I don't feel overly bad stopping the reader here */
+ archive_set_error(
+ &a->archive, EINVAL,
+ "Bad content length");
+ return (ARCHIVE_FATAL);
+ }
+ rtime = _warc_rdrtm(buf, eoh - buf);
+ if (rtime == (time_t)-1) {
+ /* record time is mandatory as per WARC/1.0,
+ * so just barf here, fast and loud */
+ archive_set_error(
+ &a->archive, EINVAL,
+ "Bad record time");
+ return (ARCHIVE_FATAL);
+ }
+
+ /* let the world know we're a WARC archive */
+ a->archive.archive_format = ARCHIVE_FORMAT_WARC;
+ if (ver != w->pver) {
+ /* stringify this entry's version */
+ archive_string_sprintf(&w->sver,
+ "WARC/%u.%u", ver / 10000, (ver % 10000) / 100);
+ /* remember the version */
+ w->pver = ver;
+ }
+ /* start off with the type */
+ ftyp = _warc_rdtyp(buf, eoh - buf);
+ /* and let future calls know about the content */
+ w->cntlen = cntlen;
+ w->cntoff = 0U;
+ mtime = 0;/* Avoid compiling error on some platform. */
+
+ switch (ftyp) {
+ case WT_RSRC:
+ case WT_RSP:
+ /* only try and read the filename in the cases that are
+ * guaranteed to have one */
+ fnam = _warc_rduri(buf, eoh - buf);
+ /* check the last character in the URI to avoid creating
+ * directory endpoints as files, see Todo above */
+ if (fnam.len == 0 || fnam.str[fnam.len - 1] == '/') {
+ /* break here for now */
+ fnam.len = 0U;
+ fnam.str = NULL;
+ break;
+ }
+ /* bang to our string pool, so we save a
+ * malloc()+free() roundtrip */
+ if (fnam.len + 1U > w->pool.len) {
+ w->pool.len = ((fnam.len + 64U) / 64U) * 64U;
+ w->pool.str = realloc(w->pool.str, w->pool.len);
+ }
+ memcpy(w->pool.str, fnam.str, fnam.len);
+ w->pool.str[fnam.len] = '\0';
+ /* let no one else know about the pool, it's a secret, shhh */
+ fnam.str = w->pool.str;
+
+ /* snarf mtime or deduce from rtime
+ * this is a custom header added by our writer, it's quite
+ * hard to believe anyone else would go through with it
+ * (apart from being part of some http responses of course) */
+ if ((mtime = _warc_rdmtm(buf, eoh - buf)) == (time_t)-1) {
+ mtime = rtime;
+ }
+ break;
+ default:
+ fnam.len = 0U;
+ fnam.str = NULL;
+ break;
+ }
+
+ /* now eat some of those delicious buffer bits */
+ __archive_read_consume(a, eoh - buf);
+
+ switch (ftyp) {
+ case WT_RSRC:
+ case WT_RSP:
+ if (fnam.len > 0U) {
+ /* populate entry object */
+ archive_entry_set_filetype(entry, AE_IFREG);
+ archive_entry_copy_pathname(entry, fnam.str);
+ archive_entry_set_size(entry, cntlen);
+ archive_entry_set_perm(entry, 0644);
+ /* rtime is the new ctime, mtime stays mtime */
+ archive_entry_set_ctime(entry, rtime, 0L);
+ archive_entry_set_mtime(entry, mtime, 0L);
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ /* consume the content and start over */
+ _warc_skip(a);
+ goto start_over;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_read(struct archive_read *a, const void **buf, size_t *bsz, int64_t *off)
+{
+ struct warc_s *w = a->format->data;
+ const char *rab;
+ ssize_t nrd;
+
+ if (w->cntoff >= w->cntlen) {
+ eof:
+ /* it's our lucky day, no work, we can leave early */
+ *buf = NULL;
+ *bsz = 0U;
+ *off = w->cntoff + 4U/*for \r\n\r\n separator*/;
+ w->unconsumed = 0U;
+ return (ARCHIVE_EOF);
+ }
+
+ rab = __archive_read_ahead(a, 1U, &nrd);
+ if (nrd < 0) {
+ *bsz = 0U;
+ /* big catastrophe */
+ return (int)nrd;
+ } else if (nrd == 0) {
+ goto eof;
+ } else if ((size_t)nrd > w->cntlen - w->cntoff) {
+ /* clamp to content-length */
+ nrd = w->cntlen - w->cntoff;
+ }
+ *off = w->cntoff;
+ *bsz = nrd;
+ *buf = rab;
+
+ w->cntoff += nrd;
+ w->unconsumed = (size_t)nrd;
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_skip(struct archive_read *a)
+{
+ struct warc_s *w = a->format->data;
+
+ __archive_read_consume(a, w->cntlen + 4U/*\r\n\r\n separator*/);
+ w->cntlen = 0U;
+ w->cntoff = 0U;
+ return (ARCHIVE_OK);
+}
+
+
+/* private routines */
+static void*
+deconst(const void *c)
+{
+ return (char *)0x1 + (((const char *)c) - (const char *)0x1);
+}
+
+static char*
+xmemmem(const char *hay, const size_t haysize,
+ const char *needle, const size_t needlesize)
+{
+ const char *const eoh = hay + haysize;
+ const char *const eon = needle + needlesize;
+ const char *hp;
+ const char *np;
+ const char *cand;
+ unsigned int hsum;
+ unsigned int nsum;
+ unsigned int eqp;
+
+ /* trivial checks first
+ * a 0-sized needle is defined to be found anywhere in haystack
+ * then run strchr() to find a candidate in HAYSTACK (i.e. a portion
+ * that happens to begin with *NEEDLE) */
+ if (needlesize == 0UL) {
+ return deconst(hay);
+ } else if ((hay = memchr(hay, *needle, haysize)) == NULL) {
+ /* trivial */
+ return NULL;
+ }
+
+ /* First characters of haystack and needle are the same now. Both are
+ * guaranteed to be at least one character long. Now computes the sum
+ * of characters values of needle together with the sum of the first
+ * needle_len characters of haystack. */
+ for (hp = hay + 1U, np = needle + 1U, hsum = *hay, nsum = *hay, eqp = 1U;
+ hp < eoh && np < eon;
+ hsum ^= *hp, nsum ^= *np, eqp &= *hp == *np, hp++, np++);
+
+ /* HP now references the (NEEDLESIZE + 1)-th character. */
+ if (np < eon) {
+ /* haystack is smaller than needle, :O */
+ return NULL;
+ } else if (eqp) {
+ /* found a match */
+ return deconst(hay);
+ }
+
+ /* now loop through the rest of haystack,
+ * updating the sum iteratively */
+ for (cand = hay; hp < eoh; hp++) {
+ hsum ^= *cand++;
+ hsum ^= *hp;
+
+ /* Since the sum of the characters is already known to be
+ * equal at that point, it is enough to check just NEEDLESIZE - 1
+ * characters for equality,
+ * also CAND is by design < HP, so no need for range checks */
+ if (hsum == nsum && memcmp(cand, needle, needlesize - 1U) == 0) {
+ return deconst(cand);
+ }
+ }
+ return NULL;
+}
+
+static int
+strtoi_lim(const char *str, const char **ep, int llim, int ulim)
+{
+ int res = 0;
+ const char *sp;
+ /* we keep track of the number of digits via rulim */
+ int rulim;
+
+ for (sp = str, rulim = ulim > 10 ? ulim : 10;
+ res * 10 <= ulim && rulim && *sp >= '0' && *sp <= '9';
+ sp++, rulim /= 10) {
+ res *= 10;
+ res += *sp - '0';
+ }
+ if (sp == str) {
+ res = -1;
+ } else if (res < llim || res > ulim) {
+ res = -2;
+ }
+ *ep = (const char*)sp;
+ return res;
+}
+
+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. */
+ if (mktime(t) == (time_t)-1)
+ return ((time_t)-1);
+ /* 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 time_t
+xstrpisotime(const char *s, char **endptr)
+{
+/** like strptime() but strictly for ISO 8601 Zulu strings */
+ struct tm tm;
+ time_t res = (time_t)-1;
+
+ /* make sure tm is clean */
+ memset(&tm, 0, sizeof(tm));
+
+ /* as a courtesy to our callers, and since this is a non-standard
+ * routine, we skip leading whitespace */
+ while (*s == ' ' || *s == '\t')
+ ++s;
+
+ /* read year */
+ if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') {
+ goto out;
+ }
+ /* read month */
+ if ((tm.tm_mon = strtoi_lim(s, &s, 1, 12)) < 0 || *s++ != '-') {
+ goto out;
+ }
+ /* read day-of-month */
+ if ((tm.tm_mday = strtoi_lim(s, &s, 1, 31)) < 0 || *s++ != 'T') {
+ goto out;
+ }
+ /* read hour */
+ if ((tm.tm_hour = strtoi_lim(s, &s, 0, 23)) < 0 || *s++ != ':') {
+ goto out;
+ }
+ /* read minute */
+ if ((tm.tm_min = strtoi_lim(s, &s, 0, 59)) < 0 || *s++ != ':') {
+ goto out;
+ }
+ /* read second */
+ if ((tm.tm_sec = strtoi_lim(s, &s, 0, 60)) < 0 || *s++ != 'Z') {
+ goto out;
+ }
+
+ /* massage TM to fulfill some of POSIX' constraints */
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+
+ /* now convert our custom tm struct to a unix stamp using UTC */
+ res = time_from_tm(&tm);
+
+out:
+ if (endptr != NULL) {
+ *endptr = deconst(s);
+ }
+ return res;
+}
+
+static unsigned int
+_warc_rdver(const char *buf, size_t bsz)
+{
+ static const char magic[] = "WARC/";
+ const char *c;
+ unsigned int ver = 0U;
+ unsigned int end = 0U;
+
+ if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) {
+ /* buffer too small or invalid magic */
+ return ver;
+ }
+ /* looks good so far, read the version number for a laugh */
+ buf += sizeof(magic) - 1U;
+
+ if (isdigit(buf[0U]) && (buf[1U] == '.') && isdigit(buf[2U])) {
+ /* we support a maximum of 2 digits in the minor version */
+ if (isdigit(buf[3U]))
+ end = 1U;
+ /* set up major version */
+ ver = (buf[0U] - '0') * 10000U;
+ /* set up minor version */
+ if (end == 1U) {
+ ver += (buf[2U] - '0') * 1000U;
+ ver += (buf[3U] - '0') * 100U;
+ } else
+ ver += (buf[2U] - '0') * 100U;
+ /*
+ * WARC below version 0.12 has a space-separated header
+ * WARC 0.12 and above terminates the version with a CRLF
+ */
+ c = buf + 3U + end;
+ if (ver >= 1200U) {
+ if (memcmp(c, "\r\n", 2U) != 0)
+ ver = 0U;
+ } else if (ver < 1200U) {
+ if (*c != ' ' && *c != '\t')
+ ver = 0U;
+ }
+ }
+ return ver;
+}
+
+static unsigned int
+_warc_rdtyp(const char *buf, size_t bsz)
+{
+ static const char _key[] = "\r\nWARC-Type:";
+ const char *val, *eol;
+
+ if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
+ /* no bother */
+ return WT_NONE;
+ }
+ val += sizeof(_key) - 1U;
+ if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* no end of line */
+ return WT_NONE;
+ }
+
+ /* overread whitespace */
+ while (val < eol && (*val == ' ' || *val == '\t'))
+ ++val;
+
+ if (val + 8U == eol) {
+ if (memcmp(val, "resource", 8U) == 0)
+ return WT_RSRC;
+ else if (memcmp(val, "response", 8U) == 0)
+ return WT_RSP;
+ }
+ return WT_NONE;
+}
+
+static warc_string_t
+_warc_rduri(const char *buf, size_t bsz)
+{
+ static const char _key[] = "\r\nWARC-Target-URI:";
+ const char *val, *uri, *eol, *p;
+ warc_string_t res = {0U, NULL};
+
+ if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
+ /* no bother */
+ return res;
+ }
+ /* overread whitespace */
+ val += sizeof(_key) - 1U;
+ if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* no end of line */
+ return res;
+ }
+
+ while (val < eol && (*val == ' ' || *val == '\t'))
+ ++val;
+
+ /* overread URL designators */
+ if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) {
+ /* not touching that! */
+ return res;
+ }
+
+ /* spaces inside uri are not allowed, CRLF should follow */
+ for (p = val; p < eol; p++) {
+ if (isspace(*p))
+ return res;
+ }
+
+ /* there must be at least space for ftp */
+ if (uri < (val + 3U))
+ return res;
+
+ /* move uri to point to after :// */
+ uri += 3U;
+
+ /* now then, inspect the URI */
+ if (memcmp(val, "file", 4U) == 0) {
+ /* perfect, nothing left to do here */
+
+ } else if (memcmp(val, "http", 4U) == 0 ||
+ memcmp(val, "ftp", 3U) == 0) {
+ /* overread domain, and the first / */
+ while (uri < eol && *uri++ != '/');
+ } else {
+ /* not sure what to do? best to bugger off */
+ return res;
+ }
+ res.str = uri;
+ res.len = eol - uri;
+ return res;
+}
+
+static ssize_t
+_warc_rdlen(const char *buf, size_t bsz)
+{
+ static const char _key[] = "\r\nContent-Length:";
+ const char *val, *eol;
+ char *on = NULL;
+ long int len;
+
+ if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
+ /* no bother */
+ return -1;
+ }
+ val += sizeof(_key) - 1U;
+ if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) {
+ /* no end of line */
+ return -1;
+ }
+
+ /* skip leading whitespace */
+ while (val < eol && (*val == ' ' || *val == '\t'))
+ val++;
+ /* there must be at least one digit */
+ if (!isdigit(*val))
+ return -1;
+ len = strtol(val, &on, 10);
+ if (on != eol) {
+ /* line must end here */
+ return -1;
+ }
+
+ return (size_t)len;
+}
+
+static time_t
+_warc_rdrtm(const char *buf, size_t bsz)
+{
+ static const char _key[] = "\r\nWARC-Date:";
+ const char *val, *eol;
+ char *on = NULL;
+ time_t res;
+
+ if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
+ /* no bother */
+ return (time_t)-1;
+ }
+ val += sizeof(_key) - 1U;
+ if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
+ /* no end of line */
+ return -1;
+ }
+
+ /* xstrpisotime() kindly overreads whitespace for us, so use that */
+ res = xstrpisotime(val, &on);
+ if (on != eol) {
+ /* line must end here */
+ return -1;
+ }
+ return res;
+}
+
+static time_t
+_warc_rdmtm(const char *buf, size_t bsz)
+{
+ static const char _key[] = "\r\nLast-Modified:";
+ const char *val, *eol;
+ char *on = NULL;
+ time_t res;
+
+ if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) {
+ /* no bother */
+ return (time_t)-1;
+ }
+ val += sizeof(_key) - 1U;
+ if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) {
+ /* no end of line */
+ return -1;
+ }
+
+ /* xstrpisotime() kindly overreads whitespace for us, so use that */
+ res = xstrpisotime(val, &on);
+ if (on != eol) {
+ /* line must end here */
+ return -1;
+ }
+ return res;
+}
+
+static const char*
+_warc_find_eoh(const char *buf, size_t bsz)
+{
+ static const char _marker[] = "\r\n\r\n";
+ const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
+
+ if (hit != NULL) {
+ hit += sizeof(_marker) - 1U;
+ }
+ return hit;
+}
+
+static const char*
+_warc_find_eol(const char *buf, size_t bsz)
+{
+ static const char _marker[] = "\r\n";
+ const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U);
+
+ return hit;
+}
+/* archive_read_support_format_warc.c ends here */
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
index 2530e34e1..eeac1c888 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c
@@ -42,16 +42,14 @@ __FBSDID("$FreeBSD$");
#include <cm_bzlib.h>
#endif
#if HAVE_LZMA_H
-#include <lzma.h>
-#elif HAVE_LZMADEC_H
-#include <lzmadec.h>
+#include <cm_lzma.h>
#endif
#ifdef HAVE_ZLIB_H
#include <cm_zlib.h>
#endif
#include "archive.h"
-#include "archive_crypto_private.h"
+#include "archive_digest_private.h"
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
@@ -334,9 +332,6 @@ struct xar {
#if HAVE_LZMA_H && HAVE_LIBLZMA
lzma_stream lzstream;
int lzstream_valid;
-#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC
- lzmadec_stream lzstream;
- int lzstream_valid;
#endif
/*
* For Checksum data.
@@ -399,6 +394,7 @@ static void checksum_update(struct archive_read *, const void *,
size_t, const void *, size_t);
static int checksum_final(struct archive_read *, const void *,
size_t, const void *, size_t);
+static void checksum_cleanup(struct archive_read *);
static int decompression_init(struct archive_read *, enum enctype);
static int decompress(struct archive_read *, const void **,
size_t *, const void *, size_t *);
@@ -468,7 +464,9 @@ archive_read_support_format_xar(struct archive *_a)
xar_read_data,
xar_read_data_skip,
NULL,
- xar_cleanup);
+ xar_cleanup,
+ NULL,
+ NULL);
if (r != ARCHIVE_OK)
free(xar);
return (r);
@@ -926,6 +924,7 @@ xar_cleanup(struct archive_read *a)
int r;
xar = (struct xar *)(a->format->data);
+ checksum_cleanup(a);
r = decompression_cleanup(a);
hdlink = xar->hdlink_list;
while (hdlink != NULL) {
@@ -936,6 +935,7 @@ xar_cleanup(struct archive_read *a)
}
for (i = 0; i < xar->file_queue.used; i++)
file_free(xar->file_queue.files[i]);
+ free(xar->file_queue.files);
while (xar->unknowntags != NULL) {
struct unknown_tag *tag;
@@ -967,10 +967,14 @@ move_reading_point(struct archive_read *a, uint64_t offset)
return ((int)step);
xar->offset += step;
} else {
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Cannot seek.");
- return (ARCHIVE_FAILED);
+ int64_t pos = __archive_read_seek(a, offset, SEEK_SET);
+ if (pos == ARCHIVE_FAILED) {
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Cannot seek.");
+ return (ARCHIVE_FAILED);
+ }
+ xar->offset = pos;
}
}
return (ARCHIVE_OK);
@@ -1101,20 +1105,23 @@ static time_t
time_from_tm(struct tm *t)
{
#if HAVE_TIMEGM
- /* Use platform timegm() if available. */
- return (timegm(t));
+ /* Use platform timegm() if available. */
+ return (timegm(t));
#elif HAVE__MKGMTIME64
- return (_mkgmtime64(t));
+ 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);
+ /* 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
}
@@ -1517,34 +1524,6 @@ decompression_init(struct archive_read *a, enum enctype encoding)
xar->lzstream.total_in = 0;
xar->lzstream.total_out = 0;
break;
-#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
- case LZMA:
- if (xar->lzstream_valid)
- lzmadec_end(&(xar->lzstream));
- r = lzmadec_init(&(xar->lzstream));
- if (r != LZMADEC_OK) {
- switch (r) {
- case LZMADEC_HEADER_ERROR:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Internal error initializing "
- "compression library: "
- "invalid header");
- break;
- case LZMADEC_MEM_ERROR:
- archive_set_error(&a->archive,
- ENOMEM,
- "Internal error initializing "
- "compression library: "
- "out of memory");
- break;
- }
- return (ARCHIVE_FATAL);
- }
- xar->lzstream_valid = 1;
- xar->lzstream.total_in = 0;
- xar->lzstream.total_out = 0;
- break;
#endif
/*
* Unsupported compression.
@@ -1554,9 +1533,7 @@ decompression_init(struct archive_read *a, enum enctype encoding)
case BZIP2:
#endif
#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
-#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
case LZMA:
-#endif
case XZ:
#endif
switch (xar->entry_encoding) {
@@ -1676,46 +1653,12 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes,
*used = avail_in - xar->lzstream.avail_in;
*outbytes = avail_out - xar->lzstream.avail_out;
break;
-#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC)
- case LZMA:
- xar->lzstream.next_in = (unsigned char *)(uintptr_t)b;
- xar->lzstream.avail_in = avail_in;
- xar->lzstream.next_out = (unsigned char *)outbuff;
- xar->lzstream.avail_out = avail_out;
- r = lzmadec_decode(&(xar->lzstream), 0);
- switch (r) {
- case LZMADEC_STREAM_END: /* Found end of stream. */
- switch (lzmadec_end(&(xar->lzstream))) {
- case LZMADEC_OK:
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "Failed to clean up lzmadec decompressor");
- return (ARCHIVE_FATAL);
- }
- xar->lzstream_valid = 0;
- /* FALLTHROUGH */
- case LZMADEC_OK: /* Decompressor made some progress. */
- break;
- default:
- archive_set_error(&(a->archive),
- ARCHIVE_ERRNO_MISC,
- "lzmadec decompression failed(%d)",
- r);
- return (ARCHIVE_FATAL);
- }
- *used = avail_in - xar->lzstream.avail_in;
- *outbytes = avail_out - xar->lzstream.avail_out;
- break;
#endif
#if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR)
case BZIP2:
#endif
#if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA)
-#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC)
case LZMA:
-#endif
case XZ:
#endif
case NONE:
@@ -1779,6 +1722,16 @@ decompression_cleanup(struct archive_read *a)
}
static void
+checksum_cleanup(struct archive_read *a) {
+ struct xar *xar;
+
+ xar = (struct xar *)(a->format->data);
+
+ _checksum_final(&(xar->a_sumwrk), NULL, 0);
+ _checksum_final(&(xar->e_sumwrk), NULL, 0);
+}
+
+static void
xmlattr_cleanup(struct xmlattr_list *list)
{
struct xmlattr *attr, *next;
@@ -1930,9 +1883,6 @@ unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)
{
struct unknown_tag *tag;
-#if DEBUG
- fprintf(stderr, "unknowntag_start:%s\n", name);
-#endif
tag = malloc(sizeof(*tag));
if (tag == NULL) {
archive_set_error(&a->archive, ENOMEM, "Out of memory");
@@ -1942,6 +1892,9 @@ unknowntag_start(struct archive_read *a, struct xar *xar, const char *name)
archive_string_init(&(tag->name));
archive_strcpy(&(tag->name), name);
if (xar->unknowntags == NULL) {
+#if DEBUG
+ fprintf(stderr, "UNKNOWNTAG_START:%s\n", name);
+#endif
xar->xmlsts_unknown = xar->xmlsts;
xar->xmlsts = UNKNOWN;
}
@@ -1954,9 +1907,6 @@ unknowntag_end(struct xar *xar, const char *name)
{
struct unknown_tag *tag;
-#if DEBUG
- fprintf(stderr, "unknowntag_end:%s\n", name);
-#endif
tag = xar->unknowntags;
if (tag == NULL || name == NULL)
return;
@@ -1964,8 +1914,12 @@ unknowntag_end(struct xar *xar, const char *name)
xar->unknowntags = tag->next;
archive_string_free(&(tag->name));
free(tag);
- if (xar->unknowntags == NULL)
+ if (xar->unknowntags == NULL) {
+#if DEBUG
+ fprintf(stderr, "UNKNOWNTAG_END:%s\n", name);
+#endif
xar->xmlsts = xar->xmlsts_unknown;
+ }
}
}
@@ -2159,7 +2113,7 @@ xml_start(struct archive_read *a, const char *name, struct xmlattr_list *list)
case FILE_ACL:
if (strcmp(name, "appleextended") == 0)
xar->xmlsts = FILE_ACL_APPLEEXTENDED;
- if (strcmp(name, "default") == 0)
+ else if (strcmp(name, "default") == 0)
xar->xmlsts = FILE_ACL_DEFAULT;
else if (strcmp(name, "access") == 0)
xar->xmlsts = FILE_ACL_ACCESS;
@@ -2681,9 +2635,9 @@ xml_data(void *userData, const char *s, int len)
#if DEBUG
{
char buff[1024];
- if (len > sizeof(buff)-1)
- len = sizeof(buff)-1;
- memcpy(buff, s, len);
+ if (len > (int)(sizeof(buff)-1))
+ len = (int)(sizeof(buff)-1);
+ strncpy(buff, s, len);
buff[len] = 0;
fprintf(stderr, "\tlen=%d:\"%s\"\n", len, buff);
}
@@ -3106,7 +3060,7 @@ xml2_read_cb(void *context, char *buffer, int len)
struct xar *xar;
const void *d;
size_t outbytes;
- size_t used;
+ size_t used = 0;
int r;
a = (struct archive_read *)context;
@@ -3183,9 +3137,8 @@ xml2_read_toc(struct archive_read *a)
case XML_READER_TYPE_ELEMENT:
empty = xmlTextReaderIsEmptyElement(reader);
r = xml2_xmlattr_setup(a, &list, reader);
- if (r != ARCHIVE_OK)
- return (r);
- r = xml_start(a, name, &list);
+ if (r == ARCHIVE_OK)
+ r = xml_start(a, name, &list);
xmlattr_cleanup(&list);
if (r != ARCHIVE_OK)
return (r);
@@ -3231,6 +3184,9 @@ expat_xmlattr_setup(struct archive_read *a,
value = strdup(atts[1]);
if (attr == NULL || name == NULL || value == NULL) {
archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ free(attr);
+ free(name);
+ free(value);
return (ARCHIVE_FATAL);
}
attr->name = name;
diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
index 2fdc08b6a..e56bd63ac 100644
--- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c
@@ -1,6 +1,7 @@
/*-
- * Copyright (c) 2004 Tim Kientzle
- * Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2004-2013 Tim Kientzle
+ * Copyright (c) 2011-2012,2014 Michihiro NAKAJIMA
+ * Copyright (c) 2013 Konrad Kleine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,6 +28,21 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102 2009-12-28 03:11:36Z kientzle $");
+/*
+ * The definitive documentation of the Zip file format is:
+ * http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ *
+ * The Info-Zip project has pioneered various extensions to better
+ * support Zip on Unix, including the 0x5455 "UT", 0x5855 "UX", 0x7855
+ * "Ux", and 0x7875 "ux" extensions for time and ownership
+ * information.
+ *
+ * History of this code: The streaming Zip reader was first added to
+ * libarchive in January 2005. Support for seekable input sources was
+ * added in Nov 2011. Zip64 support (including a significant code
+ * refactoring) was added in 2014.
+ */
+
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -38,9 +54,12 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102
#endif
#include "archive.h"
+#include "archive_digest_private.h"
+#include "archive_cryptor_private.h"
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_hmac_private.h"
#include "archive_private.h"
#include "archive_rb.h"
#include "archive_read_private.h"
@@ -51,42 +70,85 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_zip.c 201102
struct zip_entry {
struct archive_rb_node node;
+ struct zip_entry *next;
int64_t local_header_offset;
int64_t compressed_size;
int64_t uncompressed_size;
int64_t gid;
int64_t uid;
- struct archive_entry *entry;
struct archive_string rsrcname;
time_t mtime;
time_t atime;
time_t ctime;
uint32_t crc32;
uint16_t mode;
- uint16_t flags;
- char compression;
- char system;
+ uint16_t zip_flags; /* From GP Flags Field */
+ unsigned char compression;
+ unsigned char system; /* From "version written by" */
+ unsigned char flags; /* Our extra markers. */
+ unsigned char decdat;/* Used for Decryption check */
+
+ /* WinZip AES encryption extra field should be available
+ * when compression is 99. */
+ struct {
+ /* Vendor version: AE-1 - 0x0001, AE-2 - 0x0002 */
+ unsigned vendor;
+#define AES_VENDOR_AE_1 0x0001
+#define AES_VENDOR_AE_2 0x0002
+ /* AES encryption strength:
+ * 1 - 128 bits, 2 - 192 bits, 2 - 256 bits. */
+ unsigned strength;
+ /* Actual compression method. */
+ unsigned char compression;
+ } aes_extra;
+};
+
+struct trad_enc_ctx {
+ uint32_t keys[3];
};
+/* Bits used in zip_flags. */
+#define ZIP_ENCRYPTED (1 << 0)
+#define ZIP_LENGTH_AT_END (1 << 3)
+#define ZIP_STRONG_ENCRYPTED (1 << 6)
+#define ZIP_UTF8_NAME (1 << 11)
+/* See "7.2 Single Password Symmetric Encryption Method"
+ in http://www.pkware.com/documents/casestudies/APPNOTE.TXT */
+#define ZIP_CENTRAL_DIRECTORY_ENCRYPTED (1 << 13)
+
+/* Bits used in flags. */
+#define LA_USED_ZIP64 (1 << 0)
+#define LA_FROM_CENTRAL_DIRECTORY (1 << 1)
+
+/*
+ * See "WinZip - AES Encryption Information"
+ * http://www.winzip.com/aes_info.htm
+ */
+/* Value used in compression method. */
+#define WINZIP_AES_ENCRYPTION 99
+/* Authentication code size. */
+#define AUTH_CODE_SIZE 10
+/**/
+#define MAX_DERIVED_KEY_BUF_SIZE (AES_MAX_KEY_SIZE * 2 + 2)
+
struct zip {
/* Structural information about the archive. */
- int64_t end_of_central_directory_offset;
+ struct archive_string format_name;
int64_t central_directory_offset;
- size_t central_directory_size;
- size_t central_directory_entries;
- char have_central_directory;
- int64_t offset;
+ size_t central_directory_entries_total;
+ size_t central_directory_entries_on_this_disk;
+ int has_encrypted_entries;
/* List of entries (seekable Zip only) */
- size_t entries_remaining;
struct zip_entry *zip_entries;
- struct zip_entry *entry;
struct archive_rb_tree tree;
struct archive_rb_tree tree_rsrc;
+ /* Bytes read but not yet consumed via __archive_read_consume() */
size_t unconsumed;
- /* entry_bytes_remaining is the number of bytes we expect. */
+ /* Information about entry we're currently reading. */
+ struct zip_entry *entry;
int64_t entry_bytes_remaining;
/* These count the number of bytes actually read for the entry. */
@@ -95,852 +157,595 @@ struct zip {
/* Running CRC32 of the decompressed data */
unsigned long entry_crc32;
+ unsigned long (*crc32func)(unsigned long, const void *,
+ size_t);
+ char ignore_crc32;
/* Flags to mark progress of decompression. */
char decompress_init;
char end_of_entry;
- ssize_t filename_length;
- ssize_t extra_length;
-
+#ifdef HAVE_ZLIB_H
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];
-};
+ int process_mac_extensions;
-#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 *);
-static ssize_t zip_get_local_file_header_size(struct archive_read *, size_t);
-#ifdef HAVE_ZLIB_H
-static int zip_deflate_init(struct archive_read *, struct zip *);
-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 *);
+ char init_decryption;
-int archive_read_support_format_zip_streamable(struct archive *);
-int archive_read_support_format_zip_seekable(struct archive *);
+ /* Decryption buffer. */
+ /*
+ * The decrypted data starts at decrypted_ptr and
+ * extends for decrypted_bytes_remaining. Decryption
+ * adds new data to the end of this block, data is returned
+ * to clients from the beginning. When the block hits the
+ * end of decrypted_buffer, it has to be shuffled back to
+ * the beginning of the buffer.
+ */
+ unsigned char *decrypted_buffer;
+ unsigned char *decrypted_ptr;
+ size_t decrypted_buffer_size;
+ size_t decrypted_bytes_remaining;
+ size_t decrypted_unconsumed_bytes;
+
+ /* Traditional PKWARE decryption. */
+ struct trad_enc_ctx tctx;
+ char tctx_valid;
+
+ /* WinZip AES decryption. */
+ /* Contexts used for AES decryption. */
+ archive_crypto_ctx cctx;
+ char cctx_valid;
+ archive_hmac_sha1_ctx hctx;
+ char hctx_valid;
+
+ /* Strong encryption's decryption header information. */
+ unsigned iv_size;
+ unsigned alg_id;
+ unsigned bit_len;
+ unsigned flags;
+ unsigned erd_size;
+ unsigned v_size;
+ unsigned v_crc32;
+ uint8_t *iv;
+ uint8_t *erd;
+ uint8_t *v_data;
+};
-int
-archive_read_support_format_zip_streamable(struct archive *_a)
-{
- struct archive_read *a = (struct archive_read *)_a;
- struct zip *zip;
- int r;
+/* Many systems define min or MIN, but not all. */
+#define zipmin(a,b) ((a) < (b) ? (a) : (b))
- 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));
+/*
+ Traditional PKWARE Decryption functions.
+ */
- 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,
- NULL,
- archive_read_format_zip_cleanup);
+static void
+trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)
+{
+ uint8_t t;
+#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)
+
+ ctx->keys[0] = CRC32(ctx->keys[0], c);
+ ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;
+ t = (ctx->keys[1] >> 24) & 0xff;
+ ctx->keys[2] = CRC32(ctx->keys[2], t);
+#undef CRC32
+}
- if (r != ARCHIVE_OK)
- free(zip);
- return (ARCHIVE_OK);
+static uint8_t
+trad_enc_decrypt_byte(struct trad_enc_ctx *ctx)
+{
+ unsigned temp = ctx->keys[2] | 2;
+ return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff;
}
-int
-archive_read_support_format_zip_seekable(struct archive *_a)
+static void
+trad_enc_decrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in,
+ size_t in_len, uint8_t *out, size_t out_len)
{
- struct archive_read *a = (struct archive_read *)_a;
- struct zip *zip;
- int r;
+ unsigned i, max;
- archive_check_magic(_a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_NEW, "archive_read_support_format_zip_seekable");
+ max = (unsigned)((in_len < out_len)? in_len: out_len);
- zip = (struct zip *)malloc(sizeof(*zip));
- if (zip == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate zip data");
- return (ARCHIVE_FATAL);
+ for (i = 0; i < max; i++) {
+ uint8_t t = in[i] ^ trad_enc_decrypt_byte(ctx);
+ out[i] = t;
+ trad_enc_update_keys(ctx, t);
}
- 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,
- NULL,
- 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.
- *
- * We workaround this a little by passing in the best bid so far so
- * that later bidders can do nothing if they know they'll never
- * outbid. But we can certainly do better...
- */
static int
-archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
+trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len,
+ const uint8_t *key, size_t key_len, uint8_t *crcchk)
{
- 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) {
- int64_t i, tail;
- int found;
+ uint8_t header[12];
- /*
- * If there is a comment in end of central directory
- * record, 22 bytes are too short. we have to read more
- * to properly detect the record. Hopefully, a length
- * of the comment is not longer than 16362 bytes(16K-22).
- */
- if (filesize + 22 > 1024 * 16) {
- tail = 1024 * 16;
- filesize = __archive_read_seek(a, tail * -1, SEEK_END);
- } else {
- tail = filesize + 22;
- filesize = __archive_read_seek(a, 0, SEEK_SET);
- }
- if (filesize < 0)
- return 0;
- if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
- return 0;
- for (found = 0, i = 0;!found && i < tail - 22;) {
- switch (p[i]) {
- case 'P':
- if (memcmp(p+i,
- "PK\005\006\000\000\000\000", 8) == 0) {
- p += i;
- filesize += tail -
- (22 + archive_le16dec(p+20));
- found = 1;
- } else
- i += 8;
- break;
- case 'K': i += 7; break;
- case 005: i += 6; break;
- case 006: i += 5; break;
- default: i += 1; break;
- }
- }
- if (!found)
- return 0;
+ if (key_len < 12) {
+ *crcchk = 0xff;
+ return -1;
}
- /* 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);
- zip->end_of_central_directory_offset = filesize;
+ ctx->keys[0] = 305419896L;
+ ctx->keys[1] = 591751049L;
+ ctx->keys[2] = 878082192L;
- /* 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 +
- (int64_t)zip->central_directory_size > filesize)
- return 0;
+ for (;pw_len; --pw_len)
+ trad_enc_update_keys(ctx, *pw++);
- /* 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;
+ trad_enc_decrypt_update(ctx, key, 12, header, 12);
+ /* Return the last byte for CRC check. */
+ *crcchk = header[11];
+ return 0;
}
-static int
-cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
+#if 0
+static void
+crypt_derive_key_sha1(const void *p, int size, unsigned char *key,
+ int key_size)
{
- const struct zip_entry *e1 = (const struct zip_entry *)n1;
- const struct zip_entry *e2 = (const struct zip_entry *)n2;
-
- return ((int)(e2->local_header_offset - e1->local_header_offset));
+#define MD_SIZE 20
+ archive_sha1_ctx ctx;
+ unsigned char md1[MD_SIZE];
+ unsigned char md2[MD_SIZE * 2];
+ unsigned char mkb[64];
+ int i;
+
+ archive_sha1_init(&ctx);
+ archive_sha1_update(&ctx, p, size);
+ archive_sha1_final(&ctx, md1);
+
+ memset(mkb, 0x36, sizeof(mkb));
+ for (i = 0; i < MD_SIZE; i++)
+ mkb[i] ^= md1[i];
+ archive_sha1_init(&ctx);
+ archive_sha1_update(&ctx, mkb, sizeof(mkb));
+ archive_sha1_final(&ctx, md2);
+
+ memset(mkb, 0x5C, sizeof(mkb));
+ for (i = 0; i < MD_SIZE; i++)
+ mkb[i] ^= md1[i];
+ archive_sha1_init(&ctx);
+ archive_sha1_update(&ctx, mkb, sizeof(mkb));
+ archive_sha1_final(&ctx, md2 + MD_SIZE);
+
+ if (key_size > 32)
+ key_size = 32;
+ memcpy(key, md2, key_size);
+#undef MD_SIZE
}
+#endif
-static int
-cmp_key(const struct archive_rb_node *n, const void *key)
-{
- /* This function won't be called */
- (void)n; /* UNUSED */
- (void)key; /* UNUSED */
- return 1;
-}
+/*
+ * Common code for streaming or seeking modes.
+ *
+ * Includes code to read local file headers, decompress data
+ * from entry bodies, and common API.
+ */
-static int
-rsrc_cmp_node(const struct archive_rb_node *n1,
- const struct archive_rb_node *n2)
+static unsigned long
+real_crc32(unsigned long crc, const void *buff, size_t len)
{
- const struct zip_entry *e1 = (const struct zip_entry *)n1;
- const struct zip_entry *e2 = (const struct zip_entry *)n2;
-
- return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
+ return crc32(crc, buff, (unsigned int)len);
}
-static int
-rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
+/* Used by "ignorecrc32" option to speed up tests. */
+static unsigned long
+fake_crc32(unsigned long crc, const void *buff, size_t len)
{
- const struct zip_entry *e = (const struct zip_entry *)n;
- return (strcmp((const char *)key, e->rsrcname.s));
+ (void)crc; /* UNUSED */
+ (void)buff; /* UNUSED */
+ (void)len; /* UNUSED */
+ return 0;
}
+static struct {
+ int id;
+ const char * name;
+} compression_methods[] = {
+ {0, "uncompressed"}, /* The file is stored (no compression) */
+ {1, "shrinking"}, /* The file is Shrunk */
+ {2, "reduced-1"}, /* The file is Reduced with compression factor 1 */
+ {3, "reduced-2"}, /* The file is Reduced with compression factor 2 */
+ {4, "reduced-3"}, /* The file is Reduced with compression factor 3 */
+ {5, "reduced-4"}, /* The file is Reduced with compression factor 4 */
+ {6, "imploded"}, /* The file is Imploded */
+ {7, "reserved"}, /* Reserved for Tokenizing compression algorithm */
+ {8, "deflation"}, /* The file is Deflated */
+ {9, "deflation-64-bit"}, /* Enhanced Deflating using Deflate64(tm) */
+ {10, "ibm-terse"},/* PKWARE Data Compression Library Imploding
+ * (old IBM TERSE) */
+ {11, "reserved"}, /* Reserved by PKWARE */
+ {12, "bzip"}, /* File is compressed using BZIP2 algorithm */
+ {13, "reserved"}, /* Reserved by PKWARE */
+ {14, "lzma"}, /* LZMA (EFS) */
+ {15, "reserved"}, /* Reserved by PKWARE */
+ {16, "reserved"}, /* Reserved by PKWARE */
+ {17, "reserved"}, /* Reserved by PKWARE */
+ {18, "ibm-terse-new"}, /* File is compressed using IBM TERSE (new) */
+ {19, "ibm-lz777"},/* IBM LZ77 z Architecture (PFS) */
+ {97, "wav-pack"}, /* WavPack compressed data */
+ {98, "ppmd-1"}, /* PPMd version I, Rev 1 */
+ {99, "aes"} /* WinZip AES encryption */
+};
+
static const char *
-rsrc_basename(const char *name, size_t name_length)
+compression_name(const int compression)
{
- const char *s, *r;
-
- r = s = name;
- for (;;) {
- s = memchr(s, '/', name_length - (s - name));
- if (s == NULL)
- break;
- r = ++s;
+ static const int num_compression_methods =
+ sizeof(compression_methods)/sizeof(compression_methods[0]);
+ int i=0;
+
+ while(compression >= 0 && i < num_compression_methods) {
+ if (compression_methods[i].id == compression)
+ return compression_methods[i].name;
+ i++;
}
- return (r);
+ return "??";
}
-static void
-expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
-{
- struct archive_string str;
- struct zip_entry *dir;
- char *s;
-
- archive_string_init(&str);
- archive_strncpy(&str, name, name_length);
- for (;;) {
- s = strrchr(str.s, '/');
- if (s == NULL)
- break;
- *s = '\0';
- /* Transfer the parent directory from zip->tree_rsrc RB
- * tree to zip->tree RB tree to expose. */
- dir = (struct zip_entry *)
- __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
- if (dir == NULL)
- break;
- __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
- archive_string_free(&dir->rsrcname);
- __archive_rb_tree_insert_node(&zip->tree, &dir->node);
- }
- archive_string_free(&str);
-}
-
-static int
-slurp_central_directory(struct archive_read *a, struct zip *zip)
+/* Convert an MSDOS-style date/time into Unix-style time. */
+static time_t
+zip_time(const char *p)
{
- unsigned i;
- int64_t correction;
- static const struct archive_rb_tree_ops rb_ops = {
- &cmp_node, &cmp_key
- };
- static const struct archive_rb_tree_ops rb_rsrc_ops = {
- &rsrc_cmp_node, &rsrc_cmp_key
- };
-
- /*
- * Consider the archive file we are reading may be SFX.
- * So we have to calculate a SFX header size to revise
- * ZIP header offsets.
- */
- correction = zip->end_of_central_directory_offset -
- (zip->central_directory_offset + zip->central_directory_size);
- /* The central directory offset is relative value, and so
- * we revise this offset for SFX. */
- zip->central_directory_offset += correction;
-
- __archive_read_seek(a, zip->central_directory_offset, SEEK_SET);
- zip->offset = zip->central_directory_offset;
- __archive_rb_tree_init(&zip->tree, &rb_ops);
- __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
-
- 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 *name, *p, *r;
-
- 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 = (char)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) + correction;
-
- /* If we can't guess the mode, leave it zero here;
- when we read the local file header we might get
- more information. */
- zip_entry->mode = 0;
- if (zip_entry->system == 3) {
- zip_entry->mode = external_attributes >> 16;
- }
-
- /*
- * Mac resource fork files are stored under the
- * "__MACOSX/" directory, so we should check if
- * it is.
- */
- /* Make sure we have the file name. */
- if ((p = __archive_read_ahead(a, 46 + filename_length, NULL))
- == NULL)
- return ARCHIVE_FATAL;
- name = p + 46;
- r = rsrc_basename(name, filename_length);
- if (filename_length >= 9 &&
- strncmp("__MACOSX/", name, 9) == 0) {
- /* If this file is not a resource fork nor
- * a directory. We should treat it as a non
- * resource fork file to expose it. */
- if (name[filename_length-1] != '/' &&
- (r - name < 3 || r[0] != '.' || r[1] != '_')) {
- __archive_rb_tree_insert_node(&zip->tree,
- &zip_entry->node);
- /* Expose its parent directories. */
- expose_parent_dirs(zip, name, filename_length);
- } else {
- /* This file is a resource fork file or
- * a directory. */
- archive_strncpy(&(zip_entry->rsrcname), name,
- filename_length);
- __archive_rb_tree_insert_node(&zip->tree_rsrc,
- &zip_entry->node);
- }
- } else {
- /* Generate resource fork name to find its resource
- * file at zip->tree_rsrc. */
- archive_strcpy(&(zip_entry->rsrcname), "__MACOSX/");
- archive_strncat(&(zip_entry->rsrcname), name, r - name);
- archive_strcat(&(zip_entry->rsrcname), "._");
- archive_strncat(&(zip_entry->rsrcname),
- name + (r - name), filename_length - (r - name));
- /* Register an entry to RB tree to sort it by
- * file offset. */
- __archive_rb_tree_insert_node(&zip->tree,
- &zip_entry->node);
- }
-
- /* We don't read the filename until we get to the
- local file header. Reading it here would speed up
- table-of-contents operations (removing the need to
- find and read local file header to get the
- filename) at the cost of requiring a lot of extra
- space. */
- /* We don't read the extra block here. We assume it
- will be duplicated at the local file header. */
- __archive_read_consume(a,
- 46 + filename_length + extra_length + comment_length);
- }
-
- return ARCHIVE_OK;
-}
+ int msTime, msDate;
+ struct tm ts;
-static int64_t
-zip_read_consume(struct archive_read *a, int64_t bytes)
-{
- struct zip *zip = (struct zip *)a->format->data;
- int64_t skip;
+ msTime = (0xff & (unsigned)p[0]) + 256 * (0xff & (unsigned)p[1]);
+ msDate = (0xff & (unsigned)p[2]) + 256 * (0xff & (unsigned)p[3]);
- skip = __archive_read_consume(a, bytes);
- if (skip > 0)
- zip->offset += skip;
- return (skip);
+ 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);
}
+/*
+ * The extra data is stored as a list of
+ * id1+size1+data1 + id2+size2+data2 ...
+ * triplets. id and size are 2 bytes each.
+ */
static int
-zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
- struct zip_entry *rsrc)
+process_extra(struct archive_read *a, const char *p, size_t extra_length, struct zip_entry* zip_entry)
{
- struct zip *zip = (struct zip *)a->format->data;
- unsigned char *metadata, *mp;
- int64_t offset = zip->offset;
- size_t remaining_bytes, metadata_bytes;
- ssize_t hsize;
- int ret = ARCHIVE_OK, eof;
+ unsigned offset = 0;
- switch(rsrc->compression) {
- case 0: /* No compression. */
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
-#endif
- break;
- default: /* Unsupported compression. */
- /* Return a warning. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unsupported ZIP compression method (%s)",
- compression_name(rsrc->compression));
- /* We can't decompress this entry, but we will
- * be able to skip() it and try the next entry. */
- return (ARCHIVE_WARN);
+ if (extra_length == 0) {
+ return ARCHIVE_OK;
}
- if (rsrc->uncompressed_size > (128 * 1024)) {
+ if (extra_length < 4) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Mac metadata is too large: %jd > 128K bytes",
- (intmax_t)rsrc->uncompressed_size);
- return (ARCHIVE_WARN);
- }
-
- metadata = malloc((size_t)rsrc->uncompressed_size);
- if (metadata == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Mac metadata");
- return (ARCHIVE_FATAL);
+ "Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length);
+ return ARCHIVE_FAILED;
}
+ while (offset <= extra_length - 4) {
+ unsigned short headerid = archive_le16dec(p + offset);
+ unsigned short datasize = archive_le16dec(p + offset + 2);
- if (zip->offset < rsrc->local_header_offset)
- zip_read_consume(a, rsrc->local_header_offset - zip->offset);
- else if (zip->offset != rsrc->local_header_offset) {
- __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
- zip->offset = zip->entry->local_header_offset;
- }
-
- hsize = zip_get_local_file_header_size(a, 0);
- zip_read_consume(a, hsize);
-
- remaining_bytes = (size_t)rsrc->compressed_size;
- metadata_bytes = (size_t)rsrc->uncompressed_size;
- mp = metadata;
- eof = 0;
- while (!eof && remaining_bytes) {
- const unsigned char *p;
- ssize_t bytes_avail;
- size_t bytes_used;
-
- p = __archive_read_ahead(a, 1, &bytes_avail);
- if (p == NULL) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- ret = ARCHIVE_WARN;
- goto exit_mac_metadata;
+ offset += 4;
+ if (offset + datasize > extra_length) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Extra data overflow: Need %d bytes but only found %d bytes",
+ (int)datasize, (int)(extra_length - offset));
+ return ARCHIVE_FAILED;
}
- if ((size_t)bytes_avail > remaining_bytes)
- bytes_avail = remaining_bytes;
- switch(rsrc->compression) {
- case 0: /* No compression. */
- memcpy(mp, p, bytes_avail);
- bytes_used = (size_t)bytes_avail;
- metadata_bytes -= bytes_used;
- mp += bytes_used;
- if (metadata_bytes == 0)
- eof = 1;
+#ifdef DEBUG
+ fprintf(stderr, "Header id 0x%04x, length %d\n",
+ headerid, datasize);
+#endif
+ switch (headerid) {
+ case 0x0001:
+ /* Zip64 extended information extra field. */
+ zip_entry->flags |= LA_USED_ZIP64;
+ if (zip_entry->uncompressed_size == 0xffffffff) {
+ uint64_t t = 0;
+ if (datasize < 8
+ || (t = archive_le64dec(p + offset)) > INT64_MAX) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Malformed 64-bit uncompressed size");
+ return ARCHIVE_FAILED;
+ }
+ zip_entry->uncompressed_size = t;
+ offset += 8;
+ datasize -= 8;
+ }
+ if (zip_entry->compressed_size == 0xffffffff) {
+ uint64_t t = 0;
+ if (datasize < 8
+ || (t = archive_le64dec(p + offset)) > INT64_MAX) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Malformed 64-bit compressed size");
+ return ARCHIVE_FAILED;
+ }
+ zip_entry->compressed_size = t;
+ offset += 8;
+ datasize -= 8;
+ }
+ if (zip_entry->local_header_offset == 0xffffffff) {
+ uint64_t t = 0;
+ if (datasize < 8
+ || (t = archive_le64dec(p + offset)) > INT64_MAX) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Malformed 64-bit local header offset");
+ return ARCHIVE_FAILED;
+ }
+ zip_entry->local_header_offset = t;
+ offset += 8;
+ datasize -= 8;
+ }
+ /* archive_le32dec(p + offset) gives disk
+ * on which file starts, but we don't handle
+ * multi-volume Zip files. */
break;
-#ifdef HAVE_ZLIB_H
- case 8: /* Deflate compression. */
+#ifdef DEBUG
+ case 0x0017:
{
- int r;
-
- ret = zip_deflate_init(a, zip);
- if (ret != ARCHIVE_OK)
- goto exit_mac_metadata;
- zip->stream.next_in =
- (Bytef *)(uintptr_t)(const void *)p;
- zip->stream.avail_in = (uInt)bytes_avail;
- zip->stream.total_in = 0;
- zip->stream.next_out = mp;
- zip->stream.avail_out = (uInt)metadata_bytes;
- zip->stream.total_out = 0;
-
- r = inflate(&zip->stream, 0);
- switch (r) {
- case Z_OK:
- break;
- case Z_STREAM_END:
- eof = 1;
- break;
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Out of memory for ZIP decompression");
- ret = ARCHIVE_FATAL;
- goto exit_mac_metadata;
- default:
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "ZIP decompression failed (%d)", r);
- ret = ARCHIVE_FATAL;
- goto exit_mac_metadata;
+ /* Strong encryption field. */
+ if (archive_le16dec(p + offset) == 2) {
+ unsigned algId =
+ archive_le16dec(p + offset + 2);
+ unsigned bitLen =
+ archive_le16dec(p + offset + 4);
+ int flags =
+ archive_le16dec(p + offset + 6);
+ fprintf(stderr, "algId=0x%04x, bitLen=%u, "
+ "flgas=%d\n", algId, bitLen,flags);
}
- bytes_used = zip->stream.total_in;
- metadata_bytes -= zip->stream.total_out;
- mp += zip->stream.total_out;
break;
}
#endif
- default:
- bytes_used = 0;
+ 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;
}
- zip_read_consume(a, bytes_used);
- remaining_bytes -= bytes_used;
- }
- archive_entry_copy_mac_metadata(entry, metadata,
- (size_t)rsrc->uncompressed_size - metadata_bytes);
-
- __archive_read_seek(a, offset, SEEK_SET);
- zip->offset = offset;
-exit_mac_metadata:
- zip->decompress_init = 0;
- free(metadata);
- return (ret);
-}
-
-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;
- struct zip_entry *rsrc;
- int r, ret = ARCHIVE_OK;
-
- 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;
- /* Get first entry whose local header offset is lower than
- * other entries in the archive file. */
- zip->entry =
- (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
- } else if (zip->entry != NULL) {
- /* Get next entry in local header offset order. */
- zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
- &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
- }
-
- if (zip->entries_remaining <= 0 || zip->entry == NULL)
- return ARCHIVE_EOF;
- --zip->entries_remaining;
-
- if (zip->entry->rsrcname.s)
- rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
- &zip->tree_rsrc, zip->entry->rsrcname.s);
- else
- rsrc = NULL;
-
- /* File entries are sorted by the header offset, we should mostly
- * use zip_read_consume to advance a read point to avoid redundant
- * data reading. */
- if (zip->offset < zip->entry->local_header_offset)
- zip_read_consume(a,
- zip->entry->local_header_offset - zip->offset);
- else if (zip->offset != zip->entry->local_header_offset) {
- __archive_read_seek(a, zip->entry->local_header_offset,
- SEEK_SET);
- zip->offset = zip->entry->local_header_offset;
- }
- zip->unconsumed = 0;
- 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;
- struct archive_string_conv *sconv;
- size_t linkname_length = (size_t)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;
- }
-
- sconv = zip->sconv;
- if (sconv == NULL && (zip->entry->flags & ZIP_UTF8_NAME))
- sconv = zip->sconv_utf8;
- if (sconv == NULL)
- sconv = zip->sconv_default;
- if (archive_entry_copy_symlink_l(entry, p, linkname_length,
- sconv) != 0) {
- if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
- (zip->entry->flags & ZIP_UTF8_NAME))
- archive_entry_copy_symlink_l(entry, p,
- linkname_length, NULL);
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for Symlink");
- return (ARCHIVE_FATAL);
+ 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);
}
- /*
- * Since there is no character-set regulation for
- * symlink name, do not report the conversion error
- * in an automatic conversion.
- */
- if (sconv != zip->sconv_utf8 ||
- (zip->entry->flags & ZIP_UTF8_NAME) == 0) {
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Symlink cannot be converted "
- "from %s to current locale.",
- archive_string_conversion_charset_name(
- sconv));
- ret = ARCHIVE_WARN;
+ if (datasize >= 12) {
+ zip_entry->uid =
+ archive_le16dec(p + offset + 8);
+ zip_entry->gid =
+ archive_le16dec(p + offset + 10);
}
+ break;
}
- }
- if (rsrc) {
- int ret2 = zip_read_mac_metadata(a, entry, rsrc);
- if (ret2 < ret)
- ret = ret2;
- }
- return (ret);
-}
-
-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);
- }
-
- /* TODO: It's worth looking ahead a little bit for a valid
- * PK signature. In particular, that would make it possible
- * to read some UUEncoded SFX files or SFX files coming from
- * a network socket. */
-
- 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;
- return (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;
- }
- return (ret);
- }
-
- /* Note: The "warn" return is just to inform the options
- * supervisor that we didn't handle it. It will generate
- * a suitable error if no one used this option. */
- return (ARCHIVE_WARN);
-}
-
-static int
-archive_read_format_zip_streamable_read_header(struct archive_read *a,
- struct archive_entry *entry)
-{
- struct zip *zip;
+ case 0x6c78:
+ {
+ /* Experimental 'xl' field */
+ /*
+ * Introduced Dec 2013 to provide a way to
+ * include external file attributes (and other
+ * fields that ordinarily appear only in
+ * central directory) in local file header.
+ * This provides file type and permission
+ * information necessary to support full
+ * streaming extraction. Currently being
+ * discussed with other Zip developers
+ * ... subject to change.
+ *
+ * Format:
+ * The field starts with a bitmap that specifies
+ * which additional fields are included. The
+ * bitmap is variable length and can be extended in
+ * the future.
+ *
+ * n bytes - feature bitmap: first byte has low-order
+ * 7 bits. If high-order bit is set, a subsequent
+ * byte holds the next 7 bits, etc.
+ *
+ * if bitmap & 1, 2 byte "version made by"
+ * if bitmap & 2, 2 byte "internal file attributes"
+ * if bitmap & 4, 4 byte "external file attributes"
+ * if bitmap & 8, 2 byte comment length + n byte comment
+ */
+ int bitmap, bitmap_last;
- a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
- if (a->archive.archive_format_name == NULL)
- a->archive.archive_format_name = "ZIP";
+ if (datasize < 1)
+ break;
+ bitmap_last = bitmap = 0xff & p[offset];
+ offset += 1;
+ datasize -= 1;
+
+ /* We only support first 7 bits of bitmap; skip rest. */
+ while ((bitmap_last & 0x80) != 0
+ && datasize >= 1) {
+ bitmap_last = p[offset];
+ offset += 1;
+ datasize -= 1;
+ }
- zip = (struct zip *)(a->format->data);
+ if (bitmap & 1) {
+ /* 2 byte "version made by" */
+ if (datasize < 2)
+ break;
+ zip_entry->system
+ = archive_le16dec(p + offset) >> 8;
+ offset += 2;
+ datasize -= 2;
+ }
+ if (bitmap & 2) {
+ /* 2 byte "internal file attributes" */
+ uint32_t internal_attributes;
+ if (datasize < 2)
+ break;
+ internal_attributes
+ = archive_le16dec(p + offset);
+ /* Not used by libarchive at present. */
+ (void)internal_attributes; /* UNUSED */
+ offset += 2;
+ datasize -= 2;
+ }
+ if (bitmap & 4) {
+ /* 4 byte "external file attributes" */
+ uint32_t external_attributes;
+ if (datasize < 4)
+ break;
+ external_attributes
+ = archive_le32dec(p + offset);
+ if (zip_entry->system == 3) {
+ zip_entry->mode
+ = external_attributes >> 16;
+ } else if (zip_entry->system == 0) {
+ // Interpret MSDOS directory bit
+ if (0x10 == (external_attributes & 0x10)) {
+ zip_entry->mode = AE_IFDIR | 0775;
+ } else {
+ zip_entry->mode = AE_IFREG | 0664;
+ }
+ if (0x01 == (external_attributes & 0x01)) {
+ // Read-only bit; strip write permissions
+ zip_entry->mode &= 0555;
+ }
+ } else {
+ zip_entry->mode = 0;
+ }
+ offset += 4;
+ datasize -= 4;
+ }
+ if (bitmap & 8) {
+ /* 2 byte comment length + comment */
+ uint32_t comment_length;
+ if (datasize < 2)
+ break;
+ comment_length
+ = archive_le16dec(p + offset);
+ offset += 2;
+ datasize -= 2;
- /* 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;
+ if (datasize < comment_length)
+ break;
+ /* Comment is not supported by libarchive */
+ offset += comment_length;
+ datasize -= comment_length;
+ }
+ break;
}
- }
- zip->entry = zip->zip_entries;
- memset(zip->entry, 0, sizeof(struct zip_entry));
-
- /* Search ahead for the next local file header. */
- zip_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);
+ 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 (p[2] == '\003' && p[3] == '\004') {
- /* Regular file entry. */
- zip_read_consume(a, skipped);
- return zip_read_local_file_header(a,
- entry, zip);
+ /* TODO: support arbitrary uidsize/gidsize. */
+ if (datasize >= 1 && p[offset] == 1) {/* version=1 */
+ if (datasize >= 4) {
+ /* get a uid size. */
+ uidsize = 0xff & (int)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 = 0xff & (int)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);
}
-
- if (p[2] == '\005' && p[3] == '\006')
- /* End of central directory. */
- return (ARCHIVE_EOF);
}
- ++p;
- ++skipped;
+ break;
}
- zip_read_consume(a, skipped);
+ case 0x9901:
+ /* WinZip AES extra data field. */
+ if (p[offset + 2] == 'A' && p[offset + 3] == 'E') {
+ /* Vendor version. */
+ zip_entry->aes_extra.vendor =
+ archive_le16dec(p + offset);
+ /* AES encryption strength. */
+ zip_entry->aes_extra.strength = p[offset + 4];
+ /* Actual compression method. */
+ zip_entry->aes_extra.compression =
+ p[offset + 5];
+ }
+ break;
+ default:
+ break;
+ }
+ offset += datasize;
}
-}
-
-static ssize_t
-zip_get_local_file_header_size(struct archive_read *a, size_t extra)
-{
- const char *p;
- ssize_t filename_length, extra_length;
-
- if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
+ if (offset != extra_length) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Truncated ZIP file header");
- return (ARCHIVE_WARN);
- }
- p += extra;
-
- if (memcmp(p, "PK\003\004", 4) != 0) {
- archive_set_error(&a->archive, -1, "Damaged Zip archive");
- return ARCHIVE_WARN;
+ "Malformed extra data: Consumed %d bytes of %d bytes",
+ (int)offset, (int)extra_length);
+ return ARCHIVE_FAILED;
}
- filename_length = archive_le16dec(p + 26);
- extra_length = archive_le16dec(p + 28);
-
- return (30 + filename_length + extra_length);
+ return ARCHIVE_OK;
}
/*
@@ -957,16 +762,18 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
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;
+ struct zip_entry zip_entry_central_dir;
int ret = ARCHIVE_OK;
char version;
+ /* Save a copy of the original for consistency checks. */
+ zip_entry_central_dir = *zip_entry;
+
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);
+ zip->entry_crc32 = zip->crc32func(0, NULL, 0);
/* Setup default conversion. */
if (zip->sconv == NULL && !zip->init_default_conversion) {
@@ -987,52 +794,31 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
}
version = p[4];
zip_entry->system = p[5];
- zip_entry->flags = archive_le16dec(p + 6);
+ zip_entry->zip_flags = archive_le16dec(p + 6);
+ if (zip_entry->zip_flags & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)) {
+ zip->has_encrypted_entries = 1;
+ archive_entry_set_is_data_encrypted(entry, 1);
+ if (zip_entry->zip_flags & ZIP_CENTRAL_DIRECTORY_ENCRYPTED &&
+ zip_entry->zip_flags & ZIP_ENCRYPTED &&
+ zip_entry->zip_flags & ZIP_STRONG_ENCRYPTED) {
+ archive_entry_set_is_metadata_encrypted(entry, 1);
+ return ARCHIVE_FATAL;
+ }
+ }
+ zip->init_decryption = (zip_entry->zip_flags & ZIP_ENCRYPTED);
zip_entry->compression = (char)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);
+ zip_entry->crc32 = archive_le32dec(p + 14);
+ if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
+ zip_entry->decdat = p[11];
+ else
+ zip_entry->decdat = p[17];
+ zip_entry->compressed_size = archive_le32dec(p + 18);
+ zip_entry->uncompressed_size = archive_le32dec(p + 22);
filename_length = archive_le16dec(p + 26);
extra_length = archive_le16dec(p + 28);
- zip_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;
- }
+ __archive_read_consume(a, 30);
/* Read the filename. */
if ((h = __archive_read_ahead(a, filename_length, NULL)) == NULL) {
@@ -1040,7 +826,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
- if (zip_entry->flags & ZIP_UTF8_NAME) {
+ if (zip_entry->zip_flags & ZIP_UTF8_NAME) {
/* The filename is stored to be UTF-8. */
if (zip->sconv_utf8 == NULL) {
zip->sconv_utf8 =
@@ -1069,37 +855,127 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
archive_string_conversion_charset_name(sconv));
ret = ARCHIVE_WARN;
}
- zip_read_consume(a, filename_length);
+ __archive_read_consume(a, filename_length);
+ /* 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);
+ }
+
+ if (ARCHIVE_OK != process_extra(a, h, extra_length, zip_entry)) {
+ return ARCHIVE_FATAL;
+ }
+ __archive_read_consume(a, extra_length);
+
+ /* Work around a bug in Info-Zip: When reading from a pipe, it
+ * stats the pipe instead of synthesizing a file entry. */
+ if ((zip_entry->mode & AE_IFMT) == AE_IFIFO) {
+ zip_entry->mode &= ~ AE_IFMT;
+ zip_entry->mode |= AE_IFREG;
+ }
+
+ /* If the mode is totally empty, set some sane default. */
if (zip_entry->mode == 0) {
- /* Especially in streaming mode, we can end up
- here without having seen any mode information.
- Guess from the filename. */
+ zip_entry->mode |= 0664;
+ }
+
+ /* Make sure that entries with a trailing '/' are marked as directories
+ * even if the External File Attributes contains bogus values. If this
+ * is not a directory and there is no type, assume regularfile. */
+ if ((zip_entry->mode & AE_IFMT) != AE_IFDIR) {
+ int has_slash;
+
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 | 0666;
+ has_slash = len > 0 && wp[len - 1] == L'/';
} 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 | 0666;
+ has_slash = len > 0 && cp[len - 1] == '/';
+ }
+ /* Correct file type as needed. */
+ if (has_slash) {
+ zip_entry->mode &= ~AE_IFMT;
+ zip_entry->mode |= AE_IFDIR;
+ zip_entry->mode |= 0111;
+ } else if ((zip_entry->mode & AE_IFMT) == 0) {
+ zip_entry->mode |= AE_IFREG;
}
}
- /* 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);
+ /* Make sure directories end in '/' */
+ if ((zip_entry->mode & AE_IFMT) == AE_IFDIR) {
+ wp = archive_entry_pathname_w(entry);
+ if (wp != NULL) {
+ len = wcslen(wp);
+ if (len > 0 && wp[len - 1] != L'/') {
+ struct archive_wstring s;
+ archive_string_init(&s);
+ archive_wstrcat(&s, wp);
+ archive_wstrappend_wchar(&s, L'/');
+ archive_entry_copy_pathname_w(entry, s.s);
+ archive_wstring_free(&s);
+ }
+ } else {
+ cp = archive_entry_pathname(entry);
+ len = (cp != NULL)?strlen(cp):0;
+ if (len > 0 && cp[len - 1] != '/') {
+ struct archive_string s;
+ archive_string_init(&s);
+ archive_strcat(&s, cp);
+ archive_strappend_char(&s, '/');
+ archive_entry_set_pathname(entry, s.s);
+ archive_string_free(&s);
+ }
+ }
+ }
+
+ if (zip_entry->flags & LA_FROM_CENTRAL_DIRECTORY) {
+ /* If this came from the central dir, it's size info
+ * is definitive, so ignore the length-at-end flag. */
+ zip_entry->zip_flags &= ~ZIP_LENGTH_AT_END;
+ /* If local header is missing a value, use the one from
+ the central directory. If both have it, warn about
+ mismatches. */
+ if (zip_entry->crc32 == 0) {
+ zip_entry->crc32 = zip_entry_central_dir.crc32;
+ } else if (!zip->ignore_crc32
+ && zip_entry->crc32 != zip_entry_central_dir.crc32) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Inconsistent CRC32 values");
+ ret = ARCHIVE_WARN;
+ }
+ if (zip_entry->compressed_size == 0) {
+ zip_entry->compressed_size
+ = zip_entry_central_dir.compressed_size;
+ } else if (zip_entry->compressed_size
+ != zip_entry_central_dir.compressed_size) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Inconsistent compressed size: "
+ "%jd in central directory, %jd in local header",
+ (intmax_t)zip_entry_central_dir.compressed_size,
+ (intmax_t)zip_entry->compressed_size);
+ ret = ARCHIVE_WARN;
+ }
+ if (zip_entry->uncompressed_size == 0) {
+ zip_entry->uncompressed_size
+ = zip_entry_central_dir.uncompressed_size;
+ } else if (zip_entry->uncompressed_size
+ != zip_entry_central_dir.uncompressed_size) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Inconsistent uncompressed size: "
+ "%jd in central directory, %jd in local header",
+ (intmax_t)zip_entry_central_dir.uncompressed_size,
+ (intmax_t)zip_entry->uncompressed_size);
+ ret = ARCHIVE_WARN;
+ }
}
- process_extra(h, extra_length, zip_entry);
- zip_read_consume(a, extra_length);
/* Populate some additional entry fields: */
archive_entry_set_mode(entry, zip_entry->mode);
@@ -1108,155 +984,120 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry,
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);
+ if ((zip->entry->mode & AE_IFMT) == AE_IFLNK) {
+ size_t linkname_length;
+
+ if (zip_entry->compressed_size > 64 * 1024) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Zip file with oversized link entry");
+ return ARCHIVE_FATAL;
+ }
+
+ linkname_length = (size_t)zip_entry->compressed_size;
+
+ 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;
+ }
+
+ sconv = zip->sconv;
+ if (sconv == NULL && (zip->entry->zip_flags & ZIP_UTF8_NAME))
+ sconv = zip->sconv_utf8;
+ if (sconv == NULL)
+ sconv = zip->sconv_default;
+ if (archive_entry_copy_symlink_l(entry, p, linkname_length,
+ sconv) != 0) {
+ if (errno != ENOMEM && sconv == zip->sconv_utf8 &&
+ (zip->entry->zip_flags & ZIP_UTF8_NAME))
+ archive_entry_copy_symlink_l(entry, p,
+ linkname_length, NULL);
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Symlink");
+ return (ARCHIVE_FATAL);
+ }
+ /*
+ * Since there is no character-set regulation for
+ * symlink name, do not report the conversion error
+ * in an automatic conversion.
+ */
+ if (sconv != zip->sconv_utf8 ||
+ (zip->entry->zip_flags & ZIP_UTF8_NAME) == 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Symlink cannot be converted "
+ "from %s to current locale.",
+ archive_string_conversion_charset_name(
+ sconv));
+ ret = ARCHIVE_WARN;
+ }
+ }
+ zip_entry->uncompressed_size = zip_entry->compressed_size = 0;
+
+ if (__archive_read_consume(a, linkname_length) < 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Read error skipping symlink target name");
+ return ARCHIVE_FATAL;
+ }
+ } else if (0 == (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
+ || zip_entry->uncompressed_size > 0) {
+ /* Set the size only if it's meaningful. */
+ 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)
+ if (0 == (zip_entry->zip_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)",
+ archive_string_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;
+ a->archive.archive_format_name = zip->format_name.s;
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 (0 <= compression && compression <
- (int)(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)
+check_authentication_code(struct archive_read *a, const void *_p)
{
- 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);
- }
-
- zip_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,
- (unsigned)*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 authentication code. */
+ if (zip->hctx_valid) {
+ const void *p;
+ uint8_t hmac[20];
+ size_t hmac_len = 20;
+ int cmp;
+
+ archive_hmac_sha1_final(&zip->hctx, hmac, &hmac_len);
+ if (_p == NULL) {
+ /* Read authentication code. */
+ p = __archive_read_ahead(a, AUTH_CODE_SIZE, NULL);
+ if (p == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+ }
+ } else {
+ p = _p;
}
- /* 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);
+ cmp = memcmp(hmac, p, AUTH_CODE_SIZE);
+ __archive_read_consume(a, AUTH_CODE_SIZE);
+ if (cmp != 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "ZIP bad Authentication code");
return (ARCHIVE_WARN);
}
}
-
return (ARCHIVE_OK);
}
@@ -1276,9 +1117,10 @@ archive_read_format_zip_read_data(struct archive_read *a,
* 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.
+ * newer writers seem to provide the signature pretty consistently.
+ *
+ * For uncompressed data, the PK\007\010 marker seems essential
+ * to be sure we've actually seen the end of the entry.
*
* Returns ARCHIVE_OK if successful, ARCHIVE_FATAL otherwise, sets
* zip->end_of_entry if it consumes all of the data.
@@ -1290,40 +1132,69 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
struct zip *zip;
const char *buff;
ssize_t bytes_avail;
+ int r;
(void)offset; /* UNUSED */
zip = (struct zip *)(a->format->data);
- if (zip->entry->flags & ZIP_LENGTH_AT_END) {
+ if (zip->entry->zip_flags & ZIP_LENGTH_AT_END) {
const char *p;
+ ssize_t grabbing_bytes = 24;
- /* Grab at least 16 bytes. */
- buff = __archive_read_ahead(a, 16, &bytes_avail);
- if (bytes_avail < 16) {
+ if (zip->hctx_valid)
+ grabbing_bytes += AUTH_CODE_SIZE;
+ /* Grab at least 24 bytes. */
+ buff = __archive_read_ahead(a, grabbing_bytes, &bytes_avail);
+ if (bytes_avail < grabbing_bytes) {
/* 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
+ least 24 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. */
+ /* Check for a complete PK\007\010 signature, followed
+ * by the correct 4-byte CRC. */
p = buff;
- if (p[0] == 'P' && p[1] == 'K'
+ if (zip->hctx_valid)
+ p += AUTH_CODE_SIZE;
+ 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);
+ && (archive_le32dec(p + 4) == zip->entry_crc32
+ || zip->ignore_crc32
+ || (zip->hctx_valid
+ && zip->entry->aes_extra.vendor == AES_VENDOR_AE_2))) {
+ if (zip->entry->flags & LA_USED_ZIP64) {
+ uint64_t compressed, uncompressed;
+ zip->entry->crc32 = archive_le32dec(p + 4);
+ compressed = archive_le64dec(p + 8);
+ uncompressed = archive_le64dec(p + 16);
+ if (compressed > INT64_MAX || uncompressed > INT64_MAX) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Overflow of 64-bit file sizes");
+ return ARCHIVE_FAILED;
+ }
+ zip->entry->compressed_size = compressed;
+ zip->entry->uncompressed_size = uncompressed;
+ zip->unconsumed = 24;
+ } else {
+ 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;
+ }
+ if (zip->hctx_valid) {
+ r = check_authentication_code(a, buff);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
zip->end_of_entry = 1;
- zip->unconsumed = 16;
return (ARCHIVE_OK);
}
/* If not at EOF, ensure we consume at least one byte. */
@@ -1339,6 +1210,8 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
else if (p[3] == '\007') { p += 1; }
else if (p[3] == '\010' && p[2] == '\007'
&& p[1] == 'K' && p[0] == 'P') {
+ if (zip->hctx_valid)
+ p -= AUTH_CODE_SIZE;
break;
} else { p += 4; }
}
@@ -1346,6 +1219,11 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
} else {
if (zip->entry_bytes_remaining == 0) {
zip->end_of_entry = 1;
+ if (zip->hctx_valid) {
+ r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
return (ARCHIVE_OK);
}
/* Grab a bunch of bytes. */
@@ -1359,6 +1237,26 @@ zip_read_data_none(struct archive_read *a, const void **_buff,
if (bytes_avail > zip->entry_bytes_remaining)
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
+ if (zip->tctx_valid || zip->cctx_valid) {
+ size_t dec_size = bytes_avail;
+
+ if (dec_size > zip->decrypted_buffer_size)
+ dec_size = zip->decrypted_buffer_size;
+ if (zip->tctx_valid) {
+ trad_enc_decrypt_update(&zip->tctx,
+ (const uint8_t *)buff, dec_size,
+ zip->decrypted_buffer, dec_size);
+ } else {
+ size_t dsize = dec_size;
+ archive_hmac_sha1_update(&zip->hctx,
+ (const uint8_t *)buff, dec_size);
+ archive_decrypto_aes_ctr_update(&zip->cctx,
+ (const uint8_t *)buff, dec_size,
+ zip->decrypted_buffer, &dsize);
+ }
+ bytes_avail = dec_size;
+ buff = (const char *)zip->decrypted_buffer;
+ }
*size = bytes_avail;
zip->entry_bytes_remaining -= bytes_avail;
zip->entry_uncompressed_bytes_read += bytes_avail;
@@ -1400,7 +1298,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
{
struct zip *zip;
ssize_t bytes_avail;
- const void *compressed_buff;
+ const void *compressed_buff, *sp;
int r;
(void)offset; /* UNUSED */
@@ -1429,17 +1327,63 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
* 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)
+ compressed_buff = sp = __archive_read_ahead(a, 1, &bytes_avail);
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
&& bytes_avail > zip->entry_bytes_remaining) {
bytes_avail = (ssize_t)zip->entry_bytes_remaining;
}
- if (bytes_avail <= 0) {
+ if (bytes_avail < 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
}
+ if (zip->tctx_valid || zip->cctx_valid) {
+ if (zip->decrypted_bytes_remaining < (size_t)bytes_avail) {
+ size_t buff_remaining =
+ (zip->decrypted_buffer + zip->decrypted_buffer_size)
+ - (zip->decrypted_ptr + zip->decrypted_bytes_remaining);
+
+ if (buff_remaining > (size_t)bytes_avail)
+ buff_remaining = (size_t)bytes_avail;
+
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END) &&
+ zip->entry_bytes_remaining > 0) {
+ if ((int64_t)(zip->decrypted_bytes_remaining
+ + buff_remaining)
+ > zip->entry_bytes_remaining) {
+ if (zip->entry_bytes_remaining <
+ (int64_t)zip->decrypted_bytes_remaining)
+ buff_remaining = 0;
+ else
+ buff_remaining =
+ (size_t)zip->entry_bytes_remaining
+ - zip->decrypted_bytes_remaining;
+ }
+ }
+ if (buff_remaining > 0) {
+ if (zip->tctx_valid) {
+ trad_enc_decrypt_update(&zip->tctx,
+ compressed_buff, buff_remaining,
+ zip->decrypted_ptr
+ + zip->decrypted_bytes_remaining,
+ buff_remaining);
+ } else {
+ size_t dsize = buff_remaining;
+ archive_decrypto_aes_ctr_update(
+ &zip->cctx,
+ compressed_buff, buff_remaining,
+ zip->decrypted_ptr
+ + zip->decrypted_bytes_remaining,
+ &dsize);
+ }
+ zip->decrypted_bytes_remaining += buff_remaining;
+ }
+ }
+ bytes_avail = zip->decrypted_bytes_remaining;
+ compressed_buff = (const char *)zip->decrypted_ptr;
+ }
+
/*
* A bug in zlib.h: stream.next_in should be marked 'const'
* but isn't (the library never alters data through the
@@ -1472,7 +1416,17 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
/* Consume as much as the compressor actually used. */
bytes_avail = zip->stream.total_in;
- zip_read_consume(a, bytes_avail);
+ if (zip->tctx_valid || zip->cctx_valid) {
+ zip->decrypted_bytes_remaining -= bytes_avail;
+ if (zip->decrypted_bytes_remaining == 0)
+ zip->decrypted_ptr = zip->decrypted_buffer;
+ else
+ zip->decrypted_ptr += bytes_avail;
+ }
+ /* Calculate compressed data as much as we used.*/
+ if (zip->hctx_valid)
+ archive_hmac_sha1_update(&zip->hctx, sp, bytes_avail);
+ __archive_read_consume(a, bytes_avail);
zip->entry_bytes_remaining -= bytes_avail;
zip->entry_compressed_bytes_read += bytes_avail;
@@ -1480,10 +1434,16 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
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)) {
+ if (zip->end_of_entry && zip->hctx_valid) {
+ r = check_authentication_code(a, NULL);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ if (zip->end_of_entry && (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
const char *p;
- if (NULL == (p = __archive_read_ahead(a, 16, NULL))) {
+ if (NULL == (p = __archive_read_ahead(a, 24, NULL))) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP end-of-file record");
@@ -1492,10 +1452,28 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
/* 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;
+ p += 4;
+ zip->unconsumed = 4;
+ }
+ if (zip->entry->flags & LA_USED_ZIP64) {
+ uint64_t compressed, uncompressed;
+ zip->entry->crc32 = archive_le32dec(p);
+ compressed = archive_le64dec(p + 4);
+ uncompressed = archive_le64dec(p + 12);
+ if (compressed > INT64_MAX || uncompressed > INT64_MAX) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Overflow of 64-bit file sizes");
+ return ARCHIVE_FAILED;
+ }
+ zip->entry->compressed_size = compressed;
+ zip->entry->uncompressed_size = uncompressed;
+ zip->unconsumed += 20;
+ } else {
+ zip->entry->crc32 = archive_le32dec(p);
+ zip->entry->compressed_size = archive_le32dec(p + 4);
+ zip->entry->uncompressed_size = archive_le32dec(p + 8);
+ zip->unconsumed += 12;
}
}
@@ -1504,27 +1482,780 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
#endif
static int
-archive_read_format_zip_read_data_skip(struct archive_read *a)
+read_decryption_header(struct archive_read *a)
+{
+ struct zip *zip = (struct zip *)(a->format->data);
+ const char *p;
+ unsigned int remaining_size;
+ unsigned int ts;
+
+ /*
+ * Read an initialization vector data field.
+ */
+ p = __archive_read_ahead(a, 2, NULL);
+ if (p == NULL)
+ goto truncated;
+ ts = zip->iv_size;
+ zip->iv_size = archive_le16dec(p);
+ __archive_read_consume(a, 2);
+ if (ts < zip->iv_size) {
+ free(zip->iv);
+ zip->iv = NULL;
+ }
+ p = __archive_read_ahead(a, zip->iv_size, NULL);
+ if (p == NULL)
+ goto truncated;
+ if (zip->iv == NULL) {
+ zip->iv = malloc(zip->iv_size);
+ if (zip->iv == NULL)
+ goto nomem;
+ }
+ memcpy(zip->iv, p, zip->iv_size);
+ __archive_read_consume(a, zip->iv_size);
+
+ /*
+ * Read a size of remaining decryption header field.
+ */
+ p = __archive_read_ahead(a, 14, NULL);
+ if (p == NULL)
+ goto truncated;
+ remaining_size = archive_le32dec(p);
+ if (remaining_size < 16 || remaining_size > (1 << 18))
+ goto corrupted;
+
+ /* Check if format version is supported. */
+ if (archive_le16dec(p+4) != 3) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported encryption format version: %u",
+ archive_le16dec(p+4));
+ return (ARCHIVE_FAILED);
+ }
+
+ /*
+ * Read an encryption algorithm field.
+ */
+ zip->alg_id = archive_le16dec(p+6);
+ switch (zip->alg_id) {
+ case 0x6601:/* DES */
+ case 0x6602:/* RC2 */
+ case 0x6603:/* 3DES 168 */
+ case 0x6609:/* 3DES 112 */
+ case 0x660E:/* AES 128 */
+ case 0x660F:/* AES 192 */
+ case 0x6610:/* AES 256 */
+ case 0x6702:/* RC2 (version >= 5.2) */
+ case 0x6720:/* Blowfish */
+ case 0x6721:/* Twofish */
+ case 0x6801:/* RC4 */
+ /* Supported encryption algorithm. */
+ break;
+ default:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown encryption algorithm: %u", zip->alg_id);
+ return (ARCHIVE_FAILED);
+ }
+
+ /*
+ * Read a bit length field.
+ */
+ zip->bit_len = archive_le16dec(p+8);
+
+ /*
+ * Read a flags field.
+ */
+ zip->flags = archive_le16dec(p+10);
+ switch (zip->flags & 0xf000) {
+ case 0x0001: /* Password is required to decrypt. */
+ case 0x0002: /* Certificates only. */
+ case 0x0003: /* Password or certificate required to decrypt. */
+ break;
+ default:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown encryption flag: %u", zip->flags);
+ return (ARCHIVE_FAILED);
+ }
+ if ((zip->flags & 0xf000) == 0 ||
+ (zip->flags & 0xf000) == 0x4000) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unknown encryption flag: %u", zip->flags);
+ return (ARCHIVE_FAILED);
+ }
+
+ /*
+ * Read an encrypted random data field.
+ */
+ ts = zip->erd_size;
+ zip->erd_size = archive_le16dec(p+12);
+ __archive_read_consume(a, 14);
+ if ((zip->erd_size & 0xf) != 0 ||
+ (zip->erd_size + 16) > remaining_size ||
+ (zip->erd_size + 16) < zip->erd_size)
+ goto corrupted;
+
+ if (ts < zip->erd_size) {
+ free(zip->erd);
+ zip->erd = NULL;
+ }
+ p = __archive_read_ahead(a, zip->erd_size, NULL);
+ if (p == NULL)
+ goto truncated;
+ if (zip->erd == NULL) {
+ zip->erd = malloc(zip->erd_size);
+ if (zip->erd == NULL)
+ goto nomem;
+ }
+ memcpy(zip->erd, p, zip->erd_size);
+ __archive_read_consume(a, zip->erd_size);
+
+ /*
+ * Read a reserved data field.
+ */
+ p = __archive_read_ahead(a, 4, NULL);
+ if (p == NULL)
+ goto truncated;
+ /* Reserved data size should be zero. */
+ if (archive_le32dec(p) != 0)
+ goto corrupted;
+ __archive_read_consume(a, 4);
+
+ /*
+ * Read a password validation data field.
+ */
+ p = __archive_read_ahead(a, 2, NULL);
+ if (p == NULL)
+ goto truncated;
+ ts = zip->v_size;
+ zip->v_size = archive_le16dec(p);
+ __archive_read_consume(a, 2);
+ if ((zip->v_size & 0x0f) != 0 ||
+ (zip->erd_size + zip->v_size + 16) > remaining_size ||
+ (zip->erd_size + zip->v_size + 16) < (zip->erd_size + zip->v_size))
+ goto corrupted;
+ if (ts < zip->v_size) {
+ free(zip->v_data);
+ zip->v_data = NULL;
+ }
+ p = __archive_read_ahead(a, zip->v_size, NULL);
+ if (p == NULL)
+ goto truncated;
+ if (zip->v_data == NULL) {
+ zip->v_data = malloc(zip->v_size);
+ if (zip->v_data == NULL)
+ goto nomem;
+ }
+ memcpy(zip->v_data, p, zip->v_size);
+ __archive_read_consume(a, zip->v_size);
+
+ p = __archive_read_ahead(a, 4, NULL);
+ if (p == NULL)
+ goto truncated;
+ zip->v_crc32 = archive_le32dec(p);
+ __archive_read_consume(a, 4);
+
+ /*return (ARCHIVE_OK);
+ * This is not fully implemented yet.*/
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Encrypted file is unsupported");
+ return (ARCHIVE_FAILED);
+truncated:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+corrupted:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Corrupted ZIP file data");
+ return (ARCHIVE_FATAL);
+nomem:
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for ZIP decryption");
+ return (ARCHIVE_FATAL);
+}
+
+static int
+zip_alloc_decryption_buffer(struct archive_read *a)
+{
+ struct zip *zip = (struct zip *)(a->format->data);
+ size_t bs = 256 * 1024;
+
+ if (zip->decrypted_buffer == NULL) {
+ zip->decrypted_buffer_size = bs;
+ zip->decrypted_buffer = malloc(bs);
+ if (zip->decrypted_buffer == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "No memory for ZIP decryption");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ zip->decrypted_ptr = zip->decrypted_buffer;
+ return (ARCHIVE_OK);
+}
+
+static int
+init_traditional_PKWARE_decryption(struct archive_read *a)
+{
+ struct zip *zip = (struct zip *)(a->format->data);
+ const void *p;
+ int retry;
+ int r;
+
+ if (zip->tctx_valid)
+ return (ARCHIVE_OK);
+
+ /*
+ Read the 12 bytes encryption header stored at
+ the start of the data area.
+ */
+#define ENC_HEADER_SIZE 12
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ && zip->entry_bytes_remaining < ENC_HEADER_SIZE) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated Zip encrypted body: only %jd bytes available",
+ (intmax_t)zip->entry_bytes_remaining);
+ return (ARCHIVE_FATAL);
+ }
+
+ p = __archive_read_ahead(a, ENC_HEADER_SIZE, NULL);
+ if (p == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+ }
+
+ for (retry = 0;; retry++) {
+ const char *passphrase;
+ uint8_t crcchk;
+
+ passphrase = __archive_read_next_passphrase(a);
+ if (passphrase == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ (retry > 0)?
+ "Incorrect passphrase":
+ "Passphrase required for this entry");
+ return (ARCHIVE_FAILED);
+ }
+
+ /*
+ * Initialize ctx for Traditional PKWARE Decryption.
+ */
+ r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase),
+ p, ENC_HEADER_SIZE, &crcchk);
+ if (r == 0 && crcchk == zip->entry->decdat)
+ break;/* The passphrase is OK. */
+ if (retry > 10000) {
+ /* Avoid infinity loop. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Too many incorrect passphrases");
+ return (ARCHIVE_FAILED);
+ }
+ }
+
+ __archive_read_consume(a, ENC_HEADER_SIZE);
+ zip->tctx_valid = 1;
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)) {
+ zip->entry_bytes_remaining -= ENC_HEADER_SIZE;
+ }
+ /*zip->entry_uncompressed_bytes_read += ENC_HEADER_SIZE;*/
+ zip->entry_compressed_bytes_read += ENC_HEADER_SIZE;
+ zip->decrypted_bytes_remaining = 0;
+
+ return (zip_alloc_decryption_buffer(a));
+#undef ENC_HEADER_SIZE
+}
+
+static int
+init_WinZip_AES_decryption(struct archive_read *a)
+{
+ struct zip *zip = (struct zip *)(a->format->data);
+ const void *p;
+ const uint8_t *pv;
+ size_t key_len, salt_len;
+ uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];
+ int retry;
+ int r;
+
+ if (zip->cctx_valid || zip->hctx_valid)
+ return (ARCHIVE_OK);
+
+ switch (zip->entry->aes_extra.strength) {
+ case 1: salt_len = 8; key_len = 16; break;
+ case 2: salt_len = 12; key_len = 24; break;
+ case 3: salt_len = 16; key_len = 32; break;
+ default: goto corrupted;
+ }
+ p = __archive_read_ahead(a, salt_len + 2, NULL);
+ if (p == NULL)
+ goto truncated;
+
+ for (retry = 0;; retry++) {
+ const char *passphrase;
+
+ passphrase = __archive_read_next_passphrase(a);
+ if (passphrase == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ (retry > 0)?
+ "Incorrect passphrase":
+ "Passphrase required for this entry");
+ return (ARCHIVE_FAILED);
+ }
+ memset(derived_key, 0, sizeof(derived_key));
+ r = archive_pbkdf2_sha1(passphrase, strlen(passphrase),
+ p, salt_len, 1000, derived_key, key_len * 2 + 2);
+ if (r != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Decryption is unsupported due to lack of "
+ "crypto library");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Check password verification value. */
+ pv = ((const uint8_t *)p) + salt_len;
+ if (derived_key[key_len * 2] == pv[0] &&
+ derived_key[key_len * 2 + 1] == pv[1])
+ break;/* The passphrase is OK. */
+ if (retry > 10000) {
+ /* Avoid infinity loop. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Too many incorrect passphrases");
+ return (ARCHIVE_FAILED);
+ }
+ }
+
+ r = archive_decrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);
+ if (r != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Decryption is unsupported due to lack of crypto library");
+ return (ARCHIVE_FAILED);
+ }
+ r = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len, key_len);
+ if (r != 0) {
+ archive_decrypto_aes_ctr_release(&zip->cctx);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to initialize HMAC-SHA1");
+ return (ARCHIVE_FAILED);
+ }
+ zip->cctx_valid = zip->hctx_valid = 1;
+ __archive_read_consume(a, salt_len + 2);
+ zip->entry_bytes_remaining -= salt_len + 2 + AUTH_CODE_SIZE;
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ && zip->entry_bytes_remaining < 0)
+ goto corrupted;
+ zip->entry_compressed_bytes_read += salt_len + 2 + AUTH_CODE_SIZE;
+ zip->decrypted_bytes_remaining = 0;
+
+ zip->entry->compression = zip->entry->aes_extra.compression;
+ return (zip_alloc_decryption_buffer(a));
+
+truncated:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file data");
+ return (ARCHIVE_FATAL);
+corrupted:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Corrupted ZIP file data");
+ return (ARCHIVE_FATAL);
+}
+
+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);
+
+ if (zip->has_encrypted_entries ==
+ ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW) {
+ zip->has_encrypted_entries = 0;
+ }
+
+ *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);
+
+ __archive_read_consume(a, zip->unconsumed);
+ zip->unconsumed = 0;
+
+ if (zip->init_decryption) {
+ zip->has_encrypted_entries = 1;
+ if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)
+ r = read_decryption_header(a);
+ else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)
+ r = init_WinZip_AES_decryption(a);
+ else
+ r = init_traditional_PKWARE_decryption(a);
+ if (r != ARCHIVE_OK)
+ return (r);
+ zip->init_decryption = 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 = zip->crc32func(zip->entry_crc32, *buff,
+ (unsigned)*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)\n",
+ (intmax_t)zip->entry_uncompressed_bytes_read,
+ (intmax_t)zip->entry->uncompressed_size);
+ return (ARCHIVE_WARN);
+ }
+ /* Check computed CRC against header */
+ if ((!zip->hctx_valid ||
+ zip->entry->aes_extra.vendor != AES_VENDOR_AE_2) &&
+ zip->entry->crc32 != zip->entry_crc32
+ && !zip->ignore_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);
+}
+
+static int
+archive_read_format_zip_cleanup(struct archive_read *a)
+{
+ struct zip *zip;
+ struct zip_entry *zip_entry, *next_zip_entry;
+
+ zip = (struct zip *)(a->format->data);
+#ifdef HAVE_ZLIB_H
+ if (zip->stream_valid)
+ inflateEnd(&zip->stream);
+ free(zip->uncompressed_buffer);
+#endif
+ if (zip->zip_entries) {
+ zip_entry = zip->zip_entries;
+ while (zip_entry != NULL) {
+ next_zip_entry = zip_entry->next;
+ archive_string_free(&zip_entry->rsrcname);
+ free(zip_entry);
+ zip_entry = next_zip_entry;
+ }
+ }
+ free(zip->decrypted_buffer);
+ if (zip->cctx_valid)
+ archive_decrypto_aes_ctr_release(&zip->cctx);
+ if (zip->hctx_valid)
+ archive_hmac_sha1_cleanup(&zip->hctx);
+ free(zip->iv);
+ free(zip->erd);
+ free(zip->v_data);
+ archive_string_free(&zip->format_name);
+ free(zip);
+ (a->format->data) = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_read_format_zip_has_encrypted_entries(struct archive_read *_a)
+{
+ if (_a && _a->format) {
+ struct zip * zip = (struct zip *)_a->format->data;
+ if (zip) {
+ return zip->has_encrypted_entries;
+ }
+ }
+ return ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+}
+
+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 filenames as libarchive 2.x */
+ zip->init_default_conversion = (val != NULL) ? 1 : 0;
+ return (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;
+ }
+ return (ret);
+ } else if (strcmp(key, "ignorecrc32") == 0) {
+ /* Mostly useful for testing. */
+ if (val == NULL || val[0] == 0) {
+ zip->crc32func = real_crc32;
+ zip->ignore_crc32 = 0;
+ } else {
+ zip->crc32func = fake_crc32;
+ zip->ignore_crc32 = 1;
+ }
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "mac-ext") == 0) {
+ zip->process_mac_extensions = (val != NULL && val[0] != 0);
+ 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);
+}
+
+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));
+}
+
+/* ------------------------------------------------------------------------ */
+
+/*
+ * Streaming-mode support
+ */
+
+
+static int
+archive_read_support_format_zip_capabilities_streamable(struct archive_read * a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
+ ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+}
+
+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 29 here comes from:
+ * + 16 bits for "PK",
+ * + next 16-bit field has 6 options so contributes
+ * about 16 - log_2(6) ~= 16 - 2.6 ~= 13 bits
+ *
+ * So we've effectively verified ~29 total bits of check data.
+ */
+ 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] == '\006' && p[3] == '\006')
+ || (p[2] == '\007' && p[3] == '\010')
+ || (p[2] == '0' && p[3] == '0'))
+ return (29);
+ }
+
+ /* TODO: It's worth looking ahead a little bit for a valid
+ * PK signature. In particular, that would make it possible
+ * to read some UUEncoded SFX files or SFX files coming from
+ * a network socket. */
+
+ return (0);
+}
+
+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);
+ /*
+ * It should be sufficient to call archive_read_next_header() for
+ * a reader to determine if an entry is encrypted or not. If the
+ * encryption of an entry is only detectable when calling
+ * archive_read_data(), so be it. We'll do the same check there
+ * as well.
+ */
+ if (zip->has_encrypted_entries ==
+ ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)
+ zip->has_encrypted_entries = 0;
+
+ /* 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));
+
+ if (zip->cctx_valid)
+ archive_decrypto_aes_ctr_release(&zip->cctx);
+ if (zip->hctx_valid)
+ archive_hmac_sha1_cleanup(&zip->hctx);
+ zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;
+ __archive_read_reset_passphrase(a);
+
+ /* 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] == '\003' && p[3] == '\004') {
+ /* Regular file entry. */
+ __archive_read_consume(a, skipped);
+ return zip_read_local_file_header(a,
+ entry, zip);
+ }
+
+ /*
+ * TODO: We cannot restore permissions
+ * based only on the local file headers.
+ * Consider scanning the central
+ * directory and returning additional
+ * entries for at least directories.
+ * This would allow us to properly set
+ * directory permissions.
+ *
+ * This won't help us fix symlinks
+ * and may not help with regular file
+ * permissions, either. <sigh>
+ */
+ if (p[2] == '\001' && p[3] == '\002') {
+ return (ARCHIVE_EOF);
+ }
+
+ /* End of central directory? Must be an
+ * empty archive. */
+ if ((p[2] == '\005' && p[3] == '\006')
+ || (p[2] == '\006' && p[3] == '\006'))
+ return (ARCHIVE_EOF);
+ }
+ ++p;
+ ++skipped;
+ }
+ __archive_read_consume(a, skipped);
+ }
+}
+
+static int
+archive_read_format_zip_read_data_skip_streamable(struct archive_read *a)
+{
+ struct zip *zip;
+ int64_t bytes_skipped;
+
+ zip = (struct zip *)(a->format->data);
+ bytes_skipped = __archive_read_consume(a, zip->unconsumed);
+ zip->unconsumed = 0;
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+
/* If we've already read to end of data, we're done. */
if (zip->end_of_entry)
return (ARCHIVE_OK);
/* So we know we're streaming... */
- if (0 == (zip->entry->flags & ZIP_LENGTH_AT_END)) {
+ if (0 == (zip->entry->zip_flags & ZIP_LENGTH_AT_END)
+ || zip->entry->compressed_size > 0) {
/* We know the compressed length, so we can just skip. */
- int64_t bytes_skipped = zip_read_consume(a,
- zip->entry_bytes_remaining + zip->unconsumed);
+ bytes_skipped = __archive_read_consume(a,
+ zip->entry_bytes_remaining);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
- zip->unconsumed = 0;
return (ARCHIVE_OK);
}
+ if (zip->init_decryption) {
+ int r;
+
+ zip->has_encrypted_entries = 1;
+ if (zip->entry->zip_flags & ZIP_STRONG_ENCRYPTED)
+ r = read_decryption_header(a);
+ else if (zip->entry->compression == WINZIP_AES_ENCRYPTION)
+ r = init_WinZip_AES_decryption(a);
+ else
+ r = init_traditional_PKWARE_decryption(a);
+ if (r != ARCHIVE_OK)
+ return (r);
+ zip->init_decryption = 0;
+ }
+
/* 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. */
@@ -1544,8 +2275,6 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
#endif
default: /* Uncompressed or unknown. */
/* Scan for a PK\007\010 signature. */
- zip_read_consume(a, zip->unconsumed);
- zip->unconsumed = 0;
for (;;) {
const char *p, *buff;
ssize_t bytes_avail;
@@ -1563,180 +2292,821 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
else if (p[3] == '\007') { p += 1; }
else if (p[3] == '\010' && p[2] == '\007'
&& p[1] == 'K' && p[0] == 'P') {
- zip_read_consume(a, p - buff + 16);
+ if (zip->entry->flags & LA_USED_ZIP64)
+ __archive_read_consume(a,
+ p - buff + 24);
+ else
+ __archive_read_consume(a,
+ p - buff + 16);
return ARCHIVE_OK;
} else { p += 4; }
}
- zip_read_consume(a, p - buff);
+ __archive_read_consume(a, p - buff);
}
}
}
-static int
-archive_read_format_zip_cleanup(struct archive_read *a)
+int
+archive_read_support_format_zip_streamable(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct zip *zip;
+ int r;
- zip = (struct zip *)(a->format->data);
-#ifdef HAVE_ZLIB_H
- if (zip->stream_valid)
- inflateEnd(&zip->stream);
-#endif
- if (zip->zip_entries && zip->central_directory_entries) {
- unsigned i;
- for (i = 0; i < zip->central_directory_entries; i++)
- archive_string_free(&(zip->zip_entries[i].rsrcname));
+ archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_read_support_format_zip");
+
+ zip = (struct zip *)calloc(1, sizeof(*zip));
+ if (zip == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate zip data");
+ return (ARCHIVE_FATAL);
}
- free(zip->zip_entries);
- free(zip->uncompressed_buffer);
- archive_string_free(&(zip->extra));
- free(zip);
- (a->format->data) = NULL;
+
+ /* Streamable reader doesn't support mac extensions. */
+ zip->process_mac_extensions = 0;
+
+ /*
+ * Until enough data has been read, we cannot tell about
+ * any encrypted entries yet.
+ */
+ zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+ zip->crc32func = real_crc32;
+
+ 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_streamable,
+ NULL,
+ archive_read_format_zip_cleanup,
+ archive_read_support_format_zip_capabilities_streamable,
+ archive_read_format_zip_has_encrypted_entries);
+
+ if (r != ARCHIVE_OK)
+ free(zip);
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.
+ * Seeking-mode support
+ */
+
+static int
+archive_read_support_format_zip_capabilities_seekable(struct archive_read * a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_DATA |
+ ARCHIVE_READ_FORMAT_CAPS_ENCRYPT_METADATA);
+}
+
+/*
+ * 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.
+ *
+ * We workaround this a little by passing in the best bid so far so
+ * that later bidders can do nothing if they know they'll never
+ * outbid. But we can certainly do better...
+ */
+static int
+read_eocd(struct zip *zip, const char *p, int64_t current_offset)
+{
+ /* Sanity-check the EOCD we've found. */
+
+ /* This must be the first volume. */
+ if (archive_le16dec(p + 4) != 0)
+ return 0;
+ /* Central directory must be on this volume. */
+ if (archive_le16dec(p + 4) != archive_le16dec(p + 6))
+ return 0;
+ /* All central directory entries must be on this volume. */
+ if (archive_le16dec(p + 10) != archive_le16dec(p + 8))
+ return 0;
+ /* Central directory can't extend beyond start of EOCD record. */
+ if (archive_le32dec(p + 16) + archive_le32dec(p + 12)
+ > current_offset)
+ return 0;
+
+ /* Save the central directory location for later use. */
+ zip->central_directory_offset = archive_le32dec(p + 16);
+
+ /* 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;
+}
+
+/*
+ * Examine Zip64 EOCD locator: If it's valid, store the information
+ * from it.
*/
static void
-process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry)
+read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
{
- unsigned offset = 0;
+ int64_t eocd64_offset;
+ int64_t eocd64_size;
+
+ /* Sanity-check the locator record. */
+
+ /* Central dir must be on first volume. */
+ if (archive_le32dec(p + 4) != 0)
+ return;
+ /* Must be only a single volume. */
+ if (archive_le32dec(p + 16) != 1)
+ return;
+
+ /* Find the Zip64 EOCD record. */
+ eocd64_offset = archive_le64dec(p + 8);
+ if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0)
+ return;
+ if ((p = __archive_read_ahead(a, 56, NULL)) == NULL)
+ return;
+ /* Make sure we can read all of it. */
+ eocd64_size = archive_le64dec(p + 4) + 12;
+ if (eocd64_size < 56 || eocd64_size > 16384)
+ return;
+ if ((p = __archive_read_ahead(a, (size_t)eocd64_size, NULL)) == NULL)
+ return;
+
+ /* Sanity-check the EOCD64 */
+ if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */
+ return;
+ if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */
+ return;
+ /* CD can't be split. */
+ if (archive_le64dec(p + 24) != archive_le64dec(p + 32))
+ return;
+
+ /* Save the central directory offset for later use. */
+ zip->central_directory_offset = archive_le64dec(p + 48);
+}
- 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)
+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 file_size, current_offset;
+ const char *p;
+ int i, tail;
+
+ /* If someone has already bid more than 32, then avoid
+ trashing the look-ahead buffers with a seek. */
+ if (best_bid > 32)
+ return (-1);
+
+ file_size = __archive_read_seek(a, 0, SEEK_END);
+ if (file_size <= 0)
+ return 0;
+
+ /* Search last 16k of file for end-of-central-directory
+ * record (which starts with PK\005\006) */
+ tail = (int)zipmin(1024 * 16, file_size);
+ current_offset = __archive_read_seek(a, -tail, SEEK_END);
+ if (current_offset < 0)
+ return 0;
+ if ((p = __archive_read_ahead(a, (size_t)tail, NULL)) == NULL)
+ return 0;
+ /* Boyer-Moore search backwards from the end, since we want
+ * to match the last EOCD in the file (there can be more than
+ * one if there is an uncompressed Zip archive as a member
+ * within this Zip archive). */
+ for (i = tail - 22; i > 0;) {
+ switch (p[i]) {
+ case 'P':
+ if (memcmp(p + i, "PK\005\006", 4) == 0) {
+ int ret = read_eocd(zip, p + i,
+ current_offset + i);
+ if (ret > 0) {
+ /* Zip64 EOCD locator precedes
+ * regular EOCD if present. */
+ if (i >= 20
+ && memcmp(p + i - 20, "PK\006\007", 4) == 0) {
+ read_zip64_eocd(a, zip, p + i - 20);
+ }
+ return (ret);
+ }
+ }
+ i -= 4;
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);
+ case 'K': i -= 1; break;
+ case 005: i -= 2; break;
+ case 006: i -= 3; break;
+ default: i -= 4; break;
+ }
+ }
+ return 0;
+}
+
+/* The red-black trees are only used in seeking mode to manage
+ * the in-memory copy of the central directory. */
+
+static int
+cmp_node(const struct archive_rb_node *n1, const struct archive_rb_node *n2)
+{
+ const struct zip_entry *e1 = (const struct zip_entry *)n1;
+ const struct zip_entry *e2 = (const struct zip_entry *)n2;
+
+ if (e1->local_header_offset > e2->local_header_offset)
+ return -1;
+ if (e1->local_header_offset < e2->local_header_offset)
+ return 1;
+ return 0;
+}
+
+static int
+cmp_key(const struct archive_rb_node *n, const void *key)
+{
+ /* This function won't be called */
+ (void)n; /* UNUSED */
+ (void)key; /* UNUSED */
+ return 1;
+}
+
+static const struct archive_rb_tree_ops rb_ops = {
+ &cmp_node, &cmp_key
+};
+
+static int
+rsrc_cmp_node(const struct archive_rb_node *n1,
+ const struct archive_rb_node *n2)
+{
+ const struct zip_entry *e1 = (const struct zip_entry *)n1;
+ const struct zip_entry *e2 = (const struct zip_entry *)n2;
+
+ return (strcmp(e2->rsrcname.s, e1->rsrcname.s));
+}
+
+static int
+rsrc_cmp_key(const struct archive_rb_node *n, const void *key)
+{
+ const struct zip_entry *e = (const struct zip_entry *)n;
+ return (strcmp((const char *)key, e->rsrcname.s));
+}
+
+static const struct archive_rb_tree_ops rb_rsrc_ops = {
+ &rsrc_cmp_node, &rsrc_cmp_key
+};
+
+static const char *
+rsrc_basename(const char *name, size_t name_length)
+{
+ const char *s, *r;
+
+ r = s = name;
+ for (;;) {
+ s = memchr(s, '/', name_length - (s - name));
+ if (s == NULL)
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;
+ r = ++s;
+ }
+ return (r);
+}
+
+static void
+expose_parent_dirs(struct zip *zip, const char *name, size_t name_length)
+{
+ struct archive_string str;
+ struct zip_entry *dir;
+ char *s;
+
+ archive_string_init(&str);
+ archive_strncpy(&str, name, name_length);
+ for (;;) {
+ s = strrchr(str.s, '/');
+ if (s == NULL)
+ break;
+ *s = '\0';
+ /* Transfer the parent directory from zip->tree_rsrc RB
+ * tree to zip->tree RB tree to expose. */
+ dir = (struct zip_entry *)
+ __archive_rb_tree_find_node(&zip->tree_rsrc, str.s);
+ if (dir == NULL)
+ break;
+ __archive_rb_tree_remove_node(&zip->tree_rsrc, &dir->node);
+ archive_string_free(&dir->rsrcname);
+ __archive_rb_tree_insert_node(&zip->tree, &dir->node);
+ }
+ archive_string_free(&str);
+}
+
+static int
+slurp_central_directory(struct archive_read *a, struct zip *zip)
+{
+ ssize_t i;
+ unsigned found;
+ int64_t correction;
+ ssize_t bytes_avail;
+ const char *p;
+
+ /*
+ * Find the start of the central directory. The end-of-CD
+ * record has our starting point, but there are lots of
+ * Zip archives which have had other data prepended to the
+ * file, which makes the recorded offsets all too small.
+ * So we search forward from the specified offset until we
+ * find the real start of the central directory. Then we
+ * know the correction we need to apply to account for leading
+ * padding.
+ */
+ if (__archive_read_seek(a, zip->central_directory_offset, SEEK_SET) < 0)
+ return ARCHIVE_FATAL;
+
+ found = 0;
+ while (!found) {
+ if ((p = __archive_read_ahead(a, 20, &bytes_avail)) == NULL)
+ return ARCHIVE_FATAL;
+ for (found = 0, i = 0; !found && i < bytes_avail - 4;) {
+ switch (p[i + 3]) {
+ case 'P': i += 3; break;
+ case 'K': i += 2; break;
+ case 001: i += 1; break;
+ case 002:
+ if (memcmp(p + i, "PK\001\002", 4) == 0) {
+ p += i;
+ found = 1;
+ } else
+ i += 4;
+ break;
+ case 005: i += 1; break;
+ case 006:
+ if (memcmp(p + i, "PK\005\006", 4) == 0) {
+ p += i;
+ found = 1;
+ } else if (memcmp(p + i, "PK\006\006", 4) == 0) {
+ p += i;
+ found = 1;
+ } else
+ i += 1;
+ break;
+ default: i += 4; break;
}
+ }
+ __archive_read_consume(a, i);
+ }
+ correction = archive_filter_bytes(&a->archive, 0)
+ - zip->central_directory_offset;
+
+ __archive_rb_tree_init(&zip->tree, &rb_ops);
+ __archive_rb_tree_init(&zip->tree_rsrc, &rb_rsrc_ops);
+
+ zip->central_directory_entries_total = 0;
+ while (1) {
+ struct zip_entry *zip_entry;
+ size_t filename_length, extra_length, comment_length;
+ uint32_t external_attributes;
+ const char *name, *r;
+
+ if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
+ return ARCHIVE_FATAL;
+ if (memcmp(p, "PK\006\006", 4) == 0
+ || memcmp(p, "PK\005\006", 4) == 0) {
break;
+ } else if (memcmp(p, "PK\001\002", 4) != 0) {
+ archive_set_error(&a->archive,
+ -1, "Invalid central directory signature");
+ return ARCHIVE_FATAL;
}
- 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 ((p = __archive_read_ahead(a, 46, NULL)) == NULL)
+ return ARCHIVE_FATAL;
+
+ zip_entry = calloc(1, sizeof(struct zip_entry));
+ zip_entry->next = zip->zip_entries;
+ zip_entry->flags |= LA_FROM_CENTRAL_DIRECTORY;
+ zip->zip_entries = zip_entry;
+ zip->central_directory_entries_total++;
+
+ /* version = p[4]; */
+ zip_entry->system = p[5];
+ /* version_required = archive_le16dec(p + 6); */
+ zip_entry->zip_flags = archive_le16dec(p + 8);
+ if (zip_entry->zip_flags
+ & (ZIP_ENCRYPTED | ZIP_STRONG_ENCRYPTED)){
+ zip->has_encrypted_entries = 1;
+ }
+ zip_entry->compression = (char)archive_le16dec(p + 10);
+ zip_entry->mtime = zip_time(p + 12);
+ zip_entry->crc32 = archive_le32dec(p + 16);
+ if (zip_entry->zip_flags & ZIP_LENGTH_AT_END)
+ zip_entry->decdat = p[13];
+ else
+ zip_entry->decdat = p[19];
+ 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) + correction;
+
+ /* If we can't guess the mode, leave it zero here;
+ when we read the local file header we might get
+ more information. */
+ if (zip_entry->system == 3) {
+ zip_entry->mode = external_attributes >> 16;
+ } else if (zip_entry->system == 0) {
+ // Interpret MSDOS directory bit
+ if (0x10 == (external_attributes & 0x10)) {
+ zip_entry->mode = AE_IFDIR | 0775;
+ } else {
+ zip_entry->mode = AE_IFREG | 0664;
}
- if (datasize >= 12) {
- zip_entry->uid =
- archive_le16dec(p + offset + 8);
- zip_entry->gid =
- archive_le16dec(p + offset + 10);
+ if (0x01 == (external_attributes & 0x01)) {
+ // Read-only bit; strip write permissions
+ zip_entry->mode &= 0555;
}
- break;
+ } else {
+ zip_entry->mode = 0;
}
- 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));
+
+ /* We're done with the regular data; get the filename and
+ * extra data. */
+ __archive_read_consume(a, 46);
+ p = __archive_read_ahead(a, filename_length + extra_length,
+ NULL);
+ if (p == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return ARCHIVE_FATAL;
+ }
+ if (ARCHIVE_OK != process_extra(a, p + filename_length, extra_length, zip_entry)) {
+ return ARCHIVE_FATAL;
+ }
+
+ /*
+ * Mac resource fork files are stored under the
+ * "__MACOSX/" directory, so we should check if
+ * it is.
+ */
+ if (!zip->process_mac_extensions) {
+ /* Treat every entry as a regular entry. */
+ __archive_rb_tree_insert_node(&zip->tree,
+ &zip_entry->node);
+ } else {
+ name = p;
+ r = rsrc_basename(name, filename_length);
+ if (filename_length >= 9 &&
+ strncmp("__MACOSX/", name, 9) == 0) {
+ /* If this file is not a resource fork nor
+ * a directory. We should treat it as a non
+ * resource fork file to expose it. */
+ if (name[filename_length-1] != '/' &&
+ (r - name < 3 || r[0] != '.' || r[1] != '_')) {
+ __archive_rb_tree_insert_node(
+ &zip->tree, &zip_entry->node);
+ /* Expose its parent directories. */
+ expose_parent_dirs(zip, name,
+ filename_length);
+ } else {
+ /* This file is a resource fork file or
+ * a directory. */
+ archive_strncpy(&(zip_entry->rsrcname),
+ name, filename_length);
+ __archive_rb_tree_insert_node(
+ &zip->tree_rsrc, &zip_entry->node);
+ }
+ } else {
+ /* Generate resource fork name to find its
+ * resource file at zip->tree_rsrc. */
+ archive_strcpy(&(zip_entry->rsrcname),
+ "__MACOSX/");
+ archive_strncat(&(zip_entry->rsrcname),
+ name, r - name);
+ archive_strcat(&(zip_entry->rsrcname), "._");
+ archive_strncat(&(zip_entry->rsrcname),
+ name + (r - name),
+ filename_length - (r - name));
+ /* Register an entry to RB tree to sort it by
+ * file offset. */
+ __archive_rb_tree_insert_node(&zip->tree,
+ &zip_entry->node);
+ }
+ }
+
+ /* Skip the comment too ... */
+ __archive_read_consume(a,
+ filename_length + extra_length + comment_length);
+ }
+
+ return ARCHIVE_OK;
+}
+
+static ssize_t
+zip_get_local_file_header_size(struct archive_read *a, size_t extra)
+{
+ const char *p;
+ ssize_t filename_length, extra_length;
+
+ if ((p = __archive_read_ahead(a, extra + 30, NULL)) == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ return (ARCHIVE_WARN);
+ }
+ p += extra;
+
+ if (memcmp(p, "PK\003\004", 4) != 0) {
+ archive_set_error(&a->archive, -1, "Damaged Zip archive");
+ return ARCHIVE_WARN;
+ }
+ filename_length = archive_le16dec(p + 26);
+ extra_length = archive_le16dec(p + 28);
+
+ return (30 + filename_length + extra_length);
+}
+
+static int
+zip_read_mac_metadata(struct archive_read *a, struct archive_entry *entry,
+ struct zip_entry *rsrc)
+{
+ struct zip *zip = (struct zip *)a->format->data;
+ unsigned char *metadata, *mp;
+ int64_t offset = archive_filter_bytes(&a->archive, 0);
+ size_t remaining_bytes, metadata_bytes;
+ ssize_t hsize;
+ int ret = ARCHIVE_OK, eof;
+
+ switch(rsrc->compression) {
+ case 0: /* No compression. */
+ if (rsrc->uncompressed_size != rsrc->compressed_size) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Malformed OS X metadata entry: inconsistent size");
+ return (ARCHIVE_FATAL);
+ }
+#ifdef HAVE_ZLIB_H
+ case 8: /* Deflate compression. */
#endif
- if (datasize >= 2)
- zip_entry->uid = archive_le16dec(p + offset);
- if (datasize >= 4)
- zip_entry->gid =
- archive_le16dec(p + offset + 2);
+ break;
+ default: /* Unsupported compression. */
+ /* Return a warning. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Unsupported ZIP compression method (%s)",
+ compression_name(rsrc->compression));
+ /* We can't decompress this entry, but we will
+ * be able to skip() it and try the next entry. */
+ return (ARCHIVE_WARN);
+ }
+
+ if (rsrc->uncompressed_size > (4 * 1024 * 1024)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Mac metadata is too large: %jd > 4M bytes",
+ (intmax_t)rsrc->uncompressed_size);
+ return (ARCHIVE_WARN);
+ }
+ if (rsrc->compressed_size > (4 * 1024 * 1024)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Mac metadata is too large: %jd > 4M bytes",
+ (intmax_t)rsrc->compressed_size);
+ return (ARCHIVE_WARN);
+ }
+
+ metadata = malloc((size_t)rsrc->uncompressed_size);
+ if (metadata == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory for Mac metadata");
+ return (ARCHIVE_FATAL);
+ }
+
+ if (offset < rsrc->local_header_offset)
+ __archive_read_consume(a, rsrc->local_header_offset - offset);
+ else if (offset != rsrc->local_header_offset) {
+ __archive_read_seek(a, rsrc->local_header_offset, SEEK_SET);
+ }
+
+ hsize = zip_get_local_file_header_size(a, 0);
+ __archive_read_consume(a, hsize);
+
+ remaining_bytes = (size_t)rsrc->compressed_size;
+ metadata_bytes = (size_t)rsrc->uncompressed_size;
+ mp = metadata;
+ eof = 0;
+ while (!eof && remaining_bytes) {
+ const unsigned char *p;
+ ssize_t bytes_avail;
+ size_t bytes_used;
+
+ p = __archive_read_ahead(a, 1, &bytes_avail);
+ if (p == NULL) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "Truncated ZIP file header");
+ ret = ARCHIVE_WARN;
+ goto exit_mac_metadata;
+ }
+ if ((size_t)bytes_avail > remaining_bytes)
+ bytes_avail = remaining_bytes;
+ switch(rsrc->compression) {
+ case 0: /* No compression. */
+ if ((size_t)bytes_avail > metadata_bytes)
+ bytes_avail = metadata_bytes;
+ memcpy(mp, p, bytes_avail);
+ bytes_used = (size_t)bytes_avail;
+ metadata_bytes -= bytes_used;
+ mp += bytes_used;
+ if (metadata_bytes == 0)
+ eof = 1;
break;
- case 0x7875:
+#ifdef HAVE_ZLIB_H
+ case 8: /* Deflate compression. */
{
- /* Info-Zip Unix Extra Field (type 3) "ux". */
- int uidsize = 0, gidsize = 0;
+ int r;
- 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);
- }
+ ret = zip_deflate_init(a, zip);
+ if (ret != ARCHIVE_OK)
+ goto exit_mac_metadata;
+ zip->stream.next_in =
+ (Bytef *)(uintptr_t)(const void *)p;
+ zip->stream.avail_in = (uInt)bytes_avail;
+ zip->stream.total_in = 0;
+ zip->stream.next_out = mp;
+ zip->stream.avail_out = (uInt)metadata_bytes;
+ zip->stream.total_out = 0;
+
+ r = inflate(&zip->stream, 0);
+ switch (r) {
+ case Z_OK:
+ break;
+ case Z_STREAM_END:
+ eof = 1;
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(&a->archive, ENOMEM,
+ "Out of memory for ZIP decompression");
+ ret = ARCHIVE_FATAL;
+ goto exit_mac_metadata;
+ default:
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "ZIP decompression failed (%d)", r);
+ ret = ARCHIVE_FATAL;
+ goto exit_mac_metadata;
}
+ bytes_used = zip->stream.total_in;
+ metadata_bytes -= zip->stream.total_out;
+ mp += zip->stream.total_out;
break;
}
+#endif
default:
+ bytes_used = 0;
break;
}
- offset += datasize;
+ __archive_read_consume(a, bytes_used);
+ remaining_bytes -= bytes_used;
}
-#ifdef DEBUG
- if (offset != extra_length)
- {
- fprintf(stderr,
- "Extra data field contents do not match reported size!\n");
+ archive_entry_copy_mac_metadata(entry, metadata,
+ (size_t)rsrc->uncompressed_size - metadata_bytes);
+
+exit_mac_metadata:
+ __archive_read_seek(a, offset, SEEK_SET);
+ zip->decompress_init = 0;
+ free(metadata);
+ return (ret);
+}
+
+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;
+ struct zip_entry *rsrc;
+ int64_t offset;
+ int r, ret = ARCHIVE_OK;
+
+ /*
+ * It should be sufficient to call archive_read_next_header() for
+ * a reader to determine if an entry is encrypted or not. If the
+ * encryption of an entry is only detectable when calling
+ * archive_read_data(), so be it. We'll do the same check there
+ * as well.
+ */
+ if (zip->has_encrypted_entries ==
+ ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW)
+ zip->has_encrypted_entries = 0;
+
+ 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);
+ if (r != ARCHIVE_OK)
+ return r;
+ /* Get first entry whose local header offset is lower than
+ * other entries in the archive file. */
+ zip->entry =
+ (struct zip_entry *)ARCHIVE_RB_TREE_MIN(&zip->tree);
+ } else if (zip->entry != NULL) {
+ /* Get next entry in local header offset order. */
+ zip->entry = (struct zip_entry *)__archive_rb_tree_iterate(
+ &zip->tree, &zip->entry->node, ARCHIVE_RB_DIR_RIGHT);
}
+
+ if (zip->entry == NULL)
+ return ARCHIVE_EOF;
+
+ if (zip->entry->rsrcname.s)
+ rsrc = (struct zip_entry *)__archive_rb_tree_find_node(
+ &zip->tree_rsrc, zip->entry->rsrcname.s);
+ else
+ rsrc = NULL;
+
+ if (zip->cctx_valid)
+ archive_decrypto_aes_ctr_release(&zip->cctx);
+ if (zip->hctx_valid)
+ archive_hmac_sha1_cleanup(&zip->hctx);
+ zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;
+ __archive_read_reset_passphrase(a);
+
+ /* File entries are sorted by the header offset, we should mostly
+ * use __archive_read_consume to advance a read point to avoid redundant
+ * data reading. */
+ offset = archive_filter_bytes(&a->archive, 0);
+ if (offset < zip->entry->local_header_offset)
+ __archive_read_consume(a,
+ zip->entry->local_header_offset - offset);
+ else if (offset != zip->entry->local_header_offset) {
+ __archive_read_seek(a, zip->entry->local_header_offset,
+ SEEK_SET);
+ }
+ zip->unconsumed = 0;
+ r = zip_read_local_file_header(a, entry, zip);
+ if (r != ARCHIVE_OK)
+ return r;
+ if (rsrc) {
+ int ret2 = zip_read_mac_metadata(a, entry, rsrc);
+ if (ret2 < ret)
+ ret = ret2;
+ }
+ return (ret);
+}
+
+/*
+ * We're going to seek for the next header anyway, so we don't
+ * need to bother doing anything here.
+ */
+static int
+archive_read_format_zip_read_data_skip_seekable(struct archive_read *a)
+{
+ struct zip *zip;
+ zip = (struct zip *)(a->format->data);
+
+ zip->unconsumed = 0;
+ 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 *)calloc(1, sizeof(*zip));
+ if (zip == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate zip data");
+ return (ARCHIVE_FATAL);
+ }
+
+#ifdef HAVE_COPYFILE_H
+ /* Set this by default on Mac OS. */
+ zip->process_mac_extensions = 1;
#endif
+
+ /*
+ * Until enough data has been read, we cannot tell about
+ * any encrypted entries yet.
+ */
+ zip->has_encrypted_entries = ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW;
+ zip->crc32func = real_crc32;
+
+ 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_seekable,
+ NULL,
+ archive_read_format_zip_cleanup,
+ archive_read_support_format_zip_capabilities_seekable,
+ archive_read_format_zip_has_encrypted_entries);
+
+ if (r != ARCHIVE_OK)
+ free(zip);
+ return (ARCHIVE_OK);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_string.c b/Utilities/cmlibarchive/libarchive/archive_string.c
index 87f9288f1..592ead2bd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_string.c
+++ b/Utilities/cmlibarchive/libarchive/archive_string.c
@@ -71,6 +71,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string.c 201095 2009-12-28 02:33
#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
#endif
+#if !defined(HAVE_WMEMMOVE) && !defined(wmemmove)
+#define wmemmove(a,b,i) (wchar_t *)memmove((a), (b), (i) * sizeof(wchar_t))
+#endif
+
struct archive_string_conv {
struct archive_string_conv *next;
char *from_charset;
@@ -127,12 +131,7 @@ struct archive_string_conv {
#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 const char utf8_replacement_char[] = {0xef, 0xbf, 0xbd};
static struct archive_string_conv *find_sconv_object(struct archive *,
const char *, const char *);
@@ -203,7 +202,7 @@ archive_string_append(struct archive_string *as, const char *p, size_t s)
{
if (archive_string_ensure(as, as->length + s + 1) == NULL)
return (NULL);
- memcpy(as->s + as->length, p, s);
+ memmove(as->s + as->length, p, s);
as->length += s;
as->s[as->length] = 0;
return (as);
@@ -214,12 +213,18 @@ archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s)
{
if (archive_wstring_ensure(as, as->length + s + 1) == NULL)
return (NULL);
- wmemcpy(as->s + as->length, p, s);
+ wmemmove(as->s + as->length, p, s);
as->length += s;
as->s[as->length] = 0;
return (as);
}
+struct archive_string *
+archive_array_append(struct archive_string *as, const char *p, size_t s)
+{
+ return archive_string_append(as, p, s);
+}
+
void
archive_string_concat(struct archive_string *dest, struct archive_string *src)
{
@@ -560,7 +565,8 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest,
}
if (count == 0 && length != 0)
ret = -1;
- } while (0);
+ break;
+ } while (1);
}
dest->length += count;
dest->s[dest->length] = L'\0';
@@ -597,7 +603,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest,
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
+ * extra MBS when strlen(p) > len and one wide character consists of
* multi bytes.
*/
while (*mbs && mbs_length > 0) {
@@ -738,7 +744,8 @@ archive_string_append_from_wcs_in_codepage(struct archive_string *as,
}
if (count == 0)
ret = -1;
- } while (0);
+ break;
+ } while (1);
}
as->length += count;
as->s[as->length] = '\0';
@@ -1247,7 +1254,7 @@ create_sconv_object(const char *fc, const char *tc,
sc->cd = iconv_open(tc, fc);
if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) {
/*
- * Unfortunaly, all of iconv implements do support
+ * Unfortunately, all of iconv implements do support
* "CP932" character-set, so we should use "SJIS"
* instead if iconv_open failed.
*/
@@ -1260,7 +1267,7 @@ create_sconv_object(const char *fc, const char *tc,
/*
* 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
+ * so that you can do a I18N programming. This will be
* used only in archive_mstring_copy_mbs_len_l so far.
*/
if (flag & SCONV_FROM_CHARSET) {
@@ -1725,7 +1732,7 @@ archive_string_conversion_from_charset(struct archive *a, const char *charset,
* 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.
+ * for compatibility.
*/
#if defined(_WIN32) && !defined(__CYGWIN__)
struct archive_string_conv *
@@ -1826,7 +1833,7 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int 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.
+ * that filename correctly.
*/
case SCONV_SET_OPT_UTF8_LIBARCHIVE2X:
#if (defined(_WIN32) && !defined(__CYGWIN__)) \
@@ -1938,12 +1945,19 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
struct archive_string_conv *sc)
{
const void *s;
- size_t length;
+ size_t length = 0;
int i, r = 0, r2;
+ if (_p != NULL && n > 0) {
+ if (sc != NULL && (sc->flag & SCONV_FROM_UTF16))
+ length = utf16nbytes(_p, n);
+ else
+ length = mbsnbytes(_p, n);
+ }
+
/* 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) {
+ if (length == 0) {
int tn = 1;
if (sc != NULL && (sc->flag & SCONV_TO_UTF16))
tn = 2;
@@ -1959,16 +1973,11 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
* If sc is NULL, we just make a copy.
*/
if (sc == NULL) {
- length = mbsnbytes(_p, n);
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) {
@@ -1991,7 +2000,7 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n,
#if HAVE_ICONV
/*
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
iconv_strncat_in_locale(struct archive_string *as, const void *_p,
@@ -2037,7 +2046,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
if (sc->flag & (SCONV_TO_UTF8 | SCONV_TO_UTF16)) {
size_t rbytes;
if (sc->flag & SCONV_TO_UTF8)
- rbytes = UTF8_R_CHAR_SIZE;
+ rbytes = sizeof(utf8_replacement_char);
else
rbytes = 2;
@@ -2053,7 +2062,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
- as->length - to_size;
}
if (sc->flag & SCONV_TO_UTF8)
- UTF8_SET_R_CHAR(outp);
+ memcpy(outp, utf8_replacement_char, sizeof(utf8_replacement_char));
else if (sc->flag & SCONV_TO_UTF16BE)
archive_be16enc(outp, UNICODE_R_CHAR);
else
@@ -2093,7 +2102,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p,
/*
* Translate a string from a some CodePage to an another CodePage by
- * Windows APIs, and copy the result. Return -1 if conversion failes.
+ * Windows APIs, and copy the result. Return -1 if conversion fails.
*/
static int
strncat_in_codepage(struct archive_string *as,
@@ -2202,9 +2211,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
size_t length, struct archive_string_conv *sc)
{
size_t remaining;
- char *otp;
const uint8_t *itp;
- size_t avail;
int return_value = 0; /* success */
/*
@@ -2219,50 +2226,29 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p,
/*
* If a character is ASCII, this just copies it. If not, this
- * assigns '?' charater instead but in UTF-8 locale this assigns
+ * assigns '?' character 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;
itp = (const uint8_t *)_p;
- otp = as->s + as->length;
- avail = as->buffer_length - as->length -1;
while (*itp && remaining > 0) {
- if (*itp > 127 && (sc->flag & SCONV_TO_UTF8)) {
- if (avail < UTF8_R_CHAR_SIZE) {
- as->length = otp - as->s;
- if (NULL == archive_string_ensure(as,
- as->buffer_length + remaining +
- UTF8_R_CHAR_SIZE))
- return (-1);
- otp = as->s + as->length;
- avail = as->buffer_length - as->length -1;
+ if (*itp > 127) {
+ // Non-ASCII: Substitute with suitable replacement
+ if (sc->flag & SCONV_TO_UTF8) {
+ if (archive_string_append(as, utf8_replacement_char, sizeof(utf8_replacement_char)) == NULL) {
+ __archive_errx(1, "Out of memory");
+ }
+ } else {
+ archive_strappend_char(as, '?');
}
- /*
- * When coping a string in UTF-8, unknown character
- * should be U+FFFD (replacement character).
- */
- UTF8_SET_R_CHAR(otp);
- otp += UTF8_R_CHAR_SIZE;
- avail -= UTF8_R_CHAR_SIZE;
- itp++;
- remaining--;
- return_value = -1;
- } else if (*itp > 127) {
- *otp++ = '?';
- itp++;
- remaining--;
return_value = -1;
} else {
- *otp++ = (char)*itp++;
- remaining--;
+ archive_strappend_char(as, *itp);
}
+ ++itp;
}
- as->length = otp - as->s;
- as->s[as->length] = '\0';
return (return_value);
}
@@ -2320,7 +2306,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
return (0); /* Standard: return 0 for end-of-string. */
cnt = utf8_count[ch];
- /* Invalide sequence or there are not plenty bytes. */
+ /* Invalid sequence or there are not plenty bytes. */
if ((int)n < cnt) {
cnt = (int)n;
for (i = 1; i < cnt; i++) {
@@ -2401,7 +2387,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
goto invalid_sequence;
}
- /* The code point larger than 0x10FFFF is not leagal
+ /* The code point larger than 0x10FFFF is not legal
* Unicode values. */
if (wc > UNICODE_MAX)
goto invalid_sequence;
@@ -2419,7 +2405,7 @@ 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. */
+ /* Any of Surrogate pair is not legal Unicode values. */
if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc))
return (-3);
return (cnt);
@@ -2480,7 +2466,7 @@ invalid_sequence:
/*
* Convert a Unicode code point to a single UTF-8 sequence.
*
- * NOTE:This function does not check if the Unicode is leagal or not.
+ * NOTE:This function does not check if the Unicode is legal or not.
* Please you definitely check it before calling this.
*/
static size_t
@@ -2488,6 +2474,9 @@ unicode_to_utf8(char *p, size_t remaining, uint32_t uc)
{
char *_p = p;
+ /* Invalid Unicode char maps to Replacement character */
+ if (uc > UNICODE_MAX)
+ uc = UNICODE_R_CHAR;
/* Translate code point to UTF8 */
if (uc <= 0x7f) {
if (remaining == 0)
@@ -2504,22 +2493,13 @@ unicode_to_utf8(char *p, size_t remaining, uint32_t uc)
*p++ = 0xe0 | ((uc >> 12) & 0x0f);
*p++ = 0x80 | ((uc >> 6) & 0x3f);
*p++ = 0x80 | (uc & 0x3f);
- } else if (uc <= UNICODE_MAX) {
+ } else {
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);
}
@@ -2580,9 +2560,9 @@ utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be)
/*
* Surrogate pair values(0xd800 through 0xdfff) are only
- * used by UTF-16, so, after above culculation, the code
+ * used by UTF-16, so, after above calculation, the code
* must not be surrogate values, and Unicode has no codes
- * larger than 0x10ffff. Thus, those are not leagal Unicode
+ * larger than 0x10ffff. Thus, those are not legal Unicode
* values.
*/
if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) {
@@ -2929,7 +2909,7 @@ get_nfc(uint32_t uc, uint32_t uc2)
/*
* Normalize UTF-8/UTF-16BE characters to Form C and copy the result.
*
- * TODO: Convert composition exclusions,which are never converted
+ * TODO: Convert composition exclusions, which are never converted
* from NFC,NFD,NFKC and NFKD, to Form C.
*/
static int
@@ -3463,7 +3443,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as,
}
/*
- * As libarchie 2.x, translates the UTF-8 characters into
+ * As libarchive 2.x, translates the UTF-8 characters into
* wide-characters in the assumption that WCS is Unicode.
*/
if (n < 0) {
@@ -3502,7 +3482,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as,
/*
* Convert a UTF-16BE/LE string to current locale and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
@@ -3581,18 +3561,19 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes,
ll = WideCharToMultiByte(sc->to_cp, 0,
(LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size,
NULL, &defchar);
- if (ll == 0 &&
- GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- /* Need more buffer for MBS. */
- ll = WideCharToMultiByte(sc->to_cp, 0,
- (LPCWSTR)u16, (int)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;
+ /* Exit loop if we succeeded */
+ if (ll != 0 ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ break;
}
- } while (0);
+ /* Else expand buffer and loop to try again. */
+ ll = WideCharToMultiByte(sc->to_cp, 0,
+ (LPCWSTR)u16, (int)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;
+ } while (1);
archive_string_free(&tmp);
as->length += ll;
as->s[as->length] = '\0';
@@ -3625,7 +3606,7 @@ is_big_endian(void)
/*
* Convert a current locale string to UTF-16BE/LE and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
win_strncat_to_utf16(struct archive_string *as16, const void *_p,
@@ -3663,19 +3644,20 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p,
do {
count = MultiByteToWideChar(sc->from_cp,
MB_PRECOMPOSED, s, (int)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, (int)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;
+ /* Exit loop if we succeeded */
+ if (count != 0 ||
+ GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
+ break;
}
- } while (0);
+ /* Expand buffer and try again */
+ count = MultiByteToWideChar(sc->from_cp,
+ MB_PRECOMPOSED, s, (int)length, NULL, 0);
+ if (archive_string_ensure(as16, (count +1) * 2)
+ == NULL)
+ return (-1);
+ u16 = as16->s + as16->length;
+ avail = as16->buffer_length - 2;
+ } while (1);
as16->length += count * 2;
as16->s[as16->length] = 0;
as16->s[as16->length+1] = 0;
@@ -3729,7 +3711,7 @@ win_strncat_to_utf16le(struct archive_string *as16, const void *_p,
/*
* Convert a UTF-16BE string to current locale and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
best_effort_strncat_from_utf16(struct archive_string *as, const void *_p,
@@ -3787,7 +3769,7 @@ best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p,
/*
* Convert a current locale string to UTF-16BE/LE and copy the result.
- * Return -1 if conversion failes.
+ * Return -1 if conversion fails.
*/
static int
best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p,
@@ -3887,7 +3869,7 @@ archive_mstring_get_utf8(struct archive *a, struct archive_mstring *aes,
sc = archive_string_conversion_to_charset(a, "UTF-8", 1);
if (sc == NULL)
return (-1);/* Couldn't allocate memory for sc. */
- r = archive_strncpy_l(&(aes->aes_mbs), aes->aes_mbs.s,
+ r = archive_strncpy_l(&(aes->aes_utf8), aes->aes_mbs.s,
aes->aes_mbs.length, sc);
if (a == NULL)
free_sconv_object(sc);
@@ -3971,7 +3953,7 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes,
#if defined(_WIN32) && !defined(__CYGWIN__)
/*
- * Internationalization programing on Windows must use Wide
+ * Internationalization programming on Windows must use Wide
* characters because Windows platform cannot make locale UTF-8.
*/
if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) {
@@ -4062,6 +4044,19 @@ archive_mstring_copy_wcs(struct archive_mstring *aes, const wchar_t *wcs)
}
int
+archive_mstring_copy_utf8(struct archive_mstring *aes, const char *utf8)
+{
+ if (utf8 == NULL) {
+ aes->aes_set = 0;
+ }
+ aes->aes_set = AES_SET_UTF8;
+ archive_string_empty(&(aes->aes_mbs));
+ archive_string_empty(&(aes->aes_wcs));
+ archive_strncpy(&(aes->aes_utf8), utf8, strlen(utf8));
+ return (int)strlen(utf8);
+}
+
+int
archive_mstring_copy_wcs_len(struct archive_mstring *aes, const wchar_t *wcs,
size_t len)
{
@@ -4090,7 +4085,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes,
archive_string_empty(&(aes->aes_utf8));
#if defined(_WIN32) && !defined(__CYGWIN__)
/*
- * Internationalization programing on Windows must use Wide
+ * Internationalization programming on Windows must use Wide
* characters because Windows platform cannot make locale UTF-8.
*/
if (sc == NULL) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_string.h b/Utilities/cmlibarchive/libarchive/archive_string.h
index 23f491657..56dfbb28f 100644
--- a/Utilities/cmlibarchive/libarchive/archive_string.h
+++ b/Utilities/cmlibarchive/libarchive/archive_string.h
@@ -81,6 +81,10 @@ archive_strappend_char(struct archive_string *, char);
struct archive_wstring *
archive_wstrappend_wchar(struct archive_wstring *, wchar_t);
+/* Append a raw array to an archive_string, resizing as necessary */
+struct archive_string *
+archive_array_append(struct archive_string *, const char *, size_t);
+
/* Convert a Unicode string to current locale and append the result. */
/* Returns -1 if conversion fails. */
int
@@ -115,13 +119,13 @@ archive_string_conversion_set_opt(struct archive_string_conv *, int);
/* Copy one archive_string to another in locale conversion.
- * Return -1 if conversion failes. */
+ * Return -1 if conversion fails. */
int
archive_strncpy_l(struct archive_string *, const void *, size_t,
struct archive_string_conv *);
/* Copy one archive_string to another in locale conversion.
- * Return -1 if conversion failes. */
+ * Return -1 if conversion fails. */
int
archive_strncat_l(struct archive_string *, const void *, size_t,
struct archive_string_conv *);
diff --git a/Utilities/cmlibarchive/libarchive/archive_string_composition.h b/Utilities/cmlibarchive/libarchive/archive_string_composition.h
index be41e3365..8902ac1f7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_string_composition.h
+++ b/Utilities/cmlibarchive/libarchive/archive_string_composition.h
@@ -1009,7 +1009,7 @@ static const char u_decomposable_blocks[0x1D2+1] = {
(((uc) > 0x1D244)?0:\
ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F])
-/* The table of the value of Canonical Cimbining Class */
+/* The table of the value of Canonical Combining Class */
static const unsigned char ccc_val[][16] = {
/* idx=0: XXXX0 - XXXXF */
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
diff --git a/Utilities/cmlibarchive/libarchive/archive_util.c b/Utilities/cmlibarchive/libarchive/archive_util.c
index 34d8081cb..f56ca332d 100644
--- a/Utilities/cmlibarchive/libarchive/archive_util.c
+++ b/Utilities/cmlibarchive/libarchive/archive_util.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2009-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
* Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
@@ -45,15 +45,30 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:1
#if defined(HAVE_WINCRYPT_H) && !defined(__CYGWIN__)
#include <wincrypt.h>
#endif
+#ifdef HAVE_ZLIB_H
+#include <cm_zlib.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <cm_lzma.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <cm_bzlib.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
#include "archive.h"
#include "archive_private.h"
+#include "archive_random_private.h"
#include "archive_string.h"
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
+static int archive_utility_string_sort_helper(char **, unsigned int);
+
/* Generic initialization of 'struct archive' objects. */
int
__archive_clean(struct archive *a)
@@ -74,6 +89,88 @@ archive_version_string(void)
return (ARCHIVE_VERSION_STRING);
}
+const char *
+archive_version_details(void)
+{
+ static struct archive_string str;
+ static int init = 0;
+ const char *zlib = archive_zlib_version();
+ const char *liblzma = archive_liblzma_version();
+ const char *bzlib = archive_bzlib_version();
+ const char *liblz4 = archive_liblz4_version();
+
+ if (!init) {
+ archive_string_init(&str);
+
+ archive_strcat(&str, ARCHIVE_VERSION_STRING);
+ if (zlib != NULL) {
+ archive_strcat(&str, " zlib/");
+ archive_strcat(&str, zlib);
+ }
+ if (liblzma) {
+ archive_strcat(&str, " liblzma/");
+ archive_strcat(&str, liblzma);
+ }
+ if (bzlib) {
+ const char *p = bzlib;
+ const char *sep = strchr(p, ',');
+ if (sep == NULL)
+ sep = p + strlen(p);
+ archive_strcat(&str, " bz2lib/");
+ archive_strncat(&str, p, sep - p);
+ }
+ if (liblz4) {
+ archive_strcat(&str, " liblz4/");
+ archive_strcat(&str, liblz4);
+ }
+ }
+ return str.s;
+}
+
+const char *
+archive_zlib_version(void)
+{
+#ifdef HAVE_ZLIB_H
+ return ZLIB_VERSION;
+#else
+ return NULL;
+#endif
+}
+
+const char *
+archive_liblzma_version(void)
+{
+#ifdef HAVE_LZMA_H
+ return LZMA_VERSION_STRING;
+#else
+ return NULL;
+#endif
+}
+
+const char *
+archive_bzlib_version(void)
+{
+#ifdef HAVE_BZLIB_H
+ return BZ2_bzlibVersion();
+#else
+ return NULL;
+#endif
+}
+
+const char *
+archive_liblz4_version(void)
+{
+#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
+#define str(s) #s
+#define NUMBER(x) str(x)
+ return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
+#undef NUMBER
+#undef str
+#else
+ return NULL;
+#endif
+}
+
int
archive_errno(struct archive *a)
{
@@ -206,6 +303,8 @@ __archive_errx(int retvalue, const char *msg)
int
__archive_mktemp(const char *tmpdir)
{
+ static const wchar_t *prefix = L"libarchive_";
+ static const wchar_t *suffix = L"XXXXXXXXXX";
static const wchar_t num[] = {
L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
@@ -280,10 +379,10 @@ __archive_mktemp(const char *tmpdir)
/*
* Create a temporary file.
*/
- archive_wstrcat(&temp_name, L"libarchive_");
- xp = temp_name.s + archive_strlen(&temp_name);
- archive_wstrcat(&temp_name, L"XXXXXXXXXX");
+ archive_wstrcat(&temp_name, prefix);
+ archive_wstrcat(&temp_name, suffix);
ep = temp_name.s + archive_strlen(&temp_name);
+ xp = ep - wcslen(suffix);
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT)) {
@@ -420,7 +519,6 @@ __archive_mktemp(const char *tmpdir)
struct stat st;
int fd;
char *tp, *ep;
- unsigned seed;
fd = -1;
archive_string_init(&temp_name);
@@ -444,21 +542,15 @@ __archive_mktemp(const char *tmpdir)
archive_strcat(&temp_name, "XXXXXXXXXX");
ep = temp_name.s + archive_strlen(&temp_name);
- fd = open("/dev/random", O_RDONLY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(fd);
- if (fd < 0)
- seed = time(NULL);
- else {
- if (read(fd, &seed, sizeof(seed)) < 0)
- seed = time(NULL);
- close(fd);
- }
do {
char *p;
p = tp;
- while (p < ep)
- *p++ = num[((unsigned)rand_r(&seed)) % sizeof(num)];
+ archive_random(p, ep - p);
+ while (p < ep) {
+ int d = *((unsigned char *)p) % sizeof(num);
+ *p++ = num[d];
+ }
fd = open(temp_name.s, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC,
0600);
} while (fd < 0 && errno == EEXIST);
@@ -488,7 +580,7 @@ void
__archive_ensure_cloexec_flag(int fd)
{
#if defined(_WIN32) && !defined(__CYGWIN__)
- (void)fd; /* UNSED */
+ (void)fd; /* UNUSED */
#else
int flags;
@@ -499,3 +591,77 @@ __archive_ensure_cloexec_flag(int fd)
}
#endif
}
+
+/*
+ * Utility function to sort a group of strings using quicksort.
+ */
+static int
+archive_utility_string_sort_helper(char **strings, unsigned int n)
+{
+ unsigned int i, lesser_count, greater_count;
+ char **lesser, **greater, **tmp, *pivot;
+ int retval1, retval2;
+
+ /* A list of 0 or 1 elements is already sorted */
+ if (n <= 1)
+ return (ARCHIVE_OK);
+
+ lesser_count = greater_count = 0;
+ lesser = greater = NULL;
+ pivot = strings[0];
+ for (i = 1; i < n; i++)
+ {
+ if (strcmp(strings[i], pivot) < 0)
+ {
+ lesser_count++;
+ tmp = (char **)realloc(lesser,
+ lesser_count * sizeof(char *));
+ if (!tmp) {
+ free(greater);
+ free(lesser);
+ return (ARCHIVE_FATAL);
+ }
+ lesser = tmp;
+ lesser[lesser_count - 1] = strings[i];
+ }
+ else
+ {
+ greater_count++;
+ tmp = (char **)realloc(greater,
+ greater_count * sizeof(char *));
+ if (!tmp) {
+ free(greater);
+ free(lesser);
+ return (ARCHIVE_FATAL);
+ }
+ greater = tmp;
+ greater[greater_count - 1] = strings[i];
+ }
+ }
+
+ /* quicksort(lesser) */
+ retval1 = archive_utility_string_sort_helper(lesser, lesser_count);
+ for (i = 0; i < lesser_count; i++)
+ strings[i] = lesser[i];
+ free(lesser);
+
+ /* pivot */
+ strings[lesser_count] = pivot;
+
+ /* quicksort(greater) */
+ retval2 = archive_utility_string_sort_helper(greater, greater_count);
+ for (i = 0; i < greater_count; i++)
+ strings[lesser_count + 1 + i] = greater[i];
+ free(greater);
+
+ return (retval1 < retval2) ? retval1 : retval2;
+}
+
+int
+archive_utility_string_sort(char **strings)
+{
+ unsigned int size = 0;
+ while (strings[size] != NULL)
+ size++;
+ return archive_utility_string_sort_helper(strings, size);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_virtual.c b/Utilities/cmlibarchive/libarchive/archive_virtual.c
index 0c4155f21..de2595a9e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_virtual.c
+++ b/Utilities/cmlibarchive/libarchive/archive_virtual.c
@@ -55,6 +55,14 @@ archive_filter_bytes(struct archive *a, int n)
}
int
+archive_free(struct archive *a)
+{
+ if (a == NULL)
+ return (ARCHIVE_OK);
+ return ((a->vtable->archive_free)(a));
+}
+
+int
archive_write_close(struct archive *a)
{
return ((a->vtable->archive_close)(a));
@@ -76,9 +84,7 @@ archive_write_fail(struct archive *a)
int
archive_write_free(struct archive *a)
{
- if (a == NULL)
- return (ARCHIVE_OK);
- return ((a->vtable->archive_free)(a));
+ return archive_free(a);
}
#if ARCHIVE_VERSION_NUMBER < 4000000
@@ -93,9 +99,7 @@ archive_write_finish(struct archive *a)
int
archive_read_free(struct archive *a)
{
- if (a == NULL)
- return (ARCHIVE_OK);
- return ((a->vtable->archive_free)(a));
+ return archive_free(a);
}
#if ARCHIVE_VERSION_NUMBER < 4000000
diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.c b/Utilities/cmlibarchive/libarchive/archive_windows.c
index d3bf758bb..6ff8749ae 100644
--- a/Utilities/cmlibarchive/libarchive/archive_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_windows.c
@@ -301,7 +301,7 @@ __la_open(const char *path, int flags, ...)
ws = NULL;
if ((flags & ~O_BINARY) == O_RDONLY) {
/*
- * When we open a directory, _open function returns
+ * When we open a directory, _open function returns
* "Permission denied" error.
*/
attr = GetFileAttributesA(path);
@@ -515,9 +515,9 @@ __hstat(HANDLE handle, struct ustat *st)
else
mode |= S_IFREG;
st->st_mode = mode;
-
+
fileTimeToUTC(&info.ftLastAccessTime, &t, &ns);
- st->st_atime = t;
+ st->st_atime = t;
st->st_atime_nsec = ns;
fileTimeToUTC(&info.ftLastWriteTime, &t, &ns);
st->st_mtime = t;
@@ -525,7 +525,7 @@ __hstat(HANDLE handle, struct ustat *st)
fileTimeToUTC(&info.ftCreationTime, &t, &ns);
st->st_ctime = t;
st->st_ctime_nsec = ns;
- st->st_size =
+ st->st_size =
((int64_t)(info.nFileSizeHigh) * ((int64_t)MAXDWORD + 1))
+ (int64_t)(info.nFileSizeLow);
#ifdef SIMULATE_WIN_STAT
@@ -599,7 +599,7 @@ __la_stat(const char *path, struct stat *st)
struct ustat u;
int ret;
- handle = la_CreateFile(path, 0, 0, NULL, OPEN_EXISTING,
+ handle = la_CreateFile(path, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS,
NULL);
if (handle == INVALID_HANDLE_VALUE) {
@@ -766,7 +766,7 @@ __la_win_entry_in_posix_pathseparator(struct archive_entry *entry)
has_backslash = 1;
}
/*
- * If there is no backslach chars, return the original.
+ * If there is no backslash chars, return the original.
*/
if (!has_backslash)
return (entry);
@@ -891,7 +891,7 @@ __la_dosmaperr(unsigned long e)
return;
}
- for (i = 0; i < (int)sizeof(doserrors); i++)
+ for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++)
{
if (doserrors[i].winerr == e)
{
diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.h b/Utilities/cmlibarchive/libarchive/archive_windows.h
index 620810c1c..c3aed0c90 100644
--- a/Utilities/cmlibarchive/libarchive/archive_windows.h
+++ b/Utilities/cmlibarchive/libarchive/archive_windows.h
@@ -76,6 +76,7 @@
#if defined(_MSC_VER)
#pragma warning(push,1)
+#pragma warning(disable:4142) /* benign redefinition of type */
#pragma warning(disable:4761) /* integral size mismatch in argument; conversion supplied */
#endif
#if defined(__BORLANDC__)
@@ -93,7 +94,7 @@
/* Alias the Windows _function to the POSIX equivalent. */
#define close _close
-#define fcntl(fd, cmd, flg) /* No operation. */
+#define fcntl(fd, cmd, flg) /* No operation. */
#ifndef fileno
#define fileno _fileno
#endif
@@ -113,13 +114,14 @@
#define lstat __la_stat
#define open __la_open
#define read __la_read
-#if !defined(__BORLANDC__)
+#if !defined(__BORLANDC__) && !defined(__WATCOMC__)
#define setmode _setmode
#endif
#ifdef stat
#undef stat
#endif
#define stat(path,stref) __la_stat(path,stref)
+#if !defined(__WATCOMC__)
#if !defined(__BORLANDC__)
#define strdup _strdup
#endif
@@ -127,9 +129,12 @@
#if !defined(__BORLANDC__)
#define umask _umask
#endif
+#endif
#define waitpid __la_waitpid
#define write __la_write
+#if !defined(__WATCOMC__)
+
#ifndef O_RDONLY
#define O_RDONLY _O_RDONLY
#define O_WRONLY _O_WRONLY
@@ -188,6 +193,7 @@
#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 */
@@ -207,7 +213,7 @@
#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_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 */
@@ -218,14 +224,22 @@
#define S_IWUSR _S_IWUSR
#define S_IRUSR _S_IRUSR
#endif
+#ifndef S_IRWXG
#define S_IRWXG _S_IRWXG
#define S_IXGRP _S_IXGRP
#define S_IWGRP _S_IWGRP
+#endif
+#ifndef S_IRGRP
#define S_IRGRP _S_IRGRP
+#endif
+#ifndef S_IRWXO
#define S_IRWXO _S_IRWXO
#define S_IXOTH _S_IXOTH
#define S_IWOTH _S_IWOTH
#define S_IROTH _S_IROTH
+#endif
+
+#endif
#define F_DUPFD 0 /* Duplicate file descriptor. */
#define F_GETFD 1 /* Get file descriptor flags. */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write.3 b/Utilities/cmlibarchive/libarchive/archive_write.3
index 228bc2cb8..376d71dee 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write.3
@@ -155,7 +155,7 @@ myopen(struct archive *a, void *client_data)
return (ARCHIVE_FATAL);
}
-ssize_t
+la_ssize_t
mywrite(struct archive *a, void *client_data, const void *buff, size_t n)
{
struct mydata *mydata = client_data;
@@ -186,8 +186,13 @@ write_archive(const char *outname, const char **filename)
a = archive_write_new();
mydata->name = outname;
- archive_write_add_filter_gzip(a);
- archive_write_set_format_ustar(a);
+ /* Set archive format and filter according to output file extension.
+ * If it fails, set default format. Platform depended function.
+ * See supported formats in archive_write_set_format_filter_by_ext.c */
+ if (archive_write_set_format_filter_by_ext(a, outname) != ARCHIVE_OK) {
+ archive_write_add_filter_gzip(a);
+ archive_write_set_format_ustar(a);
+ }
archive_write_open(a, mydata, myopen, mywrite, myclose);
while (*filename) {
stat(*filename, &st);
@@ -197,7 +202,7 @@ write_archive(const char *outname, const char **filename)
archive_write_header(a, entry);
if ((fd = open(*filename, O_RDONLY)) != -1) {
len = read(fd, buff, sizeof(buff));
- while ( len > 0 ) {
+ while (len > 0) {
archive_write_data(a, buff, len);
len = read(fd, buff, sizeof(buff));
}
@@ -213,7 +218,7 @@ int main(int argc, const char **argv)
{
const char *outname;
argv++;
- outname = argv++;
+ outname = *argv++;
write_archive(outname, argv);
return 0;
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c
index b296069e9..0634a2296 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write.c
@@ -109,10 +109,9 @@ archive_write_new(void)
struct archive_write *a;
unsigned char *nulls;
- a = (struct archive_write *)malloc(sizeof(*a));
+ a = (struct archive_write *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_write_vtable();
@@ -126,12 +125,11 @@ archive_write_new(void)
/* Initialize a block of nulls for padding purposes. */
a->null_length = 1024;
- nulls = (unsigned char *)malloc(a->null_length);
+ nulls = (unsigned char *)calloc(1, a->null_length);
if (nulls == NULL) {
free(a);
return (NULL);
}
- memset(nulls, 0, a->null_length);
a->nulls = nulls;
return (&a->archive);
}
@@ -233,7 +231,7 @@ __archive_write_filter(struct archive_write_filter *f,
if (length == 0)
return(ARCHIVE_OK);
if (f->write == NULL)
- /* If unset, a fatal error has already ocuured, so this filter
+ /* If unset, a fatal error has already occurred, so this filter
* didn't open. We cannot write anything. */
return(ARCHIVE_FATAL);
r = (f->write)(f, buff, length);
@@ -444,6 +442,12 @@ archive_write_client_close(struct archive_write_filter *f)
/* Clear the close handler myself not to be called again. */
f->close = NULL;
a->client_data = NULL;
+ /* Clear passphrase. */
+ if (a->passphrase != NULL) {
+ memset(a->passphrase, 0, strlen(a->passphrase));
+ free(a->passphrase);
+ a->passphrase = NULL;
+ }
return (ret);
}
@@ -503,8 +507,9 @@ _archive_write_close(struct archive *_a)
archive_clear_error(&a->archive);
- /* Finish the last entry. */
- if (a->archive.state == ARCHIVE_STATE_DATA)
+ /* Finish the last entry if a finish callback is specified */
+ if (a->archive.state == ARCHIVE_STATE_DATA
+ && a->format_finish_entry != NULL)
r = ((a->format_finish_entry)(a));
/* Finish off the archive. */
@@ -591,6 +596,11 @@ _archive_write_free(struct archive *_a)
/* Release various dynamic buffers. */
free((void *)(uintptr_t)(const void *)a->nulls);
archive_string_free(&a->archive.error_string);
+ if (a->passphrase != NULL) {
+ /* A passphrase should be cleaned. */
+ memset(a->passphrase, 0, strlen(a->passphrase));
+ free(a->passphrase);
+ }
a->archive.magic = 0;
__archive_clean(&a->archive);
free(a);
@@ -638,6 +648,9 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
/* Format and write header. */
r2 = ((a->format_write_header)(a, entry));
+ if (r2 == ARCHIVE_FAILED) {
+ return (ARCHIVE_FAILED);
+ }
if (r2 == ARCHIVE_FATAL) {
a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
@@ -658,7 +671,8 @@ _archive_write_finish_entry(struct archive *_a)
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_finish_entry");
- if (a->archive.state & ARCHIVE_STATE_DATA)
+ if (a->archive.state & ARCHIVE_STATE_DATA
+ && a->format_finish_entry != NULL)
ret = (a->format_finish_entry)(a);
a->archive.state = ARCHIVE_STATE_HEADER;
return (ret);
@@ -671,8 +685,13 @@ static ssize_t
_archive_write_data(struct archive *_a, const void *buff, size_t s)
{
struct archive_write *a = (struct archive_write *)_a;
+ const size_t max_write = INT_MAX;
+
archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_data");
+ /* In particular, this catches attempts to pass negative values. */
+ if (s > max_write)
+ s = max_write;
archive_clear_error(&a->archive);
return ((a->format_write_data)(a, buff, s));
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
index 81dd683aa..ad5dc832f 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter.c
@@ -47,6 +47,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FILTER_COMPRESS, archive_write_add_filter_compress },
{ ARCHIVE_FILTER_GRZIP, archive_write_add_filter_grzip },
{ ARCHIVE_FILTER_LRZIP, archive_write_add_filter_lrzip },
+ { ARCHIVE_FILTER_LZ4, archive_write_add_filter_lz4 },
{ ARCHIVE_FILTER_LZIP, archive_write_add_filter_lzip },
{ ARCHIVE_FILTER_LZMA, archive_write_add_filter_lzma },
{ ARCHIVE_FILTER_LZOP, archive_write_add_filter_lzip },
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
index e4cba4afa..eac4011cb 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_by_name.c
@@ -51,6 +51,7 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
{ "grzip", archive_write_add_filter_grzip },
{ "gzip", archive_write_add_filter_gzip },
{ "lrzip", archive_write_add_filter_lrzip },
+ { "lz4", archive_write_add_filter_lz4 },
{ "lzip", archive_write_add_filter_lzip },
{ "lzma", archive_write_add_filter_lzma },
{ "lzop", archive_write_add_filter_lzop },
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
index 6526f5168..6bd0d1d62 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_bzip2.c
@@ -105,7 +105,7 @@ archive_write_add_filter_bzip2(struct archive *_a)
#if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
return (ARCHIVE_OK);
#else
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("bzip2");
if (data->pdata == NULL) {
free(data);
archive_set_error(&a->archive, ENOMEM, "Out of memory");
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
index 8dc287eae..371102d74 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_grzip.c
@@ -63,7 +63,7 @@ archive_write_add_filter_grzip(struct archive *_a)
archive_set_error(_a, ENOMEM, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("grzip");
if (data->pdata == NULL) {
free(data);
archive_set_error(_a, ENOMEM, "Can't allocate memory");
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
index db18fd94a..bbcc1789a 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_gzip.c
@@ -119,7 +119,7 @@ archive_write_add_filter_gzip(struct archive *_a)
data->compression_level = Z_DEFAULT_COMPRESSION;
return (ARCHIVE_OK);
#else
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("gzip");
if (data->pdata == NULL) {
free(data);
archive_set_error(&a->archive, ENOMEM, "Out of memory");
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
index 85fdf6af5..e215f8903 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lrzip.c
@@ -44,7 +44,7 @@ __FBSDID("$FreeBSD$");
struct write_lrzip {
struct archive_write_program_data *pdata;
int compression_level;
- enum { lzma = 0, bzip2, gzip, lzo, zpaq } compression;
+ enum { lzma = 0, bzip2, gzip, lzo, none, zpaq } compression;
};
static int archive_write_lrzip_open(struct archive_write_filter *);
@@ -69,7 +69,7 @@ archive_write_add_filter_lrzip(struct archive *_a)
archive_set_error(_a, ENOMEM, "Can't allocate memory");
return (ARCHIVE_FATAL);
}
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("lrzip");
if (data->pdata == NULL) {
free(data);
archive_set_error(_a, ENOMEM, "Can't allocate memory");
@@ -107,6 +107,8 @@ archive_write_lrzip_options(struct archive_write_filter *f, const char *key,
data->compression = gzip;
else if (strcmp(value, "lzo") == 0)
data->compression = lzo;
+ else if (strcmp(value, "none") == 0)
+ data->compression = none;
else if (strcmp(value, "zpaq") == 0)
data->compression = zpaq;
else
@@ -148,6 +150,9 @@ archive_write_lrzip_open(struct archive_write_filter *f)
case lzo:
archive_strcat(&as, " -l");
break;
+ case none:
+ archive_strcat(&as, " -n");
+ break;
case zpaq:
archive_strcat(&as, " -z");
break;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c
new file mode 100644
index 000000000..e6551859c
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c
@@ -0,0 +1,707 @@
+/*-
+ * Copyright (c) 2014 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 <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
+#ifdef HAVE_LZ4HC_H
+#include <lz4hc.h>
+#endif
+
+#include "archive.h"
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_write_private.h"
+#include "archive_xxhash.h"
+
+#define LZ4_MAGICNUMBER 0x184d2204
+
+struct private_data {
+ int compression_level;
+ unsigned header_written:1;
+ unsigned version_number:1;
+ unsigned block_independence:1;
+ unsigned block_checksum:1;
+ unsigned stream_size:1;
+ unsigned stream_checksum:1;
+ unsigned preset_dictionary:1;
+ unsigned block_maximum_size:3;
+#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
+ int64_t total_in;
+ char *out;
+ char *out_buffer;
+ size_t out_buffer_size;
+ size_t out_block_size;
+ char *in;
+ char *in_buffer_allocated;
+ char *in_buffer;
+ size_t in_buffer_size;
+ size_t block_size;
+
+ void *xxh32_state;
+ void *lz4_stream;
+#else
+ struct archive_write_program_data *pdata;
+#endif
+};
+
+static int archive_filter_lz4_close(struct archive_write_filter *);
+static int archive_filter_lz4_free(struct archive_write_filter *);
+static int archive_filter_lz4_open(struct archive_write_filter *);
+static int archive_filter_lz4_options(struct archive_write_filter *,
+ const char *, const char *);
+static int archive_filter_lz4_write(struct archive_write_filter *,
+ const void *, size_t);
+
+/*
+ * Add a lz4 compression filter to this write handle.
+ */
+int
+archive_write_add_filter_lz4(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct archive_write_filter *f = __archive_write_allocate_filter(_a);
+ struct private_data *data;
+
+ archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_add_filter_lz4");
+
+ data = calloc(1, sizeof(*data));
+ if (data == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+
+ /*
+ * Setup default settings.
+ */
+ data->compression_level = 1;
+ data->version_number = 0x01;
+ data->block_independence = 1;
+ data->block_checksum = 0;
+ data->stream_size = 0;
+ data->stream_checksum = 1;
+ data->preset_dictionary = 0;
+ data->block_maximum_size = 7;
+
+ /*
+ * Setup a filter setting.
+ */
+ f->data = data;
+ f->options = &archive_filter_lz4_options;
+ f->close = &archive_filter_lz4_close;
+ f->free = &archive_filter_lz4_free;
+ f->open = &archive_filter_lz4_open;
+ f->code = ARCHIVE_FILTER_LZ4;
+ f->name = "lz4";
+#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
+ return (ARCHIVE_OK);
+#else
+ /*
+ * We don't have lz4 library, and execute external lz4 program
+ * instead.
+ */
+ data->pdata = __archive_write_program_allocate("lz4");
+ if (data->pdata == NULL) {
+ free(data);
+ archive_set_error(&a->archive, ENOMEM, "Out of memory");
+ return (ARCHIVE_FATAL);
+ }
+ data->compression_level = 0;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Using external lz4 program");
+ return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Set write options.
+ */
+static int
+archive_filter_lz4_options(struct archive_write_filter *f,
+ const char *key, const char *value)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (strcmp(key, "compression-level") == 0) {
+ int val;
+ if (value == NULL || !((val = value[0] - '0') >= 1 && val <= 9) ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+
+#ifndef HAVE_LZ4HC_H
+ if(val >= 3)
+ {
+ archive_set_error(f->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "High compression not included in this build");
+ return (ARCHIVE_FATAL);
+ }
+#endif
+ data->compression_level = val;
+ return (ARCHIVE_OK);
+ }
+ if (strcmp(key, "stream-checksum") == 0) {
+ data->stream_checksum = value != NULL;
+ return (ARCHIVE_OK);
+ }
+ if (strcmp(key, "block-checksum") == 0) {
+ data->block_checksum = value != NULL;
+ return (ARCHIVE_OK);
+ }
+ if (strcmp(key, "block-size") == 0) {
+ if (value == NULL || !(value[0] >= '4' && value[0] <= '7') ||
+ value[1] != '\0')
+ return (ARCHIVE_WARN);
+ data->block_maximum_size = value[0] - '0';
+ return (ARCHIVE_OK);
+ }
+ if (strcmp(key, "block-dependence") == 0) {
+ data->block_independence = value == 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);
+}
+
+#if defined(HAVE_LIBLZ4) && LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 2
+/* Don't compile this if we don't have liblz4. */
+
+static int drive_compressor(struct archive_write_filter *, const char *,
+ size_t);
+static int drive_compressor_independence(struct archive_write_filter *,
+ const char *, size_t);
+static int drive_compressor_dependence(struct archive_write_filter *,
+ const char *, size_t);
+static int lz4_write_stream_descriptor(struct archive_write_filter *);
+static ssize_t lz4_write_one_block(struct archive_write_filter *, const char *,
+ size_t);
+
+
+/*
+ * Setup callback.
+ */
+static int
+archive_filter_lz4_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret;
+ size_t required_size;
+ static size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
+ 4 * 1024 * 1024 };
+ size_t pre_block_size;
+
+ ret = __archive_write_open_filter(f->next_filter);
+ if (ret != 0)
+ return (ret);
+
+ if (data->block_maximum_size < 4)
+ data->block_size = bkmap[0];
+ else
+ data->block_size = bkmap[data->block_maximum_size - 4];
+
+ required_size = 4 + 15 + 4 + data->block_size + 4 + 4;
+ if (data->out_buffer_size < required_size) {
+ size_t bs = required_size, bpb;
+ free(data->out_buffer);
+ if (f->archive->magic == ARCHIVE_WRITE_MAGIC) {
+ /* Buffer size should be a multiple number of
+ * the of bytes per block for performance. */
+ bpb = archive_write_get_bytes_per_block(f->archive);
+ if (bpb > bs)
+ bs = bpb;
+ else if (bpb != 0) {
+ bs += bpb;
+ bs -= bs % bpb;
+ }
+ }
+ data->out_block_size = bs;
+ bs += required_size;
+ data->out_buffer = malloc(bs);
+ data->out = data->out_buffer;
+ data->out_buffer_size = bs;
+ }
+
+ pre_block_size = (data->block_independence)? 0: 64 * 1024;
+ if (data->in_buffer_size < data->block_size + pre_block_size) {
+ free(data->in_buffer_allocated);
+ data->in_buffer_size = data->block_size;
+ data->in_buffer_allocated =
+ malloc(data->in_buffer_size + pre_block_size);
+ data->in_buffer = data->in_buffer_allocated + pre_block_size;
+ if (!data->block_independence && data->compression_level >= 3)
+ data->in_buffer = data->in_buffer_allocated;
+ data->in = data->in_buffer;
+ data->in_buffer_size = data->block_size;
+ }
+
+ if (data->out_buffer == NULL || data->in_buffer_allocated == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ return (ARCHIVE_FATAL);
+ }
+
+ f->write = archive_filter_lz4_write;
+
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Write data to the out stream.
+ *
+ * Returns ARCHIVE_OK if all data written, error otherwise.
+ */
+static int
+archive_filter_lz4_write(struct archive_write_filter *f,
+ const void *buff, size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret = ARCHIVE_OK;
+ const char *p;
+ size_t remaining;
+ ssize_t size;
+
+ /* If we haven't written a stream descriptor, we have to do it first. */
+ if (!data->header_written) {
+ ret = lz4_write_stream_descriptor(f);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ data->header_written = 1;
+ }
+
+ /* Update statistics */
+ data->total_in += length;
+
+ p = (const char *)buff;
+ remaining = length;
+ while (remaining) {
+ size_t l;
+ /* Compress input data to output buffer */
+ size = lz4_write_one_block(f, p, remaining);
+ if (size < ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ l = data->out - data->out_buffer;
+ if (l >= data->out_block_size) {
+ ret = __archive_write_filter(f->next_filter,
+ data->out_buffer, data->out_block_size);
+ l -= data->out_block_size;
+ memcpy(data->out_buffer,
+ data->out_buffer + data->out_block_size, l);
+ data->out = data->out_buffer + l;
+ if (ret < ARCHIVE_WARN)
+ break;
+ }
+ p += size;
+ remaining -= size;
+ }
+
+ return (ret);
+}
+
+/*
+ * Finish the compression.
+ */
+static int
+archive_filter_lz4_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int ret, r1;
+
+ /* Finish compression cycle. */
+ ret = (int)lz4_write_one_block(f, NULL, 0);
+ if (ret >= 0) {
+ /*
+ * Write the last block and the end of the stream data.
+ */
+
+ /* Write End Of Stream. */
+ memset(data->out, 0, 4); data->out += 4;
+ /* Write Stream checksum if needed. */
+ if (data->stream_checksum) {
+ unsigned int checksum;
+ checksum = __archive_xxhash.XXH32_digest(
+ data->xxh32_state);
+ data->xxh32_state = NULL;
+ archive_le32enc(data->out, checksum);
+ data->out += 4;
+ }
+ ret = __archive_write_filter(f->next_filter,
+ data->out_buffer, data->out - data->out_buffer);
+ }
+
+ r1 = __archive_write_close_filter(f->next_filter);
+ return (r1 < ret ? r1 : ret);
+}
+
+static int
+archive_filter_lz4_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (data->lz4_stream != NULL) {
+#ifdef HAVE_LZ4HC_H
+ if (data->compression_level >= 3)
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ LZ4_freeStreamHC(data->lz4_stream);
+#else
+ LZ4_freeHC(data->lz4_stream);
+#endif
+ else
+#endif
+#if LZ4_VERSION_MINOR >= 3
+ LZ4_freeStream(data->lz4_stream);
+#else
+ LZ4_free(data->lz4_stream);
+#endif
+ }
+ free(data->out_buffer);
+ free(data->in_buffer_allocated);
+ free(data->xxh32_state);
+ free(data);
+ f->data = NULL;
+ return (ARCHIVE_OK);
+}
+
+static int
+lz4_write_stream_descriptor(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ uint8_t *sd;
+
+ sd = (uint8_t *)data->out;
+ /* Write Magic Number. */
+ archive_le32enc(&sd[0], LZ4_MAGICNUMBER);
+ /* FLG */
+ sd[4] = (data->version_number << 6)
+ | (data->block_independence << 5)
+ | (data->block_checksum << 4)
+ | (data->stream_size << 3)
+ | (data->stream_checksum << 2)
+ | (data->preset_dictionary << 0);
+ /* BD */
+ sd[5] = (data->block_maximum_size << 4);
+ sd[6] = (__archive_xxhash.XXH32(&sd[4], 2, 0) >> 8) & 0xff;
+ data->out += 7;
+ if (data->stream_checksum)
+ data->xxh32_state = __archive_xxhash.XXH32_init(0);
+ else
+ data->xxh32_state = NULL;
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+lz4_write_one_block(struct archive_write_filter *f, const char *p,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ ssize_t r;
+
+ if (p == NULL) {
+ /* Compress remaining uncompressed data. */
+ if (data->in_buffer == data->in)
+ return 0;
+ else {
+ size_t l = data->in - data->in_buffer;
+ r = drive_compressor(f, data->in_buffer, l);
+ if (r == ARCHIVE_OK)
+ r = (ssize_t)l;
+ }
+ } else if ((data->block_independence || data->compression_level < 3) &&
+ data->in_buffer == data->in && length >= data->block_size) {
+ r = drive_compressor(f, p, data->block_size);
+ if (r == ARCHIVE_OK)
+ r = (ssize_t)data->block_size;
+ } else {
+ size_t remaining_size = data->in_buffer_size -
+ (data->in - data->in_buffer);
+ size_t l = (remaining_size > length)? length: remaining_size;
+ memcpy(data->in, p, l);
+ data->in += l;
+ if (l == remaining_size) {
+ r = drive_compressor(f, data->in_buffer,
+ data->block_size);
+ if (r == ARCHIVE_OK)
+ r = (ssize_t)l;
+ data->in = data->in_buffer;
+ } else
+ r = (ssize_t)l;
+ }
+
+ return (r);
+}
+
+
+/*
+ * Utility function to push input data through compressor, writing
+ * full output blocks as necessary.
+ *
+ * Note that this handles both the regular write case (finishing ==
+ * false) and the end-of-archive case (finishing == true).
+ */
+static int
+drive_compressor(struct archive_write_filter *f, const char *p, size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ if (data->stream_checksum)
+ __archive_xxhash.XXH32_update(data->xxh32_state,
+ p, (int)length);
+ if (data->block_independence)
+ return drive_compressor_independence(f, p, length);
+ else
+ return drive_compressor_dependence(f, p, length);
+}
+
+static int
+drive_compressor_independence(struct archive_write_filter *f, const char *p,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ unsigned int outsize;
+
+#ifdef HAVE_LZ4HC_H
+ if (data->compression_level >= 3)
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ outsize = LZ4_compress_HC(p, data->out + 4,
+ (int)length, (int)data->block_size,
+ data->compression_level);
+#else
+ outsize = LZ4_compressHC2_limitedOutput(p, data->out + 4,
+ (int)length, (int)data->block_size,
+ data->compression_level);
+#endif
+ else
+#endif
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ outsize = LZ4_compress_default(p, data->out + 4,
+ (int)length, (int)data->block_size);
+#else
+ outsize = LZ4_compress_limitedOutput(p, data->out + 4,
+ (int)length, (int)data->block_size);
+#endif
+
+ if (outsize) {
+ /* The buffer is compressed. */
+ archive_le32enc(data->out, outsize);
+ data->out += 4;
+ } else {
+ /* The buffer is not compressed. The compressed size was
+ * bigger than its uncompressed size. */
+ archive_le32enc(data->out, length | 0x80000000);
+ data->out += 4;
+ memcpy(data->out, p, length);
+ outsize = length;
+ }
+ data->out += outsize;
+ if (data->block_checksum) {
+ unsigned int checksum =
+ __archive_xxhash.XXH32(data->out - outsize, outsize, 0);
+ archive_le32enc(data->out, checksum);
+ data->out += 4;
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+drive_compressor_dependence(struct archive_write_filter *f, const char *p,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ int outsize;
+
+#define DICT_SIZE (64 * 1024)
+#ifdef HAVE_LZ4HC_H
+ if (data->compression_level >= 3) {
+ if (data->lz4_stream == NULL) {
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ data->lz4_stream = LZ4_createStreamHC();
+ LZ4_resetStreamHC(data->lz4_stream, data->compression_level);
+#else
+ data->lz4_stream =
+ LZ4_createHC(data->in_buffer_allocated);
+#endif
+ if (data->lz4_stream == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression"
+ " buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ else
+ LZ4_loadDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ outsize = LZ4_compress_HC_continue(
+ data->lz4_stream, p, data->out + 4, (int)length,
+ (int)data->block_size);
+#else
+ outsize = LZ4_compressHC2_limitedOutput_continue(
+ data->lz4_stream, p, data->out + 4, (int)length,
+ (int)data->block_size, data->compression_level);
+#endif
+ } else
+#endif
+ {
+ if (data->lz4_stream == NULL) {
+ data->lz4_stream = LZ4_createStream();
+ if (data->lz4_stream == NULL) {
+ archive_set_error(f->archive, ENOMEM,
+ "Can't allocate data for compression"
+ " buffer");
+ return (ARCHIVE_FATAL);
+ }
+ }
+ else
+ LZ4_loadDict(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ outsize = LZ4_compress_fast_continue(
+ data->lz4_stream, p, data->out + 4, (int)length,
+ (int)data->block_size, 1);
+#else
+ outsize = LZ4_compress_limitedOutput_continue(
+ data->lz4_stream, p, data->out + 4, (int)length,
+ (int)data->block_size);
+#endif
+ }
+
+ if (outsize) {
+ /* The buffer is compressed. */
+ archive_le32enc(data->out, outsize);
+ data->out += 4;
+ } else {
+ /* The buffer is not compressed. The compressed size was
+ * bigger than its uncompressed size. */
+ archive_le32enc(data->out, length | 0x80000000);
+ data->out += 4;
+ memcpy(data->out, p, length);
+ outsize = length;
+ }
+ data->out += outsize;
+ if (data->block_checksum) {
+ unsigned int checksum =
+ __archive_xxhash.XXH32(data->out - outsize, outsize, 0);
+ archive_le32enc(data->out, checksum);
+ data->out += 4;
+ }
+
+ if (length == data->block_size) {
+#ifdef HAVE_LZ4HC_H
+ if (data->compression_level >= 3) {
+#if LZ4_VERSION_MAJOR >= 1 && LZ4_VERSION_MINOR >= 7
+ LZ4_saveDictHC(data->lz4_stream, data->in_buffer_allocated, DICT_SIZE);
+#else
+ LZ4_slideInputBufferHC(data->lz4_stream);
+#endif
+ data->in_buffer = data->in_buffer_allocated + DICT_SIZE;
+ }
+ else
+#endif
+ LZ4_saveDict(data->lz4_stream,
+ data->in_buffer_allocated, DICT_SIZE);
+#undef DICT_SIZE
+ }
+ return (ARCHIVE_OK);
+}
+
+#else /* HAVE_LIBLZ4 */
+
+static int
+archive_filter_lz4_open(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+ struct archive_string as;
+ int r;
+
+ archive_string_init(&as);
+ archive_strcpy(&as, "lz4 -z -q -q");
+
+ /* Specify a compression level. */
+ if (data->compression_level > 0) {
+ archive_strcat(&as, " -");
+ archive_strappend_char(&as, '0' + data->compression_level);
+ }
+ /* Specify a block size. */
+ archive_strcat(&as, " -B");
+ archive_strappend_char(&as, '0' + data->block_maximum_size);
+
+ if (data->block_checksum)
+ archive_strcat(&as, " -BX");
+ if (data->stream_checksum == 0)
+ archive_strcat(&as, " --no-frame-crc");
+ if (data->block_independence == 0)
+ archive_strcat(&as, " -BD");
+
+ f->write = archive_filter_lz4_write;
+
+ r = __archive_write_program_open(f, data->pdata, as.s);
+ archive_string_free(&as);
+ return (r);
+}
+
+static int
+archive_filter_lz4_write(struct archive_write_filter *f, const void *buff,
+ size_t length)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_write(f, data->pdata, buff, length);
+}
+
+static int
+archive_filter_lz4_close(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ return __archive_write_program_close(f, data->pdata);
+}
+
+static int
+archive_filter_lz4_free(struct archive_write_filter *f)
+{
+ struct private_data *data = (struct private_data *)f->data;
+
+ __archive_write_program_free(data->pdata);
+ free(data);
+ return (ARCHIVE_OK);
+}
+
+#endif /* HAVE_LIBLZ4 */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
index 088ecea51..ad705c4a0 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lzop.c
@@ -85,7 +85,7 @@ static int archive_write_lzop_free(struct archive_write_filter *);
#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
/* Maximum block size. */
#define BLOCK_SIZE (256 * 1024)
-/* Block infomation is composed of uncompressed size(4 bytes),
+/* Block information is composed of uncompressed size(4 bytes),
* compressed size(4 bytes) and the checksum of uncompressed data(4 bytes)
* in this lzop writer. */
#define BLOCK_INfO_SIZE 12
@@ -173,7 +173,7 @@ archive_write_add_filter_lzop(struct archive *_a)
data->compression_level = 5;
return (ARCHIVE_OK);
#else
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate("lzop");
if (data->pdata == NULL) {
free(data);
archive_set_error(_a, ENOMEM, "Can't allocate memory");
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c
index fc232da0c..55b5e8ecd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c
@@ -68,6 +68,7 @@ struct archive_write_program_data {
char *child_buf;
size_t child_buf_len, child_buf_avail;
+ char *program_name;
};
struct private_data {
@@ -105,7 +106,7 @@ archive_write_add_filter_program(struct archive *_a, const char *cmd)
if (data->cmd == NULL)
goto memerr;
- data->pdata = __archive_write_program_allocate();
+ data->pdata = __archive_write_program_allocate(cmd);
if (data->pdata == NULL)
goto memerr;
@@ -174,7 +175,7 @@ archive_compressor_program_free(struct archive_write_filter *f)
* Allocate resources for executing an external program.
*/
struct archive_write_program_data *
-__archive_write_program_allocate(void)
+__archive_write_program_allocate(const char *program)
{
struct archive_write_program_data *data;
@@ -183,6 +184,7 @@ __archive_write_program_allocate(void)
return (data);
data->child_stdin = -1;
data->child_stdout = -1;
+ data->program_name = strdup(program);
return (data);
}
@@ -198,6 +200,7 @@ __archive_write_program_free(struct archive_write_program_data *data)
if (data->child)
CloseHandle(data->child);
#endif
+ free(data->program_name);
free(data->child_buf);
free(data);
}
@@ -231,7 +234,7 @@ __archive_write_program_open(struct archive_write_filter *f,
&data->child_stdout);
if (child == -1) {
archive_set_error(f->archive, EINVAL,
- "Can't initialise filter");
+ "Can't launch external program: %s", cmd);
return (ARCHIVE_FATAL);
}
#if defined(_WIN32) && !defined(__CYGWIN__)
@@ -242,7 +245,7 @@ __archive_write_program_open(struct archive_write_filter *f,
close(data->child_stdout);
data->child_stdout = -1;
archive_set_error(f->archive, EINVAL,
- "Can't initialise filter");
+ "Can't launch external program: %s", cmd);
return (ARCHIVE_FATAL);
}
#else
@@ -334,7 +337,7 @@ __archive_write_program_write(struct archive_write_filter *f,
ret = child_write(f, data, buf, length);
if (ret == -1 || ret == 0) {
archive_set_error(f->archive, EIO,
- "Can't write to filter");
+ "Can't write to program: %s", data->program_name);
return (ARCHIVE_FATAL);
}
length -= ret;
@@ -373,7 +376,7 @@ __archive_write_program_close(struct archive_write_filter *f,
if (bytes_read == -1) {
archive_set_error(f->archive, errno,
- "Read from filter failed unexpectedly.");
+ "Error reading from program: %s", data->program_name);
ret = ARCHIVE_FATAL;
goto cleanup;
}
@@ -403,7 +406,7 @@ cleanup:
if (status != 0) {
archive_set_error(f->archive, EIO,
- "Filter exited with failure.");
+ "Error closing program: %s", data->program_name);
ret = ARCHIVE_FATAL;
}
r1 = __archive_write_close_filter(f->next_filter);
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c
index fa73311e7..e4a353591 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c
@@ -39,7 +39,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_compression_xz.c 20110
#endif
#include <time.h>
#ifdef HAVE_LZMA_H
-#include <lzma.h>
+#include <cm_lzma.h>
#endif
#include "archive.h"
@@ -100,6 +100,7 @@ archive_write_add_filter_lzip(struct archive *a)
struct private_data {
int compression_level;
+ uint32_t threads;
lzma_stream stream;
lzma_filter lzmafilters[2];
lzma_options_lzma lzma_opt;
@@ -151,6 +152,7 @@ common_setup(struct archive_write_filter *f)
}
f->data = data;
data->compression_level = LZMA_PRESET_DEFAULT;
+ data->threads = 1;
f->open = &archive_compressor_xz_open;
f->close = archive_compressor_xz_close;
f->free = archive_compressor_xz_free;
@@ -221,23 +223,37 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f,
{
static const lzma_stream lzma_stream_init_data = LZMA_STREAM_INIT;
int ret;
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ lzma_mt mt_options;
+#endif
data->stream = lzma_stream_init_data;
data->stream.next_out = data->compressed;
data->stream.avail_out = data->compressed_buffer_size;
- if (f->code == ARCHIVE_FILTER_XZ)
- ret = lzma_stream_encoder(&(data->stream),
- data->lzmafilters, LZMA_CHECK_CRC64);
- else if (f->code == ARCHIVE_FILTER_LZMA)
+ if (f->code == ARCHIVE_FILTER_XZ) {
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ if (data->threads != 1) {
+ memset(&mt_options, 0, sizeof(mt_options));
+ mt_options.threads = data->threads;
+ mt_options.timeout = 300;
+ mt_options.filters = data->lzmafilters;
+ mt_options.check = LZMA_CHECK_CRC64;
+ ret = lzma_stream_encoder_mt(&(data->stream),
+ &mt_options);
+ } else
+#endif
+ ret = lzma_stream_encoder(&(data->stream),
+ data->lzmafilters, LZMA_CHECK_CRC64);
+ } else if (f->code == ARCHIVE_FILTER_LZMA) {
ret = lzma_alone_encoder(&(data->stream), &data->lzma_opt);
- else { /* ARCHIVE_FILTER_LZIP */
+ } else { /* ARCHIVE_FILTER_LZIP */
int dict_size = data->lzma_opt.dict_size;
int ds, log2dic, wedges;
/* Calculate a coded dictionary size */
if (dict_size < (1 << 12) || dict_size > (1 << 27)) {
archive_set_error(f->archive, ARCHIVE_ERRNO_MISC,
- "Unacceptable dictionary dize for lzip: %d",
+ "Unacceptable dictionary size for lzip: %d",
dict_size);
return (ARCHIVE_FATAL);
}
@@ -373,6 +389,22 @@ archive_compressor_xz_options(struct archive_write_filter *f,
if (data->compression_level > 6)
data->compression_level = 6;
return (ARCHIVE_OK);
+ } else if (strcmp(key, "threads") == 0) {
+ if (value == NULL)
+ return (ARCHIVE_WARN);
+ data->threads = (int)strtoul(value, NULL, 10);
+ if (data->threads == 0 && errno != 0) {
+ data->threads = 1;
+ return (ARCHIVE_WARN);
+ }
+ if (data->threads == 0) {
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ data->threads = lzma_cputhreads();
+#else
+ data->threads = 1;
+#endif
+ }
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_data.3 b/Utilities/cmlibarchive/libarchive/archive_write_data.3
index cfd5cd552..0cdd25f1f 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_data.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_data.3
@@ -34,7 +34,7 @@
Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
-.Ft ssize_t
+.Ft la_ssize_t
.Fn archive_write_data "struct archive *" "const void *" "size_t"
.Sh DESCRIPTION
Write data corresponding to the header just written.
@@ -42,8 +42,7 @@ Write data corresponding to the header just written.
.\"
.Sh RETURN VALUES
This function returns the number of bytes actually written, or
-.Li -1
-on error.
+a negative error code on error.
.\"
.Sh ERRORS
Detailed error codes and textual descriptions are available from the
@@ -52,6 +51,15 @@ and
.Fn archive_error_string
functions.
.\"
+.Sh BUGS
+In libarchive 3.x, this function sometimes returns
+zero on success instead of returning the number of bytes written.
+Specifically, this occurs when writing to an
+.Vt archive_write_disk
+handle.
+Clients should treat any value less than zero as an error
+and consider any non-negative value as success.
+.\"
.Sh SEE ALSO
.Xr tar 1 ,
.Xr libarchive 3 ,
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk.3 b/Utilities/cmlibarchive/libarchive/archive_write_disk.3
index fa925cc54..ba6c9706e 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk.3
@@ -70,9 +70,9 @@ Streaming Archive Library (libarchive, -larchive)
.Fc
.Ft int
.Fn archive_write_header "struct archive *" "struct archive_entry *"
-.Ft ssize_t
+.Ft la_ssize_t
.Fn archive_write_data "struct archive *" "const void *" "size_t"
-.Ft ssize_t
+.Ft la_ssize_t
.Fn archive_write_data_block "struct archive *" "const void *" "size_t size" "int64_t offset"
.Ft int
.Fn archive_write_finish_entry "struct archive *"
@@ -177,10 +177,16 @@ The default is to not refuse such paths.
Note that paths ending in
.Pa ..
always cause an error, regardless of this flag.
+.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+Refuse to extract an absolute path.
+The default is to not refuse such paths.
.It Cm ARCHIVE_EXTRACT_SPARSE
Scan data for blocks of NUL bytes and try to recreate them with holes.
This results in sparse files, independent of whether the archive format
supports or uses them.
+.It Cm ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS
+Before removing a file system object prior to replacing it, clear
+platform-specific file flags which might prevent its removal.
.El
.It Xo
.Fn archive_write_disk_set_group_lookup ,
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
index 97972033c..144ab7e72 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c
@@ -34,6 +34,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0
#define _ACL_PRIVATE /* For debugging */
#include <sys/acl.h>
#endif
+#if HAVE_DARWIN_ACL
+#include <membership.h>
+#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -43,7 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0
#include "archive_acl_private.h"
#include "archive_write_disk_private.h"
-#if !defined(HAVE_POSIX_ACL) || !defined(ACL_TYPE_NFS4)
+#if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL
/* Default empty function body to satisfy mainline code. */
int
archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
@@ -56,44 +59,111 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
return (ARCHIVE_OK);
}
-#else
+#else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
+
+#if HAVE_SUN_ACL
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T
+#elif HAVE_DARWIN_ACL
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+#elif HAVE_ACL_TYPE_NFS4
+#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4
+#endif
static int set_acl(struct archive *, int fd, const char *,
struct archive_acl *,
acl_type_t, int archive_entry_acl_type, const char *tn);
-/*
- * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
- */
int
archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
struct archive_acl *abstract_acl)
{
- int ret;
+ int ret = ARCHIVE_OK;
- if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) {
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
- if (ret != ARCHIVE_OK)
- return (ret);
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
+#if !HAVE_DARWIN_ACL
+ if ((archive_acl_types(abstract_acl)
+ & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+#if HAVE_SUN_ACL
+ /* Solaris writes POSIX.1e access and default ACLs together */
+ ret = set_acl(a, fd, name, abstract_acl, ACLENT_T,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
+#else /* HAVE_POSIX_ACL */
+ if ((archive_acl_types(abstract_acl)
+ & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ ret = set_acl(a, fd, name, abstract_acl,
+ ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ "access");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+ if ((archive_acl_types(abstract_acl)
+ & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ ret = set_acl(a, fd, name, abstract_acl,
+ ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+ "default");
+#endif /* !HAVE_SUN_ACL */
+ /* Simultaneous POSIX.1e and NFSv4 is not supported */
return (ret);
- } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) {
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4,
+ }
+#endif /* !HAVE_DARWIN_ACL */
+#if HAVE_NFS4_ACL
+ if ((archive_acl_types(abstract_acl) &
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ ret = set_acl(a, fd, name, abstract_acl,
+ ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
- return (ret);
- } else
- return ARCHIVE_OK;
+ }
+#endif /* HAVE_NFS4_ACL */
+ return (ret);
}
-static struct {
- int archive_perm;
- int platform_perm;
+/*
+ * Translate system ACL permissions into libarchive internal structure
+ */
+static const struct {
+ const int archive_perm;
+ const int platform_perm;
} acl_perm_map[] = {
+#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
+#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#else /* POSIX.1e ACL permissions */
{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
{ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
{ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */
{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
@@ -110,29 +180,70 @@ static struct {
{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#endif
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
};
-static struct {
- int archive_inherit;
- int platform_inherit;
+#if HAVE_NFS4_ACL
+/*
+ * Translate system NFSv4 inheritance flags into libarchive internal structure
+ */
+static const struct {
+ const int archive_inherit;
+ const int platform_inherit;
} acl_inherit_map[] = {
+#if HAVE_SUN_ACL /* Solaris NFSv4 inheritance flags */
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
+ {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
+#else /* FreeBSD NFSv4 ACL inheritance flags */
{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
+ {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
+ {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
};
+#endif /* HAVE_NFS4_ACL */
static int
set_acl(struct archive *a, int fd, const char *name,
struct archive_acl *abstract_acl,
acl_type_t acl_type, int ae_requested_type, const char *tname)
{
+#if HAVE_SUN_ACL
+ aclent_t *aclent;
+ ace_t *ace;
+ int e, r;
+ acl_t *acl;
+#else
acl_t acl;
acl_entry_t acl_entry;
acl_permset_t acl_permset;
+#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
acl_flagset_t acl_flagset;
+#endif
+#endif /* HAVE_SUN_ACL */
+#if HAVE_ACL_TYPE_NFS4
+ int r;
+#endif
int ret;
int ae_type, ae_permset, ae_tag, ae_id;
+#if HAVE_DARWIN_ACL
+ uuid_t ae_uuid;
+#endif
uid_t ae_uid;
gid_t ae_gid;
const char *ae_name;
@@ -143,22 +254,165 @@ set_acl(struct archive *a, int fd, const char *name,
entries = archive_acl_reset(abstract_acl, ae_requested_type);
if (entries == 0)
return (ARCHIVE_OK);
+
+#if HAVE_SUN_ACL
+ acl = NULL;
+ acl = malloc(sizeof(acl_t));
+ if (acl == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid ACL type");
+ return (ARCHIVE_FAILED);
+ }
+ if (acl_type == ACE_T)
+ acl->acl_entry_size = sizeof(ace_t);
+ else if (acl_type == ACLENT_T)
+ acl->acl_entry_size = sizeof(aclent_t);
+ else {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Invalid ACL type");
+ acl_free(acl);
+ return (ARCHIVE_FAILED);
+ }
+ acl->acl_type = acl_type;
+ acl->acl_cnt = entries;
+
+ acl->acl_aclp = malloc(entries * acl->acl_entry_size);
+ if (acl->acl_aclp == NULL) {
+ archive_set_error(a, errno,
+ "Can't allocate memory for acl buffer");
+ acl_free(acl);
+ return (ARCHIVE_FAILED);
+ }
+#else /* !HAVE_SUN_ACL */
acl = acl_init(entries);
+ if (acl == (acl_t)NULL) {
+ archive_set_error(a, errno,
+ "Failed to initialize ACL working storage");
+ return (ARCHIVE_FAILED);
+ }
+#endif /* !HAVE_SUN_ACL */
+#if HAVE_SUN_ACL
+ e = 0;
+#endif
while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
&ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
- acl_create_entry(&acl, &acl_entry);
-
+#if HAVE_SUN_ACL
+ ace = NULL;
+ aclent = NULL;
+ if (acl->acl_type == ACE_T) {
+ ace = &((ace_t *)acl->acl_aclp)[e];
+ ace->a_who = -1;
+ ace->a_access_mask = 0;
+ ace->a_flags = 0;
+ } else {
+ aclent = &((aclent_t *)acl->acl_aclp)[e];
+ aclent->a_id = -1;
+ aclent->a_type = 0;
+ aclent->a_perm = 0;
+ }
+#else /* !HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+ /*
+ * Mac OS doesn't support NFSv4 ACLs for
+ * owner@, group@ and everyone@.
+ * We skip any of these ACLs found.
+ */
+ if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||
+ ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||
+ ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)
+ continue;
+#endif
+ if (acl_create_entry(&acl, &acl_entry) != 0) {
+ archive_set_error(a, errno,
+ "Failed to create a new ACL entry");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif /* !HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+ switch (ae_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);
+ break;
+ default:
+ /* We don't support any other types on MacOS */
+ continue;
+ }
+#endif
switch (ae_tag) {
+#if HAVE_SUN_ACL
case ARCHIVE_ENTRY_ACL_USER:
- acl_set_tag_type(acl_entry, ACL_USER);
ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+ if (acl->acl_type == ACE_T)
+ ace->a_who = ae_uid;
+ else {
+ aclent->a_id = ae_uid;
+ aclent->a_type |= USER;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+ if (acl->acl_type == ACE_T) {
+ ace->a_who = ae_gid;
+ ace->a_flags |= ACE_IDENTIFIER_GROUP;
+ } else {
+ aclent->a_id = ae_gid;
+ aclent->a_type |= GROUP;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ if (acl->acl_type == ACE_T)
+ ace->a_flags |= ACE_OWNER;
+ else
+ aclent->a_type |= USER_OBJ;
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (acl->acl_type == ACE_T) {
+ ace->a_flags |= ACE_GROUP;
+ ace->a_flags |= ACE_IDENTIFIER_GROUP;
+ } else
+ aclent->a_type |= GROUP_OBJ;
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ aclent->a_type |= CLASS_OBJ;
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ aclent->a_type |= OTHER_OBJ;
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ ace->a_flags |= ACE_EVERYONE;
+ break;
+#else /* !HAVE_SUN_ACL */
+ case ARCHIVE_ENTRY_ACL_USER:
+ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+ acl_set_tag_type(acl_entry, ACL_USER);
acl_set_qualifier(acl_entry, &ae_uid);
+#else /* MacOS */
+ if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid,
+ sizeof(uid_t), ae_uuid) != 0)
+ continue;
+ if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
+ continue;
+#endif /* HAVE_DARWIN_ACL */
break;
case ARCHIVE_ENTRY_ACL_GROUP:
- acl_set_tag_type(acl_entry, ACL_GROUP);
ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+ acl_set_tag_type(acl_entry, ACL_GROUP);
acl_set_qualifier(acl_entry, &ae_gid);
+#else /* MacOS */
+ if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid,
+ sizeof(gid_t), ae_uuid) != 0)
+ continue;
+ if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
+ continue;
+#endif /* HAVE_DARWIN_ACL */
break;
+#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
case ARCHIVE_ENTRY_ACL_USER_OBJ:
acl_set_tag_type(acl_entry, ACL_USER_OBJ);
break;
@@ -171,79 +425,230 @@ set_acl(struct archive *a, int fd, const char *name,
case ARCHIVE_ENTRY_ACL_OTHER:
acl_set_tag_type(acl_entry, ACL_OTHER);
break;
+#if HAVE_ACL_TYPE_NFS4 /* FreeBSD only */
case ARCHIVE_ENTRY_ACL_EVERYONE:
acl_set_tag_type(acl_entry, ACL_EVERYONE);
break;
+#endif
+#endif /* !HAVE_DARWIN_ACL */
+#endif /* !HAVE_SUN_ACL */
default:
- /* XXX */
- break;
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL tag");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
}
+#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+ r = 0;
switch (ae_type) {
+#if HAVE_SUN_ACL
case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
+ if (ace != NULL)
+ ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+ else
+ r = -1;
break;
case ARCHIVE_ENTRY_ACL_TYPE_DENY:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
+ if (ace != NULL)
+ ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+ else
+ r = -1;
break;
case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
+ if (ace != NULL)
+ ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
+ else
+ r = -1;
break;
case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
- acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
+ if (ace != NULL)
+ ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
+ else
+ r = -1;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ if (aclent == NULL)
+ r = -1;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ if (aclent != NULL)
+ aclent->a_type |= ACL_DEFAULT;
+ else
+ r = -1;
+ break;
+#else /* !HAVE_SUN_ACL */
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
break;
case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
// These don't translate directly into the system ACL.
break;
+#endif /* !HAVE_SUN_ACL */
default:
- // XXX error handling here.
- break;
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL entry type");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
}
- acl_get_permset(acl_entry, &acl_permset);
- acl_clear_perms(acl_permset);
+ if (r != 0) {
+#if HAVE_SUN_ACL
+ errno = EINVAL;
+#endif
+ archive_set_error(a, errno,
+ "Failed to set ACL entry type");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+#if HAVE_SUN_ACL
+ if (acl->acl_type == ACLENT_T) {
+ if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
+ aclent->a_perm |= 1;
+ if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
+ aclent->a_perm |= 2;
+ if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
+ aclent->a_perm |= 4;
+ } else
+#else
+ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
+ archive_set_error(a, errno,
+ "Failed to get ACL permission set");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+ if (acl_clear_perms(acl_permset) != 0) {
+ archive_set_error(a, errno,
+ "Failed to clear ACL permissions");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif /* !HAVE_SUN_ACL */
for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
- if (ae_permset & acl_perm_map[i].archive_perm)
- acl_add_perm(acl_permset,
- acl_perm_map[i].platform_perm);
+ if (ae_permset & acl_perm_map[i].archive_perm) {
+#if HAVE_SUN_ACL
+ ace->a_access_mask |=
+ acl_perm_map[i].platform_perm;
+#else
+ if (acl_add_perm(acl_permset,
+ acl_perm_map[i].platform_perm) != 0) {
+ archive_set_error(a, errno,
+ "Failed to add ACL permission");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif
+ }
}
- acl_get_flagset_np(acl_entry, &acl_flagset);
- acl_clear_flags_np(acl_flagset);
- for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
- if (ae_permset & acl_inherit_map[i].archive_inherit)
- acl_add_flag_np(acl_flagset,
- acl_inherit_map[i].platform_inherit);
+#if HAVE_NFS4_ACL
+#if HAVE_SUN_ACL
+ if (acl_type == ACE_T)
+#elif HAVE_DARWIN_ACL
+ if (acl_type == ACL_TYPE_EXTENDED)
+#else /* FreeBSD */
+ if (acl_type == ACL_TYPE_NFS4)
+#endif
+ {
+#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
+ /*
+ * acl_get_flagset_np() fails with non-NFSv4 ACLs
+ */
+ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
+ archive_set_error(a, errno,
+ "Failed to get flagset from an NFSv4 ACL entry");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+ if (acl_clear_flags_np(acl_flagset) != 0) {
+ archive_set_error(a, errno,
+ "Failed to clear flags from an NFSv4 ACL flagset");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
+ for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) {
+ if (ae_permset & acl_inherit_map[i].archive_inherit) {
+#if HAVE_SUN_ACL
+ ace->a_flags |=
+ acl_inherit_map[i].platform_inherit;
+#else /* !HAVE_SUN_ACL */
+ if (acl_add_flag_np(acl_flagset,
+ acl_inherit_map[i].platform_inherit) != 0) {
+ archive_set_error(a, errno,
+ "Failed to add flag to NFSv4 ACL flagset");
+ ret = ARCHIVE_FAILED;
+ goto exit_free;
+ }
+#endif /* HAVE_SUN_ACL */
+ }
+ }
}
+#endif /* HAVE_NFS4_ACL */
+#if HAVE_SUN_ACL
+ e++;
+#endif
}
+#if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL
/* Try restoring the ACL through 'fd' if we can. */
-#if HAVE_ACL_SET_FD
- if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
- ret = ARCHIVE_OK;
- else
-#else
-#if HAVE_ACL_SET_FD_NP
- if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
- ret = ARCHIVE_OK;
- else
+#if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP
+ if (fd >= 0)
+#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
+ if (fd >= 0 && acl_type == ACL_TYPE_ACCESS)
#endif
+ {
+#if HAVE_SUN_ACL
+ if (facl_set(fd, acl) == 0)
+#elif HAVE_ACL_SET_FD_NP
+ if (acl_set_fd_np(fd, acl, acl_type) == 0)
+#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
+ if (acl_set_fd(fd, acl) == 0)
#endif
-#if HAVE_ACL_SET_LINK_NP
- if (acl_set_link_np(name, acl_type, acl) != 0) {
- archive_set_error(a, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
+ ret = ARCHIVE_OK;
+ else {
+ if (errno == EOPNOTSUPP) {
+ /* Filesystem doesn't support ACLs */
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(a, errno,
+ "Failed to set %s acl on fd", tname);
+ }
+ }
+ } else
+#endif /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */
+#if HAVE_SUN_ACL
+ if (acl_set(name, acl) != 0)
+#elif HAVE_ACL_SET_LINK_NP
+ if (acl_set_link_np(name, acl_type, acl) != 0)
#else
/* TODO: Skip this if 'name' is a symlink. */
- if (acl_set_file(name, acl_type, acl) != 0) {
- archive_set_error(a, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
+ if (acl_set_file(name, acl_type, acl) != 0)
#endif
+ {
+ if (errno == EOPNOTSUPP) {
+ /* Filesystem doesn't support ACLs */
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(a, errno, "Failed to set %s acl",
+ tname);
+ ret = ARCHIVE_WARN;
+ }
+ }
+exit_free:
acl_free(acl);
return (ret);
}
-#endif
+#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
index b69c8739d..a5f30671a 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c
@@ -110,6 +110,18 @@ __FBSDID("$FreeBSD$");
#include <sys/fcntl1.h>
#endif
+/*
+ * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared.
+ *
+ * It assumes that the input is an integer type of no more than 64 bits.
+ * If the number is less than zero, t must be a signed type, so it fits in
+ * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t
+ * without loss. But it could be a large unsigned value, so we have to clip it
+ * to INT64_MAX.*
+ */
+#define to_int64_time(t) \
+ ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t))
+
#if __APPLE__
#include <TargetConditionals.h>
#if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H
@@ -140,7 +152,17 @@ __FBSDID("$FreeBSD$");
#define O_BINARY 0
#endif
#ifndef O_CLOEXEC
-#define O_CLOEXEC 0
+#define O_CLOEXEC 0
+#endif
+
+/* Ignore non-int O_NOFOLLOW constant. */
+/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */
+#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX)
+#undef O_NOFOLLOW
+#endif
+
+#ifndef O_NOFOLLOW
+#define O_NOFOLLOW 0
#endif
struct fixup_entry {
@@ -298,7 +320,7 @@ struct archive_write_disk {
#define MAXIMUM_DIR_MODE 0775
/*
- * Maxinum uncompressed size of a decmpfs block.
+ * Maximum uncompressed size of a decmpfs block.
*/
#define MAX_DECMPFS_BLOCK_SIZE (64 * 1024)
/*
@@ -313,7 +335,7 @@ struct archive_write_disk {
#define RSRC_F_SIZE 50 /* Size of Resource fork footer. */
/* Size to write compressed data to resource fork. */
#define COMPRESSED_W_SIZE (64 * 1024)
-/* decmpfs difinitions. */
+/* decmpfs definitions. */
#define MAX_DECMPFS_XATTR_SIZE 3802
#ifndef DECMPFS_XATTR_NAME
#define DECMPFS_XATTR_NAME "com.apple.decmpfs"
@@ -326,12 +348,19 @@ struct archive_write_disk {
#define HFS_BLOCKS(s) ((s) >> 12)
+static void fsobj_error(int *, struct archive_string *, int, const char *,
+ const char *);
+static int check_symlinks_fsobj(char *, int *, struct archive_string *,
+ int);
static int check_symlinks(struct archive_write_disk *);
static int create_filesystem_object(struct archive_write_disk *);
-static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
+static struct fixup_entry *current_fixup(struct archive_write_disk *,
+ const char *pathname);
#if defined(HAVE_FCHDIR) && defined(PATH_MAX)
static void edit_deep_directories(struct archive_write_disk *ad);
#endif
+static int cleanup_pathname_fsobj(char *, int *, struct archive_string *,
+ int);
static int cleanup_pathname(struct archive_write_disk *);
static int create_dir(struct archive_write_disk *, char *);
static int create_parent_dir(struct archive_write_disk *, char *);
@@ -343,6 +372,7 @@ static int restore_entry(struct archive_write_disk *);
static int set_mac_metadata(struct archive_write_disk *, const char *,
const void *, size_t);
static int set_xattrs(struct archive_write_disk *);
+static int clear_nochange_fflags(struct archive_write_disk *);
static int set_fflags(struct archive_write_disk *);
static int set_fflags_platform(struct archive_write_disk *, int fd,
const char *name, mode_t mode,
@@ -361,11 +391,14 @@ static struct archive_vtable *archive_write_disk_vtable(void);
static int _archive_write_disk_close(struct archive *);
static int _archive_write_disk_free(struct archive *);
-static int _archive_write_disk_header(struct archive *, struct archive_entry *);
+static int _archive_write_disk_header(struct archive *,
+ struct archive_entry *);
static int64_t _archive_write_disk_filter_bytes(struct archive *, int);
static int _archive_write_disk_finish_entry(struct archive *);
-static ssize_t _archive_write_disk_data(struct archive *, const void *, size_t);
-static ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t);
+static ssize_t _archive_write_disk_data(struct archive *, const void *,
+ size_t);
+static ssize_t _archive_write_disk_data_block(struct archive *, const void *,
+ size_t, int64_t);
static int
lazy_stat(struct archive_write_disk *a)
@@ -611,9 +644,9 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
/*
* NOTE: UF_COMPRESSED is ignored even if the filesystem
* supports HFS+ Compression because the file should
- * have at least an extended attriute "com.apple.decmpfs"
+ * have at least an extended attribute "com.apple.decmpfs"
* before the flag is set to indicate that the file have
- * been compressed. If hte filesystem does not support
+ * been compressed. If the filesystem does not support
* HFS+ Compression the system call will fail.
*/
if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0)
@@ -636,7 +669,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
if (a->restore_pwd >= 0) {
r = fchdir(a->restore_pwd);
if (r != 0) {
- archive_set_error(&a->archive, errno, "chdir() failure");
+ archive_set_error(&a->archive, errno,
+ "chdir() failure");
ret = ARCHIVE_FATAL;
}
close(a->restore_pwd);
@@ -684,7 +718,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
}
if (archive_entry_birthtime_is_set(entry)) {
fe->birthtime = archive_entry_birthtime(entry);
- fe->birthtime_nanos = archive_entry_birthtime_nsec(entry);
+ fe->birthtime_nanos = archive_entry_birthtime_nsec(
+ entry);
} else {
/* If birthtime is unset, use mtime. */
fe->birthtime = fe->mtime;
@@ -710,7 +745,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
return (ARCHIVE_FATAL);
fe->mac_metadata = malloc(metadata_size);
if (fe->mac_metadata != NULL) {
- memcpy(fe->mac_metadata, metadata, metadata_size);
+ memcpy(fe->mac_metadata, metadata,
+ metadata_size);
fe->mac_metadata_size = metadata_size;
fe->fixup |= TODO_MAC_METADATA;
}
@@ -1223,7 +1259,7 @@ hfs_drive_compressor(struct archive_write_disk *a, const char *buff,
ret = hfs_write_compressed_data(a, bytes_used + rsrc_size);
a->compressed_buffer_remaining = a->compressed_buffer_size;
- /* If the compressed size is not enouph smaller than
+ /* If the compressed size is not enough smaller than
* the uncompressed size. cancel HFS+ compression.
* TODO: study a behavior of ditto utility and improve
* the condition to fall back into no HFS+ compression. */
@@ -1328,7 +1364,7 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff,
(uint32_t *)(a->resource_fork + RSRC_H_SIZE);
/* Set the block count to the resource fork. */
archive_le32enc(a->decmpfs_block_info++, block_count);
- /* Get the position where we are goint to set compressed
+ /* Get the position where we are going to set compressed
* data. */
a->compressed_rsrc_position =
RSRC_H_SIZE + 4 + (block_count * 8);
@@ -1401,7 +1437,7 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
bytes_to_write = size;
/* Seek if necessary to the specified offset. */
if (a->offset < a->fd_offset) {
- /* Can't support backword move. */
+ /* Can't support backward move. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Seek failed");
return (ARCHIVE_FATAL);
@@ -1467,10 +1503,15 @@ _archive_write_disk_data_block(struct archive *_a,
return (r);
if ((size_t)r < size) {
archive_set_error(&a->archive, 0,
- "Write request too large");
+ "Too much data: Truncating file at %ju bytes",
+ (uintmax_t)a->filesize);
return (ARCHIVE_WARN);
}
+#if ARCHIVE_VERSION_NUMBER < 3999000
return (ARCHIVE_OK);
+#else
+ return (size);
+#endif
}
static ssize_t
@@ -1661,10 +1702,26 @@ _archive_write_disk_finish_entry(struct archive *_a)
* ACLs that prevent attribute changes (including time).
*/
if (a->todo & TODO_ACLS) {
- int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
- archive_entry_pathname(a->entry),
- archive_entry_acl(a->entry));
+ int r2;
+#ifdef HAVE_DARWIN_ACL
+ /*
+ * On Mac OS, platform ACLs are stored also in mac_metadata by
+ * the operating system. If mac_metadata is present it takes
+ * precedence and we skip extracting libarchive NFSv4 ACLs
+ */
+ const void *metadata;
+ size_t metadata_size;
+ metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
+ if ((a->todo & TODO_MAC_METADATA) == 0 ||
+ metadata == NULL || metadata_size == 0) {
+#endif
+ r2 = archive_write_disk_set_acls(&a->archive, a->fd,
+ archive_entry_pathname(a->entry),
+ archive_entry_acl(a->entry));
if (r2 < ret) ret = r2;
+#ifdef HAVE_DARWIN_ACL
+ }
+#endif
}
finish_metadata:
@@ -1750,10 +1807,9 @@ archive_write_disk_new(void)
{
struct archive_write_disk *a;
- a = (struct archive_write_disk *)malloc(sizeof(*a));
+ a = (struct archive_write_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
@@ -1791,7 +1847,7 @@ edit_deep_directories(struct archive_write_disk *a)
char *tail = a->name;
/* If path is short, avoid the open() below. */
- if (strlen(tail) <= PATH_MAX)
+ if (strlen(tail) < PATH_MAX)
return;
/* Try to record our starting dir. */
@@ -1801,7 +1857,7 @@ edit_deep_directories(struct archive_write_disk *a)
return;
/* As long as the path is too long... */
- while (strlen(tail) > PATH_MAX) {
+ while (strlen(tail) >= PATH_MAX) {
/* Locate a dir prefix shorter than PATH_MAX. */
tail += PATH_MAX - 8;
while (tail > a->name && *tail != '/')
@@ -1842,6 +1898,8 @@ restore_entry(struct archive_write_disk *a)
* object is a dir, but that doesn't mean the old
* object isn't a dir.
*/
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (unlink(a->name) == 0) {
/* We removed it, reset cached stat. */
a->pst = NULL;
@@ -1869,6 +1927,13 @@ restore_entry(struct archive_write_disk *a)
en = create_filesystem_object(a);
}
+ if ((en == ENOENT) && (archive_entry_hardlink(a->entry) != NULL)) {
+ archive_set_error(&a->archive, en,
+ "Hard-link target '%s' does not exist.",
+ archive_entry_hardlink(a->entry));
+ return (ARCHIVE_FAILED);
+ }
+
if ((en == EISDIR || en == EEXIST)
&& (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
@@ -1940,6 +2005,8 @@ restore_entry(struct archive_write_disk *a)
if (!S_ISDIR(a->st.st_mode)) {
/* A non-dir is in the way, unlink it. */
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (unlink(a->name) != 0) {
archive_set_error(&a->archive, errno,
"Can't unlink already-existing object");
@@ -1950,6 +2017,8 @@ restore_entry(struct archive_write_disk *a)
en = create_filesystem_object(a);
} else if (!S_ISDIR(a->mode)) {
/* A dir is in the way of a non-dir, rmdir it. */
+ if (a->flags & ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS)
+ (void)clear_nochange_fflags(a);
if (rmdir(a->name) != 0) {
archive_set_error(&a->archive, errno,
"Can't replace existing directory with non-directory");
@@ -1975,8 +2044,9 @@ restore_entry(struct archive_write_disk *a)
if (en) {
/* Everything failed; give up here. */
- archive_set_error(&a->archive, en, "Can't create '%s'",
- a->name);
+ if ((&a->archive)->error == NULL)
+ archive_set_error(&a->archive, en, "Can't create '%s'",
+ a->name);
return (ARCHIVE_FAILED);
}
@@ -1996,6 +2066,11 @@ create_filesystem_object(struct archive_write_disk *a)
const char *linkname;
mode_t final_mode, mode;
int r;
+ /* these for check_symlinks_fsobj */
+ char *linkname_copy; /* non-const copy of linkname */
+ struct stat st;
+ struct archive_string error_string;
+ int error_number;
/* We identify hard/symlinks according to the link names. */
/* Since link(2) and symlink(2) don't handle modes, we're done here. */
@@ -2004,6 +2079,43 @@ create_filesystem_object(struct archive_write_disk *a)
#if !HAVE_LINK
return (EPERM);
#else
+ archive_string_init(&error_string);
+ linkname_copy = strdup(linkname);
+ if (linkname_copy == NULL) {
+ return (EPERM);
+ }
+ /*
+ * TODO: consider using the cleaned-up path as the link
+ * target?
+ */
+ r = cleanup_pathname_fsobj(linkname_copy, &error_number,
+ &error_string, a->flags);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ free(linkname_copy);
+ archive_string_free(&error_string);
+ /*
+ * EPERM is more appropriate than error_number for our
+ * callers
+ */
+ return (EPERM);
+ }
+ r = check_symlinks_fsobj(linkname_copy, &error_number,
+ &error_string, a->flags);
+ if (r != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ free(linkname_copy);
+ archive_string_free(&error_string);
+ /*
+ * EPERM is more appropriate than error_number for our
+ * callers
+ */
+ return (EPERM);
+ }
+ free(linkname_copy);
+ archive_string_free(&error_string);
r = link(linkname, a->name) ? errno : 0;
/*
* New cpio and pax formats allow hardlink entries
@@ -2021,11 +2133,20 @@ create_filesystem_object(struct archive_write_disk *a)
a->todo = 0;
a->deferred = 0;
} else if (r == 0 && a->filesize > 0) {
- a->fd = open(a->name,
- O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC);
- __archive_ensure_cloexec_flag(a->fd);
- if (a->fd < 0)
+#ifdef HAVE_LSTAT
+ r = lstat(a->name, &st);
+#else
+ r = stat(a->name, &st);
+#endif
+ if (r != 0)
r = errno;
+ else if ((st.st_mode & AE_IFMT) == AE_IFREG) {
+ a->fd = open(a->name, O_WRONLY | O_TRUNC |
+ O_BINARY | O_CLOEXEC | O_NOFOLLOW);
+ __archive_ensure_cloexec_flag(a->fd);
+ if (a->fd < 0)
+ r = errno;
+ }
}
return (r);
#endif
@@ -2172,8 +2293,13 @@ _archive_write_disk_close(struct archive *_a)
if (p->fixup & TODO_MODE_BASE)
chmod(p->name, p->mode);
if (p->fixup & TODO_ACLS)
- archive_write_disk_set_acls(&a->archive,
- -1, p->name, &p->acl);
+#ifdef HAVE_DARWIN_ACL
+ if ((p->fixup & TODO_MAC_METADATA) == 0 ||
+ p->mac_metadata == NULL ||
+ p->mac_metadata_size == 0)
+#endif
+ archive_write_disk_set_acls(&a->archive,
+ -1, p->name, &p->acl);
if (p->fixup & TODO_FFLAGS)
set_fflags_platform(a, -1, p->name,
p->mode, p->fflags_set, 0);
@@ -2215,7 +2341,8 @@ _archive_write_disk_free(struct archive *_a)
free(a->resource_fork);
free(a->compressed_buffer);
free(a->uncompressed_buffer);
-#ifdef HAVE_ZLIB_H
+#if defined(__APPLE__) && defined(UF_COMPRESSED) && defined(HAVE_SYS_XATTR_H)\
+ && defined(HAVE_ZLIB_H)
if (a->stream_valid) {
switch (deflateEnd(&a->stream)) {
case Z_OK:
@@ -2332,110 +2459,283 @@ current_fixup(struct archive_write_disk *a, const char *pathname)
return (a->current_fixup);
}
-/* TODO: Make this work. */
-/*
- * TODO: The deep-directory support bypasses this; disable deep directory
- * support if we're doing symlink checks.
- */
+/* Error helper for new *_fsobj functions */
+static void
+fsobj_error(int *a_eno, struct archive_string *a_estr,
+ int err, const char *errstr, const char *path)
+{
+ if (a_eno)
+ *a_eno = err;
+ if (a_estr)
+ archive_string_sprintf(a_estr, errstr, path);
+}
+
/*
* TODO: Someday, integrate this with the deep dir support; they both
* scan the path and both can be optimized by comparing against other
* recent paths.
*/
/* TODO: Extend this to support symlinks on Windows Vista and later. */
+
+/*
+ * Checks the given path to see if any elements along it are symlinks. Returns
+ * ARCHIVE_OK if there are none, otherwise puts an error in errmsg.
+ */
static int
-check_symlinks(struct archive_write_disk *a)
+check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ int flags)
{
#if !defined(HAVE_LSTAT)
/* Platform doesn't have lstat, so we can't look for symlinks. */
- (void)a; /* UNUSED */
+ (void)path; /* UNUSED */
+ (void)error_number; /* UNUSED */
+ (void)error_string; /* UNUSED */
+ (void)flags; /* UNUSED */
return (ARCHIVE_OK);
#else
- char *pn;
+ int res = ARCHIVE_OK;
+ char *tail;
+ char *head;
+ int last;
char c;
int r;
struct stat st;
+ int restore_pwd;
+
+ /* Nothing to do here if name is empty */
+ if(path[0] == '\0')
+ return (ARCHIVE_OK);
/*
* Guard against symlink tricks. Reject any archive entry whose
* destination would be altered by a symlink.
+ *
+ * Walk the filename in chunks separated by '/'. For each segment:
+ * - if it doesn't exist, continue
+ * - if it's symlink, abort or remove it
+ * - if it's a directory and it's not the last chunk, cd into it
+ * As we go:
+ * head points to the current (relative) path
+ * tail points to the temporary \0 terminating the segment we're
+ * currently examining
+ * c holds what used to be in *tail
+ * last is 1 if this is the last tail
*/
- /* Whatever we checked last time doesn't need to be re-checked. */
- pn = a->name;
- if (archive_strlen(&(a->path_safe)) > 0) {
- char *p = a->path_safe.s;
- while ((*pn != '\0') && (*p == *pn))
- ++p, ++pn;
- }
- c = pn[0];
- /* Keep going until we've checked the entire name. */
- while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) {
+ restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC);
+ __archive_ensure_cloexec_flag(restore_pwd);
+ if (restore_pwd < 0)
+ return (ARCHIVE_FATAL);
+ head = path;
+ tail = path;
+ last = 0;
+ /* TODO: reintroduce a safe cache here? */
+ /* Skip the root directory if the path is absolute. */
+ if(tail == path && tail[0] == '/')
+ ++tail;
+ /* Keep going until we've checked the entire name.
+ * head, tail, path all alias the same string, which is
+ * temporarily zeroed at tail, so be careful restoring the
+ * stashed (c=tail[0]) for error messages.
+ * Exiting the loop with break is okay; continue is not.
+ */
+ while (!last) {
+ /*
+ * Skip the separator we just consumed, plus any adjacent ones
+ */
+ while (*tail == '/')
+ ++tail;
/* Skip the next path element. */
- while (*pn != '\0' && *pn != '/')
- ++pn;
- c = pn[0];
- pn[0] = '\0';
+ while (*tail != '\0' && *tail != '/')
+ ++tail;
+ /* is this the last path component? */
+ last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0');
+ /* temporarily truncate the string here */
+ c = tail[0];
+ tail[0] = '\0';
/* Check that we haven't hit a symlink. */
- r = lstat(a->name, &st);
+ r = lstat(head, &st);
if (r != 0) {
+ tail[0] = c;
/* We've hit a dir that doesn't exist; stop now. */
- if (errno == ENOENT)
+ if (errno == ENOENT) {
+ break;
+ } else {
+ /*
+ * Treat any other error as fatal - best to be
+ * paranoid here.
+ * Note: This effectively disables deep
+ * directory support when security checks are
+ * enabled. Otherwise, very long pathnames that
+ * trigger an error here could evade the
+ * sandbox.
+ * TODO: We could do better, but it would
+ * probably require merging the symlink checks
+ * with the deep-directory editing.
+ */
+ fsobj_error(a_eno, a_estr, errno,
+ "Could not stat %s", path);
+ res = ARCHIVE_FAILED;
break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ if (!last) {
+ if (chdir(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, errno,
+ "Could not chdir %s", path);
+ res = (ARCHIVE_FATAL);
+ break;
+ }
+ /* Our view is now from inside this dir: */
+ head = tail + 1;
+ }
} else if (S_ISLNK(st.st_mode)) {
- if (c == '\0') {
+ if (last) {
/*
* Last element is symlink; remove it
* so we can overwrite it with the
* item being extracted.
*/
- if (unlink(a->name)) {
- archive_set_error(&a->archive, errno,
+ if (unlink(head)) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, errno,
"Could not remove symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ path);
+ res = ARCHIVE_FAILED;
+ break;
}
- a->pst = NULL;
/*
* Even if we did remove it, a warning
* is in order. The warning is silly,
* though, if we're just replacing one
* symlink with another symlink.
*/
- if (!S_ISLNK(a->mode)) {
- archive_set_error(&a->archive, 0,
- "Removing symlink %s",
- a->name);
+ tail[0] = c;
+ /*
+ * FIXME: not sure how important this is to
+ * restore
+ */
+ /*
+ if (!S_ISLNK(path)) {
+ fsobj_error(a_eno, a_estr, 0,
+ "Removing symlink %s", path);
}
+ */
/* Symlink gone. No more problem! */
- pn[0] = c;
- return (0);
- } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {
+ res = ARCHIVE_OK;
+ break;
+ } else if (flags & ARCHIVE_EXTRACT_UNLINK) {
/* User asked us to remove problems. */
- if (unlink(a->name) != 0) {
- archive_set_error(&a->archive, 0,
- "Cannot remove intervening symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ if (unlink(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot remove intervening "
+ "symlink %s", path);
+ res = ARCHIVE_FAILED;
+ break;
+ }
+ tail[0] = c;
+ } else if ((flags &
+ ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) {
+ /*
+ * We are not the last element and we want to
+ * follow symlinks if they are a directory.
+ *
+ * This is needed to extract hardlinks over
+ * symlinks.
+ */
+ r = stat(head, &st);
+ if (r != 0) {
+ tail[0] = c;
+ if (errno == ENOENT) {
+ break;
+ } else {
+ fsobj_error(a_eno, a_estr,
+ errno,
+ "Could not stat %s", path);
+ res = (ARCHIVE_FAILED);
+ break;
+ }
+ } else if (S_ISDIR(st.st_mode)) {
+ if (chdir(head) != 0) {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr,
+ errno,
+ "Could not chdir %s", path);
+ res = (ARCHIVE_FATAL);
+ break;
+ }
+ /*
+ * Our view is now from inside
+ * this dir:
+ */
+ head = tail + 1;
+ } else {
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot extract through "
+ "symlink %s", path);
+ res = ARCHIVE_FAILED;
+ break;
}
- a->pst = NULL;
} else {
- archive_set_error(&a->archive, 0,
- "Cannot extract through symlink %s",
- a->name);
- pn[0] = c;
- return (ARCHIVE_FAILED);
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot extract through symlink %s", path);
+ res = ARCHIVE_FAILED;
+ break;
}
}
+ /* be sure to always maintain this */
+ tail[0] = c;
+ if (tail[0] != '\0')
+ tail++; /* Advance to the next segment. */
}
- pn[0] = c;
- /* We've checked and/or cleaned the whole path, so remember it. */
- archive_strcpy(&a->path_safe, a->name);
- return (ARCHIVE_OK);
+ /* Catches loop exits via break */
+ tail[0] = c;
+#ifdef HAVE_FCHDIR
+ /* If we changed directory above, restore it here. */
+ if (restore_pwd >= 0) {
+ r = fchdir(restore_pwd);
+ if (r != 0) {
+ fsobj_error(a_eno, a_estr, errno,
+ "chdir() failure", "");
+ }
+ close(restore_pwd);
+ restore_pwd = -1;
+ if (r != 0) {
+ res = (ARCHIVE_FATAL);
+ }
+ }
+#endif
+ /* TODO: reintroduce a safe cache here? */
+ return res;
#endif
}
+/*
+ * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise
+ * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED}
+ */
+static int
+check_symlinks(struct archive_write_disk *a)
+{
+ struct archive_string error_string;
+ int error_number;
+ int rc;
+ archive_string_init(&error_string);
+ rc = check_symlinks_fsobj(a->name, &error_number, &error_string,
+ a->flags);
+ if (rc != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ }
+ archive_string_free(&error_string);
+ a->pst = NULL; /* to be safe */
+ return rc;
+}
+
+
#if defined(__CYGWIN__)
/*
* 1. Convert a path separator from '\' to '/' .
@@ -2446,7 +2746,7 @@ check_symlinks(struct archive_write_disk *a)
* See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx
*/
static void
-cleanup_pathname_win(struct archive_write_disk *a)
+cleanup_pathname_win(char *path)
{
wchar_t wc;
char *p;
@@ -2457,7 +2757,7 @@ cleanup_pathname_win(struct archive_write_disk *a)
mb = 0;
complete = 1;
utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0;
- for (p = a->name; *p != '\0'; p++) {
+ for (p = path; *p != '\0'; p++) {
++alen;
if (*p == '\\') {
/* If previous byte is smaller than 128,
@@ -2482,7 +2782,7 @@ cleanup_pathname_win(struct archive_write_disk *a)
/*
* Convert path separator in wide-character.
*/
- p = a->name;
+ p = path;
while (*p != '\0' && alen) {
l = mbtowc(&wc, p, alen);
if (l == (size_t)-1) {
@@ -2504,28 +2804,37 @@ cleanup_pathname_win(struct archive_write_disk *a)
/*
* Canonicalize the pathname. In particular, this strips duplicate
* '/' characters, '.' elements, and trailing '/'. It also raises an
- * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
- * set) any '..' in the path.
+ * error for an empty path, a trailing '..', (if _SECURE_NODOTDOT is
+ * set) any '..' in the path or (if ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+ * is set) if the path is absolute.
*/
static int
-cleanup_pathname(struct archive_write_disk *a)
+cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ int flags)
{
char *dest, *src;
char separator = '\0';
- dest = src = a->name;
+ dest = src = path;
if (*src == '\0') {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Invalid empty pathname");
+ fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+ "Invalid empty ", "pathname");
return (ARCHIVE_FAILED);
}
#if defined(__CYGWIN__)
- cleanup_pathname_win(a);
+ cleanup_pathname_win(path);
#endif
/* Skip leading '/'. */
- if (*src == '/')
+ if (*src == '/') {
+ if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) {
+ fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC,
+ "Path is ", "absolute");
+ return (ARCHIVE_FAILED);
+ }
+
separator = *src++;
+ }
/* Scan the pathname one element at a time. */
for (;;) {
@@ -2547,10 +2856,11 @@ cleanup_pathname(struct archive_write_disk *a)
} else if (src[1] == '.') {
if (src[2] == '/' || src[2] == '\0') {
/* Conditionally warn about '..' */
- if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
- archive_set_error(&a->archive,
+ if (flags
+ & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
+ fsobj_error(a_eno, a_estr,
ARCHIVE_ERRNO_MISC,
- "Path contains '..'");
+ "Path contains ", "'..'");
return (ARCHIVE_FAILED);
}
}
@@ -2581,7 +2891,7 @@ cleanup_pathname(struct archive_write_disk *a)
* We've just copied zero or more path elements, not including the
* final '/'.
*/
- if (dest == a->name) {
+ if (dest == path) {
/*
* Nothing got copied. The path must have been something
* like '.' or '/' or './' or '/././././/./'.
@@ -2596,6 +2906,23 @@ cleanup_pathname(struct archive_write_disk *a)
return (ARCHIVE_OK);
}
+static int
+cleanup_pathname(struct archive_write_disk *a)
+{
+ struct archive_string error_string;
+ int error_number;
+ int rc;
+ archive_string_init(&error_string);
+ rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string,
+ a->flags);
+ if (rc != ARCHIVE_OK) {
+ archive_set_error(&a->archive, error_number, "%s",
+ error_string.s);
+ }
+ archive_string_free(&error_string);
+ return rc;
+}
+
/*
* Create the parent directory of the specified path, assuming path
* is already in mutable storage.
@@ -2674,7 +3001,8 @@ create_dir(struct archive_write_disk *a, char *path)
}
} else if (errno != ENOENT && errno != ENOTDIR) {
/* Stat failed? */
- archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
+ archive_set_error(&a->archive, errno,
+ "Can't test directory '%s'", path);
return (ARCHIVE_FAILED);
} else if (slash != NULL) {
*slash = '\0';
@@ -2861,7 +3189,7 @@ set_time(int fd, int mode, const char *name,
#endif
}
-#ifdef F_SETTIMES /* Tru64 */
+#ifdef F_SETTIMES
static int
set_time_tru64(int fd, int mode, const char *name,
time_t atime, long atime_nsec,
@@ -2869,19 +3197,21 @@ set_time_tru64(int fd, int mode, const char *name,
time_t ctime, long ctime_nsec)
{
struct attr_timbuf tstamp;
- struct timeval times[3];
- times[0].tv_sec = atime;
- times[0].tv_usec = atime_nsec / 1000;
- times[1].tv_sec = mtime;
- times[1].tv_usec = mtime_nsec / 1000;
- times[2].tv_sec = ctime;
- times[2].tv_usec = ctime_nsec / 1000;
- tstamp.atime = times[0];
- tstamp.mtime = times[1];
- tstamp.ctime = times[2];
+ tstamp.atime.tv_sec = atime;
+ tstamp.mtime.tv_sec = mtime;
+ tstamp.ctime.tv_sec = ctime;
+#if defined (__hpux) && defined (__ia64)
+ tstamp.atime.tv_nsec = atime_nsec;
+ tstamp.mtime.tv_nsec = mtime_nsec;
+ tstamp.ctime.tv_nsec = ctime_nsec;
+#else
+ tstamp.atime.tv_usec = atime_nsec / 1000;
+ tstamp.mtime.tv_usec = mtime_nsec / 1000;
+ tstamp.ctime.tv_usec = ctime_nsec / 1000;
+#endif
return (fcntl(fd,F_SETTIMES,&tstamp));
}
-#endif /* Tru64 */
+#endif /* F_SETTIMES */
static int
set_times(struct archive_write_disk *a,
@@ -3053,9 +3383,23 @@ set_mode(struct archive_write_disk *a, int mode)
* impact.
*/
if (lchmod(a->name, mode) != 0) {
- archive_set_error(&a->archive, errno,
- "Can't set permissions to 0%o", (int)mode);
- r = ARCHIVE_WARN;
+ switch (errno) {
+ case ENOTSUP:
+ case ENOSYS:
+#if ENOTSUP != EOPNOTSUPP
+ case EOPNOTSUPP:
+#endif
+ /*
+ * if lchmod is defined but the platform
+ * doesn't support it, silently ignore
+ * error
+ */
+ break;
+ default:
+ archive_set_error(&a->archive, errno,
+ "Can't set permissions to 0%o", (int)mode);
+ r = ARCHIVE_WARN;
+ }
}
#endif
} else if (!S_ISDIR(a->mode)) {
@@ -3123,12 +3467,19 @@ set_fflags(struct archive_write_disk *a)
#ifdef UF_APPEND
critical_flags |= UF_APPEND;
#endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+ critical_flags |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
critical_flags |= EXT2_APPEND_FL;
#endif
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+ critical_flags |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
critical_flags |= EXT2_IMMUTABLE_FL;
#endif
+#ifdef FS_JOURNAL_DATA_FL
+ critical_flags |= FS_JOURNAL_DATA_FL;
+#endif
if (a->todo & TODO_FFLAGS) {
archive_entry_fflags(a->entry, &set, &clear);
@@ -3156,6 +3507,37 @@ set_fflags(struct archive_write_disk *a)
return (ARCHIVE_OK);
}
+static int
+clear_nochange_fflags(struct archive_write_disk *a)
+{
+ int nochange_flags;
+ mode_t mode = archive_entry_mode(a->entry);
+
+ /* Hopefully, the compiler will optimize this mess into a constant. */
+ nochange_flags = 0;
+#ifdef SF_IMMUTABLE
+ nochange_flags |= SF_IMMUTABLE;
+#endif
+#ifdef UF_IMMUTABLE
+ nochange_flags |= UF_IMMUTABLE;
+#endif
+#ifdef SF_APPEND
+ nochange_flags |= SF_APPEND;
+#endif
+#ifdef UF_APPEND
+ nochange_flags |= UF_APPEND;
+#endif
+#ifdef EXT2_APPEND_FL
+ nochange_flags |= EXT2_APPEND_FL;
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ nochange_flags |= EXT2_IMMUTABLE_FL;
+#endif
+
+ return (set_fflags_platform(a, a->fd, a->name, mode, 0,
+ nochange_flags));
+}
+
#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && defined(HAVE_STRUCT_STAT_ST_FLAGS)
/*
@@ -3209,7 +3591,10 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
return (ARCHIVE_WARN);
}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \
+ defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+ (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \
+ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
/*
* Linux uses ioctl() to read and write file flags.
*/
@@ -3222,7 +3607,7 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
int newflags, oldflags;
int sf_mask = 0;
- if (set == 0 && clear == 0)
+ if (set == 0 && clear == 0)
return (ARCHIVE_OK);
/* Only regular files and dirs can have flags. */
if (!S_ISREG(mode) && !S_ISDIR(mode))
@@ -3243,12 +3628,19 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
* defines. (?) The code below degrades reasonably gracefully
* if sf_mask is incomplete.
*/
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+ sf_mask |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
sf_mask |= EXT2_IMMUTABLE_FL;
#endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+ sf_mask |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
sf_mask |= EXT2_APPEND_FL;
#endif
+#if defined(FS_JOURNAL_DATA_FL)
+ sf_mask |= FS_JOURNAL_DATA_FL;
+#endif
/*
* XXX As above, this would be way simpler if we didn't have
* to read the current flags from disk. XXX
@@ -3256,12 +3648,24 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
ret = ARCHIVE_OK;
/* Read the current file flags. */
- if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_GETFLAGS
+ FS_IOC_GETFLAGS,
+#else
+ EXT2_IOC_GETFLAGS,
+#endif
+ &oldflags) < 0)
goto fail;
/* Try setting the flags as given. */
newflags = (oldflags & ~clear) | set;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+ FS_IOC_SETFLAGS,
+#else
+ EXT2_IOC_SETFLAGS,
+#endif
+ &newflags) >= 0)
goto cleanup;
if (errno != EPERM)
goto fail;
@@ -3270,7 +3674,13 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
newflags &= ~sf_mask;
oldflags &= sf_mask;
newflags |= oldflags;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+ FS_IOC_SETFLAGS,
+#else
+ EXT2_IOC_SETFLAGS,
+#endif
+ &newflags) >= 0)
goto cleanup;
/* We couldn't set the flags, so report the failure. */
@@ -3363,6 +3773,7 @@ copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
}
for (xattr_i = 0; xattr_i < xattr_size;
xattr_i += strlen(xattr_names + xattr_i) + 1) {
+ char *xattr_val_saved;
ssize_t s;
int f;
@@ -3373,11 +3784,13 @@ copy_xattrs(struct archive_write_disk *a, int tmpfd, int dffd)
ret = ARCHIVE_WARN;
goto exit_xattr;
}
+ xattr_val_saved = xattr_val;
xattr_val = realloc(xattr_val, s);
if (xattr_val == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Failed to get metadata(xattr)");
ret = ARCHIVE_WARN;
+ free(xattr_val_saved);
goto exit_xattr;
}
s = fgetxattr(tmpfd, xattr_names + xattr_i, xattr_val, s, 0, 0);
@@ -3405,6 +3818,9 @@ exit_xattr:
static int
copy_acls(struct archive_write_disk *a, int tmpfd, int dffd)
{
+#ifndef HAVE_SYS_ACL_H
+ return 0;
+#else
acl_t acl, dfacl = NULL;
int acl_r, ret = ARCHIVE_OK;
@@ -3432,6 +3848,7 @@ exit_acl:
if (dfacl)
acl_free(dfacl);
return (ret);
+#endif
}
static int
@@ -3671,7 +4088,8 @@ set_xattrs(struct archive_write_disk *a)
if (errno == ENOTSUP || errno == ENOSYS) {
if (!warning_done) {
warning_done = 1;
- archive_set_error(&a->archive, errno,
+ archive_set_error(&a->archive,
+ errno,
"Cannot restore extended "
"attributes on this file "
"system");
@@ -3682,7 +4100,8 @@ set_xattrs(struct archive_write_disk *a)
ret = ARCHIVE_WARN;
}
} else {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
"Invalid extended attribute encountered");
ret = ARCHIVE_WARN;
}
@@ -3726,19 +4145,22 @@ set_xattrs(struct archive_write_disk *a)
errno = 0;
#if HAVE_EXTATTR_SET_FD
if (a->fd >= 0)
- e = extattr_set_fd(a->fd, namespace, name, value, size);
+ e = extattr_set_fd(a->fd, namespace, name,
+ value, size);
else
#endif
/* TODO: should we use extattr_set_link() instead? */
{
- e = extattr_set_file(archive_entry_pathname(entry),
- namespace, name, value, size);
+ e = extattr_set_file(
+ archive_entry_pathname(entry), namespace,
+ name, value, size);
}
if (e != (int)size) {
if (errno == ENOTSUP || errno == ENOSYS) {
if (!warning_done) {
warning_done = 1;
- archive_set_error(&a->archive, errno,
+ archive_set_error(&a->archive,
+ errno,
"Cannot restore extended "
"attributes on this file "
"system");
@@ -3784,10 +4206,10 @@ older(struct stat *st, struct archive_entry *entry)
{
/* First, test the seconds and return if we have a definite answer. */
/* Definitely older. */
- if (st->st_mtime < archive_entry_mtime(entry))
+ if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry)))
return (1);
/* Definitely younger. */
- if (st->st_mtime > archive_entry_mtime(entry))
+ if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry)))
return (0);
/* If this platform supports fractional seconds, try those. */
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c
index e79008ef6..5c766d75d 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c
@@ -67,7 +67,7 @@ static void cleanup(void *);
* a simple cache to accelerate such lookups---into the archive_write_disk
* object. This is in a separate file because getpwnam()/getgrnam()
* can pull in a LOT of library code (including NIS/LDAP functions, which
- * pull in DNS resolveers, etc). This can easily top 500kB, which makes
+ * pull in DNS resolvers, etc). This can easily top 500kB, which makes
* it inappropriate for some space-constrained applications.
*
* Applications that are size-sensitive may want to just use the
@@ -84,10 +84,13 @@ static void cleanup(void *);
int
archive_write_disk_set_standard_lookup(struct archive *a)
{
- struct bucket *ucache = malloc(cache_size * sizeof(struct bucket));
- struct bucket *gcache = malloc(cache_size * sizeof(struct bucket));
- memset(ucache, 0, cache_size * sizeof(struct bucket));
- memset(gcache, 0, cache_size * sizeof(struct bucket));
+ struct bucket *ucache = calloc(cache_size, sizeof(struct bucket));
+ struct bucket *gcache = calloc(cache_size, sizeof(struct bucket));
+ if (ucache == NULL || gcache == NULL) {
+ free(ucache);
+ free(gcache);
+ return (ARCHIVE_FATAL);
+ }
archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);
archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);
return (ARCHIVE_OK);
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
index 0f0780a8e..94b016edf 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c
@@ -192,7 +192,7 @@ struct archive_write_disk {
/*
* Default mode for dirs created automatically (will be modified by umask).
- * Note that POSIX specifies 0777 for implicity-created dirs, "modified
+ * Note that POSIX specifies 0777 for implicitly-created dirs, "modified
* by the process' file creation mask."
*/
#define DEFAULT_DIR_MODE 0777
@@ -330,8 +330,6 @@ file_information(struct archive_write_disk *a, wchar_t *path,
break;
case L'C': case L'c':
if (((p[2] == L'M' || p[2] == L'm' ) &&
- (p[3] == L'D' || p[3] == L'd' )) ||
- ((p[2] == L'M' || p[2] == L'm' ) &&
(p[3] == L'D' || p[3] == L'd' )))
*mode |= S_IXUSR | S_IXGRP | S_IXOTH;
break;
@@ -398,7 +396,7 @@ permissive_name_w(struct archive_write_disk *a)
}
/*
- * A full-pathname pointig a network drive
+ * A full-pathname pointing to a network drive
* like "\\<server-name>\<share-name>\file".
*/
if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') {
@@ -470,9 +468,17 @@ permissive_name_w(struct archive_write_disk *a)
return (-1);
archive_wstring_ensure(&(a->_name_data), 4 + l + 1 + wcslen(wn) + 1);
a->name = a->_name_data.s;
- /* Prepend "\\?\" and drive name. */
- archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
- archive_wstrncat(&(a->_name_data), wsp, l);
+ /* Prepend "\\?\" and drive name if not already added. */
+ if (l > 3 && wsp[0] == L'\\' && wsp[1] == L'\\' &&
+ wsp[2] == L'?' && wsp[3] == L'\\')
+ {
+ archive_wstrncpy(&(a->_name_data), wsp, l);
+ }
+ else
+ {
+ archive_wstrncpy(&(a->_name_data), L"\\\\?\\", 4);
+ archive_wstrncat(&(a->_name_data), wsp, l);
+ }
archive_wstrncat(&(a->_name_data), L"\\", 1);
archive_wstrcat(&(a->_name_data), wn);
a->name = a->_name_data.s;
@@ -525,7 +531,7 @@ la_GetFunctionKernel32(const char *name)
static int set;
if (!set) {
set = 1;
- lib = LoadLibrary("kernel32.dll");
+ lib = LoadLibrary(TEXT("kernel32.dll"));
}
if (lib == NULL) {
fprintf(stderr, "Can't load kernel32.dll?!\n");
@@ -1011,7 +1017,11 @@ _archive_write_disk_data_block(struct archive *_a,
"Write request too large");
return (ARCHIVE_WARN);
}
+#if ARCHIVE_VERSION_NUMBER < 3999000
return (ARCHIVE_OK);
+#else
+ return (size);
+#endif
}
static ssize_t
@@ -1211,10 +1221,9 @@ archive_write_disk_new(void)
{
struct archive_write_disk *a;
- a = (struct archive_write_disk *)malloc(sizeof(*a));
+ a = (struct archive_write_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
/* We're ready to write a header immediately. */
a->archive.state = ARCHIVE_STATE_HEADER;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_filter.3 b/Utilities/cmlibarchive/libarchive/archive_write_filter.3
index 3ca248b72..e1d189150 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_filter.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_filter.3
@@ -24,50 +24,80 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 2, 2012
+.Dd August 14, 2014
.Dt ARCHIVE_WRITE_FILTER 3
.Os
.Sh NAME
+.Nm archive_write_add_filter_b64encode ,
+.Nm archive_write_add_filter_by_name ,
.Nm archive_write_add_filter_bzip2 ,
.Nm archive_write_add_filter_compress ,
+.Nm archive_write_add_filter_grzip ,
.Nm archive_write_add_filter_gzip ,
+.Nm archive_write_add_filter_lrzip ,
+.Nm archive_write_add_filter_lz4 ,
.Nm archive_write_add_filter_lzip ,
.Nm archive_write_add_filter_lzma ,
+.Nm archive_write_add_filter_lzop ,
.Nm archive_write_add_filter_none ,
.Nm archive_write_add_filter_program ,
+.Nm archive_write_add_filter_uuencode ,
.Nm archive_write_add_filter_xz
+.Nd functions enabling output filters
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
.Ft int
+.Fn archive_write_add_filter_b64encode "struct archive *"
+.Ft int
.Fn archive_write_add_filter_bzip2 "struct archive *"
.Ft int
.Fn archive_write_add_filter_compress "struct archive *"
.Ft int
+.Fn archive_write_add_filter_grzip "struct archive *"
+.Ft int
.Fn archive_write_add_filter_gzip "struct archive *"
.Ft int
+.Fn archive_write_add_filter_lrzip "struct archive *"
+.Ft int
+.Fn archive_write_add_filter_lz4 "struct archive *"
+.Ft int
.Fn archive_write_add_filter_lzip "struct archive *"
.Ft int
.Fn archive_write_add_filter_lzma "struct archive *"
.Ft int
+.Fn archive_write_add_filter_lzop "struct archive *"
+.Ft int
.Fn archive_write_add_filter_none "struct archive *"
.Ft int
.Fn archive_write_add_filter_program "struct archive *" "const char * cmd"
.Ft int
+.Fn archive_write_add_filter_uuencode "struct archive *"
+.Ft int
.Fn archive_write_add_filter_xz "struct archive *"
.Sh DESCRIPTION
.Bl -tag -width indent
.It Xo
.Fn archive_write_add_filter_bzip2 ,
.Fn archive_write_add_filter_compress ,
+.Fn archive_write_add_filter_grzip ,
.Fn archive_write_add_filter_gzip ,
+.Fn archive_write_add_filter_lrzip ,
+.Fn archive_write_add_filter_lz4 ,
.Fn archive_write_add_filter_lzip ,
.Fn archive_write_add_filter_lzma ,
+.Fn archive_write_add_filter_lzop ,
.Fn archive_write_add_filter_xz ,
.Xc
The resulting archive will be compressed as specified.
Note that the compressed output is always properly blocked.
+.It Xo
+.Fn archive_write_add_filter_b64encode ,
+.Fn archive_write_add_filter_uuencode ,
+.Xc
+The output will be encoded as specified.
+The encoded output is always properly blocked.
.It Fn archive_write_add_filter_none
This is never necessary.
It is provided only for backwards compatibility.
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_finish_entry.3 b/Utilities/cmlibarchive/libarchive/archive_write_finish_entry.3
index d881c80ea..c5ef69ebc 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_finish_entry.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_finish_entry.3
@@ -41,7 +41,7 @@ Close out the entry just written.
In particular, this writes out the final padding required by some formats.
Ordinarily, clients never need to call this, as it
is called automatically by
-.Fn archive_write_next_header
+.Fn archive_write_header
and
.Fn archive_write_close
as needed.
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_format.3 b/Utilities/cmlibarchive/libarchive/archive_write_format.3
index dad2f7d7e..d4ba6abff 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_format.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_format.3
@@ -24,58 +24,133 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 2, 2012
+.Dd February 14, 2013
.Dt ARCHIVE_WRITE_FORMAT 3
.Os
.Sh NAME
+.Nm archive_write_set_format ,
+.Nm archive_write_set_format_7zip ,
+.Nm archive_write_set_format_ar ,
+.Nm archive_write_set_format_ar_bsd ,
+.Nm archive_write_set_format_ar_svr4 ,
+.Nm archive_write_set_format_by_name ,
.Nm archive_write_set_format_cpio ,
+.Nm archive_write_set_format_cpio_newc ,
+.Nm archive_write_set_format_filter_by_ext ,
+.Nm archive_write_set_format_filter_by_ext_def ,
+.Nm archive_write_set_format_gnutar ,
+.Nm archive_write_set_format_iso9660 ,
+.Nm archive_write_set_format_mtree ,
+.Nm archive_write_set_format_mtree_classic ,
+.Nm archive_write_set_format_mtree_default ,
.Nm archive_write_set_format_pax ,
.Nm archive_write_set_format_pax_restricted ,
+.Nm archive_write_set_format_raw ,
.Nm archive_write_set_format_shar ,
.Nm archive_write_set_format_shar_dump ,
-.Nm archive_write_set_format_ustar
+.Nm archive_write_set_format_ustar ,
+.Nm archive_write_set_format_v7tar ,
+.Nm archive_write_set_format_warc ,
+.Nm archive_write_set_format_xar ,
+.Nm archive_write_set_format_zip ,
.Nd functions for creating archives
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
.Ft int
+.Fn archive_write_set_format "struct archive *" "int code"
+.Ft int
+.Fn archive_write_set_format_7zip "struct archive *"
+.Ft int
+.Fn archive_write_set_format_ar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_ar_bsd "struct archive *"
+.Ft int
+.Fn archive_write_set_format_ar_svr4 "struct archive *"
+.Ft int
+.Fn archive_write_set_format_by_name "struct archive *" "const char *name"
+.Ft int
.Fn archive_write_set_format_cpio "struct archive *"
.Ft int
+.Fn archive_write_set_format_cpio_newc "struct archive *"
+.Ft int
+.Fn archive_write_set_format_filter_by_ext "struct archive *" "const char *filename"
+.Ft int
+.Fn archive_write_set_format_filter_by_ext_def "struct archive *" "const char *filename" "const char *def_ext"
+.Ft int
+.Fn archive_write_set_format_gnutar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_iso9660 "struct archive *"
+.Ft int
+.Fn archive_write_set_format_mtree "struct archive *"
+.Ft int
.Fn archive_write_set_format_pax "struct archive *"
.Ft int
.Fn archive_write_set_format_pax_restricted "struct archive *"
.Ft int
+.Fn archive_write_set_format_raw "struct archive *"
+.Ft int
.Fn archive_write_set_format_shar "struct archive *"
.Ft int
.Fn archive_write_set_format_shar_dump "struct archive *"
.Ft int
.Fn archive_write_set_format_ustar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_v7tar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_warc "struct archive *"
+.Ft int
+.Fn archive_write_set_format_xar "struct archive *"
+.Ft int
+.Fn archive_write_set_format_zip "struct archive *"
.Sh DESCRIPTION
These functions set the format that will be used for the archive.
.Pp
-The library can write
-POSIX octet-oriented cpio format archives,
-POSIX-standard
-.Dq pax interchange
-format archives,
-traditional
-.Dq shar
-archives,
-enhanced
-.Dq dump
-shar archives that store a variety of file attributes and handle binary files,
-and
-POSIX-standard
-.Dq ustar
-archives.
-The pax interchange format is a backwards-compatible tar format that
-adds key/value attributes to each entry and supports arbitrary
-filenames, linknames, uids, sizes, etc.
-.Dq Restricted pax interchange format
-is the library default; this is the same as pax format, but suppresses
-the pax extended header for most normal files.
-In most cases, this will result in ordinary ustar archives.
+The library can write a variety of common archive formats.
+
+.Bl -tag -width indent
+.It Fn archive_write_set_format
+Sets the format based on the format code (see
+.Pa archive.h
+for the full list of format codes).
+In particular, this can be used in conjunction with
+.Fn archive_format
+to create a new archive with the same format as an existing archive.
+.It Fn archive_write_set_format_by_name
+Sets the corresponding format based on the common name.
+.It Xo
+.Fn archive_write_set_format_filter_by_ext ,
+.Fn archive_write_set_format_filter_by_ext_def
+.Xc
+Sets both filters and format based on the output filename.
+Supported extensions: .7z, .zip, .jar, .cpio, .iso, .a, .ar, .tar, .tgz, .tar.gz, .tar.bz2, .tar.xz
+.It Xo
+.Fn archive_write_set_format_7zip
+.Fn archive_write_set_format_ar_bsd ,
+.Fn archive_write_set_format_ar_svr4 ,
+.Fn archive_write_set_format_cpio
+.Fn archive_write_set_format_cpio_newc
+.Fn archive_write_set_format_gnutar
+.Fn archive_write_set_format_iso9660
+.Fn archive_write_set_format_mtree
+.Fn archive_write_set_format_mtree_classic
+.Fn archive_write_set_format_pax
+.Fn archive_write_set_format_pax_restricted
+.Fn archive_write_set_format_raw
+.Fn archive_write_set_format_shar
+.Fn archive_write_set_format_shar_dump
+.Fn archive_write_set_format_ustar
+.Fn archive_write_set_format_v7tar
+.Fn archive_write_set_format_warc
+.Fn archive_write_set_format_xar
+.Fn archive_write_set_format_zip
+.Xc
+Set the format as specified.
+More details on the formats supported by libarchive can be found in the
+.Xr libarchive-formats 5
+manual page.
+.El
.\"
.Sh RETURN VALUES
These functions return
@@ -96,5 +171,6 @@ functions.
.Xr archive_write 3 ,
.Xr archive_write_set_options 3 ,
.Xr cpio 5 ,
+.Xr libarchive-formats 5 ,
.Xr mtree 5 ,
.Xr tar 5
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open.3 b/Utilities/cmlibarchive/libarchive/archive_write_open.3
index 4037248e0..457873e61 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_open.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_open.3
@@ -66,6 +66,7 @@ Freeze the settings, open the archive, and prepare for writing entries.
This is the most generic form of this function, which accepts
pointers to three callback functions which will be invoked by
the compression layer to write the constructed archive.
+This does not alter the default archive padding.
.It Fn archive_write_open_fd
A convenience form of
.Fn archive_write_open
@@ -123,12 +124,21 @@ is currently in use.
You should be careful to ensure that this variable
remains allocated until after the archive is
closed.
+This function will disable padding unless you
+have specifically set the block size.
.El
More information about the
.Va struct archive
object and the overall design of the library can be found in the
.Xr libarchive 3
overview.
+.Pp
+Note that the convenience forms above vary in how
+they block the output.
+See
+.Xr archive_write_blocksize 3
+if you need to control the block size used for writes
+or the end-of-file padding behavior.
.\"
.Sh CLIENT CALLBACKS
To use this library, you will need to define and register
@@ -154,7 +164,7 @@ to register an error code and message and return
.Cm ARCHIVE_FATAL .
.Bl -item -offset indent
.It
-.Ft typedef ssize_t
+.Ft typedef la_ssize_t
.Fo archive_write_callback
.Fa "struct archive *"
.Fa "void *client_data"
@@ -226,6 +236,7 @@ functions.
.Xr tar 1 ,
.Xr libarchive 3 ,
.Xr archive_write 3 ,
+.Xr archive_write_blocksize 3 ,
.Xr archive_write_filter 3 ,
.Xr archive_write_format 3 ,
.Xr archive_write_new 3 ,
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open_filename.c b/Utilities/cmlibarchive/libarchive/archive_write_open_filename.c
index 196b770e8..66e0dfee9 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_open_filename.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_open_filename.c
@@ -243,7 +243,10 @@ file_close(struct archive *a, void *client_data)
struct write_file_data *mine = (struct write_file_data *)client_data;
(void)a; /* UNUSED */
- close(mine->fd);
+
+ if (mine->fd >= 0)
+ close(mine->fd);
+
archive_mstring_clean(&mine->filename);
free(mine);
return (ARCHIVE_OK);
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c b/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c
index 4f8d679e5..ea6ae0ac5 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c
@@ -53,12 +53,11 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t
{
struct write_memory_data *mine;
- mine = (struct write_memory_data *)malloc(sizeof(*mine));
+ mine = (struct write_memory_data *)calloc(1, sizeof(*mine));
if (mine == NULL) {
archive_set_error(a, ENOMEM, "No memory");
return (ARCHIVE_FATAL);
}
- memset(mine, 0, sizeof(*mine));
mine->buff = buff;
mine->size = buffSize;
mine->client_size = used;
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_private.h b/Utilities/cmlibarchive/libarchive/archive_write_private.h
index e600d5474..0dfd1b1bc 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_private.h
+++ b/Utilities/cmlibarchive/libarchive/archive_write_private.h
@@ -26,8 +26,10 @@
*/
#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
#error This header is only to be used internally to libarchive.
#endif
+#endif
#ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED
@@ -116,6 +118,14 @@ struct archive_write {
const void *buff, size_t);
int (*format_close)(struct archive_write *);
int (*format_free)(struct archive_write *);
+
+
+ /*
+ * Encryption passphrase.
+ */
+ char *passphrase;
+ archive_passphrase_callback *passphrase_callback;
+ void *passphrase_client_data;
};
/*
@@ -134,7 +144,7 @@ __archive_write_format_header_ustar(struct archive_write *, char buff[512],
struct archive_string_conv *);
struct archive_write_program_data;
-struct archive_write_program_data * __archive_write_program_allocate(void);
+struct archive_write_program_data * __archive_write_program_allocate(const char *program_name);
int __archive_write_program_free(struct archive_write_program_data *);
int __archive_write_program_open(struct archive_write_filter *,
struct archive_write_program_data *, const char *);
@@ -142,4 +152,9 @@ int __archive_write_program_close(struct archive_write_filter *,
struct archive_write_program_data *);
int __archive_write_program_write(struct archive_write_filter *,
struct archive_write_program_data *, const void *, size_t);
+
+/*
+ * Get a encryption passphrase.
+ */
+const char * __archive_write_get_passphrase(struct archive_write *a);
#endif
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c
index 641d56f6c..744302d06 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format.c
@@ -47,6 +47,7 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FORMAT_CPIO_SVR4_NOCRC, archive_write_set_format_cpio_newc },
{ ARCHIVE_FORMAT_ISO9660, archive_write_set_format_iso9660 },
{ ARCHIVE_FORMAT_MTREE, archive_write_set_format_mtree },
+ { ARCHIVE_FORMAT_RAW, archive_write_set_format_raw },
{ ARCHIVE_FORMAT_SHAR, archive_write_set_format_shar },
{ ARCHIVE_FORMAT_SHAR_BASE, archive_write_set_format_shar },
{ ARCHIVE_FORMAT_SHAR_DUMP, archive_write_set_format_shar_dump },
@@ -56,8 +57,9 @@ struct { int code; int (*setter)(struct archive *); } codes[] =
{ ARCHIVE_FORMAT_TAR_PAX_RESTRICTED,
archive_write_set_format_pax_restricted },
{ ARCHIVE_FORMAT_TAR_USTAR, archive_write_set_format_ustar },
+ { ARCHIVE_FORMAT_WARC, archive_write_set_format_warc },
{ ARCHIVE_FORMAT_XAR, archive_write_set_format_xar },
- { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip },
+ { ARCHIVE_FORMAT_ZIP, archive_write_set_format_zip },
{ 0, NULL }
};
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
index 4f1bc2622..3fc5a07d7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c
@@ -34,7 +34,7 @@ __FBSDID("$FreeBSD$");
#include <cm_bzlib.h>
#endif
#if HAVE_LZMA_H
-#include <lzma.h>
+#include <cm_lzma.h>
#endif
#ifdef HAVE_ZLIB_H
#include <cm_zlib.h>
@@ -205,7 +205,7 @@ struct _7zip {
/*
* 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.
+ * We use 'next' (a member of struct file) to chain.
*/
struct {
struct file *first;
@@ -1358,7 +1358,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size,
if (r < 0)
return (r);
- /* Write Nume size. */
+ /* Write Name size. */
r = enc_uint64(a, zip->total_bytes_entry_name+1);
if (r < 0)
return (r);
@@ -1450,6 +1450,10 @@ _7z_free(struct archive_write *a)
{
struct _7zip *zip = (struct _7zip *)a->format_data;
+ /* Close the temporary file. */
+ if (zip->temp_fd >= 0)
+ close(zip->temp_fd);
+
file_free_register(zip);
compression_end(&(a->archive), &(zip->stream));
free(zip->coder.props);
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
index 9f17564c3..c9771d81a 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c
@@ -126,12 +126,11 @@ archive_write_set_format_ar(struct archive_write *a)
if (a->format_free != NULL)
(a->format_free)(a);
- ar = (struct ar_w *)malloc(sizeof(*ar));
+ ar = (struct ar_w *)calloc(1, sizeof(*ar));
if (ar == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data");
return (ARCHIVE_FATAL);
}
- memset(ar, 0, sizeof(*ar));
a->format_data = ar;
a->format_name = "ar";
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c
index af3105e48..a2ce7c6cd 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_by_name.c
@@ -63,12 +63,14 @@ struct { const char *name; int (*setter)(struct archive *); } names[] =
{ "pax", archive_write_set_format_pax },
{ "paxr", archive_write_set_format_pax_restricted },
{ "posix", archive_write_set_format_pax },
+ { "raw", archive_write_set_format_raw },
{ "rpax", archive_write_set_format_pax_restricted },
{ "shar", archive_write_set_format_shar },
{ "shardump", archive_write_set_format_shar_dump },
{ "ustar", archive_write_set_format_ustar },
{ "v7tar", archive_write_set_format_v7tar },
{ "v7", archive_write_set_format_v7tar },
+ { "warc", archive_write_set_format_warc },
{ "xar", archive_write_set_format_xar },
{ "zip", archive_write_set_format_zip },
{ NULL, NULL }
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c
index 352649365..a4c9d1ed2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c
@@ -289,7 +289,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
sconv = get_sconv(a);
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c
index a9bfa808c..957f1a333 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c
@@ -116,12 +116,11 @@ archive_write_set_format_cpio_newc(struct archive *_a)
if (a->format_free != NULL)
(a->format_free)(a);
- cpio = (struct cpio *)malloc(sizeof(*cpio));
+ cpio = (struct cpio *)calloc(1, sizeof(*cpio));
if (cpio == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
- memset(cpio, 0, sizeof(*cpio));
a->format_data = cpio;
a->format_name = "cpio";
a->format_options = archive_write_newc_options;
@@ -232,7 +231,7 @@ write_header(struct archive_write *a, struct archive_entry *entry)
sconv = get_sconv(a);
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_filter_by_ext.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_filter_by_ext.c
new file mode 100644
index 000000000..adec9b265
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_filter_by_ext.c
@@ -0,0 +1,142 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2015 Okhotnikov Kirill
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 201168 2009-12-29 06:15:32Z kientzle $");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+
+/* A table that maps names to functions. */
+static
+struct { const char *name; int (*format)(struct archive *); int (*filter)(struct archive *); } names[] =
+{
+ { ".7z", archive_write_set_format_7zip, archive_write_add_filter_none},
+ { ".zip", archive_write_set_format_zip, archive_write_add_filter_none},
+ { ".jar", archive_write_set_format_zip, archive_write_add_filter_none},
+ { ".cpio", archive_write_set_format_cpio, archive_write_add_filter_none},
+ { ".iso", archive_write_set_format_iso9660, archive_write_add_filter_none},
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__)
+ { ".a", archive_write_set_format_ar_bsd, archive_write_add_filter_none},
+ { ".ar", archive_write_set_format_ar_bsd, archive_write_add_filter_none},
+#else
+ { ".a", archive_write_set_format_ar_svr4, archive_write_add_filter_none},
+ { ".ar", archive_write_set_format_ar_svr4, archive_write_add_filter_none},
+#endif
+ { ".tar", archive_write_set_format_pax_restricted, archive_write_add_filter_none},
+ { ".tgz", archive_write_set_format_pax_restricted, archive_write_add_filter_gzip},
+ { ".tar.gz", archive_write_set_format_pax_restricted, archive_write_add_filter_gzip},
+ { ".tar.bz2", archive_write_set_format_pax_restricted, archive_write_add_filter_bzip2},
+ { ".tar.xz", archive_write_set_format_pax_restricted, archive_write_add_filter_xz},
+ { NULL, NULL, NULL }
+};
+
+static
+int cmpsuff(const char *str, const char *suffix)
+{
+ size_t length_str, length_suffix;
+
+ if ((str == NULL) || (suffix == NULL))
+ return -1;
+
+ length_str = strlen(str);
+ length_suffix = strlen(suffix);
+
+ if (length_str >= length_suffix) {
+ return strcmp(str + (length_str - length_suffix), suffix);
+ } else {
+ return -1;
+ }
+}
+
+static int get_array_index(const char *name)
+{
+ int i;
+
+ for (i = 0; names[i].name != NULL; i++)
+ {
+ if (cmpsuff(name, names[i].name) == 0)
+ return i;
+ }
+ return -1;
+
+}
+
+int
+archive_write_set_format_filter_by_ext(struct archive *a, const char *filename)
+{
+ int names_index = get_array_index(filename);
+
+ if (names_index >= 0)
+ {
+ int format_state = (names[names_index].format)(a);
+ if (format_state == ARCHIVE_OK)
+ return ((names[names_index].filter)(a));
+ else
+ return format_state;
+ }
+
+ archive_set_error(a, EINVAL, "No such format '%s'", filename);
+ a->state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+}
+
+int
+archive_write_set_format_filter_by_ext_def(struct archive *a, const char *filename, const char * def_ext)
+{
+ int names_index = get_array_index(filename);
+
+ if (names_index < 0)
+ names_index = get_array_index(def_ext);
+
+ if (names_index >= 0)
+ {
+ int format_state = (names[names_index].format)(a);
+ if (format_state == ARCHIVE_OK)
+ return ((names[names_index].filter)(a));
+ else
+ return format_state;
+ }
+
+ archive_set_error(a, EINVAL, "No such format '%s'", filename);
+ a->state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+}
+
+
+
+
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c
index 13942c132..2d858c9f7 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c
@@ -119,9 +119,9 @@ static const char template_header[] = {
'0','0','0','0','0','0', '0','\0',
/* gid, null termination: 8 bytes */
'0','0','0','0','0','0', '0','\0',
- /* size, space termation: 12 bytes */
+ /* size, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', '\0',
- /* mtime, space termation: 12 bytes */
+ /* mtime, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', '\0',
/* Initial checksum value: 8 spaces */
' ',' ',' ',' ',' ',' ',' ',' ',
@@ -368,7 +368,7 @@ archive_write_gnutar_header(struct archive_write *a,
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
@@ -467,7 +467,7 @@ archive_write_gnutar_header(struct archive_write *a,
}
}
if (gnutar->linkname_length > GNUTAR_linkname_size) {
- size_t todo = gnutar->linkname_length;
+ size_t length = gnutar->linkname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them;
@@ -476,19 +476,20 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink");
- archive_entry_set_size(temp, gnutar->linkname_length + 1);
+ archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'K');
+ archive_entry_free(temp);
if (ret < ARCHIVE_WARN)
goto exit_write_header;
ret = __archive_write_output(a, buff, 512);
- if(ret < ARCHIVE_WARN)
+ if (ret < ARCHIVE_WARN)
goto exit_write_header;
- archive_entry_free(temp);
- /* Write as many 512 bytes blocks as needed to write full name. */
- ret = __archive_write_output(a, gnutar->linkname, todo);
- if(ret < ARCHIVE_WARN)
+ /* Write name and trailing null byte. */
+ ret = __archive_write_output(a, gnutar->linkname, length);
+ if (ret < ARCHIVE_WARN)
goto exit_write_header;
- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
+ /* Pad to 512 bytes */
+ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN)
goto exit_write_header;
}
@@ -496,7 +497,7 @@ archive_write_gnutar_header(struct archive_write *a,
/* If pathname is longer than 100 chars we need to add an 'L' header. */
if (gnutar->pathname_length > GNUTAR_name_size) {
const char *pathname = gnutar->pathname;
- size_t todo = gnutar->pathname_length;
+ size_t length = gnutar->pathname_length + 1;
struct archive_entry *temp = archive_entry_new2(&a->archive);
/* Uname/gname here don't really matter since no one reads them;
@@ -505,19 +506,20 @@ archive_write_gnutar_header(struct archive_write *a,
archive_entry_set_gname(temp, "wheel");
archive_entry_set_pathname(temp, "././@LongLink");
- archive_entry_set_size(temp, gnutar->pathname_length + 1);
+ archive_entry_set_size(temp, length);
ret = archive_format_gnutar_header(a, buff, temp, 'L');
+ archive_entry_free(temp);
if (ret < ARCHIVE_WARN)
goto exit_write_header;
ret = __archive_write_output(a, buff, 512);
if(ret < ARCHIVE_WARN)
goto exit_write_header;
- archive_entry_free(temp);
- /* Write as many 512 bytes blocks as needed to write full name. */
- ret = __archive_write_output(a, pathname, todo);
+ /* Write pathname + trailing null byte. */
+ ret = __archive_write_output(a, pathname, length);
if(ret < ARCHIVE_WARN)
goto exit_write_header;
- ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)todo));
+ /* Pad to multiple of 512 bytes. */
+ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length));
if (ret < ARCHIVE_WARN)
goto exit_write_header;
}
@@ -644,18 +646,18 @@ archive_format_gnutar_header(struct archive_write *a, char h[512],
format_octal(archive_entry_mode(entry) & 07777,
h + GNUTAR_mode_offset, GNUTAR_mode_size);
- /* TODO: How does GNU tar handle large UIDs? */
- if (format_octal(archive_entry_uid(entry),
- h + GNUTAR_uid_offset, GNUTAR_uid_size)) {
+ /* GNU tar supports base-256 here, so should never overflow. */
+ if (format_number(archive_entry_uid(entry), h + GNUTAR_uid_offset,
+ GNUTAR_uid_size, GNUTAR_uid_max_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric user ID %jd too large",
(intmax_t)archive_entry_uid(entry));
ret = ARCHIVE_FAILED;
}
- /* TODO: How does GNU tar handle large GIDs? */
- if (format_octal(archive_entry_gid(entry),
- h + GNUTAR_gid_offset, GNUTAR_gid_size)) {
+ /* GNU tar supports base-256 here, so should never overflow. */
+ if (format_number(archive_entry_gid(entry), h + GNUTAR_gid_offset,
+ GNUTAR_gid_size, GNUTAR_gid_max_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric group ID %jd too large",
(intmax_t)archive_entry_gid(entry));
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
index e7226256b..4adf68e68 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c
@@ -161,7 +161,7 @@ struct isofile {
/* Used for managing struct isofile list. */
struct isofile *allnext;
struct isofile *datanext;
- /* Used for managing a hardlined struct isofile list. */
+ /* Used for managing a hardlinked struct isofile list. */
struct isofile *hlnext;
struct isofile *hardlink_target;
@@ -436,7 +436,7 @@ struct iso_option {
* Type : string
* Default: Auto detect
* : We check a size of boot image;
- * : If ths size is just 1.22M/1.44M/2.88M,
+ * : If the size is just 1.22M/1.44M/2.88M,
* : we assume boot_type is 'fd';
* : otherwise boot_type is 'no-emulation'.
* COMPAT :
@@ -528,7 +528,7 @@ struct iso_option {
* - allow more then 8 depths of directory trees;
* - disable a version number to a File Name;
* - disable a forced period to the tail of a File Name;
- * - the maxinum length of files and directories is raised to 193.
+ * - the maximum length of files and directories is raised to 193.
* if rockridge option is disabled, raised to 207.
*/
unsigned int iso_level:3;
@@ -626,7 +626,7 @@ struct iso_option {
* : NOTE Our rockridge=useful option does not set a zero
* : to uid and gid, you should use application
* : option such as --gid,--gname,--uid and --uname
- * : badtar options instead.
+ * : bsdtar options instead.
* Type : boolean/string
* Default: Enabled as rockridge=useful
* COMPAT : mkisofs -r / -R
@@ -660,7 +660,7 @@ struct iso_option {
* : for making zisofs.
* : When the file size is less than one Logical Block
* : size, that file will not zisofs'ed since it does
- * : reduece an ISO-image size.
+ * : reduce an ISO-image size.
* :
* : When you specify option 'boot=<boot-image>', that
* : 'boot-image' file won't be converted to zisofs file.
@@ -680,7 +680,7 @@ struct iso9660 {
/* The creation time of ISO image. */
time_t birth_time;
/* A file stream of a temporary file, which file contents
- * save to until ISO iamge can be created. */
+ * save to until ISO image can be created. */
int temp_fd;
struct isofile *cur_file;
@@ -703,7 +703,7 @@ struct iso9660 {
} all_file_list;
/* A list of struct isofile entries which have its
- * contents and are not a directory, a hardlined file
+ * contents and are not a directory, a hardlinked file
* and a symlink file. */
struct {
struct isofile *first;
@@ -1907,9 +1907,9 @@ iso9660_close(struct archive_write *a)
iso9660->primary.rootent);
if (ret < 0)
return (ret);
- /* Make sure we have UTF-16BE convertors.
- * if there is no file entry, convertors are still
- * uninitilized. */
+ /* Make sure we have UTF-16BE converters.
+ * if there is no file entry, converters are still
+ * uninitialized. */
if (iso9660->sconv_to_utf16be == NULL) {
iso9660->sconv_to_utf16be =
archive_string_conversion_to_charset(
@@ -1995,7 +1995,7 @@ iso9660_close(struct archive_write *a)
* Write an ISO 9660 image.
*/
- /* Switc to start using wbuff as file buffer. */
+ /* Switch to start using wbuff as file buffer. */
iso9660->wbuff_remaining = wb_buffmax();
iso9660->wbuff_type = WB_TO_STREAM;
iso9660->wbuff_offset = 0;
@@ -2524,7 +2524,8 @@ get_tmfromtime(struct tm *tm, time_t *t)
tzset();
localtime_r(t, tm);
#elif HAVE__LOCALTIME64_S
- _localtime64_s(tm, t);
+ __time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits
+ _localtime64_s(tm, &tmp_t);
#else
memcpy(tm, localtime(t), sizeof(*tm));
#endif
@@ -2553,7 +2554,7 @@ set_date_time(unsigned char *p, time_t t)
static void
set_date_time_null(unsigned char *p)
{
- memset(p, '0', 16);
+ memset(p, (int)'0', 16);
p[16] = 0;
}
@@ -2719,6 +2720,16 @@ extra_get_record(struct isoent *isoent, int *space, int *off, int *loc)
rec->offset = 0;
/* Insert `rec` into the tail of isoent->extr_rec_list */
rec->next = NULL;
+ /*
+ * Note: testing isoent->extr_rec_list.last == NULL
+ * here is really unneeded since it has been already
+ * initialized at isoent_new function but Clang Static
+ * Analyzer claims that it is dereference of null
+ * pointer.
+ */
+ if (isoent->extr_rec_list.last == NULL)
+ isoent->extr_rec_list.last =
+ &(isoent->extr_rec_list.first);
*isoent->extr_rec_list.last = rec;
isoent->extr_rec_list.last = &(rec->next);
}
@@ -2949,7 +2960,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
gid = archive_entry_gid(file->entry);
if (iso9660->opt.rr == OPT_RR_USEFUL) {
/*
- * This action is simular mkisofs -r option
+ * This action is similar to mkisofs -r option
* but our rockridge=useful option does not
* set a zero to uid and gid.
*/
@@ -3014,8 +3025,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
* +----+----+----+----+----+
* 10 11 12 13 14 15
*
- * - cflg : flag of componet
- * - clen : length of componet
+ * - cflg : flag of component
+ * - clen : length of component
*/
const char *sl;
char sl_last;
@@ -3098,7 +3109,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len,
/*
* flg len
* +----+----+
- * | 02 | 00 | CURREENT component.
+ * | 02 | 00 | CURRENT component.
* +----+----+ (".")
*/
if (nc != NULL) {
@@ -3937,7 +3948,7 @@ write_VD(struct archive_write *a, struct vdd *vdd)
"Abstract File", 0, D_CHAR);
if (r != ARCHIVE_OK)
return (r);
- /* Bibliongraphic File Identifier */
+ /* Bibliographic File Identifier */
r = set_file_identifier(bp, 777, 813, vdc, a, vdd,
&(iso9660->bibliographic_file_identifier),
"Bibliongraphic File", 0, D_CHAR);
@@ -4063,7 +4074,10 @@ write_information_block(struct archive_write *a)
memset(info.s, 0, info_size);
opt = 0;
#if defined(HAVE__CTIME64_S)
- _ctime64_s(buf, sizeof(buf), &(iso9660->birth_time));
+ {
+ __time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
+ _ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
+ }
#elif defined(HAVE_CTIME_R)
ctime_r(&(iso9660->birth_time), buf);
#else
@@ -4548,7 +4562,7 @@ write_file_descriptors(struct archive_write *a)
file->cur_content = &(file->content);
do {
blocks += file->cur_content->blocks;
- /* Next fragument */
+ /* Next fragment */
file->cur_content = file->cur_content->next;
} while (file->cur_content != NULL);
}
@@ -4738,7 +4752,7 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file)
}
/*
- * Converte a filename to UTF-16BE.
+ * Convert a filename to UTF-16BE.
*/
if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len,
iso9660->sconv_to_utf16be)) {
@@ -5502,7 +5516,7 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location)
file->cur_content->location = location;
location += file->cur_content->blocks;
total_block += file->cur_content->blocks;
- /* Next fragument */
+ /* Next fragment */
file->cur_content = file->cur_content->next;
} while (file->cur_content != NULL);
}
@@ -6125,7 +6139,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
off = ffmax - extlen;
if (off == 0) {
/* A dot('.') character
- * does't place to the first
+ * doesn't place to the first
* byte of identifier. */
off ++;
extlen --;
@@ -6154,7 +6168,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent,
np->id_len = l = ext_off + np->ext_len;
/* Make an offset of the number which is used to be set
- * hexadecimal number to avoid duplicate identififier. */
+ * hexadecimal number to avoid duplicate identifier. */
if (iso9660->opt.iso_level == 1) {
if (ext_off >= 5)
noff = 5;
@@ -6215,7 +6229,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
unsigned char *p;
size_t l;
int r;
- int ffmax, parent_len;
+ size_t ffmax, parent_len;
static const struct archive_rb_tree_ops rb_ops = {
isoent_cmp_node_joliet, isoent_cmp_key_joliet
};
@@ -6229,7 +6243,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
else
ffmax = 128;
- r = idr_start(a, idr, isoent->children.cnt, ffmax, 6, 2, &rb_ops);
+ r = idr_start(a, idr, isoent->children.cnt, (int)ffmax, 6, 2, &rb_ops);
if (r < 0)
return (r);
@@ -6242,7 +6256,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
int ext_off, noff, weight;
size_t lt;
- if ((int)(l = np->file->basename_utf16.length) > ffmax)
+ if ((l = np->file->basename_utf16.length) > ffmax)
l = ffmax;
p = malloc((l+1)*2);
@@ -6275,7 +6289,7 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/*
* Get a length of MBS of a full-pathname.
*/
- if ((int)np->file->basename_utf16.length > ffmax) {
+ if (np->file->basename_utf16.length > ffmax) {
if (archive_strncpy_l(&iso9660->mbs,
(const char *)np->identifier, l,
iso9660->sconv_from_utf16be) != 0 &&
@@ -6292,7 +6306,9 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/* If a length of full-pathname is longer than 240 bytes,
* it violates Joliet extensions regulation. */
- if (parent_len + np->mb_len > 240) {
+ if (parent_len > 240
+ || np->mb_len > 240
+ || parent_len + np->mb_len > 240) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"The regulation of Joliet extensions;"
" A length of a full-pathname of `%s' is "
@@ -6304,11 +6320,11 @@ isoent_gen_joliet_identifier(struct archive_write *a, struct isoent *isoent,
/* Make an offset of the number which is used to be set
* hexadecimal number to avoid duplicate identifier. */
- if ((int)l == ffmax)
+ if (l == ffmax)
noff = ext_off - 6;
- else if ((int)l == ffmax-2)
+ else if (l == ffmax-2)
noff = ext_off - 4;
- else if ((int)l == ffmax-4)
+ else if (l == ffmax-4)
noff = ext_off - 2;
else
noff = ext_off;
@@ -6730,7 +6746,7 @@ isoent_rr_move(struct archive_write *a)
int r;
pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]);
- /* Theare aren't level 8 directories reaching a deepr level. */
+ /* There aren't level 8 directories reaching a deeper level. */
if (pt->cnt == 0)
return (ARCHIVE_OK);
@@ -6801,7 +6817,7 @@ _compare_path_table(const void *v1, const void *v2)
if (cmp != 0)
return (cmp);
- /* Compare indetifier */
+ /* Compare identifier */
s1 = p1->identifier;
s2 = p2->identifier;
l = p1->ext_off;
@@ -6843,7 +6859,7 @@ _compare_path_table_joliet(const void *v1, const void *v2)
if (cmp != 0)
return (cmp);
- /* Compare indetifier */
+ /* Compare identifier */
s1 = (const unsigned char *)p1->identifier;
s2 = (const unsigned char *)p2->identifier;
l = p1->ext_off;
@@ -7137,7 +7153,7 @@ isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent)
iso9660->el_torito.catalog = isoent;
/*
- * Get a boot medai type.
+ * Get a boot media type.
*/
switch (iso9660->opt.boot_type) {
default:
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c
index 9c0613c9b..493d47356 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c
@@ -35,7 +35,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_mtree.c 201171
#include <string.h>
#include "archive.h"
-#include "archive_crypto_private.h"
+#include "archive_digest_private.h"
#include "archive_entry.h"
#include "archive_private.h"
#include "archive_rb.h"
@@ -128,6 +128,9 @@ struct mtree_entry {
unsigned long fflags_clear;
dev_t rdevmajor;
dev_t rdevminor;
+ dev_t devmajor;
+ dev_t devminor;
+ int64_t ino;
};
struct mtree_writer {
@@ -210,6 +213,9 @@ struct mtree_writer {
#define F_SHA256 0x00800000 /* SHA-256 digest */
#define F_SHA384 0x01000000 /* SHA-384 digest */
#define F_SHA512 0x02000000 /* SHA-512 digest */
+#define F_INO 0x04000000 /* inode number */
+#define F_RESDEV 0x08000000 /* device ID on which the
+ * entry resides */
/* Options */
int dironly; /* If it is set, ignore all files except
@@ -633,7 +639,7 @@ attr_counter_inc(struct attr_counter **top, struct attr_counter *ac,
*top = ac;
ac->next->prev = ac;
}
- } else {
+ } else if (last != NULL) {
ac = attr_counter_new(me, last);
if (ac == NULL)
return (-1);
@@ -823,8 +829,11 @@ mtree_entry_new(struct archive_write *a, struct archive_entry *entry,
archive_entry_fflags(entry, &me->fflags_set, &me->fflags_clear);
me->mtime = archive_entry_mtime(entry);
me->mtime_nsec = archive_entry_mtime_nsec(entry);
- me->rdevmajor = archive_entry_rdevmajor(entry);
+ me->rdevmajor = archive_entry_rdevmajor(entry);
me->rdevminor = archive_entry_rdevminor(entry);
+ me->devmajor = archive_entry_devmajor(entry);
+ me->devminor = archive_entry_devminor(entry);
+ me->ino = archive_entry_ino(entry);
me->size = archive_entry_size(entry);
if (me->filetype == AE_IFDIR) {
me->dir_info = calloc(1, sizeof(*me->dir_info));
@@ -882,7 +891,7 @@ archive_write_mtree_header(struct archive_write *a,
mtree->first = 0;
archive_strcat(&mtree->buf, "#mtree\n");
if ((mtree->keys & SET_KEYS) == 0)
- mtree->output_global_set = 0;/* Disalbed. */
+ mtree->output_global_set = 0;/* Disabled. */
}
mtree->entry_bytes_remaining = archive_entry_size(entry);
@@ -983,6 +992,15 @@ write_mtree_entry(struct archive_write *a, struct mtree_entry *me)
if ((keys & F_UID) != 0)
archive_string_sprintf(str, " uid=%jd", (intmax_t)me->uid);
+ if ((keys & F_INO) != 0)
+ archive_string_sprintf(str, " inode=%jd", (intmax_t)me->ino);
+ if ((keys & F_RESDEV) != 0) {
+ archive_string_sprintf(str,
+ " resdevice=native,%ju,%ju",
+ (uintmax_t)me->devmajor,
+ (uintmax_t)me->devminor);
+ }
+
switch (me->filetype) {
case AE_IFLNK:
if ((keys & F_TYPE) != 0)
@@ -1097,7 +1115,7 @@ write_mtree_entry_tree(struct archive_write *a)
do {
if (mtree->output_global_set) {
/*
- * Collect attribute infomation to know which value
+ * Collect attribute information to know which value
* is frequently used among the children.
*/
attr_counter_set_reset(mtree);
@@ -1117,7 +1135,7 @@ write_mtree_entry_tree(struct archive_write *a)
} else {
/* Whenever output_global_set is enabled
* output global value(/set keywords)
- * even if the directory entry is not allowd
+ * even if the directory entry is not allowed
* to be written because the global values
* can be used for the children. */
if (mtree->output_global_set)
@@ -1296,6 +1314,8 @@ archive_write_mtree_options(struct archive_write *a, const char *key,
if (strcmp(key, "indent") == 0) {
mtree->indent = (value != NULL)? 1: 0;
return (ARCHIVE_OK);
+ } else if (strcmp(key, "inode") == 0) {
+ keybit = F_INO;
}
break;
case 'l':
@@ -1314,7 +1334,9 @@ archive_write_mtree_options(struct archive_write *a, const char *key,
keybit = F_NLINK;
break;
case 'r':
- if (strcmp(key, "ripemd160digest") == 0 ||
+ if (strcmp(key, "resdevice") == 0) {
+ keybit = F_RESDEV;
+ } else if (strcmp(key, "ripemd160digest") == 0 ||
strcmp(key, "rmd160") == 0 ||
strcmp(key, "rmd160digest") == 0)
keybit = F_RMD160;
@@ -1818,9 +1840,9 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
len = strlen(p);
/*
- * Add "./" prefiex.
+ * Add "./" prefix.
* NOTE: If the pathname does not have a path separator, we have
- * to add "./" to the head of the pathename because mtree reader
+ * to add "./" to the head of the pathname because mtree reader
* will suppose that it is v1(a.k.a classic) mtree format and
* change the directory unexpectedly and so it will make a wrong
* path.
@@ -1855,9 +1877,9 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file,
return (ret);
}
- /* Make a basename from dirname and slash */
+ /* Make a basename from file->parentdir.s and slash */
*slash = '\0';
- file->parentdir.length = slash - dirname;
+ file->parentdir.length = slash - file->parentdir.s;
archive_strcpy(&(file->basename), slash + 1);
return (ret);
}
@@ -2198,6 +2220,9 @@ mtree_entry_exchange_same_entry(struct archive_write *a, struct mtree_entry *np,
np->mtime_nsec = file->mtime_nsec;
np->rdevmajor = file->rdevmajor;
np->rdevminor = file->rdevminor;
+ np->devmajor = file->devmajor;
+ np->devminor = file->devminor;
+ np->ino = file->ino;
return (ARCHIVE_WARN);
}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
index 687f8e48a..6a301ac2d 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -61,15 +62,24 @@ struct pax {
struct sparse_block *sparse_tail;
struct archive_string_conv *sconv_utf8;
int opt_binary;
+
+ unsigned flags;
+#define WRITE_SCHILY_XATTR (1 << 0)
+#define WRITE_LIBARCHIVE_XATTR (1 << 1)
};
static void add_pax_attr(struct archive_string *, const char *key,
const char *value);
+static void add_pax_attr_binary(struct archive_string *,
+ const char *key,
+ const char *value, size_t value_len);
static void add_pax_attr_int(struct archive_string *,
const char *key, int64_t value);
static void add_pax_attr_time(struct archive_string *,
const char *key, int64_t sec,
unsigned long nanos);
+static int add_pax_acl(struct archive_write *,
+ struct archive_entry *, struct pax *, int);
static ssize_t archive_write_pax_data(struct archive_write *,
const void *, size_t);
static int archive_write_pax_close(struct archive_write *);
@@ -127,13 +137,14 @@ archive_write_set_format_pax(struct archive *_a)
if (a->format_free != NULL)
(a->format_free)(a);
- pax = (struct pax *)malloc(sizeof(*pax));
+ pax = (struct pax *)calloc(1, sizeof(*pax));
if (pax == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate pax data");
return (ARCHIVE_FATAL);
}
- memset(pax, 0, sizeof(*pax));
+ pax->flags = WRITE_LIBARCHIVE_XATTR | WRITE_SCHILY_XATTR;
+
a->format_data = pax;
a->format_name = "pax";
a->format_options = archive_write_pax_options;
@@ -273,6 +284,17 @@ add_pax_attr_int(struct archive_string *as, const char *key, int64_t value)
static void
add_pax_attr(struct archive_string *as, const char *key, const char *value)
{
+ add_pax_attr_binary(as, key, value, strlen(value));
+}
+
+/*
+ * Add a key/value attribute to the pax header. This function handles
+ * binary values.
+ */
+static void
+add_pax_attr_binary(struct archive_string *as, const char *key,
+ const char *value, size_t value_len)
+{
int digits, i, len, next_ten;
char tmp[1 + 3 * sizeof(int)]; /* < 3 base-10 digits per byte */
@@ -280,7 +302,7 @@ add_pax_attr(struct archive_string *as, const char *key, const char *value)
* PAX attributes have the following layout:
* <len> <space> <key> <=> <value> <nl>
*/
- len = 1 + (int)strlen(key) + 1 + (int)strlen(value) + 1;
+ len = 1 + (int)strlen(key) + 1 + (int)value_len + 1;
/*
* The <len> field includes the length of the <len> field, so
@@ -311,21 +333,47 @@ add_pax_attr(struct archive_string *as, const char *key, const char *value)
archive_strappend_char(as, ' ');
archive_strcat(as, key);
archive_strappend_char(as, '=');
- archive_strcat(as, value);
+ archive_array_append(as, value, value_len);
archive_strappend_char(as, '\n');
}
+static void
+archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name,
+ const void *value, size_t value_len)
+{
+ struct archive_string s;
+ char *encoded_value;
+
+ if (pax->flags & WRITE_LIBARCHIVE_XATTR) {
+ encoded_value = base64_encode((const char *)value, value_len);
+
+ if (encoded_name != NULL && encoded_value != NULL) {
+ archive_string_init(&s);
+ archive_strcpy(&s, "LIBARCHIVE.xattr.");
+ archive_strcat(&s, encoded_name);
+ add_pax_attr(&(pax->pax_header), s.s, encoded_value);
+ archive_string_free(&s);
+ }
+ free(encoded_value);
+ }
+ if (pax->flags & WRITE_SCHILY_XATTR) {
+ archive_string_init(&s);
+ archive_strcpy(&s, "SCHILY.xattr.");
+ archive_strcat(&s, encoded_name);
+ add_pax_attr_binary(&(pax->pax_header), s.s, value, value_len);
+ archive_string_free(&s);
+ }
+}
+
static int
archive_write_pax_header_xattrs(struct archive_write *a,
struct pax *pax, struct archive_entry *entry)
{
- struct archive_string s;
int i = archive_entry_xattr_reset(entry);
while (i--) {
const char *name;
const void *value;
- char *encoded_value;
char *url_encoded_name = NULL, *encoded_name = NULL;
size_t size;
int r;
@@ -346,16 +394,9 @@ archive_write_pax_header_xattrs(struct archive_write *a,
}
}
- encoded_value = base64_encode((const char *)value, size);
+ archive_write_pax_header_xattr(pax, encoded_name,
+ value, size);
- if (encoded_name != NULL && encoded_value != NULL) {
- archive_string_init(&s);
- archive_strcpy(&s, "LIBARCHIVE.xattr.");
- archive_strcat(&s, encoded_name);
- add_pax_attr(&(pax->pax_header), s.s, encoded_value);
- archive_string_free(&s);
- }
- free(encoded_value);
}
return (ARCHIVE_OK);
}
@@ -450,6 +491,45 @@ get_entry_symlink(struct archive_write *a, struct archive_entry *entry,
return (ARCHIVE_OK);
}
+/* Add ACL to pax header */
+static int
+add_pax_acl(struct archive_write *a,
+ struct archive_entry *entry, struct pax *pax, int flags)
+{
+ char *p;
+ const char *attr;
+ int acl_types;
+
+ acl_types = archive_entry_acl_types(entry);
+
+ if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
+ attr = "SCHILY.acl.ace";
+ else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ attr = "SCHILY.acl.access";
+ else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ attr = "SCHILY.acl.default";
+ else
+ return (ARCHIVE_FATAL);
+
+ p = archive_entry_acl_to_text_l(entry, NULL, flags, pax->sconv_utf8);
+ if (p == NULL) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM, "%s %s",
+ "Can't allocate memory for ", attr);
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s",
+ "Can't translate ", attr, " to UTF-8");
+ return(ARCHIVE_WARN);
+ } else if (*p != '\0') {
+ add_pax_attr(&(pax->pax_header),
+ attr, p);
+ free(p);
+ }
+ return(ARCHIVE_OK);
+}
+
/*
* TODO: Consider adding 'comment' and 'charset' fields to
* archive_entry so that clients can specify them. Also, consider
@@ -466,6 +546,7 @@ archive_write_pax_header(struct archive_write *a,
const char *p;
const char *suffix;
int need_extension, r, ret;
+ int acl_types;
int sparse_count;
uint64_t sparse_total, real_size;
struct pax *pax;
@@ -709,7 +790,7 @@ archive_write_pax_header(struct archive_write *a,
/* Copy entry so we can modify it as needed. */
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry_original);
if (entry_main == entry_original)
@@ -1017,16 +1098,6 @@ archive_write_pax_header(struct archive_write *a,
if (!need_extension && p != NULL && *p != '\0')
need_extension = 1;
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
- need_extension = 1;
-
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
- need_extension = 1;
-
/* If there are extended attributes, we need an extension */
if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
need_extension = 1;
@@ -1035,23 +1106,19 @@ archive_write_pax_header(struct archive_write *a,
if (!need_extension && sparse_count > 0)
need_extension = 1;
- /*
- * The following items are handled differently in "pax
- * restricted" format. In particular, in "pax restricted"
- * format they won't be added unless need_extension is
- * already set (we're already generating an extended header, so
- * may as well include these).
- */
- if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
- need_extension) {
+ acl_types = archive_entry_acl_types(entry_original);
- if (archive_entry_mtime(entry_main) < 0 ||
- archive_entry_mtime(entry_main) >= 0x7fffffff ||
- archive_entry_mtime_nsec(entry_main) != 0)
- add_pax_attr_time(&(pax->pax_header), "mtime",
- archive_entry_mtime(entry_main),
- archive_entry_mtime_nsec(entry_main));
+ /* If there are any ACL entries, we need an extension */
+ if (!need_extension && acl_types != 0)
+ need_extension = 1;
+ /*
+ * Libarchive used to include these in extended headers for
+ * restricted pax format, but that confused people who
+ * expected ustar-like time semantics. So now we only include
+ * them in full pax format.
+ */
+ if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED) {
if (archive_entry_ctime(entry_main) != 0 ||
archive_entry_ctime_nsec(entry_main) != 0)
add_pax_attr_time(&(pax->pax_header), "ctime",
@@ -1072,6 +1139,23 @@ archive_write_pax_header(struct archive_write *a,
"LIBARCHIVE.creationtime",
archive_entry_birthtime(entry_main),
archive_entry_birthtime_nsec(entry_main));
+ }
+
+ /*
+ * The following items are handled differently in "pax
+ * restricted" format. In particular, in "pax restricted"
+ * format they won't be added unless need_extension is
+ * already set (we're already generating an extended header, so
+ * may as well include these).
+ */
+ if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
+ need_extension) {
+ if (archive_entry_mtime(entry_main) < 0 ||
+ archive_entry_mtime(entry_main) >= 0x7fffffff ||
+ archive_entry_mtime_nsec(entry_main) != 0)
+ add_pax_attr_time(&(pax->pax_header), "mtime",
+ archive_entry_mtime(entry_main),
+ archive_entry_mtime_nsec(entry_main));
/* I use a star-compatible file flag attribute. */
p = archive_entry_fflags_text(entry_main);
@@ -1079,43 +1163,29 @@ archive_write_pax_header(struct archive_write *a,
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
/* I use star-compatible ACL attributes. */
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.access");
+ if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA |
+ ARCHIVE_ENTRY_ACL_STYLE_COMPACT);
+ if (ret == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.access to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.access", p);
}
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.default");
+ if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);
+ if (ret == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+ }
+ if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);
+ if (ret == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.default to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.default", p);
}
/* We use GNU-tar-compatible sparse attributes. */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c
new file mode 100644
index 000000000..feff93697
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_raw.c
@@ -0,0 +1,125 @@
+/*-
+ * Copyright (c) 2013 Marek Kubica
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive_entry.h"
+#include "archive_write_private.h"
+
+static ssize_t archive_write_raw_data(struct archive_write *,
+ const void *buff, size_t s);
+static int archive_write_raw_free(struct archive_write *);
+static int archive_write_raw_header(struct archive_write *,
+ struct archive_entry *);
+
+struct raw {
+ int entries_written;
+};
+
+/*
+ * Set output format to 'raw' format.
+ */
+int
+archive_write_set_format_raw(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct raw *raw;
+
+ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_format_raw");
+
+ /* If someone else was already registered, unregister them. */
+ if (a->format_free != NULL)
+ (a->format_free)(a);
+
+ raw = (struct raw *)calloc(1, sizeof(*raw));
+ if (raw == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate raw data");
+ return (ARCHIVE_FATAL);
+ }
+ raw->entries_written = 0;
+ a->format_data = raw;
+ a->format_name = "raw";
+ /* no options exist for this format */
+ a->format_options = NULL;
+ a->format_write_header = archive_write_raw_header;
+ a->format_write_data = archive_write_raw_data;
+ a->format_finish_entry = NULL;
+ /* nothing needs to be done on closing */
+ a->format_close = NULL;
+ a->format_free = archive_write_raw_free;
+ a->archive.archive_format = ARCHIVE_FORMAT_RAW;
+ a->archive.archive_format_name = "RAW";
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_raw_header(struct archive_write *a, struct archive_entry *entry)
+{
+ struct raw *raw = (struct raw *)a->format_data;
+
+ if (archive_entry_filetype(entry) != AE_IFREG) {
+ archive_set_error(&a->archive, ERANGE,
+ "Raw format only supports filetype AE_IFREG");
+ return (ARCHIVE_FATAL);
+ }
+
+
+ if (raw->entries_written > 0) {
+ archive_set_error(&a->archive, ERANGE,
+ "Raw format only supports one entry per archive");
+ return (ARCHIVE_FATAL);
+ }
+ raw->entries_written++;
+
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+archive_write_raw_data(struct archive_write *a, const void *buff, size_t s)
+{
+ int ret;
+
+ ret = __archive_write_output(a, buff, s);
+ if (ret >= 0)
+ return (s);
+ else
+ return (ret);
+}
+
+static int
+archive_write_raw_free(struct archive_write *a)
+{
+ struct raw *raw;
+
+ raw = (struct raw *)a->format_data;
+ free(raw);
+ a->format_data = NULL;
+ return (ARCHIVE_OK);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c
index 9ec15f915..5be310a07 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c
@@ -113,12 +113,11 @@ archive_write_set_format_shar(struct archive *_a)
if (a->format_free != NULL)
(a->format_free)(a);
- shar = (struct shar *)malloc(sizeof(*shar));
+ shar = (struct shar *)calloc(1, sizeof(*shar));
if (shar == NULL) {
archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data");
return (ARCHIVE_FATAL);
}
- memset(shar, 0, sizeof(*shar));
archive_string_init(&shar->work);
archive_string_init(&shar->quoted_name);
a->format_data = shar;
@@ -548,6 +547,7 @@ archive_write_shar_finish_entry(struct archive_write *a)
archive_strcat(&shar->work, ":");
shar_quote(&shar->work, g, 1);
}
+ archive_strcat(&shar->work, " ");
shar_quote(&shar->work,
archive_entry_pathname(shar->entry), 1);
archive_strcat(&shar->work, "\n");
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c
index 484ab34b2..c54aeabdb 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c
@@ -114,9 +114,9 @@ static const char template_header[] = {
'0','0','0','0','0','0', ' ','\0',
/* gid, space-null termination: 8 bytes */
'0','0','0','0','0','0', ' ','\0',
- /* size, space termation: 12 bytes */
+ /* size, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
- /* mtime, space termation: 12 bytes */
+ /* mtime, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
/* Initial checksum value: 8 spaces */
' ',' ',' ',' ',' ',' ',' ',' ',
@@ -184,13 +184,12 @@ archive_write_set_format_ustar(struct archive *_a)
return (ARCHIVE_FATAL);
}
- ustar = (struct ustar *)malloc(sizeof(*ustar));
+ ustar = (struct ustar *)calloc(1, sizeof(*ustar));
if (ustar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate ustar data");
return (ARCHIVE_FATAL);
}
- memset(ustar, 0, sizeof(*ustar));
a->format_data = ustar;
a->format_name = "ustar";
a->format_options = archive_write_ustar_options;
@@ -307,7 +306,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
* case getting WCS failed. On POSIX, this is a
* normal operation.
*/
- if (p != NULL && p[strlen(p) - 1] != '/') {
+ if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') {
struct archive_string as;
archive_string_init(&as);
@@ -336,7 +335,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c
index 17efbaf75..62b152294 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c
@@ -98,9 +98,9 @@ static const char template_header[] = {
'0','0','0','0','0','0', ' ','\0',
/* gid, space-null termination: 8 bytes */
'0','0','0','0','0','0', ' ','\0',
- /* size, space termation: 12 bytes */
+ /* size, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
- /* mtime, space termation: 12 bytes */
+ /* mtime, space termination: 12 bytes */
'0','0','0','0','0','0','0','0','0','0','0', ' ',
/* Initial checksum value: 8 spaces */
' ',' ',' ',' ',' ',' ',' ',' ',
@@ -161,13 +161,12 @@ archive_write_set_format_v7tar(struct archive *_a)
return (ARCHIVE_FATAL);
}
- v7tar = (struct v7tar *)malloc(sizeof(*v7tar));
+ v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar));
if (v7tar == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate v7tar data");
return (ARCHIVE_FATAL);
}
- memset(v7tar, 0, sizeof(*v7tar));
a->format_data = v7tar;
a->format_name = "tar (non-POSIX)";
a->format_options = archive_write_v7tar_options;
@@ -314,7 +313,7 @@ archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry)
}
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
entry_main = __la_win_entry_in_posix_pathseparator(entry);
if (entry_main == NULL) {
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c
new file mode 100644
index 000000000..8b6daf942
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c
@@ -0,0 +1,445 @@
+/*-
+ * Copyright (c) 2014 Sebastian Freundt
+ * Author: Sebastian Freundt <devel@fresse.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_entry_locale.h"
+#include "archive_private.h"
+#include "archive_random_private.h"
+#include "archive_write_private.h"
+
+struct warc_s {
+ unsigned int omit_warcinfo:1;
+
+ time_t now;
+ mode_t typ;
+ unsigned int rng;
+ /* populated size */
+ uint64_t populz;
+};
+
+static const char warcinfo[] =
+ "software: libarchive/" ARCHIVE_VERSION_ONLY_STRING "\r\n"
+ "format: WARC file version 1.0\r\n";
+
+typedef enum {
+ WT_NONE,
+ /* warcinfo */
+ WT_INFO,
+ /* metadata */
+ WT_META,
+ /* resource */
+ WT_RSRC,
+ /* request, unsupported */
+ WT_REQ,
+ /* response, unsupported */
+ WT_RSP,
+ /* revisit, unsupported */
+ WT_RVIS,
+ /* conversion, unsupported */
+ WT_CONV,
+ /* continuation, unsupported at the moment */
+ WT_CONT,
+ /* invalid type */
+ LAST_WT
+} warc_type_t;
+
+typedef struct {
+ warc_type_t type;
+ const char *tgturi;
+ const char *recid;
+ time_t rtime;
+ time_t mtime;
+ const char *cnttyp;
+ uint64_t cntlen;
+} warc_essential_hdr_t;
+
+typedef struct {
+ unsigned int u[4U];
+} warc_uuid_t;
+
+static int _warc_options(struct archive_write*, const char *key, const char *v);
+static int _warc_header(struct archive_write *a, struct archive_entry *entry);
+static ssize_t _warc_data(struct archive_write *a, const void *buf, size_t sz);
+static int _warc_finish_entry(struct archive_write *a);
+static int _warc_close(struct archive_write *a);
+static int _warc_free(struct archive_write *a);
+
+/* private routines */
+static ssize_t _popul_ehdr(struct archive_string *t, size_t z, warc_essential_hdr_t);
+static int _gen_uuid(warc_uuid_t *tgt);
+
+
+/*
+ * Set output format to ISO 28500 (aka WARC) format.
+ */
+int
+archive_write_set_format_warc(struct archive *_a)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ struct warc_s *w;
+
+ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_format_warc");
+
+ /* If another format was already registered, unregister it. */
+ if (a->format_free != NULL) {
+ (a->format_free)(a);
+ }
+
+ w = malloc(sizeof(*w));
+ if (w == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate warc data");
+ return (ARCHIVE_FATAL);
+ }
+ /* by default we're emitting a file wide header */
+ w->omit_warcinfo = 0U;
+ /* obtain current time for date fields */
+ w->now = time(NULL);
+ /* reset file type info */
+ w->typ = 0;
+ /* also initialise our rng */
+ w->rng = (unsigned int)w->now;
+
+ a->format_data = w;
+ a->format_name = "WARC/1.0";
+ a->format_options = _warc_options;
+ a->format_write_header = _warc_header;
+ a->format_write_data = _warc_data;
+ a->format_close = _warc_close;
+ a->format_free = _warc_free;
+ a->format_finish_entry = _warc_finish_entry;
+ a->archive.archive_format = ARCHIVE_FORMAT_WARC;
+ a->archive.archive_format_name = "WARC/1.0";
+ return (ARCHIVE_OK);
+}
+
+
+/* archive methods */
+static int
+_warc_options(struct archive_write *a, const char *key, const char *val)
+{
+ struct warc_s *w = a->format_data;
+
+ if (strcmp(key, "omit-warcinfo") == 0) {
+ if (val == NULL || strcmp(val, "true") == 0) {
+ /* great */
+ w->omit_warcinfo = 1U;
+ 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
+_warc_header(struct archive_write *a, struct archive_entry *entry)
+{
+ struct warc_s *w = a->format_data;
+ struct archive_string hdr;
+#define MAX_HDR_SIZE 512
+
+ /* check whether warcinfo record needs outputting */
+ if (!w->omit_warcinfo) {
+ ssize_t r;
+ warc_essential_hdr_t wi = {
+ WT_INFO,
+ /*uri*/NULL,
+ /*urn*/NULL,
+ /*rtm*/0,
+ /*mtm*/0,
+ /*cty*/"application/warc-fields",
+ /*len*/sizeof(warcinfo) - 1U,
+ };
+ wi.rtime = w->now;
+ wi.mtime = w->now;
+
+ archive_string_init(&hdr);
+ r = _popul_ehdr(&hdr, MAX_HDR_SIZE, wi);
+ if (r >= 0) {
+ /* jackpot! */
+ /* now also use HDR buffer for the actual warcinfo */
+ archive_strncat(&hdr, warcinfo, sizeof(warcinfo) -1);
+
+ /* append end-of-record indicator */
+ archive_strncat(&hdr, "\r\n\r\n", 4);
+
+ /* write to output stream */
+ __archive_write_output(a, hdr.s, archive_strlen(&hdr));
+ }
+ /* indicate we're done with file header writing */
+ w->omit_warcinfo = 1U;
+ archive_string_free(&hdr);
+ }
+
+ if (archive_entry_pathname(entry) == NULL) {
+ archive_set_error(&a->archive, EINVAL,
+ "Invalid filename");
+ return (ARCHIVE_WARN);
+ }
+
+ w->typ = archive_entry_filetype(entry);
+ w->populz = 0U;
+ if (w->typ == AE_IFREG) {
+ warc_essential_hdr_t rh = {
+ WT_RSRC,
+ /*uri*/NULL,
+ /*urn*/NULL,
+ /*rtm*/0,
+ /*mtm*/0,
+ /*cty*/NULL,
+ /*len*/0,
+ };
+ ssize_t r;
+ rh.tgturi = archive_entry_pathname(entry);
+ rh.rtime = w->now;
+ rh.mtime = archive_entry_mtime(entry);
+ rh.cntlen = (size_t)archive_entry_size(entry);
+
+ archive_string_init(&hdr);
+ r = _popul_ehdr(&hdr, MAX_HDR_SIZE, rh);
+ if (r < 0) {
+ /* don't bother */
+ archive_set_error(
+ &a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "cannot archive file");
+ return (ARCHIVE_WARN);
+ }
+ /* otherwise append to output stream */
+ __archive_write_output(a, hdr.s, r);
+ /* and let subsequent calls to _data() know about the size */
+ w->populz = rh.cntlen;
+ archive_string_free(&hdr);
+ return (ARCHIVE_OK);
+ }
+ /* just resort to erroring as per Tim's advice */
+ archive_set_error(
+ &a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
+ "WARC can only process regular files");
+ return (ARCHIVE_FAILED);
+}
+
+static ssize_t
+_warc_data(struct archive_write *a, const void *buf, size_t len)
+{
+ struct warc_s *w = a->format_data;
+
+ if (w->typ == AE_IFREG) {
+ int rc;
+
+ /* never write more bytes than announced */
+ if (len > w->populz) {
+ len = (size_t)w->populz;
+ }
+
+ /* now then, out we put the whole shebang */
+ rc = __archive_write_output(a, buf, len);
+ if (rc != ARCHIVE_OK) {
+ return rc;
+ }
+ }
+ return len;
+}
+
+static int
+_warc_finish_entry(struct archive_write *a)
+{
+ static const char _eor[] = "\r\n\r\n";
+ struct warc_s *w = a->format_data;
+
+ if (w->typ == AE_IFREG) {
+ int rc = __archive_write_output(a, _eor, sizeof(_eor) - 1U);
+
+ if (rc != ARCHIVE_OK) {
+ return rc;
+ }
+ }
+ /* reset type info */
+ w->typ = 0;
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_close(struct archive_write *a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+static int
+_warc_free(struct archive_write *a)
+{
+ struct warc_s *w = a->format_data;
+
+ free(w);
+ a->format_data = NULL;
+ return (ARCHIVE_OK);
+}
+
+
+/* private routines */
+static void
+xstrftime(struct archive_string *as, const char *fmt, time_t t)
+{
+/** like strftime(3) but for time_t objects */
+ struct tm *rt;
+#if defined(HAVE_GMTIME_R) || defined(HAVE__GMTIME64_S)
+ struct tm timeHere;
+#endif
+ char strtime[100];
+ size_t len;
+
+#ifdef HAVE_GMTIME_R
+ if ((rt = gmtime_r(&t, &timeHere)) == NULL)
+ return;
+#elif defined(HAVE__GMTIME64_S)
+ _gmtime64_s(&timeHere, &t);
+#else
+ if ((rt = gmtime(&t)) == NULL)
+ return;
+#endif
+ /* leave the hard yacker to our role model strftime() */
+ len = strftime(strtime, sizeof(strtime)-1, fmt, rt);
+ archive_strncat(as, strtime, len);
+}
+
+static ssize_t
+_popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)
+{
+ static const char _ver[] = "WARC/1.0\r\n";
+ static const char *_typ[LAST_WT] = {
+ NULL, "warcinfo", "metadata", "resource", NULL
+ };
+ char std_uuid[48U];
+
+ if (hdr.type == WT_NONE || hdr.type > WT_RSRC) {
+ /* brilliant, how exactly did we get here? */
+ return -1;
+ }
+
+ archive_strcpy(tgt, _ver);
+
+ archive_string_sprintf(tgt, "WARC-Type: %s\r\n", _typ[hdr.type]);
+
+ if (hdr.tgturi != NULL) {
+ /* check if there's a xyz:// */
+ static const char _uri[] = "";
+ static const char _fil[] = "file://";
+ const char *u;
+ char *chk = strchr(hdr.tgturi, ':');
+
+ if (chk != NULL && chk[1U] == '/' && chk[2U] == '/') {
+ /* yep, it's definitely a URI */
+ u = _uri;
+ } else {
+ /* hm, best to prepend file:// then */
+ u = _fil;
+ }
+ archive_string_sprintf(tgt,
+ "WARC-Target-URI: %s%s\r\n", u, hdr.tgturi);
+ }
+
+ /* record time is usually when the http is sent off,
+ * just treat the archive writing as such for a moment */
+ xstrftime(tgt, "WARC-Date: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.rtime);
+
+ /* while we're at it, record the mtime */
+ xstrftime(tgt, "Last-Modified: %Y-%m-%dT%H:%M:%SZ\r\n", hdr.mtime);
+
+ if (hdr.recid == NULL) {
+ /* generate one, grrrr */
+ warc_uuid_t u;
+
+ _gen_uuid(&u);
+ /* Unfortunately, archive_string_sprintf does not
+ * handle the minimum number following '%'.
+ * So we have to use snprintf function here instead
+ * of archive_string_snprintf function. */
+#if defined(_WIN32) && !defined(__CYGWIN__) && !( defined(_MSC_VER) && _MSC_VER >= 1900)
+#define snprintf _snprintf
+#endif
+ snprintf(
+ std_uuid, sizeof(std_uuid),
+ "<urn:uuid:%08x-%04x-%04x-%04x-%04x%08x>",
+ u.u[0U],
+ u.u[1U] >> 16U, u.u[1U] & 0xffffU,
+ u.u[2U] >> 16U, u.u[2U] & 0xffffU,
+ u.u[3U]);
+ hdr.recid = std_uuid;
+ }
+
+ /* record-id is mandatory, fingers crossed we won't fail */
+ archive_string_sprintf(tgt, "WARC-Record-ID: %s\r\n", hdr.recid);
+
+ if (hdr.cnttyp != NULL) {
+ archive_string_sprintf(tgt, "Content-Type: %s\r\n", hdr.cnttyp);
+ }
+
+ /* next one is mandatory */
+ archive_string_sprintf(tgt, "Content-Length: %ju\r\n", (uintmax_t)hdr.cntlen);
+ /**/
+ archive_strncat(tgt, "\r\n", 2);
+
+ return (archive_strlen(tgt) >= tsz)? -1: (ssize_t)archive_strlen(tgt);
+}
+
+static int
+_gen_uuid(warc_uuid_t *tgt)
+{
+ archive_random(tgt->u, sizeof(tgt->u));
+ /* obey uuid version 4 rules */
+ tgt->u[1U] &= 0xffff0fffU;
+ tgt->u[1U] |= 0x4000U;
+ tgt->u[2U] &= 0x3fffffffU;
+ tgt->u[2U] |= 0x80000000U;
+ return 0;
+}
+
+/* archive_write_set_format_warc.c ends here */
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
index a4ce7ee6f..3c617ecd9 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c
@@ -40,14 +40,14 @@ __FBSDID("$FreeBSD$");
#include <cm_bzlib.h>
#endif
#if HAVE_LZMA_H
-#include <lzma.h>
+#include <cm_lzma.h>
#endif
#ifdef HAVE_ZLIB_H
#include <cm_zlib.h>
#endif
#include "archive.h"
-#include "archive_crypto_private.h"
+#include "archive_digest_private.h"
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
@@ -63,7 +63,7 @@ __FBSDID("$FreeBSD$");
* - 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
+ * libarchive 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
@@ -114,7 +114,7 @@ enum sumalg {
#define MAX_SUM_SIZE 20
#define MD5_NAME "md5"
#define SHA1_NAME "sha1"
-
+
enum enctype {
NONE,
GZIP,
@@ -192,7 +192,7 @@ struct file {
struct file *parent; /* parent directory entry */
/*
* To manage sub directory files.
- * We use 'chnext' a menber of struct file to chain.
+ * We use 'chnext' (a member of struct file) to chain.
*/
struct {
struct file *first;
@@ -242,6 +242,7 @@ struct xar {
enum sumalg opt_sumalg;
enum enctype opt_compression;
int opt_compression_level;
+ uint32_t opt_threads;
struct chksumwork a_sumwrk; /* archived checksum. */
struct chksumwork e_sumwrk; /* extracted checksum. */
@@ -257,7 +258,7 @@ struct xar {
/*
* The list of all file entries is used to manage struct file
* objects.
- * We use 'next' a menber of struct file to chain.
+ * We use 'next' (a member of struct file) to chain.
*/
struct {
struct file *first;
@@ -265,7 +266,7 @@ struct xar {
} file_list;
/*
* The list of hard-linked file entries.
- * We use 'hlnext' a menber of struct file to chain.
+ * We use 'hlnext' (a member of struct file) to chain.
*/
struct archive_rb_tree hardlink_rbtree;
};
@@ -317,7 +318,7 @@ static int compression_end_bzip2(struct archive *, struct la_zstream *);
static int compression_init_encoder_lzma(struct archive *,
struct la_zstream *, int);
static int compression_init_encoder_xz(struct archive *,
- struct la_zstream *, int);
+ struct la_zstream *, int, int);
#if defined(HAVE_LZMA_H)
static int compression_code_lzma(struct archive *,
struct la_zstream *, enum la_zaction);
@@ -380,9 +381,10 @@ archive_write_set_format_xar(struct archive *_a)
/* Set default checksum type. */
xar->opt_toc_sumalg = CKSUM_SHA1;
xar->opt_sumalg = CKSUM_SHA1;
- /* Set default compression type and level. */
+ /* Set default compression type, level, and number of threads. */
xar->opt_compression = GZIP;
xar->opt_compression_level = 6;
+ xar->opt_threads = 1;
a->format_data = xar;
@@ -493,6 +495,26 @@ xar_options(struct archive_write *a, const char *key, const char *value)
}
return (ARCHIVE_OK);
}
+ if (strcmp(key, "threads") == 0) {
+ if (value == NULL)
+ return (ARCHIVE_FAILED);
+ xar->opt_threads = (int)strtoul(value, NULL, 10);
+ if (xar->opt_threads == 0 && errno != 0) {
+ xar->opt_threads = 1;
+ archive_set_error(&(a->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Illegal value `%s'",
+ value);
+ return (ARCHIVE_FAILED);
+ }
+ if (xar->opt_threads == 0) {
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ xar->opt_threads = lzma_cputhreads();
+#else
+ xar->opt_threads = 1;
+#endif
+ }
+ }
/* Note: The "warn" return is just to inform the options
* supervisor that we didn't handle it. It will generate
@@ -805,7 +827,7 @@ xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
if (value == NULL)
return (ARCHIVE_OK);
-
+
r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
if (r < 0) {
archive_set_error(&a->archive,
@@ -1205,7 +1227,7 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
case AE_IFLNK:
/*
* xar utility has checked a file type, which
- * a symblic-link file has referenced.
+ * a symbolic-link file has referenced.
* For example:
* <link type="directory">../ref/</link>
* The symlink target file is "../ref/" and its
@@ -1215,8 +1237,8 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
* 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",
+ * But our implementation cannot do it, and then we
+ * always record that a attribute "type" is "broken",
* for example:
* <link type="broken">foo/bar</link>
* It means "foo/bar" is not reachable.
@@ -1522,7 +1544,7 @@ make_toc(struct archive_write *a)
}
/*
- * Start recoding TOC
+ * Start recording TOC
*/
r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
if (r < 0) {
@@ -1855,6 +1877,11 @@ xar_free(struct archive_write *a)
struct xar *xar;
xar = (struct xar *)a->format_data;
+
+ /* Close the temporary file. */
+ if (xar->temp_fd >= 0)
+ close(xar->temp_fd);
+
archive_string_free(&(xar->cur_dirstr));
archive_string_free(&(xar->tstr));
archive_string_free(&(xar->vstr));
@@ -1875,7 +1902,7 @@ file_cmp_node(const struct archive_rb_node *n1,
return (strcmp(f1->basename.s, f2->basename.s));
}
-
+
static int
file_cmp_key(const struct archive_rb_node *n, const void *key)
{
@@ -1934,6 +1961,7 @@ file_free(struct file *file)
archive_string_free(&(file->basename));
archive_string_free(&(file->symlink));
archive_string_free(&(file->script));
+ archive_entry_free(file->entry);
free(file);
}
@@ -2154,7 +2182,7 @@ file_gen_utility_names(struct archive_write *a, struct file *file)
file->parentdir.length = len;
archive_string_copy(&(file->basename), &(file->parentdir));
archive_string_empty(&(file->parentdir));
- file->parentdir.s = '\0';
+ *file->parentdir.s = '\0';
return (r);
}
@@ -2457,7 +2485,7 @@ file_connect_hardlink_files(struct xar *xar)
archive_entry_set_nlink(target->entry, hl->nlink);
if (hl->nlink > 1)
/* It means this file is a hardlink
- * targe itself. */
+ * target itself. */
target->hardlink_target = target;
for (nf = target->hlnext;
nf != NULL; nf = nf->hlnext) {
@@ -2494,7 +2522,7 @@ 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);
}
@@ -2848,13 +2876,18 @@ compression_init_encoder_lzma(struct archive *a,
static int
compression_init_encoder_xz(struct archive *a,
- struct la_zstream *lastrm, int level)
+ struct la_zstream *lastrm, int level, int threads)
{
static const lzma_stream lzma_init_data = LZMA_STREAM_INIT;
lzma_stream *strm;
lzma_filter *lzmafilters;
lzma_options_lzma lzma_opt;
int r;
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ lzma_mt mt_options;
+#endif
+
+ (void)threads; /* UNUSED (if multi-threaded LZMA library not avail) */
if (lastrm->valid)
compression_end(a, lastrm);
@@ -2879,7 +2912,17 @@ compression_init_encoder_xz(struct archive *a,
lzmafilters[1].id = LZMA_VLI_UNKNOWN;/* Terminate */
*strm = lzma_init_data;
- r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
+#ifdef HAVE_LZMA_STREAM_ENCODER_MT
+ if (threads > 1) {
+ memset(&mt_options, 0, sizeof(mt_options));
+ mt_options.threads = threads;
+ mt_options.timeout = 300;
+ mt_options.filters = lzmafilters;
+ mt_options.check = LZMA_CHECK_CRC64;
+ r = lzma_stream_encoder_mt(strm, &mt_options);
+ } else
+#endif
+ r = lzma_stream_encoder(strm, lzmafilters, LZMA_CHECK_CRC64);
switch (r) {
case LZMA_OK:
lastrm->real_stream = strm;
@@ -2979,10 +3022,11 @@ compression_init_encoder_lzma(struct archive *a,
}
static int
compression_init_encoder_xz(struct archive *a,
- struct la_zstream *lastrm, int level)
+ struct la_zstream *lastrm, int level, int threads)
{
(void) level; /* UNUSED */
+ (void) threads; /* UNUSED */
if (lastrm->valid)
compression_end(a, lastrm);
return (compression_unsupported_encoder(a, lastrm, "xz"));
@@ -3015,7 +3059,7 @@ xar_compression_init_encoder(struct archive_write *a)
case XZ:
r = compression_init_encoder_xz(
&(a->archive), &(xar->stream),
- xar->opt_compression_level);
+ xar->opt_compression_level, xar->opt_threads);
break;
default:
r = ARCHIVE_OK;
@@ -3178,4 +3222,3 @@ getalgname(enum sumalg sumalg)
}
#endif /* Support xar format */
-
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
index 5a9f114f0..a4ae229b2 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c
@@ -1,7 +1,7 @@
/*-
* Copyright (c) 2008 Anselm Strauss
* Copyright (c) 2009 Joerg Sonnenberger
- * Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2011-2012,2014 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -29,24 +29,6 @@
* 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 $");
@@ -67,35 +49,133 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_zip.c 201168 20
#endif
#include "archive.h"
+#include "archive_cryptor_private.h"
#include "archive_endian.h"
#include "archive_entry.h"
#include "archive_entry_locale.h"
+#include "archive_hmac_private.h"
#include "archive_private.h"
+#include "archive_random_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)
+#define ZIP_ENTRY_FLAG_ENCRYPTED (1<<0)
+#define ZIP_ENTRY_FLAG_LENGTH_AT_END (1<<3)
+#define ZIP_ENTRY_FLAG_UTF8_NAME (1 << 11)
+
+#define ZIP_4GB_MAX ARCHIVE_LITERAL_LL(0xffffffff)
+#define ZIP_4GB_MAX_UNCOMPRESSED ARCHIVE_LITERAL_LL(0xff000000)
enum compression {
- COMPRESSION_STORE = 0
-#ifdef HAVE_ZLIB_H
- ,
+ COMPRESSION_UNSPECIFIED = -1,
+ COMPRESSION_STORE = 0,
COMPRESSION_DEFLATE = 8
+};
+
+#ifdef HAVE_ZLIB_H
+#define COMPRESSION_DEFAULT COMPRESSION_DEFLATE
+#else
+#define COMPRESSION_DEFAULT COMPRESSION_STORE
#endif
+
+enum encryption {
+ ENCRYPTION_NONE = 0,
+ ENCRYPTION_TRADITIONAL, /* Traditional PKWARE encryption. */
+ ENCRYPTION_WINZIP_AES128, /* WinZIP AES-128 encryption. */
+ ENCRYPTION_WINZIP_AES256, /* WinZIP AES-256 encryption. */
+};
+
+#define TRAD_HEADER_SIZE 12
+/*
+ * See "WinZip - AES Encryption Information"
+ * http://www.winzip.com/aes_info.htm
+ */
+/* Value used in compression method. */
+#define WINZIP_AES_ENCRYPTION 99
+/* A WinZip AES header size which is stored at the beginning of
+ * file contents. */
+#define WINZIP_AES128_HEADER_SIZE (8 + 2)
+#define WINZIP_AES256_HEADER_SIZE (16 + 2)
+/* AES vendor version. */
+#define AES_VENDOR_AE_1 0x0001
+#define AES_VENDOR_AE_2 0x0002
+/* Authentication code size. */
+#define AUTH_CODE_SIZE 10
+/**/
+#define MAX_DERIVED_KEY_BUF_SIZE (AES_MAX_KEY_SIZE * 2 + 2)
+
+struct cd_segment {
+ struct cd_segment *next;
+ size_t buff_size;
+ unsigned char *buff;
+ unsigned char *p;
+};
+
+struct trad_enc_ctx {
+ uint32_t keys[3];
};
+struct zip {
+
+ int64_t entry_offset;
+ int64_t entry_compressed_size;
+ int64_t entry_uncompressed_size;
+ int64_t entry_compressed_written;
+ int64_t entry_uncompressed_written;
+ int64_t entry_uncompressed_limit;
+ struct archive_entry *entry;
+ uint32_t entry_crc32;
+ enum compression entry_compression;
+ enum encryption entry_encryption;
+ int entry_flags;
+ int entry_uses_zip64;
+ int experiments;
+ struct trad_enc_ctx tctx;
+ char tctx_valid;
+ unsigned char trad_chkdat;
+ unsigned aes_vendor;
+ archive_crypto_ctx cctx;
+ char cctx_valid;
+ archive_hmac_sha1_ctx hctx;
+ char hctx_valid;
+
+ unsigned char *file_header;
+ size_t file_header_extra_offset;
+ unsigned long (*crc32func)(unsigned long crc, const void *buff, size_t len);
+
+ struct cd_segment *central_directory;
+ struct cd_segment *central_directory_last;
+ size_t central_directory_bytes;
+ size_t central_directory_entries;
+
+ int64_t written_bytes; /* Overall position in file. */
+
+ struct archive_string_conv *opt_sconv;
+ struct archive_string_conv *sconv_default;
+ enum compression requested_compression;
+ int deflate_compression_level;
+ int init_default_conversion;
+ enum encryption encryption_type;
+
+#define ZIP_FLAG_AVOID_ZIP64 1
+#define ZIP_FLAG_FORCE_ZIP64 2
+#define ZIP_FLAG_EXPERIMENT_xl 4
+ int flags;
+
+#ifdef HAVE_ZLIB_H
+ z_stream stream;
+#endif
+ size_t len_buf;
+ unsigned char *buf;
+};
+
+/* Don't call this min or MIN, since those are already defined
+ on lots of platforms (but not all). */
+#define zipmin(a, b) ((a) > (b) ? (b) : (a))
+
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 *);
@@ -108,106 +188,65 @@ static int archive_write_zip_options(struct archive_write *,
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 *);
+static void copy_path(struct archive_entry *, unsigned char *);
+static struct archive_string_conv *get_sconv(struct archive_write *, struct zip *);
+static int trad_enc_init(struct trad_enc_ctx *, const char *, size_t);
+static unsigned trad_enc_encrypt_update(struct trad_enc_ctx *, const uint8_t *,
+ size_t, uint8_t *, size_t);
+static int init_traditional_pkware_encryption(struct archive_write *);
+static int is_traditional_pkware_encryption_supported(void);
+static int init_winzip_aes_encryption(struct archive_write *);
+static int is_winzip_aes_encryption_supported(int encryption);
+
+static unsigned char *
+cd_alloc(struct zip *zip, size_t length)
+{
+ unsigned char *p;
+
+ if (zip->central_directory == NULL
+ || (zip->central_directory_last->p + length
+ > zip->central_directory_last->buff + zip->central_directory_last->buff_size)) {
+ struct cd_segment *segment = calloc(1, sizeof(*segment));
+ if (segment == NULL)
+ return NULL;
+ segment->buff_size = 64 * 1024;
+ segment->buff = malloc(segment->buff_size);
+ if (segment->buff == NULL) {
+ free(segment);
+ return NULL;
+ }
+ segment->p = segment->buff;
-#define LOCAL_FILE_HEADER_SIGNATURE 0
-#define LOCAL_FILE_HEADER_VERSION 4
-#define LOCAL_FILE_HEADER_FLAGS 6
-#define LOCAL_FILE_HEADER_COMPRESSION 8
-#define LOCAL_FILE_HEADER_TIMEDATE 10
-#define LOCAL_FILE_HEADER_CRC32 14
-#define LOCAL_FILE_HEADER_COMPRESSED_SIZE 18
-#define LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE 22
-#define LOCAL_FILE_HEADER_FILENAME_LENGTH 26
-#define LOCAL_FILE_HEADER_EXTRA_LENGTH 28
-#define SIZE_LOCAL_FILE_HEADER 30
-
-#define FILE_HEADER_SIGNATURE 0
-#define FILE_HEADER_VERSION_BY 4
-#define FILE_HEADER_VERSION_EXTRACT 6
-#define FILE_HEADER_FLAGS 8
-#define FILE_HEADER_COMPRESSION 10
-#define FILE_HEADER_TIMEDATE 12
-#define FILE_HEADER_CRC32 16
-#define FILE_HEADER_COMPRESSED_SIZE 20
-#define FILE_HEADER_UNCOMPRESSED_SIZE 24
-#define FILE_HEADER_FILENAME_LENGTH 28
-#define FILE_HEADER_EXTRA_LENGTH 30
-#define FILE_HEADER_COMMENT_LENGTH 32
-#define FILE_HEADER_DISK_NUMBER 34
-#define FILE_HEADER_ATTRIBUTES_INTERNAL 36
-#define FILE_HEADER_ATTRIBUTES_EXTERNAL 38
-#define FILE_HEADER_OFFSET 42
-#define SIZE_FILE_HEADER 46
-
- /* Not mandatory, but recommended by specification. */
-#define DATA_DESCRIPTOR_SIGNATURE 0
-#define DATA_DESCRIPTOR_CRC32 4
-#define DATA_DESCRIPTOR_COMPRESSED_SIZE 8
-#define DATA_DESCRIPTOR_UNCOMPRESSED_SIZE 12
-#define SIZE_DATA_DESCRIPTOR 16
-
-#define EXTRA_DATA_LOCAL_TIME_ID 0
-#define EXTRA_DATA_LOCAL_TIME_SIZE 2
-#define EXTRA_DATA_LOCAL_TIME_FLAG 4
-#define EXTRA_DATA_LOCAL_MTIME 5
-#define EXTRA_DATA_LOCAL_ATIME 9
-#define EXTRA_DATA_LOCAL_CTIME 13
-#define EXTRA_DATA_LOCAL_UNIX_ID 17
-#define EXTRA_DATA_LOCAL_UNIX_SIZE 19
-#define EXTRA_DATA_LOCAL_UNIX_VERSION 21
-#define EXTRA_DATA_LOCAL_UNIX_UID_SIZE 22
-#define EXTRA_DATA_LOCAL_UNIX_UID 23
-#define EXTRA_DATA_LOCAL_UNIX_GID_SIZE 27
-#define EXTRA_DATA_LOCAL_UNIX_GID 28
-#define SIZE_EXTRA_DATA_LOCAL 32
-
-#define EXTRA_DATA_CENTRAL_TIME_ID 0
-#define EXTRA_DATA_CENTRAL_TIME_SIZE 2
-#define EXTRA_DATA_CENTRAL_TIME_FLAG 4
-#define EXTRA_DATA_CENTRAL_MTIME 5
-#define EXTRA_DATA_CENTRAL_UNIX_ID 9
-#define EXTRA_DATA_CENTRAL_UNIX_SIZE 11
-#define SIZE_EXTRA_DATA_CENTRAL 13
-
-#define CENTRAL_DIRECTORY_END_SIGNATURE 0
-#define CENTRAL_DIRECTORY_END_DISK 4
-#define CENTRAL_DIRECTORY_END_START_DISK 6
-#define CENTRAL_DIRECTORY_END_ENTRIES_DISK 8
-#define CENTRAL_DIRECTORY_END_ENTRIES 10
-#define CENTRAL_DIRECTORY_END_SIZE 12
-#define CENTRAL_DIRECTORY_END_OFFSET 16
-#define CENTRAL_DIRECTORY_END_COMMENT_LENGTH 20
-#define SIZE_CENTRAL_DIRECTORY_END 22
-
-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;
-};
+ if (zip->central_directory == NULL) {
+ zip->central_directory
+ = zip->central_directory_last
+ = segment;
+ } else {
+ zip->central_directory_last->next = segment;
+ zip->central_directory_last = segment;
+ }
+ }
-struct zip {
- uint8_t data_descriptor[SIZE_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;
+ p = zip->central_directory_last->p;
+ zip->central_directory_last->p += length;
+ zip->central_directory_bytes += length;
+ return (p);
+}
-#ifdef HAVE_ZLIB_H
- z_stream stream;
- size_t len_buf;
- unsigned char *buf;
-#endif
-};
+static unsigned long
+real_crc32(unsigned long crc, const void *buff, size_t len)
+{
+ return crc32(crc, buff, (unsigned int)len);
+}
+
+static unsigned long
+fake_crc32(unsigned long crc, const void *buff, size_t len)
+{
+ (void)crc; /* UNUSED */
+ (void)buff; /* UNUSED */
+ (void)len; /* UNUSED */
+ return 0;
+}
static int
archive_write_zip_options(struct archive_write *a, const char *key,
@@ -217,24 +256,108 @@ archive_write_zip_options(struct archive_write *a, const char *key,
int ret = ARCHIVE_FAILED;
if (strcmp(key, "compression") == 0) {
+ /*
+ * Set compression to use on all future entries.
+ * This only affects regular files.
+ */
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;
+ zip->requested_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;
+ zip->requested_compression = COMPRESSION_STORE;
ret = ARCHIVE_OK;
}
return (ret);
+ } else if (strcmp(key, "compression-level") == 0) {
+ if (val == NULL || !(val[0] >= '0' && val[0] <= '9') || val[1] != '\0') {
+ return ARCHIVE_WARN;
+ }
+
+ if (val[0] == '0') {
+ zip->requested_compression = COMPRESSION_STORE;
+ return ARCHIVE_OK;
+ } else {
+#ifdef HAVE_ZLIB_H
+ zip->requested_compression = COMPRESSION_DEFLATE;
+ zip->deflate_compression_level = val[0] - '0';
+ return ARCHIVE_OK;
+#else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "deflate compression not supported");
+#endif
+ }
+ } else if (strcmp(key, "encryption") == 0) {
+ if (val == NULL) {
+ zip->encryption_type = ENCRYPTION_NONE;
+ ret = ARCHIVE_OK;
+ } else if (val[0] == '1' || strcmp(val, "traditional") == 0
+ || strcmp(val, "zipcrypt") == 0
+ || strcmp(val, "ZipCrypt") == 0) {
+ if (is_traditional_pkware_encryption_supported()) {
+ zip->encryption_type = ENCRYPTION_TRADITIONAL;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else if (strcmp(val, "aes128") == 0) {
+ if (is_winzip_aes_encryption_supported(
+ ENCRYPTION_WINZIP_AES128)) {
+ zip->encryption_type = ENCRYPTION_WINZIP_AES128;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else if (strcmp(val, "aes256") == 0) {
+ if (is_winzip_aes_encryption_supported(
+ ENCRYPTION_WINZIP_AES256)) {
+ zip->encryption_type = ENCRYPTION_WINZIP_AES256;
+ ret = ARCHIVE_OK;
+ } else {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "encryption not supported");
+ }
+ } else {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "%s: unknown encryption '%s'",
+ a->format_name, val);
+ }
+ return (ret);
+ } else if (strcmp(key, "experimental") == 0) {
+ if (val == NULL || val[0] == 0) {
+ zip->flags &= ~ ZIP_FLAG_EXPERIMENT_xl;
+ } else {
+ zip->flags |= ZIP_FLAG_EXPERIMENT_xl;
+ }
+ return (ARCHIVE_OK);
+ } else if (strcmp(key, "fakecrc32") == 0) {
+ /*
+ * FOR TESTING ONLY: disable CRC calculation to speed up
+ * certain complex tests.
+ */
+ if (val == NULL || val[0] == 0) {
+ zip->crc32func = real_crc32;
+ } else {
+ zip->crc32func = fake_crc32;
+ }
+ return (ARCHIVE_OK);
} else if (strcmp(key, "hdrcharset") == 0) {
+ /*
+ * Set the character set used in translating filenames.
+ */
if (val == NULL || val[0] == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"%s: hdrcharset option needs a character-set name",
@@ -248,6 +371,21 @@ archive_write_zip_options(struct archive_write *a, const char *key,
ret = ARCHIVE_FATAL;
}
return (ret);
+ } else if (strcmp(key, "zip64") == 0) {
+ /*
+ * Bias decisions about Zip64: force them to be
+ * generated in certain cases where they are not
+ * forbidden or avoid them in certain cases where they
+ * are not strictly required.
+ */
+ if (val != NULL && *val != '\0') {
+ zip->flags |= ZIP_FLAG_FORCE_ZIP64;
+ zip->flags &= ~ZIP_FLAG_AVOID_ZIP64;
+ } else {
+ zip->flags &= ~ZIP_FLAG_FORCE_ZIP64;
+ zip->flags |= ZIP_FLAG_AVOID_ZIP64;
+ }
+ return (ARCHIVE_OK);
}
/* Note: The "warn" return is just to inform the options
@@ -261,9 +399,9 @@ archive_write_zip_set_compression_deflate(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
int ret = ARCHIVE_FAILED;
-
+
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_zip_set_compression_deflate");
if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -273,11 +411,12 @@ archive_write_zip_set_compression_deflate(struct archive *_a)
} else {
#ifdef HAVE_ZLIB_H
struct zip *zip = a->format_data;
- zip->compression = COMPRESSION_DEFLATE;
+ zip->requested_compression = COMPRESSION_DEFLATE;
ret = ARCHIVE_OK;
#else
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"deflate compression not supported");
+ ret = ARCHIVE_FAILED;
#endif
}
return (ret);
@@ -289,9 +428,9 @@ archive_write_zip_set_compression_store(struct archive *_a)
struct archive_write *a = (struct archive_write *)_a;
struct zip *zip = a->format_data;
int ret = ARCHIVE_FAILED;
-
+
archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
- ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER,
+ ARCHIVE_STATE_NEW | ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_zip_set_compression_deflate");
if (a->archive.archive_format != ARCHIVE_FORMAT_ZIP) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -299,7 +438,7 @@ archive_write_zip_set_compression_store(struct archive *_a)
" with zip format");
ret = ARCHIVE_FATAL;
} else {
- zip->compression = COMPRESSION_STORE;
+ zip->requested_compression = COMPRESSION_STORE;
ret = ARCHIVE_OK;
}
return (ret);
@@ -324,14 +463,15 @@ archive_write_set_format_zip(struct archive *_a)
"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;
+ /* "Unspecified" lets us choose the appropriate compression. */
+ zip->requested_compression = COMPRESSION_UNSPECIFIED;
#ifdef HAVE_ZLIB_H
- zip->compression = COMPRESSION_DEFLATE;
+ zip->deflate_compression_level = Z_DEFAULT_COMPRESSION;
+#endif
+ zip->crc32func = real_crc32;
+
+ /* A buffer used for both compression and encryption. */
zip->len_buf = 65536;
zip->buf = malloc(zip->len_buf);
if (zip->buf == NULL) {
@@ -340,9 +480,6 @@ archive_write_set_format_zip(struct archive *_a)
"Can't allocate compression buffer");
return (ARCHIVE_FATAL);
}
-#else
- zip->compression = COMPRESSION_STORE;
-#endif
a->format_data = zip;
a->format_name = "zip";
@@ -355,9 +492,6 @@ archive_write_set_format_zip(struct archive *_a)
a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
a->archive.archive_format_name = "ZIP";
- archive_le32enc(&zip->data_descriptor[DATA_DESCRIPTOR_SIGNATURE],
- ZIP_SIGNATURE_DATA_DESCRIPTOR);
-
return (ARCHIVE_OK);
}
@@ -376,17 +510,20 @@ is_all_ascii(const char *p)
static int
archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
{
- struct zip *zip;
- uint8_t h[SIZE_LOCAL_FILE_HEADER];
- uint8_t e[SIZE_EXTRA_DATA_LOCAL];
- uint8_t *d;
- struct zip_file_header_link *l;
- struct archive_string_conv *sconv;
+ unsigned char local_header[32];
+ unsigned char local_extra[144];
+ struct zip *zip = a->format_data;
+ unsigned char *e;
+ unsigned char *cd_extra;
+ size_t filename_length;
+ const char *slink = NULL;
+ size_t slink_size = 0;
+ struct archive_string_conv *sconv = get_sconv(a, zip);
int ret, ret2 = ARCHIVE_OK;
- int64_t size;
mode_t type;
+ int version_needed = 10;
- /* Entries other than a regular file or a folder are skipped. */
+ /* Ignore types of entries that we don't support. */
type = archive_entry_filetype(entry);
if (type != AE_IFREG && type != AE_IFDIR && type != AE_IFLNK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
@@ -394,70 +531,87 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
return ARCHIVE_FAILED;
};
- /* Directory entries should have a size of 0. */
- if (type == AE_IFDIR)
+ /* If we're not using Zip64, reject large files. */
+ if (zip->flags & ZIP_FLAG_AVOID_ZIP64) {
+ /* Reject entries over 4GB. */
+ if (archive_entry_size_is_set(entry)
+ && (archive_entry_size(entry) > ZIP_4GB_MAX)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Files > 4GB require Zip64 extensions");
+ return ARCHIVE_FAILED;
+ }
+ /* Reject entries if archive is > 4GB. */
+ if (zip->written_bytes > ZIP_4GB_MAX) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Archives > 4GB require Zip64 extensions");
+ return ARCHIVE_FAILED;
+ }
+ }
+
+ /* Only regular files can have size > 0. */
+ if (type != AE_IFREG)
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;
+
+ /* Reset information from last entry. */
+ zip->entry_offset = zip->written_bytes;
+ zip->entry_uncompressed_limit = INT64_MAX;
+ zip->entry_compressed_size = 0;
+ zip->entry_uncompressed_size = 0;
+ zip->entry_compressed_written = 0;
+ zip->entry_uncompressed_written = 0;
+ zip->entry_flags = 0;
+ zip->entry_uses_zip64 = 0;
+ zip->entry_crc32 = zip->crc32func(0, NULL, 0);
+ zip->entry_encryption = 0;
+ if (zip->entry != NULL) {
+ archive_entry_free(zip->entry);
+ zip->entry = NULL;
}
- 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
+ if (zip->cctx_valid)
+ archive_encrypto_aes_ctr_release(&zip->cctx);
+ if (zip->hctx_valid)
+ archive_hmac_sha1_cleanup(&zip->hctx);
+ zip->tctx_valid = zip->cctx_valid = zip->hctx_valid = 0;
+
+ if (type == AE_IFREG
+ &&(!archive_entry_size_is_set(entry)
+ || archive_entry_size(entry) > 0)) {
+ switch (zip->encryption_type) {
+ case ENCRYPTION_TRADITIONAL:
+ case ENCRYPTION_WINZIP_AES128:
+ case ENCRYPTION_WINZIP_AES256:
+ zip->entry_flags |= ZIP_ENTRY_FLAG_ENCRYPTED;
+ zip->entry_encryption = zip->encryption_type;
+ break;
+ default:
+ break;
}
}
- 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);
- }
+
#if defined(_WIN32) && !defined(__CYGWIN__)
- /* Make sure the path separators in pahtname, hardlink and symlink
+ /* Make sure the path separators in pathname, hardlink and symlink
* are all slash '/', not the Windows path separator '\'. */
- l->entry = __la_win_entry_in_posix_pathseparator(entry);
- if (l->entry == entry)
- l->entry = archive_entry_clone(entry);
+ zip->entry = __la_win_entry_in_posix_pathseparator(entry);
+ if (zip->entry == entry)
+ zip->entry = archive_entry_clone(entry);
#else
- l->entry = archive_entry_clone(entry);
+ zip->entry = archive_entry_clone(entry);
#endif
- if (l->entry == NULL) {
+ if (zip->entry == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate zip header data");
- free(l);
return (ARCHIVE_FATAL);
}
- 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_entry_free(l->entry);
- free(l);
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Pathname");
return (ARCHIVE_FATAL);
@@ -470,163 +624,378 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry)
ret2 = ARCHIVE_WARN;
}
if (len > 0)
- archive_entry_set_pathname(l->entry, p);
+ archive_entry_set_pathname(zip->entry, p);
/*
- * Although there is no character-set regulation for Symlink,
- * it is suitable to convert a character-set of Symlinke to
- * what those of the Pathname has been converted to.
+ * There is no standard for symlink handling; we convert
+ * it using the same character-set translation that we use
+ * for filename.
*/
if (type == AE_IFLNK) {
if (archive_entry_symlink_l(entry, &p, &len, sconv)) {
if (errno == ENOMEM) {
- archive_entry_free(l->entry);
- free(l);
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory "
" for Symlink");
return (ARCHIVE_FATAL);
}
- /*
- * Even if the strng conversion failed,
- * we should not report the error since
- * thre is no regulation for.
- */
+ /* No error if we can't convert. */
} else if (len > 0)
- archive_entry_set_symlink(l->entry, p);
+ archive_entry_set_symlink(zip->entry, p);
+ }
+ }
+
+ /* If filename isn't ASCII and we can use UTF-8, set the UTF-8 flag. */
+ if (!is_all_ascii(archive_entry_pathname(zip->entry))) {
+ if (zip->opt_sconv != NULL) {
+ if (strcmp(archive_string_conversion_charset_name(
+ zip->opt_sconv), "UTF-8") == 0)
+ zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME;
+#if HAVE_NL_LANGINFO
+ } else if (strcmp(nl_langinfo(CODESET), "UTF-8") == 0) {
+ zip->entry_flags |= ZIP_ENTRY_FLAG_UTF8_NAME;
+#endif
}
}
- /* If all characters in a filename are 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;
+ filename_length = path_length(zip->entry);
- /* Initialize the CRC variable and potentially the local crc32(). */
- l->crc32 = crc32(0, NULL, 0);
+ /* Determine appropriate compression and size for this entry. */
if (type == AE_IFLNK) {
- const char *p = archive_entry_symlink(l->entry);
- if (p != NULL)
- size = strlen(p);
+ slink = archive_entry_symlink(zip->entry);
+ if (slink != NULL)
+ slink_size = strlen(slink);
else
- size = 0;
- zip->remaining_data_bytes = 0;
- archive_entry_set_size(l->entry, size);
- l->compression = COMPRESSION_STORE;
- l->compressed_size = size;
+ slink_size = 0;
+ zip->entry_uncompressed_limit = slink_size;
+ zip->entry_compressed_size = slink_size;
+ zip->entry_uncompressed_size = slink_size;
+ zip->entry_crc32 = zip->crc32func(zip->entry_crc32,
+ (const unsigned char *)slink, slink_size);
+ zip->entry_compression = COMPRESSION_STORE;
+ version_needed = 20;
+ } else if (type != AE_IFREG) {
+ zip->entry_compression = COMPRESSION_STORE;
+ zip->entry_uncompressed_limit = 0;
+ version_needed = 20;
+ } else if (archive_entry_size_is_set(zip->entry)) {
+ int64_t size = archive_entry_size(zip->entry);
+ int64_t additional_size = 0;
+
+ zip->entry_uncompressed_limit = size;
+ zip->entry_compression = zip->requested_compression;
+ if (zip->entry_compression == COMPRESSION_UNSPECIFIED) {
+ zip->entry_compression = COMPRESSION_DEFAULT;
+ }
+ if (zip->entry_compression == COMPRESSION_STORE) {
+ zip->entry_compressed_size = size;
+ zip->entry_uncompressed_size = size;
+ version_needed = 10;
+ } else {
+ zip->entry_uncompressed_size = size;
+ version_needed = 20;
+ }
+
+ if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {
+ switch (zip->entry_encryption) {
+ case ENCRYPTION_TRADITIONAL:
+ additional_size = TRAD_HEADER_SIZE;
+ version_needed = 20;
+ break;
+ case ENCRYPTION_WINZIP_AES128:
+ additional_size = WINZIP_AES128_HEADER_SIZE
+ + AUTH_CODE_SIZE;
+ version_needed = 20;
+ break;
+ case ENCRYPTION_WINZIP_AES256:
+ additional_size = WINZIP_AES256_HEADER_SIZE
+ + AUTH_CODE_SIZE;
+ version_needed = 20;
+ break;
+ default:
+ break;
+ }
+ if (zip->entry_compression == COMPRESSION_STORE)
+ zip->entry_compressed_size += additional_size;
+ }
+
+ /*
+ * Set Zip64 extension in any of the following cases
+ * (this was suggested by discussion on info-zip-dev
+ * mailing list):
+ * = Zip64 is being forced by user
+ * = File is over 4GiB uncompressed
+ * (including encryption header, if any)
+ * = File is close to 4GiB and is being compressed
+ * (compression might make file larger)
+ */
+ if ((zip->flags & ZIP_FLAG_FORCE_ZIP64)
+ || (zip->entry_uncompressed_size + additional_size > ZIP_4GB_MAX)
+ || (zip->entry_uncompressed_size > ZIP_4GB_MAX_UNCOMPRESSED
+ && zip->entry_compression != COMPRESSION_STORE)) {
+ zip->entry_uses_zip64 = 1;
+ version_needed = 45;
+ }
+
+ /* We may know the size, but never the CRC. */
+ zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;
} else {
- l->compression = zip->compression;
- l->compressed_size = 0;
+ /* We don't know the size. In this case, we prefer
+ * deflate (it has a clear end-of-data marker which
+ * makes length-at-end more reliable) and will
+ * enable Zip64 extensions unless we're told not to.
+ */
+ zip->entry_compression = COMPRESSION_DEFAULT;
+ zip->entry_flags |= ZIP_ENTRY_FLAG_LENGTH_AT_END;
+ if ((zip->flags & ZIP_FLAG_AVOID_ZIP64) == 0) {
+ zip->entry_uses_zip64 = 1;
+ version_needed = 45;
+ } else if (zip->entry_compression == COMPRESSION_STORE) {
+ version_needed = 10;
+ } else {
+ version_needed = 20;
+ }
+
+ if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {
+ switch (zip->entry_encryption) {
+ case ENCRYPTION_TRADITIONAL:
+ case ENCRYPTION_WINZIP_AES128:
+ case ENCRYPTION_WINZIP_AES256:
+ if (version_needed < 20)
+ version_needed = 20;
+ break;
+ default:
+ break;
+ }
+ }
}
- l->next = NULL;
- if (zip->central_directory == NULL) {
- zip->central_directory = l;
+
+ /* Format the local header. */
+ memset(local_header, 0, sizeof(local_header));
+ memcpy(local_header, "PK\003\004", 4);
+ archive_le16enc(local_header + 4, version_needed);
+ archive_le16enc(local_header + 6, zip->entry_flags);
+ if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128
+ || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)
+ archive_le16enc(local_header + 8, WINZIP_AES_ENCRYPTION);
+ else
+ archive_le16enc(local_header + 8, zip->entry_compression);
+ archive_le32enc(local_header + 10,
+ dos_time(archive_entry_mtime(zip->entry)));
+ archive_le32enc(local_header + 14, zip->entry_crc32);
+ if (zip->entry_uses_zip64) {
+ /* Zip64 data in the local header "must" include both
+ * compressed and uncompressed sizes AND those fields
+ * are included only if these are 0xffffffff;
+ * THEREFORE these must be set this way, even if we
+ * know one of them is smaller. */
+ archive_le32enc(local_header + 18, ZIP_4GB_MAX);
+ archive_le32enc(local_header + 22, ZIP_4GB_MAX);
} else {
- zip->central_directory_end->next = l;
- }
- zip->central_directory_end = l;
-
- /* 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[LOCAL_FILE_HEADER_SIGNATURE],
- ZIP_SIGNATURE_LOCAL_FILE_HEADER);
- archive_le16enc(&h[LOCAL_FILE_HEADER_VERSION], ZIP_VERSION_EXTRACT);
- archive_le16enc(&h[LOCAL_FILE_HEADER_FLAGS], l->flags);
- archive_le16enc(&h[LOCAL_FILE_HEADER_COMPRESSION], l->compression);
- archive_le32enc(&h[LOCAL_FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(entry)));
- archive_le16enc(&h[LOCAL_FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(l->entry));
-
- 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. */
- archive_le32enc(&h[LOCAL_FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)size);
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
- break;
-#ifdef HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
- archive_le32enc(&h[LOCAL_FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)size);
+ archive_le32enc(local_header + 18, (uint32_t)zip->entry_compressed_size);
+ archive_le32enc(local_header + 22, (uint32_t)zip->entry_uncompressed_size);
+ }
+ archive_le16enc(local_header + 26, (uint16_t)filename_length);
- 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 = (uInt)zip->len_buf;
- 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);
+ if (zip->entry_encryption == ENCRYPTION_TRADITIONAL) {
+ if (zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END)
+ zip->trad_chkdat = local_header[11];
+ else
+ zip->trad_chkdat = local_header[17];
+ }
+
+ /* Format as much of central directory file header as we can: */
+ zip->file_header = cd_alloc(zip, 46);
+ /* If (zip->file_header == NULL) XXXX */
+ ++zip->central_directory_entries;
+ memset(zip->file_header, 0, 46);
+ memcpy(zip->file_header, "PK\001\002", 4);
+ /* "Made by PKZip 2.0 on Unix." */
+ archive_le16enc(zip->file_header + 4, 3 * 256 + version_needed);
+ archive_le16enc(zip->file_header + 6, version_needed);
+ archive_le16enc(zip->file_header + 8, zip->entry_flags);
+ if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128
+ || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)
+ archive_le16enc(zip->file_header + 10, WINZIP_AES_ENCRYPTION);
+ else
+ archive_le16enc(zip->file_header + 10, zip->entry_compression);
+ archive_le32enc(zip->file_header + 12,
+ dos_time(archive_entry_mtime(zip->entry)));
+ archive_le16enc(zip->file_header + 28, (uint16_t)filename_length);
+ /* Following Info-Zip, store mode in the "external attributes" field. */
+ archive_le32enc(zip->file_header + 38,
+ ((uint32_t)archive_entry_mode(zip->entry)) << 16);
+ e = cd_alloc(zip, filename_length);
+ /* If (e == NULL) XXXX */
+ copy_path(zip->entry, e);
+
+ /* Format extra data. */
+ memset(local_extra, 0, sizeof(local_extra));
+ e = local_extra;
+
+ /* First, extra blocks that are the same between
+ * the local file header and the central directory.
+ * We format them once and then duplicate them. */
+
+ /* UT timestamp, length depends on what timestamps are set. */
+ memcpy(e, "UT", 2);
+ archive_le16enc(e + 2,
+ 1
+ + (archive_entry_mtime_is_set(entry) ? 4 : 0)
+ + (archive_entry_atime_is_set(entry) ? 4 : 0)
+ + (archive_entry_ctime_is_set(entry) ? 4 : 0));
+ e += 4;
+ *e++ =
+ (archive_entry_mtime_is_set(entry) ? 1 : 0)
+ | (archive_entry_atime_is_set(entry) ? 2 : 0)
+ | (archive_entry_ctime_is_set(entry) ? 4 : 0);
+ if (archive_entry_mtime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_mtime(entry));
+ e += 4;
+ }
+ if (archive_entry_atime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_atime(entry));
+ e += 4;
+ }
+ if (archive_entry_ctime_is_set(entry)) {
+ archive_le32enc(e, (uint32_t)archive_entry_ctime(entry));
+ e += 4;
+ }
+
+ /* ux Unix extra data, length 11, version 1 */
+ /* TODO: If uid < 64k, use 2 bytes, ditto for gid. */
+ memcpy(e, "ux\013\000\001", 5);
+ e += 5;
+ *e++ = 4; /* Length of following UID */
+ archive_le32enc(e, (uint32_t)archive_entry_uid(entry));
+ e += 4;
+ *e++ = 4; /* Length of following GID */
+ archive_le32enc(e, (uint32_t)archive_entry_gid(entry));
+ e += 4;
+
+ /* AES extra data field: WinZIP AES information, ID=0x9901 */
+ if ((zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED)
+ && (zip->entry_encryption == ENCRYPTION_WINZIP_AES128
+ || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)) {
+
+ memcpy(e, "\001\231\007\000\001\000AE", 8);
+ /* AES vendor version AE-2 does not store a CRC.
+ * WinZip 11 uses AE-1, which does store the CRC,
+ * but it does not store the CRC when the file size
+ * is less than 20 bytes. So we simulate what
+ * WinZip 11 does.
+ * NOTE: WinZip 9.0 and 10.0 uses AE-2 by default. */
+ if (archive_entry_size_is_set(zip->entry)
+ && archive_entry_size(zip->entry) < 20) {
+ archive_le16enc(e+4, AES_VENDOR_AE_2);
+ zip->aes_vendor = AES_VENDOR_AE_2;/* no CRC. */
+ } else
+ zip->aes_vendor = AES_VENDOR_AE_1;
+ e += 8;
+ /* AES encryption strength. */
+ *e++ = (zip->entry_encryption == ENCRYPTION_WINZIP_AES128)?1:3;
+ /* Actual compression method. */
+ archive_le16enc(e, zip->entry_compression);
+ e += 2;
+ }
+
+ /* Copy UT ,ux, and AES-extra into central directory as well. */
+ zip->file_header_extra_offset = zip->central_directory_bytes;
+ cd_extra = cd_alloc(zip, e - local_extra);
+ memcpy(cd_extra, local_extra, e - local_extra);
+
+ /*
+ * Following extra blocks vary between local header and
+ * central directory. These are the local header versions.
+ * Central directory versions get formatted in
+ * archive_write_zip_finish_entry() below.
+ */
+
+ /* "[Zip64 entry] in the local header MUST include BOTH
+ * original [uncompressed] and compressed size fields." */
+ if (zip->entry_uses_zip64) {
+ unsigned char *zip64_start = e;
+ memcpy(e, "\001\000\020\000", 4);
+ e += 4;
+ archive_le64enc(e, zip->entry_uncompressed_size);
+ e += 8;
+ archive_le64enc(e, zip->entry_compressed_size);
+ e += 8;
+ archive_le16enc(zip64_start + 2, (uint16_t)(e - (zip64_start + 4)));
+ }
+
+ if (zip->flags & ZIP_FLAG_EXPERIMENT_xl) {
+ /* Experimental 'xl' extension to improve streaming. */
+ unsigned char *external_info = e;
+ int included = 7;
+ memcpy(e, "xl\000\000", 4); // 0x6c65 + 2-byte length
+ e += 4;
+ e[0] = included; /* bitmap of included fields */
+ e += 1;
+ if (included & 1) {
+ archive_le16enc(e, /* "Version created by" */
+ 3 * 256 + version_needed);
+ e += 2;
}
- break;
-#endif
+ if (included & 2) {
+ archive_le16enc(e, 0); /* internal file attributes */
+ e += 2;
+ }
+ if (included & 4) {
+ archive_le32enc(e, /* external file attributes */
+ ((uint32_t)archive_entry_mode(zip->entry)) << 16);
+ e += 4;
+ }
+ if (included & 8) {
+ // Libarchive does not currently support file comments.
+ }
+ archive_le16enc(external_info + 2, (uint16_t)(e - (external_info + 4)));
}
- /* Formatting extra data. */
- archive_le16enc(&h[LOCAL_FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_TIME_SIZE], 1 + 4 * 3);
- e[EXTRA_DATA_LOCAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_MTIME],
- (uint32_t)archive_entry_mtime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_ATIME],
- (uint32_t)archive_entry_atime(entry));
- archive_le32enc(&e[EXTRA_DATA_LOCAL_CTIME],
- (uint32_t)archive_entry_ctime(entry));
-
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_LOCAL_UNIX_SIZE], 1 + (1 + 4) * 2);
- e[EXTRA_DATA_LOCAL_UNIX_VERSION] = 1;
- e[EXTRA_DATA_LOCAL_UNIX_UID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_UID],
- (uint32_t)archive_entry_uid(entry));
- e[EXTRA_DATA_LOCAL_UNIX_GID_SIZE] = 4;
- archive_le32enc(&e[EXTRA_DATA_LOCAL_UNIX_GID],
- (uint32_t)archive_entry_gid(entry));
-
- archive_le32enc(&d[DATA_DESCRIPTOR_UNCOMPRESSED_SIZE],
- (uint32_t)size);
-
- ret = __archive_write_output(a, h, sizeof(h));
+ /* Update local header with size of extra data and write it all out: */
+ archive_le16enc(local_header + 28, (uint16_t)(e - local_extra));
+
+ ret = __archive_write_output(a, local_header, 30);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(h);
+ zip->written_bytes += 30;
- ret = write_path(l->entry, a);
+ ret = write_path(zip->entry, a);
if (ret <= ARCHIVE_OK)
return (ARCHIVE_FATAL);
zip->written_bytes += ret;
- ret = __archive_write_output(a, e, sizeof(e));
+ ret = __archive_write_output(a, local_extra, e - local_extra);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
-
- if (type == AE_IFLNK) {
- const unsigned char *p;
+ zip->written_bytes += e - local_extra;
- p = (const unsigned char *)archive_entry_symlink(l->entry);
- ret = __archive_write_output(a, p, (size_t)size);
+ /* For symlinks, write the body now. */
+ if (slink != NULL) {
+ ret = __archive_write_output(a, slink, slink_size);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += size;
- l->crc32 = crc32(l->crc32, p, (unsigned)size);
+ zip->entry_compressed_written += slink_size;
+ zip->entry_uncompressed_written += slink_size;
+ zip->written_bytes += slink_size;
}
- if (ret2 != ARCHIVE_OK)
- return (ret2);
- return (ARCHIVE_OK);
+#ifdef HAVE_ZLIB_H
+ if (zip->entry_compression == COMPRESSION_DEFLATE) {
+ 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 = (uInt)zip->len_buf;
+ if (deflateInit2(&zip->stream, zip->deflate_compression_level,
+ Z_DEFLATED, -15, 8, Z_DEFAULT_STRATEGY) != Z_OK) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't init deflate compressor");
+ return (ARCHIVE_FATAL);
+ }
+ }
+#endif
+
+ return (ret2);
}
static ssize_t
@@ -634,22 +1003,80 @@ 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 ((int64_t)s > zip->entry_uncompressed_limit)
+ s = (size_t)zip->entry_uncompressed_limit;
+ zip->entry_uncompressed_written += s;
if (s == 0) return 0;
- switch (l->compression) {
+ if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) {
+ switch (zip->entry_encryption) {
+ case ENCRYPTION_TRADITIONAL:
+ /* Initialize traditional PKWARE encryption context. */
+ if (!zip->tctx_valid) {
+ ret = init_traditional_pkware_encryption(a);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->tctx_valid = 1;
+ }
+ break;
+ case ENCRYPTION_WINZIP_AES128:
+ case ENCRYPTION_WINZIP_AES256:
+ if (!zip->cctx_valid) {
+ ret = init_winzip_aes_encryption(a);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->cctx_valid = zip->hctx_valid = 1;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ switch (zip->entry_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, (unsigned)s);
- return (s);
+ if (zip->tctx_valid || zip->cctx_valid) {
+ const uint8_t *rb = (const uint8_t *)buff;
+ const uint8_t * const re = rb + s;
+
+ while (rb < re) {
+ size_t l;
+
+ if (zip->tctx_valid) {
+ l = trad_enc_encrypt_update(&zip->tctx,
+ rb, re - rb,
+ zip->buf, zip->len_buf);
+ } else {
+ l = zip->len_buf;
+ ret = archive_encrypto_aes_ctr_update(
+ &zip->cctx,
+ rb, re - rb, zip->buf, &l);
+ if (ret < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to encrypt file");
+ return (ARCHIVE_FAILED);
+ }
+ archive_hmac_sha1_update(&zip->hctx,
+ zip->buf, l);
+ }
+ ret = __archive_write_output(a, zip->buf, l);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->entry_compressed_written += l;
+ zip->written_bytes += l;
+ rb += l;
+ }
+ } else {
+ ret = __archive_write_output(a, buff, s);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->written_bytes += s;
+ zip->entry_compressed_written += s;
+ }
+ break;
#if HAVE_ZLIB_H
case COMPRESSION_DEFLATE:
zip->stream.next_in = (unsigned char*)(uintptr_t)buff;
@@ -659,20 +1086,36 @@ 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) {
+ if (zip->tctx_valid) {
+ trad_enc_encrypt_update(&zip->tctx,
+ zip->buf, zip->len_buf,
+ zip->buf, zip->len_buf);
+ } else if (zip->cctx_valid) {
+ size_t outl = zip->len_buf;
+ ret = archive_encrypto_aes_ctr_update(
+ &zip->cctx,
+ zip->buf, zip->len_buf,
+ zip->buf, &outl);
+ if (ret < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to encrypt file");
+ return (ARCHIVE_FAILED);
+ }
+ archive_hmac_sha1_update(&zip->hctx,
+ 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->entry_compressed_written += zip->len_buf;
zip->written_bytes += zip->len_buf;
zip->stream.next_out = zip->buf;
zip->stream.avail_out = (uInt)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, (uInt)s);
- return (s);
+ break;
#endif
default:
@@ -680,153 +1123,222 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s)
"Invalid ZIP compression type");
return ARCHIVE_FATAL;
}
+
+ zip->entry_uncompressed_limit -= s;
+ if (!zip->cctx_valid || zip->aes_vendor != AES_VENDOR_AE_2)
+ zip->entry_crc32 =
+ zip->crc32func(zip->entry_crc32, buff, (unsigned)s);
+ return (s);
+
}
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;
- uint8_t *d = zip->data_descriptor;
- struct zip_file_header_link *l = zip->central_directory_end;
-#if HAVE_ZLIB_H
- size_t reminder;
-#endif
+ int ret;
- switch(l->compression) {
- case COMPRESSION_STORE:
- break;
#if HAVE_ZLIB_H
- case COMPRESSION_DEFLATE:
+ if (zip->entry_compression == COMPRESSION_DEFLATE) {
for (;;) {
+ size_t remainder;
+
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);
+ remainder = zip->len_buf - zip->stream.avail_out;
+ if (zip->tctx_valid) {
+ trad_enc_encrypt_update(&zip->tctx,
+ zip->buf, remainder, zip->buf, remainder);
+ } else if (zip->cctx_valid) {
+ size_t outl = remainder;
+ ret = archive_encrypto_aes_ctr_update(
+ &zip->cctx, zip->buf, remainder,
+ zip->buf, &outl);
+ if (ret < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to encrypt file");
+ return (ARCHIVE_FAILED);
+ }
+ archive_hmac_sha1_update(&zip->hctx,
+ zip->buf, remainder);
+ }
+ ret = __archive_write_output(a, zip->buf, remainder);
if (ret != ARCHIVE_OK)
return (ret);
- l->compressed_size += reminder;
- zip->written_bytes += reminder;
+ zip->entry_compressed_written += remainder;
+ zip->written_bytes += remainder;
zip->stream.next_out = zip->buf;
if (zip->stream.avail_out != 0)
break;
zip->stream.avail_out = (uInt)zip->len_buf;
}
deflateEnd(&zip->stream);
- break;
+ }
#endif
+ if (zip->hctx_valid) {
+ uint8_t hmac[20];
+ size_t hmac_len = 20;
+
+ archive_hmac_sha1_final(&zip->hctx, hmac, &hmac_len);
+ ret = __archive_write_output(a, hmac, AUTH_CODE_SIZE);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->entry_compressed_written += AUTH_CODE_SIZE;
+ zip->written_bytes += AUTH_CODE_SIZE;
}
- archive_le32enc(&d[DATA_DESCRIPTOR_CRC32], l->crc32);
- archive_le32enc(&d[DATA_DESCRIPTOR_COMPRESSED_SIZE],
- (uint32_t)l->compressed_size);
- ret = __archive_write_output(a, d, SIZE_DATA_DESCRIPTOR);
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += SIZE_DATA_DESCRIPTOR;
+ /* Write trailing data descriptor. */
+ if ((zip->entry_flags & ZIP_ENTRY_FLAG_LENGTH_AT_END) != 0) {
+ char d[24];
+ memcpy(d, "PK\007\010", 4);
+ if (zip->cctx_valid && zip->aes_vendor == AES_VENDOR_AE_2)
+ archive_le32enc(d + 4, 0);/* no CRC.*/
+ else
+ archive_le32enc(d + 4, zip->entry_crc32);
+ if (zip->entry_uses_zip64) {
+ archive_le64enc(d + 8,
+ (uint64_t)zip->entry_compressed_written);
+ archive_le64enc(d + 16,
+ (uint64_t)zip->entry_uncompressed_written);
+ ret = __archive_write_output(a, d, 24);
+ zip->written_bytes += 24;
+ } else {
+ archive_le32enc(d + 8,
+ (uint32_t)zip->entry_compressed_written);
+ archive_le32enc(d + 12,
+ (uint32_t)zip->entry_uncompressed_written);
+ ret = __archive_write_output(a, d, 16);
+ zip->written_bytes += 16;
+ }
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ }
+
+ /* Append Zip64 extra data to central directory information. */
+ if (zip->entry_compressed_written > ZIP_4GB_MAX
+ || zip->entry_uncompressed_written > ZIP_4GB_MAX
+ || zip->entry_offset > ZIP_4GB_MAX) {
+ unsigned char zip64[32];
+ unsigned char *z = zip64, *zd;
+ memcpy(z, "\001\000\000\000", 4);
+ z += 4;
+ if (zip->entry_uncompressed_written >= ZIP_4GB_MAX) {
+ archive_le64enc(z, zip->entry_uncompressed_written);
+ z += 8;
+ }
+ if (zip->entry_compressed_written >= ZIP_4GB_MAX) {
+ archive_le64enc(z, zip->entry_compressed_written);
+ z += 8;
+ }
+ if (zip->entry_offset >= ZIP_4GB_MAX) {
+ archive_le64enc(z, zip->entry_offset);
+ z += 8;
+ }
+ archive_le16enc(zip64 + 2, (uint16_t)(z - (zip64 + 4)));
+ zd = cd_alloc(zip, z - zip64);
+ if (zd == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate zip data");
+ return (ARCHIVE_FATAL);
+ }
+ memcpy(zd, zip64, z - zip64);
+ /* Zip64 means version needs to be set to at least 4.5 */
+ if (archive_le16dec(zip->file_header + 6) < 45)
+ archive_le16enc(zip->file_header + 6, 45);
+ }
+
+ /* Fix up central directory file header. */
+ if (zip->cctx_valid && zip->aes_vendor == AES_VENDOR_AE_2)
+ archive_le32enc(zip->file_header + 16, 0);/* no CRC.*/
+ else
+ archive_le32enc(zip->file_header + 16, zip->entry_crc32);
+ archive_le32enc(zip->file_header + 20,
+ (uint32_t)zipmin(zip->entry_compressed_written,
+ ZIP_4GB_MAX));
+ archive_le32enc(zip->file_header + 24,
+ (uint32_t)zipmin(zip->entry_uncompressed_written,
+ ZIP_4GB_MAX));
+ archive_le16enc(zip->file_header + 30,
+ (uint16_t)(zip->central_directory_bytes - zip->file_header_extra_offset));
+ archive_le32enc(zip->file_header + 42,
+ (uint32_t)zipmin(zip->entry_offset,
+ ZIP_4GB_MAX));
+
return (ARCHIVE_OK);
}
static int
archive_write_zip_close(struct archive_write *a)
{
- struct zip *zip;
- struct zip_file_header_link *l;
- uint8_t h[SIZE_FILE_HEADER];
- uint8_t end[SIZE_CENTRAL_DIRECTORY_END];
- uint8_t e[SIZE_EXTRA_DATA_CENTRAL];
+ uint8_t buff[64];
int64_t offset_start, offset_end;
- int entries;
+ struct zip *zip = a->format_data;
+ struct cd_segment *segment;
int ret;
- zip = a->format_data;
- l = zip->central_directory;
-
- /*
- * 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[FILE_HEADER_SIGNATURE], ZIP_SIGNATURE_FILE_HEADER);
- archive_le16enc(&h[FILE_HEADER_VERSION_BY], ZIP_VERSION_BY);
- archive_le16enc(&h[FILE_HEADER_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[FILE_HEADER_FLAGS], l->flags);
- archive_le16enc(&h[FILE_HEADER_COMPRESSION], l->compression);
- archive_le32enc(&h[FILE_HEADER_TIMEDATE],
- dos_time(archive_entry_mtime(l->entry)));
- archive_le32enc(&h[FILE_HEADER_CRC32], l->crc32);
- archive_le32enc(&h[FILE_HEADER_COMPRESSED_SIZE],
- (uint32_t)l->compressed_size);
- archive_le32enc(&h[FILE_HEADER_UNCOMPRESSED_SIZE],
- (uint32_t)archive_entry_size(l->entry));
- archive_le16enc(&h[FILE_HEADER_FILENAME_LENGTH],
- (uint16_t)path_length(l->entry));
- archive_le16enc(&h[FILE_HEADER_EXTRA_LENGTH], sizeof(e));
- archive_le16enc(&h[FILE_HEADER_ATTRIBUTES_EXTERNAL+2],
- archive_entry_mode(l->entry));
- archive_le32enc(&h[FILE_HEADER_OFFSET], (uint32_t)l->offset);
-
- /* Formatting extra data. */
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_ID],
- ZIP_SIGNATURE_EXTRA_TIMESTAMP);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_TIME_SIZE], 1 + 4);
- e[EXTRA_DATA_CENTRAL_TIME_FLAG] = 0x07;
- archive_le32enc(&e[EXTRA_DATA_CENTRAL_MTIME],
- (uint32_t)archive_entry_mtime(l->entry));
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_ID],
- ZIP_SIGNATURE_EXTRA_NEW_UNIX);
- archive_le16enc(&e[EXTRA_DATA_CENTRAL_UNIX_SIZE], 0x0000);
-
- ret = __archive_write_output(a, h, sizeof(h));
+ segment = zip->central_directory;
+ while (segment != NULL) {
+ ret = __archive_write_output(a,
+ segment->buff, segment->p - segment->buff);
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;
+ zip->written_bytes += segment->p - segment->buff;
+ segment = segment->next;
+ }
+ offset_end = zip->written_bytes;
- ret = __archive_write_output(a, e, sizeof(e));
- if (ret != ARCHIVE_OK)
- return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(e);
+ /* If central dir info is too large, write Zip64 end-of-cd */
+ if (offset_end - offset_start > ZIP_4GB_MAX
+ || offset_start > ZIP_4GB_MAX
+ || zip->central_directory_entries > 0xffffUL
+ || (zip->flags & ZIP_FLAG_FORCE_ZIP64)) {
+ /* Zip64 end-of-cd record */
+ memset(buff, 0, 56);
+ memcpy(buff, "PK\006\006", 4);
+ archive_le64enc(buff + 4, 44);
+ archive_le16enc(buff + 12, 45);
+ archive_le16enc(buff + 14, 45);
+ /* This is disk 0 of 0. */
+ archive_le64enc(buff + 24, zip->central_directory_entries);
+ archive_le64enc(buff + 32, zip->central_directory_entries);
+ archive_le64enc(buff + 40, offset_end - offset_start);
+ archive_le64enc(buff + 48, offset_start);
+ ret = __archive_write_output(a, buff, 56);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ zip->written_bytes += 56;
+
+ /* Zip64 end-of-cd locator record. */
+ memset(buff, 0, 20);
+ memcpy(buff, "PK\006\007", 4);
+ archive_le32enc(buff + 4, 0);
+ archive_le64enc(buff + 8, offset_end);
+ archive_le32enc(buff + 16, 1);
+ ret = __archive_write_output(a, buff, 20);
+ if (ret != ARCHIVE_OK)
+ return (ARCHIVE_FATAL);
+ zip->written_bytes += 20;
- l = l->next;
- entries++;
}
- offset_end = zip->written_bytes;
- /* Formatting end of central directory. */
- memset(end, 0, sizeof(end));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIGNATURE],
- ZIP_SIGNATURE_CENTRAL_DIRECTORY_END);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES_DISK], entries);
- archive_le16enc(&end[CENTRAL_DIRECTORY_END_ENTRIES], entries);
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_SIZE],
- (uint32_t)(offset_end - offset_start));
- archive_le32enc(&end[CENTRAL_DIRECTORY_END_OFFSET],
- (uint32_t)offset_start);
-
- /* Writing end of central directory. */
- ret = __archive_write_output(a, end, sizeof(end));
+ /* Format and write end of central directory. */
+ memset(buff, 0, sizeof(buff));
+ memcpy(buff, "PK\005\006", 4);
+ archive_le16enc(buff + 8, (uint16_t)zipmin(0xffffU,
+ zip->central_directory_entries));
+ archive_le16enc(buff + 10, (uint16_t)zipmin(0xffffU,
+ zip->central_directory_entries));
+ archive_le32enc(buff + 12,
+ (uint32_t)zipmin(ZIP_4GB_MAX, (offset_end - offset_start)));
+ archive_le32enc(buff + 16,
+ (uint32_t)zipmin(ZIP_4GB_MAX, offset_start));
+ ret = __archive_write_output(a, buff, 22);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- zip->written_bytes += sizeof(end);
+ zip->written_bytes += 22;
return (ARCHIVE_OK);
}
@@ -834,18 +1346,23 @@ static int
archive_write_zip_free(struct archive_write *a)
{
struct zip *zip;
- struct zip_file_header_link *l;
+ struct cd_segment *segment;
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);
+ segment = zip->central_directory;
+ zip->central_directory = segment->next;
+ free(segment->buff);
+ free(segment);
}
-#ifdef HAVE_ZLIB_H
free(zip->buf);
-#endif
+ archive_entry_free(zip->entry);
+ if (zip->cctx_valid)
+ archive_encrypto_aes_ctr_release(&zip->cctx);
+ if (zip->hctx_valid)
+ archive_hmac_sha1_cleanup(&zip->hctx);
+ /* TODO: Free opt_sconv, sconv_default */
+
free(zip);
a->format_data = NULL;
return (ARCHIVE_OK);
@@ -918,7 +1435,7 @@ write_path(struct archive_entry *entry, struct archive_write *archive)
return (ARCHIVE_FATAL);
written_bytes += strlen(path);
- /* Folders are recognized by a traling slash. */
+ /* Folders are recognized by a trailing slash. */
if ((type == AE_IFDIR) & (path[strlen(path) - 1] != '/')) {
ret = __archive_write_output(archive, "/", 1);
if (ret != ARCHIVE_OK)
@@ -928,3 +1445,234 @@ write_path(struct archive_entry *entry, struct archive_write *archive)
return ((int)written_bytes);
}
+
+static void
+copy_path(struct archive_entry *entry, unsigned char *p)
+{
+ const char *path;
+ size_t pathlen;
+ mode_t type;
+
+ path = archive_entry_pathname(entry);
+ pathlen = strlen(path);
+ type = archive_entry_filetype(entry);
+
+ memcpy(p, path, pathlen);
+
+ /* Folders are recognized by a trailing slash. */
+ if ((type == AE_IFDIR) & (path[pathlen - 1] != '/')) {
+ p[pathlen] = '/';
+ p[pathlen + 1] = '\0';
+ }
+}
+
+
+static struct archive_string_conv *
+get_sconv(struct archive_write *a, struct zip *zip)
+{
+ if (zip->opt_sconv != NULL)
+ return (zip->opt_sconv);
+
+ if (!zip->init_default_conversion) {
+ zip->sconv_default =
+ archive_string_default_conversion_for_write(&(a->archive));
+ zip->init_default_conversion = 1;
+ }
+ return (zip->sconv_default);
+}
+
+/*
+ Traditional PKWARE Decryption functions.
+ */
+
+static void
+trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c)
+{
+ uint8_t t;
+#define CRC32(c, b) (crc32(c ^ 0xffffffffUL, &b, 1) ^ 0xffffffffUL)
+
+ ctx->keys[0] = CRC32(ctx->keys[0], c);
+ ctx->keys[1] = (ctx->keys[1] + (ctx->keys[0] & 0xff)) * 134775813L + 1;
+ t = (ctx->keys[1] >> 24) & 0xff;
+ ctx->keys[2] = CRC32(ctx->keys[2], t);
+#undef CRC32
+}
+
+static uint8_t
+trad_enc_decrypt_byte(struct trad_enc_ctx *ctx)
+{
+ unsigned temp = ctx->keys[2] | 2;
+ return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff;
+}
+
+static unsigned
+trad_enc_encrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in,
+ size_t in_len, uint8_t *out, size_t out_len)
+{
+ unsigned i, max;
+
+ max = (unsigned)((in_len < out_len)? in_len: out_len);
+
+ for (i = 0; i < max; i++) {
+ uint8_t t = in[i];
+ out[i] = t ^ trad_enc_decrypt_byte(ctx);
+ trad_enc_update_keys(ctx, t);
+ }
+ return i;
+}
+
+static int
+trad_enc_init(struct trad_enc_ctx *ctx, const char *pw, size_t pw_len)
+{
+
+ ctx->keys[0] = 305419896L;
+ ctx->keys[1] = 591751049L;
+ ctx->keys[2] = 878082192L;
+
+ for (;pw_len; --pw_len)
+ trad_enc_update_keys(ctx, *pw++);
+ return 0;
+}
+
+static int
+is_traditional_pkware_encryption_supported(void)
+{
+ uint8_t key[TRAD_HEADER_SIZE];
+
+ if (archive_random(key, sizeof(key)-1) != ARCHIVE_OK)
+ return (0);
+ return (1);
+}
+
+static int
+init_traditional_pkware_encryption(struct archive_write *a)
+{
+ struct zip *zip = a->format_data;
+ const char *passphrase;
+ uint8_t key[TRAD_HEADER_SIZE];
+ uint8_t key_encrypted[TRAD_HEADER_SIZE];
+ int ret;
+
+ passphrase = __archive_write_get_passphrase(a);
+ if (passphrase == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Encryption needs passphrase");
+ return ARCHIVE_FAILED;
+ }
+ if (archive_random(key, sizeof(key)-1) != ARCHIVE_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't generate random number for encryption");
+ return ARCHIVE_FATAL;
+ }
+ trad_enc_init(&zip->tctx, passphrase, strlen(passphrase));
+ /* Set the last key code which will be used as a check code
+ * for verifying passphrase in decryption. */
+ key[TRAD_HEADER_SIZE-1] = zip->trad_chkdat;
+ trad_enc_encrypt_update(&zip->tctx, key, TRAD_HEADER_SIZE,
+ key_encrypted, TRAD_HEADER_SIZE);
+ /* Write encrypted keys in the top of the file content. */
+ ret = __archive_write_output(a, key_encrypted, TRAD_HEADER_SIZE);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->written_bytes += TRAD_HEADER_SIZE;
+ zip->entry_compressed_written += TRAD_HEADER_SIZE;
+ return (ret);
+}
+
+static int
+init_winzip_aes_encryption(struct archive_write *a)
+{
+ struct zip *zip = a->format_data;
+ const char *passphrase;
+ size_t key_len, salt_len;
+ uint8_t salt[16 + 2];
+ uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];
+ int ret;
+
+ passphrase = __archive_write_get_passphrase(a);
+ if (passphrase == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Encryption needs passphrase");
+ return (ARCHIVE_FAILED);
+ }
+ if (zip->entry_encryption == ENCRYPTION_WINZIP_AES128) {
+ salt_len = 8;
+ key_len = 16;
+ } else {
+ /* AES 256 */
+ salt_len = 16;
+ key_len = 32;
+ }
+ if (archive_random(salt, salt_len) != ARCHIVE_OK) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't generate random number for encryption");
+ return (ARCHIVE_FATAL);
+ }
+ archive_pbkdf2_sha1(passphrase, strlen(passphrase),
+ salt, salt_len, 1000, derived_key, key_len * 2 + 2);
+
+ ret = archive_encrypto_aes_ctr_init(&zip->cctx, derived_key, key_len);
+ if (ret != 0) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Decryption is unsupported due to lack of crypto library");
+ return (ARCHIVE_FAILED);
+ }
+ ret = archive_hmac_sha1_init(&zip->hctx, derived_key + key_len,
+ key_len);
+ if (ret != 0) {
+ archive_encrypto_aes_ctr_release(&zip->cctx);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to initialize HMAC-SHA1");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Set a password verification value after the 'salt'. */
+ salt[salt_len] = derived_key[key_len * 2];
+ salt[salt_len + 1] = derived_key[key_len * 2 + 1];
+
+ /* Write encrypted keys in the top of the file content. */
+ ret = __archive_write_output(a, salt, salt_len + 2);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ zip->written_bytes += salt_len + 2;
+ zip->entry_compressed_written += salt_len + 2;
+
+ return (ARCHIVE_OK);
+}
+
+static int
+is_winzip_aes_encryption_supported(int encryption)
+{
+ size_t key_len, salt_len;
+ uint8_t salt[16 + 2];
+ uint8_t derived_key[MAX_DERIVED_KEY_BUF_SIZE];
+ archive_crypto_ctx cctx;
+ archive_hmac_sha1_ctx hctx;
+ int ret;
+
+ if (encryption == ENCRYPTION_WINZIP_AES128) {
+ salt_len = 8;
+ key_len = 16;
+ } else {
+ /* AES 256 */
+ salt_len = 16;
+ key_len = 32;
+ }
+ if (archive_random(salt, salt_len) != ARCHIVE_OK)
+ return (0);
+ ret = archive_pbkdf2_sha1("p", 1, salt, salt_len, 1000,
+ derived_key, key_len * 2 + 2);
+ if (ret != 0)
+ return (0);
+
+ ret = archive_encrypto_aes_ctr_init(&cctx, derived_key, key_len);
+ if (ret != 0)
+ return (0);
+ ret = archive_hmac_sha1_init(&hctx, derived_key + key_len,
+ key_len);
+ archive_encrypto_aes_ctr_release(&cctx);
+ if (ret != 0)
+ return (0);
+ archive_hmac_sha1_cleanup(&hctx);
+ return (1);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_options.3 b/Utilities/cmlibarchive/libarchive/archive_write_set_options.3
index 9d605151a..aeb7a1848 100644
--- a/Utilities/cmlibarchive/libarchive/archive_write_set_options.3
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_options.3
@@ -32,7 +32,7 @@
.Nm archive_write_set_format_option ,
.Nm archive_write_set_option ,
.Nm archive_write_set_options
-.Nd functions controlling options for reading archives
+.Nd functions controlling options for writing archives
.Sh LIBRARY
Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
@@ -101,7 +101,12 @@ and
.Ar value
will be provided to the filter or reader named
.Ar module .
-The return value will be that of the module.
+The return value will be either
+.Cm ARCHIVE_OK
+if the option was successfully handled or
+.Cm ARCHIVE_WARN
+if the option was unrecognized by the module or could otherwise
+not be handled.
If there is no such module,
.Cm ARCHIVE_FAILED
will be returned.
@@ -123,9 +128,7 @@ will be returned if any module accepts the option, and
.Cm ARCHIVE_FAILED
in all other cases.
.\"
-.It Xo
-.Fn archive_write_set_option
-.Xc
+.It Fn archive_write_set_option
Calls
.Fn archive_write_set_format_option ,
then
@@ -137,9 +140,7 @@ will be returned
immediately.
Otherwise, greater of the two values will be returned.
.\"
-.It Xo
-.Fn archive_write_set_options
-.Xc
+.It Fn archive_write_set_options
.Ar options
is a comma-separated list of options.
If
@@ -255,7 +256,7 @@ If the
.Ar value
is
.Cm hd ,
-then the the boot image is assumed to be a bootable hard disk image.
+then the boot image is assumed to be a bootable hard disk image.
If the
.Ar value
is
@@ -397,6 +398,48 @@ Specifies a filename that should not be compressed when using
This option can be provided multiple times to suppress compression
on many files.
.El
+.It Format zip
+.Bl -tag -compact -width indent
+.It Cm compression
+The value is either
+.Dq store
+or
+.Dq deflate
+to indicate how the following entries should be compressed.
+Note that this setting is ignored for directories, symbolic links,
+and other special entries.
+.It Cm experimental
+This boolean option enables or disables experimental Zip features
+that may not be compatible with other Zip implementations.
+.It Cm fakecrc32
+This boolean option disables CRC calculations.
+All CRC fields are set to zero.
+It should not be used except for testing purposes.
+.It Cm hdrcharset
+This sets the character set used for filenames.
+.It Cm zip64
+Zip64 extensions provide additional file size information
+for entries larger than 4 GiB.
+They also provide extended file offset and archive size information
+when archives exceed 4 GiB.
+By default, the Zip writer selectively enables these extensions only as needed.
+In particular, if the file size is unknown, the Zip writer will
+include Zip64 extensions to guard against the possibility that the
+file might be larger than 4 GiB.
+.Pp
+Setting this boolean option will force the writer to use Zip64 extensions
+even for small files that would not otherwise require them.
+This is primarily useful for testing.
+.Pp
+Disabling this option with
+.Cm !zip64
+will force the Zip writer to avoid Zip64 extensions:
+It will reject files with size greater than 4 GiB,
+it will reject any new entries once the total archive size reaches 4 GiB,
+and it will not use Zip64 extensions for files with unknown size.
+In particular, this can improve compatibility when generating archives
+where the entry sizes are not known in advance.
+.El
.El
.Sh EXAMPLES
The following example creates an archive write handle to
@@ -414,7 +457,7 @@ archive_write_open_filename(a, filename, blocksize);
.Ed
.\"
.Sh ERRORS
-Detailed error codes and textual descriptions are available from the
+More detailed error codes and textual descriptions are available from the
.Fn archive_errno
and
.Fn archive_error_string
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.3 b/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.3
new file mode 100644
index 000000000..2585595e3
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.3
@@ -0,0 +1,74 @@
+.\" Copyright (c) 2014 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 AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 21, 2014
+.Dt ARCHIVE_WRITE_SET_PASSPHRASE 3
+.Os
+.Sh NAME
+.Nm archive_write_set_passphrase ,
+.Nm archive_write_set_passphrase_callback
+.Nd functions for writing encrypted archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_write_set_passphrase
+.Fa "struct archive *"
+.Fa "const char *passphrase"
+.Fc
+.Ft int
+.Fo archive_write_set_passphrase_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_passphrase_callback *"
+.Fc
+.Sh DESCRIPTION
+.Bl -tag -width indent
+.It Fn archive_write_set_passphrase
+Set a passphrase for writing an encryption archive.
+If
+.Ar passphrase
+is
+.Dv NULL
+or empty, this function will do nothing and
+.Cm ARCHIVE_FAILED
+will be returned.
+Otherwise,
+.Cm ARCHIVE_OK
+will be returned.
+.It Fn archive_write_set_passphrase_callback
+Register callback function that will be invoked to get a passphrase
+for encrption if the passphrase was not set by the
+.Fn archive_write_set_passphrase
+function.
+.El
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_write 3 ,
+.Xr archive_write_set_options 3
diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.c b/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.c
new file mode 100644
index 000000000..710ecba52
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_write_set_passphrase.c
@@ -0,0 +1,95 @@
+/*-
+ * Copyright (c) 2014 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 "archive_write_private.h"
+
+int
+archive_write_set_passphrase(struct archive *_a, const char *p)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+
+ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_write_set_passphrase");
+
+ if (p == NULL || p[0] == '\0') {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Empty passphrase is unacceptable");
+ return (ARCHIVE_FAILED);
+ }
+ free(a->passphrase);
+ a->passphrase = strdup(p);
+ if (a->passphrase == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate data for passphrase");
+ return (ARCHIVE_FATAL);
+ }
+ return (ARCHIVE_OK);
+}
+
+
+int
+archive_write_set_passphrase_callback(struct archive *_a, void *client_data,
+ archive_passphrase_callback *cb)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+
+ archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_write_set_passphrase_callback");
+
+ a->passphrase_callback = cb;
+ a->passphrase_client_data = client_data;
+ return (ARCHIVE_OK);
+}
+
+
+const char *
+__archive_write_get_passphrase(struct archive_write *a)
+{
+
+ if (a->passphrase != NULL)
+ return (a->passphrase);
+
+ if (a->passphrase_callback != NULL) {
+ const char *p;
+ p = a->passphrase_callback(&a->archive,
+ a->passphrase_client_data);
+ if (p != NULL) {
+ a->passphrase = strdup(p);
+ if (a->passphrase == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate data for passphrase");
+ return (NULL);
+ }
+ return (a->passphrase);
+ }
+ }
+ return (NULL);
+}
diff --git a/Utilities/cmlibarchive/libarchive/archive_xxhash.h b/Utilities/cmlibarchive/libarchive/archive_xxhash.h
new file mode 100644
index 000000000..427241641
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/archive_xxhash.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2014 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.
+ *
+ */
+
+#ifndef __LIBARCHIVE_BUILD
+#error This header is only to be used internally to libarchive.
+#endif
+
+#ifndef ARCHIVE_XXHASH_H
+#define ARCHIVE_XXHASH_H
+
+typedef enum { XXH_OK=0, XXH_ERROR } XXH_errorcode;
+
+struct archive_xxhash {
+ unsigned int (*XXH32)(const void* input, unsigned int len,
+ unsigned int seed);
+ void* (*XXH32_init)(unsigned int seed);
+ XXH_errorcode (*XXH32_update)(void* state, const void* input,
+ unsigned int len);
+ unsigned int (*XXH32_digest)(void* state);
+};
+
+extern const struct archive_xxhash __archive_xxhash;
+
+#endif
diff --git a/Utilities/cmlibarchive/libarchive/config_freebsd.h b/Utilities/cmlibarchive/libarchive/config_freebsd.h
index 207343163..215e886be 100644
--- a/Utilities/cmlibarchive/libarchive/config_freebsd.h
+++ b/Utilities/cmlibarchive/libarchive/config_freebsd.h
@@ -28,6 +28,7 @@
/* FreeBSD 5.0 and later have ACL and extattr support. */
#if __FreeBSD__ > 4
#define HAVE_ACL_CREATE_ENTRY 1
+#define HAVE_ACL_GET_FD_NP 1
#define HAVE_ACL_GET_LINK_NP 1
#define HAVE_ACL_GET_PERM_NP 1
#define HAVE_ACL_INIT 1
@@ -39,6 +40,7 @@
#define HAVE_EXTATTR_LIST_FILE 1
#define HAVE_EXTATTR_SET_FD 1
#define HAVE_EXTATTR_SET_FILE 1
+#define HAVE_STRUCT_XVFSCONF 1
#define HAVE_SYS_ACL_H 1
#define HAVE_SYS_EXTATTR_H 1
#endif
diff --git a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c
index fa59cc9e9..ad271fe68 100644
--- a/Utilities/cmlibarchive/libarchive/filter_fork_windows.c
+++ b/Utilities/cmlibarchive/libarchive/filter_fork_windows.c
@@ -36,7 +36,7 @@ __archive_create_child(const char *cmd, int *child_stdin, int *child_stdout)
{
HANDLE childStdout[2], childStdin[2],childStderr;
SECURITY_ATTRIBUTES secAtts;
- STARTUPINFO staInfo;
+ STARTUPINFOA staInfo;
PROCESS_INFORMATION childInfo;
struct archive_string cmdline;
struct archive_string fullpath;
diff --git a/Utilities/cmlibarchive/libarchive/libarchive-formats.5 b/Utilities/cmlibarchive/libarchive/libarchive-formats.5
index 4a709b33c..62359ddc2 100644
--- a/Utilities/cmlibarchive/libarchive/libarchive-formats.5
+++ b/Utilities/cmlibarchive/libarchive/libarchive-formats.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 18, 2012
+.Dd December 27, 2016
.Dt LIBARCHIVE-FORMATS 5
.Os
.Sh NAME
@@ -55,7 +55,7 @@ It can write POSIX-standard
.Dq ustar
and
.Dq pax interchange
-formats and a subset of the legacy GNU tar format.
+formats as well as v7 tar format and a subset of the legacy GNU tar format.
.Pp
All tar formats store each entry in one or more 512-byte records.
The first record is used for file metadata, including filename,
@@ -65,7 +65,6 @@ Later variants have extended this by either appropriating undefined
areas of the header record, extending the header to multiple records,
or by storing special entries that modify the interpretation of
subsequent entries.
-.Pp
.Bl -tag -width indent
.It Cm gnutar
The
@@ -150,6 +149,30 @@ Archive entries are limited to 8 gigabytes in size.
Note that the pax interchange format has none of these restrictions.
The ustar format is old and widely supported.
It is recommended when compatibility is the primary concern.
+.It Cm v7
+The libarchive library can read and write the legacy v7 tar format.
+This format has the following limitations:
+.Bl -bullet -compact
+.It
+Only regular files, directories, and symbolic links can be archived.
+Block and character device nodes, FIFOs, and sockets cannot be archived.
+.It
+Path names in the archive are limited to 100 bytes.
+.It
+Symbolic links and hard links are stored in the archive with
+the name of the referenced file.
+This name is limited to 100 bytes.
+.It
+User and group information are stored as numeric IDs; there
+is no provision for storing user or group names.
+.It
+Extended attributes, file flags, and other extended
+security information cannot be stored.
+.It
+Archive entries are limited to 8 gigabytes in size.
+.El
+Generally, users should prefer the ustar format for portability
+as the v7 tar format is both less useful and less portable.
.El
.Pp
The libarchive library also reads a variety of commonly-used extensions to
@@ -168,8 +191,6 @@ and device numbers.
.It Solaris extensions
Libarchive recognizes ACL and extended attribute records written
by Solaris tar.
-Currently, libarchive only has support for old-style ACLs; the
-newer NFSv4 ACLs are recognized but discarded.
.El
.Pp
The first tar program appeared in Seventh Edition Unix in 1979.
@@ -211,7 +232,7 @@ This format stores the header contents as octal values in ASCII.
It is standard, portable, and immune from byte-order confusion.
File sizes and mtime are limited to 33 bits (8GB file size),
other fields are limited to 18 bits.
-.It Cm SVR4
+.It Cm SVR4/newc
The libarchive library can read both CRC and non-CRC variants of
this format.
The SVR4 format uses eight-digit hexadecimal values for
@@ -364,8 +385,10 @@ area adjacent to the entry.
Libarchive can read both extensions,
including archives that may include both types of long filenames.
Programs using libarchive can write GNU/SVR4 format
-if they provide a filename table to be written into
-the archive before any of the entries.
+if they provide an entry called
+.Pa //
+containing a filename table to be written into the archive
+before any of the entries.
Any entries whose names are not in the filename table
will be written using BSD-style long filenames.
This can cause problems for programs such as
@@ -406,18 +429,29 @@ using libarchive.
If it cannot locate and open the file on disk, libarchive
will return an error for any attempt to read the entry
body.
-.Ss LHA
-XXX Information about libarchive's LHA support XXX
+.Ss 7-Zip
+Libarchive can read and write 7-Zip format archives.
+TODO: Need more information
.Ss CAB
-XXX Information about libarchive's CAB support XXX
-.Ss XAR
-XXX Information about libarchive's XAR support XXX
+Libarchive can read Microsoft Cabinet (
+.Dq CAB )
+format archives.
+TODO: Need more information.
+.Ss LHA
+TODO: Information about libarchive's LHA support
.Ss RAR
Libarchive has limited support for reading RAR format archives.
Currently, libarchive can read RARv3 format archives
which have been either created uncompressed, or compressed using
any of the compression methods supported by the RARv3 format.
Libarchive can also read self-extracting RAR archives.
+.Ss Warc
+Libarchive can read and write
+.Dq web archives .
+TODO: Need more information
+.Ss XAR
+Libarchive can read and write the XAR format used by many Apple tools.
+TODO: Need more information
.Sh SEE ALSO
.Xr ar 1 ,
.Xr cpio 1 ,
diff --git a/Utilities/cmlibarchive/libarchive/libarchive.3 b/Utilities/cmlibarchive/libarchive/libarchive.3
index 3a9a841d3..c6894d2d4 100644
--- a/Utilities/cmlibarchive/libarchive/libarchive.3
+++ b/Utilities/cmlibarchive/libarchive/libarchive.3
@@ -146,11 +146,11 @@ pages for each API or utility function.
.\"
.Sh READING AN ARCHIVE
See
-.Xr libarchive_read 3 .
+.Xr archive_read 3 .
.\"
.Sh WRITING AN ARCHIVE
See
-.Xr libarchive_write 3 .
+.Xr archive_write 3 .
.\"
.Sh WRITING ENTRIES TO DISK
The
diff --git a/Utilities/cmlibarchive/libarchive/libarchive_changes.3 b/Utilities/cmlibarchive/libarchive/libarchive_changes.3
index bacd6e123..881a67cdd 100644
--- a/Utilities/cmlibarchive/libarchive/libarchive_changes.3
+++ b/Utilities/cmlibarchive/libarchive/libarchive_changes.3
@@ -28,7 +28,7 @@
.Dt LIBARCHIVE_CHANGES 3
.Os
.Sh NAME
-.Nm changes in libarchive interface
+.Nd changes in libarchive interface
.\"
.Sh CHANGES IN LIBARCHIVE 3
This page describes user-visible changes in libarchive3, and lists
diff --git a/Utilities/cmlibarchive/libarchive/libarchive_internals.3 b/Utilities/cmlibarchive/libarchive/libarchive_internals.3
index 4aa09f93e..8275d66e6 100644
--- a/Utilities/cmlibarchive/libarchive/libarchive_internals.3
+++ b/Utilities/cmlibarchive/libarchive/libarchive_internals.3
@@ -347,11 +347,11 @@ Fortunately, such archives are very rare, and libarchive can read
most ZIP archives, though it cannot always extract as much information
as a dedicated ZIP program.
.Sh SEE ALSO
-.Xr archive 3 ,
.Xr archive_entry 3 ,
.Xr archive_read 3 ,
.Xr archive_write 3 ,
.Xr archive_write_disk 3
+.Xr libarchive 3 ,
.Sh HISTORY
The
.Nm libarchive
diff --git a/Utilities/cmlibarchive/libarchive/mtree.5 b/Utilities/cmlibarchive/libarchive/mtree.5
index 983fff723..16c8abec4 100644
--- a/Utilities/cmlibarchive/libarchive/mtree.5
+++ b/Utilities/cmlibarchive/libarchive/mtree.5
@@ -28,7 +28,7 @@
.\" From: @(#)mtree.8 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
-.Dd May 6, 2008
+.Dd September 4, 2013
.Dt MTREE 5
.Os
.Sh NAME
@@ -56,14 +56,6 @@ corresponding character.
.Pp
Each line is interpreted independently as one of the following types:
.Bl -tag -width Cm
-.It Signature
-The first line of any mtree file must begin with
-.Dq #mtree .
-If a file contains any full path entries, the first line should
-begin with
-.Dq #mtree v2.0 ,
-otherwise, the first line should begin with
-.Dq #mtree v1.0 .
.It Blank
Blank lines are ignored.
.It Comment
@@ -134,6 +126,52 @@ The checksum of the file using the default algorithm specified by
the
.Xr cksum 1
utility.
+.It Cm device
+The device number for
+.Sy block
+or
+.Sy char
+file types.
+The value must be one of the following forms:
+.Pp
+.Bl -tag -width 4n
+.It Ar format , Ns Ar major , Ns Ar minor Ns Bo , Ns Ar subunit Bc
+A device with
+.Ar major , minor
+and optional
+.Ar subunit
+fields.
+Their meaning is specified by the operating's system
+.Ar format .
+See below for valid formats.
+.It Ar number
+Opaque number (as stored on the file system).
+.El
+.Pp
+The following values for
+.Ar format
+are recognized:
+.Sy native ,
+.Sy 386bsd ,
+.Sy 4bsd ,
+.Sy bsdos ,
+.Sy freebsd ,
+.Sy hpux ,
+.Sy isc ,
+.Sy linux ,
+.Sy netbsd ,
+.Sy osf1 ,
+.Sy sco ,
+.Sy solaris ,
+.Sy sunos ,
+.Sy svr3 ,
+.Sy svr4 ,
+and
+.Sy ultrix .
+.Pp
+See
+.Xr mknod 8
+for more details.
.It Cm contents
The full pathname of a file that holds the contents of this file.
.It Cm flags
@@ -150,6 +188,8 @@ The file group as a numeric value.
The file group as a symbolic name.
.It Cm ignore
Ignore any file hierarchy below this file.
+.It Cm inode
+The inode number.
.It Cm link
The target of the symbolic link when type=link.
.It Cm md5
@@ -164,6 +204,16 @@ value.
The number of hard links the file is expected to have.
.It Cm nochange
Make sure this file or directory exists but otherwise ignore all attributes.
+.It Cm optional
+The file is optional; do not complain about the file if it is not in
+the file hierarchy.
+.It Cm resdevice
+The
+.Dq resident
+device number of the file, e.g. the ID of the device that
+contains the file.
+Its format is the same as the one for
+.Cm device .
.It Cm ripemd160digest
The
.Tn RIPEMD160
@@ -192,6 +242,24 @@ message digest of the file.
.It Cm sha256digest
A synonym for
.Cm sha256 .
+.It Cm sha384
+The
+.Tn FIPS
+180-2
+.Pq Dq Tn SHA-384
+message digest of the file.
+.It Cm sha384digest
+A synonym for
+.Cm sha384 .
+.It Cm sha512
+The
+.Tn FIPS
+180-2
+.Pq Dq Tn SHA-512
+message digest of the file.
+.It Cm sha512digest
+A synonym for
+.Cm sha512 .
.It Cm size
The size, in bytes, of the file.
.It Cm time
@@ -226,16 +294,6 @@ The file owner as a symbolic name.
.Xr find 1 ,
.Xr mtree 8
.Sh BUGS
-The
-.Fx
-implementation of mtree does not currently support
-the
-.Nm
-2.0
-format.
-The requirement for a
-.Dq #mtree
-signature line is new and not yet widely implemented.
.Sh HISTORY
The
.Nm
diff --git a/Utilities/cmlibarchive/libarchive/tar.5 b/Utilities/cmlibarchive/libarchive/tar.5
index 688bb922c..30b837dc4 100644
--- a/Utilities/cmlibarchive/libarchive/tar.5
+++ b/Utilities/cmlibarchive/libarchive/tar.5
@@ -1,4 +1,5 @@
.\" Copyright (c) 2003-2009 Tim Kientzle
+.\" Copyright (c) 2016 Martin Matuska
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 23, 2011
+.Dd December 27, 2016
.Dt TAR 5
.Os
.Sh NAME
@@ -440,11 +441,11 @@ archives to store files much larger than the historic 8GB limit.
Vendor-specific attributes used by Joerg Schilling's
.Nm star
implementation.
-.It Cm SCHILY.acl.access , Cm SCHILY.acl.default
-Stores the access and default ACLs as textual strings in a format
+.It Cm SCHILY.acl.access , Cm SCHILY.acl.default, Cm SCHILY.acl.ace
+Stores the access, default and NFSv4 ACLs as textual strings in a format
that is an extension of the format specified by POSIX.1e draft 17.
-In particular, each user or group access specification can include a fourth
-colon-separated field with the numeric UID or GID.
+In particular, each user or group access specification can include
+an additional colon-separated field with the numeric UID or GID.
This allows ACLs to be restored on systems that may not have complete
user or group information available (such as when NIS/YP or LDAP services
are temporarily unavailable).
@@ -935,7 +936,7 @@ and formed the basis of
(circa 1988).
Joerg Shilling's
.Nm star
-archiver is another open-source (GPL) archiver (originally developed
+archiver is another open-source (CDDL) archiver (originally developed
circa 1985) which features complete support for pax interchange
format.
.Pp
diff --git a/Utilities/cmlibarchive/libarchive/xxhash.c b/Utilities/cmlibarchive/libarchive/xxhash.c
new file mode 100644
index 000000000..6f5ba52fa
--- /dev/null
+++ b/Utilities/cmlibarchive/libarchive/xxhash.c
@@ -0,0 +1,515 @@
+/*
+xxHash - Fast Hash algorithm
+Copyright (C) 2012-2014, Yann Collet.
+BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+* 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 COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+You can contact the author at :
+- xxHash source repository : http://code.google.com/p/xxhash/
+*/
+#include "archive_platform.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "archive_xxhash.h"
+
+#ifdef HAVE_LIBLZ4
+
+/***************************************
+** Tuning parameters
+****************************************/
+/* Unaligned memory access is automatically enabled for "common" CPU, such as x86.
+** For others CPU, the compiler will be more cautious, and insert extra code to ensure aligned access is respected.
+** If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance.
+** You can also enable this parameter if you know your input data will always be aligned (boundaries of 4, for U32).
+*/
+#if defined(__ARM_FEATURE_UNALIGNED) || defined(__i386) || defined(_M_IX86) || defined(__x86_64__) || defined(_M_X64)
+# define XXH_USE_UNALIGNED_ACCESS 1
+#endif
+
+/* XXH_ACCEPT_NULL_INPUT_POINTER :
+** If the input pointer is a null pointer, xxHash default behavior is to trigger a memory access error, since it is a bad pointer.
+** When this option is enabled, xxHash output for null input pointers will be the same as a null-length input.
+** This option has a very small performance cost (only measurable on small inputs).
+** By default, this option is disabled. To enable it, uncomment below define :
+** #define XXH_ACCEPT_NULL_INPUT_POINTER 1
+
+** XXH_FORCE_NATIVE_FORMAT :
+** By default, xxHash library provides endian-independent Hash values, based on little-endian convention.
+** Results are therefore identical for little-endian and big-endian CPU.
+** This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format.
+** Should endian-independence be of no importance for your application, you may set the #define below to 1.
+** It will improve speed for Big-endian CPU.
+** This option has no impact on Little_Endian CPU.
+*/
+#define XXH_FORCE_NATIVE_FORMAT 0
+
+/***************************************
+** Compiler Specific Options
+****************************************/
+/* Disable some Visual warning messages */
+#ifdef _MSC_VER /* Visual Studio */
+# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
+#endif
+
+#ifdef _MSC_VER /* Visual Studio */
+# define FORCE_INLINE __forceinline
+#else
+# ifdef __GNUC__
+# define FORCE_INLINE inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE inline
+# endif
+#endif
+
+/***************************************
+** Includes & Memory related functions
+****************************************/
+#define XXH_malloc malloc
+#define XXH_free free
+#define XXH_memcpy memcpy
+
+
+static unsigned int XXH32 (const void*, unsigned int, unsigned int);
+static void* XXH32_init (unsigned int);
+static XXH_errorcode XXH32_update (void*, const void*, unsigned int);
+static unsigned int XXH32_digest (void*);
+/*static int XXH32_sizeofState(void);*/
+static XXH_errorcode XXH32_resetState(void*, unsigned int);
+#define XXH32_SIZEOFSTATE 48
+typedef struct { long long ll[(XXH32_SIZEOFSTATE+(sizeof(long long)-1))/sizeof(long long)]; } XXH32_stateSpace_t;
+static unsigned int XXH32_intermediateDigest (void*);
+
+/***************************************
+** Basic Types
+****************************************/
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+#else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+#endif
+
+#if defined(__GNUC__) && !defined(XXH_USE_UNALIGNED_ACCESS)
+# define _PACKED __attribute__ ((packed))
+#else
+# define _PACKED
+#endif
+
+#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+# ifdef __IBMC__
+# pragma pack(1)
+# else
+# pragma pack(push, 1)
+# endif
+#endif
+
+typedef struct _U32_S { U32 v; } _PACKED U32_S;
+
+#if !defined(XXH_USE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+# pragma pack(pop)
+#endif
+
+#define A32(x) (((const U32_S *)(x))->v)
+
+
+/****************************************
+** Compiler-specific Functions and Macros
+*****************************************/
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+/* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
+#if defined(_MSC_VER)
+# define XXH_rotl32(x,r) _rotl(x,r)
+#else
+# define XXH_rotl32(x,r) ((x << r) | (x >> (32 - r)))
+#endif
+
+#if defined(_MSC_VER) /* Visual Studio */
+# define XXH_swap32 _byteswap_ulong
+#elif GCC_VERSION >= 403
+# define XXH_swap32 __builtin_bswap32
+#else
+static inline U32 XXH_swap32 (U32 x) {
+ return ((x << 24) & 0xff000000 ) |
+ ((x << 8) & 0x00ff0000 ) |
+ ((x >> 8) & 0x0000ff00 ) |
+ ((x >> 24) & 0x000000ff );}
+#endif
+
+
+/***************************************
+** Constants
+****************************************/
+#define PRIME32_1 2654435761U
+#define PRIME32_2 2246822519U
+#define PRIME32_3 3266489917U
+#define PRIME32_4 668265263U
+#define PRIME32_5 374761393U
+
+
+/***************************************
+** Architecture Macros
+****************************************/
+typedef enum { XXH_bigEndian=0, XXH_littleEndian=1 } XXH_endianess;
+#ifndef XXH_CPU_LITTLE_ENDIAN /* It is possible to define XXH_CPU_LITTLE_ENDIAN externally, for example using a compiler switch */
+ static const int one = 1;
+# define XXH_CPU_LITTLE_ENDIAN (*(const char*)(&one))
+#endif
+
+
+/***************************************
+** Macros
+****************************************/
+#define XXH_STATIC_ASSERT(c) { enum { XXH_static_assert = 1/(!!(c)) }; } /* use only *after* variable declarations */
+
+
+/*****************************
+** Memory reads
+******************************/
+typedef enum { XXH_aligned, XXH_unaligned } XXH_alignment;
+
+static
+FORCE_INLINE U32 XXH_readLE32_align(const U32* ptr, XXH_endianess endian, XXH_alignment align)
+{
+ if (align==XXH_unaligned)
+ return endian==XXH_littleEndian ? A32(ptr) : XXH_swap32(A32(ptr));
+ else
+ return endian==XXH_littleEndian ? *ptr : XXH_swap32(*ptr);
+}
+
+static
+FORCE_INLINE U32 XXH_readLE32(const U32* ptr, XXH_endianess endian) { return XXH_readLE32_align(ptr, endian, XXH_unaligned); }
+
+
+/*****************************
+** Simple Hash Functions
+******************************/
+static
+FORCE_INLINE U32 XXH32_endian_align(const void* input, unsigned int len, U32 seed, XXH_endianess endian, XXH_alignment align)
+{
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* bEnd = p + len;
+ U32 h32;
+#define XXH_get32bits(p) XXH_readLE32_align((const U32*)p, endian, align)
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (p==NULL) { len=0; bEnd=p=(const BYTE*)(size_t)16; }
+#endif
+
+ if (len>=16)
+ {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = seed + PRIME32_1 + PRIME32_2;
+ U32 v2 = seed + PRIME32_2;
+ U32 v3 = seed + 0;
+ U32 v4 = seed - PRIME32_1;
+
+ do
+ {
+ v1 += XXH_get32bits(p) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;
+ v2 += XXH_get32bits(p) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;
+ v3 += XXH_get32bits(p) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;
+ v4 += XXH_get32bits(p) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;
+ } while (p<=limit);
+
+ h32 = XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18);
+ }
+ else
+ {
+ h32 = seed + PRIME32_5;
+ }
+
+ h32 += (U32) len;
+
+ while (p<=bEnd-4)
+ {
+ h32 += XXH_get32bits(p) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4 ;
+ p+=4;
+ }
+
+ while (p<bEnd)
+ {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1 ;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+
+U32 XXH32(const void* input, unsigned int len, U32 seed)
+{
+#if 0
+ // Simple version, good for code maintenance, but unfortunately slow for small inputs
+ void* state = XXH32_init(seed);
+ XXH32_update(state, input, len);
+ return XXH32_digest(state);
+#else
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+# if !defined(XXH_USE_UNALIGNED_ACCESS)
+ if ((((size_t)input) & 3) == 0) /* Input is aligned, let's leverage the speed advantage */
+ {
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_aligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_aligned);
+ }
+# endif
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned);
+ else
+ return XXH32_endian_align(input, len, seed, XXH_bigEndian, XXH_unaligned);
+#endif
+}
+
+/*****************************
+** Advanced Hash Functions
+******************************/
+
+struct XXH_state32_t
+{
+ U64 total_len;
+ U32 seed;
+ U32 v1;
+ U32 v2;
+ U32 v3;
+ U32 v4;
+ int memsize;
+ char memory[16];
+};
+
+#if 0
+static
+int XXH32_sizeofState(void)
+{
+ XXH_STATIC_ASSERT(XXH32_SIZEOFSTATE >= sizeof(struct XXH_state32_t)); /* A compilation error here means XXH32_SIZEOFSTATE is not large enough */
+ return sizeof(struct XXH_state32_t);
+}
+#endif
+
+static
+XXH_errorcode XXH32_resetState(void* state_in, U32 seed)
+{
+ struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+ state->seed = seed;
+ state->v1 = seed + PRIME32_1 + PRIME32_2;
+ state->v2 = seed + PRIME32_2;
+ state->v3 = seed + 0;
+ state->v4 = seed - PRIME32_1;
+ state->total_len = 0;
+ state->memsize = 0;
+ return XXH_OK;
+}
+
+static
+void* XXH32_init (U32 seed)
+{
+ void* state = XXH_malloc (sizeof(struct XXH_state32_t));
+ XXH32_resetState(state, seed);
+ return state;
+}
+
+static
+FORCE_INLINE XXH_errorcode XXH32_update_endian (void* state_in, const void* input, int len, XXH_endianess endian)
+{
+ struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+ const BYTE* p = (const BYTE*)input;
+ const BYTE* const bEnd = p + len;
+
+#ifdef XXH_ACCEPT_NULL_INPUT_POINTER
+ if (input==NULL) return XXH_ERROR;
+#endif
+
+ state->total_len += len;
+
+ if (state->memsize + len < 16) /* fill in tmp buffer */
+ {
+ XXH_memcpy(state->memory + state->memsize, input, len);
+ state->memsize += len;
+ return XXH_OK;
+ }
+
+ if (state->memsize) /* some data left from previous update */
+ {
+ XXH_memcpy(state->memory + state->memsize, input, 16-state->memsize);
+ {
+ const U32* p32 = (const U32*)state->memory;
+ state->v1 += XXH_readLE32(p32, endian) * PRIME32_2; state->v1 = XXH_rotl32(state->v1, 13); state->v1 *= PRIME32_1; p32++;
+ state->v2 += XXH_readLE32(p32, endian) * PRIME32_2; state->v2 = XXH_rotl32(state->v2, 13); state->v2 *= PRIME32_1; p32++;
+ state->v3 += XXH_readLE32(p32, endian) * PRIME32_2; state->v3 = XXH_rotl32(state->v3, 13); state->v3 *= PRIME32_1; p32++;
+ state->v4 += XXH_readLE32(p32, endian) * PRIME32_2; state->v4 = XXH_rotl32(state->v4, 13); state->v4 *= PRIME32_1; p32++;
+ }
+ p += 16-state->memsize;
+ state->memsize = 0;
+ }
+
+ if (p <= bEnd-16)
+ {
+ const BYTE* const limit = bEnd - 16;
+ U32 v1 = state->v1;
+ U32 v2 = state->v2;
+ U32 v3 = state->v3;
+ U32 v4 = state->v4;
+
+ do
+ {
+ v1 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v1 = XXH_rotl32(v1, 13); v1 *= PRIME32_1; p+=4;
+ v2 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v2 = XXH_rotl32(v2, 13); v2 *= PRIME32_1; p+=4;
+ v3 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v3 = XXH_rotl32(v3, 13); v3 *= PRIME32_1; p+=4;
+ v4 += XXH_readLE32((const U32*)p, endian) * PRIME32_2; v4 = XXH_rotl32(v4, 13); v4 *= PRIME32_1; p+=4;
+ } while (p<=limit);
+
+ state->v1 = v1;
+ state->v2 = v2;
+ state->v3 = v3;
+ state->v4 = v4;
+ }
+
+ if (p < bEnd)
+ {
+ XXH_memcpy(state->memory, p, bEnd-p);
+ state->memsize = (int)(bEnd-p);
+ }
+
+ return XXH_OK;
+}
+
+static
+XXH_errorcode XXH32_update (void* state_in, const void* input, unsigned int len)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_update_endian(state_in, input, len, XXH_littleEndian);
+ else
+ return XXH32_update_endian(state_in, input, len, XXH_bigEndian);
+}
+
+
+
+static
+FORCE_INLINE U32 XXH32_intermediateDigest_endian (void* state_in, XXH_endianess endian)
+{
+ struct XXH_state32_t * state = (struct XXH_state32_t *) state_in;
+ const BYTE * p = (const BYTE*)state->memory;
+ BYTE* bEnd = (BYTE*)state->memory + state->memsize;
+ U32 h32;
+
+ if (state->total_len >= 16)
+ {
+ h32 = XXH_rotl32(state->v1, 1) + XXH_rotl32(state->v2, 7) + XXH_rotl32(state->v3, 12) + XXH_rotl32(state->v4, 18);
+ }
+ else
+ {
+ h32 = state->seed + PRIME32_5;
+ }
+
+ h32 += (U32) state->total_len;
+
+ while (p<=bEnd-4)
+ {
+ h32 += XXH_readLE32((const U32*)p, endian) * PRIME32_3;
+ h32 = XXH_rotl32(h32, 17) * PRIME32_4;
+ p+=4;
+ }
+
+ while (p<bEnd)
+ {
+ h32 += (*p) * PRIME32_5;
+ h32 = XXH_rotl32(h32, 11) * PRIME32_1;
+ p++;
+ }
+
+ h32 ^= h32 >> 15;
+ h32 *= PRIME32_2;
+ h32 ^= h32 >> 13;
+ h32 *= PRIME32_3;
+ h32 ^= h32 >> 16;
+
+ return h32;
+}
+
+static
+U32 XXH32_intermediateDigest (void* state_in)
+{
+ XXH_endianess endian_detected = (XXH_endianess)XXH_CPU_LITTLE_ENDIAN;
+
+ if ((endian_detected==XXH_littleEndian) || XXH_FORCE_NATIVE_FORMAT)
+ return XXH32_intermediateDigest_endian(state_in, XXH_littleEndian);
+ else
+ return XXH32_intermediateDigest_endian(state_in, XXH_bigEndian);
+}
+
+static
+U32 XXH32_digest (void* state_in)
+{
+ U32 h32 = XXH32_intermediateDigest(state_in);
+
+ XXH_free(state_in);
+
+ return h32;
+}
+
+const
+struct archive_xxhash __archive_xxhash = {
+ XXH32,
+ XXH32_init,
+ XXH32_update,
+ XXH32_digest
+};
+#else
+
+/*
+ * Define an empty version of the struct if we aren't using the LZ4 library.
+ */
+const
+struct archive_xxhash __archive_xxhash = {
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+#endif /* HAVE_LIBLZ4 */
diff --git a/Utilities/cmliblzma/.gitattributes b/Utilities/cmliblzma/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmliblzma/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmliblzma/CMakeLists.txt b/Utilities/cmliblzma/CMakeLists.txt
new file mode 100644
index 000000000..bb3b8a71f
--- /dev/null
+++ b/Utilities/cmliblzma/CMakeLists.txt
@@ -0,0 +1,220 @@
+PROJECT(CMLIBLZMA C)
+
+include(CheckCSourceCompiles)
+include(CheckIncludeFile)
+include(CheckSymbolExists)
+include(CheckTypeSize)
+include(TestBigEndian)
+
+CHECK_C_SOURCE_COMPILES(
+ "int test (void *restrict x);\nint main (void) {return 0;}"
+ HAVE_RESTRICT)
+
+CHECK_C_SOURCE_COMPILES(
+"typedef struct abc *d;\nint test (d __restrict x);\nint main (void) {return 0;}"
+ HAVE___RESTRICT)
+
+CHECK_C_SOURCE_COMPILES(
+ "static inline int test (void) {return 0;}\nint main (void) {return test();}"
+ HAVE_INLINE)
+
+CHECK_C_SOURCE_COMPILES (
+ "static __inline int test (void) {return 0;}\nint main (void) {return test();}"
+ HAVE___INLINE)
+
+CHECK_INCLUDE_FILE(byteswap.h HAVE_BYTESWAP_H)
+CHECK_INCLUDE_FILE(inttypes.h HAVE_INTTYPES_H)
+CHECK_INCLUDE_FILE(limits.h HAVE_LIMITS_H)
+CHECK_INCLUDE_FILE(memory.h HAVE_MEMORY_H)
+CHECK_INCLUDE_FILE(strings.h HAVE_STRINGS_H)
+CHECK_INCLUDE_FILE(string.h HAVE_STRING_H)
+CHECK_INCLUDE_FILE(sys/sysctl.h HAVE_SYS_SYSCTL_H)
+
+CHECK_INCLUDE_FILE(stdbool.h HAVE_STDBOOL_H)
+if(NOT HAVE_STDBOOL_H)
+ CHECK_TYPE_SIZE(_Bool _BOOL)
+endif()
+
+CHECK_C_SOURCE_COMPILES (
+ "#include<byteswap.h>\nint main(void){bswap_16(0);return 0;}"
+ HAVE_BSWAP_16)
+CHECK_C_SOURCE_COMPILES (
+ "#include<byteswap.h>\nint main(void){bswap_32(0);return 0;}"
+ HAVE_BSWAP_32)
+CHECK_C_SOURCE_COMPILES (
+ "#include<byteswap.h>\nint main(void){bswap_64(0);return 0;}"
+ HAVE_BSWAP_64)
+
+TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
+
+set(HAVE_CHECK_CRC64 1)
+set(HAVE_CHECK_SHA256 1)
+
+set(HAVE_DECODER_ARM 1)
+set(HAVE_DECODER_ARMTHUMB 1)
+set(HAVE_DECODER_DELTA 1)
+set(HAVE_DECODER_IA64 1)
+set(HAVE_DECODER_LZMA1 1)
+set(HAVE_DECODER_LZMA2 1)
+set(HAVE_DECODER_POWERPC 1)
+set(HAVE_DECODER_SPARC 1)
+set(HAVE_DECODER_X86 1)
+
+set(HAVE_ENCODER_ARM 1)
+set(HAVE_ENCODER_ARMTHUMB 1)
+set(HAVE_ENCODER_DELTA 1)
+set(HAVE_ENCODER_IA64 1)
+set(HAVE_ENCODER_LZMA1 1)
+set(HAVE_ENCODER_LZMA2 1)
+set(HAVE_ENCODER_POWERPC 1)
+set(HAVE_ENCODER_SPARC 1)
+set(HAVE_ENCODER_X86 1)
+
+set(HAVE_MF_BT2 1)
+set(HAVE_MF_BT3 1)
+set(HAVE_MF_BT4 1)
+set(HAVE_MF_HC3 1)
+set(HAVE_MF_HC4 1)
+
+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("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("size_t" SIZE_OF_SIZE_T)
+
+CHECK_TYPE_SIZE("__int64" __INT64)
+CHECK_TYPE_SIZE("unsigned __int64" UNSIGNED___INT64)
+
+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()
+
+
+SET(LZMA_SRCS
+ common/sysdefs.h
+ common/tuklib_integer.h
+ liblzma/check/check.c
+ liblzma/check/crc32_fast.c
+ liblzma/check/crc32_table.c
+ liblzma/check/crc64_fast.c
+ liblzma/check/crc64_table.c
+ liblzma/check/sha256.c
+ liblzma/common/alone_decoder.c
+ liblzma/common/alone_encoder.c
+ liblzma/common/auto_decoder.c
+ liblzma/common/block_buffer_decoder.c
+ liblzma/common/block_buffer_encoder.c
+ liblzma/common/block_decoder.c
+ liblzma/common/block_encoder.c
+ liblzma/common/block_header_decoder.c
+ liblzma/common/block_header_encoder.c
+ liblzma/common/block_util.c
+ liblzma/common/common.c
+ liblzma/common/easy_buffer_encoder.c
+ liblzma/common/easy_decoder_memusage.c
+ liblzma/common/easy_encoder.c
+ liblzma/common/easy_encoder_memusage.c
+ liblzma/common/easy_preset.c
+ liblzma/common/filter_buffer_decoder.c
+ liblzma/common/filter_buffer_encoder.c
+ liblzma/common/filter_common.c
+ liblzma/common/filter_decoder.c
+ liblzma/common/filter_encoder.c
+ liblzma/common/filter_flags_decoder.c
+ liblzma/common/filter_flags_encoder.c
+ liblzma/common/index.c
+ liblzma/common/index_decoder.c
+ liblzma/common/index_encoder.c
+ liblzma/common/index_hash.c
+ liblzma/common/stream_buffer_decoder.c
+ liblzma/common/stream_buffer_encoder.c
+ liblzma/common/stream_decoder.c
+ liblzma/common/stream_encoder.c
+ liblzma/common/stream_flags_common.c
+ liblzma/common/stream_flags_decoder.c
+ liblzma/common/stream_flags_encoder.c
+ liblzma/common/vli_decoder.c
+ liblzma/common/vli_encoder.c
+ liblzma/common/vli_size.c
+ liblzma/delta/delta_common.c
+ liblzma/delta/delta_decoder.c
+ liblzma/delta/delta_encoder.c
+ liblzma/lz/lz_decoder.c
+ liblzma/lz/lz_encoder.c
+ liblzma/lz/lz_encoder_mf.c
+ liblzma/lzma/fastpos_table.c
+ liblzma/lzma/lzma2_decoder.c
+ liblzma/lzma/lzma2_encoder.c
+ liblzma/lzma/lzma_decoder.c
+ liblzma/lzma/lzma_encoder.c
+ liblzma/lzma/lzma_encoder_optimum_fast.c
+ liblzma/lzma/lzma_encoder_optimum_normal.c
+ liblzma/lzma/lzma_encoder_presets.c
+ liblzma/rangecoder/price_table.c
+ liblzma/simple/arm.c
+ liblzma/simple/armthumb.c
+ liblzma/simple/ia64.c
+ liblzma/simple/powerpc.c
+ liblzma/simple/simple_coder.c
+ liblzma/simple/simple_decoder.c
+ liblzma/simple/simple_encoder.c
+ liblzma/simple/sparc.c
+ liblzma/simple/x86.c
+ )
+
+CONFIGURE_FILE(config.h.in config.h @ONLY)
+
+INCLUDE_DIRECTORIES(
+ "${CMLIBLZMA_SOURCE_DIR}/common"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/api"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/check"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/common"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/delta"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/lz"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/lzma"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/rangecoder"
+ "${CMLIBLZMA_SOURCE_DIR}/liblzma/simple"
+ "${CMLIBLZMA_BINARY_DIR}"
+ )
+
+# Disable warnings to avoid changing 3rd party code.
+IF(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+ENDIF()
+
+ADD_LIBRARY(cmliblzma STATIC ${LZMA_SRCS})
+
+IF(CMAKE_C_COMPILER_ID STREQUAL "XL")
+ # Disable the XL compiler optimizer because it causes crashes
+ # and other bad behavior in liblzma code.
+ SET_PROPERTY(TARGET cmliblzma PROPERTY COMPILE_FLAGS "-qnooptimize")
+ELSEIF(CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
+ CMAKE_C_COMPILER_VERSION VERSION_LESS 3.4)
+ # Disable the old GNU compiler optimizer.
+ SET_PROPERTY(TARGET cmliblzma PROPERTY COMPILE_FLAGS "-O0")
+ENDIF()
+
+INSTALL(FILES COPYING DESTINATION ${CMAKE_DOC_DIR}/cmliblzma)
diff --git a/Utilities/cmliblzma/COPYING b/Utilities/cmliblzma/COPYING
new file mode 100644
index 000000000..43c90d059
--- /dev/null
+++ b/Utilities/cmliblzma/COPYING
@@ -0,0 +1,65 @@
+
+XZ Utils Licensing
+==================
+
+ Different licenses apply to different files in this package. Here
+ is a rough summary of which licenses apply to which parts of this
+ package (but check the individual files to be sure!):
+
+ - liblzma is in the public domain.
+
+ - xz, xzdec, and lzmadec command line tools are in the public
+ domain unless GNU getopt_long had to be compiled and linked
+ in from the lib directory. The getopt_long code is under
+ GNU LGPLv2.1+.
+
+ - The scripts to grep, diff, and view compressed files have been
+ adapted from gzip. These scripts and their documentation are
+ under GNU GPLv2+.
+
+ - All the documentation in the doc directory and most of the
+ XZ Utils specific documentation files in other directories
+ are in the public domain.
+
+ - Translated messages are in the public domain.
+
+ - The build system contains public domain files, and files that
+ are under GNU GPLv2+ or GNU GPLv3+. None of these files end up
+ in the binaries being built.
+
+ - Test files and test code in the tests directory, and debugging
+ utilities in the debug directory are in the public domain.
+
+ - The extra directory may contain public domain files, and files
+ that are under various free software licenses.
+
+ You can do whatever you want with the files that have been put into
+ the public domain. If you find public domain legally problematic,
+ take the previous sentence as a license grant. If you still find
+ the lack of copyright legally problematic, you have too many
+ lawyers.
+
+ As usual, this software is provided "as is", without any warranty.
+
+ If you copy significant amounts of public domain code from XZ Utils
+ into your project, acknowledging this somewhere in your software is
+ polite (especially if it is proprietary, non-free software), but
+ naturally it is not legally required. Here is an example of a good
+ notice to put into "about box" or into documentation:
+
+ This software includes code from XZ Utils <http://tukaani.org/xz/>.
+
+ The following license texts are included in the following files:
+ - COPYING.LGPLv2.1: GNU Lesser General Public License version 2.1
+ - COPYING.GPLv2: GNU General Public License version 2
+ - COPYING.GPLv3: GNU General Public License version 3
+
+ Note that the toolchain (compiler, linker etc.) may add some code
+ pieces that are copyrighted. Thus, it is possible that e.g. liblzma
+ binary wouldn't actually be in the public domain in its entirety
+ even though it contains no copyrighted code from the XZ Utils source
+ package.
+
+ If you have questions, don't hesitate to ask the author(s) for more
+ information.
+
diff --git a/Utilities/cmliblzma/common/common_w32res.rc b/Utilities/cmliblzma/common/common_w32res.rc
new file mode 100644
index 000000000..fdb88d184
--- /dev/null
+++ b/Utilities/cmliblzma/common/common_w32res.rc
@@ -0,0 +1,50 @@
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#include <winresrc.h>
+#include "config.h"
+#define LZMA_H_INTERNAL
+#define LZMA_H_INTERNAL_RC
+#include "lzma/version.h"
+
+#ifndef MY_BUILD
+# define MY_BUILD 0
+#endif
+#define MY_VERSION LZMA_VERSION_MAJOR,LZMA_VERSION_MINOR,LZMA_VERSION_PATCH,MY_BUILD
+
+#define MY_FILENAME MY_NAME MY_SUFFIX
+#define MY_COMPANY "The Tukaani Project <http://tukaani.org/>"
+#define MY_PRODUCT PACKAGE_NAME " <" PACKAGE_URL ">"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION MY_VERSION
+ PRODUCTVERSION MY_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS 0
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE MY_TYPE
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", MY_COMPANY
+ VALUE "FileDescription", MY_DESC
+ VALUE "FileVersion", LZMA_VERSION_STRING
+ VALUE "InternalName", MY_NAME
+ VALUE "OriginalFilename", MY_FILENAME
+ VALUE "ProductName", MY_PRODUCT
+ VALUE "ProductVersion", LZMA_VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/Utilities/cmliblzma/common/sysdefs.h b/Utilities/cmliblzma/common/sysdefs.h
new file mode 100644
index 000000000..a6edea8b0
--- /dev/null
+++ b/Utilities/cmliblzma/common/sysdefs.h
@@ -0,0 +1,202 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file sysdefs.h
+/// \brief Common includes, definitions, system-specific things etc.
+///
+/// This file is used also by the lzma command line tool, that's why this
+/// file is separate from common.h.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SYSDEFS_H
+#define LZMA_SYSDEFS_H
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+# pragma warning(disable: 4142) /* benign redefinition of type */
+# pragma warning(disable: 4761) /* integral size mismatch in argument */
+#endif
+
+//////////////
+// Includes //
+//////////////
+
+#include "config.h"
+
+// Get standard-compliant stdio functions under MinGW and MinGW-w64.
+#ifdef __MINGW32__
+# define __USE_MINGW_ANSI_STDIO 1
+#endif
+
+// size_t and NULL
+#include <stddef.h>
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+// C99 says that inttypes.h always includes stdint.h, but some systems
+// don't do that, and require including stdint.h separately.
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+
+// Some pre-C99 systems have SIZE_MAX in limits.h instead of stdint.h. The
+// limits are also used to figure out some macros missing from pre-C99 systems.
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+
+#if defined(_MSC_VER) && (_MSC_VER < 1310)
+# define UINT64_C(n) n ## ui64
+#endif
+
+
+// Be more compatible with systems that have non-conforming inttypes.h.
+// We assume that int is 32-bit and that long is either 32-bit or 64-bit.
+// Full Autoconf test could be more correct, but this should work well enough.
+// Note that this duplicates some code from lzma.h, but this is better since
+// we can work without inttypes.h thanks to Autoconf tests.
+#ifndef UINT32_C
+# if UINT_MAX != 4294967295U
+# error UINT32_C is not defined and unsigned int is not 32-bit.
+# endif
+# define UINT32_C(n) n ## U
+#endif
+#ifndef UINT32_MAX
+# define UINT32_MAX UINT32_C(4294967295)
+#endif
+#ifndef PRIu32
+# define PRIu32 "u"
+#endif
+#ifndef PRIx32
+# define PRIx32 "x"
+#endif
+#ifndef PRIX32
+# define PRIX32 "X"
+#endif
+
+#if ULONG_MAX == 4294967295UL
+# ifndef UINT64_C
+# define UINT64_C(n) n ## ULL
+# endif
+# ifndef PRIu64
+# define PRIu64 "llu"
+# endif
+# ifndef PRIx64
+# define PRIx64 "llx"
+# endif
+# ifndef PRIX64
+# define PRIX64 "llX"
+# endif
+#else
+# ifndef UINT64_C
+# define UINT64_C(n) n ## UL
+# endif
+# ifndef PRIu64
+# define PRIu64 "lu"
+# endif
+# ifndef PRIx64
+# define PRIx64 "lx"
+# endif
+# ifndef PRIX64
+# define PRIX64 "lX"
+# endif
+#endif
+#ifndef UINT64_MAX
+# define UINT64_MAX UINT64_C(18446744073709551615)
+#endif
+
+// Incorrect(?) SIZE_MAX:
+// - Interix headers typedef size_t to unsigned long,
+// but a few lines later define SIZE_MAX to INT32_MAX.
+// - SCO OpenServer (x86) headers typedef size_t to unsigned int
+// but define SIZE_MAX to INT32_MAX.
+#if defined(__INTERIX) || defined(_SCO_DS)
+# undef SIZE_MAX
+#endif
+
+// The code currently assumes that size_t is either 32-bit or 64-bit.
+#ifndef SIZE_MAX
+# if SIZE_OF_SIZE_T == 4
+# define SIZE_MAX UINT32_MAX
+# elif SIZE_OF_SIZE_T == 8
+# define SIZE_MAX UINT64_MAX
+# else
+# error size_t is not 32-bit or 64-bit
+# endif
+#endif
+#if SIZE_MAX != UINT32_MAX && SIZE_MAX != UINT64_MAX
+# error size_t is not 32-bit or 64-bit
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+
+// Pre-C99 systems lack stdbool.h. All the code in LZMA Utils must be written
+// so that it works with fake bool type, for example:
+//
+// bool foo = (flags & 0x100) != 0;
+// bool bar = !!(flags & 0x100);
+//
+// This works with the real C99 bool but breaks with fake bool:
+//
+// bool baz = (flags & 0x100);
+//
+#ifdef HAVE_STDBOOL_H
+# include <stdbool.h>
+#else
+# if ! HAVE__BOOL
+typedef unsigned char _Bool;
+# endif
+# define bool _Bool
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+#endif
+
+// string.h should be enough but let's include strings.h and memory.h too if
+// they exists, since that shouldn't do any harm, but may improve portability.
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+
+////////////
+// Macros //
+////////////
+
+#undef memzero
+#define memzero(s, n) memset(s, 0, n)
+
+// NOTE: Avoid using MIN() and MAX(), because even conditionally defining
+// those macros can cause some portability trouble, since on some systems
+// the system headers insist defining their own versions.
+#define my_min(x, y) ((x) < (y) ? (x) : (y))
+#define my_max(x, y) ((x) > (y) ? (x) : (y))
+
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0]))
+#endif
+
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 3) || __GNUC__ > 4
+# define lzma_attr_alloc_size(x) __attribute__((__alloc_size__(x)))
+#else
+# define lzma_attr_alloc_size(x)
+#endif
+
+#endif
diff --git a/Utilities/cmliblzma/common/tuklib_integer.h b/Utilities/cmliblzma/common/tuklib_integer.h
new file mode 100644
index 000000000..5e8262a11
--- /dev/null
+++ b/Utilities/cmliblzma/common/tuklib_integer.h
@@ -0,0 +1,514 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file tuklib_integer.h
+/// \brief Various integer and bit operations
+///
+/// This file provides macros or functions to do some basic integer and bit
+/// operations.
+///
+/// Endianness related integer operations (XX = 16, 32, or 64; Y = b or l):
+/// - Byte swapping: bswapXX(num)
+/// - Byte order conversions to/from native: convXXYe(num)
+/// - Aligned reads: readXXYe(ptr)
+/// - Aligned writes: writeXXYe(ptr, num)
+/// - Unaligned reads (16/32-bit only): unaligned_readXXYe(ptr)
+/// - Unaligned writes (16/32-bit only): unaligned_writeXXYe(ptr, num)
+///
+/// Since they can macros, the arguments should have no side effects since
+/// they may be evaluated more than once.
+///
+/// \todo PowerPC and possibly some other architectures support
+/// byte swapping load and store instructions. This file
+/// doesn't take advantage of those instructions.
+///
+/// Bit scan operations for non-zero 32-bit integers:
+/// - Bit scan reverse (find highest non-zero bit): bsr32(num)
+/// - Count leading zeros: clz32(num)
+/// - Count trailing zeros: ctz32(num)
+/// - Bit scan forward (simply an alias for ctz32()): bsf32(num)
+///
+/// The above bit scan operations return 0-31. If num is zero,
+/// the result is undefined.
+//
+// Authors: Lasse Collin
+// Joachim Henke
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef TUKLIB_INTEGER_H
+#define TUKLIB_INTEGER_H
+
+#include "sysdefs.h"
+
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define TUKLIB_GNUC_REQ(major, minor) \
+ ((__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)) \
+ || __GNUC__ > (major))
+#else
+# define TUKLIB_GNUC_REQ(major, minor) 0
+#endif
+
+
+////////////////////////////////////////
+// Operating system specific features //
+////////////////////////////////////////
+
+#if defined(HAVE_BYTESWAP_H)
+ // glibc, uClibc, dietlibc
+# include <byteswap.h>
+# ifdef HAVE_BSWAP_16
+# define bswap16(num) bswap_16(num)
+# endif
+# ifdef HAVE_BSWAP_32
+# define bswap32(num) bswap_32(num)
+# endif
+# ifdef HAVE_BSWAP_64
+# define bswap64(num) bswap_64(num)
+# endif
+
+#elif defined(HAVE_SYS_ENDIAN_H)
+ // *BSDs and Darwin
+# include <sys/endian.h>
+
+#elif defined(HAVE_SYS_BYTEORDER_H)
+ // Solaris
+# include <sys/byteorder.h>
+# ifdef BSWAP_16
+# define bswap16(num) BSWAP_16(num)
+# endif
+# ifdef BSWAP_32
+# define bswap32(num) BSWAP_32(num)
+# endif
+# ifdef BSWAP_64
+# define bswap64(num) BSWAP_64(num)
+# endif
+# ifdef BE_16
+# define conv16be(num) BE_16(num)
+# endif
+# ifdef BE_32
+# define conv32be(num) BE_32(num)
+# endif
+# ifdef BE_64
+# define conv64be(num) BE_64(num)
+# endif
+# ifdef LE_16
+# define conv16le(num) LE_16(num)
+# endif
+# ifdef LE_32
+# define conv32le(num) LE_32(num)
+# endif
+# ifdef LE_64
+# define conv64le(num) LE_64(num)
+# endif
+#endif
+
+
+///////////////////
+// Byte swapping //
+///////////////////
+
+#ifndef bswap16
+# define bswap16(num) \
+ (((uint16_t)(num) << 8) | ((uint16_t)(num) >> 8))
+#endif
+
+#ifndef bswap32
+# define bswap32(num) \
+ ( (((uint32_t)(num) << 24) ) \
+ | (((uint32_t)(num) << 8) & UINT32_C(0x00FF0000)) \
+ | (((uint32_t)(num) >> 8) & UINT32_C(0x0000FF00)) \
+ | (((uint32_t)(num) >> 24) ) )
+#endif
+
+#ifndef bswap64
+# define bswap64(num) \
+ ( (((uint64_t)(num) << 56) ) \
+ | (((uint64_t)(num) << 40) & UINT64_C(0x00FF000000000000)) \
+ | (((uint64_t)(num) << 24) & UINT64_C(0x0000FF0000000000)) \
+ | (((uint64_t)(num) << 8) & UINT64_C(0x000000FF00000000)) \
+ | (((uint64_t)(num) >> 8) & UINT64_C(0x00000000FF000000)) \
+ | (((uint64_t)(num) >> 24) & UINT64_C(0x0000000000FF0000)) \
+ | (((uint64_t)(num) >> 40) & UINT64_C(0x000000000000FF00)) \
+ | (((uint64_t)(num) >> 56) ) )
+#endif
+
+// Define conversion macros using the basic byte swapping macros.
+#ifdef WORDS_BIGENDIAN
+# ifndef conv16be
+# define conv16be(num) ((uint16_t)(num))
+# endif
+# ifndef conv32be
+# define conv32be(num) ((uint32_t)(num))
+# endif
+# ifndef conv64be
+# define conv64be(num) ((uint64_t)(num))
+# endif
+# ifndef conv16le
+# define conv16le(num) bswap16(num)
+# endif
+# ifndef conv32le
+# define conv32le(num) bswap32(num)
+# endif
+# ifndef conv64le
+# define conv64le(num) bswap64(num)
+# endif
+#else
+# ifndef conv16be
+# define conv16be(num) bswap16(num)
+# endif
+# ifndef conv32be
+# define conv32be(num) bswap32(num)
+# endif
+# ifndef conv64be
+# define conv64be(num) bswap64(num)
+# endif
+# ifndef conv16le
+# define conv16le(num) ((uint16_t)(num))
+# endif
+# ifndef conv32le
+# define conv32le(num) ((uint32_t)(num))
+# endif
+# ifndef conv64le
+# define conv64le(num) ((uint64_t)(num))
+# endif
+#endif
+
+
+//////////////////////////////
+// Aligned reads and writes //
+//////////////////////////////
+
+static inline uint16_t
+read16be(const uint8_t *buf)
+{
+ uint16_t num = *(const uint16_t *)buf;
+ return conv16be(num);
+}
+
+
+static inline uint16_t
+read16le(const uint8_t *buf)
+{
+ uint16_t num = *(const uint16_t *)buf;
+ return conv16le(num);
+}
+
+
+static inline uint32_t
+read32be(const uint8_t *buf)
+{
+ uint32_t num = *(const uint32_t *)buf;
+ return conv32be(num);
+}
+
+
+static inline uint32_t
+read32le(const uint8_t *buf)
+{
+ uint32_t num = *(const uint32_t *)buf;
+ return conv32le(num);
+}
+
+
+static inline uint64_t
+read64be(const uint8_t *buf)
+{
+ uint64_t num = *(const uint64_t *)buf;
+ return conv64be(num);
+}
+
+
+static inline uint64_t
+read64le(const uint8_t *buf)
+{
+ uint64_t num = *(const uint64_t *)buf;
+ return conv64le(num);
+}
+
+
+// NOTE: Possible byte swapping must be done in a macro to allow GCC
+// to optimize byte swapping of constants when using glibc's or *BSD's
+// byte swapping macros. The actual write is done in an inline function
+// to make type checking of the buf pointer possible similarly to readXXYe()
+// functions.
+
+#define write16be(buf, num) write16ne((buf), conv16be(num))
+#define write16le(buf, num) write16ne((buf), conv16le(num))
+#define write32be(buf, num) write32ne((buf), conv32be(num))
+#define write32le(buf, num) write32ne((buf), conv32le(num))
+#define write64be(buf, num) write64ne((buf), conv64be(num))
+#define write64le(buf, num) write64ne((buf), conv64le(num))
+
+
+static inline void
+write16ne(uint8_t *buf, uint16_t num)
+{
+ *(uint16_t *)buf = num;
+ return;
+}
+
+
+static inline void
+write32ne(uint8_t *buf, uint32_t num)
+{
+ *(uint32_t *)buf = num;
+ return;
+}
+
+
+static inline void
+write64ne(uint8_t *buf, uint64_t num)
+{
+ *(uint64_t *)buf = num;
+ return;
+}
+
+
+////////////////////////////////
+// Unaligned reads and writes //
+////////////////////////////////
+
+// NOTE: TUKLIB_FAST_UNALIGNED_ACCESS indicates only support for 16-bit and
+// 32-bit unaligned integer loads and stores. It's possible that 64-bit
+// unaligned access doesn't work or is slower than byte-by-byte access.
+// Since unaligned 64-bit is probably not needed as often as 16-bit or
+// 32-bit, we simply don't support 64-bit unaligned access for now.
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+# define unaligned_read16be read16be
+# define unaligned_read16le read16le
+# define unaligned_read32be read32be
+# define unaligned_read32le read32le
+# define unaligned_write16be write16be
+# define unaligned_write16le write16le
+# define unaligned_write32be write32be
+# define unaligned_write32le write32le
+
+#else
+
+static inline uint16_t
+unaligned_read16be(const uint8_t *buf)
+{
+ uint16_t num = ((uint16_t)buf[0] << 8) | (uint16_t)buf[1];
+ return num;
+}
+
+
+static inline uint16_t
+unaligned_read16le(const uint8_t *buf)
+{
+ uint16_t num = ((uint16_t)buf[0]) | ((uint16_t)buf[1] << 8);
+ return num;
+}
+
+
+static inline uint32_t
+unaligned_read32be(const uint8_t *buf)
+{
+ uint32_t num = (uint32_t)buf[0] << 24;
+ num |= (uint32_t)buf[1] << 16;
+ num |= (uint32_t)buf[2] << 8;
+ num |= (uint32_t)buf[3];
+ return num;
+}
+
+
+static inline uint32_t
+unaligned_read32le(const uint8_t *buf)
+{
+ uint32_t num = (uint32_t)buf[0];
+ num |= (uint32_t)buf[1] << 8;
+ num |= (uint32_t)buf[2] << 16;
+ num |= (uint32_t)buf[3] << 24;
+ return num;
+}
+
+
+static inline void
+unaligned_write16be(uint8_t *buf, uint16_t num)
+{
+ buf[0] = num >> 8;
+ buf[1] = num;
+ return;
+}
+
+
+static inline void
+unaligned_write16le(uint8_t *buf, uint16_t num)
+{
+ buf[0] = num;
+ buf[1] = num >> 8;
+ return;
+}
+
+
+static inline void
+unaligned_write32be(uint8_t *buf, uint32_t num)
+{
+ buf[0] = num >> 24;
+ buf[1] = num >> 16;
+ buf[2] = num >> 8;
+ buf[3] = num;
+ return;
+}
+
+
+static inline void
+unaligned_write32le(uint8_t *buf, uint32_t num)
+{
+ buf[0] = num;
+ buf[1] = num >> 8;
+ buf[2] = num >> 16;
+ buf[3] = num >> 24;
+ return;
+}
+
+#endif
+
+
+static inline uint32_t
+bsr32(uint32_t n)
+{
+ // Check for ICC first, since it tends to define __GNUC__ too.
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(n);
+
+#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX
+ // GCC >= 3.4 has __builtin_clz(), which gives good results on
+ // multiple architectures. On x86, __builtin_clz() ^ 31U becomes
+ // either plain BSR (so the XOR gets optimized away) or LZCNT and
+ // XOR (if -march indicates that SSE4a instructions are supported).
+ return __builtin_clz(n) ^ 31U;
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ uint32_t i;
+ __asm__("bsrl %1, %0" : "=r" (i) : "rm" (n));
+ return i;
+
+#else
+ uint32_t i = 31;
+
+ if ((n & UINT32_C(0xFFFF0000)) == 0) {
+ n <<= 16;
+ i = 15;
+ }
+
+ if ((n & UINT32_C(0xFF000000)) == 0) {
+ n <<= 8;
+ i -= 8;
+ }
+
+ if ((n & UINT32_C(0xF0000000)) == 0) {
+ n <<= 4;
+ i -= 4;
+ }
+
+ if ((n & UINT32_C(0xC0000000)) == 0) {
+ n <<= 2;
+ i -= 2;
+ }
+
+ if ((n & UINT32_C(0x80000000)) == 0)
+ --i;
+
+ return i;
+#endif
+}
+
+
+static inline uint32_t
+clz32(uint32_t n)
+{
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_reverse(n) ^ 31U;
+
+#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX == UINT32_MAX
+ return __builtin_clz(n);
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ uint32_t i;
+ __asm__("bsrl %1, %0\n\t"
+ "xorl $31, %0"
+ : "=r" (i) : "rm" (n));
+ return i;
+
+#else
+ uint32_t i = 0;
+
+ if ((n & UINT32_C(0xFFFF0000)) == 0) {
+ n <<= 16;
+ i = 16;
+ }
+
+ if ((n & UINT32_C(0xFF000000)) == 0) {
+ n <<= 8;
+ i += 8;
+ }
+
+ if ((n & UINT32_C(0xF0000000)) == 0) {
+ n <<= 4;
+ i += 4;
+ }
+
+ if ((n & UINT32_C(0xC0000000)) == 0) {
+ n <<= 2;
+ i += 2;
+ }
+
+ if ((n & UINT32_C(0x80000000)) == 0)
+ ++i;
+
+ return i;
+#endif
+}
+
+
+static inline uint32_t
+ctz32(uint32_t n)
+{
+#if defined(__INTEL_COMPILER)
+ return _bit_scan_forward(n);
+
+#elif TUKLIB_GNUC_REQ(3, 4) && UINT_MAX >= UINT32_MAX
+ return __builtin_ctz(n);
+
+#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+ uint32_t i;
+ __asm__("bsfl %1, %0" : "=r" (i) : "rm" (n));
+ return i;
+
+#else
+ uint32_t i = 0;
+
+ if ((n & UINT32_C(0x0000FFFF)) == 0) {
+ n >>= 16;
+ i = 16;
+ }
+
+ if ((n & UINT32_C(0x000000FF)) == 0) {
+ n >>= 8;
+ i += 8;
+ }
+
+ if ((n & UINT32_C(0x0000000F)) == 0) {
+ n >>= 4;
+ i += 4;
+ }
+
+ if ((n & UINT32_C(0x00000003)) == 0) {
+ n >>= 2;
+ i += 2;
+ }
+
+ if ((n & UINT32_C(0x00000001)) == 0)
+ ++i;
+
+ return i;
+#endif
+}
+
+#define bsf32 ctz32
+
+#endif
diff --git a/Utilities/cmliblzma/config.h.in b/Utilities/cmliblzma/config.h.in
new file mode 100644
index 000000000..9c53150bf
--- /dev/null
+++ b/Utilities/cmliblzma/config.h.in
@@ -0,0 +1,289 @@
+
+/*
+ * Ensure we have C99-style int64_t, etc, all defined.
+ */
+
+/* First, we need to know if the system has already defined them. */
+#cmakedefine HAVE_INT16_T
+#cmakedefine HAVE_INT32_T
+#cmakedefine HAVE_INT64_T
+#cmakedefine HAVE_INTMAX_T
+
+#cmakedefine HAVE_UINT8_T
+#cmakedefine HAVE_UINT16_T
+#cmakedefine HAVE_UINT32_T
+#cmakedefine HAVE_UINT64_T
+#cmakedefine HAVE_UINTMAX_T
+
+/* We might have the types we want under other spellings. */
+#cmakedefine HAVE___INT64
+#cmakedefine HAVE_U_INT64_T
+#cmakedefine HAVE_UNSIGNED___INT64
+
+/* The sizes of various standard integer types. */
+@SIZE_OF_SHORT_CODE@
+@SIZE_OF_INT_CODE@
+@SIZE_OF_LONG_CODE@
+@SIZE_OF_LONG_LONG_CODE@
+@SIZE_OF_UNSIGNED_SHORT_CODE@
+@SIZE_OF_UNSIGNED_CODE@
+@SIZE_OF_UNSIGNED_LONG_CODE@
+@SIZE_OF_UNSIGNED_LONG_LONG_CODE@
+@SIZE_OF_SIZE_T_CODE@
+
+/*
+ * If we lack int64_t, define it to the first of __int64, int, long, and long long
+ * that exists and is the right size.
+ */
+#if !defined(HAVE_INT64_T) && defined(HAVE___INT64)
+typedef __int64 int64_t;
+#define HAVE_INT64_T
+#endif
+
+#if !defined(HAVE_INT64_T) && SIZE_OF_INT == 8
+typedef int int64_t;
+#define HAVE_INT64_T
+#endif
+
+#if !defined(HAVE_INT64_T) && SIZE_OF_LONG == 8
+typedef long int64_t;
+#define HAVE_INT64_T
+#endif
+
+#if !defined(HAVE_INT64_T) && SIZE_OF_LONG_LONG == 8
+typedef long long int64_t;
+#define HAVE_INT64_T
+#endif
+
+#if !defined(HAVE_INT64_T)
+#error No 64-bit integer type was found.
+#endif
+
+/*
+ * Similarly for int32_t
+ */
+#if !defined(HAVE_INT32_T) && SIZE_OF_INT == 4
+typedef int int32_t;
+#define HAVE_INT32_T
+#endif
+
+#if !defined(HAVE_INT32_T) && SIZE_OF_LONG == 4
+typedef long int32_t;
+#define HAVE_INT32_T
+#endif
+
+#if !defined(HAVE_INT32_T)
+#error No 32-bit integer type was found.
+#endif
+
+/*
+ * Similarly for int16_t
+ */
+#if !defined(HAVE_INT16_T) && SIZE_OF_INT == 2
+typedef int int16_t;
+#define HAVE_INT16_T
+#endif
+
+#if !defined(HAVE_INT16_T) && SIZE_OF_SHORT == 2
+typedef short int16_t;
+#define HAVE_INT16_T
+#endif
+
+#if !defined(HAVE_INT16_T)
+#error No 16-bit integer type was found.
+#endif
+
+/*
+ * Similarly for uint64_t
+ */
+#if !defined(HAVE_UINT64_T) && defined(HAVE_UNSIGNED___INT64)
+typedef unsigned __int64 uint64_t;
+#define HAVE_UINT64_T
+#endif
+
+#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED == 8
+typedef unsigned uint64_t;
+#define HAVE_UINT64_T
+#endif
+
+#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG == 8
+typedef unsigned long uint64_t;
+#define HAVE_UINT64_T
+#endif
+
+#if !defined(HAVE_UINT64_T) && SIZE_OF_UNSIGNED_LONG_LONG == 8
+typedef unsigned long long uint64_t;
+#define HAVE_UINT64_T
+#endif
+
+#if !defined(HAVE_UINT64_T)
+#error No 64-bit unsigned integer type was found.
+#endif
+
+/*
+ * Similarly for uint32_t
+ */
+#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED == 4
+typedef unsigned uint32_t;
+#define HAVE_UINT32_T
+#endif
+
+#if !defined(HAVE_UINT32_T) && SIZE_OF_UNSIGNED_LONG == 4
+typedef unsigned long uint32_t;
+#define HAVE_UINT32_T
+#endif
+
+#if !defined(HAVE_UINT32_T)
+#error No 32-bit unsigned integer type was found.
+#endif
+
+/*
+ * Similarly for uint16_t
+ */
+#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED == 2
+typedef unsigned uint16_t;
+#define HAVE_UINT16_T
+#endif
+
+#if !defined(HAVE_UINT16_T) && SIZE_OF_UNSIGNED_SHORT == 2
+typedef unsigned short uint16_t;
+#define HAVE_UINT16_T
+#endif
+
+#if !defined(HAVE_UINT16_T)
+#error No 16-bit unsigned integer type was found.
+#endif
+
+/*
+ * Similarly for uint8_t
+ */
+#if !defined(HAVE_UINT8_T)
+typedef unsigned char uint8_t;
+#define HAVE_UINT8_T
+#endif
+
+#if !defined(HAVE_UINT16_T)
+#error No 8-bit unsigned integer type was found.
+#endif
+
+/* Define intmax_t and uintmax_t if they are not already defined. */
+#if !defined(HAVE_INTMAX_T)
+typedef int64_t intmax_t;
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#endif
+
+#if !defined(HAVE_UINTMAX_T)
+typedef uint64_t uintmax_t;
+#endif
+
+
+#cmakedefine uintptr_t @uintptr_t@
+
+
+#cmakedefine HAVE_RESTRICT
+#cmakedefine HAVE___RESTRICT
+
+#cmakedefine HAVE_INLINE
+#cmakedefine HAVE___INLINE
+
+#ifndef HAVE_RESTRICT
+# ifdef HAVE___RESTRICT
+# define LZMA_RESTRICT __restrict
+# else
+# define LZMA_RESTRICT
+# endif
+#else
+# define LZMA_RESTRICT restrict
+#endif /* HAVE_RESTRICT */
+
+#ifndef HAVE_INLINE
+# ifdef HAVE___INLINE
+# define inline __inline
+# else
+# define inline
+# endif
+#endif /* HAVE_INLINE */
+
+
+#cmakedefine WORDS_BIGENDIAN 1
+
+#cmakedefine HAVE_BYTESWAP_H 1
+#cmakedefine HAVE_BSWAP_16 1
+#cmakedefine HAVE_BSWAP_32 1
+#cmakedefine HAVE_BSWAP_64 1
+
+
+#define HAVE_CHECK_CRC32 1
+#define HAVE_CHECK_CRC64 1
+#define HAVE_CHECK_SHA256 1
+
+#define HAVE_DECODER_ARM 1
+#define HAVE_DECODER_ARMTHUMB 1
+#define HAVE_DECODER_DELTA 1
+#define HAVE_DECODER_IA64 1
+#define HAVE_DECODER_LZMA1 1
+#define HAVE_DECODER_LZMA2 1
+#define HAVE_DECODER_POWERPC 1
+#define HAVE_DECODER_SPARC 1
+#define HAVE_DECODER_X86 1
+
+#define HAVE_ENCODER_ARM 1
+#define HAVE_ENCODER_ARMTHUMB 1
+#define HAVE_ENCODER_DELTA 1
+#define HAVE_ENCODER_IA64 1
+#define HAVE_ENCODER_LZMA1 1
+#define HAVE_ENCODER_LZMA2 1
+#define HAVE_ENCODER_POWERPC 1
+#define HAVE_ENCODER_SPARC 1
+#define HAVE_ENCODER_X86 1
+
+#define HAVE_MF_BT2 1
+#define HAVE_MF_BT3 1
+#define HAVE_MF_BT4 1
+#define HAVE_MF_HC3 1
+#define HAVE_MF_HC4 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#cmakedefine HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#cmakedefine HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#cmakedefine HAVE_MEMORY_H 1
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#cmakedefine HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#cmakedefine HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#cmakedefine HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#cmakedefine HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/byteorder.h> header file. */
+#cmakedefine HAVE_SYS_BYTEORDER_H 1
+
+/* Define to 1 if you have the <sys/endian.h> header file. */
+#cmakedefine HAVE_SYS_ENDIAN_H 1
+
+/* Define to 1 or 0, depending whether the compiler supports simple visibility
+ declarations. */
+#cmakedefine HAVE_VISIBILITY 1
+
+/* Define to 1 if the system has the type `_Bool'. */
+#cmakedefine HAVE__BOOL 1
+
+/* Define to 1 if the system supports fast unaligned access to 16-bit and
+ 32-bit integers. */
+#if defined(__i386) || defined(__i386__) || defined(_M_IX86) \
+ || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) \
+ || defined(__amd64) || defined(__amd64__) \
+ || defined(__powerpc) || defined(__powerpc__) \
+ || defined(__ppc) || defined(__ppc__) || defined(__POWERPC__)
+# define TUKLIB_FAST_UNALIGNED_ACCESS 1
+#endif
diff --git a/Utilities/cmliblzma/liblzma/api/lzma.h b/Utilities/cmliblzma/liblzma/api/lzma.h
new file mode 100644
index 000000000..fb874c3e1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma.h
@@ -0,0 +1,313 @@
+/**
+ * \file api/lzma.h
+ * \brief The public API of liblzma data compression library
+ *
+ * liblzma is a public domain general-purpose data compression library with
+ * a zlib-like API. The native file format is .xz, but also the old .lzma
+ * format and raw (no headers) streams are supported. Multiple compression
+ * algorithms (filters) are supported. Currently LZMA2 is the primary filter.
+ *
+ * liblzma is part of XZ Utils <http://tukaani.org/xz/>. XZ Utils includes
+ * a gzip-like command line tool named xz and some other tools. XZ Utils
+ * is developed and maintained by Lasse Collin.
+ *
+ * Major parts of liblzma are based on Igor Pavlov's public domain LZMA SDK
+ * <http://7-zip.org/sdk.html>.
+ *
+ * The SHA-256 implementation is based on the public domain code found from
+ * 7-Zip <http://7-zip.org/>, which has a modified version of the public
+ * domain SHA-256 code found from Crypto++ <http://www.cryptopp.com/>.
+ * The SHA-256 code in Crypto++ was written by Kevin Springle and Wei Dai.
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#ifndef LZMA_H
+#define LZMA_H
+
+/*****************************
+ * Required standard headers *
+ *****************************/
+
+/*
+ * liblzma API headers need some standard types and macros. To allow
+ * including lzma.h without requiring the application to include other
+ * headers first, lzma.h includes the required standard headers unless
+ * they already seem to be included already or if LZMA_MANUAL_HEADERS
+ * has been defined.
+ *
+ * Here's what types and macros are needed and from which headers:
+ * - stddef.h: size_t, NULL
+ * - stdint.h: uint8_t, uint32_t, uint64_t, UINT32_C(n), uint64_C(n),
+ * UINT32_MAX, UINT64_MAX
+ *
+ * However, inttypes.h is a little more portable than stdint.h, although
+ * inttypes.h declares some unneeded things compared to plain stdint.h.
+ *
+ * The hacks below aren't perfect, specifically they assume that inttypes.h
+ * exists and that it typedefs at least uint8_t, uint32_t, and uint64_t,
+ * and that, in case of incomplete inttypes.h, unsigned int is 32-bit.
+ * If the application already takes care of setting up all the types and
+ * macros properly (for example by using gnulib's stdint.h or inttypes.h),
+ * we try to detect that the macros are already defined and don't include
+ * inttypes.h here again. However, you may define LZMA_MANUAL_HEADERS to
+ * force this file to never include any system headers.
+ *
+ * Some could argue that liblzma API should provide all the required types,
+ * for example lzma_uint64, LZMA_UINT64_C(n), and LZMA_UINT64_MAX. This was
+ * seen as an unnecessary mess, since most systems already provide all the
+ * necessary types and macros in the standard headers.
+ *
+ * Note that liblzma API still has lzma_bool, because using stdbool.h would
+ * break C89 and C++ programs on many systems. sizeof(bool) in C99 isn't
+ * necessarily the same as sizeof(bool) in C++.
+ */
+
+#ifndef LZMA_MANUAL_HEADERS
+ /*
+ * I suppose this works portably also in C++. Note that in C++,
+ * we need to get size_t into the global namespace.
+ */
+# include <stddef.h>
+
+ /*
+ * Skip inttypes.h if we already have all the required macros. If we
+ * have the macros, we assume that we have the matching typedefs too.
+ */
+# if !defined(UINT32_C) || !defined(UINT64_C) \
+ || !defined(UINT32_MAX) || !defined(UINT64_MAX)
+ /*
+ * MSVC has no C99 support, and thus it cannot be used to
+ * compile liblzma. The liblzma API has to still be usable
+ * from MSVC, so we need to define the required standard
+ * integer types here.
+ */
+# if defined(_WIN32) && defined(_MSC_VER)
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int32 uint32_t;
+ typedef unsigned __int64 uint64_t;
+# else
+ /* Use the standard inttypes.h. */
+# ifdef __cplusplus
+ /*
+ * C99 sections 7.18.2 and 7.18.4 specify
+ * that C++ implementations define the limit
+ * and constant macros only if specifically
+ * requested. Note that if you want the
+ * format macros (PRIu64 etc.) too, you need
+ * to define __STDC_FORMAT_MACROS before
+ * including lzma.h, since re-including
+ * inttypes.h with __STDC_FORMAT_MACROS
+ * defined doesn't necessarily work.
+ */
+# ifndef __STDC_LIMIT_MACROS
+# define __STDC_LIMIT_MACROS 1
+# endif
+# ifndef __STDC_CONSTANT_MACROS
+# define __STDC_CONSTANT_MACROS 1
+# endif
+# endif
+
+# include <inttypes.h>
+# endif
+
+ /*
+ * Some old systems have only the typedefs in inttypes.h, and
+ * lack all the macros. For those systems, we need a few more
+ * hacks. We assume that unsigned int is 32-bit and unsigned
+ * long is either 32-bit or 64-bit. If these hacks aren't
+ * enough, the application has to setup the types manually
+ * before including lzma.h.
+ */
+# ifndef UINT32_C
+# if defined(_WIN32) && defined(_MSC_VER)
+# define UINT32_C(n) n ## UI32
+# else
+# define UINT32_C(n) n ## U
+# endif
+# endif
+
+# ifndef UINT64_C
+# if defined(_WIN32) && defined(_MSC_VER)
+# define UINT64_C(n) n ## UI64
+# else
+ /* Get ULONG_MAX. */
+# include <limits.h>
+# if ULONG_MAX == 4294967295UL
+# define UINT64_C(n) n ## ULL
+# else
+# define UINT64_C(n) n ## UL
+# endif
+# endif
+# endif
+
+# ifndef UINT32_MAX
+# define UINT32_MAX (UINT32_C(4294967295))
+# endif
+
+# ifndef UINT64_MAX
+# define UINT64_MAX (UINT64_C(18446744073709551615))
+# endif
+# endif
+#endif /* ifdef LZMA_MANUAL_HEADERS */
+
+
+/******************
+ * LZMA_API macro *
+ ******************/
+
+/*
+ * Some systems require that the functions and function pointers are
+ * declared specially in the headers. LZMA_API_IMPORT is for importing
+ * symbols and LZMA_API_CALL is to specify the calling convention.
+ *
+ * By default it is assumed that the application will link dynamically
+ * against liblzma. #define LZMA_API_STATIC in your application if you
+ * want to link against static liblzma. If you don't care about portability
+ * to operating systems like Windows, or at least don't care about linking
+ * against static liblzma on them, don't worry about LZMA_API_STATIC. That
+ * is, most developers will never need to use LZMA_API_STATIC.
+ *
+ * The GCC variants are a special case on Windows (Cygwin and MinGW).
+ * We rely on GCC doing the right thing with its auto-import feature,
+ * and thus don't use __declspec(dllimport). This way developers don't
+ * need to worry about LZMA_API_STATIC. Also the calling convention is
+ * omitted on Cygwin but not on MinGW.
+ */
+#ifndef LZMA_API_IMPORT
+# if !defined(LZMA_API_STATIC) && defined(_WIN32) && !defined(__GNUC__)
+# define LZMA_API_IMPORT __declspec(dllimport)
+# else
+# define LZMA_API_IMPORT
+# endif
+#endif
+
+#ifndef LZMA_API_CALL
+# if defined(_WIN32) && !defined(__CYGWIN__)
+# define LZMA_API_CALL __cdecl
+# else
+# define LZMA_API_CALL
+# endif
+#endif
+
+#ifndef LZMA_API
+# define LZMA_API(type) LZMA_API_IMPORT type LZMA_API_CALL
+#endif
+
+
+/***********
+ * nothrow *
+ ***********/
+
+/*
+ * None of the functions in liblzma may throw an exception. Even
+ * the functions that use callback functions won't throw exceptions,
+ * because liblzma would break if a callback function threw an exception.
+ */
+#ifndef lzma_nothrow
+# if defined(__cplusplus)
+# define lzma_nothrow throw()
+# elif __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)
+# define lzma_nothrow __attribute__((__nothrow__))
+# else
+# define lzma_nothrow
+# endif
+#endif
+
+
+/********************
+ * GNU C extensions *
+ ********************/
+
+/*
+ * GNU C extensions are used conditionally in the public API. It doesn't
+ * break anything if these are sometimes enabled and sometimes not, only
+ * affects warnings and optimizations.
+ */
+#if __GNUC__ >= 3
+# ifndef lzma_attribute
+# define lzma_attribute(attr) __attribute__(attr)
+# endif
+
+ /* warn_unused_result was added in GCC 3.4. */
+# ifndef lzma_attr_warn_unused_result
+# if __GNUC__ == 3 && __GNUC_MINOR__ < 4
+# define lzma_attr_warn_unused_result
+# endif
+# endif
+
+#else
+# ifndef lzma_attribute
+# define lzma_attribute(attr)
+# endif
+#endif
+
+
+#ifndef lzma_attr_pure
+# define lzma_attr_pure lzma_attribute((__pure__))
+#endif
+
+#ifndef lzma_attr_const
+# define lzma_attr_const lzma_attribute((__const__))
+#endif
+
+#ifndef lzma_attr_warn_unused_result
+# define lzma_attr_warn_unused_result \
+ lzma_attribute((__warn_unused_result__))
+#endif
+
+
+/**************
+ * Subheaders *
+ **************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Subheaders check that this is defined. It is to prevent including
+ * them directly from applications.
+ */
+#define LZMA_H_INTERNAL 1
+
+/* Basic features */
+#include "lzma/version.h"
+#include "lzma/base.h"
+#include "lzma/vli.h"
+#include "lzma/check.h"
+
+/* Filters */
+#include "lzma/filter.h"
+#include "lzma/bcj.h"
+#include "lzma/delta.h"
+#include "lzma/lzma.h"
+
+/* Container formats */
+#include "lzma/container.h"
+
+/* Advanced features */
+#include "lzma/stream_flags.h"
+#include "lzma/block.h"
+#include "lzma/index.h"
+#include "lzma/index_hash.h"
+
+/* Hardware information */
+#include "lzma/hardware.h"
+
+/*
+ * All subheaders included. Undefine LZMA_H_INTERNAL to prevent applications
+ * re-including the subheaders.
+ */
+#undef LZMA_H_INTERNAL
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef LZMA_H */
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/base.h b/Utilities/cmliblzma/liblzma/api/lzma/base.h
new file mode 100644
index 000000000..43dde8d60
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/base.h
@@ -0,0 +1,601 @@
+/**
+ * \file lzma/base.h
+ * \brief Data types and functions used in many places in liblzma API
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Boolean
+ *
+ * This is here because C89 doesn't have stdbool.h. To set a value for
+ * variables having type lzma_bool, you can use
+ * - C99's `true' and `false' from stdbool.h;
+ * - C++'s internal `true' and `false'; or
+ * - integers one (true) and zero (false).
+ */
+typedef unsigned char lzma_bool;
+
+
+/**
+ * \brief Type of reserved enumeration variable in structures
+ *
+ * To avoid breaking library ABI when new features are added, several
+ * structures contain extra variables that may be used in future. Since
+ * sizeof(enum) can be different than sizeof(int), and sizeof(enum) may
+ * even vary depending on the range of enumeration constants, we specify
+ * a separate type to be used for reserved enumeration variables. All
+ * enumeration constants in liblzma API will be non-negative and less
+ * than 128, which should guarantee that the ABI won't break even when
+ * new constants are added to existing enumerations.
+ */
+typedef enum {
+ LZMA_RESERVED_ENUM = 0
+} lzma_reserved_enum;
+
+
+/**
+ * \brief Return values used by several functions in liblzma
+ *
+ * Check the descriptions of specific functions to find out which return
+ * values they can return. With some functions the return values may have
+ * more specific meanings than described here; those differences are
+ * described per-function basis.
+ */
+typedef enum {
+ LZMA_OK = 0,
+ /**<
+ * \brief Operation completed successfully
+ */
+
+ LZMA_STREAM_END = 1,
+ /**<
+ * \brief End of stream was reached
+ *
+ * In encoder, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or
+ * LZMA_FINISH was finished. In decoder, this indicates
+ * that all the data was successfully decoded.
+ *
+ * In all cases, when LZMA_STREAM_END is returned, the last
+ * output bytes should be picked from strm->next_out.
+ */
+
+ LZMA_NO_CHECK = 2,
+ /**<
+ * \brief Input stream has no integrity check
+ *
+ * This return value can be returned only if the
+ * LZMA_TELL_NO_CHECK flag was used when initializing
+ * the decoder. LZMA_NO_CHECK is just a warning, and
+ * the decoding can be continued normally.
+ *
+ * It is possible to call lzma_get_check() immediately after
+ * lzma_code has returned LZMA_NO_CHECK. The result will
+ * naturally be LZMA_CHECK_NONE, but the possibility to call
+ * lzma_get_check() may be convenient in some applications.
+ */
+
+ LZMA_UNSUPPORTED_CHECK = 3,
+ /**<
+ * \brief Cannot calculate the integrity check
+ *
+ * The usage of this return value is different in encoders
+ * and decoders.
+ *
+ * Encoders can return this value only from the initialization
+ * function. If initialization fails with this value, the
+ * encoding cannot be done, because there's no way to produce
+ * output with the correct integrity check.
+ *
+ * Decoders can return this value only from lzma_code() and
+ * only if the LZMA_TELL_UNSUPPORTED_CHECK flag was used when
+ * initializing the decoder. The decoding can still be
+ * continued normally even if the check type is unsupported,
+ * but naturally the check will not be validated, and possible
+ * errors may go undetected.
+ *
+ * With decoder, it is possible to call lzma_get_check()
+ * immediately after lzma_code() has returned
+ * LZMA_UNSUPPORTED_CHECK. This way it is possible to find
+ * out what the unsupported Check ID was.
+ */
+
+ LZMA_GET_CHECK = 4,
+ /**<
+ * \brief Integrity check type is now available
+ *
+ * This value can be returned only by the lzma_code() function
+ * and only if the decoder was initialized with the
+ * LZMA_TELL_ANY_CHECK flag. LZMA_GET_CHECK tells the
+ * application that it may now call lzma_get_check() to find
+ * out the Check ID. This can be used, for example, to
+ * implement a decoder that accepts only files that have
+ * strong enough integrity check.
+ */
+
+ LZMA_MEM_ERROR = 5,
+ /**<
+ * \brief Cannot allocate memory
+ *
+ * Memory allocation failed, or the size of the allocation
+ * would be greater than SIZE_MAX.
+ *
+ * Due to internal implementation reasons, the coding cannot
+ * be continued even if more memory were made available after
+ * LZMA_MEM_ERROR.
+ */
+
+ LZMA_MEMLIMIT_ERROR = 6,
+ /**
+ * \brief Memory usage limit was reached
+ *
+ * Decoder would need more memory than allowed by the
+ * specified memory usage limit. To continue decoding,
+ * the memory usage limit has to be increased with
+ * lzma_memlimit_set().
+ */
+
+ LZMA_FORMAT_ERROR = 7,
+ /**<
+ * \brief File format not recognized
+ *
+ * The decoder did not recognize the input as supported file
+ * format. This error can occur, for example, when trying to
+ * decode .lzma format file with lzma_stream_decoder,
+ * because lzma_stream_decoder accepts only the .xz format.
+ */
+
+ LZMA_OPTIONS_ERROR = 8,
+ /**<
+ * \brief Invalid or unsupported options
+ *
+ * Invalid or unsupported options, for example
+ * - unsupported filter(s) or filter options; or
+ * - reserved bits set in headers (decoder only).
+ *
+ * Rebuilding liblzma with more features enabled, or
+ * upgrading to a newer version of liblzma may help.
+ */
+
+ LZMA_DATA_ERROR = 9,
+ /**<
+ * \brief Data is corrupt
+ *
+ * The usage of this return value is different in encoders
+ * and decoders. In both encoder and decoder, the coding
+ * cannot continue after this error.
+ *
+ * Encoders return this if size limits of the target file
+ * format would be exceeded. These limits are huge, thus
+ * getting this error from an encoder is mostly theoretical.
+ * For example, the maximum compressed and uncompressed
+ * size of a .xz Stream is roughly 8 EiB (2^63 bytes).
+ *
+ * Decoders return this error if the input data is corrupt.
+ * This can mean, for example, invalid CRC32 in headers
+ * or invalid check of uncompressed data.
+ */
+
+ LZMA_BUF_ERROR = 10,
+ /**<
+ * \brief No progress is possible
+ *
+ * This error code is returned when the coder cannot consume
+ * any new input and produce any new output. The most common
+ * reason for this error is that the input stream being
+ * decoded is truncated or corrupt.
+ *
+ * This error is not fatal. Coding can be continued normally
+ * by providing more input and/or more output space, if
+ * possible.
+ *
+ * Typically the first call to lzma_code() that can do no
+ * progress returns LZMA_OK instead of LZMA_BUF_ERROR. Only
+ * the second consecutive call doing no progress will return
+ * LZMA_BUF_ERROR. This is intentional.
+ *
+ * With zlib, Z_BUF_ERROR may be returned even if the
+ * application is doing nothing wrong, so apps will need
+ * to handle Z_BUF_ERROR specially. The above hack
+ * guarantees that liblzma never returns LZMA_BUF_ERROR
+ * to properly written applications unless the input file
+ * is truncated or corrupt. This should simplify the
+ * applications a little.
+ */
+
+ LZMA_PROG_ERROR = 11,
+ /**<
+ * \brief Programming error
+ *
+ * This indicates that the arguments given to the function are
+ * invalid or the internal state of the decoder is corrupt.
+ * - Function arguments are invalid or the structures
+ * pointed by the argument pointers are invalid
+ * e.g. if strm->next_out has been set to NULL and
+ * strm->avail_out > 0 when calling lzma_code().
+ * - lzma_* functions have been called in wrong order
+ * e.g. lzma_code() was called right after lzma_end().
+ * - If errors occur randomly, the reason might be flaky
+ * hardware.
+ *
+ * If you think that your code is correct, this error code
+ * can be a sign of a bug in liblzma. See the documentation
+ * how to report bugs.
+ */
+} lzma_ret;
+
+
+/**
+ * \brief The `action' argument for lzma_code()
+ *
+ * After the first use of LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, or LZMA_FINISH,
+ * the same `action' must is used until lzma_code() returns LZMA_STREAM_END.
+ * Also, the amount of input (that is, strm->avail_in) must not be modified
+ * by the application until lzma_code() returns LZMA_STREAM_END. Changing the
+ * `action' or modifying the amount of input will make lzma_code() return
+ * LZMA_PROG_ERROR.
+ */
+typedef enum {
+ LZMA_RUN = 0,
+ /**<
+ * \brief Continue coding
+ *
+ * Encoder: Encode as much input as possible. Some internal
+ * buffering will probably be done (depends on the filter
+ * chain in use), which causes latency: the input used won't
+ * usually be decodeable from the output of the same
+ * lzma_code() call.
+ *
+ * Decoder: Decode as much input as possible and produce as
+ * much output as possible.
+ */
+
+ LZMA_SYNC_FLUSH = 1,
+ /**<
+ * \brief Make all the input available at output
+ *
+ * Normally the encoder introduces some latency.
+ * LZMA_SYNC_FLUSH forces all the buffered data to be
+ * available at output without resetting the internal
+ * state of the encoder. This way it is possible to use
+ * compressed stream for example for communication over
+ * network.
+ *
+ * Only some filters support LZMA_SYNC_FLUSH. Trying to use
+ * LZMA_SYNC_FLUSH with filters that don't support it will
+ * make lzma_code() return LZMA_OPTIONS_ERROR. For example,
+ * LZMA1 doesn't support LZMA_SYNC_FLUSH but LZMA2 does.
+ *
+ * Using LZMA_SYNC_FLUSH very often can dramatically reduce
+ * the compression ratio. With some filters (for example,
+ * LZMA2), fine-tuning the compression options may help
+ * mitigate this problem significantly (for example,
+ * match finder with LZMA2).
+ *
+ * Decoders don't support LZMA_SYNC_FLUSH.
+ */
+
+ LZMA_FULL_FLUSH = 2,
+ /**<
+ * \brief Finish encoding of the current Block
+ *
+ * All the input data going to the current Block must have
+ * been given to the encoder (the last bytes can still be
+ * pending in* next_in). Call lzma_code() with LZMA_FULL_FLUSH
+ * until it returns LZMA_STREAM_END. Then continue normally
+ * with LZMA_RUN or finish the Stream with LZMA_FINISH.
+ *
+ * This action is currently supported only by Stream encoder
+ * and easy encoder (which uses Stream encoder). If there is
+ * no unfinished Block, no empty Block is created.
+ */
+
+ LZMA_FINISH = 3
+ /**<
+ * \brief Finish the coding operation
+ *
+ * All the input data must have been given to the encoder
+ * (the last bytes can still be pending in next_in).
+ * Call lzma_code() with LZMA_FINISH until it returns
+ * LZMA_STREAM_END. Once LZMA_FINISH has been used,
+ * the amount of input must no longer be changed by
+ * the application.
+ *
+ * When decoding, using LZMA_FINISH is optional unless the
+ * LZMA_CONCATENATED flag was used when the decoder was
+ * initialized. When LZMA_CONCATENATED was not used, the only
+ * effect of LZMA_FINISH is that the amount of input must not
+ * be changed just like in the encoder.
+ */
+} lzma_action;
+
+
+/**
+ * \brief Custom functions for memory handling
+ *
+ * A pointer to lzma_allocator may be passed via lzma_stream structure
+ * to liblzma, and some advanced functions take a pointer to lzma_allocator
+ * as a separate function argument. The library will use the functions
+ * specified in lzma_allocator for memory handling instead of the default
+ * malloc() and free(). C++ users should note that the custom memory
+ * handling functions must not throw exceptions.
+ *
+ * liblzma doesn't make an internal copy of lzma_allocator. Thus, it is
+ * OK to change these function pointers in the middle of the coding
+ * process, but obviously it must be done carefully to make sure that the
+ * replacement `free' can deallocate memory allocated by the earlier
+ * `alloc' function(s).
+ */
+typedef struct {
+ /**
+ * \brief Pointer to a custom memory allocation function
+ *
+ * If you don't want a custom allocator, but still want
+ * custom free(), set this to NULL and liblzma will use
+ * the standard malloc().
+ *
+ * \param opaque lzma_allocator.opaque (see below)
+ * \param nmemb Number of elements like in calloc(). liblzma
+ * will always set nmemb to 1, so it is safe to
+ * ignore nmemb in a custom allocator if you like.
+ * The nmemb argument exists only for
+ * compatibility with zlib and libbzip2.
+ * \param size Size of an element in bytes.
+ * liblzma never sets this to zero.
+ *
+ * \return Pointer to the beginning of a memory block of
+ * `size' bytes, or NULL if allocation fails
+ * for some reason. When allocation fails, functions
+ * of liblzma return LZMA_MEM_ERROR.
+ *
+ * The allocator should not waste time zeroing the allocated buffers.
+ * This is not only about speed, but also memory usage, since the
+ * operating system kernel doesn't necessarily allocate the requested
+ * memory in physical memory until it is actually used. With small
+ * input files, liblzma may actually need only a fraction of the
+ * memory that it requested for allocation.
+ *
+ * \note LZMA_MEM_ERROR is also used when the size of the
+ * allocation would be greater than SIZE_MAX. Thus,
+ * don't assume that the custom allocator must have
+ * returned NULL if some function from liblzma
+ * returns LZMA_MEM_ERROR.
+ */
+ void *(LZMA_API_CALL *alloc)(void *opaque, size_t nmemb, size_t size);
+
+ /**
+ * \brief Pointer to a custom memory freeing function
+ *
+ * If you don't want a custom freeing function, but still
+ * want a custom allocator, set this to NULL and liblzma
+ * will use the standard free().
+ *
+ * \param opaque lzma_allocator.opaque (see below)
+ * \param ptr Pointer returned by lzma_allocator.alloc(),
+ * or when it is set to NULL, a pointer returned
+ * by the standard malloc().
+ */
+ void (LZMA_API_CALL *free)(void *opaque, void *ptr);
+
+ /**
+ * \brief Pointer passed to .alloc() and .free()
+ *
+ * opaque is passed as the first argument to lzma_allocator.alloc()
+ * and lzma_allocator.free(). This intended to ease implementing
+ * custom memory allocation functions for use with liblzma.
+ *
+ * If you don't need this, you should set this to NULL.
+ */
+ void *opaque;
+
+} lzma_allocator;
+
+
+/**
+ * \brief Internal data structure
+ *
+ * The contents of this structure is not visible outside the library.
+ */
+typedef struct lzma_internal_s lzma_internal;
+
+
+/**
+ * \brief Passing data to and from liblzma
+ *
+ * The lzma_stream structure is used for
+ * - passing pointers to input and output buffers to liblzma;
+ * - defining custom memory hander functions; and
+ * - holding a pointer to coder-specific internal data structures.
+ *
+ * Typical usage:
+ *
+ * - After allocating lzma_stream (on stack or with malloc()), it must be
+ * initialized to LZMA_STREAM_INIT (see LZMA_STREAM_INIT for details).
+ *
+ * - Initialize a coder to the lzma_stream, for example by using
+ * lzma_easy_encoder() or lzma_auto_decoder(). Some notes:
+ * - In contrast to zlib, strm->next_in and strm->next_out are
+ * ignored by all initialization functions, thus it is safe
+ * to not initialize them yet.
+ * - The initialization functions always set strm->total_in and
+ * strm->total_out to zero.
+ * - If the initialization function fails, no memory is left allocated
+ * that would require freeing with lzma_end() even if some memory was
+ * associated with the lzma_stream structure when the initialization
+ * function was called.
+ *
+ * - Use lzma_code() to do the actual work.
+ *
+ * - Once the coding has been finished, the existing lzma_stream can be
+ * reused. It is OK to reuse lzma_stream with different initialization
+ * function without calling lzma_end() first. Old allocations are
+ * automatically freed.
+ *
+ * - Finally, use lzma_end() to free the allocated memory. lzma_end() never
+ * frees the lzma_stream structure itself.
+ *
+ * Application may modify the values of total_in and total_out as it wants.
+ * They are updated by liblzma to match the amount of data read and
+ * written, but aren't used for anything else.
+ */
+typedef struct {
+ const uint8_t *next_in; /**< Pointer to the next input byte. */
+ size_t avail_in; /**< Number of available input bytes in next_in. */
+ uint64_t total_in; /**< Total number of bytes read by liblzma. */
+
+ uint8_t *next_out; /**< Pointer to the next output position. */
+ size_t avail_out; /**< Amount of free space in next_out. */
+ uint64_t total_out; /**< Total number of bytes written by liblzma. */
+
+ /**
+ * \brief Custom memory allocation functions
+ *
+ * In most cases this is NULL which makes liblzma use
+ * the standard malloc() and free().
+ */
+ lzma_allocator *allocator;
+
+ /** Internal state is not visible to applications. */
+ lzma_internal *internal;
+
+ /*
+ * Reserved space to allow possible future extensions without
+ * breaking the ABI. Excluding the initialization of this structure,
+ * you should not touch these, because the names of these variables
+ * may change.
+ */
+ void *reserved_ptr1;
+ void *reserved_ptr2;
+ void *reserved_ptr3;
+ void *reserved_ptr4;
+ uint64_t reserved_int1;
+ uint64_t reserved_int2;
+ size_t reserved_int3;
+ size_t reserved_int4;
+ lzma_reserved_enum reserved_enum1;
+ lzma_reserved_enum reserved_enum2;
+
+} lzma_stream;
+
+
+/**
+ * \brief Initialization for lzma_stream
+ *
+ * When you declare an instance of lzma_stream, you can immediately
+ * initialize it so that initialization functions know that no memory
+ * has been allocated yet:
+ *
+ * lzma_stream strm = LZMA_STREAM_INIT;
+ *
+ * If you need to initialize a dynamically allocated lzma_stream, you can use
+ * memset(strm_pointer, 0, sizeof(lzma_stream)). Strictly speaking, this
+ * violates the C standard since NULL may have different internal
+ * representation than zero, but it should be portable enough in practice.
+ * Anyway, for maximum portability, you can use something like this:
+ *
+ * lzma_stream tmp = LZMA_STREAM_INIT;
+ * *strm = tmp;
+ */
+#define LZMA_STREAM_INIT \
+ { NULL, 0, 0, NULL, 0, 0, NULL, NULL, \
+ NULL, NULL, NULL, NULL, 0, 0, 0, 0, \
+ LZMA_RESERVED_ENUM, LZMA_RESERVED_ENUM }
+
+
+/**
+ * \brief Encode or decode data
+ *
+ * Once the lzma_stream has been successfully initialized (e.g. with
+ * lzma_stream_encoder()), the actual encoding or decoding is done
+ * using this function. The application has to update strm->next_in,
+ * strm->avail_in, strm->next_out, and strm->avail_out to pass input
+ * to and get output from liblzma.
+ *
+ * See the description of the coder-specific initialization function to find
+ * out what `action' values are supported by the coder.
+ */
+extern LZMA_API(lzma_ret) lzma_code(lzma_stream *strm, lzma_action action)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Free memory allocated for the coder data structures
+ *
+ * \param strm Pointer to lzma_stream that is at least initialized
+ * with LZMA_STREAM_INIT.
+ *
+ * After lzma_end(strm), strm->internal is guaranteed to be NULL. No other
+ * members of the lzma_stream structure are touched.
+ *
+ * \note zlib indicates an error if application end()s unfinished
+ * stream structure. liblzma doesn't do this, and assumes that
+ * application knows what it is doing.
+ */
+extern LZMA_API(void) lzma_end(lzma_stream *strm) lzma_nothrow;
+
+
+/**
+ * \brief Get the memory usage of decoder filter chain
+ *
+ * This function is currently supported only when *strm has been initialized
+ * with a function that takes a memlimit argument. With other functions, you
+ * should use e.g. lzma_raw_encoder_memusage() or lzma_raw_decoder_memusage()
+ * to estimate the memory requirements.
+ *
+ * This function is useful e.g. after LZMA_MEMLIMIT_ERROR to find out how big
+ * the memory usage limit should have been to decode the input. Note that
+ * this may give misleading information if decoding .xz Streams that have
+ * multiple Blocks, because each Block can have different memory requirements.
+ *
+ * \return How much memory is currently allocated for the filter
+ * decoders. If no filter chain is currently allocated,
+ * some non-zero value is still returned, which is less than
+ * or equal to what any filter chain would indicate as its
+ * memory requirement.
+ *
+ * If this function isn't supported by *strm or some other error
+ * occurs, zero is returned.
+ */
+extern LZMA_API(uint64_t) lzma_memusage(const lzma_stream *strm)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the current memory usage limit
+ *
+ * This function is supported only when *strm has been initialized with
+ * a function that takes a memlimit argument.
+ *
+ * \return On success, the current memory usage limit is returned
+ * (always non-zero). On error, zero is returned.
+ */
+extern LZMA_API(uint64_t) lzma_memlimit_get(const lzma_stream *strm)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Set the memory usage limit
+ *
+ * This function is supported only when *strm has been initialized with
+ * a function that takes a memlimit argument.
+ *
+ * \return - LZMA_OK: New memory usage limit successfully set.
+ * - LZMA_MEMLIMIT_ERROR: The new limit is too small.
+ * The limit was not changed.
+ * - LZMA_PROG_ERROR: Invalid arguments, e.g. *strm doesn't
+ * support memory usage limit or memlimit was zero.
+ */
+extern LZMA_API(lzma_ret) lzma_memlimit_set(
+ lzma_stream *strm, uint64_t memlimit) lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/bcj.h b/Utilities/cmliblzma/liblzma/api/lzma/bcj.h
new file mode 100644
index 000000000..8e37538ad
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/bcj.h
@@ -0,0 +1,90 @@
+/**
+ * \file lzma/bcj.h
+ * \brief Branch/Call/Jump conversion filters
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/* Filter IDs for lzma_filter.id */
+
+#define LZMA_FILTER_X86 LZMA_VLI_C(0x04)
+ /**<
+ * Filter for x86 binaries
+ */
+
+#define LZMA_FILTER_POWERPC LZMA_VLI_C(0x05)
+ /**<
+ * Filter for Big endian PowerPC binaries
+ */
+
+#define LZMA_FILTER_IA64 LZMA_VLI_C(0x06)
+ /**<
+ * Filter for IA-64 (Itanium) binaries.
+ */
+
+#define LZMA_FILTER_ARM LZMA_VLI_C(0x07)
+ /**<
+ * Filter for ARM binaries.
+ */
+
+#define LZMA_FILTER_ARMTHUMB LZMA_VLI_C(0x08)
+ /**<
+ * Filter for ARM-Thumb binaries.
+ */
+
+#define LZMA_FILTER_SPARC LZMA_VLI_C(0x09)
+ /**<
+ * Filter for SPARC binaries.
+ */
+
+
+/**
+ * \brief Options for BCJ filters
+ *
+ * The BCJ filters never change the size of the data. Specifying options
+ * for them is optional: if pointer to options is NULL, default value is
+ * used. You probably never need to specify options to BCJ filters, so just
+ * set the options pointer to NULL and be happy.
+ *
+ * If options with non-default values have been specified when encoding,
+ * the same options must also be specified when decoding.
+ *
+ * \note At the moment, none of the BCJ filters support
+ * LZMA_SYNC_FLUSH. If LZMA_SYNC_FLUSH is specified,
+ * LZMA_OPTIONS_ERROR will be returned. If there is need,
+ * partial support for LZMA_SYNC_FLUSH can be added in future.
+ * Partial means that flushing would be possible only at
+ * offsets that are multiple of 2, 4, or 16 depending on
+ * the filter, except x86 which cannot be made to support
+ * LZMA_SYNC_FLUSH predictably.
+ */
+typedef struct {
+ /**
+ * \brief Start offset for conversions
+ *
+ * This setting is useful only when the same filter is used
+ * _separately_ for multiple sections of the same executable file,
+ * and the sections contain cross-section branch/call/jump
+ * instructions. In that case it is beneficial to set the start
+ * offset of the non-first sections so that the relative addresses
+ * of the cross-section branch/call/jump instructions will use the
+ * same absolute addresses as in the first section.
+ *
+ * When the pointer to options is NULL, the default value (zero)
+ * is used.
+ */
+ uint32_t start_offset;
+
+} lzma_options_bcj;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/block.h b/Utilities/cmliblzma/liblzma/api/lzma/block.h
new file mode 100644
index 000000000..e6710a7bc
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/block.h
@@ -0,0 +1,533 @@
+/**
+ * \file lzma/block.h
+ * \brief .xz Block handling
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Options for the Block and Block Header encoders and decoders
+ *
+ * Different Block handling functions use different parts of this structure.
+ * Some read some members, other functions write, and some do both. Only the
+ * members listed for reading need to be initialized when the specified
+ * functions are called. The members marked for writing will be assigned
+ * new values at some point either by calling the given function or by
+ * later calls to lzma_code().
+ */
+typedef struct {
+ /**
+ * \brief Block format version
+ *
+ * To prevent API and ABI breakages if new features are needed in
+ * the Block field, a version number is used to indicate which
+ * fields in this structure are in use. For now, version must always
+ * be zero. With non-zero version, most Block related functions will
+ * return LZMA_OPTIONS_ERROR.
+ *
+ * Read by:
+ * - All functions that take pointer to lzma_block as argument,
+ * including lzma_block_header_decode().
+ *
+ * Written by:
+ * - lzma_block_header_decode()
+ */
+ uint32_t version;
+
+ /**
+ * \brief Size of the Block Header field
+ *
+ * This is always a multiple of four.
+ *
+ * Read by:
+ * - lzma_block_header_encode()
+ * - lzma_block_header_decode()
+ * - lzma_block_compressed_size()
+ * - lzma_block_unpadded_size()
+ * - lzma_block_total_size()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_decode()
+ *
+ * Written by:
+ * - lzma_block_header_size()
+ * - lzma_block_buffer_encode()
+ */
+ uint32_t header_size;
+# define LZMA_BLOCK_HEADER_SIZE_MIN 8
+# define LZMA_BLOCK_HEADER_SIZE_MAX 1024
+
+ /**
+ * \brief Type of integrity Check
+ *
+ * The Check ID is not stored into the Block Header, thus its value
+ * must be provided also when decoding.
+ *
+ * Read by:
+ * - lzma_block_header_encode()
+ * - lzma_block_header_decode()
+ * - lzma_block_compressed_size()
+ * - lzma_block_unpadded_size()
+ * - lzma_block_total_size()
+ * - lzma_block_encoder()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_encode()
+ * - lzma_block_buffer_decode()
+ */
+ lzma_check check;
+
+ /**
+ * \brief Size of the Compressed Data in bytes
+ *
+ * Encoding: If this is not LZMA_VLI_UNKNOWN, Block Header encoder
+ * will store this value to the Block Header. Block encoder doesn't
+ * care about this value, but will set it once the encoding has been
+ * finished.
+ *
+ * Decoding: If this is not LZMA_VLI_UNKNOWN, Block decoder will
+ * verify that the size of the Compressed Data field matches
+ * compressed_size.
+ *
+ * Usually you don't know this value when encoding in streamed mode,
+ * and thus cannot write this field into the Block Header.
+ *
+ * In non-streamed mode you can reserve space for this field before
+ * encoding the actual Block. After encoding the data, finish the
+ * Block by encoding the Block Header. Steps in detail:
+ *
+ * - Set compressed_size to some big enough value. If you don't know
+ * better, use LZMA_VLI_MAX, but remember that bigger values take
+ * more space in Block Header.
+ *
+ * - Call lzma_block_header_size() to see how much space you need to
+ * reserve for the Block Header.
+ *
+ * - Encode the Block using lzma_block_encoder() and lzma_code().
+ * It sets compressed_size to the correct value.
+ *
+ * - Use lzma_block_header_encode() to encode the Block Header.
+ * Because space was reserved in the first step, you don't need
+ * to call lzma_block_header_size() anymore, because due to
+ * reserving, header_size has to be big enough. If it is "too big",
+ * lzma_block_header_encode() will add enough Header Padding to
+ * make Block Header to match the size specified by header_size.
+ *
+ * Read by:
+ * - lzma_block_header_size()
+ * - lzma_block_header_encode()
+ * - lzma_block_compressed_size()
+ * - lzma_block_unpadded_size()
+ * - lzma_block_total_size()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_decode()
+ *
+ * Written by:
+ * - lzma_block_header_decode()
+ * - lzma_block_compressed_size()
+ * - lzma_block_encoder()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_encode()
+ * - lzma_block_buffer_decode()
+ */
+ lzma_vli compressed_size;
+
+ /**
+ * \brief Uncompressed Size in bytes
+ *
+ * This is handled very similarly to compressed_size above.
+ *
+ * uncompressed_size is needed by fewer functions than
+ * compressed_size. This is because uncompressed_size isn't
+ * needed to validate that Block stays within proper limits.
+ *
+ * Read by:
+ * - lzma_block_header_size()
+ * - lzma_block_header_encode()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_decode()
+ *
+ * Written by:
+ * - lzma_block_header_decode()
+ * - lzma_block_encoder()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_encode()
+ * - lzma_block_buffer_decode()
+ */
+ lzma_vli uncompressed_size;
+
+ /**
+ * \brief Array of filters
+ *
+ * There can be 1-4 filters. The end of the array is marked with
+ * .id = LZMA_VLI_UNKNOWN.
+ *
+ * Read by:
+ * - lzma_block_header_size()
+ * - lzma_block_header_encode()
+ * - lzma_block_encoder()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_encode()
+ * - lzma_block_buffer_decode()
+ *
+ * Written by:
+ * - lzma_block_header_decode(): Note that this does NOT free()
+ * the old filter options structures. All unused filters[] will
+ * have .id == LZMA_VLI_UNKNOWN and .options == NULL. If
+ * decoding fails, all filters[] are guaranteed to be
+ * LZMA_VLI_UNKNOWN and NULL.
+ *
+ * \note Because of the array is terminated with
+ * .id = LZMA_VLI_UNKNOWN, the actual array must
+ * have LZMA_FILTERS_MAX + 1 members or the Block
+ * Header decoder will overflow the buffer.
+ */
+ lzma_filter *filters;
+
+ /**
+ * \brief Raw value stored in the Check field
+ *
+ * After successful coding, the first lzma_check_size(check) bytes
+ * of this array contain the raw value stored in the Check field.
+ *
+ * Note that CRC32 and CRC64 are stored in little endian byte order.
+ * Take it into account if you display the Check values to the user.
+ *
+ * Written by:
+ * - lzma_block_encoder()
+ * - lzma_block_decoder()
+ * - lzma_block_buffer_encode()
+ * - lzma_block_buffer_decode()
+ */
+ uint8_t raw_check[LZMA_CHECK_SIZE_MAX];
+
+ /*
+ * Reserved space to allow possible future extensions without
+ * breaking the ABI. You should not touch these, because the names
+ * of these variables may change. These are and will never be used
+ * with the currently supported options, so it is safe to leave these
+ * uninitialized.
+ */
+ void *reserved_ptr1;
+ void *reserved_ptr2;
+ void *reserved_ptr3;
+ uint32_t reserved_int1;
+ uint32_t reserved_int2;
+ lzma_vli reserved_int3;
+ lzma_vli reserved_int4;
+ lzma_vli reserved_int5;
+ lzma_vli reserved_int6;
+ lzma_vli reserved_int7;
+ lzma_vli reserved_int8;
+ lzma_reserved_enum reserved_enum1;
+ lzma_reserved_enum reserved_enum2;
+ lzma_reserved_enum reserved_enum3;
+ lzma_reserved_enum reserved_enum4;
+ lzma_bool reserved_bool1;
+ lzma_bool reserved_bool2;
+ lzma_bool reserved_bool3;
+ lzma_bool reserved_bool4;
+ lzma_bool reserved_bool5;
+ lzma_bool reserved_bool6;
+ lzma_bool reserved_bool7;
+ lzma_bool reserved_bool8;
+
+} lzma_block;
+
+
+/**
+ * \brief Decode the Block Header Size field
+ *
+ * To decode Block Header using lzma_block_header_decode(), the size of the
+ * Block Header has to be known and stored into lzma_block.header_size.
+ * The size can be calculated from the first byte of a Block using this macro.
+ * Note that if the first byte is 0x00, it indicates beginning of Index; use
+ * this macro only when the byte is not 0x00.
+ *
+ * There is no encoding macro, because Block Header encoder is enough for that.
+ */
+#define lzma_block_header_size_decode(b) (((uint32_t)(b) + 1) * 4)
+
+
+/**
+ * \brief Calculate Block Header Size
+ *
+ * Calculate the minimum size needed for the Block Header field using the
+ * settings specified in the lzma_block structure. Note that it is OK to
+ * increase the calculated header_size value as long as it is a multiple of
+ * four and doesn't exceed LZMA_BLOCK_HEADER_SIZE_MAX. Increasing header_size
+ * just means that lzma_block_header_encode() will add Header Padding.
+ *
+ * \return - LZMA_OK: Size calculated successfully and stored to
+ * block->header_size.
+ * - LZMA_OPTIONS_ERROR: Unsupported version, filters or
+ * filter options.
+ * - LZMA_PROG_ERROR: Invalid values like compressed_size == 0.
+ *
+ * \note This doesn't check that all the options are valid i.e. this
+ * may return LZMA_OK even if lzma_block_header_encode() or
+ * lzma_block_encoder() would fail. If you want to validate the
+ * filter chain, consider using lzma_memlimit_encoder() which as
+ * a side-effect validates the filter chain.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_size(lzma_block *block)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Encode Block Header
+ *
+ * The caller must have calculated the size of the Block Header already with
+ * lzma_block_header_size(). If a value larger than the one calculated by
+ * lzma_block_header_size() is used, the Block Header will be padded to the
+ * specified size.
+ *
+ * \param out Beginning of the output buffer. This must be
+ * at least block->header_size bytes.
+ * \param block Block options to be encoded.
+ *
+ * \return - LZMA_OK: Encoding was successful. block->header_size
+ * bytes were written to output buffer.
+ * - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
+ * - LZMA_PROG_ERROR: Invalid arguments, for example
+ * block->header_size is invalid or block->filters is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_encode(
+ const lzma_block *block, uint8_t *out)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode Block Header
+ *
+ * block->version should be set to the highest value supported by the
+ * application; currently the only possible version is zero. This function
+ * will set version to the lowest value that still supports all the features
+ * required by the Block Header.
+ *
+ * The size of the Block Header must have already been decoded with
+ * lzma_block_header_size_decode() macro and stored to block->header_size.
+ *
+ * The integrity check type from Stream Header must have been stored
+ * to block->check.
+ *
+ * block->filters must have been allocated, but they don't need to be
+ * initialized (possible existing filter options are not freed).
+ *
+ * \param block Destination for Block options.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() (and also free()
+ * if an error occurs).
+ * \param in Beginning of the input buffer. This must be
+ * at least block->header_size bytes.
+ *
+ * \return - LZMA_OK: Decoding was successful. block->header_size
+ * bytes were read from the input buffer.
+ * - LZMA_OPTIONS_ERROR: The Block Header specifies some
+ * unsupported options such as unsupported filters. This can
+ * happen also if block->version was set to a too low value
+ * compared to what would be required to properly represent
+ * the information stored in the Block Header.
+ * - LZMA_DATA_ERROR: Block Header is corrupt, for example,
+ * the CRC32 doesn't match.
+ * - LZMA_PROG_ERROR: Invalid arguments, for example
+ * block->header_size is invalid or block->filters is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_block_header_decode(lzma_block *block,
+ lzma_allocator *allocator, const uint8_t *in)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Validate and set Compressed Size according to Unpadded Size
+ *
+ * Block Header stores Compressed Size, but Index has Unpadded Size. If the
+ * application has already parsed the Index and is now decoding Blocks,
+ * it can calculate Compressed Size from Unpadded Size. This function does
+ * exactly that with error checking:
+ *
+ * - Compressed Size calculated from Unpadded Size must be positive integer,
+ * that is, Unpadded Size must be big enough that after Block Header and
+ * Check fields there's still at least one byte for Compressed Size.
+ *
+ * - If Compressed Size was present in Block Header, the new value
+ * calculated from Unpadded Size is compared against the value
+ * from Block Header.
+ *
+ * \note This function must be called _after_ decoding the Block Header
+ * field so that it can properly validate Compressed Size if it
+ * was present in Block Header.
+ *
+ * \return - LZMA_OK: block->compressed_size was set successfully.
+ * - LZMA_DATA_ERROR: unpadded_size is too small compared to
+ * block->header_size and lzma_check_size(block->check).
+ * - LZMA_PROG_ERROR: Some values are invalid. For example,
+ * block->header_size must be a multiple of four and
+ * between 8 and 1024 inclusive.
+ */
+extern LZMA_API(lzma_ret) lzma_block_compressed_size(
+ lzma_block *block, lzma_vli unpadded_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Calculate Unpadded Size
+ *
+ * The Index field stores Unpadded Size and Uncompressed Size. The latter
+ * can be taken directly from the lzma_block structure after coding a Block,
+ * but Unpadded Size needs to be calculated from Block Header Size,
+ * Compressed Size, and size of the Check field. This is where this function
+ * is needed.
+ *
+ * \return Unpadded Size on success, or zero on error.
+ */
+extern LZMA_API(lzma_vli) lzma_block_unpadded_size(const lzma_block *block)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Calculate the total encoded size of a Block
+ *
+ * This is equivalent to lzma_block_unpadded_size() except that the returned
+ * value includes the size of the Block Padding field.
+ *
+ * \return On success, total encoded size of the Block. On error,
+ * zero is returned.
+ */
+extern LZMA_API(lzma_vli) lzma_block_total_size(const lzma_block *block)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Initialize .xz Block encoder
+ *
+ * Valid actions for lzma_code() are LZMA_RUN, LZMA_SYNC_FLUSH (only if the
+ * filter chain supports it), and LZMA_FINISH.
+ *
+ * \return - LZMA_OK: All good, continue with lzma_code().
+ * - LZMA_MEM_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_UNSUPPORTED_CHECK: block->check specifies a Check ID
+ * that is not supported by this buid of liblzma. Initializing
+ * the encoder failed.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_encoder(
+ lzma_stream *strm, lzma_block *block)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize .xz Block decoder
+ *
+ * Valid actions for lzma_code() are LZMA_RUN and LZMA_FINISH. Using
+ * LZMA_FINISH is not required. It is supported only for convenience.
+ *
+ * \return - LZMA_OK: All good, continue with lzma_code().
+ * - LZMA_UNSUPPORTED_CHECK: Initialization was successful, but
+ * the given Check ID is not supported, thus Check will be
+ * ignored.
+ * - LZMA_PROG_ERROR
+ * - LZMA_MEM_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_decoder(
+ lzma_stream *strm, lzma_block *block)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Calculate maximum output size for single-call Block encoding
+ *
+ * This is equivalent to lzma_stream_buffer_bound() but for .xz Blocks.
+ * See the documentation of lzma_stream_buffer_bound().
+ */
+extern LZMA_API(size_t) lzma_block_buffer_bound(size_t uncompressed_size)
+ lzma_nothrow;
+
+
+/**
+ * \brief Single-call .xz Block encoder
+ *
+ * In contrast to the multi-call encoder initialized with
+ * lzma_block_encoder(), this function encodes also the Block Header. This
+ * is required to make it possible to write appropriate Block Header also
+ * in case the data isn't compressible, and different filter chain has to be
+ * used to encode the data in uncompressed form using uncompressed chunks
+ * of the LZMA2 filter.
+ *
+ * When the data isn't compressible, header_size, compressed_size, and
+ * uncompressed_size are set just like when the data was compressible, but
+ * it is possible that header_size is too small to hold the filter chain
+ * specified in block->filters, because that isn't necessarily the filter
+ * chain that was actually used to encode the data. lzma_block_unpadded_size()
+ * still works normally, because it doesn't read the filters array.
+ *
+ * \param block Block options: block->version, block->check,
+ * and block->filters must have been initialized.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_size Size of the input buffer
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_BUF_ERROR: Not enough output buffer space.
+ * - LZMA_UNSUPPORTED_CHECK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_buffer_encode(
+ lzma_block *block, lzma_allocator *allocator,
+ const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Single-call .xz Block decoder
+ *
+ * This is single-call equivalent of lzma_block_decoder(), and requires that
+ * the caller has already decoded Block Header and checked its memory usage.
+ *
+ * \param block Block options just like with lzma_block_decoder().
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_pos The next byte will be read from in[*in_pos].
+ * *in_pos is updated only if decoding succeeds.
+ * \param in_size Size of the input buffer; the first byte that
+ * won't be read is in[in_size].
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Decoding was successful.
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_BUF_ERROR: Output buffer was too small.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_block_buffer_decode(
+ lzma_block *block, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+ lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/check.h b/Utilities/cmliblzma/liblzma/api/lzma/check.h
new file mode 100644
index 000000000..6a243db0d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/check.h
@@ -0,0 +1,150 @@
+/**
+ * \file lzma/check.h
+ * \brief Integrity checks
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Type of the integrity check (Check ID)
+ *
+ * The .xz format supports multiple types of checks that are calculated
+ * from the uncompressed data. They vary in both speed and ability to
+ * detect errors.
+ */
+typedef enum {
+ LZMA_CHECK_NONE = 0,
+ /**<
+ * No Check is calculated.
+ *
+ * Size of the Check field: 0 bytes
+ */
+
+ LZMA_CHECK_CRC32 = 1,
+ /**<
+ * CRC32 using the polynomial from the IEEE 802.3 standard
+ *
+ * Size of the Check field: 4 bytes
+ */
+
+ LZMA_CHECK_CRC64 = 4,
+ /**<
+ * CRC64 using the polynomial from the ECMA-182 standard
+ *
+ * Size of the Check field: 8 bytes
+ */
+
+ LZMA_CHECK_SHA256 = 10
+ /**<
+ * SHA-256
+ *
+ * Size of the Check field: 32 bytes
+ */
+} lzma_check;
+
+
+/**
+ * \brief Maximum valid Check ID
+ *
+ * The .xz file format specification specifies 16 Check IDs (0-15). Some
+ * of them are only reserved, that is, no actual Check algorithm has been
+ * assigned. When decoding, liblzma still accepts unknown Check IDs for
+ * future compatibility. If a valid but unsupported Check ID is detected,
+ * liblzma can indicate a warning; see the flags LZMA_TELL_NO_CHECK,
+ * LZMA_TELL_UNSUPPORTED_CHECK, and LZMA_TELL_ANY_CHECK in container.h.
+ */
+#define LZMA_CHECK_ID_MAX 15
+
+
+/**
+ * \brief Test if the given Check ID is supported
+ *
+ * Return true if the given Check ID is supported by this liblzma build.
+ * Otherwise false is returned. It is safe to call this with a value that
+ * is not in the range [0, 15]; in that case the return value is always false.
+ *
+ * You can assume that LZMA_CHECK_NONE and LZMA_CHECK_CRC32 are always
+ * supported (even if liblzma is built with limited features).
+ */
+extern LZMA_API(lzma_bool) lzma_check_is_supported(lzma_check check)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Get the size of the Check field with the given Check ID
+ *
+ * Although not all Check IDs have a check algorithm associated, the size of
+ * every Check is already frozen. This function returns the size (in bytes) of
+ * the Check field with the specified Check ID. The values are:
+ * { 0, 4, 4, 4, 8, 8, 8, 16, 16, 16, 32, 32, 32, 64, 64, 64 }
+ *
+ * If the argument is not in the range [0, 15], UINT32_MAX is returned.
+ */
+extern LZMA_API(uint32_t) lzma_check_size(lzma_check check)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Maximum size of a Check field
+ */
+#define LZMA_CHECK_SIZE_MAX 64
+
+
+/**
+ * \brief Calculate CRC32
+ *
+ * Calculate CRC32 using the polynomial from the IEEE 802.3 standard.
+ *
+ * \param buf Pointer to the input buffer
+ * \param size Size of the input buffer
+ * \param crc Previously returned CRC value. This is used to
+ * calculate the CRC of a big buffer in smaller chunks.
+ * Set to zero when starting a new calculation.
+ *
+ * \return Updated CRC value, which can be passed to this function
+ * again to continue CRC calculation.
+ */
+extern LZMA_API(uint32_t) lzma_crc32(
+ const uint8_t *buf, size_t size, uint32_t crc)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Calculate CRC64
+ *
+ * Calculate CRC64 using the polynomial from the ECMA-182 standard.
+ *
+ * This function is used similarly to lzma_crc32(). See its documentation.
+ */
+extern LZMA_API(uint64_t) lzma_crc64(
+ const uint8_t *buf, size_t size, uint64_t crc)
+ lzma_nothrow lzma_attr_pure;
+
+
+/*
+ * SHA-256 functions are currently not exported to public API.
+ * Contact Lasse Collin if you think it should be.
+ */
+
+
+/**
+ * \brief Get the type of the integrity check
+ *
+ * This function can be called only immediately after lzma_code() has
+ * returned LZMA_NO_CHECK, LZMA_UNSUPPORTED_CHECK, or LZMA_GET_CHECK.
+ * Calling this function in any other situation has undefined behavior.
+ */
+extern LZMA_API(lzma_check) lzma_get_check(const lzma_stream *strm)
+ lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/container.h b/Utilities/cmliblzma/liblzma/api/lzma/container.h
new file mode 100644
index 000000000..7a9ffc645
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/container.h
@@ -0,0 +1,424 @@
+/**
+ * \file lzma/container.h
+ * \brief File formats
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/************
+ * Encoding *
+ ************/
+
+/**
+ * \brief Default compression preset
+ *
+ * It's not straightforward to recommend a default preset, because in some
+ * cases keeping the resource usage relatively low is more important that
+ * getting the maximum compression ratio.
+ */
+#define LZMA_PRESET_DEFAULT UINT32_C(6)
+
+
+/**
+ * \brief Mask for preset level
+ *
+ * This is useful only if you need to extract the level from the preset
+ * variable. That should be rare.
+ */
+#define LZMA_PRESET_LEVEL_MASK UINT32_C(0x1F)
+
+
+/*
+ * Preset flags
+ *
+ * Currently only one flag is defined.
+ */
+
+/**
+ * \brief Extreme compression preset
+ *
+ * This flag modifies the preset to make the encoding significantly slower
+ * while improving the compression ratio only marginally. This is useful
+ * when you don't mind wasting time to get as small result as possible.
+ *
+ * This flag doesn't affect the memory usage requirements of the decoder (at
+ * least not significantly). The memory usage of the encoder may be increased
+ * a little but only at the lowest preset levels (0-3).
+ */
+#define LZMA_PRESET_EXTREME (UINT32_C(1) << 31)
+
+
+/**
+ * \brief Calculate approximate memory usage of easy encoder
+ *
+ * This function is a wrapper for lzma_raw_encoder_memusage().
+ *
+ * \param preset Compression preset (level and possible flags)
+ *
+ * \return Number of bytes of memory required for the given
+ * preset when encoding. If an error occurs, for example
+ * due to unsupported preset, UINT64_MAX is returned.
+ */
+extern LZMA_API(uint64_t) lzma_easy_encoder_memusage(uint32_t preset)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Calculate approximate decoder memory usage of a preset
+ *
+ * This function is a wrapper for lzma_raw_decoder_memusage().
+ *
+ * \param preset Compression preset (level and possible flags)
+ *
+ * \return Number of bytes of memory required to decompress a file
+ * that was compressed using the given preset. If an error
+ * occurs, for example due to unsupported preset, UINT64_MAX
+ * is returned.
+ */
+extern LZMA_API(uint64_t) lzma_easy_decoder_memusage(uint32_t preset)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Initialize .xz Stream encoder using a preset number
+ *
+ * This function is intended for those who just want to use the basic features
+ * if liblzma (that is, most developers out there).
+ *
+ * \param strm Pointer to lzma_stream that is at least initialized
+ * with LZMA_STREAM_INIT.
+ * \param preset Compression preset to use. A preset consist of level
+ * number and zero or more flags. Usually flags aren't
+ * used, so preset is simply a number [0, 9] which match
+ * the options -0 ... -9 of the xz command line tool.
+ * Additional flags can be be set using bitwise-or with
+ * the preset level number, e.g. 6 | LZMA_PRESET_EXTREME.
+ * \param check Integrity check type to use. See check.h for available
+ * checks. The xz command line tool defaults to
+ * LZMA_CHECK_CRC64, which is a good choice if you are
+ * unsure. LZMA_CHECK_CRC32 is good too as long as the
+ * uncompressed file is not many gigabytes.
+ *
+ * \return - LZMA_OK: Initialization succeeded. Use lzma_code() to
+ * encode your data.
+ * - LZMA_MEM_ERROR: Memory allocation failed.
+ * - LZMA_OPTIONS_ERROR: The given compression preset is not
+ * supported by this build of liblzma.
+ * - LZMA_UNSUPPORTED_CHECK: The given check type is not
+ * supported by this liblzma build.
+ * - LZMA_PROG_ERROR: One or more of the parameters have values
+ * that will never be valid. For example, strm == NULL.
+ *
+ * If initialization fails (return value is not LZMA_OK), all the memory
+ * allocated for *strm by liblzma is always freed. Thus, there is no need
+ * to call lzma_end() after failed initialization.
+ *
+ * If initialization succeeds, use lzma_code() to do the actual encoding.
+ * Valid values for `action' (the second argument of lzma_code()) are
+ * LZMA_RUN, LZMA_SYNC_FLUSH, LZMA_FULL_FLUSH, and LZMA_FINISH. In future,
+ * there may be compression levels or flags that don't support LZMA_SYNC_FLUSH.
+ */
+extern LZMA_API(lzma_ret) lzma_easy_encoder(
+ lzma_stream *strm, uint32_t preset, lzma_check check)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Single-call .xz Stream encoding using a preset number
+ *
+ * The maximum required output buffer size can be calculated with
+ * lzma_stream_buffer_bound().
+ *
+ * \param preset Compression preset to use. See the description
+ * in lzma_easy_encoder().
+ * \param check Type of the integrity check to calculate from
+ * uncompressed data.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_size Size of the input buffer
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_BUF_ERROR: Not enough output buffer space.
+ * - LZMA_UNSUPPORTED_CHECK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_easy_buffer_encode(
+ uint32_t preset, lzma_check check,
+ lzma_allocator *allocator, const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief Initialize .xz Stream encoder using a custom filter chain
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param filters Array of filters. This must be terminated with
+ * filters[n].id = LZMA_VLI_UNKNOWN. See filter.h for
+ * more information.
+ * \param check Type of the integrity check to calculate from
+ * uncompressed data.
+ *
+ * \return - LZMA_OK: Initialization was successful.
+ * - LZMA_MEM_ERROR
+ * - LZMA_UNSUPPORTED_CHECK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_encoder(lzma_stream *strm,
+ const lzma_filter *filters, lzma_check check)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize .lzma encoder (legacy file format)
+ *
+ * The .lzma format is sometimes called the LZMA_Alone format, which is the
+ * reason for the name of this function. The .lzma format supports only the
+ * LZMA1 filter. There is no support for integrity checks like CRC32.
+ *
+ * Use this function if and only if you need to create files readable by
+ * legacy LZMA tools such as LZMA Utils 4.32.x. Moving to the .xz format
+ * is strongly recommended.
+ *
+ * The valid action values for lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * No kind of flushing is supported, because the file format doesn't make
+ * it possible.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_alone_encoder(
+ lzma_stream *strm, const lzma_options_lzma *options)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Calculate output buffer size for single-call Stream encoder
+ *
+ * When trying to compress uncompressible data, the encoded size will be
+ * slightly bigger than the input data. This function calculates how much
+ * output buffer space is required to be sure that lzma_stream_buffer_encode()
+ * doesn't return LZMA_BUF_ERROR.
+ *
+ * The calculated value is not exact, but it is guaranteed to be big enough.
+ * The actual maximum output space required may be slightly smaller (up to
+ * about 100 bytes). This should not be a problem in practice.
+ *
+ * If the calculated maximum size doesn't fit into size_t or would make the
+ * Stream grow past LZMA_VLI_MAX (which should never happen in practice),
+ * zero is returned to indicate the error.
+ *
+ * \note The limit calculated by this function applies only to
+ * single-call encoding. Multi-call encoding may (and probably
+ * will) have larger maximum expansion when encoding
+ * uncompressible data. Currently there is no function to
+ * calculate the maximum expansion of multi-call encoding.
+ */
+extern LZMA_API(size_t) lzma_stream_buffer_bound(size_t uncompressed_size)
+ lzma_nothrow;
+
+
+/**
+ * \brief Single-call .xz Stream encoder
+ *
+ * \param filters Array of filters. This must be terminated with
+ * filters[n].id = LZMA_VLI_UNKNOWN. See filter.h
+ * for more information.
+ * \param check Type of the integrity check to calculate from
+ * uncompressed data.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_size Size of the input buffer
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_BUF_ERROR: Not enough output buffer space.
+ * - LZMA_UNSUPPORTED_CHECK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_buffer_encode(
+ lzma_filter *filters, lzma_check check,
+ lzma_allocator *allocator, const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/************
+ * Decoding *
+ ************/
+
+/**
+ * This flag makes lzma_code() return LZMA_NO_CHECK if the input stream
+ * being decoded has no integrity check. Note that when used with
+ * lzma_auto_decoder(), all .lzma files will trigger LZMA_NO_CHECK
+ * if LZMA_TELL_NO_CHECK is used.
+ */
+#define LZMA_TELL_NO_CHECK UINT32_C(0x01)
+
+
+/**
+ * This flag makes lzma_code() return LZMA_UNSUPPORTED_CHECK if the input
+ * stream has an integrity check, but the type of the integrity check is not
+ * supported by this liblzma version or build. Such files can still be
+ * decoded, but the integrity check cannot be verified.
+ */
+#define LZMA_TELL_UNSUPPORTED_CHECK UINT32_C(0x02)
+
+
+/**
+ * This flag makes lzma_code() return LZMA_GET_CHECK as soon as the type
+ * of the integrity check is known. The type can then be got with
+ * lzma_get_check().
+ */
+#define LZMA_TELL_ANY_CHECK UINT32_C(0x04)
+
+
+/**
+ * This flag enables decoding of concatenated files with file formats that
+ * allow concatenating compressed files as is. From the formats currently
+ * supported by liblzma, only the .xz format allows concatenated files.
+ * Concatenated files are not allowed with the legacy .lzma format.
+ *
+ * This flag also affects the usage of the `action' argument for lzma_code().
+ * When LZMA_CONCATENATED is used, lzma_code() won't return LZMA_STREAM_END
+ * unless LZMA_FINISH is used as `action'. Thus, the application has to set
+ * LZMA_FINISH in the same way as it does when encoding.
+ *
+ * If LZMA_CONCATENATED is not used, the decoders still accept LZMA_FINISH
+ * as `action' for lzma_code(), but the usage of LZMA_FINISH isn't required.
+ */
+#define LZMA_CONCATENATED UINT32_C(0x08)
+
+
+/**
+ * \brief Initialize .xz Stream decoder
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param memlimit Memory usage limit as bytes. Use UINT64_MAX
+ * to effectively disable the limiter.
+ * \param flags Bitwise-or of zero or more of the decoder flags:
+ * LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ * LZMA_TELL_ANY_CHECK, LZMA_CONCATENATED
+ *
+ * \return - LZMA_OK: Initialization was successful.
+ * - LZMA_MEM_ERROR: Cannot allocate memory.
+ * - LZMA_OPTIONS_ERROR: Unsupported flags
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_decoder(
+ lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode .xz Streams and .lzma files with autodetection
+ *
+ * This decoder autodetects between the .xz and .lzma file formats, and
+ * calls lzma_stream_decoder() or lzma_alone_decoder() once the type
+ * of the input file has been detected.
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param memlimit Memory usage limit as bytes. Use UINT64_MAX
+ * to effectively disable the limiter.
+ * \param flags Bitwise-or of flags, or zero for no flags.
+ *
+ * \return - LZMA_OK: Initialization was successful.
+ * - LZMA_MEM_ERROR: Cannot allocate memory.
+ * - LZMA_OPTIONS_ERROR: Unsupported flags
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_auto_decoder(
+ lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize .lzma decoder (legacy file format)
+ *
+ * Valid `action' arguments to lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * There is no need to use LZMA_FINISH, but allowing it may simplify
+ * certain types of applications.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_alone_decoder(
+ lzma_stream *strm, uint64_t memlimit)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Single-call .xz Stream decoder
+ *
+ * \param memlimit Pointer to how much memory the decoder is allowed
+ * to allocate. The value pointed by this pointer is
+ * modified if and only if LZMA_MEMLIMIT_ERROR is
+ * returned.
+ * \param flags Bitwise-or of zero or more of the decoder flags:
+ * LZMA_TELL_NO_CHECK, LZMA_TELL_UNSUPPORTED_CHECK,
+ * LZMA_CONCATENATED. Note that LZMA_TELL_ANY_CHECK
+ * is not allowed and will return LZMA_PROG_ERROR.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_pos The next byte will be read from in[*in_pos].
+ * *in_pos is updated only if decoding succeeds.
+ * \param in_size Size of the input buffer; the first byte that
+ * won't be read is in[in_size].
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if decoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Decoding was successful.
+ * - LZMA_FORMAT_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_NO_CHECK: This can be returned only if using
+ * the LZMA_TELL_NO_CHECK flag.
+ * - LZMA_UNSUPPORTED_CHECK: This can be returned only if using
+ * the LZMA_TELL_UNSUPPORTED_CHECK flag.
+ * - LZMA_MEM_ERROR
+ * - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
+ * The minimum required memlimit value was stored to *memlimit.
+ * - LZMA_BUF_ERROR: Output buffer was too small.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_stream_buffer_decode(
+ uint64_t *memlimit, uint32_t flags, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/delta.h b/Utilities/cmliblzma/liblzma/api/lzma/delta.h
new file mode 100644
index 000000000..592fc4f84
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/delta.h
@@ -0,0 +1,77 @@
+/**
+ * \file lzma/delta.h
+ * \brief Delta filter
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Filter ID
+ *
+ * Filter ID of the Delta filter. This is used as lzma_filter.id.
+ */
+#define LZMA_FILTER_DELTA LZMA_VLI_C(0x03)
+
+
+/**
+ * \brief Type of the delta calculation
+ *
+ * Currently only byte-wise delta is supported. Other possible types could
+ * be, for example, delta of 16/32/64-bit little/big endian integers, but
+ * these are not currently planned since byte-wise delta is almost as good.
+ */
+typedef enum {
+ LZMA_DELTA_TYPE_BYTE
+} lzma_delta_type;
+
+
+/**
+ * \brief Options for the Delta filter
+ *
+ * These options are needed by both encoder and decoder.
+ */
+typedef struct {
+ /** For now, this must always be LZMA_DELTA_TYPE_BYTE. */
+ lzma_delta_type type;
+
+ /**
+ * \brief Delta distance
+ *
+ * With the only currently supported type, LZMA_DELTA_TYPE_BYTE,
+ * the distance is as bytes.
+ *
+ * Examples:
+ * - 16-bit stereo audio: distance = 4 bytes
+ * - 24-bit RGB image data: distance = 3 bytes
+ */
+ uint32_t dist;
+# define LZMA_DELTA_DIST_MIN 1
+# define LZMA_DELTA_DIST_MAX 256
+
+ /*
+ * Reserved space to allow possible future extensions without
+ * breaking the ABI. You should not touch these, because the names
+ * of these variables may change. These are and will never be used
+ * when type is LZMA_DELTA_TYPE_BYTE, so it is safe to leave these
+ * uninitialized.
+ */
+ uint32_t reserved_int1;
+ uint32_t reserved_int2;
+ uint32_t reserved_int3;
+ uint32_t reserved_int4;
+ void *reserved_ptr1;
+ void *reserved_ptr2;
+
+} lzma_options_delta;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/filter.h b/Utilities/cmliblzma/liblzma/api/lzma/filter.h
new file mode 100644
index 000000000..e0bc163ad
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/filter.h
@@ -0,0 +1,424 @@
+/**
+ * \file lzma/filter.h
+ * \brief Common filter related types and functions
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Maximum number of filters in a chain
+ *
+ * A filter chain can have 1-4 filters, of which three are allowed to change
+ * the size of the data. Usually only one or two filters are needed.
+ */
+#define LZMA_FILTERS_MAX 4
+
+
+/**
+ * \brief Filter options
+ *
+ * This structure is used to pass Filter ID and a pointer filter's
+ * options to liblzma. A few functions work with a single lzma_filter
+ * structure, while most functions expect a filter chain.
+ *
+ * A filter chain is indicated with an array of lzma_filter structures.
+ * The array is terminated with .id = LZMA_VLI_UNKNOWN. Thus, the filter
+ * array must have LZMA_FILTERS_MAX + 1 elements (that is, five) to
+ * be able to hold any arbitrary filter chain. This is important when
+ * using lzma_block_header_decode() from block.h, because too small
+ * array would make liblzma write past the end of the filters array.
+ */
+typedef struct {
+ /**
+ * \brief Filter ID
+ *
+ * Use constants whose name begin with `LZMA_FILTER_' to specify
+ * different filters. In an array of lzma_filter structures, use
+ * LZMA_VLI_UNKNOWN to indicate end of filters.
+ *
+ * \note This is not an enum, because on some systems enums
+ * cannot be 64-bit.
+ */
+ lzma_vli id;
+
+ /**
+ * \brief Pointer to filter-specific options structure
+ *
+ * If the filter doesn't need options, set this to NULL. If id is
+ * set to LZMA_VLI_UNKNOWN, options is ignored, and thus
+ * doesn't need be initialized.
+ */
+ void *options;
+
+} lzma_filter;
+
+
+/**
+ * \brief Test if the given Filter ID is supported for encoding
+ *
+ * Return true if the give Filter ID is supported for encoding by this
+ * liblzma build. Otherwise false is returned.
+ *
+ * There is no way to list which filters are available in this particular
+ * liblzma version and build. It would be useless, because the application
+ * couldn't know what kind of options the filter would need.
+ */
+extern LZMA_API(lzma_bool) lzma_filter_encoder_is_supported(lzma_vli id)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Test if the given Filter ID is supported for decoding
+ *
+ * Return true if the give Filter ID is supported for decoding by this
+ * liblzma build. Otherwise false is returned.
+ */
+extern LZMA_API(lzma_bool) lzma_filter_decoder_is_supported(lzma_vli id)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Copy the filters array
+ *
+ * Copy the Filter IDs and filter-specific options from src to dest.
+ * Up to LZMA_FILTERS_MAX filters are copied, plus the terminating
+ * .id == LZMA_VLI_UNKNOWN. Thus, dest should have at least
+ * LZMA_FILTERS_MAX + 1 elements space unless the caller knows that
+ * src is smaller than that.
+ *
+ * Unless the filter-specific options is NULL, the Filter ID has to be
+ * supported by liblzma, because liblzma needs to know the size of every
+ * filter-specific options structure. The filter-specific options are not
+ * validated. If options is NULL, any unsupported Filter IDs are copied
+ * without returning an error.
+ *
+ * Old filter-specific options in dest are not freed, so dest doesn't
+ * need to be initialized by the caller in any way.
+ *
+ * If an error occurs, memory possibly already allocated by this function
+ * is always freed.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_OPTIONS_ERROR: Unsupported Filter ID and its options
+ * is not NULL.
+ * - LZMA_PROG_ERROR: src or dest is NULL.
+ */
+extern LZMA_API(lzma_ret) lzma_filters_copy(const lzma_filter *src,
+ lzma_filter *dest, lzma_allocator *allocator) lzma_nothrow;
+
+
+/**
+ * \brief Calculate approximate memory requirements for raw encoder
+ *
+ * This function can be used to calculate the memory requirements for
+ * Block and Stream encoders too because Block and Stream encoders don't
+ * need significantly more memory than raw encoder.
+ *
+ * \param filters Array of filters terminated with
+ * .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return Number of bytes of memory required for the given
+ * filter chain when encoding. If an error occurs,
+ * for example due to unsupported filter chain,
+ * UINT64_MAX is returned.
+ */
+extern LZMA_API(uint64_t) lzma_raw_encoder_memusage(const lzma_filter *filters)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Calculate approximate memory requirements for raw decoder
+ *
+ * This function can be used to calculate the memory requirements for
+ * Block and Stream decoders too because Block and Stream decoders don't
+ * need significantly more memory than raw decoder.
+ *
+ * \param filters Array of filters terminated with
+ * .id == LZMA_VLI_UNKNOWN.
+ *
+ * \return Number of bytes of memory required for the given
+ * filter chain when decoding. If an error occurs,
+ * for example due to unsupported filter chain,
+ * UINT64_MAX is returned.
+ */
+extern LZMA_API(uint64_t) lzma_raw_decoder_memusage(const lzma_filter *filters)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Initialize raw encoder
+ *
+ * This function may be useful when implementing custom file formats.
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param filters Array of lzma_filter structures. The end of the
+ * array must be marked with .id = LZMA_VLI_UNKNOWN.
+ *
+ * The `action' with lzma_code() can be LZMA_RUN, LZMA_SYNC_FLUSH (if the
+ * filter chain supports it), or LZMA_FINISH.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_encoder(
+ lzma_stream *strm, const lzma_filter *filters)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize raw decoder
+ *
+ * The initialization of raw decoder goes similarly to raw encoder.
+ *
+ * The `action' with lzma_code() can be LZMA_RUN or LZMA_FINISH. Using
+ * LZMA_FINISH is not required, it is supported just for convenience.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_raw_decoder(
+ lzma_stream *strm, const lzma_filter *filters)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Update the filter chain in the encoder
+ *
+ * This function is for advanced users only. This function has two slightly
+ * different purposes:
+ *
+ * - After LZMA_FULL_FLUSH when using Stream encoder: Set a new filter
+ * chain, which will be used starting from the next Block.
+ *
+ * - After LZMA_SYNC_FLUSH using Raw, Block, or Stream encoder: Change
+ * the filter-specific options in the middle of encoding. The actual
+ * filters in the chain (Filter IDs) cannot be changed. In the future,
+ * it might become possible to change the filter options without
+ * using LZMA_SYNC_FLUSH.
+ *
+ * While rarely useful, this function may be called also when no data has
+ * been compressed yet. In that case, this function will behave as if
+ * LZMA_FULL_FLUSH (Stream encoder) or LZMA_SYNC_FLUSH (Raw or Block
+ * encoder) had been used right before calling this function.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_MEMLIMIT_ERROR
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_filters_update(
+ lzma_stream *strm, const lzma_filter *filters) lzma_nothrow;
+
+
+/**
+ * \brief Single-call raw encoder
+ *
+ * \param filters Array of lzma_filter structures. The end of the
+ * array must be marked with .id = LZMA_VLI_UNKNOWN.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_size Size of the input buffer
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_BUF_ERROR: Not enough output buffer space.
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_DATA_ERROR
+ * - LZMA_PROG_ERROR
+ *
+ * \note There is no function to calculate how big output buffer
+ * would surely be big enough. (lzma_stream_buffer_bound()
+ * works only for lzma_stream_buffer_encode(); raw encoder
+ * won't necessarily meet that bound.)
+ */
+extern LZMA_API(lzma_ret) lzma_raw_buffer_encode(
+ const lzma_filter *filters, lzma_allocator *allocator,
+ const uint8_t *in, size_t in_size, uint8_t *out,
+ size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief Single-call raw decoder
+ *
+ * \param filters Array of lzma_filter structures. The end of the
+ * array must be marked with .id = LZMA_VLI_UNKNOWN.
+ * \param allocator lzma_allocator for custom allocator functions.
+ * Set to NULL to use malloc() and free().
+ * \param in Beginning of the input buffer
+ * \param in_pos The next byte will be read from in[*in_pos].
+ * *in_pos is updated only if decoding succeeds.
+ * \param in_size Size of the input buffer; the first byte that
+ * won't be read is in[in_size].
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ */
+extern LZMA_API(lzma_ret) lzma_raw_buffer_decode(
+ const lzma_filter *filters, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief Get the size of the Filter Properties field
+ *
+ * This function may be useful when implementing custom file formats
+ * using the raw encoder and decoder.
+ *
+ * \param size Pointer to uint32_t to hold the size of the properties
+ * \param filter Filter ID and options (the size of the properties may
+ * vary depending on the options)
+ *
+ * \return - LZMA_OK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ *
+ * \note This function validates the Filter ID, but does not
+ * necessarily validate the options. Thus, it is possible
+ * that this returns LZMA_OK while the following call to
+ * lzma_properties_encode() returns LZMA_OPTIONS_ERROR.
+ */
+extern LZMA_API(lzma_ret) lzma_properties_size(
+ uint32_t *size, const lzma_filter *filter) lzma_nothrow;
+
+
+/**
+ * \brief Encode the Filter Properties field
+ *
+ * \param filter Filter ID and options
+ * \param props Buffer to hold the encoded options. The size of
+ * buffer must have been already determined with
+ * lzma_properties_size().
+ *
+ * \return - LZMA_OK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_PROG_ERROR
+ *
+ * \note Even this function won't validate more options than actually
+ * necessary. Thus, it is possible that encoding the properties
+ * succeeds but using the same options to initialize the encoder
+ * will fail.
+ *
+ * \note If lzma_properties_size() indicated that the size
+ * of the Filter Properties field is zero, calling
+ * lzma_properties_encode() is not required, but it
+ * won't do any harm either.
+ */
+extern LZMA_API(lzma_ret) lzma_properties_encode(
+ const lzma_filter *filter, uint8_t *props) lzma_nothrow;
+
+
+/**
+ * \brief Decode the Filter Properties field
+ *
+ * \param filter filter->id must have been set to the correct
+ * Filter ID. filter->options doesn't need to be
+ * initialized (it's not freed by this function). The
+ * decoded options will be stored to filter->options.
+ * filter->options is set to NULL if there are no
+ * properties or if an error occurs.
+ * \param allocator Custom memory allocator used to allocate the
+ * options. Set to NULL to use the default malloc(),
+ * and in case of an error, also free().
+ * \param props Input buffer containing the properties.
+ * \param props_size Size of the properties. This must be the exact
+ * size; giving too much or too little input will
+ * return LZMA_OPTIONS_ERROR.
+ *
+ * \return - LZMA_OK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_properties_decode(
+ lzma_filter *filter, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size) lzma_nothrow;
+
+
+/**
+ * \brief Calculate encoded size of a Filter Flags field
+ *
+ * Knowing the size of Filter Flags is useful to know when allocating
+ * memory to hold the encoded Filter Flags.
+ *
+ * \param size Pointer to integer to hold the calculated size
+ * \param filter Filter ID and associated options whose encoded
+ * size is to be calculated
+ *
+ * \return - LZMA_OK: *size set successfully. Note that this doesn't
+ * guarantee that filter->options is valid, thus
+ * lzma_filter_flags_encode() may still fail.
+ * - LZMA_OPTIONS_ERROR: Unknown Filter ID or unsupported options.
+ * - LZMA_PROG_ERROR: Invalid options
+ *
+ * \note If you need to calculate size of List of Filter Flags,
+ * you need to loop over every lzma_filter entry.
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_size(
+ uint32_t *size, const lzma_filter *filter)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Encode Filter Flags into given buffer
+ *
+ * In contrast to some functions, this doesn't allocate the needed buffer.
+ * This is due to how this function is used internally by liblzma.
+ *
+ * \param filter Filter ID and options to be encoded
+ * \param out Beginning of the output buffer
+ * \param out_pos out[*out_pos] is the next write position. This
+ * is updated by the encoder.
+ * \param out_size out[out_size] is the first byte to not write.
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_OPTIONS_ERROR: Invalid or unsupported options.
+ * - LZMA_PROG_ERROR: Invalid options or not enough output
+ * buffer space (you should have checked it with
+ * lzma_filter_flags_size()).
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_encode(const lzma_filter *filter,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode Filter Flags from given buffer
+ *
+ * The decoded result is stored into *filter. The old value of
+ * filter->options is not free()d.
+ *
+ * \return - LZMA_OK
+ * - LZMA_OPTIONS_ERROR
+ * - LZMA_MEM_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_filter_flags_decode(
+ lzma_filter *filter, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/hardware.h b/Utilities/cmliblzma/liblzma/api/lzma/hardware.h
new file mode 100644
index 000000000..e7dd03c3e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/hardware.h
@@ -0,0 +1,50 @@
+/**
+ * \file lzma/hardware.h
+ * \brief Hardware information
+ *
+ * Since liblzma can consume a lot of system resources, it also provides
+ * ways to limit the resource usage. Applications linking against liblzma
+ * need to do the actual decisions how much resources to let liblzma to use.
+ * To ease making these decisions, liblzma provides functions to find out
+ * the relevant capabilities of the underlaying hardware. Currently there
+ * is only a function to find out the amount of RAM, but in the future there
+ * will be also a function to detect how many concurrent threads the system
+ * can run.
+ *
+ * \note On some operating systems, these function may temporarily
+ * load a shared library or open file descriptor(s) to find out
+ * the requested hardware information. Unless the application
+ * assumes that specific file descriptors are not touched by
+ * other threads, this should have no effect on thread safety.
+ * Possible operations involving file descriptors will restart
+ * the syscalls if they return EINTR.
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Get the total amount of physical memory (RAM) in bytes
+ *
+ * This function may be useful when determining a reasonable memory
+ * usage limit for decompressing or how much memory it is OK to use
+ * for compressing.
+ *
+ * \return On success, the total amount of physical memory in bytes
+ * is returned. If the amount of RAM cannot be determined,
+ * zero is returned. This can happen if an error occurs
+ * or if there is no code in liblzma to detect the amount
+ * of RAM on the specific operating system.
+ */
+extern LZMA_API(uint64_t) lzma_physmem(void) lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/index.h b/Utilities/cmliblzma/liblzma/api/lzma/index.h
new file mode 100644
index 000000000..16bacc287
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/index.h
@@ -0,0 +1,682 @@
+/**
+ * \file lzma/index.h
+ * \brief Handling of .xz Index and related information
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Opaque data type to hold the Index(es) and other information
+ *
+ * lzma_index often holds just one .xz Index and possibly the Stream Flags
+ * of the same Stream and size of the Stream Padding field. However,
+ * multiple lzma_indexes can be concatenated with lzma_index_cat() and then
+ * there may be information about multiple Streams in the same lzma_index.
+ *
+ * Notes about thread safety: Only one thread may modify lzma_index at
+ * a time. All functions that take non-const pointer to lzma_index
+ * modify it. As long as no thread is modifying the lzma_index, getting
+ * information from the same lzma_index can be done from multiple threads
+ * at the same time with functions that take a const pointer to
+ * lzma_index or use lzma_index_iter. The same iterator must be used
+ * only by one thread at a time, of course, but there can be as many
+ * iterators for the same lzma_index as needed.
+ */
+typedef struct lzma_index_s lzma_index;
+
+
+/**
+ * \brief Iterator to get information about Blocks and Streams
+ */
+typedef struct {
+ struct {
+ /**
+ * \brief Pointer to Stream Flags
+ *
+ * This is NULL if Stream Flags have not been set for
+ * this Stream with lzma_index_stream_flags().
+ */
+ const lzma_stream_flags *flags;
+
+ const void *reserved_ptr1;
+ const void *reserved_ptr2;
+ const void *reserved_ptr3;
+
+ /**
+ * \brief Stream number in the lzma_index
+ *
+ * The first Stream is 1.
+ */
+ lzma_vli number;
+
+ /**
+ * \brief Number of Blocks in the Stream
+ *
+ * If this is zero, the block structure below has
+ * undefined values.
+ */
+ lzma_vli block_count;
+
+ /**
+ * \brief Compressed start offset of this Stream
+ *
+ * The offset is relative to the beginning of the lzma_index
+ * (i.e. usually the beginning of the .xz file).
+ */
+ lzma_vli compressed_offset;
+
+ /**
+ * \brief Uncompressed start offset of this Stream
+ *
+ * The offset is relative to the beginning of the lzma_index
+ * (i.e. usually the beginning of the .xz file).
+ */
+ lzma_vli uncompressed_offset;
+
+ /**
+ * \brief Compressed size of this Stream
+ *
+ * This includes all headers except the possible
+ * Stream Padding after this Stream.
+ */
+ lzma_vli compressed_size;
+
+ /**
+ * \brief Uncompressed size of this Stream
+ */
+ lzma_vli uncompressed_size;
+
+ /**
+ * \brief Size of Stream Padding after this Stream
+ *
+ * If it hasn't been set with lzma_index_stream_padding(),
+ * this defaults to zero. Stream Padding is always
+ * a multiple of four bytes.
+ */
+ lzma_vli padding;
+
+ lzma_vli reserved_vli1;
+ lzma_vli reserved_vli2;
+ lzma_vli reserved_vli3;
+ lzma_vli reserved_vli4;
+ } stream;
+
+ struct {
+ /**
+ * \brief Block number in the file
+ *
+ * The first Block is 1.
+ */
+ lzma_vli number_in_file;
+
+ /**
+ * \brief Compressed start offset of this Block
+ *
+ * This offset is relative to the beginning of the
+ * lzma_index (i.e. usually the beginning of the .xz file).
+ * Normally this is where you should seek in the .xz file
+ * to start decompressing this Block.
+ */
+ lzma_vli compressed_file_offset;
+
+ /**
+ * \brief Uncompressed start offset of this Block
+ *
+ * This offset is relative to the beginning of the lzma_index
+ * (i.e. usually the beginning of the .xz file).
+ *
+ * When doing random-access reading, it is possible that
+ * the target offset is not exactly at Block boundary. One
+ * will need to compare the target offset against
+ * uncompressed_file_offset or uncompressed_stream_offset,
+ * and possibly decode and throw away some amount of data
+ * before reaching the target offset.
+ */
+ lzma_vli uncompressed_file_offset;
+
+ /**
+ * \brief Block number in this Stream
+ *
+ * The first Block is 1.
+ */
+ lzma_vli number_in_stream;
+
+ /**
+ * \brief Compressed start offset of this Block
+ *
+ * This offset is relative to the beginning of the Stream
+ * containing this Block.
+ */
+ lzma_vli compressed_stream_offset;
+
+ /**
+ * \brief Uncompressed start offset of this Block
+ *
+ * This offset is relative to the beginning of the Stream
+ * containing this Block.
+ */
+ lzma_vli uncompressed_stream_offset;
+
+ /**
+ * \brief Uncompressed size of this Block
+ *
+ * You should pass this to the Block decoder if you will
+ * decode this Block. It will allow the Block decoder to
+ * validate the uncompressed size.
+ */
+ lzma_vli uncompressed_size;
+
+ /**
+ * \brief Unpadded size of this Block
+ *
+ * You should pass this to the Block decoder if you will
+ * decode this Block. It will allow the Block decoder to
+ * validate the unpadded size.
+ */
+ lzma_vli unpadded_size;
+
+ /**
+ * \brief Total compressed size
+ *
+ * This includes all headers and padding in this Block.
+ * This is useful if you need to know how many bytes
+ * the Block decoder will actually read.
+ */
+ lzma_vli total_size;
+
+ lzma_vli reserved_vli1;
+ lzma_vli reserved_vli2;
+ lzma_vli reserved_vli3;
+ lzma_vli reserved_vli4;
+
+ const void *reserved_ptr1;
+ const void *reserved_ptr2;
+ const void *reserved_ptr3;
+ const void *reserved_ptr4;
+ } block;
+
+ /*
+ * Internal data which is used to store the state of the iterator.
+ * The exact format may vary between liblzma versions, so don't
+ * touch these in any way.
+ */
+ union {
+ const void *p;
+ size_t s;
+ lzma_vli v;
+ } internal[6];
+} lzma_index_iter;
+
+
+/**
+ * \brief Operation mode for lzma_index_iter_next()
+ */
+typedef enum {
+ LZMA_INDEX_ITER_ANY = 0,
+ /**<
+ * \brief Get the next Block or Stream
+ *
+ * Go to the next Block if the current Stream has at least
+ * one Block left. Otherwise go to the next Stream even if
+ * it has no Blocks. If the Stream has no Blocks
+ * (lzma_index_iter.stream.block_count == 0),
+ * lzma_index_iter.block will have undefined values.
+ */
+
+ LZMA_INDEX_ITER_STREAM = 1,
+ /**<
+ * \brief Get the next Stream
+ *
+ * Go to the next Stream even if the current Stream has
+ * unread Blocks left. If the next Stream has at least one
+ * Block, the iterator will point to the first Block.
+ * If there are no Blocks, lzma_index_iter.block will have
+ * undefined values.
+ */
+
+ LZMA_INDEX_ITER_BLOCK = 2,
+ /**<
+ * \brief Get the next Block
+ *
+ * Go to the next Block if the current Stream has at least
+ * one Block left. If the current Stream has no Blocks left,
+ * the next Stream with at least one Block is located and
+ * the iterator will be made to point to the first Block of
+ * that Stream.
+ */
+
+ LZMA_INDEX_ITER_NONEMPTY_BLOCK = 3
+ /**<
+ * \brief Get the next non-empty Block
+ *
+ * This is like LZMA_INDEX_ITER_BLOCK except that it will
+ * skip Blocks whose Uncompressed Size is zero.
+ */
+
+} lzma_index_iter_mode;
+
+
+/**
+ * \brief Calculate memory usage of lzma_index
+ *
+ * On disk, the size of the Index field depends on both the number of Records
+ * stored and how big values the Records store (due to variable-length integer
+ * encoding). When the Index is kept in lzma_index structure, the memory usage
+ * depends only on the number of Records/Blocks stored in the Index(es), and
+ * in case of concatenated lzma_indexes, the number of Streams. The size in
+ * RAM is almost always significantly bigger than in the encoded form on disk.
+ *
+ * This function calculates an approximate amount of memory needed hold
+ * the given number of Streams and Blocks in lzma_index structure. This
+ * value may vary between CPU architectures and also between liblzma versions
+ * if the internal implementation is modified.
+ */
+extern LZMA_API(uint64_t) lzma_index_memusage(
+ lzma_vli streams, lzma_vli blocks) lzma_nothrow;
+
+
+/**
+ * \brief Calculate the memory usage of an existing lzma_index
+ *
+ * This is a shorthand for lzma_index_memusage(lzma_index_stream_count(i),
+ * lzma_index_block_count(i)).
+ */
+extern LZMA_API(uint64_t) lzma_index_memused(const lzma_index *i)
+ lzma_nothrow;
+
+
+/**
+ * \brief Allocate and initialize a new lzma_index structure
+ *
+ * \return On success, a pointer to an empty initialized lzma_index is
+ * returned. If allocation fails, NULL is returned.
+ */
+extern LZMA_API(lzma_index *) lzma_index_init(lzma_allocator *allocator)
+ lzma_nothrow;
+
+
+/**
+ * \brief Deallocate lzma_index
+ *
+ * If i is NULL, this does nothing.
+ */
+extern LZMA_API(void) lzma_index_end(lzma_index *i, lzma_allocator *allocator)
+ lzma_nothrow;
+
+
+/**
+ * \brief Add a new Block to lzma_index
+ *
+ * \param i Pointer to a lzma_index structure
+ * \param allocator Pointer to lzma_allocator, or NULL to
+ * use malloc()
+ * \param unpadded_size Unpadded Size of a Block. This can be
+ * calculated with lzma_block_unpadded_size()
+ * after encoding or decoding the Block.
+ * \param uncompressed_size Uncompressed Size of a Block. This can be
+ * taken directly from lzma_block structure
+ * after encoding or decoding the Block.
+ *
+ * Appending a new Block does not invalidate iterators. For example,
+ * if an iterator was pointing to the end of the lzma_index, after
+ * lzma_index_append() it is possible to read the next Block with
+ * an existing iterator.
+ *
+ * \return - LZMA_OK
+ * - LZMA_MEM_ERROR
+ * - LZMA_DATA_ERROR: Compressed or uncompressed size of the
+ * Stream or size of the Index field would grow too big.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_append(
+ lzma_index *i, lzma_allocator *allocator,
+ lzma_vli unpadded_size, lzma_vli uncompressed_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Set the Stream Flags
+ *
+ * Set the Stream Flags of the last (and typically the only) Stream
+ * in lzma_index. This can be useful when reading information from the
+ * lzma_index, because to decode Blocks, knowing the integrity check type
+ * is needed.
+ *
+ * The given Stream Flags are copied into internal preallocated structure
+ * in the lzma_index, thus the caller doesn't need to keep the *stream_flags
+ * available after calling this function.
+ *
+ * \return - LZMA_OK
+ * - LZMA_OPTIONS_ERROR: Unsupported stream_flags->version.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_stream_flags(
+ lzma_index *i, const lzma_stream_flags *stream_flags)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Get the types of integrity Checks
+ *
+ * If lzma_index_stream_flags() is used to set the Stream Flags for
+ * every Stream, lzma_index_checks() can be used to get a bitmask to
+ * indicate which Check types have been used. It can be useful e.g. if
+ * showing the Check types to the user.
+ *
+ * The bitmask is 1 << check_id, e.g. CRC32 is 1 << 1 and SHA-256 is 1 << 10.
+ */
+extern LZMA_API(uint32_t) lzma_index_checks(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Set the amount of Stream Padding
+ *
+ * Set the amount of Stream Padding of the last (and typically the only)
+ * Stream in the lzma_index. This is needed when planning to do random-access
+ * reading within multiple concatenated Streams.
+ *
+ * By default, the amount of Stream Padding is assumed to be zero bytes.
+ *
+ * \return - LZMA_OK
+ * - LZMA_DATA_ERROR: The file size would grow too big.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_stream_padding(
+ lzma_index *i, lzma_vli stream_padding)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Get the number of Streams
+ */
+extern LZMA_API(lzma_vli) lzma_index_stream_count(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the number of Blocks
+ *
+ * This returns the total number of Blocks in lzma_index. To get number
+ * of Blocks in individual Streams, use lzma_index_iter.
+ */
+extern LZMA_API(lzma_vli) lzma_index_block_count(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the size of the Index field as bytes
+ *
+ * This is needed to verify the Backward Size field in the Stream Footer.
+ */
+extern LZMA_API(lzma_vli) lzma_index_size(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the total size of the Stream
+ *
+ * If multiple lzma_indexes have been combined, this works as if the Blocks
+ * were in a single Stream. This is useful if you are going to combine
+ * Blocks from multiple Streams into a single new Stream.
+ */
+extern LZMA_API(lzma_vli) lzma_index_stream_size(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the total size of the Blocks
+ *
+ * This doesn't include the Stream Header, Stream Footer, Stream Padding,
+ * or Index fields.
+ */
+extern LZMA_API(lzma_vli) lzma_index_total_size(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the total size of the file
+ *
+ * When no lzma_indexes have been combined with lzma_index_cat() and there is
+ * no Stream Padding, this function is identical to lzma_index_stream_size().
+ * If multiple lzma_indexes have been combined, this includes also the headers
+ * of each separate Stream and the possible Stream Padding fields.
+ */
+extern LZMA_API(lzma_vli) lzma_index_file_size(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Get the uncompressed size of the file
+ */
+extern LZMA_API(lzma_vli) lzma_index_uncompressed_size(const lzma_index *i)
+ lzma_nothrow lzma_attr_pure;
+
+
+/**
+ * \brief Initialize an iterator
+ *
+ * \param iter Pointer to a lzma_index_iter structure
+ * \param i lzma_index to which the iterator will be associated
+ *
+ * This function associates the iterator with the given lzma_index, and calls
+ * lzma_index_iter_rewind() on the iterator.
+ *
+ * This function doesn't allocate any memory, thus there is no
+ * lzma_index_iter_end(). The iterator is valid as long as the
+ * associated lzma_index is valid, that is, until lzma_index_end() or
+ * using it as source in lzma_index_cat(). Specifically, lzma_index doesn't
+ * become invalid if new Blocks are added to it with lzma_index_append() or
+ * if it is used as the destination in lzma_index_cat().
+ *
+ * It is safe to make copies of an initialized lzma_index_iter, for example,
+ * to easily restart reading at some particular position.
+ */
+extern LZMA_API(void) lzma_index_iter_init(
+ lzma_index_iter *iter, const lzma_index *i) lzma_nothrow;
+
+
+/**
+ * \brief Rewind the iterator
+ *
+ * Rewind the iterator so that next call to lzma_index_iter_next() will
+ * return the first Block or Stream.
+ */
+extern LZMA_API(void) lzma_index_iter_rewind(lzma_index_iter *iter)
+ lzma_nothrow;
+
+
+/**
+ * \brief Get the next Block or Stream
+ *
+ * \param iter Iterator initialized with lzma_index_iter_init()
+ * \param mode Specify what kind of information the caller wants
+ * to get. See lzma_index_iter_mode for details.
+ *
+ * \return If next Block or Stream matching the mode was found, *iter
+ * is updated and this function returns false. If no Block or
+ * Stream matching the mode is found, *iter is not modified
+ * and this function returns true. If mode is set to an unknown
+ * value, *iter is not modified and this function returns true.
+ */
+extern LZMA_API(lzma_bool) lzma_index_iter_next(
+ lzma_index_iter *iter, lzma_index_iter_mode mode)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Locate a Block
+ *
+ * If it is possible to seek in the .xz file, it is possible to parse
+ * the Index field(s) and use lzma_index_iter_locate() to do random-access
+ * reading with granularity of Block size.
+ *
+ * \param iter Iterator that was earlier initialized with
+ * lzma_index_iter_init().
+ * \param target Uncompressed target offset which the caller would
+ * like to locate from the Stream
+ *
+ * If the target is smaller than the uncompressed size of the Stream (can be
+ * checked with lzma_index_uncompressed_size()):
+ * - Information about the Stream and Block containing the requested
+ * uncompressed offset is stored into *iter.
+ * - Internal state of the iterator is adjusted so that
+ * lzma_index_iter_next() can be used to read subsequent Blocks or Streams.
+ * - This function returns false.
+ *
+ * If target is greater than the uncompressed size of the Stream, *iter
+ * is not modified, and this function returns true.
+ */
+extern LZMA_API(lzma_bool) lzma_index_iter_locate(
+ lzma_index_iter *iter, lzma_vli target) lzma_nothrow;
+
+
+/**
+ * \brief Concatenate lzma_indexes
+ *
+ * Concatenating lzma_indexes is useful when doing random-access reading in
+ * multi-Stream .xz file, or when combining multiple Streams into single
+ * Stream.
+ *
+ * \param dest lzma_index after which src is appended
+ * \param src lzma_index to be appended after dest. If this
+ * function succeeds, the memory allocated for src
+ * is freed or moved to be part of dest, and all
+ * iterators pointing to src will become invalid.
+ * \param allocator Custom memory allocator; can be NULL to use
+ * malloc() and free().
+ *
+ * \return - LZMA_OK: lzma_indexes were concatenated successfully.
+ * src is now a dangling pointer.
+ * - LZMA_DATA_ERROR: *dest would grow too big.
+ * - LZMA_MEM_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_cat(
+ lzma_index *dest, lzma_index *src, lzma_allocator *allocator)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Duplicate lzma_index
+ *
+ * \return A copy of the lzma_index, or NULL if memory allocation failed.
+ */
+extern LZMA_API(lzma_index *) lzma_index_dup(
+ const lzma_index *i, lzma_allocator *allocator)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize .xz Index encoder
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param i Pointer to lzma_index which should be encoded.
+ *
+ * The valid `action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * It is enough to use only one of them (you can choose freely; use LZMA_RUN
+ * to support liblzma versions older than 5.0.0).
+ *
+ * \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
+ * - LZMA_MEM_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_encoder(
+ lzma_stream *strm, const lzma_index *i)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Initialize .xz Index decoder
+ *
+ * \param strm Pointer to properly prepared lzma_stream
+ * \param i The decoded Index will be made available via
+ * this pointer. Initially this function will
+ * set *i to NULL (the old value is ignored). If
+ * decoding succeeds (lzma_code() returns
+ * LZMA_STREAM_END), *i will be set to point
+ * to a new lzma_index, which the application
+ * has to later free with lzma_index_end().
+ * \param memlimit How much memory the resulting lzma_index is
+ * allowed to require.
+ *
+ * The valid `action' values for lzma_code() are LZMA_RUN and LZMA_FINISH.
+ * It is enough to use only one of them (you can choose freely; use LZMA_RUN
+ * to support liblzma versions older than 5.0.0).
+ *
+ * \return - LZMA_OK: Initialization succeeded, continue with lzma_code().
+ * - LZMA_MEM_ERROR
+ * - LZMA_MEMLIMIT_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_decoder(
+ lzma_stream *strm, lzma_index **i, uint64_t memlimit)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Single-call .xz Index encoder
+ *
+ * \param i lzma_index to be encoded
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * *out_pos is updated only if encoding succeeds.
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_BUF_ERROR: Output buffer is too small. Use
+ * lzma_index_size() to find out how much output
+ * space is needed.
+ * - LZMA_PROG_ERROR
+ *
+ * \note This function doesn't take allocator argument since all
+ * the internal data is allocated on stack.
+ */
+extern LZMA_API(lzma_ret) lzma_index_buffer_encode(const lzma_index *i,
+ uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief Single-call .xz Index decoder
+ *
+ * \param i If decoding succeeds, *i will point to a new
+ * lzma_index, which the application has to
+ * later free with lzma_index_end(). If an error
+ * occurs, *i will be NULL. The old value of *i
+ * is always ignored and thus doesn't need to be
+ * initialized by the caller.
+ * \param memlimit Pointer to how much memory the resulting
+ * lzma_index is allowed to require. The value
+ * pointed by this pointer is modified if and only
+ * if LZMA_MEMLIMIT_ERROR is returned.
+ * \param allocator Pointer to lzma_allocator, or NULL to use malloc()
+ * \param in Beginning of the input buffer
+ * \param in_pos The next byte will be read from in[*in_pos].
+ * *in_pos is updated only if decoding succeeds.
+ * \param in_size Size of the input buffer; the first byte that
+ * won't be read is in[in_size].
+ *
+ * \return - LZMA_OK: Decoding was successful.
+ * - LZMA_MEM_ERROR
+ * - LZMA_MEMLIMIT_ERROR: Memory usage limit was reached.
+ * The minimum required memlimit value was stored to *memlimit.
+ * - LZMA_DATA_ERROR
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_buffer_decode(lzma_index **i,
+ uint64_t *memlimit, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+ lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/index_hash.h b/Utilities/cmliblzma/liblzma/api/lzma/index_hash.h
new file mode 100644
index 000000000..fa2e048d5
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/index_hash.h
@@ -0,0 +1,107 @@
+/**
+ * \file lzma/index_hash.h
+ * \brief Validate Index by using a hash function
+ *
+ * Hashing makes it possible to use constant amount of memory to validate
+ * Index of arbitrary size.
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+/**
+ * \brief Opaque data type to hold the Index hash
+ */
+typedef struct lzma_index_hash_s lzma_index_hash;
+
+
+/**
+ * \brief Allocate and initialize a new lzma_index_hash structure
+ *
+ * If index_hash is NULL, a new lzma_index_hash structure is allocated,
+ * initialized, and a pointer to it returned. If allocation fails, NULL
+ * is returned.
+ *
+ * If index_hash is non-NULL, it is reinitialized and the same pointer
+ * returned. In this case, return value cannot be NULL or a different
+ * pointer than the index_hash that was given as an argument.
+ */
+extern LZMA_API(lzma_index_hash *) lzma_index_hash_init(
+ lzma_index_hash *index_hash, lzma_allocator *allocator)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Deallocate lzma_index_hash structure
+ */
+extern LZMA_API(void) lzma_index_hash_end(
+ lzma_index_hash *index_hash, lzma_allocator *allocator)
+ lzma_nothrow;
+
+
+/**
+ * \brief Add a new Record to an Index hash
+ *
+ * \param index Pointer to a lzma_index_hash structure
+ * \param unpadded_size Unpadded Size of a Block
+ * \param uncompressed_size Uncompressed Size of a Block
+ *
+ * \return - LZMA_OK
+ * - LZMA_DATA_ERROR: Compressed or uncompressed size of the
+ * Stream or size of the Index field would grow too big.
+ * - LZMA_PROG_ERROR: Invalid arguments or this function is being
+ * used when lzma_index_hash_decode() has already been used.
+ */
+extern LZMA_API(lzma_ret) lzma_index_hash_append(lzma_index_hash *index_hash,
+ lzma_vli unpadded_size, lzma_vli uncompressed_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode and validate the Index field
+ *
+ * After telling the sizes of all Blocks with lzma_index_hash_append(),
+ * the actual Index field is decoded with this function. Specifically,
+ * once decoding of the Index field has been started, no more Records
+ * can be added using lzma_index_hash_append().
+ *
+ * This function doesn't use lzma_stream structure to pass the input data.
+ * Instead, the input buffer is specified using three arguments. This is
+ * because it matches better the internal APIs of liblzma.
+ *
+ * \param index_hash Pointer to a lzma_index_hash structure
+ * \param in Pointer to the beginning of the input buffer
+ * \param in_pos in[*in_pos] is the next byte to process
+ * \param in_size in[in_size] is the first byte not to process
+ *
+ * \return - LZMA_OK: So far good, but more input is needed.
+ * - LZMA_STREAM_END: Index decoded successfully and it matches
+ * the Records given with lzma_index_hash_append().
+ * - LZMA_DATA_ERROR: Index is corrupt or doesn't match the
+ * information given with lzma_index_hash_append().
+ * - LZMA_BUF_ERROR: Cannot progress because *in_pos >= in_size.
+ * - LZMA_PROG_ERROR
+ */
+extern LZMA_API(lzma_ret) lzma_index_hash_decode(lzma_index_hash *index_hash,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Get the size of the Index field as bytes
+ *
+ * This is needed to verify the Backward Size field in the Stream Footer.
+ */
+extern LZMA_API(lzma_vli) lzma_index_hash_size(
+ const lzma_index_hash *index_hash)
+ lzma_nothrow lzma_attr_pure;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/lzma.h b/Utilities/cmliblzma/liblzma/api/lzma/lzma.h
new file mode 100644
index 000000000..3f8e095f7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/lzma.h
@@ -0,0 +1,420 @@
+/**
+ * \file lzma/lzma.h
+ * \brief LZMA1 and LZMA2 filters
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief LZMA1 Filter ID
+ *
+ * LZMA1 is the very same thing as what was called just LZMA in LZMA Utils,
+ * 7-Zip, and LZMA SDK. It's called LZMA1 here to prevent developers from
+ * accidentally using LZMA when they actually want LZMA2.
+ *
+ * LZMA1 shouldn't be used for new applications unless you _really_ know
+ * what you are doing. LZMA2 is almost always a better choice.
+ */
+#define LZMA_FILTER_LZMA1 LZMA_VLI_C(0x4000000000000001)
+
+/**
+ * \brief LZMA2 Filter ID
+ *
+ * Usually you want this instead of LZMA1. Compared to LZMA1, LZMA2 adds
+ * support for LZMA_SYNC_FLUSH, uncompressed chunks (smaller expansion
+ * when trying to compress uncompressible data), possibility to change
+ * lc/lp/pb in the middle of encoding, and some other internal improvements.
+ */
+#define LZMA_FILTER_LZMA2 LZMA_VLI_C(0x21)
+
+
+/**
+ * \brief Match finders
+ *
+ * Match finder has major effect on both speed and compression ratio.
+ * Usually hash chains are faster than binary trees.
+ *
+ * If you will use LZMA_SYNC_FLUSH often, the hash chains may be a better
+ * choice, because binary trees get much higher compression ratio penalty
+ * with LZMA_SYNC_FLUSH.
+ *
+ * The memory usage formulas are only rough estimates, which are closest to
+ * reality when dict_size is a power of two. The formulas are more complex
+ * in reality, and can also change a little between liblzma versions. Use
+ * lzma_raw_encoder_memusage() to get more accurate estimate of memory usage.
+ */
+typedef enum {
+ LZMA_MF_HC3 = 0x03,
+ /**<
+ * \brief Hash Chain with 2- and 3-byte hashing
+ *
+ * Minimum nice_len: 3
+ *
+ * Memory usage:
+ * - dict_size <= 16 MiB: dict_size * 7.5
+ * - dict_size > 16 MiB: dict_size * 5.5 + 64 MiB
+ */
+
+ LZMA_MF_HC4 = 0x04,
+ /**<
+ * \brief Hash Chain with 2-, 3-, and 4-byte hashing
+ *
+ * Minimum nice_len: 4
+ *
+ * Memory usage:
+ * - dict_size <= 32 MiB: dict_size * 7.5
+ * - dict_size > 32 MiB: dict_size * 6.5
+ */
+
+ LZMA_MF_BT2 = 0x12,
+ /**<
+ * \brief Binary Tree with 2-byte hashing
+ *
+ * Minimum nice_len: 2
+ *
+ * Memory usage: dict_size * 9.5
+ */
+
+ LZMA_MF_BT3 = 0x13,
+ /**<
+ * \brief Binary Tree with 2- and 3-byte hashing
+ *
+ * Minimum nice_len: 3
+ *
+ * Memory usage:
+ * - dict_size <= 16 MiB: dict_size * 11.5
+ * - dict_size > 16 MiB: dict_size * 9.5 + 64 MiB
+ */
+
+ LZMA_MF_BT4 = 0x14
+ /**<
+ * \brief Binary Tree with 2-, 3-, and 4-byte hashing
+ *
+ * Minimum nice_len: 4
+ *
+ * Memory usage:
+ * - dict_size <= 32 MiB: dict_size * 11.5
+ * - dict_size > 32 MiB: dict_size * 10.5
+ */
+} lzma_match_finder;
+
+
+/**
+ * \brief Test if given match finder is supported
+ *
+ * Return true if the given match finder is supported by this liblzma build.
+ * Otherwise false is returned. It is safe to call this with a value that
+ * isn't listed in lzma_match_finder enumeration; the return value will be
+ * false.
+ *
+ * There is no way to list which match finders are available in this
+ * particular liblzma version and build. It would be useless, because
+ * a new match finder, which the application developer wasn't aware,
+ * could require giving additional options to the encoder that the older
+ * match finders don't need.
+ */
+extern LZMA_API(lzma_bool) lzma_mf_is_supported(lzma_match_finder match_finder)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Compression modes
+ *
+ * This selects the function used to analyze the data produced by the match
+ * finder.
+ */
+typedef enum {
+ LZMA_MODE_FAST = 1,
+ /**<
+ * \brief Fast compression
+ *
+ * Fast mode is usually at its best when combined with
+ * a hash chain match finder.
+ */
+
+ LZMA_MODE_NORMAL = 2
+ /**<
+ * \brief Normal compression
+ *
+ * This is usually notably slower than fast mode. Use this
+ * together with binary tree match finders to expose the
+ * full potential of the LZMA1 or LZMA2 encoder.
+ */
+} lzma_mode;
+
+
+/**
+ * \brief Test if given compression mode is supported
+ *
+ * Return true if the given compression mode is supported by this liblzma
+ * build. Otherwise false is returned. It is safe to call this with a value
+ * that isn't listed in lzma_mode enumeration; the return value will be false.
+ *
+ * There is no way to list which modes are available in this particular
+ * liblzma version and build. It would be useless, because a new compression
+ * mode, which the application developer wasn't aware, could require giving
+ * additional options to the encoder that the older modes don't need.
+ */
+extern LZMA_API(lzma_bool) lzma_mode_is_supported(lzma_mode mode)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Options specific to the LZMA1 and LZMA2 filters
+ *
+ * Since LZMA1 and LZMA2 share most of the code, it's simplest to share
+ * the options structure too. For encoding, all but the reserved variables
+ * need to be initialized unless specifically mentioned otherwise.
+ * lzma_lzma_preset() can be used to get a good starting point.
+ *
+ * For raw decoding, both LZMA1 and LZMA2 need dict_size, preset_dict, and
+ * preset_dict_size (if preset_dict != NULL). LZMA1 needs also lc, lp, and pb.
+ */
+typedef struct {
+ /**
+ * \brief Dictionary size in bytes
+ *
+ * Dictionary size indicates how many bytes of the recently processed
+ * uncompressed data is kept in memory. One method to reduce size of
+ * the uncompressed data is to store distance-length pairs, which
+ * indicate what data to repeat from the dictionary buffer. Thus,
+ * the bigger the dictionary, the better the compression ratio
+ * usually is.
+ *
+ * Maximum size of the dictionary depends on multiple things:
+ * - Memory usage limit
+ * - Available address space (not a problem on 64-bit systems)
+ * - Selected match finder (encoder only)
+ *
+ * Currently the maximum dictionary size for encoding is 1.5 GiB
+ * (i.e. (UINT32_C(1) << 30) + (UINT32_C(1) << 29)) even on 64-bit
+ * systems for certain match finder implementation reasons. In the
+ * future, there may be match finders that support bigger
+ * dictionaries.
+ *
+ * Decoder already supports dictionaries up to 4 GiB - 1 B (i.e.
+ * UINT32_MAX), so increasing the maximum dictionary size of the
+ * encoder won't cause problems for old decoders.
+ *
+ * Because extremely small dictionaries sizes would have unneeded
+ * overhead in the decoder, the minimum dictionary size is 4096 bytes.
+ *
+ * \note When decoding, too big dictionary does no other harm
+ * than wasting memory.
+ */
+ uint32_t dict_size;
+# define LZMA_DICT_SIZE_MIN UINT32_C(4096)
+# define LZMA_DICT_SIZE_DEFAULT (UINT32_C(1) << 23)
+
+ /**
+ * \brief Pointer to an initial dictionary
+ *
+ * It is possible to initialize the LZ77 history window using
+ * a preset dictionary. It is useful when compressing many
+ * similar, relatively small chunks of data independently from
+ * each other. The preset dictionary should contain typical
+ * strings that occur in the files being compressed. The most
+ * probable strings should be near the end of the preset dictionary.
+ *
+ * This feature should be used only in special situations. For
+ * now, it works correctly only with raw encoding and decoding.
+ * Currently none of the container formats supported by
+ * liblzma allow preset dictionary when decoding, thus if
+ * you create a .xz or .lzma file with preset dictionary, it
+ * cannot be decoded with the regular decoder functions. In the
+ * future, the .xz format will likely get support for preset
+ * dictionary though.
+ */
+ const uint8_t *preset_dict;
+
+ /**
+ * \brief Size of the preset dictionary
+ *
+ * Specifies the size of the preset dictionary. If the size is
+ * bigger than dict_size, only the last dict_size bytes are
+ * processed.
+ *
+ * This variable is read only when preset_dict is not NULL.
+ * If preset_dict is not NULL but preset_dict_size is zero,
+ * no preset dictionary is used (identical to only setting
+ * preset_dict to NULL).
+ */
+ uint32_t preset_dict_size;
+
+ /**
+ * \brief Number of literal context bits
+ *
+ * How many of the highest bits of the previous uncompressed
+ * eight-bit byte (also known as `literal') are taken into
+ * account when predicting the bits of the next literal.
+ *
+ * E.g. in typical English text, an upper-case letter is
+ * often followed by a lower-case letter, and a lower-case
+ * letter is usually followed by another lower-case letter.
+ * In the US-ASCII character set, the highest three bits are 010
+ * for upper-case letters and 011 for lower-case letters.
+ * When lc is at least 3, the literal coding can take advantage of
+ * this property in the uncompressed data.
+ *
+ * There is a limit that applies to literal context bits and literal
+ * position bits together: lc + lp <= 4. Without this limit the
+ * decoding could become very slow, which could have security related
+ * results in some cases like email servers doing virus scanning.
+ * This limit also simplifies the internal implementation in liblzma.
+ *
+ * There may be LZMA1 streams that have lc + lp > 4 (maximum possible
+ * lc would be 8). It is not possible to decode such streams with
+ * liblzma.
+ */
+ uint32_t lc;
+# define LZMA_LCLP_MIN 0
+# define LZMA_LCLP_MAX 4
+# define LZMA_LC_DEFAULT 3
+
+ /**
+ * \brief Number of literal position bits
+ *
+ * lp affects what kind of alignment in the uncompressed data is
+ * assumed when encoding literals. A literal is a single 8-bit byte.
+ * See pb below for more information about alignment.
+ */
+ uint32_t lp;
+# define LZMA_LP_DEFAULT 0
+
+ /**
+ * \brief Number of position bits
+ *
+ * pb affects what kind of alignment in the uncompressed data is
+ * assumed in general. The default means four-byte alignment
+ * (2^ pb =2^2=4), which is often a good choice when there's
+ * no better guess.
+ *
+ * When the aligment is known, setting pb accordingly may reduce
+ * the file size a little. E.g. with text files having one-byte
+ * alignment (US-ASCII, ISO-8859-*, UTF-8), setting pb=0 can
+ * improve compression slightly. For UTF-16 text, pb=1 is a good
+ * choice. If the alignment is an odd number like 3 bytes, pb=0
+ * might be the best choice.
+ *
+ * Even though the assumed alignment can be adjusted with pb and
+ * lp, LZMA1 and LZMA2 still slightly favor 16-byte alignment.
+ * It might be worth taking into account when designing file formats
+ * that are likely to be often compressed with LZMA1 or LZMA2.
+ */
+ uint32_t pb;
+# define LZMA_PB_MIN 0
+# define LZMA_PB_MAX 4
+# define LZMA_PB_DEFAULT 2
+
+ /** Compression mode */
+ lzma_mode mode;
+
+ /**
+ * \brief Nice length of a match
+ *
+ * This determines how many bytes the encoder compares from the match
+ * candidates when looking for the best match. Once a match of at
+ * least nice_len bytes long is found, the encoder stops looking for
+ * better candidates and encodes the match. (Naturally, if the found
+ * match is actually longer than nice_len, the actual length is
+ * encoded; it's not truncated to nice_len.)
+ *
+ * Bigger values usually increase the compression ratio and
+ * compression time. For most files, 32 to 128 is a good value,
+ * which gives very good compression ratio at good speed.
+ *
+ * The exact minimum value depends on the match finder. The maximum
+ * is 273, which is the maximum length of a match that LZMA1 and
+ * LZMA2 can encode.
+ */
+ uint32_t nice_len;
+
+ /** Match finder ID */
+ lzma_match_finder mf;
+
+ /**
+ * \brief Maximum search depth in the match finder
+ *
+ * For every input byte, match finder searches through the hash chain
+ * or binary tree in a loop, each iteration going one step deeper in
+ * the chain or tree. The searching stops if
+ * - a match of at least nice_len bytes long is found;
+ * - all match candidates from the hash chain or binary tree have
+ * been checked; or
+ * - maximum search depth is reached.
+ *
+ * Maximum search depth is needed to prevent the match finder from
+ * wasting too much time in case there are lots of short match
+ * candidates. On the other hand, stopping the search before all
+ * candidates have been checked can reduce compression ratio.
+ *
+ * Setting depth to zero tells liblzma to use an automatic default
+ * value, that depends on the selected match finder and nice_len.
+ * The default is in the range [4, 200] or so (it may vary between
+ * liblzma versions).
+ *
+ * Using a bigger depth value than the default can increase
+ * compression ratio in some cases. There is no strict maximum value,
+ * but high values (thousands or millions) should be used with care:
+ * the encoder could remain fast enough with typical input, but
+ * malicious input could cause the match finder to slow down
+ * dramatically, possibly creating a denial of service attack.
+ */
+ uint32_t depth;
+
+ /*
+ * Reserved space to allow possible future extensions without
+ * breaking the ABI. You should not touch these, because the names
+ * of these variables may change. These are and will never be used
+ * with the currently supported options, so it is safe to leave these
+ * uninitialized.
+ */
+ uint32_t reserved_int1;
+ uint32_t reserved_int2;
+ uint32_t reserved_int3;
+ uint32_t reserved_int4;
+ uint32_t reserved_int5;
+ uint32_t reserved_int6;
+ uint32_t reserved_int7;
+ uint32_t reserved_int8;
+ lzma_reserved_enum reserved_enum1;
+ lzma_reserved_enum reserved_enum2;
+ lzma_reserved_enum reserved_enum3;
+ lzma_reserved_enum reserved_enum4;
+ void *reserved_ptr1;
+ void *reserved_ptr2;
+
+} lzma_options_lzma;
+
+
+/**
+ * \brief Set a compression preset to lzma_options_lzma structure
+ *
+ * 0 is the fastest and 9 is the slowest. These match the switches -0 .. -9
+ * of the xz command line tool. In addition, it is possible to bitwise-or
+ * flags to the preset. Currently only LZMA_PRESET_EXTREME is supported.
+ * The flags are defined in container.h, because the flags are used also
+ * with lzma_easy_encoder().
+ *
+ * The preset values are subject to changes between liblzma versions.
+ *
+ * This function is available only if LZMA1 or LZMA2 encoder has been enabled
+ * when building liblzma.
+ *
+ * \return On success, false is returned. If the preset is not
+ * supported, true is returned.
+ */
+extern LZMA_API(lzma_bool) lzma_lzma_preset(
+ lzma_options_lzma *options, uint32_t preset) lzma_nothrow;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/stream_flags.h b/Utilities/cmliblzma/liblzma/api/lzma/stream_flags.h
new file mode 100644
index 000000000..bbdd40826
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/stream_flags.h
@@ -0,0 +1,223 @@
+/**
+ * \file lzma/stream_flags.h
+ * \brief .xz Stream Header and Stream Footer encoder and decoder
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Size of Stream Header and Stream Footer
+ *
+ * Stream Header and Stream Footer have the same size and they are not
+ * going to change even if a newer version of the .xz file format is
+ * developed in future.
+ */
+#define LZMA_STREAM_HEADER_SIZE 12
+
+
+/**
+ * \brief Options for encoding/decoding Stream Header and Stream Footer
+ */
+typedef struct {
+ /**
+ * \brief Stream Flags format version
+ *
+ * To prevent API and ABI breakages if new features are needed in
+ * Stream Header or Stream Footer, a version number is used to
+ * indicate which fields in this structure are in use. For now,
+ * version must always be zero. With non-zero version, the
+ * lzma_stream_header_encode() and lzma_stream_footer_encode()
+ * will return LZMA_OPTIONS_ERROR.
+ *
+ * lzma_stream_header_decode() and lzma_stream_footer_decode()
+ * will always set this to the lowest value that supports all the
+ * features indicated by the Stream Flags field. The application
+ * must check that the version number set by the decoding functions
+ * is supported by the application. Otherwise it is possible that
+ * the application will decode the Stream incorrectly.
+ */
+ uint32_t version;
+
+ /**
+ * \brief Backward Size
+ *
+ * Backward Size must be a multiple of four bytes. In this Stream
+ * format version, Backward Size is the size of the Index field.
+ *
+ * Backward Size isn't actually part of the Stream Flags field, but
+ * it is convenient to include in this structure anyway. Backward
+ * Size is present only in the Stream Footer. There is no need to
+ * initialize backward_size when encoding Stream Header.
+ *
+ * lzma_stream_header_decode() always sets backward_size to
+ * LZMA_VLI_UNKNOWN so that it is convenient to use
+ * lzma_stream_flags_compare() when both Stream Header and Stream
+ * Footer have been decoded.
+ */
+ lzma_vli backward_size;
+# define LZMA_BACKWARD_SIZE_MIN 4
+# define LZMA_BACKWARD_SIZE_MAX (LZMA_VLI_C(1) << 34)
+
+ /**
+ * \brief Check ID
+ *
+ * This indicates the type of the integrity check calculated from
+ * uncompressed data.
+ */
+ lzma_check check;
+
+ /*
+ * Reserved space to allow possible future extensions without
+ * breaking the ABI. You should not touch these, because the
+ * names of these variables may change.
+ *
+ * (We will never be able to use all of these since Stream Flags
+ * is just two bytes plus Backward Size of four bytes. But it's
+ * nice to have the proper types when they are needed.)
+ */
+ lzma_reserved_enum reserved_enum1;
+ lzma_reserved_enum reserved_enum2;
+ lzma_reserved_enum reserved_enum3;
+ lzma_reserved_enum reserved_enum4;
+ lzma_bool reserved_bool1;
+ lzma_bool reserved_bool2;
+ lzma_bool reserved_bool3;
+ lzma_bool reserved_bool4;
+ lzma_bool reserved_bool5;
+ lzma_bool reserved_bool6;
+ lzma_bool reserved_bool7;
+ lzma_bool reserved_bool8;
+ uint32_t reserved_int1;
+ uint32_t reserved_int2;
+
+} lzma_stream_flags;
+
+
+/**
+ * \brief Encode Stream Header
+ *
+ * \param options Stream Header options to be encoded.
+ * options->backward_size is ignored and doesn't
+ * need to be initialized.
+ * \param out Beginning of the output buffer of
+ * LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_OPTIONS_ERROR: options->version is not supported by
+ * this liblzma version.
+ * - LZMA_PROG_ERROR: Invalid options.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_header_encode(
+ const lzma_stream_flags *options, uint8_t *out)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Encode Stream Footer
+ *
+ * \param options Stream Footer options to be encoded.
+ * \param out Beginning of the output buffer of
+ * LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return - LZMA_OK: Encoding was successful.
+ * - LZMA_OPTIONS_ERROR: options->version is not supported by
+ * this liblzma version.
+ * - LZMA_PROG_ERROR: Invalid options.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_footer_encode(
+ const lzma_stream_flags *options, uint8_t *out)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode Stream Header
+ *
+ * \param options Target for the decoded Stream Header options.
+ * \param in Beginning of the input buffer of
+ * LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * options->backward_size is always set to LZMA_VLI_UNKNOWN. This is to
+ * help comparing Stream Flags from Stream Header and Stream Footer with
+ * lzma_stream_flags_compare().
+ *
+ * \return - LZMA_OK: Decoding was successful.
+ * - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
+ * buffer cannot be Stream Header.
+ * - LZMA_DATA_ERROR: CRC32 doesn't match, thus the header
+ * is corrupt.
+ * - LZMA_OPTIONS_ERROR: Unsupported options are present
+ * in the header.
+ *
+ * \note When decoding .xz files that contain multiple Streams, it may
+ * make sense to print "file format not recognized" only if
+ * decoding of the Stream Header of the _first_ Stream gives
+ * LZMA_FORMAT_ERROR. If non-first Stream Header gives
+ * LZMA_FORMAT_ERROR, the message used for LZMA_DATA_ERROR is
+ * probably more appropriate.
+ *
+ * For example, Stream decoder in liblzma uses LZMA_DATA_ERROR if
+ * LZMA_FORMAT_ERROR is returned by lzma_stream_header_decode()
+ * when decoding non-first Stream.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_header_decode(
+ lzma_stream_flags *options, const uint8_t *in)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Decode Stream Footer
+ *
+ * \param options Target for the decoded Stream Header options.
+ * \param in Beginning of the input buffer of
+ * LZMA_STREAM_HEADER_SIZE bytes.
+ *
+ * \return - LZMA_OK: Decoding was successful.
+ * - LZMA_FORMAT_ERROR: Magic bytes don't match, thus the given
+ * buffer cannot be Stream Footer.
+ * - LZMA_DATA_ERROR: CRC32 doesn't match, thus the Stream Footer
+ * is corrupt.
+ * - LZMA_OPTIONS_ERROR: Unsupported options are present
+ * in Stream Footer.
+ *
+ * \note If Stream Header was already decoded successfully, but
+ * decoding Stream Footer returns LZMA_FORMAT_ERROR, the
+ * application should probably report some other error message
+ * than "file format not recognized", since the file more likely
+ * is corrupt (possibly truncated). Stream decoder in liblzma
+ * uses LZMA_DATA_ERROR in this situation.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_footer_decode(
+ lzma_stream_flags *options, const uint8_t *in)
+ lzma_nothrow lzma_attr_warn_unused_result;
+
+
+/**
+ * \brief Compare two lzma_stream_flags structures
+ *
+ * backward_size values are compared only if both are not
+ * LZMA_VLI_UNKNOWN.
+ *
+ * \return - LZMA_OK: Both are equal. If either had backward_size set
+ * to LZMA_VLI_UNKNOWN, backward_size values were not
+ * compared or validated.
+ * - LZMA_DATA_ERROR: The structures differ.
+ * - LZMA_OPTIONS_ERROR: version in either structure is greater
+ * than the maximum supported version (currently zero).
+ * - LZMA_PROG_ERROR: Invalid value, e.g. invalid check or
+ * backward_size.
+ */
+extern LZMA_API(lzma_ret) lzma_stream_flags_compare(
+ const lzma_stream_flags *a, const lzma_stream_flags *b)
+ lzma_nothrow lzma_attr_pure;
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/version.h b/Utilities/cmliblzma/liblzma/api/lzma/version.h
new file mode 100644
index 000000000..09866b982
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/version.h
@@ -0,0 +1,121 @@
+/**
+ * \file lzma/version.h
+ * \brief Version number
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/*
+ * Version number split into components
+ */
+#define LZMA_VERSION_MAJOR 5
+#define LZMA_VERSION_MINOR 0
+#define LZMA_VERSION_PATCH 8
+#define LZMA_VERSION_STABILITY LZMA_VERSION_STABILITY_STABLE
+
+#ifndef LZMA_VERSION_COMMIT
+# define LZMA_VERSION_COMMIT ""
+#endif
+
+
+/*
+ * Map symbolic stability levels to integers.
+ */
+#define LZMA_VERSION_STABILITY_ALPHA 0
+#define LZMA_VERSION_STABILITY_BETA 1
+#define LZMA_VERSION_STABILITY_STABLE 2
+
+
+/**
+ * \brief Compile-time version number
+ *
+ * The version number is of format xyyyzzzs where
+ * - x = major
+ * - yyy = minor
+ * - zzz = revision
+ * - s indicates stability: 0 = alpha, 1 = beta, 2 = stable
+ *
+ * The same xyyyzzz triplet is never reused with different stability levels.
+ * For example, if 5.1.0alpha has been released, there will never be 5.1.0beta
+ * or 5.1.0 stable.
+ *
+ * \note The version number of liblzma has nothing to with
+ * the version number of Igor Pavlov's LZMA SDK.
+ */
+#define LZMA_VERSION (LZMA_VERSION_MAJOR * UINT32_C(10000000) \
+ + LZMA_VERSION_MINOR * UINT32_C(10000) \
+ + LZMA_VERSION_PATCH * UINT32_C(10) \
+ + LZMA_VERSION_STABILITY)
+
+
+/*
+ * Macros to construct the compile-time version string
+ */
+#if LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_ALPHA
+# define LZMA_VERSION_STABILITY_STRING "alpha"
+#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_BETA
+# define LZMA_VERSION_STABILITY_STRING "beta"
+#elif LZMA_VERSION_STABILITY == LZMA_VERSION_STABILITY_STABLE
+# define LZMA_VERSION_STABILITY_STRING ""
+#else
+# error Incorrect LZMA_VERSION_STABILITY
+#endif
+
+#define LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit) \
+ #major "." #minor "." #patch stability commit
+
+#define LZMA_VERSION_STRING_C(major, minor, patch, stability, commit) \
+ LZMA_VERSION_STRING_C_(major, minor, patch, stability, commit)
+
+
+/**
+ * \brief Compile-time version as a string
+ *
+ * This can be for example "4.999.5alpha", "4.999.8beta", or "5.0.0" (stable
+ * versions don't have any "stable" suffix). In future, a snapshot built
+ * from source code repository may include an additional suffix, for example
+ * "4.999.8beta-21-g1d92". The commit ID won't be available in numeric form
+ * in LZMA_VERSION macro.
+ */
+#define LZMA_VERSION_STRING LZMA_VERSION_STRING_C( \
+ LZMA_VERSION_MAJOR, LZMA_VERSION_MINOR, \
+ LZMA_VERSION_PATCH, LZMA_VERSION_STABILITY_STRING, \
+ LZMA_VERSION_COMMIT)
+
+
+/* #ifndef is needed for use with windres (MinGW or Cygwin). */
+#ifndef LZMA_H_INTERNAL_RC
+
+/**
+ * \brief Run-time version number as an integer
+ *
+ * Return the value of LZMA_VERSION macro at the compile time of liblzma.
+ * This allows the application to compare if it was built against the same,
+ * older, or newer version of liblzma that is currently running.
+ */
+extern LZMA_API(uint32_t) lzma_version_number(void)
+ lzma_nothrow lzma_attr_const;
+
+
+/**
+ * \brief Run-time version as a string
+ *
+ * This function may be useful if you want to display which version of
+ * liblzma your application is currently using.
+ */
+extern LZMA_API(const char *) lzma_version_string(void)
+ lzma_nothrow lzma_attr_const;
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/api/lzma/vli.h b/Utilities/cmliblzma/liblzma/api/lzma/vli.h
new file mode 100644
index 000000000..9ad13f2e2
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/api/lzma/vli.h
@@ -0,0 +1,166 @@
+/**
+ * \file lzma/vli.h
+ * \brief Variable-length integer handling
+ *
+ * In the .xz format, most integers are encoded in a variable-length
+ * representation, which is sometimes called little endian base-128 encoding.
+ * This saves space when smaller values are more likely than bigger values.
+ *
+ * The encoding scheme encodes seven bits to every byte, using minimum
+ * number of bytes required to represent the given value. Encodings that use
+ * non-minimum number of bytes are invalid, thus every integer has exactly
+ * one encoded representation. The maximum number of bits in a VLI is 63,
+ * thus the vli argument must be less than or equal to UINT64_MAX / 2. You
+ * should use LZMA_VLI_MAX for clarity.
+ */
+
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * See ../lzma.h for information about liblzma as a whole.
+ */
+
+#ifndef LZMA_H_INTERNAL
+# error Never include this file directly. Use <lzma.h> instead.
+#endif
+
+
+/**
+ * \brief Maximum supported value of a variable-length integer
+ */
+#define LZMA_VLI_MAX (UINT64_MAX / 2)
+
+/**
+ * \brief VLI value to denote that the value is unknown
+ */
+#define LZMA_VLI_UNKNOWN UINT64_MAX
+
+/**
+ * \brief Maximum supported encoded length of variable length integers
+ */
+#define LZMA_VLI_BYTES_MAX 9
+
+/**
+ * \brief VLI constant suffix
+ */
+#define LZMA_VLI_C(n) UINT64_C(n)
+
+
+/**
+ * \brief Variable-length integer type
+ *
+ * Valid VLI values are in the range [0, LZMA_VLI_MAX]. Unknown value is
+ * indicated with LZMA_VLI_UNKNOWN, which is the maximum value of the
+ * underlaying integer type.
+ *
+ * lzma_vli will be uint64_t for the foreseeable future. If a bigger size
+ * is needed in the future, it is guaranteed that 2 * LZMA_VLI_MAX will
+ * not overflow lzma_vli. This simplifies integer overflow detection.
+ */
+typedef uint64_t lzma_vli;
+
+
+/**
+ * \brief Validate a variable-length integer
+ *
+ * This is useful to test that application has given acceptable values
+ * for example in the uncompressed_size and compressed_size variables.
+ *
+ * \return True if the integer is representable as VLI or if it
+ * indicates unknown value.
+ */
+#define lzma_vli_is_valid(vli) \
+ ((vli) <= LZMA_VLI_MAX || (vli) == LZMA_VLI_UNKNOWN)
+
+
+/**
+ * \brief Encode a variable-length integer
+ *
+ * This function has two modes: single-call and multi-call. Single-call mode
+ * encodes the whole integer at once; it is an error if the output buffer is
+ * too small. Multi-call mode saves the position in *vli_pos, and thus it is
+ * possible to continue encoding if the buffer becomes full before the whole
+ * integer has been encoded.
+ *
+ * \param vli Integer to be encoded
+ * \param vli_pos How many VLI-encoded bytes have already been written
+ * out. When starting to encode a new integer in
+ * multi-call mode, *vli_pos must be set to zero.
+ * To use single-call encoding, set vli_pos to NULL.
+ * \param out Beginning of the output buffer
+ * \param out_pos The next byte will be written to out[*out_pos].
+ * \param out_size Size of the out buffer; the first byte into
+ * which no data is written to is out[out_size].
+ *
+ * \return Slightly different return values are used in multi-call and
+ * single-call modes.
+ *
+ * Single-call (vli_pos == NULL):
+ * - LZMA_OK: Integer successfully encoded.
+ * - LZMA_PROG_ERROR: Arguments are not sane. This can be due
+ * to too little output space; single-call mode doesn't use
+ * LZMA_BUF_ERROR, since the application should have checked
+ * the encoded size with lzma_vli_size().
+ *
+ * Multi-call (vli_pos != NULL):
+ * - LZMA_OK: So far all OK, but the integer is not
+ * completely written out yet.
+ * - LZMA_STREAM_END: Integer successfully encoded.
+ * - LZMA_BUF_ERROR: No output space was provided.
+ * - LZMA_PROG_ERROR: Arguments are not sane.
+ */
+extern LZMA_API(lzma_ret) lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
+ uint8_t *out, size_t *out_pos, size_t out_size) lzma_nothrow;
+
+
+/**
+ * \brief Decode a variable-length integer
+ *
+ * Like lzma_vli_encode(), this function has single-call and multi-call modes.
+ *
+ * \param vli Pointer to decoded integer. The decoder will
+ * initialize it to zero when *vli_pos == 0, so
+ * application isn't required to initialize *vli.
+ * \param vli_pos How many bytes have already been decoded. When
+ * starting to decode a new integer in multi-call
+ * mode, *vli_pos must be initialized to zero. To
+ * use single-call decoding, set vli_pos to NULL.
+ * \param in Beginning of the input buffer
+ * \param in_pos The next byte will be read from in[*in_pos].
+ * \param in_size Size of the input buffer; the first byte that
+ * won't be read is in[in_size].
+ *
+ * \return Slightly different return values are used in multi-call and
+ * single-call modes.
+ *
+ * Single-call (vli_pos == NULL):
+ * - LZMA_OK: Integer successfully decoded.
+ * - LZMA_DATA_ERROR: Integer is corrupt. This includes hitting
+ * the end of the input buffer before the whole integer was
+ * decoded; providing no input at all will use LZMA_DATA_ERROR.
+ * - LZMA_PROG_ERROR: Arguments are not sane.
+ *
+ * Multi-call (vli_pos != NULL):
+ * - LZMA_OK: So far all OK, but the integer is not
+ * completely decoded yet.
+ * - LZMA_STREAM_END: Integer successfully decoded.
+ * - LZMA_DATA_ERROR: Integer is corrupt.
+ * - LZMA_BUF_ERROR: No input was provided.
+ * - LZMA_PROG_ERROR: Arguments are not sane.
+ */
+extern LZMA_API(lzma_ret) lzma_vli_decode(lzma_vli *vli, size_t *vli_pos,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+ lzma_nothrow;
+
+
+/**
+ * \brief Get the number of bytes required to encode a VLI
+ *
+ * \return Number of bytes on success (1-9). If vli isn't valid,
+ * zero is returned.
+ */
+extern LZMA_API(uint32_t) lzma_vli_size(lzma_vli vli)
+ lzma_nothrow lzma_attr_pure;
diff --git a/Utilities/cmliblzma/liblzma/check/check.c b/Utilities/cmliblzma/liblzma/check/check.c
new file mode 100644
index 000000000..979b0a818
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/check.c
@@ -0,0 +1,174 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file check.c
+/// \brief Single API to access different integrity checks
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+extern LZMA_API(lzma_bool)
+lzma_check_is_supported(lzma_check type)
+{
+ static const lzma_bool available_checks[LZMA_CHECK_ID_MAX + 1] = {
+ true, // LZMA_CHECK_NONE
+
+#ifdef HAVE_CHECK_CRC32
+ true,
+#else
+ false,
+#endif
+
+ false, // Reserved
+ false, // Reserved
+
+#ifdef HAVE_CHECK_CRC64
+ true,
+#else
+ false,
+#endif
+
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+
+#ifdef HAVE_CHECK_SHA256
+ true,
+#else
+ false,
+#endif
+
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+ false, // Reserved
+ };
+
+ if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
+ return false;
+
+ return available_checks[(unsigned int)(type)];
+}
+
+
+extern LZMA_API(uint32_t)
+lzma_check_size(lzma_check type)
+{
+ // See file-format.txt section 2.1.1.2.
+ static const uint8_t check_sizes[LZMA_CHECK_ID_MAX + 1] = {
+ 0,
+ 4, 4, 4,
+ 8, 8, 8,
+ 16, 16, 16,
+ 32, 32, 32,
+ 64, 64, 64
+ };
+
+ if ((unsigned int)(type) > LZMA_CHECK_ID_MAX)
+ return UINT32_MAX;
+
+ return check_sizes[(unsigned int)(type)];
+}
+
+
+extern void
+lzma_check_init(lzma_check_state *check, lzma_check type)
+{
+ switch (type) {
+ case LZMA_CHECK_NONE:
+ break;
+
+#ifdef HAVE_CHECK_CRC32
+ case LZMA_CHECK_CRC32:
+ check->state.crc32 = 0;
+ break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+ case LZMA_CHECK_CRC64:
+ check->state.crc64 = 0;
+ break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+ case LZMA_CHECK_SHA256:
+ lzma_sha256_init(check);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+extern void
+lzma_check_update(lzma_check_state *check, lzma_check type,
+ const uint8_t *buf, size_t size)
+{
+ switch (type) {
+#ifdef HAVE_CHECK_CRC32
+ case LZMA_CHECK_CRC32:
+ check->state.crc32 = lzma_crc32(buf, size, check->state.crc32);
+ break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+ case LZMA_CHECK_CRC64:
+ check->state.crc64 = lzma_crc64(buf, size, check->state.crc64);
+ break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+ case LZMA_CHECK_SHA256:
+ lzma_sha256_update(buf, size, check);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return;
+}
+
+
+extern void
+lzma_check_finish(lzma_check_state *check, lzma_check type)
+{
+ switch (type) {
+#ifdef HAVE_CHECK_CRC32
+ case LZMA_CHECK_CRC32:
+ check->buffer.u32[0] = conv32le(check->state.crc32);
+ break;
+#endif
+
+#ifdef HAVE_CHECK_CRC64
+ case LZMA_CHECK_CRC64:
+ check->buffer.u64[0] = conv64le(check->state.crc64);
+ break;
+#endif
+
+#ifdef HAVE_CHECK_SHA256
+ case LZMA_CHECK_SHA256:
+ lzma_sha256_finish(check);
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/check.h b/Utilities/cmliblzma/liblzma/check/check.h
new file mode 100644
index 000000000..e100d2b85
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/check.h
@@ -0,0 +1,95 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file check.h
+/// \brief Internal API to different integrity check functions
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_CHECK_H
+#define LZMA_CHECK_H
+
+#include "common.h"
+
+
+// Index hashing needs the best possible hash function (preferably
+// a cryptographic hash) for maximum reliability.
+#if defined(HAVE_CHECK_SHA256)
+# define LZMA_CHECK_BEST LZMA_CHECK_SHA256
+#elif defined(HAVE_CHECK_CRC64)
+# define LZMA_CHECK_BEST LZMA_CHECK_CRC64
+#else
+# define LZMA_CHECK_BEST LZMA_CHECK_CRC32
+#endif
+
+
+/// \brief Structure to hold internal state of the check being calculated
+///
+/// \note This is not in the public API because this structure may
+/// change in future if new integrity check algorithms are added.
+typedef struct {
+ /// Buffer to hold the final result and a temporary buffer for SHA256.
+ union {
+ uint8_t u8[64];
+ uint32_t u32[16];
+ uint64_t u64[8];
+ } buffer;
+
+ /// Check-specific data
+ union {
+ uint32_t crc32;
+ uint64_t crc64;
+
+ struct {
+ /// Internal state
+ uint32_t state[8];
+
+ /// Size of the message excluding padding
+ uint64_t size;
+ } sha256;
+ } state;
+
+} lzma_check_state;
+
+
+/// lzma_crc32_table[0] is needed by LZ encoder so we need to keep
+/// the array two-dimensional.
+#ifdef HAVE_SMALL
+extern uint32_t lzma_crc32_table[1][256];
+extern void lzma_crc32_init(void);
+#else
+extern const uint32_t lzma_crc32_table[8][256];
+extern const uint64_t lzma_crc64_table[4][256];
+#endif
+
+
+/// \brief Initialize *check depending on type
+///
+/// \return LZMA_OK on success. LZMA_UNSUPPORTED_CHECK if the type is not
+/// supported by the current version or build of liblzma.
+/// LZMA_PROG_ERROR if type > LZMA_CHECK_ID_MAX.
+extern void lzma_check_init(lzma_check_state *check, lzma_check type);
+
+/// Update the check state
+extern void lzma_check_update(lzma_check_state *check, lzma_check type,
+ const uint8_t *buf, size_t size);
+
+/// Finish the check calculation and store the result to check->buffer.u8.
+extern void lzma_check_finish(lzma_check_state *check, lzma_check type);
+
+
+/// Prepare SHA-256 state for new input.
+extern void lzma_sha256_init(lzma_check_state *check);
+
+/// Update the SHA-256 hash state
+extern void lzma_sha256_update(
+ const uint8_t *buf, size_t size, lzma_check_state *check);
+
+/// Finish the SHA-256 calculation and store the result to check->buffer.u8.
+extern void lzma_sha256_finish(lzma_check_state *check);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_fast.c b/Utilities/cmliblzma/liblzma/check/crc32_fast.c
new file mode 100644
index 000000000..c2c3cb79b
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_fast.c
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc32.c
+/// \brief CRC32 calculation
+///
+/// Calculate the CRC32 using the slice-by-eight algorithm.
+/// It is explained in this document:
+/// http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
+/// The code in this file is not the same as in Intel's paper, but
+/// the basic principle is identical.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+#include "crc_macros.h"
+
+
+// If you make any changes, do some benchmarking! Seemingly unrelated
+// changes can very easily ruin the performance (and very probably is
+// very compiler dependent).
+extern LZMA_API(uint32_t)
+lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+ crc = ~crc;
+
+#ifdef WORDS_BIGENDIAN
+ crc = bswap32(crc);
+#endif
+
+ if (size > 8) {
+ const uint8_t * limit;
+
+ // Fix the alignment, if needed. The if statement above
+ // ensures that this won't read past the end of buf[].
+ while ((uintptr_t)(buf) & 7) {
+ crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
+ --size;
+ }
+
+ // Calculate the position where to stop.
+ limit = buf + (size & ~(size_t)(7));
+
+ // Calculate how many bytes must be calculated separately
+ // before returning the result.
+ size &= (size_t)(7);
+
+ // Calculate the CRC32 using the slice-by-eight algorithm.
+ while (buf < limit) {
+ uint32_t tmp;
+
+ crc ^= *(const uint32_t *)(buf);
+ buf += 4;
+
+ crc = lzma_crc32_table[7][A(crc)]
+ ^ lzma_crc32_table[6][B(crc)]
+ ^ lzma_crc32_table[5][C(crc)]
+ ^ lzma_crc32_table[4][D(crc)];
+
+ tmp = *(const uint32_t *)(buf);
+ buf += 4;
+
+ // At least with some compilers, it is critical for
+ // performance, that the crc variable is XORed
+ // between the two table-lookup pairs.
+ crc = lzma_crc32_table[3][A(tmp)]
+ ^ lzma_crc32_table[2][B(tmp)]
+ ^ crc
+ ^ lzma_crc32_table[1][C(tmp)]
+ ^ lzma_crc32_table[0][D(tmp)];
+ }
+ }
+
+ while (size-- != 0)
+ crc = lzma_crc32_table[0][*buf++ ^ A(crc)] ^ S8(crc);
+
+#ifdef WORDS_BIGENDIAN
+ crc = bswap32(crc);
+#endif
+
+ return ~crc;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_small.c b/Utilities/cmliblzma/liblzma/check/crc32_small.c
new file mode 100644
index 000000000..5f8a32868
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_small.c
@@ -0,0 +1,61 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc32_small.c
+/// \brief CRC32 calculation (size-optimized)
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+uint32_t lzma_crc32_table[1][256];
+
+
+static void
+crc32_init(void)
+{
+ static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+ for (size_t b = 0; b < 256; ++b) {
+ uint32_t r = b;
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly32;
+ else
+ r >>= 1;
+ }
+
+ lzma_crc32_table[0][b] = r;
+ }
+
+ return;
+}
+
+
+extern void
+lzma_crc32_init(void)
+{
+ mythread_once(crc32_init);
+ return;
+}
+
+
+extern LZMA_API(uint32_t)
+lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc)
+{
+ lzma_crc32_init();
+
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = lzma_crc32_table[0][*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_table.c b/Utilities/cmliblzma/liblzma/check/crc32_table.c
new file mode 100644
index 000000000..368874eb7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_table.c
@@ -0,0 +1,19 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc32_table.c
+/// \brief Precalculated CRC32 table with correct endianness
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+#ifdef WORDS_BIGENDIAN
+# include "crc32_table_be.h"
+#else
+# include "crc32_table_le.h"
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_table_be.h b/Utilities/cmliblzma/liblzma/check/crc32_table_be.h
new file mode 100644
index 000000000..c483cb670
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_table_be.h
@@ -0,0 +1,525 @@
+/* This file has been automatically generated by crc32_tablegen.c. */
+
+const uint32_t lzma_crc32_table[8][256] = {
+ {
+ 0x00000000, 0x96300777, 0x2C610EEE, 0xBA510999,
+ 0x19C46D07, 0x8FF46A70, 0x35A563E9, 0xA395649E,
+ 0x3288DB0E, 0xA4B8DC79, 0x1EE9D5E0, 0x88D9D297,
+ 0x2B4CB609, 0xBD7CB17E, 0x072DB8E7, 0x911DBF90,
+ 0x6410B71D, 0xF220B06A, 0x4871B9F3, 0xDE41BE84,
+ 0x7DD4DA1A, 0xEBE4DD6D, 0x51B5D4F4, 0xC785D383,
+ 0x56986C13, 0xC0A86B64, 0x7AF962FD, 0xECC9658A,
+ 0x4F5C0114, 0xD96C0663, 0x633D0FFA, 0xF50D088D,
+ 0xC8206E3B, 0x5E10694C, 0xE44160D5, 0x727167A2,
+ 0xD1E4033C, 0x47D4044B, 0xFD850DD2, 0x6BB50AA5,
+ 0xFAA8B535, 0x6C98B242, 0xD6C9BBDB, 0x40F9BCAC,
+ 0xE36CD832, 0x755CDF45, 0xCF0DD6DC, 0x593DD1AB,
+ 0xAC30D926, 0x3A00DE51, 0x8051D7C8, 0x1661D0BF,
+ 0xB5F4B421, 0x23C4B356, 0x9995BACF, 0x0FA5BDB8,
+ 0x9EB80228, 0x0888055F, 0xB2D90CC6, 0x24E90BB1,
+ 0x877C6F2F, 0x114C6858, 0xAB1D61C1, 0x3D2D66B6,
+ 0x9041DC76, 0x0671DB01, 0xBC20D298, 0x2A10D5EF,
+ 0x8985B171, 0x1FB5B606, 0xA5E4BF9F, 0x33D4B8E8,
+ 0xA2C90778, 0x34F9000F, 0x8EA80996, 0x18980EE1,
+ 0xBB0D6A7F, 0x2D3D6D08, 0x976C6491, 0x015C63E6,
+ 0xF4516B6B, 0x62616C1C, 0xD8306585, 0x4E0062F2,
+ 0xED95066C, 0x7BA5011B, 0xC1F40882, 0x57C40FF5,
+ 0xC6D9B065, 0x50E9B712, 0xEAB8BE8B, 0x7C88B9FC,
+ 0xDF1DDD62, 0x492DDA15, 0xF37CD38C, 0x654CD4FB,
+ 0x5861B24D, 0xCE51B53A, 0x7400BCA3, 0xE230BBD4,
+ 0x41A5DF4A, 0xD795D83D, 0x6DC4D1A4, 0xFBF4D6D3,
+ 0x6AE96943, 0xFCD96E34, 0x468867AD, 0xD0B860DA,
+ 0x732D0444, 0xE51D0333, 0x5F4C0AAA, 0xC97C0DDD,
+ 0x3C710550, 0xAA410227, 0x10100BBE, 0x86200CC9,
+ 0x25B56857, 0xB3856F20, 0x09D466B9, 0x9FE461CE,
+ 0x0EF9DE5E, 0x98C9D929, 0x2298D0B0, 0xB4A8D7C7,
+ 0x173DB359, 0x810DB42E, 0x3B5CBDB7, 0xAD6CBAC0,
+ 0x2083B8ED, 0xB6B3BF9A, 0x0CE2B603, 0x9AD2B174,
+ 0x3947D5EA, 0xAF77D29D, 0x1526DB04, 0x8316DC73,
+ 0x120B63E3, 0x843B6494, 0x3E6A6D0D, 0xA85A6A7A,
+ 0x0BCF0EE4, 0x9DFF0993, 0x27AE000A, 0xB19E077D,
+ 0x44930FF0, 0xD2A30887, 0x68F2011E, 0xFEC20669,
+ 0x5D5762F7, 0xCB676580, 0x71366C19, 0xE7066B6E,
+ 0x761BD4FE, 0xE02BD389, 0x5A7ADA10, 0xCC4ADD67,
+ 0x6FDFB9F9, 0xF9EFBE8E, 0x43BEB717, 0xD58EB060,
+ 0xE8A3D6D6, 0x7E93D1A1, 0xC4C2D838, 0x52F2DF4F,
+ 0xF167BBD1, 0x6757BCA6, 0xDD06B53F, 0x4B36B248,
+ 0xDA2B0DD8, 0x4C1B0AAF, 0xF64A0336, 0x607A0441,
+ 0xC3EF60DF, 0x55DF67A8, 0xEF8E6E31, 0x79BE6946,
+ 0x8CB361CB, 0x1A8366BC, 0xA0D26F25, 0x36E26852,
+ 0x95770CCC, 0x03470BBB, 0xB9160222, 0x2F260555,
+ 0xBE3BBAC5, 0x280BBDB2, 0x925AB42B, 0x046AB35C,
+ 0xA7FFD7C2, 0x31CFD0B5, 0x8B9ED92C, 0x1DAEDE5B,
+ 0xB0C2649B, 0x26F263EC, 0x9CA36A75, 0x0A936D02,
+ 0xA906099C, 0x3F360EEB, 0x85670772, 0x13570005,
+ 0x824ABF95, 0x147AB8E2, 0xAE2BB17B, 0x381BB60C,
+ 0x9B8ED292, 0x0DBED5E5, 0xB7EFDC7C, 0x21DFDB0B,
+ 0xD4D2D386, 0x42E2D4F1, 0xF8B3DD68, 0x6E83DA1F,
+ 0xCD16BE81, 0x5B26B9F6, 0xE177B06F, 0x7747B718,
+ 0xE65A0888, 0x706A0FFF, 0xCA3B0666, 0x5C0B0111,
+ 0xFF9E658F, 0x69AE62F8, 0xD3FF6B61, 0x45CF6C16,
+ 0x78E20AA0, 0xEED20DD7, 0x5483044E, 0xC2B30339,
+ 0x612667A7, 0xF71660D0, 0x4D476949, 0xDB776E3E,
+ 0x4A6AD1AE, 0xDC5AD6D9, 0x660BDF40, 0xF03BD837,
+ 0x53AEBCA9, 0xC59EBBDE, 0x7FCFB247, 0xE9FFB530,
+ 0x1CF2BDBD, 0x8AC2BACA, 0x3093B353, 0xA6A3B424,
+ 0x0536D0BA, 0x9306D7CD, 0x2957DE54, 0xBF67D923,
+ 0x2E7A66B3, 0xB84A61C4, 0x021B685D, 0x942B6F2A,
+ 0x37BE0BB4, 0xA18E0CC3, 0x1BDF055A, 0x8DEF022D
+ }, {
+ 0x00000000, 0x41311B19, 0x82623632, 0xC3532D2B,
+ 0x04C56C64, 0x45F4777D, 0x86A75A56, 0xC796414F,
+ 0x088AD9C8, 0x49BBC2D1, 0x8AE8EFFA, 0xCBD9F4E3,
+ 0x0C4FB5AC, 0x4D7EAEB5, 0x8E2D839E, 0xCF1C9887,
+ 0x5112C24A, 0x1023D953, 0xD370F478, 0x9241EF61,
+ 0x55D7AE2E, 0x14E6B537, 0xD7B5981C, 0x96848305,
+ 0x59981B82, 0x18A9009B, 0xDBFA2DB0, 0x9ACB36A9,
+ 0x5D5D77E6, 0x1C6C6CFF, 0xDF3F41D4, 0x9E0E5ACD,
+ 0xA2248495, 0xE3159F8C, 0x2046B2A7, 0x6177A9BE,
+ 0xA6E1E8F1, 0xE7D0F3E8, 0x2483DEC3, 0x65B2C5DA,
+ 0xAAAE5D5D, 0xEB9F4644, 0x28CC6B6F, 0x69FD7076,
+ 0xAE6B3139, 0xEF5A2A20, 0x2C09070B, 0x6D381C12,
+ 0xF33646DF, 0xB2075DC6, 0x715470ED, 0x30656BF4,
+ 0xF7F32ABB, 0xB6C231A2, 0x75911C89, 0x34A00790,
+ 0xFBBC9F17, 0xBA8D840E, 0x79DEA925, 0x38EFB23C,
+ 0xFF79F373, 0xBE48E86A, 0x7D1BC541, 0x3C2ADE58,
+ 0x054F79F0, 0x447E62E9, 0x872D4FC2, 0xC61C54DB,
+ 0x018A1594, 0x40BB0E8D, 0x83E823A6, 0xC2D938BF,
+ 0x0DC5A038, 0x4CF4BB21, 0x8FA7960A, 0xCE968D13,
+ 0x0900CC5C, 0x4831D745, 0x8B62FA6E, 0xCA53E177,
+ 0x545DBBBA, 0x156CA0A3, 0xD63F8D88, 0x970E9691,
+ 0x5098D7DE, 0x11A9CCC7, 0xD2FAE1EC, 0x93CBFAF5,
+ 0x5CD76272, 0x1DE6796B, 0xDEB55440, 0x9F844F59,
+ 0x58120E16, 0x1923150F, 0xDA703824, 0x9B41233D,
+ 0xA76BFD65, 0xE65AE67C, 0x2509CB57, 0x6438D04E,
+ 0xA3AE9101, 0xE29F8A18, 0x21CCA733, 0x60FDBC2A,
+ 0xAFE124AD, 0xEED03FB4, 0x2D83129F, 0x6CB20986,
+ 0xAB2448C9, 0xEA1553D0, 0x29467EFB, 0x687765E2,
+ 0xF6793F2F, 0xB7482436, 0x741B091D, 0x352A1204,
+ 0xF2BC534B, 0xB38D4852, 0x70DE6579, 0x31EF7E60,
+ 0xFEF3E6E7, 0xBFC2FDFE, 0x7C91D0D5, 0x3DA0CBCC,
+ 0xFA368A83, 0xBB07919A, 0x7854BCB1, 0x3965A7A8,
+ 0x4B98833B, 0x0AA99822, 0xC9FAB509, 0x88CBAE10,
+ 0x4F5DEF5F, 0x0E6CF446, 0xCD3FD96D, 0x8C0EC274,
+ 0x43125AF3, 0x022341EA, 0xC1706CC1, 0x804177D8,
+ 0x47D73697, 0x06E62D8E, 0xC5B500A5, 0x84841BBC,
+ 0x1A8A4171, 0x5BBB5A68, 0x98E87743, 0xD9D96C5A,
+ 0x1E4F2D15, 0x5F7E360C, 0x9C2D1B27, 0xDD1C003E,
+ 0x120098B9, 0x533183A0, 0x9062AE8B, 0xD153B592,
+ 0x16C5F4DD, 0x57F4EFC4, 0x94A7C2EF, 0xD596D9F6,
+ 0xE9BC07AE, 0xA88D1CB7, 0x6BDE319C, 0x2AEF2A85,
+ 0xED796BCA, 0xAC4870D3, 0x6F1B5DF8, 0x2E2A46E1,
+ 0xE136DE66, 0xA007C57F, 0x6354E854, 0x2265F34D,
+ 0xE5F3B202, 0xA4C2A91B, 0x67918430, 0x26A09F29,
+ 0xB8AEC5E4, 0xF99FDEFD, 0x3ACCF3D6, 0x7BFDE8CF,
+ 0xBC6BA980, 0xFD5AB299, 0x3E099FB2, 0x7F3884AB,
+ 0xB0241C2C, 0xF1150735, 0x32462A1E, 0x73773107,
+ 0xB4E17048, 0xF5D06B51, 0x3683467A, 0x77B25D63,
+ 0x4ED7FACB, 0x0FE6E1D2, 0xCCB5CCF9, 0x8D84D7E0,
+ 0x4A1296AF, 0x0B238DB6, 0xC870A09D, 0x8941BB84,
+ 0x465D2303, 0x076C381A, 0xC43F1531, 0x850E0E28,
+ 0x42984F67, 0x03A9547E, 0xC0FA7955, 0x81CB624C,
+ 0x1FC53881, 0x5EF42398, 0x9DA70EB3, 0xDC9615AA,
+ 0x1B0054E5, 0x5A314FFC, 0x996262D7, 0xD85379CE,
+ 0x174FE149, 0x567EFA50, 0x952DD77B, 0xD41CCC62,
+ 0x138A8D2D, 0x52BB9634, 0x91E8BB1F, 0xD0D9A006,
+ 0xECF37E5E, 0xADC26547, 0x6E91486C, 0x2FA05375,
+ 0xE836123A, 0xA9070923, 0x6A542408, 0x2B653F11,
+ 0xE479A796, 0xA548BC8F, 0x661B91A4, 0x272A8ABD,
+ 0xE0BCCBF2, 0xA18DD0EB, 0x62DEFDC0, 0x23EFE6D9,
+ 0xBDE1BC14, 0xFCD0A70D, 0x3F838A26, 0x7EB2913F,
+ 0xB924D070, 0xF815CB69, 0x3B46E642, 0x7A77FD5B,
+ 0xB56B65DC, 0xF45A7EC5, 0x370953EE, 0x763848F7,
+ 0xB1AE09B8, 0xF09F12A1, 0x33CC3F8A, 0x72FD2493
+ }, {
+ 0x00000000, 0x376AC201, 0x6ED48403, 0x59BE4602,
+ 0xDCA80907, 0xEBC2CB06, 0xB27C8D04, 0x85164F05,
+ 0xB851130E, 0x8F3BD10F, 0xD685970D, 0xE1EF550C,
+ 0x64F91A09, 0x5393D808, 0x0A2D9E0A, 0x3D475C0B,
+ 0x70A3261C, 0x47C9E41D, 0x1E77A21F, 0x291D601E,
+ 0xAC0B2F1B, 0x9B61ED1A, 0xC2DFAB18, 0xF5B56919,
+ 0xC8F23512, 0xFF98F713, 0xA626B111, 0x914C7310,
+ 0x145A3C15, 0x2330FE14, 0x7A8EB816, 0x4DE47A17,
+ 0xE0464D38, 0xD72C8F39, 0x8E92C93B, 0xB9F80B3A,
+ 0x3CEE443F, 0x0B84863E, 0x523AC03C, 0x6550023D,
+ 0x58175E36, 0x6F7D9C37, 0x36C3DA35, 0x01A91834,
+ 0x84BF5731, 0xB3D59530, 0xEA6BD332, 0xDD011133,
+ 0x90E56B24, 0xA78FA925, 0xFE31EF27, 0xC95B2D26,
+ 0x4C4D6223, 0x7B27A022, 0x2299E620, 0x15F32421,
+ 0x28B4782A, 0x1FDEBA2B, 0x4660FC29, 0x710A3E28,
+ 0xF41C712D, 0xC376B32C, 0x9AC8F52E, 0xADA2372F,
+ 0xC08D9A70, 0xF7E75871, 0xAE591E73, 0x9933DC72,
+ 0x1C259377, 0x2B4F5176, 0x72F11774, 0x459BD575,
+ 0x78DC897E, 0x4FB64B7F, 0x16080D7D, 0x2162CF7C,
+ 0xA4748079, 0x931E4278, 0xCAA0047A, 0xFDCAC67B,
+ 0xB02EBC6C, 0x87447E6D, 0xDEFA386F, 0xE990FA6E,
+ 0x6C86B56B, 0x5BEC776A, 0x02523168, 0x3538F369,
+ 0x087FAF62, 0x3F156D63, 0x66AB2B61, 0x51C1E960,
+ 0xD4D7A665, 0xE3BD6464, 0xBA032266, 0x8D69E067,
+ 0x20CBD748, 0x17A11549, 0x4E1F534B, 0x7975914A,
+ 0xFC63DE4F, 0xCB091C4E, 0x92B75A4C, 0xA5DD984D,
+ 0x989AC446, 0xAFF00647, 0xF64E4045, 0xC1248244,
+ 0x4432CD41, 0x73580F40, 0x2AE64942, 0x1D8C8B43,
+ 0x5068F154, 0x67023355, 0x3EBC7557, 0x09D6B756,
+ 0x8CC0F853, 0xBBAA3A52, 0xE2147C50, 0xD57EBE51,
+ 0xE839E25A, 0xDF53205B, 0x86ED6659, 0xB187A458,
+ 0x3491EB5D, 0x03FB295C, 0x5A456F5E, 0x6D2FAD5F,
+ 0x801B35E1, 0xB771F7E0, 0xEECFB1E2, 0xD9A573E3,
+ 0x5CB33CE6, 0x6BD9FEE7, 0x3267B8E5, 0x050D7AE4,
+ 0x384A26EF, 0x0F20E4EE, 0x569EA2EC, 0x61F460ED,
+ 0xE4E22FE8, 0xD388EDE9, 0x8A36ABEB, 0xBD5C69EA,
+ 0xF0B813FD, 0xC7D2D1FC, 0x9E6C97FE, 0xA90655FF,
+ 0x2C101AFA, 0x1B7AD8FB, 0x42C49EF9, 0x75AE5CF8,
+ 0x48E900F3, 0x7F83C2F2, 0x263D84F0, 0x115746F1,
+ 0x944109F4, 0xA32BCBF5, 0xFA958DF7, 0xCDFF4FF6,
+ 0x605D78D9, 0x5737BAD8, 0x0E89FCDA, 0x39E33EDB,
+ 0xBCF571DE, 0x8B9FB3DF, 0xD221F5DD, 0xE54B37DC,
+ 0xD80C6BD7, 0xEF66A9D6, 0xB6D8EFD4, 0x81B22DD5,
+ 0x04A462D0, 0x33CEA0D1, 0x6A70E6D3, 0x5D1A24D2,
+ 0x10FE5EC5, 0x27949CC4, 0x7E2ADAC6, 0x494018C7,
+ 0xCC5657C2, 0xFB3C95C3, 0xA282D3C1, 0x95E811C0,
+ 0xA8AF4DCB, 0x9FC58FCA, 0xC67BC9C8, 0xF1110BC9,
+ 0x740744CC, 0x436D86CD, 0x1AD3C0CF, 0x2DB902CE,
+ 0x4096AF91, 0x77FC6D90, 0x2E422B92, 0x1928E993,
+ 0x9C3EA696, 0xAB546497, 0xF2EA2295, 0xC580E094,
+ 0xF8C7BC9F, 0xCFAD7E9E, 0x9613389C, 0xA179FA9D,
+ 0x246FB598, 0x13057799, 0x4ABB319B, 0x7DD1F39A,
+ 0x3035898D, 0x075F4B8C, 0x5EE10D8E, 0x698BCF8F,
+ 0xEC9D808A, 0xDBF7428B, 0x82490489, 0xB523C688,
+ 0x88649A83, 0xBF0E5882, 0xE6B01E80, 0xD1DADC81,
+ 0x54CC9384, 0x63A65185, 0x3A181787, 0x0D72D586,
+ 0xA0D0E2A9, 0x97BA20A8, 0xCE0466AA, 0xF96EA4AB,
+ 0x7C78EBAE, 0x4B1229AF, 0x12AC6FAD, 0x25C6ADAC,
+ 0x1881F1A7, 0x2FEB33A6, 0x765575A4, 0x413FB7A5,
+ 0xC429F8A0, 0xF3433AA1, 0xAAFD7CA3, 0x9D97BEA2,
+ 0xD073C4B5, 0xE71906B4, 0xBEA740B6, 0x89CD82B7,
+ 0x0CDBCDB2, 0x3BB10FB3, 0x620F49B1, 0x55658BB0,
+ 0x6822D7BB, 0x5F4815BA, 0x06F653B8, 0x319C91B9,
+ 0xB48ADEBC, 0x83E01CBD, 0xDA5E5ABF, 0xED3498BE
+ }, {
+ 0x00000000, 0x6567BCB8, 0x8BC809AA, 0xEEAFB512,
+ 0x5797628F, 0x32F0DE37, 0xDC5F6B25, 0xB938D79D,
+ 0xEF28B4C5, 0x8A4F087D, 0x64E0BD6F, 0x018701D7,
+ 0xB8BFD64A, 0xDDD86AF2, 0x3377DFE0, 0x56106358,
+ 0x9F571950, 0xFA30A5E8, 0x149F10FA, 0x71F8AC42,
+ 0xC8C07BDF, 0xADA7C767, 0x43087275, 0x266FCECD,
+ 0x707FAD95, 0x1518112D, 0xFBB7A43F, 0x9ED01887,
+ 0x27E8CF1A, 0x428F73A2, 0xAC20C6B0, 0xC9477A08,
+ 0x3EAF32A0, 0x5BC88E18, 0xB5673B0A, 0xD00087B2,
+ 0x6938502F, 0x0C5FEC97, 0xE2F05985, 0x8797E53D,
+ 0xD1878665, 0xB4E03ADD, 0x5A4F8FCF, 0x3F283377,
+ 0x8610E4EA, 0xE3775852, 0x0DD8ED40, 0x68BF51F8,
+ 0xA1F82BF0, 0xC49F9748, 0x2A30225A, 0x4F579EE2,
+ 0xF66F497F, 0x9308F5C7, 0x7DA740D5, 0x18C0FC6D,
+ 0x4ED09F35, 0x2BB7238D, 0xC518969F, 0xA07F2A27,
+ 0x1947FDBA, 0x7C204102, 0x928FF410, 0xF7E848A8,
+ 0x3D58149B, 0x583FA823, 0xB6901D31, 0xD3F7A189,
+ 0x6ACF7614, 0x0FA8CAAC, 0xE1077FBE, 0x8460C306,
+ 0xD270A05E, 0xB7171CE6, 0x59B8A9F4, 0x3CDF154C,
+ 0x85E7C2D1, 0xE0807E69, 0x0E2FCB7B, 0x6B4877C3,
+ 0xA20F0DCB, 0xC768B173, 0x29C70461, 0x4CA0B8D9,
+ 0xF5986F44, 0x90FFD3FC, 0x7E5066EE, 0x1B37DA56,
+ 0x4D27B90E, 0x284005B6, 0xC6EFB0A4, 0xA3880C1C,
+ 0x1AB0DB81, 0x7FD76739, 0x9178D22B, 0xF41F6E93,
+ 0x03F7263B, 0x66909A83, 0x883F2F91, 0xED589329,
+ 0x546044B4, 0x3107F80C, 0xDFA84D1E, 0xBACFF1A6,
+ 0xECDF92FE, 0x89B82E46, 0x67179B54, 0x027027EC,
+ 0xBB48F071, 0xDE2F4CC9, 0x3080F9DB, 0x55E74563,
+ 0x9CA03F6B, 0xF9C783D3, 0x176836C1, 0x720F8A79,
+ 0xCB375DE4, 0xAE50E15C, 0x40FF544E, 0x2598E8F6,
+ 0x73888BAE, 0x16EF3716, 0xF8408204, 0x9D273EBC,
+ 0x241FE921, 0x41785599, 0xAFD7E08B, 0xCAB05C33,
+ 0x3BB659ED, 0x5ED1E555, 0xB07E5047, 0xD519ECFF,
+ 0x6C213B62, 0x094687DA, 0xE7E932C8, 0x828E8E70,
+ 0xD49EED28, 0xB1F95190, 0x5F56E482, 0x3A31583A,
+ 0x83098FA7, 0xE66E331F, 0x08C1860D, 0x6DA63AB5,
+ 0xA4E140BD, 0xC186FC05, 0x2F294917, 0x4A4EF5AF,
+ 0xF3762232, 0x96119E8A, 0x78BE2B98, 0x1DD99720,
+ 0x4BC9F478, 0x2EAE48C0, 0xC001FDD2, 0xA566416A,
+ 0x1C5E96F7, 0x79392A4F, 0x97969F5D, 0xF2F123E5,
+ 0x05196B4D, 0x607ED7F5, 0x8ED162E7, 0xEBB6DE5F,
+ 0x528E09C2, 0x37E9B57A, 0xD9460068, 0xBC21BCD0,
+ 0xEA31DF88, 0x8F566330, 0x61F9D622, 0x049E6A9A,
+ 0xBDA6BD07, 0xD8C101BF, 0x366EB4AD, 0x53090815,
+ 0x9A4E721D, 0xFF29CEA5, 0x11867BB7, 0x74E1C70F,
+ 0xCDD91092, 0xA8BEAC2A, 0x46111938, 0x2376A580,
+ 0x7566C6D8, 0x10017A60, 0xFEAECF72, 0x9BC973CA,
+ 0x22F1A457, 0x479618EF, 0xA939ADFD, 0xCC5E1145,
+ 0x06EE4D76, 0x6389F1CE, 0x8D2644DC, 0xE841F864,
+ 0x51792FF9, 0x341E9341, 0xDAB12653, 0xBFD69AEB,
+ 0xE9C6F9B3, 0x8CA1450B, 0x620EF019, 0x07694CA1,
+ 0xBE519B3C, 0xDB362784, 0x35999296, 0x50FE2E2E,
+ 0x99B95426, 0xFCDEE89E, 0x12715D8C, 0x7716E134,
+ 0xCE2E36A9, 0xAB498A11, 0x45E63F03, 0x208183BB,
+ 0x7691E0E3, 0x13F65C5B, 0xFD59E949, 0x983E55F1,
+ 0x2106826C, 0x44613ED4, 0xAACE8BC6, 0xCFA9377E,
+ 0x38417FD6, 0x5D26C36E, 0xB389767C, 0xD6EECAC4,
+ 0x6FD61D59, 0x0AB1A1E1, 0xE41E14F3, 0x8179A84B,
+ 0xD769CB13, 0xB20E77AB, 0x5CA1C2B9, 0x39C67E01,
+ 0x80FEA99C, 0xE5991524, 0x0B36A036, 0x6E511C8E,
+ 0xA7166686, 0xC271DA3E, 0x2CDE6F2C, 0x49B9D394,
+ 0xF0810409, 0x95E6B8B1, 0x7B490DA3, 0x1E2EB11B,
+ 0x483ED243, 0x2D596EFB, 0xC3F6DBE9, 0xA6916751,
+ 0x1FA9B0CC, 0x7ACE0C74, 0x9461B966, 0xF10605DE
+ }, {
+ 0x00000000, 0xB029603D, 0x6053C07A, 0xD07AA047,
+ 0xC0A680F5, 0x708FE0C8, 0xA0F5408F, 0x10DC20B2,
+ 0xC14B7030, 0x7162100D, 0xA118B04A, 0x1131D077,
+ 0x01EDF0C5, 0xB1C490F8, 0x61BE30BF, 0xD1975082,
+ 0x8297E060, 0x32BE805D, 0xE2C4201A, 0x52ED4027,
+ 0x42316095, 0xF21800A8, 0x2262A0EF, 0x924BC0D2,
+ 0x43DC9050, 0xF3F5F06D, 0x238F502A, 0x93A63017,
+ 0x837A10A5, 0x33537098, 0xE329D0DF, 0x5300B0E2,
+ 0x042FC1C1, 0xB406A1FC, 0x647C01BB, 0xD4556186,
+ 0xC4894134, 0x74A02109, 0xA4DA814E, 0x14F3E173,
+ 0xC564B1F1, 0x754DD1CC, 0xA537718B, 0x151E11B6,
+ 0x05C23104, 0xB5EB5139, 0x6591F17E, 0xD5B89143,
+ 0x86B821A1, 0x3691419C, 0xE6EBE1DB, 0x56C281E6,
+ 0x461EA154, 0xF637C169, 0x264D612E, 0x96640113,
+ 0x47F35191, 0xF7DA31AC, 0x27A091EB, 0x9789F1D6,
+ 0x8755D164, 0x377CB159, 0xE706111E, 0x572F7123,
+ 0x4958F358, 0xF9719365, 0x290B3322, 0x9922531F,
+ 0x89FE73AD, 0x39D71390, 0xE9ADB3D7, 0x5984D3EA,
+ 0x88138368, 0x383AE355, 0xE8404312, 0x5869232F,
+ 0x48B5039D, 0xF89C63A0, 0x28E6C3E7, 0x98CFA3DA,
+ 0xCBCF1338, 0x7BE67305, 0xAB9CD342, 0x1BB5B37F,
+ 0x0B6993CD, 0xBB40F3F0, 0x6B3A53B7, 0xDB13338A,
+ 0x0A846308, 0xBAAD0335, 0x6AD7A372, 0xDAFEC34F,
+ 0xCA22E3FD, 0x7A0B83C0, 0xAA712387, 0x1A5843BA,
+ 0x4D773299, 0xFD5E52A4, 0x2D24F2E3, 0x9D0D92DE,
+ 0x8DD1B26C, 0x3DF8D251, 0xED827216, 0x5DAB122B,
+ 0x8C3C42A9, 0x3C152294, 0xEC6F82D3, 0x5C46E2EE,
+ 0x4C9AC25C, 0xFCB3A261, 0x2CC90226, 0x9CE0621B,
+ 0xCFE0D2F9, 0x7FC9B2C4, 0xAFB31283, 0x1F9A72BE,
+ 0x0F46520C, 0xBF6F3231, 0x6F159276, 0xDF3CF24B,
+ 0x0EABA2C9, 0xBE82C2F4, 0x6EF862B3, 0xDED1028E,
+ 0xCE0D223C, 0x7E244201, 0xAE5EE246, 0x1E77827B,
+ 0x92B0E6B1, 0x2299868C, 0xF2E326CB, 0x42CA46F6,
+ 0x52166644, 0xE23F0679, 0x3245A63E, 0x826CC603,
+ 0x53FB9681, 0xE3D2F6BC, 0x33A856FB, 0x838136C6,
+ 0x935D1674, 0x23747649, 0xF30ED60E, 0x4327B633,
+ 0x102706D1, 0xA00E66EC, 0x7074C6AB, 0xC05DA696,
+ 0xD0818624, 0x60A8E619, 0xB0D2465E, 0x00FB2663,
+ 0xD16C76E1, 0x614516DC, 0xB13FB69B, 0x0116D6A6,
+ 0x11CAF614, 0xA1E39629, 0x7199366E, 0xC1B05653,
+ 0x969F2770, 0x26B6474D, 0xF6CCE70A, 0x46E58737,
+ 0x5639A785, 0xE610C7B8, 0x366A67FF, 0x864307C2,
+ 0x57D45740, 0xE7FD377D, 0x3787973A, 0x87AEF707,
+ 0x9772D7B5, 0x275BB788, 0xF72117CF, 0x470877F2,
+ 0x1408C710, 0xA421A72D, 0x745B076A, 0xC4726757,
+ 0xD4AE47E5, 0x648727D8, 0xB4FD879F, 0x04D4E7A2,
+ 0xD543B720, 0x656AD71D, 0xB510775A, 0x05391767,
+ 0x15E537D5, 0xA5CC57E8, 0x75B6F7AF, 0xC59F9792,
+ 0xDBE815E9, 0x6BC175D4, 0xBBBBD593, 0x0B92B5AE,
+ 0x1B4E951C, 0xAB67F521, 0x7B1D5566, 0xCB34355B,
+ 0x1AA365D9, 0xAA8A05E4, 0x7AF0A5A3, 0xCAD9C59E,
+ 0xDA05E52C, 0x6A2C8511, 0xBA562556, 0x0A7F456B,
+ 0x597FF589, 0xE95695B4, 0x392C35F3, 0x890555CE,
+ 0x99D9757C, 0x29F01541, 0xF98AB506, 0x49A3D53B,
+ 0x983485B9, 0x281DE584, 0xF86745C3, 0x484E25FE,
+ 0x5892054C, 0xE8BB6571, 0x38C1C536, 0x88E8A50B,
+ 0xDFC7D428, 0x6FEEB415, 0xBF941452, 0x0FBD746F,
+ 0x1F6154DD, 0xAF4834E0, 0x7F3294A7, 0xCF1BF49A,
+ 0x1E8CA418, 0xAEA5C425, 0x7EDF6462, 0xCEF6045F,
+ 0xDE2A24ED, 0x6E0344D0, 0xBE79E497, 0x0E5084AA,
+ 0x5D503448, 0xED795475, 0x3D03F432, 0x8D2A940F,
+ 0x9DF6B4BD, 0x2DDFD480, 0xFDA574C7, 0x4D8C14FA,
+ 0x9C1B4478, 0x2C322445, 0xFC488402, 0x4C61E43F,
+ 0x5CBDC48D, 0xEC94A4B0, 0x3CEE04F7, 0x8CC764CA
+ }, {
+ 0x00000000, 0xA5D35CCB, 0x0BA1C84D, 0xAE729486,
+ 0x1642919B, 0xB391CD50, 0x1DE359D6, 0xB830051D,
+ 0x6D8253EC, 0xC8510F27, 0x66239BA1, 0xC3F0C76A,
+ 0x7BC0C277, 0xDE139EBC, 0x70610A3A, 0xD5B256F1,
+ 0x9B02D603, 0x3ED18AC8, 0x90A31E4E, 0x35704285,
+ 0x8D404798, 0x28931B53, 0x86E18FD5, 0x2332D31E,
+ 0xF68085EF, 0x5353D924, 0xFD214DA2, 0x58F21169,
+ 0xE0C21474, 0x451148BF, 0xEB63DC39, 0x4EB080F2,
+ 0x3605AC07, 0x93D6F0CC, 0x3DA4644A, 0x98773881,
+ 0x20473D9C, 0x85946157, 0x2BE6F5D1, 0x8E35A91A,
+ 0x5B87FFEB, 0xFE54A320, 0x502637A6, 0xF5F56B6D,
+ 0x4DC56E70, 0xE81632BB, 0x4664A63D, 0xE3B7FAF6,
+ 0xAD077A04, 0x08D426CF, 0xA6A6B249, 0x0375EE82,
+ 0xBB45EB9F, 0x1E96B754, 0xB0E423D2, 0x15377F19,
+ 0xC08529E8, 0x65567523, 0xCB24E1A5, 0x6EF7BD6E,
+ 0xD6C7B873, 0x7314E4B8, 0xDD66703E, 0x78B52CF5,
+ 0x6C0A580F, 0xC9D904C4, 0x67AB9042, 0xC278CC89,
+ 0x7A48C994, 0xDF9B955F, 0x71E901D9, 0xD43A5D12,
+ 0x01880BE3, 0xA45B5728, 0x0A29C3AE, 0xAFFA9F65,
+ 0x17CA9A78, 0xB219C6B3, 0x1C6B5235, 0xB9B80EFE,
+ 0xF7088E0C, 0x52DBD2C7, 0xFCA94641, 0x597A1A8A,
+ 0xE14A1F97, 0x4499435C, 0xEAEBD7DA, 0x4F388B11,
+ 0x9A8ADDE0, 0x3F59812B, 0x912B15AD, 0x34F84966,
+ 0x8CC84C7B, 0x291B10B0, 0x87698436, 0x22BAD8FD,
+ 0x5A0FF408, 0xFFDCA8C3, 0x51AE3C45, 0xF47D608E,
+ 0x4C4D6593, 0xE99E3958, 0x47ECADDE, 0xE23FF115,
+ 0x378DA7E4, 0x925EFB2F, 0x3C2C6FA9, 0x99FF3362,
+ 0x21CF367F, 0x841C6AB4, 0x2A6EFE32, 0x8FBDA2F9,
+ 0xC10D220B, 0x64DE7EC0, 0xCAACEA46, 0x6F7FB68D,
+ 0xD74FB390, 0x729CEF5B, 0xDCEE7BDD, 0x793D2716,
+ 0xAC8F71E7, 0x095C2D2C, 0xA72EB9AA, 0x02FDE561,
+ 0xBACDE07C, 0x1F1EBCB7, 0xB16C2831, 0x14BF74FA,
+ 0xD814B01E, 0x7DC7ECD5, 0xD3B57853, 0x76662498,
+ 0xCE562185, 0x6B857D4E, 0xC5F7E9C8, 0x6024B503,
+ 0xB596E3F2, 0x1045BF39, 0xBE372BBF, 0x1BE47774,
+ 0xA3D47269, 0x06072EA2, 0xA875BA24, 0x0DA6E6EF,
+ 0x4316661D, 0xE6C53AD6, 0x48B7AE50, 0xED64F29B,
+ 0x5554F786, 0xF087AB4D, 0x5EF53FCB, 0xFB266300,
+ 0x2E9435F1, 0x8B47693A, 0x2535FDBC, 0x80E6A177,
+ 0x38D6A46A, 0x9D05F8A1, 0x33776C27, 0x96A430EC,
+ 0xEE111C19, 0x4BC240D2, 0xE5B0D454, 0x4063889F,
+ 0xF8538D82, 0x5D80D149, 0xF3F245CF, 0x56211904,
+ 0x83934FF5, 0x2640133E, 0x883287B8, 0x2DE1DB73,
+ 0x95D1DE6E, 0x300282A5, 0x9E701623, 0x3BA34AE8,
+ 0x7513CA1A, 0xD0C096D1, 0x7EB20257, 0xDB615E9C,
+ 0x63515B81, 0xC682074A, 0x68F093CC, 0xCD23CF07,
+ 0x189199F6, 0xBD42C53D, 0x133051BB, 0xB6E30D70,
+ 0x0ED3086D, 0xAB0054A6, 0x0572C020, 0xA0A19CEB,
+ 0xB41EE811, 0x11CDB4DA, 0xBFBF205C, 0x1A6C7C97,
+ 0xA25C798A, 0x078F2541, 0xA9FDB1C7, 0x0C2EED0C,
+ 0xD99CBBFD, 0x7C4FE736, 0xD23D73B0, 0x77EE2F7B,
+ 0xCFDE2A66, 0x6A0D76AD, 0xC47FE22B, 0x61ACBEE0,
+ 0x2F1C3E12, 0x8ACF62D9, 0x24BDF65F, 0x816EAA94,
+ 0x395EAF89, 0x9C8DF342, 0x32FF67C4, 0x972C3B0F,
+ 0x429E6DFE, 0xE74D3135, 0x493FA5B3, 0xECECF978,
+ 0x54DCFC65, 0xF10FA0AE, 0x5F7D3428, 0xFAAE68E3,
+ 0x821B4416, 0x27C818DD, 0x89BA8C5B, 0x2C69D090,
+ 0x9459D58D, 0x318A8946, 0x9FF81DC0, 0x3A2B410B,
+ 0xEF9917FA, 0x4A4A4B31, 0xE438DFB7, 0x41EB837C,
+ 0xF9DB8661, 0x5C08DAAA, 0xF27A4E2C, 0x57A912E7,
+ 0x19199215, 0xBCCACEDE, 0x12B85A58, 0xB76B0693,
+ 0x0F5B038E, 0xAA885F45, 0x04FACBC3, 0xA1299708,
+ 0x749BC1F9, 0xD1489D32, 0x7F3A09B4, 0xDAE9557F,
+ 0x62D95062, 0xC70A0CA9, 0x6978982F, 0xCCABC4E4
+ }, {
+ 0x00000000, 0xB40B77A6, 0x29119F97, 0x9D1AE831,
+ 0x13244FF4, 0xA72F3852, 0x3A35D063, 0x8E3EA7C5,
+ 0x674EEF33, 0xD3459895, 0x4E5F70A4, 0xFA540702,
+ 0x746AA0C7, 0xC061D761, 0x5D7B3F50, 0xE97048F6,
+ 0xCE9CDE67, 0x7A97A9C1, 0xE78D41F0, 0x53863656,
+ 0xDDB89193, 0x69B3E635, 0xF4A90E04, 0x40A279A2,
+ 0xA9D23154, 0x1DD946F2, 0x80C3AEC3, 0x34C8D965,
+ 0xBAF67EA0, 0x0EFD0906, 0x93E7E137, 0x27EC9691,
+ 0x9C39BDCF, 0x2832CA69, 0xB5282258, 0x012355FE,
+ 0x8F1DF23B, 0x3B16859D, 0xA60C6DAC, 0x12071A0A,
+ 0xFB7752FC, 0x4F7C255A, 0xD266CD6B, 0x666DBACD,
+ 0xE8531D08, 0x5C586AAE, 0xC142829F, 0x7549F539,
+ 0x52A563A8, 0xE6AE140E, 0x7BB4FC3F, 0xCFBF8B99,
+ 0x41812C5C, 0xF58A5BFA, 0x6890B3CB, 0xDC9BC46D,
+ 0x35EB8C9B, 0x81E0FB3D, 0x1CFA130C, 0xA8F164AA,
+ 0x26CFC36F, 0x92C4B4C9, 0x0FDE5CF8, 0xBBD52B5E,
+ 0x79750B44, 0xCD7E7CE2, 0x506494D3, 0xE46FE375,
+ 0x6A5144B0, 0xDE5A3316, 0x4340DB27, 0xF74BAC81,
+ 0x1E3BE477, 0xAA3093D1, 0x372A7BE0, 0x83210C46,
+ 0x0D1FAB83, 0xB914DC25, 0x240E3414, 0x900543B2,
+ 0xB7E9D523, 0x03E2A285, 0x9EF84AB4, 0x2AF33D12,
+ 0xA4CD9AD7, 0x10C6ED71, 0x8DDC0540, 0x39D772E6,
+ 0xD0A73A10, 0x64AC4DB6, 0xF9B6A587, 0x4DBDD221,
+ 0xC38375E4, 0x77880242, 0xEA92EA73, 0x5E999DD5,
+ 0xE54CB68B, 0x5147C12D, 0xCC5D291C, 0x78565EBA,
+ 0xF668F97F, 0x42638ED9, 0xDF7966E8, 0x6B72114E,
+ 0x820259B8, 0x36092E1E, 0xAB13C62F, 0x1F18B189,
+ 0x9126164C, 0x252D61EA, 0xB83789DB, 0x0C3CFE7D,
+ 0x2BD068EC, 0x9FDB1F4A, 0x02C1F77B, 0xB6CA80DD,
+ 0x38F42718, 0x8CFF50BE, 0x11E5B88F, 0xA5EECF29,
+ 0x4C9E87DF, 0xF895F079, 0x658F1848, 0xD1846FEE,
+ 0x5FBAC82B, 0xEBB1BF8D, 0x76AB57BC, 0xC2A0201A,
+ 0xF2EA1688, 0x46E1612E, 0xDBFB891F, 0x6FF0FEB9,
+ 0xE1CE597C, 0x55C52EDA, 0xC8DFC6EB, 0x7CD4B14D,
+ 0x95A4F9BB, 0x21AF8E1D, 0xBCB5662C, 0x08BE118A,
+ 0x8680B64F, 0x328BC1E9, 0xAF9129D8, 0x1B9A5E7E,
+ 0x3C76C8EF, 0x887DBF49, 0x15675778, 0xA16C20DE,
+ 0x2F52871B, 0x9B59F0BD, 0x0643188C, 0xB2486F2A,
+ 0x5B3827DC, 0xEF33507A, 0x7229B84B, 0xC622CFED,
+ 0x481C6828, 0xFC171F8E, 0x610DF7BF, 0xD5068019,
+ 0x6ED3AB47, 0xDAD8DCE1, 0x47C234D0, 0xF3C94376,
+ 0x7DF7E4B3, 0xC9FC9315, 0x54E67B24, 0xE0ED0C82,
+ 0x099D4474, 0xBD9633D2, 0x208CDBE3, 0x9487AC45,
+ 0x1AB90B80, 0xAEB27C26, 0x33A89417, 0x87A3E3B1,
+ 0xA04F7520, 0x14440286, 0x895EEAB7, 0x3D559D11,
+ 0xB36B3AD4, 0x07604D72, 0x9A7AA543, 0x2E71D2E5,
+ 0xC7019A13, 0x730AEDB5, 0xEE100584, 0x5A1B7222,
+ 0xD425D5E7, 0x602EA241, 0xFD344A70, 0x493F3DD6,
+ 0x8B9F1DCC, 0x3F946A6A, 0xA28E825B, 0x1685F5FD,
+ 0x98BB5238, 0x2CB0259E, 0xB1AACDAF, 0x05A1BA09,
+ 0xECD1F2FF, 0x58DA8559, 0xC5C06D68, 0x71CB1ACE,
+ 0xFFF5BD0B, 0x4BFECAAD, 0xD6E4229C, 0x62EF553A,
+ 0x4503C3AB, 0xF108B40D, 0x6C125C3C, 0xD8192B9A,
+ 0x56278C5F, 0xE22CFBF9, 0x7F3613C8, 0xCB3D646E,
+ 0x224D2C98, 0x96465B3E, 0x0B5CB30F, 0xBF57C4A9,
+ 0x3169636C, 0x856214CA, 0x1878FCFB, 0xAC738B5D,
+ 0x17A6A003, 0xA3ADD7A5, 0x3EB73F94, 0x8ABC4832,
+ 0x0482EFF7, 0xB0899851, 0x2D937060, 0x999807C6,
+ 0x70E84F30, 0xC4E33896, 0x59F9D0A7, 0xEDF2A701,
+ 0x63CC00C4, 0xD7C77762, 0x4ADD9F53, 0xFED6E8F5,
+ 0xD93A7E64, 0x6D3109C2, 0xF02BE1F3, 0x44209655,
+ 0xCA1E3190, 0x7E154636, 0xE30FAE07, 0x5704D9A1,
+ 0xBE749157, 0x0A7FE6F1, 0x97650EC0, 0x236E7966,
+ 0xAD50DEA3, 0x195BA905, 0x84414134, 0x304A3692
+ }, {
+ 0x00000000, 0x9E00AACC, 0x7D072542, 0xE3078F8E,
+ 0xFA0E4A84, 0x640EE048, 0x87096FC6, 0x1909C50A,
+ 0xB51BE5D3, 0x2B1B4F1F, 0xC81CC091, 0x561C6A5D,
+ 0x4F15AF57, 0xD115059B, 0x32128A15, 0xAC1220D9,
+ 0x2B31BB7C, 0xB53111B0, 0x56369E3E, 0xC83634F2,
+ 0xD13FF1F8, 0x4F3F5B34, 0xAC38D4BA, 0x32387E76,
+ 0x9E2A5EAF, 0x002AF463, 0xE32D7BED, 0x7D2DD121,
+ 0x6424142B, 0xFA24BEE7, 0x19233169, 0x87239BA5,
+ 0x566276F9, 0xC862DC35, 0x2B6553BB, 0xB565F977,
+ 0xAC6C3C7D, 0x326C96B1, 0xD16B193F, 0x4F6BB3F3,
+ 0xE379932A, 0x7D7939E6, 0x9E7EB668, 0x007E1CA4,
+ 0x1977D9AE, 0x87777362, 0x6470FCEC, 0xFA705620,
+ 0x7D53CD85, 0xE3536749, 0x0054E8C7, 0x9E54420B,
+ 0x875D8701, 0x195D2DCD, 0xFA5AA243, 0x645A088F,
+ 0xC8482856, 0x5648829A, 0xB54F0D14, 0x2B4FA7D8,
+ 0x324662D2, 0xAC46C81E, 0x4F414790, 0xD141ED5C,
+ 0xEDC29D29, 0x73C237E5, 0x90C5B86B, 0x0EC512A7,
+ 0x17CCD7AD, 0x89CC7D61, 0x6ACBF2EF, 0xF4CB5823,
+ 0x58D978FA, 0xC6D9D236, 0x25DE5DB8, 0xBBDEF774,
+ 0xA2D7327E, 0x3CD798B2, 0xDFD0173C, 0x41D0BDF0,
+ 0xC6F32655, 0x58F38C99, 0xBBF40317, 0x25F4A9DB,
+ 0x3CFD6CD1, 0xA2FDC61D, 0x41FA4993, 0xDFFAE35F,
+ 0x73E8C386, 0xEDE8694A, 0x0EEFE6C4, 0x90EF4C08,
+ 0x89E68902, 0x17E623CE, 0xF4E1AC40, 0x6AE1068C,
+ 0xBBA0EBD0, 0x25A0411C, 0xC6A7CE92, 0x58A7645E,
+ 0x41AEA154, 0xDFAE0B98, 0x3CA98416, 0xA2A92EDA,
+ 0x0EBB0E03, 0x90BBA4CF, 0x73BC2B41, 0xEDBC818D,
+ 0xF4B54487, 0x6AB5EE4B, 0x89B261C5, 0x17B2CB09,
+ 0x909150AC, 0x0E91FA60, 0xED9675EE, 0x7396DF22,
+ 0x6A9F1A28, 0xF49FB0E4, 0x17983F6A, 0x899895A6,
+ 0x258AB57F, 0xBB8A1FB3, 0x588D903D, 0xC68D3AF1,
+ 0xDF84FFFB, 0x41845537, 0xA283DAB9, 0x3C837075,
+ 0xDA853B53, 0x4485919F, 0xA7821E11, 0x3982B4DD,
+ 0x208B71D7, 0xBE8BDB1B, 0x5D8C5495, 0xC38CFE59,
+ 0x6F9EDE80, 0xF19E744C, 0x1299FBC2, 0x8C99510E,
+ 0x95909404, 0x0B903EC8, 0xE897B146, 0x76971B8A,
+ 0xF1B4802F, 0x6FB42AE3, 0x8CB3A56D, 0x12B30FA1,
+ 0x0BBACAAB, 0x95BA6067, 0x76BDEFE9, 0xE8BD4525,
+ 0x44AF65FC, 0xDAAFCF30, 0x39A840BE, 0xA7A8EA72,
+ 0xBEA12F78, 0x20A185B4, 0xC3A60A3A, 0x5DA6A0F6,
+ 0x8CE74DAA, 0x12E7E766, 0xF1E068E8, 0x6FE0C224,
+ 0x76E9072E, 0xE8E9ADE2, 0x0BEE226C, 0x95EE88A0,
+ 0x39FCA879, 0xA7FC02B5, 0x44FB8D3B, 0xDAFB27F7,
+ 0xC3F2E2FD, 0x5DF24831, 0xBEF5C7BF, 0x20F56D73,
+ 0xA7D6F6D6, 0x39D65C1A, 0xDAD1D394, 0x44D17958,
+ 0x5DD8BC52, 0xC3D8169E, 0x20DF9910, 0xBEDF33DC,
+ 0x12CD1305, 0x8CCDB9C9, 0x6FCA3647, 0xF1CA9C8B,
+ 0xE8C35981, 0x76C3F34D, 0x95C47CC3, 0x0BC4D60F,
+ 0x3747A67A, 0xA9470CB6, 0x4A408338, 0xD44029F4,
+ 0xCD49ECFE, 0x53494632, 0xB04EC9BC, 0x2E4E6370,
+ 0x825C43A9, 0x1C5CE965, 0xFF5B66EB, 0x615BCC27,
+ 0x7852092D, 0xE652A3E1, 0x05552C6F, 0x9B5586A3,
+ 0x1C761D06, 0x8276B7CA, 0x61713844, 0xFF719288,
+ 0xE6785782, 0x7878FD4E, 0x9B7F72C0, 0x057FD80C,
+ 0xA96DF8D5, 0x376D5219, 0xD46ADD97, 0x4A6A775B,
+ 0x5363B251, 0xCD63189D, 0x2E649713, 0xB0643DDF,
+ 0x6125D083, 0xFF257A4F, 0x1C22F5C1, 0x82225F0D,
+ 0x9B2B9A07, 0x052B30CB, 0xE62CBF45, 0x782C1589,
+ 0xD43E3550, 0x4A3E9F9C, 0xA9391012, 0x3739BADE,
+ 0x2E307FD4, 0xB030D518, 0x53375A96, 0xCD37F05A,
+ 0x4A146BFF, 0xD414C133, 0x37134EBD, 0xA913E471,
+ 0xB01A217B, 0x2E1A8BB7, 0xCD1D0439, 0x531DAEF5,
+ 0xFF0F8E2C, 0x610F24E0, 0x8208AB6E, 0x1C0801A2,
+ 0x0501C4A8, 0x9B016E64, 0x7806E1EA, 0xE6064B26
+ }
+};
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_table_le.h b/Utilities/cmliblzma/liblzma/check/crc32_table_le.h
new file mode 100644
index 000000000..25f4fc443
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_table_le.h
@@ -0,0 +1,525 @@
+/* This file has been automatically generated by crc32_tablegen.c. */
+
+const uint32_t lzma_crc32_table[8][256] = {
+ {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+ }, {
+ 0x00000000, 0x191B3141, 0x32366282, 0x2B2D53C3,
+ 0x646CC504, 0x7D77F445, 0x565AA786, 0x4F4196C7,
+ 0xC8D98A08, 0xD1C2BB49, 0xFAEFE88A, 0xE3F4D9CB,
+ 0xACB54F0C, 0xB5AE7E4D, 0x9E832D8E, 0x87981CCF,
+ 0x4AC21251, 0x53D92310, 0x78F470D3, 0x61EF4192,
+ 0x2EAED755, 0x37B5E614, 0x1C98B5D7, 0x05838496,
+ 0x821B9859, 0x9B00A918, 0xB02DFADB, 0xA936CB9A,
+ 0xE6775D5D, 0xFF6C6C1C, 0xD4413FDF, 0xCD5A0E9E,
+ 0x958424A2, 0x8C9F15E3, 0xA7B24620, 0xBEA97761,
+ 0xF1E8E1A6, 0xE8F3D0E7, 0xC3DE8324, 0xDAC5B265,
+ 0x5D5DAEAA, 0x44469FEB, 0x6F6BCC28, 0x7670FD69,
+ 0x39316BAE, 0x202A5AEF, 0x0B07092C, 0x121C386D,
+ 0xDF4636F3, 0xC65D07B2, 0xED705471, 0xF46B6530,
+ 0xBB2AF3F7, 0xA231C2B6, 0x891C9175, 0x9007A034,
+ 0x179FBCFB, 0x0E848DBA, 0x25A9DE79, 0x3CB2EF38,
+ 0x73F379FF, 0x6AE848BE, 0x41C51B7D, 0x58DE2A3C,
+ 0xF0794F05, 0xE9627E44, 0xC24F2D87, 0xDB541CC6,
+ 0x94158A01, 0x8D0EBB40, 0xA623E883, 0xBF38D9C2,
+ 0x38A0C50D, 0x21BBF44C, 0x0A96A78F, 0x138D96CE,
+ 0x5CCC0009, 0x45D73148, 0x6EFA628B, 0x77E153CA,
+ 0xBABB5D54, 0xA3A06C15, 0x888D3FD6, 0x91960E97,
+ 0xDED79850, 0xC7CCA911, 0xECE1FAD2, 0xF5FACB93,
+ 0x7262D75C, 0x6B79E61D, 0x4054B5DE, 0x594F849F,
+ 0x160E1258, 0x0F152319, 0x243870DA, 0x3D23419B,
+ 0x65FD6BA7, 0x7CE65AE6, 0x57CB0925, 0x4ED03864,
+ 0x0191AEA3, 0x188A9FE2, 0x33A7CC21, 0x2ABCFD60,
+ 0xAD24E1AF, 0xB43FD0EE, 0x9F12832D, 0x8609B26C,
+ 0xC94824AB, 0xD05315EA, 0xFB7E4629, 0xE2657768,
+ 0x2F3F79F6, 0x362448B7, 0x1D091B74, 0x04122A35,
+ 0x4B53BCF2, 0x52488DB3, 0x7965DE70, 0x607EEF31,
+ 0xE7E6F3FE, 0xFEFDC2BF, 0xD5D0917C, 0xCCCBA03D,
+ 0x838A36FA, 0x9A9107BB, 0xB1BC5478, 0xA8A76539,
+ 0x3B83984B, 0x2298A90A, 0x09B5FAC9, 0x10AECB88,
+ 0x5FEF5D4F, 0x46F46C0E, 0x6DD93FCD, 0x74C20E8C,
+ 0xF35A1243, 0xEA412302, 0xC16C70C1, 0xD8774180,
+ 0x9736D747, 0x8E2DE606, 0xA500B5C5, 0xBC1B8484,
+ 0x71418A1A, 0x685ABB5B, 0x4377E898, 0x5A6CD9D9,
+ 0x152D4F1E, 0x0C367E5F, 0x271B2D9C, 0x3E001CDD,
+ 0xB9980012, 0xA0833153, 0x8BAE6290, 0x92B553D1,
+ 0xDDF4C516, 0xC4EFF457, 0xEFC2A794, 0xF6D996D5,
+ 0xAE07BCE9, 0xB71C8DA8, 0x9C31DE6B, 0x852AEF2A,
+ 0xCA6B79ED, 0xD37048AC, 0xF85D1B6F, 0xE1462A2E,
+ 0x66DE36E1, 0x7FC507A0, 0x54E85463, 0x4DF36522,
+ 0x02B2F3E5, 0x1BA9C2A4, 0x30849167, 0x299FA026,
+ 0xE4C5AEB8, 0xFDDE9FF9, 0xD6F3CC3A, 0xCFE8FD7B,
+ 0x80A96BBC, 0x99B25AFD, 0xB29F093E, 0xAB84387F,
+ 0x2C1C24B0, 0x350715F1, 0x1E2A4632, 0x07317773,
+ 0x4870E1B4, 0x516BD0F5, 0x7A468336, 0x635DB277,
+ 0xCBFAD74E, 0xD2E1E60F, 0xF9CCB5CC, 0xE0D7848D,
+ 0xAF96124A, 0xB68D230B, 0x9DA070C8, 0x84BB4189,
+ 0x03235D46, 0x1A386C07, 0x31153FC4, 0x280E0E85,
+ 0x674F9842, 0x7E54A903, 0x5579FAC0, 0x4C62CB81,
+ 0x8138C51F, 0x9823F45E, 0xB30EA79D, 0xAA1596DC,
+ 0xE554001B, 0xFC4F315A, 0xD7626299, 0xCE7953D8,
+ 0x49E14F17, 0x50FA7E56, 0x7BD72D95, 0x62CC1CD4,
+ 0x2D8D8A13, 0x3496BB52, 0x1FBBE891, 0x06A0D9D0,
+ 0x5E7EF3EC, 0x4765C2AD, 0x6C48916E, 0x7553A02F,
+ 0x3A1236E8, 0x230907A9, 0x0824546A, 0x113F652B,
+ 0x96A779E4, 0x8FBC48A5, 0xA4911B66, 0xBD8A2A27,
+ 0xF2CBBCE0, 0xEBD08DA1, 0xC0FDDE62, 0xD9E6EF23,
+ 0x14BCE1BD, 0x0DA7D0FC, 0x268A833F, 0x3F91B27E,
+ 0x70D024B9, 0x69CB15F8, 0x42E6463B, 0x5BFD777A,
+ 0xDC656BB5, 0xC57E5AF4, 0xEE530937, 0xF7483876,
+ 0xB809AEB1, 0xA1129FF0, 0x8A3FCC33, 0x9324FD72
+ }, {
+ 0x00000000, 0x01C26A37, 0x0384D46E, 0x0246BE59,
+ 0x0709A8DC, 0x06CBC2EB, 0x048D7CB2, 0x054F1685,
+ 0x0E1351B8, 0x0FD13B8F, 0x0D9785D6, 0x0C55EFE1,
+ 0x091AF964, 0x08D89353, 0x0A9E2D0A, 0x0B5C473D,
+ 0x1C26A370, 0x1DE4C947, 0x1FA2771E, 0x1E601D29,
+ 0x1B2F0BAC, 0x1AED619B, 0x18ABDFC2, 0x1969B5F5,
+ 0x1235F2C8, 0x13F798FF, 0x11B126A6, 0x10734C91,
+ 0x153C5A14, 0x14FE3023, 0x16B88E7A, 0x177AE44D,
+ 0x384D46E0, 0x398F2CD7, 0x3BC9928E, 0x3A0BF8B9,
+ 0x3F44EE3C, 0x3E86840B, 0x3CC03A52, 0x3D025065,
+ 0x365E1758, 0x379C7D6F, 0x35DAC336, 0x3418A901,
+ 0x3157BF84, 0x3095D5B3, 0x32D36BEA, 0x331101DD,
+ 0x246BE590, 0x25A98FA7, 0x27EF31FE, 0x262D5BC9,
+ 0x23624D4C, 0x22A0277B, 0x20E69922, 0x2124F315,
+ 0x2A78B428, 0x2BBADE1F, 0x29FC6046, 0x283E0A71,
+ 0x2D711CF4, 0x2CB376C3, 0x2EF5C89A, 0x2F37A2AD,
+ 0x709A8DC0, 0x7158E7F7, 0x731E59AE, 0x72DC3399,
+ 0x7793251C, 0x76514F2B, 0x7417F172, 0x75D59B45,
+ 0x7E89DC78, 0x7F4BB64F, 0x7D0D0816, 0x7CCF6221,
+ 0x798074A4, 0x78421E93, 0x7A04A0CA, 0x7BC6CAFD,
+ 0x6CBC2EB0, 0x6D7E4487, 0x6F38FADE, 0x6EFA90E9,
+ 0x6BB5866C, 0x6A77EC5B, 0x68315202, 0x69F33835,
+ 0x62AF7F08, 0x636D153F, 0x612BAB66, 0x60E9C151,
+ 0x65A6D7D4, 0x6464BDE3, 0x662203BA, 0x67E0698D,
+ 0x48D7CB20, 0x4915A117, 0x4B531F4E, 0x4A917579,
+ 0x4FDE63FC, 0x4E1C09CB, 0x4C5AB792, 0x4D98DDA5,
+ 0x46C49A98, 0x4706F0AF, 0x45404EF6, 0x448224C1,
+ 0x41CD3244, 0x400F5873, 0x4249E62A, 0x438B8C1D,
+ 0x54F16850, 0x55330267, 0x5775BC3E, 0x56B7D609,
+ 0x53F8C08C, 0x523AAABB, 0x507C14E2, 0x51BE7ED5,
+ 0x5AE239E8, 0x5B2053DF, 0x5966ED86, 0x58A487B1,
+ 0x5DEB9134, 0x5C29FB03, 0x5E6F455A, 0x5FAD2F6D,
+ 0xE1351B80, 0xE0F771B7, 0xE2B1CFEE, 0xE373A5D9,
+ 0xE63CB35C, 0xE7FED96B, 0xE5B86732, 0xE47A0D05,
+ 0xEF264A38, 0xEEE4200F, 0xECA29E56, 0xED60F461,
+ 0xE82FE2E4, 0xE9ED88D3, 0xEBAB368A, 0xEA695CBD,
+ 0xFD13B8F0, 0xFCD1D2C7, 0xFE976C9E, 0xFF5506A9,
+ 0xFA1A102C, 0xFBD87A1B, 0xF99EC442, 0xF85CAE75,
+ 0xF300E948, 0xF2C2837F, 0xF0843D26, 0xF1465711,
+ 0xF4094194, 0xF5CB2BA3, 0xF78D95FA, 0xF64FFFCD,
+ 0xD9785D60, 0xD8BA3757, 0xDAFC890E, 0xDB3EE339,
+ 0xDE71F5BC, 0xDFB39F8B, 0xDDF521D2, 0xDC374BE5,
+ 0xD76B0CD8, 0xD6A966EF, 0xD4EFD8B6, 0xD52DB281,
+ 0xD062A404, 0xD1A0CE33, 0xD3E6706A, 0xD2241A5D,
+ 0xC55EFE10, 0xC49C9427, 0xC6DA2A7E, 0xC7184049,
+ 0xC25756CC, 0xC3953CFB, 0xC1D382A2, 0xC011E895,
+ 0xCB4DAFA8, 0xCA8FC59F, 0xC8C97BC6, 0xC90B11F1,
+ 0xCC440774, 0xCD866D43, 0xCFC0D31A, 0xCE02B92D,
+ 0x91AF9640, 0x906DFC77, 0x922B422E, 0x93E92819,
+ 0x96A63E9C, 0x976454AB, 0x9522EAF2, 0x94E080C5,
+ 0x9FBCC7F8, 0x9E7EADCF, 0x9C381396, 0x9DFA79A1,
+ 0x98B56F24, 0x99770513, 0x9B31BB4A, 0x9AF3D17D,
+ 0x8D893530, 0x8C4B5F07, 0x8E0DE15E, 0x8FCF8B69,
+ 0x8A809DEC, 0x8B42F7DB, 0x89044982, 0x88C623B5,
+ 0x839A6488, 0x82580EBF, 0x801EB0E6, 0x81DCDAD1,
+ 0x8493CC54, 0x8551A663, 0x8717183A, 0x86D5720D,
+ 0xA9E2D0A0, 0xA820BA97, 0xAA6604CE, 0xABA46EF9,
+ 0xAEEB787C, 0xAF29124B, 0xAD6FAC12, 0xACADC625,
+ 0xA7F18118, 0xA633EB2F, 0xA4755576, 0xA5B73F41,
+ 0xA0F829C4, 0xA13A43F3, 0xA37CFDAA, 0xA2BE979D,
+ 0xB5C473D0, 0xB40619E7, 0xB640A7BE, 0xB782CD89,
+ 0xB2CDDB0C, 0xB30FB13B, 0xB1490F62, 0xB08B6555,
+ 0xBBD72268, 0xBA15485F, 0xB853F606, 0xB9919C31,
+ 0xBCDE8AB4, 0xBD1CE083, 0xBF5A5EDA, 0xBE9834ED
+ }, {
+ 0x00000000, 0xB8BC6765, 0xAA09C88B, 0x12B5AFEE,
+ 0x8F629757, 0x37DEF032, 0x256B5FDC, 0x9DD738B9,
+ 0xC5B428EF, 0x7D084F8A, 0x6FBDE064, 0xD7018701,
+ 0x4AD6BFB8, 0xF26AD8DD, 0xE0DF7733, 0x58631056,
+ 0x5019579F, 0xE8A530FA, 0xFA109F14, 0x42ACF871,
+ 0xDF7BC0C8, 0x67C7A7AD, 0x75720843, 0xCDCE6F26,
+ 0x95AD7F70, 0x2D111815, 0x3FA4B7FB, 0x8718D09E,
+ 0x1ACFE827, 0xA2738F42, 0xB0C620AC, 0x087A47C9,
+ 0xA032AF3E, 0x188EC85B, 0x0A3B67B5, 0xB28700D0,
+ 0x2F503869, 0x97EC5F0C, 0x8559F0E2, 0x3DE59787,
+ 0x658687D1, 0xDD3AE0B4, 0xCF8F4F5A, 0x7733283F,
+ 0xEAE41086, 0x525877E3, 0x40EDD80D, 0xF851BF68,
+ 0xF02BF8A1, 0x48979FC4, 0x5A22302A, 0xE29E574F,
+ 0x7F496FF6, 0xC7F50893, 0xD540A77D, 0x6DFCC018,
+ 0x359FD04E, 0x8D23B72B, 0x9F9618C5, 0x272A7FA0,
+ 0xBAFD4719, 0x0241207C, 0x10F48F92, 0xA848E8F7,
+ 0x9B14583D, 0x23A83F58, 0x311D90B6, 0x89A1F7D3,
+ 0x1476CF6A, 0xACCAA80F, 0xBE7F07E1, 0x06C36084,
+ 0x5EA070D2, 0xE61C17B7, 0xF4A9B859, 0x4C15DF3C,
+ 0xD1C2E785, 0x697E80E0, 0x7BCB2F0E, 0xC377486B,
+ 0xCB0D0FA2, 0x73B168C7, 0x6104C729, 0xD9B8A04C,
+ 0x446F98F5, 0xFCD3FF90, 0xEE66507E, 0x56DA371B,
+ 0x0EB9274D, 0xB6054028, 0xA4B0EFC6, 0x1C0C88A3,
+ 0x81DBB01A, 0x3967D77F, 0x2BD27891, 0x936E1FF4,
+ 0x3B26F703, 0x839A9066, 0x912F3F88, 0x299358ED,
+ 0xB4446054, 0x0CF80731, 0x1E4DA8DF, 0xA6F1CFBA,
+ 0xFE92DFEC, 0x462EB889, 0x549B1767, 0xEC277002,
+ 0x71F048BB, 0xC94C2FDE, 0xDBF98030, 0x6345E755,
+ 0x6B3FA09C, 0xD383C7F9, 0xC1366817, 0x798A0F72,
+ 0xE45D37CB, 0x5CE150AE, 0x4E54FF40, 0xF6E89825,
+ 0xAE8B8873, 0x1637EF16, 0x048240F8, 0xBC3E279D,
+ 0x21E91F24, 0x99557841, 0x8BE0D7AF, 0x335CB0CA,
+ 0xED59B63B, 0x55E5D15E, 0x47507EB0, 0xFFEC19D5,
+ 0x623B216C, 0xDA874609, 0xC832E9E7, 0x708E8E82,
+ 0x28ED9ED4, 0x9051F9B1, 0x82E4565F, 0x3A58313A,
+ 0xA78F0983, 0x1F336EE6, 0x0D86C108, 0xB53AA66D,
+ 0xBD40E1A4, 0x05FC86C1, 0x1749292F, 0xAFF54E4A,
+ 0x322276F3, 0x8A9E1196, 0x982BBE78, 0x2097D91D,
+ 0x78F4C94B, 0xC048AE2E, 0xD2FD01C0, 0x6A4166A5,
+ 0xF7965E1C, 0x4F2A3979, 0x5D9F9697, 0xE523F1F2,
+ 0x4D6B1905, 0xF5D77E60, 0xE762D18E, 0x5FDEB6EB,
+ 0xC2098E52, 0x7AB5E937, 0x680046D9, 0xD0BC21BC,
+ 0x88DF31EA, 0x3063568F, 0x22D6F961, 0x9A6A9E04,
+ 0x07BDA6BD, 0xBF01C1D8, 0xADB46E36, 0x15080953,
+ 0x1D724E9A, 0xA5CE29FF, 0xB77B8611, 0x0FC7E174,
+ 0x9210D9CD, 0x2AACBEA8, 0x38191146, 0x80A57623,
+ 0xD8C66675, 0x607A0110, 0x72CFAEFE, 0xCA73C99B,
+ 0x57A4F122, 0xEF189647, 0xFDAD39A9, 0x45115ECC,
+ 0x764DEE06, 0xCEF18963, 0xDC44268D, 0x64F841E8,
+ 0xF92F7951, 0x41931E34, 0x5326B1DA, 0xEB9AD6BF,
+ 0xB3F9C6E9, 0x0B45A18C, 0x19F00E62, 0xA14C6907,
+ 0x3C9B51BE, 0x842736DB, 0x96929935, 0x2E2EFE50,
+ 0x2654B999, 0x9EE8DEFC, 0x8C5D7112, 0x34E11677,
+ 0xA9362ECE, 0x118A49AB, 0x033FE645, 0xBB838120,
+ 0xE3E09176, 0x5B5CF613, 0x49E959FD, 0xF1553E98,
+ 0x6C820621, 0xD43E6144, 0xC68BCEAA, 0x7E37A9CF,
+ 0xD67F4138, 0x6EC3265D, 0x7C7689B3, 0xC4CAEED6,
+ 0x591DD66F, 0xE1A1B10A, 0xF3141EE4, 0x4BA87981,
+ 0x13CB69D7, 0xAB770EB2, 0xB9C2A15C, 0x017EC639,
+ 0x9CA9FE80, 0x241599E5, 0x36A0360B, 0x8E1C516E,
+ 0x866616A7, 0x3EDA71C2, 0x2C6FDE2C, 0x94D3B949,
+ 0x090481F0, 0xB1B8E695, 0xA30D497B, 0x1BB12E1E,
+ 0x43D23E48, 0xFB6E592D, 0xE9DBF6C3, 0x516791A6,
+ 0xCCB0A91F, 0x740CCE7A, 0x66B96194, 0xDE0506F1
+ }, {
+ 0x00000000, 0x3D6029B0, 0x7AC05360, 0x47A07AD0,
+ 0xF580A6C0, 0xC8E08F70, 0x8F40F5A0, 0xB220DC10,
+ 0x30704BC1, 0x0D106271, 0x4AB018A1, 0x77D03111,
+ 0xC5F0ED01, 0xF890C4B1, 0xBF30BE61, 0x825097D1,
+ 0x60E09782, 0x5D80BE32, 0x1A20C4E2, 0x2740ED52,
+ 0x95603142, 0xA80018F2, 0xEFA06222, 0xD2C04B92,
+ 0x5090DC43, 0x6DF0F5F3, 0x2A508F23, 0x1730A693,
+ 0xA5107A83, 0x98705333, 0xDFD029E3, 0xE2B00053,
+ 0xC1C12F04, 0xFCA106B4, 0xBB017C64, 0x866155D4,
+ 0x344189C4, 0x0921A074, 0x4E81DAA4, 0x73E1F314,
+ 0xF1B164C5, 0xCCD14D75, 0x8B7137A5, 0xB6111E15,
+ 0x0431C205, 0x3951EBB5, 0x7EF19165, 0x4391B8D5,
+ 0xA121B886, 0x9C419136, 0xDBE1EBE6, 0xE681C256,
+ 0x54A11E46, 0x69C137F6, 0x2E614D26, 0x13016496,
+ 0x9151F347, 0xAC31DAF7, 0xEB91A027, 0xD6F18997,
+ 0x64D15587, 0x59B17C37, 0x1E1106E7, 0x23712F57,
+ 0x58F35849, 0x659371F9, 0x22330B29, 0x1F532299,
+ 0xAD73FE89, 0x9013D739, 0xD7B3ADE9, 0xEAD38459,
+ 0x68831388, 0x55E33A38, 0x124340E8, 0x2F236958,
+ 0x9D03B548, 0xA0639CF8, 0xE7C3E628, 0xDAA3CF98,
+ 0x3813CFCB, 0x0573E67B, 0x42D39CAB, 0x7FB3B51B,
+ 0xCD93690B, 0xF0F340BB, 0xB7533A6B, 0x8A3313DB,
+ 0x0863840A, 0x3503ADBA, 0x72A3D76A, 0x4FC3FEDA,
+ 0xFDE322CA, 0xC0830B7A, 0x872371AA, 0xBA43581A,
+ 0x9932774D, 0xA4525EFD, 0xE3F2242D, 0xDE920D9D,
+ 0x6CB2D18D, 0x51D2F83D, 0x167282ED, 0x2B12AB5D,
+ 0xA9423C8C, 0x9422153C, 0xD3826FEC, 0xEEE2465C,
+ 0x5CC29A4C, 0x61A2B3FC, 0x2602C92C, 0x1B62E09C,
+ 0xF9D2E0CF, 0xC4B2C97F, 0x8312B3AF, 0xBE729A1F,
+ 0x0C52460F, 0x31326FBF, 0x7692156F, 0x4BF23CDF,
+ 0xC9A2AB0E, 0xF4C282BE, 0xB362F86E, 0x8E02D1DE,
+ 0x3C220DCE, 0x0142247E, 0x46E25EAE, 0x7B82771E,
+ 0xB1E6B092, 0x8C869922, 0xCB26E3F2, 0xF646CA42,
+ 0x44661652, 0x79063FE2, 0x3EA64532, 0x03C66C82,
+ 0x8196FB53, 0xBCF6D2E3, 0xFB56A833, 0xC6368183,
+ 0x74165D93, 0x49767423, 0x0ED60EF3, 0x33B62743,
+ 0xD1062710, 0xEC660EA0, 0xABC67470, 0x96A65DC0,
+ 0x248681D0, 0x19E6A860, 0x5E46D2B0, 0x6326FB00,
+ 0xE1766CD1, 0xDC164561, 0x9BB63FB1, 0xA6D61601,
+ 0x14F6CA11, 0x2996E3A1, 0x6E369971, 0x5356B0C1,
+ 0x70279F96, 0x4D47B626, 0x0AE7CCF6, 0x3787E546,
+ 0x85A73956, 0xB8C710E6, 0xFF676A36, 0xC2074386,
+ 0x4057D457, 0x7D37FDE7, 0x3A978737, 0x07F7AE87,
+ 0xB5D77297, 0x88B75B27, 0xCF1721F7, 0xF2770847,
+ 0x10C70814, 0x2DA721A4, 0x6A075B74, 0x576772C4,
+ 0xE547AED4, 0xD8278764, 0x9F87FDB4, 0xA2E7D404,
+ 0x20B743D5, 0x1DD76A65, 0x5A7710B5, 0x67173905,
+ 0xD537E515, 0xE857CCA5, 0xAFF7B675, 0x92979FC5,
+ 0xE915E8DB, 0xD475C16B, 0x93D5BBBB, 0xAEB5920B,
+ 0x1C954E1B, 0x21F567AB, 0x66551D7B, 0x5B3534CB,
+ 0xD965A31A, 0xE4058AAA, 0xA3A5F07A, 0x9EC5D9CA,
+ 0x2CE505DA, 0x11852C6A, 0x562556BA, 0x6B457F0A,
+ 0x89F57F59, 0xB49556E9, 0xF3352C39, 0xCE550589,
+ 0x7C75D999, 0x4115F029, 0x06B58AF9, 0x3BD5A349,
+ 0xB9853498, 0x84E51D28, 0xC34567F8, 0xFE254E48,
+ 0x4C059258, 0x7165BBE8, 0x36C5C138, 0x0BA5E888,
+ 0x28D4C7DF, 0x15B4EE6F, 0x521494BF, 0x6F74BD0F,
+ 0xDD54611F, 0xE03448AF, 0xA794327F, 0x9AF41BCF,
+ 0x18A48C1E, 0x25C4A5AE, 0x6264DF7E, 0x5F04F6CE,
+ 0xED242ADE, 0xD044036E, 0x97E479BE, 0xAA84500E,
+ 0x4834505D, 0x755479ED, 0x32F4033D, 0x0F942A8D,
+ 0xBDB4F69D, 0x80D4DF2D, 0xC774A5FD, 0xFA148C4D,
+ 0x78441B9C, 0x4524322C, 0x028448FC, 0x3FE4614C,
+ 0x8DC4BD5C, 0xB0A494EC, 0xF704EE3C, 0xCA64C78C
+ }, {
+ 0x00000000, 0xCB5CD3A5, 0x4DC8A10B, 0x869472AE,
+ 0x9B914216, 0x50CD91B3, 0xD659E31D, 0x1D0530B8,
+ 0xEC53826D, 0x270F51C8, 0xA19B2366, 0x6AC7F0C3,
+ 0x77C2C07B, 0xBC9E13DE, 0x3A0A6170, 0xF156B2D5,
+ 0x03D6029B, 0xC88AD13E, 0x4E1EA390, 0x85427035,
+ 0x9847408D, 0x531B9328, 0xD58FE186, 0x1ED33223,
+ 0xEF8580F6, 0x24D95353, 0xA24D21FD, 0x6911F258,
+ 0x7414C2E0, 0xBF481145, 0x39DC63EB, 0xF280B04E,
+ 0x07AC0536, 0xCCF0D693, 0x4A64A43D, 0x81387798,
+ 0x9C3D4720, 0x57619485, 0xD1F5E62B, 0x1AA9358E,
+ 0xEBFF875B, 0x20A354FE, 0xA6372650, 0x6D6BF5F5,
+ 0x706EC54D, 0xBB3216E8, 0x3DA66446, 0xF6FAB7E3,
+ 0x047A07AD, 0xCF26D408, 0x49B2A6A6, 0x82EE7503,
+ 0x9FEB45BB, 0x54B7961E, 0xD223E4B0, 0x197F3715,
+ 0xE82985C0, 0x23755665, 0xA5E124CB, 0x6EBDF76E,
+ 0x73B8C7D6, 0xB8E41473, 0x3E7066DD, 0xF52CB578,
+ 0x0F580A6C, 0xC404D9C9, 0x4290AB67, 0x89CC78C2,
+ 0x94C9487A, 0x5F959BDF, 0xD901E971, 0x125D3AD4,
+ 0xE30B8801, 0x28575BA4, 0xAEC3290A, 0x659FFAAF,
+ 0x789ACA17, 0xB3C619B2, 0x35526B1C, 0xFE0EB8B9,
+ 0x0C8E08F7, 0xC7D2DB52, 0x4146A9FC, 0x8A1A7A59,
+ 0x971F4AE1, 0x5C439944, 0xDAD7EBEA, 0x118B384F,
+ 0xE0DD8A9A, 0x2B81593F, 0xAD152B91, 0x6649F834,
+ 0x7B4CC88C, 0xB0101B29, 0x36846987, 0xFDD8BA22,
+ 0x08F40F5A, 0xC3A8DCFF, 0x453CAE51, 0x8E607DF4,
+ 0x93654D4C, 0x58399EE9, 0xDEADEC47, 0x15F13FE2,
+ 0xE4A78D37, 0x2FFB5E92, 0xA96F2C3C, 0x6233FF99,
+ 0x7F36CF21, 0xB46A1C84, 0x32FE6E2A, 0xF9A2BD8F,
+ 0x0B220DC1, 0xC07EDE64, 0x46EAACCA, 0x8DB67F6F,
+ 0x90B34FD7, 0x5BEF9C72, 0xDD7BEEDC, 0x16273D79,
+ 0xE7718FAC, 0x2C2D5C09, 0xAAB92EA7, 0x61E5FD02,
+ 0x7CE0CDBA, 0xB7BC1E1F, 0x31286CB1, 0xFA74BF14,
+ 0x1EB014D8, 0xD5ECC77D, 0x5378B5D3, 0x98246676,
+ 0x852156CE, 0x4E7D856B, 0xC8E9F7C5, 0x03B52460,
+ 0xF2E396B5, 0x39BF4510, 0xBF2B37BE, 0x7477E41B,
+ 0x6972D4A3, 0xA22E0706, 0x24BA75A8, 0xEFE6A60D,
+ 0x1D661643, 0xD63AC5E6, 0x50AEB748, 0x9BF264ED,
+ 0x86F75455, 0x4DAB87F0, 0xCB3FF55E, 0x006326FB,
+ 0xF135942E, 0x3A69478B, 0xBCFD3525, 0x77A1E680,
+ 0x6AA4D638, 0xA1F8059D, 0x276C7733, 0xEC30A496,
+ 0x191C11EE, 0xD240C24B, 0x54D4B0E5, 0x9F886340,
+ 0x828D53F8, 0x49D1805D, 0xCF45F2F3, 0x04192156,
+ 0xF54F9383, 0x3E134026, 0xB8873288, 0x73DBE12D,
+ 0x6EDED195, 0xA5820230, 0x2316709E, 0xE84AA33B,
+ 0x1ACA1375, 0xD196C0D0, 0x5702B27E, 0x9C5E61DB,
+ 0x815B5163, 0x4A0782C6, 0xCC93F068, 0x07CF23CD,
+ 0xF6999118, 0x3DC542BD, 0xBB513013, 0x700DE3B6,
+ 0x6D08D30E, 0xA65400AB, 0x20C07205, 0xEB9CA1A0,
+ 0x11E81EB4, 0xDAB4CD11, 0x5C20BFBF, 0x977C6C1A,
+ 0x8A795CA2, 0x41258F07, 0xC7B1FDA9, 0x0CED2E0C,
+ 0xFDBB9CD9, 0x36E74F7C, 0xB0733DD2, 0x7B2FEE77,
+ 0x662ADECF, 0xAD760D6A, 0x2BE27FC4, 0xE0BEAC61,
+ 0x123E1C2F, 0xD962CF8A, 0x5FF6BD24, 0x94AA6E81,
+ 0x89AF5E39, 0x42F38D9C, 0xC467FF32, 0x0F3B2C97,
+ 0xFE6D9E42, 0x35314DE7, 0xB3A53F49, 0x78F9ECEC,
+ 0x65FCDC54, 0xAEA00FF1, 0x28347D5F, 0xE368AEFA,
+ 0x16441B82, 0xDD18C827, 0x5B8CBA89, 0x90D0692C,
+ 0x8DD55994, 0x46898A31, 0xC01DF89F, 0x0B412B3A,
+ 0xFA1799EF, 0x314B4A4A, 0xB7DF38E4, 0x7C83EB41,
+ 0x6186DBF9, 0xAADA085C, 0x2C4E7AF2, 0xE712A957,
+ 0x15921919, 0xDECECABC, 0x585AB812, 0x93066BB7,
+ 0x8E035B0F, 0x455F88AA, 0xC3CBFA04, 0x089729A1,
+ 0xF9C19B74, 0x329D48D1, 0xB4093A7F, 0x7F55E9DA,
+ 0x6250D962, 0xA90C0AC7, 0x2F987869, 0xE4C4ABCC
+ }, {
+ 0x00000000, 0xA6770BB4, 0x979F1129, 0x31E81A9D,
+ 0xF44F2413, 0x52382FA7, 0x63D0353A, 0xC5A73E8E,
+ 0x33EF4E67, 0x959845D3, 0xA4705F4E, 0x020754FA,
+ 0xC7A06A74, 0x61D761C0, 0x503F7B5D, 0xF64870E9,
+ 0x67DE9CCE, 0xC1A9977A, 0xF0418DE7, 0x56368653,
+ 0x9391B8DD, 0x35E6B369, 0x040EA9F4, 0xA279A240,
+ 0x5431D2A9, 0xF246D91D, 0xC3AEC380, 0x65D9C834,
+ 0xA07EF6BA, 0x0609FD0E, 0x37E1E793, 0x9196EC27,
+ 0xCFBD399C, 0x69CA3228, 0x582228B5, 0xFE552301,
+ 0x3BF21D8F, 0x9D85163B, 0xAC6D0CA6, 0x0A1A0712,
+ 0xFC5277FB, 0x5A257C4F, 0x6BCD66D2, 0xCDBA6D66,
+ 0x081D53E8, 0xAE6A585C, 0x9F8242C1, 0x39F54975,
+ 0xA863A552, 0x0E14AEE6, 0x3FFCB47B, 0x998BBFCF,
+ 0x5C2C8141, 0xFA5B8AF5, 0xCBB39068, 0x6DC49BDC,
+ 0x9B8CEB35, 0x3DFBE081, 0x0C13FA1C, 0xAA64F1A8,
+ 0x6FC3CF26, 0xC9B4C492, 0xF85CDE0F, 0x5E2BD5BB,
+ 0x440B7579, 0xE27C7ECD, 0xD3946450, 0x75E36FE4,
+ 0xB044516A, 0x16335ADE, 0x27DB4043, 0x81AC4BF7,
+ 0x77E43B1E, 0xD19330AA, 0xE07B2A37, 0x460C2183,
+ 0x83AB1F0D, 0x25DC14B9, 0x14340E24, 0xB2430590,
+ 0x23D5E9B7, 0x85A2E203, 0xB44AF89E, 0x123DF32A,
+ 0xD79ACDA4, 0x71EDC610, 0x4005DC8D, 0xE672D739,
+ 0x103AA7D0, 0xB64DAC64, 0x87A5B6F9, 0x21D2BD4D,
+ 0xE47583C3, 0x42028877, 0x73EA92EA, 0xD59D995E,
+ 0x8BB64CE5, 0x2DC14751, 0x1C295DCC, 0xBA5E5678,
+ 0x7FF968F6, 0xD98E6342, 0xE86679DF, 0x4E11726B,
+ 0xB8590282, 0x1E2E0936, 0x2FC613AB, 0x89B1181F,
+ 0x4C162691, 0xEA612D25, 0xDB8937B8, 0x7DFE3C0C,
+ 0xEC68D02B, 0x4A1FDB9F, 0x7BF7C102, 0xDD80CAB6,
+ 0x1827F438, 0xBE50FF8C, 0x8FB8E511, 0x29CFEEA5,
+ 0xDF879E4C, 0x79F095F8, 0x48188F65, 0xEE6F84D1,
+ 0x2BC8BA5F, 0x8DBFB1EB, 0xBC57AB76, 0x1A20A0C2,
+ 0x8816EAF2, 0x2E61E146, 0x1F89FBDB, 0xB9FEF06F,
+ 0x7C59CEE1, 0xDA2EC555, 0xEBC6DFC8, 0x4DB1D47C,
+ 0xBBF9A495, 0x1D8EAF21, 0x2C66B5BC, 0x8A11BE08,
+ 0x4FB68086, 0xE9C18B32, 0xD82991AF, 0x7E5E9A1B,
+ 0xEFC8763C, 0x49BF7D88, 0x78576715, 0xDE206CA1,
+ 0x1B87522F, 0xBDF0599B, 0x8C184306, 0x2A6F48B2,
+ 0xDC27385B, 0x7A5033EF, 0x4BB82972, 0xEDCF22C6,
+ 0x28681C48, 0x8E1F17FC, 0xBFF70D61, 0x198006D5,
+ 0x47ABD36E, 0xE1DCD8DA, 0xD034C247, 0x7643C9F3,
+ 0xB3E4F77D, 0x1593FCC9, 0x247BE654, 0x820CEDE0,
+ 0x74449D09, 0xD23396BD, 0xE3DB8C20, 0x45AC8794,
+ 0x800BB91A, 0x267CB2AE, 0x1794A833, 0xB1E3A387,
+ 0x20754FA0, 0x86024414, 0xB7EA5E89, 0x119D553D,
+ 0xD43A6BB3, 0x724D6007, 0x43A57A9A, 0xE5D2712E,
+ 0x139A01C7, 0xB5ED0A73, 0x840510EE, 0x22721B5A,
+ 0xE7D525D4, 0x41A22E60, 0x704A34FD, 0xD63D3F49,
+ 0xCC1D9F8B, 0x6A6A943F, 0x5B828EA2, 0xFDF58516,
+ 0x3852BB98, 0x9E25B02C, 0xAFCDAAB1, 0x09BAA105,
+ 0xFFF2D1EC, 0x5985DA58, 0x686DC0C5, 0xCE1ACB71,
+ 0x0BBDF5FF, 0xADCAFE4B, 0x9C22E4D6, 0x3A55EF62,
+ 0xABC30345, 0x0DB408F1, 0x3C5C126C, 0x9A2B19D8,
+ 0x5F8C2756, 0xF9FB2CE2, 0xC813367F, 0x6E643DCB,
+ 0x982C4D22, 0x3E5B4696, 0x0FB35C0B, 0xA9C457BF,
+ 0x6C636931, 0xCA146285, 0xFBFC7818, 0x5D8B73AC,
+ 0x03A0A617, 0xA5D7ADA3, 0x943FB73E, 0x3248BC8A,
+ 0xF7EF8204, 0x519889B0, 0x6070932D, 0xC6079899,
+ 0x304FE870, 0x9638E3C4, 0xA7D0F959, 0x01A7F2ED,
+ 0xC400CC63, 0x6277C7D7, 0x539FDD4A, 0xF5E8D6FE,
+ 0x647E3AD9, 0xC209316D, 0xF3E12BF0, 0x55962044,
+ 0x90311ECA, 0x3646157E, 0x07AE0FE3, 0xA1D90457,
+ 0x579174BE, 0xF1E67F0A, 0xC00E6597, 0x66796E23,
+ 0xA3DE50AD, 0x05A95B19, 0x34414184, 0x92364A30
+ }, {
+ 0x00000000, 0xCCAA009E, 0x4225077D, 0x8E8F07E3,
+ 0x844A0EFA, 0x48E00E64, 0xC66F0987, 0x0AC50919,
+ 0xD3E51BB5, 0x1F4F1B2B, 0x91C01CC8, 0x5D6A1C56,
+ 0x57AF154F, 0x9B0515D1, 0x158A1232, 0xD92012AC,
+ 0x7CBB312B, 0xB01131B5, 0x3E9E3656, 0xF23436C8,
+ 0xF8F13FD1, 0x345B3F4F, 0xBAD438AC, 0x767E3832,
+ 0xAF5E2A9E, 0x63F42A00, 0xED7B2DE3, 0x21D12D7D,
+ 0x2B142464, 0xE7BE24FA, 0x69312319, 0xA59B2387,
+ 0xF9766256, 0x35DC62C8, 0xBB53652B, 0x77F965B5,
+ 0x7D3C6CAC, 0xB1966C32, 0x3F196BD1, 0xF3B36B4F,
+ 0x2A9379E3, 0xE639797D, 0x68B67E9E, 0xA41C7E00,
+ 0xAED97719, 0x62737787, 0xECFC7064, 0x205670FA,
+ 0x85CD537D, 0x496753E3, 0xC7E85400, 0x0B42549E,
+ 0x01875D87, 0xCD2D5D19, 0x43A25AFA, 0x8F085A64,
+ 0x562848C8, 0x9A824856, 0x140D4FB5, 0xD8A74F2B,
+ 0xD2624632, 0x1EC846AC, 0x9047414F, 0x5CED41D1,
+ 0x299DC2ED, 0xE537C273, 0x6BB8C590, 0xA712C50E,
+ 0xADD7CC17, 0x617DCC89, 0xEFF2CB6A, 0x2358CBF4,
+ 0xFA78D958, 0x36D2D9C6, 0xB85DDE25, 0x74F7DEBB,
+ 0x7E32D7A2, 0xB298D73C, 0x3C17D0DF, 0xF0BDD041,
+ 0x5526F3C6, 0x998CF358, 0x1703F4BB, 0xDBA9F425,
+ 0xD16CFD3C, 0x1DC6FDA2, 0x9349FA41, 0x5FE3FADF,
+ 0x86C3E873, 0x4A69E8ED, 0xC4E6EF0E, 0x084CEF90,
+ 0x0289E689, 0xCE23E617, 0x40ACE1F4, 0x8C06E16A,
+ 0xD0EBA0BB, 0x1C41A025, 0x92CEA7C6, 0x5E64A758,
+ 0x54A1AE41, 0x980BAEDF, 0x1684A93C, 0xDA2EA9A2,
+ 0x030EBB0E, 0xCFA4BB90, 0x412BBC73, 0x8D81BCED,
+ 0x8744B5F4, 0x4BEEB56A, 0xC561B289, 0x09CBB217,
+ 0xAC509190, 0x60FA910E, 0xEE7596ED, 0x22DF9673,
+ 0x281A9F6A, 0xE4B09FF4, 0x6A3F9817, 0xA6959889,
+ 0x7FB58A25, 0xB31F8ABB, 0x3D908D58, 0xF13A8DC6,
+ 0xFBFF84DF, 0x37558441, 0xB9DA83A2, 0x7570833C,
+ 0x533B85DA, 0x9F918544, 0x111E82A7, 0xDDB48239,
+ 0xD7718B20, 0x1BDB8BBE, 0x95548C5D, 0x59FE8CC3,
+ 0x80DE9E6F, 0x4C749EF1, 0xC2FB9912, 0x0E51998C,
+ 0x04949095, 0xC83E900B, 0x46B197E8, 0x8A1B9776,
+ 0x2F80B4F1, 0xE32AB46F, 0x6DA5B38C, 0xA10FB312,
+ 0xABCABA0B, 0x6760BA95, 0xE9EFBD76, 0x2545BDE8,
+ 0xFC65AF44, 0x30CFAFDA, 0xBE40A839, 0x72EAA8A7,
+ 0x782FA1BE, 0xB485A120, 0x3A0AA6C3, 0xF6A0A65D,
+ 0xAA4DE78C, 0x66E7E712, 0xE868E0F1, 0x24C2E06F,
+ 0x2E07E976, 0xE2ADE9E8, 0x6C22EE0B, 0xA088EE95,
+ 0x79A8FC39, 0xB502FCA7, 0x3B8DFB44, 0xF727FBDA,
+ 0xFDE2F2C3, 0x3148F25D, 0xBFC7F5BE, 0x736DF520,
+ 0xD6F6D6A7, 0x1A5CD639, 0x94D3D1DA, 0x5879D144,
+ 0x52BCD85D, 0x9E16D8C3, 0x1099DF20, 0xDC33DFBE,
+ 0x0513CD12, 0xC9B9CD8C, 0x4736CA6F, 0x8B9CCAF1,
+ 0x8159C3E8, 0x4DF3C376, 0xC37CC495, 0x0FD6C40B,
+ 0x7AA64737, 0xB60C47A9, 0x3883404A, 0xF42940D4,
+ 0xFEEC49CD, 0x32464953, 0xBCC94EB0, 0x70634E2E,
+ 0xA9435C82, 0x65E95C1C, 0xEB665BFF, 0x27CC5B61,
+ 0x2D095278, 0xE1A352E6, 0x6F2C5505, 0xA386559B,
+ 0x061D761C, 0xCAB77682, 0x44387161, 0x889271FF,
+ 0x825778E6, 0x4EFD7878, 0xC0727F9B, 0x0CD87F05,
+ 0xD5F86DA9, 0x19526D37, 0x97DD6AD4, 0x5B776A4A,
+ 0x51B26353, 0x9D1863CD, 0x1397642E, 0xDF3D64B0,
+ 0x83D02561, 0x4F7A25FF, 0xC1F5221C, 0x0D5F2282,
+ 0x079A2B9B, 0xCB302B05, 0x45BF2CE6, 0x89152C78,
+ 0x50353ED4, 0x9C9F3E4A, 0x121039A9, 0xDEBA3937,
+ 0xD47F302E, 0x18D530B0, 0x965A3753, 0x5AF037CD,
+ 0xFF6B144A, 0x33C114D4, 0xBD4E1337, 0x71E413A9,
+ 0x7B211AB0, 0xB78B1A2E, 0x39041DCD, 0xF5AE1D53,
+ 0x2C8E0FFF, 0xE0240F61, 0x6EAB0882, 0xA201081C,
+ 0xA8C40105, 0x646E019B, 0xEAE10678, 0x264B06E6
+ }
+};
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_tablegen.c b/Utilities/cmliblzma/liblzma/check/crc32_tablegen.c
new file mode 100644
index 000000000..31a4d2751
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_tablegen.c
@@ -0,0 +1,117 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc32_tablegen.c
+/// \brief Generate crc32_table_le.h and crc32_table_be.h
+///
+/// Compiling: gcc -std=c99 -o crc32_tablegen crc32_tablegen.c
+/// Add -DWORDS_BIGENDIAN to generate big endian table.
+/// Add -DLZ_HASH_TABLE to generate lz_encoder_hash_table.h (little endian).
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "../../common/tuklib_integer.h"
+
+
+static uint32_t crc32_table[8][256];
+
+
+static void
+init_crc32_table(void)
+{
+ static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+ for (size_t s = 0; s < 8; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ uint32_t r = s == 0 ? b : crc32_table[s - 1][b];
+
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly32;
+ else
+ r >>= 1;
+ }
+
+ crc32_table[s][b] = r;
+ }
+ }
+
+#ifdef WORDS_BIGENDIAN
+ for (size_t s = 0; s < 8; ++s)
+ for (size_t b = 0; b < 256; ++b)
+ crc32_table[s][b] = bswap32(crc32_table[s][b]);
+#endif
+
+ return;
+}
+
+
+static void
+print_crc32_table(void)
+{
+ printf("/* This file has been automatically generated by "
+ "crc32_tablegen.c. */\n\n"
+ "const uint32_t lzma_crc32_table[8][256] = {\n\t{");
+
+ for (size_t s = 0; s < 8; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ if ((b % 4) == 0)
+ printf("\n\t\t");
+
+ printf("0x%08" PRIX32, crc32_table[s][b]);
+
+ if (b != 255)
+ printf(",%s", (b+1) % 4 == 0 ? "" : " ");
+ }
+
+ if (s == 7)
+ printf("\n\t}\n};\n");
+ else
+ printf("\n\t}, {");
+ }
+
+ return;
+}
+
+
+static void
+print_lz_table(void)
+{
+ printf("/* This file has been automatically generated by "
+ "crc32_tablegen.c. */\n\n"
+ "const uint32_t lzma_lz_hash_table[256] = {");
+
+ for (size_t b = 0; b < 256; ++b) {
+ if ((b % 4) == 0)
+ printf("\n\t");
+
+ printf("0x%08" PRIX32, crc32_table[0][b]);
+
+ if (b != 255)
+ printf(",%s", (b+1) % 4 == 0 ? "" : " ");
+ }
+
+ printf("\n};\n");
+
+ return;
+}
+
+
+int
+main(void)
+{
+ init_crc32_table();
+
+#ifdef LZ_HASH_TABLE
+ print_lz_table();
+#else
+ print_crc32_table();
+#endif
+
+ return 0;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc32_x86.S b/Utilities/cmliblzma/liblzma/check/crc32_x86.S
new file mode 100644
index 000000000..67f68a414
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc32_x86.S
@@ -0,0 +1,304 @@
+/*
+ * Speed-optimized CRC32 using slicing-by-eight algorithm
+ *
+ * This uses only i386 instructions, but it is optimized for i686 and later
+ * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2). For i586
+ * (e.g. Pentium), slicing-by-four would be better, and even the C version
+ * of slicing-by-eight built with gcc -march=i586 tends to be a little bit
+ * better than this. Very few probably run this code on i586 or older x86
+ * so this shouldn't be a problem in practice.
+ *
+ * Authors: Igor Pavlov (original version)
+ * Lasse Collin (AT&T syntax, PIC support, better portability)
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * This code needs lzma_crc32_table, which can be created using the
+ * following C code:
+
+uint32_t lzma_crc32_table[8][256];
+
+void
+init_table(void)
+{
+ // IEEE-802.3
+ static const uint32_t poly32 = UINT32_C(0xEDB88320);
+
+ // Castagnoli
+ // static const uint32_t poly32 = UINT32_C(0x82F63B78);
+
+ // Koopman
+ // static const uint32_t poly32 = UINT32_C(0xEB31D82E);
+
+ for (size_t s = 0; s < 8; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ uint32_t r = s == 0 ? b : lzma_crc32_table[s - 1][b];
+
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly32;
+ else
+ r >>= 1;
+ }
+
+ lzma_crc32_table[s][b] = r;
+ }
+ }
+}
+
+ * The prototype of the CRC32 function:
+ * extern uint32_t lzma_crc32(const uint8_t *buf, size_t size, uint32_t crc);
+ */
+
+/*
+ * On some systems, the functions need to be prefixed. The prefix is
+ * usually an underscore.
+ */
+#ifndef __USER_LABEL_PREFIX__
+# define __USER_LABEL_PREFIX__
+#endif
+#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
+#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
+#define LZMA_CRC32 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32)
+#define LZMA_CRC32_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc32_table)
+
+/*
+ * Solaris assembler doesn't have .p2align, and Darwin uses .align
+ * differently than GNU/Linux and Solaris.
+ */
+#if defined(__APPLE__) || defined(__MSDOS__)
+# define ALIGN(pow2, abs) .align pow2
+#else
+# define ALIGN(pow2, abs) .align abs
+#endif
+
+ .text
+ .globl LZMA_CRC32
+
+#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
+ && !defined(__MSDOS__)
+ .type LZMA_CRC32, @function
+#endif
+
+ ALIGN(4, 16)
+LZMA_CRC32:
+ /*
+ * Register usage:
+ * %eax crc
+ * %esi buf
+ * %edi size or buf + size
+ * %ebx lzma_crc32_table
+ * %ebp Table index
+ * %ecx Temporary
+ * %edx Temporary
+ */
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ movl 0x14(%esp), %esi /* buf */
+ movl 0x18(%esp), %edi /* size */
+ movl 0x1C(%esp), %eax /* crc */
+
+ /*
+ * Store the address of lzma_crc32_table to %ebx. This is needed to
+ * get position-independent code (PIC).
+ *
+ * The PIC macro is defined by libtool, while __PIC__ is defined
+ * by GCC but only on some systems. Testing for both makes it simpler
+ * to test this code without libtool, and keeps the code working also
+ * when built with libtool but using something else than GCC.
+ *
+ * I understood that libtool may define PIC on Windows even though
+ * the code in Windows DLLs is not PIC in sense that it is in ELF
+ * binaries, so we need a separate check to always use the non-PIC
+ * code on Windows.
+ */
+#if (!defined(PIC) && !defined(__PIC__)) \
+ || (defined(_WIN32) || defined(__CYGWIN__))
+ /* Not PIC */
+ movl $ LZMA_CRC32_TABLE, %ebx
+#elif defined(__APPLE__)
+ /* Mach-O */
+ call .L_get_pc
+.L_pic:
+ leal .L_lzma_crc32_table$non_lazy_ptr-.L_pic(%ebx), %ebx
+ movl (%ebx), %ebx
+#else
+ /* ELF */
+ call .L_get_pc
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl LZMA_CRC32_TABLE@GOT(%ebx), %ebx
+#endif
+
+ /* Complement the initial value. */
+ notl %eax
+
+ ALIGN(4, 16)
+.L_align:
+ /*
+ * Check if there is enough input to use slicing-by-eight.
+ * We need 16 bytes, because the loop pre-reads eight bytes.
+ */
+ cmpl $16, %edi
+ jb .L_rest
+
+ /* Check if we have reached alignment of eight bytes. */
+ testl $7, %esi
+ jz .L_slice
+
+ /* Calculate CRC of the next input byte. */
+ movzbl (%esi), %ebp
+ incl %esi
+ movzbl %al, %ecx
+ xorl %ecx, %ebp
+ shrl $8, %eax
+ xorl (%ebx, %ebp, 4), %eax
+ decl %edi
+ jmp .L_align
+
+ ALIGN(2, 4)
+.L_slice:
+ /*
+ * If we get here, there's at least 16 bytes of aligned input
+ * available. Make %edi multiple of eight bytes. Store the possible
+ * remainder over the "size" variable in the argument stack.
+ */
+ movl %edi, 0x18(%esp)
+ andl $-8, %edi
+ subl %edi, 0x18(%esp)
+
+ /*
+ * Let %edi be buf + size - 8 while running the main loop. This way
+ * we can compare for equality to determine when exit the loop.
+ */
+ addl %esi, %edi
+ subl $8, %edi
+
+ /* Read in the first eight aligned bytes. */
+ xorl (%esi), %eax
+ movl 4(%esi), %ecx
+ movzbl %cl, %ebp
+
+.L_loop:
+ movl 0x0C00(%ebx, %ebp, 4), %edx
+ movzbl %ch, %ebp
+ xorl 0x0800(%ebx, %ebp, 4), %edx
+ shrl $16, %ecx
+ xorl 8(%esi), %edx
+ movzbl %cl, %ebp
+ xorl 0x0400(%ebx, %ebp, 4), %edx
+ movzbl %ch, %ebp
+ xorl (%ebx, %ebp, 4), %edx
+ movzbl %al, %ebp
+
+ /*
+ * Read the next four bytes, for which the CRC is calculated
+ * on the next interation of the loop.
+ */
+ movl 12(%esi), %ecx
+
+ xorl 0x1C00(%ebx, %ebp, 4), %edx
+ movzbl %ah, %ebp
+ shrl $16, %eax
+ xorl 0x1800(%ebx, %ebp, 4), %edx
+ movzbl %ah, %ebp
+ movzbl %al, %eax
+ movl 0x1400(%ebx, %eax, 4), %eax
+ addl $8, %esi
+ xorl %edx, %eax
+ xorl 0x1000(%ebx, %ebp, 4), %eax
+
+ /* Check for end of aligned input. */
+ cmpl %edi, %esi
+ movzbl %cl, %ebp
+ jne .L_loop
+
+ /*
+ * Process the remaining eight bytes, which we have already
+ * copied to %ecx and %edx.
+ */
+ movl 0x0C00(%ebx, %ebp, 4), %edx
+ movzbl %ch, %ebp
+ xorl 0x0800(%ebx, %ebp, 4), %edx
+ shrl $16, %ecx
+ movzbl %cl, %ebp
+ xorl 0x0400(%ebx, %ebp, 4), %edx
+ movzbl %ch, %ebp
+ xorl (%ebx, %ebp, 4), %edx
+ movzbl %al, %ebp
+
+ xorl 0x1C00(%ebx, %ebp, 4), %edx
+ movzbl %ah, %ebp
+ shrl $16, %eax
+ xorl 0x1800(%ebx, %ebp, 4), %edx
+ movzbl %ah, %ebp
+ movzbl %al, %eax
+ movl 0x1400(%ebx, %eax, 4), %eax
+ addl $8, %esi
+ xorl %edx, %eax
+ xorl 0x1000(%ebx, %ebp, 4), %eax
+
+ /* Copy the number of remaining bytes to %edi. */
+ movl 0x18(%esp), %edi
+
+.L_rest:
+ /* Check for end of input. */
+ testl %edi, %edi
+ jz .L_return
+
+ /* Calculate CRC of the next input byte. */
+ movzbl (%esi), %ebp
+ incl %esi
+ movzbl %al, %ecx
+ xorl %ecx, %ebp
+ shrl $8, %eax
+ xorl (%ebx, %ebp, 4), %eax
+ decl %edi
+ jmp .L_rest
+
+.L_return:
+ /* Complement the final value. */
+ notl %eax
+
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+#if defined(PIC) || defined(__PIC__)
+ ALIGN(4, 16)
+.L_get_pc:
+ movl (%esp), %ebx
+ ret
+#endif
+
+#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
+ /* Mach-O PIC */
+ .section __IMPORT,__pointers,non_lazy_symbol_pointers
+.L_lzma_crc32_table$non_lazy_ptr:
+ .indirect_symbol LZMA_CRC32_TABLE
+ .long 0
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
+# ifdef DLL_EXPORT
+ /* This is equivalent of __declspec(dllexport). */
+ .section .drectve
+ .ascii " -export:lzma_crc32"
+# endif
+
+#elif !defined(__MSDOS__)
+ /* ELF */
+ .size LZMA_CRC32, .-LZMA_CRC32
+#endif
+
+/*
+ * This is needed to support non-executable stack. It's ugly to
+ * use __linux__ here, but I don't know a way to detect when
+ * we are using GNU assembler.
+ */
+#if defined(__ELF__) && defined(__linux__)
+ .section .note.GNU-stack,"",@progbits
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_fast.c b/Utilities/cmliblzma/liblzma/check/crc64_fast.c
new file mode 100644
index 000000000..1436557af
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_fast.c
@@ -0,0 +1,74 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc64.c
+/// \brief CRC64 calculation
+///
+/// Calculate the CRC64 using the slice-by-four algorithm. This is the same
+/// idea that is used in crc32_fast.c, but for CRC64 we use only four tables
+/// instead of eight to avoid increasing CPU cache usage.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+#include "crc_macros.h"
+
+
+#ifdef WORDS_BIGENDIAN
+# define A1(x) ((x) >> 56)
+#else
+# define A1 A
+#endif
+
+
+// See the comments in crc32_fast.c. They aren't duplicated here.
+extern LZMA_API(uint64_t)
+lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+ crc = ~crc;
+
+#ifdef WORDS_BIGENDIAN
+ crc = bswap64(crc);
+#endif
+
+ if (size > 4) {
+ const uint8_t *limit;
+
+ while ((uintptr_t)(buf) & 3) {
+ crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
+ --size;
+ }
+
+ limit = buf + (size & ~(size_t)(3));
+ size &= (size_t)(3);
+
+ while (buf < limit) {
+#ifdef WORDS_BIGENDIAN
+ const uint32_t tmp = (crc >> 32)
+ ^ *(const uint32_t *)(buf);
+#else
+ const uint32_t tmp = crc ^ *(const uint32_t *)(buf);
+#endif
+ buf += 4;
+
+ crc = lzma_crc64_table[3][A(tmp)]
+ ^ lzma_crc64_table[2][B(tmp)]
+ ^ S32(crc)
+ ^ lzma_crc64_table[1][C(tmp)]
+ ^ lzma_crc64_table[0][D(tmp)];
+ }
+ }
+
+ while (size-- != 0)
+ crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc);
+
+#ifdef WORDS_BIGENDIAN
+ crc = bswap64(crc);
+#endif
+
+ return ~crc;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_small.c b/Utilities/cmliblzma/liblzma/check/crc64_small.c
new file mode 100644
index 000000000..55d72316b
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_small.c
@@ -0,0 +1,53 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc64_small.c
+/// \brief CRC64 calculation (size-optimized)
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "check.h"
+
+
+static uint64_t crc64_table[256];
+
+
+static void
+crc64_init(void)
+{
+ static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+ for (size_t b = 0; b < 256; ++b) {
+ uint64_t r = b;
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly64;
+ else
+ r >>= 1;
+ }
+
+ crc64_table[b] = r;
+ }
+
+ return;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc)
+{
+ mythread_once(crc64_init);
+
+ crc = ~crc;
+
+ while (size != 0) {
+ crc = crc64_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8);
+ --size;
+ }
+
+ return ~crc;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_table.c b/Utilities/cmliblzma/liblzma/check/crc64_table.c
new file mode 100644
index 000000000..1fbcd9470
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_table.c
@@ -0,0 +1,19 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc64_table.c
+/// \brief Precalculated CRC64 table with correct endianness
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+#ifdef WORDS_BIGENDIAN
+# include "crc64_table_be.h"
+#else
+# include "crc64_table_le.h"
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_table_be.h b/Utilities/cmliblzma/liblzma/check/crc64_table_be.h
new file mode 100644
index 000000000..ea074f397
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_table_be.h
@@ -0,0 +1,521 @@
+/* This file has been automatically generated by crc64_tablegen.c. */
+
+const uint64_t lzma_crc64_table[4][256] = {
+ {
+ UINT64_C(0x0000000000000000), UINT64_C(0x6F5FA703BE4C2EB3),
+ UINT64_C(0x5BA040A8573684F4), UINT64_C(0x34FFE7ABE97AAA47),
+ UINT64_C(0x335E8FFF84C3D07B), UINT64_C(0x5C0128FC3A8FFEC8),
+ UINT64_C(0x68FECF57D3F5548F), UINT64_C(0x07A168546DB97A3C),
+ UINT64_C(0x66BC1EFF0987A1F7), UINT64_C(0x09E3B9FCB7CB8F44),
+ UINT64_C(0x3D1C5E575EB12503), UINT64_C(0x5243F954E0FD0BB0),
+ UINT64_C(0x55E291008D44718C), UINT64_C(0x3ABD360333085F3F),
+ UINT64_C(0x0E42D1A8DA72F578), UINT64_C(0x611D76AB643EDBCB),
+ UINT64_C(0x4966335138A19B7D), UINT64_C(0x2639945286EDB5CE),
+ UINT64_C(0x12C673F96F971F89), UINT64_C(0x7D99D4FAD1DB313A),
+ UINT64_C(0x7A38BCAEBC624B06), UINT64_C(0x15671BAD022E65B5),
+ UINT64_C(0x2198FC06EB54CFF2), UINT64_C(0x4EC75B055518E141),
+ UINT64_C(0x2FDA2DAE31263A8A), UINT64_C(0x40858AAD8F6A1439),
+ UINT64_C(0x747A6D066610BE7E), UINT64_C(0x1B25CA05D85C90CD),
+ UINT64_C(0x1C84A251B5E5EAF1), UINT64_C(0x73DB05520BA9C442),
+ UINT64_C(0x4724E2F9E2D36E05), UINT64_C(0x287B45FA5C9F40B6),
+ UINT64_C(0x92CC66A2704237FB), UINT64_C(0xFD93C1A1CE0E1948),
+ UINT64_C(0xC96C260A2774B30F), UINT64_C(0xA633810999389DBC),
+ UINT64_C(0xA192E95DF481E780), UINT64_C(0xCECD4E5E4ACDC933),
+ UINT64_C(0xFA32A9F5A3B76374), UINT64_C(0x956D0EF61DFB4DC7),
+ UINT64_C(0xF470785D79C5960C), UINT64_C(0x9B2FDF5EC789B8BF),
+ UINT64_C(0xAFD038F52EF312F8), UINT64_C(0xC08F9FF690BF3C4B),
+ UINT64_C(0xC72EF7A2FD064677), UINT64_C(0xA87150A1434A68C4),
+ UINT64_C(0x9C8EB70AAA30C283), UINT64_C(0xF3D11009147CEC30),
+ UINT64_C(0xDBAA55F348E3AC86), UINT64_C(0xB4F5F2F0F6AF8235),
+ UINT64_C(0x800A155B1FD52872), UINT64_C(0xEF55B258A19906C1),
+ UINT64_C(0xE8F4DA0CCC207CFD), UINT64_C(0x87AB7D0F726C524E),
+ UINT64_C(0xB3549AA49B16F809), UINT64_C(0xDC0B3DA7255AD6BA),
+ UINT64_C(0xBD164B0C41640D71), UINT64_C(0xD249EC0FFF2823C2),
+ UINT64_C(0xE6B60BA416528985), UINT64_C(0x89E9ACA7A81EA736),
+ UINT64_C(0x8E48C4F3C5A7DD0A), UINT64_C(0xE11763F07BEBF3B9),
+ UINT64_C(0xD5E8845B929159FE), UINT64_C(0xBAB723582CDD774D),
+ UINT64_C(0xA187C3EBCA2BB664), UINT64_C(0xCED864E8746798D7),
+ UINT64_C(0xFA2783439D1D3290), UINT64_C(0x9578244023511C23),
+ UINT64_C(0x92D94C144EE8661F), UINT64_C(0xFD86EB17F0A448AC),
+ UINT64_C(0xC9790CBC19DEE2EB), UINT64_C(0xA626ABBFA792CC58),
+ UINT64_C(0xC73BDD14C3AC1793), UINT64_C(0xA8647A177DE03920),
+ UINT64_C(0x9C9B9DBC949A9367), UINT64_C(0xF3C43ABF2AD6BDD4),
+ UINT64_C(0xF46552EB476FC7E8), UINT64_C(0x9B3AF5E8F923E95B),
+ UINT64_C(0xAFC512431059431C), UINT64_C(0xC09AB540AE156DAF),
+ UINT64_C(0xE8E1F0BAF28A2D19), UINT64_C(0x87BE57B94CC603AA),
+ UINT64_C(0xB341B012A5BCA9ED), UINT64_C(0xDC1E17111BF0875E),
+ UINT64_C(0xDBBF7F457649FD62), UINT64_C(0xB4E0D846C805D3D1),
+ UINT64_C(0x801F3FED217F7996), UINT64_C(0xEF4098EE9F335725),
+ UINT64_C(0x8E5DEE45FB0D8CEE), UINT64_C(0xE10249464541A25D),
+ UINT64_C(0xD5FDAEEDAC3B081A), UINT64_C(0xBAA209EE127726A9),
+ UINT64_C(0xBD0361BA7FCE5C95), UINT64_C(0xD25CC6B9C1827226),
+ UINT64_C(0xE6A3211228F8D861), UINT64_C(0x89FC861196B4F6D2),
+ UINT64_C(0x334BA549BA69819F), UINT64_C(0x5C14024A0425AF2C),
+ UINT64_C(0x68EBE5E1ED5F056B), UINT64_C(0x07B442E253132BD8),
+ UINT64_C(0x00152AB63EAA51E4), UINT64_C(0x6F4A8DB580E67F57),
+ UINT64_C(0x5BB56A1E699CD510), UINT64_C(0x34EACD1DD7D0FBA3),
+ UINT64_C(0x55F7BBB6B3EE2068), UINT64_C(0x3AA81CB50DA20EDB),
+ UINT64_C(0x0E57FB1EE4D8A49C), UINT64_C(0x61085C1D5A948A2F),
+ UINT64_C(0x66A93449372DF013), UINT64_C(0x09F6934A8961DEA0),
+ UINT64_C(0x3D0974E1601B74E7), UINT64_C(0x5256D3E2DE575A54),
+ UINT64_C(0x7A2D961882C81AE2), UINT64_C(0x1572311B3C843451),
+ UINT64_C(0x218DD6B0D5FE9E16), UINT64_C(0x4ED271B36BB2B0A5),
+ UINT64_C(0x497319E7060BCA99), UINT64_C(0x262CBEE4B847E42A),
+ UINT64_C(0x12D3594F513D4E6D), UINT64_C(0x7D8CFE4CEF7160DE),
+ UINT64_C(0x1C9188E78B4FBB15), UINT64_C(0x73CE2FE4350395A6),
+ UINT64_C(0x4731C84FDC793FE1), UINT64_C(0x286E6F4C62351152),
+ UINT64_C(0x2FCF07180F8C6B6E), UINT64_C(0x4090A01BB1C045DD),
+ UINT64_C(0x746F47B058BAEF9A), UINT64_C(0x1B30E0B3E6F6C129),
+ UINT64_C(0x420F87D795576CC9), UINT64_C(0x2D5020D42B1B427A),
+ UINT64_C(0x19AFC77FC261E83D), UINT64_C(0x76F0607C7C2DC68E),
+ UINT64_C(0x715108281194BCB2), UINT64_C(0x1E0EAF2BAFD89201),
+ UINT64_C(0x2AF1488046A23846), UINT64_C(0x45AEEF83F8EE16F5),
+ UINT64_C(0x24B399289CD0CD3E), UINT64_C(0x4BEC3E2B229CE38D),
+ UINT64_C(0x7F13D980CBE649CA), UINT64_C(0x104C7E8375AA6779),
+ UINT64_C(0x17ED16D718131D45), UINT64_C(0x78B2B1D4A65F33F6),
+ UINT64_C(0x4C4D567F4F2599B1), UINT64_C(0x2312F17CF169B702),
+ UINT64_C(0x0B69B486ADF6F7B4), UINT64_C(0x6436138513BAD907),
+ UINT64_C(0x50C9F42EFAC07340), UINT64_C(0x3F96532D448C5DF3),
+ UINT64_C(0x38373B79293527CF), UINT64_C(0x57689C7A9779097C),
+ UINT64_C(0x63977BD17E03A33B), UINT64_C(0x0CC8DCD2C04F8D88),
+ UINT64_C(0x6DD5AA79A4715643), UINT64_C(0x028A0D7A1A3D78F0),
+ UINT64_C(0x3675EAD1F347D2B7), UINT64_C(0x592A4DD24D0BFC04),
+ UINT64_C(0x5E8B258620B28638), UINT64_C(0x31D482859EFEA88B),
+ UINT64_C(0x052B652E778402CC), UINT64_C(0x6A74C22DC9C82C7F),
+ UINT64_C(0xD0C3E175E5155B32), UINT64_C(0xBF9C46765B597581),
+ UINT64_C(0x8B63A1DDB223DFC6), UINT64_C(0xE43C06DE0C6FF175),
+ UINT64_C(0xE39D6E8A61D68B49), UINT64_C(0x8CC2C989DF9AA5FA),
+ UINT64_C(0xB83D2E2236E00FBD), UINT64_C(0xD762892188AC210E),
+ UINT64_C(0xB67FFF8AEC92FAC5), UINT64_C(0xD920588952DED476),
+ UINT64_C(0xEDDFBF22BBA47E31), UINT64_C(0x8280182105E85082),
+ UINT64_C(0x8521707568512ABE), UINT64_C(0xEA7ED776D61D040D),
+ UINT64_C(0xDE8130DD3F67AE4A), UINT64_C(0xB1DE97DE812B80F9),
+ UINT64_C(0x99A5D224DDB4C04F), UINT64_C(0xF6FA752763F8EEFC),
+ UINT64_C(0xC205928C8A8244BB), UINT64_C(0xAD5A358F34CE6A08),
+ UINT64_C(0xAAFB5DDB59771034), UINT64_C(0xC5A4FAD8E73B3E87),
+ UINT64_C(0xF15B1D730E4194C0), UINT64_C(0x9E04BA70B00DBA73),
+ UINT64_C(0xFF19CCDBD43361B8), UINT64_C(0x90466BD86A7F4F0B),
+ UINT64_C(0xA4B98C738305E54C), UINT64_C(0xCBE62B703D49CBFF),
+ UINT64_C(0xCC47432450F0B1C3), UINT64_C(0xA318E427EEBC9F70),
+ UINT64_C(0x97E7038C07C63537), UINT64_C(0xF8B8A48FB98A1B84),
+ UINT64_C(0xE388443C5F7CDAAD), UINT64_C(0x8CD7E33FE130F41E),
+ UINT64_C(0xB8280494084A5E59), UINT64_C(0xD777A397B60670EA),
+ UINT64_C(0xD0D6CBC3DBBF0AD6), UINT64_C(0xBF896CC065F32465),
+ UINT64_C(0x8B768B6B8C898E22), UINT64_C(0xE4292C6832C5A091),
+ UINT64_C(0x85345AC356FB7B5A), UINT64_C(0xEA6BFDC0E8B755E9),
+ UINT64_C(0xDE941A6B01CDFFAE), UINT64_C(0xB1CBBD68BF81D11D),
+ UINT64_C(0xB66AD53CD238AB21), UINT64_C(0xD935723F6C748592),
+ UINT64_C(0xEDCA9594850E2FD5), UINT64_C(0x829532973B420166),
+ UINT64_C(0xAAEE776D67DD41D0), UINT64_C(0xC5B1D06ED9916F63),
+ UINT64_C(0xF14E37C530EBC524), UINT64_C(0x9E1190C68EA7EB97),
+ UINT64_C(0x99B0F892E31E91AB), UINT64_C(0xF6EF5F915D52BF18),
+ UINT64_C(0xC210B83AB428155F), UINT64_C(0xAD4F1F390A643BEC),
+ UINT64_C(0xCC5269926E5AE027), UINT64_C(0xA30DCE91D016CE94),
+ UINT64_C(0x97F2293A396C64D3), UINT64_C(0xF8AD8E3987204A60),
+ UINT64_C(0xFF0CE66DEA99305C), UINT64_C(0x9053416E54D51EEF),
+ UINT64_C(0xA4ACA6C5BDAFB4A8), UINT64_C(0xCBF301C603E39A1B),
+ UINT64_C(0x7144229E2F3EED56), UINT64_C(0x1E1B859D9172C3E5),
+ UINT64_C(0x2AE46236780869A2), UINT64_C(0x45BBC535C6444711),
+ UINT64_C(0x421AAD61ABFD3D2D), UINT64_C(0x2D450A6215B1139E),
+ UINT64_C(0x19BAEDC9FCCBB9D9), UINT64_C(0x76E54ACA4287976A),
+ UINT64_C(0x17F83C6126B94CA1), UINT64_C(0x78A79B6298F56212),
+ UINT64_C(0x4C587CC9718FC855), UINT64_C(0x2307DBCACFC3E6E6),
+ UINT64_C(0x24A6B39EA27A9CDA), UINT64_C(0x4BF9149D1C36B269),
+ UINT64_C(0x7F06F336F54C182E), UINT64_C(0x105954354B00369D),
+ UINT64_C(0x382211CF179F762B), UINT64_C(0x577DB6CCA9D35898),
+ UINT64_C(0x6382516740A9F2DF), UINT64_C(0x0CDDF664FEE5DC6C),
+ UINT64_C(0x0B7C9E30935CA650), UINT64_C(0x642339332D1088E3),
+ UINT64_C(0x50DCDE98C46A22A4), UINT64_C(0x3F83799B7A260C17),
+ UINT64_C(0x5E9E0F301E18D7DC), UINT64_C(0x31C1A833A054F96F),
+ UINT64_C(0x053E4F98492E5328), UINT64_C(0x6A61E89BF7627D9B),
+ UINT64_C(0x6DC080CF9ADB07A7), UINT64_C(0x029F27CC24972914),
+ UINT64_C(0x3660C067CDED8353), UINT64_C(0x593F676473A1ADE0)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0x0DF1D05C9279E954),
+ UINT64_C(0x1AE2A1B924F3D2A9), UINT64_C(0x171371E5B68A3BFD),
+ UINT64_C(0xB1DA4DDC62497DC1), UINT64_C(0xBC2B9D80F0309495),
+ UINT64_C(0xAB38EC6546BAAF68), UINT64_C(0xA6C93C39D4C3463C),
+ UINT64_C(0xE7AB9517EE3D2210), UINT64_C(0xEA5A454B7C44CB44),
+ UINT64_C(0xFD4934AECACEF0B9), UINT64_C(0xF0B8E4F258B719ED),
+ UINT64_C(0x5671D8CB8C745FD1), UINT64_C(0x5B8008971E0DB685),
+ UINT64_C(0x4C937972A8878D78), UINT64_C(0x4162A92E3AFE642C),
+ UINT64_C(0xCE572B2FDC7B4420), UINT64_C(0xC3A6FB734E02AD74),
+ UINT64_C(0xD4B58A96F8889689), UINT64_C(0xD9445ACA6AF17FDD),
+ UINT64_C(0x7F8D66F3BE3239E1), UINT64_C(0x727CB6AF2C4BD0B5),
+ UINT64_C(0x656FC74A9AC1EB48), UINT64_C(0x689E171608B8021C),
+ UINT64_C(0x29FCBE3832466630), UINT64_C(0x240D6E64A03F8F64),
+ UINT64_C(0x331E1F8116B5B499), UINT64_C(0x3EEFCFDD84CC5DCD),
+ UINT64_C(0x9826F3E4500F1BF1), UINT64_C(0x95D723B8C276F2A5),
+ UINT64_C(0x82C4525D74FCC958), UINT64_C(0x8F358201E685200C),
+ UINT64_C(0x9CAF565EB8F78840), UINT64_C(0x915E86022A8E6114),
+ UINT64_C(0x864DF7E79C045AE9), UINT64_C(0x8BBC27BB0E7DB3BD),
+ UINT64_C(0x2D751B82DABEF581), UINT64_C(0x2084CBDE48C71CD5),
+ UINT64_C(0x3797BA3BFE4D2728), UINT64_C(0x3A666A676C34CE7C),
+ UINT64_C(0x7B04C34956CAAA50), UINT64_C(0x76F51315C4B34304),
+ UINT64_C(0x61E662F0723978F9), UINT64_C(0x6C17B2ACE04091AD),
+ UINT64_C(0xCADE8E953483D791), UINT64_C(0xC72F5EC9A6FA3EC5),
+ UINT64_C(0xD03C2F2C10700538), UINT64_C(0xDDCDFF708209EC6C),
+ UINT64_C(0x52F87D71648CCC60), UINT64_C(0x5F09AD2DF6F52534),
+ UINT64_C(0x481ADCC8407F1EC9), UINT64_C(0x45EB0C94D206F79D),
+ UINT64_C(0xE32230AD06C5B1A1), UINT64_C(0xEED3E0F194BC58F5),
+ UINT64_C(0xF9C0911422366308), UINT64_C(0xF4314148B04F8A5C),
+ UINT64_C(0xB553E8668AB1EE70), UINT64_C(0xB8A2383A18C80724),
+ UINT64_C(0xAFB149DFAE423CD9), UINT64_C(0xA24099833C3BD58D),
+ UINT64_C(0x0489A5BAE8F893B1), UINT64_C(0x097875E67A817AE5),
+ UINT64_C(0x1E6B0403CC0B4118), UINT64_C(0x139AD45F5E72A84C),
+ UINT64_C(0x385FADBC70EF1181), UINT64_C(0x35AE7DE0E296F8D5),
+ UINT64_C(0x22BD0C05541CC328), UINT64_C(0x2F4CDC59C6652A7C),
+ UINT64_C(0x8985E06012A66C40), UINT64_C(0x8474303C80DF8514),
+ UINT64_C(0x936741D93655BEE9), UINT64_C(0x9E969185A42C57BD),
+ UINT64_C(0xDFF438AB9ED23391), UINT64_C(0xD205E8F70CABDAC5),
+ UINT64_C(0xC5169912BA21E138), UINT64_C(0xC8E7494E2858086C),
+ UINT64_C(0x6E2E7577FC9B4E50), UINT64_C(0x63DFA52B6EE2A704),
+ UINT64_C(0x74CCD4CED8689CF9), UINT64_C(0x793D04924A1175AD),
+ UINT64_C(0xF6088693AC9455A1), UINT64_C(0xFBF956CF3EEDBCF5),
+ UINT64_C(0xECEA272A88678708), UINT64_C(0xE11BF7761A1E6E5C),
+ UINT64_C(0x47D2CB4FCEDD2860), UINT64_C(0x4A231B135CA4C134),
+ UINT64_C(0x5D306AF6EA2EFAC9), UINT64_C(0x50C1BAAA7857139D),
+ UINT64_C(0x11A3138442A977B1), UINT64_C(0x1C52C3D8D0D09EE5),
+ UINT64_C(0x0B41B23D665AA518), UINT64_C(0x06B06261F4234C4C),
+ UINT64_C(0xA0795E5820E00A70), UINT64_C(0xAD888E04B299E324),
+ UINT64_C(0xBA9BFFE10413D8D9), UINT64_C(0xB76A2FBD966A318D),
+ UINT64_C(0xA4F0FBE2C81899C1), UINT64_C(0xA9012BBE5A617095),
+ UINT64_C(0xBE125A5BECEB4B68), UINT64_C(0xB3E38A077E92A23C),
+ UINT64_C(0x152AB63EAA51E400), UINT64_C(0x18DB666238280D54),
+ UINT64_C(0x0FC817878EA236A9), UINT64_C(0x0239C7DB1CDBDFFD),
+ UINT64_C(0x435B6EF52625BBD1), UINT64_C(0x4EAABEA9B45C5285),
+ UINT64_C(0x59B9CF4C02D66978), UINT64_C(0x54481F1090AF802C),
+ UINT64_C(0xF2812329446CC610), UINT64_C(0xFF70F375D6152F44),
+ UINT64_C(0xE8638290609F14B9), UINT64_C(0xE59252CCF2E6FDED),
+ UINT64_C(0x6AA7D0CD1463DDE1), UINT64_C(0x67560091861A34B5),
+ UINT64_C(0x7045717430900F48), UINT64_C(0x7DB4A128A2E9E61C),
+ UINT64_C(0xDB7D9D11762AA020), UINT64_C(0xD68C4D4DE4534974),
+ UINT64_C(0xC19F3CA852D97289), UINT64_C(0xCC6EECF4C0A09BDD),
+ UINT64_C(0x8D0C45DAFA5EFFF1), UINT64_C(0x80FD9586682716A5),
+ UINT64_C(0x97EEE463DEAD2D58), UINT64_C(0x9A1F343F4CD4C40C),
+ UINT64_C(0x3CD6080698178230), UINT64_C(0x3127D85A0A6E6B64),
+ UINT64_C(0x2634A9BFBCE45099), UINT64_C(0x2BC579E32E9DB9CD),
+ UINT64_C(0xF5A054D6CA71FB90), UINT64_C(0xF851848A580812C4),
+ UINT64_C(0xEF42F56FEE822939), UINT64_C(0xE2B325337CFBC06D),
+ UINT64_C(0x447A190AA8388651), UINT64_C(0x498BC9563A416F05),
+ UINT64_C(0x5E98B8B38CCB54F8), UINT64_C(0x536968EF1EB2BDAC),
+ UINT64_C(0x120BC1C1244CD980), UINT64_C(0x1FFA119DB63530D4),
+ UINT64_C(0x08E9607800BF0B29), UINT64_C(0x0518B02492C6E27D),
+ UINT64_C(0xA3D18C1D4605A441), UINT64_C(0xAE205C41D47C4D15),
+ UINT64_C(0xB9332DA462F676E8), UINT64_C(0xB4C2FDF8F08F9FBC),
+ UINT64_C(0x3BF77FF9160ABFB0), UINT64_C(0x3606AFA5847356E4),
+ UINT64_C(0x2115DE4032F96D19), UINT64_C(0x2CE40E1CA080844D),
+ UINT64_C(0x8A2D32257443C271), UINT64_C(0x87DCE279E63A2B25),
+ UINT64_C(0x90CF939C50B010D8), UINT64_C(0x9D3E43C0C2C9F98C),
+ UINT64_C(0xDC5CEAEEF8379DA0), UINT64_C(0xD1AD3AB26A4E74F4),
+ UINT64_C(0xC6BE4B57DCC44F09), UINT64_C(0xCB4F9B0B4EBDA65D),
+ UINT64_C(0x6D86A7329A7EE061), UINT64_C(0x6077776E08070935),
+ UINT64_C(0x7764068BBE8D32C8), UINT64_C(0x7A95D6D72CF4DB9C),
+ UINT64_C(0x690F0288728673D0), UINT64_C(0x64FED2D4E0FF9A84),
+ UINT64_C(0x73EDA3315675A179), UINT64_C(0x7E1C736DC40C482D),
+ UINT64_C(0xD8D54F5410CF0E11), UINT64_C(0xD5249F0882B6E745),
+ UINT64_C(0xC237EEED343CDCB8), UINT64_C(0xCFC63EB1A64535EC),
+ UINT64_C(0x8EA4979F9CBB51C0), UINT64_C(0x835547C30EC2B894),
+ UINT64_C(0x94463626B8488369), UINT64_C(0x99B7E67A2A316A3D),
+ UINT64_C(0x3F7EDA43FEF22C01), UINT64_C(0x328F0A1F6C8BC555),
+ UINT64_C(0x259C7BFADA01FEA8), UINT64_C(0x286DABA6487817FC),
+ UINT64_C(0xA75829A7AEFD37F0), UINT64_C(0xAAA9F9FB3C84DEA4),
+ UINT64_C(0xBDBA881E8A0EE559), UINT64_C(0xB04B584218770C0D),
+ UINT64_C(0x1682647BCCB44A31), UINT64_C(0x1B73B4275ECDA365),
+ UINT64_C(0x0C60C5C2E8479898), UINT64_C(0x0191159E7A3E71CC),
+ UINT64_C(0x40F3BCB040C015E0), UINT64_C(0x4D026CECD2B9FCB4),
+ UINT64_C(0x5A111D096433C749), UINT64_C(0x57E0CD55F64A2E1D),
+ UINT64_C(0xF129F16C22896821), UINT64_C(0xFCD82130B0F08175),
+ UINT64_C(0xEBCB50D5067ABA88), UINT64_C(0xE63A8089940353DC),
+ UINT64_C(0xCDFFF96ABA9EEA11), UINT64_C(0xC00E293628E70345),
+ UINT64_C(0xD71D58D39E6D38B8), UINT64_C(0xDAEC888F0C14D1EC),
+ UINT64_C(0x7C25B4B6D8D797D0), UINT64_C(0x71D464EA4AAE7E84),
+ UINT64_C(0x66C7150FFC244579), UINT64_C(0x6B36C5536E5DAC2D),
+ UINT64_C(0x2A546C7D54A3C801), UINT64_C(0x27A5BC21C6DA2155),
+ UINT64_C(0x30B6CDC470501AA8), UINT64_C(0x3D471D98E229F3FC),
+ UINT64_C(0x9B8E21A136EAB5C0), UINT64_C(0x967FF1FDA4935C94),
+ UINT64_C(0x816C801812196769), UINT64_C(0x8C9D504480608E3D),
+ UINT64_C(0x03A8D24566E5AE31), UINT64_C(0x0E590219F49C4765),
+ UINT64_C(0x194A73FC42167C98), UINT64_C(0x14BBA3A0D06F95CC),
+ UINT64_C(0xB2729F9904ACD3F0), UINT64_C(0xBF834FC596D53AA4),
+ UINT64_C(0xA8903E20205F0159), UINT64_C(0xA561EE7CB226E80D),
+ UINT64_C(0xE403475288D88C21), UINT64_C(0xE9F2970E1AA16575),
+ UINT64_C(0xFEE1E6EBAC2B5E88), UINT64_C(0xF31036B73E52B7DC),
+ UINT64_C(0x55D90A8EEA91F1E0), UINT64_C(0x5828DAD278E818B4),
+ UINT64_C(0x4F3BAB37CE622349), UINT64_C(0x42CA7B6B5C1BCA1D),
+ UINT64_C(0x5150AF3402696251), UINT64_C(0x5CA17F6890108B05),
+ UINT64_C(0x4BB20E8D269AB0F8), UINT64_C(0x4643DED1B4E359AC),
+ UINT64_C(0xE08AE2E860201F90), UINT64_C(0xED7B32B4F259F6C4),
+ UINT64_C(0xFA68435144D3CD39), UINT64_C(0xF799930DD6AA246D),
+ UINT64_C(0xB6FB3A23EC544041), UINT64_C(0xBB0AEA7F7E2DA915),
+ UINT64_C(0xAC199B9AC8A792E8), UINT64_C(0xA1E84BC65ADE7BBC),
+ UINT64_C(0x072177FF8E1D3D80), UINT64_C(0x0AD0A7A31C64D4D4),
+ UINT64_C(0x1DC3D646AAEEEF29), UINT64_C(0x1032061A3897067D),
+ UINT64_C(0x9F07841BDE122671), UINT64_C(0x92F654474C6BCF25),
+ UINT64_C(0x85E525A2FAE1F4D8), UINT64_C(0x8814F5FE68981D8C),
+ UINT64_C(0x2EDDC9C7BC5B5BB0), UINT64_C(0x232C199B2E22B2E4),
+ UINT64_C(0x343F687E98A88919), UINT64_C(0x39CEB8220AD1604D),
+ UINT64_C(0x78AC110C302F0461), UINT64_C(0x755DC150A256ED35),
+ UINT64_C(0x624EB0B514DCD6C8), UINT64_C(0x6FBF60E986A53F9C),
+ UINT64_C(0xC9765CD0526679A0), UINT64_C(0xC4878C8CC01F90F4),
+ UINT64_C(0xD394FD697695AB09), UINT64_C(0xDE652D35E4EC425D)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0xCB6D6A914AE10B3F),
+ UINT64_C(0x96DBD42295C2177E), UINT64_C(0x5DB6BEB3DF231C41),
+ UINT64_C(0x2CB7A9452A852FFC), UINT64_C(0xE7DAC3D4606424C3),
+ UINT64_C(0xBA6C7D67BF473882), UINT64_C(0x710117F6F5A633BD),
+ UINT64_C(0xDD705D247FA5876A), UINT64_C(0x161D37B535448C55),
+ UINT64_C(0x4BAB8906EA679014), UINT64_C(0x80C6E397A0869B2B),
+ UINT64_C(0xF1C7F4615520A896), UINT64_C(0x3AAA9EF01FC1A3A9),
+ UINT64_C(0x671C2043C0E2BFE8), UINT64_C(0xAC714AD28A03B4D7),
+ UINT64_C(0xBAE1BA48FE4A0FD5), UINT64_C(0x718CD0D9B4AB04EA),
+ UINT64_C(0x2C3A6E6A6B8818AB), UINT64_C(0xE75704FB21691394),
+ UINT64_C(0x9656130DD4CF2029), UINT64_C(0x5D3B799C9E2E2B16),
+ UINT64_C(0x008DC72F410D3757), UINT64_C(0xCBE0ADBE0BEC3C68),
+ UINT64_C(0x6791E76C81EF88BF), UINT64_C(0xACFC8DFDCB0E8380),
+ UINT64_C(0xF14A334E142D9FC1), UINT64_C(0x3A2759DF5ECC94FE),
+ UINT64_C(0x4B264E29AB6AA743), UINT64_C(0x804B24B8E18BAC7C),
+ UINT64_C(0xDDFD9A0B3EA8B03D), UINT64_C(0x1690F09A7449BB02),
+ UINT64_C(0xF1DD7B3ED73AC638), UINT64_C(0x3AB011AF9DDBCD07),
+ UINT64_C(0x6706AF1C42F8D146), UINT64_C(0xAC6BC58D0819DA79),
+ UINT64_C(0xDD6AD27BFDBFE9C4), UINT64_C(0x1607B8EAB75EE2FB),
+ UINT64_C(0x4BB10659687DFEBA), UINT64_C(0x80DC6CC8229CF585),
+ UINT64_C(0x2CAD261AA89F4152), UINT64_C(0xE7C04C8BE27E4A6D),
+ UINT64_C(0xBA76F2383D5D562C), UINT64_C(0x711B98A977BC5D13),
+ UINT64_C(0x001A8F5F821A6EAE), UINT64_C(0xCB77E5CEC8FB6591),
+ UINT64_C(0x96C15B7D17D879D0), UINT64_C(0x5DAC31EC5D3972EF),
+ UINT64_C(0x4B3CC1762970C9ED), UINT64_C(0x8051ABE76391C2D2),
+ UINT64_C(0xDDE71554BCB2DE93), UINT64_C(0x168A7FC5F653D5AC),
+ UINT64_C(0x678B683303F5E611), UINT64_C(0xACE602A24914ED2E),
+ UINT64_C(0xF150BC119637F16F), UINT64_C(0x3A3DD680DCD6FA50),
+ UINT64_C(0x964C9C5256D54E87), UINT64_C(0x5D21F6C31C3445B8),
+ UINT64_C(0x00974870C31759F9), UINT64_C(0xCBFA22E189F652C6),
+ UINT64_C(0xBAFB35177C50617B), UINT64_C(0x71965F8636B16A44),
+ UINT64_C(0x2C20E135E9927605), UINT64_C(0xE74D8BA4A3737D3A),
+ UINT64_C(0xE2BBF77CAE758C71), UINT64_C(0x29D69DEDE494874E),
+ UINT64_C(0x7460235E3BB79B0F), UINT64_C(0xBF0D49CF71569030),
+ UINT64_C(0xCE0C5E3984F0A38D), UINT64_C(0x056134A8CE11A8B2),
+ UINT64_C(0x58D78A1B1132B4F3), UINT64_C(0x93BAE08A5BD3BFCC),
+ UINT64_C(0x3FCBAA58D1D00B1B), UINT64_C(0xF4A6C0C99B310024),
+ UINT64_C(0xA9107E7A44121C65), UINT64_C(0x627D14EB0EF3175A),
+ UINT64_C(0x137C031DFB5524E7), UINT64_C(0xD811698CB1B42FD8),
+ UINT64_C(0x85A7D73F6E973399), UINT64_C(0x4ECABDAE247638A6),
+ UINT64_C(0x585A4D34503F83A4), UINT64_C(0x933727A51ADE889B),
+ UINT64_C(0xCE819916C5FD94DA), UINT64_C(0x05ECF3878F1C9FE5),
+ UINT64_C(0x74EDE4717ABAAC58), UINT64_C(0xBF808EE0305BA767),
+ UINT64_C(0xE2363053EF78BB26), UINT64_C(0x295B5AC2A599B019),
+ UINT64_C(0x852A10102F9A04CE), UINT64_C(0x4E477A81657B0FF1),
+ UINT64_C(0x13F1C432BA5813B0), UINT64_C(0xD89CAEA3F0B9188F),
+ UINT64_C(0xA99DB955051F2B32), UINT64_C(0x62F0D3C44FFE200D),
+ UINT64_C(0x3F466D7790DD3C4C), UINT64_C(0xF42B07E6DA3C3773),
+ UINT64_C(0x13668C42794F4A49), UINT64_C(0xD80BE6D333AE4176),
+ UINT64_C(0x85BD5860EC8D5D37), UINT64_C(0x4ED032F1A66C5608),
+ UINT64_C(0x3FD1250753CA65B5), UINT64_C(0xF4BC4F96192B6E8A),
+ UINT64_C(0xA90AF125C60872CB), UINT64_C(0x62679BB48CE979F4),
+ UINT64_C(0xCE16D16606EACD23), UINT64_C(0x057BBBF74C0BC61C),
+ UINT64_C(0x58CD05449328DA5D), UINT64_C(0x93A06FD5D9C9D162),
+ UINT64_C(0xE2A178232C6FE2DF), UINT64_C(0x29CC12B2668EE9E0),
+ UINT64_C(0x747AAC01B9ADF5A1), UINT64_C(0xBF17C690F34CFE9E),
+ UINT64_C(0xA987360A8705459C), UINT64_C(0x62EA5C9BCDE44EA3),
+ UINT64_C(0x3F5CE22812C752E2), UINT64_C(0xF43188B9582659DD),
+ UINT64_C(0x85309F4FAD806A60), UINT64_C(0x4E5DF5DEE761615F),
+ UINT64_C(0x13EB4B6D38427D1E), UINT64_C(0xD88621FC72A37621),
+ UINT64_C(0x74F76B2EF8A0C2F6), UINT64_C(0xBF9A01BFB241C9C9),
+ UINT64_C(0xE22CBF0C6D62D588), UINT64_C(0x2941D59D2783DEB7),
+ UINT64_C(0x5840C26BD225ED0A), UINT64_C(0x932DA8FA98C4E635),
+ UINT64_C(0xCE9B164947E7FA74), UINT64_C(0x05F67CD80D06F14B),
+ UINT64_C(0xC477EFF95CEB18E3), UINT64_C(0x0F1A8568160A13DC),
+ UINT64_C(0x52AC3BDBC9290F9D), UINT64_C(0x99C1514A83C804A2),
+ UINT64_C(0xE8C046BC766E371F), UINT64_C(0x23AD2C2D3C8F3C20),
+ UINT64_C(0x7E1B929EE3AC2061), UINT64_C(0xB576F80FA94D2B5E),
+ UINT64_C(0x1907B2DD234E9F89), UINT64_C(0xD26AD84C69AF94B6),
+ UINT64_C(0x8FDC66FFB68C88F7), UINT64_C(0x44B10C6EFC6D83C8),
+ UINT64_C(0x35B01B9809CBB075), UINT64_C(0xFEDD7109432ABB4A),
+ UINT64_C(0xA36BCFBA9C09A70B), UINT64_C(0x6806A52BD6E8AC34),
+ UINT64_C(0x7E9655B1A2A11736), UINT64_C(0xB5FB3F20E8401C09),
+ UINT64_C(0xE84D819337630048), UINT64_C(0x2320EB027D820B77),
+ UINT64_C(0x5221FCF4882438CA), UINT64_C(0x994C9665C2C533F5),
+ UINT64_C(0xC4FA28D61DE62FB4), UINT64_C(0x0F9742475707248B),
+ UINT64_C(0xA3E60895DD04905C), UINT64_C(0x688B620497E59B63),
+ UINT64_C(0x353DDCB748C68722), UINT64_C(0xFE50B62602278C1D),
+ UINT64_C(0x8F51A1D0F781BFA0), UINT64_C(0x443CCB41BD60B49F),
+ UINT64_C(0x198A75F26243A8DE), UINT64_C(0xD2E71F6328A2A3E1),
+ UINT64_C(0x35AA94C78BD1DEDB), UINT64_C(0xFEC7FE56C130D5E4),
+ UINT64_C(0xA37140E51E13C9A5), UINT64_C(0x681C2A7454F2C29A),
+ UINT64_C(0x191D3D82A154F127), UINT64_C(0xD2705713EBB5FA18),
+ UINT64_C(0x8FC6E9A03496E659), UINT64_C(0x44AB83317E77ED66),
+ UINT64_C(0xE8DAC9E3F47459B1), UINT64_C(0x23B7A372BE95528E),
+ UINT64_C(0x7E011DC161B64ECF), UINT64_C(0xB56C77502B5745F0),
+ UINT64_C(0xC46D60A6DEF1764D), UINT64_C(0x0F000A3794107D72),
+ UINT64_C(0x52B6B4844B336133), UINT64_C(0x99DBDE1501D26A0C),
+ UINT64_C(0x8F4B2E8F759BD10E), UINT64_C(0x4426441E3F7ADA31),
+ UINT64_C(0x1990FAADE059C670), UINT64_C(0xD2FD903CAAB8CD4F),
+ UINT64_C(0xA3FC87CA5F1EFEF2), UINT64_C(0x6891ED5B15FFF5CD),
+ UINT64_C(0x352753E8CADCE98C), UINT64_C(0xFE4A3979803DE2B3),
+ UINT64_C(0x523B73AB0A3E5664), UINT64_C(0x9956193A40DF5D5B),
+ UINT64_C(0xC4E0A7899FFC411A), UINT64_C(0x0F8DCD18D51D4A25),
+ UINT64_C(0x7E8CDAEE20BB7998), UINT64_C(0xB5E1B07F6A5A72A7),
+ UINT64_C(0xE8570ECCB5796EE6), UINT64_C(0x233A645DFF9865D9),
+ UINT64_C(0x26CC1885F29E9492), UINT64_C(0xEDA17214B87F9FAD),
+ UINT64_C(0xB017CCA7675C83EC), UINT64_C(0x7B7AA6362DBD88D3),
+ UINT64_C(0x0A7BB1C0D81BBB6E), UINT64_C(0xC116DB5192FAB051),
+ UINT64_C(0x9CA065E24DD9AC10), UINT64_C(0x57CD0F730738A72F),
+ UINT64_C(0xFBBC45A18D3B13F8), UINT64_C(0x30D12F30C7DA18C7),
+ UINT64_C(0x6D67918318F90486), UINT64_C(0xA60AFB1252180FB9),
+ UINT64_C(0xD70BECE4A7BE3C04), UINT64_C(0x1C668675ED5F373B),
+ UINT64_C(0x41D038C6327C2B7A), UINT64_C(0x8ABD5257789D2045),
+ UINT64_C(0x9C2DA2CD0CD49B47), UINT64_C(0x5740C85C46359078),
+ UINT64_C(0x0AF676EF99168C39), UINT64_C(0xC19B1C7ED3F78706),
+ UINT64_C(0xB09A0B882651B4BB), UINT64_C(0x7BF761196CB0BF84),
+ UINT64_C(0x2641DFAAB393A3C5), UINT64_C(0xED2CB53BF972A8FA),
+ UINT64_C(0x415DFFE973711C2D), UINT64_C(0x8A30957839901712),
+ UINT64_C(0xD7862BCBE6B30B53), UINT64_C(0x1CEB415AAC52006C),
+ UINT64_C(0x6DEA56AC59F433D1), UINT64_C(0xA6873C3D131538EE),
+ UINT64_C(0xFB31828ECC3624AF), UINT64_C(0x305CE81F86D72F90),
+ UINT64_C(0xD71163BB25A452AA), UINT64_C(0x1C7C092A6F455995),
+ UINT64_C(0x41CAB799B06645D4), UINT64_C(0x8AA7DD08FA874EEB),
+ UINT64_C(0xFBA6CAFE0F217D56), UINT64_C(0x30CBA06F45C07669),
+ UINT64_C(0x6D7D1EDC9AE36A28), UINT64_C(0xA610744DD0026117),
+ UINT64_C(0x0A613E9F5A01D5C0), UINT64_C(0xC10C540E10E0DEFF),
+ UINT64_C(0x9CBAEABDCFC3C2BE), UINT64_C(0x57D7802C8522C981),
+ UINT64_C(0x26D697DA7084FA3C), UINT64_C(0xEDBBFD4B3A65F103),
+ UINT64_C(0xB00D43F8E546ED42), UINT64_C(0x7B602969AFA7E67D),
+ UINT64_C(0x6DF0D9F3DBEE5D7F), UINT64_C(0xA69DB362910F5640),
+ UINT64_C(0xFB2B0DD14E2C4A01), UINT64_C(0x3046674004CD413E),
+ UINT64_C(0x414770B6F16B7283), UINT64_C(0x8A2A1A27BB8A79BC),
+ UINT64_C(0xD79CA49464A965FD), UINT64_C(0x1CF1CE052E486EC2),
+ UINT64_C(0xB08084D7A44BDA15), UINT64_C(0x7BEDEE46EEAAD12A),
+ UINT64_C(0x265B50F53189CD6B), UINT64_C(0xED363A647B68C654),
+ UINT64_C(0x9C372D928ECEF5E9), UINT64_C(0x575A4703C42FFED6),
+ UINT64_C(0x0AECF9B01B0CE297), UINT64_C(0xC181932151EDE9A8)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0xDCA12C225E8AEE1D),
+ UINT64_C(0xB8435944BC14DD3B), UINT64_C(0x64E27566E29E3326),
+ UINT64_C(0x7087B2887829BA77), UINT64_C(0xAC269EAA26A3546A),
+ UINT64_C(0xC8C4EBCCC43D674C), UINT64_C(0x1465C7EE9AB78951),
+ UINT64_C(0xE00E6511F15274EF), UINT64_C(0x3CAF4933AFD89AF2),
+ UINT64_C(0x584D3C554D46A9D4), UINT64_C(0x84EC107713CC47C9),
+ UINT64_C(0x9089D799897BCE98), UINT64_C(0x4C28FBBBD7F12085),
+ UINT64_C(0x28CA8EDD356F13A3), UINT64_C(0xF46BA2FF6BE5FDBE),
+ UINT64_C(0x4503C48DC90A304C), UINT64_C(0x99A2E8AF9780DE51),
+ UINT64_C(0xFD409DC9751EED77), UINT64_C(0x21E1B1EB2B94036A),
+ UINT64_C(0x35847605B1238A3B), UINT64_C(0xE9255A27EFA96426),
+ UINT64_C(0x8DC72F410D375700), UINT64_C(0x5166036353BDB91D),
+ UINT64_C(0xA50DA19C385844A3), UINT64_C(0x79AC8DBE66D2AABE),
+ UINT64_C(0x1D4EF8D8844C9998), UINT64_C(0xC1EFD4FADAC67785),
+ UINT64_C(0xD58A13144071FED4), UINT64_C(0x092B3F361EFB10C9),
+ UINT64_C(0x6DC94A50FC6523EF), UINT64_C(0xB1686672A2EFCDF2),
+ UINT64_C(0x8A06881B93156098), UINT64_C(0x56A7A439CD9F8E85),
+ UINT64_C(0x3245D15F2F01BDA3), UINT64_C(0xEEE4FD7D718B53BE),
+ UINT64_C(0xFA813A93EB3CDAEF), UINT64_C(0x262016B1B5B634F2),
+ UINT64_C(0x42C263D7572807D4), UINT64_C(0x9E634FF509A2E9C9),
+ UINT64_C(0x6A08ED0A62471477), UINT64_C(0xB6A9C1283CCDFA6A),
+ UINT64_C(0xD24BB44EDE53C94C), UINT64_C(0x0EEA986C80D92751),
+ UINT64_C(0x1A8F5F821A6EAE00), UINT64_C(0xC62E73A044E4401D),
+ UINT64_C(0xA2CC06C6A67A733B), UINT64_C(0x7E6D2AE4F8F09D26),
+ UINT64_C(0xCF054C965A1F50D4), UINT64_C(0x13A460B40495BEC9),
+ UINT64_C(0x774615D2E60B8DEF), UINT64_C(0xABE739F0B88163F2),
+ UINT64_C(0xBF82FE1E2236EAA3), UINT64_C(0x6323D23C7CBC04BE),
+ UINT64_C(0x07C1A75A9E223798), UINT64_C(0xDB608B78C0A8D985),
+ UINT64_C(0x2F0B2987AB4D243B), UINT64_C(0xF3AA05A5F5C7CA26),
+ UINT64_C(0x974870C31759F900), UINT64_C(0x4BE95CE149D3171D),
+ UINT64_C(0x5F8C9B0FD3649E4C), UINT64_C(0x832DB72D8DEE7051),
+ UINT64_C(0xE7CFC24B6F704377), UINT64_C(0x3B6EEE6931FAAD6A),
+ UINT64_C(0x91131E980D8418A2), UINT64_C(0x4DB232BA530EF6BF),
+ UINT64_C(0x295047DCB190C599), UINT64_C(0xF5F16BFEEF1A2B84),
+ UINT64_C(0xE194AC1075ADA2D5), UINT64_C(0x3D3580322B274CC8),
+ UINT64_C(0x59D7F554C9B97FEE), UINT64_C(0x8576D976973391F3),
+ UINT64_C(0x711D7B89FCD66C4D), UINT64_C(0xADBC57ABA25C8250),
+ UINT64_C(0xC95E22CD40C2B176), UINT64_C(0x15FF0EEF1E485F6B),
+ UINT64_C(0x019AC90184FFD63A), UINT64_C(0xDD3BE523DA753827),
+ UINT64_C(0xB9D9904538EB0B01), UINT64_C(0x6578BC676661E51C),
+ UINT64_C(0xD410DA15C48E28EE), UINT64_C(0x08B1F6379A04C6F3),
+ UINT64_C(0x6C538351789AF5D5), UINT64_C(0xB0F2AF7326101BC8),
+ UINT64_C(0xA497689DBCA79299), UINT64_C(0x783644BFE22D7C84),
+ UINT64_C(0x1CD431D900B34FA2), UINT64_C(0xC0751DFB5E39A1BF),
+ UINT64_C(0x341EBF0435DC5C01), UINT64_C(0xE8BF93266B56B21C),
+ UINT64_C(0x8C5DE64089C8813A), UINT64_C(0x50FCCA62D7426F27),
+ UINT64_C(0x44990D8C4DF5E676), UINT64_C(0x983821AE137F086B),
+ UINT64_C(0xFCDA54C8F1E13B4D), UINT64_C(0x207B78EAAF6BD550),
+ UINT64_C(0x1B1596839E91783A), UINT64_C(0xC7B4BAA1C01B9627),
+ UINT64_C(0xA356CFC72285A501), UINT64_C(0x7FF7E3E57C0F4B1C),
+ UINT64_C(0x6B92240BE6B8C24D), UINT64_C(0xB7330829B8322C50),
+ UINT64_C(0xD3D17D4F5AAC1F76), UINT64_C(0x0F70516D0426F16B),
+ UINT64_C(0xFB1BF3926FC30CD5), UINT64_C(0x27BADFB03149E2C8),
+ UINT64_C(0x4358AAD6D3D7D1EE), UINT64_C(0x9FF986F48D5D3FF3),
+ UINT64_C(0x8B9C411A17EAB6A2), UINT64_C(0x573D6D38496058BF),
+ UINT64_C(0x33DF185EABFE6B99), UINT64_C(0xEF7E347CF5748584),
+ UINT64_C(0x5E16520E579B4876), UINT64_C(0x82B77E2C0911A66B),
+ UINT64_C(0xE6550B4AEB8F954D), UINT64_C(0x3AF42768B5057B50),
+ UINT64_C(0x2E91E0862FB2F201), UINT64_C(0xF230CCA471381C1C),
+ UINT64_C(0x96D2B9C293A62F3A), UINT64_C(0x4A7395E0CD2CC127),
+ UINT64_C(0xBE18371FA6C93C99), UINT64_C(0x62B91B3DF843D284),
+ UINT64_C(0x065B6E5B1ADDE1A2), UINT64_C(0xDAFA427944570FBF),
+ UINT64_C(0xCE9F8597DEE086EE), UINT64_C(0x123EA9B5806A68F3),
+ UINT64_C(0x76DCDCD362F45BD5), UINT64_C(0xAA7DF0F13C7EB5C8),
+ UINT64_C(0xA739329F30A7E9D6), UINT64_C(0x7B981EBD6E2D07CB),
+ UINT64_C(0x1F7A6BDB8CB334ED), UINT64_C(0xC3DB47F9D239DAF0),
+ UINT64_C(0xD7BE8017488E53A1), UINT64_C(0x0B1FAC351604BDBC),
+ UINT64_C(0x6FFDD953F49A8E9A), UINT64_C(0xB35CF571AA106087),
+ UINT64_C(0x4737578EC1F59D39), UINT64_C(0x9B967BAC9F7F7324),
+ UINT64_C(0xFF740ECA7DE14002), UINT64_C(0x23D522E8236BAE1F),
+ UINT64_C(0x37B0E506B9DC274E), UINT64_C(0xEB11C924E756C953),
+ UINT64_C(0x8FF3BC4205C8FA75), UINT64_C(0x535290605B421468),
+ UINT64_C(0xE23AF612F9ADD99A), UINT64_C(0x3E9BDA30A7273787),
+ UINT64_C(0x5A79AF5645B904A1), UINT64_C(0x86D883741B33EABC),
+ UINT64_C(0x92BD449A818463ED), UINT64_C(0x4E1C68B8DF0E8DF0),
+ UINT64_C(0x2AFE1DDE3D90BED6), UINT64_C(0xF65F31FC631A50CB),
+ UINT64_C(0x0234930308FFAD75), UINT64_C(0xDE95BF2156754368),
+ UINT64_C(0xBA77CA47B4EB704E), UINT64_C(0x66D6E665EA619E53),
+ UINT64_C(0x72B3218B70D61702), UINT64_C(0xAE120DA92E5CF91F),
+ UINT64_C(0xCAF078CFCCC2CA39), UINT64_C(0x165154ED92482424),
+ UINT64_C(0x2D3FBA84A3B2894E), UINT64_C(0xF19E96A6FD386753),
+ UINT64_C(0x957CE3C01FA65475), UINT64_C(0x49DDCFE2412CBA68),
+ UINT64_C(0x5DB8080CDB9B3339), UINT64_C(0x8119242E8511DD24),
+ UINT64_C(0xE5FB5148678FEE02), UINT64_C(0x395A7D6A3905001F),
+ UINT64_C(0xCD31DF9552E0FDA1), UINT64_C(0x1190F3B70C6A13BC),
+ UINT64_C(0x757286D1EEF4209A), UINT64_C(0xA9D3AAF3B07ECE87),
+ UINT64_C(0xBDB66D1D2AC947D6), UINT64_C(0x6117413F7443A9CB),
+ UINT64_C(0x05F5345996DD9AED), UINT64_C(0xD954187BC85774F0),
+ UINT64_C(0x683C7E096AB8B902), UINT64_C(0xB49D522B3432571F),
+ UINT64_C(0xD07F274DD6AC6439), UINT64_C(0x0CDE0B6F88268A24),
+ UINT64_C(0x18BBCC8112910375), UINT64_C(0xC41AE0A34C1BED68),
+ UINT64_C(0xA0F895C5AE85DE4E), UINT64_C(0x7C59B9E7F00F3053),
+ UINT64_C(0x88321B189BEACDED), UINT64_C(0x5493373AC56023F0),
+ UINT64_C(0x3071425C27FE10D6), UINT64_C(0xECD06E7E7974FECB),
+ UINT64_C(0xF8B5A990E3C3779A), UINT64_C(0x241485B2BD499987),
+ UINT64_C(0x40F6F0D45FD7AAA1), UINT64_C(0x9C57DCF6015D44BC),
+ UINT64_C(0x362A2C073D23F174), UINT64_C(0xEA8B002563A91F69),
+ UINT64_C(0x8E69754381372C4F), UINT64_C(0x52C85961DFBDC252),
+ UINT64_C(0x46AD9E8F450A4B03), UINT64_C(0x9A0CB2AD1B80A51E),
+ UINT64_C(0xFEEEC7CBF91E9638), UINT64_C(0x224FEBE9A7947825),
+ UINT64_C(0xD6244916CC71859B), UINT64_C(0x0A85653492FB6B86),
+ UINT64_C(0x6E671052706558A0), UINT64_C(0xB2C63C702EEFB6BD),
+ UINT64_C(0xA6A3FB9EB4583FEC), UINT64_C(0x7A02D7BCEAD2D1F1),
+ UINT64_C(0x1EE0A2DA084CE2D7), UINT64_C(0xC2418EF856C60CCA),
+ UINT64_C(0x7329E88AF429C138), UINT64_C(0xAF88C4A8AAA32F25),
+ UINT64_C(0xCB6AB1CE483D1C03), UINT64_C(0x17CB9DEC16B7F21E),
+ UINT64_C(0x03AE5A028C007B4F), UINT64_C(0xDF0F7620D28A9552),
+ UINT64_C(0xBBED03463014A674), UINT64_C(0x674C2F646E9E4869),
+ UINT64_C(0x93278D9B057BB5D7), UINT64_C(0x4F86A1B95BF15BCA),
+ UINT64_C(0x2B64D4DFB96F68EC), UINT64_C(0xF7C5F8FDE7E586F1),
+ UINT64_C(0xE3A03F137D520FA0), UINT64_C(0x3F01133123D8E1BD),
+ UINT64_C(0x5BE36657C146D29B), UINT64_C(0x87424A759FCC3C86),
+ UINT64_C(0xBC2CA41CAE3691EC), UINT64_C(0x608D883EF0BC7FF1),
+ UINT64_C(0x046FFD5812224CD7), UINT64_C(0xD8CED17A4CA8A2CA),
+ UINT64_C(0xCCAB1694D61F2B9B), UINT64_C(0x100A3AB68895C586),
+ UINT64_C(0x74E84FD06A0BF6A0), UINT64_C(0xA84963F2348118BD),
+ UINT64_C(0x5C22C10D5F64E503), UINT64_C(0x8083ED2F01EE0B1E),
+ UINT64_C(0xE4619849E3703838), UINT64_C(0x38C0B46BBDFAD625),
+ UINT64_C(0x2CA57385274D5F74), UINT64_C(0xF0045FA779C7B169),
+ UINT64_C(0x94E62AC19B59824F), UINT64_C(0x484706E3C5D36C52),
+ UINT64_C(0xF92F6091673CA1A0), UINT64_C(0x258E4CB339B64FBD),
+ UINT64_C(0x416C39D5DB287C9B), UINT64_C(0x9DCD15F785A29286),
+ UINT64_C(0x89A8D2191F151BD7), UINT64_C(0x5509FE3B419FF5CA),
+ UINT64_C(0x31EB8B5DA301C6EC), UINT64_C(0xED4AA77FFD8B28F1),
+ UINT64_C(0x19210580966ED54F), UINT64_C(0xC58029A2C8E43B52),
+ UINT64_C(0xA1625CC42A7A0874), UINT64_C(0x7DC370E674F0E669),
+ UINT64_C(0x69A6B708EE476F38), UINT64_C(0xB5079B2AB0CD8125),
+ UINT64_C(0xD1E5EE4C5253B203), UINT64_C(0x0D44C26E0CD95C1E)
+ }
+};
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_table_le.h b/Utilities/cmliblzma/liblzma/check/crc64_table_le.h
new file mode 100644
index 000000000..1196b31e1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_table_le.h
@@ -0,0 +1,521 @@
+/* This file has been automatically generated by crc64_tablegen.c. */
+
+const uint64_t lzma_crc64_table[4][256] = {
+ {
+ UINT64_C(0x0000000000000000), UINT64_C(0xB32E4CBE03A75F6F),
+ UINT64_C(0xF4843657A840A05B), UINT64_C(0x47AA7AE9ABE7FF34),
+ UINT64_C(0x7BD0C384FF8F5E33), UINT64_C(0xC8FE8F3AFC28015C),
+ UINT64_C(0x8F54F5D357CFFE68), UINT64_C(0x3C7AB96D5468A107),
+ UINT64_C(0xF7A18709FF1EBC66), UINT64_C(0x448FCBB7FCB9E309),
+ UINT64_C(0x0325B15E575E1C3D), UINT64_C(0xB00BFDE054F94352),
+ UINT64_C(0x8C71448D0091E255), UINT64_C(0x3F5F08330336BD3A),
+ UINT64_C(0x78F572DAA8D1420E), UINT64_C(0xCBDB3E64AB761D61),
+ UINT64_C(0x7D9BA13851336649), UINT64_C(0xCEB5ED8652943926),
+ UINT64_C(0x891F976FF973C612), UINT64_C(0x3A31DBD1FAD4997D),
+ UINT64_C(0x064B62BCAEBC387A), UINT64_C(0xB5652E02AD1B6715),
+ UINT64_C(0xF2CF54EB06FC9821), UINT64_C(0x41E11855055BC74E),
+ UINT64_C(0x8A3A2631AE2DDA2F), UINT64_C(0x39146A8FAD8A8540),
+ UINT64_C(0x7EBE1066066D7A74), UINT64_C(0xCD905CD805CA251B),
+ UINT64_C(0xF1EAE5B551A2841C), UINT64_C(0x42C4A90B5205DB73),
+ UINT64_C(0x056ED3E2F9E22447), UINT64_C(0xB6409F5CFA457B28),
+ UINT64_C(0xFB374270A266CC92), UINT64_C(0x48190ECEA1C193FD),
+ UINT64_C(0x0FB374270A266CC9), UINT64_C(0xBC9D3899098133A6),
+ UINT64_C(0x80E781F45DE992A1), UINT64_C(0x33C9CD4A5E4ECDCE),
+ UINT64_C(0x7463B7A3F5A932FA), UINT64_C(0xC74DFB1DF60E6D95),
+ UINT64_C(0x0C96C5795D7870F4), UINT64_C(0xBFB889C75EDF2F9B),
+ UINT64_C(0xF812F32EF538D0AF), UINT64_C(0x4B3CBF90F69F8FC0),
+ UINT64_C(0x774606FDA2F72EC7), UINT64_C(0xC4684A43A15071A8),
+ UINT64_C(0x83C230AA0AB78E9C), UINT64_C(0x30EC7C140910D1F3),
+ UINT64_C(0x86ACE348F355AADB), UINT64_C(0x3582AFF6F0F2F5B4),
+ UINT64_C(0x7228D51F5B150A80), UINT64_C(0xC10699A158B255EF),
+ UINT64_C(0xFD7C20CC0CDAF4E8), UINT64_C(0x4E526C720F7DAB87),
+ UINT64_C(0x09F8169BA49A54B3), UINT64_C(0xBAD65A25A73D0BDC),
+ UINT64_C(0x710D64410C4B16BD), UINT64_C(0xC22328FF0FEC49D2),
+ UINT64_C(0x85895216A40BB6E6), UINT64_C(0x36A71EA8A7ACE989),
+ UINT64_C(0x0ADDA7C5F3C4488E), UINT64_C(0xB9F3EB7BF06317E1),
+ UINT64_C(0xFE5991925B84E8D5), UINT64_C(0x4D77DD2C5823B7BA),
+ UINT64_C(0x64B62BCAEBC387A1), UINT64_C(0xD7986774E864D8CE),
+ UINT64_C(0x90321D9D438327FA), UINT64_C(0x231C512340247895),
+ UINT64_C(0x1F66E84E144CD992), UINT64_C(0xAC48A4F017EB86FD),
+ UINT64_C(0xEBE2DE19BC0C79C9), UINT64_C(0x58CC92A7BFAB26A6),
+ UINT64_C(0x9317ACC314DD3BC7), UINT64_C(0x2039E07D177A64A8),
+ UINT64_C(0x67939A94BC9D9B9C), UINT64_C(0xD4BDD62ABF3AC4F3),
+ UINT64_C(0xE8C76F47EB5265F4), UINT64_C(0x5BE923F9E8F53A9B),
+ UINT64_C(0x1C4359104312C5AF), UINT64_C(0xAF6D15AE40B59AC0),
+ UINT64_C(0x192D8AF2BAF0E1E8), UINT64_C(0xAA03C64CB957BE87),
+ UINT64_C(0xEDA9BCA512B041B3), UINT64_C(0x5E87F01B11171EDC),
+ UINT64_C(0x62FD4976457FBFDB), UINT64_C(0xD1D305C846D8E0B4),
+ UINT64_C(0x96797F21ED3F1F80), UINT64_C(0x2557339FEE9840EF),
+ UINT64_C(0xEE8C0DFB45EE5D8E), UINT64_C(0x5DA24145464902E1),
+ UINT64_C(0x1A083BACEDAEFDD5), UINT64_C(0xA9267712EE09A2BA),
+ UINT64_C(0x955CCE7FBA6103BD), UINT64_C(0x267282C1B9C65CD2),
+ UINT64_C(0x61D8F8281221A3E6), UINT64_C(0xD2F6B4961186FC89),
+ UINT64_C(0x9F8169BA49A54B33), UINT64_C(0x2CAF25044A02145C),
+ UINT64_C(0x6B055FEDE1E5EB68), UINT64_C(0xD82B1353E242B407),
+ UINT64_C(0xE451AA3EB62A1500), UINT64_C(0x577FE680B58D4A6F),
+ UINT64_C(0x10D59C691E6AB55B), UINT64_C(0xA3FBD0D71DCDEA34),
+ UINT64_C(0x6820EEB3B6BBF755), UINT64_C(0xDB0EA20DB51CA83A),
+ UINT64_C(0x9CA4D8E41EFB570E), UINT64_C(0x2F8A945A1D5C0861),
+ UINT64_C(0x13F02D374934A966), UINT64_C(0xA0DE61894A93F609),
+ UINT64_C(0xE7741B60E174093D), UINT64_C(0x545A57DEE2D35652),
+ UINT64_C(0xE21AC88218962D7A), UINT64_C(0x5134843C1B317215),
+ UINT64_C(0x169EFED5B0D68D21), UINT64_C(0xA5B0B26BB371D24E),
+ UINT64_C(0x99CA0B06E7197349), UINT64_C(0x2AE447B8E4BE2C26),
+ UINT64_C(0x6D4E3D514F59D312), UINT64_C(0xDE6071EF4CFE8C7D),
+ UINT64_C(0x15BB4F8BE788911C), UINT64_C(0xA6950335E42FCE73),
+ UINT64_C(0xE13F79DC4FC83147), UINT64_C(0x521135624C6F6E28),
+ UINT64_C(0x6E6B8C0F1807CF2F), UINT64_C(0xDD45C0B11BA09040),
+ UINT64_C(0x9AEFBA58B0476F74), UINT64_C(0x29C1F6E6B3E0301B),
+ UINT64_C(0xC96C5795D7870F42), UINT64_C(0x7A421B2BD420502D),
+ UINT64_C(0x3DE861C27FC7AF19), UINT64_C(0x8EC62D7C7C60F076),
+ UINT64_C(0xB2BC941128085171), UINT64_C(0x0192D8AF2BAF0E1E),
+ UINT64_C(0x4638A2468048F12A), UINT64_C(0xF516EEF883EFAE45),
+ UINT64_C(0x3ECDD09C2899B324), UINT64_C(0x8DE39C222B3EEC4B),
+ UINT64_C(0xCA49E6CB80D9137F), UINT64_C(0x7967AA75837E4C10),
+ UINT64_C(0x451D1318D716ED17), UINT64_C(0xF6335FA6D4B1B278),
+ UINT64_C(0xB199254F7F564D4C), UINT64_C(0x02B769F17CF11223),
+ UINT64_C(0xB4F7F6AD86B4690B), UINT64_C(0x07D9BA1385133664),
+ UINT64_C(0x4073C0FA2EF4C950), UINT64_C(0xF35D8C442D53963F),
+ UINT64_C(0xCF273529793B3738), UINT64_C(0x7C0979977A9C6857),
+ UINT64_C(0x3BA3037ED17B9763), UINT64_C(0x888D4FC0D2DCC80C),
+ UINT64_C(0x435671A479AAD56D), UINT64_C(0xF0783D1A7A0D8A02),
+ UINT64_C(0xB7D247F3D1EA7536), UINT64_C(0x04FC0B4DD24D2A59),
+ UINT64_C(0x3886B22086258B5E), UINT64_C(0x8BA8FE9E8582D431),
+ UINT64_C(0xCC0284772E652B05), UINT64_C(0x7F2CC8C92DC2746A),
+ UINT64_C(0x325B15E575E1C3D0), UINT64_C(0x8175595B76469CBF),
+ UINT64_C(0xC6DF23B2DDA1638B), UINT64_C(0x75F16F0CDE063CE4),
+ UINT64_C(0x498BD6618A6E9DE3), UINT64_C(0xFAA59ADF89C9C28C),
+ UINT64_C(0xBD0FE036222E3DB8), UINT64_C(0x0E21AC88218962D7),
+ UINT64_C(0xC5FA92EC8AFF7FB6), UINT64_C(0x76D4DE52895820D9),
+ UINT64_C(0x317EA4BB22BFDFED), UINT64_C(0x8250E80521188082),
+ UINT64_C(0xBE2A516875702185), UINT64_C(0x0D041DD676D77EEA),
+ UINT64_C(0x4AAE673FDD3081DE), UINT64_C(0xF9802B81DE97DEB1),
+ UINT64_C(0x4FC0B4DD24D2A599), UINT64_C(0xFCEEF8632775FAF6),
+ UINT64_C(0xBB44828A8C9205C2), UINT64_C(0x086ACE348F355AAD),
+ UINT64_C(0x34107759DB5DFBAA), UINT64_C(0x873E3BE7D8FAA4C5),
+ UINT64_C(0xC094410E731D5BF1), UINT64_C(0x73BA0DB070BA049E),
+ UINT64_C(0xB86133D4DBCC19FF), UINT64_C(0x0B4F7F6AD86B4690),
+ UINT64_C(0x4CE50583738CB9A4), UINT64_C(0xFFCB493D702BE6CB),
+ UINT64_C(0xC3B1F050244347CC), UINT64_C(0x709FBCEE27E418A3),
+ UINT64_C(0x3735C6078C03E797), UINT64_C(0x841B8AB98FA4B8F8),
+ UINT64_C(0xADDA7C5F3C4488E3), UINT64_C(0x1EF430E13FE3D78C),
+ UINT64_C(0x595E4A08940428B8), UINT64_C(0xEA7006B697A377D7),
+ UINT64_C(0xD60ABFDBC3CBD6D0), UINT64_C(0x6524F365C06C89BF),
+ UINT64_C(0x228E898C6B8B768B), UINT64_C(0x91A0C532682C29E4),
+ UINT64_C(0x5A7BFB56C35A3485), UINT64_C(0xE955B7E8C0FD6BEA),
+ UINT64_C(0xAEFFCD016B1A94DE), UINT64_C(0x1DD181BF68BDCBB1),
+ UINT64_C(0x21AB38D23CD56AB6), UINT64_C(0x9285746C3F7235D9),
+ UINT64_C(0xD52F0E859495CAED), UINT64_C(0x6601423B97329582),
+ UINT64_C(0xD041DD676D77EEAA), UINT64_C(0x636F91D96ED0B1C5),
+ UINT64_C(0x24C5EB30C5374EF1), UINT64_C(0x97EBA78EC690119E),
+ UINT64_C(0xAB911EE392F8B099), UINT64_C(0x18BF525D915FEFF6),
+ UINT64_C(0x5F1528B43AB810C2), UINT64_C(0xEC3B640A391F4FAD),
+ UINT64_C(0x27E05A6E926952CC), UINT64_C(0x94CE16D091CE0DA3),
+ UINT64_C(0xD3646C393A29F297), UINT64_C(0x604A2087398EADF8),
+ UINT64_C(0x5C3099EA6DE60CFF), UINT64_C(0xEF1ED5546E415390),
+ UINT64_C(0xA8B4AFBDC5A6ACA4), UINT64_C(0x1B9AE303C601F3CB),
+ UINT64_C(0x56ED3E2F9E224471), UINT64_C(0xE5C372919D851B1E),
+ UINT64_C(0xA26908783662E42A), UINT64_C(0x114744C635C5BB45),
+ UINT64_C(0x2D3DFDAB61AD1A42), UINT64_C(0x9E13B115620A452D),
+ UINT64_C(0xD9B9CBFCC9EDBA19), UINT64_C(0x6A978742CA4AE576),
+ UINT64_C(0xA14CB926613CF817), UINT64_C(0x1262F598629BA778),
+ UINT64_C(0x55C88F71C97C584C), UINT64_C(0xE6E6C3CFCADB0723),
+ UINT64_C(0xDA9C7AA29EB3A624), UINT64_C(0x69B2361C9D14F94B),
+ UINT64_C(0x2E184CF536F3067F), UINT64_C(0x9D36004B35545910),
+ UINT64_C(0x2B769F17CF112238), UINT64_C(0x9858D3A9CCB67D57),
+ UINT64_C(0xDFF2A94067518263), UINT64_C(0x6CDCE5FE64F6DD0C),
+ UINT64_C(0x50A65C93309E7C0B), UINT64_C(0xE388102D33392364),
+ UINT64_C(0xA4226AC498DEDC50), UINT64_C(0x170C267A9B79833F),
+ UINT64_C(0xDCD7181E300F9E5E), UINT64_C(0x6FF954A033A8C131),
+ UINT64_C(0x28532E49984F3E05), UINT64_C(0x9B7D62F79BE8616A),
+ UINT64_C(0xA707DB9ACF80C06D), UINT64_C(0x14299724CC279F02),
+ UINT64_C(0x5383EDCD67C06036), UINT64_C(0xE0ADA17364673F59)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0x54E979925CD0F10D),
+ UINT64_C(0xA9D2F324B9A1E21A), UINT64_C(0xFD3B8AB6E5711317),
+ UINT64_C(0xC17D4962DC4DDAB1), UINT64_C(0x959430F0809D2BBC),
+ UINT64_C(0x68AFBA4665EC38AB), UINT64_C(0x3C46C3D4393CC9A6),
+ UINT64_C(0x10223DEE1795ABE7), UINT64_C(0x44CB447C4B455AEA),
+ UINT64_C(0xB9F0CECAAE3449FD), UINT64_C(0xED19B758F2E4B8F0),
+ UINT64_C(0xD15F748CCBD87156), UINT64_C(0x85B60D1E9708805B),
+ UINT64_C(0x788D87A87279934C), UINT64_C(0x2C64FE3A2EA96241),
+ UINT64_C(0x20447BDC2F2B57CE), UINT64_C(0x74AD024E73FBA6C3),
+ UINT64_C(0x899688F8968AB5D4), UINT64_C(0xDD7FF16ACA5A44D9),
+ UINT64_C(0xE13932BEF3668D7F), UINT64_C(0xB5D04B2CAFB67C72),
+ UINT64_C(0x48EBC19A4AC76F65), UINT64_C(0x1C02B80816179E68),
+ UINT64_C(0x3066463238BEFC29), UINT64_C(0x648F3FA0646E0D24),
+ UINT64_C(0x99B4B516811F1E33), UINT64_C(0xCD5DCC84DDCFEF3E),
+ UINT64_C(0xF11B0F50E4F32698), UINT64_C(0xA5F276C2B823D795),
+ UINT64_C(0x58C9FC745D52C482), UINT64_C(0x0C2085E60182358F),
+ UINT64_C(0x4088F7B85E56AF9C), UINT64_C(0x14618E2A02865E91),
+ UINT64_C(0xE95A049CE7F74D86), UINT64_C(0xBDB37D0EBB27BC8B),
+ UINT64_C(0x81F5BEDA821B752D), UINT64_C(0xD51CC748DECB8420),
+ UINT64_C(0x28274DFE3BBA9737), UINT64_C(0x7CCE346C676A663A),
+ UINT64_C(0x50AACA5649C3047B), UINT64_C(0x0443B3C41513F576),
+ UINT64_C(0xF9783972F062E661), UINT64_C(0xAD9140E0ACB2176C),
+ UINT64_C(0x91D78334958EDECA), UINT64_C(0xC53EFAA6C95E2FC7),
+ UINT64_C(0x380570102C2F3CD0), UINT64_C(0x6CEC098270FFCDDD),
+ UINT64_C(0x60CC8C64717DF852), UINT64_C(0x3425F5F62DAD095F),
+ UINT64_C(0xC91E7F40C8DC1A48), UINT64_C(0x9DF706D2940CEB45),
+ UINT64_C(0xA1B1C506AD3022E3), UINT64_C(0xF558BC94F1E0D3EE),
+ UINT64_C(0x086336221491C0F9), UINT64_C(0x5C8A4FB0484131F4),
+ UINT64_C(0x70EEB18A66E853B5), UINT64_C(0x2407C8183A38A2B8),
+ UINT64_C(0xD93C42AEDF49B1AF), UINT64_C(0x8DD53B3C839940A2),
+ UINT64_C(0xB193F8E8BAA58904), UINT64_C(0xE57A817AE6757809),
+ UINT64_C(0x18410BCC03046B1E), UINT64_C(0x4CA8725E5FD49A13),
+ UINT64_C(0x8111EF70BCAD5F38), UINT64_C(0xD5F896E2E07DAE35),
+ UINT64_C(0x28C31C54050CBD22), UINT64_C(0x7C2A65C659DC4C2F),
+ UINT64_C(0x406CA61260E08589), UINT64_C(0x1485DF803C307484),
+ UINT64_C(0xE9BE5536D9416793), UINT64_C(0xBD572CA48591969E),
+ UINT64_C(0x9133D29EAB38F4DF), UINT64_C(0xC5DAAB0CF7E805D2),
+ UINT64_C(0x38E121BA129916C5), UINT64_C(0x6C0858284E49E7C8),
+ UINT64_C(0x504E9BFC77752E6E), UINT64_C(0x04A7E26E2BA5DF63),
+ UINT64_C(0xF99C68D8CED4CC74), UINT64_C(0xAD75114A92043D79),
+ UINT64_C(0xA15594AC938608F6), UINT64_C(0xF5BCED3ECF56F9FB),
+ UINT64_C(0x088767882A27EAEC), UINT64_C(0x5C6E1E1A76F71BE1),
+ UINT64_C(0x6028DDCE4FCBD247), UINT64_C(0x34C1A45C131B234A),
+ UINT64_C(0xC9FA2EEAF66A305D), UINT64_C(0x9D135778AABAC150),
+ UINT64_C(0xB177A9428413A311), UINT64_C(0xE59ED0D0D8C3521C),
+ UINT64_C(0x18A55A663DB2410B), UINT64_C(0x4C4C23F46162B006),
+ UINT64_C(0x700AE020585E79A0), UINT64_C(0x24E399B2048E88AD),
+ UINT64_C(0xD9D81304E1FF9BBA), UINT64_C(0x8D316A96BD2F6AB7),
+ UINT64_C(0xC19918C8E2FBF0A4), UINT64_C(0x9570615ABE2B01A9),
+ UINT64_C(0x684BEBEC5B5A12BE), UINT64_C(0x3CA2927E078AE3B3),
+ UINT64_C(0x00E451AA3EB62A15), UINT64_C(0x540D28386266DB18),
+ UINT64_C(0xA936A28E8717C80F), UINT64_C(0xFDDFDB1CDBC73902),
+ UINT64_C(0xD1BB2526F56E5B43), UINT64_C(0x85525CB4A9BEAA4E),
+ UINT64_C(0x7869D6024CCFB959), UINT64_C(0x2C80AF90101F4854),
+ UINT64_C(0x10C66C44292381F2), UINT64_C(0x442F15D675F370FF),
+ UINT64_C(0xB9149F60908263E8), UINT64_C(0xEDFDE6F2CC5292E5),
+ UINT64_C(0xE1DD6314CDD0A76A), UINT64_C(0xB5341A8691005667),
+ UINT64_C(0x480F903074714570), UINT64_C(0x1CE6E9A228A1B47D),
+ UINT64_C(0x20A02A76119D7DDB), UINT64_C(0x744953E44D4D8CD6),
+ UINT64_C(0x8972D952A83C9FC1), UINT64_C(0xDD9BA0C0F4EC6ECC),
+ UINT64_C(0xF1FF5EFADA450C8D), UINT64_C(0xA51627688695FD80),
+ UINT64_C(0x582DADDE63E4EE97), UINT64_C(0x0CC4D44C3F341F9A),
+ UINT64_C(0x308217980608D63C), UINT64_C(0x646B6E0A5AD82731),
+ UINT64_C(0x9950E4BCBFA93426), UINT64_C(0xCDB99D2EE379C52B),
+ UINT64_C(0x90FB71CAD654A0F5), UINT64_C(0xC41208588A8451F8),
+ UINT64_C(0x392982EE6FF542EF), UINT64_C(0x6DC0FB7C3325B3E2),
+ UINT64_C(0x518638A80A197A44), UINT64_C(0x056F413A56C98B49),
+ UINT64_C(0xF854CB8CB3B8985E), UINT64_C(0xACBDB21EEF686953),
+ UINT64_C(0x80D94C24C1C10B12), UINT64_C(0xD43035B69D11FA1F),
+ UINT64_C(0x290BBF007860E908), UINT64_C(0x7DE2C69224B01805),
+ UINT64_C(0x41A405461D8CD1A3), UINT64_C(0x154D7CD4415C20AE),
+ UINT64_C(0xE876F662A42D33B9), UINT64_C(0xBC9F8FF0F8FDC2B4),
+ UINT64_C(0xB0BF0A16F97FF73B), UINT64_C(0xE4567384A5AF0636),
+ UINT64_C(0x196DF93240DE1521), UINT64_C(0x4D8480A01C0EE42C),
+ UINT64_C(0x71C2437425322D8A), UINT64_C(0x252B3AE679E2DC87),
+ UINT64_C(0xD810B0509C93CF90), UINT64_C(0x8CF9C9C2C0433E9D),
+ UINT64_C(0xA09D37F8EEEA5CDC), UINT64_C(0xF4744E6AB23AADD1),
+ UINT64_C(0x094FC4DC574BBEC6), UINT64_C(0x5DA6BD4E0B9B4FCB),
+ UINT64_C(0x61E07E9A32A7866D), UINT64_C(0x350907086E777760),
+ UINT64_C(0xC8328DBE8B066477), UINT64_C(0x9CDBF42CD7D6957A),
+ UINT64_C(0xD073867288020F69), UINT64_C(0x849AFFE0D4D2FE64),
+ UINT64_C(0x79A1755631A3ED73), UINT64_C(0x2D480CC46D731C7E),
+ UINT64_C(0x110ECF10544FD5D8), UINT64_C(0x45E7B682089F24D5),
+ UINT64_C(0xB8DC3C34EDEE37C2), UINT64_C(0xEC3545A6B13EC6CF),
+ UINT64_C(0xC051BB9C9F97A48E), UINT64_C(0x94B8C20EC3475583),
+ UINT64_C(0x698348B826364694), UINT64_C(0x3D6A312A7AE6B799),
+ UINT64_C(0x012CF2FE43DA7E3F), UINT64_C(0x55C58B6C1F0A8F32),
+ UINT64_C(0xA8FE01DAFA7B9C25), UINT64_C(0xFC177848A6AB6D28),
+ UINT64_C(0xF037FDAEA72958A7), UINT64_C(0xA4DE843CFBF9A9AA),
+ UINT64_C(0x59E50E8A1E88BABD), UINT64_C(0x0D0C771842584BB0),
+ UINT64_C(0x314AB4CC7B648216), UINT64_C(0x65A3CD5E27B4731B),
+ UINT64_C(0x989847E8C2C5600C), UINT64_C(0xCC713E7A9E159101),
+ UINT64_C(0xE015C040B0BCF340), UINT64_C(0xB4FCB9D2EC6C024D),
+ UINT64_C(0x49C73364091D115A), UINT64_C(0x1D2E4AF655CDE057),
+ UINT64_C(0x216889226CF129F1), UINT64_C(0x7581F0B03021D8FC),
+ UINT64_C(0x88BA7A06D550CBEB), UINT64_C(0xDC53039489803AE6),
+ UINT64_C(0x11EA9EBA6AF9FFCD), UINT64_C(0x4503E72836290EC0),
+ UINT64_C(0xB8386D9ED3581DD7), UINT64_C(0xECD1140C8F88ECDA),
+ UINT64_C(0xD097D7D8B6B4257C), UINT64_C(0x847EAE4AEA64D471),
+ UINT64_C(0x794524FC0F15C766), UINT64_C(0x2DAC5D6E53C5366B),
+ UINT64_C(0x01C8A3547D6C542A), UINT64_C(0x5521DAC621BCA527),
+ UINT64_C(0xA81A5070C4CDB630), UINT64_C(0xFCF329E2981D473D),
+ UINT64_C(0xC0B5EA36A1218E9B), UINT64_C(0x945C93A4FDF17F96),
+ UINT64_C(0x6967191218806C81), UINT64_C(0x3D8E608044509D8C),
+ UINT64_C(0x31AEE56645D2A803), UINT64_C(0x65479CF41902590E),
+ UINT64_C(0x987C1642FC734A19), UINT64_C(0xCC956FD0A0A3BB14),
+ UINT64_C(0xF0D3AC04999F72B2), UINT64_C(0xA43AD596C54F83BF),
+ UINT64_C(0x59015F20203E90A8), UINT64_C(0x0DE826B27CEE61A5),
+ UINT64_C(0x218CD888524703E4), UINT64_C(0x7565A11A0E97F2E9),
+ UINT64_C(0x885E2BACEBE6E1FE), UINT64_C(0xDCB7523EB73610F3),
+ UINT64_C(0xE0F191EA8E0AD955), UINT64_C(0xB418E878D2DA2858),
+ UINT64_C(0x492362CE37AB3B4F), UINT64_C(0x1DCA1B5C6B7BCA42),
+ UINT64_C(0x5162690234AF5051), UINT64_C(0x058B1090687FA15C),
+ UINT64_C(0xF8B09A268D0EB24B), UINT64_C(0xAC59E3B4D1DE4346),
+ UINT64_C(0x901F2060E8E28AE0), UINT64_C(0xC4F659F2B4327BED),
+ UINT64_C(0x39CDD344514368FA), UINT64_C(0x6D24AAD60D9399F7),
+ UINT64_C(0x414054EC233AFBB6), UINT64_C(0x15A92D7E7FEA0ABB),
+ UINT64_C(0xE892A7C89A9B19AC), UINT64_C(0xBC7BDE5AC64BE8A1),
+ UINT64_C(0x803D1D8EFF772107), UINT64_C(0xD4D4641CA3A7D00A),
+ UINT64_C(0x29EFEEAA46D6C31D), UINT64_C(0x7D0697381A063210),
+ UINT64_C(0x712612DE1B84079F), UINT64_C(0x25CF6B4C4754F692),
+ UINT64_C(0xD8F4E1FAA225E585), UINT64_C(0x8C1D9868FEF51488),
+ UINT64_C(0xB05B5BBCC7C9DD2E), UINT64_C(0xE4B2222E9B192C23),
+ UINT64_C(0x1989A8987E683F34), UINT64_C(0x4D60D10A22B8CE39),
+ UINT64_C(0x61042F300C11AC78), UINT64_C(0x35ED56A250C15D75),
+ UINT64_C(0xC8D6DC14B5B04E62), UINT64_C(0x9C3FA586E960BF6F),
+ UINT64_C(0xA0796652D05C76C9), UINT64_C(0xF4901FC08C8C87C4),
+ UINT64_C(0x09AB957669FD94D3), UINT64_C(0x5D42ECE4352D65DE)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0x3F0BE14A916A6DCB),
+ UINT64_C(0x7E17C29522D4DB96), UINT64_C(0x411C23DFB3BEB65D),
+ UINT64_C(0xFC2F852A45A9B72C), UINT64_C(0xC3246460D4C3DAE7),
+ UINT64_C(0x823847BF677D6CBA), UINT64_C(0xBD33A6F5F6170171),
+ UINT64_C(0x6A87A57F245D70DD), UINT64_C(0x558C4435B5371D16),
+ UINT64_C(0x149067EA0689AB4B), UINT64_C(0x2B9B86A097E3C680),
+ UINT64_C(0x96A8205561F4C7F1), UINT64_C(0xA9A3C11FF09EAA3A),
+ UINT64_C(0xE8BFE2C043201C67), UINT64_C(0xD7B4038AD24A71AC),
+ UINT64_C(0xD50F4AFE48BAE1BA), UINT64_C(0xEA04ABB4D9D08C71),
+ UINT64_C(0xAB18886B6A6E3A2C), UINT64_C(0x94136921FB0457E7),
+ UINT64_C(0x2920CFD40D135696), UINT64_C(0x162B2E9E9C793B5D),
+ UINT64_C(0x57370D412FC78D00), UINT64_C(0x683CEC0BBEADE0CB),
+ UINT64_C(0xBF88EF816CE79167), UINT64_C(0x80830ECBFD8DFCAC),
+ UINT64_C(0xC19F2D144E334AF1), UINT64_C(0xFE94CC5EDF59273A),
+ UINT64_C(0x43A76AAB294E264B), UINT64_C(0x7CAC8BE1B8244B80),
+ UINT64_C(0x3DB0A83E0B9AFDDD), UINT64_C(0x02BB49749AF09016),
+ UINT64_C(0x38C63AD73E7BDDF1), UINT64_C(0x07CDDB9DAF11B03A),
+ UINT64_C(0x46D1F8421CAF0667), UINT64_C(0x79DA19088DC56BAC),
+ UINT64_C(0xC4E9BFFD7BD26ADD), UINT64_C(0xFBE25EB7EAB80716),
+ UINT64_C(0xBAFE7D685906B14B), UINT64_C(0x85F59C22C86CDC80),
+ UINT64_C(0x52419FA81A26AD2C), UINT64_C(0x6D4A7EE28B4CC0E7),
+ UINT64_C(0x2C565D3D38F276BA), UINT64_C(0x135DBC77A9981B71),
+ UINT64_C(0xAE6E1A825F8F1A00), UINT64_C(0x9165FBC8CEE577CB),
+ UINT64_C(0xD079D8177D5BC196), UINT64_C(0xEF72395DEC31AC5D),
+ UINT64_C(0xEDC9702976C13C4B), UINT64_C(0xD2C29163E7AB5180),
+ UINT64_C(0x93DEB2BC5415E7DD), UINT64_C(0xACD553F6C57F8A16),
+ UINT64_C(0x11E6F50333688B67), UINT64_C(0x2EED1449A202E6AC),
+ UINT64_C(0x6FF1379611BC50F1), UINT64_C(0x50FAD6DC80D63D3A),
+ UINT64_C(0x874ED556529C4C96), UINT64_C(0xB845341CC3F6215D),
+ UINT64_C(0xF95917C370489700), UINT64_C(0xC652F689E122FACB),
+ UINT64_C(0x7B61507C1735FBBA), UINT64_C(0x446AB136865F9671),
+ UINT64_C(0x057692E935E1202C), UINT64_C(0x3A7D73A3A48B4DE7),
+ UINT64_C(0x718C75AE7CF7BBE2), UINT64_C(0x4E8794E4ED9DD629),
+ UINT64_C(0x0F9BB73B5E236074), UINT64_C(0x30905671CF490DBF),
+ UINT64_C(0x8DA3F084395E0CCE), UINT64_C(0xB2A811CEA8346105),
+ UINT64_C(0xF3B432111B8AD758), UINT64_C(0xCCBFD35B8AE0BA93),
+ UINT64_C(0x1B0BD0D158AACB3F), UINT64_C(0x2400319BC9C0A6F4),
+ UINT64_C(0x651C12447A7E10A9), UINT64_C(0x5A17F30EEB147D62),
+ UINT64_C(0xE72455FB1D037C13), UINT64_C(0xD82FB4B18C6911D8),
+ UINT64_C(0x9933976E3FD7A785), UINT64_C(0xA6387624AEBDCA4E),
+ UINT64_C(0xA4833F50344D5A58), UINT64_C(0x9B88DE1AA5273793),
+ UINT64_C(0xDA94FDC5169981CE), UINT64_C(0xE59F1C8F87F3EC05),
+ UINT64_C(0x58ACBA7A71E4ED74), UINT64_C(0x67A75B30E08E80BF),
+ UINT64_C(0x26BB78EF533036E2), UINT64_C(0x19B099A5C25A5B29),
+ UINT64_C(0xCE049A2F10102A85), UINT64_C(0xF10F7B65817A474E),
+ UINT64_C(0xB01358BA32C4F113), UINT64_C(0x8F18B9F0A3AE9CD8),
+ UINT64_C(0x322B1F0555B99DA9), UINT64_C(0x0D20FE4FC4D3F062),
+ UINT64_C(0x4C3CDD90776D463F), UINT64_C(0x73373CDAE6072BF4),
+ UINT64_C(0x494A4F79428C6613), UINT64_C(0x7641AE33D3E60BD8),
+ UINT64_C(0x375D8DEC6058BD85), UINT64_C(0x08566CA6F132D04E),
+ UINT64_C(0xB565CA530725D13F), UINT64_C(0x8A6E2B19964FBCF4),
+ UINT64_C(0xCB7208C625F10AA9), UINT64_C(0xF479E98CB49B6762),
+ UINT64_C(0x23CDEA0666D116CE), UINT64_C(0x1CC60B4CF7BB7B05),
+ UINT64_C(0x5DDA28934405CD58), UINT64_C(0x62D1C9D9D56FA093),
+ UINT64_C(0xDFE26F2C2378A1E2), UINT64_C(0xE0E98E66B212CC29),
+ UINT64_C(0xA1F5ADB901AC7A74), UINT64_C(0x9EFE4CF390C617BF),
+ UINT64_C(0x9C4505870A3687A9), UINT64_C(0xA34EE4CD9B5CEA62),
+ UINT64_C(0xE252C71228E25C3F), UINT64_C(0xDD592658B98831F4),
+ UINT64_C(0x606A80AD4F9F3085), UINT64_C(0x5F6161E7DEF55D4E),
+ UINT64_C(0x1E7D42386D4BEB13), UINT64_C(0x2176A372FC2186D8),
+ UINT64_C(0xF6C2A0F82E6BF774), UINT64_C(0xC9C941B2BF019ABF),
+ UINT64_C(0x88D5626D0CBF2CE2), UINT64_C(0xB7DE83279DD54129),
+ UINT64_C(0x0AED25D26BC24058), UINT64_C(0x35E6C498FAA82D93),
+ UINT64_C(0x74FAE74749169BCE), UINT64_C(0x4BF1060DD87CF605),
+ UINT64_C(0xE318EB5CF9EF77C4), UINT64_C(0xDC130A1668851A0F),
+ UINT64_C(0x9D0F29C9DB3BAC52), UINT64_C(0xA204C8834A51C199),
+ UINT64_C(0x1F376E76BC46C0E8), UINT64_C(0x203C8F3C2D2CAD23),
+ UINT64_C(0x6120ACE39E921B7E), UINT64_C(0x5E2B4DA90FF876B5),
+ UINT64_C(0x899F4E23DDB20719), UINT64_C(0xB694AF694CD86AD2),
+ UINT64_C(0xF7888CB6FF66DC8F), UINT64_C(0xC8836DFC6E0CB144),
+ UINT64_C(0x75B0CB09981BB035), UINT64_C(0x4ABB2A430971DDFE),
+ UINT64_C(0x0BA7099CBACF6BA3), UINT64_C(0x34ACE8D62BA50668),
+ UINT64_C(0x3617A1A2B155967E), UINT64_C(0x091C40E8203FFBB5),
+ UINT64_C(0x4800633793814DE8), UINT64_C(0x770B827D02EB2023),
+ UINT64_C(0xCA382488F4FC2152), UINT64_C(0xF533C5C265964C99),
+ UINT64_C(0xB42FE61DD628FAC4), UINT64_C(0x8B2407574742970F),
+ UINT64_C(0x5C9004DD9508E6A3), UINT64_C(0x639BE59704628B68),
+ UINT64_C(0x2287C648B7DC3D35), UINT64_C(0x1D8C270226B650FE),
+ UINT64_C(0xA0BF81F7D0A1518F), UINT64_C(0x9FB460BD41CB3C44),
+ UINT64_C(0xDEA84362F2758A19), UINT64_C(0xE1A3A228631FE7D2),
+ UINT64_C(0xDBDED18BC794AA35), UINT64_C(0xE4D530C156FEC7FE),
+ UINT64_C(0xA5C9131EE54071A3), UINT64_C(0x9AC2F254742A1C68),
+ UINT64_C(0x27F154A1823D1D19), UINT64_C(0x18FAB5EB135770D2),
+ UINT64_C(0x59E69634A0E9C68F), UINT64_C(0x66ED777E3183AB44),
+ UINT64_C(0xB15974F4E3C9DAE8), UINT64_C(0x8E5295BE72A3B723),
+ UINT64_C(0xCF4EB661C11D017E), UINT64_C(0xF045572B50776CB5),
+ UINT64_C(0x4D76F1DEA6606DC4), UINT64_C(0x727D1094370A000F),
+ UINT64_C(0x3361334B84B4B652), UINT64_C(0x0C6AD20115DEDB99),
+ UINT64_C(0x0ED19B758F2E4B8F), UINT64_C(0x31DA7A3F1E442644),
+ UINT64_C(0x70C659E0ADFA9019), UINT64_C(0x4FCDB8AA3C90FDD2),
+ UINT64_C(0xF2FE1E5FCA87FCA3), UINT64_C(0xCDF5FF155BED9168),
+ UINT64_C(0x8CE9DCCAE8532735), UINT64_C(0xB3E23D8079394AFE),
+ UINT64_C(0x64563E0AAB733B52), UINT64_C(0x5B5DDF403A195699),
+ UINT64_C(0x1A41FC9F89A7E0C4), UINT64_C(0x254A1DD518CD8D0F),
+ UINT64_C(0x9879BB20EEDA8C7E), UINT64_C(0xA7725A6A7FB0E1B5),
+ UINT64_C(0xE66E79B5CC0E57E8), UINT64_C(0xD96598FF5D643A23),
+ UINT64_C(0x92949EF28518CC26), UINT64_C(0xAD9F7FB81472A1ED),
+ UINT64_C(0xEC835C67A7CC17B0), UINT64_C(0xD388BD2D36A67A7B),
+ UINT64_C(0x6EBB1BD8C0B17B0A), UINT64_C(0x51B0FA9251DB16C1),
+ UINT64_C(0x10ACD94DE265A09C), UINT64_C(0x2FA73807730FCD57),
+ UINT64_C(0xF8133B8DA145BCFB), UINT64_C(0xC718DAC7302FD130),
+ UINT64_C(0x8604F9188391676D), UINT64_C(0xB90F185212FB0AA6),
+ UINT64_C(0x043CBEA7E4EC0BD7), UINT64_C(0x3B375FED7586661C),
+ UINT64_C(0x7A2B7C32C638D041), UINT64_C(0x45209D785752BD8A),
+ UINT64_C(0x479BD40CCDA22D9C), UINT64_C(0x789035465CC84057),
+ UINT64_C(0x398C1699EF76F60A), UINT64_C(0x0687F7D37E1C9BC1),
+ UINT64_C(0xBBB45126880B9AB0), UINT64_C(0x84BFB06C1961F77B),
+ UINT64_C(0xC5A393B3AADF4126), UINT64_C(0xFAA872F93BB52CED),
+ UINT64_C(0x2D1C7173E9FF5D41), UINT64_C(0x121790397895308A),
+ UINT64_C(0x530BB3E6CB2B86D7), UINT64_C(0x6C0052AC5A41EB1C),
+ UINT64_C(0xD133F459AC56EA6D), UINT64_C(0xEE3815133D3C87A6),
+ UINT64_C(0xAF2436CC8E8231FB), UINT64_C(0x902FD7861FE85C30),
+ UINT64_C(0xAA52A425BB6311D7), UINT64_C(0x9559456F2A097C1C),
+ UINT64_C(0xD44566B099B7CA41), UINT64_C(0xEB4E87FA08DDA78A),
+ UINT64_C(0x567D210FFECAA6FB), UINT64_C(0x6976C0456FA0CB30),
+ UINT64_C(0x286AE39ADC1E7D6D), UINT64_C(0x176102D04D7410A6),
+ UINT64_C(0xC0D5015A9F3E610A), UINT64_C(0xFFDEE0100E540CC1),
+ UINT64_C(0xBEC2C3CFBDEABA9C), UINT64_C(0x81C922852C80D757),
+ UINT64_C(0x3CFA8470DA97D626), UINT64_C(0x03F1653A4BFDBBED),
+ UINT64_C(0x42ED46E5F8430DB0), UINT64_C(0x7DE6A7AF6929607B),
+ UINT64_C(0x7F5DEEDBF3D9F06D), UINT64_C(0x40560F9162B39DA6),
+ UINT64_C(0x014A2C4ED10D2BFB), UINT64_C(0x3E41CD0440674630),
+ UINT64_C(0x83726BF1B6704741), UINT64_C(0xBC798ABB271A2A8A),
+ UINT64_C(0xFD65A96494A49CD7), UINT64_C(0xC26E482E05CEF11C),
+ UINT64_C(0x15DA4BA4D78480B0), UINT64_C(0x2AD1AAEE46EEED7B),
+ UINT64_C(0x6BCD8931F5505B26), UINT64_C(0x54C6687B643A36ED),
+ UINT64_C(0xE9F5CE8E922D379C), UINT64_C(0xD6FE2FC403475A57),
+ UINT64_C(0x97E20C1BB0F9EC0A), UINT64_C(0xA8E9ED51219381C1)
+ }, {
+ UINT64_C(0x0000000000000000), UINT64_C(0x1DEE8A5E222CA1DC),
+ UINT64_C(0x3BDD14BC445943B8), UINT64_C(0x26339EE26675E264),
+ UINT64_C(0x77BA297888B28770), UINT64_C(0x6A54A326AA9E26AC),
+ UINT64_C(0x4C673DC4CCEBC4C8), UINT64_C(0x5189B79AEEC76514),
+ UINT64_C(0xEF7452F111650EE0), UINT64_C(0xF29AD8AF3349AF3C),
+ UINT64_C(0xD4A9464D553C4D58), UINT64_C(0xC947CC137710EC84),
+ UINT64_C(0x98CE7B8999D78990), UINT64_C(0x8520F1D7BBFB284C),
+ UINT64_C(0xA3136F35DD8ECA28), UINT64_C(0xBEFDE56BFFA26BF4),
+ UINT64_C(0x4C300AC98DC40345), UINT64_C(0x51DE8097AFE8A299),
+ UINT64_C(0x77ED1E75C99D40FD), UINT64_C(0x6A03942BEBB1E121),
+ UINT64_C(0x3B8A23B105768435), UINT64_C(0x2664A9EF275A25E9),
+ UINT64_C(0x0057370D412FC78D), UINT64_C(0x1DB9BD5363036651),
+ UINT64_C(0xA34458389CA10DA5), UINT64_C(0xBEAAD266BE8DAC79),
+ UINT64_C(0x98994C84D8F84E1D), UINT64_C(0x8577C6DAFAD4EFC1),
+ UINT64_C(0xD4FE714014138AD5), UINT64_C(0xC910FB1E363F2B09),
+ UINT64_C(0xEF2365FC504AC96D), UINT64_C(0xF2CDEFA2726668B1),
+ UINT64_C(0x986015931B88068A), UINT64_C(0x858E9FCD39A4A756),
+ UINT64_C(0xA3BD012F5FD14532), UINT64_C(0xBE538B717DFDE4EE),
+ UINT64_C(0xEFDA3CEB933A81FA), UINT64_C(0xF234B6B5B1162026),
+ UINT64_C(0xD4072857D763C242), UINT64_C(0xC9E9A209F54F639E),
+ UINT64_C(0x771447620AED086A), UINT64_C(0x6AFACD3C28C1A9B6),
+ UINT64_C(0x4CC953DE4EB44BD2), UINT64_C(0x5127D9806C98EA0E),
+ UINT64_C(0x00AE6E1A825F8F1A), UINT64_C(0x1D40E444A0732EC6),
+ UINT64_C(0x3B737AA6C606CCA2), UINT64_C(0x269DF0F8E42A6D7E),
+ UINT64_C(0xD4501F5A964C05CF), UINT64_C(0xC9BE9504B460A413),
+ UINT64_C(0xEF8D0BE6D2154677), UINT64_C(0xF26381B8F039E7AB),
+ UINT64_C(0xA3EA36221EFE82BF), UINT64_C(0xBE04BC7C3CD22363),
+ UINT64_C(0x9837229E5AA7C107), UINT64_C(0x85D9A8C0788B60DB),
+ UINT64_C(0x3B244DAB87290B2F), UINT64_C(0x26CAC7F5A505AAF3),
+ UINT64_C(0x00F95917C3704897), UINT64_C(0x1D17D349E15CE94B),
+ UINT64_C(0x4C9E64D30F9B8C5F), UINT64_C(0x5170EE8D2DB72D83),
+ UINT64_C(0x7743706F4BC2CFE7), UINT64_C(0x6AADFA3169EE6E3B),
+ UINT64_C(0xA218840D981E1391), UINT64_C(0xBFF60E53BA32B24D),
+ UINT64_C(0x99C590B1DC475029), UINT64_C(0x842B1AEFFE6BF1F5),
+ UINT64_C(0xD5A2AD7510AC94E1), UINT64_C(0xC84C272B3280353D),
+ UINT64_C(0xEE7FB9C954F5D759), UINT64_C(0xF391339776D97685),
+ UINT64_C(0x4D6CD6FC897B1D71), UINT64_C(0x50825CA2AB57BCAD),
+ UINT64_C(0x76B1C240CD225EC9), UINT64_C(0x6B5F481EEF0EFF15),
+ UINT64_C(0x3AD6FF8401C99A01), UINT64_C(0x273875DA23E53BDD),
+ UINT64_C(0x010BEB384590D9B9), UINT64_C(0x1CE5616667BC7865),
+ UINT64_C(0xEE288EC415DA10D4), UINT64_C(0xF3C6049A37F6B108),
+ UINT64_C(0xD5F59A785183536C), UINT64_C(0xC81B102673AFF2B0),
+ UINT64_C(0x9992A7BC9D6897A4), UINT64_C(0x847C2DE2BF443678),
+ UINT64_C(0xA24FB300D931D41C), UINT64_C(0xBFA1395EFB1D75C0),
+ UINT64_C(0x015CDC3504BF1E34), UINT64_C(0x1CB2566B2693BFE8),
+ UINT64_C(0x3A81C88940E65D8C), UINT64_C(0x276F42D762CAFC50),
+ UINT64_C(0x76E6F54D8C0D9944), UINT64_C(0x6B087F13AE213898),
+ UINT64_C(0x4D3BE1F1C854DAFC), UINT64_C(0x50D56BAFEA787B20),
+ UINT64_C(0x3A78919E8396151B), UINT64_C(0x27961BC0A1BAB4C7),
+ UINT64_C(0x01A58522C7CF56A3), UINT64_C(0x1C4B0F7CE5E3F77F),
+ UINT64_C(0x4DC2B8E60B24926B), UINT64_C(0x502C32B8290833B7),
+ UINT64_C(0x761FAC5A4F7DD1D3), UINT64_C(0x6BF126046D51700F),
+ UINT64_C(0xD50CC36F92F31BFB), UINT64_C(0xC8E24931B0DFBA27),
+ UINT64_C(0xEED1D7D3D6AA5843), UINT64_C(0xF33F5D8DF486F99F),
+ UINT64_C(0xA2B6EA171A419C8B), UINT64_C(0xBF586049386D3D57),
+ UINT64_C(0x996BFEAB5E18DF33), UINT64_C(0x848574F57C347EEF),
+ UINT64_C(0x76489B570E52165E), UINT64_C(0x6BA611092C7EB782),
+ UINT64_C(0x4D958FEB4A0B55E6), UINT64_C(0x507B05B56827F43A),
+ UINT64_C(0x01F2B22F86E0912E), UINT64_C(0x1C1C3871A4CC30F2),
+ UINT64_C(0x3A2FA693C2B9D296), UINT64_C(0x27C12CCDE095734A),
+ UINT64_C(0x993CC9A61F3718BE), UINT64_C(0x84D243F83D1BB962),
+ UINT64_C(0xA2E1DD1A5B6E5B06), UINT64_C(0xBF0F57447942FADA),
+ UINT64_C(0xEE86E0DE97859FCE), UINT64_C(0xF3686A80B5A93E12),
+ UINT64_C(0xD55BF462D3DCDC76), UINT64_C(0xC8B57E3CF1F07DAA),
+ UINT64_C(0xD6E9A7309F3239A7), UINT64_C(0xCB072D6EBD1E987B),
+ UINT64_C(0xED34B38CDB6B7A1F), UINT64_C(0xF0DA39D2F947DBC3),
+ UINT64_C(0xA1538E481780BED7), UINT64_C(0xBCBD041635AC1F0B),
+ UINT64_C(0x9A8E9AF453D9FD6F), UINT64_C(0x876010AA71F55CB3),
+ UINT64_C(0x399DF5C18E573747), UINT64_C(0x24737F9FAC7B969B),
+ UINT64_C(0x0240E17DCA0E74FF), UINT64_C(0x1FAE6B23E822D523),
+ UINT64_C(0x4E27DCB906E5B037), UINT64_C(0x53C956E724C911EB),
+ UINT64_C(0x75FAC80542BCF38F), UINT64_C(0x6814425B60905253),
+ UINT64_C(0x9AD9ADF912F63AE2), UINT64_C(0x873727A730DA9B3E),
+ UINT64_C(0xA104B94556AF795A), UINT64_C(0xBCEA331B7483D886),
+ UINT64_C(0xED6384819A44BD92), UINT64_C(0xF08D0EDFB8681C4E),
+ UINT64_C(0xD6BE903DDE1DFE2A), UINT64_C(0xCB501A63FC315FF6),
+ UINT64_C(0x75ADFF0803933402), UINT64_C(0x6843755621BF95DE),
+ UINT64_C(0x4E70EBB447CA77BA), UINT64_C(0x539E61EA65E6D666),
+ UINT64_C(0x0217D6708B21B372), UINT64_C(0x1FF95C2EA90D12AE),
+ UINT64_C(0x39CAC2CCCF78F0CA), UINT64_C(0x24244892ED545116),
+ UINT64_C(0x4E89B2A384BA3F2D), UINT64_C(0x536738FDA6969EF1),
+ UINT64_C(0x7554A61FC0E37C95), UINT64_C(0x68BA2C41E2CFDD49),
+ UINT64_C(0x39339BDB0C08B85D), UINT64_C(0x24DD11852E241981),
+ UINT64_C(0x02EE8F674851FBE5), UINT64_C(0x1F0005396A7D5A39),
+ UINT64_C(0xA1FDE05295DF31CD), UINT64_C(0xBC136A0CB7F39011),
+ UINT64_C(0x9A20F4EED1867275), UINT64_C(0x87CE7EB0F3AAD3A9),
+ UINT64_C(0xD647C92A1D6DB6BD), UINT64_C(0xCBA943743F411761),
+ UINT64_C(0xED9ADD965934F505), UINT64_C(0xF07457C87B1854D9),
+ UINT64_C(0x02B9B86A097E3C68), UINT64_C(0x1F5732342B529DB4),
+ UINT64_C(0x3964ACD64D277FD0), UINT64_C(0x248A26886F0BDE0C),
+ UINT64_C(0x7503911281CCBB18), UINT64_C(0x68ED1B4CA3E01AC4),
+ UINT64_C(0x4EDE85AEC595F8A0), UINT64_C(0x53300FF0E7B9597C),
+ UINT64_C(0xEDCDEA9B181B3288), UINT64_C(0xF02360C53A379354),
+ UINT64_C(0xD610FE275C427130), UINT64_C(0xCBFE74797E6ED0EC),
+ UINT64_C(0x9A77C3E390A9B5F8), UINT64_C(0x879949BDB2851424),
+ UINT64_C(0xA1AAD75FD4F0F640), UINT64_C(0xBC445D01F6DC579C),
+ UINT64_C(0x74F1233D072C2A36), UINT64_C(0x691FA96325008BEA),
+ UINT64_C(0x4F2C37814375698E), UINT64_C(0x52C2BDDF6159C852),
+ UINT64_C(0x034B0A458F9EAD46), UINT64_C(0x1EA5801BADB20C9A),
+ UINT64_C(0x38961EF9CBC7EEFE), UINT64_C(0x257894A7E9EB4F22),
+ UINT64_C(0x9B8571CC164924D6), UINT64_C(0x866BFB923465850A),
+ UINT64_C(0xA05865705210676E), UINT64_C(0xBDB6EF2E703CC6B2),
+ UINT64_C(0xEC3F58B49EFBA3A6), UINT64_C(0xF1D1D2EABCD7027A),
+ UINT64_C(0xD7E24C08DAA2E01E), UINT64_C(0xCA0CC656F88E41C2),
+ UINT64_C(0x38C129F48AE82973), UINT64_C(0x252FA3AAA8C488AF),
+ UINT64_C(0x031C3D48CEB16ACB), UINT64_C(0x1EF2B716EC9DCB17),
+ UINT64_C(0x4F7B008C025AAE03), UINT64_C(0x52958AD220760FDF),
+ UINT64_C(0x74A614304603EDBB), UINT64_C(0x69489E6E642F4C67),
+ UINT64_C(0xD7B57B059B8D2793), UINT64_C(0xCA5BF15BB9A1864F),
+ UINT64_C(0xEC686FB9DFD4642B), UINT64_C(0xF186E5E7FDF8C5F7),
+ UINT64_C(0xA00F527D133FA0E3), UINT64_C(0xBDE1D8233113013F),
+ UINT64_C(0x9BD246C15766E35B), UINT64_C(0x863CCC9F754A4287),
+ UINT64_C(0xEC9136AE1CA42CBC), UINT64_C(0xF17FBCF03E888D60),
+ UINT64_C(0xD74C221258FD6F04), UINT64_C(0xCAA2A84C7AD1CED8),
+ UINT64_C(0x9B2B1FD69416ABCC), UINT64_C(0x86C59588B63A0A10),
+ UINT64_C(0xA0F60B6AD04FE874), UINT64_C(0xBD188134F26349A8),
+ UINT64_C(0x03E5645F0DC1225C), UINT64_C(0x1E0BEE012FED8380),
+ UINT64_C(0x383870E3499861E4), UINT64_C(0x25D6FABD6BB4C038),
+ UINT64_C(0x745F4D278573A52C), UINT64_C(0x69B1C779A75F04F0),
+ UINT64_C(0x4F82599BC12AE694), UINT64_C(0x526CD3C5E3064748),
+ UINT64_C(0xA0A13C6791602FF9), UINT64_C(0xBD4FB639B34C8E25),
+ UINT64_C(0x9B7C28DBD5396C41), UINT64_C(0x8692A285F715CD9D),
+ UINT64_C(0xD71B151F19D2A889), UINT64_C(0xCAF59F413BFE0955),
+ UINT64_C(0xECC601A35D8BEB31), UINT64_C(0xF1288BFD7FA74AED),
+ UINT64_C(0x4FD56E9680052119), UINT64_C(0x523BE4C8A22980C5),
+ UINT64_C(0x74087A2AC45C62A1), UINT64_C(0x69E6F074E670C37D),
+ UINT64_C(0x386F47EE08B7A669), UINT64_C(0x2581CDB02A9B07B5),
+ UINT64_C(0x03B253524CEEE5D1), UINT64_C(0x1E5CD90C6EC2440D)
+ }
+};
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_tablegen.c b/Utilities/cmliblzma/liblzma/check/crc64_tablegen.c
new file mode 100644
index 000000000..fddaa7ed1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_tablegen.c
@@ -0,0 +1,88 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc64_tablegen.c
+/// \brief Generate crc64_table_le.h and crc64_table_be.h
+///
+/// Compiling: gcc -std=c99 -o crc64_tablegen crc64_tablegen.c
+/// Add -DWORDS_BIGENDIAN to generate big endian table.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <stdio.h>
+#include "../../common/tuklib_integer.h"
+
+
+static uint64_t crc64_table[4][256];
+
+
+extern void
+init_crc64_table(void)
+{
+ static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+ for (size_t s = 0; s < 4; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ uint64_t r = s == 0 ? b : crc64_table[s - 1][b];
+
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly64;
+ else
+ r >>= 1;
+ }
+
+ crc64_table[s][b] = r;
+ }
+ }
+
+#ifdef WORDS_BIGENDIAN
+ for (size_t s = 0; s < 4; ++s)
+ for (size_t b = 0; b < 256; ++b)
+ crc64_table[s][b] = bswap64(crc64_table[s][b]);
+#endif
+
+ return;
+}
+
+
+static void
+print_crc64_table(void)
+{
+ printf("/* This file has been automatically generated by "
+ "crc64_tablegen.c. */\n\n"
+ "const uint64_t lzma_crc64_table[4][256] = {\n\t{");
+
+ for (size_t s = 0; s < 4; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ if ((b % 2) == 0)
+ printf("\n\t\t");
+
+ printf("UINT64_C(0x%016" PRIX64 ")",
+ crc64_table[s][b]);
+
+ if (b != 255)
+ printf(",%s", (b+1) % 2 == 0 ? "" : " ");
+ }
+
+ if (s == 3)
+ printf("\n\t}\n};\n");
+ else
+ printf("\n\t}, {");
+ }
+
+ return;
+}
+
+
+int
+main(void)
+{
+ init_crc64_table();
+ print_crc64_table();
+ return 0;
+}
diff --git a/Utilities/cmliblzma/liblzma/check/crc64_x86.S b/Utilities/cmliblzma/liblzma/check/crc64_x86.S
new file mode 100644
index 000000000..f5bb84b97
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc64_x86.S
@@ -0,0 +1,287 @@
+/*
+ * Speed-optimized CRC64 using slicing-by-four algorithm
+ *
+ * This uses only i386 instructions, but it is optimized for i686 and later
+ * (including e.g. Pentium II/III/IV, Athlon XP, and Core 2).
+ *
+ * Authors: Igor Pavlov (original CRC32 assembly code)
+ * Lasse Collin (CRC64 adaptation of the modified CRC32 code)
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ *
+ * This code needs lzma_crc64_table, which can be created using the
+ * following C code:
+
+uint64_t lzma_crc64_table[4][256];
+
+void
+init_table(void)
+{
+ // ECMA-182
+ static const uint64_t poly64 = UINT64_C(0xC96C5795D7870F42);
+
+ for (size_t s = 0; s < 4; ++s) {
+ for (size_t b = 0; b < 256; ++b) {
+ uint64_t r = s == 0 ? b : lzma_crc64_table[s - 1][b];
+
+ for (size_t i = 0; i < 8; ++i) {
+ if (r & 1)
+ r = (r >> 1) ^ poly64;
+ else
+ r >>= 1;
+ }
+
+ lzma_crc64_table[s][b] = r;
+ }
+ }
+}
+
+ * The prototype of the CRC64 function:
+ * extern uint64_t lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc);
+ */
+
+/*
+ * On some systems, the functions need to be prefixed. The prefix is
+ * usually an underscore.
+ */
+#ifndef __USER_LABEL_PREFIX__
+# define __USER_LABEL_PREFIX__
+#endif
+#define MAKE_SYM_CAT(prefix, sym) prefix ## sym
+#define MAKE_SYM(prefix, sym) MAKE_SYM_CAT(prefix, sym)
+#define LZMA_CRC64 MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64)
+#define LZMA_CRC64_TABLE MAKE_SYM(__USER_LABEL_PREFIX__, lzma_crc64_table)
+
+/*
+ * Solaris assembler doesn't have .p2align, and Darwin uses .align
+ * differently than GNU/Linux and Solaris.
+ */
+#if defined(__APPLE__) || defined(__MSDOS__)
+# define ALIGN(pow2, abs) .align pow2
+#else
+# define ALIGN(pow2, abs) .align abs
+#endif
+
+ .text
+ .globl LZMA_CRC64
+
+#if !defined(__APPLE__) && !defined(_WIN32) && !defined(__CYGWIN__) \
+ && !defined(__MSDOS__)
+ .type LZMA_CRC64, @function
+#endif
+
+ ALIGN(4, 16)
+LZMA_CRC64:
+ /*
+ * Register usage:
+ * %eax crc LSB
+ * %edx crc MSB
+ * %esi buf
+ * %edi size or buf + size
+ * %ebx lzma_crc64_table
+ * %ebp Table index
+ * %ecx Temporary
+ */
+ pushl %ebx
+ pushl %esi
+ pushl %edi
+ pushl %ebp
+ movl 0x14(%esp), %esi /* buf */
+ movl 0x18(%esp), %edi /* size */
+ movl 0x1C(%esp), %eax /* crc LSB */
+ movl 0x20(%esp), %edx /* crc MSB */
+
+ /*
+ * Store the address of lzma_crc64_table to %ebx. This is needed to
+ * get position-independent code (PIC).
+ *
+ * The PIC macro is defined by libtool, while __PIC__ is defined
+ * by GCC but only on some systems. Testing for both makes it simpler
+ * to test this code without libtool, and keeps the code working also
+ * when built with libtool but using something else than GCC.
+ *
+ * I understood that libtool may define PIC on Windows even though
+ * the code in Windows DLLs is not PIC in sense that it is in ELF
+ * binaries, so we need a separate check to always use the non-PIC
+ * code on Windows.
+ */
+#if (!defined(PIC) && !defined(__PIC__)) \
+ || (defined(_WIN32) || defined(__CYGWIN__))
+ /* Not PIC */
+ movl $ LZMA_CRC64_TABLE, %ebx
+#elif defined(__APPLE__)
+ /* Mach-O */
+ call .L_get_pc
+.L_pic:
+ leal .L_lzma_crc64_table$non_lazy_ptr-.L_pic(%ebx), %ebx
+ movl (%ebx), %ebx
+#else
+ /* ELF */
+ call .L_get_pc
+ addl $_GLOBAL_OFFSET_TABLE_, %ebx
+ movl LZMA_CRC64_TABLE@GOT(%ebx), %ebx
+#endif
+
+ /* Complement the initial value. */
+ notl %eax
+ notl %edx
+
+.L_align:
+ /*
+ * Check if there is enough input to use slicing-by-four.
+ * We need eight bytes, because the loop pre-reads four bytes.
+ */
+ cmpl $8, %edi
+ jb .L_rest
+
+ /* Check if we have reached alignment of four bytes. */
+ testl $3, %esi
+ jz .L_slice
+
+ /* Calculate CRC of the next input byte. */
+ movzbl (%esi), %ebp
+ incl %esi
+ movzbl %al, %ecx
+ xorl %ecx, %ebp
+ shrdl $8, %edx, %eax
+ xorl (%ebx, %ebp, 8), %eax
+ shrl $8, %edx
+ xorl 4(%ebx, %ebp, 8), %edx
+ decl %edi
+ jmp .L_align
+
+.L_slice:
+ /*
+ * If we get here, there's at least eight bytes of aligned input
+ * available. Make %edi multiple of four bytes. Store the possible
+ * remainder over the "size" variable in the argument stack.
+ */
+ movl %edi, 0x18(%esp)
+ andl $-4, %edi
+ subl %edi, 0x18(%esp)
+
+ /*
+ * Let %edi be buf + size - 4 while running the main loop. This way
+ * we can compare for equality to determine when exit the loop.
+ */
+ addl %esi, %edi
+ subl $4, %edi
+
+ /* Read in the first four aligned bytes. */
+ movl (%esi), %ecx
+
+.L_loop:
+ xorl %eax, %ecx
+ movzbl %cl, %ebp
+ movl 0x1800(%ebx, %ebp, 8), %eax
+ xorl %edx, %eax
+ movl 0x1804(%ebx, %ebp, 8), %edx
+ movzbl %ch, %ebp
+ xorl 0x1000(%ebx, %ebp, 8), %eax
+ xorl 0x1004(%ebx, %ebp, 8), %edx
+ shrl $16, %ecx
+ movzbl %cl, %ebp
+ xorl 0x0800(%ebx, %ebp, 8), %eax
+ xorl 0x0804(%ebx, %ebp, 8), %edx
+ movzbl %ch, %ebp
+ addl $4, %esi
+ xorl (%ebx, %ebp, 8), %eax
+ xorl 4(%ebx, %ebp, 8), %edx
+
+ /* Check for end of aligned input. */
+ cmpl %edi, %esi
+
+ /*
+ * Copy the next input byte to %ecx. It is slightly faster to
+ * read it here than at the top of the loop.
+ */
+ movl (%esi), %ecx
+ jb .L_loop
+
+ /*
+ * Process the remaining four bytes, which we have already
+ * copied to %ecx.
+ */
+ xorl %eax, %ecx
+ movzbl %cl, %ebp
+ movl 0x1800(%ebx, %ebp, 8), %eax
+ xorl %edx, %eax
+ movl 0x1804(%ebx, %ebp, 8), %edx
+ movzbl %ch, %ebp
+ xorl 0x1000(%ebx, %ebp, 8), %eax
+ xorl 0x1004(%ebx, %ebp, 8), %edx
+ shrl $16, %ecx
+ movzbl %cl, %ebp
+ xorl 0x0800(%ebx, %ebp, 8), %eax
+ xorl 0x0804(%ebx, %ebp, 8), %edx
+ movzbl %ch, %ebp
+ addl $4, %esi
+ xorl (%ebx, %ebp, 8), %eax
+ xorl 4(%ebx, %ebp, 8), %edx
+
+ /* Copy the number of remaining bytes to %edi. */
+ movl 0x18(%esp), %edi
+
+.L_rest:
+ /* Check for end of input. */
+ testl %edi, %edi
+ jz .L_return
+
+ /* Calculate CRC of the next input byte. */
+ movzbl (%esi), %ebp
+ incl %esi
+ movzbl %al, %ecx
+ xorl %ecx, %ebp
+ shrdl $8, %edx, %eax
+ xorl (%ebx, %ebp, 8), %eax
+ shrl $8, %edx
+ xorl 4(%ebx, %ebp, 8), %edx
+ decl %edi
+ jmp .L_rest
+
+.L_return:
+ /* Complement the final value. */
+ notl %eax
+ notl %edx
+
+ popl %ebp
+ popl %edi
+ popl %esi
+ popl %ebx
+ ret
+
+#if defined(PIC) || defined(__PIC__)
+ ALIGN(4, 16)
+.L_get_pc:
+ movl (%esp), %ebx
+ ret
+#endif
+
+#if defined(__APPLE__) && (defined(PIC) || defined(__PIC__))
+ /* Mach-O PIC */
+ .section __IMPORT,__pointers,non_lazy_symbol_pointers
+.L_lzma_crc64_table$non_lazy_ptr:
+ .indirect_symbol LZMA_CRC64_TABLE
+ .long 0
+
+#elif defined(_WIN32) || defined(__CYGWIN__)
+# ifdef DLL_EXPORT
+ /* This is equivalent of __declspec(dllexport). */
+ .section .drectve
+ .ascii " -export:lzma_crc64"
+# endif
+
+#elif !defined(__MSDOS__)
+ /* ELF */
+ .size LZMA_CRC64, .-LZMA_CRC64
+#endif
+
+/*
+ * This is needed to support non-executable stack. It's ugly to
+ * use __linux__ here, but I don't know a way to detect when
+ * we are using GNU assembler.
+ */
+#if defined(__ELF__) && defined(__linux__)
+ .section .note.GNU-stack,"",@progbits
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/crc_macros.h b/Utilities/cmliblzma/liblzma/check/crc_macros.h
new file mode 100644
index 000000000..a7c21b765
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/crc_macros.h
@@ -0,0 +1,30 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file crc_macros.h
+/// \brief Some endian-dependent macros for CRC32 and CRC64
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifdef WORDS_BIGENDIAN
+# define A(x) ((x) >> 24)
+# define B(x) (((x) >> 16) & 0xFF)
+# define C(x) (((x) >> 8) & 0xFF)
+# define D(x) ((x) & 0xFF)
+
+# define S8(x) ((x) << 8)
+# define S32(x) ((x) << 32)
+
+#else
+# define A(x) ((x) & 0xFF)
+# define B(x) (((x) >> 8) & 0xFF)
+# define C(x) (((x) >> 16) & 0xFF)
+# define D(x) ((x) >> 24)
+
+# define S8(x) ((x) >> 8)
+# define S32(x) ((x) >> 32)
+#endif
diff --git a/Utilities/cmliblzma/liblzma/check/sha256.c b/Utilities/cmliblzma/liblzma/check/sha256.c
new file mode 100644
index 000000000..3af6aa67d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/check/sha256.c
@@ -0,0 +1,204 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file sha256.c
+/// \brief SHA-256
+///
+/// \todo Crypto++ has x86 ASM optimizations. They use SSE so if they
+/// are imported to liblzma, SSE instructions need to be used
+/// conditionally to keep the code working on older boxes.
+//
+// This code is based on the code found from 7-Zip, which has a modified
+// version of the SHA-256 found from Crypto++ <http://www.cryptopp.com/>.
+// The code was modified a little to fit into liblzma.
+//
+// Authors: Kevin Springle
+// Wei Dai
+// Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// Avoid bogus warnings in transform().
+#if (__GNUC__ == 4 && __GNUC_MINOR__ >= 2) || __GNUC__ > 4
+# pragma GCC diagnostic ignored "-Wuninitialized"
+#endif
+
+#include "check.h"
+
+// At least on x86, GCC is able to optimize this to a rotate instruction.
+#define rotr_32(num, amount) ((num) >> (amount) | (num) << (32 - (amount)))
+
+#define blk0(i) (W[i] = data[i])
+#define blk2(i) (W[i & 15] += s1(W[(i - 2) & 15]) + W[(i - 7) & 15] \
+ + s0(W[(i - 15) & 15]))
+
+#define Ch(x, y, z) (z ^ (x & (y ^ z)))
+#define Maj(x, y, z) ((x & y) | (z & (x | y)))
+
+#define a(i) T[(0 - i) & 7]
+#define b(i) T[(1 - i) & 7]
+#define c(i) T[(2 - i) & 7]
+#define d(i) T[(3 - i) & 7]
+#define e(i) T[(4 - i) & 7]
+#define f(i) T[(5 - i) & 7]
+#define g(i) T[(6 - i) & 7]
+#define h(i) T[(7 - i) & 7]
+
+#define R(i) \
+ h(i) += S1(e(i)) + Ch(e(i), f(i), g(i)) + SHA256_K[i + j] \
+ + (j ? blk2(i) : blk0(i)); \
+ d(i) += h(i); \
+ h(i) += S0(a(i)) + Maj(a(i), b(i), c(i))
+
+#define S0(x) (rotr_32(x, 2) ^ rotr_32(x, 13) ^ rotr_32(x, 22))
+#define S1(x) (rotr_32(x, 6) ^ rotr_32(x, 11) ^ rotr_32(x, 25))
+#define s0(x) (rotr_32(x, 7) ^ rotr_32(x, 18) ^ (x >> 3))
+#define s1(x) (rotr_32(x, 17) ^ rotr_32(x, 19) ^ (x >> 10))
+
+
+static const uint32_t SHA256_K[64] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2,
+};
+
+
+static void
+transform(uint32_t state[8], const uint32_t data[16])
+{
+ uint32_t W[16];
+ uint32_t T[8];
+ unsigned int j;
+
+ // Copy state[] to working vars.
+ memcpy(T, state, sizeof(T));
+
+ // 64 operations, partially loop unrolled
+ for (j = 0; j < 64; j += 16) {
+ R( 0); R( 1); R( 2); R( 3);
+ R( 4); R( 5); R( 6); R( 7);
+ R( 8); R( 9); R(10); R(11);
+ R(12); R(13); R(14); R(15);
+ }
+
+ // Add the working vars back into state[].
+ state[0] += a(0);
+ state[1] += b(0);
+ state[2] += c(0);
+ state[3] += d(0);
+ state[4] += e(0);
+ state[5] += f(0);
+ state[6] += g(0);
+ state[7] += h(0);
+}
+
+
+static void
+process(lzma_check_state *check)
+{
+#ifdef WORDS_BIGENDIAN
+ transform(check->state.sha256.state, check->buffer.u32);
+
+#else
+ uint32_t data[16];
+ size_t i;
+
+ for (i = 0; i < 16; ++i)
+ data[i] = bswap32(check->buffer.u32[i]);
+
+ transform(check->state.sha256.state, data);
+#endif
+
+ return;
+}
+
+
+extern void
+lzma_sha256_init(lzma_check_state *check)
+{
+ static const uint32_t s[8] = {
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
+ };
+
+ memcpy(check->state.sha256.state, s, sizeof(s));
+ check->state.sha256.size = 0;
+
+ return;
+}
+
+
+extern void
+lzma_sha256_update(const uint8_t *buf, size_t size, lzma_check_state *check)
+{
+ // Copy the input data into a properly aligned temporary buffer.
+ // This way we can be called with arbitrarily sized buffers
+ // (no need to be multiple of 64 bytes), and the code works also
+ // on architectures that don't allow unaligned memory access.
+ while (size > 0) {
+ const size_t copy_start = check->state.sha256.size & 0x3F;
+ size_t copy_size = 64 - copy_start;
+ if (copy_size > size)
+ copy_size = size;
+
+ memcpy(check->buffer.u8 + copy_start, buf, copy_size);
+
+ buf += copy_size;
+ size -= copy_size;
+ check->state.sha256.size += copy_size;
+
+ if ((check->state.sha256.size & 0x3F) == 0)
+ process(check);
+ }
+
+ return;
+}
+
+
+extern void
+lzma_sha256_finish(lzma_check_state *check)
+{
+ size_t i;
+
+ // Add padding as described in RFC 3174 (it describes SHA-1 but
+ // the same padding style is used for SHA-256 too).
+ size_t pos = check->state.sha256.size & 0x3F;
+ check->buffer.u8[pos++] = 0x80;
+
+ while (pos != 64 - 8) {
+ if (pos == 64) {
+ process(check);
+ pos = 0;
+ }
+
+ check->buffer.u8[pos++] = 0x00;
+ }
+
+ // Convert the message size from bytes to bits.
+ check->state.sha256.size *= 8;
+
+ check->buffer.u64[(64 - 8) / 8] = conv64be(check->state.sha256.size);
+
+ process(check);
+
+ for (i = 0; i < 8; ++i)
+ check->buffer.u32[i] = conv32be(check->state.sha256.state[i]);
+
+ return;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/alone_decoder.c b/Utilities/cmliblzma/liblzma/common/alone_decoder.c
new file mode 100644
index 000000000..5f5e564ab
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/alone_decoder.c
@@ -0,0 +1,236 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.c
+/// \brief Decoder for LZMA_Alone files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "alone_decoder.h"
+#include "lzma_decoder.h"
+#include "lz_decoder.h"
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+
+ enum {
+ SEQ_PROPERTIES,
+ SEQ_DICTIONARY_SIZE,
+ SEQ_UNCOMPRESSED_SIZE,
+ SEQ_CODER_INIT,
+ SEQ_CODE,
+ } sequence;
+
+ /// If true, reject files that are unlikely to be .lzma files.
+ /// If false, more non-.lzma files get accepted and will give
+ /// LZMA_DATA_ERROR either immediately or after a few output bytes.
+ bool picky;
+
+ /// Position in the header fields
+ size_t pos;
+
+ /// Uncompressed size decoded from the header
+ lzma_vli uncompressed_size;
+
+ /// Memory usage limit
+ uint64_t memlimit;
+
+ /// Amount of memory actually needed (only an estimate)
+ uint64_t memusage;
+
+ /// Options decoded from the header needed to initialize
+ /// the LZMA decoder
+ lzma_options_lzma options;
+};
+
+
+static lzma_ret
+alone_decode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((__unused__)),
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size,
+ lzma_action action)
+{
+ while (*out_pos < out_size
+ && (coder->sequence == SEQ_CODE || *in_pos < in_size))
+ switch (coder->sequence) {
+ case SEQ_PROPERTIES:
+ if (lzma_lzma_lclppb_decode(&coder->options, in[*in_pos]))
+ return LZMA_FORMAT_ERROR;
+
+ coder->sequence = SEQ_DICTIONARY_SIZE;
+ ++*in_pos;
+ break;
+
+ case SEQ_DICTIONARY_SIZE:
+ coder->options.dict_size
+ |= (size_t)(in[*in_pos]) << (coder->pos * 8);
+
+ if (++coder->pos == 4) {
+ if (coder->picky && coder->options.dict_size
+ != UINT32_MAX) {
+ // A hack to ditch tons of false positives:
+ // We allow only dictionary sizes that are
+ // 2^n or 2^n + 2^(n-1). LZMA_Alone created
+ // only files with 2^n, but accepts any
+ // dictionary size.
+ uint32_t d = coder->options.dict_size - 1;
+ d |= d >> 2;
+ d |= d >> 3;
+ d |= d >> 4;
+ d |= d >> 8;
+ d |= d >> 16;
+ ++d;
+
+ if (d != coder->options.dict_size)
+ return LZMA_FORMAT_ERROR;
+ }
+
+ coder->pos = 0;
+ coder->sequence = SEQ_UNCOMPRESSED_SIZE;
+ }
+
+ ++*in_pos;
+ break;
+
+ case SEQ_UNCOMPRESSED_SIZE:
+ coder->uncompressed_size
+ |= (lzma_vli)(in[*in_pos]) << (coder->pos * 8);
+ ++*in_pos;
+ if (++coder->pos < 8)
+ break;
+
+ // Another hack to ditch false positives: Assume that
+ // if the uncompressed size is known, it must be less
+ // than 256 GiB.
+ if (coder->picky
+ && coder->uncompressed_size != LZMA_VLI_UNKNOWN
+ && coder->uncompressed_size
+ >= (LZMA_VLI_C(1) << 38))
+ return LZMA_FORMAT_ERROR;
+
+ // Calculate the memory usage so that it is ready
+ // for SEQ_CODER_INIT.
+ coder->memusage = lzma_lzma_decoder_memusage(&coder->options)
+ + LZMA_MEMUSAGE_BASE;
+
+ coder->pos = 0;
+ coder->sequence = SEQ_CODER_INIT;
+
+ // Fall through
+
+ case SEQ_CODER_INIT: {
+ lzma_ret ret;
+
+ lzma_filter_info filters[2] = {
+ { 0, &lzma_lzma_decoder_init, &coder->options },
+ { 0, NULL, NULL }
+ };
+
+ if (coder->memusage > coder->memlimit)
+ return LZMA_MEMLIMIT_ERROR;
+
+ ret = lzma_next_filter_init(&coder->next,
+ allocator, filters);
+ if (ret != LZMA_OK)
+ return ret;
+
+ // Use a hack to set the uncompressed size.
+ lzma_lz_decoder_uncompressed(coder->next.coder,
+ coder->uncompressed_size);
+
+ coder->sequence = SEQ_CODE;
+ break;
+ }
+
+ case SEQ_CODE: {
+ return coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ }
+
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+alone_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+alone_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
+ uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+ *memusage = coder->memusage;
+ *old_memlimit = coder->memlimit;
+
+ if (new_memlimit != 0) {
+ if (new_memlimit < coder->memusage)
+ return LZMA_MEMLIMIT_ERROR;
+
+ coder->memlimit = new_memlimit;
+ }
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_alone_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ uint64_t memlimit, bool picky)
+{
+ lzma_next_coder_init(&lzma_alone_decoder_init, next, allocator);
+
+ if (memlimit == 0)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &alone_decode;
+ next->end = &alone_decoder_end;
+ next->memconfig = &alone_decoder_memconfig;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ next->coder->sequence = SEQ_PROPERTIES;
+ next->coder->picky = picky;
+ next->coder->pos = 0;
+ next->coder->options.dict_size = 0;
+ next->coder->options.preset_dict = NULL;
+ next->coder->options.preset_dict_size = 0;
+ next->coder->uncompressed_size = 0;
+ next->coder->memlimit = memlimit;
+ next->coder->memusage = LZMA_MEMUSAGE_BASE;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_alone_decoder(lzma_stream *strm, uint64_t memlimit)
+{
+ lzma_next_strm_init2(lzma_alone_decoder_init, strm, memlimit, false);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/alone_decoder.h b/Utilities/cmliblzma/liblzma/common/alone_decoder.h
new file mode 100644
index 000000000..f666fc382
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/alone_decoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.h
+/// \brief Decoder for LZMA_Alone files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_ALONE_DECODER_H
+#define LZMA_ALONE_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_alone_decoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ uint64_t memlimit, bool picky);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/alone_encoder.c b/Utilities/cmliblzma/liblzma/common/alone_encoder.c
new file mode 100644
index 000000000..4207b4a52
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/alone_encoder.c
@@ -0,0 +1,155 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file alone_decoder.c
+/// \brief Decoder for LZMA_Alone files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "lzma_encoder.h"
+
+
+#define ALONE_HEADER_SIZE (1 + 4 + 8)
+
+
+struct lzma_coder_s {
+ lzma_next_coder next;
+
+ enum {
+ SEQ_HEADER,
+ SEQ_CODE,
+ } sequence;
+
+ size_t header_pos;
+ uint8_t header[ALONE_HEADER_SIZE];
+};
+
+
+static lzma_ret
+alone_encode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((__unused__)),
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size,
+ lzma_action action)
+{
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_HEADER:
+ lzma_bufcpy(coder->header, &coder->header_pos,
+ ALONE_HEADER_SIZE,
+ out, out_pos, out_size);
+ if (coder->header_pos < ALONE_HEADER_SIZE)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_CODE;
+ break;
+
+ case SEQ_CODE:
+ return coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+alone_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+// At least for now, this is not used by any internal function.
+static lzma_ret
+alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_options_lzma *options)
+{
+ uint32_t d;
+
+ // Initialize the LZMA encoder.
+ const lzma_filter_info filters[2] = {
+ { 0, &lzma_lzma_encoder_init, (void *)(options) },
+ { 0, NULL, NULL }
+ };
+
+ lzma_next_coder_init(&alone_encoder_init, next, allocator);
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &alone_encode;
+ next->end = &alone_encoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Basic initializations
+ next->coder->sequence = SEQ_HEADER;
+ next->coder->header_pos = 0;
+
+ // Encode the header:
+ // - Properties (1 byte)
+ if (lzma_lzma_lclppb_encode(options, next->coder->header))
+ return LZMA_OPTIONS_ERROR;
+
+ // - Dictionary size (4 bytes)
+ if (options->dict_size < LZMA_DICT_SIZE_MIN)
+ return LZMA_OPTIONS_ERROR;
+
+ // Round up to the next 2^n or 2^n + 2^(n - 1) depending on which
+ // one is the next unless it is UINT32_MAX. While the header would
+ // allow any 32-bit integer, we do this to keep the decoder of liblzma
+ // accepting the resulting files.
+ d = options->dict_size - 1;
+ d |= d >> 2;
+ d |= d >> 3;
+ d |= d >> 4;
+ d |= d >> 8;
+ d |= d >> 16;
+ if (d != UINT32_MAX)
+ ++d;
+
+ unaligned_write32le(next->coder->header + 1, d);
+
+ // - Uncompressed size (always unknown and using EOPM)
+ memset(next->coder->header + 1 + 4, 0xFF, 8);
+
+ return lzma_next_filter_init(&next->coder->next, allocator, filters);
+}
+
+
+/*
+extern lzma_ret
+lzma_alone_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_options_alone *options)
+{
+ lzma_next_coder_init(&alone_encoder_init, next, allocator, options);
+}
+*/
+
+
+extern LZMA_API(lzma_ret)
+lzma_alone_encoder(lzma_stream *strm, const lzma_options_lzma *options)
+{
+ lzma_next_strm_init1(alone_encoder_init, strm, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/auto_decoder.c b/Utilities/cmliblzma/liblzma/common/auto_decoder.c
new file mode 100644
index 000000000..24cf48905
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/auto_decoder.c
@@ -0,0 +1,186 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file auto_decoder.c
+/// \brief Autodetect between .xz Stream and .lzma (LZMA_Alone) formats
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+#include "alone_decoder.h"
+
+
+struct lzma_coder_s {
+ /// Stream decoder or LZMA_Alone decoder
+ lzma_next_coder next;
+
+ uint64_t memlimit;
+ uint32_t flags;
+
+ enum {
+ SEQ_INIT,
+ SEQ_CODE,
+ SEQ_FINISH,
+ } sequence;
+};
+
+
+static lzma_ret
+auto_decode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ switch (coder->sequence) {
+ case SEQ_INIT:
+ if (*in_pos >= in_size)
+ return LZMA_OK;
+
+ // Update the sequence now, because we want to continue from
+ // SEQ_CODE even if we return some LZMA_*_CHECK.
+ coder->sequence = SEQ_CODE;
+
+ // Detect the file format. For now this is simple, since if
+ // it doesn't start with 0xFD (the first magic byte of the
+ // new format), it has to be LZMA_Alone, or something that
+ // we don't support at all.
+ if (in[*in_pos] == 0xFD) {
+ return_if_error(lzma_stream_decoder_init(
+ &coder->next, allocator,
+ coder->memlimit, coder->flags));
+ } else {
+ return_if_error(lzma_alone_decoder_init(&coder->next,
+ allocator, coder->memlimit, true));
+
+ // If the application wants to know about missing
+ // integrity check or about the check in general, we
+ // need to handle it here, because LZMA_Alone decoder
+ // doesn't accept any flags.
+ if (coder->flags & LZMA_TELL_NO_CHECK)
+ return LZMA_NO_CHECK;
+
+ if (coder->flags & LZMA_TELL_ANY_CHECK)
+ return LZMA_GET_CHECK;
+ }
+
+ // Fall through
+
+ case SEQ_CODE: {
+ const lzma_ret ret = coder->next.code(
+ coder->next.coder, allocator,
+ in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ if (ret != LZMA_STREAM_END
+ || (coder->flags & LZMA_CONCATENATED) == 0)
+ return ret;
+
+ coder->sequence = SEQ_FINISH;
+ }
+
+ // Fall through
+
+ case SEQ_FINISH:
+ // When LZMA_DECODE_CONCATENATED was used and we were decoding
+ // LZMA_Alone file, we need to check check that there is no
+ // trailing garbage and wait for LZMA_FINISH.
+ if (*in_pos < in_size)
+ return LZMA_DATA_ERROR;
+
+ return action == LZMA_FINISH ? LZMA_STREAM_END : LZMA_OK;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+}
+
+
+static void
+auto_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_check
+auto_decoder_get_check(const lzma_coder *coder)
+{
+ // It is LZMA_Alone if get_check is NULL.
+ return coder->next.get_check == NULL ? LZMA_CHECK_NONE
+ : coder->next.get_check(coder->next.coder);
+}
+
+
+static lzma_ret
+auto_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
+ uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+ lzma_ret ret;
+
+ if (coder->next.memconfig != NULL) {
+ ret = coder->next.memconfig(coder->next.coder,
+ memusage, old_memlimit, new_memlimit);
+ assert(*old_memlimit == coder->memlimit);
+ } else {
+ // No coder is configured yet. Use the base value as
+ // the current memory usage.
+ *memusage = LZMA_MEMUSAGE_BASE;
+ *old_memlimit = coder->memlimit;
+ ret = LZMA_OK;
+ }
+
+ if (ret == LZMA_OK && new_memlimit != 0)
+ coder->memlimit = new_memlimit;
+
+ return ret;
+}
+
+
+static lzma_ret
+auto_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ uint64_t memlimit, uint32_t flags)
+{
+ lzma_next_coder_init(&auto_decoder_init, next, allocator);
+
+ if (memlimit == 0)
+ return LZMA_PROG_ERROR;
+
+ if (flags & ~LZMA_SUPPORTED_FLAGS)
+ return LZMA_OPTIONS_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &auto_decode;
+ next->end = &auto_decoder_end;
+ next->get_check = &auto_decoder_get_check;
+ next->memconfig = &auto_decoder_memconfig;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ next->coder->memlimit = memlimit;
+ next->coder->flags = flags;
+ next->coder->sequence = SEQ_INIT;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_auto_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+{
+ lzma_next_strm_init2(auto_decoder_init, strm, memlimit, flags);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_buffer_decoder.c b/Utilities/cmliblzma/liblzma/common/block_buffer_decoder.c
new file mode 100644
index 000000000..b4bd388eb
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_buffer_decoder.c
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_buffer_decoder.c
+/// \brief Single-call .xz Block decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_buffer_decode(lzma_block *block, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ lzma_next_coder block_decoder;
+ lzma_ret ret;
+
+ if (in_pos == NULL || (in == NULL && *in_pos != in_size)
+ || *in_pos > in_size || out_pos == NULL
+ || (out == NULL && *out_pos != out_size)
+ || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // Initialize the Block decoder.
+ block_decoder = LZMA_NEXT_CODER_INIT;
+ ret = lzma_block_decoder_init(&block_decoder, allocator, block);
+
+ if (ret == LZMA_OK) {
+ // Save the positions so that we can restore them in case
+ // an error occurs.
+ const size_t in_start = *in_pos;
+ const size_t out_start = *out_pos;
+
+ // Do the actual decoding.
+ ret = block_decoder.code(block_decoder.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ LZMA_FINISH);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ if (ret == LZMA_OK) {
+ // Either the input was truncated or the
+ // output buffer was too small.
+ assert(*in_pos == in_size
+ || *out_pos == out_size);
+
+ // If all the input was consumed, then the
+ // input is truncated, even if the output
+ // buffer is also full. This is because
+ // processing the last byte of the Block
+ // never produces output.
+ //
+ // NOTE: This assumption may break when new
+ // filters are added, if the end marker of
+ // the filter doesn't consume at least one
+ // complete byte.
+ if (*in_pos == in_size)
+ ret = LZMA_DATA_ERROR;
+ else
+ ret = LZMA_BUF_ERROR;
+ }
+
+ // Restore the positions.
+ *in_pos = in_start;
+ *out_pos = out_start;
+ }
+ }
+
+ // Free the decoder memory. This needs to be done even if
+ // initialization fails, because the internal API doesn't
+ // require the initialization function to free its memory on error.
+ lzma_next_end(&block_decoder, allocator);
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_buffer_encoder.c b/Utilities/cmliblzma/liblzma/common/block_buffer_encoder.c
new file mode 100644
index 000000000..136f7f573
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_buffer_encoder.c
@@ -0,0 +1,315 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_buffer_encoder.c
+/// \brief Single-call .xz Block encoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_encoder.h"
+#include "filter_encoder.h"
+#include "lzma2_encoder.h"
+#include "check.h"
+
+
+/// Estimate the maximum size of the Block Header and Check fields for
+/// a Block that uses LZMA2 uncompressed chunks. We could use
+/// lzma_block_header_size() but this is simpler.
+///
+/// Block Header Size + Block Flags + Compressed Size
+/// + Uncompressed Size + Filter Flags for LZMA2 + CRC32 + Check
+/// and round up to the next multiple of four to take Header Padding
+/// into account.
+#define HEADERS_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 3 + 4 \
+ + LZMA_CHECK_SIZE_MAX + 3) & ~3)
+
+
+static lzma_vli
+lzma2_bound(lzma_vli uncompressed_size)
+{
+ lzma_vli overhead;
+
+ // Prevent integer overflow in overhead calculation.
+ if (uncompressed_size > COMPRESSED_SIZE_MAX)
+ return 0;
+
+ // Calculate the exact overhead of the LZMA2 headers: Round
+ // uncompressed_size up to the next multiple of LZMA2_CHUNK_MAX,
+ // multiply by the size of per-chunk header, and add one byte for
+ // the end marker.
+ overhead = ((uncompressed_size + LZMA2_CHUNK_MAX - 1)
+ / LZMA2_CHUNK_MAX)
+ * LZMA2_HEADER_UNCOMPRESSED + 1;
+
+ // Catch the possible integer overflow.
+ if (COMPRESSED_SIZE_MAX - overhead < uncompressed_size)
+ return 0;
+
+ return uncompressed_size + overhead;
+}
+
+
+extern LZMA_API(size_t)
+lzma_block_buffer_bound(size_t uncompressed_size)
+{
+ // For now, if the data doesn't compress, we always use uncompressed
+ // chunks of LZMA2. In future we may use Subblock filter too, but
+ // but for simplicity we probably will still use the same bound
+ // calculation even though Subblock filter would have slightly less
+ // overhead.
+ lzma_vli lzma2_size = lzma2_bound(uncompressed_size);
+ if (lzma2_size == 0)
+ return 0;
+
+ // Take Block Padding into account.
+ lzma2_size = (lzma2_size + 3) & ~LZMA_VLI_C(3);
+
+#if SIZE_MAX < LZMA_VLI_MAX
+ // Catch the possible integer overflow on 32-bit systems. There's no
+ // overflow on 64-bit systems, because lzma2_bound() already takes
+ // into account the size of the headers in the Block.
+ if (SIZE_MAX - HEADERS_BOUND < lzma2_size)
+ return 0;
+#endif
+
+ return HEADERS_BOUND + lzma2_size;
+}
+
+
+static lzma_ret
+block_encode_uncompressed(lzma_block *block, const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ size_t in_pos = 0;
+ uint8_t control = 0x01; // Dictionary reset
+ lzma_filter *filters_orig;
+
+ // TODO: Figure out if the last filter is LZMA2 or Subblock and use
+ // that filter to encode the uncompressed chunks.
+
+ // Use LZMA2 uncompressed chunks. We wouldn't need a dictionary at
+ // all, but LZMA2 always requires a dictionary, so use the minimum
+ // value to minimize memory usage of the decoder.
+ lzma_options_lzma lzma2 = { LZMA_DICT_SIZE_MIN };
+
+ lzma_filter filters[2];
+ filters[0].id = LZMA_FILTER_LZMA2;
+ filters[0].options = &lzma2;
+ filters[1].id = LZMA_VLI_UNKNOWN;
+
+ // Set the above filter options to *block temporarily so that we can
+ // encode the Block Header.
+ filters_orig = block->filters;
+ block->filters = filters;
+
+ if (lzma_block_header_size(block) != LZMA_OK) {
+ block->filters = filters_orig;
+ return LZMA_PROG_ERROR;
+ }
+
+ // Check that there's enough output space. The caller has already
+ // set block->compressed_size to what lzma2_bound() has returned,
+ // so we can reuse that value. We know that compressed_size is a
+ // known valid VLI and header_size is a small value so their sum
+ // will never overflow.
+ assert(block->compressed_size == lzma2_bound(in_size));
+ if (out_size - *out_pos
+ < block->header_size + block->compressed_size) {
+ block->filters = filters_orig;
+ return LZMA_BUF_ERROR;
+ }
+
+ if (lzma_block_header_encode(block, out + *out_pos) != LZMA_OK) {
+ block->filters = filters_orig;
+ return LZMA_PROG_ERROR;
+ }
+
+ block->filters = filters_orig;
+ *out_pos += block->header_size;
+
+ // Encode the data using LZMA2 uncompressed chunks.
+
+ while (in_pos < in_size) {
+ size_t copy_size;
+
+ // Control byte: Indicate uncompressed chunk, of which
+ // the first resets the dictionary.
+ out[(*out_pos)++] = control;
+ control = 0x02; // No dictionary reset
+
+ // Size of the uncompressed chunk
+ copy_size = my_min(in_size - in_pos, LZMA2_CHUNK_MAX);
+ out[(*out_pos)++] = (copy_size - 1) >> 8;
+ out[(*out_pos)++] = (copy_size - 1) & 0xFF;
+
+ // The actual data
+ assert(*out_pos + copy_size <= out_size);
+ memcpy(out + *out_pos, in + in_pos, copy_size);
+
+ in_pos += copy_size;
+ *out_pos += copy_size;
+ }
+
+ // End marker
+ out[(*out_pos)++] = 0x00;
+ assert(*out_pos <= out_size);
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+block_encode_normal(lzma_block *block, lzma_allocator *allocator,
+ const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ size_t out_start;
+ lzma_next_coder raw_encoder = LZMA_NEXT_CODER_INIT;
+ lzma_ret ret;
+
+ // Find out the size of the Block Header.
+ block->compressed_size = lzma2_bound(in_size);
+ if (block->compressed_size == 0)
+ return LZMA_DATA_ERROR;
+
+ block->uncompressed_size = in_size;
+ return_if_error(lzma_block_header_size(block));
+
+ // Reserve space for the Block Header and skip it for now.
+ if (out_size - *out_pos <= block->header_size)
+ return LZMA_BUF_ERROR;
+
+ out_start = *out_pos;
+ *out_pos += block->header_size;
+
+ // Limit out_size so that we stop encoding if the output would grow
+ // bigger than what uncompressed Block would be.
+ if (out_size - *out_pos > block->compressed_size)
+ out_size = *out_pos + block->compressed_size;
+
+ // TODO: In many common cases this could be optimized to use
+ // significantly less memory.
+ ret = lzma_raw_encoder_init(
+ &raw_encoder, allocator, block->filters);
+
+ if (ret == LZMA_OK) {
+ size_t in_pos = 0;
+ ret = raw_encoder.code(raw_encoder.coder, allocator,
+ in, &in_pos, in_size, out, out_pos, out_size,
+ LZMA_FINISH);
+ }
+
+ // NOTE: This needs to be run even if lzma_raw_encoder_init() failed.
+ lzma_next_end(&raw_encoder, allocator);
+
+ if (ret == LZMA_STREAM_END) {
+ // Compression was successful. Write the Block Header.
+ block->compressed_size
+ = *out_pos - (out_start + block->header_size);
+ ret = lzma_block_header_encode(block, out + out_start);
+ if (ret != LZMA_OK)
+ ret = LZMA_PROG_ERROR;
+
+ } else if (ret == LZMA_OK) {
+ // Output buffer became full.
+ ret = LZMA_BUF_ERROR;
+ }
+
+ // Reset *out_pos if something went wrong.
+ if (ret != LZMA_OK)
+ *out_pos = out_start;
+
+ return ret;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_buffer_encode(lzma_block *block, lzma_allocator *allocator,
+ const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ size_t check_size;
+ lzma_ret ret;
+ size_t i;
+
+ // Validate the arguments.
+ if (block == NULL || (in == NULL && in_size != 0) || out == NULL
+ || out_pos == NULL || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // The contents of the structure may depend on the version so
+ // check the version before validating the contents of *block.
+ if (block->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX
+ || block->filters == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (!lzma_check_is_supported(block->check))
+ return LZMA_UNSUPPORTED_CHECK;
+
+ // Size of a Block has to be a multiple of four, so limit the size
+ // here already. This way we don't need to check it again when adding
+ // Block Padding.
+ out_size -= (out_size - *out_pos) & 3;
+
+ // Get the size of the Check field.
+ check_size = lzma_check_size(block->check);
+ assert(check_size != UINT32_MAX);
+
+ // Reserve space for the Check field.
+ if (out_size - *out_pos <= check_size)
+ return LZMA_BUF_ERROR;
+
+ out_size -= check_size;
+
+ // Do the actual compression.
+ ret = block_encode_normal(block, allocator,
+ in, in_size, out, out_pos, out_size);
+ if (ret != LZMA_OK) {
+ // If the error was something else than output buffer
+ // becoming full, return the error now.
+ if (ret != LZMA_BUF_ERROR)
+ return ret;
+
+ // The data was uncompressible (at least with the options
+ // given to us) or the output buffer was too small. Use the
+ // uncompressed chunks of LZMA2 to wrap the data into a valid
+ // Block. If we haven't been given enough output space, even
+ // this may fail.
+ return_if_error(block_encode_uncompressed(block, in, in_size,
+ out, out_pos, out_size));
+ }
+
+ assert(*out_pos <= out_size);
+
+ // Block Padding. No buffer overflow here, because we already adjusted
+ // out_size so that (out_size - out_start) is a multiple of four.
+ // Thus, if the buffer is full, the loop body can never run.
+ for (i = (size_t)(block->compressed_size); i & 3; ++i) {
+ assert(*out_pos < out_size);
+ out[(*out_pos)++] = 0x00;
+ }
+
+ // If there's no Check field, we are done now.
+ if (check_size > 0) {
+ // Calculate the integrity check. We reserved space for
+ // the Check field earlier so we don't need to check for
+ // available output space here.
+ lzma_check_state check;
+ lzma_check_init(&check, block->check);
+ lzma_check_update(&check, block->check, in, in_size);
+ lzma_check_finish(&check, block->check);
+
+ memcpy(block->raw_check, check.buffer.u8, check_size);
+ memcpy(out + *out_pos, check.buffer.u8, check_size);
+ *out_pos += check_size;
+ }
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_decoder.c b/Utilities/cmliblzma/liblzma/common/block_decoder.c
new file mode 100644
index 000000000..35996e7cf
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_decoder.c
@@ -0,0 +1,242 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_decoder.c
+/// \brief Decodes .xz Blocks
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_decoder.h"
+#include "filter_decoder.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_CODE,
+ SEQ_PADDING,
+ SEQ_CHECK,
+ } sequence;
+
+ /// The filters in the chain; initialized with lzma_raw_decoder_init().
+ lzma_next_coder next;
+
+ /// Decoding options; we also write Compressed Size and Uncompressed
+ /// Size back to this structure when the decoding has been finished.
+ lzma_block *block;
+
+ /// Compressed Size calculated while decoding
+ lzma_vli compressed_size;
+
+ /// Uncompressed Size calculated while decoding
+ lzma_vli uncompressed_size;
+
+ /// Maximum allowed Compressed Size; this takes into account the
+ /// size of the Block Header and Check fields when Compressed Size
+ /// is unknown.
+ lzma_vli compressed_limit;
+
+ /// Position when reading the Check field
+ size_t check_pos;
+
+ /// Check of the uncompressed data
+ lzma_check_state check;
+};
+
+
+static inline bool
+update_size(lzma_vli *size, lzma_vli add, lzma_vli limit)
+{
+ if (limit > LZMA_VLI_MAX)
+ limit = LZMA_VLI_MAX;
+
+ if (limit < *size || limit - *size < add)
+ return true;
+
+ *size += add;
+
+ return false;
+}
+
+
+static inline bool
+is_size_valid(lzma_vli size, lzma_vli reference)
+{
+ return reference == LZMA_VLI_UNKNOWN || reference == size;
+}
+
+
+static lzma_ret
+block_decode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ switch (coder->sequence) {
+ case SEQ_CODE: {
+ const size_t in_start = *in_pos;
+ const size_t out_start = *out_pos;
+
+ const lzma_ret ret = coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+
+ const size_t in_used = *in_pos - in_start;
+ const size_t out_used = *out_pos - out_start;
+
+ // NOTE: We compare to compressed_limit here, which prevents
+ // the total size of the Block growing past LZMA_VLI_MAX.
+ if (update_size(&coder->compressed_size, in_used,
+ coder->compressed_limit)
+ || update_size(&coder->uncompressed_size,
+ out_used,
+ coder->block->uncompressed_size))
+ return LZMA_DATA_ERROR;
+
+ lzma_check_update(&coder->check, coder->block->check,
+ out + out_start, out_used);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ // Compressed and Uncompressed Sizes are now at their final
+ // values. Verify that they match the values given to us.
+ if (!is_size_valid(coder->compressed_size,
+ coder->block->compressed_size)
+ || !is_size_valid(coder->uncompressed_size,
+ coder->block->uncompressed_size))
+ return LZMA_DATA_ERROR;
+
+ // Copy the values into coder->block. The caller
+ // may use this information to construct Index.
+ coder->block->compressed_size = coder->compressed_size;
+ coder->block->uncompressed_size = coder->uncompressed_size;
+
+ coder->sequence = SEQ_PADDING;
+ }
+
+ // Fall through
+
+ case SEQ_PADDING:
+ // Compressed Data is padded to a multiple of four bytes.
+ while (coder->compressed_size & 3) {
+ if (*in_pos >= in_size)
+ return LZMA_OK;
+
+ // We use compressed_size here just get the Padding
+ // right. The actual Compressed Size was stored to
+ // coder->block already, and won't be modified by
+ // us anymore.
+ ++coder->compressed_size;
+
+ if (in[(*in_pos)++] != 0x00)
+ return LZMA_DATA_ERROR;
+ }
+
+ if (coder->block->check == LZMA_CHECK_NONE)
+ return LZMA_STREAM_END;
+
+ lzma_check_finish(&coder->check, coder->block->check);
+ coder->sequence = SEQ_CHECK;
+
+ // Fall through
+
+ case SEQ_CHECK: {
+ const size_t check_size = lzma_check_size(coder->block->check);
+ lzma_bufcpy(in, in_pos, in_size, coder->block->raw_check,
+ &coder->check_pos, check_size);
+ if (coder->check_pos < check_size)
+ return LZMA_OK;
+
+ // Validate the Check only if we support it.
+ // coder->check.buffer may be uninitialized
+ // when the Check ID is not supported.
+ if (lzma_check_is_supported(coder->block->check)
+ && memcmp(coder->block->raw_check,
+ coder->check.buffer.u8,
+ check_size) != 0)
+ return LZMA_DATA_ERROR;
+
+ return LZMA_STREAM_END;
+ }
+ }
+
+ return LZMA_PROG_ERROR;
+}
+
+
+static void
+block_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_block_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_block *block)
+{
+ lzma_next_coder_init(&lzma_block_decoder_init, next, allocator);
+
+ // Validate the options. lzma_block_unpadded_size() does that for us
+ // except for Uncompressed Size and filters. Filters are validated
+ // by the raw decoder.
+ if (lzma_block_unpadded_size(block) == 0
+ || !lzma_vli_is_valid(block->uncompressed_size))
+ return LZMA_PROG_ERROR;
+
+ // Allocate and initialize *next->coder if needed.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &block_decode;
+ next->end = &block_decoder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Basic initializations
+ next->coder->sequence = SEQ_CODE;
+ next->coder->block = block;
+ next->coder->compressed_size = 0;
+ next->coder->uncompressed_size = 0;
+
+ // If Compressed Size is not known, we calculate the maximum allowed
+ // value so that encoded size of the Block (including Block Padding)
+ // is still a valid VLI and a multiple of four.
+ next->coder->compressed_limit
+ = block->compressed_size == LZMA_VLI_UNKNOWN
+ ? (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
+ - block->header_size
+ - lzma_check_size(block->check)
+ : block->compressed_size;
+
+ // Initialize the check. It's caller's problem if the Check ID is not
+ // supported, and the Block decoder cannot verify the Check field.
+ // Caller can test lzma_check_is_supported(block->check).
+ next->coder->check_pos = 0;
+ lzma_check_init(&next->coder->check, block->check);
+
+ // Initialize the filter chain.
+ return lzma_raw_decoder_init(&next->coder->next, allocator,
+ block->filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_decoder(lzma_stream *strm, lzma_block *block)
+{
+ lzma_next_strm_init1(lzma_block_decoder_init, strm, block);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_decoder.h b/Utilities/cmliblzma/liblzma/common/block_decoder.h
new file mode 100644
index 000000000..7da9df63f
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_decoder.h
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_decoder.h
+/// \brief Decodes .xz Blocks
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_DECODER_H
+#define LZMA_BLOCK_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_block_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_block *block);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/block_encoder.c b/Utilities/cmliblzma/liblzma/common/block_encoder.c
new file mode 100644
index 000000000..ed748273e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_encoder.c
@@ -0,0 +1,217 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_encoder.c
+/// \brief Encodes .xz Blocks
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "block_encoder.h"
+#include "filter_encoder.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ /// The filters in the chain; initialized with lzma_raw_decoder_init().
+ lzma_next_coder next;
+
+ /// Encoding options; we also write Unpadded Size, Compressed Size,
+ /// and Uncompressed Size back to this structure when the encoding
+ /// has been finished.
+ lzma_block *block;
+
+ enum {
+ SEQ_CODE,
+ SEQ_PADDING,
+ SEQ_CHECK,
+ } sequence;
+
+ /// Compressed Size calculated while encoding
+ lzma_vli compressed_size;
+
+ /// Uncompressed Size calculated while encoding
+ lzma_vli uncompressed_size;
+
+ /// Position in the Check field
+ size_t pos;
+
+ /// Check of the uncompressed data
+ lzma_check_state check;
+};
+
+
+static lzma_ret
+block_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ // Check that our amount of input stays in proper limits.
+ if (LZMA_VLI_MAX - coder->uncompressed_size < in_size - *in_pos)
+ return LZMA_DATA_ERROR;
+
+ switch (coder->sequence) {
+ case SEQ_CODE: {
+ const size_t in_start = *in_pos;
+ const size_t out_start = *out_pos;
+
+ const lzma_ret ret = coder->next.code(coder->next.coder,
+ allocator, in, in_pos, in_size,
+ out, out_pos, out_size, action);
+
+ const size_t in_used = *in_pos - in_start;
+ const size_t out_used = *out_pos - out_start;
+
+ if (COMPRESSED_SIZE_MAX - coder->compressed_size < out_used)
+ return LZMA_DATA_ERROR;
+
+ coder->compressed_size += out_used;
+
+ // No need to check for overflow because we have already
+ // checked it at the beginning of this function.
+ coder->uncompressed_size += in_used;
+
+ lzma_check_update(&coder->check, coder->block->check,
+ in + in_start, in_used);
+
+ if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+ return ret;
+
+ assert(*in_pos == in_size);
+ assert(action == LZMA_FINISH);
+
+ // Copy the values into coder->block. The caller
+ // may use this information to construct Index.
+ coder->block->compressed_size = coder->compressed_size;
+ coder->block->uncompressed_size = coder->uncompressed_size;
+
+ coder->sequence = SEQ_PADDING;
+ }
+
+ // Fall through
+
+ case SEQ_PADDING:
+ // Pad Compressed Data to a multiple of four bytes. We can
+ // use coder->compressed_size for this since we don't need
+ // it for anything else anymore.
+ while (coder->compressed_size & 3) {
+ if (*out_pos >= out_size)
+ return LZMA_OK;
+
+ out[*out_pos] = 0x00;
+ ++*out_pos;
+ ++coder->compressed_size;
+ }
+
+ if (coder->block->check == LZMA_CHECK_NONE)
+ return LZMA_STREAM_END;
+
+ lzma_check_finish(&coder->check, coder->block->check);
+
+ coder->sequence = SEQ_CHECK;
+
+ // Fall through
+
+ case SEQ_CHECK: {
+ const size_t check_size = lzma_check_size(coder->block->check);
+ lzma_bufcpy(coder->check.buffer.u8, &coder->pos, check_size,
+ out, out_pos, out_size);
+ if (coder->pos < check_size)
+ return LZMA_OK;
+
+ memcpy(coder->block->raw_check, coder->check.buffer.u8,
+ check_size);
+ return LZMA_STREAM_END;
+ }
+ }
+
+ return LZMA_PROG_ERROR;
+}
+
+
+static void
+block_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+block_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters lzma_attribute((__unused__)),
+ const lzma_filter *reversed_filters)
+{
+ if (coder->sequence != SEQ_CODE)
+ return LZMA_PROG_ERROR;
+
+ return lzma_next_filter_update(
+ &coder->next, allocator, reversed_filters);
+}
+
+
+extern lzma_ret
+lzma_block_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_block *block)
+{
+ lzma_next_coder_init(&lzma_block_encoder_init, next, allocator);
+
+ if (block == NULL)
+ return LZMA_PROG_ERROR;
+
+ // The contents of the structure may depend on the version so
+ // check the version first.
+ if (block->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ // If the Check ID is not supported, we cannot calculate the check and
+ // thus not create a proper Block.
+ if ((unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+ return LZMA_PROG_ERROR;
+
+ if (!lzma_check_is_supported(block->check))
+ return LZMA_UNSUPPORTED_CHECK;
+
+ // Allocate and initialize *next->coder if needed.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &block_encode;
+ next->end = &block_encoder_end;
+ next->update = &block_encoder_update;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Basic initializations
+ next->coder->sequence = SEQ_CODE;
+ next->coder->block = block;
+ next->coder->compressed_size = 0;
+ next->coder->uncompressed_size = 0;
+ next->coder->pos = 0;
+
+ // Initialize the check
+ lzma_check_init(&next->coder->check, block->check);
+
+ // Initialize the requested filters.
+ return lzma_raw_encoder_init(&next->coder->next, allocator,
+ block->filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_encoder(lzma_stream *strm, lzma_block *block)
+{
+ lzma_next_strm_init1(lzma_block_encoder_init, strm, block);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_encoder.h b/Utilities/cmliblzma/liblzma/common/block_encoder.h
new file mode 100644
index 000000000..b9eff0be2
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_encoder.h
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_encoder.h
+/// \brief Encodes .xz Blocks
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_BLOCK_ENCODER_H
+#define LZMA_BLOCK_ENCODER_H
+
+#include "common.h"
+
+
+/// \brief Biggest Compressed Size value that the Block encoder supports
+///
+/// The maximum size of a single Block is limited by the maximum size of
+/// a Stream, which in theory is 2^63 - 3 bytes (i.e. LZMA_VLI_MAX - 3).
+/// While the size is really big and no one should hit it in practice, we
+/// take it into account in some places anyway to catch some errors e.g. if
+/// application passes insanely big value to some function.
+///
+/// We could take into account the headers etc. to determine the exact
+/// maximum size of the Compressed Data field, but the complexity would give
+/// us nothing useful. Instead, limit the size of Compressed Data so that
+/// even with biggest possible Block Header and Check fields the total
+/// encoded size of the Block stays as a valid VLI. This doesn't guarantee
+/// that the size of the Stream doesn't grow too big, but that problem is
+/// taken care outside the Block handling code.
+///
+/// ~LZMA_VLI_C(3) is to guarantee that if we need padding at the end of
+/// the Compressed Data field, it will still stay in the proper limit.
+///
+/// This constant is in this file because it is needed in both
+/// block_encoder.c and block_buffer_encoder.c.
+#define COMPRESSED_SIZE_MAX ((LZMA_VLI_MAX - LZMA_BLOCK_HEADER_SIZE_MAX \
+ - LZMA_CHECK_SIZE_MAX) & ~LZMA_VLI_C(3))
+
+
+extern lzma_ret lzma_block_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, lzma_block *block);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/block_header_decoder.c b/Utilities/cmliblzma/liblzma/common/block_header_decoder.c
new file mode 100644
index 000000000..f6e470e69
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_header_decoder.c
@@ -0,0 +1,121 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_header_decoder.c
+/// \brief Decodes Block Header from .xz files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "check.h"
+
+
+static void
+free_properties(lzma_block *block, lzma_allocator *allocator)
+{
+ size_t i;
+
+ // Free allocated filter options. The last array member is not
+ // touched after the initialization in the beginning of
+ // lzma_block_header_decode(), so we don't need to touch that here.
+ for (i = 0; i < LZMA_FILTERS_MAX; ++i) {
+ lzma_free(block->filters[i].options, allocator);
+ block->filters[i].id = LZMA_VLI_UNKNOWN;
+ block->filters[i].options = NULL;
+ }
+
+ return;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_decode(lzma_block *block,
+ lzma_allocator *allocator, const uint8_t *in)
+{
+ const size_t filter_count = (in[1] & 3) + 1;
+ size_t in_size;
+ size_t i;
+
+ // Start after the Block Header Size and Block Flags fields.
+ size_t in_pos = 2;
+
+ // NOTE: We consider the header to be corrupt not only when the
+ // CRC32 doesn't match, but also when variable-length integers
+ // are invalid or over 63 bits, or if the header is too small
+ // to contain the claimed information.
+
+ // Initialize the filter options array. This way the caller can
+ // safely free() the options even if an error occurs in this function.
+ for (i = 0; i <= LZMA_FILTERS_MAX; ++i) {
+ block->filters[i].id = LZMA_VLI_UNKNOWN;
+ block->filters[i].options = NULL;
+ }
+
+ // Always zero for now.
+ block->version = 0;
+
+ // Validate Block Header Size and Check type. The caller must have
+ // already set these, so it is a programming error if this test fails.
+ if (lzma_block_header_size_decode(in[0]) != block->header_size
+ || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+ return LZMA_PROG_ERROR;
+
+ // Exclude the CRC32 field.
+ in_size = block->header_size - 4;
+
+ // Verify CRC32
+ if (lzma_crc32(in, in_size, 0) != unaligned_read32le(in + in_size))
+ return LZMA_DATA_ERROR;
+
+ // Check for unsupported flags.
+ if (in[1] & 0x3C)
+ return LZMA_OPTIONS_ERROR;
+
+ // Compressed Size
+ if (in[1] & 0x40) {
+ return_if_error(lzma_vli_decode(&block->compressed_size,
+ NULL, in, &in_pos, in_size));
+
+ // Validate Compressed Size. This checks that it isn't zero
+ // and that the total size of the Block is a valid VLI.
+ if (lzma_block_unpadded_size(block) == 0)
+ return LZMA_DATA_ERROR;
+ } else {
+ block->compressed_size = LZMA_VLI_UNKNOWN;
+ }
+
+ // Uncompressed Size
+ if (in[1] & 0x80)
+ return_if_error(lzma_vli_decode(&block->uncompressed_size,
+ NULL, in, &in_pos, in_size));
+ else
+ block->uncompressed_size = LZMA_VLI_UNKNOWN;
+
+ // Filter Flags
+ for (i = 0; i < filter_count; ++i) {
+ const lzma_ret ret = lzma_filter_flags_decode(
+ &block->filters[i], allocator,
+ in, &in_pos, in_size);
+ if (ret != LZMA_OK) {
+ free_properties(block, allocator);
+ return ret;
+ }
+ }
+
+ // Padding
+ while (in_pos < in_size) {
+ if (in[in_pos++] != 0x00) {
+ free_properties(block, allocator);
+
+ // Possibly some new field present so use
+ // LZMA_OPTIONS_ERROR instead of LZMA_DATA_ERROR.
+ return LZMA_OPTIONS_ERROR;
+ }
+ }
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_header_encoder.c b/Utilities/cmliblzma/liblzma/common/block_header_encoder.c
new file mode 100644
index 000000000..650295c00
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_header_encoder.c
@@ -0,0 +1,137 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_header_encoder.c
+/// \brief Encodes Block Header for .xz files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "check.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_size(lzma_block *block)
+{
+ size_t i;
+
+ // Block Header Size + Block Flags + CRC32.
+ uint32_t size = 1 + 1 + 4;
+
+ if (block->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ // Compressed Size
+ if (block->compressed_size != LZMA_VLI_UNKNOWN) {
+ const uint32_t add = lzma_vli_size(block->compressed_size);
+ if (add == 0 || block->compressed_size == 0)
+ return LZMA_PROG_ERROR;
+
+ size += add;
+ }
+
+ // Uncompressed Size
+ if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
+ const uint32_t add = lzma_vli_size(block->uncompressed_size);
+ if (add == 0)
+ return LZMA_PROG_ERROR;
+
+ size += add;
+ }
+
+ // List of Filter Flags
+ if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
+ return LZMA_PROG_ERROR;
+
+ for (i = 0; block->filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+ uint32_t add;
+
+ // Don't allow too many filters.
+ if (i == LZMA_FILTERS_MAX)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_filter_flags_size(&add,
+ block->filters + i));
+
+ size += add;
+ }
+
+ // Pad to a multiple of four bytes.
+ block->header_size = (size + 3) & ~UINT32_C(3);
+
+ // NOTE: We don't verify that the encoded size of the Block stays
+ // within limits. This is because it is possible that we are called
+ // with exaggerated Compressed Size (e.g. LZMA_VLI_MAX) to reserve
+ // space for Block Header, and later called again with lower,
+ // real values.
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_header_encode(const lzma_block *block, uint8_t *out)
+{
+ size_t out_size;
+ size_t out_pos = 2;
+ size_t filter_count = 0;
+
+ // Validate everything but filters.
+ if (lzma_block_unpadded_size(block) == 0
+ || !lzma_vli_is_valid(block->uncompressed_size))
+ return LZMA_PROG_ERROR;
+
+ // Indicate the size of the buffer _excluding_ the CRC32 field.
+ out_size = block->header_size - 4;
+
+ // Store the Block Header Size.
+ out[0] = out_size / 4;
+
+ // We write Block Flags in pieces.
+ out[1] = 0x00;
+
+ // Compressed Size
+ if (block->compressed_size != LZMA_VLI_UNKNOWN) {
+ return_if_error(lzma_vli_encode(block->compressed_size, NULL,
+ out, &out_pos, out_size));
+
+ out[1] |= 0x40;
+ }
+
+ // Uncompressed Size
+ if (block->uncompressed_size != LZMA_VLI_UNKNOWN) {
+ return_if_error(lzma_vli_encode(block->uncompressed_size, NULL,
+ out, &out_pos, out_size));
+
+ out[1] |= 0x80;
+ }
+
+ // Filter Flags
+ if (block->filters == NULL || block->filters[0].id == LZMA_VLI_UNKNOWN)
+ return LZMA_PROG_ERROR;
+
+ do {
+ // There can be a maximum of four filters.
+ if (filter_count == LZMA_FILTERS_MAX)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_filter_flags_encode(
+ block->filters + filter_count,
+ out, &out_pos, out_size));
+
+ } while (block->filters[++filter_count].id != LZMA_VLI_UNKNOWN);
+
+ out[1] |= filter_count - 1;
+
+ // Padding
+ memzero(out + out_pos, out_size - out_pos);
+
+ // CRC32
+ unaligned_write32le(out + out_size, lzma_crc32(out, out_size, 0));
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/block_util.c b/Utilities/cmliblzma/liblzma/common/block_util.c
new file mode 100644
index 000000000..4cd34d100
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/block_util.c
@@ -0,0 +1,95 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file block_header.c
+/// \brief Utility functions to handle lzma_block
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_block_compressed_size(lzma_block *block, lzma_vli unpadded_size)
+{
+ uint32_t container_size;
+ lzma_vli compressed_size;
+
+ // Validate everything but Uncompressed Size and filters.
+ if (lzma_block_unpadded_size(block) == 0)
+ return LZMA_PROG_ERROR;
+
+ container_size = block->header_size
+ + lzma_check_size(block->check);
+
+ // Validate that Compressed Size will be greater than zero.
+ if (unpadded_size <= container_size)
+ return LZMA_DATA_ERROR;
+
+ // Calculate what Compressed Size is supposed to be.
+ // If Compressed Size was present in Block Header,
+ // compare that the new value matches it.
+ compressed_size = unpadded_size - container_size;
+ if (block->compressed_size != LZMA_VLI_UNKNOWN
+ && block->compressed_size != compressed_size)
+ return LZMA_DATA_ERROR;
+
+ block->compressed_size = compressed_size;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_block_unpadded_size(const lzma_block *block)
+{
+ lzma_vli unpadded_size;
+
+ // Validate the values that we are interested in i.e. all but
+ // Uncompressed Size and the filters.
+ //
+ // NOTE: This function is used for validation too, so it is
+ // essential that these checks are always done even if
+ // Compressed Size is unknown.
+ if (block == NULL || block->version != 0
+ || block->header_size < LZMA_BLOCK_HEADER_SIZE_MIN
+ || block->header_size > LZMA_BLOCK_HEADER_SIZE_MAX
+ || (block->header_size & 3)
+ || !lzma_vli_is_valid(block->compressed_size)
+ || block->compressed_size == 0
+ || (unsigned int)(block->check) > LZMA_CHECK_ID_MAX)
+ return 0;
+
+ // If Compressed Size is unknown, return that we cannot know
+ // size of the Block either.
+ if (block->compressed_size == LZMA_VLI_UNKNOWN)
+ return LZMA_VLI_UNKNOWN;
+
+ // Calculate Unpadded Size and validate it.
+ unpadded_size = block->compressed_size
+ + block->header_size
+ + lzma_check_size(block->check);
+
+ assert(unpadded_size >= UNPADDED_SIZE_MIN);
+ if (unpadded_size > UNPADDED_SIZE_MAX)
+ return 0;
+
+ return unpadded_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_block_total_size(const lzma_block *block)
+{
+ lzma_vli unpadded_size = lzma_block_unpadded_size(block);
+
+ if (unpadded_size != LZMA_VLI_UNKNOWN)
+ unpadded_size = vli_ceil4(unpadded_size);
+
+ return unpadded_size;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/common.c b/Utilities/cmliblzma/liblzma/common/common.c
new file mode 100644
index 000000000..2e723c8fe
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/common.c
@@ -0,0 +1,390 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file common.h
+/// \brief Common functions needed in many places in liblzma
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+/////////////
+// Version //
+/////////////
+
+extern LZMA_API(uint32_t)
+lzma_version_number(void)
+{
+ return LZMA_VERSION;
+}
+
+
+extern LZMA_API(const char *)
+lzma_version_string(void)
+{
+ return LZMA_VERSION_STRING;
+}
+
+
+///////////////////////
+// Memory allocation //
+///////////////////////
+
+extern void * lzma_attribute((__malloc__)) lzma_attr_alloc_size(1)
+lzma_alloc(size_t size, lzma_allocator *allocator)
+{
+ void *ptr;
+
+ // Some malloc() variants return NULL if called with size == 0.
+ if (size == 0)
+ size = 1;
+
+ if (allocator != NULL && allocator->alloc != NULL)
+ ptr = allocator->alloc(allocator->opaque, 1, size);
+ else
+ ptr = malloc(size);
+
+ return ptr;
+}
+
+
+extern void
+lzma_free(void *ptr, lzma_allocator *allocator)
+{
+ if (allocator != NULL && allocator->free != NULL)
+ allocator->free(allocator->opaque, ptr);
+ else
+ free(ptr);
+
+ return;
+}
+
+
+//////////
+// Misc //
+//////////
+
+extern size_t
+lzma_bufcpy(const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size)
+{
+ const size_t in_avail = in_size - *in_pos;
+ const size_t out_avail = out_size - *out_pos;
+ const size_t copy_size = my_min(in_avail, out_avail);
+
+ memcpy(out + *out_pos, in + *in_pos, copy_size);
+
+ *in_pos += copy_size;
+ *out_pos += copy_size;
+
+ return copy_size;
+}
+
+
+extern lzma_ret
+lzma_next_filter_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ lzma_next_coder_init(filters[0].init, next, allocator);
+ next->id = filters[0].id;
+ return filters[0].init == NULL
+ ? LZMA_OK : filters[0].init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_next_filter_update(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *reversed_filters)
+{
+ // Check that the application isn't trying to change the Filter ID.
+ // End of filters is indicated with LZMA_VLI_UNKNOWN in both
+ // reversed_filters[0].id and next->id.
+ if (reversed_filters[0].id != next->id)
+ return LZMA_PROG_ERROR;
+
+ if (reversed_filters[0].id == LZMA_VLI_UNKNOWN)
+ return LZMA_OK;
+
+ assert(next->update != NULL);
+ return next->update(next->coder, allocator, NULL, reversed_filters);
+}
+
+
+extern void
+lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator)
+{
+ if (next->init != (uintptr_t)(NULL)) {
+ // To avoid tiny end functions that simply call
+ // lzma_free(coder, allocator), we allow leaving next->end
+ // NULL and call lzma_free() here.
+ if (next->end != NULL)
+ next->end(next->coder, allocator);
+ else
+ lzma_free(next->coder, allocator);
+
+ // Reset the variables so the we don't accidentally think
+ // that it is an already initialized coder.
+ *next = LZMA_NEXT_CODER_INIT;
+ }
+
+ return;
+}
+
+
+//////////////////////////////////////
+// External to internal API wrapper //
+//////////////////////////////////////
+
+extern lzma_ret
+lzma_strm_init(lzma_stream *strm)
+{
+ if (strm == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (strm->internal == NULL) {
+ strm->internal = lzma_alloc(sizeof(lzma_internal),
+ strm->allocator);
+ if (strm->internal == NULL)
+ return LZMA_MEM_ERROR;
+
+ strm->internal->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ strm->internal->supported_actions[LZMA_RUN] = false;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = false;
+ strm->internal->supported_actions[LZMA_FULL_FLUSH] = false;
+ strm->internal->supported_actions[LZMA_FINISH] = false;
+ strm->internal->sequence = ISEQ_RUN;
+ strm->internal->allow_buf_error = false;
+
+ strm->total_in = 0;
+ strm->total_out = 0;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_code(lzma_stream *strm, lzma_action action)
+{
+ size_t in_pos = 0;
+ size_t out_pos = 0;
+ lzma_ret ret;
+
+ // Sanity checks
+ if ((strm->next_in == NULL && strm->avail_in != 0)
+ || (strm->next_out == NULL && strm->avail_out != 0)
+ || strm->internal == NULL
+ || strm->internal->next.code == NULL
+ || (unsigned int)(action) > LZMA_FINISH
+ || !strm->internal->supported_actions[action])
+ return LZMA_PROG_ERROR;
+
+ // Check if unsupported members have been set to non-zero or non-NULL,
+ // which would indicate that some new feature is wanted.
+ if (strm->reserved_ptr1 != NULL
+ || strm->reserved_ptr2 != NULL
+ || strm->reserved_ptr3 != NULL
+ || strm->reserved_ptr4 != NULL
+ || strm->reserved_int1 != 0
+ || strm->reserved_int2 != 0
+ || strm->reserved_int3 != 0
+ || strm->reserved_int4 != 0
+ || strm->reserved_enum1 != LZMA_RESERVED_ENUM
+ || strm->reserved_enum2 != LZMA_RESERVED_ENUM)
+ return LZMA_OPTIONS_ERROR;
+
+ switch (strm->internal->sequence) {
+ case ISEQ_RUN:
+ switch (action) {
+ case LZMA_RUN:
+ break;
+
+ case LZMA_SYNC_FLUSH:
+ strm->internal->sequence = ISEQ_SYNC_FLUSH;
+ break;
+
+ case LZMA_FULL_FLUSH:
+ strm->internal->sequence = ISEQ_FULL_FLUSH;
+ break;
+
+ case LZMA_FINISH:
+ strm->internal->sequence = ISEQ_FINISH;
+ break;
+ }
+
+ break;
+
+ case ISEQ_SYNC_FLUSH:
+ // The same action must be used until we return
+ // LZMA_STREAM_END, and the amount of input must not change.
+ if (action != LZMA_SYNC_FLUSH
+ || strm->internal->avail_in != strm->avail_in)
+ return LZMA_PROG_ERROR;
+
+ break;
+
+ case ISEQ_FULL_FLUSH:
+ if (action != LZMA_FULL_FLUSH
+ || strm->internal->avail_in != strm->avail_in)
+ return LZMA_PROG_ERROR;
+
+ break;
+
+ case ISEQ_FINISH:
+ if (action != LZMA_FINISH
+ || strm->internal->avail_in != strm->avail_in)
+ return LZMA_PROG_ERROR;
+
+ break;
+
+ case ISEQ_END:
+ return LZMA_STREAM_END;
+
+ case ISEQ_ERROR:
+ default:
+ return LZMA_PROG_ERROR;
+ }
+
+ ret = strm->internal->next.code(
+ strm->internal->next.coder, strm->allocator,
+ strm->next_in, &in_pos, strm->avail_in,
+ strm->next_out, &out_pos, strm->avail_out, action);
+
+ strm->next_in += in_pos;
+ strm->avail_in -= in_pos;
+ strm->total_in += in_pos;
+
+ strm->next_out += out_pos;
+ strm->avail_out -= out_pos;
+ strm->total_out += out_pos;
+
+ strm->internal->avail_in = strm->avail_in;
+
+ switch (ret) {
+ case LZMA_OK:
+ // Don't return LZMA_BUF_ERROR when it happens the first time.
+ // This is to avoid returning LZMA_BUF_ERROR when avail_out
+ // was zero but still there was no more data left to written
+ // to next_out.
+ if (out_pos == 0 && in_pos == 0) {
+ if (strm->internal->allow_buf_error)
+ ret = LZMA_BUF_ERROR;
+ else
+ strm->internal->allow_buf_error = true;
+ } else {
+ strm->internal->allow_buf_error = false;
+ }
+ break;
+
+ case LZMA_STREAM_END:
+ if (strm->internal->sequence == ISEQ_SYNC_FLUSH
+ || strm->internal->sequence == ISEQ_FULL_FLUSH)
+ strm->internal->sequence = ISEQ_RUN;
+ else
+ strm->internal->sequence = ISEQ_END;
+
+ // Fall through
+
+ case LZMA_NO_CHECK:
+ case LZMA_UNSUPPORTED_CHECK:
+ case LZMA_GET_CHECK:
+ case LZMA_MEMLIMIT_ERROR:
+ // Something else than LZMA_OK, but not a fatal error,
+ // that is, coding may be continued (except if ISEQ_END).
+ strm->internal->allow_buf_error = false;
+ break;
+
+ default:
+ // All the other errors are fatal; coding cannot be continued.
+ assert(ret != LZMA_BUF_ERROR);
+ strm->internal->sequence = ISEQ_ERROR;
+ break;
+ }
+
+ return ret;
+}
+
+
+extern LZMA_API(void)
+lzma_end(lzma_stream *strm)
+{
+ if (strm != NULL && strm->internal != NULL) {
+ lzma_next_end(&strm->internal->next, strm->allocator);
+ lzma_free(strm->internal, strm->allocator);
+ strm->internal = NULL;
+ }
+
+ return;
+}
+
+
+extern LZMA_API(lzma_check)
+lzma_get_check(const lzma_stream *strm)
+{
+ // Return LZMA_CHECK_NONE if we cannot know the check type.
+ // It's a bug in the application if this happens.
+ if (strm->internal->next.get_check == NULL)
+ return LZMA_CHECK_NONE;
+
+ return strm->internal->next.get_check(strm->internal->next.coder);
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_memusage(const lzma_stream *strm)
+{
+ uint64_t memusage;
+ uint64_t old_memlimit;
+
+ if (strm == NULL || strm->internal == NULL
+ || strm->internal->next.memconfig == NULL
+ || strm->internal->next.memconfig(
+ strm->internal->next.coder,
+ &memusage, &old_memlimit, 0) != LZMA_OK)
+ return 0;
+
+ return memusage;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_memlimit_get(const lzma_stream *strm)
+{
+ uint64_t old_memlimit;
+ uint64_t memusage;
+
+ if (strm == NULL || strm->internal == NULL
+ || strm->internal->next.memconfig == NULL
+ || strm->internal->next.memconfig(
+ strm->internal->next.coder,
+ &memusage, &old_memlimit, 0) != LZMA_OK)
+ return 0;
+
+ return old_memlimit;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_memlimit_set(lzma_stream *strm, uint64_t new_memlimit)
+{
+ // Dummy variables to simplify memconfig functions
+ uint64_t old_memlimit;
+ uint64_t memusage;
+
+ if (strm == NULL || strm->internal == NULL
+ || strm->internal->next.memconfig == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (new_memlimit != 0 && new_memlimit < LZMA_MEMUSAGE_BASE)
+ return LZMA_MEMLIMIT_ERROR;
+
+ return strm->internal->next.memconfig(strm->internal->next.coder,
+ &memusage, &old_memlimit, new_memlimit);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/common.h b/Utilities/cmliblzma/liblzma/common/common.h
new file mode 100644
index 000000000..a6a28189e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/common.h
@@ -0,0 +1,305 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file common.h
+/// \brief Definitions common to the whole liblzma library
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_COMMON_H
+#define LZMA_COMMON_H
+
+#include "sysdefs.h"
+#include "tuklib_integer.h"
+
+#if defined(_WIN32) || defined(__CYGWIN__)
+# ifdef DLL_EXPORT
+# define LZMA_API_EXPORT __declspec(dllexport)
+# else
+# define LZMA_API_EXPORT
+# endif
+// Don't use ifdef or defined() below.
+#elif HAVE_VISIBILITY
+# define LZMA_API_EXPORT __attribute__((__visibility__("default")))
+#else
+# define LZMA_API_EXPORT
+#endif
+
+#define LZMA_API(type) LZMA_API_EXPORT type LZMA_API_CALL
+
+#include "lzma.h"
+
+// These allow helping the compiler in some often-executed branches, whose
+// result is almost always the same.
+#ifdef __GNUC__
+# define likely(expr) __builtin_expect(expr, true)
+# define unlikely(expr) __builtin_expect(expr, false)
+#else
+# define likely(expr) (expr)
+# define unlikely(expr) (expr)
+#endif
+
+
+/// Size of temporary buffers needed in some filters
+#define LZMA_BUFFER_SIZE 4096
+
+
+/// Starting value for memory usage estimates. Instead of calculating size
+/// of _every_ structure and taking into account malloc() overhead etc., we
+/// add a base size to all memory usage estimates. It's not very accurate
+/// but should be easily good enough.
+#define LZMA_MEMUSAGE_BASE (UINT64_C(1) << 15)
+
+/// Start of internal Filter ID space. These IDs must never be used
+/// in Streams.
+#define LZMA_FILTER_RESERVED_START (LZMA_VLI_C(1) << 62)
+
+
+/// Supported flags that can be passed to lzma_stream_decoder()
+/// or lzma_auto_decoder().
+#define LZMA_SUPPORTED_FLAGS \
+ ( LZMA_TELL_NO_CHECK \
+ | LZMA_TELL_UNSUPPORTED_CHECK \
+ | LZMA_TELL_ANY_CHECK \
+ | LZMA_CONCATENATED )
+
+
+/// Type of encoder/decoder specific data; the actual structure is defined
+/// differently in different coders.
+typedef struct lzma_coder_s lzma_coder;
+
+typedef struct lzma_next_coder_s lzma_next_coder;
+
+typedef struct lzma_filter_info_s lzma_filter_info;
+
+
+/// Type of a function used to initialize a filter encoder or decoder
+typedef lzma_ret (*lzma_init_function)(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters);
+
+/// Type of a function to do some kind of coding work (filters, Stream,
+/// Block encoders/decoders etc.). Some special coders use don't use both
+/// input and output buffers, but for simplicity they still use this same
+/// function prototype.
+typedef lzma_ret (*lzma_code_function)(
+ lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size,
+ lzma_action action);
+
+/// Type of a function to free the memory allocated for the coder
+typedef void (*lzma_end_function)(
+ lzma_coder *coder, lzma_allocator *allocator);
+
+
+/// Raw coder validates and converts an array of lzma_filter structures to
+/// an array of lzma_filter_info structures. This array is used with
+/// lzma_next_filter_init to initialize the filter chain.
+struct lzma_filter_info_s {
+ /// Filter ID. This is used only by the encoder
+ /// with lzma_filters_update().
+ lzma_vli id;
+
+ /// Pointer to function used to initialize the filter.
+ /// This is NULL to indicate end of array.
+ lzma_init_function init;
+
+ /// Pointer to filter's options structure
+ void *options;
+};
+
+
+/// Hold data and function pointers of the next filter in the chain.
+struct lzma_next_coder_s {
+ /// Pointer to coder-specific data
+ lzma_coder *coder;
+
+ /// Filter ID. This is LZMA_VLI_UNKNOWN when this structure doesn't
+ /// point to a filter coder.
+ lzma_vli id;
+
+ /// "Pointer" to init function. This is never called here.
+ /// We need only to detect if we are initializing a coder
+ /// that was allocated earlier. See lzma_next_coder_init and
+ /// lzma_next_strm_init macros in this file.
+ uintptr_t init;
+
+ /// Pointer to function to do the actual coding
+ lzma_code_function code;
+
+ /// Pointer to function to free lzma_next_coder.coder. This can
+ /// be NULL; in that case, lzma_free is called to free
+ /// lzma_next_coder.coder.
+ lzma_end_function end;
+
+ /// Pointer to function to return the type of the integrity check.
+ /// Most coders won't support this.
+ lzma_check (*get_check)(const lzma_coder *coder);
+
+ /// Pointer to function to get and/or change the memory usage limit.
+ /// If new_memlimit == 0, the limit is not changed.
+ lzma_ret (*memconfig)(lzma_coder *coder, uint64_t *memusage,
+ uint64_t *old_memlimit, uint64_t new_memlimit);
+
+ /// Update the filter-specific options or the whole filter chain
+ /// in the encoder.
+ lzma_ret (*update)(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters,
+ const lzma_filter *reversed_filters);
+};
+
+
+/// Constant to initialize lzma_next_coder structure
+static const lzma_next_coder LZMA_NEXT_CODER_INIT =
+ {
+ NULL,
+ LZMA_VLI_UNKNOWN,
+ (uintptr_t)(NULL),
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ };
+
+
+/// Internal data for lzma_strm_init, lzma_code, and lzma_end. A pointer to
+/// this is stored in lzma_stream.
+struct lzma_internal_s {
+ /// The actual coder that should do something useful
+ lzma_next_coder next;
+
+ /// Track the state of the coder. This is used to validate arguments
+ /// so that the actual coders can rely on e.g. that LZMA_SYNC_FLUSH
+ /// is used on every call to lzma_code until next.code has returned
+ /// LZMA_STREAM_END.
+ enum {
+ ISEQ_RUN,
+ ISEQ_SYNC_FLUSH,
+ ISEQ_FULL_FLUSH,
+ ISEQ_FINISH,
+ ISEQ_END,
+ ISEQ_ERROR,
+ } sequence;
+
+ /// A copy of lzma_stream avail_in. This is used to verify that the
+ /// amount of input doesn't change once e.g. LZMA_FINISH has been
+ /// used.
+ size_t avail_in;
+
+ /// Indicates which lzma_action values are allowed by next.code.
+ bool supported_actions[4];
+
+ /// If true, lzma_code will return LZMA_BUF_ERROR if no progress was
+ /// made (no input consumed and no output produced by next.code).
+ bool allow_buf_error;
+};
+
+
+/// Allocates memory
+extern void *lzma_alloc(size_t size, lzma_allocator *allocator)
+ lzma_attribute((__malloc__)) lzma_attr_alloc_size(1);
+
+/// Frees memory
+extern void lzma_free(void *ptr, lzma_allocator *allocator);
+
+
+/// Allocates strm->internal if it is NULL, and initializes *strm and
+/// strm->internal. This function is only called via lzma_next_strm_init2 macro.
+extern lzma_ret lzma_strm_init(lzma_stream *strm);
+
+/// Initializes the next filter in the chain, if any. This takes care of
+/// freeing the memory of previously initialized filter if it is different
+/// than the filter being initialized now. This way the actual filter
+/// initialization functions don't need to use lzma_next_coder_init macro.
+extern lzma_ret lzma_next_filter_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+/// Update the next filter in the chain, if any. This checks that
+/// the application is not trying to change the Filter IDs.
+extern lzma_ret lzma_next_filter_update(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *reversed_filters);
+
+/// Frees the memory allocated for next->coder either using next->end or,
+/// if next->end is NULL, using lzma_free.
+extern void lzma_next_end(lzma_next_coder *next, lzma_allocator *allocator);
+
+
+/// Copy as much data as possible from in[] to out[] and update *in_pos
+/// and *out_pos accordingly. Returns the number of bytes copied.
+extern size_t lzma_bufcpy(const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size);
+
+
+/// \brief Return if expression doesn't evaluate to LZMA_OK
+///
+/// There are several situations where we want to return immediately
+/// with the value of expr if it isn't LZMA_OK. This macro shortens
+/// the code a little.
+#define return_if_error(expr) \
+do { \
+ const lzma_ret ret_ = (expr); \
+ if (ret_ != LZMA_OK) \
+ return ret_; \
+} while (0)
+
+
+/// If next isn't already initialized, free the previous coder. Then mark
+/// that next is _possibly_ initialized for the coder using this macro.
+/// "Possibly" means that if e.g. allocation of next->coder fails, the
+/// structure isn't actually initialized for this coder, but leaving
+/// next->init to func is still OK.
+#define lzma_next_coder_init(func, next, allocator) \
+do { \
+ if ((uintptr_t)(func) != (next)->init) \
+ lzma_next_end(next, allocator); \
+ (next)->init = (uintptr_t)(func); \
+} while (0)
+
+
+/// Initializes lzma_strm and calls func() to initialize strm->internal->next.
+/// (The function being called will use lzma_next_coder_init()). If
+/// initialization fails, memory that wasn't freed by func() is freed
+/// along strm->internal.
+#define lzma_next_strm_init1(func, strm, arg1) \
+do { \
+ lzma_ret ret_; \
+ return_if_error(lzma_strm_init(strm)); \
+ ret_ = func(&(strm)->internal->next, (strm)->allocator, arg1); \
+ if (ret_ != LZMA_OK) { \
+ lzma_end(strm); \
+ return ret_; \
+ } \
+} while (0)
+
+#define lzma_next_strm_init2(func, strm, arg1, arg2) \
+do { \
+ lzma_ret ret_; \
+ return_if_error(lzma_strm_init(strm)); \
+ ret_ = func(&(strm)->internal->next, (strm)->allocator, arg1, arg2); \
+ if (ret_ != LZMA_OK) { \
+ lzma_end(strm); \
+ return ret_; \
+ } \
+} while (0)
+
+#define lzma_next_strm_init3(func, strm, arg1, arg2, arg3) \
+do { \
+ lzma_ret ret_; \
+ return_if_error(lzma_strm_init(strm)); \
+ ret_ = func(&(strm)->internal->next, (strm)->allocator, arg1, arg2, arg3); \
+ if (ret_ != LZMA_OK) { \
+ lzma_end(strm); \
+ return ret_; \
+ } \
+} while (0)
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/easy_buffer_encoder.c b/Utilities/cmliblzma/liblzma/common/easy_buffer_encoder.c
new file mode 100644
index 000000000..c4be34ccf
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_buffer_encoder.c
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_buffer_encoder.c
+/// \brief Easy single-call .xz Stream encoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_easy_buffer_encode(uint32_t preset, lzma_check check,
+ lzma_allocator *allocator, const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ lzma_options_easy opt_easy;
+ if (lzma_easy_preset(&opt_easy, preset))
+ return LZMA_OPTIONS_ERROR;
+
+ return lzma_stream_buffer_encode(opt_easy.filters, check,
+ allocator, in, in_size, out, out_pos, out_size);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/easy_decoder_memusage.c b/Utilities/cmliblzma/liblzma/common/easy_decoder_memusage.c
new file mode 100644
index 000000000..20bcd5b71
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_decoder_memusage.c
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_decoder_memusage.c
+/// \brief Decoder memory usage calculation to match easy encoder presets
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_easy_decoder_memusage(uint32_t preset)
+{
+ lzma_options_easy opt_easy;
+ if (lzma_easy_preset(&opt_easy, preset))
+ return UINT32_MAX;
+
+ return lzma_raw_decoder_memusage(opt_easy.filters);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/easy_encoder.c b/Utilities/cmliblzma/liblzma/common/easy_encoder.c
new file mode 100644
index 000000000..d13ccd735
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_encoder.c
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_encoder.c
+/// \brief Easy .xz Stream encoder initialization
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+#include "stream_encoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_easy_encoder(lzma_stream *strm, uint32_t preset, lzma_check check)
+{
+ lzma_options_easy opt_easy;
+ if (lzma_easy_preset(&opt_easy, preset))
+ return LZMA_OPTIONS_ERROR;
+
+ return lzma_stream_encoder(strm, opt_easy.filters, check);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/easy_encoder_memusage.c b/Utilities/cmliblzma/liblzma/common/easy_encoder_memusage.c
new file mode 100644
index 000000000..e91057584
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_encoder_memusage.c
@@ -0,0 +1,24 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_encoder_memusage.c
+/// \brief Easy .xz Stream encoder memory usage calculation
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_easy_encoder_memusage(uint32_t preset)
+{
+ lzma_options_easy opt_easy;
+ if (lzma_easy_preset(&opt_easy, preset))
+ return UINT32_MAX;
+
+ return lzma_raw_encoder_memusage(opt_easy.filters);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/easy_preset.c b/Utilities/cmliblzma/liblzma/common/easy_preset.c
new file mode 100644
index 000000000..2f9859860
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_preset.c
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_preset.c
+/// \brief Preset handling for easy encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "easy_preset.h"
+
+
+extern bool
+lzma_easy_preset(lzma_options_easy *opt_easy, uint32_t preset)
+{
+ if (lzma_lzma_preset(&opt_easy->opt_lzma, preset))
+ return true;
+
+ opt_easy->filters[0].id = LZMA_FILTER_LZMA2;
+ opt_easy->filters[0].options = &opt_easy->opt_lzma;
+ opt_easy->filters[1].id = LZMA_VLI_UNKNOWN;
+
+ return false;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/easy_preset.h b/Utilities/cmliblzma/liblzma/common/easy_preset.h
new file mode 100644
index 000000000..382ade894
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/easy_preset.h
@@ -0,0 +1,32 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file easy_preset.h
+/// \brief Preset handling for easy encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+typedef struct {
+ /// We need to keep the filters array available in case
+ /// LZMA_FULL_FLUSH is used.
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+ /// Options for LZMA2
+ lzma_options_lzma opt_lzma;
+
+ // Options for more filters can be added later, so this struct
+ // is not ready to be put into the public API.
+
+} lzma_options_easy;
+
+
+/// Set *easy to the settings given by the preset. Returns true on error,
+/// false on success.
+extern bool lzma_easy_preset(lzma_options_easy *easy, uint32_t preset);
diff --git a/Utilities/cmliblzma/liblzma/common/filter_buffer_decoder.c b/Utilities/cmliblzma/liblzma/common/filter_buffer_decoder.c
new file mode 100644
index 000000000..65665c17d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_buffer_decoder.c
@@ -0,0 +1,91 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_buffer_decoder.c
+/// \brief Single-call raw decoding
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_buffer_decode(const lzma_filter *filters, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ lzma_next_coder next = LZMA_NEXT_CODER_INIT;
+ size_t in_start;
+ size_t out_start;
+ lzma_ret ret;
+
+ // Validate what isn't validated later in filter_common.c.
+ if (in == NULL || in_pos == NULL || *in_pos > in_size || out == NULL
+ || out_pos == NULL || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // Initialize the decoer.
+ return_if_error(lzma_raw_decoder_init(&next, allocator, filters));
+
+ // Store the positions so that we can restore them if something
+ // goes wrong.
+ in_start = *in_pos;
+ out_start = *out_pos;
+
+ // Do the actual decoding and free decoder's memory.
+ ret = next.code(next.coder, allocator, in, in_pos, in_size,
+ out, out_pos, out_size, LZMA_FINISH);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ if (ret == LZMA_OK) {
+ // Either the input was truncated or the
+ // output buffer was too small.
+ assert(*in_pos == in_size || *out_pos == out_size);
+
+ if (*in_pos != in_size) {
+ // Since input wasn't consumed completely,
+ // the output buffer became full and is
+ // too small.
+ ret = LZMA_BUF_ERROR;
+
+ } else if (*out_pos != out_size) {
+ // Since output didn't became full, the input
+ // has to be truncated.
+ ret = LZMA_DATA_ERROR;
+
+ } else {
+ // All the input was consumed and output
+ // buffer is full. Now we don't immediately
+ // know the reason for the error. Try
+ // decoding one more byte. If it succeeds,
+ // then the output buffer was too small. If
+ // we cannot get a new output byte, the input
+ // is truncated.
+ uint8_t tmp[1];
+ size_t tmp_pos = 0;
+ (void)next.code(next.coder, allocator,
+ in, in_pos, in_size,
+ tmp, &tmp_pos, 1, LZMA_FINISH);
+
+ if (tmp_pos == 1)
+ ret = LZMA_BUF_ERROR;
+ else
+ ret = LZMA_DATA_ERROR;
+ }
+ }
+
+ // Restore the positions.
+ *in_pos = in_start;
+ *out_pos = out_start;
+ }
+
+ lzma_next_end(&next, allocator);
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_buffer_encoder.c b/Utilities/cmliblzma/liblzma/common/filter_buffer_encoder.c
new file mode 100644
index 000000000..b23329f3e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_buffer_encoder.c
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_buffer_encoder.c
+/// \brief Single-call raw encoding
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_buffer_encode(const lzma_filter *filters, lzma_allocator *allocator,
+ const uint8_t *in, size_t in_size, uint8_t *out,
+ size_t *out_pos, size_t out_size)
+{
+ lzma_next_coder next = LZMA_NEXT_CODER_INIT;
+ size_t out_start;
+ size_t in_pos = 0;
+ lzma_ret ret;
+
+ // Validate what isn't validated later in filter_common.c.
+ if ((in == NULL && in_size != 0) || out == NULL
+ || out_pos == NULL || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // Initialize the encoder
+ return_if_error(lzma_raw_encoder_init(&next, allocator, filters));
+
+ // Store the output position so that we can restore it if
+ // something goes wrong.
+ out_start = *out_pos;
+
+ // Do the actual encoding and free coder's memory.
+ ret = next.code(next.coder, allocator, in, &in_pos, in_size,
+ out, out_pos, out_size, LZMA_FINISH);
+ lzma_next_end(&next, allocator);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ if (ret == LZMA_OK) {
+ // Output buffer was too small.
+ assert(*out_pos == out_size);
+ ret = LZMA_BUF_ERROR;
+ }
+
+ // Restore the output position.
+ *out_pos = out_start;
+ }
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_common.c b/Utilities/cmliblzma/liblzma/common/filter_common.c
new file mode 100644
index 000000000..d2b9e086e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_common.c
@@ -0,0 +1,342 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_common.c
+/// \brief Filter-specific stuff common for both encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_common.h"
+
+
+static const struct {
+ /// Filter ID
+ lzma_vli id;
+
+ /// Size of the filter-specific options structure
+ size_t options_size;
+
+ /// True if it is OK to use this filter as non-last filter in
+ /// the chain.
+ bool non_last_ok;
+
+ /// True if it is OK to use this filter as the last filter in
+ /// the chain.
+ bool last_ok;
+
+ /// True if the filter may change the size of the data (that is, the
+ /// amount of encoded output can be different than the amount of
+ /// uncompressed input).
+ bool changes_size;
+
+} features[] = {
+#if defined (HAVE_ENCODER_LZMA1) || defined(HAVE_DECODER_LZMA1)
+ {
+ LZMA_FILTER_LZMA1,
+ sizeof(lzma_options_lzma),
+ false,
+ true,
+ true,
+ },
+#endif
+#if defined(HAVE_ENCODER_LZMA2) || defined(HAVE_DECODER_LZMA2)
+ {
+ LZMA_FILTER_LZMA2,
+ sizeof(lzma_options_lzma),
+ false,
+ true,
+ true,
+ },
+#endif
+#if defined(HAVE_ENCODER_X86) || defined(HAVE_DECODER_X86)
+ {
+ LZMA_FILTER_X86,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_POWERPC) || defined(HAVE_DECODER_POWERPC)
+ {
+ LZMA_FILTER_POWERPC,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_IA64) || defined(HAVE_DECODER_IA64)
+ {
+ LZMA_FILTER_IA64,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_ARM) || defined(HAVE_DECODER_ARM)
+ {
+ LZMA_FILTER_ARM,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_ARMTHUMB) || defined(HAVE_DECODER_ARMTHUMB)
+ {
+ LZMA_FILTER_ARMTHUMB,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_SPARC) || defined(HAVE_DECODER_SPARC)
+ {
+ LZMA_FILTER_SPARC,
+ sizeof(lzma_options_bcj),
+ true,
+ false,
+ false,
+ },
+#endif
+#if defined(HAVE_ENCODER_DELTA) || defined(HAVE_DECODER_DELTA)
+ {
+ LZMA_FILTER_DELTA,
+ sizeof(lzma_options_delta),
+ true,
+ false,
+ false,
+ },
+#endif
+ {
+ LZMA_VLI_UNKNOWN
+ }
+};
+
+
+extern LZMA_API(lzma_ret)
+lzma_filters_copy(const lzma_filter *src, lzma_filter *dest,
+ lzma_allocator *allocator)
+{
+ size_t i;
+ lzma_ret ret;
+
+ if (src == NULL || dest == NULL)
+ return LZMA_PROG_ERROR;
+
+ for (i = 0; src[i].id != LZMA_VLI_UNKNOWN; ++i) {
+ // There must be a maximum of four filters plus
+ // the array terminator.
+ if (i == LZMA_FILTERS_MAX) {
+ ret = LZMA_OPTIONS_ERROR;
+ goto error;
+ }
+
+ dest[i].id = src[i].id;
+
+ if (src[i].options == NULL) {
+ dest[i].options = NULL;
+ } else {
+ // See if the filter is supported only when the
+ // options is not NULL. This might be convenient
+ // sometimes if the app is actually copying only
+ // a partial filter chain with a place holder ID.
+ //
+ // When options is not NULL, the Filter ID must be
+ // supported by us, because otherwise we don't know
+ // how big the options are.
+ size_t j;
+ for (j = 0; src[i].id != features[j].id; ++j) {
+ if (features[j].id == LZMA_VLI_UNKNOWN) {
+ ret = LZMA_OPTIONS_ERROR;
+ goto error;
+ }
+ }
+
+ // Allocate and copy the options.
+ dest[i].options = lzma_alloc(features[j].options_size,
+ allocator);
+ if (dest[i].options == NULL) {
+ ret = LZMA_MEM_ERROR;
+ goto error;
+ }
+
+ memcpy(dest[i].options, src[i].options,
+ features[j].options_size);
+ }
+ }
+
+ // Terminate the filter array.
+ assert(i <= LZMA_FILTERS_MAX + 1);
+ dest[i].id = LZMA_VLI_UNKNOWN;
+ dest[i].options = NULL;
+
+ return LZMA_OK;
+
+error:
+ // Free the options which we have already allocated.
+ while (i-- > 0) {
+ lzma_free(dest[i].options, allocator);
+ dest[i].options = NULL;
+ }
+
+ return ret;
+}
+
+
+static lzma_ret
+validate_chain(const lzma_filter *filters, size_t *count)
+{
+ // Number of non-last filters that may change the size of the data
+ // significantly (that is, more than 1-2 % or so).
+ size_t changes_size_count = 0;
+
+ // True if it is OK to add a new filter after the current filter.
+ bool non_last_ok = true;
+
+ // True if the last filter in the given chain is actually usable as
+ // the last filter. Only filters that support embedding End of Payload
+ // Marker can be used as the last filter in the chain.
+ bool last_ok = false;
+
+ size_t i = 0;
+
+ // There must be at least one filter.
+ if (filters == NULL || filters[0].id == LZMA_VLI_UNKNOWN)
+ return LZMA_PROG_ERROR;
+
+ do {
+ size_t j;
+ for (j = 0; filters[i].id != features[j].id; ++j)
+ if (features[j].id == LZMA_VLI_UNKNOWN)
+ return LZMA_OPTIONS_ERROR;
+
+ // If the previous filter in the chain cannot be a non-last
+ // filter, the chain is invalid.
+ if (!non_last_ok)
+ return LZMA_OPTIONS_ERROR;
+
+ non_last_ok = features[j].non_last_ok;
+ last_ok = features[j].last_ok;
+ changes_size_count += features[j].changes_size;
+
+ } while (filters[++i].id != LZMA_VLI_UNKNOWN);
+
+ // There must be 1-4 filters. The last filter must be usable as
+ // the last filter in the chain. A maximum of three filters are
+ // allowed to change the size of the data.
+ if (i > LZMA_FILTERS_MAX || !last_ok || changes_size_count > 3)
+ return LZMA_OPTIONS_ERROR;
+
+ *count = i;
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_raw_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *options,
+ lzma_filter_find coder_find, bool is_encoder)
+{
+ lzma_filter_info filters[LZMA_FILTERS_MAX + 1];
+ size_t count;
+ size_t i;
+ lzma_ret ret;
+
+ // Do some basic validation and get the number of filters.
+ return_if_error(validate_chain(options, &count));
+
+ // Set the filter functions and copy the options pointer.
+ if (is_encoder) {
+ for (i = 0; i < count; ++i) {
+ // The order of the filters is reversed in the
+ // encoder. It allows more efficient handling
+ // of the uncompressed data.
+ const size_t j = count - i - 1;
+
+ const lzma_filter_coder *const fc
+ = coder_find(options[i].id);
+ if (fc == NULL || fc->init == NULL)
+ return LZMA_OPTIONS_ERROR;
+
+ filters[j].id = options[i].id;
+ filters[j].init = fc->init;
+ filters[j].options = options[i].options;
+ }
+ } else {
+ for (i = 0; i < count; ++i) {
+ const lzma_filter_coder *const fc
+ = coder_find(options[i].id);
+ if (fc == NULL || fc->init == NULL)
+ return LZMA_OPTIONS_ERROR;
+
+ filters[i].id = options[i].id;
+ filters[i].init = fc->init;
+ filters[i].options = options[i].options;
+ }
+ }
+
+ // Terminate the array.
+ filters[count].id = LZMA_VLI_UNKNOWN;
+ filters[count].init = NULL;
+
+ // Initialize the filters.
+ ret = lzma_next_filter_init(next, allocator, filters);
+ if (ret != LZMA_OK)
+ lzma_next_end(next, allocator);
+
+ return ret;
+}
+
+
+extern uint64_t
+lzma_raw_coder_memusage(lzma_filter_find coder_find,
+ const lzma_filter *filters)
+{
+ uint64_t total = 0;
+ size_t i = 0;
+
+ // The chain has to have at least one filter.
+ {
+ size_t tmp;
+ if (validate_chain(filters, &tmp) != LZMA_OK)
+ return UINT64_MAX;
+ }
+
+ do {
+ const lzma_filter_coder *const fc
+ = coder_find(filters[i].id);
+ if (fc == NULL)
+ return UINT64_MAX; // Unsupported Filter ID
+
+ if (fc->memusage == NULL) {
+ // This filter doesn't have a function to calculate
+ // the memory usage and validate the options. Such
+ // filters need only little memory, so we use 1 KiB
+ // as a good estimate. They also accept all possible
+ // options, so there's no need to worry about lack
+ // of validation.
+ total += 1024;
+ } else {
+ // Call the filter-specific memory usage calculation
+ // function.
+ const uint64_t usage
+ = fc->memusage(filters[i].options);
+ if (usage == UINT64_MAX)
+ return UINT64_MAX; // Invalid options
+
+ total += usage;
+ }
+ } while (filters[++i].id != LZMA_VLI_UNKNOWN);
+
+ // Add some fixed amount of extra. It's to compensate memory usage
+ // of Stream, Block etc. coders, malloc() overhead, stack etc.
+ return total + LZMA_MEMUSAGE_BASE;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_common.h b/Utilities/cmliblzma/liblzma/common/filter_common.h
new file mode 100644
index 000000000..cd61fc072
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_common.h
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_common.c
+/// \brief Filter-specific stuff common for both encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_COMMON_H
+#define LZMA_FILTER_COMMON_H
+
+#include "common.h"
+
+
+/// Both lzma_filter_encoder and lzma_filter_decoder begin with these members.
+typedef struct {
+ /// Filter ID
+ lzma_vli id;
+
+ /// Initializes the filter encoder and calls lzma_next_filter_init()
+ /// for filters + 1.
+ lzma_init_function init;
+
+ /// Calculates memory usage of the encoder. If the options are
+ /// invalid, UINT64_MAX is returned.
+ uint64_t (*memusage)(const void *options);
+
+} lzma_filter_coder;
+
+
+typedef const lzma_filter_coder *(*lzma_filter_find)(lzma_vli id);
+
+
+extern lzma_ret lzma_raw_coder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *filters,
+ lzma_filter_find coder_find, bool is_encoder);
+
+
+extern uint64_t lzma_raw_coder_memusage(lzma_filter_find coder_find,
+ const lzma_filter *filters);
+
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/filter_decoder.c b/Utilities/cmliblzma/liblzma/common/filter_decoder.c
new file mode 100644
index 000000000..cce2b30ea
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_decoder.c
@@ -0,0 +1,185 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_decoder.c
+/// \brief Filter ID mapping to filter-specific functions
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+#include "filter_common.h"
+#include "lzma_decoder.h"
+#include "lzma2_decoder.h"
+#include "simple_decoder.h"
+#include "delta_decoder.h"
+
+
+typedef struct {
+ /// Filter ID
+ lzma_vli id;
+
+ /// Initializes the filter encoder and calls lzma_next_filter_init()
+ /// for filters + 1.
+ lzma_init_function init;
+
+ /// Calculates memory usage of the encoder. If the options are
+ /// invalid, UINT64_MAX is returned.
+ uint64_t (*memusage)(const void *options);
+
+ /// Decodes Filter Properties.
+ ///
+ /// \return - LZMA_OK: Properties decoded successfully.
+ /// - LZMA_OPTIONS_ERROR: Unsupported properties
+ /// - LZMA_MEM_ERROR: Memory allocation failed.
+ lzma_ret (*props_decode)(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+} lzma_filter_decoder;
+
+
+static const lzma_filter_decoder decoders[] = {
+#ifdef HAVE_DECODER_LZMA1
+ {
+ LZMA_FILTER_LZMA1,
+ &lzma_lzma_decoder_init,
+ &lzma_lzma_decoder_memusage,
+ &lzma_lzma_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_LZMA2
+ {
+ LZMA_FILTER_LZMA2,
+ &lzma_lzma2_decoder_init,
+ &lzma_lzma2_decoder_memusage,
+ &lzma_lzma2_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_X86
+ {
+ LZMA_FILTER_X86,
+ &lzma_simple_x86_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_POWERPC
+ {
+ LZMA_FILTER_POWERPC,
+ &lzma_simple_powerpc_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_IA64
+ {
+ LZMA_FILTER_IA64,
+ &lzma_simple_ia64_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_ARM
+ {
+ LZMA_FILTER_ARM,
+ &lzma_simple_arm_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_ARMTHUMB
+ {
+ LZMA_FILTER_ARMTHUMB,
+ &lzma_simple_armthumb_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_SPARC
+ {
+ LZMA_FILTER_SPARC,
+ &lzma_simple_sparc_decoder_init,
+ NULL,
+ &lzma_simple_props_decode,
+ },
+#endif
+#ifdef HAVE_DECODER_DELTA
+ {
+ LZMA_FILTER_DELTA,
+ &lzma_delta_decoder_init,
+ &lzma_delta_coder_memusage,
+ &lzma_delta_props_decode,
+ },
+#endif
+};
+
+
+static const lzma_filter_decoder *
+decoder_find(lzma_vli id)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(decoders); ++i)
+ if (decoders[i].id == id)
+ return decoders + i;
+
+ return NULL;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_filter_decoder_is_supported(lzma_vli id)
+{
+ return decoder_find(id) != NULL;
+}
+
+
+extern lzma_ret
+lzma_raw_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *options)
+{
+ return lzma_raw_coder_init(next, allocator,
+ options, (lzma_filter_find)(&decoder_find), false);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_decoder(lzma_stream *strm, const lzma_filter *options)
+{
+ lzma_next_strm_init1(lzma_raw_decoder_init, strm, options);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_raw_decoder_memusage(const lzma_filter *filters)
+{
+ return lzma_raw_coder_memusage(
+ (lzma_filter_find)(&decoder_find), filters);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_decode(lzma_filter *filter, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ const lzma_filter_decoder *const fd = decoder_find(filter->id);
+
+ // Make it always NULL so that the caller can always safely free() it.
+ filter->options = NULL;
+
+ if (fd == NULL)
+ return LZMA_OPTIONS_ERROR;
+
+ if (fd->props_decode == NULL)
+ return props_size == 0 ? LZMA_OK : LZMA_OPTIONS_ERROR;
+
+ return fd->props_decode(
+ &filter->options, allocator, props, props_size);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_decoder.h b/Utilities/cmliblzma/liblzma/common/filter_decoder.h
new file mode 100644
index 000000000..d5c68bdd4
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_decoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_decoder.c
+/// \brief Filter ID mapping to filter-specific functions
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_DECODER_H
+#define LZMA_FILTER_DECODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_raw_decoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *options);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/filter_encoder.c b/Utilities/cmliblzma/liblzma/common/filter_encoder.c
new file mode 100644
index 000000000..9fdb10008
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_encoder.c
@@ -0,0 +1,297 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_decoder.c
+/// \brief Filter ID mapping to filter-specific functions
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+#include "filter_common.h"
+#include "lzma_encoder.h"
+#include "lzma2_encoder.h"
+#include "simple_encoder.h"
+#include "delta_encoder.h"
+
+
+typedef struct {
+ /// Filter ID
+ lzma_vli id;
+
+ /// Initializes the filter encoder and calls lzma_next_filter_init()
+ /// for filters + 1.
+ lzma_init_function init;
+
+ /// Calculates memory usage of the encoder. If the options are
+ /// invalid, UINT64_MAX is returned.
+ uint64_t (*memusage)(const void *options);
+
+ /// Calculates the minimum sane size for Blocks (or other types of
+ /// chunks) to which the input data can be split to make
+ /// multithreaded encoding possible. If this is NULL, it is assumed
+ /// that the encoder is fast enough with single thread.
+ lzma_vli (*chunk_size)(const void *options);
+
+ /// Tells the size of the Filter Properties field. If options are
+ /// invalid, UINT32_MAX is returned. If this is NULL, props_size_fixed
+ /// is used.
+ lzma_ret (*props_size_get)(uint32_t *size, const void *options);
+ uint32_t props_size_fixed;
+
+ /// Encodes Filter Properties.
+ ///
+ /// \return - LZMA_OK: Properties encoded successfully.
+ /// - LZMA_OPTIONS_ERROR: Unsupported options
+ /// - LZMA_PROG_ERROR: Invalid options or not enough
+ /// output space
+ lzma_ret (*props_encode)(const void *options, uint8_t *out);
+
+} lzma_filter_encoder;
+
+
+static const lzma_filter_encoder encoders[] = {
+#ifdef HAVE_ENCODER_LZMA1
+ {
+ LZMA_FILTER_LZMA1,
+ &lzma_lzma_encoder_init,
+ &lzma_lzma_encoder_memusage,
+ NULL, // FIXME
+ NULL,
+ 5,
+ &lzma_lzma_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_LZMA2
+ {
+ LZMA_FILTER_LZMA2,
+ &lzma_lzma2_encoder_init,
+ &lzma_lzma2_encoder_memusage,
+ NULL, // FIXME
+ NULL,
+ 1,
+ &lzma_lzma2_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_X86
+ {
+ LZMA_FILTER_X86,
+ &lzma_simple_x86_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_POWERPC
+ {
+ LZMA_FILTER_POWERPC,
+ &lzma_simple_powerpc_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_IA64
+ {
+ LZMA_FILTER_IA64,
+ &lzma_simple_ia64_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_ARM
+ {
+ LZMA_FILTER_ARM,
+ &lzma_simple_arm_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_ARMTHUMB
+ {
+ LZMA_FILTER_ARMTHUMB,
+ &lzma_simple_armthumb_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_SPARC
+ {
+ LZMA_FILTER_SPARC,
+ &lzma_simple_sparc_encoder_init,
+ NULL,
+ NULL,
+ &lzma_simple_props_size,
+ 0,
+ &lzma_simple_props_encode,
+ },
+#endif
+#ifdef HAVE_ENCODER_DELTA
+ {
+ LZMA_FILTER_DELTA,
+ &lzma_delta_encoder_init,
+ &lzma_delta_coder_memusage,
+ NULL,
+ NULL,
+ 1,
+ &lzma_delta_props_encode,
+ },
+#endif
+};
+
+
+static const lzma_filter_encoder *
+encoder_find(lzma_vli id)
+{
+ size_t i;
+ for (i = 0; i < ARRAY_SIZE(encoders); ++i)
+ if (encoders[i].id == id)
+ return encoders + i;
+
+ return NULL;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_filter_encoder_is_supported(lzma_vli id)
+{
+ return encoder_find(id) != NULL;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_filters_update(lzma_stream *strm, const lzma_filter *filters)
+{
+ size_t i;
+ size_t count = 1;
+ lzma_filter reversed_filters[LZMA_FILTERS_MAX + 1];
+
+ if (strm->internal->next.update == NULL)
+ return LZMA_PROG_ERROR;
+
+ // Validate the filter chain.
+ if (lzma_raw_encoder_memusage(filters) == UINT64_MAX)
+ return LZMA_OPTIONS_ERROR;
+
+ // The actual filter chain in the encoder is reversed. Some things
+ // still want the normal order chain, so we provide both.
+ while (filters[count].id != LZMA_VLI_UNKNOWN)
+ ++count;
+
+ for (i = 0; i < count; ++i)
+ reversed_filters[count - i - 1] = filters[i];
+
+ reversed_filters[count].id = LZMA_VLI_UNKNOWN;
+
+ return strm->internal->next.update(strm->internal->next.coder,
+ strm->allocator, filters, reversed_filters);
+}
+
+
+extern lzma_ret
+lzma_raw_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *options)
+{
+ return lzma_raw_coder_init(next, allocator,
+ options, (lzma_filter_find)(&encoder_find), true);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_raw_encoder(lzma_stream *strm, const lzma_filter *options)
+{
+ lzma_next_strm_init3(lzma_raw_coder_init, strm, options,
+ (lzma_filter_find)(&encoder_find), true);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_raw_encoder_memusage(const lzma_filter *filters)
+{
+ return lzma_raw_coder_memusage(
+ (lzma_filter_find)(&encoder_find), filters);
+}
+
+
+/*
+extern LZMA_API(lzma_vli)
+lzma_chunk_size(const lzma_filter *filters)
+{
+ lzma_vli max = 0;
+
+ for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) {
+ const lzma_filter_encoder *const fe
+ = encoder_find(filters[i].id);
+ if (fe->chunk_size != NULL) {
+ const lzma_vli size
+ = fe->chunk_size(filters[i].options);
+ if (size == LZMA_VLI_UNKNOWN)
+ return LZMA_VLI_UNKNOWN;
+
+ if (size > max)
+ max = size;
+ }
+ }
+
+ return max;
+}
+*/
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_size(uint32_t *size, const lzma_filter *filter)
+{
+ const lzma_filter_encoder *const fe = encoder_find(filter->id);
+ if (fe == NULL) {
+ // Unknown filter - if the Filter ID is a proper VLI,
+ // return LZMA_OPTIONS_ERROR instead of LZMA_PROG_ERROR,
+ // because it's possible that we just don't have support
+ // compiled in for the requested filter.
+ return filter->id <= LZMA_VLI_MAX
+ ? LZMA_OPTIONS_ERROR : LZMA_PROG_ERROR;
+ }
+
+ if (fe->props_size_get == NULL) {
+ // No props_size_get() function, use props_size_fixed.
+ *size = fe->props_size_fixed;
+ return LZMA_OK;
+ }
+
+ return fe->props_size_get(size, filter->options);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_properties_encode(const lzma_filter *filter, uint8_t *props)
+{
+ const lzma_filter_encoder *const fe = encoder_find(filter->id);
+ if (fe == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (fe->props_encode == NULL)
+ return LZMA_OK;
+
+ return fe->props_encode(filter->options, props);
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_encoder.h b/Utilities/cmliblzma/liblzma/common/filter_encoder.h
new file mode 100644
index 000000000..5bc137f64
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_encoder.h
@@ -0,0 +1,27 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_encoder.c
+/// \brief Filter ID mapping to filter-specific functions
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FILTER_ENCODER_H
+#define LZMA_FILTER_ENCODER_H
+
+#include "common.h"
+
+
+// FIXME: Might become a part of the public API once finished.
+// extern lzma_vli lzma_chunk_size(const lzma_filter *filters);
+
+
+extern lzma_ret lzma_raw_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *filters);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/filter_flags_decoder.c b/Utilities/cmliblzma/liblzma/common/filter_flags_decoder.c
new file mode 100644
index 000000000..aa2dbd560
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_flags_decoder.c
@@ -0,0 +1,48 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_flags_decoder.c
+/// \brief Decodes a Filter Flags field
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_decode(
+ lzma_filter *filter, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ lzma_vli props_size;
+ lzma_ret ret;
+
+ // Set the pointer to NULL so the caller can always safely free it.
+ filter->options = NULL;
+
+ // Filter ID
+ return_if_error(lzma_vli_decode(&filter->id, NULL,
+ in, in_pos, in_size));
+
+ if (filter->id >= LZMA_FILTER_RESERVED_START)
+ return LZMA_DATA_ERROR;
+
+ // Size of Properties
+ return_if_error(lzma_vli_decode(&props_size, NULL,
+ in, in_pos, in_size));
+
+ // Filter Properties
+ if (in_size - *in_pos < props_size)
+ return LZMA_DATA_ERROR;
+
+ ret = lzma_properties_decode(
+ filter, allocator, in + *in_pos, props_size);
+
+ *in_pos += props_size;
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/filter_flags_encoder.c b/Utilities/cmliblzma/liblzma/common/filter_flags_encoder.c
new file mode 100644
index 000000000..755c407f6
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/filter_flags_encoder.c
@@ -0,0 +1,57 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file filter_flags_encoder.c
+/// \brief Decodes a Filter Flags field
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "filter_encoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_size(uint32_t *size, const lzma_filter *filter)
+{
+ if (filter->id >= LZMA_FILTER_RESERVED_START)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_properties_size(size, filter));
+
+ *size += lzma_vli_size(filter->id) + lzma_vli_size(*size);
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_filter_flags_encode(const lzma_filter *filter,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ uint32_t props_size;
+
+ // Filter ID
+ if (filter->id >= LZMA_FILTER_RESERVED_START)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_vli_encode(filter->id, NULL,
+ out, out_pos, out_size));
+
+ // Size of Properties
+ return_if_error(lzma_properties_size(&props_size, filter));
+ return_if_error(lzma_vli_encode(props_size, NULL,
+ out, out_pos, out_size));
+
+ // Filter Properties
+ if (out_size - *out_pos < props_size)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_properties_encode(filter, out + *out_pos));
+
+ *out_pos += props_size;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/hardware_physmem.c b/Utilities/cmliblzma/liblzma/common/hardware_physmem.c
new file mode 100644
index 000000000..7405b658a
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/hardware_physmem.c
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file hardware_physmem.c
+/// \brief Get the total amount of physical memory (RAM)
+//
+// Author: Jonathan Nieder
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+#include "tuklib_physmem.h"
+
+
+extern LZMA_API(uint64_t)
+lzma_physmem(void)
+{
+ // It is simpler to make lzma_physmem() a wrapper for
+ // tuklib_physmem() than to hack appropriate symbol visiblity
+ // support for the tuklib modules.
+ return tuklib_physmem();
+}
diff --git a/Utilities/cmliblzma/liblzma/common/index.c b/Utilities/cmliblzma/liblzma/common/index.c
new file mode 100644
index 000000000..26135d22c
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index.c
@@ -0,0 +1,1276 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index.c
+/// \brief Handling of .xz Indexes and some other Stream information
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index.h"
+#include "stream_flags_common.h"
+
+
+/// \brief How many Records to allocate at once
+///
+/// This should be big enough to avoid making lots of tiny allocations
+/// but small enough to avoid too much unused memory at once.
+#define INDEX_GROUP_SIZE 512
+
+
+/// \brief How many Records can be allocated at once at maximum
+#define PREALLOC_MAX ((SIZE_MAX - sizeof(index_group)) / sizeof(index_record))
+
+
+/// \brief Base structure for index_stream and index_group structures
+typedef struct index_tree_node_s index_tree_node;
+struct index_tree_node_s {
+ /// Uncompressed start offset of this Stream (relative to the
+ /// beginning of the file) or Block (relative to the beginning
+ /// of the Stream)
+ lzma_vli uncompressed_base;
+
+ /// Compressed start offset of this Stream or Block
+ lzma_vli compressed_base;
+
+ index_tree_node *parent;
+ index_tree_node *left;
+ index_tree_node *right;
+};
+
+
+/// \brief AVL tree to hold index_stream or index_group structures
+typedef struct {
+ /// Root node
+ index_tree_node *root;
+
+ /// Leftmost node. Since the tree will be filled sequentially,
+ /// this won't change after the first node has been added to
+ /// the tree.
+ index_tree_node *leftmost;
+
+ /// The rightmost node in the tree. Since the tree is filled
+ /// sequentially, this is always the node where to add the new data.
+ index_tree_node *rightmost;
+
+ /// Number of nodes in the tree
+ uint32_t count;
+
+} index_tree;
+
+
+typedef struct {
+ lzma_vli uncompressed_sum;
+ lzma_vli unpadded_sum;
+} index_record;
+
+
+typedef struct {
+ /// Every Record group is part of index_stream.groups tree.
+ index_tree_node node;
+
+ /// Number of Blocks in this Stream before this group.
+ lzma_vli number_base;
+
+ /// Number of Records that can be put in records[].
+ size_t allocated;
+
+ /// Index of the last Record in use.
+ size_t last;
+
+ /// The sizes in this array are stored as cumulative sums relative
+ /// to the beginning of the Stream. This makes it possible to
+ /// use binary search in lzma_index_locate().
+ ///
+ /// Note that the cumulative summing is done specially for
+ /// unpadded_sum: The previous value is rounded up to the next
+ /// multiple of four before adding the Unpadded Size of the new
+ /// Block. The total encoded size of the Blocks in the Stream
+ /// is records[last].unpadded_sum in the last Record group of
+ /// the Stream.
+ ///
+ /// For example, if the Unpadded Sizes are 39, 57, and 81, the
+ /// stored values are 39, 97 (40 + 57), and 181 (100 + 181).
+ /// The total encoded size of these Blocks is 184.
+ ///
+ /// This is a flexible array, because it makes easy to optimize
+ /// memory usage in case someone concatenates many Streams that
+ /// have only one or few Blocks.
+ index_record records[];
+
+} index_group;
+
+
+typedef struct {
+ /// Every index_stream is a node in the tree of Sreams.
+ index_tree_node node;
+
+ /// Number of this Stream (first one is 1)
+ uint32_t number;
+
+ /// Total number of Blocks before this Stream
+ lzma_vli block_number_base;
+
+ /// Record groups of this Stream are stored in a tree.
+ /// It's a T-tree with AVL-tree balancing. There are
+ /// INDEX_GROUP_SIZE Records per node by default.
+ /// This keeps the number of memory allocations reasonable
+ /// and finding a Record is fast.
+ index_tree groups;
+
+ /// Number of Records in this Stream
+ lzma_vli record_count;
+
+ /// Size of the List of Records field in this Stream. This is used
+ /// together with record_count to calculate the size of the Index
+ /// field and thus the total size of the Stream.
+ lzma_vli index_list_size;
+
+ /// Stream Flags of this Stream. This is meaningful only if
+ /// the Stream Flags have been told us with lzma_index_stream_flags().
+ /// Initially stream_flags.version is set to UINT32_MAX to indicate
+ /// that the Stream Flags are unknown.
+ lzma_stream_flags stream_flags;
+
+ /// Amount of Stream Padding after this Stream. This defaults to
+ /// zero and can be set with lzma_index_stream_padding().
+ lzma_vli stream_padding;
+
+} index_stream;
+
+
+struct lzma_index_s {
+ /// AVL-tree containing the Stream(s). Often there is just one
+ /// Stream, but using a tree keeps lookups fast even when there
+ /// are many concatenated Streams.
+ index_tree streams;
+
+ /// Uncompressed size of all the Blocks in the Stream(s)
+ lzma_vli uncompressed_size;
+
+ /// Total size of all the Blocks in the Stream(s)
+ lzma_vli total_size;
+
+ /// Total number of Records in all Streams in this lzma_index
+ lzma_vli record_count;
+
+ /// Size of the List of Records field if all the Streams in this
+ /// lzma_index were packed into a single Stream (makes it simpler to
+ /// take many .xz files and combine them into a single Stream).
+ ///
+ /// This value together with record_count is needed to calculate
+ /// Backward Size that is stored into Stream Footer.
+ lzma_vli index_list_size;
+
+ /// How many Records to allocate at once in lzma_index_append().
+ /// This defaults to INDEX_GROUP_SIZE but can be overriden with
+ /// lzma_index_prealloc().
+ size_t prealloc;
+
+ /// Bitmask indicating what integrity check types have been used
+ /// as set by lzma_index_stream_flags(). The bit of the last Stream
+ /// is not included here, since it is possible to change it by
+ /// calling lzma_index_stream_flags() again.
+ uint32_t checks;
+};
+
+
+static void
+index_tree_init(index_tree *tree)
+{
+ tree->root = NULL;
+ tree->leftmost = NULL;
+ tree->rightmost = NULL;
+ tree->count = 0;
+ return;
+}
+
+
+/// Helper for index_tree_end()
+static void
+index_tree_node_end(index_tree_node *node, lzma_allocator *allocator,
+ void (*free_func)(void *node, lzma_allocator *allocator))
+{
+ // The tree won't ever be very huge, so recursion should be fine.
+ // 20 levels in the tree is likely quite a lot already in practice.
+ if (node->left != NULL)
+ index_tree_node_end(node->left, allocator, free_func);
+
+ if (node->right != NULL)
+ index_tree_node_end(node->right, allocator, free_func);
+
+ if (free_func != NULL)
+ free_func(node, allocator);
+
+ lzma_free(node, allocator);
+ return;
+}
+
+
+/// Free the meory allocated for a tree. If free_func is not NULL,
+/// it is called on each node before freeing the node. This is used
+/// to free the Record groups from each index_stream before freeing
+/// the index_stream itself.
+static void
+index_tree_end(index_tree *tree, lzma_allocator *allocator,
+ void (*free_func)(void *node, lzma_allocator *allocator))
+{
+ if (tree->root != NULL)
+ index_tree_node_end(tree->root, allocator, free_func);
+
+ return;
+}
+
+
+/// Add a new node to the tree. node->uncompressed_base and
+/// node->compressed_base must have been set by the caller already.
+static void
+index_tree_append(index_tree *tree, index_tree_node *node)
+{
+ uint32_t up;
+ node->parent = tree->rightmost;
+ node->left = NULL;
+ node->right = NULL;
+
+ ++tree->count;
+
+ // Handle the special case of adding the first node.
+ if (tree->root == NULL) {
+ tree->root = node;
+ tree->leftmost = node;
+ tree->rightmost = node;
+ return;
+ }
+
+ // The tree is always filled sequentially.
+ assert(tree->rightmost->uncompressed_base <= node->uncompressed_base);
+ assert(tree->rightmost->compressed_base < node->compressed_base);
+
+ // Add the new node after the rightmost node. It's the correct
+ // place due to the reason above.
+ tree->rightmost->right = node;
+ tree->rightmost = node;
+
+ // Balance the AVL-tree if needed. We don't need to keep the balance
+ // factors in nodes, because we always fill the tree sequentially,
+ // and thus know the state of the tree just by looking at the node
+ // count. From the node count we can calculate how many steps to go
+ // up in the tree to find the rotation root.
+ up = tree->count ^ (UINT32_C(1) << bsr32(tree->count));
+ if (up != 0) {
+ index_tree_node *pivot;
+
+ // Locate the root node for the rotation.
+ up = ctz32(tree->count) + 2;
+ do {
+ node = node->parent;
+ } while (--up > 0);
+
+ // Rotate left using node as the rotation root.
+ pivot = node->right;
+
+ if (node->parent == NULL) {
+ tree->root = pivot;
+ } else {
+ assert(node->parent->right == node);
+ node->parent->right = pivot;
+ }
+
+ pivot->parent = node->parent;
+
+ node->right = pivot->left;
+ if (node->right != NULL)
+ node->right->parent = node;
+
+ pivot->left = node;
+ node->parent = pivot;
+ }
+
+ return;
+}
+
+
+/// Get the next node in the tree. Return NULL if there are no more nodes.
+static void *
+index_tree_next(const index_tree_node *node)
+{
+ if (node->right != NULL) {
+ node = node->right;
+ while (node->left != NULL)
+ node = node->left;
+
+ return (void *)(node);
+ }
+
+ while (node->parent != NULL && node->parent->right == node)
+ node = node->parent;
+
+ return (void *)(node->parent);
+}
+
+
+/// Locate a node that contains the given uncompressed offset. It is
+/// caller's job to check that target is not bigger than the uncompressed
+/// size of the tree (the last node would be returned in that case still).
+static void *
+index_tree_locate(const index_tree *tree, lzma_vli target)
+{
+ const index_tree_node *result = NULL;
+ const index_tree_node *node = tree->root;
+
+ assert(tree->leftmost == NULL
+ || tree->leftmost->uncompressed_base == 0);
+
+ // Consecutive nodes may have the same uncompressed_base.
+ // We must pick the rightmost one.
+ while (node != NULL) {
+ if (node->uncompressed_base > target) {
+ node = node->left;
+ } else {
+ result = node;
+ node = node->right;
+ }
+ }
+
+ return (void *)(result);
+}
+
+
+/// Allocate and initialize a new Stream using the given base offsets.
+static index_stream *
+index_stream_init(lzma_vli compressed_base, lzma_vli uncompressed_base,
+ lzma_vli stream_number, lzma_vli block_number_base,
+ lzma_allocator *allocator)
+{
+ index_stream *s = lzma_alloc(sizeof(index_stream), allocator);
+ if (s == NULL)
+ return NULL;
+
+ s->node.uncompressed_base = uncompressed_base;
+ s->node.compressed_base = compressed_base;
+ s->node.parent = NULL;
+ s->node.left = NULL;
+ s->node.right = NULL;
+
+ s->number = stream_number;
+ s->block_number_base = block_number_base;
+
+ index_tree_init(&s->groups);
+
+ s->record_count = 0;
+ s->index_list_size = 0;
+ s->stream_flags.version = UINT32_MAX;
+ s->stream_padding = 0;
+
+ return s;
+}
+
+
+/// Free the memory allocated for a Stream and its Record groups.
+static void
+index_stream_end(void *node, lzma_allocator *allocator)
+{
+ index_stream *s = node;
+ index_tree_end(&s->groups, allocator, NULL);
+ return;
+}
+
+
+static lzma_index *
+index_init_plain(lzma_allocator *allocator)
+{
+ lzma_index *i = lzma_alloc(sizeof(lzma_index), allocator);
+ if (i != NULL) {
+ index_tree_init(&i->streams);
+ i->uncompressed_size = 0;
+ i->total_size = 0;
+ i->record_count = 0;
+ i->index_list_size = 0;
+ i->prealloc = INDEX_GROUP_SIZE;
+ i->checks = 0;
+ }
+
+ return i;
+}
+
+
+extern LZMA_API(lzma_index *)
+lzma_index_init(lzma_allocator *allocator)
+{
+ index_stream *s;
+
+ lzma_index *i = index_init_plain(allocator);
+ if (i == NULL)
+ return NULL;
+
+ s = index_stream_init(0, 0, 1, 0, allocator);
+ if (s == NULL) {
+ lzma_free(i, allocator);
+ return NULL;
+ }
+
+ index_tree_append(&i->streams, &s->node);
+
+ return i;
+}
+
+
+extern LZMA_API(void)
+lzma_index_end(lzma_index *i, lzma_allocator *allocator)
+{
+ // NOTE: If you modify this function, check also the bottom
+ // of lzma_index_cat().
+ if (i != NULL) {
+ index_tree_end(&i->streams, allocator, &index_stream_end);
+ lzma_free(i, allocator);
+ }
+
+ return;
+}
+
+
+extern void
+lzma_index_prealloc(lzma_index *i, lzma_vli records)
+{
+ if (records > PREALLOC_MAX)
+ records = PREALLOC_MAX;
+
+ i->prealloc = (size_t)(records);
+ return;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_index_memusage(lzma_vli streams, lzma_vli blocks)
+{
+ // This calculates an upper bound that is only a little bit
+ // bigger than the exact maximum memory usage with the given
+ // parameters.
+
+ // Typical malloc() overhead is 2 * sizeof(void *) but we take
+ // a little bit extra just in case. Using LZMA_MEMUSAGE_BASE
+ // instead would give too inaccurate estimate.
+ const size_t alloc_overhead = 4 * sizeof(void *);
+
+ // Amount of memory needed for each Stream base structures.
+ // We assume that every Stream has at least one Block and
+ // thus at least one group.
+ const size_t stream_base = sizeof(index_stream)
+ + sizeof(index_group) + 2 * alloc_overhead;
+
+ // Amount of memory needed per group.
+ const size_t group_base = sizeof(index_group)
+ + INDEX_GROUP_SIZE * sizeof(index_record)
+ + alloc_overhead;
+
+ // Number of groups. There may actually be more, but that overhead
+ // has been taken into account in stream_base already.
+ const lzma_vli groups
+ = (blocks + INDEX_GROUP_SIZE - 1) / INDEX_GROUP_SIZE;
+
+ // Memory used by index_stream and index_group structures.
+ const uint64_t streams_mem = streams * stream_base;
+ const uint64_t groups_mem = groups * group_base;
+
+ // Memory used by the base structure.
+ const uint64_t index_base = sizeof(lzma_index) + alloc_overhead;
+
+ // Validate the arguments and catch integer overflows.
+ // Maximum number of Streams is "only" UINT32_MAX, because
+ // that limit is used by the tree containing the Streams.
+ const uint64_t limit = UINT64_MAX - index_base;
+ if (streams == 0 || streams > UINT32_MAX || blocks > LZMA_VLI_MAX
+ || streams > limit / stream_base
+ || groups > limit / group_base
+ || limit - streams_mem < groups_mem)
+ return UINT64_MAX;
+
+ return index_base + streams_mem + groups_mem;
+}
+
+
+extern LZMA_API(uint64_t)
+lzma_index_memused(const lzma_index *i)
+{
+ return lzma_index_memusage(i->streams.count, i->record_count);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_block_count(const lzma_index *i)
+{
+ return i->record_count;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_stream_count(const lzma_index *i)
+{
+ return i->streams.count;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_size(const lzma_index *i)
+{
+ return index_size(i->record_count, i->index_list_size);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_total_size(const lzma_index *i)
+{
+ return i->total_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_stream_size(const lzma_index *i)
+{
+ // Stream Header + Blocks + Index + Stream Footer
+ return LZMA_STREAM_HEADER_SIZE + i->total_size
+ + index_size(i->record_count, i->index_list_size)
+ + LZMA_STREAM_HEADER_SIZE;
+}
+
+
+static lzma_vli
+index_file_size(lzma_vli compressed_base, lzma_vli unpadded_sum,
+ lzma_vli record_count, lzma_vli index_list_size,
+ lzma_vli stream_padding)
+{
+ // Earlier Streams and Stream Paddings + Stream Header
+ // + Blocks + Index + Stream Footer + Stream Padding
+ //
+ // This might go over LZMA_VLI_MAX due to too big unpadded_sum
+ // when this function is used in lzma_index_append().
+ lzma_vli file_size = compressed_base + 2 * LZMA_STREAM_HEADER_SIZE
+ + stream_padding + vli_ceil4(unpadded_sum);
+ if (file_size > LZMA_VLI_MAX)
+ return LZMA_VLI_UNKNOWN;
+
+ // The same applies here.
+ file_size += index_size(record_count, index_list_size);
+ if (file_size > LZMA_VLI_MAX)
+ return LZMA_VLI_UNKNOWN;
+
+ return file_size;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_file_size(const lzma_index *i)
+{
+ const index_stream *s = (const index_stream *)(i->streams.rightmost);
+ const index_group *g = (const index_group *)(s->groups.rightmost);
+ return index_file_size(s->node.compressed_base,
+ g == NULL ? 0 : g->records[g->last].unpadded_sum,
+ s->record_count, s->index_list_size,
+ s->stream_padding);
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_uncompressed_size(const lzma_index *i)
+{
+ return i->uncompressed_size;
+}
+
+
+extern LZMA_API(uint32_t)
+lzma_index_checks(const lzma_index *i)
+{
+ uint32_t checks = i->checks;
+
+ // Get the type of the Check of the last Stream too.
+ const index_stream *s = (const index_stream *)(i->streams.rightmost);
+ if (s->stream_flags.version != UINT32_MAX)
+ checks |= UINT32_C(1) << s->stream_flags.check;
+
+ return checks;
+}
+
+
+extern uint32_t
+lzma_index_padding_size(const lzma_index *i)
+{
+ return (LZMA_VLI_C(4) - index_size_unpadded(
+ i->record_count, i->index_list_size)) & 3;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_stream_flags(lzma_index *i, const lzma_stream_flags *stream_flags)
+{
+ index_stream *s;
+
+ if (i == NULL || stream_flags == NULL)
+ return LZMA_PROG_ERROR;
+
+ // Validate the Stream Flags.
+ return_if_error(lzma_stream_flags_compare(
+ stream_flags, stream_flags));
+
+ s = (index_stream *)(i->streams.rightmost);
+ s->stream_flags = *stream_flags;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_stream_padding(lzma_index *i, lzma_vli stream_padding)
+{
+ index_stream *s;
+ lzma_vli old_stream_padding;
+
+ if (i == NULL || stream_padding > LZMA_VLI_MAX
+ || (stream_padding & 3) != 0)
+ return LZMA_PROG_ERROR;
+
+ s = (index_stream *)(i->streams.rightmost);
+
+ // Check that the new value won't make the file grow too big.
+ old_stream_padding = s->stream_padding;
+ s->stream_padding = 0;
+ if (lzma_index_file_size(i) + stream_padding > LZMA_VLI_MAX) {
+ s->stream_padding = old_stream_padding;
+ return LZMA_DATA_ERROR;
+ }
+
+ s->stream_padding = stream_padding;
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_append(lzma_index *i, lzma_allocator *allocator,
+ lzma_vli unpadded_size, lzma_vli uncompressed_size)
+{
+ index_stream *s;
+ index_group *g;
+ lzma_vli compressed_base;
+ lzma_vli uncompressed_base;
+ uint32_t index_list_size_add;
+
+ // Validate.
+ if (i == NULL || unpadded_size < UNPADDED_SIZE_MIN
+ || unpadded_size > UNPADDED_SIZE_MAX
+ || uncompressed_size > LZMA_VLI_MAX)
+ return LZMA_PROG_ERROR;
+
+ s = (index_stream *)(i->streams.rightmost);
+ g = (index_group *)(s->groups.rightmost);
+
+ compressed_base = g == NULL ? 0
+ : vli_ceil4(g->records[g->last].unpadded_sum);
+ uncompressed_base = g == NULL ? 0
+ : g->records[g->last].uncompressed_sum;
+ index_list_size_add = lzma_vli_size(unpadded_size)
+ + lzma_vli_size(uncompressed_size);
+
+ // Check that the file size will stay within limits.
+ if (index_file_size(s->node.compressed_base,
+ compressed_base + unpadded_size, s->record_count + 1,
+ s->index_list_size + index_list_size_add,
+ s->stream_padding) == LZMA_VLI_UNKNOWN)
+ return LZMA_DATA_ERROR;
+
+ // The size of the Index field must not exceed the maximum value
+ // that can be stored in the Backward Size field.
+ if (index_size(i->record_count + 1,
+ i->index_list_size + index_list_size_add)
+ > LZMA_BACKWARD_SIZE_MAX)
+ return LZMA_DATA_ERROR;
+
+ if (g != NULL && g->last + 1 < g->allocated) {
+ // There is space in the last group at least for one Record.
+ ++g->last;
+ } else {
+ // We need to allocate a new group.
+ g = lzma_alloc(sizeof(index_group)
+ + i->prealloc * sizeof(index_record),
+ allocator);
+ if (g == NULL)
+ return LZMA_MEM_ERROR;
+
+ g->last = 0;
+ g->allocated = i->prealloc;
+
+ // Reset prealloc so that if the application happens to
+ // add new Records, the allocation size will be sane.
+ i->prealloc = INDEX_GROUP_SIZE;
+
+ // Set the start offsets of this group.
+ g->node.uncompressed_base = uncompressed_base;
+ g->node.compressed_base = compressed_base;
+ g->number_base = s->record_count + 1;
+
+ // Add the new group to the Stream.
+ index_tree_append(&s->groups, &g->node);
+ }
+
+ // Add the new Record to the group.
+ g->records[g->last].uncompressed_sum
+ = uncompressed_base + uncompressed_size;
+ g->records[g->last].unpadded_sum
+ = compressed_base + unpadded_size;
+
+ // Update the totals.
+ ++s->record_count;
+ s->index_list_size += index_list_size_add;
+
+ i->total_size += vli_ceil4(unpadded_size);
+ i->uncompressed_size += uncompressed_size;
+ ++i->record_count;
+ i->index_list_size += index_list_size_add;
+
+ return LZMA_OK;
+}
+
+
+/// Structure to pass info to index_cat_helper()
+typedef struct {
+ /// Uncompressed size of the destination
+ lzma_vli uncompressed_size;
+
+ /// Compressed file size of the destination
+ lzma_vli file_size;
+
+ /// Same as above but for Block numbers
+ lzma_vli block_number_add;
+
+ /// Number of Streams that were in the destination index before we
+ /// started appending new Streams from the source index. This is
+ /// used to fix the Stream numbering.
+ uint32_t stream_number_add;
+
+ /// Destination index' Stream tree
+ index_tree *streams;
+
+} index_cat_info;
+
+
+/// Add the Stream nodes from the source index to dest using recursion.
+/// Simplest iterative traversal of the source tree wouldn't work, because
+/// we update the pointers in nodes when moving them to the destination tree.
+static void
+index_cat_helper(const index_cat_info *info, index_stream *this)
+{
+ index_stream *left = (index_stream *)(this->node.left);
+ index_stream *right = (index_stream *)(this->node.right);
+
+ if (left != NULL)
+ index_cat_helper(info, left);
+
+ this->node.uncompressed_base += info->uncompressed_size;
+ this->node.compressed_base += info->file_size;
+ this->number += info->stream_number_add;
+ this->block_number_base += info->block_number_add;
+ index_tree_append(info->streams, &this->node);
+
+ if (right != NULL)
+ index_cat_helper(info, right);
+
+ return;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_cat(lzma_index *LZMA_RESTRICT dest, lzma_index *LZMA_RESTRICT src,
+ lzma_allocator *allocator)
+{
+ index_cat_info info;
+ const lzma_vli dest_file_size = lzma_index_file_size(dest);
+
+ // Check that we don't exceed the file size limits.
+ if (dest_file_size + lzma_index_file_size(src) > LZMA_VLI_MAX
+ || dest->uncompressed_size + src->uncompressed_size
+ > LZMA_VLI_MAX)
+ return LZMA_DATA_ERROR;
+
+ // Check that the encoded size of the combined lzma_indexes stays
+ // within limits. In theory, this should be done only if we know
+ // that the user plans to actually combine the Streams and thus
+ // construct a single Index (probably rare). However, exceeding
+ // this limit is quite theoretical, so we do this check always
+ // to simplify things elsewhere.
+ {
+ const lzma_vli dest_size = index_size_unpadded(
+ dest->record_count, dest->index_list_size);
+ const lzma_vli src_size = index_size_unpadded(
+ src->record_count, src->index_list_size);
+ if (vli_ceil4(dest_size + src_size) > LZMA_BACKWARD_SIZE_MAX)
+ return LZMA_DATA_ERROR;
+ }
+
+ // Optimize the last group to minimize memory usage. Allocation has
+ // to be done before modifying dest or src.
+ {
+ index_stream *s = (index_stream *)(dest->streams.rightmost);
+ index_group *g = (index_group *)(s->groups.rightmost);
+ if (g != NULL && g->last + 1 < g->allocated) {
+ index_group *newg;
+
+ assert(g->node.left == NULL);
+ assert(g->node.right == NULL);
+
+ newg = lzma_alloc(sizeof(index_group)
+ + (g->last + 1)
+ * sizeof(index_record),
+ allocator);
+ if (newg == NULL)
+ return LZMA_MEM_ERROR;
+
+ newg->node = g->node;
+ newg->allocated = g->last + 1;
+ newg->last = g->last;
+ newg->number_base = g->number_base;
+
+ memcpy(newg->records, g->records, newg->allocated
+ * sizeof(index_record));
+
+ if (g->node.parent != NULL) {
+ assert(g->node.parent->right == &g->node);
+ g->node.parent->right = &newg->node;
+ }
+
+ if (s->groups.leftmost == &g->node) {
+ assert(s->groups.root == &g->node);
+ s->groups.leftmost = &newg->node;
+ s->groups.root = &newg->node;
+ }
+
+ if (s->groups.rightmost == &g->node)
+ s->groups.rightmost = &newg->node;
+
+ lzma_free(g, allocator);
+ }
+ }
+
+ // Add all the Streams from src to dest. Update the base offsets
+ // of each Stream from src.
+ info.uncompressed_size = dest->uncompressed_size;
+ info.file_size = dest_file_size;
+ info.stream_number_add = dest->streams.count;
+ info.block_number_add = dest->record_count;
+ info.streams = &dest->streams;
+
+ index_cat_helper(&info, (index_stream *)(src->streams.root));
+
+ // Update info about all the combined Streams.
+ dest->uncompressed_size += src->uncompressed_size;
+ dest->total_size += src->total_size;
+ dest->record_count += src->record_count;
+ dest->index_list_size += src->index_list_size;
+ dest->checks = lzma_index_checks(dest) | src->checks;
+
+ // There's nothing else left in src than the base structure.
+ lzma_free(src, allocator);
+
+ return LZMA_OK;
+}
+
+
+/// Duplicate an index_stream.
+static index_stream *
+index_dup_stream(const index_stream *src, lzma_allocator *allocator)
+{
+ index_stream *dest;
+ index_group *destg;
+ index_group *srcg;
+ size_t i = 0;
+
+ // Catch a somewhat theoretical integer overflow.
+ if (src->record_count > PREALLOC_MAX)
+ return NULL;
+
+ // Allocate and initialize a new Stream.
+ dest = index_stream_init(src->node.compressed_base,
+ src->node.uncompressed_base, src->number,
+ src->block_number_base, allocator);
+
+ // Return immediately if allocation failed or if there are
+ // no groups to duplicate.
+ if (dest == NULL || src->groups.leftmost == NULL)
+ return dest;
+
+ // Copy the overall information.
+ dest->record_count = src->record_count;
+ dest->index_list_size = src->index_list_size;
+ dest->stream_flags = src->stream_flags;
+ dest->stream_padding = src->stream_padding;
+
+ // Allocate memory for the Records. We put all the Records into
+ // a single group. It's simplest and also tends to make
+ // lzma_index_locate() a little bit faster with very big Indexes.
+ destg = lzma_alloc(sizeof(index_group)
+ + src->record_count * sizeof(index_record),
+ allocator);
+ if (destg == NULL) {
+ index_stream_end(dest, allocator);
+ return NULL;
+ }
+
+ // Initialize destg.
+ destg->node.uncompressed_base = 0;
+ destg->node.compressed_base = 0;
+ destg->number_base = 1;
+ destg->allocated = src->record_count;
+ destg->last = src->record_count - 1;
+
+ // Go through all the groups in src and copy the Records into destg.
+ srcg = (index_group *)(src->groups.leftmost);
+ do {
+ memcpy(destg->records + i, srcg->records,
+ (srcg->last + 1) * sizeof(index_record));
+ i += srcg->last + 1;
+ srcg = index_tree_next(&srcg->node);
+ } while (srcg != NULL);
+
+ assert(i == destg->allocated);
+
+ // Add the group to the new Stream.
+ index_tree_append(&dest->groups, &destg->node);
+
+ return dest;
+}
+
+
+extern LZMA_API(lzma_index *)
+lzma_index_dup(const lzma_index *src, lzma_allocator *allocator)
+{
+ index_stream *srcstream;
+ index_stream *deststream;
+
+ // Allocate the base structure (no initial Stream).
+ lzma_index *dest = index_init_plain(allocator);
+ if (dest == NULL)
+ return NULL;
+
+ // Copy the totals.
+ dest->uncompressed_size = src->uncompressed_size;
+ dest->total_size = src->total_size;
+ dest->record_count = src->record_count;
+ dest->index_list_size = src->index_list_size;
+
+ // Copy the Streams and the groups in them.
+ srcstream = (index_stream *)(src->streams.leftmost);
+ do {
+ deststream = index_dup_stream(srcstream, allocator);
+ if (deststream == NULL) {
+ lzma_index_end(dest, allocator);
+ return NULL;
+ }
+
+ index_tree_append(&dest->streams, &deststream->node);
+
+ srcstream = index_tree_next(&srcstream->node);
+ } while (srcstream != NULL);
+
+ return dest;
+}
+
+
+/// Indexing for lzma_index_iter.internal[]
+enum {
+ ITER_INDEX,
+ ITER_STREAM,
+ ITER_GROUP,
+ ITER_RECORD,
+ ITER_METHOD,
+};
+
+
+/// Values for lzma_index_iter.internal[ITER_METHOD].s
+enum {
+ ITER_METHOD_NORMAL,
+ ITER_METHOD_NEXT,
+ ITER_METHOD_LEFTMOST,
+};
+
+
+static void
+iter_set_info(lzma_index_iter *iter)
+{
+ const lzma_index *i = iter->internal[ITER_INDEX].p;
+ const index_stream *stream = iter->internal[ITER_STREAM].p;
+ const index_group *group = iter->internal[ITER_GROUP].p;
+ const size_t record = iter->internal[ITER_RECORD].s;
+
+ // lzma_index_iter.internal must not contain a pointer to the last
+ // group in the index, because that may be reallocated by
+ // lzma_index_cat().
+ if (group == NULL) {
+ // There are no groups.
+ assert(stream->groups.root == NULL);
+ iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
+
+ } else if (i->streams.rightmost != &stream->node
+ || stream->groups.rightmost != &group->node) {
+ // The group is not not the last group in the index.
+ iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
+
+ } else if (stream->groups.leftmost != &group->node) {
+ // The group isn't the only group in the Stream, thus we
+ // know that it must have a parent group i.e. it's not
+ // the root node.
+ assert(stream->groups.root != &group->node);
+ assert(group->node.parent->right == &group->node);
+ iter->internal[ITER_METHOD].s = ITER_METHOD_NEXT;
+ iter->internal[ITER_GROUP].p = group->node.parent;
+
+ } else {
+ // The Stream has only one group.
+ assert(stream->groups.root == &group->node);
+ assert(group->node.parent == NULL);
+ iter->internal[ITER_METHOD].s = ITER_METHOD_LEFTMOST;
+ iter->internal[ITER_GROUP].p = NULL;
+ }
+
+ iter->stream.number = stream->number;
+ iter->stream.block_count = stream->record_count;
+ iter->stream.compressed_offset = stream->node.compressed_base;
+ iter->stream.uncompressed_offset = stream->node.uncompressed_base;
+
+ // iter->stream.flags will be NULL if the Stream Flags haven't been
+ // set with lzma_index_stream_flags().
+ iter->stream.flags = stream->stream_flags.version == UINT32_MAX
+ ? NULL : &stream->stream_flags;
+ iter->stream.padding = stream->stream_padding;
+
+ if (stream->groups.rightmost == NULL) {
+ // Stream has no Blocks.
+ iter->stream.compressed_size = index_size(0, 0)
+ + 2 * LZMA_STREAM_HEADER_SIZE;
+ iter->stream.uncompressed_size = 0;
+ } else {
+ const index_group *g = (const index_group *)(
+ stream->groups.rightmost);
+
+ // Stream Header + Stream Footer + Index + Blocks
+ iter->stream.compressed_size = 2 * LZMA_STREAM_HEADER_SIZE
+ + index_size(stream->record_count,
+ stream->index_list_size)
+ + vli_ceil4(g->records[g->last].unpadded_sum);
+ iter->stream.uncompressed_size
+ = g->records[g->last].uncompressed_sum;
+ }
+
+ if (group != NULL) {
+ iter->block.number_in_stream = group->number_base + record;
+ iter->block.number_in_file = iter->block.number_in_stream
+ + stream->block_number_base;
+
+ iter->block.compressed_stream_offset
+ = record == 0 ? group->node.compressed_base
+ : vli_ceil4(group->records[
+ record - 1].unpadded_sum);
+ iter->block.uncompressed_stream_offset
+ = record == 0 ? group->node.uncompressed_base
+ : group->records[record - 1].uncompressed_sum;
+
+ iter->block.uncompressed_size
+ = group->records[record].uncompressed_sum
+ - iter->block.uncompressed_stream_offset;
+ iter->block.unpadded_size
+ = group->records[record].unpadded_sum
+ - iter->block.compressed_stream_offset;
+ iter->block.total_size = vli_ceil4(iter->block.unpadded_size);
+
+ iter->block.compressed_stream_offset
+ += LZMA_STREAM_HEADER_SIZE;
+
+ iter->block.compressed_file_offset
+ = iter->block.compressed_stream_offset
+ + iter->stream.compressed_offset;
+ iter->block.uncompressed_file_offset
+ = iter->block.uncompressed_stream_offset
+ + iter->stream.uncompressed_offset;
+ }
+
+ return;
+}
+
+
+extern LZMA_API(void)
+lzma_index_iter_init(lzma_index_iter *iter, const lzma_index *i)
+{
+ iter->internal[ITER_INDEX].p = i;
+ lzma_index_iter_rewind(iter);
+ return;
+}
+
+
+extern LZMA_API(void)
+lzma_index_iter_rewind(lzma_index_iter *iter)
+{
+ iter->internal[ITER_STREAM].p = NULL;
+ iter->internal[ITER_GROUP].p = NULL;
+ iter->internal[ITER_RECORD].s = 0;
+ iter->internal[ITER_METHOD].s = ITER_METHOD_NORMAL;
+ return;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_index_iter_next(lzma_index_iter *iter, lzma_index_iter_mode mode)
+{
+ const lzma_index *i;
+ const index_stream *stream;
+ const index_group *group;
+ size_t record;
+
+ // Catch unsupported mode values.
+ if ((unsigned int)(mode) > LZMA_INDEX_ITER_NONEMPTY_BLOCK)
+ return true;
+
+ i = iter->internal[ITER_INDEX].p;
+ stream = iter->internal[ITER_STREAM].p;
+ group = NULL;
+ record = iter->internal[ITER_RECORD].s;
+
+ // If we are being asked for the next Stream, leave group to NULL
+ // so that the rest of the this function thinks that this Stream
+ // has no groups and will thus go to the next Stream.
+ if (mode != LZMA_INDEX_ITER_STREAM) {
+ // Get the pointer to the current group. See iter_set_inf()
+ // for explanation.
+ switch (iter->internal[ITER_METHOD].s) {
+ case ITER_METHOD_NORMAL:
+ group = iter->internal[ITER_GROUP].p;
+ break;
+
+ case ITER_METHOD_NEXT:
+ group = index_tree_next(iter->internal[ITER_GROUP].p);
+ break;
+
+ case ITER_METHOD_LEFTMOST:
+ group = (const index_group *)(
+ stream->groups.leftmost);
+ break;
+ }
+ }
+
+again:
+ if (stream == NULL) {
+ // We at the beginning of the lzma_index.
+ // Locate the first Stream.
+ stream = (const index_stream *)(i->streams.leftmost);
+ if (mode >= LZMA_INDEX_ITER_BLOCK) {
+ // Since we are being asked to return information
+ // about the first a Block, skip Streams that have
+ // no Blocks.
+ while (stream->groups.leftmost == NULL) {
+ stream = index_tree_next(&stream->node);
+ if (stream == NULL)
+ return true;
+ }
+ }
+
+ // Start from the first Record in the Stream.
+ group = (const index_group *)(stream->groups.leftmost);
+ record = 0;
+
+ } else if (group != NULL && record < group->last) {
+ // The next Record is in the same group.
+ ++record;
+
+ } else {
+ // This group has no more Records or this Stream has
+ // no Blocks at all.
+ record = 0;
+
+ // If group is not NULL, this Stream has at least one Block
+ // and thus at least one group. Find the next group.
+ if (group != NULL)
+ group = index_tree_next(&group->node);
+
+ if (group == NULL) {
+ // This Stream has no more Records. Find the next
+ // Stream. If we are being asked to return information
+ // about a Block, we skip empty Streams.
+ do {
+ stream = index_tree_next(&stream->node);
+ if (stream == NULL)
+ return true;
+ } while (mode >= LZMA_INDEX_ITER_BLOCK
+ && stream->groups.leftmost == NULL);
+
+ group = (const index_group *)(
+ stream->groups.leftmost);
+ }
+ }
+
+ if (mode == LZMA_INDEX_ITER_NONEMPTY_BLOCK) {
+ // We need to look for the next Block again if this Block
+ // is empty.
+ if (record == 0) {
+ if (group->node.uncompressed_base
+ == group->records[0].uncompressed_sum)
+ goto again;
+ } else if (group->records[record - 1].uncompressed_sum
+ == group->records[record].uncompressed_sum) {
+ goto again;
+ }
+ }
+
+ iter->internal[ITER_STREAM].p = stream;
+ iter->internal[ITER_GROUP].p = group;
+ iter->internal[ITER_RECORD].s = record;
+
+ iter_set_info(iter);
+
+ return false;
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_index_iter_locate(lzma_index_iter *iter, lzma_vli target)
+{
+ const index_stream *stream;
+ const index_group *group;
+ size_t left, right;
+
+ const lzma_index *i = iter->internal[ITER_INDEX].p;
+
+ // If the target is past the end of the file, return immediately.
+ if (i->uncompressed_size <= target)
+ return true;
+
+ // Locate the Stream containing the target offset.
+ stream = index_tree_locate(&i->streams, target);
+ assert(stream != NULL);
+ target -= stream->node.uncompressed_base;
+
+ // Locate the group containing the target offset.
+ group = index_tree_locate(&stream->groups, target);
+ assert(group != NULL);
+
+ // Use binary search to locate the exact Record. It is the first
+ // Record whose uncompressed_sum is greater than target.
+ // This is because we want the rightmost Record that fullfills the
+ // search criterion. It is possible that there are empty Blocks;
+ // we don't want to return them.
+ left = 0;
+ right = group->last;
+
+ while (left < right) {
+ const size_t pos = left + (right - left) / 2;
+ if (group->records[pos].uncompressed_sum <= target)
+ left = pos + 1;
+ else
+ right = pos;
+ }
+
+ iter->internal[ITER_STREAM].p = stream;
+ iter->internal[ITER_GROUP].p = group;
+ iter->internal[ITER_RECORD].s = left;
+
+ iter_set_info(iter);
+
+ return false;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/index.h b/Utilities/cmliblzma/liblzma/common/index.h
new file mode 100644
index 000000000..64e97247d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index.h
@@ -0,0 +1,73 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index.h
+/// \brief Handling of Index
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_INDEX_H
+#define LZMA_INDEX_H
+
+#include "common.h"
+
+
+/// Minimum Unpadded Size
+#define UNPADDED_SIZE_MIN LZMA_VLI_C(5)
+
+/// Maximum Unpadded Size
+#define UNPADDED_SIZE_MAX (LZMA_VLI_MAX & ~LZMA_VLI_C(3))
+
+
+/// Get the size of the Index Padding field. This is needed by Index encoder
+/// and decoder, but applications should have no use for this.
+extern uint32_t lzma_index_padding_size(const lzma_index *i);
+
+
+/// Set for how many Records to allocate memory the next time
+/// lzma_index_append() needs to allocate space for a new Record.
+/// This is used only by the Index decoder.
+extern void lzma_index_prealloc(lzma_index *i, lzma_vli records);
+
+
+/// Round the variable-length integer to the next multiple of four.
+static inline lzma_vli
+vli_ceil4(lzma_vli vli)
+{
+ assert(vli <= LZMA_VLI_MAX);
+ return (vli + 3) & ~LZMA_VLI_C(3);
+}
+
+
+/// Calculate the size of the Index field excluding Index Padding
+static inline lzma_vli
+index_size_unpadded(lzma_vli count, lzma_vli index_list_size)
+{
+ // Index Indicator + Number of Records + List of Records + CRC32
+ return 1 + lzma_vli_size(count) + index_list_size + 4;
+}
+
+
+/// Calculate the size of the Index field including Index Padding
+static inline lzma_vli
+index_size(lzma_vli count, lzma_vli index_list_size)
+{
+ return vli_ceil4(index_size_unpadded(count, index_list_size));
+}
+
+
+/// Calculate the total size of the Stream
+static inline lzma_vli
+index_stream_size(lzma_vli blocks_size,
+ lzma_vli count, lzma_vli index_list_size)
+{
+ return LZMA_STREAM_HEADER_SIZE + blocks_size
+ + index_size(count, index_list_size)
+ + LZMA_STREAM_HEADER_SIZE;
+}
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/index_decoder.c b/Utilities/cmliblzma/liblzma/common/index_decoder.c
new file mode 100644
index 000000000..943cfd58a
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index_decoder.c
@@ -0,0 +1,347 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index_decoder.c
+/// \brief Decodes the Index field
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_INDICATOR,
+ SEQ_COUNT,
+ SEQ_MEMUSAGE,
+ SEQ_UNPADDED,
+ SEQ_UNCOMPRESSED,
+ SEQ_PADDING_INIT,
+ SEQ_PADDING,
+ SEQ_CRC32,
+ } sequence;
+
+ /// Memory usage limit
+ uint64_t memlimit;
+
+ /// Target Index
+ lzma_index *index;
+
+ /// Pointer give by the application, which is set after
+ /// successful decoding.
+ lzma_index **index_ptr;
+
+ /// Number of Records left to decode.
+ lzma_vli count;
+
+ /// The most recent Unpadded Size field
+ lzma_vli unpadded_size;
+
+ /// The most recent Uncompressed Size field
+ lzma_vli uncompressed_size;
+
+ /// Position in integers
+ size_t pos;
+
+ /// CRC32 of the List of Records field
+ uint32_t crc32;
+};
+
+
+static lzma_ret
+index_decode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size,
+ uint8_t *LZMA_RESTRICT out lzma_attribute((__unused__)),
+ size_t *LZMA_RESTRICT out_pos lzma_attribute((__unused__)),
+ size_t out_size lzma_attribute((__unused__)),
+ lzma_action action lzma_attribute((__unused__)))
+{
+ // Similar optimization as in index_encoder.c
+ const size_t in_start = *in_pos;
+ lzma_ret ret = LZMA_OK;
+
+ while (*in_pos < in_size)
+ switch (coder->sequence) {
+ case SEQ_INDICATOR:
+ // Return LZMA_DATA_ERROR instead of e.g. LZMA_PROG_ERROR or
+ // LZMA_FORMAT_ERROR, because a typical usage case for Index
+ // decoder is when parsing the Stream backwards. If seeking
+ // backward from the Stream Footer gives us something that
+ // doesn't begin with Index Indicator, the file is considered
+ // corrupt, not "programming error" or "unrecognized file
+ // format". One could argue that the application should
+ // verify the Index Indicator before trying to decode the
+ // Index, but well, I suppose it is simpler this way.
+ if (in[(*in_pos)++] != 0x00)
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_COUNT;
+ break;
+
+ case SEQ_COUNT:
+ ret = lzma_vli_decode(&coder->count, &coder->pos,
+ in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ coder->pos = 0;
+ coder->sequence = SEQ_MEMUSAGE;
+
+ // Fall through
+
+ case SEQ_MEMUSAGE:
+ if (lzma_index_memusage(1, coder->count) > coder->memlimit) {
+ ret = LZMA_MEMLIMIT_ERROR;
+ goto out;
+ }
+
+ // Tell the Index handling code how many Records this
+ // Index has to allow it to allocate memory more efficiently.
+ lzma_index_prealloc(coder->index, coder->count);
+
+ ret = LZMA_OK;
+ coder->sequence = coder->count == 0
+ ? SEQ_PADDING_INIT : SEQ_UNPADDED;
+ break;
+
+ case SEQ_UNPADDED:
+ case SEQ_UNCOMPRESSED: {
+ lzma_vli *size = coder->sequence == SEQ_UNPADDED
+ ? &coder->unpadded_size
+ : &coder->uncompressed_size;
+
+ ret = lzma_vli_decode(size, &coder->pos,
+ in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ ret = LZMA_OK;
+ coder->pos = 0;
+
+ if (coder->sequence == SEQ_UNPADDED) {
+ // Validate that encoded Unpadded Size isn't too small
+ // or too big.
+ if (coder->unpadded_size < UNPADDED_SIZE_MIN
+ || coder->unpadded_size
+ > UNPADDED_SIZE_MAX)
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_UNCOMPRESSED;
+ } else {
+ // Add the decoded Record to the Index.
+ return_if_error(lzma_index_append(
+ coder->index, allocator,
+ coder->unpadded_size,
+ coder->uncompressed_size));
+
+ // Check if this was the last Record.
+ coder->sequence = --coder->count == 0
+ ? SEQ_PADDING_INIT
+ : SEQ_UNPADDED;
+ }
+
+ break;
+ }
+
+ case SEQ_PADDING_INIT:
+ coder->pos = lzma_index_padding_size(coder->index);
+ coder->sequence = SEQ_PADDING;
+
+ // Fall through
+
+ case SEQ_PADDING:
+ if (coder->pos > 0) {
+ --coder->pos;
+ if (in[(*in_pos)++] != 0x00)
+ return LZMA_DATA_ERROR;
+
+ break;
+ }
+
+ // Finish the CRC32 calculation.
+ coder->crc32 = lzma_crc32(in + in_start,
+ *in_pos - in_start, coder->crc32);
+
+ coder->sequence = SEQ_CRC32;
+
+ // Fall through
+
+ case SEQ_CRC32:
+ do {
+ if (*in_pos == in_size)
+ return LZMA_OK;
+
+ if (((coder->crc32 >> (coder->pos * 8)) & 0xFF)
+ != in[(*in_pos)++])
+ return LZMA_DATA_ERROR;
+
+ } while (++coder->pos < 4);
+
+ // Decoding was successful, now we can let the application
+ // see the decoded Index.
+ *coder->index_ptr = coder->index;
+
+ // Make index NULL so we don't free it unintentionally.
+ coder->index = NULL;
+
+ return LZMA_STREAM_END;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+out:
+ // Update the CRC32,
+ coder->crc32 = lzma_crc32(in + in_start,
+ *in_pos - in_start, coder->crc32);
+
+ return ret;
+}
+
+
+static void
+index_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_index_end(coder->index, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+index_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
+ uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+ *memusage = lzma_index_memusage(1, coder->count);
+ *old_memlimit = coder->memlimit;
+
+ if (new_memlimit != 0) {
+ if (new_memlimit < *memusage)
+ return LZMA_MEMLIMIT_ERROR;
+
+ coder->memlimit = new_memlimit;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+index_decoder_reset(lzma_coder *coder, lzma_allocator *allocator,
+ lzma_index **i, uint64_t memlimit)
+{
+ // Remember the pointer given by the application. We will set it
+ // to point to the decoded Index only if decoding is successful.
+ // Before that, keep it NULL so that applications can always safely
+ // pass it to lzma_index_end() no matter did decoding succeed or not.
+ coder->index_ptr = i;
+ *i = NULL;
+
+ // We always allocate a new lzma_index.
+ coder->index = lzma_index_init(allocator);
+ if (coder->index == NULL)
+ return LZMA_MEM_ERROR;
+
+ // Initialize the rest.
+ coder->sequence = SEQ_INDICATOR;
+ coder->memlimit = memlimit;
+ coder->count = 0; // Needs to be initialized due to _memconfig().
+ coder->pos = 0;
+ coder->crc32 = 0;
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+index_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ lzma_index **i, uint64_t memlimit)
+{
+ lzma_next_coder_init(&index_decoder_init, next, allocator);
+
+ if (i == NULL || memlimit == 0)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &index_decode;
+ next->end = &index_decoder_end;
+ next->memconfig = &index_decoder_memconfig;
+ next->coder->index = NULL;
+ } else {
+ lzma_index_end(next->coder->index, allocator);
+ }
+
+ return index_decoder_reset(next->coder, allocator, i, memlimit);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_decoder(lzma_stream *strm, lzma_index **i, uint64_t memlimit)
+{
+ lzma_next_strm_init2(index_decoder_init, strm, i, memlimit);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_buffer_decode(
+ lzma_index **i, uint64_t *memlimit, lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size)
+{
+ lzma_coder coder;
+ lzma_ret ret;
+
+ // Store the input start position so that we can restore it in case
+ // of an error.
+ const size_t in_start = *in_pos;
+
+ // Sanity checks
+ if (i == NULL || memlimit == NULL
+ || in == NULL || in_pos == NULL || *in_pos > in_size)
+ return LZMA_PROG_ERROR;
+
+ // Initialize the decoder.
+ return_if_error(index_decoder_reset(&coder, allocator, i, *memlimit));
+
+ // Do the actual decoding.
+ ret = index_decode(&coder, allocator, in, in_pos, in_size,
+ NULL, NULL, 0, LZMA_RUN);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ // Something went wrong, free the Index structure and restore
+ // the input position.
+ lzma_index_end(coder.index, allocator);
+ *in_pos = in_start;
+
+ if (ret == LZMA_OK) {
+ // The input is truncated or otherwise corrupt.
+ // Use LZMA_DATA_ERROR instead of LZMA_BUF_ERROR
+ // like lzma_vli_decode() does in single-call mode.
+ ret = LZMA_DATA_ERROR;
+
+ } else if (ret == LZMA_MEMLIMIT_ERROR) {
+ // Tell the caller how much memory would have
+ // been needed.
+ *memlimit = lzma_index_memusage(1, coder.count);
+ }
+ }
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/index_encoder.c b/Utilities/cmliblzma/liblzma/common/index_encoder.c
new file mode 100644
index 000000000..194bf2113
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index_encoder.c
@@ -0,0 +1,257 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index_encoder.c
+/// \brief Encodes the Index field
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index_encoder.h"
+#include "index.h"
+#include "check.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_INDICATOR,
+ SEQ_COUNT,
+ SEQ_UNPADDED,
+ SEQ_UNCOMPRESSED,
+ SEQ_NEXT,
+ SEQ_PADDING,
+ SEQ_CRC32,
+ } sequence;
+
+ /// Index being encoded
+ const lzma_index *index;
+
+ /// Iterator for the Index being encoded
+ lzma_index_iter iter;
+
+ /// Position in integers
+ size_t pos;
+
+ /// CRC32 of the List of Records field
+ uint32_t crc32;
+};
+
+
+static lzma_ret
+index_encode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((__unused__)),
+ const uint8_t *LZMA_RESTRICT in lzma_attribute((__unused__)),
+ size_t *LZMA_RESTRICT in_pos lzma_attribute((__unused__)),
+ size_t in_size lzma_attribute((__unused__)),
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size,
+ lzma_action action lzma_attribute((__unused__)))
+{
+ // Position where to start calculating CRC32. The idea is that we
+ // need to call lzma_crc32() only once per call to index_encode().
+ const size_t out_start = *out_pos;
+
+ // Return value to use if we return at the end of this function.
+ // We use "goto out" to jump out of the while-switch construct
+ // instead of returning directly, because that way we don't need
+ // to copypaste the lzma_crc32() call to many places.
+ lzma_ret ret = LZMA_OK;
+
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_INDICATOR:
+ out[*out_pos] = 0x00;
+ ++*out_pos;
+ coder->sequence = SEQ_COUNT;
+ break;
+
+ case SEQ_COUNT: {
+ const lzma_vli count = lzma_index_block_count(coder->index);
+ ret = lzma_vli_encode(count, &coder->pos,
+ out, out_pos, out_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ ret = LZMA_OK;
+ coder->pos = 0;
+ coder->sequence = SEQ_NEXT;
+ break;
+ }
+
+ case SEQ_NEXT:
+ if (lzma_index_iter_next(
+ &coder->iter, LZMA_INDEX_ITER_BLOCK)) {
+ // Get the size of the Index Padding field.
+ coder->pos = lzma_index_padding_size(coder->index);
+ assert(coder->pos <= 3);
+ coder->sequence = SEQ_PADDING;
+ break;
+ }
+
+ coder->sequence = SEQ_UNPADDED;
+
+ // Fall through
+
+ case SEQ_UNPADDED:
+ case SEQ_UNCOMPRESSED: {
+ const lzma_vli size = coder->sequence == SEQ_UNPADDED
+ ? coder->iter.block.unpadded_size
+ : coder->iter.block.uncompressed_size;
+
+ ret = lzma_vli_encode(size, &coder->pos,
+ out, out_pos, out_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ ret = LZMA_OK;
+ coder->pos = 0;
+
+ // Advance to SEQ_UNCOMPRESSED or SEQ_NEXT.
+ ++coder->sequence;
+ break;
+ }
+
+ case SEQ_PADDING:
+ if (coder->pos > 0) {
+ --coder->pos;
+ out[(*out_pos)++] = 0x00;
+ break;
+ }
+
+ // Finish the CRC32 calculation.
+ coder->crc32 = lzma_crc32(out + out_start,
+ *out_pos - out_start, coder->crc32);
+
+ coder->sequence = SEQ_CRC32;
+
+ // Fall through
+
+ case SEQ_CRC32:
+ // We don't use the main loop, because we don't want
+ // coder->crc32 to be touched anymore.
+ do {
+ if (*out_pos == out_size)
+ return LZMA_OK;
+
+ out[*out_pos] = (coder->crc32 >> (coder->pos * 8))
+ & 0xFF;
+ ++*out_pos;
+
+ } while (++coder->pos < 4);
+
+ return LZMA_STREAM_END;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+out:
+ // Update the CRC32.
+ coder->crc32 = lzma_crc32(out + out_start,
+ *out_pos - out_start, coder->crc32);
+
+ return ret;
+}
+
+
+static void
+index_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static void
+index_encoder_reset(lzma_coder *coder, const lzma_index *i)
+{
+ lzma_index_iter_init(&coder->iter, i);
+
+ coder->sequence = SEQ_INDICATOR;
+ coder->index = i;
+ coder->pos = 0;
+ coder->crc32 = 0;
+
+ return;
+}
+
+
+extern lzma_ret
+lzma_index_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_index *i)
+{
+ lzma_next_coder_init(&lzma_index_encoder_init, next, allocator);
+
+ if (i == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &index_encode;
+ next->end = &index_encoder_end;
+ }
+
+ index_encoder_reset(next->coder, i);
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_encoder(lzma_stream *strm, const lzma_index *i)
+{
+ lzma_next_strm_init1(lzma_index_encoder_init, strm, i);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_buffer_encode(const lzma_index *i,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ lzma_coder coder;
+ size_t out_start;
+ lzma_ret ret;
+
+ // Validate the arguments.
+ if (i == NULL || out == NULL || out_pos == NULL || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // Don't try to encode if there's not enough output space.
+ if (out_size - *out_pos < lzma_index_size(i))
+ return LZMA_BUF_ERROR;
+
+ // The Index encoder needs just one small data structure so we can
+ // allocate it on stack.
+ index_encoder_reset(&coder, i);
+
+ // Do the actual encoding. This should never fail, but store
+ // the original *out_pos just in case.
+ out_start = *out_pos;
+ ret = index_encode(&coder, NULL, NULL, NULL, 0,
+ out, out_pos, out_size, LZMA_RUN);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ // We should never get here, but just in case, restore the
+ // output position and set the error accordingly if something
+ // goes wrong and debugging isn't enabled.
+ assert(0);
+ *out_pos = out_start;
+ ret = LZMA_PROG_ERROR;
+ }
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/index_encoder.h b/Utilities/cmliblzma/liblzma/common/index_encoder.h
new file mode 100644
index 000000000..a13c94dcd
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index_encoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index_encoder.h
+/// \brief Encodes the Index field
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_INDEX_ENCODER_H
+#define LZMA_INDEX_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_index_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_index *i);
+
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/index_hash.c b/Utilities/cmliblzma/liblzma/common/index_hash.c
new file mode 100644
index 000000000..0cf86b307
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/index_hash.c
@@ -0,0 +1,336 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file index_hash.c
+/// \brief Validates Index by using a hash function
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+#include "index.h"
+#include "check.h"
+
+
+typedef struct {
+ /// Sum of the Block sizes (including Block Padding)
+ lzma_vli blocks_size;
+
+ /// Sum of the Uncompressed Size fields
+ lzma_vli uncompressed_size;
+
+ /// Number of Records
+ lzma_vli count;
+
+ /// Size of the List of Index Records as bytes
+ lzma_vli index_list_size;
+
+ /// Check calculated from Unpadded Sizes and Uncompressed Sizes.
+ lzma_check_state check;
+
+} lzma_index_hash_info;
+
+
+struct lzma_index_hash_s {
+ enum {
+ SEQ_BLOCK,
+ SEQ_COUNT,
+ SEQ_UNPADDED,
+ SEQ_UNCOMPRESSED,
+ SEQ_PADDING_INIT,
+ SEQ_PADDING,
+ SEQ_CRC32,
+ } sequence;
+
+ /// Information collected while decoding the actual Blocks.
+ lzma_index_hash_info blocks;
+
+ /// Information collected from the Index field.
+ lzma_index_hash_info records;
+
+ /// Number of Records not fully decoded
+ lzma_vli remaining;
+
+ /// Unpadded Size currently being read from an Index Record.
+ lzma_vli unpadded_size;
+
+ /// Uncompressed Size currently being read from an Index Record.
+ lzma_vli uncompressed_size;
+
+ /// Position in variable-length integers when decoding them from
+ /// the List of Records.
+ size_t pos;
+
+ /// CRC32 of the Index
+ uint32_t crc32;
+};
+
+
+extern LZMA_API(lzma_index_hash *)
+lzma_index_hash_init(lzma_index_hash *index_hash, lzma_allocator *allocator)
+{
+ if (index_hash == NULL) {
+ index_hash = lzma_alloc(sizeof(lzma_index_hash), allocator);
+ if (index_hash == NULL)
+ return NULL;
+ }
+
+ index_hash->sequence = SEQ_BLOCK;
+ index_hash->blocks.blocks_size = 0;
+ index_hash->blocks.uncompressed_size = 0;
+ index_hash->blocks.count = 0;
+ index_hash->blocks.index_list_size = 0;
+ index_hash->records.blocks_size = 0;
+ index_hash->records.uncompressed_size = 0;
+ index_hash->records.count = 0;
+ index_hash->records.index_list_size = 0;
+ index_hash->unpadded_size = 0;
+ index_hash->uncompressed_size = 0;
+ index_hash->pos = 0;
+ index_hash->crc32 = 0;
+
+ // These cannot fail because LZMA_CHECK_BEST is known to be supported.
+ (void)lzma_check_init(&index_hash->blocks.check, LZMA_CHECK_BEST);
+ (void)lzma_check_init(&index_hash->records.check, LZMA_CHECK_BEST);
+
+ return index_hash;
+}
+
+
+extern LZMA_API(void)
+lzma_index_hash_end(lzma_index_hash *index_hash, lzma_allocator *allocator)
+{
+ lzma_free(index_hash, allocator);
+ return;
+}
+
+
+extern LZMA_API(lzma_vli)
+lzma_index_hash_size(const lzma_index_hash *index_hash)
+{
+ // Get the size of the Index from ->blocks instead of ->records for
+ // cases where application wants to know the Index Size before
+ // decoding the Index.
+ return index_size(index_hash->blocks.count,
+ index_hash->blocks.index_list_size);
+}
+
+
+/// Updates the sizes and the hash without any validation.
+static lzma_ret
+hash_append(lzma_index_hash_info *info, lzma_vli unpadded_size,
+ lzma_vli uncompressed_size)
+{
+ const lzma_vli sizes[2] = { unpadded_size, uncompressed_size };
+
+ info->blocks_size += vli_ceil4(unpadded_size);
+ info->uncompressed_size += uncompressed_size;
+ info->index_list_size += lzma_vli_size(unpadded_size)
+ + lzma_vli_size(uncompressed_size);
+ ++info->count;
+
+ lzma_check_update(&info->check, LZMA_CHECK_BEST,
+ (const uint8_t *)(sizes), sizeof(sizes));
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_hash_append(lzma_index_hash *index_hash, lzma_vli unpadded_size,
+ lzma_vli uncompressed_size)
+{
+ // Validate the arguments.
+ if (index_hash->sequence != SEQ_BLOCK
+ || unpadded_size < UNPADDED_SIZE_MIN
+ || unpadded_size > UNPADDED_SIZE_MAX
+ || uncompressed_size > LZMA_VLI_MAX)
+ return LZMA_PROG_ERROR;
+
+ // Update the hash.
+ return_if_error(hash_append(&index_hash->blocks,
+ unpadded_size, uncompressed_size));
+
+ // Validate the properties of *info are still in allowed limits.
+ if (index_hash->blocks.blocks_size > LZMA_VLI_MAX
+ || index_hash->blocks.uncompressed_size > LZMA_VLI_MAX
+ || index_size(index_hash->blocks.count,
+ index_hash->blocks.index_list_size)
+ > LZMA_BACKWARD_SIZE_MAX
+ || index_stream_size(index_hash->blocks.blocks_size,
+ index_hash->blocks.count,
+ index_hash->blocks.index_list_size)
+ > LZMA_VLI_MAX)
+ return LZMA_DATA_ERROR;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_index_hash_decode(lzma_index_hash *index_hash, const uint8_t *in,
+ size_t *in_pos, size_t in_size)
+{
+ size_t in_start;
+ lzma_ret ret;
+
+ // Catch zero input buffer here, because in contrast to Index encoder
+ // and decoder functions, applications call this function directly
+ // instead of via lzma_code(), which does the buffer checking.
+ if (*in_pos >= in_size)
+ return LZMA_BUF_ERROR;
+
+ // NOTE: This function has many similarities to index_encode() and
+ // index_decode() functions found from index_encoder.c and
+ // index_decoder.c. See the comments especially in index_encoder.c.
+ in_start = *in_pos;
+ ret = LZMA_OK;
+
+ while (*in_pos < in_size)
+ switch (index_hash->sequence) {
+ case SEQ_BLOCK:
+ // Check the Index Indicator is present.
+ if (in[(*in_pos)++] != 0x00)
+ return LZMA_DATA_ERROR;
+
+ index_hash->sequence = SEQ_COUNT;
+ break;
+
+ case SEQ_COUNT: {
+ ret = lzma_vli_decode(&index_hash->remaining,
+ &index_hash->pos, in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ // The count must match the count of the Blocks decoded.
+ if (index_hash->remaining != index_hash->blocks.count)
+ return LZMA_DATA_ERROR;
+
+ ret = LZMA_OK;
+ index_hash->pos = 0;
+
+ // Handle the special case when there are no Blocks.
+ index_hash->sequence = index_hash->remaining == 0
+ ? SEQ_PADDING_INIT : SEQ_UNPADDED;
+ break;
+ }
+
+ case SEQ_UNPADDED:
+ case SEQ_UNCOMPRESSED: {
+ lzma_vli *size = index_hash->sequence == SEQ_UNPADDED
+ ? &index_hash->unpadded_size
+ : &index_hash->uncompressed_size;
+
+ ret = lzma_vli_decode(size, &index_hash->pos,
+ in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ goto out;
+
+ ret = LZMA_OK;
+ index_hash->pos = 0;
+
+ if (index_hash->sequence == SEQ_UNPADDED) {
+ if (index_hash->unpadded_size < UNPADDED_SIZE_MIN
+ || index_hash->unpadded_size
+ > UNPADDED_SIZE_MAX)
+ return LZMA_DATA_ERROR;
+
+ index_hash->sequence = SEQ_UNCOMPRESSED;
+ } else {
+ // Update the hash.
+ return_if_error(hash_append(&index_hash->records,
+ index_hash->unpadded_size,
+ index_hash->uncompressed_size));
+
+ // Verify that we don't go over the known sizes. Note
+ // that this validation is simpler than the one used
+ // in lzma_index_hash_append(), because here we know
+ // that values in index_hash->blocks are already
+ // validated and we are fine as long as we don't
+ // exceed them in index_hash->records.
+ if (index_hash->blocks.blocks_size
+ < index_hash->records.blocks_size
+ || index_hash->blocks.uncompressed_size
+ < index_hash->records.uncompressed_size
+ || index_hash->blocks.index_list_size
+ < index_hash->records.index_list_size)
+ return LZMA_DATA_ERROR;
+
+ // Check if this was the last Record.
+ index_hash->sequence = --index_hash->remaining == 0
+ ? SEQ_PADDING_INIT : SEQ_UNPADDED;
+ }
+
+ break;
+ }
+
+ case SEQ_PADDING_INIT:
+ index_hash->pos = (LZMA_VLI_C(4) - index_size_unpadded(
+ index_hash->records.count,
+ index_hash->records.index_list_size)) & 3;
+ index_hash->sequence = SEQ_PADDING;
+
+ // Fall through
+
+ case SEQ_PADDING:
+ if (index_hash->pos > 0) {
+ --index_hash->pos;
+ if (in[(*in_pos)++] != 0x00)
+ return LZMA_DATA_ERROR;
+
+ break;
+ }
+
+ // Compare the sizes.
+ if (index_hash->blocks.blocks_size
+ != index_hash->records.blocks_size
+ || index_hash->blocks.uncompressed_size
+ != index_hash->records.uncompressed_size
+ || index_hash->blocks.index_list_size
+ != index_hash->records.index_list_size)
+ return LZMA_DATA_ERROR;
+
+ // Finish the hashes and compare them.
+ lzma_check_finish(&index_hash->blocks.check, LZMA_CHECK_BEST);
+ lzma_check_finish(&index_hash->records.check, LZMA_CHECK_BEST);
+ if (memcmp(index_hash->blocks.check.buffer.u8,
+ index_hash->records.check.buffer.u8,
+ lzma_check_size(LZMA_CHECK_BEST)) != 0)
+ return LZMA_DATA_ERROR;
+
+ // Finish the CRC32 calculation.
+ index_hash->crc32 = lzma_crc32(in + in_start,
+ *in_pos - in_start, index_hash->crc32);
+
+ index_hash->sequence = SEQ_CRC32;
+
+ // Fall through
+
+ case SEQ_CRC32:
+ do {
+ if (*in_pos == in_size)
+ return LZMA_OK;
+
+ if (((index_hash->crc32 >> (index_hash->pos * 8))
+ & 0xFF) != in[(*in_pos)++])
+ return LZMA_DATA_ERROR;
+
+ } while (++index_hash->pos < 4);
+
+ return LZMA_STREAM_END;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+out:
+ // Update the CRC32,
+ index_hash->crc32 = lzma_crc32(in + in_start,
+ *in_pos - in_start, index_hash->crc32);
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_buffer_decoder.c b/Utilities/cmliblzma/liblzma/common/stream_buffer_decoder.c
new file mode 100644
index 000000000..9e2e1da83
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_buffer_decoder.c
@@ -0,0 +1,93 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_buffer_decoder.c
+/// \brief Single-call .xz Stream decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_buffer_decode(uint64_t *memlimit, uint32_t flags,
+ lzma_allocator *allocator,
+ const uint8_t *in, size_t *in_pos, size_t in_size,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ lzma_next_coder stream_decoder = LZMA_NEXT_CODER_INIT;
+ lzma_ret ret;
+
+ // Sanity checks
+ if (in_pos == NULL || (in == NULL && *in_pos != in_size)
+ || *in_pos > in_size || out_pos == NULL
+ || (out == NULL && *out_pos != out_size)
+ || *out_pos > out_size)
+ return LZMA_PROG_ERROR;
+
+ // Catch flags that are not allowed in buffer-to-buffer decoding.
+ if (flags & LZMA_TELL_ANY_CHECK)
+ return LZMA_PROG_ERROR;
+
+ // Initialize the Stream decoder.
+ // TODO: We need something to tell the decoder that it can use the
+ // output buffer as workspace, and thus save significant amount of RAM.
+ ret = lzma_stream_decoder_init(
+ &stream_decoder, allocator, *memlimit, flags);
+
+ if (ret == LZMA_OK) {
+ // Save the positions so that we can restore them in case
+ // an error occurs.
+ const size_t in_start = *in_pos;
+ const size_t out_start = *out_pos;
+
+ // Do the actual decoding.
+ ret = stream_decoder.code(stream_decoder.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ LZMA_FINISH);
+
+ if (ret == LZMA_STREAM_END) {
+ ret = LZMA_OK;
+ } else {
+ // Something went wrong, restore the positions.
+ *in_pos = in_start;
+ *out_pos = out_start;
+
+ if (ret == LZMA_OK) {
+ // Either the input was truncated or the
+ // output buffer was too small.
+ assert(*in_pos == in_size
+ || *out_pos == out_size);
+
+ // If all the input was consumed, then the
+ // input is truncated, even if the output
+ // buffer is also full. This is because
+ // processing the last byte of the Stream
+ // never produces output.
+ if (*in_pos == in_size)
+ ret = LZMA_DATA_ERROR;
+ else
+ ret = LZMA_BUF_ERROR;
+
+ } else if (ret == LZMA_MEMLIMIT_ERROR) {
+ // Let the caller know how much memory would
+ // have been needed.
+ uint64_t memusage;
+ (void)stream_decoder.memconfig(
+ stream_decoder.coder,
+ memlimit, &memusage, 0);
+ }
+ }
+ }
+
+ // Free the decoder memory. This needs to be done even if
+ // initialization fails, because the internal API doesn't
+ // require the initialization function to free its memory on error.
+ lzma_next_end(&stream_decoder, allocator);
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_buffer_encoder.c b/Utilities/cmliblzma/liblzma/common/stream_buffer_encoder.c
new file mode 100644
index 000000000..8bca87f47
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_buffer_encoder.c
@@ -0,0 +1,140 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_buffer_encoder.c
+/// \brief Single-call .xz Stream encoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "index.h"
+
+
+/// Maximum size of Index that has exactly one Record.
+/// Index Indicator + Number of Records + Record + CRC32 rounded up to
+/// the next multiple of four.
+#define INDEX_BOUND ((1 + 1 + 2 * LZMA_VLI_BYTES_MAX + 4 + 3) & ~3)
+
+/// Stream Header, Stream Footer, and Index
+#define HEADERS_BOUND (2 * LZMA_STREAM_HEADER_SIZE + INDEX_BOUND)
+
+
+extern LZMA_API(size_t)
+lzma_stream_buffer_bound(size_t uncompressed_size)
+{
+ // Get the maximum possible size of a Block.
+ const size_t block_bound = lzma_block_buffer_bound(uncompressed_size);
+ if (block_bound == 0)
+ return 0;
+
+ // Catch the possible integer overflow and also prevent the size of
+ // the Stream exceeding LZMA_VLI_MAX (theoretically possible on
+ // 64-bit systems).
+ if (my_min(SIZE_MAX, LZMA_VLI_MAX) - block_bound < HEADERS_BOUND)
+ return 0;
+
+ return block_bound + HEADERS_BOUND;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_buffer_encode(lzma_filter *filters, lzma_check check,
+ lzma_allocator *allocator, const uint8_t *in, size_t in_size,
+ uint8_t *out, size_t *out_pos_ptr, size_t out_size)
+{
+ lzma_stream_flags stream_flags = { 0 };
+ lzma_block block = { 0 };
+ size_t out_pos;
+
+ // Sanity checks
+ if (filters == NULL || (unsigned int)(check) > LZMA_CHECK_ID_MAX
+ || (in == NULL && in_size != 0) || out == NULL
+ || out_pos_ptr == NULL || *out_pos_ptr > out_size)
+ return LZMA_PROG_ERROR;
+
+ if (!lzma_check_is_supported(check))
+ return LZMA_UNSUPPORTED_CHECK;
+
+ // Note for the paranoids: Index encoder prevents the Stream from
+ // getting too big and still being accepted with LZMA_OK, and Block
+ // encoder catches if the input is too big. So we don't need to
+ // separately check if the buffers are too big.
+
+ // Use a local copy. We update *out_pos_ptr only if everything
+ // succeeds.
+ out_pos = *out_pos_ptr;
+
+ // Check that there's enough space for both Stream Header and
+ // Stream Footer.
+ if (out_size - out_pos <= 2 * LZMA_STREAM_HEADER_SIZE)
+ return LZMA_BUF_ERROR;
+
+ // Reserve space for Stream Footer so we don't need to check for
+ // available space again before encoding Stream Footer.
+ out_size -= LZMA_STREAM_HEADER_SIZE;
+
+ // Encode the Stream Header.
+ stream_flags.check = check;
+
+ if (lzma_stream_header_encode(&stream_flags, out + out_pos)
+ != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ out_pos += LZMA_STREAM_HEADER_SIZE;
+
+ // Encode a Block but only if there is at least one byte of input.
+ block.check = check;
+ block.filters = filters;
+
+ if (in_size > 0)
+ return_if_error(lzma_block_buffer_encode(&block, allocator,
+ in, in_size, out, &out_pos, out_size));
+
+ // Index
+ {
+ lzma_ret ret;
+
+ // Create an Index. It will have one Record if there was
+ // at least one byte of input to encode. Otherwise the
+ // Index will be empty.
+ lzma_index *i = lzma_index_init(allocator);
+ if (i == NULL)
+ return LZMA_MEM_ERROR;
+
+ ret = LZMA_OK;
+
+ if (in_size > 0)
+ ret = lzma_index_append(i, allocator,
+ lzma_block_unpadded_size(&block),
+ block.uncompressed_size);
+
+ // If adding the Record was successful, encode the Index
+ // and get its size which will be stored into Stream Footer.
+ if (ret == LZMA_OK) {
+ ret = lzma_index_buffer_encode(
+ i, out, &out_pos, out_size);
+
+ stream_flags.backward_size = lzma_index_size(i);
+ }
+
+ lzma_index_end(i, allocator);
+
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ // Stream Footer. We have already reserved space for this.
+ if (lzma_stream_footer_encode(&stream_flags, out + out_pos)
+ != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ out_pos += LZMA_STREAM_HEADER_SIZE;
+
+ // Everything went fine, make the new output position available
+ // to the application.
+ *out_pos_ptr = out_pos;
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_decoder.c b/Utilities/cmliblzma/liblzma/common/stream_decoder.c
new file mode 100644
index 000000000..5e9a22069
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_decoder.c
@@ -0,0 +1,459 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_decoder.c
+/// \brief Decodes .xz Streams
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_decoder.h"
+#include "block_decoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK,
+ SEQ_INDEX,
+ SEQ_STREAM_FOOTER,
+ SEQ_STREAM_PADDING,
+ } sequence;
+
+ /// Block or Metadata decoder. This takes little memory and the same
+ /// data structure can be used to decode every Block Header, so it's
+ /// a good idea to have a separate lzma_next_coder structure for it.
+ lzma_next_coder block_decoder;
+
+ /// Block options decoded by the Block Header decoder and used by
+ /// the Block decoder.
+ lzma_block block_options;
+
+ /// Stream Flags from Stream Header
+ lzma_stream_flags stream_flags;
+
+ /// Index is hashed so that it can be compared to the sizes of Blocks
+ /// with O(1) memory usage.
+ lzma_index_hash *index_hash;
+
+ /// Memory usage limit
+ uint64_t memlimit;
+
+ /// Amount of memory actually needed (only an estimate)
+ uint64_t memusage;
+
+ /// If true, LZMA_NO_CHECK is returned if the Stream has
+ /// no integrity check.
+ bool tell_no_check;
+
+ /// If true, LZMA_UNSUPPORTED_CHECK is returned if the Stream has
+ /// an integrity check that isn't supported by this liblzma build.
+ bool tell_unsupported_check;
+
+ /// If true, LZMA_GET_CHECK is returned after decoding Stream Header.
+ bool tell_any_check;
+
+ /// If true, we will decode concatenated Streams that possibly have
+ /// Stream Padding between or after them. LZMA_STREAM_END is returned
+ /// once the application isn't giving us any new input, and we aren't
+ /// in the middle of a Stream, and possible Stream Padding is a
+ /// multiple of four bytes.
+ bool concatenated;
+
+ /// When decoding concatenated Streams, this is true as long as we
+ /// are decoding the first Stream. This is needed to avoid misleading
+ /// LZMA_FORMAT_ERROR in case the later Streams don't have valid magic
+ /// bytes.
+ bool first_stream;
+
+ /// Write position in buffer[] and position in Stream Padding
+ size_t pos;
+
+ /// Buffer to hold Stream Header, Block Header, and Stream Footer.
+ /// Block Header has biggest maximum size.
+ uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
+};
+
+
+static lzma_ret
+stream_decoder_reset(lzma_coder *coder, lzma_allocator *allocator)
+{
+ // Initialize the Index hash used to verify the Index.
+ coder->index_hash = lzma_index_hash_init(coder->index_hash, allocator);
+ if (coder->index_hash == NULL)
+ return LZMA_MEM_ERROR;
+
+ // Reset the rest of the variables.
+ coder->sequence = SEQ_STREAM_HEADER;
+ coder->pos = 0;
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+stream_decode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ // When decoding the actual Block, it may be able to produce more
+ // output even if we don't give it any new input.
+ while (true)
+ switch (coder->sequence) {
+ case SEQ_STREAM_HEADER: {
+ lzma_ret ret;
+
+ // Copy the Stream Header to the internal buffer.
+ lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+ LZMA_STREAM_HEADER_SIZE);
+
+ // Return if we didn't get the whole Stream Header yet.
+ if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+ return LZMA_OK;
+
+ coder->pos = 0;
+
+ // Decode the Stream Header.
+ ret = lzma_stream_header_decode(
+ &coder->stream_flags, coder->buffer);
+ if (ret != LZMA_OK)
+ return ret == LZMA_FORMAT_ERROR && !coder->first_stream
+ ? LZMA_DATA_ERROR : ret;
+
+ // If we are decoding concatenated Streams, and the later
+ // Streams have invalid Header Magic Bytes, we give
+ // LZMA_DATA_ERROR instead of LZMA_FORMAT_ERROR.
+ coder->first_stream = false;
+
+ // Copy the type of the Check so that Block Header and Block
+ // decoders see it.
+ coder->block_options.check = coder->stream_flags.check;
+
+ // Even if we return LZMA_*_CHECK below, we want
+ // to continue from Block Header decoding.
+ coder->sequence = SEQ_BLOCK_HEADER;
+
+ // Detect if there's no integrity check or if it is
+ // unsupported if those were requested by the application.
+ if (coder->tell_no_check && coder->stream_flags.check
+ == LZMA_CHECK_NONE)
+ return LZMA_NO_CHECK;
+
+ if (coder->tell_unsupported_check
+ && !lzma_check_is_supported(
+ coder->stream_flags.check))
+ return LZMA_UNSUPPORTED_CHECK;
+
+ if (coder->tell_any_check)
+ return LZMA_GET_CHECK;
+ }
+
+ // Fall through
+
+ case SEQ_BLOCK_HEADER: {
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+ uint64_t memusage;
+ lzma_ret ret;
+ size_t i;
+
+ if (*in_pos >= in_size)
+ return LZMA_OK;
+
+ if (coder->pos == 0) {
+ // Detect if it's Index.
+ if (in[*in_pos] == 0x00) {
+ coder->sequence = SEQ_INDEX;
+ break;
+ }
+
+ // Calculate the size of the Block Header. Note that
+ // Block Header decoder wants to see this byte too
+ // so don't advance *in_pos.
+ coder->block_options.header_size
+ = lzma_block_header_size_decode(
+ in[*in_pos]);
+ }
+
+ // Copy the Block Header to the internal buffer.
+ lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+ coder->block_options.header_size);
+
+ // Return if we didn't get the whole Block Header yet.
+ if (coder->pos < coder->block_options.header_size)
+ return LZMA_OK;
+
+ coder->pos = 0;
+
+ // Version 0 is currently the only possible version.
+ coder->block_options.version = 0;
+
+ // Set up a buffer to hold the filter chain. Block Header
+ // decoder will initialize all members of this array so
+ // we don't need to do it here.
+ coder->block_options.filters = filters;
+
+ // Decode the Block Header.
+ return_if_error(lzma_block_header_decode(&coder->block_options,
+ allocator, coder->buffer));
+
+ // Check the memory usage limit.
+ memusage = lzma_raw_decoder_memusage(filters);
+ if (memusage == UINT64_MAX) {
+ // One or more unknown Filter IDs.
+ ret = LZMA_OPTIONS_ERROR;
+ } else {
+ // Now we can set coder->memusage since we know that
+ // the filter chain is valid. We don't want
+ // lzma_memusage() to return UINT64_MAX in case of
+ // invalid filter chain.
+ coder->memusage = memusage;
+
+ if (memusage > coder->memlimit) {
+ // The chain would need too much memory.
+ ret = LZMA_MEMLIMIT_ERROR;
+ } else {
+ // Memory usage is OK.
+ // Initialize the Block decoder.
+ ret = lzma_block_decoder_init(
+ &coder->block_decoder,
+ allocator,
+ &coder->block_options);
+ }
+ }
+
+ // Free the allocated filter options since they are needed
+ // only to initialize the Block decoder.
+ for (i = 0; i < LZMA_FILTERS_MAX; ++i)
+ lzma_free(filters[i].options, allocator);
+
+ coder->block_options.filters = NULL;
+
+ // Check if memory usage calculation and Block enocoder
+ // initialization succeeded.
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->sequence = SEQ_BLOCK;
+ }
+
+ // Fall through
+
+ case SEQ_BLOCK: {
+ const lzma_ret ret = coder->block_decoder.code(
+ coder->block_decoder.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ // Block decoded successfully. Add the new size pair to
+ // the Index hash.
+ return_if_error(lzma_index_hash_append(coder->index_hash,
+ lzma_block_unpadded_size(
+ &coder->block_options),
+ coder->block_options.uncompressed_size));
+
+ coder->sequence = SEQ_BLOCK_HEADER;
+ break;
+ }
+
+ case SEQ_INDEX: {
+ lzma_ret ret;
+
+ // If we don't have any input, don't call
+ // lzma_index_hash_decode() since it would return
+ // LZMA_BUF_ERROR, which we must not do here.
+ if (*in_pos >= in_size)
+ return LZMA_OK;
+
+ // Decode the Index and compare it to the hash calculated
+ // from the sizes of the Blocks (if any).
+ ret = lzma_index_hash_decode(coder->index_hash,
+ in, in_pos, in_size);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ coder->sequence = SEQ_STREAM_FOOTER;
+ }
+
+ // Fall through
+
+ case SEQ_STREAM_FOOTER: {
+ lzma_stream_flags footer_flags;
+ lzma_ret ret;
+
+ // Copy the Stream Footer to the internal buffer.
+ lzma_bufcpy(in, in_pos, in_size, coder->buffer, &coder->pos,
+ LZMA_STREAM_HEADER_SIZE);
+
+ // Return if we didn't get the whole Stream Footer yet.
+ if (coder->pos < LZMA_STREAM_HEADER_SIZE)
+ return LZMA_OK;
+
+ coder->pos = 0;
+
+ // Decode the Stream Footer. The decoder gives
+ // LZMA_FORMAT_ERROR if the magic bytes don't match,
+ // so convert that return code to LZMA_DATA_ERROR.
+ ret = lzma_stream_footer_decode(
+ &footer_flags, coder->buffer);
+ if (ret != LZMA_OK)
+ return ret == LZMA_FORMAT_ERROR
+ ? LZMA_DATA_ERROR : ret;
+
+ // Check that Index Size stored in the Stream Footer matches
+ // the real size of the Index field.
+ if (lzma_index_hash_size(coder->index_hash)
+ != footer_flags.backward_size)
+ return LZMA_DATA_ERROR;
+
+ // Compare that the Stream Flags fields are identical in
+ // both Stream Header and Stream Footer.
+ return_if_error(lzma_stream_flags_compare(
+ &coder->stream_flags, &footer_flags));
+
+ if (!coder->concatenated)
+ return LZMA_STREAM_END;
+
+ coder->sequence = SEQ_STREAM_PADDING;
+ }
+
+ // Fall through
+
+ case SEQ_STREAM_PADDING:
+ assert(coder->concatenated);
+
+ // Skip over possible Stream Padding.
+ while (true) {
+ if (*in_pos >= in_size) {
+ // Unless LZMA_FINISH was used, we cannot
+ // know if there's more input coming later.
+ if (action != LZMA_FINISH)
+ return LZMA_OK;
+
+ // Stream Padding must be a multiple of
+ // four bytes.
+ return coder->pos == 0
+ ? LZMA_STREAM_END
+ : LZMA_DATA_ERROR;
+ }
+
+ // If the byte is not zero, it probably indicates
+ // beginning of a new Stream (or the file is corrupt).
+ if (in[*in_pos] != 0x00)
+ break;
+
+ ++*in_pos;
+ coder->pos = (coder->pos + 1) & 3;
+ }
+
+ // Stream Padding must be a multiple of four bytes (empty
+ // Stream Padding is OK).
+ if (coder->pos != 0) {
+ ++*in_pos;
+ return LZMA_DATA_ERROR;
+ }
+
+ // Prepare to decode the next Stream.
+ return_if_error(stream_decoder_reset(coder, allocator));
+ break;
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ // Never reached
+}
+
+
+static void
+stream_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->block_decoder, allocator);
+ lzma_index_hash_end(coder->index_hash, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_check
+stream_decoder_get_check(const lzma_coder *coder)
+{
+ return coder->stream_flags.check;
+}
+
+
+static lzma_ret
+stream_decoder_memconfig(lzma_coder *coder, uint64_t *memusage,
+ uint64_t *old_memlimit, uint64_t new_memlimit)
+{
+ *memusage = coder->memusage;
+ *old_memlimit = coder->memlimit;
+
+ if (new_memlimit != 0) {
+ if (new_memlimit < coder->memusage)
+ return LZMA_MEMLIMIT_ERROR;
+
+ coder->memlimit = new_memlimit;
+ }
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_stream_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ uint64_t memlimit, uint32_t flags)
+{
+ lzma_next_coder_init(&lzma_stream_decoder_init, next, allocator);
+
+ if (memlimit == 0)
+ return LZMA_PROG_ERROR;
+
+ if (flags & ~LZMA_SUPPORTED_FLAGS)
+ return LZMA_OPTIONS_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &stream_decode;
+ next->end = &stream_decoder_end;
+ next->get_check = &stream_decoder_get_check;
+ next->memconfig = &stream_decoder_memconfig;
+
+ next->coder->block_decoder = LZMA_NEXT_CODER_INIT;
+ next->coder->index_hash = NULL;
+ }
+
+ next->coder->memlimit = memlimit;
+ next->coder->memusage = LZMA_MEMUSAGE_BASE;
+ next->coder->tell_no_check = (flags & LZMA_TELL_NO_CHECK) != 0;
+ next->coder->tell_unsupported_check
+ = (flags & LZMA_TELL_UNSUPPORTED_CHECK) != 0;
+ next->coder->tell_any_check = (flags & LZMA_TELL_ANY_CHECK) != 0;
+ next->coder->concatenated = (flags & LZMA_CONCATENATED) != 0;
+ next->coder->first_stream = true;
+
+ return stream_decoder_reset(next->coder, allocator);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_decoder(lzma_stream *strm, uint64_t memlimit, uint32_t flags)
+{
+ lzma_next_strm_init2(lzma_stream_decoder_init, strm, memlimit, flags);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_decoder.h b/Utilities/cmliblzma/liblzma/common/stream_decoder.h
new file mode 100644
index 000000000..e54ac28f4
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_decoder.h
@@ -0,0 +1,21 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_decoder.h
+/// \brief Decodes .xz Streams
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_DECODER_H
+#define LZMA_STREAM_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_stream_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, uint64_t memlimit, uint32_t flags);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/stream_encoder.c b/Utilities/cmliblzma/liblzma/common/stream_encoder.c
new file mode 100644
index 000000000..1ba45acec
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_encoder.c
@@ -0,0 +1,338 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_encoder.c
+/// \brief Encodes .xz Streams
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_encoder.h"
+#include "block_encoder.h"
+#include "index_encoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_STREAM_HEADER,
+ SEQ_BLOCK_INIT,
+ SEQ_BLOCK_HEADER,
+ SEQ_BLOCK_ENCODE,
+ SEQ_INDEX_ENCODE,
+ SEQ_STREAM_FOOTER,
+ } sequence;
+
+ /// True if Block encoder has been initialized by
+ /// lzma_stream_encoder_init() or stream_encoder_update()
+ /// and thus doesn't need to be initialized in stream_encode().
+ bool block_encoder_is_initialized;
+
+ /// Block
+ lzma_next_coder block_encoder;
+
+ /// Options for the Block encoder
+ lzma_block block_options;
+
+ /// The filter chain currently in use
+ lzma_filter filters[LZMA_FILTERS_MAX + 1];
+
+ /// Index encoder. This is separate from Block encoder, because this
+ /// doesn't take much memory, and when encoding multiple Streams
+ /// with the same encoding options we avoid reallocating memory.
+ lzma_next_coder index_encoder;
+
+ /// Index to hold sizes of the Blocks
+ lzma_index *index;
+
+ /// Read position in buffer[]
+ size_t buffer_pos;
+
+ /// Total number of bytes in buffer[]
+ size_t buffer_size;
+
+ /// Buffer to hold Stream Header, Block Header, and Stream Footer.
+ /// Block Header has biggest maximum size.
+ uint8_t buffer[LZMA_BLOCK_HEADER_SIZE_MAX];
+};
+
+
+static lzma_ret
+block_encoder_init(lzma_coder *coder, lzma_allocator *allocator)
+{
+ // Prepare the Block options. Even though Block encoder doesn't need
+ // compressed_size, uncompressed_size, and header_size to be
+ // initialized, it is a good idea to do it here, because this way
+ // we catch if someone gave us Filter ID that cannot be used in
+ // Blocks/Streams.
+ coder->block_options.compressed_size = LZMA_VLI_UNKNOWN;
+ coder->block_options.uncompressed_size = LZMA_VLI_UNKNOWN;
+
+ return_if_error(lzma_block_header_size(&coder->block_options));
+
+ // Initialize the actual Block encoder.
+ return lzma_block_encoder_init(&coder->block_encoder, allocator,
+ &coder->block_options);
+}
+
+
+static lzma_ret
+stream_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ // Main loop
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_STREAM_HEADER:
+ case SEQ_BLOCK_HEADER:
+ case SEQ_STREAM_FOOTER:
+ lzma_bufcpy(coder->buffer, &coder->buffer_pos,
+ coder->buffer_size, out, out_pos, out_size);
+ if (coder->buffer_pos < coder->buffer_size)
+ return LZMA_OK;
+
+ if (coder->sequence == SEQ_STREAM_FOOTER)
+ return LZMA_STREAM_END;
+
+ coder->buffer_pos = 0;
+ ++coder->sequence;
+ break;
+
+ case SEQ_BLOCK_INIT: {
+ if (*in_pos == in_size) {
+ // If we are requested to flush or finish the current
+ // Block, return LZMA_STREAM_END immediately since
+ // there's nothing to do.
+ if (action != LZMA_FINISH)
+ return action == LZMA_RUN
+ ? LZMA_OK : LZMA_STREAM_END;
+
+ // The application had used LZMA_FULL_FLUSH to finish
+ // the previous Block, but now wants to finish without
+ // encoding new data, or it is simply creating an
+ // empty Stream with no Blocks.
+ //
+ // Initialize the Index encoder, and continue to
+ // actually encoding the Index.
+ return_if_error(lzma_index_encoder_init(
+ &coder->index_encoder, allocator,
+ coder->index));
+ coder->sequence = SEQ_INDEX_ENCODE;
+ break;
+ }
+
+ // Initialize the Block encoder unless it was already
+ // initialized by lzma_stream_encoder_init() or
+ // stream_encoder_update().
+ if (!coder->block_encoder_is_initialized)
+ return_if_error(block_encoder_init(coder, allocator));
+
+ // Make it false so that we don't skip the initialization
+ // with the next Block.
+ coder->block_encoder_is_initialized = false;
+
+ // Encode the Block Header. This shouldn't fail since we have
+ // already initialized the Block encoder.
+ if (lzma_block_header_encode(&coder->block_options,
+ coder->buffer) != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ coder->buffer_size = coder->block_options.header_size;
+ coder->sequence = SEQ_BLOCK_HEADER;
+ break;
+ }
+
+ case SEQ_BLOCK_ENCODE: {
+ lzma_vli unpadded_size;
+
+ static const lzma_action convert[4] = {
+ LZMA_RUN,
+ LZMA_SYNC_FLUSH,
+ LZMA_FINISH,
+ LZMA_FINISH,
+ };
+
+ const lzma_ret ret = coder->block_encoder.code(
+ coder->block_encoder.coder, allocator,
+ in, in_pos, in_size,
+ out, out_pos, out_size, convert[action]);
+ if (ret != LZMA_STREAM_END || action == LZMA_SYNC_FLUSH)
+ return ret;
+
+ // Add a new Index Record.
+ unpadded_size = lzma_block_unpadded_size(
+ &coder->block_options);
+ assert(unpadded_size != 0);
+ return_if_error(lzma_index_append(coder->index, allocator,
+ unpadded_size,
+ coder->block_options.uncompressed_size));
+
+ coder->sequence = SEQ_BLOCK_INIT;
+ break;
+ }
+
+ case SEQ_INDEX_ENCODE: {
+ const lzma_stream_flags stream_flags = {
+ 0,
+ lzma_index_size(coder->index),
+ coder->block_options.check,
+ };
+
+ // Call the Index encoder. It doesn't take any input, so
+ // those pointers can be NULL.
+ const lzma_ret ret = coder->index_encoder.code(
+ coder->index_encoder.coder, allocator,
+ NULL, NULL, 0,
+ out, out_pos, out_size, LZMA_RUN);
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ // Encode the Stream Footer into coder->buffer.
+
+ if (lzma_stream_footer_encode(&stream_flags, coder->buffer)
+ != LZMA_OK)
+ return LZMA_PROG_ERROR;
+
+ coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
+ coder->sequence = SEQ_STREAM_FOOTER;
+ break;
+ }
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+stream_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ size_t i;
+
+ lzma_next_end(&coder->block_encoder, allocator);
+ lzma_next_end(&coder->index_encoder, allocator);
+ lzma_index_end(coder->index, allocator);
+
+ for (i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
+ lzma_free(coder->filters[i].options, allocator);
+
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+stream_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters,
+ const lzma_filter *reversed_filters)
+{
+ size_t i;
+
+ if (coder->sequence <= SEQ_BLOCK_INIT) {
+ lzma_ret ret;
+
+ // There is no incomplete Block waiting to be finished,
+ // thus we can change the whole filter chain. Start by
+ // trying to initialize the Block encoder with the new
+ // chain. This way we detect if the chain is valid.
+ coder->block_encoder_is_initialized = false;
+ coder->block_options.filters = (lzma_filter *)(filters);
+ ret = block_encoder_init(coder, allocator);
+ coder->block_options.filters = coder->filters;
+ if (ret != LZMA_OK)
+ return ret;
+
+ coder->block_encoder_is_initialized = true;
+
+ } else if (coder->sequence <= SEQ_BLOCK_ENCODE) {
+ // We are in the middle of a Block. Try to update only
+ // the filter-specific options.
+ return_if_error(coder->block_encoder.update(
+ coder->block_encoder.coder, allocator,
+ filters, reversed_filters));
+ } else {
+ // Trying to update the filter chain when we are already
+ // encoding Index or Stream Footer.
+ return LZMA_PROG_ERROR;
+ }
+
+ // Free the copy of the old chain and make a copy of the new chain.
+ for (i = 0; coder->filters[i].id != LZMA_VLI_UNKNOWN; ++i)
+ lzma_free(coder->filters[i].options, allocator);
+
+ return lzma_filters_copy(filters, coder->filters, allocator);
+}
+
+
+extern lzma_ret
+lzma_stream_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *filters, lzma_check check)
+{
+ lzma_stream_flags stream_flags = { 0, 0, check };
+
+ lzma_next_coder_init(&lzma_stream_encoder_init, next, allocator);
+
+ if (filters == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &stream_encode;
+ next->end = &stream_encoder_end;
+ next->update = &stream_encoder_update;
+
+ next->coder->filters[0].id = LZMA_VLI_UNKNOWN;
+ next->coder->block_encoder = LZMA_NEXT_CODER_INIT;
+ next->coder->index_encoder = LZMA_NEXT_CODER_INIT;
+ next->coder->index = NULL;
+ }
+
+ // Basic initializations
+ next->coder->sequence = SEQ_STREAM_HEADER;
+ next->coder->block_options.version = 0;
+ next->coder->block_options.check = check;
+
+ // Initialize the Index
+ lzma_index_end(next->coder->index, allocator);
+ next->coder->index = lzma_index_init(allocator);
+ if (next->coder->index == NULL)
+ return LZMA_MEM_ERROR;
+
+ // Encode the Stream Header
+ return_if_error(lzma_stream_header_encode(
+ &stream_flags, next->coder->buffer));
+
+ next->coder->buffer_pos = 0;
+ next->coder->buffer_size = LZMA_STREAM_HEADER_SIZE;
+
+ // Initialize the Block encoder. This way we detect unsupported
+ // filter chains when initializing the Stream encoder instead of
+ // giving an error after Stream Header has already written out.
+ return stream_encoder_update(
+ next->coder, allocator, filters, NULL);
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_encoder(lzma_stream *strm,
+ const lzma_filter *filters, lzma_check check)
+{
+ lzma_next_strm_init2(lzma_stream_encoder_init, strm, filters, check);
+
+ strm->internal->supported_actions[LZMA_RUN] = true;
+ strm->internal->supported_actions[LZMA_SYNC_FLUSH] = true;
+ strm->internal->supported_actions[LZMA_FULL_FLUSH] = true;
+ strm->internal->supported_actions[LZMA_FINISH] = true;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_encoder.h b/Utilities/cmliblzma/liblzma/common/stream_encoder.h
new file mode 100644
index 000000000..46a7aed72
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_encoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_encoder.h
+/// \brief Encodes .xz Streams
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_ENCODER_H
+#define LZMA_STREAM_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_stream_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter *filters, lzma_check check);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/stream_flags_common.c b/Utilities/cmliblzma/liblzma/common/stream_flags_common.c
new file mode 100644
index 000000000..fbe8eb8ab
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_flags_common.c
@@ -0,0 +1,47 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_common.c
+/// \brief Common stuff for Stream flags coders
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+const uint8_t lzma_header_magic[6] = { 0xFD, 0x37, 0x7A, 0x58, 0x5A, 0x00 };
+const uint8_t lzma_footer_magic[2] = { 0x59, 0x5A };
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_flags_compare(
+ const lzma_stream_flags *a, const lzma_stream_flags *b)
+{
+ // We can compare only version 0 structures.
+ if (a->version != 0 || b->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ // Check type
+ if ((unsigned int)(a->check) > LZMA_CHECK_ID_MAX
+ || (unsigned int)(b->check) > LZMA_CHECK_ID_MAX)
+ return LZMA_PROG_ERROR;
+
+ if (a->check != b->check)
+ return LZMA_DATA_ERROR;
+
+ // Backward Sizes are compared only if they are known in both.
+ if (a->backward_size != LZMA_VLI_UNKNOWN
+ && b->backward_size != LZMA_VLI_UNKNOWN) {
+ if (!is_backward_size_valid(a) || !is_backward_size_valid(b))
+ return LZMA_PROG_ERROR;
+
+ if (a->backward_size != b->backward_size)
+ return LZMA_DATA_ERROR;
+ }
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_flags_common.h b/Utilities/cmliblzma/liblzma/common/stream_flags_common.h
new file mode 100644
index 000000000..9f3122a3b
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_flags_common.h
@@ -0,0 +1,33 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_common.h
+/// \brief Common stuff for Stream flags coders
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_STREAM_FLAGS_COMMON_H
+#define LZMA_STREAM_FLAGS_COMMON_H
+
+#include "common.h"
+
+/// Size of the Stream Flags field
+#define LZMA_STREAM_FLAGS_SIZE 2
+
+extern const uint8_t lzma_header_magic[6];
+extern const uint8_t lzma_footer_magic[2];
+
+
+static inline bool
+is_backward_size_valid(const lzma_stream_flags *options)
+{
+ return options->backward_size >= LZMA_BACKWARD_SIZE_MIN
+ && options->backward_size <= LZMA_BACKWARD_SIZE_MAX
+ && (options->backward_size & 3) == 0;
+}
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/common/stream_flags_decoder.c b/Utilities/cmliblzma/liblzma/common/stream_flags_decoder.c
new file mode 100644
index 000000000..8cf48a4ca
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_flags_decoder.c
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_decoder.c
+/// \brief Decodes Stream Header and Stream Footer from .xz files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+static bool
+stream_flags_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+ // Reserved bits must be unset.
+ if (in[0] != 0x00 || (in[1] & 0xF0))
+ return true;
+
+ options->version = 0;
+ options->check = in[1] & 0x0F;
+
+ return false;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_header_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+ uint32_t crc;
+
+ // Magic
+ if (memcmp(in, lzma_header_magic, sizeof(lzma_header_magic)) != 0)
+ return LZMA_FORMAT_ERROR;
+
+ // Verify the CRC32 so we can distinguish between corrupt
+ // and unsupported files.
+ crc = lzma_crc32(in + sizeof(lzma_header_magic),
+ LZMA_STREAM_FLAGS_SIZE, 0);
+ if (crc != unaligned_read32le(in + sizeof(lzma_header_magic)
+ + LZMA_STREAM_FLAGS_SIZE))
+ return LZMA_DATA_ERROR;
+
+ // Stream Flags
+ if (stream_flags_decode(options, in + sizeof(lzma_header_magic)))
+ return LZMA_OPTIONS_ERROR;
+
+ // Set Backward Size to indicate unknown value. That way
+ // lzma_stream_flags_compare() can be used to compare Stream Header
+ // and Stream Footer while keeping it useful also for comparing
+ // two Stream Footers.
+ options->backward_size = LZMA_VLI_UNKNOWN;
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_footer_decode(lzma_stream_flags *options, const uint8_t *in)
+{
+ uint32_t crc;
+
+ // Magic
+ if (memcmp(in + sizeof(uint32_t) * 2 + LZMA_STREAM_FLAGS_SIZE,
+ lzma_footer_magic, sizeof(lzma_footer_magic)) != 0)
+ return LZMA_FORMAT_ERROR;
+
+ // CRC32
+ crc = lzma_crc32(in + sizeof(uint32_t),
+ sizeof(uint32_t) + LZMA_STREAM_FLAGS_SIZE, 0);
+ if (crc != unaligned_read32le(in))
+ return LZMA_DATA_ERROR;
+
+ // Stream Flags
+ if (stream_flags_decode(options, in + sizeof(uint32_t) * 2))
+ return LZMA_OPTIONS_ERROR;
+
+ // Backward Size
+ options->backward_size = unaligned_read32le(in + sizeof(uint32_t));
+ options->backward_size = (options->backward_size + 1) * 4;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/stream_flags_encoder.c b/Utilities/cmliblzma/liblzma/common/stream_flags_encoder.c
new file mode 100644
index 000000000..290339e08
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/stream_flags_encoder.c
@@ -0,0 +1,90 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file stream_flags_encoder.c
+/// \brief Encodes Stream Header and Stream Footer for .xz files
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "stream_flags_common.h"
+
+
+static bool
+stream_flags_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+ if ((unsigned int)(options->check) > LZMA_CHECK_ID_MAX)
+ return true;
+
+ out[0] = 0x00;
+ out[1] = options->check;
+
+ return false;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_header_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+ uint32_t crc;
+
+ assert(sizeof(lzma_header_magic) + LZMA_STREAM_FLAGS_SIZE
+ + 4 == LZMA_STREAM_HEADER_SIZE);
+
+ if (options->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ // Magic
+ memcpy(out, lzma_header_magic, sizeof(lzma_header_magic));
+
+ // Stream Flags
+ if (stream_flags_encode(options, out + sizeof(lzma_header_magic)))
+ return LZMA_PROG_ERROR;
+
+ // CRC32 of the Stream Header
+ crc = lzma_crc32(out + sizeof(lzma_header_magic),
+ LZMA_STREAM_FLAGS_SIZE, 0);
+
+ unaligned_write32le(out + sizeof(lzma_header_magic)
+ + LZMA_STREAM_FLAGS_SIZE, crc);
+
+ return LZMA_OK;
+}
+
+
+extern LZMA_API(lzma_ret)
+lzma_stream_footer_encode(const lzma_stream_flags *options, uint8_t *out)
+{
+ uint32_t crc;
+
+ assert(2 * 4 + LZMA_STREAM_FLAGS_SIZE + sizeof(lzma_footer_magic)
+ == LZMA_STREAM_HEADER_SIZE);
+
+ if (options->version != 0)
+ return LZMA_OPTIONS_ERROR;
+
+ // Backward Size
+ if (!is_backward_size_valid(options))
+ return LZMA_PROG_ERROR;
+
+ unaligned_write32le(out + 4, options->backward_size / 4 - 1);
+
+ // Stream Flags
+ if (stream_flags_encode(options, out + 2 * 4))
+ return LZMA_PROG_ERROR;
+
+ // CRC32
+ crc = lzma_crc32(
+ out + 4, 4 + LZMA_STREAM_FLAGS_SIZE, 0);
+
+ unaligned_write32le(out, crc);
+
+ // Magic
+ memcpy(out + 2 * 4 + LZMA_STREAM_FLAGS_SIZE,
+ lzma_footer_magic, sizeof(lzma_footer_magic));
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/vli_decoder.c b/Utilities/cmliblzma/liblzma/common/vli_decoder.c
new file mode 100644
index 000000000..1c663844f
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/vli_decoder.c
@@ -0,0 +1,86 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_decoder.c
+/// \brief Decodes variable-length integers
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_vli_decode(lzma_vli *LZMA_RESTRICT vli, size_t *vli_pos,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size)
+{
+ // If we haven't been given vli_pos, work in single-call mode.
+ size_t vli_pos_internal = 0;
+ if (vli_pos == NULL) {
+ vli_pos = &vli_pos_internal;
+ *vli = 0;
+
+ // If there's no input, use LZMA_DATA_ERROR. This way it is
+ // easy to decode VLIs from buffers that have known size,
+ // and get the correct error code in case the buffer is
+ // too short.
+ if (*in_pos >= in_size)
+ return LZMA_DATA_ERROR;
+
+ } else {
+ // Initialize *vli when starting to decode a new integer.
+ if (*vli_pos == 0)
+ *vli = 0;
+
+ // Validate the arguments.
+ if (*vli_pos >= LZMA_VLI_BYTES_MAX
+ || (*vli >> (*vli_pos * 7)) != 0)
+ return LZMA_PROG_ERROR;;
+
+ if (*in_pos >= in_size)
+ return LZMA_BUF_ERROR;
+ }
+
+ do {
+ // Read the next byte. Use a temporary variable so that we
+ // can update *in_pos immediately.
+ const uint8_t byte = in[*in_pos];
+ ++*in_pos;
+
+ // Add the newly read byte to *vli.
+ *vli += (lzma_vli)(byte & 0x7F) << (*vli_pos * 7);
+ ++*vli_pos;
+
+ // Check if this is the last byte of a multibyte integer.
+ if ((byte & 0x80) == 0) {
+ // We don't allow using variable-length integers as
+ // padding i.e. the encoding must use the most the
+ // compact form.
+ if (byte == 0x00 && *vli_pos > 1)
+ return LZMA_DATA_ERROR;
+
+ return vli_pos == &vli_pos_internal
+ ? LZMA_OK : LZMA_STREAM_END;
+ }
+
+ // There is at least one more byte coming. If we have already
+ // read maximum number of bytes, the integer is considered
+ // corrupt.
+ //
+ // If we need bigger integers in future, old versions liblzma
+ // will confusingly indicate the file being corrupt istead of
+ // unsupported. I suppose it's still better this way, because
+ // in the foreseeable future (writing this in 2008) the only
+ // reason why files would appear having over 63-bit integers
+ // is that the files are simply corrupt.
+ if (*vli_pos == LZMA_VLI_BYTES_MAX)
+ return LZMA_DATA_ERROR;
+
+ } while (*in_pos < in_size);
+
+ return vli_pos == &vli_pos_internal ? LZMA_DATA_ERROR : LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/common/vli_encoder.c b/Utilities/cmliblzma/liblzma/common/vli_encoder.c
new file mode 100644
index 000000000..09e90cbd7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/vli_encoder.c
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_encoder.c
+/// \brief Encodes variable-length integers
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_ret)
+lzma_vli_encode(lzma_vli vli, size_t *vli_pos,
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size)
+{
+ // If we haven't been given vli_pos, work in single-call mode.
+ size_t vli_pos_internal = 0;
+ if (vli_pos == NULL) {
+ vli_pos = &vli_pos_internal;
+
+ // In single-call mode, we expect that the caller has
+ // reserved enough output space.
+ if (*out_pos >= out_size)
+ return LZMA_PROG_ERROR;
+ } else {
+ // This never happens when we are called by liblzma, but
+ // may happen if called directly from an application.
+ if (*out_pos >= out_size)
+ return LZMA_BUF_ERROR;
+ }
+
+ // Validate the arguments.
+ if (*vli_pos >= LZMA_VLI_BYTES_MAX || vli > LZMA_VLI_MAX)
+ return LZMA_PROG_ERROR;
+
+ // Shift vli so that the next bits to encode are the lowest. In
+ // single-call mode this never changes vli since *vli_pos is zero.
+ vli >>= *vli_pos * 7;
+
+ // Write the non-last bytes in a loop.
+ while (vli >= 0x80) {
+ // We don't need *vli_pos during this function call anymore,
+ // but update it here so that it is ready if we need to
+ // return before the whole integer has been decoded.
+ ++*vli_pos;
+ assert(*vli_pos < LZMA_VLI_BYTES_MAX);
+
+ // Write the next byte.
+ out[*out_pos] = (uint8_t)(vli) | 0x80;
+ vli >>= 7;
+
+ if (++*out_pos == out_size)
+ return vli_pos == &vli_pos_internal
+ ? LZMA_PROG_ERROR : LZMA_OK;
+ }
+
+ // Write the last byte.
+ out[*out_pos] = (uint8_t)(vli);
+ ++*out_pos;
+ ++*vli_pos;
+
+ return vli_pos == &vli_pos_internal ? LZMA_OK : LZMA_STREAM_END;
+
+}
diff --git a/Utilities/cmliblzma/liblzma/common/vli_size.c b/Utilities/cmliblzma/liblzma/common/vli_size.c
new file mode 100644
index 000000000..8b931e40b
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/common/vli_size.c
@@ -0,0 +1,31 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file vli_size.c
+/// \brief Calculates the encoded size of a variable-length integer
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(uint32_t)
+lzma_vli_size(lzma_vli vli)
+{
+ uint32_t i = 0;
+
+ if (vli > LZMA_VLI_MAX)
+ return 0;
+
+ do {
+ vli >>= 7;
+ ++i;
+ } while (vli != 0);
+
+ assert(i <= LZMA_VLI_BYTES_MAX);
+ return i;
+}
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_common.c b/Utilities/cmliblzma/liblzma/delta/delta_common.c
new file mode 100644
index 000000000..803e674a1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_common.c
@@ -0,0 +1,72 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_common.c
+/// \brief Common stuff for Delta encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_common.h"
+#include "delta_private.h"
+
+
+static void
+delta_coder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_delta_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ const lzma_options_delta *opt;
+
+ // Allocate memory for the decoder if needed.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ // End function is the same for encoder and decoder.
+ next->end = &delta_coder_end;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Validate the options.
+ if (lzma_delta_coder_memusage(filters[0].options) == UINT64_MAX)
+ return LZMA_OPTIONS_ERROR;
+
+ // Set the delta distance.
+ opt = filters[0].options;
+ next->coder->distance = opt->dist;
+
+ // Initialize the rest of the variables.
+ next->coder->pos = 0;
+ memzero(next->coder->history, LZMA_DELTA_DIST_MAX);
+
+ // Initialize the next decoder in the chain, if any.
+ return lzma_next_filter_init(&next->coder->next,
+ allocator, filters + 1);
+}
+
+
+extern uint64_t
+lzma_delta_coder_memusage(const void *options)
+{
+ const lzma_options_delta *opt = options;
+
+ if (opt == NULL || opt->type != LZMA_DELTA_TYPE_BYTE
+ || opt->dist < LZMA_DELTA_DIST_MIN
+ || opt->dist > LZMA_DELTA_DIST_MAX)
+ return UINT64_MAX;
+
+ return sizeof(lzma_coder);
+}
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_common.h b/Utilities/cmliblzma/liblzma/delta/delta_common.h
new file mode 100644
index 000000000..7e7e1baaf
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_common.h
@@ -0,0 +1,20 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_common.h
+/// \brief Common stuff for Delta encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_COMMON_H
+#define LZMA_DELTA_COMMON_H
+
+#include "common.h"
+
+extern uint64_t lzma_delta_coder_memusage(const void *options);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_decoder.c b/Utilities/cmliblzma/liblzma/delta/delta_decoder.c
new file mode 100644
index 000000000..28df72735
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_decoder.c
@@ -0,0 +1,79 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_decoder.c
+/// \brief Delta filter decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_decoder.h"
+#include "delta_private.h"
+
+
+static void
+decode_buffer(lzma_coder *coder, uint8_t *buffer, size_t size)
+{
+ size_t i;
+ const size_t distance = coder->distance;
+
+ for (i = 0; i < size; ++i) {
+ buffer[i] += coder->history[(distance + coder->pos) & 0xFF];
+ coder->history[coder->pos-- & 0xFF] = buffer[i];
+ }
+}
+
+
+static lzma_ret
+delta_decode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ const size_t out_start = *out_pos;
+ lzma_ret ret;
+
+ assert(coder->next.code != NULL);
+
+ ret = coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+
+ decode_buffer(coder, out + out_start, *out_pos - out_start);
+
+ return ret;
+}
+
+
+extern lzma_ret
+lzma_delta_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ next->code = &delta_decode;
+ return lzma_delta_coder_init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_delta_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ lzma_options_delta *opt;
+
+ if (props_size != 1)
+ return LZMA_OPTIONS_ERROR;
+
+ opt = lzma_alloc(sizeof(lzma_options_delta), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ opt->type = LZMA_DELTA_TYPE_BYTE;
+ opt->dist = props[0] + 1;
+
+ *options = opt;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_decoder.h b/Utilities/cmliblzma/liblzma/delta/delta_decoder.h
new file mode 100644
index 000000000..ae89acc59
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_decoder.h
@@ -0,0 +1,25 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_decoder.h
+/// \brief Delta filter decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_DECODER_H
+#define LZMA_DELTA_DECODER_H
+
+#include "delta_common.h"
+
+extern lzma_ret lzma_delta_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_delta_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_encoder.c b/Utilities/cmliblzma/liblzma/delta/delta_encoder.c
new file mode 100644
index 000000000..a39c154f1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_encoder.c
@@ -0,0 +1,124 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_encoder.c
+/// \brief Delta filter encoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "delta_encoder.h"
+#include "delta_private.h"
+
+
+/// Copies and encodes the data at the same time. This is used when Delta
+/// is the first filter in the chain (and thus the last filter in the
+/// encoder's filter stack).
+static void
+copy_and_encode(lzma_coder *coder,
+ const uint8_t *LZMA_RESTRICT in, uint8_t *LZMA_RESTRICT out, size_t size)
+{
+ size_t i;
+ const size_t distance = coder->distance;
+
+ for (i = 0; i < size; ++i) {
+ const uint8_t tmp = coder->history[
+ (distance + coder->pos) & 0xFF];
+ coder->history[coder->pos-- & 0xFF] = in[i];
+ out[i] = in[i] - tmp;
+ }
+}
+
+
+/// Encodes the data in place. This is used when we are the last filter
+/// in the chain (and thus non-last filter in the encoder's filter stack).
+static void
+encode_in_place(lzma_coder *coder, uint8_t *buffer, size_t size)
+{
+ size_t i;
+ const size_t distance = coder->distance;
+
+ for (i = 0; i < size; ++i) {
+ const uint8_t tmp = coder->history[
+ (distance + coder->pos) & 0xFF];
+ coder->history[coder->pos-- & 0xFF] = buffer[i];
+ buffer[i] -= tmp;
+ }
+}
+
+
+static lzma_ret
+delta_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ lzma_ret ret;
+
+ if (coder->next.code == NULL) {
+ const size_t in_avail = in_size - *in_pos;
+ const size_t out_avail = out_size - *out_pos;
+ const size_t size = my_min(in_avail, out_avail);
+
+ copy_and_encode(coder, in + *in_pos, out + *out_pos, size);
+
+ *in_pos += size;
+ *out_pos += size;
+
+ ret = action != LZMA_RUN && *in_pos == in_size
+ ? LZMA_STREAM_END : LZMA_OK;
+
+ } else {
+ const size_t out_start = *out_pos;
+
+ ret = coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size, out, out_pos, out_size,
+ action);
+
+ encode_in_place(coder, out + out_start, *out_pos - out_start);
+ }
+
+ return ret;
+}
+
+
+static lzma_ret
+delta_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters_null lzma_attribute((__unused__)),
+ const lzma_filter *reversed_filters)
+{
+ // Delta doesn't and will never support changing the options in
+ // the middle of encoding. If the app tries to change them, we
+ // simply ignore them.
+ return lzma_next_filter_update(
+ &coder->next, allocator, reversed_filters + 1);
+}
+
+
+extern lzma_ret
+lzma_delta_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ next->code = &delta_encode;
+ next->update = &delta_encoder_update;
+ return lzma_delta_coder_init(next, allocator, filters);
+}
+
+
+extern lzma_ret
+lzma_delta_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_delta *opt = options;
+
+ // The caller must have already validated the options, so it's
+ // LZMA_PROG_ERROR if they are invalid.
+ if (lzma_delta_coder_memusage(options) == UINT64_MAX)
+ return LZMA_PROG_ERROR;
+
+ out[0] = opt->dist - LZMA_DELTA_DIST_MIN;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_encoder.h b/Utilities/cmliblzma/liblzma/delta/delta_encoder.h
new file mode 100644
index 000000000..a447862f2
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_encoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_encoder.h
+/// \brief Delta filter encoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_ENCODER_H
+#define LZMA_DELTA_ENCODER_H
+
+#include "delta_common.h"
+
+extern lzma_ret lzma_delta_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_delta_props_encode(const void *options, uint8_t *out);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/delta/delta_private.h b/Utilities/cmliblzma/liblzma/delta/delta_private.h
new file mode 100644
index 000000000..62b7fed86
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/delta/delta_private.h
@@ -0,0 +1,37 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file delta_private.h
+/// \brief Private common stuff for Delta encoder and decoder
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_DELTA_PRIVATE_H
+#define LZMA_DELTA_PRIVATE_H
+
+#include "delta_common.h"
+
+struct lzma_coder_s {
+ /// Next coder in the chain
+ lzma_next_coder next;
+
+ /// Delta distance
+ size_t distance;
+
+ /// Position in history[]
+ uint8_t pos;
+
+ /// Buffer to hold history of the original data
+ uint8_t history[LZMA_DELTA_DIST_MAX];
+};
+
+
+extern lzma_ret lzma_delta_coder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/liblzma.pc.in b/Utilities/cmliblzma/liblzma/liblzma.pc.in
new file mode 100644
index 000000000..7f11f1a20
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/liblzma.pc.in
@@ -0,0 +1,19 @@
+#
+# Author: Lasse Collin
+#
+# This file has been put into the public domain.
+# You can do whatever you want with this file.
+#
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: liblzma
+Description: General purpose data compression library
+URL: @PACKAGE_URL@
+Version: @PACKAGE_VERSION@
+Cflags: -I${includedir}
+Libs: -L${libdir} -llzma
+Libs.private: @PTHREAD_CFLAGS@ @PTHREAD_LIBS@
diff --git a/Utilities/cmliblzma/liblzma/liblzma_w32res.rc b/Utilities/cmliblzma/liblzma/liblzma_w32res.rc
new file mode 100644
index 000000000..773caf8b4
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/liblzma_w32res.rc
@@ -0,0 +1,14 @@
+/*
+ * Author: Lasse Collin
+ *
+ * This file has been put into the public domain.
+ * You can do whatever you want with this file.
+ */
+
+#define MY_TYPE VFT_DLL
+#define MY_NAME "liblzma"
+#define MY_SUFFIX ".dll"
+#define MY_DESC "liblzma data compression library"
+#define PACKAGE_NAME "XZ Utils"
+#define PACKAGE_URL "http://tukaani.org/xz/"
+#include "common_w32res.rc"
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_decoder.c b/Utilities/cmliblzma/liblzma/lz/lz_decoder.c
new file mode 100644
index 000000000..9fa1bdc3a
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_decoder.c
@@ -0,0 +1,307 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_decoder.c
+/// \brief LZ out window
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+// liblzma supports multiple LZ77-based filters. The LZ part is shared
+// between these filters. The LZ code takes care of dictionary handling
+// and passing the data between filters in the chain. The filter-specific
+// part decodes from the input buffer to the dictionary.
+
+
+#include "lz_decoder.h"
+
+
+struct lzma_coder_s {
+ /// Dictionary (history buffer)
+ lzma_dict dict;
+
+ /// The actual LZ-based decoder e.g. LZMA
+ lzma_lz_decoder lz;
+
+ /// Next filter in the chain, if any. Note that LZMA and LZMA2 are
+ /// only allowed as the last filter, but the long-range filter in
+ /// future can be in the middle of the chain.
+ lzma_next_coder next;
+
+ /// True if the next filter in the chain has returned LZMA_STREAM_END.
+ bool next_finished;
+
+ /// True if the LZ decoder (e.g. LZMA) has detected end of payload
+ /// marker. This may become true before next_finished becomes true.
+ bool this_finished;
+
+ /// Temporary buffer needed when the LZ-based filter is not the last
+ /// filter in the chain. The output of the next filter is first
+ /// decoded into buffer[], which is then used as input for the actual
+ /// LZ-based decoder.
+ struct {
+ size_t pos;
+ size_t size;
+ uint8_t buffer[LZMA_BUFFER_SIZE];
+ } temp;
+};
+
+
+static void
+lz_decoder_reset(lzma_coder *coder)
+{
+ coder->dict.pos = 0;
+ coder->dict.full = 0;
+ coder->dict.buf[coder->dict.size - 1] = '\0';
+ coder->dict.need_reset = false;
+ return;
+}
+
+
+static lzma_ret
+decode_buffer(lzma_coder *coder,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size)
+{
+ while (true) {
+ size_t copy_size;
+ size_t dict_start;
+ lzma_ret ret;
+
+ // Wrap the dictionary if needed.
+ if (coder->dict.pos == coder->dict.size)
+ coder->dict.pos = 0;
+
+ // Store the current dictionary position. It is needed to know
+ // where to start copying to the out[] buffer.
+ dict_start = coder->dict.pos;
+
+ // Calculate how much we allow coder->lz.code() to decode.
+ // It must not decode past the end of the dictionary
+ // buffer, and we don't want it to decode more than is
+ // actually needed to fill the out[] buffer.
+ coder->dict.limit = coder->dict.pos
+ + my_min(out_size - *out_pos,
+ coder->dict.size - coder->dict.pos);
+
+ // Call the coder->lz.code() to do the actual decoding.
+ ret = coder->lz.code(
+ coder->lz.coder, &coder->dict,
+ in, in_pos, in_size);
+
+ // Copy the decoded data from the dictionary to the out[]
+ // buffer.
+ copy_size = coder->dict.pos - dict_start;
+ assert(copy_size <= out_size - *out_pos);
+ memcpy(out + *out_pos, coder->dict.buf + dict_start,
+ copy_size);
+ *out_pos += copy_size;
+
+ // Reset the dictionary if so requested by coder->lz.code().
+ if (coder->dict.need_reset) {
+ lz_decoder_reset(coder);
+
+ // Since we reset dictionary, we don't check if
+ // dictionary became full.
+ if (ret != LZMA_OK || *out_pos == out_size)
+ return ret;
+ } else {
+ // Return if everything got decoded or an error
+ // occurred, or if there's no more data to decode.
+ //
+ // Note that detecting if there's something to decode
+ // is done by looking if dictionary become full
+ // instead of looking if *in_pos == in_size. This
+ // is because it is possible that all the input was
+ // consumed already but some data is pending to be
+ // written to the dictionary.
+ if (ret != LZMA_OK || *out_pos == out_size
+ || coder->dict.pos < coder->dict.size)
+ return ret;
+ }
+ }
+}
+
+
+static lzma_ret
+lz_decode(lzma_coder *coder,
+ lzma_allocator *allocator lzma_attribute((__unused__)),
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size,
+ lzma_action action)
+{
+ if (coder->next.code == NULL)
+ return decode_buffer(coder, in, in_pos, in_size,
+ out, out_pos, out_size);
+
+ // We aren't the last coder in the chain, we need to decode
+ // our input to a temporary buffer.
+ while (*out_pos < out_size) {
+ lzma_ret ret;
+
+ // Fill the temporary buffer if it is empty.
+ if (!coder->next_finished
+ && coder->temp.pos == coder->temp.size) {
+ coder->temp.pos = 0;
+ coder->temp.size = 0;
+
+ ret = coder->next.code(
+ coder->next.coder,
+ allocator, in, in_pos, in_size,
+ coder->temp.buffer, &coder->temp.size,
+ LZMA_BUFFER_SIZE, action);
+
+ if (ret == LZMA_STREAM_END)
+ coder->next_finished = true;
+ else if (ret != LZMA_OK || coder->temp.size == 0)
+ return ret;
+ }
+
+ if (coder->this_finished) {
+ if (coder->temp.size != 0)
+ return LZMA_DATA_ERROR;
+
+ if (coder->next_finished)
+ return LZMA_STREAM_END;
+
+ return LZMA_OK;
+ }
+
+ ret = decode_buffer(coder, coder->temp.buffer,
+ &coder->temp.pos, coder->temp.size,
+ out, out_pos, out_size);
+
+ if (ret == LZMA_STREAM_END)
+ coder->this_finished = true;
+ else if (ret != LZMA_OK)
+ return ret;
+ else if (coder->next_finished && *out_pos < out_size)
+ return LZMA_DATA_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+lz_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder->dict.buf, allocator);
+
+ if (coder->lz.end != NULL)
+ coder->lz.end(coder->lz.coder, allocator);
+ else
+ lzma_free(coder->lz.coder, allocator);
+
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+extern lzma_ret
+lzma_lz_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options))
+{
+ lzma_lz_options lz_options;
+
+ // Allocate the base structure if it isn't already allocated.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &lz_decode;
+ next->end = &lz_decoder_end;
+
+ next->coder->dict.buf = NULL;
+ next->coder->dict.size = 0;
+ next->coder->lz = LZMA_LZ_DECODER_INIT;
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Allocate and initialize the LZ-based decoder. It will also give
+ // us the dictionary size.
+ return_if_error(lz_init(&next->coder->lz, allocator,
+ filters[0].options, &lz_options));
+
+ // If the dictionary size is very small, increase it to 4096 bytes.
+ // This is to prevent constant wrapping of the dictionary, which
+ // would slow things down. The downside is that since we don't check
+ // separately for the real dictionary size, we may happily accept
+ // corrupt files.
+ if (lz_options.dict_size < 4096)
+ lz_options.dict_size = 4096;
+
+ // Make dictionary size a multipe of 16. Some LZ-based decoders like
+ // LZMA use the lowest bits lzma_dict.pos to know the alignment of the
+ // data. Aligned buffer is also good when memcpying from the
+ // dictionary to the output buffer, since applications are
+ // recommended to give aligned buffers to liblzma.
+ //
+ // Avoid integer overflow.
+ if (lz_options.dict_size > SIZE_MAX - 15)
+ return LZMA_MEM_ERROR;
+
+ lz_options.dict_size = (lz_options.dict_size + 15) & ~((size_t)(15));
+
+ // Allocate and initialize the dictionary.
+ if (next->coder->dict.size != lz_options.dict_size) {
+ lzma_free(next->coder->dict.buf, allocator);
+ next->coder->dict.buf
+ = lzma_alloc(lz_options.dict_size, allocator);
+ if (next->coder->dict.buf == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->coder->dict.size = lz_options.dict_size;
+ }
+
+ lz_decoder_reset(next->coder);
+
+ // Use the preset dictionary if it was given to us.
+ if (lz_options.preset_dict != NULL
+ && lz_options.preset_dict_size > 0) {
+ // If the preset dictionary is bigger than the actual
+ // dictionary, copy only the tail.
+ const size_t copy_size = my_min(lz_options.preset_dict_size,
+ lz_options.dict_size);
+ const size_t offset = lz_options.preset_dict_size - copy_size;
+ memcpy(next->coder->dict.buf, lz_options.preset_dict + offset,
+ copy_size);
+ next->coder->dict.pos = copy_size;
+ next->coder->dict.full = copy_size;
+ }
+
+ // Miscellaneous initializations
+ next->coder->next_finished = false;
+ next->coder->this_finished = false;
+ next->coder->temp.pos = 0;
+ next->coder->temp.size = 0;
+
+ // Initialize the next filter in the chain, if any.
+ return lzma_next_filter_init(&next->coder->next, allocator,
+ filters + 1);
+}
+
+
+extern uint64_t
+lzma_lz_decoder_memusage(size_t dictionary_size)
+{
+ return sizeof(lzma_coder) + (uint64_t)(dictionary_size);
+}
+
+
+extern void
+lzma_lz_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
+{
+ coder->lz.set_uncompressed(coder->lz.coder, uncompressed_size);
+}
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_decoder.h b/Utilities/cmliblzma/liblzma/lz/lz_decoder.h
new file mode 100644
index 000000000..76011f2ad
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_decoder.h
@@ -0,0 +1,236 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_decoder.h
+/// \brief LZ out window
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_DECODER_H
+#define LZMA_LZ_DECODER_H
+
+#include "common.h"
+
+
+typedef struct {
+ /// Pointer to the dictionary buffer. It can be an allocated buffer
+ /// internal to liblzma, or it can a be a buffer given by the
+ /// application when in single-call mode (not implemented yet).
+ uint8_t *buf;
+
+ /// Write position in dictionary. The next byte will be written to
+ /// buf[pos].
+ size_t pos;
+
+ /// Indicates how full the dictionary is. This is used by
+ /// dict_is_distance_valid() to detect corrupt files that would
+ /// read beyond the beginning of the dictionary.
+ size_t full;
+
+ /// Write limit
+ size_t limit;
+
+ /// Size of the dictionary
+ size_t size;
+
+ /// True when dictionary should be reset before decoding more data.
+ bool need_reset;
+
+} lzma_dict;
+
+
+typedef struct {
+ size_t dict_size;
+ const uint8_t *preset_dict;
+ size_t preset_dict_size;
+} lzma_lz_options;
+
+
+typedef struct {
+ /// Data specific to the LZ-based decoder
+ lzma_coder *coder;
+
+ /// Function to decode from in[] to *dict
+ lzma_ret (*code)(lzma_coder *LZMA_RESTRICT coder,
+ lzma_dict *LZMA_RESTRICT dict, const uint8_t *LZMA_RESTRICT in,
+ size_t *LZMA_RESTRICT in_pos, size_t in_size);
+
+ void (*reset)(lzma_coder *coder, const void *options);
+
+ /// Set the uncompressed size
+ void (*set_uncompressed)(lzma_coder *coder,
+ lzma_vli uncompressed_size);
+
+ /// Free allocated resources
+ void (*end)(lzma_coder *coder, lzma_allocator *allocator);
+
+} lzma_lz_decoder;
+
+
+static const lzma_lz_decoder LZMA_LZ_DECODER_INIT =
+ {
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ };
+
+
+extern lzma_ret lzma_lz_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_decoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options));
+
+extern uint64_t lzma_lz_decoder_memusage(size_t dictionary_size);
+
+extern void lzma_lz_decoder_uncompressed(
+ lzma_coder *coder, lzma_vli uncompressed_size);
+
+
+//////////////////////
+// Inline functions //
+//////////////////////
+
+/// Get a byte from the history buffer.
+static inline uint8_t
+dict_get(const lzma_dict *const dict, const uint32_t distance)
+{
+ return dict->buf[dict->pos - distance - 1
+ + (distance < dict->pos ? 0 : dict->size)];
+}
+
+
+/// Test if dictionary is empty.
+static inline bool
+dict_is_empty(const lzma_dict *const dict)
+{
+ return dict->full == 0;
+}
+
+
+/// Validate the match distance
+static inline bool
+dict_is_distance_valid(const lzma_dict *const dict, const size_t distance)
+{
+ return dict->full > distance;
+}
+
+
+/// Repeat *len bytes at distance.
+static inline bool
+dict_repeat(lzma_dict *dict, uint32_t distance, uint32_t *len)
+{
+ // Don't write past the end of the dictionary.
+ const size_t dict_avail = dict->limit - dict->pos;
+ uint32_t left = my_min(dict_avail, *len);
+ *len -= left;
+
+ // Repeat a block of data from the history. Because memcpy() is faster
+ // than copying byte by byte in a loop, the copying process gets split
+ // into three cases.
+ if (distance < left) {
+ // Source and target areas overlap, thus we can't use
+ // memcpy() nor even memmove() safely.
+ do {
+ dict->buf[dict->pos] = dict_get(dict, distance);
+ ++dict->pos;
+ } while (--left > 0);
+
+ } else if (distance < dict->pos) {
+ // The easiest and fastest case
+ memcpy(dict->buf + dict->pos,
+ dict->buf + dict->pos - distance - 1,
+ left);
+ dict->pos += left;
+
+ } else {
+ uint32_t copy_pos;
+ uint32_t copy_size;
+
+ // The bigger the dictionary, the more rare this
+ // case occurs. We need to "wrap" the dict, thus
+ // we might need two memcpy() to copy all the data.
+ assert(dict->full == dict->size);
+ copy_pos = dict->pos - distance - 1 + dict->size;
+ copy_size = dict->size - copy_pos;
+
+ if (copy_size < left) {
+ memmove(dict->buf + dict->pos, dict->buf + copy_pos,
+ copy_size);
+ dict->pos += copy_size;
+ copy_size = left - copy_size;
+ memcpy(dict->buf + dict->pos, dict->buf, copy_size);
+ dict->pos += copy_size;
+ } else {
+ memmove(dict->buf + dict->pos, dict->buf + copy_pos,
+ left);
+ dict->pos += left;
+ }
+ }
+
+ // Update how full the dictionary is.
+ if (dict->full < dict->pos)
+ dict->full = dict->pos;
+
+ return unlikely(*len != 0);
+}
+
+
+/// Puts one byte into the dictionary. Returns true if the dictionary was
+/// already full and the byte couldn't be added.
+static inline bool
+dict_put(lzma_dict *dict, uint8_t byte)
+{
+ if (unlikely(dict->pos == dict->limit))
+ return true;
+
+ dict->buf[dict->pos++] = byte;
+
+ if (dict->pos > dict->full)
+ dict->full = dict->pos;
+
+ return false;
+}
+
+
+/// Copies arbitrary amount of data into the dictionary.
+static inline void
+dict_write(lzma_dict *LZMA_RESTRICT dict, const uint8_t *LZMA_RESTRICT in,
+ size_t *LZMA_RESTRICT in_pos, size_t in_size,
+ size_t *LZMA_RESTRICT left)
+{
+ // NOTE: If we are being given more data than the size of the
+ // dictionary, it could be possible to optimize the LZ decoder
+ // so that not everything needs to go through the dictionary.
+ // This shouldn't be very common thing in practice though, and
+ // the slowdown of one extra memcpy() isn't bad compared to how
+ // much time it would have taken if the data were compressed.
+
+ if (in_size - *in_pos > *left)
+ in_size = *in_pos + *left;
+
+ *left -= lzma_bufcpy(in, in_pos, in_size,
+ dict->buf, &dict->pos, dict->limit);
+
+ if (dict->pos > dict->full)
+ dict->full = dict->pos;
+
+ return;
+}
+
+
+static inline void
+dict_reset(lzma_dict *dict)
+{
+ dict->need_reset = true;
+ return;
+}
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_encoder.c b/Utilities/cmliblzma/liblzma/lz/lz_encoder.c
new file mode 100644
index 000000000..1dae924b4
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_encoder.c
@@ -0,0 +1,594 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder.c
+/// \brief LZ in window
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
+
+// See lz_encoder_hash.h. This is a bit hackish but avoids making
+// endianness a conditional in makefiles.
+#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
+# include "lz_encoder_hash_table.h"
+#endif
+
+
+struct lzma_coder_s {
+ /// LZ-based encoder e.g. LZMA
+ lzma_lz_encoder lz;
+
+ /// History buffer and match finder
+ lzma_mf mf;
+
+ /// Next coder in the chain
+ lzma_next_coder next;
+};
+
+
+/// \brief Moves the data in the input window to free space for new data
+///
+/// mf->buffer is a sliding input window, which keeps mf->keep_size_before
+/// bytes of input history available all the time. Now and then we need to
+/// "slide" the buffer to make space for the new data to the end of the
+/// buffer. At the same time, data older than keep_size_before is dropped.
+///
+static void
+move_window(lzma_mf *mf)
+{
+ uint32_t move_offset;
+ size_t move_size;
+
+ // Align the move to a multiple of 16 bytes. Some LZ-based encoders
+ // like LZMA use the lowest bits of mf->read_pos to know the
+ // alignment of the uncompressed data. We also get better speed
+ // for memmove() with aligned buffers.
+ assert(mf->read_pos > mf->keep_size_before);
+ move_offset = (mf->read_pos - mf->keep_size_before) & ~UINT32_C(15);
+
+ assert(mf->write_pos > move_offset);
+ move_size = mf->write_pos - move_offset;
+
+ assert(move_offset + move_size <= mf->size);
+
+ memmove(mf->buffer, mf->buffer + move_offset, move_size);
+
+ mf->offset += move_offset;
+ mf->read_pos -= move_offset;
+ mf->read_limit -= move_offset;
+ mf->write_pos -= move_offset;
+
+ return;
+}
+
+
+/// \brief Tries to fill the input window (mf->buffer)
+///
+/// If we are the last encoder in the chain, our input data is in in[].
+/// Otherwise we call the next filter in the chain to process in[] and
+/// write its output to mf->buffer.
+///
+/// This function must not be called once it has returned LZMA_STREAM_END.
+///
+static lzma_ret
+fill_window(lzma_coder *coder, lzma_allocator *allocator, const uint8_t *in,
+ size_t *in_pos, size_t in_size, lzma_action action)
+{
+ size_t write_pos;
+ lzma_ret ret;
+
+ assert(coder->mf.read_pos <= coder->mf.write_pos);
+
+ // Move the sliding window if needed.
+ if (coder->mf.read_pos >= coder->mf.size - coder->mf.keep_size_after)
+ move_window(&coder->mf);
+
+ // Maybe this is ugly, but lzma_mf uses uint32_t for most things
+ // (which I find cleanest), but we need size_t here when filling
+ // the history window.
+ write_pos = coder->mf.write_pos;
+ if (coder->next.code == NULL) {
+ // Not using a filter, simply memcpy() as much as possible.
+ lzma_bufcpy(in, in_pos, in_size, coder->mf.buffer,
+ &write_pos, coder->mf.size);
+
+ ret = action != LZMA_RUN && *in_pos == in_size
+ ? LZMA_STREAM_END : LZMA_OK;
+
+ } else {
+ ret = coder->next.code(coder->next.coder, allocator,
+ in, in_pos, in_size,
+ coder->mf.buffer, &write_pos,
+ coder->mf.size, action);
+ }
+
+ coder->mf.write_pos = write_pos;
+
+ // If end of stream has been reached or flushing completed, we allow
+ // the encoder to process all the input (that is, read_pos is allowed
+ // to reach write_pos). Otherwise we keep keep_size_after bytes
+ // available as prebuffer.
+ if (ret == LZMA_STREAM_END) {
+ assert(*in_pos == in_size);
+ ret = LZMA_OK;
+ coder->mf.action = action;
+ coder->mf.read_limit = coder->mf.write_pos;
+
+ } else if (coder->mf.write_pos > coder->mf.keep_size_after) {
+ // This needs to be done conditionally, because if we got
+ // only little new input, there may be too little input
+ // to do any encoding yet.
+ coder->mf.read_limit = coder->mf.write_pos
+ - coder->mf.keep_size_after;
+ }
+
+ // Restart the match finder after finished LZMA_SYNC_FLUSH.
+ if (coder->mf.pending > 0
+ && coder->mf.read_pos < coder->mf.read_limit) {
+ // Match finder may update coder->pending and expects it to
+ // start from zero, so use a temporary variable.
+ const size_t pending = coder->mf.pending;
+ coder->mf.pending = 0;
+
+ // Rewind read_pos so that the match finder can hash
+ // the pending bytes.
+ assert(coder->mf.read_pos >= pending);
+ coder->mf.read_pos -= pending;
+
+ // Call the skip function directly instead of using
+ // mf_skip(), since we don't want to touch mf->read_ahead.
+ coder->mf.skip(&coder->mf, pending);
+ }
+
+ return ret;
+}
+
+
+static lzma_ret
+lz_encode(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size,
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size, lzma_action action)
+{
+ while (*out_pos < out_size
+ && (*in_pos < in_size || action != LZMA_RUN)) {
+ lzma_ret ret;
+
+ // Read more data to coder->mf.buffer if needed.
+ if (coder->mf.action == LZMA_RUN && coder->mf.read_pos
+ >= coder->mf.read_limit)
+ return_if_error(fill_window(coder, allocator,
+ in, in_pos, in_size, action));
+
+ // Encode
+ ret = coder->lz.code(coder->lz.coder,
+ &coder->mf, out, out_pos, out_size);
+ if (ret != LZMA_OK) {
+ // Setting this to LZMA_RUN for cases when we are
+ // flushing. It doesn't matter when finishing or if
+ // an error occurred.
+ coder->mf.action = LZMA_RUN;
+ return ret;
+ }
+ }
+
+ return LZMA_OK;
+}
+
+
+static bool
+lz_encoder_prepare(lzma_mf *mf, lzma_allocator *allocator,
+ const lzma_lz_options *lz_options)
+{
+ bool is_bt;
+ uint32_t new_count;
+ uint32_t reserve;
+ uint32_t old_size;
+ uint32_t hash_bytes;
+ uint32_t hs;
+ uint32_t old_count;
+
+ // For now, the dictionary size is limited to 1.5 GiB. This may grow
+ // in the future if needed, but it needs a little more work than just
+ // changing this check.
+ if (lz_options->dict_size < LZMA_DICT_SIZE_MIN
+ || lz_options->dict_size
+ > (UINT32_C(1) << 30) + (UINT32_C(1) << 29)
+ || lz_options->nice_len > lz_options->match_len_max)
+ return true;
+
+ mf->keep_size_before = lz_options->before_size + lz_options->dict_size;
+
+ mf->keep_size_after = lz_options->after_size
+ + lz_options->match_len_max;
+
+ // To avoid constant memmove()s, allocate some extra space. Since
+ // memmove()s become more expensive when the size of the buffer
+ // increases, we reserve more space when a large dictionary is
+ // used to make the memmove() calls rarer.
+ //
+ // This works with dictionaries up to about 3 GiB. If bigger
+ // dictionary is wanted, some extra work is needed:
+ // - Several variables in lzma_mf have to be changed from uint32_t
+ // to size_t.
+ // - Memory usage calculation needs something too, e.g. use uint64_t
+ // for mf->size.
+ reserve = lz_options->dict_size / 2;
+ if (reserve > (UINT32_C(1) << 30))
+ reserve /= 2;
+
+ reserve += (lz_options->before_size + lz_options->match_len_max
+ + lz_options->after_size) / 2 + (UINT32_C(1) << 19);
+
+ old_size = mf->size;
+ mf->size = mf->keep_size_before + reserve + mf->keep_size_after;
+
+ // Deallocate the old history buffer if it exists but has different
+ // size than what is needed now.
+ if (mf->buffer != NULL && old_size != mf->size) {
+ lzma_free(mf->buffer, allocator);
+ mf->buffer = NULL;
+ }
+
+ // Match finder options
+ mf->match_len_max = lz_options->match_len_max;
+ mf->nice_len = lz_options->nice_len;
+
+ // cyclic_size has to stay smaller than 2 Gi. Note that this doesn't
+ // mean limiting dictionary size to less than 2 GiB. With a match
+ // finder that uses multibyte resolution (hashes start at e.g. every
+ // fourth byte), cyclic_size would stay below 2 Gi even when
+ // dictionary size is greater than 2 GiB.
+ //
+ // It would be possible to allow cyclic_size >= 2 Gi, but then we
+ // would need to be careful to use 64-bit types in various places
+ // (size_t could do since we would need bigger than 32-bit address
+ // space anyway). It would also require either zeroing a multigigabyte
+ // buffer at initialization (waste of time and RAM) or allow
+ // normalization in lz_encoder_mf.c to access uninitialized
+ // memory to keep the code simpler. The current way is simple and
+ // still allows pretty big dictionaries, so I don't expect these
+ // limits to change.
+ mf->cyclic_size = lz_options->dict_size + 1;
+
+ // Validate the match finder ID and setup the function pointers.
+ switch (lz_options->match_finder) {
+#ifdef HAVE_MF_HC3
+ case LZMA_MF_HC3:
+ mf->find = &lzma_mf_hc3_find;
+ mf->skip = &lzma_mf_hc3_skip;
+ break;
+#endif
+#ifdef HAVE_MF_HC4
+ case LZMA_MF_HC4:
+ mf->find = &lzma_mf_hc4_find;
+ mf->skip = &lzma_mf_hc4_skip;
+ break;
+#endif
+#ifdef HAVE_MF_BT2
+ case LZMA_MF_BT2:
+ mf->find = &lzma_mf_bt2_find;
+ mf->skip = &lzma_mf_bt2_skip;
+ break;
+#endif
+#ifdef HAVE_MF_BT3
+ case LZMA_MF_BT3:
+ mf->find = &lzma_mf_bt3_find;
+ mf->skip = &lzma_mf_bt3_skip;
+ break;
+#endif
+#ifdef HAVE_MF_BT4
+ case LZMA_MF_BT4:
+ mf->find = &lzma_mf_bt4_find;
+ mf->skip = &lzma_mf_bt4_skip;
+ break;
+#endif
+
+ default:
+ return true;
+ }
+
+ // Calculate the sizes of mf->hash and mf->son and check that
+ // nice_len is big enough for the selected match finder.
+ hash_bytes = lz_options->match_finder & 0x0F;
+ if (hash_bytes > mf->nice_len)
+ return true;
+
+ is_bt = (lz_options->match_finder & 0x10) != 0;
+
+ if (hash_bytes == 2) {
+ hs = 0xFFFF;
+ } else {
+ // Round dictionary size up to the next 2^n - 1 so it can
+ // be used as a hash mask.
+ hs = lz_options->dict_size - 1;
+ hs |= hs >> 1;
+ hs |= hs >> 2;
+ hs |= hs >> 4;
+ hs |= hs >> 8;
+ hs >>= 1;
+ hs |= 0xFFFF;
+
+ if (hs > (UINT32_C(1) << 24)) {
+ if (hash_bytes == 3)
+ hs = (UINT32_C(1) << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+
+ mf->hash_mask = hs;
+
+ ++hs;
+ if (hash_bytes > 2)
+ hs += HASH_2_SIZE;
+ if (hash_bytes > 3)
+ hs += HASH_3_SIZE;
+/*
+ No match finder uses this at the moment.
+ if (mf->hash_bytes > 4)
+ hs += HASH_4_SIZE;
+*/
+
+ // If the above code calculating hs is modified, make sure that
+ // this assertion stays valid (UINT32_MAX / 5 is not strictly the
+ // exact limit). If it doesn't, you need to calculate that
+ // hash_size_sum + sons_count cannot overflow.
+ assert(hs < UINT32_MAX / 5);
+
+ old_count = mf->hash_size_sum + mf->sons_count;
+ mf->hash_size_sum = hs;
+ mf->sons_count = mf->cyclic_size;
+ if (is_bt)
+ mf->sons_count *= 2;
+
+ new_count = mf->hash_size_sum + mf->sons_count;
+
+ // Deallocate the old hash array if it exists and has different size
+ // than what is needed now.
+ if (old_count != new_count) {
+ lzma_free(mf->hash, allocator);
+ mf->hash = NULL;
+ }
+
+ // Maximum number of match finder cycles
+ mf->depth = lz_options->depth;
+ if (mf->depth == 0) {
+ if (is_bt)
+ mf->depth = 16 + mf->nice_len / 2;
+ else
+ mf->depth = 4 + mf->nice_len / 4;
+ }
+
+ return false;
+}
+
+
+static bool
+lz_encoder_init(lzma_mf *mf, lzma_allocator *allocator,
+ const lzma_lz_options *lz_options)
+{
+ size_t alloc_count;
+
+ // Allocate the history buffer.
+ if (mf->buffer == NULL) {
+ mf->buffer = lzma_alloc(mf->size, allocator);
+ if (mf->buffer == NULL)
+ return true;
+ }
+
+ // Use cyclic_size as initial mf->offset. This allows
+ // avoiding a few branches in the match finders. The downside is
+ // that match finder needs to be normalized more often, which may
+ // hurt performance with huge dictionaries.
+ mf->offset = mf->cyclic_size;
+ mf->read_pos = 0;
+ mf->read_ahead = 0;
+ mf->read_limit = 0;
+ mf->write_pos = 0;
+ mf->pending = 0;
+
+ // Allocate match finder's hash array.
+ alloc_count = mf->hash_size_sum + mf->sons_count;
+
+#if UINT32_MAX >= SIZE_MAX / 4
+ // Check for integer overflow. (Huge dictionaries are not
+ // possible on 32-bit CPU.)
+ if (alloc_count > SIZE_MAX / sizeof(uint32_t))
+ return true;
+#endif
+
+ if (mf->hash == NULL) {
+ mf->hash = lzma_alloc(alloc_count * sizeof(uint32_t),
+ allocator);
+ if (mf->hash == NULL)
+ return true;
+ }
+
+ mf->son = mf->hash + mf->hash_size_sum;
+ mf->cyclic_pos = 0;
+
+ // Initialize the hash table. Since EMPTY_HASH_VALUE is zero, we
+ // can use memset().
+/*
+ for (uint32_t i = 0; i < hash_size_sum; ++i)
+ mf->hash[i] = EMPTY_HASH_VALUE;
+*/
+ memzero(mf->hash, (size_t)(mf->hash_size_sum) * sizeof(uint32_t));
+
+ // We don't need to initialize mf->son, but not doing that will
+ // make Valgrind complain in normalization (see normalize() in
+ // lz_encoder_mf.c).
+ //
+ // Skipping this initialization is *very* good when big dictionary is
+ // used but only small amount of data gets actually compressed: most
+ // of the mf->hash won't get actually allocated by the kernel, so
+ // we avoid wasting RAM and improve initialization speed a lot.
+ //memzero(mf->son, (size_t)(mf->sons_count) * sizeof(uint32_t));
+
+ // Handle preset dictionary.
+ if (lz_options->preset_dict != NULL
+ && lz_options->preset_dict_size > 0) {
+ // If the preset dictionary is bigger than the actual
+ // dictionary, use only the tail.
+ mf->write_pos = my_min(lz_options->preset_dict_size, mf->size);
+ memcpy(mf->buffer, lz_options->preset_dict
+ + lz_options->preset_dict_size - mf->write_pos,
+ mf->write_pos);
+ mf->action = LZMA_SYNC_FLUSH;
+ mf->skip(mf, mf->write_pos);
+ }
+
+ mf->action = LZMA_RUN;
+
+ return false;
+}
+
+
+extern uint64_t
+lzma_lz_encoder_memusage(const lzma_lz_options *lz_options)
+{
+ // Old buffers must not exist when calling lz_encoder_prepare().
+ lzma_mf mf = { NULL };
+
+ // Setup the size information into mf.
+ if (lz_encoder_prepare(&mf, NULL, lz_options))
+ return UINT64_MAX;
+
+ // Calculate the memory usage.
+ return (uint64_t)(mf.hash_size_sum + mf.sons_count)
+ * sizeof(uint32_t)
+ + (uint64_t)(mf.size) + sizeof(lzma_coder);
+}
+
+
+static void
+lz_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+
+ lzma_free(coder->mf.hash, allocator);
+ lzma_free(coder->mf.buffer, allocator);
+
+ if (coder->lz.end != NULL)
+ coder->lz.end(coder->lz.coder, allocator);
+ else
+ lzma_free(coder->lz.coder, allocator);
+
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+lz_encoder_update(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters_null lzma_attribute((__unused__)),
+ const lzma_filter *reversed_filters)
+{
+ if (coder->lz.options_update == NULL)
+ return LZMA_PROG_ERROR;
+
+ return_if_error(coder->lz.options_update(
+ coder->lz.coder, reversed_filters));
+
+ return lzma_next_filter_update(
+ &coder->next, allocator, reversed_filters + 1);
+}
+
+
+extern lzma_ret
+lzma_lz_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options))
+{
+ lzma_lz_options lz_options;
+
+#ifdef HAVE_SMALL
+ // We need that the CRC32 table has been initialized.
+ lzma_crc32_init();
+#endif
+
+ // Allocate and initialize the base data structure.
+ if (next->coder == NULL) {
+ next->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &lz_encode;
+ next->end = &lz_encoder_end;
+ next->update = &lz_encoder_update;
+
+ next->coder->lz.coder = NULL;
+ next->coder->lz.code = NULL;
+ next->coder->lz.end = NULL;
+
+ next->coder->mf.buffer = NULL;
+ next->coder->mf.hash = NULL;
+ next->coder->mf.hash_size_sum = 0;
+ next->coder->mf.sons_count = 0;
+
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ }
+
+ // Initialize the LZ-based encoder.
+ return_if_error(lz_init(&next->coder->lz, allocator,
+ filters[0].options, &lz_options));
+
+ // Setup the size information into next->coder->mf and deallocate
+ // old buffers if they have wrong size.
+ if (lz_encoder_prepare(&next->coder->mf, allocator, &lz_options))
+ return LZMA_OPTIONS_ERROR;
+
+ // Allocate new buffers if needed, and do the rest of
+ // the initialization.
+ if (lz_encoder_init(&next->coder->mf, allocator, &lz_options))
+ return LZMA_MEM_ERROR;
+
+ // Initialize the next filter in the chain, if any.
+ return lzma_next_filter_init(&next->coder->next, allocator,
+ filters + 1);
+}
+
+
+extern LZMA_API(lzma_bool)
+lzma_mf_is_supported(lzma_match_finder mf)
+{
+ bool ret = false;
+
+#ifdef HAVE_MF_HC3
+ if (mf == LZMA_MF_HC3)
+ ret = true;
+#endif
+
+#ifdef HAVE_MF_HC4
+ if (mf == LZMA_MF_HC4)
+ ret = true;
+#endif
+
+#ifdef HAVE_MF_BT2
+ if (mf == LZMA_MF_BT2)
+ ret = true;
+#endif
+
+#ifdef HAVE_MF_BT3
+ if (mf == LZMA_MF_BT3)
+ ret = true;
+#endif
+
+#ifdef HAVE_MF_BT4
+ if (mf == LZMA_MF_BT4)
+ ret = true;
+#endif
+
+ return ret;
+}
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_encoder.h b/Utilities/cmliblzma/liblzma/lz/lz_encoder.h
new file mode 100644
index 000000000..dcb4b2c5b
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_encoder.h
@@ -0,0 +1,328 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder.h
+/// \brief LZ in window and match finder API
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_ENCODER_H
+#define LZMA_LZ_ENCODER_H
+
+#include "common.h"
+
+
+/// A table of these is used by the LZ-based encoder to hold
+/// the length-distance pairs found by the match finder.
+typedef struct {
+ uint32_t len;
+ uint32_t dist;
+} lzma_match;
+
+
+typedef struct lzma_mf_s lzma_mf;
+struct lzma_mf_s {
+ ///////////////
+ // In Window //
+ ///////////////
+
+ /// Pointer to buffer with data to be compressed
+ uint8_t *buffer;
+
+ /// Total size of the allocated buffer (that is, including all
+ /// the extra space)
+ uint32_t size;
+
+ /// Number of bytes that must be kept available in our input history.
+ /// That is, once keep_size_before bytes have been processed,
+ /// buffer[read_pos - keep_size_before] is the oldest byte that
+ /// must be available for reading.
+ uint32_t keep_size_before;
+
+ /// Number of bytes that must be kept in buffer after read_pos.
+ /// That is, read_pos <= write_pos - keep_size_after as long as
+ /// action is LZMA_RUN; when action != LZMA_RUN, read_pos is allowed
+ /// to reach write_pos so that the last bytes get encoded too.
+ uint32_t keep_size_after;
+
+ /// Match finders store locations of matches using 32-bit integers.
+ /// To avoid adjusting several megabytes of integers every time the
+ /// input window is moved with move_window, we only adjust the
+ /// offset of the buffer. Thus, buffer[value_in_hash_table - offset]
+ /// is the byte pointed by value_in_hash_table.
+ uint32_t offset;
+
+ /// buffer[read_pos] is the next byte to run through the match
+ /// finder. This is incremented in the match finder once the byte
+ /// has been processed.
+ uint32_t read_pos;
+
+ /// Number of bytes that have been ran through the match finder, but
+ /// which haven't been encoded by the LZ-based encoder yet.
+ uint32_t read_ahead;
+
+ /// As long as read_pos is less than read_limit, there is enough
+ /// input available in buffer for at least one encoding loop.
+ ///
+ /// Because of the stateful API, read_limit may and will get greater
+ /// than read_pos quite often. This is taken into account when
+ /// calculating the value for keep_size_after.
+ uint32_t read_limit;
+
+ /// buffer[write_pos] is the first byte that doesn't contain valid
+ /// uncompressed data; that is, the next input byte will be copied
+ /// to buffer[write_pos].
+ uint32_t write_pos;
+
+ /// Number of bytes not hashed before read_pos. This is needed to
+ /// restart the match finder after LZMA_SYNC_FLUSH.
+ uint32_t pending;
+
+ //////////////////
+ // Match Finder //
+ //////////////////
+
+ /// Find matches. Returns the number of distance-length pairs written
+ /// to the matches array. This is called only via lzma_mf_find().
+ uint32_t (*find)(lzma_mf *mf, lzma_match *matches);
+
+ /// Skips num bytes. This is like find() but doesn't make the
+ /// distance-length pairs available, thus being a little faster.
+ /// This is called only via mf_skip().
+ void (*skip)(lzma_mf *mf, uint32_t num);
+
+ uint32_t *hash;
+ uint32_t *son;
+ uint32_t cyclic_pos;
+ uint32_t cyclic_size; // Must be dictionary size + 1.
+ uint32_t hash_mask;
+
+ /// Maximum number of loops in the match finder
+ uint32_t depth;
+
+ /// Maximum length of a match that the match finder will try to find.
+ uint32_t nice_len;
+
+ /// Maximum length of a match supported by the LZ-based encoder.
+ /// If the longest match found by the match finder is nice_len,
+ /// mf_find() tries to expand it up to match_len_max bytes.
+ uint32_t match_len_max;
+
+ /// When running out of input, binary tree match finders need to know
+ /// if it is due to flushing or finishing. The action is used also
+ /// by the LZ-based encoders themselves.
+ lzma_action action;
+
+ /// Number of elements in hash[]
+ uint32_t hash_size_sum;
+
+ /// Number of elements in son[]
+ uint32_t sons_count;
+};
+
+
+typedef struct {
+ /// Extra amount of data to keep available before the "actual"
+ /// dictionary.
+ size_t before_size;
+
+ /// Size of the history buffer
+ size_t dict_size;
+
+ /// Extra amount of data to keep available after the "actual"
+ /// dictionary.
+ size_t after_size;
+
+ /// Maximum length of a match that the LZ-based encoder can accept.
+ /// This is used to extend matches of length nice_len to the
+ /// maximum possible length.
+ size_t match_len_max;
+
+ /// Match finder will search matches up to this length.
+ /// This must be less than or equal to match_len_max.
+ size_t nice_len;
+
+ /// Type of the match finder to use
+ lzma_match_finder match_finder;
+
+ /// Maximum search depth
+ uint32_t depth;
+
+ /// TODO: Comment
+ const uint8_t *preset_dict;
+
+ uint32_t preset_dict_size;
+
+} lzma_lz_options;
+
+
+// The total usable buffer space at any moment outside the match finder:
+// before_size + dict_size + after_size + match_len_max
+//
+// In reality, there's some extra space allocated to prevent the number of
+// memmove() calls reasonable. The bigger the dict_size is, the bigger
+// this extra buffer will be since with bigger dictionaries memmove() would
+// also take longer.
+//
+// A single encoder loop in the LZ-based encoder may call the match finder
+// (mf_find() or mf_skip()) at most after_size times. In other words,
+// a single encoder loop may increment lzma_mf.read_pos at most after_size
+// times. Since matches are looked up to
+// lzma_mf.buffer[lzma_mf.read_pos + match_len_max - 1], the total
+// amount of extra buffer needed after dict_size becomes
+// after_size + match_len_max.
+//
+// before_size has two uses. The first one is to keep literals available
+// in cases when the LZ-based encoder has made some read ahead.
+// TODO: Maybe this could be changed by making the LZ-based encoders to
+// store the actual literals as they do with length-distance pairs.
+//
+// Algorithms such as LZMA2 first try to compress a chunk, and then check
+// if the encoded result is smaller than the uncompressed one. If the chunk
+// was uncompressible, it is better to store it in uncompressed form in
+// the output stream. To do this, the whole uncompressed chunk has to be
+// still available in the history buffer. before_size achieves that.
+
+
+typedef struct {
+ /// Data specific to the LZ-based encoder
+ lzma_coder *coder;
+
+ /// Function to encode from *dict to out[]
+ lzma_ret (*code)(lzma_coder *LZMA_RESTRICT coder,
+ lzma_mf *LZMA_RESTRICT mf, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size);
+
+ /// Free allocated resources
+ void (*end)(lzma_coder *coder, lzma_allocator *allocator);
+
+ /// Update the options in the middle of the encoding.
+ lzma_ret (*options_update)(lzma_coder *coder,
+ const lzma_filter *filter);
+
+} lzma_lz_encoder;
+
+
+// Basic steps:
+// 1. Input gets copied into the dictionary.
+// 2. Data in dictionary gets run through the match finder byte by byte.
+// 3. The literals and matches are encoded using e.g. LZMA.
+//
+// The bytes that have been ran through the match finder, but not encoded yet,
+// are called `read ahead'.
+
+
+/// Get pointer to the first byte not ran through the match finder
+static inline uint8_t *
+mf_ptr(const lzma_mf *mf)
+{
+ return mf->buffer + mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been ran through the match finder yet.
+static inline uint32_t
+mf_avail(const lzma_mf *mf)
+{
+ return mf->write_pos - mf->read_pos;
+}
+
+
+/// Get the number of bytes that haven't been encoded yet (some of these
+/// bytes may have been ran through the match finder though).
+static inline uint32_t
+mf_unencoded(const lzma_mf *mf)
+{
+ return mf->write_pos - mf->read_pos + mf->read_ahead;
+}
+
+
+/// Calculate the absolute offset from the beginning of the most recent
+/// dictionary reset. Only the lowest four bits are important, so there's no
+/// problem that we don't know the 64-bit size of the data encoded so far.
+///
+/// NOTE: When moving the input window, we need to do it so that the lowest
+/// bits of dict->read_pos are not modified to keep this macro working
+/// as intended.
+static inline uint32_t
+mf_position(const lzma_mf *mf)
+{
+ return mf->read_pos - mf->read_ahead;
+}
+
+
+/// Since everything else begins with mf_, use it also for lzma_mf_find().
+#define mf_find lzma_mf_find
+
+
+/// Skip the given number of bytes. This is used when a good match was found.
+/// For example, if mf_find() finds a match of 200 bytes long, the first byte
+/// of that match was already consumed by mf_find(), and the rest 199 bytes
+/// have to be skipped with mf_skip(mf, 199).
+static inline void
+mf_skip(lzma_mf *mf, uint32_t amount)
+{
+ if (amount != 0) {
+ mf->skip(mf, amount);
+ mf->read_ahead += amount;
+ }
+}
+
+
+/// Copies at most *left number of bytes from the history buffer
+/// to out[]. This is needed by LZMA2 to encode uncompressed chunks.
+static inline void
+mf_read(lzma_mf *mf, uint8_t *out, size_t *out_pos, size_t out_size,
+ size_t *left)
+{
+ const size_t out_avail = out_size - *out_pos;
+ const size_t copy_size = my_min(out_avail, *left);
+
+ assert(mf->read_ahead == 0);
+ assert(mf->read_pos >= *left);
+
+ memcpy(out + *out_pos, mf->buffer + mf->read_pos - *left,
+ copy_size);
+
+ *out_pos += copy_size;
+ *left -= copy_size;
+ return;
+}
+
+
+extern lzma_ret lzma_lz_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ lzma_ret (*lz_init)(lzma_lz_encoder *lz,
+ lzma_allocator *allocator, const void *options,
+ lzma_lz_options *lz_options));
+
+
+extern uint64_t lzma_lz_encoder_memusage(const lzma_lz_options *lz_options);
+
+
+// These are only for LZ encoder's internal use.
+extern uint32_t lzma_mf_find(
+ lzma_mf *mf, uint32_t *count, lzma_match *matches);
+
+extern uint32_t lzma_mf_hc3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc3_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_hc4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_hc4_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt2_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt2_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt3_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt3_skip(lzma_mf *dict, uint32_t amount);
+
+extern uint32_t lzma_mf_bt4_find(lzma_mf *dict, lzma_match *matches);
+extern void lzma_mf_bt4_skip(lzma_mf *dict, uint32_t amount);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash.h b/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash.h
new file mode 100644
index 000000000..de17c54fc
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash.h
@@ -0,0 +1,105 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder_hash.h
+/// \brief Hash macros for match finders
+//
+// Author: Igor Pavlov
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZ_ENCODER_HASH_H
+#define LZMA_LZ_ENCODER_HASH_H
+
+#if defined(WORDS_BIGENDIAN) && !defined(HAVE_SMALL)
+ // This is to make liblzma produce the same output on big endian
+ // systems that it does on little endian systems. lz_encoder.c
+ // takes care of including the actual table.
+ extern const uint32_t lzma_lz_hash_table[256];
+# define hash_table lzma_lz_hash_table
+#else
+# include "check.h"
+# define hash_table lzma_crc32_table[0]
+#endif
+
+#define HASH_2_SIZE (UINT32_C(1) << 10)
+#define HASH_3_SIZE (UINT32_C(1) << 16)
+#define HASH_4_SIZE (UINT32_C(1) << 20)
+
+#define HASH_2_MASK (HASH_2_SIZE - 1)
+#define HASH_3_MASK (HASH_3_SIZE - 1)
+#define HASH_4_MASK (HASH_4_SIZE - 1)
+
+#define FIX_3_HASH_SIZE (HASH_2_SIZE)
+#define FIX_4_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE)
+#define FIX_5_HASH_SIZE (HASH_2_SIZE + HASH_3_SIZE + HASH_4_SIZE)
+
+// Endianness doesn't matter in hash_2_calc() (no effect on the output).
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+# define hash_2_calc() \
+ hash_value = *(const uint16_t *)(cur)
+#else
+# define hash_2_calc() \
+ hash_value = (uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)
+#endif
+
+#define hash_3_calc() \
+ temp = hash_table[cur[0]] ^ cur[1]; \
+ hash_2_value = temp & HASH_2_MASK; \
+ hash_value = (temp ^ ((uint32_t)(cur[2]) << 8)) & mf->hash_mask
+
+#define hash_4_calc() \
+ temp = hash_table[cur[0]] ^ cur[1]; \
+ hash_2_value = temp & HASH_2_MASK; \
+ hash_3_value = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ hash_value = (temp ^ ((uint32_t)(cur[2]) << 8) \
+ ^ (hash_table[cur[3]] << 5)) & mf->hash_mask
+
+
+// The following are not currently used.
+
+#define hash_5_calc() \
+ const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+ ^ hash_table[cur[3]] << 5); \
+ const uint32_t hash_value \
+ = (hash_4_value ^ (hash_table[cur[4]] << 3)) \
+ & mf->hash_mask; \
+ hash_4_value &= HASH_4_MASK
+
+/*
+#define hash_zip_calc() \
+ const uint32_t hash_value \
+ = (((uint32_t)(cur[0]) | ((uint32_t)(cur[1]) << 8)) \
+ ^ hash_table[cur[2]]) & 0xFFFF
+*/
+
+#define hash_zip_calc() \
+ const uint32_t hash_value \
+ = (((uint32_t)(cur[2]) | ((uint32_t)(cur[0]) << 8)) \
+ ^ hash_table[cur[1]]) & 0xFFFF
+
+#define mt_hash_2_calc() \
+ const uint32_t hash_2_value \
+ = (hash_table[cur[0]] ^ cur[1]) & HASH_2_MASK
+
+#define mt_hash_3_calc() \
+ const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK
+
+#define mt_hash_4_calc() \
+ const uint32_t temp = hash_table[cur[0]] ^ cur[1]; \
+ const uint32_t hash_2_value = temp & HASH_2_MASK; \
+ const uint32_t hash_3_value \
+ = (temp ^ ((uint32_t)(cur[2]) << 8)) & HASH_3_MASK; \
+ const uint32_t hash_4_value = (temp ^ ((uint32_t)(cur[2]) << 8) ^ \
+ (hash_table[cur[3]] << 5)) & HASH_4_MASK
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash_table.h b/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash_table.h
new file mode 100644
index 000000000..8c51717d7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_encoder_hash_table.h
@@ -0,0 +1,68 @@
+/* This file has been automatically generated by crc32_tablegen.c. */
+
+const uint32_t lzma_lz_hash_table[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
+ 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
+ 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
+ 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+ 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
+ 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
+ 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
+ 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
+ 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
+ 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
+ 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+ 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
+ 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
+ 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
+ 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
+ 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
+ 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
+ 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+ 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
+ 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
+ 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
+ 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
+ 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
+ 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
+ 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+ 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
+ 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
+ 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
+ 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
+ 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
+ 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
+ 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+ 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+};
diff --git a/Utilities/cmliblzma/liblzma/lz/lz_encoder_mf.c b/Utilities/cmliblzma/liblzma/lz/lz_encoder_mf.c
new file mode 100644
index 000000000..50c3459aa
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lz/lz_encoder_mf.c
@@ -0,0 +1,814 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lz_encoder_mf.c
+/// \brief Match finders
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lz_encoder_hash.h"
+
+
+/// \brief Find matches starting from the current byte
+///
+/// \return The length of the longest match found
+extern uint32_t
+lzma_mf_find(lzma_mf *mf, uint32_t *count_ptr, lzma_match *matches)
+{
+ // Call the match finder. It returns the number of length-distance
+ // pairs found.
+ // FIXME: Minimum count is zero, what _exactly_ is the maximum?
+ const uint32_t count = mf->find(mf, matches);
+
+ // Length of the longest match; assume that no matches were found
+ // and thus the maximum length is zero.
+ uint32_t len_best = 0;
+
+ if (count > 0) {
+#ifndef NDEBUG
+ uint32_t i;
+ // Validate the matches.
+ for (i = 0; i < count; ++i) {
+ assert(matches[i].len <= mf->nice_len);
+ assert(matches[i].dist < mf->read_pos);
+ assert(memcmp(mf_ptr(mf) - 1,
+ mf_ptr(mf) - matches[i].dist - 2,
+ matches[i].len) == 0);
+ }
+#endif
+
+ // The last used element in the array contains
+ // the longest match.
+ len_best = matches[count - 1].len;
+
+ // If a match of maximum search length was found, try to
+ // extend the match to maximum possible length.
+ if (len_best == mf->nice_len) {
+ uint8_t *p1;
+ uint8_t *p2;
+
+ // The limit for the match length is either the
+ // maximum match length supported by the LZ-based
+ // encoder or the number of bytes left in the
+ // dictionary, whichever is smaller.
+ uint32_t limit = mf_avail(mf) + 1;
+ if (limit > mf->match_len_max)
+ limit = mf->match_len_max;
+
+ // Pointer to the byte we just ran through
+ // the match finder.
+ p1 = mf_ptr(mf) - 1;
+
+ // Pointer to the beginning of the match. We need -1
+ // here because the match distances are zero based.
+ p2 = p1 - matches[count - 1].dist - 1;
+
+ while (len_best < limit
+ && p1[len_best] == p2[len_best])
+ ++len_best;
+ }
+ }
+
+ *count_ptr = count;
+
+ // Finally update the read position to indicate that match finder was
+ // run for this dictionary offset.
+ ++mf->read_ahead;
+
+ return len_best;
+}
+
+
+/// Hash value to indicate unused element in the hash. Since we start the
+/// positions from dict_size + 1, zero is always too far to qualify
+/// as usable match position.
+#define EMPTY_HASH_VALUE 0
+
+
+/// Normalization must be done when lzma_mf.offset + lzma_mf.read_pos
+/// reaches MUST_NORMALIZE_POS.
+#define MUST_NORMALIZE_POS UINT32_MAX
+
+
+/// \brief Normalizes hash values
+///
+/// The hash arrays store positions of match candidates. The positions are
+/// relative to an arbitrary offset that is not the same as the absolute
+/// offset in the input stream. The relative position of the current byte
+/// is lzma_mf.offset + lzma_mf.read_pos. The distances of the matches are
+/// the differences of the current read position and the position found from
+/// the hash.
+///
+/// To prevent integer overflows of the offsets stored in the hash arrays,
+/// we need to "normalize" the stored values now and then. During the
+/// normalization, we drop values that indicate distance greater than the
+/// dictionary size, thus making space for new values.
+static void
+normalize(lzma_mf *mf)
+{
+ uint32_t i;
+ uint32_t subvalue;
+ uint32_t count;
+ uint32_t *hash;
+
+ assert(mf->read_pos + mf->offset == MUST_NORMALIZE_POS);
+
+ // In future we may not want to touch the lowest bits, because there
+ // may be match finders that use larger resolution than one byte.
+ subvalue = (MUST_NORMALIZE_POS - mf->cyclic_size);
+ // & (~(UINT32_C(1) << 10) - 1);
+
+ count = mf->hash_size_sum + mf->sons_count;
+ hash = mf->hash;
+
+ for (i = 0; i < count; ++i) {
+ // If the distance is greater than the dictionary size,
+ // we can simply mark the hash element as empty.
+ //
+ // NOTE: Only the first mf->hash_size_sum elements are
+ // initialized for sure. There may be uninitialized elements
+ // in mf->son. Since we go through both mf->hash and
+ // mf->son here in normalization, Valgrind may complain
+ // that the "if" below depends on uninitialized value. In
+ // this case it is safe to ignore the warning. See also the
+ // comments in lz_encoder_init() in lz_encoder.c.
+ if (hash[i] <= subvalue)
+ hash[i] = EMPTY_HASH_VALUE;
+ else
+ hash[i] -= subvalue;
+ }
+
+ // Update offset to match the new locations.
+ mf->offset -= subvalue;
+
+ return;
+}
+
+
+/// Mark the current byte as processed from point of view of the match finder.
+static void
+move_pos(lzma_mf *mf)
+{
+ if (++mf->cyclic_pos == mf->cyclic_size)
+ mf->cyclic_pos = 0;
+
+ ++mf->read_pos;
+ assert(mf->read_pos <= mf->write_pos);
+
+ if (unlikely(mf->read_pos + mf->offset == UINT32_MAX))
+ normalize(mf);
+}
+
+
+/// When flushing, we cannot run the match finder unless there is nice_len
+/// bytes available in the dictionary. Instead, we skip running the match
+/// finder (indicating that no match was found), and count how many bytes we
+/// have ignored this way.
+///
+/// When new data is given after the flushing was completed, the match finder
+/// is restarted by rewinding mf->read_pos backwards by mf->pending. Then
+/// the missed bytes are added to the hash using the match finder's skip
+/// function (with small amount of input, it may start using mf->pending
+/// again if flushing).
+///
+/// Due to this rewinding, we don't touch cyclic_pos or test for
+/// normalization. It will be done when the match finder's skip function
+/// catches up after a flush.
+static void
+move_pending(lzma_mf *mf)
+{
+ ++mf->read_pos;
+ assert(mf->read_pos <= mf->write_pos);
+ ++mf->pending;
+}
+
+
+/// Calculate len_limit and determine if there is enough input to run
+/// the actual match finder code. Sets up "cur" and "pos". This macro
+/// is used by all find functions and binary tree skip functions. Hash
+/// chain skip function doesn't need len_limit so a simpler code is used
+/// in them.
+#define header(is_bt, len_min, ret_op) \
+ uint32_t len_limit = mf_avail(mf); \
+ if (mf->nice_len <= len_limit) { \
+ len_limit = mf->nice_len; \
+ } else if (len_limit < (len_min) \
+ || (is_bt && mf->action == LZMA_SYNC_FLUSH)) { \
+ assert(mf->action != LZMA_RUN); \
+ move_pending(mf); \
+ ret_op; \
+ } \
+ cur = mf_ptr(mf); \
+ pos = mf->read_pos + mf->offset
+
+
+/// Header for find functions. "return 0" indicates that zero matches
+/// were found.
+#define header_find(is_bt, len_min) \
+ header(is_bt, len_min, return 0)
+
+
+/// Header for a loop in a skip function. "continue" tells to skip the rest
+/// of the code in the loop.
+#define header_skip(is_bt, len_min) \
+ header(is_bt, len_min, continue)
+
+
+/// Calls hc_find_func() or bt_find_func() and calculates the total number
+/// of matches found. Updates the dictionary position and returns the number
+/// of matches found.
+#define call_find(func, len_best) \
+do { \
+ matches_count = func(len_limit, pos, cur, cur_match, mf->depth, \
+ mf->son, mf->cyclic_pos, mf->cyclic_size, \
+ matches + matches_count, len_best) \
+ - matches; \
+ move_pos(mf); \
+ return matches_count; \
+} while (0)
+
+
+////////////////
+// Hash Chain //
+////////////////
+
+#if defined(HAVE_MF_HC3) || defined(HAVE_MF_HC4)
+///
+///
+/// \param len_limit Don't look for matches longer than len_limit.
+/// \param pos lzma_mf.read_pos + lzma_mf.offset
+/// \param cur Pointer to current byte (mf_ptr(mf))
+/// \param cur_match Start position of the current match candidate
+/// \param depth Maximum length of the hash chain
+/// \param son lzma_mf.son (contains the hash chain)
+/// \param cyclic_pos
+/// \param cyclic_size
+/// \param matches Array to hold the matches.
+/// \param len_best The length of the longest match found so far.
+static lzma_match *
+hc_find_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t depth,
+ uint32_t *const son,
+ const uint32_t cyclic_pos,
+ const uint32_t cyclic_size,
+ lzma_match *matches,
+ uint32_t len_best)
+{
+ son[cyclic_pos] = cur_match;
+
+ while (true) {
+ const uint32_t delta = pos - cur_match;
+ const uint8_t *pb;
+ if (depth-- == 0 || delta >= cyclic_size)
+ return matches;
+
+ pb = cur - delta;
+ cur_match = son[cyclic_pos - delta
+ + (delta > cyclic_pos ? cyclic_size : 0)];
+
+ if (pb[len_best] == cur[len_best] && pb[0] == cur[0]) {
+ uint32_t len = 0;
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len_best < len) {
+ len_best = len;
+ matches->len = len;
+ matches->dist = delta - 1;
+ ++matches;
+
+ if (len == len_limit)
+ return matches;
+ }
+ }
+ }
+}
+
+
+#define hc_find(len_best) \
+ call_find(hc_find_func, len_best)
+
+
+#define hc_skip() \
+do { \
+ mf->son[mf->cyclic_pos] = cur_match; \
+ move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_HC3
+extern uint32_t
+lzma_mf_hc3_find(lzma_mf *mf, lzma_match *matches)
+{
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value; /* hash_3_calc */
+ uint32_t delta2, cur_match;
+ uint32_t len_best = 2;
+ uint32_t matches_count = 0;
+
+ header_find(false, 3);
+
+ hash_3_calc();
+
+ delta2 = pos - mf->hash[hash_2_value];
+ cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[0].len = len_best;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+
+ if (len_best == len_limit) {
+ hc_skip();
+ return 1; // matches_count
+ }
+ }
+
+ hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc3_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value; /* hash_3_calc */
+ uint32_t cur_match;
+
+ if (mf_avail(mf) < 3) {
+ move_pending(mf);
+ continue;
+ }
+
+ cur = mf_ptr(mf);
+ pos = mf->read_pos + mf->offset;
+
+ hash_3_calc();
+
+ cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ hc_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_HC4
+extern uint32_t
+lzma_mf_hc4_find(lzma_mf *mf, lzma_match *matches)
+{
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value, hash_3_value; /* hash_4_calc */
+ uint32_t delta2, delta3, cur_match;
+ uint32_t len_best = 1;
+ uint32_t matches_count = 0;
+
+ header_find(false, 4);
+
+ hash_4_calc();
+
+ delta2 = pos - mf->hash[hash_2_value];
+ delta3 = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+ cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value ] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+ len_best = 2;
+ matches[0].len = 2;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+ }
+
+ if (delta2 != delta3 && delta3 < mf->cyclic_size
+ && *(cur - delta3) == *cur) {
+ len_best = 3;
+ matches[matches_count++].dist = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ if (matches_count != 0) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[matches_count - 1].len = len_best;
+
+ if (len_best == len_limit) {
+ hc_skip();
+ return matches_count;
+ }
+ }
+
+ if (len_best < 3)
+ len_best = 3;
+
+ hc_find(len_best);
+}
+
+
+extern void
+lzma_mf_hc4_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value, hash_3_value; /* hash_4_calc */
+ uint32_t cur_match;
+
+ if (mf_avail(mf) < 4) {
+ move_pending(mf);
+ continue;
+ }
+
+ cur = mf_ptr(mf);
+ pos = mf->read_pos + mf->offset;
+
+ hash_4_calc();
+
+ cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ hc_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+/////////////////
+// Binary Tree //
+/////////////////
+
+#if defined(HAVE_MF_BT2) || defined(HAVE_MF_BT3) || defined(HAVE_MF_BT4)
+static lzma_match *
+bt_find_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t depth,
+ uint32_t *const son,
+ const uint32_t cyclic_pos,
+ const uint32_t cyclic_size,
+ lzma_match *matches,
+ uint32_t len_best)
+{
+ uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
+ uint32_t *ptr1 = son + (cyclic_pos << 1);
+
+ uint32_t len0 = 0;
+ uint32_t len1 = 0;
+
+ while (true) {
+ uint32_t *pair;
+ const uint8_t *pb;
+ uint32_t len;
+
+ const uint32_t delta = pos - cur_match;
+ if (depth-- == 0 || delta >= cyclic_size) {
+ *ptr0 = EMPTY_HASH_VALUE;
+ *ptr1 = EMPTY_HASH_VALUE;
+ return matches;
+ }
+
+ pair = son + ((cyclic_pos - delta
+ + (delta > cyclic_pos ? cyclic_size : 0))
+ << 1);
+
+ pb = cur - delta;
+ len = my_min(len0, len1);
+
+ if (pb[len] == cur[len]) {
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len_best < len) {
+ len_best = len;
+ matches->len = len;
+ matches->dist = delta - 1;
+ ++matches;
+
+ if (len == len_limit) {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return matches;
+ }
+ }
+ }
+
+ if (pb[len] < cur[len]) {
+ *ptr1 = cur_match;
+ ptr1 = pair + 1;
+ cur_match = *ptr1;
+ len1 = len;
+ } else {
+ *ptr0 = cur_match;
+ ptr0 = pair;
+ cur_match = *ptr0;
+ len0 = len;
+ }
+ }
+}
+
+
+static void
+bt_skip_func(
+ const uint32_t len_limit,
+ const uint32_t pos,
+ const uint8_t *const cur,
+ uint32_t cur_match,
+ uint32_t depth,
+ uint32_t *const son,
+ const uint32_t cyclic_pos,
+ const uint32_t cyclic_size)
+{
+ uint32_t *ptr0 = son + (cyclic_pos << 1) + 1;
+ uint32_t *ptr1 = son + (cyclic_pos << 1);
+
+ uint32_t len0 = 0;
+ uint32_t len1 = 0;
+
+ while (true) {
+ uint32_t *pair;
+ const uint8_t *pb;
+ uint32_t len;
+
+ const uint32_t delta = pos - cur_match;
+ if (depth-- == 0 || delta >= cyclic_size) {
+ *ptr0 = EMPTY_HASH_VALUE;
+ *ptr1 = EMPTY_HASH_VALUE;
+ return;
+ }
+
+ pair = son + ((cyclic_pos - delta
+ + (delta > cyclic_pos ? cyclic_size : 0))
+ << 1);
+ pb = cur - delta;
+ len = my_min(len0, len1);
+
+ if (pb[len] == cur[len]) {
+ while (++len != len_limit)
+ if (pb[len] != cur[len])
+ break;
+
+ if (len == len_limit) {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+
+ if (pb[len] < cur[len]) {
+ *ptr1 = cur_match;
+ ptr1 = pair + 1;
+ cur_match = *ptr1;
+ len1 = len;
+ } else {
+ *ptr0 = cur_match;
+ ptr0 = pair;
+ cur_match = *ptr0;
+ len0 = len;
+ }
+ }
+}
+
+
+#define bt_find(len_best) \
+ call_find(bt_find_func, len_best)
+
+#define bt_skip() \
+do { \
+ bt_skip_func(len_limit, pos, cur, cur_match, mf->depth, \
+ mf->son, mf->cyclic_pos, \
+ mf->cyclic_size); \
+ move_pos(mf); \
+} while (0)
+
+#endif
+
+
+#ifdef HAVE_MF_BT2
+extern uint32_t
+lzma_mf_bt2_find(lzma_mf *mf, lzma_match *matches)
+{
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t hash_value; /* hash_2_calc */
+ uint32_t cur_match;
+ uint32_t matches_count = 0;
+
+ header_find(true, 2);
+
+ hash_2_calc();
+
+ cur_match = mf->hash[hash_value];
+ mf->hash[hash_value] = pos;
+
+ bt_find(1);
+}
+
+
+extern void
+lzma_mf_bt2_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t hash_value; /* hash_2_calc */
+ uint32_t cur_match;
+
+ header_skip(true, 2);
+
+ hash_2_calc();
+
+ cur_match = mf->hash[hash_value];
+ mf->hash[hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT3
+extern uint32_t
+lzma_mf_bt3_find(lzma_mf *mf, lzma_match *matches)
+{
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value; /* hash_3_calc */
+ uint32_t delta2, cur_match;
+ uint32_t len_best = 2;
+ uint32_t matches_count = 0;
+
+ header_find(true, 3);
+
+ hash_3_calc();
+
+ delta2 = pos - mf->hash[hash_2_value];
+ cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[0].len = len_best;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+
+ if (len_best == len_limit) {
+ bt_skip();
+ return 1; // matches_count
+ }
+ }
+
+ bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt3_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value; /* hash_3_calc */
+ uint32_t cur_match;
+
+ header_skip(true, 3);
+
+ hash_3_calc();
+
+ cur_match = mf->hash[FIX_3_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
+
+
+#ifdef HAVE_MF_BT4
+extern uint32_t
+lzma_mf_bt4_find(lzma_mf *mf, lzma_match *matches)
+{
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value, hash_3_value; /* hash_4_calc */
+ uint32_t delta2, delta3, cur_match;
+ uint32_t len_best = 1;
+ uint32_t matches_count = 0;
+
+ header_find(true, 4);
+
+ hash_4_calc();
+
+ delta2 = pos - mf->hash[hash_2_value];
+ delta3 = pos - mf->hash[FIX_3_HASH_SIZE + hash_3_value];
+ cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ if (delta2 < mf->cyclic_size && *(cur - delta2) == *cur) {
+ len_best = 2;
+ matches[0].len = 2;
+ matches[0].dist = delta2 - 1;
+ matches_count = 1;
+ }
+
+ if (delta2 != delta3 && delta3 < mf->cyclic_size
+ && *(cur - delta3) == *cur) {
+ len_best = 3;
+ matches[matches_count++].dist = delta3 - 1;
+ delta2 = delta3;
+ }
+
+ if (matches_count != 0) {
+ for ( ; len_best != len_limit; ++len_best)
+ if (*(cur + len_best - delta2) != cur[len_best])
+ break;
+
+ matches[matches_count - 1].len = len_best;
+
+ if (len_best == len_limit) {
+ bt_skip();
+ return matches_count;
+ }
+ }
+
+ if (len_best < 3)
+ len_best = 3;
+
+ bt_find(len_best);
+}
+
+
+extern void
+lzma_mf_bt4_skip(lzma_mf *mf, uint32_t amount)
+{
+ do {
+ const uint8_t *cur;
+ uint32_t pos;
+ uint32_t temp, hash_value, hash_2_value, hash_3_value; /* hash_4_calc */
+ uint32_t cur_match;
+
+ header_skip(true, 4);
+
+ hash_4_calc();
+
+ cur_match = mf->hash[FIX_4_HASH_SIZE + hash_value];
+
+ mf->hash[hash_2_value] = pos;
+ mf->hash[FIX_3_HASH_SIZE + hash_3_value] = pos;
+ mf->hash[FIX_4_HASH_SIZE + hash_value] = pos;
+
+ bt_skip();
+
+ } while (--amount != 0);
+}
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/fastpos.h b/Utilities/cmliblzma/liblzma/lzma/fastpos.h
new file mode 100644
index 000000000..5a834d68d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/fastpos.h
@@ -0,0 +1,142 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fastpos.h
+/// \brief Kind of two-bit version of bit scan reverse
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_FASTPOS_H
+#define LZMA_FASTPOS_H
+
+// LZMA encodes match distances (positions) by storing the highest two
+// bits using a six-bit value [0, 63], and then the missing lower bits.
+// Dictionary size is also stored using this encoding in the new .lzma
+// file format header.
+//
+// fastpos.h provides a way to quickly find out the correct six-bit
+// values. The following table gives some examples of this encoding:
+//
+// pos return
+// 0 0
+// 1 1
+// 2 2
+// 3 3
+// 4 4
+// 5 4
+// 6 5
+// 7 5
+// 8 6
+// 11 6
+// 12 7
+// ... ...
+// 15 7
+// 16 8
+// 17 8
+// ... ...
+// 23 8
+// 24 9
+// 25 9
+// ... ...
+//
+//
+// Provided functions or macros
+// ----------------------------
+//
+// get_pos_slot(pos) is the basic version. get_pos_slot_2(pos)
+// assumes that pos >= FULL_DISTANCES, thus the result is at least
+// FULL_DISTANCES_BITS * 2. Using get_pos_slot(pos) instead of
+// get_pos_slot_2(pos) would give the same result, but get_pos_slot_2(pos)
+// should be tiny bit faster due to the assumption being made.
+//
+//
+// Size vs. speed
+// --------------
+//
+// With some CPUs that have fast BSR (bit scan reverse) instruction, the
+// size optimized version is slightly faster than the bigger table based
+// approach. Such CPUs include Intel Pentium Pro, Pentium II, Pentium III
+// and Core 2 (possibly others). AMD K7 seems to have slower BSR, but that
+// would still have speed roughly comparable to the table version. Older
+// x86 CPUs like the original Pentium have very slow BSR; on those systems
+// the table version is a lot faster.
+//
+// On some CPUs, the table version is a lot faster when using position
+// dependent code, but with position independent code the size optimized
+// version is slightly faster. This occurs at least on 32-bit SPARC (no
+// ASM optimizations).
+//
+// I'm making the table version the default, because that has good speed
+// on all systems I have tried. The size optimized version is sometimes
+// slightly faster, but sometimes it is a lot slower.
+
+#include "config.h"
+
+#ifdef HAVE_SMALL
+# define get_pos_slot(pos) ((pos) <= 4 ? (pos) : get_pos_slot_2(pos))
+
+static inline uint32_t
+get_pos_slot_2(uint32_t pos)
+{
+ const uint32_t i = bsr32(pos);
+ return (i + i) + ((pos >> (i - 1)) & 1);
+}
+
+
+#else
+
+#define FASTPOS_BITS 13
+
+extern const uint8_t lzma_fastpos[1 << FASTPOS_BITS];
+
+
+#define fastpos_shift(extra, n) \
+ ((extra) + (n) * (FASTPOS_BITS - 1))
+
+#define fastpos_limit(extra, n) \
+ (UINT32_C(1) << (FASTPOS_BITS + fastpos_shift(extra, n)))
+
+#define fastpos_result(pos, extra, n) \
+ lzma_fastpos[(pos) >> fastpos_shift(extra, n)] \
+ + 2 * fastpos_shift(extra, n)
+
+
+static inline uint32_t
+get_pos_slot(uint32_t pos)
+{
+ // If it is small enough, we can pick the result directly from
+ // the precalculated table.
+ if (pos < fastpos_limit(0, 0))
+ return lzma_fastpos[pos];
+
+ if (pos < fastpos_limit(0, 1))
+ return fastpos_result(pos, 0, 1);
+
+ return fastpos_result(pos, 0, 2);
+}
+
+
+#ifdef FULL_DISTANCES_BITS
+static inline uint32_t
+get_pos_slot_2(uint32_t pos)
+{
+ assert(pos >= FULL_DISTANCES);
+
+ if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 0))
+ return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 0);
+
+ if (pos < fastpos_limit(FULL_DISTANCES_BITS - 1, 1))
+ return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 1);
+
+ return fastpos_result(pos, FULL_DISTANCES_BITS - 1, 2);
+}
+#endif
+
+#endif
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/fastpos_table.c b/Utilities/cmliblzma/liblzma/lzma/fastpos_table.c
new file mode 100644
index 000000000..6a3ceac0e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/fastpos_table.c
@@ -0,0 +1,519 @@
+/* This file has been automatically generated by fastpos_tablegen.c. */
+
+#include "common.h"
+#include "fastpos.h"
+
+const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {
+ 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25
+};
diff --git a/Utilities/cmliblzma/liblzma/lzma/fastpos_tablegen.c b/Utilities/cmliblzma/liblzma/lzma/fastpos_tablegen.c
new file mode 100644
index 000000000..c97e6f411
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/fastpos_tablegen.c
@@ -0,0 +1,56 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file fastpos_tablegen.c
+/// \brief Generates the lzma_fastpos[] lookup table
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <sys/types.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include "fastpos.h"
+
+
+int
+main(void)
+{
+ uint8_t fastpos[1 << FASTPOS_BITS];
+
+ const uint8_t fast_slots = 2 * FASTPOS_BITS;
+ uint32_t c = 2;
+
+ fastpos[0] = 0;
+ fastpos[1] = 1;
+
+ for (uint8_t slot_fast = 2; slot_fast < fast_slots; ++slot_fast) {
+ const uint32_t k = 1 << ((slot_fast >> 1) - 1);
+ for (uint32_t j = 0; j < k; ++j, ++c)
+ fastpos[c] = slot_fast;
+ }
+
+ printf("/* This file has been automatically generated "
+ "by fastpos_tablegen.c. */\n\n"
+ "#include \"common.h\"\n"
+ "#include \"fastpos.h\"\n\n"
+ "const uint8_t lzma_fastpos[1 << FASTPOS_BITS] = {");
+
+ for (size_t i = 0; i < (1 << FASTPOS_BITS); ++i) {
+ if (i % 16 == 0)
+ printf("\n\t");
+
+ printf("%3u", (unsigned int)(fastpos[i]));
+
+ if (i != (1 << FASTPOS_BITS) - 1)
+ printf(",");
+ }
+
+ printf("\n};\n");
+
+ return 0;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.c b/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.c
new file mode 100644
index 000000000..bd2a73782
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.c
@@ -0,0 +1,305 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_decoder.c
+/// \brief LZMA2 decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma2_decoder.h"
+#include "lz_decoder.h"
+#include "lzma_decoder.h"
+
+
+struct lzma_coder_s {
+ enum sequence {
+ SEQ_CONTROL,
+ SEQ_UNCOMPRESSED_1,
+ SEQ_UNCOMPRESSED_2,
+ SEQ_COMPRESSED_0,
+ SEQ_COMPRESSED_1,
+ SEQ_PROPERTIES,
+ SEQ_LZMA,
+ SEQ_COPY,
+ } sequence;
+
+ /// Sequence after the size fields have been decoded.
+ enum sequence next_sequence;
+
+ /// LZMA decoder
+ lzma_lz_decoder lzma;
+
+ /// Uncompressed size of LZMA chunk
+ size_t uncompressed_size;
+
+ /// Compressed size of the chunk (naturally equals to uncompressed
+ /// size of uncompressed chunk)
+ size_t compressed_size;
+
+ /// True if properties are needed. This is false before the
+ /// first LZMA chunk.
+ bool need_properties;
+
+ /// True if dictionary reset is needed. This is false before the
+ /// first chunk (LZMA or uncompressed).
+ bool need_dictionary_reset;
+
+ lzma_options_lzma options;
+};
+
+
+static lzma_ret
+lzma2_decode(lzma_coder *LZMA_RESTRICT coder, lzma_dict *LZMA_RESTRICT dict,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size)
+{
+ // With SEQ_LZMA it is possible that no new input is needed to do
+ // some progress. The rest of the sequences assume that there is
+ // at least one byte of input.
+ while (*in_pos < in_size || coder->sequence == SEQ_LZMA)
+ switch (coder->sequence) {
+ case SEQ_CONTROL: {
+ const uint32_t control = in[*in_pos];
+ ++*in_pos;
+
+ // End marker
+ if (control == 0x00)
+ return LZMA_STREAM_END;
+
+ if (control >= 0xE0 || control == 1) {
+ // Dictionary reset implies that next LZMA chunk has
+ // to set new properties.
+ coder->need_properties = true;
+ coder->need_dictionary_reset = true;
+ } else if (coder->need_dictionary_reset) {
+ return LZMA_DATA_ERROR;
+ }
+
+ if (control >= 0x80) {
+ // LZMA chunk. The highest five bits of the
+ // uncompressed size are taken from the control byte.
+ coder->uncompressed_size = (control & 0x1F) << 16;
+ coder->sequence = SEQ_UNCOMPRESSED_1;
+
+ // See if there are new properties or if we need to
+ // reset the state.
+ if (control >= 0xC0) {
+ // When there are new properties, state reset
+ // is done at SEQ_PROPERTIES.
+ coder->need_properties = false;
+ coder->next_sequence = SEQ_PROPERTIES;
+
+ } else if (coder->need_properties) {
+ return LZMA_DATA_ERROR;
+
+ } else {
+ coder->next_sequence = SEQ_LZMA;
+
+ // If only state reset is wanted with old
+ // properties, do the resetting here for
+ // simplicity.
+ if (control >= 0xA0)
+ coder->lzma.reset(coder->lzma.coder,
+ &coder->options);
+ }
+ } else {
+ // Invalid control values
+ if (control > 2)
+ return LZMA_DATA_ERROR;
+
+ // It's uncompressed chunk
+ coder->sequence = SEQ_COMPRESSED_0;
+ coder->next_sequence = SEQ_COPY;
+ }
+
+ if (coder->need_dictionary_reset) {
+ // Finish the dictionary reset and let the caller
+ // flush the dictionary to the actual output buffer.
+ coder->need_dictionary_reset = false;
+ dict_reset(dict);
+ return LZMA_OK;
+ }
+
+ break;
+ }
+
+ case SEQ_UNCOMPRESSED_1:
+ coder->uncompressed_size += (uint32_t)(in[(*in_pos)++]) << 8;
+ coder->sequence = SEQ_UNCOMPRESSED_2;
+ break;
+
+ case SEQ_UNCOMPRESSED_2:
+ coder->uncompressed_size += in[(*in_pos)++] + 1;
+ coder->sequence = SEQ_COMPRESSED_0;
+ coder->lzma.set_uncompressed(coder->lzma.coder,
+ coder->uncompressed_size);
+ break;
+
+ case SEQ_COMPRESSED_0:
+ coder->compressed_size = (uint32_t)(in[(*in_pos)++]) << 8;
+ coder->sequence = SEQ_COMPRESSED_1;
+ break;
+
+ case SEQ_COMPRESSED_1:
+ coder->compressed_size += in[(*in_pos)++] + 1;
+ coder->sequence = coder->next_sequence;
+ break;
+
+ case SEQ_PROPERTIES:
+ if (lzma_lzma_lclppb_decode(&coder->options, in[(*in_pos)++]))
+ return LZMA_DATA_ERROR;
+
+ coder->lzma.reset(coder->lzma.coder, &coder->options);
+
+ coder->sequence = SEQ_LZMA;
+ break;
+
+ case SEQ_LZMA: {
+ // Store the start offset so that we can update
+ // coder->compressed_size later.
+ const size_t in_start = *in_pos;
+
+ // Decode from in[] to *dict.
+ const lzma_ret ret = coder->lzma.code(coder->lzma.coder,
+ dict, in, in_pos, in_size);
+
+ // Validate and update coder->compressed_size.
+ const size_t in_used = *in_pos - in_start;
+ if (in_used > coder->compressed_size)
+ return LZMA_DATA_ERROR;
+
+ coder->compressed_size -= in_used;
+
+ // Return if we didn't finish the chunk, or an error occurred.
+ if (ret != LZMA_STREAM_END)
+ return ret;
+
+ // The LZMA decoder must have consumed the whole chunk now.
+ // We don't need to worry about uncompressed size since it
+ // is checked by the LZMA decoder.
+ if (coder->compressed_size != 0)
+ return LZMA_DATA_ERROR;
+
+ coder->sequence = SEQ_CONTROL;
+ break;
+ }
+
+ case SEQ_COPY: {
+ // Copy from input to the dictionary as is.
+ dict_write(dict, in, in_pos, in_size, &coder->compressed_size);
+ if (coder->compressed_size != 0)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_CONTROL;
+ break;
+ }
+
+ default:
+ assert(0);
+ return LZMA_PROG_ERROR;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+lzma2_decoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ assert(coder->lzma.end == NULL);
+ lzma_free(coder->lzma.coder, allocator);
+
+ lzma_free(coder, allocator);
+
+ return;
+}
+
+
+static lzma_ret
+lzma2_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *opt, lzma_lz_options *lz_options)
+{
+ const lzma_options_lzma *options = opt;
+
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma2_decode;
+ lz->end = &lzma2_decoder_end;
+
+ lz->coder->lzma = LZMA_LZ_DECODER_INIT;
+ }
+
+ lz->coder->sequence = SEQ_CONTROL;
+ lz->coder->need_properties = true;
+ lz->coder->need_dictionary_reset = options->preset_dict == NULL
+ || options->preset_dict_size == 0;
+
+ return lzma_lzma_decoder_create(&lz->coder->lzma,
+ allocator, options, lz_options);
+}
+
+
+extern lzma_ret
+lzma_lzma2_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ // LZMA2 can only be the last filter in the chain. This is enforced
+ // by the raw_decoder initialization.
+ assert(filters[1].init == NULL);
+
+ return lzma_lz_decoder_init(next, allocator, filters,
+ &lzma2_decoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_decoder_memusage(const void *options)
+{
+ return sizeof(lzma_coder)
+ + lzma_lzma_decoder_memusage_nocheck(options);
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ lzma_options_lzma *opt;
+
+ if (props_size != 1)
+ return LZMA_OPTIONS_ERROR;
+
+ // Check that reserved bits are unset.
+ if (props[0] & 0xC0)
+ return LZMA_OPTIONS_ERROR;
+
+ // Decode the dictionary size.
+ if (props[0] > 40)
+ return LZMA_OPTIONS_ERROR;
+
+ opt = lzma_alloc(sizeof(lzma_options_lzma), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ if (props[0] == 40) {
+ opt->dict_size = UINT32_MAX;
+ } else {
+ opt->dict_size = 2 | (props[0] & 1);
+ opt->dict_size <<= props[0] / 2 + 11;
+ }
+
+ opt->preset_dict = NULL;
+ opt->preset_dict_size = 0;
+
+ *options = opt;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.h b/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.h
new file mode 100644
index 000000000..fac4ac487
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma2_decoder.h
@@ -0,0 +1,28 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_decoder.h
+/// \brief LZMA2 decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA2_DECODER_H
+#define LZMA_LZMA2_DECODER_H
+
+#include "common.h"
+
+extern lzma_ret lzma_lzma2_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.c b/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.c
new file mode 100644
index 000000000..a3651a7c6
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.c
@@ -0,0 +1,399 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_encoder.c
+/// \brief LZMA2 encoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_encoder.h"
+#include "lzma_encoder.h"
+#include "fastpos.h"
+#include "lzma2_encoder.h"
+
+
+struct lzma_coder_s {
+ enum {
+ SEQ_INIT,
+ SEQ_LZMA_ENCODE,
+ SEQ_LZMA_COPY,
+ SEQ_UNCOMPRESSED_HEADER,
+ SEQ_UNCOMPRESSED_COPY,
+ } sequence;
+
+ /// LZMA encoder
+ lzma_coder *lzma;
+
+ /// LZMA options currently in use.
+ lzma_options_lzma opt_cur;
+
+ bool need_properties;
+ bool need_state_reset;
+ bool need_dictionary_reset;
+
+ /// Uncompressed size of a chunk
+ size_t uncompressed_size;
+
+ /// Compressed size of a chunk (excluding headers); this is also used
+ /// to indicate the end of buf[] in SEQ_LZMA_COPY.
+ size_t compressed_size;
+
+ /// Read position in buf[]
+ size_t buf_pos;
+
+ /// Buffer to hold the chunk header and LZMA compressed data
+ uint8_t buf[LZMA2_HEADER_MAX + LZMA2_CHUNK_MAX];
+};
+
+
+static void
+lzma2_header_lzma(lzma_coder *coder)
+{
+ size_t pos;
+ size_t size;
+
+ assert(coder->uncompressed_size > 0);
+ assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+ assert(coder->compressed_size > 0);
+ assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+
+ if (coder->need_properties) {
+ pos = 0;
+
+ if (coder->need_dictionary_reset)
+ coder->buf[pos] = 0x80 + (3 << 5);
+ else
+ coder->buf[pos] = 0x80 + (2 << 5);
+ } else {
+ pos = 1;
+
+ if (coder->need_state_reset)
+ coder->buf[pos] = 0x80 + (1 << 5);
+ else
+ coder->buf[pos] = 0x80;
+ }
+
+ // Set the start position for copying.
+ coder->buf_pos = pos;
+
+ // Uncompressed size
+ size = coder->uncompressed_size - 1;
+ coder->buf[pos++] += size >> 16;
+ coder->buf[pos++] = (size >> 8) & 0xFF;
+ coder->buf[pos++] = size & 0xFF;
+
+ // Compressed size
+ size = coder->compressed_size - 1;
+ coder->buf[pos++] = size >> 8;
+ coder->buf[pos++] = size & 0xFF;
+
+ // Properties, if needed
+ if (coder->need_properties)
+ lzma_lzma_lclppb_encode(&coder->opt_cur, coder->buf + pos);
+
+ coder->need_properties = false;
+ coder->need_state_reset = false;
+ coder->need_dictionary_reset = false;
+
+ // The copying code uses coder->compressed_size to indicate the end
+ // of coder->buf[], so we need add the maximum size of the header here.
+ coder->compressed_size += LZMA2_HEADER_MAX;
+
+ return;
+}
+
+
+static void
+lzma2_header_uncompressed(lzma_coder *coder)
+{
+ assert(coder->uncompressed_size > 0);
+ assert(coder->uncompressed_size <= LZMA2_CHUNK_MAX);
+
+ // If this is the first chunk, we need to include dictionary
+ // reset indicator.
+ if (coder->need_dictionary_reset)
+ coder->buf[0] = 1;
+ else
+ coder->buf[0] = 2;
+
+ coder->need_dictionary_reset = false;
+
+ // "Compressed" size
+ coder->buf[1] = (coder->uncompressed_size - 1) >> 8;
+ coder->buf[2] = (coder->uncompressed_size - 1) & 0xFF;
+
+ // Set the start position for copying.
+ coder->buf_pos = 0;
+ return;
+}
+
+
+static lzma_ret
+lzma2_encode(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size)
+{
+ while (*out_pos < out_size)
+ switch (coder->sequence) {
+ case SEQ_INIT:
+ // If there's no input left and we are flushing or finishing,
+ // don't start a new chunk.
+ if (mf_unencoded(mf) == 0) {
+ // Write end of payload marker if finishing.
+ if (mf->action == LZMA_FINISH)
+ out[(*out_pos)++] = 0;
+
+ return mf->action == LZMA_RUN
+ ? LZMA_OK : LZMA_STREAM_END;
+ }
+
+ if (coder->need_state_reset)
+ return_if_error(lzma_lzma_encoder_reset(
+ coder->lzma, &coder->opt_cur));
+
+ coder->uncompressed_size = 0;
+ coder->compressed_size = 0;
+ coder->sequence = SEQ_LZMA_ENCODE;
+
+ // Fall through
+
+ case SEQ_LZMA_ENCODE: {
+ uint32_t read_start;
+ lzma_ret ret;
+
+ // Calculate how much more uncompressed data this chunk
+ // could accept.
+ const uint32_t left = LZMA2_UNCOMPRESSED_MAX
+ - coder->uncompressed_size;
+ uint32_t limit;
+
+ if (left < mf->match_len_max) {
+ // Must flush immediately since the next LZMA symbol
+ // could make the uncompressed size of the chunk too
+ // big.
+ limit = 0;
+ } else {
+ // Calculate maximum read_limit that is OK from point
+ // of view of LZMA2 chunk size.
+ limit = mf->read_pos - mf->read_ahead
+ + left - mf->match_len_max;
+ }
+
+ // Save the start position so that we can update
+ // coder->uncompressed_size.
+ read_start = mf->read_pos - mf->read_ahead;
+
+ // Call the LZMA encoder until the chunk is finished.
+ ret = lzma_lzma_encode(coder->lzma, mf,
+ coder->buf + LZMA2_HEADER_MAX,
+ &coder->compressed_size,
+ LZMA2_CHUNK_MAX, limit);
+
+ coder->uncompressed_size += mf->read_pos - mf->read_ahead
+ - read_start;
+
+ assert(coder->compressed_size <= LZMA2_CHUNK_MAX);
+ assert(coder->uncompressed_size <= LZMA2_UNCOMPRESSED_MAX);
+
+ if (ret != LZMA_STREAM_END)
+ return LZMA_OK;
+
+ // See if the chunk compressed. If it didn't, we encode it
+ // as uncompressed chunk. This saves a few bytes of space
+ // and makes decoding faster.
+ if (coder->compressed_size >= coder->uncompressed_size) {
+ coder->uncompressed_size += mf->read_ahead;
+ assert(coder->uncompressed_size
+ <= LZMA2_UNCOMPRESSED_MAX);
+ mf->read_ahead = 0;
+ lzma2_header_uncompressed(coder);
+ coder->need_state_reset = true;
+ coder->sequence = SEQ_UNCOMPRESSED_HEADER;
+ break;
+ }
+
+ // The chunk did compress at least by one byte, so we store
+ // the chunk as LZMA.
+ lzma2_header_lzma(coder);
+
+ coder->sequence = SEQ_LZMA_COPY;
+ }
+
+ // Fall through
+
+ case SEQ_LZMA_COPY:
+ // Copy the compressed chunk along its headers to the
+ // output buffer.
+ lzma_bufcpy(coder->buf, &coder->buf_pos,
+ coder->compressed_size,
+ out, out_pos, out_size);
+ if (coder->buf_pos != coder->compressed_size)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_INIT;
+ break;
+
+ case SEQ_UNCOMPRESSED_HEADER:
+ // Copy the three-byte header to indicate uncompressed chunk.
+ lzma_bufcpy(coder->buf, &coder->buf_pos,
+ LZMA2_HEADER_UNCOMPRESSED,
+ out, out_pos, out_size);
+ if (coder->buf_pos != LZMA2_HEADER_UNCOMPRESSED)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_UNCOMPRESSED_COPY;
+
+ // Fall through
+
+ case SEQ_UNCOMPRESSED_COPY:
+ // Copy the uncompressed data as is from the dictionary
+ // to the output buffer.
+ mf_read(mf, out, out_pos, out_size, &coder->uncompressed_size);
+ if (coder->uncompressed_size != 0)
+ return LZMA_OK;
+
+ coder->sequence = SEQ_INIT;
+ break;
+ }
+
+ return LZMA_OK;
+}
+
+
+static void
+lzma2_encoder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_free(coder->lzma, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+lzma2_encoder_options_update(lzma_coder *coder, const lzma_filter *filter)
+{
+ lzma_options_lzma *opt;
+
+ // New options can be set only when there is no incomplete chunk.
+ // This is the case at the beginning of the raw stream and right
+ // after LZMA_SYNC_FLUSH.
+ if (filter->options == NULL || coder->sequence != SEQ_INIT)
+ return LZMA_PROG_ERROR;
+
+ // Look if there are new options. At least for now,
+ // only lc/lp/pb can be changed.
+ opt = filter->options;
+ if (coder->opt_cur.lc != opt->lc || coder->opt_cur.lp != opt->lp
+ || coder->opt_cur.pb != opt->pb) {
+ // Validate the options.
+ if (opt->lc > LZMA_LCLP_MAX || opt->lp > LZMA_LCLP_MAX
+ || opt->lc + opt->lp > LZMA_LCLP_MAX
+ || opt->pb > LZMA_PB_MAX)
+ return LZMA_OPTIONS_ERROR;
+
+ // The new options will be used when the encoder starts
+ // a new LZMA2 chunk.
+ coder->opt_cur.lc = opt->lc;
+ coder->opt_cur.lp = opt->lp;
+ coder->opt_cur.pb = opt->pb;
+ coder->need_properties = true;
+ coder->need_state_reset = true;
+ }
+
+ return LZMA_OK;
+}
+
+
+static lzma_ret
+lzma2_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
+ const void *options, lzma_lz_options *lz_options)
+{
+ if (options == NULL)
+ return LZMA_PROG_ERROR;
+
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma2_encode;
+ lz->end = &lzma2_encoder_end;
+ lz->options_update = &lzma2_encoder_options_update;
+
+ lz->coder->lzma = NULL;
+ }
+
+ lz->coder->opt_cur = *(const lzma_options_lzma *)(options);
+
+ lz->coder->sequence = SEQ_INIT;
+ lz->coder->need_properties = true;
+ lz->coder->need_state_reset = false;
+ lz->coder->need_dictionary_reset
+ = lz->coder->opt_cur.preset_dict == NULL
+ || lz->coder->opt_cur.preset_dict_size == 0;
+
+ // Initialize LZMA encoder
+ return_if_error(lzma_lzma_encoder_create(&lz->coder->lzma, allocator,
+ &lz->coder->opt_cur, lz_options));
+
+ // Make sure that we will always have enough history available in
+ // case we need to use uncompressed chunks. They are used when the
+ // compressed size of a chunk is not smaller than the uncompressed
+ // size, so we need to have at least LZMA2_COMPRESSED_MAX bytes
+ // history available.
+ if (lz_options->before_size + lz_options->dict_size < LZMA2_CHUNK_MAX)
+ lz_options->before_size
+ = LZMA2_CHUNK_MAX - lz_options->dict_size;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma2_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return lzma_lz_encoder_init(
+ next, allocator, filters, &lzma2_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma2_encoder_memusage(const void *options)
+{
+ const uint64_t lzma_mem = lzma_lzma_encoder_memusage(options);
+ if (lzma_mem == UINT64_MAX)
+ return UINT64_MAX;
+
+ return sizeof(lzma_coder) + lzma_mem;
+}
+
+
+extern lzma_ret
+lzma_lzma2_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_lzma *const opt = options;
+ uint32_t d = my_max(opt->dict_size, LZMA_DICT_SIZE_MIN);
+
+ // Round up to the next 2^n - 1 or 2^n + 2^(n - 1) - 1 depending
+ // on which one is the next:
+ --d;
+ d |= d >> 2;
+ d |= d >> 3;
+ d |= d >> 4;
+ d |= d >> 8;
+ d |= d >> 16;
+
+ // Get the highest two bits using the proper encoding:
+ if (d == UINT32_MAX)
+ out[0] = 40;
+ else
+ out[0] = get_pos_slot(d + 1) - 24;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.h b/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.h
new file mode 100644
index 000000000..ca19ef469
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma2_encoder.h
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma2_encoder.h
+/// \brief LZMA2 encoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA2_ENCODER_H
+#define LZMA_LZMA2_ENCODER_H
+
+#include "common.h"
+
+
+/// Maximum number of bytes of actual data per chunk (no headers)
+#define LZMA2_CHUNK_MAX (UINT32_C(1) << 16)
+
+/// Maximum uncompressed size of LZMA chunk (no headers)
+#define LZMA2_UNCOMPRESSED_MAX (UINT32_C(1) << 21)
+
+/// Maximum size of LZMA2 headers
+#define LZMA2_HEADER_MAX 6
+
+/// Size of a header for uncompressed chunk
+#define LZMA2_HEADER_UNCOMPRESSED 3
+
+
+extern lzma_ret lzma_lzma2_encoder_init(
+ lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma2_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma2_props_encode(const void *options, uint8_t *out);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_common.h b/Utilities/cmliblzma/liblzma/lzma/lzma_common.h
new file mode 100644
index 000000000..36267dc88
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_common.h
@@ -0,0 +1,226 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_common.h
+/// \brief Private definitions common to LZMA encoder and decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_COMMON_H
+#define LZMA_LZMA_COMMON_H
+
+#include "common.h"
+#include "range_common.h"
+
+
+///////////////////
+// Miscellaneous //
+///////////////////
+
+/// Maximum number of position states. A position state is the lowest pos bits
+/// number of bits of the current uncompressed offset. In some places there
+/// are different sets of probabilities for different pos states.
+#define POS_STATES_MAX (1 << LZMA_PB_MAX)
+
+
+/// Validates lc, lp, and pb.
+static inline bool
+is_lclppb_valid(const lzma_options_lzma *options)
+{
+ return options->lc <= LZMA_LCLP_MAX && options->lp <= LZMA_LCLP_MAX
+ && options->lc + options->lp <= LZMA_LCLP_MAX
+ && options->pb <= LZMA_PB_MAX;
+}
+
+
+///////////
+// State //
+///////////
+
+/// This enum is used to track which events have occurred most recently and
+/// in which order. This information is used to predict the next event.
+///
+/// Events:
+/// - Literal: One 8-bit byte
+/// - Match: Repeat a chunk of data at some distance
+/// - Long repeat: Multi-byte match at a recently seen distance
+/// - Short repeat: One-byte repeat at a recently seen distance
+///
+/// The event names are in from STATE_oldest_older_previous. REP means
+/// either short or long repeated match, and NONLIT means any non-literal.
+typedef enum {
+ STATE_LIT_LIT,
+ STATE_MATCH_LIT_LIT,
+ STATE_REP_LIT_LIT,
+ STATE_SHORTREP_LIT_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT,
+ STATE_SHORTREP_LIT,
+ STATE_LIT_MATCH,
+ STATE_LIT_LONGREP,
+ STATE_LIT_SHORTREP,
+ STATE_NONLIT_MATCH,
+ STATE_NONLIT_REP,
+} lzma_lzma_state;
+
+
+/// Total number of states
+#define STATES 12
+
+/// The lowest 7 states indicate that the previous state was a literal.
+#define LIT_STATES 7
+
+
+/// Indicate that the latest state was a literal.
+#define update_literal(state) \
+ state = ((state) <= STATE_SHORTREP_LIT_LIT \
+ ? STATE_LIT_LIT \
+ : ((state) <= STATE_LIT_SHORTREP \
+ ? (state) - 3 \
+ : (state) - 6))
+
+/// Indicate that the latest state was a match.
+#define update_match(state) \
+ state = ((state) < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH)
+
+/// Indicate that the latest state was a long repeated match.
+#define update_long_rep(state) \
+ state = ((state) < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP)
+
+/// Indicate that the latest state was a short match.
+#define update_short_rep(state) \
+ state = ((state) < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP)
+
+/// Test if the previous state was a literal.
+#define is_literal_state(state) \
+ ((state) < LIT_STATES)
+
+
+/////////////
+// Literal //
+/////////////
+
+/// Each literal coder is divided in three sections:
+/// - 0x001-0x0FF: Without match byte
+/// - 0x101-0x1FF: With match byte; match bit is 0
+/// - 0x201-0x2FF: With match byte; match bit is 1
+///
+/// Match byte is used when the previous LZMA symbol was something else than
+/// a literal (that is, it was some kind of match).
+#define LITERAL_CODER_SIZE 0x300
+
+/// Maximum number of literal coders
+#define LITERAL_CODERS_MAX (1 << LZMA_LCLP_MAX)
+
+/// Locate the literal coder for the next literal byte. The choice depends on
+/// - the lowest literal_pos_bits bits of the position of the current
+/// byte; and
+/// - the highest literal_context_bits bits of the previous byte.
+#define literal_subcoder(probs, lc, lp_mask, pos, prev_byte) \
+ ((probs)[(((pos) & lp_mask) << lc) + ((prev_byte) >> (8 - lc))])
+
+
+static inline void
+literal_init(probability (*probs)[LITERAL_CODER_SIZE],
+ uint32_t lc, uint32_t lp)
+{
+ uint32_t coders;
+ uint32_t i, j;
+
+ assert(lc + lp <= LZMA_LCLP_MAX);
+
+ coders = 1U << (lc + lp);
+
+ for (i = 0; i < coders; ++i)
+ for (j = 0; j < LITERAL_CODER_SIZE; ++j)
+ bit_reset(probs[i][j]);
+
+ return;
+}
+
+
+//////////////////
+// Match length //
+//////////////////
+
+// Minimum length of a match is two bytes.
+#define MATCH_LEN_MIN 2
+
+// Match length is encoded with 4, 5, or 10 bits.
+//
+// Length Bits
+// 2-9 4 = Choice=0 + 3 bits
+// 10-17 5 = Choice=1 + Choice2=0 + 3 bits
+// 18-273 10 = Choice=1 + Choice2=1 + 8 bits
+#define LEN_LOW_BITS 3
+#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS)
+#define LEN_MID_BITS 3
+#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS)
+#define LEN_HIGH_BITS 8
+#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS)
+#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS)
+
+// Maximum length of a match is 273 which is a result of the encoding
+// described above.
+#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1)
+
+
+////////////////////
+// Match distance //
+////////////////////
+
+// Different set of probabilities is used for match distances that have very
+// short match length: Lengths of 2, 3, and 4 bytes have a separate set of
+// probabilities for each length. The matches with longer length use a shared
+// set of probabilities.
+#define LEN_TO_POS_STATES 4
+
+// Macro to get the index of the appropriate probability array.
+#define get_len_to_pos_state(len) \
+ ((len) < LEN_TO_POS_STATES + MATCH_LEN_MIN \
+ ? (len) - MATCH_LEN_MIN \
+ : LEN_TO_POS_STATES - 1)
+
+// The highest two bits of a match distance (pos slot) are encoded using six
+// bits. See fastpos.h for more explanation.
+#define POS_SLOT_BITS 6
+#define POS_SLOTS (1 << POS_SLOT_BITS)
+
+// Match distances up to 127 are fully encoded using probabilities. Since
+// the highest two bits (pos slot) are always encoded using six bits, the
+// distances 0-3 don't need any additional bits to encode, since the pos
+// slot itself is the same as the actual distance. START_POS_MODEL_INDEX
+// indicates the first pos slot where at least one additional bit is needed.
+#define START_POS_MODEL_INDEX 4
+
+// Match distances greater than 127 are encoded in three pieces:
+// - pos slot: the highest two bits
+// - direct bits: 2-26 bits below the highest two bits
+// - alignment bits: four lowest bits
+//
+// Direct bits don't use any probabilities.
+//
+// The pos slot value of 14 is for distances 128-191 (see the table in
+// fastpos.h to understand why).
+#define END_POS_MODEL_INDEX 14
+
+// Pos slots that indicate a distance <= 127.
+#define FULL_DISTANCES_BITS (END_POS_MODEL_INDEX / 2)
+#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS)
+
+// For match distances greater than 127, only the highest two bits and the
+// lowest four bits (alignment) is encoded using probabilities.
+#define ALIGN_BITS 4
+#define ALIGN_TABLE_SIZE (1 << ALIGN_BITS)
+#define ALIGN_MASK (ALIGN_TABLE_SIZE - 1)
+
+// LZMA remembers the four most recent match distances. Reusing these distances
+// tends to take less space than re-encoding the actual distance value.
+#define REP_DISTANCES 4
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.c b/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.c
new file mode 100644
index 000000000..3c0f39331
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.c
@@ -0,0 +1,1075 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_decoder.c
+/// \brief LZMA decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lz_decoder.h"
+#include "lzma_common.h"
+#include "lzma_decoder.h"
+#include "range_decoder.h"
+
+
+#ifdef HAVE_SMALL
+
+// Macros for (somewhat) size-optimized code.
+#define seq_4(seq) seq
+
+#define seq_6(seq) seq
+
+#define seq_8(seq) seq
+
+#define seq_len(seq) \
+ seq ## _CHOICE, \
+ seq ## _CHOICE2, \
+ seq ## _BITTREE
+
+#define len_decode(target, ld, pos_state, seq) \
+do { \
+case seq ## _CHOICE: \
+ rc_if_0(ld.choice, seq ## _CHOICE) { \
+ rc_update_0(ld.choice); \
+ probs = ld.low[pos_state];\
+ limit = LEN_LOW_SYMBOLS; \
+ target = MATCH_LEN_MIN; \
+ } else { \
+ rc_update_1(ld.choice); \
+case seq ## _CHOICE2: \
+ rc_if_0(ld.choice2, seq ## _CHOICE2) { \
+ rc_update_0(ld.choice2); \
+ probs = ld.mid[pos_state]; \
+ limit = LEN_MID_SYMBOLS; \
+ target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
+ } else { \
+ rc_update_1(ld.choice2); \
+ probs = ld.high; \
+ limit = LEN_HIGH_SYMBOLS; \
+ target = MATCH_LEN_MIN + LEN_LOW_SYMBOLS \
+ + LEN_MID_SYMBOLS; \
+ } \
+ } \
+ symbol = 1; \
+case seq ## _BITTREE: \
+ do { \
+ rc_bit(probs[symbol], , , seq ## _BITTREE); \
+ } while (symbol < limit); \
+ target += symbol - limit; \
+} while (0)
+
+#else // HAVE_SMALL
+
+// Unrolled versions
+#define seq_4(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3
+
+#define seq_6(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3, \
+ seq ## 4, \
+ seq ## 5
+
+#define seq_8(seq) \
+ seq ## 0, \
+ seq ## 1, \
+ seq ## 2, \
+ seq ## 3, \
+ seq ## 4, \
+ seq ## 5, \
+ seq ## 6, \
+ seq ## 7
+
+#define seq_len(seq) \
+ seq ## _CHOICE, \
+ seq ## _LOW0, \
+ seq ## _LOW1, \
+ seq ## _LOW2, \
+ seq ## _CHOICE2, \
+ seq ## _MID0, \
+ seq ## _MID1, \
+ seq ## _MID2, \
+ seq ## _HIGH0, \
+ seq ## _HIGH1, \
+ seq ## _HIGH2, \
+ seq ## _HIGH3, \
+ seq ## _HIGH4, \
+ seq ## _HIGH5, \
+ seq ## _HIGH6, \
+ seq ## _HIGH7
+
+#define len_decode(target, ld, pos_state, seq) \
+do { \
+ symbol = 1; \
+case seq ## _CHOICE: \
+ rc_if_0(ld.choice, seq ## _CHOICE) { \
+ rc_update_0(ld.choice); \
+ rc_bit_case(ld.low[pos_state][symbol], 0, 0, seq ## _LOW0); \
+ rc_bit_case(ld.low[pos_state][symbol], 0, 0, seq ## _LOW1); \
+ rc_bit_case(ld.low[pos_state][symbol], 0, 0, seq ## _LOW2); \
+ target = symbol - LEN_LOW_SYMBOLS + MATCH_LEN_MIN; \
+ } else { \
+ rc_update_1(ld.choice); \
+case seq ## _CHOICE2: \
+ rc_if_0(ld.choice2, seq ## _CHOICE2) { \
+ rc_update_0(ld.choice2); \
+ rc_bit_case(ld.mid[pos_state][symbol], 0, 0, \
+ seq ## _MID0); \
+ rc_bit_case(ld.mid[pos_state][symbol], 0, 0, \
+ seq ## _MID1); \
+ rc_bit_case(ld.mid[pos_state][symbol], 0, 0, \
+ seq ## _MID2); \
+ target = symbol - LEN_MID_SYMBOLS \
+ + MATCH_LEN_MIN + LEN_LOW_SYMBOLS; \
+ } else { \
+ rc_update_1(ld.choice2); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH0); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH1); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH2); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH3); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH4); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH5); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH6); \
+ rc_bit_case(ld.high[symbol], 0, 0, seq ## _HIGH7); \
+ target = symbol - LEN_HIGH_SYMBOLS \
+ + MATCH_LEN_MIN \
+ + LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; \
+ } \
+ } \
+} while (0)
+
+#endif // HAVE_SMALL
+
+
+/// Length decoder probabilities; see comments in lzma_common.h.
+typedef struct {
+ probability choice;
+ probability choice2;
+ probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+ probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+ probability high[LEN_HIGH_SYMBOLS];
+} lzma_length_decoder;
+
+
+struct lzma_coder_s {
+ ///////////////////
+ // Probabilities //
+ ///////////////////
+
+ /// Literals; see comments in lzma_common.h.
+ probability literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+
+ /// If 1, it's a match. Otherwise it's a single 8-bit literal.
+ probability is_match[STATES][POS_STATES_MAX];
+
+ /// If 1, it's a repeated match. The distance is one of rep0 .. rep3.
+ probability is_rep[STATES];
+
+ /// If 0, distance of a repeated match is rep0.
+ /// Otherwise check is_rep1.
+ probability is_rep0[STATES];
+
+ /// If 0, distance of a repeated match is rep1.
+ /// Otherwise check is_rep2.
+ probability is_rep1[STATES];
+
+ /// If 0, distance of a repeated match is rep2. Otherwise it is rep3.
+ probability is_rep2[STATES];
+
+ /// If 1, the repeated match has length of one byte. Otherwise
+ /// the length is decoded from rep_len_decoder.
+ probability is_rep0_long[STATES][POS_STATES_MAX];
+
+ /// Probability tree for the highest two bits of the match distance.
+ /// There is a separate probability tree for match lengths of
+ /// 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273].
+ probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
+
+ /// Probability trees for additional bits for match distance when the
+ /// distance is in the range [4, 127].
+ probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
+
+ /// Probability tree for the lowest four bits of a match distance
+ /// that is equal to or greater than 128.
+ probability pos_align[ALIGN_TABLE_SIZE];
+
+ /// Length of a normal match
+ lzma_length_decoder match_len_decoder;
+
+ /// Length of a repeated match
+ lzma_length_decoder rep_len_decoder;
+
+ ///////////////////
+ // Decoder state //
+ ///////////////////
+
+ // Range coder
+ lzma_range_decoder rc;
+
+ // Types of the most recently seen LZMA symbols
+ lzma_lzma_state state;
+
+ uint32_t rep0; ///< Distance of the latest match
+ uint32_t rep1; ///< Distance of second latest match
+ uint32_t rep2; ///< Distance of third latest match
+ uint32_t rep3; ///< Distance of fourth latest match
+
+ uint32_t pos_mask; // (1U << pb) - 1
+ uint32_t literal_context_bits;
+ uint32_t literal_pos_mask;
+
+ /// Uncompressed size as bytes, or LZMA_VLI_UNKNOWN if end of
+ /// payload marker is expected.
+ lzma_vli uncompressed_size;
+
+ ////////////////////////////////
+ // State of incomplete symbol //
+ ////////////////////////////////
+
+ /// Position where to continue the decoder loop
+ enum {
+ SEQ_NORMALIZE,
+ SEQ_IS_MATCH,
+ seq_8(SEQ_LITERAL),
+ seq_8(SEQ_LITERAL_MATCHED),
+ SEQ_LITERAL_WRITE,
+ SEQ_IS_REP,
+ seq_len(SEQ_MATCH_LEN),
+ seq_6(SEQ_POS_SLOT),
+ SEQ_POS_MODEL,
+ SEQ_DIRECT,
+ seq_4(SEQ_ALIGN),
+ SEQ_EOPM,
+ SEQ_IS_REP0,
+ SEQ_SHORTREP,
+ SEQ_IS_REP0_LONG,
+ SEQ_IS_REP1,
+ SEQ_IS_REP2,
+ seq_len(SEQ_REP_LEN),
+ SEQ_COPY,
+ } sequence;
+
+ /// Base of the current probability tree
+ probability *probs;
+
+ /// Symbol being decoded. This is also used as an index variable in
+ /// bittree decoders: probs[symbol]
+ uint32_t symbol;
+
+ /// Used as a loop termination condition on bittree decoders and
+ /// direct bits decoder.
+ uint32_t limit;
+
+ /// Matched literal decoder: 0x100 or 0 to help avoiding branches.
+ /// Bittree reverse decoders: Offset of the next bit: 1 << offset
+ uint32_t offset;
+
+ /// If decoding a literal: match byte.
+ /// If decoding a match: length of the match.
+ uint32_t len;
+};
+
+
+static lzma_ret
+lzma_decode(lzma_coder *LZMA_RESTRICT coder, lzma_dict *LZMA_RESTRICT dictptr,
+ const uint8_t *LZMA_RESTRICT in,
+ size_t *LZMA_RESTRICT in_pos, size_t in_size)
+{
+ ///////////////
+ // Variables //
+ ///////////////
+
+ // Making local copies of often-used variables improves both
+ // speed and readability.
+
+ lzma_dict dict = *dictptr;
+
+ const size_t dict_start = dict.pos;
+
+ // Range decoder
+ rc_to_local(coder->rc, *in_pos);
+
+ // State
+ uint32_t state = coder->state;
+ uint32_t rep0 = coder->rep0;
+ uint32_t rep1 = coder->rep1;
+ uint32_t rep2 = coder->rep2;
+ uint32_t rep3 = coder->rep3;
+
+ const uint32_t pos_mask = coder->pos_mask;
+
+ // These variables are actually needed only if we last time ran
+ // out of input in the middle of the decoder loop.
+ probability *probs = coder->probs;
+ uint32_t symbol = coder->symbol;
+ uint32_t limit = coder->limit;
+ uint32_t offset = coder->offset;
+ uint32_t len = coder->len;
+
+ const uint32_t literal_pos_mask = coder->literal_pos_mask;
+ const uint32_t literal_context_bits = coder->literal_context_bits;
+
+ // Temporary variables
+ uint32_t pos_state = dict.pos & pos_mask;
+
+ lzma_ret ret = LZMA_OK;
+
+ // If uncompressed size is known, there must be no end of payload
+ // marker.
+ const bool no_eopm = coder->uncompressed_size
+ != LZMA_VLI_UNKNOWN;
+ if (no_eopm && coder->uncompressed_size < dict.limit - dict.pos)
+ dict.limit = dict.pos + (size_t)(coder->uncompressed_size);
+
+ ////////////////////
+ // Initialization //
+ ////////////////////
+
+ if (!rc_read_init(&coder->rc, in, in_pos, in_size))
+ return LZMA_OK;
+
+ rc = coder->rc;
+ rc_in_pos = *in_pos;
+
+ // The main decoder loop. The "switch" is used to restart the decoder at
+ // correct location. Once restarted, the "switch" is no longer used.
+ switch (coder->sequence)
+ while (true) {
+ // Calculate new pos_state. This is skipped on the first loop
+ // since we already calculated it when setting up the local
+ // variables.
+ pos_state = dict.pos & pos_mask;
+
+ case SEQ_NORMALIZE:
+ case SEQ_IS_MATCH:
+ if (unlikely(no_eopm && dict.pos == dict.limit))
+ break;
+
+ rc_if_0(coder->is_match[state][pos_state], SEQ_IS_MATCH) {
+ static const lzma_lzma_state next_state[] = {
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_LIT_LIT,
+ STATE_MATCH_LIT_LIT,
+ STATE_REP_LIT_LIT,
+ STATE_SHORTREP_LIT_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT,
+ STATE_SHORTREP_LIT,
+ STATE_MATCH_LIT,
+ STATE_REP_LIT
+ };
+
+ rc_update_0(coder->is_match[state][pos_state]);
+
+ // It's a literal i.e. a single 8-bit byte.
+
+ probs = literal_subcoder(coder->literal,
+ literal_context_bits, literal_pos_mask,
+ dict.pos, dict_get(&dict, 0));
+ symbol = 1;
+
+ if (is_literal_state(state)) {
+ // Decode literal without match byte.
+#ifdef HAVE_SMALL
+ case SEQ_LITERAL:
+ do {
+ rc_bit(probs[symbol], , , SEQ_LITERAL);
+ } while (symbol < (1 << 8));
+#else
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL0);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL1);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL2);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL3);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL4);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL5);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL6);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_LITERAL7);
+#endif
+ } else {
+#ifndef HAVE_SMALL
+ uint32_t match_bit;
+ uint32_t subcoder_index;
+#endif
+
+ // Decode literal with match byte.
+ //
+ // We store the byte we compare against
+ // ("match byte") to "len" to minimize the
+ // number of variables we need to store
+ // between decoder calls.
+ len = dict_get(&dict, rep0) << 1;
+
+ // The usage of "offset" allows omitting some
+ // branches, which should give tiny speed
+ // improvement on some CPUs. "offset" gets
+ // set to zero if match_bit didn't match.
+ offset = 0x100;
+
+#ifdef HAVE_SMALL
+ case SEQ_LITERAL_MATCHED:
+ do {
+ const uint32_t match_bit
+ = len & offset;
+ const uint32_t subcoder_index
+ = offset + match_bit
+ + symbol;
+
+ rc_bit(probs[subcoder_index],
+ offset &= ~match_bit,
+ offset &= match_bit,
+ SEQ_LITERAL_MATCHED);
+
+ // It seems to be faster to do this
+ // here instead of putting it to the
+ // beginning of the loop and then
+ // putting the "case" in the middle
+ // of the loop.
+ len <<= 1;
+
+ } while (symbol < (1 << 8));
+#else
+ // Unroll the loop.
+
+# define d(seq) \
+ case seq: \
+ match_bit = len & offset; \
+ subcoder_index = offset + match_bit + symbol; \
+ rc_bit(probs[subcoder_index], \
+ offset &= ~match_bit, \
+ offset &= match_bit, \
+ seq)
+
+ d(SEQ_LITERAL_MATCHED0);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED1);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED2);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED3);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED4);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED5);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED6);
+ len <<= 1;
+ d(SEQ_LITERAL_MATCHED7);
+# undef d
+#endif
+ }
+
+ //update_literal(state);
+ // Use a lookup table to update to literal state,
+ // since compared to other state updates, this would
+ // need two branches.
+ state = next_state[state];
+
+ case SEQ_LITERAL_WRITE:
+ if (unlikely(dict_put(&dict, symbol))) {
+ coder->sequence = SEQ_LITERAL_WRITE;
+ goto out;
+ }
+
+ continue;
+ }
+
+ // Instead of a new byte we are going to get a byte range
+ // (distance and length) which will be repeated from our
+ // output history.
+
+ rc_update_1(coder->is_match[state][pos_state]);
+
+ case SEQ_IS_REP:
+ rc_if_0(coder->is_rep[state], SEQ_IS_REP) {
+ // Not a repeated match
+ rc_update_0(coder->is_rep[state]);
+ update_match(state);
+
+ // The latest three match distances are kept in
+ // memory in case there are repeated matches.
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+
+ // Decode the length of the match.
+ len_decode(len, coder->match_len_decoder,
+ pos_state, SEQ_MATCH_LEN);
+
+ // Prepare to decode the highest two bits of the
+ // match distance.
+ probs = coder->pos_slot[get_len_to_pos_state(len)];
+ symbol = 1;
+
+#ifdef HAVE_SMALL
+ case SEQ_POS_SLOT:
+ do {
+ rc_bit(probs[symbol], , , SEQ_POS_SLOT);
+ } while (symbol < POS_SLOTS);
+#else
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT0);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT1);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT2);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT3);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT4);
+ rc_bit_case(probs[symbol], 0, 0, SEQ_POS_SLOT5);
+#endif
+ // Get rid of the highest bit that was needed for
+ // indexing of the probability array.
+ symbol -= POS_SLOTS;
+ assert(symbol <= 63);
+
+ if (symbol < START_POS_MODEL_INDEX) {
+ // Match distances [0, 3] have only two bits.
+ rep0 = symbol;
+ } else {
+ // Decode the lowest [1, 29] bits of
+ // the match distance.
+ limit = (symbol >> 1) - 1;
+ assert(limit >= 1 && limit <= 30);
+ rep0 = 2 + (symbol & 1);
+
+ if (symbol < END_POS_MODEL_INDEX) {
+ // Prepare to decode the low bits for
+ // a distance of [4, 127].
+ assert(limit <= 5);
+ rep0 <<= limit;
+ assert(rep0 <= 96);
+ // -1 is fine, because we start
+ // decoding at probs[1], not probs[0].
+ // NOTE: This violates the C standard,
+ // since we are doing pointer
+ // arithmetic past the beginning of
+ // the array.
+ assert((int32_t)(rep0 - symbol - 1)
+ >= -1);
+ assert((int32_t)(rep0 - symbol - 1)
+ <= 82);
+ probs = coder->pos_special + rep0
+ - symbol - 1;
+ symbol = 1;
+ offset = 0;
+ case SEQ_POS_MODEL:
+#ifdef HAVE_SMALL
+ do {
+ rc_bit(probs[symbol], ,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ } while (++offset < limit);
+#else
+ switch (limit) {
+ case 5:
+ assert(offset == 0);
+ rc_bit(probs[symbol], 0,
+ rep0 += 1,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 4:
+ rc_bit(probs[symbol], 0,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 3:
+ rc_bit(probs[symbol], 0,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 2:
+ rc_bit(probs[symbol], 0,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ ++offset;
+ --limit;
+ case 1:
+ // We need "symbol" only for
+ // indexing the probability
+ // array, thus we can use
+ // rc_bit_last() here to omit
+ // the unneeded updating of
+ // "symbol".
+ rc_bit_last(probs[symbol], 0,
+ rep0 += 1 << offset,
+ SEQ_POS_MODEL);
+ }
+#endif
+ } else {
+ // The distance is >= 128. Decode the
+ // lower bits without probabilities
+ // except the lowest four bits.
+ assert(symbol >= 14);
+ assert(limit >= 6);
+ limit -= ALIGN_BITS;
+ assert(limit >= 2);
+ case SEQ_DIRECT:
+ // Not worth manual unrolling
+ do {
+ rc_direct(rep0, SEQ_DIRECT);
+ } while (--limit > 0);
+
+ // Decode the lowest four bits using
+ // probabilities.
+ rep0 <<= ALIGN_BITS;
+ symbol = 1;
+#ifdef HAVE_SMALL
+ offset = 0;
+ case SEQ_ALIGN:
+ do {
+ rc_bit(coder->pos_align[
+ symbol], ,
+ rep0 += 1 << offset,
+ SEQ_ALIGN);
+ } while (++offset < ALIGN_BITS);
+#else
+ case SEQ_ALIGN0:
+ rc_bit(coder->pos_align[symbol], 0,
+ rep0 += 1, SEQ_ALIGN0);
+ case SEQ_ALIGN1:
+ rc_bit(coder->pos_align[symbol], 0,
+ rep0 += 2, SEQ_ALIGN1);
+ case SEQ_ALIGN2:
+ rc_bit(coder->pos_align[symbol], 0,
+ rep0 += 4, SEQ_ALIGN2);
+ case SEQ_ALIGN3:
+ // Like in SEQ_POS_MODEL, we don't
+ // need "symbol" for anything else
+ // than indexing the probability array.
+ rc_bit_last(coder->pos_align[symbol], 0,
+ rep0 += 8, SEQ_ALIGN3);
+#endif
+
+ if (rep0 == UINT32_MAX) {
+ // End of payload marker was
+ // found. It must not be
+ // present if uncompressed
+ // size is known.
+ if (coder->uncompressed_size
+ != LZMA_VLI_UNKNOWN) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
+ }
+
+ case SEQ_EOPM:
+ // LZMA1 stream with
+ // end-of-payload marker.
+ rc_normalize(SEQ_EOPM);
+ ret = LZMA_STREAM_END;
+ goto out;
+ }
+ }
+ }
+
+ // Validate the distance we just decoded.
+ if (unlikely(!dict_is_distance_valid(&dict, rep0))) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
+ }
+
+ } else {
+ rc_update_1(coder->is_rep[state]);
+
+ // Repeated match
+ //
+ // The match distance is a value that we have had
+ // earlier. The latest four match distances are
+ // available as rep0, rep1, rep2 and rep3. We will
+ // now decode which of them is the new distance.
+ //
+ // There cannot be a match if we haven't produced
+ // any output, so check that first.
+ if (unlikely(!dict_is_distance_valid(&dict, 0))) {
+ ret = LZMA_DATA_ERROR;
+ goto out;
+ }
+
+ case SEQ_IS_REP0:
+ rc_if_0(coder->is_rep0[state], SEQ_IS_REP0) {
+ rc_update_0(coder->is_rep0[state]);
+ // The distance is rep0.
+
+ case SEQ_IS_REP0_LONG:
+ rc_if_0(coder->is_rep0_long[state][pos_state],
+ SEQ_IS_REP0_LONG) {
+ rc_update_0(coder->is_rep0_long[
+ state][pos_state]);
+
+ update_short_rep(state);
+
+ case SEQ_SHORTREP:
+ if (unlikely(dict_put(&dict, dict_get(
+ &dict, rep0)))) {
+ coder->sequence = SEQ_SHORTREP;
+ goto out;
+ }
+
+ continue;
+ }
+
+ // Repeating more than one byte at
+ // distance of rep0.
+ rc_update_1(coder->is_rep0_long[
+ state][pos_state]);
+
+ } else {
+ rc_update_1(coder->is_rep0[state]);
+
+ case SEQ_IS_REP1:
+ // The distance is rep1, rep2 or rep3. Once
+ // we find out which one of these three, it
+ // is stored to rep0 and rep1, rep2 and rep3
+ // are updated accordingly.
+ rc_if_0(coder->is_rep1[state], SEQ_IS_REP1) {
+ uint32_t distance;
+
+ rc_update_0(coder->is_rep1[state]);
+
+ distance = rep1;
+ rep1 = rep0;
+ rep0 = distance;
+
+ } else {
+ rc_update_1(coder->is_rep1[state]);
+ case SEQ_IS_REP2:
+ rc_if_0(coder->is_rep2[state],
+ SEQ_IS_REP2) {
+ uint32_t distance;
+
+ rc_update_0(coder->is_rep2[
+ state]);
+
+ distance = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance;
+
+ } else {
+ uint32_t distance;
+
+ rc_update_1(coder->is_rep2[
+ state]);
+
+ distance = rep3;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ }
+ }
+
+ update_long_rep(state);
+
+ // Decode the length of the repeated match.
+ len_decode(len, coder->rep_len_decoder,
+ pos_state, SEQ_REP_LEN);
+ }
+
+ /////////////////////////////////
+ // Repeat from history buffer. //
+ /////////////////////////////////
+
+ // The length is always between these limits. There is no way
+ // to trigger the algorithm to set len outside this range.
+ assert(len >= MATCH_LEN_MIN);
+ assert(len <= MATCH_LEN_MAX);
+
+ case SEQ_COPY:
+ // Repeat len bytes from distance of rep0.
+ if (unlikely(dict_repeat(&dict, rep0, &len))) {
+ coder->sequence = SEQ_COPY;
+ goto out;
+ }
+ }
+
+ rc_normalize(SEQ_NORMALIZE);
+ coder->sequence = SEQ_IS_MATCH;
+
+out:
+ // Save state
+
+ // NOTE: Must not copy dict.limit.
+ dictptr->pos = dict.pos;
+ dictptr->full = dict.full;
+
+ rc_from_local(coder->rc, *in_pos);
+
+ coder->state = state;
+ coder->rep0 = rep0;
+ coder->rep1 = rep1;
+ coder->rep2 = rep2;
+ coder->rep3 = rep3;
+
+ coder->probs = probs;
+ coder->symbol = symbol;
+ coder->limit = limit;
+ coder->offset = offset;
+ coder->len = len;
+
+ // Update the remaining amount of uncompressed data if uncompressed
+ // size was known.
+ if (coder->uncompressed_size != LZMA_VLI_UNKNOWN) {
+ coder->uncompressed_size -= dict.pos - dict_start;
+
+ // Since there cannot be end of payload marker if the
+ // uncompressed size was known, we check here if we
+ // finished decoding.
+ if (coder->uncompressed_size == 0 && ret == LZMA_OK
+ && coder->sequence != SEQ_NORMALIZE)
+ ret = coder->sequence == SEQ_IS_MATCH
+ ? LZMA_STREAM_END : LZMA_DATA_ERROR;
+ }
+
+ // We can do an additional check in the range decoder to catch some
+ // corrupted files.
+ if (ret == LZMA_STREAM_END) {
+ if (!rc_is_finished(coder->rc))
+ ret = LZMA_DATA_ERROR;
+
+ // Reset the range decoder so that it is ready to reinitialize
+ // for a new LZMA2 chunk.
+ rc_reset(coder->rc);
+ }
+
+ return ret;
+}
+
+
+
+static void
+lzma_decoder_uncompressed(lzma_coder *coder, lzma_vli uncompressed_size)
+{
+ coder->uncompressed_size = uncompressed_size;
+}
+
+/*
+extern void
+lzma_lzma_decoder_uncompressed(void *coder_ptr, lzma_vli uncompressed_size)
+{
+ // This is hack.
+ (*(lzma_coder **)(coder))->uncompressed_size = uncompressed_size;
+}
+*/
+
+static void
+lzma_decoder_reset(lzma_coder *coder, const void *opt)
+{
+ uint32_t i, j, pos_state;
+ uint32_t num_pos_states;
+
+ const lzma_options_lzma *options = opt;
+
+ // NOTE: We assume that lc/lp/pb are valid since they were
+ // successfully decoded with lzma_lzma_decode_properties().
+
+ // Calculate pos_mask. We don't need pos_bits as is for anything.
+ coder->pos_mask = (1U << options->pb) - 1;
+
+ // Initialize the literal decoder.
+ literal_init(coder->literal, options->lc, options->lp);
+
+ coder->literal_context_bits = options->lc;
+ coder->literal_pos_mask = (1U << options->lp) - 1;
+
+ // State
+ coder->state = STATE_LIT_LIT;
+ coder->rep0 = 0;
+ coder->rep1 = 0;
+ coder->rep2 = 0;
+ coder->rep3 = 0;
+ coder->pos_mask = (1U << options->pb) - 1;
+
+ // Range decoder
+ rc_reset(coder->rc);
+
+ // Bit and bittree decoders
+ for (i = 0; i < STATES; ++i) {
+ for (j = 0; j <= coder->pos_mask; ++j) {
+ bit_reset(coder->is_match[i][j]);
+ bit_reset(coder->is_rep0_long[i][j]);
+ }
+
+ bit_reset(coder->is_rep[i]);
+ bit_reset(coder->is_rep0[i]);
+ bit_reset(coder->is_rep1[i]);
+ bit_reset(coder->is_rep2[i]);
+ }
+
+ for (i = 0; i < LEN_TO_POS_STATES; ++i)
+ bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
+
+ for (i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
+ bit_reset(coder->pos_special[i]);
+
+ bittree_reset(coder->pos_align, ALIGN_BITS);
+
+ // Len decoders (also bit/bittree)
+ num_pos_states = 1U << options->pb;
+ bit_reset(coder->match_len_decoder.choice);
+ bit_reset(coder->match_len_decoder.choice2);
+ bit_reset(coder->rep_len_decoder.choice);
+ bit_reset(coder->rep_len_decoder.choice2);
+
+ for (pos_state = 0; pos_state < num_pos_states; ++pos_state) {
+ bittree_reset(coder->match_len_decoder.low[pos_state],
+ LEN_LOW_BITS);
+ bittree_reset(coder->match_len_decoder.mid[pos_state],
+ LEN_MID_BITS);
+
+ bittree_reset(coder->rep_len_decoder.low[pos_state],
+ LEN_LOW_BITS);
+ bittree_reset(coder->rep_len_decoder.mid[pos_state],
+ LEN_MID_BITS);
+ }
+
+ bittree_reset(coder->match_len_decoder.high, LEN_HIGH_BITS);
+ bittree_reset(coder->rep_len_decoder.high, LEN_HIGH_BITS);
+
+ coder->sequence = SEQ_IS_MATCH;
+ coder->probs = NULL;
+ coder->symbol = 0;
+ coder->limit = 0;
+ coder->offset = 0;
+ coder->len = 0;
+
+ return;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_create(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *opt, lzma_lz_options *lz_options)
+{
+ const lzma_options_lzma *options = opt;
+
+ if (lz->coder == NULL) {
+ lz->coder = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (lz->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ lz->code = &lzma_decode;
+ lz->reset = &lzma_decoder_reset;
+ lz->set_uncompressed = &lzma_decoder_uncompressed;
+ }
+
+ // All dictionary sizes are OK here. LZ decoder will take care of
+ // the special cases.
+ lz_options->dict_size = options->dict_size;
+ lz_options->preset_dict = options->preset_dict;
+ lz_options->preset_dict_size = options->preset_dict_size;
+
+ return LZMA_OK;
+}
+
+
+/// Allocate and initialize LZMA decoder. This is used only via LZ
+/// initialization (lzma_lzma_decoder_init() passes function pointer to
+/// the LZ initialization).
+static lzma_ret
+lzma_decoder_init(lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *options, lzma_lz_options *lz_options)
+{
+ if (!is_lclppb_valid(options))
+ return LZMA_PROG_ERROR;
+
+ return_if_error(lzma_lzma_decoder_create(
+ lz, allocator, options, lz_options));
+
+ lzma_decoder_reset(lz->coder, options);
+ lzma_decoder_uncompressed(lz->coder, LZMA_VLI_UNKNOWN);
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ // LZMA can only be the last filter in the chain. This is enforced
+ // by the raw_decoder initialization.
+ assert(filters[1].init == NULL);
+
+ return lzma_lz_decoder_init(next, allocator, filters,
+ &lzma_decoder_init);
+}
+
+
+extern bool
+lzma_lzma_lclppb_decode(lzma_options_lzma *options, uint8_t byte)
+{
+ if (byte > (4 * 5 + 4) * 9 + 8)
+ return true;
+
+ // See the file format specification to understand this.
+ options->pb = byte / (9 * 5);
+ byte -= options->pb * 9 * 5;
+ options->lp = byte / 9;
+ options->lc = byte - options->lp * 9;
+
+ return options->lc + options->lp > LZMA_LCLP_MAX;
+}
+
+
+extern uint64_t
+lzma_lzma_decoder_memusage_nocheck(const void *options)
+{
+ const lzma_options_lzma *const opt = options;
+ return sizeof(lzma_coder) + lzma_lz_decoder_memusage(opt->dict_size);
+}
+
+
+extern uint64_t
+lzma_lzma_decoder_memusage(const void *options)
+{
+ if (!is_lclppb_valid(options))
+ return UINT64_MAX;
+
+ return lzma_lzma_decoder_memusage_nocheck(options);
+}
+
+
+extern lzma_ret
+lzma_lzma_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ lzma_options_lzma *opt;
+
+ if (props_size != 5)
+ return LZMA_OPTIONS_ERROR;
+
+ opt = lzma_alloc(sizeof(lzma_options_lzma), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ if (lzma_lzma_lclppb_decode(opt, props[0]))
+ goto error;
+
+ // All dictionary sizes are accepted, including zero. LZ decoder
+ // will automatically use a dictionary at least a few KiB even if
+ // a smaller dictionary is requested.
+ opt->dict_size = unaligned_read32le(props + 1);
+
+ opt->preset_dict = NULL;
+ opt->preset_dict_size = 0;
+
+ *options = opt;
+
+ return LZMA_OK;
+
+error:
+ lzma_free(opt, allocator);
+ return LZMA_OPTIONS_ERROR;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.h b/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.h
new file mode 100644
index 000000000..a463a76fc
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_decoder.h
@@ -0,0 +1,52 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_decoder.h
+/// \brief LZMA decoder API
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_DECODER_H
+#define LZMA_LZMA_DECODER_H
+
+#include "common.h"
+
+
+/// Allocates and initializes LZMA decoder
+extern lzma_ret lzma_lzma_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern uint64_t lzma_lzma_decoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+
+/// \brief Decodes the LZMA Properties byte (lc/lp/pb)
+///
+/// \return true if error occurred, false on success
+///
+extern bool lzma_lzma_lclppb_decode(
+ lzma_options_lzma *options, uint8_t byte);
+
+
+#ifdef LZMA_LZ_DECODER_H
+/// Allocate and setup function pointers only. This is used by LZMA1 and
+/// LZMA2 decoders.
+extern lzma_ret lzma_lzma_decoder_create(
+ lzma_lz_decoder *lz, lzma_allocator *allocator,
+ const void *opt, lzma_lz_options *lz_options);
+
+/// Gets memory usage without validating lc/lp/pb. This is used by LZMA2
+/// decoder, because raw LZMA2 decoding doesn't need lc/lp/pb.
+extern uint64_t lzma_lzma_decoder_memusage_nocheck(const void *options);
+
+#endif
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c
new file mode 100644
index 000000000..e8738f411
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.c
@@ -0,0 +1,695 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder.c
+/// \brief LZMA encoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma2_encoder.h"
+#include "lzma_encoder_private.h"
+#include "fastpos.h"
+
+
+/////////////
+// Literal //
+/////////////
+
+static inline void
+literal_matched(lzma_range_encoder *rc, probability *subcoder,
+ uint32_t match_byte, uint32_t symbol)
+{
+ uint32_t offset = 0x100;
+ symbol += UINT32_C(1) << 8;
+
+ do {
+ uint32_t match_bit;
+ uint32_t subcoder_index;
+ uint32_t bit;
+
+ match_byte <<= 1;
+ match_bit = match_byte & offset;
+ subcoder_index = offset + match_bit + (symbol >> 8);
+ bit = (symbol >> 7) & 1;
+ rc_bit(rc, &subcoder[subcoder_index], bit);
+
+ symbol <<= 1;
+ offset &= ~(match_byte ^ symbol);
+
+ } while (symbol < (UINT32_C(1) << 16));
+}
+
+
+static inline void
+literal(lzma_coder *coder, lzma_mf *mf, uint32_t position)
+{
+ // Locate the literal byte to be encoded and the subcoder.
+ const uint8_t cur_byte = mf->buffer[
+ mf->read_pos - mf->read_ahead];
+ probability *subcoder = literal_subcoder(coder->literal,
+ coder->literal_context_bits, coder->literal_pos_mask,
+ position, mf->buffer[mf->read_pos - mf->read_ahead - 1]);
+
+ if (is_literal_state(coder->state)) {
+ // Previous LZMA-symbol was a literal. Encode a normal
+ // literal without a match byte.
+ rc_bittree(&coder->rc, subcoder, 8, cur_byte);
+ } else {
+ // Previous LZMA-symbol was a match. Use the last byte of
+ // the match as a "match byte". That is, compare the bits
+ // of the current literal and the match byte.
+ const uint8_t match_byte = mf->buffer[
+ mf->read_pos - coder->reps[0] - 1
+ - mf->read_ahead];
+ literal_matched(&coder->rc, subcoder, match_byte, cur_byte);
+ }
+
+ update_literal(coder->state);
+}
+
+
+//////////////////
+// Match length //
+//////////////////
+
+static void
+length_update_prices(lzma_length_encoder *lc, const uint32_t pos_state)
+{
+ uint32_t a0, a1, b0, b1;
+ uint32_t *prices;
+ uint32_t i;
+
+ const uint32_t table_size = lc->table_size;
+ lc->counters[pos_state] = table_size;
+
+ a0 = rc_bit_0_price(lc->choice);
+ a1 = rc_bit_1_price(lc->choice);
+ b0 = a1 + rc_bit_0_price(lc->choice2);
+ b1 = a1 + rc_bit_1_price(lc->choice2);
+ prices = lc->prices[pos_state];
+
+ for (i = 0; i < table_size && i < LEN_LOW_SYMBOLS; ++i)
+ prices[i] = a0 + rc_bittree_price(lc->low[pos_state],
+ LEN_LOW_BITS, i);
+
+ for (; i < table_size && i < LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS; ++i)
+ prices[i] = b0 + rc_bittree_price(lc->mid[pos_state],
+ LEN_MID_BITS, i - LEN_LOW_SYMBOLS);
+
+ for (; i < table_size; ++i)
+ prices[i] = b1 + rc_bittree_price(lc->high, LEN_HIGH_BITS,
+ i - LEN_LOW_SYMBOLS - LEN_MID_SYMBOLS);
+
+ return;
+}
+
+
+static inline void
+length(lzma_range_encoder *rc, lzma_length_encoder *lc,
+ const uint32_t pos_state, uint32_t len, const bool fast_mode)
+{
+ assert(len <= MATCH_LEN_MAX);
+ len -= MATCH_LEN_MIN;
+
+ if (len < LEN_LOW_SYMBOLS) {
+ rc_bit(rc, &lc->choice, 0);
+ rc_bittree(rc, lc->low[pos_state], LEN_LOW_BITS, len);
+ } else {
+ rc_bit(rc, &lc->choice, 1);
+ len -= LEN_LOW_SYMBOLS;
+
+ if (len < LEN_MID_SYMBOLS) {
+ rc_bit(rc, &lc->choice2, 0);
+ rc_bittree(rc, lc->mid[pos_state], LEN_MID_BITS, len);
+ } else {
+ rc_bit(rc, &lc->choice2, 1);
+ len -= LEN_MID_SYMBOLS;
+ rc_bittree(rc, lc->high, LEN_HIGH_BITS, len);
+ }
+ }
+
+ // Only getoptimum uses the prices so don't update the table when
+ // in fast mode.
+ if (!fast_mode)
+ if (--lc->counters[pos_state] == 0)
+ length_update_prices(lc, pos_state);
+}
+
+
+///////////
+// Match //
+///////////
+
+static inline void
+match(lzma_coder *coder, const uint32_t pos_state,
+ const uint32_t distance, const uint32_t len)
+{
+ uint32_t pos_slot;
+ uint32_t len_to_pos_state;
+
+ update_match(coder->state);
+
+ length(&coder->rc, &coder->match_len_encoder, pos_state, len,
+ coder->fast_mode);
+
+ pos_slot = get_pos_slot(distance);
+ len_to_pos_state = get_len_to_pos_state(len);
+ rc_bittree(&coder->rc, coder->pos_slot[len_to_pos_state],
+ POS_SLOT_BITS, pos_slot);
+
+ if (pos_slot >= START_POS_MODEL_INDEX) {
+ const uint32_t footer_bits = (pos_slot >> 1) - 1;
+ const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
+ const uint32_t pos_reduced = distance - base;
+
+ if (pos_slot < END_POS_MODEL_INDEX) {
+ // Careful here: base - pos_slot - 1 can be -1, but
+ // rc_bittree_reverse starts at probs[1], not probs[0].
+ rc_bittree_reverse(&coder->rc,
+ coder->pos_special + base - pos_slot - 1,
+ footer_bits, pos_reduced);
+ } else {
+ rc_direct(&coder->rc, pos_reduced >> ALIGN_BITS,
+ footer_bits - ALIGN_BITS);
+ rc_bittree_reverse(
+ &coder->rc, coder->pos_align,
+ ALIGN_BITS, pos_reduced & ALIGN_MASK);
+ ++coder->align_price_count;
+ }
+ }
+
+ coder->reps[3] = coder->reps[2];
+ coder->reps[2] = coder->reps[1];
+ coder->reps[1] = coder->reps[0];
+ coder->reps[0] = distance;
+ ++coder->match_price_count;
+}
+
+
+////////////////////
+// Repeated match //
+////////////////////
+
+static inline void
+rep_match(lzma_coder *coder, const uint32_t pos_state,
+ const uint32_t rep, const uint32_t len)
+{
+ if (rep == 0) {
+ rc_bit(&coder->rc, &coder->is_rep0[coder->state], 0);
+ rc_bit(&coder->rc,
+ &coder->is_rep0_long[coder->state][pos_state],
+ len != 1);
+ } else {
+ const uint32_t distance = coder->reps[rep];
+ rc_bit(&coder->rc, &coder->is_rep0[coder->state], 1);
+
+ if (rep == 1) {
+ rc_bit(&coder->rc, &coder->is_rep1[coder->state], 0);
+ } else {
+ rc_bit(&coder->rc, &coder->is_rep1[coder->state], 1);
+ rc_bit(&coder->rc, &coder->is_rep2[coder->state],
+ rep - 2);
+
+ if (rep == 3)
+ coder->reps[3] = coder->reps[2];
+
+ coder->reps[2] = coder->reps[1];
+ }
+
+ coder->reps[1] = coder->reps[0];
+ coder->reps[0] = distance;
+ }
+
+ if (len == 1) {
+ update_short_rep(coder->state);
+ } else {
+ length(&coder->rc, &coder->rep_len_encoder, pos_state, len,
+ coder->fast_mode);
+ update_long_rep(coder->state);
+ }
+}
+
+
+//////////
+// Main //
+//////////
+
+static void
+encode_symbol(lzma_coder *coder, lzma_mf *mf,
+ uint32_t back, uint32_t len, uint32_t position)
+{
+ const uint32_t pos_state = position & coder->pos_mask;
+
+ if (back == UINT32_MAX) {
+ // Literal i.e. eight-bit byte
+ assert(len == 1);
+ rc_bit(&coder->rc,
+ &coder->is_match[coder->state][pos_state], 0);
+ literal(coder, mf, position);
+ } else {
+ // Some type of match
+ rc_bit(&coder->rc,
+ &coder->is_match[coder->state][pos_state], 1);
+
+ if (back < REP_DISTANCES) {
+ // It's a repeated match i.e. the same distance
+ // has been used earlier.
+ rc_bit(&coder->rc, &coder->is_rep[coder->state], 1);
+ rep_match(coder, pos_state, back, len);
+ } else {
+ // Normal match
+ rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
+ match(coder, pos_state, back - REP_DISTANCES, len);
+ }
+ }
+
+ assert(mf->read_ahead >= len);
+ mf->read_ahead -= len;
+}
+
+
+static bool
+encode_init(lzma_coder *coder, lzma_mf *mf)
+{
+ assert(mf_position(mf) == 0);
+
+ if (mf->read_pos == mf->read_limit) {
+ if (mf->action == LZMA_RUN)
+ return false; // We cannot do anything.
+
+ // We are finishing (we cannot get here when flushing).
+ assert(mf->write_pos == mf->read_pos);
+ assert(mf->action == LZMA_FINISH);
+ } else {
+ // Do the actual initialization. The first LZMA symbol must
+ // always be a literal.
+ mf_skip(mf, 1);
+ mf->read_ahead = 0;
+ rc_bit(&coder->rc, &coder->is_match[0][0], 0);
+ rc_bittree(&coder->rc, coder->literal[0], 8, mf->buffer[0]);
+ }
+
+ // Initialization is done (except if empty file).
+ coder->is_initialized = true;
+
+ return true;
+}
+
+
+static void
+encode_eopm(lzma_coder *coder, uint32_t position)
+{
+ const uint32_t pos_state = position & coder->pos_mask;
+ rc_bit(&coder->rc, &coder->is_match[coder->state][pos_state], 1);
+ rc_bit(&coder->rc, &coder->is_rep[coder->state], 0);
+ match(coder, pos_state, UINT32_MAX, MATCH_LEN_MIN);
+}
+
+
+/// Number of bytes that a single encoding loop in lzma_lzma_encode() can
+/// consume from the dictionary. This limit comes from lzma_lzma_optimum()
+/// and may need to be updated if that function is significantly modified.
+#define LOOP_INPUT_MAX (OPTS + 1)
+
+
+extern lzma_ret
+lzma_lzma_encode(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size, uint32_t limit)
+{
+ uint32_t position;
+
+ // Initialize the stream if no data has been encoded yet.
+ if (!coder->is_initialized && !encode_init(coder, mf))
+ return LZMA_OK;
+
+ // Get the lowest bits of the uncompressed offset from the LZ layer.
+ position = mf_position(mf);
+
+ while (true) {
+ uint32_t len;
+ uint32_t back;
+
+ // Encode pending bits, if any. Calling this before encoding
+ // the next symbol is needed only with plain LZMA, since
+ // LZMA2 always provides big enough buffer to flush
+ // everything out from the range encoder. For the same reason,
+ // rc_encode() never returns true when this function is used
+ // as part of LZMA2 encoder.
+ if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+ assert(limit == UINT32_MAX);
+ return LZMA_OK;
+ }
+
+ // With LZMA2 we need to take care that compressed size of
+ // a chunk doesn't get too big.
+ // FIXME? Check if this could be improved.
+ if (limit != UINT32_MAX
+ && (mf->read_pos - mf->read_ahead >= limit
+ || *out_pos + rc_pending(&coder->rc)
+ >= LZMA2_CHUNK_MAX
+ - LOOP_INPUT_MAX))
+ break;
+
+ // Check that there is some input to process.
+ if (mf->read_pos >= mf->read_limit) {
+ if (mf->action == LZMA_RUN)
+ return LZMA_OK;
+
+ if (mf->read_ahead == 0)
+ break;
+ }
+
+ // Get optimal match (repeat position and length).
+ // Value ranges for pos:
+ // - [0, REP_DISTANCES): repeated match
+ // - [REP_DISTANCES, UINT32_MAX):
+ // match at (pos - REP_DISTANCES)
+ // - UINT32_MAX: not a match but a literal
+ // Value ranges for len:
+ // - [MATCH_LEN_MIN, MATCH_LEN_MAX]
+
+ if (coder->fast_mode)
+ lzma_lzma_optimum_fast(coder, mf, &back, &len);
+ else
+ lzma_lzma_optimum_normal(
+ coder, mf, &back, &len, position);
+
+ encode_symbol(coder, mf, back, len, position);
+
+ position += len;
+ }
+
+ if (!coder->is_flushed) {
+ coder->is_flushed = true;
+
+ // We don't support encoding plain LZMA streams without EOPM,
+ // and LZMA2 doesn't use EOPM at LZMA level.
+ if (limit == UINT32_MAX)
+ encode_eopm(coder, position);
+
+ // Flush the remaining bytes from the range encoder.
+ rc_flush(&coder->rc);
+
+ // Copy the remaining bytes to the output buffer. If there
+ // isn't enough output space, we will copy out the remaining
+ // bytes on the next call to this function by using
+ // the rc_encode() call in the encoding loop above.
+ if (rc_encode(&coder->rc, out, out_pos, out_size)) {
+ assert(limit == UINT32_MAX);
+ return LZMA_OK;
+ }
+ }
+
+ // Make it ready for the next LZMA2 chunk.
+ coder->is_flushed = false;
+
+ return LZMA_STREAM_END;
+}
+
+
+static lzma_ret
+lzma_encode(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint8_t *LZMA_RESTRICT out, size_t *LZMA_RESTRICT out_pos,
+ size_t out_size)
+{
+ // Plain LZMA has no support for sync-flushing.
+ if (unlikely(mf->action == LZMA_SYNC_FLUSH))
+ return LZMA_OPTIONS_ERROR;
+
+ return lzma_lzma_encode(coder, mf, out, out_pos, out_size, UINT32_MAX);
+}
+
+
+////////////////////
+// Initialization //
+////////////////////
+
+static bool
+is_options_valid(const lzma_options_lzma *options)
+{
+ // Validate some of the options. LZ encoder validates nice_len too
+ // but we need a valid value here earlier.
+ return is_lclppb_valid(options)
+ && options->nice_len >= MATCH_LEN_MIN
+ && options->nice_len <= MATCH_LEN_MAX
+ && (options->mode == LZMA_MODE_FAST
+ || options->mode == LZMA_MODE_NORMAL);
+}
+
+
+static void
+set_lz_options(lzma_lz_options *lz_options, const lzma_options_lzma *options)
+{
+ // LZ encoder initialization does the validation for these so we
+ // don't need to validate here.
+ lz_options->before_size = OPTS;
+ lz_options->dict_size = options->dict_size;
+ lz_options->after_size = LOOP_INPUT_MAX;
+ lz_options->match_len_max = MATCH_LEN_MAX;
+ lz_options->nice_len = options->nice_len;
+ lz_options->match_finder = options->mf;
+ lz_options->depth = options->depth;
+ lz_options->preset_dict = options->preset_dict;
+ lz_options->preset_dict_size = options->preset_dict_size;
+ return;
+}
+
+
+static void
+length_encoder_reset(lzma_length_encoder *lencoder,
+ const uint32_t num_pos_states, const bool fast_mode)
+{
+ size_t pos_state;
+
+ bit_reset(lencoder->choice);
+ bit_reset(lencoder->choice2);
+
+ for (pos_state = 0; pos_state < num_pos_states; ++pos_state) {
+ bittree_reset(lencoder->low[pos_state], LEN_LOW_BITS);
+ bittree_reset(lencoder->mid[pos_state], LEN_MID_BITS);
+ }
+
+ bittree_reset(lencoder->high, LEN_HIGH_BITS);
+
+ if (!fast_mode)
+ for (pos_state = 0; pos_state < num_pos_states;
+ ++pos_state)
+ length_update_prices(lencoder, pos_state);
+
+ return;
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_reset(lzma_coder *coder, const lzma_options_lzma *options)
+{
+ size_t i, j;
+
+ if (!is_options_valid(options))
+ return LZMA_OPTIONS_ERROR;
+
+ coder->pos_mask = (1U << options->pb) - 1;
+ coder->literal_context_bits = options->lc;
+ coder->literal_pos_mask = (1U << options->lp) - 1;
+
+ // Range coder
+ rc_reset(&coder->rc);
+
+ // State
+ coder->state = STATE_LIT_LIT;
+ for (i = 0; i < REP_DISTANCES; ++i)
+ coder->reps[i] = 0;
+
+ literal_init(coder->literal, options->lc, options->lp);
+
+ // Bit encoders
+ for (i = 0; i < STATES; ++i) {
+ for (j = 0; j <= coder->pos_mask; ++j) {
+ bit_reset(coder->is_match[i][j]);
+ bit_reset(coder->is_rep0_long[i][j]);
+ }
+
+ bit_reset(coder->is_rep[i]);
+ bit_reset(coder->is_rep0[i]);
+ bit_reset(coder->is_rep1[i]);
+ bit_reset(coder->is_rep2[i]);
+ }
+
+ for (i = 0; i < FULL_DISTANCES - END_POS_MODEL_INDEX; ++i)
+ bit_reset(coder->pos_special[i]);
+
+ // Bit tree encoders
+ for (i = 0; i < LEN_TO_POS_STATES; ++i)
+ bittree_reset(coder->pos_slot[i], POS_SLOT_BITS);
+
+ bittree_reset(coder->pos_align, ALIGN_BITS);
+
+ // Length encoders
+ length_encoder_reset(&coder->match_len_encoder,
+ 1U << options->pb, coder->fast_mode);
+
+ length_encoder_reset(&coder->rep_len_encoder,
+ 1U << options->pb, coder->fast_mode);
+
+ // Price counts are incremented every time appropriate probabilities
+ // are changed. price counts are set to zero when the price tables
+ // are updated, which is done when the appropriate price counts have
+ // big enough value, and lzma_mf.read_ahead == 0 which happens at
+ // least every OPTS (a few thousand) possible price count increments.
+ //
+ // By resetting price counts to UINT32_MAX / 2, we make sure that the
+ // price tables will be initialized before they will be used (since
+ // the value is definitely big enough), and that it is OK to increment
+ // price counts without risk of integer overflow (since UINT32_MAX / 2
+ // is small enough). The current code doesn't increment price counts
+ // before initializing price tables, but it maybe done in future if
+ // we add support for saving the state between LZMA2 chunks.
+ coder->match_price_count = UINT32_MAX / 2;
+ coder->align_price_count = UINT32_MAX / 2;
+
+ coder->opts_end_index = 0;
+ coder->opts_current_index = 0;
+
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_create(lzma_coder **coder_ptr, lzma_allocator *allocator,
+ const lzma_options_lzma *options, lzma_lz_options *lz_options)
+{
+ lzma_coder *coder;
+ uint32_t log_size = 0;
+
+ // Allocate lzma_coder if it wasn't already allocated.
+ if (*coder_ptr == NULL) {
+ *coder_ptr = lzma_alloc(sizeof(lzma_coder), allocator);
+ if (*coder_ptr == NULL)
+ return LZMA_MEM_ERROR;
+ }
+
+ coder = *coder_ptr;
+
+ // Set compression mode. We haven't validates the options yet,
+ // but it's OK here, since nothing bad happens with invalid
+ // options in the code below, and they will get rejected by
+ // lzma_lzma_encoder_reset() call at the end of this function.
+ switch (options->mode) {
+ case LZMA_MODE_FAST:
+ coder->fast_mode = true;
+ break;
+
+ case LZMA_MODE_NORMAL: {
+ coder->fast_mode = false;
+
+ // Set dist_table_size.
+ // Round the dictionary size up to next 2^n.
+ while ((UINT32_C(1) << log_size) < options->dict_size)
+ ++log_size;
+
+ coder->dist_table_size = log_size * 2;
+
+ // Length encoders' price table size
+ coder->match_len_encoder.table_size
+ = options->nice_len + 1 - MATCH_LEN_MIN;
+ coder->rep_len_encoder.table_size
+ = options->nice_len + 1 - MATCH_LEN_MIN;
+ break;
+ }
+
+ default:
+ return LZMA_OPTIONS_ERROR;
+ }
+
+ // We don't need to write the first byte as literal if there is
+ // a non-empty preset dictionary. encode_init() wouldn't even work
+ // if there is a non-empty preset dictionary, because encode_init()
+ // assumes that position is zero and previous byte is also zero.
+ coder->is_initialized = options->preset_dict != NULL
+ && options->preset_dict_size > 0;
+ coder->is_flushed = false;
+
+ set_lz_options(lz_options, options);
+
+ return lzma_lzma_encoder_reset(coder, options);
+}
+
+
+static lzma_ret
+lzma_encoder_init(lzma_lz_encoder *lz, lzma_allocator *allocator,
+ const void *options, lzma_lz_options *lz_options)
+{
+ lz->code = &lzma_encode;
+ return lzma_lzma_encoder_create(
+ &lz->coder, allocator, options, lz_options);
+}
+
+
+extern lzma_ret
+lzma_lzma_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return lzma_lz_encoder_init(
+ next, allocator, filters, &lzma_encoder_init);
+}
+
+
+extern uint64_t
+lzma_lzma_encoder_memusage(const void *options)
+{
+ lzma_lz_options lz_options;
+ uint64_t lz_memusage;
+
+ if (!is_options_valid(options))
+ return UINT64_MAX;
+
+ set_lz_options(&lz_options, options);
+
+ lz_memusage = lzma_lz_encoder_memusage(&lz_options);
+ if (lz_memusage == UINT64_MAX)
+ return UINT64_MAX;
+
+ return (uint64_t)(sizeof(lzma_coder)) + lz_memusage;
+}
+
+
+extern bool
+lzma_lzma_lclppb_encode(const lzma_options_lzma *options, uint8_t *byte)
+{
+ if (!is_lclppb_valid(options))
+ return true;
+
+ *byte = (options->pb * 5 + options->lp) * 9 + options->lc;
+ assert(*byte <= (4 * 5 + 4) * 9 + 8);
+
+ return false;
+}
+
+
+#ifdef HAVE_ENCODER_LZMA1
+extern lzma_ret
+lzma_lzma_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_lzma *const opt = options;
+
+ if (lzma_lzma_lclppb_encode(opt, out))
+ return LZMA_PROG_ERROR;
+
+ unaligned_write32le(out + 1, opt->dict_size);
+
+ return LZMA_OK;
+}
+#endif
+
+
+extern LZMA_API(lzma_bool)
+lzma_mode_is_supported(lzma_mode mode)
+{
+ return mode == LZMA_MODE_FAST || mode == LZMA_MODE_NORMAL;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.h b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.h
new file mode 100644
index 000000000..abb8d8b46
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder.h
@@ -0,0 +1,54 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder.h
+/// \brief LZMA encoder API
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_ENCODER_H
+#define LZMA_LZMA_ENCODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_lzma_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern uint64_t lzma_lzma_encoder_memusage(const void *options);
+
+extern lzma_ret lzma_lzma_props_encode(const void *options, uint8_t *out);
+
+
+/// Encodes lc/lp/pb into one byte. Returns false on success and true on error.
+extern bool lzma_lzma_lclppb_encode(
+ const lzma_options_lzma *options, uint8_t *byte);
+
+
+#ifdef LZMA_LZ_ENCODER_H
+
+/// Initializes raw LZMA encoder; this is used by LZMA2.
+extern lzma_ret lzma_lzma_encoder_create(
+ lzma_coder **coder_ptr, lzma_allocator *allocator,
+ const lzma_options_lzma *options, lzma_lz_options *lz_options);
+
+
+/// Resets an already initialized LZMA encoder; this is used by LZMA2.
+extern lzma_ret lzma_lzma_encoder_reset(
+ lzma_coder *coder, const lzma_options_lzma *options);
+
+
+extern lzma_ret lzma_lzma_encode(lzma_coder *LZMA_RESTRICT coder,
+ lzma_mf *LZMA_RESTRICT mf, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size,
+ uint32_t read_limit);
+
+#endif
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c
new file mode 100644
index 000000000..f98312643
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_fast.c
@@ -0,0 +1,185 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_optimum_fast.c
+//
+// Author: Igor Pavlov
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+
+
+#define change_pair(small_dist, big_dist) \
+ (((big_dist) >> 7) > (small_dist))
+
+
+extern void
+lzma_lzma_optimum_fast(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res)
+{
+ const uint8_t *buf;
+ uint32_t buf_avail;
+ uint32_t i;
+ uint32_t rep_len = 0;
+ uint32_t rep_index = 0;
+ uint32_t back_main = 0;
+ uint32_t limit;
+
+ const uint32_t nice_len = mf->nice_len;
+
+ uint32_t len_main;
+ uint32_t matches_count;
+ if (mf->read_ahead == 0) {
+ len_main = mf_find(mf, &matches_count, coder->matches);
+ } else {
+ assert(mf->read_ahead == 1);
+ len_main = coder->longest_match_length;
+ matches_count = coder->matches_count;
+ }
+
+ buf = mf_ptr(mf) - 1;
+ buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
+
+ if (buf_avail < 2) {
+ // There's not enough input left to encode a match.
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return;
+ }
+
+ // Look for repeated matches; scan the previous four match distances
+ for (i = 0; i < REP_DISTANCES; ++i) {
+ uint32_t len;
+
+ // Pointer to the beginning of the match candidate
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ // If the first two bytes (2 == MATCH_LEN_MIN) do not match,
+ // this rep is not useful.
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ // The first two bytes matched.
+ // Calculate the length of the match.
+ for (len = 2; len < buf_avail
+ && buf[len] == buf_back[len]; ++len) ;
+
+ // If we have found a repeated match that is at least
+ // nice_len long, return it immediately.
+ if (len >= nice_len) {
+ *back_res = i;
+ *len_res = len;
+ mf_skip(mf, len - 1);
+ return;
+ }
+
+ if (len > rep_len) {
+ rep_index = i;
+ rep_len = len;
+ }
+ }
+
+ // We didn't find a long enough repeated match. Encode it as a normal
+ // match if the match length is at least nice_len.
+ if (len_main >= nice_len) {
+ *back_res = coder->matches[matches_count - 1].dist
+ + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 1);
+ return;
+ }
+
+ if (len_main >= 2) {
+ back_main = coder->matches[matches_count - 1].dist;
+
+ while (matches_count > 1 && len_main ==
+ coder->matches[matches_count - 2].len + 1) {
+ if (!change_pair(coder->matches[
+ matches_count - 2].dist,
+ back_main))
+ break;
+
+ --matches_count;
+ len_main = coder->matches[matches_count - 1].len;
+ back_main = coder->matches[matches_count - 1].dist;
+ }
+
+ if (len_main == 2 && back_main >= 0x80)
+ len_main = 1;
+ }
+
+ if (rep_len >= 2) {
+ if (rep_len + 1 >= len_main
+ || (rep_len + 2 >= len_main
+ && back_main > (UINT32_C(1) << 9))
+ || (rep_len + 3 >= len_main
+ && back_main > (UINT32_C(1) << 15))) {
+ *back_res = rep_index;
+ *len_res = rep_len;
+ mf_skip(mf, rep_len - 1);
+ return;
+ }
+ }
+
+ if (len_main < 2 || buf_avail <= 2) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return;
+ }
+
+ // Get the matches for the next byte. If we find a better match,
+ // the current byte is encoded as a literal.
+ coder->longest_match_length = mf_find(mf,
+ &coder->matches_count, coder->matches);
+
+ if (coder->longest_match_length >= 2) {
+ const uint32_t new_dist = coder->matches[
+ coder->matches_count - 1].dist;
+
+ if ((coder->longest_match_length >= len_main
+ && new_dist < back_main)
+ || (coder->longest_match_length == len_main + 1
+ && !change_pair(back_main, new_dist))
+ || (coder->longest_match_length > len_main + 1)
+ || (coder->longest_match_length + 1 >= len_main
+ && len_main >= 3
+ && change_pair(new_dist, back_main))) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return;
+ }
+ }
+
+ // In contrast to LZMA SDK, dictionary could not have been moved
+ // between mf_find() calls, thus it is safe to just increment
+ // the old buf pointer instead of recalculating it with mf_ptr().
+ ++buf;
+
+ limit = len_main - 1;
+
+ for (i = 0; i < REP_DISTANCES; ++i) {
+ uint32_t len;
+
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ for (len = 2; len < limit
+ && buf[len] == buf_back[len]; ++len) ;
+
+ if (len >= limit) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return;
+ }
+ }
+
+ *back_res = back_main + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 2);
+ return;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_normal.c b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_normal.c
new file mode 100644
index 000000000..d3a63485c
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_optimum_normal.c
@@ -0,0 +1,925 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_optimum_normal.c
+//
+// Author: Igor Pavlov
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "lzma_encoder_private.h"
+#include "fastpos.h"
+
+
+////////////
+// Prices //
+////////////
+
+static uint32_t
+get_literal_price(const lzma_coder *const coder, const uint32_t pos,
+ const uint32_t prev_byte, const bool match_mode,
+ uint32_t match_byte, uint32_t symbol)
+{
+ const probability *const subcoder = literal_subcoder(coder->literal,
+ coder->literal_context_bits, coder->literal_pos_mask,
+ pos, prev_byte);
+
+ uint32_t price = 0;
+
+ if (!match_mode) {
+ price = rc_bittree_price(subcoder, 8, symbol);
+ } else {
+ uint32_t offset = 0x100;
+ symbol += UINT32_C(1) << 8;
+
+ do {
+ uint32_t match_bit;
+ uint32_t subcoder_index;
+ uint32_t bit;
+
+ match_byte <<= 1;
+
+ match_bit = match_byte & offset;
+ subcoder_index = offset + match_bit + (symbol >> 8);
+ bit = (symbol >> 7) & 1;
+ price += rc_bit_price(subcoder[subcoder_index], bit);
+
+ symbol <<= 1;
+ offset &= ~(match_byte ^ symbol);
+
+ } while (symbol < (UINT32_C(1) << 16));
+ }
+
+ return price;
+}
+
+
+static inline uint32_t
+get_len_price(const lzma_length_encoder *const lencoder,
+ const uint32_t len, const uint32_t pos_state)
+{
+ // NOTE: Unlike the other price tables, length prices are updated
+ // in lzma_encoder.c
+ return lencoder->prices[pos_state][len - MATCH_LEN_MIN];
+}
+
+
+static inline uint32_t
+get_short_rep_price(const lzma_coder *const coder,
+ const lzma_lzma_state state, const uint32_t pos_state)
+{
+ return rc_bit_0_price(coder->is_rep0[state])
+ + rc_bit_0_price(coder->is_rep0_long[state][pos_state]);
+}
+
+
+static inline uint32_t
+get_pure_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
+ const lzma_lzma_state state, uint32_t pos_state)
+{
+ uint32_t price;
+
+ if (rep_index == 0) {
+ price = rc_bit_0_price(coder->is_rep0[state]);
+ price += rc_bit_1_price(coder->is_rep0_long[state][pos_state]);
+ } else {
+ price = rc_bit_1_price(coder->is_rep0[state]);
+
+ if (rep_index == 1) {
+ price += rc_bit_0_price(coder->is_rep1[state]);
+ } else {
+ price += rc_bit_1_price(coder->is_rep1[state]);
+ price += rc_bit_price(coder->is_rep2[state],
+ rep_index - 2);
+ }
+ }
+
+ return price;
+}
+
+
+static inline uint32_t
+get_rep_price(const lzma_coder *const coder, const uint32_t rep_index,
+ const uint32_t len, const lzma_lzma_state state,
+ const uint32_t pos_state)
+{
+ return get_len_price(&coder->rep_len_encoder, len, pos_state)
+ + get_pure_rep_price(coder, rep_index, state, pos_state);
+}
+
+
+static inline uint32_t
+get_pos_len_price(const lzma_coder *const coder, const uint32_t pos,
+ const uint32_t len, const uint32_t pos_state)
+{
+ const uint32_t len_to_pos_state = get_len_to_pos_state(len);
+ uint32_t price;
+
+ if (pos < FULL_DISTANCES) {
+ price = coder->distances_prices[len_to_pos_state][pos];
+ } else {
+ const uint32_t pos_slot = get_pos_slot_2(pos);
+ price = coder->pos_slot_prices[len_to_pos_state][pos_slot]
+ + coder->align_prices[pos & ALIGN_MASK];
+ }
+
+ price += get_len_price(&coder->match_len_encoder, len, pos_state);
+
+ return price;
+}
+
+
+static void
+fill_distances_prices(lzma_coder *coder)
+{
+ uint32_t len_to_pos_state;
+ uint32_t pos_slot;
+ uint32_t i;
+
+ for (len_to_pos_state = 0;
+ len_to_pos_state < LEN_TO_POS_STATES;
+ ++len_to_pos_state) {
+
+ uint32_t *const pos_slot_prices
+ = coder->pos_slot_prices[len_to_pos_state];
+
+ // Price to encode the pos_slot.
+ for (pos_slot = 0;
+ pos_slot < coder->dist_table_size; ++pos_slot)
+ pos_slot_prices[pos_slot] = rc_bittree_price(
+ coder->pos_slot[len_to_pos_state],
+ POS_SLOT_BITS, pos_slot);
+
+ // For matches with distance >= FULL_DISTANCES, add the price
+ // of the direct bits part of the match distance. (Align bits
+ // are handled by fill_align_prices()).
+ for (pos_slot = END_POS_MODEL_INDEX;
+ pos_slot < coder->dist_table_size; ++pos_slot)
+ pos_slot_prices[pos_slot] += rc_direct_price(
+ ((pos_slot >> 1) - 1) - ALIGN_BITS);
+
+ // Distances in the range [0, 3] are fully encoded with
+ // pos_slot, so they are used for coder->distances_prices
+ // as is.
+ for (i = 0; i < START_POS_MODEL_INDEX; ++i)
+ coder->distances_prices[len_to_pos_state][i]
+ = pos_slot_prices[i];
+ }
+
+ // Distances in the range [4, 127] depend on pos_slot and pos_special.
+ // We do this in a loop separate from the above loop to avoid
+ // redundant calls to get_pos_slot().
+ for (i = START_POS_MODEL_INDEX; i < FULL_DISTANCES; ++i) {
+ const uint32_t pos_slot = get_pos_slot(i);
+ const uint32_t footer_bits = ((pos_slot >> 1) - 1);
+ const uint32_t base = (2 | (pos_slot & 1)) << footer_bits;
+ const uint32_t price = rc_bittree_reverse_price(
+ coder->pos_special + base - pos_slot - 1,
+ footer_bits, i - base);
+
+ for (len_to_pos_state = 0;
+ len_to_pos_state < LEN_TO_POS_STATES;
+ ++len_to_pos_state)
+ coder->distances_prices[len_to_pos_state][i]
+ = price + coder->pos_slot_prices[
+ len_to_pos_state][pos_slot];
+ }
+
+ coder->match_price_count = 0;
+ return;
+}
+
+
+static void
+fill_align_prices(lzma_coder *coder)
+{
+ uint32_t i;
+ for (i = 0; i < ALIGN_TABLE_SIZE; ++i)
+ coder->align_prices[i] = rc_bittree_reverse_price(
+ coder->pos_align, ALIGN_BITS, i);
+
+ coder->align_price_count = 0;
+ return;
+}
+
+
+/////////////
+// Optimal //
+/////////////
+
+static inline void
+make_literal(lzma_optimal *optimal)
+{
+ optimal->back_prev = UINT32_MAX;
+ optimal->prev_1_is_literal = false;
+}
+
+
+static inline void
+make_short_rep(lzma_optimal *optimal)
+{
+ optimal->back_prev = 0;
+ optimal->prev_1_is_literal = false;
+}
+
+
+#define is_short_rep(optimal) \
+ ((optimal).back_prev == 0)
+
+
+static void
+backward(lzma_coder *LZMA_RESTRICT coder, uint32_t *LZMA_RESTRICT len_res,
+ uint32_t *LZMA_RESTRICT back_res, uint32_t cur)
+{
+ uint32_t pos_mem = coder->opts[cur].pos_prev;
+ uint32_t back_mem = coder->opts[cur].back_prev;
+
+ coder->opts_end_index = cur;
+
+ do {
+ const uint32_t pos_prev = pos_mem;
+ const uint32_t back_cur = back_mem;
+
+ if (coder->opts[cur].prev_1_is_literal) {
+ make_literal(&coder->opts[pos_mem]);
+ coder->opts[pos_mem].pos_prev = pos_mem - 1;
+
+ if (coder->opts[cur].prev_2) {
+ coder->opts[pos_mem - 1].prev_1_is_literal
+ = false;
+ coder->opts[pos_mem - 1].pos_prev
+ = coder->opts[cur].pos_prev_2;
+ coder->opts[pos_mem - 1].back_prev
+ = coder->opts[cur].back_prev_2;
+ }
+ }
+
+ back_mem = coder->opts[pos_prev].back_prev;
+ pos_mem = coder->opts[pos_prev].pos_prev;
+
+ coder->opts[pos_prev].back_prev = back_cur;
+ coder->opts[pos_prev].pos_prev = cur;
+ cur = pos_prev;
+
+ } while (cur != 0);
+
+ coder->opts_current_index = coder->opts[0].pos_prev;
+ *len_res = coder->opts[0].pos_prev;
+ *back_res = coder->opts[0].back_prev;
+
+ return;
+}
+
+
+//////////
+// Main //
+//////////
+
+static inline uint32_t
+helper1(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res,
+ uint32_t position)
+{
+ uint32_t buf_avail;
+ const uint8_t *buf;
+ uint32_t rep_lens[REP_DISTANCES];
+ uint32_t rep_max_index = 0;
+ uint32_t i;
+
+ uint8_t current_byte;
+ uint8_t match_byte;
+
+ uint32_t pos_state;
+ uint32_t match_price;
+ uint32_t rep_match_price;
+ uint32_t len_end;
+ uint32_t len;
+
+ uint32_t normal_match_price;
+
+ const uint32_t nice_len = mf->nice_len;
+
+ uint32_t len_main;
+ uint32_t matches_count;
+
+ if (mf->read_ahead == 0) {
+ len_main = mf_find(mf, &matches_count, coder->matches);
+ } else {
+ assert(mf->read_ahead == 1);
+ len_main = coder->longest_match_length;
+ matches_count = coder->matches_count;
+ }
+
+ buf_avail = my_min(mf_avail(mf) + 1, MATCH_LEN_MAX);
+ if (buf_avail < 2) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ buf = mf_ptr(mf) - 1;
+
+ for (i = 0; i < REP_DISTANCES; ++i) {
+ uint32_t len_test;
+
+ const uint8_t *const buf_back = buf - coder->reps[i] - 1;
+
+ if (not_equal_16(buf, buf_back)) {
+ rep_lens[i] = 0;
+ continue;
+ }
+
+ for (len_test = 2; len_test < buf_avail
+ && buf[len_test] == buf_back[len_test];
+ ++len_test) ;
+
+ rep_lens[i] = len_test;
+ if (len_test > rep_lens[rep_max_index])
+ rep_max_index = i;
+ }
+
+ if (rep_lens[rep_max_index] >= nice_len) {
+ *back_res = rep_max_index;
+ *len_res = rep_lens[rep_max_index];
+ mf_skip(mf, *len_res - 1);
+ return UINT32_MAX;
+ }
+
+
+ if (len_main >= nice_len) {
+ *back_res = coder->matches[matches_count - 1].dist
+ + REP_DISTANCES;
+ *len_res = len_main;
+ mf_skip(mf, len_main - 1);
+ return UINT32_MAX;
+ }
+
+ current_byte = *buf;
+ match_byte = *(buf - coder->reps[0] - 1);
+
+ if (len_main < 2 && current_byte != match_byte
+ && rep_lens[rep_max_index] < 2) {
+ *back_res = UINT32_MAX;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ coder->opts[0].state = coder->state;
+
+ pos_state = position & coder->pos_mask;
+
+ coder->opts[1].price = rc_bit_0_price(
+ coder->is_match[coder->state][pos_state])
+ + get_literal_price(coder, position, buf[-1],
+ !is_literal_state(coder->state),
+ match_byte, current_byte);
+
+ make_literal(&coder->opts[1]);
+
+ match_price = rc_bit_1_price(
+ coder->is_match[coder->state][pos_state]);
+ rep_match_price = match_price
+ + rc_bit_1_price(coder->is_rep[coder->state]);
+
+ if (match_byte == current_byte) {
+ const uint32_t short_rep_price = rep_match_price
+ + get_short_rep_price(
+ coder, coder->state, pos_state);
+
+ if (short_rep_price < coder->opts[1].price) {
+ coder->opts[1].price = short_rep_price;
+ make_short_rep(&coder->opts[1]);
+ }
+ }
+
+ len_end = my_max(len_main, rep_lens[rep_max_index]);
+
+ if (len_end < 2) {
+ *back_res = coder->opts[1].back_prev;
+ *len_res = 1;
+ return UINT32_MAX;
+ }
+
+ coder->opts[1].pos_prev = 0;
+
+ for (i = 0; i < REP_DISTANCES; ++i)
+ coder->opts[0].backs[i] = coder->reps[i];
+
+ len = len_end;
+ do {
+ coder->opts[len].price = RC_INFINITY_PRICE;
+ } while (--len >= 2);
+
+
+ for (i = 0; i < REP_DISTANCES; ++i) {
+ uint32_t price;
+
+ uint32_t rep_len = rep_lens[i];
+ if (rep_len < 2)
+ continue;
+
+ price = rep_match_price + get_pure_rep_price(
+ coder, i, coder->state, pos_state);
+
+ do {
+ const uint32_t cur_and_len_price = price
+ + get_len_price(
+ &coder->rep_len_encoder,
+ rep_len, pos_state);
+
+ if (cur_and_len_price < coder->opts[rep_len].price) {
+ coder->opts[rep_len].price = cur_and_len_price;
+ coder->opts[rep_len].pos_prev = 0;
+ coder->opts[rep_len].back_prev = i;
+ coder->opts[rep_len].prev_1_is_literal = false;
+ }
+ } while (--rep_len >= 2);
+ }
+
+
+ normal_match_price = match_price
+ + rc_bit_0_price(coder->is_rep[coder->state]);
+
+ len = rep_lens[0] >= 2 ? rep_lens[0] + 1 : 2;
+ if (len <= len_main) {
+ uint32_t i = 0;
+ while (len > coder->matches[i].len)
+ ++i;
+
+ for(; ; ++len) {
+ const uint32_t dist = coder->matches[i].dist;
+ const uint32_t cur_and_len_price = normal_match_price
+ + get_pos_len_price(coder,
+ dist, len, pos_state);
+
+ if (cur_and_len_price < coder->opts[len].price) {
+ coder->opts[len].price = cur_and_len_price;
+ coder->opts[len].pos_prev = 0;
+ coder->opts[len].back_prev
+ = dist + REP_DISTANCES;
+ coder->opts[len].prev_1_is_literal = false;
+ }
+
+ if (len == coder->matches[i].len)
+ if (++i == matches_count)
+ break;
+ }
+ }
+
+ return len_end;
+}
+
+
+static inline uint32_t
+helper2(lzma_coder *coder, uint32_t *reps, const uint8_t *buf,
+ uint32_t len_end, uint32_t position, const uint32_t cur,
+ const uint32_t nice_len, const uint32_t buf_avail_full)
+{
+ uint32_t matches_count = coder->matches_count;
+ uint32_t new_len = coder->longest_match_length;
+ uint32_t pos_prev = coder->opts[cur].pos_prev;
+ lzma_lzma_state state;
+ uint32_t buf_avail;
+ uint32_t rep_index;
+ uint32_t i;
+
+ uint32_t cur_price;
+ uint8_t current_byte;
+ uint8_t match_byte;
+ uint32_t pos_state;
+ uint32_t cur_and_1_price;
+ bool next_is_literal = false;
+ uint32_t match_price;
+ uint32_t rep_match_price;
+ uint32_t start_len = 2;
+
+ if (coder->opts[cur].prev_1_is_literal) {
+ --pos_prev;
+
+ if (coder->opts[cur].prev_2) {
+ state = coder->opts[coder->opts[cur].pos_prev_2].state;
+
+ if (coder->opts[cur].back_prev_2 < REP_DISTANCES)
+ update_long_rep(state);
+ else
+ update_match(state);
+
+ } else {
+ state = coder->opts[pos_prev].state;
+ }
+
+ update_literal(state);
+
+ } else {
+ state = coder->opts[pos_prev].state;
+ }
+
+ if (pos_prev == cur - 1) {
+ if (is_short_rep(coder->opts[cur]))
+ update_short_rep(state);
+ else
+ update_literal(state);
+ } else {
+ uint32_t pos;
+ if (coder->opts[cur].prev_1_is_literal
+ && coder->opts[cur].prev_2) {
+ pos_prev = coder->opts[cur].pos_prev_2;
+ pos = coder->opts[cur].back_prev_2;
+ update_long_rep(state);
+ } else {
+ pos = coder->opts[cur].back_prev;
+ if (pos < REP_DISTANCES)
+ update_long_rep(state);
+ else
+ update_match(state);
+ }
+
+ if (pos < REP_DISTANCES) {
+ uint32_t i;
+
+ reps[0] = coder->opts[pos_prev].backs[pos];
+
+ for (i = 1; i <= pos; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i - 1];
+
+ for (; i < REP_DISTANCES; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i];
+
+ } else {
+ reps[0] = pos - REP_DISTANCES;
+
+ for (i = 1; i < REP_DISTANCES; ++i)
+ reps[i] = coder->opts[pos_prev].backs[i - 1];
+ }
+ }
+
+ coder->opts[cur].state = state;
+
+ for (i = 0; i < REP_DISTANCES; ++i)
+ coder->opts[cur].backs[i] = reps[i];
+
+ cur_price = coder->opts[cur].price;
+
+ current_byte = *buf;
+ match_byte = *(buf - reps[0] - 1);
+
+ pos_state = position & coder->pos_mask;
+
+ cur_and_1_price = cur_price
+ + rc_bit_0_price(coder->is_match[state][pos_state])
+ + get_literal_price(coder, position, buf[-1],
+ !is_literal_state(state), match_byte, current_byte);
+
+ if (cur_and_1_price < coder->opts[cur + 1].price) {
+ coder->opts[cur + 1].price = cur_and_1_price;
+ coder->opts[cur + 1].pos_prev = cur;
+ make_literal(&coder->opts[cur + 1]);
+ next_is_literal = true;
+ }
+
+ match_price = cur_price
+ + rc_bit_1_price(coder->is_match[state][pos_state]);
+ rep_match_price = match_price
+ + rc_bit_1_price(coder->is_rep[state]);
+
+ if (match_byte == current_byte
+ && !(coder->opts[cur + 1].pos_prev < cur
+ && coder->opts[cur + 1].back_prev == 0)) {
+
+ const uint32_t short_rep_price = rep_match_price
+ + get_short_rep_price(coder, state, pos_state);
+
+ if (short_rep_price <= coder->opts[cur + 1].price) {
+ coder->opts[cur + 1].price = short_rep_price;
+ coder->opts[cur + 1].pos_prev = cur;
+ make_short_rep(&coder->opts[cur + 1]);
+ next_is_literal = true;
+ }
+ }
+
+ if (buf_avail_full < 2)
+ return len_end;
+
+ buf_avail = my_min(buf_avail_full, nice_len);
+
+ if (!next_is_literal && match_byte != current_byte) { // speed optimization
+ // try literal + rep0
+ const uint8_t *const buf_back = buf - reps[0] - 1;
+ const uint32_t limit = my_min(buf_avail_full, nice_len + 1);
+
+ uint32_t len_test = 1;
+ while (len_test < limit && buf[len_test] == buf_back[len_test])
+ ++len_test;
+
+ --len_test;
+
+ if (len_test >= 2) {
+ uint32_t pos_state_next;
+ uint32_t next_rep_match_price;
+ uint32_t offset;
+ uint32_t cur_and_len_price;
+
+ lzma_lzma_state state_2 = state;
+ update_literal(state_2);
+
+ pos_state_next = (position + 1) & coder->pos_mask;
+ next_rep_match_price = cur_and_1_price
+ + rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ //for (; len_test >= 2; --len_test) {
+ offset = cur + 1 + len_test;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = false;
+ }
+ //}
+ }
+ }
+
+
+ for (rep_index = 0; rep_index < REP_DISTANCES; ++rep_index) {
+ uint32_t len_test, len_test_2, len_test_temp;
+ uint32_t price, limit;
+
+ const uint8_t *const buf_back = buf - reps[rep_index] - 1;
+ if (not_equal_16(buf, buf_back))
+ continue;
+
+ for (len_test = 2; len_test < buf_avail
+ && buf[len_test] == buf_back[len_test];
+ ++len_test) ;
+
+ while (len_end < cur + len_test)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ len_test_temp = len_test;
+ price = rep_match_price + get_pure_rep_price(
+ coder, rep_index, state, pos_state);
+
+ do {
+ const uint32_t cur_and_len_price = price
+ + get_len_price(&coder->rep_len_encoder,
+ len_test, pos_state);
+
+ if (cur_and_len_price < coder->opts[cur + len_test].price) {
+ coder->opts[cur + len_test].price = cur_and_len_price;
+ coder->opts[cur + len_test].pos_prev = cur;
+ coder->opts[cur + len_test].back_prev = rep_index;
+ coder->opts[cur + len_test].prev_1_is_literal = false;
+ }
+ } while (--len_test >= 2);
+
+ len_test = len_test_temp;
+
+ if (rep_index == 0)
+ start_len = len_test + 1;
+
+
+ len_test_2 = len_test + 1;
+ limit = my_min(buf_avail_full,
+ len_test_2 + nice_len);
+ for (; len_test_2 < limit
+ && buf[len_test_2] == buf_back[len_test_2];
+ ++len_test_2) ;
+
+ len_test_2 -= len_test + 1;
+
+ if (len_test_2 >= 2) {
+ uint32_t pos_state_next;
+ uint32_t cur_and_len_literal_price;
+ uint32_t next_rep_match_price;
+ uint32_t offset;
+ uint32_t cur_and_len_price;
+
+ lzma_lzma_state state_2 = state;
+ update_long_rep(state_2);
+
+ pos_state_next = (position + len_test) & coder->pos_mask;
+
+ cur_and_len_literal_price = price
+ + get_len_price(&coder->rep_len_encoder,
+ len_test, pos_state)
+ + rc_bit_0_price(coder->is_match[state_2][pos_state_next])
+ + get_literal_price(coder, position + len_test,
+ buf[len_test - 1], true,
+ buf_back[len_test], buf[len_test]);
+
+ update_literal(state_2);
+
+ pos_state_next = (position + len_test + 1) & coder->pos_mask;
+
+ next_rep_match_price = cur_and_len_literal_price
+ + rc_bit_1_price(coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ //for(; len_test_2 >= 2; len_test_2--) {
+ offset = cur + len_test + 1 + len_test_2;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test_2,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + len_test + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = true;
+ coder->opts[offset].pos_prev_2 = cur;
+ coder->opts[offset].back_prev_2 = rep_index;
+ }
+ //}
+ }
+ }
+
+
+ //for (uint32_t len_test = 2; len_test <= new_len; ++len_test)
+ if (new_len > buf_avail) {
+ new_len = buf_avail;
+
+ matches_count = 0;
+ while (new_len > coder->matches[matches_count].len)
+ ++matches_count;
+
+ coder->matches[matches_count++].len = new_len;
+ }
+
+
+ if (new_len >= start_len) {
+ uint32_t len_test;
+ uint32_t i = 0;
+
+ const uint32_t normal_match_price = match_price
+ + rc_bit_0_price(coder->is_rep[state]);
+
+ while (len_end < cur + new_len)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ while (start_len > coder->matches[i].len)
+ ++i;
+
+ for (len_test = start_len; ; ++len_test) {
+ const uint32_t cur_back = coder->matches[i].dist;
+ uint32_t cur_and_len_price = normal_match_price
+ + get_pos_len_price(coder,
+ cur_back, len_test, pos_state);
+
+ if (cur_and_len_price < coder->opts[cur + len_test].price) {
+ coder->opts[cur + len_test].price = cur_and_len_price;
+ coder->opts[cur + len_test].pos_prev = cur;
+ coder->opts[cur + len_test].back_prev
+ = cur_back + REP_DISTANCES;
+ coder->opts[cur + len_test].prev_1_is_literal = false;
+ }
+
+ if (len_test == coder->matches[i].len) {
+ // Try Match + Literal + Rep0
+ const uint8_t *const buf_back = buf - cur_back - 1;
+ uint32_t len_test_2 = len_test + 1;
+ const uint32_t limit = my_min(buf_avail_full,
+ len_test_2 + nice_len);
+
+ for (; len_test_2 < limit &&
+ buf[len_test_2] == buf_back[len_test_2];
+ ++len_test_2) ;
+
+ len_test_2 -= len_test + 1;
+
+ if (len_test_2 >= 2) {
+ uint32_t pos_state_next;
+ uint32_t cur_and_len_literal_price;
+ uint32_t next_rep_match_price;
+ uint32_t offset;
+
+ lzma_lzma_state state_2 = state;
+ update_match(state_2);
+ pos_state_next = (position + len_test) & coder->pos_mask;
+
+ cur_and_len_literal_price = cur_and_len_price
+ + rc_bit_0_price(
+ coder->is_match[state_2][pos_state_next])
+ + get_literal_price(coder,
+ position + len_test,
+ buf[len_test - 1],
+ true,
+ buf_back[len_test],
+ buf[len_test]);
+
+ update_literal(state_2);
+ pos_state_next = (pos_state_next + 1) & coder->pos_mask;
+
+ next_rep_match_price
+ = cur_and_len_literal_price
+ + rc_bit_1_price(
+ coder->is_match[state_2][pos_state_next])
+ + rc_bit_1_price(coder->is_rep[state_2]);
+
+ // for(; len_test_2 >= 2; --len_test_2) {
+ offset = cur + len_test + 1 + len_test_2;
+
+ while (len_end < offset)
+ coder->opts[++len_end].price = RC_INFINITY_PRICE;
+
+ cur_and_len_price = next_rep_match_price
+ + get_rep_price(coder, 0, len_test_2,
+ state_2, pos_state_next);
+
+ if (cur_and_len_price < coder->opts[offset].price) {
+ coder->opts[offset].price = cur_and_len_price;
+ coder->opts[offset].pos_prev = cur + len_test + 1;
+ coder->opts[offset].back_prev = 0;
+ coder->opts[offset].prev_1_is_literal = true;
+ coder->opts[offset].prev_2 = true;
+ coder->opts[offset].pos_prev_2 = cur;
+ coder->opts[offset].back_prev_2
+ = cur_back + REP_DISTANCES;
+ }
+ //}
+ }
+
+ if (++i == matches_count)
+ break;
+ }
+ }
+ }
+
+ return len_end;
+}
+
+
+extern void
+lzma_lzma_optimum_normal(lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res,
+ uint32_t position)
+{
+ uint32_t reps[REP_DISTANCES];
+ uint32_t len_end;
+ uint32_t cur;
+
+ // If we have symbols pending, return the next pending symbol.
+ if (coder->opts_end_index != coder->opts_current_index) {
+ assert(mf->read_ahead > 0);
+ *len_res = coder->opts[coder->opts_current_index].pos_prev
+ - coder->opts_current_index;
+ *back_res = coder->opts[coder->opts_current_index].back_prev;
+ coder->opts_current_index = coder->opts[
+ coder->opts_current_index].pos_prev;
+ return;
+ }
+
+ // Update the price tables. In LZMA SDK <= 4.60 (and possibly later)
+ // this was done in both initialization function and in the main loop.
+ // In liblzma they were moved into this single place.
+ if (mf->read_ahead == 0) {
+ if (coder->match_price_count >= (1 << 7))
+ fill_distances_prices(coder);
+
+ if (coder->align_price_count >= ALIGN_TABLE_SIZE)
+ fill_align_prices(coder);
+ }
+
+ // TODO: This needs quite a bit of cleaning still. But splitting
+ // the original function into two pieces makes it at least a little
+ // more readable, since those two parts don't share many variables.
+
+ len_end = helper1(coder, mf, back_res, len_res, position);
+ if (len_end == UINT32_MAX)
+ return;
+
+
+ memcpy(reps, coder->reps, sizeof(reps));
+
+ for (cur = 1; cur < len_end; ++cur) {
+ assert(cur < OPTS);
+
+ coder->longest_match_length = mf_find(
+ mf, &coder->matches_count, coder->matches);
+
+ if (coder->longest_match_length >= mf->nice_len)
+ break;
+
+ len_end = helper2(coder, reps, mf_ptr(mf) - 1, len_end,
+ position + cur, cur, mf->nice_len,
+ my_min(mf_avail(mf) + 1, OPTS - 1 - cur));
+ }
+
+ backward(coder, len_res, back_res, cur);
+ return;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_presets.c b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_presets.c
new file mode 100644
index 000000000..9332abfa5
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_presets.c
@@ -0,0 +1,64 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_presets.c
+/// \brief Encoder presets
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "common.h"
+
+
+extern LZMA_API(lzma_bool)
+lzma_lzma_preset(lzma_options_lzma *options, uint32_t preset)
+{
+ static const uint8_t dict_pow2[]
+ = { 18, 20, 21, 22, 22, 23, 23, 24, 25, 26 };
+ static const uint8_t depths[] = { 4, 8, 24, 48 };
+
+ const uint32_t level = preset & LZMA_PRESET_LEVEL_MASK;
+ const uint32_t flags = preset & ~LZMA_PRESET_LEVEL_MASK;
+ const uint32_t supported_flags = LZMA_PRESET_EXTREME;
+
+ if (level > 9 || (flags & ~supported_flags))
+ return true;
+
+ options->preset_dict = NULL;
+ options->preset_dict_size = 0;
+
+ options->lc = LZMA_LC_DEFAULT;
+ options->lp = LZMA_LP_DEFAULT;
+ options->pb = LZMA_PB_DEFAULT;
+
+ options->dict_size = UINT32_C(1) << dict_pow2[level];
+
+ if (level <= 3) {
+ options->mode = LZMA_MODE_FAST;
+ options->mf = level == 0 ? LZMA_MF_HC3 : LZMA_MF_HC4;
+ options->nice_len = level <= 1 ? 128 : 273;
+ options->depth = depths[level];
+ } else {
+ options->mode = LZMA_MODE_NORMAL;
+ options->mf = LZMA_MF_BT4;
+ options->nice_len = level == 4 ? 16 : level == 5 ? 32 : 64;
+ options->depth = 0;
+ }
+
+ if (flags & LZMA_PRESET_EXTREME) {
+ options->mode = LZMA_MODE_NORMAL;
+ options->mf = LZMA_MF_BT4;
+ if (level == 3 || level == 5) {
+ options->nice_len = 192;
+ options->depth = 0;
+ } else {
+ options->nice_len = 273;
+ options->depth = 512;
+ }
+ }
+
+ return false;
+}
diff --git a/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_private.h b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_private.h
new file mode 100644
index 000000000..04fb29e90
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/lzma/lzma_encoder_private.h
@@ -0,0 +1,148 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file lzma_encoder_private.h
+/// \brief Private definitions for LZMA encoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_LZMA_ENCODER_PRIVATE_H
+#define LZMA_LZMA_ENCODER_PRIVATE_H
+
+#include "lz_encoder.h"
+#include "range_encoder.h"
+#include "lzma_common.h"
+#include "lzma_encoder.h"
+
+
+// Macro to compare if the first two bytes in two buffers differ. This is
+// needed in lzma_lzma_optimum_*() to test if the match is at least
+// MATCH_LEN_MIN bytes. Unaligned access gives tiny gain so there's no
+// reason to not use it when it is supported.
+#ifdef TUKLIB_FAST_UNALIGNED_ACCESS
+# define not_equal_16(a, b) \
+ (*(const uint16_t *)(a) != *(const uint16_t *)(b))
+#else
+# define not_equal_16(a, b) \
+ ((a)[0] != (b)[0] || (a)[1] != (b)[1])
+#endif
+
+
+// Optimal - Number of entries in the optimum array.
+#define OPTS (1 << 12)
+
+
+typedef struct {
+ probability choice;
+ probability choice2;
+ probability low[POS_STATES_MAX][LEN_LOW_SYMBOLS];
+ probability mid[POS_STATES_MAX][LEN_MID_SYMBOLS];
+ probability high[LEN_HIGH_SYMBOLS];
+
+ uint32_t prices[POS_STATES_MAX][LEN_SYMBOLS];
+ uint32_t table_size;
+ uint32_t counters[POS_STATES_MAX];
+
+} lzma_length_encoder;
+
+
+typedef struct {
+ lzma_lzma_state state;
+
+ bool prev_1_is_literal;
+ bool prev_2;
+
+ uint32_t pos_prev_2;
+ uint32_t back_prev_2;
+
+ uint32_t price;
+ uint32_t pos_prev; // pos_next;
+ uint32_t back_prev;
+
+ uint32_t backs[REP_DISTANCES];
+
+} lzma_optimal;
+
+
+struct lzma_coder_s {
+ /// Range encoder
+ lzma_range_encoder rc;
+
+ /// State
+ lzma_lzma_state state;
+
+ /// The four most recent match distances
+ uint32_t reps[REP_DISTANCES];
+
+ /// Array of match candidates
+ lzma_match matches[MATCH_LEN_MAX + 1];
+
+ /// Number of match candidates in matches[]
+ uint32_t matches_count;
+
+ /// Variable to hold the length of the longest match between calls
+ /// to lzma_lzma_optimum_*().
+ uint32_t longest_match_length;
+
+ /// True if using getoptimumfast
+ bool fast_mode;
+
+ /// True if the encoder has been initialized by encoding the first
+ /// byte as a literal.
+ bool is_initialized;
+
+ /// True if the range encoder has been flushed, but not all bytes
+ /// have been written to the output buffer yet.
+ bool is_flushed;
+
+ uint32_t pos_mask; ///< (1 << pos_bits) - 1
+ uint32_t literal_context_bits;
+ uint32_t literal_pos_mask;
+
+ // These are the same as in lzma_decoder.c. See comments there.
+ probability literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE];
+ probability is_match[STATES][POS_STATES_MAX];
+ probability is_rep[STATES];
+ probability is_rep0[STATES];
+ probability is_rep1[STATES];
+ probability is_rep2[STATES];
+ probability is_rep0_long[STATES][POS_STATES_MAX];
+ probability pos_slot[LEN_TO_POS_STATES][POS_SLOTS];
+ probability pos_special[FULL_DISTANCES - END_POS_MODEL_INDEX];
+ probability pos_align[ALIGN_TABLE_SIZE];
+
+ // These are the same as in lzma_decoder.c except that the encoders
+ // include also price tables.
+ lzma_length_encoder match_len_encoder;
+ lzma_length_encoder rep_len_encoder;
+
+ // Price tables
+ uint32_t pos_slot_prices[LEN_TO_POS_STATES][POS_SLOTS];
+ uint32_t distances_prices[LEN_TO_POS_STATES][FULL_DISTANCES];
+ uint32_t dist_table_size;
+ uint32_t match_price_count;
+
+ uint32_t align_prices[ALIGN_TABLE_SIZE];
+ uint32_t align_price_count;
+
+ // Optimal
+ uint32_t opts_end_index;
+ uint32_t opts_current_index;
+ lzma_optimal opts[OPTS];
+};
+
+
+extern void lzma_lzma_optimum_fast(
+ lzma_coder *LZMA_RESTRICT coder, lzma_mf *LZMA_RESTRICT mf,
+ uint32_t *LZMA_RESTRICT back_res, uint32_t *LZMA_RESTRICT len_res);
+
+extern void lzma_lzma_optimum_normal(lzma_coder *LZMA_RESTRICT coder,
+ lzma_mf *LZMA_RESTRICT mf, uint32_t *LZMA_RESTRICT back_res,
+ uint32_t *LZMA_RESTRICT len_res, uint32_t position);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/price.h b/Utilities/cmliblzma/liblzma/rangecoder/price.h
new file mode 100644
index 000000000..8ae02ca74
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/price.h
@@ -0,0 +1,92 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file price.h
+/// \brief Probability price calculation
+//
+// Author: Igor Pavlov
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_PRICE_H
+#define LZMA_PRICE_H
+
+
+#define RC_MOVE_REDUCING_BITS 4
+#define RC_BIT_PRICE_SHIFT_BITS 4
+#define RC_PRICE_TABLE_SIZE (RC_BIT_MODEL_TOTAL >> RC_MOVE_REDUCING_BITS)
+
+#define RC_INFINITY_PRICE (UINT32_C(1) << 30)
+
+
+/// Lookup table for the inline functions defined in this file.
+extern const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE];
+
+
+static inline uint32_t
+rc_bit_price(const probability prob, const uint32_t bit)
+{
+ return lzma_rc_prices[(prob ^ ((UINT32_C(0) - bit)
+ & (RC_BIT_MODEL_TOTAL - 1))) >> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bit_0_price(const probability prob)
+{
+ return lzma_rc_prices[prob >> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bit_1_price(const probability prob)
+{
+ return lzma_rc_prices[(prob ^ (RC_BIT_MODEL_TOTAL - 1))
+ >> RC_MOVE_REDUCING_BITS];
+}
+
+
+static inline uint32_t
+rc_bittree_price(const probability *const probs,
+ const uint32_t bit_levels, uint32_t symbol)
+{
+ uint32_t price = 0;
+ symbol += UINT32_C(1) << bit_levels;
+
+ do {
+ const uint32_t bit = symbol & 1;
+ symbol >>= 1;
+ price += rc_bit_price(probs[symbol], bit);
+ } while (symbol != 1);
+
+ return price;
+}
+
+
+static inline uint32_t
+rc_bittree_reverse_price(const probability *const probs,
+ uint32_t bit_levels, uint32_t symbol)
+{
+ uint32_t price = 0;
+ uint32_t model_index = 1;
+
+ do {
+ const uint32_t bit = symbol & 1;
+ symbol >>= 1;
+ price += rc_bit_price(probs[model_index], bit);
+ model_index = (model_index << 1) + bit;
+ } while (--bit_levels != 0);
+
+ return price;
+}
+
+
+static inline uint32_t
+rc_direct_price(const uint32_t bits)
+{
+ return bits << RC_BIT_PRICE_SHIFT_BITS;
+}
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/price_table.c b/Utilities/cmliblzma/liblzma/rangecoder/price_table.c
new file mode 100644
index 000000000..ac64bf62c
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/price_table.c
@@ -0,0 +1,22 @@
+/* This file has been automatically generated by price_tablegen.c. */
+
+#include "range_encoder.h"
+
+const uint8_t lzma_rc_prices[RC_PRICE_TABLE_SIZE] = {
+ 128, 103, 91, 84, 78, 73, 69, 66,
+ 63, 61, 58, 56, 54, 52, 51, 49,
+ 48, 46, 45, 44, 43, 42, 41, 40,
+ 39, 38, 37, 36, 35, 34, 34, 33,
+ 32, 31, 31, 30, 29, 29, 28, 28,
+ 27, 26, 26, 25, 25, 24, 24, 23,
+ 23, 22, 22, 22, 21, 21, 20, 20,
+ 19, 19, 19, 18, 18, 17, 17, 17,
+ 16, 16, 16, 15, 15, 15, 14, 14,
+ 14, 13, 13, 13, 12, 12, 12, 11,
+ 11, 11, 11, 10, 10, 10, 10, 9,
+ 9, 9, 9, 8, 8, 8, 8, 7,
+ 7, 7, 7, 6, 6, 6, 6, 5,
+ 5, 5, 5, 5, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 2, 2, 2,
+ 2, 2, 2, 1, 1, 1, 1, 1
+};
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/price_tablegen.c b/Utilities/cmliblzma/liblzma/rangecoder/price_tablegen.c
new file mode 100644
index 000000000..bf08ce39d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/price_tablegen.c
@@ -0,0 +1,87 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file price_tablegen.c
+/// \brief Probability price table generator
+///
+/// Compiling: gcc -std=c99 -o price_tablegen price_tablegen.c
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <inttypes.h>
+#include <stdio.h>
+#include "range_common.h"
+#include "price.h"
+
+
+static uint32_t rc_prices[RC_PRICE_TABLE_SIZE];
+
+
+static void
+init_price_table(void)
+{
+ for (uint32_t i = (UINT32_C(1) << RC_MOVE_REDUCING_BITS) / 2;
+ i < RC_BIT_MODEL_TOTAL;
+ i += (UINT32_C(1) << RC_MOVE_REDUCING_BITS)) {
+ const uint32_t cycles_bits = RC_BIT_PRICE_SHIFT_BITS;
+ uint32_t w = i;
+ uint32_t bit_count = 0;
+
+ for (uint32_t j = 0; j < cycles_bits; ++j) {
+ w *= w;
+ bit_count <<= 1;
+
+ while (w >= (UINT32_C(1) << 16)) {
+ w >>= 1;
+ ++bit_count;
+ }
+ }
+
+ rc_prices[i >> RC_MOVE_REDUCING_BITS]
+ = (RC_BIT_MODEL_TOTAL_BITS << cycles_bits)
+ - 15 - bit_count;
+ }
+
+ return;
+}
+
+
+static void
+print_price_table(void)
+{
+ printf("/* This file has been automatically generated by "
+ "price_tablegen.c. */\n\n"
+ "#include \"range_encoder.h\"\n\n"
+ "const uint8_t lzma_rc_prices["
+ "RC_PRICE_TABLE_SIZE] = {");
+
+ const size_t array_size = sizeof(lzma_rc_prices)
+ / sizeof(lzma_rc_prices[0]);
+ for (size_t i = 0; i < array_size; ++i) {
+ if (i % 8 == 0)
+ printf("\n\t");
+
+ printf("%4" PRIu32, rc_prices[i]);
+
+ if (i != array_size - 1)
+ printf(",");
+ }
+
+ printf("\n};\n");
+
+ return;
+}
+
+
+int
+main(void)
+{
+ init_price_table();
+ print_price_table();
+ return 0;
+}
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/range_common.h b/Utilities/cmliblzma/liblzma/rangecoder/range_common.h
new file mode 100644
index 000000000..f15623ea6
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/range_common.h
@@ -0,0 +1,74 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file range_common.h
+/// \brief Common things for range encoder and decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_COMMON_H
+#define LZMA_RANGE_COMMON_H
+
+#include "common.h"
+
+
+///////////////
+// Constants //
+///////////////
+
+#define RC_SHIFT_BITS 8
+#define RC_TOP_BITS 24
+#define RC_TOP_VALUE (UINT32_C(1) << RC_TOP_BITS)
+#define RC_BIT_MODEL_TOTAL_BITS 11
+#define RC_BIT_MODEL_TOTAL (UINT32_C(1) << RC_BIT_MODEL_TOTAL_BITS)
+#define RC_MOVE_BITS 5
+
+
+////////////
+// Macros //
+////////////
+
+// Resets the probability so that both 0 and 1 have probability of 50 %
+#define bit_reset(prob) \
+ prob = RC_BIT_MODEL_TOTAL >> 1
+
+// This does the same for a complete bit tree.
+// (A tree represented as an array.)
+#define bittree_reset(probs, bit_levels) \
+ do { \
+ uint32_t bt_i; \
+ for (bt_i = 0; bt_i < (1 << (bit_levels)); ++bt_i) \
+ bit_reset((probs)[bt_i]); \
+ } while (0)
+
+
+//////////////////////
+// Type definitions //
+//////////////////////
+
+/// \brief Type of probabilities used with range coder
+///
+/// This needs to be at least 12-bit integer, so uint16_t is a logical choice.
+/// However, on some architecture and compiler combinations, a bigger type
+/// may give better speed, because the probability variables are accessed
+/// a lot. On the other hand, bigger probability type increases cache
+/// footprint, since there are 2 to 14 thousand probability variables in
+/// LZMA (assuming the limit of lc + lp <= 4; with lc + lp <= 12 there
+/// would be about 1.5 million variables).
+///
+/// With malicious files, the initialization speed of the LZMA decoder can
+/// become important. In that case, smaller probability variables mean that
+/// there is less bytes to write to RAM, which makes initialization faster.
+/// With big probability type, the initialization can become so slow that it
+/// can be a problem e.g. for email servers doing virus scanning.
+///
+/// I will be sticking to uint16_t unless some specific architectures
+/// are *much* faster (20-50 %) with uint32_t.
+typedef uint16_t probability;
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/range_decoder.h b/Utilities/cmliblzma/liblzma/rangecoder/range_decoder.h
new file mode 100644
index 000000000..199e7b5a6
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/range_decoder.h
@@ -0,0 +1,179 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file range_decoder.h
+/// \brief Range Decoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_DECODER_H
+#define LZMA_RANGE_DECODER_H
+
+#include "range_common.h"
+
+
+typedef struct {
+ uint32_t range;
+ uint32_t code;
+ uint32_t init_bytes_left;
+} lzma_range_decoder;
+
+
+/// Reads the first five bytes to initialize the range decoder.
+static inline bool
+rc_read_init(lzma_range_decoder *rc, const uint8_t *LZMA_RESTRICT in,
+ size_t *LZMA_RESTRICT in_pos, size_t in_size)
+{
+ while (rc->init_bytes_left > 0) {
+ if (*in_pos == in_size)
+ return false;
+
+ rc->code = (rc->code << 8) | in[*in_pos];
+ ++*in_pos;
+ --rc->init_bytes_left;
+ }
+
+ return true;
+}
+
+
+/// Makes local copies of range decoder and *in_pos variables. Doing this
+/// improves speed significantly. The range decoder macros expect also
+/// variables `in' and `in_size' to be defined.
+#define rc_to_local(range_decoder, in_pos) \
+ lzma_range_decoder rc = range_decoder; \
+ size_t rc_in_pos = (in_pos); \
+ uint32_t rc_bound
+
+
+/// Stores the local copes back to the range decoder structure.
+#define rc_from_local(range_decoder, in_pos) \
+do { \
+ range_decoder = rc; \
+ in_pos = rc_in_pos; \
+} while (0)
+
+
+/// Resets the range decoder structure.
+#define rc_reset(range_decoder) \
+do { \
+ (range_decoder).range = UINT32_MAX; \
+ (range_decoder).code = 0; \
+ (range_decoder).init_bytes_left = 5; \
+} while (0)
+
+
+/// When decoding has been properly finished, rc.code is always zero unless
+/// the input stream is corrupt. So checking this can catch some corrupt
+/// files especially if they don't have any other integrity check.
+#define rc_is_finished(range_decoder) \
+ ((range_decoder).code == 0)
+
+
+/// Read the next input byte if needed. If more input is needed but there is
+/// no more input available, "goto out" is used to jump out of the main
+/// decoder loop.
+#define rc_normalize(seq) \
+do { \
+ if (rc.range < RC_TOP_VALUE) { \
+ if (unlikely(rc_in_pos == in_size)) { \
+ coder->sequence = seq; \
+ goto out; \
+ } \
+ rc.range <<= RC_SHIFT_BITS; \
+ rc.code = (rc.code << RC_SHIFT_BITS) | in[rc_in_pos++]; \
+ } \
+} while (0)
+
+
+/// Start decoding a bit. This must be used together with rc_update_0()
+/// and rc_update_1():
+///
+/// rc_if_0(prob, seq) {
+/// rc_update_0(prob);
+/// // Do something
+/// } else {
+/// rc_update_1(prob);
+/// // Do something else
+/// }
+///
+#define rc_if_0(prob, seq) \
+ rc_normalize(seq); \
+ rc_bound = (rc.range >> RC_BIT_MODEL_TOTAL_BITS) * (prob); \
+ if (rc.code < rc_bound)
+
+
+/// Update the range decoder state and the used probability variable to
+/// match a decoded bit of 0.
+#define rc_update_0(prob) \
+do { \
+ rc.range = rc_bound; \
+ prob += (RC_BIT_MODEL_TOTAL - (prob)) >> RC_MOVE_BITS; \
+} while (0)
+
+
+/// Update the range decoder state and the used probability variable to
+/// match a decoded bit of 1.
+#define rc_update_1(prob) \
+do { \
+ rc.range -= rc_bound; \
+ rc.code -= rc_bound; \
+ prob -= (prob) >> RC_MOVE_BITS; \
+} while (0)
+
+
+/// Decodes one bit and runs action0 or action1 depending on the decoded bit.
+/// This macro is used as the last step in bittree reverse decoders since
+/// those don't use "symbol" for anything else than indexing the probability
+/// arrays.
+#define rc_bit_last(prob, action0, action1, seq) \
+do { \
+ rc_if_0(prob, seq) { \
+ rc_update_0(prob); \
+ action0; \
+ } else { \
+ rc_update_1(prob); \
+ action1; \
+ } \
+} while (0)
+
+
+/// Decodes one bit, updates "symbol", and runs action0 or action1 depending
+/// on the decoded bit.
+#define rc_bit(prob, action0, action1, seq) \
+ rc_bit_last(prob, \
+ symbol <<= 1; action0, \
+ symbol = (symbol << 1) + 1; action1, \
+ seq);
+
+
+/// Like rc_bit() but add "case seq:" as a prefix. This makes the unrolled
+/// loops more readable because the code isn't littered with "case"
+/// statements. On the other hand this also makes it less readable, since
+/// spotting the places where the decoder loop may be restarted is less
+/// obvious.
+#define rc_bit_case(prob, action0, action1, seq) \
+ case seq: rc_bit(prob, action0, action1, seq)
+
+
+/// Decode a bit without using a probability.
+#define rc_direct(dest, seq) \
+do { \
+ rc_normalize(seq); \
+ rc.range >>= 1; \
+ rc.code -= rc.range; \
+ rc_bound = UINT32_C(0) - (rc.code >> 31); \
+ rc.code += rc.range & rc_bound; \
+ dest = (dest << 1) + (rc_bound + 1); \
+} while (0)
+
+
+// NOTE: No macros are provided for bittree decoding. It seems to be simpler
+// to just write them open in the code.
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/rangecoder/range_encoder.h b/Utilities/cmliblzma/liblzma/rangecoder/range_encoder.h
new file mode 100644
index 000000000..e9614f252
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/rangecoder/range_encoder.h
@@ -0,0 +1,232 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file range_encoder.h
+/// \brief Range Encoder
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_RANGE_ENCODER_H
+#define LZMA_RANGE_ENCODER_H
+
+#include "range_common.h"
+#include "price.h"
+
+
+/// Maximum number of symbols that can be put pending into lzma_range_encoder
+/// structure between calls to lzma_rc_encode(). For LZMA, 52+5 is enough
+/// (match with big distance and length followed by range encoder flush).
+#define RC_SYMBOLS_MAX 58
+
+
+typedef struct {
+ uint64_t low;
+ uint64_t cache_size;
+ uint32_t range;
+ uint8_t cache;
+
+ /// Number of symbols in the tables
+ size_t count;
+
+ /// rc_encode()'s position in the tables
+ size_t pos;
+
+ /// Symbols to encode
+ enum {
+ RC_BIT_0,
+ RC_BIT_1,
+ RC_DIRECT_0,
+ RC_DIRECT_1,
+ RC_FLUSH,
+ } symbols[RC_SYMBOLS_MAX];
+
+ /// Probabilities associated with RC_BIT_0 or RC_BIT_1
+ probability *probs[RC_SYMBOLS_MAX];
+
+} lzma_range_encoder;
+
+
+static inline void
+rc_reset(lzma_range_encoder *rc)
+{
+ rc->low = 0;
+ rc->cache_size = 1;
+ rc->range = UINT32_MAX;
+ rc->cache = 0;
+ rc->count = 0;
+ rc->pos = 0;
+}
+
+
+static inline void
+rc_bit(lzma_range_encoder *rc, probability *prob, uint32_t bit)
+{
+ rc->symbols[rc->count] = bit;
+ rc->probs[rc->count] = prob;
+ ++rc->count;
+}
+
+
+static inline void
+rc_bittree(lzma_range_encoder *rc, probability *probs,
+ uint32_t bit_count, uint32_t symbol)
+{
+ uint32_t model_index = 1;
+
+ do {
+ const uint32_t bit = (symbol >> --bit_count) & 1;
+ rc_bit(rc, &probs[model_index], bit);
+ model_index = (model_index << 1) + bit;
+ } while (bit_count != 0);
+}
+
+
+static inline void
+rc_bittree_reverse(lzma_range_encoder *rc, probability *probs,
+ uint32_t bit_count, uint32_t symbol)
+{
+ uint32_t model_index = 1;
+
+ do {
+ const uint32_t bit = symbol & 1;
+ symbol >>= 1;
+ rc_bit(rc, &probs[model_index], bit);
+ model_index = (model_index << 1) + bit;
+ } while (--bit_count != 0);
+}
+
+
+static inline void
+rc_direct(lzma_range_encoder *rc,
+ uint32_t value, uint32_t bit_count)
+{
+ do {
+ rc->symbols[rc->count++]
+ = RC_DIRECT_0 + ((value >> --bit_count) & 1);
+ } while (bit_count != 0);
+}
+
+
+static inline void
+rc_flush(lzma_range_encoder *rc)
+{
+ size_t i;
+ for (i = 0; i < 5; ++i)
+ rc->symbols[rc->count++] = RC_FLUSH;
+}
+
+
+static inline bool
+rc_shift_low(lzma_range_encoder *rc,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ if ((uint32_t)(rc->low) < (uint32_t)(0xFF000000)
+ || (uint32_t)(rc->low >> 32) != 0) {
+ do {
+ if (*out_pos == out_size)
+ return true;
+
+ out[*out_pos] = rc->cache + (uint8_t)(rc->low >> 32);
+ ++*out_pos;
+ rc->cache = 0xFF;
+
+ } while (--rc->cache_size != 0);
+
+ rc->cache = (rc->low >> 24) & 0xFF;
+ }
+
+ ++rc->cache_size;
+ rc->low = (rc->low & 0x00FFFFFF) << RC_SHIFT_BITS;
+
+ return false;
+}
+
+
+static inline bool
+rc_encode(lzma_range_encoder *rc,
+ uint8_t *out, size_t *out_pos, size_t out_size)
+{
+ assert(rc->count <= RC_SYMBOLS_MAX);
+
+ while (rc->pos < rc->count) {
+ // Normalize
+ if (rc->range < RC_TOP_VALUE) {
+ if (rc_shift_low(rc, out, out_pos, out_size))
+ return true;
+
+ rc->range <<= RC_SHIFT_BITS;
+ }
+
+ // Encode a bit
+ switch (rc->symbols[rc->pos]) {
+ case RC_BIT_0: {
+ probability prob = *rc->probs[rc->pos];
+ rc->range = (rc->range >> RC_BIT_MODEL_TOTAL_BITS)
+ * prob;
+ prob += (RC_BIT_MODEL_TOTAL - prob) >> RC_MOVE_BITS;
+ *rc->probs[rc->pos] = prob;
+ break;
+ }
+
+ case RC_BIT_1: {
+ probability prob = *rc->probs[rc->pos];
+ const uint32_t bound = prob * (rc->range
+ >> RC_BIT_MODEL_TOTAL_BITS);
+ rc->low += bound;
+ rc->range -= bound;
+ prob -= prob >> RC_MOVE_BITS;
+ *rc->probs[rc->pos] = prob;
+ break;
+ }
+
+ case RC_DIRECT_0:
+ rc->range >>= 1;
+ break;
+
+ case RC_DIRECT_1:
+ rc->range >>= 1;
+ rc->low += rc->range;
+ break;
+
+ case RC_FLUSH:
+ // Prevent further normalizations.
+ rc->range = UINT32_MAX;
+
+ // Flush the last five bytes (see rc_flush()).
+ do {
+ if (rc_shift_low(rc, out, out_pos, out_size))
+ return true;
+ } while (++rc->pos < rc->count);
+
+ // Reset the range encoder so we are ready to continue
+ // encoding if we weren't finishing the stream.
+ rc_reset(rc);
+ return false;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ ++rc->pos;
+ }
+
+ rc->count = 0;
+ rc->pos = 0;
+
+ return false;
+}
+
+
+static inline uint64_t
+rc_pending(const lzma_range_encoder *rc)
+{
+ return rc->cache_size + 5 - 1;
+}
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/simple/arm.c b/Utilities/cmliblzma/liblzma/simple/arm.c
new file mode 100644
index 000000000..8dcba39fd
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/arm.c
@@ -0,0 +1,69 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file arm.c
+/// \brief Filter for ARM binaries
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+arm_code(lzma_simple *simple lzma_attribute((__unused__)),
+ uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ size_t i;
+ for (i = 0; i + 4 <= size; i += 4) {
+ if (buffer[i + 3] == 0xEB) {
+ uint32_t dest;
+ uint32_t src = (buffer[i + 2] << 16)
+ | (buffer[i + 1] << 8)
+ | (buffer[i + 0]);
+ src <<= 2;
+
+ if (is_encoder)
+ dest = now_pos + (uint32_t)(i) + 8 + src;
+ else
+ dest = src - (now_pos + (uint32_t)(i) + 8);
+
+ dest >>= 2;
+ buffer[i + 2] = (dest >> 16);
+ buffer[i + 1] = (dest >> 8);
+ buffer[i + 0] = dest;
+ }
+ }
+
+ return i;
+}
+
+
+static lzma_ret
+arm_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ return lzma_simple_coder_init(next, allocator, filters,
+ &arm_code, 0, 4, 4, is_encoder);
+}
+
+
+extern lzma_ret
+lzma_simple_arm_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return arm_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_arm_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return arm_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/armthumb.c b/Utilities/cmliblzma/liblzma/simple/armthumb.c
new file mode 100644
index 000000000..4b890a395
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/armthumb.c
@@ -0,0 +1,74 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file armthumb.c
+/// \brief Filter for ARM-Thumb binaries
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+armthumb_code(lzma_simple *simple lzma_attribute((__unused__)),
+ uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ size_t i;
+ for (i = 0; i + 4 <= size; i += 2) {
+ if ((buffer[i + 1] & 0xF8) == 0xF0
+ && (buffer[i + 3] & 0xF8) == 0xF8) {
+ uint32_t dest;
+ uint32_t src = ((buffer[i + 1] & 0x7) << 19)
+ | (buffer[i + 0] << 11)
+ | ((buffer[i + 3] & 0x7) << 8)
+ | (buffer[i + 2]);
+
+ src <<= 1;
+
+ if (is_encoder)
+ dest = now_pos + (uint32_t)(i) + 4 + src;
+ else
+ dest = src - (now_pos + (uint32_t)(i) + 4);
+
+ dest >>= 1;
+ buffer[i + 1] = 0xF0 | ((dest >> 19) & 0x7);
+ buffer[i + 0] = (dest >> 11);
+ buffer[i + 3] = 0xF8 | ((dest >> 8) & 0x7);
+ buffer[i + 2] = (dest);
+ i += 2;
+ }
+ }
+
+ return i;
+}
+
+
+static lzma_ret
+armthumb_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ return lzma_simple_coder_init(next, allocator, filters,
+ &armthumb_code, 0, 4, 2, is_encoder);
+}
+
+
+extern lzma_ret
+lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return armthumb_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return armthumb_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/ia64.c b/Utilities/cmliblzma/liblzma/simple/ia64.c
new file mode 100644
index 000000000..c537caca1
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/ia64.c
@@ -0,0 +1,116 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file ia64.c
+/// \brief Filter for IA64 (Itanium) binaries
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+ia64_code(lzma_simple *simple lzma_attribute((__unused__)),
+ uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ static const uint32_t BRANCH_TABLE[32] = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+ };
+
+ size_t i;
+ for (i = 0; i + 16 <= size; i += 16) {
+ size_t slot;
+
+ const uint32_t instr_template = buffer[i] & 0x1F;
+ const uint32_t mask = BRANCH_TABLE[instr_template];
+ uint32_t bit_pos = 5;
+
+ for (slot = 0; slot < 3; ++slot, bit_pos += 41) {
+ const size_t byte_pos = (bit_pos >> 3);
+ const uint32_t bit_res = bit_pos & 0x7;
+ uint64_t instruction = 0;
+ uint64_t inst_norm;
+ size_t j;
+
+ if (((mask >> slot) & 1) == 0)
+ continue;
+
+ for (j = 0; j < 6; ++j)
+ instruction += (uint64_t)(
+ buffer[i + j + byte_pos])
+ << (8 * j);
+
+ inst_norm = instruction >> bit_res;
+
+ if (((inst_norm >> 37) & 0xF) == 0x5
+ && ((inst_norm >> 9) & 0x7) == 0
+ /* && (inst_norm & 0x3F)== 0 */
+ ) {
+ uint32_t dest;
+ size_t j;
+
+ uint32_t src = (uint32_t)(
+ (inst_norm >> 13) & 0xFFFFF);
+ src |= ((inst_norm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (is_encoder)
+ dest = now_pos + (uint32_t)(i) + src;
+ else
+ dest = src - (now_pos + (uint32_t)(i));
+
+ dest >>= 4;
+
+ inst_norm &= ~((uint64_t)(0x8FFFFF) << 13);
+ inst_norm |= (uint64_t)(dest & 0xFFFFF) << 13;
+ inst_norm |= (uint64_t)(dest & 0x100000)
+ << (36 - 20);
+
+ instruction &= (1 << bit_res) - 1;
+ instruction |= (inst_norm << bit_res);
+
+ for (j = 0; j < 6; j++)
+ buffer[i + j + byte_pos] = (uint8_t)(
+ instruction
+ >> (8 * j));
+ }
+ }
+ }
+
+ return i;
+}
+
+
+static lzma_ret
+ia64_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ return lzma_simple_coder_init(next, allocator, filters,
+ &ia64_code, 0, 16, 16, is_encoder);
+}
+
+
+extern lzma_ret
+lzma_simple_ia64_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return ia64_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_ia64_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return ia64_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/powerpc.c b/Utilities/cmliblzma/liblzma/simple/powerpc.c
new file mode 100644
index 000000000..6f8351176
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/powerpc.c
@@ -0,0 +1,73 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file powerpc.c
+/// \brief Filter for PowerPC (big endian) binaries
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+powerpc_code(lzma_simple *simple lzma_attribute((__unused__)),
+ uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ size_t i;
+ for (i = 0; i + 4 <= size; i += 4) {
+ // PowerPC branch 6(48) 24(Offset) 1(Abs) 1(Link)
+ if ((buffer[i] >> 2) == 0x12
+ && ((buffer[i + 3] & 3) == 1)) {
+
+ const uint32_t src = ((buffer[i + 0] & 3) << 24)
+ | (buffer[i + 1] << 16)
+ | (buffer[i + 2] << 8)
+ | (buffer[i + 3] & (~3));
+
+ uint32_t dest;
+ if (is_encoder)
+ dest = now_pos + (uint32_t)(i) + src;
+ else
+ dest = src - (now_pos + (uint32_t)(i));
+
+ buffer[i + 0] = 0x48 | ((dest >> 24) & 0x03);
+ buffer[i + 1] = (dest >> 16);
+ buffer[i + 2] = (dest >> 8);
+ buffer[i + 3] &= 0x03;
+ buffer[i + 3] |= dest;
+ }
+ }
+
+ return i;
+}
+
+
+static lzma_ret
+powerpc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ return lzma_simple_coder_init(next, allocator, filters,
+ &powerpc_code, 0, 4, 4, is_encoder);
+}
+
+
+extern lzma_ret
+lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return powerpc_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return powerpc_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_coder.c b/Utilities/cmliblzma/liblzma/simple/simple_coder.c
new file mode 100644
index 000000000..f3bbdd7a7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_coder.c
@@ -0,0 +1,283 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_coder.c
+/// \brief Wrapper for simple filters
+///
+/// Simple filters don't change the size of the data i.e. number of bytes
+/// in equals the number of bytes out.
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+/// Copied or encodes/decodes more data to out[].
+static lzma_ret
+copy_or_code(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ assert(!coder->end_was_reached);
+
+ if (coder->next.code == NULL) {
+ lzma_bufcpy(in, in_pos, in_size, out, out_pos, out_size);
+
+ // Check if end of stream was reached.
+ if (coder->is_encoder && action == LZMA_FINISH
+ && *in_pos == in_size)
+ coder->end_was_reached = true;
+
+ } else {
+ // Call the next coder in the chain to provide us some data.
+ const lzma_ret ret = coder->next.code(
+ coder->next.coder, allocator,
+ in, in_pos, in_size,
+ out, out_pos, out_size, action);
+
+ if (ret == LZMA_STREAM_END) {
+ assert(!coder->is_encoder
+ || action == LZMA_FINISH);
+ coder->end_was_reached = true;
+
+ } else if (ret != LZMA_OK) {
+ return ret;
+ }
+ }
+
+ return LZMA_OK;
+}
+
+
+static size_t
+call_filter(lzma_coder *coder, uint8_t *buffer, size_t size)
+{
+ const size_t filtered = coder->filter(coder->simple,
+ coder->now_pos, coder->is_encoder,
+ buffer, size);
+ coder->now_pos += filtered;
+ return filtered;
+}
+
+
+static lzma_ret
+simple_code(lzma_coder *coder, lzma_allocator *allocator,
+ const uint8_t *LZMA_RESTRICT in, size_t *LZMA_RESTRICT in_pos,
+ size_t in_size, uint8_t *LZMA_RESTRICT out,
+ size_t *LZMA_RESTRICT out_pos, size_t out_size, lzma_action action)
+{
+ size_t out_avail;
+ size_t buf_avail;
+
+ // TODO: Add partial support for LZMA_SYNC_FLUSH. We can support it
+ // in cases when the filter is able to filter everything. With most
+ // simple filters it can be done at offset that is a multiple of 2,
+ // 4, or 16. With x86 filter, it needs good luck, and thus cannot
+ // be made to work predictably.
+ if (action == LZMA_SYNC_FLUSH)
+ return LZMA_OPTIONS_ERROR;
+
+ // Flush already filtered data from coder->buffer[] to out[].
+ if (coder->pos < coder->filtered) {
+ lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
+ out, out_pos, out_size);
+
+ // If we couldn't flush all the filtered data, return to
+ // application immediately.
+ if (coder->pos < coder->filtered)
+ return LZMA_OK;
+
+ if (coder->end_was_reached) {
+ assert(coder->filtered == coder->size);
+ return LZMA_STREAM_END;
+ }
+ }
+
+ // If we get here, there is no filtered data left in the buffer.
+ coder->filtered = 0;
+
+ assert(!coder->end_was_reached);
+
+ // If there is more output space left than there is unfiltered data
+ // in coder->buffer[], flush coder->buffer[] to out[], and copy/code
+ // more data to out[] hopefully filling it completely. Then filter
+ // the data in out[]. This step is where most of the data gets
+ // filtered if the buffer sizes used by the application are reasonable.
+ out_avail = out_size - *out_pos;
+ buf_avail = coder->size - coder->pos;
+ if (out_avail > buf_avail || buf_avail == 0) {
+ size_t size;
+ size_t filtered;
+ size_t unfiltered;
+
+ // Store the old position so that we know from which byte
+ // to start filtering.
+ const size_t out_start = *out_pos;
+
+ // Flush data from coder->buffer[] to out[], but don't reset
+ // coder->pos and coder->size yet. This way the coder can be
+ // restarted if the next filter in the chain returns e.g.
+ // LZMA_MEM_ERROR.
+ memcpy(out + *out_pos, coder->buffer + coder->pos, buf_avail);
+ *out_pos += buf_avail;
+
+ // Copy/Encode/Decode more data to out[].
+ {
+ const lzma_ret ret = copy_or_code(coder, allocator,
+ in, in_pos, in_size,
+ out, out_pos, out_size, action);
+ assert(ret != LZMA_STREAM_END);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ // Filter out[].
+ size = *out_pos - out_start;
+ filtered = call_filter(coder, out + out_start, size);
+
+ unfiltered = size - filtered;
+ assert(unfiltered <= coder->allocated / 2);
+
+ // Now we can update coder->pos and coder->size, because
+ // the next coder in the chain (if any) was successful.
+ coder->pos = 0;
+ coder->size = unfiltered;
+
+ if (coder->end_was_reached) {
+ // The last byte has been copied to out[] already.
+ // They are left as is.
+ coder->size = 0;
+
+ } else if (unfiltered > 0) {
+ // There is unfiltered data left in out[]. Copy it to
+ // coder->buffer[] and rewind *out_pos appropriately.
+ *out_pos -= unfiltered;
+ memcpy(coder->buffer, out + *out_pos, unfiltered);
+ }
+ } else if (coder->pos > 0) {
+ memmove(coder->buffer, coder->buffer + coder->pos, buf_avail);
+ coder->size -= coder->pos;
+ coder->pos = 0;
+ }
+
+ assert(coder->pos == 0);
+
+ // If coder->buffer[] isn't empty, try to fill it by copying/decoding
+ // more data. Then filter coder->buffer[] and copy the successfully
+ // filtered data to out[]. It is probable, that some filtered and
+ // unfiltered data will be left to coder->buffer[].
+ if (coder->size > 0) {
+ {
+ const lzma_ret ret = copy_or_code(coder, allocator,
+ in, in_pos, in_size,
+ coder->buffer, &coder->size,
+ coder->allocated, action);
+ assert(ret != LZMA_STREAM_END);
+ if (ret != LZMA_OK)
+ return ret;
+ }
+
+ coder->filtered = call_filter(
+ coder, coder->buffer, coder->size);
+
+ // Everything is considered to be filtered if coder->buffer[]
+ // contains the last bytes of the data.
+ if (coder->end_was_reached)
+ coder->filtered = coder->size;
+
+ // Flush as much as possible.
+ lzma_bufcpy(coder->buffer, &coder->pos, coder->filtered,
+ out, out_pos, out_size);
+ }
+
+ // Check if we got everything done.
+ if (coder->end_was_reached && coder->pos == coder->size)
+ return LZMA_STREAM_END;
+
+ return LZMA_OK;
+}
+
+
+static void
+simple_coder_end(lzma_coder *coder, lzma_allocator *allocator)
+{
+ lzma_next_end(&coder->next, allocator);
+ lzma_free(coder->simple, allocator);
+ lzma_free(coder, allocator);
+ return;
+}
+
+
+static lzma_ret
+simple_coder_update(lzma_coder *coder, lzma_allocator *allocator,
+ const lzma_filter *filters_null lzma_attribute((__unused__)),
+ const lzma_filter *reversed_filters)
+{
+ // No update support, just call the next filter in the chain.
+ return lzma_next_filter_update(
+ &coder->next, allocator, reversed_filters + 1);
+}
+
+
+extern lzma_ret
+lzma_simple_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters,
+ size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
+ bool is_encoder, uint8_t *buffer, size_t size),
+ size_t simple_size, size_t unfiltered_max,
+ uint32_t alignment, bool is_encoder)
+{
+ // Allocate memory for the lzma_coder structure if needed.
+ if (next->coder == NULL) {
+ // Here we allocate space also for the temporary buffer. We
+ // need twice the size of unfiltered_max, because then it
+ // is always possible to filter at least unfiltered_max bytes
+ // more data in coder->buffer[] if it can be filled completely.
+ next->coder = lzma_alloc(sizeof(lzma_coder)
+ + 2 * unfiltered_max, allocator);
+ if (next->coder == NULL)
+ return LZMA_MEM_ERROR;
+
+ next->code = &simple_code;
+ next->end = &simple_coder_end;
+ next->update = &simple_coder_update;
+
+ next->coder->next = LZMA_NEXT_CODER_INIT;
+ next->coder->filter = filter;
+ next->coder->allocated = 2 * unfiltered_max;
+
+ // Allocate memory for filter-specific data structure.
+ if (simple_size > 0) {
+ next->coder->simple = lzma_alloc(
+ simple_size, allocator);
+ if (next->coder->simple == NULL)
+ return LZMA_MEM_ERROR;
+ } else {
+ next->coder->simple = NULL;
+ }
+ }
+
+ if (filters[0].options != NULL) {
+ const lzma_options_bcj *simple = filters[0].options;
+ next->coder->now_pos = simple->start_offset;
+ if (next->coder->now_pos & (alignment - 1))
+ return LZMA_OPTIONS_ERROR;
+ } else {
+ next->coder->now_pos = 0;
+ }
+
+ // Reset variables.
+ next->coder->is_encoder = is_encoder;
+ next->coder->end_was_reached = false;
+ next->coder->pos = 0;
+ next->coder->filtered = 0;
+ next->coder->size = 0;
+
+ return lzma_next_filter_init(
+ &next->coder->next, allocator, filters + 1);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_coder.h b/Utilities/cmliblzma/liblzma/simple/simple_coder.h
new file mode 100644
index 000000000..0952fad33
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_coder.h
@@ -0,0 +1,60 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_coder.h
+/// \brief Wrapper for simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_CODER_H
+#define LZMA_SIMPLE_CODER_H
+
+#include "common.h"
+
+
+extern lzma_ret lzma_simple_x86_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_x86_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_powerpc_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_powerpc_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_ia64_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_ia64_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_arm_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_arm_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_armthumb_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_armthumb_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+
+extern lzma_ret lzma_simple_sparc_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+extern lzma_ret lzma_simple_sparc_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_decoder.c b/Utilities/cmliblzma/liblzma/simple/simple_decoder.c
new file mode 100644
index 000000000..034e158ff
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_decoder.c
@@ -0,0 +1,41 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_decoder.c
+/// \brief Properties decoder for simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_decoder.h"
+
+
+extern lzma_ret
+lzma_simple_props_decode(void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size)
+{
+ lzma_options_bcj *opt;
+
+ if (props_size == 0)
+ return LZMA_OK;
+
+ if (props_size != 4)
+ return LZMA_OPTIONS_ERROR;
+
+ opt = lzma_alloc(sizeof(lzma_options_bcj), allocator);
+ if (opt == NULL)
+ return LZMA_MEM_ERROR;
+
+ opt->start_offset = unaligned_read32le(props);
+
+ // Don't leave an options structure allocated if start_offset is zero.
+ if (opt->start_offset == 0)
+ lzma_free(opt, allocator);
+ else
+ *options = opt;
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_decoder.h b/Utilities/cmliblzma/liblzma/simple/simple_decoder.h
new file mode 100644
index 000000000..b8bf590f7
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_decoder.h
@@ -0,0 +1,22 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_decoder.h
+/// \brief Properties decoder for simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_DECODER_H
+#define LZMA_SIMPLE_DECODER_H
+
+#include "simple_coder.h"
+
+extern lzma_ret lzma_simple_props_decode(
+ void **options, lzma_allocator *allocator,
+ const uint8_t *props, size_t props_size);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_encoder.c b/Utilities/cmliblzma/liblzma/simple/simple_encoder.c
new file mode 100644
index 000000000..8aa463bed
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_encoder.c
@@ -0,0 +1,38 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_encoder.c
+/// \brief Properties encoder for simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_encoder.h"
+
+
+extern lzma_ret
+lzma_simple_props_size(uint32_t *size, const void *options)
+{
+ const lzma_options_bcj *const opt = options;
+ *size = (opt == NULL || opt->start_offset == 0) ? 0 : 4;
+ return LZMA_OK;
+}
+
+
+extern lzma_ret
+lzma_simple_props_encode(const void *options, uint8_t *out)
+{
+ const lzma_options_bcj *const opt = options;
+
+ // The default start offset is zero, so we don't need to store any
+ // options unless the start offset is non-zero.
+ if (opt == NULL || opt->start_offset == 0)
+ return LZMA_OK;
+
+ unaligned_write32le(out, opt->start_offset);
+
+ return LZMA_OK;
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_encoder.h b/Utilities/cmliblzma/liblzma/simple/simple_encoder.h
new file mode 100644
index 000000000..1cee4823a
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_encoder.h
@@ -0,0 +1,23 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_encoder.c
+/// \brief Properties encoder for simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_ENCODER_H
+#define LZMA_SIMPLE_ENCODER_H
+
+#include "simple_coder.h"
+
+
+extern lzma_ret lzma_simple_props_size(uint32_t *size, const void *options);
+
+extern lzma_ret lzma_simple_props_encode(const void *options, uint8_t *out);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/simple/simple_private.h b/Utilities/cmliblzma/liblzma/simple/simple_private.h
new file mode 100644
index 000000000..fcf9f7c19
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/simple_private.h
@@ -0,0 +1,75 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file simple_private.h
+/// \brief Private definitions for so called simple filters
+//
+// Author: Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef LZMA_SIMPLE_PRIVATE_H
+#define LZMA_SIMPLE_PRIVATE_H
+
+#include "simple_coder.h"
+
+
+typedef struct lzma_simple_s lzma_simple;
+
+struct lzma_coder_s {
+ /// Next filter in the chain
+ lzma_next_coder next;
+
+ /// True if the next coder in the chain has returned LZMA_STREAM_END.
+ bool end_was_reached;
+
+ /// True if filter() should encode the data; false to decode.
+ /// Currently all simple filters use the same function for encoding
+ /// and decoding, because the difference between encoders and decoders
+ /// is very small.
+ bool is_encoder;
+
+ /// Pointer to filter-specific function, which does
+ /// the actual filtering.
+ size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
+ bool is_encoder, uint8_t *buffer, size_t size);
+
+ /// Pointer to filter-specific data, or NULL if filter doesn't need
+ /// any extra data.
+ lzma_simple *simple;
+
+ /// The lowest 32 bits of the current position in the data. Most
+ /// filters need this to do conversions between absolute and relative
+ /// addresses.
+ uint32_t now_pos;
+
+ /// Size of the memory allocated for the buffer.
+ size_t allocated;
+
+ /// Flushing position in the temporary buffer. buffer[pos] is the
+ /// next byte to be copied to out[].
+ size_t pos;
+
+ /// buffer[filtered] is the first unfiltered byte. When pos is smaller
+ /// than filtered, there is unflushed filtered data in the buffer.
+ size_t filtered;
+
+ /// Total number of bytes (both filtered and unfiltered) currently
+ /// in the temporary buffer.
+ size_t size;
+
+ /// Temporary buffer
+ uint8_t buffer[];
+};
+
+
+extern lzma_ret lzma_simple_coder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters,
+ size_t (*filter)(lzma_simple *simple, uint32_t now_pos,
+ bool is_encoder, uint8_t *buffer, size_t size),
+ size_t simple_size, size_t unfiltered_max,
+ uint32_t alignment, bool is_encoder);
+
+#endif
diff --git a/Utilities/cmliblzma/liblzma/simple/sparc.c b/Utilities/cmliblzma/liblzma/simple/sparc.c
new file mode 100644
index 000000000..0ddd2ac9d
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/sparc.c
@@ -0,0 +1,82 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file sparc.c
+/// \brief Filter for SPARC binaries
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+static size_t
+sparc_code(lzma_simple *simple lzma_attribute((__unused__)),
+ uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ size_t i;
+ for (i = 0; i + 4 <= size; i += 4) {
+
+ if ((buffer[i] == 0x40 && (buffer[i + 1] & 0xC0) == 0x00)
+ || (buffer[i] == 0x7F
+ && (buffer[i + 1] & 0xC0) == 0xC0)) {
+
+ uint32_t dest;
+
+ uint32_t src = ((uint32_t)buffer[i + 0] << 24)
+ | ((uint32_t)buffer[i + 1] << 16)
+ | ((uint32_t)buffer[i + 2] << 8)
+ | ((uint32_t)buffer[i + 3]);
+
+ src <<= 2;
+
+ if (is_encoder)
+ dest = now_pos + (uint32_t)(i) + src;
+ else
+ dest = src - (now_pos + (uint32_t)(i));
+
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF)
+ | (dest & 0x3FFFFF)
+ | 0x40000000;
+
+ buffer[i + 0] = (uint8_t)(dest >> 24);
+ buffer[i + 1] = (uint8_t)(dest >> 16);
+ buffer[i + 2] = (uint8_t)(dest >> 8);
+ buffer[i + 3] = (uint8_t)(dest);
+ }
+ }
+
+ return i;
+}
+
+
+static lzma_ret
+sparc_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ return lzma_simple_coder_init(next, allocator, filters,
+ &sparc_code, 0, 4, 4, is_encoder);
+}
+
+
+extern lzma_ret
+lzma_simple_sparc_encoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return sparc_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_sparc_decoder_init(lzma_next_coder *next,
+ lzma_allocator *allocator, const lzma_filter_info *filters)
+{
+ return sparc_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmliblzma/liblzma/simple/x86.c b/Utilities/cmliblzma/liblzma/simple/x86.c
new file mode 100644
index 000000000..95858e51e
--- /dev/null
+++ b/Utilities/cmliblzma/liblzma/simple/x86.c
@@ -0,0 +1,161 @@
+///////////////////////////////////////////////////////////////////////////////
+//
+/// \file x86.c
+/// \brief Filter for x86 binaries (BCJ filter)
+///
+// Authors: Igor Pavlov
+// Lasse Collin
+//
+// This file has been put into the public domain.
+// You can do whatever you want with this file.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "simple_private.h"
+
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+
+struct lzma_simple_s {
+ uint32_t prev_mask;
+ uint32_t prev_pos;
+};
+
+
+static size_t
+x86_code(lzma_simple *simple, uint32_t now_pos, bool is_encoder,
+ uint8_t *buffer, size_t size)
+{
+ static const bool MASK_TO_ALLOWED_STATUS[8]
+ = { true, true, true, false, true, false, false, false };
+
+ static const uint32_t MASK_TO_BIT_NUMBER[8]
+ = { 0, 1, 2, 2, 3, 3, 3, 3 };
+
+ uint32_t prev_mask = simple->prev_mask;
+ uint32_t prev_pos = simple->prev_pos;
+
+ size_t limit;
+ size_t buffer_pos;
+
+ if (size < 5)
+ return 0;
+
+ if (now_pos - prev_pos > 5)
+ prev_pos = now_pos - 5;
+
+ limit = size - 5;
+ buffer_pos = 0;
+
+ while (buffer_pos <= limit) {
+ uint32_t offset;
+ uint32_t i;
+
+ uint8_t b = buffer[buffer_pos];
+ if (b != 0xE8 && b != 0xE9) {
+ ++buffer_pos;
+ continue;
+ }
+
+ offset = now_pos + (uint32_t)(buffer_pos)
+ - prev_pos;
+ prev_pos = now_pos + (uint32_t)(buffer_pos);
+
+ if (offset > 5) {
+ prev_mask = 0;
+ } else {
+ for (i = 0; i < offset; ++i) {
+ prev_mask &= 0x77;
+ prev_mask <<= 1;
+ }
+ }
+
+ b = buffer[buffer_pos + 4];
+
+ if (Test86MSByte(b)
+ && MASK_TO_ALLOWED_STATUS[(prev_mask >> 1) & 0x7]
+ && (prev_mask >> 1) < 0x10) {
+
+ uint32_t src = ((uint32_t)(b) << 24)
+ | ((uint32_t)(buffer[buffer_pos + 3]) << 16)
+ | ((uint32_t)(buffer[buffer_pos + 2]) << 8)
+ | (buffer[buffer_pos + 1]);
+
+ uint32_t dest;
+ while (true) {
+ uint32_t i;
+
+ if (is_encoder)
+ dest = src + (now_pos + (uint32_t)(
+ buffer_pos) + 5);
+ else
+ dest = src - (now_pos + (uint32_t)(
+ buffer_pos) + 5);
+
+ if (prev_mask == 0)
+ break;
+
+ i = MASK_TO_BIT_NUMBER[prev_mask >> 1];
+
+ b = (uint8_t)(dest >> (24 - i * 8));
+
+ if (!Test86MSByte(b))
+ break;
+
+ src = dest ^ ((1u << (32 - i * 8)) - 1);
+ }
+
+ buffer[buffer_pos + 4]
+ = (uint8_t)(~(((dest >> 24) & 1) - 1));
+ buffer[buffer_pos + 3] = (uint8_t)(dest >> 16);
+ buffer[buffer_pos + 2] = (uint8_t)(dest >> 8);
+ buffer[buffer_pos + 1] = (uint8_t)(dest);
+ buffer_pos += 5;
+ prev_mask = 0;
+
+ } else {
+ ++buffer_pos;
+ prev_mask |= 1;
+ if (Test86MSByte(b))
+ prev_mask |= 0x10;
+ }
+ }
+
+ simple->prev_mask = prev_mask;
+ simple->prev_pos = prev_pos;
+
+ return buffer_pos;
+}
+
+
+static lzma_ret
+x86_coder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters, bool is_encoder)
+{
+ const lzma_ret ret = lzma_simple_coder_init(next, allocator, filters,
+ &x86_code, sizeof(lzma_simple), 5, 1, is_encoder);
+
+ if (ret == LZMA_OK) {
+ next->coder->simple->prev_mask = 0;
+ next->coder->simple->prev_pos = (uint32_t)(-5);
+ }
+
+ return ret;
+}
+
+
+extern lzma_ret
+lzma_simple_x86_encoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return x86_coder_init(next, allocator, filters, true);
+}
+
+
+extern lzma_ret
+lzma_simple_x86_decoder_init(lzma_next_coder *next, lzma_allocator *allocator,
+ const lzma_filter_info *filters)
+{
+ return x86_coder_init(next, allocator, filters, false);
+}
diff --git a/Utilities/cmlibrhash/.gitattributes b/Utilities/cmlibrhash/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmlibrhash/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmlibrhash/CMakeLists.txt b/Utilities/cmlibrhash/CMakeLists.txt
new file mode 100644
index 000000000..aa280554c
--- /dev/null
+++ b/Utilities/cmlibrhash/CMakeLists.txt
@@ -0,0 +1,40 @@
+project(librhash C)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+set(librhash_sources
+ librhash/algorithms.c
+ librhash/algorithms.h
+ librhash/byte_order.c
+ librhash/byte_order.h
+ librhash/hex.c
+ librhash/hex.h
+ librhash/md5.c
+ librhash/md5.h
+ librhash/rhash.c
+ librhash/rhash.h
+ librhash/sha1.c
+ librhash/sha1.h
+ librhash/sha256.c
+ librhash/sha256.h
+ librhash/sha3.c
+ librhash/sha3.h
+ librhash/sha512.c
+ librhash/sha512.h
+ librhash/ustd.h
+ librhash/util.h
+ )
+
+include_directories(
+ ${KWSYS_HEADER_ROOT}
+ )
+
+add_library(cmlibrhash ${librhash_sources})
+
+install(FILES COPYING README DESTINATION ${CMAKE_DOC_DIR}/cmlibrhash)
diff --git a/Utilities/cmlibrhash/COPYING b/Utilities/cmlibrhash/COPYING
new file mode 100644
index 000000000..bf65ee1af
--- /dev/null
+++ b/Utilities/cmlibrhash/COPYING
@@ -0,0 +1,15 @@
+
+ RHash License
+
+Copyright (c) 2005-2014 Aleksey Kravchenko <rhash.admin@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so.
+
+The Software is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. Use this program at your own risk!
diff --git a/Utilities/cmlibrhash/README b/Utilities/cmlibrhash/README
new file mode 100644
index 000000000..4ea492fd2
--- /dev/null
+++ b/Utilities/cmlibrhash/README
@@ -0,0 +1,7 @@
+ === Notes on RHash License ===
+
+The RHash program and LibRHash library are distributed under RHash License,
+see the COPYING file for details. In particular, the program, the library
+and source code can be used free of charge under the MIT, BSD, GPL,
+commercial or freeware license without additional restrictions. In the case
+the OSI-approved license is required the MIT license should be used.
diff --git a/Utilities/cmlibrhash/librhash/algorithms.c b/Utilities/cmlibrhash/librhash/algorithms.c
new file mode 100644
index 000000000..fc0169058
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/algorithms.c
@@ -0,0 +1,220 @@
+/* algorithms.c - the algorithms supported by the rhash library
+ *
+ * Copyright: 2011-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "byte_order.h"
+#include "rhash.h"
+#include "algorithms.h"
+
+/* header files of all supported hash sums */
+#if 0
+#include "aich.h"
+#include "crc32.h"
+#include "ed2k.h"
+#include "edonr.h"
+#include "gost.h"
+#include "has160.h"
+#include "md4.h"
+#endif
+#include "md5.h"
+#if 0
+#include "ripemd-160.h"
+#include "snefru.h"
+#endif
+#include "sha1.h"
+#include "sha256.h"
+#include "sha512.h"
+#include "sha3.h"
+#if 0
+#include "tiger.h"
+#include "tth.h"
+#include "whirlpool.h"
+#endif
+
+#ifdef USE_OPENSSL
+/* note: BTIH and AICH depends on the used SHA1 algorithm */
+# define NEED_OPENSSL_INIT (RHASH_MD4 | RHASH_MD5 | \
+ RHASH_SHA1 | RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | RHASH_SHA512 | \
+ RHASH_BTIH | RHASH_AICH | RHASH_RIPEMD160 | RHASH_WHIRLPOOL)
+#else
+# define NEED_OPENSSL_INIT 0
+#endif /* USE_OPENSSL */
+#ifdef GENERATE_GOST_LOOKUP_TABLE
+# define NEED_GOST_INIT (RHASH_GOST | RHASH_GOST_CRYPTOPRO)
+#else
+# define NEED_GOST_INIT 0
+#endif /* GENERATE_GOST_LOOKUP_TABLE */
+#ifdef GENERATE_CRC32_TABLE
+# define NEED_CRC32_INIT RHASH_CRC32
+#else
+# define NEED_CRC32_INIT 0
+#endif /* GENERATE_CRC32_TABLE */
+
+#define RHASH_NEED_INIT_ALG (NEED_CRC32_INIT | NEED_GOST_INIT | NEED_OPENSSL_INIT)
+unsigned rhash_uninitialized_algorithms = RHASH_NEED_INIT_ALG;
+
+rhash_hash_info* rhash_info_table = rhash_hash_info_default;
+int rhash_info_size = RHASH_HASH_COUNT;
+
+#if 0
+static void rhash_crc32_init(uint32_t* crc32);
+static void rhash_crc32_update(uint32_t* crc32, const unsigned char* msg, size_t size);
+static void rhash_crc32_final(uint32_t* crc32, unsigned char* result);
+#endif
+
+#if 0
+rhash_info info_crc32 = { RHASH_CRC32, F_BE32, 4, "CRC32", "crc32" };
+rhash_info info_md4 = { RHASH_MD4, F_LE32, 16, "MD4", "md4" };
+#endif
+rhash_info info_md5 = { RHASH_MD5, F_LE32, 16, "MD5", "md5" };
+rhash_info info_sha1 = { RHASH_SHA1, F_BE32, 20, "SHA1", "sha1" };
+#if 0
+rhash_info info_tiger = { RHASH_TIGER, F_LE64, 24, "TIGER", "tiger" };
+rhash_info info_tth = { RHASH_TTH, F_BS32, 24, "TTH", "tree:tiger" };
+rhash_info info_btih = { RHASH_BTIH, 0, 20, "BTIH", "btih" };
+rhash_info info_ed2k = { RHASH_ED2K, F_LE32, 16, "ED2K", "ed2k" };
+rhash_info info_aich = { RHASH_AICH, F_BS32, 20, "AICH", "aich" };
+rhash_info info_whirlpool = { RHASH_WHIRLPOOL, F_BE64, 64, "WHIRLPOOL", "whirlpool" };
+rhash_info info_rmd160 = { RHASH_RIPEMD160, F_LE32, 20, "RIPEMD-160", "ripemd160" };
+rhash_info info_gost = { RHASH_GOST, F_LE32, 32, "GOST", "gost" };
+rhash_info info_gostpro = { RHASH_GOST_CRYPTOPRO, F_LE32, 32, "GOST-CRYPTOPRO", "gost-cryptopro" };
+rhash_info info_has160 = { RHASH_HAS160, F_LE32, 20, "HAS-160", "has160" };
+rhash_info info_snf128 = { RHASH_SNEFRU128, F_BE32, 16, "SNEFRU-128", "snefru128" };
+rhash_info info_snf256 = { RHASH_SNEFRU256, F_BE32, 32, "SNEFRU-256", "snefru256" };
+#endif
+rhash_info info_sha224 = { RHASH_SHA224, F_BE32, 28, "SHA-224", "sha224" };
+rhash_info info_sha256 = { RHASH_SHA256, F_BE32, 32, "SHA-256", "sha256" };
+rhash_info info_sha384 = { RHASH_SHA384, F_BE64, 48, "SHA-384", "sha384" };
+rhash_info info_sha512 = { RHASH_SHA512, F_BE64, 64, "SHA-512", "sha512" };
+#if 0
+rhash_info info_edr256 = { RHASH_EDONR256, F_LE32, 32, "EDON-R256", "edon-r256" };
+rhash_info info_edr512 = { RHASH_EDONR512, F_LE64, 64, "EDON-R512", "edon-r512" };
+#endif
+rhash_info info_sha3_224 = { RHASH_SHA3_224, F_LE64, 28, "SHA3-224", "sha3-224" };
+rhash_info info_sha3_256 = { RHASH_SHA3_256, F_LE64, 32, "SHA3-256", "sha3-256" };
+rhash_info info_sha3_384 = { RHASH_SHA3_384, F_LE64, 48, "SHA3-384", "sha3-384" };
+rhash_info info_sha3_512 = { RHASH_SHA3_512, F_LE64, 64, "SHA3-512", "sha3-512" };
+
+/* some helper macros */
+#define dgshft(name) (((char*)&((name##_ctx*)0)->hash) - (char*)0)
+#define dgshft2(name, field) (((char*)&((name##_ctx*)0)->field) - (char*)0)
+#define ini(name) ((pinit_t)(name##_init))
+#define upd(name) ((pupdate_t)(name##_update))
+#define fin(name) ((pfinal_t)(name##_final))
+#define iuf(name) ini(name), upd(name), fin(name)
+#define diuf(name) dgshft(name), ini(name), upd(name), fin(name)
+
+/* information about all hashes */
+rhash_hash_info rhash_hash_info_default[RHASH_HASH_COUNT] =
+{
+#if 0
+ { &info_crc32, sizeof(uint32_t), 0, iuf(rhash_crc32), 0 }, /* 32 bit */
+ { &info_md4, sizeof(md4_ctx), dgshft(md4), iuf(rhash_md4), 0 }, /* 128 bit */
+#endif
+ { &info_md5, sizeof(md5_ctx), dgshft(md5), iuf(rhash_md5), 0 }, /* 128 bit */
+ { &info_sha1, sizeof(sha1_ctx), dgshft(sha1), iuf(rhash_sha1), 0 }, /* 160 bit */
+#if 0
+ { &info_tiger, sizeof(tiger_ctx), dgshft(tiger), iuf(rhash_tiger), 0 }, /* 192 bit */
+ { &info_tth, sizeof(tth_ctx), dgshft2(tth, tiger.hash), iuf(rhash_tth), 0 }, /* 192 bit */
+ { &info_ed2k, sizeof(ed2k_ctx), dgshft2(ed2k, md4_context_inner.hash), iuf(rhash_ed2k), 0 }, /* 128 bit */
+ { &info_aich, sizeof(aich_ctx), dgshft2(aich, sha1_context.hash), iuf(rhash_aich), (pcleanup_t)rhash_aich_cleanup }, /* 160 bit */
+ { &info_whirlpool, sizeof(whirlpool_ctx), dgshft(whirlpool), iuf(rhash_whirlpool), 0 }, /* 512 bit */
+ { &info_rmd160, sizeof(ripemd160_ctx), dgshft(ripemd160), iuf(rhash_ripemd160), 0 }, /* 160 bit */
+ { &info_gost, sizeof(gost_ctx), dgshft(gost), iuf(rhash_gost), 0 }, /* 256 bit */
+ { &info_gostpro, sizeof(gost_ctx), dgshft(gost), ini(rhash_gost_cryptopro), upd(rhash_gost), fin(rhash_gost), 0 }, /* 256 bit */
+ { &info_has160, sizeof(has160_ctx), dgshft(has160), iuf(rhash_has160), 0 }, /* 160 bit */
+ { &info_snf128, sizeof(snefru_ctx), dgshft(snefru), ini(rhash_snefru128), upd(rhash_snefru), fin(rhash_snefru), 0 }, /* 128 bit */
+ { &info_snf256, sizeof(snefru_ctx), dgshft(snefru), ini(rhash_snefru256), upd(rhash_snefru), fin(rhash_snefru), 0 }, /* 256 bit */
+#endif
+ { &info_sha224, sizeof(sha256_ctx), dgshft(sha256), ini(rhash_sha224), upd(rhash_sha256), fin(rhash_sha256), 0 }, /* 224 bit */
+ { &info_sha256, sizeof(sha256_ctx), dgshft(sha256), iuf(rhash_sha256), 0 }, /* 256 bit */
+ { &info_sha384, sizeof(sha512_ctx), dgshft(sha512), ini(rhash_sha384), upd(rhash_sha512), fin(rhash_sha512), 0 }, /* 384 bit */
+ { &info_sha512, sizeof(sha512_ctx), dgshft(sha512), iuf(rhash_sha512), 0 }, /* 512 bit */
+#if 0
+ { &info_edr256, sizeof(edonr_ctx), dgshft2(edonr, u.data256.hash) + 32, iuf(rhash_edonr256), 0 }, /* 256 bit */
+ { &info_edr512, sizeof(edonr_ctx), dgshft2(edonr, u.data512.hash) + 64, iuf(rhash_edonr512), 0 }, /* 512 bit */
+#endif
+ { &info_sha3_224, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_224), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 224 bit */
+ { &info_sha3_256, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_256), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 256 bit */
+ { &info_sha3_384, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_384), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 384 bit */
+ { &info_sha3_512, sizeof(sha3_ctx), dgshft(sha3), ini(rhash_sha3_512), upd(rhash_sha3), fin(rhash_sha3), 0 }, /* 512 bit */
+};
+
+/**
+ * Initialize requested algorithms.
+ */
+void rhash_init_algorithms(unsigned mask)
+{
+ (void)mask; /* unused now */
+
+ /* verify that RHASH_HASH_COUNT is the index of the major bit of RHASH_ALL_HASHES */
+ assert(1 == (RHASH_ALL_HASHES >> (RHASH_HASH_COUNT - 1)));
+
+#ifdef GENERATE_CRC32_TABLE
+ rhash_crc32_init_table();
+#endif
+#ifdef GENERATE_GOST_LOOKUP_TABLE
+ rhash_gost_init_table();
+#endif
+ rhash_uninitialized_algorithms = 0;
+}
+
+#if 0
+/* CRC32 helper functions */
+
+/**
+ * Initialize crc32 hash.
+ *
+ * @param crc32 pointer to the hash to initialize
+ */
+static void rhash_crc32_init(uint32_t* crc32)
+{
+ *crc32 = 0; /* note: context size is sizeof(uint32_t) */
+}
+
+/**
+ * Calculate message CRC32 hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param crc32 pointer to the hash
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+static void rhash_crc32_update(uint32_t* crc32, const unsigned char* msg, size_t size)
+{
+ *crc32 = rhash_get_crc32(*crc32, msg, size);
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param crc32 pointer to the current hash value
+ * @param result calculated hash in binary form
+ */
+static void rhash_crc32_final(uint32_t* crc32, unsigned char* result)
+{
+#if defined(CPU_IA32) || defined(CPU_X64)
+ /* intel CPUs support assigment with non 32-bit aligned pointers */
+ *(unsigned*)result = be2me_32(*crc32);
+#else
+ /* correct saving BigEndian integer on all archs */
+ result[0] = (unsigned char)(*crc32 >> 24), result[1] = (unsigned char)(*crc32 >> 16);
+ result[2] = (unsigned char)(*crc32 >> 8), result[3] = (unsigned char)(*crc32);
+#endif
+}
+#endif
diff --git a/Utilities/cmlibrhash/librhash/algorithms.h b/Utilities/cmlibrhash/librhash/algorithms.h
new file mode 100644
index 000000000..4db2517c9
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/algorithms.h
@@ -0,0 +1,120 @@
+/* algorithms.h - rhash library algorithms */
+#ifndef RHASH_ALGORITHMS_H
+#define RHASH_ALGORITHMS_H
+
+#include <stddef.h> /* for ptrdiff_t */
+#include "rhash.h"
+#include "byte_order.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef RHASH_API
+/* modifier for RHash library functions */
+# define RHASH_API
+#endif
+
+typedef void (*pinit_t)(void*);
+typedef void (*pupdate_t)(void *ctx, const void* msg, size_t size);
+typedef void (*pfinal_t)(void*, unsigned char*);
+typedef void (*pcleanup_t)(void*);
+
+/**
+ * Information about a hash function
+ */
+typedef struct rhash_hash_info
+{
+ rhash_info *info;
+ size_t context_size;
+ ptrdiff_t digest_diff;
+ pinit_t init;
+ pupdate_t update;
+ pfinal_t final;
+ pcleanup_t cleanup;
+} rhash_hash_info;
+
+/**
+ * Information on a hash function and its context
+ */
+typedef struct rhash_vector_item
+{
+ struct rhash_hash_info* hash_info;
+ void *context;
+} rhash_vector_item;
+
+/**
+ * The rhash context containing contexts for several hash functions
+ */
+typedef struct rhash_context_ext
+{
+ struct rhash_context rc;
+ unsigned hash_vector_size; /* number of contained hash sums */
+ unsigned flags;
+ unsigned state;
+ void *callback, *callback_data;
+ void *bt_ctx;
+ rhash_vector_item vector[1]; /* contexts of contained hash sums */
+} rhash_context_ext;
+
+extern rhash_hash_info rhash_hash_info_default[RHASH_HASH_COUNT];
+extern rhash_hash_info* rhash_info_table;
+extern int rhash_info_size;
+extern unsigned rhash_uninitialized_algorithms;
+
+extern rhash_info info_crc32;
+extern rhash_info info_md4;
+extern rhash_info info_md5;
+extern rhash_info info_sha1;
+extern rhash_info info_tiger;
+extern rhash_info info_tth ;
+extern rhash_info info_btih;
+extern rhash_info info_ed2k;
+extern rhash_info info_aich;
+extern rhash_info info_whirlpool;
+extern rhash_info info_rmd160;
+extern rhash_info info_gost;
+extern rhash_info info_gostpro;
+extern rhash_info info_has160;
+extern rhash_info info_snf128;
+extern rhash_info info_snf256;
+extern rhash_info info_sha224;
+extern rhash_info info_sha256;
+extern rhash_info info_sha384;
+extern rhash_info info_sha512;
+extern rhash_info info_sha3_224;
+extern rhash_info info_sha3_256;
+extern rhash_info info_sha3_384;
+extern rhash_info info_sha3_512;
+extern rhash_info info_edr256;
+extern rhash_info info_edr512;
+
+/* rhash_info flags */
+#define F_BS32 1 /* default output in base32 */
+#define F_SWAP32 2 /* Big endian flag */
+#define F_SWAP64 4
+
+/* define endianness flags */
+#ifndef CPU_BIG_ENDIAN
+#define F_LE32 0
+#define F_LE64 0
+#define F_BE32 F_SWAP32
+#define F_BE64 F_SWAP64
+#else
+#define F_LE32 F_SWAP32
+#define F_LE64 F_SWAP64
+#define F_BE32 0
+#define F_BE64 0
+#endif
+
+void rhash_init_algorithms(unsigned mask);
+
+#if defined(OPENSSL_RUNTIME) && !defined(USE_OPENSSL)
+# define USE_OPENSSL
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* RHASH_ALGORITHMS_H */
diff --git a/Utilities/cmlibrhash/librhash/byte_order.c b/Utilities/cmlibrhash/librhash/byte_order.c
new file mode 100644
index 000000000..8ce6fc89e
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/byte_order.c
@@ -0,0 +1,150 @@
+/* byte_order.c - byte order related platform dependent routines,
+ *
+ * Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+#include "byte_order.h"
+
+#if !(__GNUC__ >= 4 || (__GNUC__ ==3 && __GNUC_MINOR__ >= 4)) /* if !GCC or GCC < 4.3 */
+
+# if _MSC_VER >= 1300 && (_M_IX86 || _M_AMD64 || _M_IA64) /* if MSVC++ >= 2002 on x86/x64 */
+# include <intrin.h>
+# pragma intrinsic(_BitScanForward)
+
+/**
+ * Returns index of the trailing bit of x.
+ *
+ * @param x the number to process
+ * @return zero-based index of the trailing bit
+ */
+unsigned rhash_ctz(unsigned x)
+{
+ unsigned long index;
+ unsigned char isNonzero = _BitScanForward(&index, x); /* MSVC intrinsic */
+ return (isNonzero ? (unsigned)index : 0);
+}
+# else /* _MSC_VER >= 1300... */
+
+/**
+ * Returns index of the trailing bit of a 32-bit number.
+ * This is a plain C equivalent for GCC __builtin_ctz() bit scan.
+ *
+ * @param x the number to process
+ * @return zero-based index of the trailing bit
+ */
+unsigned rhash_ctz(unsigned x)
+{
+ /* array for conversion to bit position */
+ static unsigned char bit_pos[32] = {
+ 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+ 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+ };
+
+ /* The De Bruijn bit-scan was devised in 1997, according to Donald Knuth
+ * by Martin Lauter. The constant 0x077CB531UL is a De Bruijn sequence,
+ * which produces a unique pattern of bits into the high 5 bits for each
+ * possible bit position that it is multiplied against.
+ * See http://graphics.stanford.edu/~seander/bithacks.html
+ * and http://chessprogramming.wikispaces.com/BitScan */
+ return (unsigned)bit_pos[((uint32_t)((x & -x) * 0x077CB531U)) >> 27];
+}
+# endif /* _MSC_VER >= 1300... */
+#endif /* !(GCC >= 4.3) */
+
+/**
+ * Copy a memory block with simultaneous exchanging byte order.
+ * The byte order is changed from little-endian 32-bit integers
+ * to big-endian (or vice-versa).
+ *
+ * @param to the pointer where to copy memory block
+ * @param index the index to start writing from
+ * @param from the source block to copy
+ * @param length length of the memory block
+ */
+void rhash_swap_copy_str_to_u32(void* to, int index, const void* from, size_t length)
+{
+ /* if all pointers and length are 32-bits aligned */
+ if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 3) ) {
+ /* copy memory as 32-bit words */
+ const uint32_t* src = (const uint32_t*)from;
+ const uint32_t* end = (const uint32_t*)((const char*)src + length);
+ uint32_t* dst = (uint32_t*)((char*)to + index);
+ while (src < end) *(dst++) = bswap_32( *(src++) );
+ } else {
+ const char* src = (const char*)from;
+ for (length += index; (size_t)index < length; index++) ((char*)to)[index ^ 3] = *(src++);
+ }
+}
+
+/**
+ * Copy a memory block with changed byte order.
+ * The byte order is changed from little-endian 64-bit integers
+ * to big-endian (or vice-versa).
+ *
+ * @param to the pointer where to copy memory block
+ * @param index the index to start writing from
+ * @param from the source block to copy
+ * @param length length of the memory block
+ */
+void rhash_swap_copy_str_to_u64(void* to, int index, const void* from, size_t length)
+{
+ /* if all pointers and length are 64-bits aligned */
+ if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 7) ) {
+ /* copy aligned memory block as 64-bit integers */
+ const uint64_t* src = (const uint64_t*)from;
+ const uint64_t* end = (const uint64_t*)((const char*)src + length);
+ uint64_t* dst = (uint64_t*)((char*)to + index);
+ while (src < end) *(dst++) = bswap_64( *(src++) );
+ } else {
+ const char* src = (const char*)from;
+ for (length += index; (size_t)index < length; index++) ((char*)to)[index ^ 7] = *(src++);
+ }
+}
+
+/**
+ * Copy data from a sequence of 64-bit words to a binary string of given length,
+ * while changing byte order.
+ *
+ * @param to the binary string to receive data
+ * @param from the source sequence of 64-bit words
+ * @param length the size in bytes of the data being copied
+ */
+void rhash_swap_copy_u64_to_str(void* to, const void* from, size_t length)
+{
+ /* if all pointers and length are 64-bits aligned */
+ if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | length ) & 7) ) {
+ /* copy aligned memory block as 64-bit integers */
+ const uint64_t* src = (const uint64_t*)from;
+ const uint64_t* end = (const uint64_t*)((const char*)src + length);
+ uint64_t* dst = (uint64_t*)to;
+ while (src < end) *(dst++) = bswap_64( *(src++) );
+ } else {
+ size_t index;
+ char* dst = (char*)to;
+ for (index = 0; index < length; index++) *(dst++) = ((char*)from)[index ^ 7];
+ }
+}
+
+/**
+ * Exchange byte order in the given array of 32-bit integers.
+ *
+ * @param arr the array to process
+ * @param length array length
+ */
+void rhash_u32_mem_swap(unsigned *arr, int length)
+{
+ unsigned* end = arr + length;
+ for (; arr < end; arr++) {
+ *arr = bswap_32(*arr);
+ }
+}
diff --git a/Utilities/cmlibrhash/librhash/byte_order.h b/Utilities/cmlibrhash/librhash/byte_order.h
new file mode 100644
index 000000000..d34a020b8
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/byte_order.h
@@ -0,0 +1,156 @@
+/* byte_order.h */
+#ifndef BYTE_ORDER_H
+#define BYTE_ORDER_H
+#include "ustd.h"
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* if x86 compatible cpu */
+#if defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(__pentium__) || \
+ defined(__pentiumpro__) || defined(__pentium4__) || \
+ defined(__nocona__) || defined(prescott) || defined(__core2__) || \
+ defined(__k6__) || defined(__k8__) || defined(__athlon__) || \
+ defined(__amd64) || defined(__amd64__) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_IX86) || \
+ defined(_M_AMD64) || defined(_M_IA64) || defined(_M_X64)
+/* detect if x86-64 instruction set is supported */
+# if defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \
+ defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+# define CPU_X64
+# else
+# define CPU_IA32
+# endif
+#endif
+
+
+/* detect CPU endianness */
+#include <cm_kwiml.h>
+#if KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_LITTLE
+# define CPU_LITTLE_ENDIAN
+# define IS_BIG_ENDIAN 0
+# define IS_LITTLE_ENDIAN 1
+#elif KWIML_ABI_ENDIAN_ID == KWIML_ABI_ENDIAN_ID_BIG
+# define CPU_BIG_ENDIAN
+# define IS_BIG_ENDIAN 1
+# define IS_LITTLE_ENDIAN 0
+#else
+# error "Can't detect CPU architechture"
+#endif
+
+#define IS_ALIGNED_32(p) (0 == (3 & ((const char*)(p) - (const char*)0)))
+#define IS_ALIGNED_64(p) (0 == (7 & ((const char*)(p) - (const char*)0)))
+
+#if defined(_MSC_VER)
+#define ALIGN_ATTR(n) __declspec(align(n))
+#elif defined(__GNUC__)
+#define ALIGN_ATTR(n) __attribute__((aligned (n)))
+#else
+#define ALIGN_ATTR(n) /* nothing */
+#endif
+
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+#define I64(x) x##ui64
+#else
+#define I64(x) x##LL
+#endif
+
+/* convert a hash flag to index */
+#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) /* GCC < 3.4 */
+# define rhash_ctz(x) __builtin_ctz(x)
+#else
+unsigned rhash_ctz(unsigned); /* define as function */
+#endif
+
+void rhash_swap_copy_str_to_u32(void* to, int index, const void* from, size_t length);
+void rhash_swap_copy_str_to_u64(void* to, int index, const void* from, size_t length);
+void rhash_swap_copy_u64_to_str(void* to, const void* from, size_t length);
+void rhash_u32_mem_swap(unsigned *p, int length_in_u32);
+
+#ifndef __has_builtin
+# define __has_builtin(x) 0
+#endif
+
+/* define bswap_32 */
+#if defined(__GNUC__) && defined(CPU_IA32) && !defined(__i386__)
+/* for intel x86 CPU */
+static inline uint32_t bswap_32(uint32_t x) {
+ __asm("bswap\t%0" : "=r" (x) : "0" (x));
+ return x;
+}
+#elif defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)
+/* for GCC >= 4.3 */
+# define bswap_32(x) __builtin_bswap32(x)
+#elif defined(__clang__) && __has_builtin(__builtin_bswap32)
+# define bswap_32(x) __builtin_bswap32(x)
+#elif (_MSC_VER > 1300) && (defined(CPU_IA32) || defined(CPU_X64)) /* MS VC */
+# define bswap_32(x) _byteswap_ulong((unsigned long)x)
+#else
+/* general bswap_32 definition */
+static uint32_t bswap_32(uint32_t x) {
+ x = ((x << 8) & 0xFF00FF00) | ((x >> 8) & 0x00FF00FF);
+ return (x >> 16) | (x << 16);
+}
+#endif /* bswap_32 */
+
+#if defined(__GNUC__) && (__GNUC__ >= 4) && (__GNUC__ > 4 || __GNUC_MINOR__ >= 3)
+# define bswap_64(x) __builtin_bswap64(x)
+#elif defined(__clang__) && __has_builtin(__builtin_bswap64)
+# define bswap_64(x) __builtin_bswap64(x)
+#elif (_MSC_VER > 1300) && (defined(CPU_IA32) || defined(CPU_X64)) /* MS VC */
+# define bswap_64(x) _byteswap_uint64((__int64)x)
+#else
+static uint64_t bswap_64(uint64_t x) {
+ union {
+ uint64_t ll;
+ uint32_t l[2];
+ } w, r;
+ w.ll = x;
+ r.l[0] = bswap_32(w.l[1]);
+ r.l[1] = bswap_32(w.l[0]);
+ return r.ll;
+}
+#endif
+
+#ifdef CPU_BIG_ENDIAN
+# define be2me_32(x) (x)
+# define be2me_64(x) (x)
+# define le2me_32(x) bswap_32(x)
+# define le2me_64(x) bswap_64(x)
+
+# define be32_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
+# define le32_copy(to, index, from, length) rhash_swap_copy_str_to_u32((to), (index), (from), (length))
+# define be64_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
+# define le64_copy(to, index, from, length) rhash_swap_copy_str_to_u64((to), (index), (from), (length))
+# define me64_to_be_str(to, from, length) memcpy((to), (from), (length))
+# define me64_to_le_str(to, from, length) rhash_swap_copy_u64_to_str((to), (from), (length))
+
+#else /* CPU_BIG_ENDIAN */
+# define be2me_32(x) bswap_32(x)
+# define be2me_64(x) bswap_64(x)
+# define le2me_32(x) (x)
+# define le2me_64(x) (x)
+
+# define be32_copy(to, index, from, length) rhash_swap_copy_str_to_u32((to), (index), (from), (length))
+# define le32_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
+# define be64_copy(to, index, from, length) rhash_swap_copy_str_to_u64((to), (index), (from), (length))
+# define le64_copy(to, index, from, length) memcpy((to) + (index), (from), (length))
+# define me64_to_be_str(to, from, length) rhash_swap_copy_u64_to_str((to), (from), (length))
+# define me64_to_le_str(to, from, length) memcpy((to), (from), (length))
+#endif /* CPU_BIG_ENDIAN */
+
+/* ROTL/ROTR macros rotate a 32/64-bit word left/right by n bits */
+#define ROTL32(dword, n) ((dword) << (n) ^ ((dword) >> (32 - (n))))
+#define ROTR32(dword, n) ((dword) >> (n) ^ ((dword) << (32 - (n))))
+#define ROTL64(qword, n) ((qword) << (n) ^ ((qword) >> (64 - (n))))
+#define ROTR64(qword, n) ((qword) >> (n) ^ ((qword) << (64 - (n))))
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* BYTE_ORDER_H */
diff --git a/Utilities/cmlibrhash/librhash/hex.c b/Utilities/cmlibrhash/librhash/hex.c
new file mode 100644
index 000000000..c941149ab
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/hex.c
@@ -0,0 +1,188 @@
+/* hex.c - conversion for hexadecimal and base32 strings.
+ *
+ * Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+#include <string.h>
+#include <ctype.h>
+#include "hex.h"
+
+/**
+* Convert a byte to a hexadecimal number. The result, consisting of two
+* hexadecimal digits is stored into a buffer.
+ *
+ * @param dest the buffer to receive two symbols of hex representation
+ * @param byte the byte to decode
+ * @param upper_case flag to print string in uppercase
+ * @return pointer to the chararcter just after the written number (dest + 2)
+ */
+char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case)
+{
+ const char add = (upper_case ? 'A' - 10 : 'a' - 10);
+ unsigned char c = (byte >> 4) & 15;
+ *dest++ = (c > 9 ? c + add : c + '0');
+ c = byte & 15;
+ *dest++ = (c > 9 ? c + add : c + '0');
+ return dest;
+}
+
+/**
+ * Store hexadecimal representation of a binary string to given buffer.
+ *
+ * @param dest the buffer to receive hexadecimal representation
+ * @param src binary string
+ * @param len string length
+ * @param upper_case flag to print string in uppercase
+ */
+void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case)
+{
+ while (len-- > 0) {
+ dest = rhash_print_hex_byte(dest, *src++, upper_case);
+ }
+ *dest = '\0';
+}
+
+/**
+ * Encode a binary string to base32.
+ *
+ * @param dest the buffer to store result
+ * @param src binary string
+ * @param len string length
+ * @param upper_case flag to print string in uppercase
+ */
+void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case)
+{
+ const char a = (upper_case ? 'A' : 'a');
+ unsigned shift = 0;
+ unsigned char word;
+ const unsigned char* e = src + len;
+ while (src < e) {
+ if (shift > 3) {
+ word = (*src & (0xFF >> shift));
+ shift = (shift + 5) % 8;
+ word <<= shift;
+ if (src + 1 < e)
+ word |= *(src + 1) >> (8 - shift);
+ ++src;
+ } else {
+ shift = (shift + 5) % 8;
+ word = ( *src >> ( (8 - shift) & 7 ) ) & 0x1F;
+ if (shift == 0) src++;
+ }
+ *dest++ = ( word < 26 ? word + a : word + '2' - 26 );
+ }
+ *dest = '\0';
+}
+
+/**
+ * Encode a binary string to base64.
+ * Encoded output length is always a multiple of 4 bytes.
+ *
+ * @param dest the buffer to store result
+ * @param src binary string
+ * @param len string length
+ */
+void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len)
+{
+ static const char* tail = "0123456789+/";
+ unsigned shift = 0;
+ unsigned char word;
+ const unsigned char* e = src + len;
+ while (src < e) {
+ if (shift > 2) {
+ word = (*src & (0xFF >> shift));
+ shift = (shift + 6) % 8;
+ word <<= shift;
+ if (src + 1 < e)
+ word |= *(src + 1) >> (8 - shift);
+ ++src;
+ } else {
+ shift = (shift + 6) % 8;
+ word = ( *src >> ( (8 - shift) & 7 ) ) & 0x3F;
+ if (shift == 0) src++;
+ }
+ *dest++ = ( word < 52 ? (word < 26 ? word + 'A' : word - 26 + 'a') : tail[word - 52]);
+ }
+ if (shift > 0) {
+ *dest++ = '=';
+ if (shift == 4) *dest++ = '=';
+ }
+ *dest = '\0';
+}
+
+/* unsafe characters are "<>{}[]%#/|\^~`@:;?=&+ */
+#define IS_GOOD_URL_CHAR(c) (isalnum((unsigned char)c) || strchr("$-_.!'(),", c))
+
+/**
+ * URL-encode a string.
+ *
+ * @param dst buffer to receive result or NULL to calculate
+ * the lengths of encoded string
+ * @param filename the file name
+ * @return the length of the result string
+ */
+int rhash_urlencode(char *dst, const char *name)
+{
+ const char *start;
+ if (!dst) {
+ int len;
+ for (len = 0; *name; name++) len += (IS_GOOD_URL_CHAR(*name) ? 1 : 3);
+ return len;
+ }
+ /* encode URL as specified by RFC 1738 */
+ for (start = dst; *name; name++) {
+ if ( IS_GOOD_URL_CHAR(*name) ) {
+ *dst++ = *name;
+ } else {
+ *dst++ = '%';
+ dst = rhash_print_hex_byte(dst, *name, 'A');
+ }
+ }
+ *dst = 0;
+ return (int)(dst - start);
+}
+
+/**
+ * Print 64-bit number with trailing '\0' to a string buffer.
+ * if dst is NULL, then just return the length of the number.
+ *
+ * @param dst output buffer
+ * @param number the number to print
+ * @return length of the printed number (without trailing '\0')
+ */
+int rhash_sprintI64(char *dst, uint64_t number)
+{
+ /* The biggest number has 20 digits: 2^64 = 18 446 744 073 709 551 616 */
+ char buf[24], *p;
+ size_t length;
+
+ if (dst == NULL) {
+ /* just calculate the length of the number */
+ if (number == 0) return 1;
+ for (length = 0; number != 0; number /= 10) length++;
+ return (int)length;
+ }
+
+ p = buf + 23;
+ *p = '\0'; /* last symbol should be '\0' */
+ if (number == 0) {
+ *(--p) = '0';
+ } else {
+ for (; p >= buf && number != 0; number /= 10) {
+ *(--p) = '0' + (char)(number % 10);
+ }
+ }
+ length = buf + 23 - p;
+ memcpy(dst, p, length + 1);
+ return (int)length;
+}
diff --git a/Utilities/cmlibrhash/librhash/hex.h b/Utilities/cmlibrhash/librhash/hex.h
new file mode 100644
index 000000000..2b365e2fc
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/hex.h
@@ -0,0 +1,25 @@
+/* hex.h - conversion for hexadecimal and base32 strings. */
+#ifndef HEX_H
+#define HEX_H
+
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void rhash_byte_to_hex(char *dest, const unsigned char *src, unsigned len, int upper_case);
+void rhash_byte_to_base32(char* dest, const unsigned char* src, unsigned len, int upper_case);
+void rhash_byte_to_base64(char* dest, const unsigned char* src, unsigned len);
+char* rhash_print_hex_byte(char *dest, const unsigned char byte, int upper_case);
+int rhash_urlencode(char *dst, const char *name);
+int rhash_sprintI64(char *dst, uint64_t number);
+
+#define BASE32_LENGTH(bytes) (((bytes) * 8 + 4) / 5)
+#define BASE64_LENGTH(bytes) ((((bytes) + 2) / 3) * 4)
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* HEX_H */
diff --git a/Utilities/cmlibrhash/librhash/md5.c b/Utilities/cmlibrhash/librhash/md5.c
new file mode 100644
index 000000000..b20de45e9
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/md5.c
@@ -0,0 +1,236 @@
+/* md5.c - an implementation of the MD5 algorithm, based on RFC 1321.
+ *
+ * Copyright: 2007-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <string.h>
+#include "byte_order.h"
+#include "md5.h"
+
+/**
+ * Initialize context before calculaing hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_md5_init(md5_ctx *ctx)
+{
+ ctx->length = 0;
+
+ /* initialize state */
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+}
+
+/* First, define four auxiliary functions that each take as input
+ * three 32-bit words and returns a 32-bit word.*/
+
+/* F(x,y,z) = ((y XOR z) AND x) XOR z - is faster then original version */
+#define MD5_F(x, y, z) ((((y) ^ (z)) & (x)) ^ (z))
+#define MD5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define MD5_H(x, y, z) ((x) ^ (y) ^ (z))
+#define MD5_I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* transformations for rounds 1, 2, 3, and 4. */
+#define MD5_ROUND1(a, b, c, d, x, s, ac) { \
+ (a) += MD5_F((b), (c), (d)) + (x) + (ac); \
+ (a) = ROTL32((a), (s)); \
+ (a) += (b); \
+}
+#define MD5_ROUND2(a, b, c, d, x, s, ac) { \
+ (a) += MD5_G((b), (c), (d)) + (x) + (ac); \
+ (a) = ROTL32((a), (s)); \
+ (a) += (b); \
+}
+#define MD5_ROUND3(a, b, c, d, x, s, ac) { \
+ (a) += MD5_H((b), (c), (d)) + (x) + (ac); \
+ (a) = ROTL32((a), (s)); \
+ (a) += (b); \
+}
+#define MD5_ROUND4(a, b, c, d, x, s, ac) { \
+ (a) += MD5_I((b), (c), (d)) + (x) + (ac); \
+ (a) = ROTL32((a), (s)); \
+ (a) += (b); \
+}
+
+/**
+ * The core transformation. Process a 512-bit block.
+ * The function has been taken from RFC 1321 with little changes.
+ *
+ * @param state algorithm state
+ * @param x the message block to process
+ */
+static void rhash_md5_process_block(unsigned state[4], const unsigned* x)
+{
+ register unsigned a, b, c, d;
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD5_ROUND1(a, b, c, d, x[ 0], 7, 0xd76aa478);
+ MD5_ROUND1(d, a, b, c, x[ 1], 12, 0xe8c7b756);
+ MD5_ROUND1(c, d, a, b, x[ 2], 17, 0x242070db);
+ MD5_ROUND1(b, c, d, a, x[ 3], 22, 0xc1bdceee);
+ MD5_ROUND1(a, b, c, d, x[ 4], 7, 0xf57c0faf);
+ MD5_ROUND1(d, a, b, c, x[ 5], 12, 0x4787c62a);
+ MD5_ROUND1(c, d, a, b, x[ 6], 17, 0xa8304613);
+ MD5_ROUND1(b, c, d, a, x[ 7], 22, 0xfd469501);
+ MD5_ROUND1(a, b, c, d, x[ 8], 7, 0x698098d8);
+ MD5_ROUND1(d, a, b, c, x[ 9], 12, 0x8b44f7af);
+ MD5_ROUND1(c, d, a, b, x[10], 17, 0xffff5bb1);
+ MD5_ROUND1(b, c, d, a, x[11], 22, 0x895cd7be);
+ MD5_ROUND1(a, b, c, d, x[12], 7, 0x6b901122);
+ MD5_ROUND1(d, a, b, c, x[13], 12, 0xfd987193);
+ MD5_ROUND1(c, d, a, b, x[14], 17, 0xa679438e);
+ MD5_ROUND1(b, c, d, a, x[15], 22, 0x49b40821);
+
+ MD5_ROUND2(a, b, c, d, x[ 1], 5, 0xf61e2562);
+ MD5_ROUND2(d, a, b, c, x[ 6], 9, 0xc040b340);
+ MD5_ROUND2(c, d, a, b, x[11], 14, 0x265e5a51);
+ MD5_ROUND2(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
+ MD5_ROUND2(a, b, c, d, x[ 5], 5, 0xd62f105d);
+ MD5_ROUND2(d, a, b, c, x[10], 9, 0x2441453);
+ MD5_ROUND2(c, d, a, b, x[15], 14, 0xd8a1e681);
+ MD5_ROUND2(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
+ MD5_ROUND2(a, b, c, d, x[ 9], 5, 0x21e1cde6);
+ MD5_ROUND2(d, a, b, c, x[14], 9, 0xc33707d6);
+ MD5_ROUND2(c, d, a, b, x[ 3], 14, 0xf4d50d87);
+ MD5_ROUND2(b, c, d, a, x[ 8], 20, 0x455a14ed);
+ MD5_ROUND2(a, b, c, d, x[13], 5, 0xa9e3e905);
+ MD5_ROUND2(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
+ MD5_ROUND2(c, d, a, b, x[ 7], 14, 0x676f02d9);
+ MD5_ROUND2(b, c, d, a, x[12], 20, 0x8d2a4c8a);
+
+ MD5_ROUND3(a, b, c, d, x[ 5], 4, 0xfffa3942);
+ MD5_ROUND3(d, a, b, c, x[ 8], 11, 0x8771f681);
+ MD5_ROUND3(c, d, a, b, x[11], 16, 0x6d9d6122);
+ MD5_ROUND3(b, c, d, a, x[14], 23, 0xfde5380c);
+ MD5_ROUND3(a, b, c, d, x[ 1], 4, 0xa4beea44);
+ MD5_ROUND3(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
+ MD5_ROUND3(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
+ MD5_ROUND3(b, c, d, a, x[10], 23, 0xbebfbc70);
+ MD5_ROUND3(a, b, c, d, x[13], 4, 0x289b7ec6);
+ MD5_ROUND3(d, a, b, c, x[ 0], 11, 0xeaa127fa);
+ MD5_ROUND3(c, d, a, b, x[ 3], 16, 0xd4ef3085);
+ MD5_ROUND3(b, c, d, a, x[ 6], 23, 0x4881d05);
+ MD5_ROUND3(a, b, c, d, x[ 9], 4, 0xd9d4d039);
+ MD5_ROUND3(d, a, b, c, x[12], 11, 0xe6db99e5);
+ MD5_ROUND3(c, d, a, b, x[15], 16, 0x1fa27cf8);
+ MD5_ROUND3(b, c, d, a, x[ 2], 23, 0xc4ac5665);
+
+ MD5_ROUND4(a, b, c, d, x[ 0], 6, 0xf4292244);
+ MD5_ROUND4(d, a, b, c, x[ 7], 10, 0x432aff97);
+ MD5_ROUND4(c, d, a, b, x[14], 15, 0xab9423a7);
+ MD5_ROUND4(b, c, d, a, x[ 5], 21, 0xfc93a039);
+ MD5_ROUND4(a, b, c, d, x[12], 6, 0x655b59c3);
+ MD5_ROUND4(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
+ MD5_ROUND4(c, d, a, b, x[10], 15, 0xffeff47d);
+ MD5_ROUND4(b, c, d, a, x[ 1], 21, 0x85845dd1);
+ MD5_ROUND4(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
+ MD5_ROUND4(d, a, b, c, x[15], 10, 0xfe2ce6e0);
+ MD5_ROUND4(c, d, a, b, x[ 6], 15, 0xa3014314);
+ MD5_ROUND4(b, c, d, a, x[13], 21, 0x4e0811a1);
+ MD5_ROUND4(a, b, c, d, x[ 4], 6, 0xf7537e82);
+ MD5_ROUND4(d, a, b, c, x[11], 10, 0xbd3af235);
+ MD5_ROUND4(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
+ MD5_ROUND4(b, c, d, a, x[ 9], 21, 0xeb86d391);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+
+/**
+ * Calculate message hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+void rhash_md5_update(md5_ctx *ctx, const unsigned char* msg, size_t size)
+{
+ unsigned index = (unsigned)ctx->length & 63;
+ ctx->length += size;
+
+ /* fill partial block */
+ if (index) {
+ unsigned left = md5_block_size - index;
+ le32_copy((char*)ctx->message, index, msg, (size < left ? size : left));
+ if (size < left) return;
+
+ /* process partial block */
+ rhash_md5_process_block(ctx->hash, ctx->message);
+ msg += left;
+ size -= left;
+ }
+ while (size >= md5_block_size) {
+ unsigned* aligned_message_block;
+ if (IS_LITTLE_ENDIAN && IS_ALIGNED_32(msg)) {
+ /* the most common case is processing a 32-bit aligned message
+ on a little-endian CPU without copying it */
+ aligned_message_block = (unsigned*)msg;
+ } else {
+ le32_copy(ctx->message, 0, msg, md5_block_size);
+ aligned_message_block = ctx->message;
+ }
+
+ rhash_md5_process_block(ctx->hash, aligned_message_block);
+ msg += md5_block_size;
+ size -= md5_block_size;
+ }
+ if (size) {
+ /* save leftovers */
+ le32_copy(ctx->message, 0, msg, size);
+ }
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param result calculated hash in binary form
+ */
+void rhash_md5_final(md5_ctx *ctx, unsigned char* result)
+{
+ unsigned index = ((unsigned)ctx->length & 63) >> 2;
+ unsigned shift = ((unsigned)ctx->length & 3) * 8;
+
+ /* pad message and run for last block */
+
+ /* append the byte 0x80 to the message */
+ ctx->message[index] &= ~(0xFFFFFFFFu << shift);
+ ctx->message[index++] ^= 0x80u << shift;
+
+ /* if no room left in the message to store 64-bit message length */
+ if (index > 14) {
+ /* then fill the rest with zeros and process it */
+ while (index < 16) {
+ ctx->message[index++] = 0;
+ }
+ rhash_md5_process_block(ctx->hash, ctx->message);
+ index = 0;
+ }
+ while (index < 14) {
+ ctx->message[index++] = 0;
+ }
+ ctx->message[14] = (unsigned)(ctx->length << 3);
+ ctx->message[15] = (unsigned)(ctx->length >> 29);
+ rhash_md5_process_block(ctx->hash, ctx->message);
+
+ if (result) le32_copy(result, 0, &ctx->hash, 16);
+}
diff --git a/Utilities/cmlibrhash/librhash/md5.h b/Utilities/cmlibrhash/librhash/md5.h
new file mode 100644
index 000000000..1af6f133c
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/md5.h
@@ -0,0 +1,31 @@
+/* md5.h */
+#ifndef MD5_HIDER
+#define MD5_HIDER
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define md5_block_size 64
+#define md5_hash_size 16
+
+/* algorithm context */
+typedef struct md5_ctx
+{
+ unsigned message[md5_block_size / 4]; /* 512-bit buffer for leftovers */
+ uint64_t length; /* number of processed bytes */
+ unsigned hash[4]; /* 128-bit algorithm internal hashing state */
+} md5_ctx;
+
+/* hash functions */
+
+void rhash_md5_init(md5_ctx *ctx);
+void rhash_md5_update(md5_ctx *ctx, const unsigned char* msg, size_t size);
+void rhash_md5_final(md5_ctx *ctx, unsigned char result[16]);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* MD5_HIDER */
diff --git a/Utilities/cmlibrhash/librhash/rhash.c b/Utilities/cmlibrhash/librhash/rhash.c
new file mode 100644
index 000000000..ad6249b17
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/rhash.c
@@ -0,0 +1,872 @@
+/* rhash.c - implementation of LibRHash library calls
+ *
+ * Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+/* macros for large file support, must be defined before any include file */
+#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+
+#include <string.h> /* memset() */
+#include <stdlib.h> /* free() */
+#include <stddef.h> /* ptrdiff_t */
+#include <stdio.h>
+#include <assert.h>
+#include <errno.h>
+
+/* modifier for Windows DLL */
+#if defined(_WIN32) && defined(RHASH_EXPORTS)
+# define RHASH_API __declspec(dllexport)
+#endif
+
+#include "byte_order.h"
+#include "algorithms.h"
+#include "util.h"
+#include "hex.h"
+#include "rhash.h" /* RHash library interface */
+
+#define STATE_ACTIVE 0xb01dbabe
+#define STATE_STOPED 0xdeadbeef
+#define STATE_DELETED 0xdecea5ed
+#define RCTX_AUTO_FINAL 0x1
+#define RCTX_FINALIZED 0x2
+#define RCTX_FINALIZED_MASK (RCTX_AUTO_FINAL | RCTX_FINALIZED)
+#define RHPR_FORMAT (RHPR_RAW | RHPR_HEX | RHPR_BASE32 | RHPR_BASE64)
+#define RHPR_MODIFIER (RHPR_UPPERCASE | RHPR_REVERSE)
+
+/**
+ * Initialize static data of rhash algorithms
+ */
+void rhash_library_init(void)
+{
+ rhash_init_algorithms(RHASH_ALL_HASHES);
+#ifdef USE_OPENSSL
+ rhash_plug_openssl();
+#endif
+}
+
+/**
+ * Returns the number of supported hash algorithms.
+ *
+ * @return the number of supported hash functions
+ */
+int RHASH_API rhash_count(void)
+{
+ return rhash_info_size;
+}
+
+/* Lo-level rhash library functions */
+
+/**
+ * Allocate and initialize RHash context for calculating hash(es).
+ * After initializing rhash_update()/rhash_final() functions should be used.
+ * Then the context must be freed by calling rhash_free().
+ *
+ * @param hash_id union of bit flags, containing ids of hashes to calculate.
+ * @return initialized rhash context, NULL on error and errno is set
+ */
+RHASH_API rhash rhash_init(unsigned hash_id)
+{
+ unsigned tail_bit_index; /* index of hash_id trailing bit */
+ unsigned num = 0; /* number of hashes to compute */
+ rhash_context_ext *rctx = NULL; /* allocated rhash context */
+ size_t hash_size_sum = 0; /* size of hash contexts to store in rctx */
+
+ unsigned i, bit_index, id;
+ struct rhash_hash_info* info;
+ size_t aligned_size;
+ char* phash_ctx;
+
+ hash_id &= RHASH_ALL_HASHES;
+ if (hash_id == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ tail_bit_index = rhash_ctz(hash_id); /* get trailing bit index */
+ assert(tail_bit_index < RHASH_HASH_COUNT);
+
+ id = 1 << tail_bit_index;
+
+ if (hash_id == id) {
+ /* handle the most common case of only one hash */
+ num = 1;
+ info = &rhash_info_table[tail_bit_index];
+ hash_size_sum = info->context_size;
+ } else {
+ /* another case: hash_id contains several hashes */
+ for (bit_index = tail_bit_index; id <= hash_id; bit_index++, id = id << 1) {
+ assert(id != 0);
+ assert(bit_index < RHASH_HASH_COUNT);
+ info = &rhash_info_table[bit_index];
+ if (hash_id & id) {
+ /* align sizes by 8 bytes */
+ aligned_size = (info->context_size + 7) & ~7;
+ hash_size_sum += aligned_size;
+ num++;
+ }
+ }
+ assert(num > 1);
+ }
+
+ /* align the size of the rhash context common part */
+ aligned_size = (offsetof(rhash_context_ext, vector[num]) + 7) & ~7;
+ assert(aligned_size >= sizeof(rhash_context_ext));
+
+ /* allocate rhash context with enough memory to store contexts of all used hashes */
+ rctx = (rhash_context_ext*)malloc(aligned_size + hash_size_sum);
+ if (rctx == NULL) return NULL;
+
+ /* initialize common fields of the rhash context */
+ memset(rctx, 0, sizeof(rhash_context_ext));
+ rctx->rc.hash_id = hash_id;
+ rctx->flags = RCTX_AUTO_FINAL; /* turn on auto-final by default */
+ rctx->state = STATE_ACTIVE;
+ rctx->hash_vector_size = num;
+
+ /* aligned hash contexts follows rctx->vector[num] in the same memory block */
+ phash_ctx = (char*)rctx + aligned_size;
+ assert(phash_ctx >= (char*)&rctx->vector[num]);
+
+ /* initialize context for every hash in a loop */
+ for (bit_index = tail_bit_index, id = 1 << tail_bit_index, i = 0;
+ id <= hash_id; bit_index++, id = id << 1)
+ {
+ /* check if a hash function with given id shall be included into rctx */
+ if ((hash_id & id) != 0) {
+ info = &rhash_info_table[bit_index];
+ assert(info->context_size > 0);
+ assert(((phash_ctx - (char*)0) & 7) == 0); /* hash context is aligned */
+ assert(info->init != NULL);
+
+ rctx->vector[i].hash_info = info;
+ rctx->vector[i].context = phash_ctx;
+
+#if 0
+ /* BTIH initialization is complex, save pointer for later */
+ if ((id & RHASH_BTIH) != 0) rctx->bt_ctx = phash_ctx;
+#endif
+ phash_ctx += (info->context_size + 7) & ~7;
+
+ /* initialize the i-th hash context */
+ info->init(rctx->vector[i].context);
+ i++;
+ }
+ }
+
+ return &rctx->rc; /* return allocated and initialized rhash context */
+}
+
+/**
+ * Free RHash context memory.
+ *
+ * @param ctx the context to free.
+ */
+void rhash_free(rhash ctx)
+{
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ unsigned i;
+
+ if (ctx == 0) return;
+ assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
+ ectx->state = STATE_DELETED; /* mark memory block as being removed */
+
+ /* clean the hash functions, which require additional clean up */
+ for (i = 0; i < ectx->hash_vector_size; i++) {
+ struct rhash_hash_info* info = ectx->vector[i].hash_info;
+ if (info->cleanup != 0) {
+ info->cleanup(ectx->vector[i].context);
+ }
+ }
+
+ free(ectx);
+}
+
+/**
+ * Re-initialize RHash context to reuse it.
+ * Useful to speed up processing of many small messages.
+ *
+ * @param ctx context to reinitialize
+ */
+RHASH_API void rhash_reset(rhash ctx)
+{
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ unsigned i;
+
+ assert(ectx->hash_vector_size > 0);
+ assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
+ ectx->state = STATE_ACTIVE; /* re-activate the structure */
+
+ /* re-initialize every hash in a loop */
+ for (i = 0; i < ectx->hash_vector_size; i++) {
+ struct rhash_hash_info* info = ectx->vector[i].hash_info;
+ if (info->cleanup != 0) {
+ info->cleanup(ectx->vector[i].context);
+ }
+
+ assert(info->init != NULL);
+ info->init(ectx->vector[i].context);
+ }
+ ectx->flags &= ~RCTX_FINALIZED; /* clear finalized state */
+}
+
+/**
+ * Calculate hashes of message.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the rhash context
+ * @param message message chunk
+ * @param length length of the message chunk
+ * @return 0 on success; On fail return -1 and set errno
+ */
+RHASH_API int rhash_update(rhash ctx, const void* message, size_t length)
+{
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ unsigned i;
+
+ assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
+ if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
+
+ ctx->msg_size += length;
+
+ /* call update method for every algorithm */
+ for (i = 0; i < ectx->hash_vector_size; i++) {
+ struct rhash_hash_info* info = ectx->vector[i].hash_info;
+ assert(info->update != 0);
+ info->update(ectx->vector[i].context, message, length);
+ }
+ return 0; /* no error processing at the moment */
+}
+
+/**
+ * Finalize hash calculation and optionally store the first hash.
+ *
+ * @param ctx the rhash context
+ * @param first_result optional buffer to store a calculated hash with the lowest available id
+ * @return 0 on success; On fail return -1 and set errno
+ */
+RHASH_API int rhash_final(rhash ctx, unsigned char* first_result)
+{
+ unsigned i = 0;
+ unsigned char buffer[130];
+ unsigned char* out = (first_result ? first_result : buffer);
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ assert(ectx->hash_vector_size <= RHASH_HASH_COUNT);
+
+ /* skip final call if already finalized and auto-final is on */
+ if ((ectx->flags & RCTX_FINALIZED_MASK) ==
+ (RCTX_AUTO_FINAL | RCTX_FINALIZED)) return 0;
+
+ /* call final method for every algorithm */
+ for (i = 0; i < ectx->hash_vector_size; i++) {
+ struct rhash_hash_info* info = ectx->vector[i].hash_info;
+ assert(info->final != 0);
+ assert(info->info->digest_size < sizeof(buffer));
+ info->final(ectx->vector[i].context, out);
+ out = buffer;
+ }
+ ectx->flags |= RCTX_FINALIZED;
+ return 0; /* no error processing at the moment */
+}
+
+/**
+ * Store digest for given hash_id.
+ * If hash_id is zero, function stores digest for a hash with the lowest id found in the context.
+ * For nonzero hash_id the context must contain it, otherwise function silently does nothing.
+ *
+ * @param ctx rhash context
+ * @param hash_id id of hash to retrieve or zero for hash with the lowest available id
+ * @param result buffer to put the hash into
+ */
+static void rhash_put_digest(rhash ctx, unsigned hash_id, unsigned char* result)
+{
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ unsigned i;
+ rhash_vector_item *item;
+ struct rhash_hash_info* info;
+ unsigned char* digest;
+
+ assert(ectx);
+ assert(ectx->hash_vector_size > 0 && ectx->hash_vector_size <= RHASH_HASH_COUNT);
+
+ /* finalize context if not yet finalized and auto-final is on */
+ if ((ectx->flags & RCTX_FINALIZED_MASK) == RCTX_AUTO_FINAL) {
+ rhash_final(ctx, NULL);
+ }
+
+ if (hash_id == 0) {
+ item = &ectx->vector[0]; /* get the first hash */
+ info = item->hash_info;
+ } else {
+ for (i = 0;; i++) {
+ if (i >= ectx->hash_vector_size) {
+ return; /* hash_id not found, do nothing */
+ }
+ item = &ectx->vector[i];
+ info = item->hash_info;
+ if (info->info->hash_id == hash_id) break;
+ }
+ }
+ digest = ((unsigned char*)item->context + info->digest_diff);
+ if (info->info->flags & F_SWAP32) {
+ assert((info->info->digest_size & 3) == 0);
+ /* NB: the next call is correct only for multiple of 4 byte size */
+ rhash_swap_copy_str_to_u32(result, 0, digest, info->info->digest_size);
+ } else if (info->info->flags & F_SWAP64) {
+ rhash_swap_copy_u64_to_str(result, digest, info->info->digest_size);
+ } else {
+ memcpy(result, digest, info->info->digest_size);
+ }
+}
+
+/**
+ * Set the callback function to be called from the
+ * rhash_file() and rhash_file_update() functions
+ * on processing every file block. The file block
+ * size is set internally by rhash and now is 8 KiB.
+ *
+ * @param ctx rhash context
+ * @param callback pointer to the callback function
+ * @param callback_data pointer to data passed to the callback
+ */
+RHASH_API void rhash_set_callback(rhash ctx, rhash_callback_t callback, void* callback_data)
+{
+ ((rhash_context_ext*)ctx)->callback = callback;
+ ((rhash_context_ext*)ctx)->callback_data = callback_data;
+}
+
+
+/* hi-level message hashing interface */
+
+/**
+ * Compute a hash of the given message.
+ *
+ * @param hash_id id of hash sum to compute
+ * @param message the message to process
+ * @param length message length
+ * @param result buffer to receive binary hash string
+ * @return 0 on success, -1 on error
+ */
+RHASH_API int rhash_msg(unsigned hash_id, const void* message, size_t length, unsigned char* result)
+{
+ rhash ctx;
+ hash_id &= RHASH_ALL_HASHES;
+ ctx = rhash_init(hash_id);
+ if (ctx == NULL) return -1;
+ rhash_update(ctx, message, length);
+ rhash_final(ctx, result);
+ rhash_free(ctx);
+ return 0;
+}
+
+/**
+ * Hash a file or stream. Multiple hashes can be computed.
+ * First, inintialize ctx parameter with rhash_init() before calling
+ * rhash_file_update(). Then use rhash_final() and rhash_print()
+ * to retrive hash values. Finaly call rhash_free() on ctx
+ * to free allocated memory or call rhash_reset() to reuse ctx.
+ *
+ * @param ctx rhash context
+ * @param fd descriptor of the file to hash
+ * @return 0 on success, -1 on error and errno is set
+ */
+RHASH_API int rhash_file_update(rhash ctx, FILE* fd)
+{
+ rhash_context_ext* const ectx = (rhash_context_ext*)ctx;
+ const size_t block_size = 8192;
+ unsigned char *buffer, *pmem;
+ size_t length = 0, align8;
+ int res = 0;
+ if (ectx->state != STATE_ACTIVE) return 0; /* do nothing if canceled */
+
+ if (ctx == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ pmem = (unsigned char*)malloc(block_size + 8);
+ if (!pmem) return -1; /* errno is set to ENOMEM according to UNIX 98 */
+
+ align8 = ((unsigned char*)0 - pmem) & 7;
+ buffer = pmem + align8;
+
+ while (!feof(fd)) {
+ /* stop if canceled */
+ if (ectx->state != STATE_ACTIVE) break;
+
+ length = fread(buffer, 1, block_size, fd);
+
+ if (ferror(fd)) {
+ res = -1; /* note: errno contains error code */
+ break;
+ } else if (length) {
+ rhash_update(ctx, buffer, length);
+
+ if (ectx->callback) {
+ ((rhash_callback_t)ectx->callback)(ectx->callback_data, ectx->rc.msg_size);
+ }
+ }
+ }
+
+ free(buffer);
+ return res;
+}
+
+/**
+ * Compute a single hash for given file.
+ *
+ * @param hash_id id of hash sum to compute
+ * @param filepath path to the file to hash
+ * @param result buffer to receive hash value with the lowest requested id
+ * @return 0 on success, -1 on error and errno is set
+ */
+RHASH_API int rhash_file(unsigned hash_id, const char* filepath, unsigned char* result)
+{
+ FILE* fd;
+ rhash ctx;
+ int res;
+
+ hash_id &= RHASH_ALL_HASHES;
+ if (hash_id == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((fd = fopen(filepath, "rb")) == NULL) return -1;
+
+ if ((ctx = rhash_init(hash_id)) == NULL) return -1;
+
+ res = rhash_file_update(ctx, fd); /* hash the file */
+ fclose(fd);
+
+ rhash_final(ctx, result);
+ rhash_free(ctx);
+ return res;
+}
+
+#ifdef _WIN32 /* windows only function */
+#include <share.h>
+
+/**
+ * Compute a single hash for given file.
+ *
+ * @param hash_id id of hash sum to compute
+ * @param filepath path to the file to hash
+ * @param result buffer to receive hash value with the lowest requested id
+ * @return 0 on success, -1 on error, -1 on error and errno is set
+ */
+RHASH_API int rhash_wfile(unsigned hash_id, const wchar_t* filepath, unsigned char* result)
+{
+ FILE* fd;
+ rhash ctx;
+ int res;
+
+ hash_id &= RHASH_ALL_HASHES;
+ if (hash_id == 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if ((fd = _wfsopen(filepath, L"rb", _SH_DENYWR)) == NULL) return -1;
+
+ if ((ctx = rhash_init(hash_id)) == NULL) return -1;
+
+ res = rhash_file_update(ctx, fd); /* hash the file */
+ fclose(fd);
+
+ rhash_final(ctx, result);
+ rhash_free(ctx);
+ return res;
+}
+#endif
+
+/* RHash information functions */
+
+/**
+ * Returns information about a hash function by its hash_id.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return pointer to the rhash_info structure containing the information
+ */
+const rhash_info* rhash_info_by_id(unsigned hash_id)
+{
+ hash_id &= RHASH_ALL_HASHES;
+ /* check that only one bit is set */
+ if (hash_id != (hash_id & -(int)hash_id)) return NULL;
+ /* note: alternative condition is (hash_id == 0 || (hash_id & (hash_id - 1)) != 0) */
+ return rhash_info_table[rhash_ctz(hash_id)].info;
+}
+
+#if 0
+/**
+ * Detect default digest output format for given hash algorithm.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return 1 for base32 format, 0 for hexadecimal
+ */
+RHASH_API int rhash_is_base32(unsigned hash_id)
+{
+ /* fast method is just to test a bit-mask */
+ return ((hash_id & (RHASH_TTH | RHASH_AICH)) != 0);
+}
+#endif
+
+/**
+ * Returns size of binary digest for given hash algorithm.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return digest size in bytes
+ */
+RHASH_API int rhash_get_digest_size(unsigned hash_id)
+{
+ hash_id &= RHASH_ALL_HASHES;
+ if (hash_id == 0 || (hash_id & (hash_id - 1)) != 0) return -1;
+ return (int)rhash_info_table[rhash_ctz(hash_id)].info->digest_size;
+}
+
+/**
+ * Returns length of digest hash string in default output format.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return the length of hash string
+ */
+RHASH_API int rhash_get_hash_length(unsigned hash_id)
+{
+ const rhash_info* info = rhash_info_by_id(hash_id);
+ return (int)(info ? (info->flags & F_BS32 ?
+ BASE32_LENGTH(info->digest_size) : info->digest_size * 2) : 0);
+}
+
+/**
+ * Returns a name of given hash algorithm.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return algorithm name
+ */
+RHASH_API const char* rhash_get_name(unsigned hash_id)
+{
+ const rhash_info* info = rhash_info_by_id(hash_id);
+ return (info ? info->name : 0);
+}
+
+/**
+ * Returns a name part of magnet urn of the given hash algorithm.
+ * Such magnet_name is used to generate a magnet link of the form
+ * urn:&lt;magnet_name&gt;=&lt;hash_value&gt;.
+ *
+ * @param hash_id the id of hash algorithm
+ * @return name
+ */
+RHASH_API const char* rhash_get_magnet_name(unsigned hash_id)
+{
+ const rhash_info* info = rhash_info_by_id(hash_id);
+ return (info ? info->magnet_name : 0);
+}
+
+#if 0
+static size_t rhash_get_magnet_url_size(const char* filepath,
+ rhash context, unsigned hash_mask, int flags)
+{
+ size_t size = 0; /* count terminating '\0' */
+ unsigned bit, hash = context->hash_id & hash_mask;
+
+ /* RHPR_NO_MAGNET, RHPR_FILESIZE */
+ if ((flags & RHPR_NO_MAGNET) == 0) {
+ size += 8;
+ }
+
+ if ((flags & RHPR_FILESIZE) != 0) {
+ uint64_t num = context->msg_size;
+
+ size += 4;
+ if (num == 0) size++;
+ else {
+ for (; num; num /= 10, size++);
+ }
+ }
+
+ if (filepath) {
+ size += 4 + rhash_urlencode(NULL, filepath);
+ }
+
+ /* loop through hash values */
+ for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
+ const char* name;
+ if ((bit & hash) == 0) continue;
+ if ((name = rhash_get_magnet_name(bit)) == 0) continue;
+
+ size += (7 + 2) + strlen(name);
+ size += rhash_print(NULL, context, bit,
+ (bit & (RHASH_SHA1 | RHASH_BTIH) ? RHPR_BASE32 : 0));
+ }
+
+ return size;
+}
+
+/**
+ * Print magnet link with given filepath and calculated hash sums into the
+ * output buffer. The hash_mask can limit which hash values will be printed.
+ * The function returns the size of the required buffer.
+ * If output is NULL the .
+ *
+ * @param output a string buffer to receive the magnet link or NULL
+ * @param filepath the file path to be printed or NULL
+ * @param context algorithms state
+ * @param hash_mask bit mask of the hash sums to add to the link
+ * @param flags can be combination of bits RHPR_UPPERCASE, RHPR_NO_MAGNET,
+ * RHPR_FILESIZE
+ * @return number of written characters, including terminating '\0' on success, 0 on fail
+ */
+RHASH_API size_t rhash_print_magnet(char* output, const char* filepath,
+ rhash context, unsigned hash_mask, int flags)
+{
+ int i;
+ const char* begin = output;
+
+ if (output == NULL) return rhash_get_magnet_url_size(
+ filepath, context, hash_mask, flags);
+
+ /* RHPR_NO_MAGNET, RHPR_FILESIZE */
+ if ((flags & RHPR_NO_MAGNET) == 0) {
+ strcpy(output, "magnet:?");
+ output += 8;
+ }
+
+ if ((flags & RHPR_FILESIZE) != 0) {
+ strcpy(output, "xl=");
+ output += 3;
+ output += rhash_sprintI64(output, context->msg_size);
+ *(output++) = '&';
+ }
+
+ if (filepath) {
+ strcpy(output, "dn=");
+ output += 3;
+ output += rhash_urlencode(output, filepath);
+ *(output++) = '&';
+ }
+ flags &= RHPR_UPPERCASE;
+
+ for (i = 0; i < 2; i++) {
+ unsigned bit;
+ unsigned hash = context->hash_id & hash_mask;
+ hash = (i == 0 ? hash & (RHASH_ED2K | RHASH_AICH)
+ : hash & ~(RHASH_ED2K | RHASH_AICH));
+ if (!hash) continue;
+
+ /* loop through hash values */
+ for (bit = hash & -(int)hash; bit <= hash; bit <<= 1) {
+ const char* name;
+ if ((bit & hash) == 0) continue;
+ if (!(name = rhash_get_magnet_name(bit))) continue;
+
+ strcpy(output, "xt=urn:");
+ output += 7;
+ strcpy(output, name);
+ output += strlen(name);
+ *(output++) = ':';
+ output += rhash_print(output, context, bit,
+ (bit & (RHASH_SHA1 | RHASH_BTIH) ? flags | RHPR_BASE32 : flags));
+ *(output++) = '&';
+ }
+ }
+ output[-1] = '\0'; /* terminate the line */
+
+ return (output - begin);
+}
+
+/* hash sum output */
+
+/**
+ * Print a text presentation of a given hash sum to the specified buffer,
+ *
+ * @param output a buffer to print the hash to
+ * @param bytes a hash sum to print
+ * @param size a size of hash sum in bytes
+ * @param flags a bit-mask controlling how to format the hash sum,
+ * can be a mix of the flags: RHPR_RAW, RHPR_HEX, RHPR_BASE32,
+ * RHPR_BASE64, RHPR_UPPERCASE, RHPR_REVERSE
+ * @return the number of written characters
+ */
+size_t rhash_print_bytes(char* output, const unsigned char* bytes,
+ size_t size, int flags)
+{
+ size_t str_len;
+ int upper_case = (flags & RHPR_UPPERCASE);
+ int format = (flags & ~RHPR_MODIFIER);
+
+ switch (format) {
+ case RHPR_HEX:
+ str_len = size * 2;
+ rhash_byte_to_hex(output, bytes, (unsigned)size, upper_case);
+ break;
+ case RHPR_BASE32:
+ str_len = BASE32_LENGTH(size);
+ rhash_byte_to_base32(output, bytes, (unsigned)size, upper_case);
+ break;
+ case RHPR_BASE64:
+ str_len = BASE64_LENGTH(size);
+ rhash_byte_to_base64(output, bytes, (unsigned)size);
+ break;
+ default:
+ str_len = size;
+ memcpy(output, bytes, size);
+ break;
+ }
+ return str_len;
+}
+
+/**
+ * Print text presentation of a hash sum with given hash_id to the specified
+ * output buffer. If the hash_id is zero, then print the hash sum with
+ * the lowest id stored in the hash context.
+ * The function call fails if the context doesn't include a hash with the
+ * given hash_id.
+ *
+ * @param output a buffer to print the hash to
+ * @param context algorithms state
+ * @param hash_id id of the hash sum to print or 0 to print the first hash
+ * saved in the context.
+ * @param flags a bitmask controlling how to print the hash. Can contain flags
+ * RHPR_UPPERCASE, RHPR_HEX, RHPR_BASE32, RHPR_BASE64, etc.
+ * @return the number of written characters on success or 0 on fail
+ */
+size_t RHASH_API rhash_print(char* output, rhash context, unsigned hash_id, int flags)
+{
+ const rhash_info* info;
+ unsigned char digest[80];
+ size_t digest_size;
+
+ info = (hash_id != 0 ? rhash_info_by_id(hash_id) :
+ ((rhash_context_ext*)context)->vector[0].hash_info->info);
+
+ if (info == NULL) return 0;
+ digest_size = info->digest_size;
+ assert(digest_size <= 64);
+
+ flags &= (RHPR_FORMAT | RHPR_MODIFIER);
+ if ((flags & RHPR_FORMAT) == 0) {
+ /* use default format if not specified by flags */
+ flags |= (info->flags & RHASH_INFO_BASE32 ? RHPR_BASE32 : RHPR_HEX);
+ }
+
+ if (output == NULL) {
+ switch (flags & RHPR_FORMAT) {
+ case RHPR_HEX:
+ return (digest_size * 2);
+ case RHPR_BASE32:
+ return BASE32_LENGTH(digest_size);
+ case RHPR_BASE64:
+ return BASE64_LENGTH(digest_size);
+ default:
+ return digest_size;
+ }
+ }
+
+ /* note: use info->hash_id, cause hash_id can be 0 */
+ rhash_put_digest(context, info->hash_id, digest);
+
+ if ((flags & ~RHPR_UPPERCASE) == (RHPR_REVERSE | RHPR_HEX)) {
+ /* reverse the digest */
+ unsigned char *p = digest, *r = digest + digest_size - 1;
+ char tmp;
+ for (; p < r; p++, r--) {
+ tmp = *p;
+ *p = *r;
+ *r = tmp;
+ }
+ }
+
+ return rhash_print_bytes(output, digest, digest_size, flags);
+}
+
+#if defined(_WIN32) && defined(RHASH_EXPORTS)
+#include <windows.h>
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved);
+BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID reserved)
+{
+ (void)hModule;
+ (void)reserved;
+ switch (reason) {
+ case DLL_PROCESS_ATTACH:
+ rhash_library_init();
+ break;
+ case DLL_PROCESS_DETACH:
+ /*rhash_library_free();*/
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+#define PVOID2UPTR(p) ((rhash_uptr_t)((char*)p - 0))
+
+/**
+ * Process a rhash message.
+ *
+ * @param msg_id message identifier
+ * @param dst message destination (can be NULL for generic messages)
+ * @param ldata data depending on message
+ * @param rdata data depending on message
+ * @return message-specific data
+ */
+RHASH_API rhash_uptr_t rhash_transmit(unsigned msg_id, void* dst, rhash_uptr_t ldata, rhash_uptr_t rdata)
+{
+ /* for messages working with rhash context */
+ rhash_context_ext* const ctx = (rhash_context_ext*)dst;
+
+ switch (msg_id) {
+ case RMSG_GET_CONTEXT:
+ {
+ unsigned i;
+ for (i = 0; i < ctx->hash_vector_size; i++) {
+ struct rhash_hash_info* info = ctx->vector[i].hash_info;
+ if (info->info->hash_id == (unsigned)ldata)
+ return PVOID2UPTR(ctx->vector[i].context);
+ }
+ return (rhash_uptr_t)0;
+ }
+
+ case RMSG_CANCEL:
+ /* mark rhash context as canceled, in a multithreaded program */
+ atomic_compare_and_swap(&ctx->state, STATE_ACTIVE, STATE_STOPED);
+ return 0;
+
+ case RMSG_IS_CANCELED:
+ return (ctx->state == STATE_STOPED);
+
+ case RMSG_GET_FINALIZED:
+ return ((ctx->flags & RCTX_FINALIZED) != 0);
+ case RMSG_SET_AUTOFINAL:
+ ctx->flags &= ~RCTX_AUTO_FINAL;
+ if (ldata) ctx->flags |= RCTX_AUTO_FINAL;
+ break;
+
+ /* OpenSSL related messages */
+#ifdef USE_OPENSSL
+ case RMSG_SET_OPENSSL_MASK:
+ rhash_openssl_hash_mask = (unsigned)ldata;
+ break;
+ case RMSG_GET_OPENSSL_MASK:
+ return rhash_openssl_hash_mask;
+#endif
+
+ default:
+ return RHASH_ERROR; /* unknown message */
+ }
+ return 0;
+}
+#endif
diff --git a/Utilities/cmlibrhash/librhash/rhash.h b/Utilities/cmlibrhash/librhash/rhash.h
new file mode 100644
index 000000000..cee0e253e
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/rhash.h
@@ -0,0 +1,288 @@
+/** @file rhash.h LibRHash interface */
+#ifndef RHASH_H
+#define RHASH_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef RHASH_API
+/* modifier for LibRHash functions */
+# define RHASH_API
+#endif
+
+/**
+ * Identifiers of supported hash functions.
+ * The rhash_init() function allows mixing several ids using
+ * binary OR, to calculate several hash functions for one message.
+ */
+enum rhash_ids
+{
+#if 0
+ RHASH_CRC32 = 0x01,
+ RHASH_MD4 = 0x02,
+ RHASH_MD5 = 0x04,
+ RHASH_SHA1 = 0x08,
+ RHASH_TIGER = 0x10,
+ RHASH_TTH = 0x20,
+ RHASH_BTIH = 0x40,
+ RHASH_ED2K = 0x80,
+ RHASH_AICH = 0x100,
+ RHASH_WHIRLPOOL = 0x200,
+ RHASH_RIPEMD160 = 0x400,
+ RHASH_GOST = 0x800,
+ RHASH_GOST_CRYPTOPRO = 0x1000,
+ RHASH_HAS160 = 0x2000,
+ RHASH_SNEFRU128 = 0x4000,
+ RHASH_SNEFRU256 = 0x8000,
+ RHASH_SHA224 = 0x10000,
+ RHASH_SHA256 = 0x20000,
+ RHASH_SHA384 = 0x40000,
+ RHASH_SHA512 = 0x80000,
+ RHASH_EDONR256 = 0x0100000,
+ RHASH_EDONR512 = 0x0200000,
+ RHASH_SHA3_224 = 0x0400000,
+ RHASH_SHA3_256 = 0x0800000,
+ RHASH_SHA3_384 = 0x1000000,
+ RHASH_SHA3_512 = 0x2000000,
+
+ /** The bit-mask containing all supported hashe functions */
+ RHASH_ALL_HASHES = RHASH_CRC32 | RHASH_MD4 | RHASH_MD5 | RHASH_ED2K | RHASH_SHA1 |
+ RHASH_TIGER | RHASH_TTH | RHASH_GOST | RHASH_GOST_CRYPTOPRO |
+ RHASH_BTIH | RHASH_AICH | RHASH_WHIRLPOOL | RHASH_RIPEMD160 |
+ RHASH_HAS160 | RHASH_SNEFRU128 | RHASH_SNEFRU256 |
+ RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | RHASH_SHA512 |
+ RHASH_SHA3_224 | RHASH_SHA3_256 | RHASH_SHA3_384 | RHASH_SHA3_512 |
+ RHASH_EDONR256 | RHASH_EDONR512,
+
+ /** The number of supported hash functions */
+ RHASH_HASH_COUNT = 26
+#else
+ RHASH_MD5 = 0x01,
+ RHASH_SHA1 = 0x02,
+ RHASH_SHA224 = 0x04,
+ RHASH_SHA256 = 0x08,
+ RHASH_SHA384 = 0x10,
+ RHASH_SHA512 = 0x20,
+ RHASH_SHA3_224 = 0x40,
+ RHASH_SHA3_256 = 0x80,
+ RHASH_SHA3_384 = 0x100,
+ RHASH_SHA3_512 = 0x200,
+ RHASH_ALL_HASHES =
+ RHASH_MD5 |
+ RHASH_SHA1 |
+ RHASH_SHA224 |
+ RHASH_SHA256 |
+ RHASH_SHA384 |
+ RHASH_SHA512 |
+ RHASH_SHA3_224 |
+ RHASH_SHA3_256 |
+ RHASH_SHA3_384 |
+ RHASH_SHA3_512,
+ RHASH_HASH_COUNT = 10
+#endif
+};
+
+/**
+ * The rhash context structure contains contexts for several hash functions
+ */
+typedef struct rhash_context
+{
+ /** The size of the hashed message */
+ unsigned long long msg_size;
+
+ /**
+ * The bit-mask containing identifiers of the hashes being calculated
+ */
+ unsigned hash_id;
+} rhash_context;
+
+#ifndef LIBRHASH_RHASH_CTX_DEFINED
+#define LIBRHASH_RHASH_CTX_DEFINED
+/**
+ * Hashing context.
+ */
+typedef struct rhash_context* rhash;
+#endif /* LIBRHASH_RHASH_CTX_DEFINED */
+
+/** type of a callback to be called periodically while hashing a file */
+typedef void (*rhash_callback_t)(void* data, unsigned long long offset);
+
+RHASH_API void rhash_library_init(void); /* initialize static data */
+
+/* hi-level hashing functions */
+RHASH_API int rhash_msg(unsigned hash_id, const void* message, size_t length, unsigned char* result);
+RHASH_API int rhash_file(unsigned hash_id, const char* filepath, unsigned char* result);
+RHASH_API int rhash_file_update(rhash ctx, FILE* fd);
+
+#ifdef _WIN32 /* windows only function */
+RHASH_API int rhash_wfile(unsigned hash_id, const wchar_t* filepath, unsigned char* result);
+#endif
+
+/* lo-level interface */
+RHASH_API rhash rhash_init(unsigned hash_id);
+/*RHASH_API rhash rhash_init_by_ids(unsigned hash_ids[], unsigned count);*/
+RHASH_API int rhash_update(rhash ctx, const void* message, size_t length);
+RHASH_API int rhash_final(rhash ctx, unsigned char* first_result);
+RHASH_API void rhash_reset(rhash ctx); /* reinitialize the context */
+RHASH_API void rhash_free(rhash ctx);
+
+/* additional lo-level functions */
+RHASH_API void rhash_set_callback(rhash ctx, rhash_callback_t callback, void* callback_data);
+
+/** bit-flag: default hash output format is base32 */
+#define RHASH_INFO_BASE32 1
+
+/**
+ * Information about a hash function.
+ */
+typedef struct rhash_info
+{
+ /** hash function indentifier */
+ unsigned hash_id;
+ /** flags bit-mask, including RHASH_INFO_BASE32 bit */
+ unsigned flags;
+ /** size of binary message digest in bytes */
+ size_t digest_size;
+ const char* name;
+ const char* magnet_name;
+} rhash_info;
+
+/* information functions */
+RHASH_API int rhash_count(void); /* number of supported hashes */
+RHASH_API int rhash_get_digest_size(unsigned hash_id); /* size of binary message digest */
+RHASH_API int rhash_get_hash_length(unsigned hash_id); /* length of formatted hash string */
+RHASH_API int rhash_is_base32(unsigned hash_id); /* default digest output format */
+RHASH_API const char* rhash_get_name(unsigned hash_id); /* get hash function name */
+RHASH_API const char* rhash_get_magnet_name(unsigned hash_id); /* get name part of magnet urn */
+
+/* note, that rhash_info_by_id() is not exported to a shared library or DLL */
+const rhash_info* rhash_info_by_id(unsigned hash_id); /* get hash sum info by hash id */
+
+#if 0
+/**
+ * Flags for printing a hash sum
+ */
+enum rhash_print_sum_flags
+{
+ /** print in a default format */
+ RHPR_DEFAULT = 0x0,
+ /** output as binary message digest */
+ RHPR_RAW = 0x1,
+ /** print as a hexadecimal string */
+ RHPR_HEX = 0x2,
+ /** print as a base32-encoded string */
+ RHPR_BASE32 = 0x3,
+ /** print as a base64-encoded string */
+ RHPR_BASE64 = 0x4,
+
+ /**
+ * Print as an uppercase string. Can be used
+ * for base32 or hexadecimal format only.
+ */
+ RHPR_UPPERCASE = 0x8,
+
+ /**
+ * Reverse hash bytes. Can be used for GOST hash.
+ */
+ RHPR_REVERSE = 0x10,
+
+ /** don't print 'magnet:?' prefix in rhash_print_magnet */
+ RHPR_NO_MAGNET = 0x20,
+ /** print file size in rhash_print_magnet */
+ RHPR_FILESIZE = 0x40,
+};
+#endif
+
+/* output hash into the given buffer */
+RHASH_API size_t rhash_print_bytes(char* output,
+ const unsigned char* bytes, size_t size, int flags);
+
+RHASH_API size_t rhash_print(char* output, rhash ctx, unsigned hash_id,
+ int flags);
+
+/* output magnet URL into the given buffer */
+RHASH_API size_t rhash_print_magnet(char* output, const char* filepath,
+ rhash context, unsigned hash_mask, int flags);
+
+/* macros for message API */
+
+/** The type of an unsigned integer large enough to hold a pointer */
+#if defined(UINTPTR_MAX)
+typedef uintptr_t rhash_uptr_t;
+#elif defined(_LP64) || defined(__LP64__) || defined(__x86_64) || \
+ defined(__x86_64__) || defined(_M_AMD64) || defined(_M_X64)
+typedef unsigned long long rhash_uptr_t;
+#else
+typedef unsigned long rhash_uptr_t;
+#endif
+
+/** The value returned by rhash_transmit on error */
+#define RHASH_ERROR ((rhash_uptr_t)-1)
+/** Convert a pointer to rhash_uptr_t */
+#define RHASH_STR2UPTR(str) ((rhash_uptr_t)(char*)(str))
+/** Convert a rhash_uptr_t to a void* pointer */
+#define RHASH_UPTR2PVOID(u) ((void*)((char*)0 + (u)))
+
+/* rhash API to set/get data via messages */
+RHASH_API rhash_uptr_t rhash_transmit(
+ unsigned msg_id, void* dst, rhash_uptr_t ldata, rhash_uptr_t rdata);
+
+/* rhash message constants */
+
+#define RMSG_GET_CONTEXT 1
+#define RMSG_CANCEL 2
+#define RMSG_IS_CANCELED 3
+#define RMSG_GET_FINALIZED 4
+#define RMSG_SET_AUTOFINAL 5
+#define RMSG_SET_OPENSSL_MASK 10
+#define RMSG_GET_OPENSSL_MASK 11
+
+/* helper macros */
+
+/** Get a pointer to context of the specified hash function */
+#define rhash_get_context_ptr(ctx, hash_id) RHASH_UPTR2PVOID(rhash_transmit(RMSG_GET_CONTEXT, ctx, hash_id, 0))
+/** Cancel hash calculation of a file */
+#define rhash_cancel(ctx) rhash_transmit(RMSG_CANCEL, ctx, 0, 0)
+/** Return non-zero if hash calculation was canceled, zero otherwise */
+#define rhash_is_canceled(ctx) rhash_transmit(RMSG_IS_CANCELED, ctx, 0, 0)
+/** Return non-zero if rhash_final was called for rhash_context */
+#define rhash_get_finalized(ctx) rhash_transmit(RMSG_GET_FINALIZED, ctx, 0, 0)
+
+/**
+ * Turn on/off the auto-final flag for the given rhash_context. By default
+ * auto-final is on, which means rhash_final is called automatically, if
+ * needed when a hash value is retrived by rhash_print call.
+ */
+#define rhash_set_autofinal(ctx, on) rhash_transmit(RMSG_SET_AUTOFINAL, ctx, on, 0)
+
+/**
+ * Set the bit-mask of hash algorithms to be calculated by OpenSSL library.
+ * The call rhash_set_openssl_mask(0) made before rhash_library_init(),
+ * turns off loading of the OpenSSL dynamic library.
+ * This call works if the LibRHash was compiled with OpenSSL support.
+ */
+#define rhash_set_openssl_mask(mask) rhash_transmit(RMSG_SET_OPENSSL_MASK, NULL, mask, 0)
+
+/**
+ * Return current bit-mask of hash algorithms selected to be calculated
+ * by OpenSSL library.
+ */
+#define rhash_get_openssl_mask() rhash_transmit(RMSG_GET_OPENSSL_MASK, NULL, 0, 0)
+
+/** The bit mask of hash algorithms implemented by OpenSSL */
+#if defined(USE_OPENSSL) || defined(OPENSSL_RUNTIME)
+# define RHASH_OPENSSL_SUPPORTED_HASHES (RHASH_MD4 | RHASH_MD5 | \
+ RHASH_SHA1 | RHASH_SHA224 | RHASH_SHA256 | RHASH_SHA384 | \
+ RHASH_SHA512 | RHASH_RIPEMD160 | RHASH_WHIRLPOOL)
+#else
+# define RHASH_OPENSSL_SUPPORTED_HASHES 0
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* RHASH_H */
diff --git a/Utilities/cmlibrhash/librhash/sha1.c b/Utilities/cmlibrhash/librhash/sha1.c
new file mode 100644
index 000000000..f5a053be2
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha1.c
@@ -0,0 +1,196 @@
+/* sha1.c - an implementation of Secure Hash Algorithm 1 (SHA1)
+ * based on RFC 3174.
+ *
+ * Copyright: 2008-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <string.h>
+#include "byte_order.h"
+#include "sha1.h"
+
+/**
+ * Initialize context before calculaing hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha1_init(sha1_ctx *ctx)
+{
+ ctx->length = 0;
+
+ /* initialize algorithm state */
+ ctx->hash[0] = 0x67452301;
+ ctx->hash[1] = 0xefcdab89;
+ ctx->hash[2] = 0x98badcfe;
+ ctx->hash[3] = 0x10325476;
+ ctx->hash[4] = 0xc3d2e1f0;
+}
+
+/**
+ * The core transformation. Process a 512-bit block.
+ * The function has been taken from RFC 3174 with little changes.
+ *
+ * @param hash algorithm state
+ * @param block the message block to process
+ */
+static void rhash_sha1_process_block(unsigned* hash, const unsigned* block)
+{
+ int t; /* Loop counter */
+ uint32_t temp; /* Temporary word value */
+ uint32_t W[80]; /* Word sequence */
+ uint32_t A, B, C, D, E; /* Word buffers */
+
+ /* initialize the first 16 words in the array W */
+ for (t = 0; t < 16; t++) {
+ /* note: it is much faster to apply be2me here, then using be32_copy */
+ W[t] = be2me_32(block[t]);
+ }
+
+ /* initialize the rest */
+ for (t = 16; t < 80; t++) {
+ W[t] = ROTL32(W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16], 1);
+ }
+
+ A = hash[0];
+ B = hash[1];
+ C = hash[2];
+ D = hash[3];
+ E = hash[4];
+
+ for (t = 0; t < 20; t++) {
+ /* the following is faster than ((B & C) | ((~B) & D)) */
+ temp = ROTL32(A, 5) + (((C ^ D) & B) ^ D)
+ + E + W[t] + 0x5A827999;
+ E = D;
+ D = C;
+ C = ROTL32(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 20; t < 40; t++) {
+ temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0x6ED9EBA1;
+ E = D;
+ D = C;
+ C = ROTL32(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 40; t < 60; t++) {
+ temp = ROTL32(A, 5) + ((B & C) | (B & D) | (C & D))
+ + E + W[t] + 0x8F1BBCDC;
+ E = D;
+ D = C;
+ C = ROTL32(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (t = 60; t < 80; t++) {
+ temp = ROTL32(A, 5) + (B ^ C ^ D) + E + W[t] + 0xCA62C1D6;
+ E = D;
+ D = C;
+ C = ROTL32(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ hash[0] += A;
+ hash[1] += B;
+ hash[2] += C;
+ hash[3] += D;
+ hash[4] += E;
+}
+
+/**
+ * Calculate message hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size)
+{
+ unsigned index = (unsigned)ctx->length & 63;
+ ctx->length += size;
+
+ /* fill partial block */
+ if (index) {
+ unsigned left = sha1_block_size - index;
+ memcpy(ctx->message + index, msg, (size < left ? size : left));
+ if (size < left) return;
+
+ /* process partial block */
+ rhash_sha1_process_block(ctx->hash, (unsigned*)ctx->message);
+ msg += left;
+ size -= left;
+ }
+ while (size >= sha1_block_size) {
+ unsigned* aligned_message_block;
+ if (IS_ALIGNED_32(msg)) {
+ /* the most common case is processing of an already aligned message
+ without copying it */
+ aligned_message_block = (unsigned*)msg;
+ } else {
+ memcpy(ctx->message, msg, sha1_block_size);
+ aligned_message_block = (unsigned*)ctx->message;
+ }
+
+ rhash_sha1_process_block(ctx->hash, aligned_message_block);
+ msg += sha1_block_size;
+ size -= sha1_block_size;
+ }
+ if (size) {
+ /* save leftovers */
+ memcpy(ctx->message, msg, size);
+ }
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param result calculated hash in binary form
+ */
+void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result)
+{
+ unsigned index = (unsigned)ctx->length & 63;
+ unsigned* msg32 = (unsigned*)ctx->message;
+
+ /* pad message and run for last block */
+ ctx->message[index++] = 0x80;
+ while ((index & 3) != 0) {
+ ctx->message[index++] = 0;
+ }
+ index >>= 2;
+
+ /* if no room left in the message to store 64-bit message length */
+ if (index > 14) {
+ /* then fill the rest with zeros and process it */
+ while (index < 16) {
+ msg32[index++] = 0;
+ }
+ rhash_sha1_process_block(ctx->hash, msg32);
+ index = 0;
+ }
+ while (index < 14) {
+ msg32[index++] = 0;
+ }
+ msg32[14] = be2me_32( (unsigned)(ctx->length >> 29) );
+ msg32[15] = be2me_32( (unsigned)(ctx->length << 3) );
+ rhash_sha1_process_block(ctx->hash, msg32);
+
+ if (result) be32_copy(result, 0, &ctx->hash, sha1_hash_size);
+}
diff --git a/Utilities/cmlibrhash/librhash/sha1.h b/Utilities/cmlibrhash/librhash/sha1.h
new file mode 100644
index 000000000..74b2f948f
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha1.h
@@ -0,0 +1,31 @@
+/* sha1.h */
+#ifndef SHA1_H
+#define SHA1_H
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sha1_block_size 64
+#define sha1_hash_size 20
+
+/* algorithm context */
+typedef struct sha1_ctx
+{
+ unsigned char message[sha1_block_size]; /* 512-bit buffer for leftovers */
+ uint64_t length; /* number of processed bytes */
+ unsigned hash[5]; /* 160-bit algorithm internal hashing state */
+} sha1_ctx;
+
+/* hash functions */
+
+void rhash_sha1_init(sha1_ctx *ctx);
+void rhash_sha1_update(sha1_ctx *ctx, const unsigned char* msg, size_t size);
+void rhash_sha1_final(sha1_ctx *ctx, unsigned char* result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SHA1_H */
diff --git a/Utilities/cmlibrhash/librhash/sha256.c b/Utilities/cmlibrhash/librhash/sha256.c
new file mode 100644
index 000000000..af5b0fe54
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha256.c
@@ -0,0 +1,241 @@
+/* sha256.c - an implementation of SHA-256/224 hash functions
+ * based on FIPS 180-3 (Federal Information Processing Standart).
+ *
+ * Copyright: 2010-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <string.h>
+#include "byte_order.h"
+#include "sha256.h"
+
+/* SHA-224 and SHA-256 constants for 64 rounds. These words represent
+ * the first 32 bits of the fractional parts of the cube
+ * roots of the first 64 prime numbers. */
+static const unsigned rhash_k256[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1,
+ 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786,
+ 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147,
+ 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
+ 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a,
+ 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+/* The SHA256/224 functions defined by FIPS 180-3, 4.1.2 */
+/* Optimized version of Ch(x,y,z)=((x & y) | (~x & z)) */
+#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
+/* Optimized version of Maj(x,y,z)=((x & y) ^ (x & z) ^ (y & z)) */
+#define Maj(x,y,z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))
+
+#define Sigma0(x) (ROTR32((x), 2) ^ ROTR32((x), 13) ^ ROTR32((x), 22))
+#define Sigma1(x) (ROTR32((x), 6) ^ ROTR32((x), 11) ^ ROTR32((x), 25))
+#define sigma0(x) (ROTR32((x), 7) ^ ROTR32((x), 18) ^ ((x) >> 3))
+#define sigma1(x) (ROTR32((x),17) ^ ROTR32((x), 19) ^ ((x) >> 10))
+
+/* Recalculate element n-th of circular buffer W using formula
+ * W[n] = sigma1(W[n - 2]) + W[n - 7] + sigma0(W[n - 15]) + W[n - 16]; */
+#define RECALCULATE_W(W,n) (W[n] += \
+ (sigma1(W[(n - 2) & 15]) + W[(n - 7) & 15] + sigma0(W[(n - 15) & 15])))
+
+#define ROUND(a,b,c,d,e,f,g,h,k,data) { \
+ unsigned T1 = h + Sigma1(e) + Ch(e,f,g) + k + (data); \
+ d += T1, h = T1 + Sigma0(a) + Maj(a,b,c); }
+#define ROUND_1_16(a,b,c,d,e,f,g,h,n) \
+ ROUND(a,b,c,d,e,f,g,h, rhash_k256[n], W[n] = be2me_32(block[n]))
+#define ROUND_17_64(a,b,c,d,e,f,g,h,n) \
+ ROUND(a,b,c,d,e,f,g,h, k[n], RECALCULATE_W(W, n))
+
+/**
+ * Initialize context before calculaing hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha256_init(sha256_ctx *ctx)
+{
+ /* Initial values. These words were obtained by taking the first 32
+ * bits of the fractional parts of the square roots of the first
+ * eight prime numbers. */
+ static const unsigned SHA256_H0[8] = {
+ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
+ 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
+ };
+
+ ctx->length = 0;
+ ctx->digest_length = sha256_hash_size;
+
+ /* initialize algorithm state */
+ memcpy(ctx->hash, SHA256_H0, sizeof(ctx->hash));
+}
+
+/**
+ * Initialize context before calculaing hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha224_init(struct sha256_ctx *ctx)
+{
+ /* Initial values from FIPS 180-3. These words were obtained by taking
+ * bits from 33th to 64th of the fractional parts of the square
+ * roots of ninth through sixteenth prime numbers. */
+ static const unsigned SHA224_H0[8] = {
+ 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939,
+ 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4
+ };
+
+ ctx->length = 0;
+ ctx->digest_length = sha224_hash_size;
+
+ memcpy(ctx->hash, SHA224_H0, sizeof(ctx->hash));
+}
+
+/**
+ * The core transformation. Process a 512-bit block.
+ *
+ * @param hash algorithm state
+ * @param block the message block to process
+ */
+static void rhash_sha256_process_block(unsigned hash[8], unsigned block[16])
+{
+ unsigned A, B, C, D, E, F, G, H;
+ unsigned W[16];
+ const unsigned *k;
+ int i;
+
+ A = hash[0], B = hash[1], C = hash[2], D = hash[3];
+ E = hash[4], F = hash[5], G = hash[6], H = hash[7];
+
+ /* Compute SHA using alternate Method: FIPS 180-3 6.1.3 */
+ ROUND_1_16(A, B, C, D, E, F, G, H, 0);
+ ROUND_1_16(H, A, B, C, D, E, F, G, 1);
+ ROUND_1_16(G, H, A, B, C, D, E, F, 2);
+ ROUND_1_16(F, G, H, A, B, C, D, E, 3);
+ ROUND_1_16(E, F, G, H, A, B, C, D, 4);
+ ROUND_1_16(D, E, F, G, H, A, B, C, 5);
+ ROUND_1_16(C, D, E, F, G, H, A, B, 6);
+ ROUND_1_16(B, C, D, E, F, G, H, A, 7);
+ ROUND_1_16(A, B, C, D, E, F, G, H, 8);
+ ROUND_1_16(H, A, B, C, D, E, F, G, 9);
+ ROUND_1_16(G, H, A, B, C, D, E, F, 10);
+ ROUND_1_16(F, G, H, A, B, C, D, E, 11);
+ ROUND_1_16(E, F, G, H, A, B, C, D, 12);
+ ROUND_1_16(D, E, F, G, H, A, B, C, 13);
+ ROUND_1_16(C, D, E, F, G, H, A, B, 14);
+ ROUND_1_16(B, C, D, E, F, G, H, A, 15);
+
+ for (i = 16, k = &rhash_k256[16]; i < 64; i += 16, k += 16) {
+ ROUND_17_64(A, B, C, D, E, F, G, H, 0);
+ ROUND_17_64(H, A, B, C, D, E, F, G, 1);
+ ROUND_17_64(G, H, A, B, C, D, E, F, 2);
+ ROUND_17_64(F, G, H, A, B, C, D, E, 3);
+ ROUND_17_64(E, F, G, H, A, B, C, D, 4);
+ ROUND_17_64(D, E, F, G, H, A, B, C, 5);
+ ROUND_17_64(C, D, E, F, G, H, A, B, 6);
+ ROUND_17_64(B, C, D, E, F, G, H, A, 7);
+ ROUND_17_64(A, B, C, D, E, F, G, H, 8);
+ ROUND_17_64(H, A, B, C, D, E, F, G, 9);
+ ROUND_17_64(G, H, A, B, C, D, E, F, 10);
+ ROUND_17_64(F, G, H, A, B, C, D, E, 11);
+ ROUND_17_64(E, F, G, H, A, B, C, D, 12);
+ ROUND_17_64(D, E, F, G, H, A, B, C, 13);
+ ROUND_17_64(C, D, E, F, G, H, A, B, 14);
+ ROUND_17_64(B, C, D, E, F, G, H, A, 15);
+ }
+
+ hash[0] += A, hash[1] += B, hash[2] += C, hash[3] += D;
+ hash[4] += E, hash[5] += F, hash[6] += G, hash[7] += H;
+}
+
+/**
+ * Calculate message hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+void rhash_sha256_update(sha256_ctx *ctx, const unsigned char *msg, size_t size)
+{
+ size_t index = (size_t)ctx->length & 63;
+ ctx->length += size;
+
+ /* fill partial block */
+ if (index) {
+ size_t left = sha256_block_size - index;
+ memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
+ if (size < left) return;
+
+ /* process partial block */
+ rhash_sha256_process_block(ctx->hash, (unsigned*)ctx->message);
+ msg += left;
+ size -= left;
+ }
+ while (size >= sha256_block_size) {
+ unsigned* aligned_message_block;
+ if (IS_ALIGNED_32(msg)) {
+ /* the most common case is processing of an already aligned message
+ without copying it */
+ aligned_message_block = (unsigned*)msg;
+ } else {
+ memcpy(ctx->message, msg, sha256_block_size);
+ aligned_message_block = (unsigned*)ctx->message;
+ }
+
+ rhash_sha256_process_block(ctx->hash, aligned_message_block);
+ msg += sha256_block_size;
+ size -= sha256_block_size;
+ }
+ if (size) {
+ memcpy(ctx->message, msg, size); /* save leftovers */
+ }
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param result calculated hash in binary form
+ */
+void rhash_sha256_final(sha256_ctx *ctx, unsigned char* result)
+{
+ size_t index = ((unsigned)ctx->length & 63) >> 2;
+ unsigned shift = ((unsigned)ctx->length & 3) * 8;
+
+ /* pad message and run for last block */
+
+ /* append the byte 0x80 to the message */
+ ctx->message[index] &= le2me_32(~(0xFFFFFFFFu << shift));
+ ctx->message[index++] ^= le2me_32(0x80u << shift);
+
+ /* if no room left in the message to store 64-bit message length */
+ if (index > 14) {
+ /* then fill the rest with zeros and process it */
+ while (index < 16) {
+ ctx->message[index++] = 0;
+ }
+ rhash_sha256_process_block(ctx->hash, ctx->message);
+ index = 0;
+ }
+ while (index < 14) {
+ ctx->message[index++] = 0;
+ }
+ ctx->message[14] = be2me_32( (unsigned)(ctx->length >> 29) );
+ ctx->message[15] = be2me_32( (unsigned)(ctx->length << 3) );
+ rhash_sha256_process_block(ctx->hash, ctx->message);
+
+ if (result) be32_copy(result, 0, ctx->hash, ctx->digest_length);
+}
diff --git a/Utilities/cmlibrhash/librhash/sha256.h b/Utilities/cmlibrhash/librhash/sha256.h
new file mode 100644
index 000000000..f87ebaa69
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha256.h
@@ -0,0 +1,32 @@
+/* sha.h sha256 and sha224 hash functions */
+#ifndef SHA256_H
+#define SHA256_H
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sha256_block_size 64
+#define sha256_hash_size 32
+#define sha224_hash_size 28
+
+/* algorithm context */
+typedef struct sha256_ctx
+{
+ unsigned message[16]; /* 512-bit buffer for leftovers */
+ uint64_t length; /* number of processed bytes */
+ unsigned hash[8]; /* 256-bit algorithm internal hashing state */
+ unsigned digest_length; /* length of the algorithm digest in bytes */
+} sha256_ctx;
+
+void rhash_sha224_init(sha256_ctx *ctx);
+void rhash_sha256_init(sha256_ctx *ctx);
+void rhash_sha256_update(sha256_ctx *ctx, const unsigned char* data, size_t length);
+void rhash_sha256_final(sha256_ctx *ctx, unsigned char result[32]);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SHA256_H */
diff --git a/Utilities/cmlibrhash/librhash/sha3.c b/Utilities/cmlibrhash/librhash/sha3.c
new file mode 100644
index 000000000..e4a845f66
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha3.c
@@ -0,0 +1,356 @@
+/* sha3.c - an implementation of Secure Hash Algorithm 3 (Keccak).
+ * based on the
+ * The Keccak SHA-3 submission. Submission to NIST (Round 3), 2011
+ * by Guido Bertoni, Joan Daemen, Michaël Peeters and Gilles Van Assche
+ *
+ * Copyright: 2013 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <assert.h>
+#include <string.h>
+#include "byte_order.h"
+#include "sha3.h"
+
+/* constants */
+#define NumberOfRounds 24
+
+/* SHA3 (Keccak) constants for 24 rounds */
+static uint64_t keccak_round_constants[NumberOfRounds] = {
+ I64(0x0000000000000001), I64(0x0000000000008082), I64(0x800000000000808A), I64(0x8000000080008000),
+ I64(0x000000000000808B), I64(0x0000000080000001), I64(0x8000000080008081), I64(0x8000000000008009),
+ I64(0x000000000000008A), I64(0x0000000000000088), I64(0x0000000080008009), I64(0x000000008000000A),
+ I64(0x000000008000808B), I64(0x800000000000008B), I64(0x8000000000008089), I64(0x8000000000008003),
+ I64(0x8000000000008002), I64(0x8000000000000080), I64(0x000000000000800A), I64(0x800000008000000A),
+ I64(0x8000000080008081), I64(0x8000000000008080), I64(0x0000000080000001), I64(0x8000000080008008)
+};
+
+/* Initializing a sha3 context for given number of output bits */
+static void rhash_keccak_init(sha3_ctx *ctx, unsigned bits)
+{
+ /* NB: The Keccak capacity parameter = bits * 2 */
+ unsigned rate = 1600 - bits * 2;
+
+ memset(ctx, 0, sizeof(sha3_ctx));
+ ctx->block_size = rate / 8;
+ assert(rate <= 1600 && (rate % 64) == 0);
+}
+
+/**
+ * Initialize context before calculating hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha3_224_init(sha3_ctx *ctx)
+{
+ rhash_keccak_init(ctx, 224);
+}
+
+/**
+ * Initialize context before calculating hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha3_256_init(sha3_ctx *ctx)
+{
+ rhash_keccak_init(ctx, 256);
+}
+
+/**
+ * Initialize context before calculating hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha3_384_init(sha3_ctx *ctx)
+{
+ rhash_keccak_init(ctx, 384);
+}
+
+/**
+ * Initialize context before calculating hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha3_512_init(sha3_ctx *ctx)
+{
+ rhash_keccak_init(ctx, 512);
+}
+
+/* Keccak theta() transformation */
+static void keccak_theta(uint64_t *A)
+{
+ unsigned int x;
+ uint64_t C[5], D[5];
+
+ for (x = 0; x < 5; x++) {
+ C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];
+ }
+ D[0] = ROTL64(C[1], 1) ^ C[4];
+ D[1] = ROTL64(C[2], 1) ^ C[0];
+ D[2] = ROTL64(C[3], 1) ^ C[1];
+ D[3] = ROTL64(C[4], 1) ^ C[2];
+ D[4] = ROTL64(C[0], 1) ^ C[3];
+
+ for (x = 0; x < 5; x++) {
+ A[x] ^= D[x];
+ A[x + 5] ^= D[x];
+ A[x + 10] ^= D[x];
+ A[x + 15] ^= D[x];
+ A[x + 20] ^= D[x];
+ }
+}
+
+/* Keccak pi() transformation */
+static void keccak_pi(uint64_t *A)
+{
+ uint64_t A1;
+ A1 = A[1];
+ A[ 1] = A[ 6];
+ A[ 6] = A[ 9];
+ A[ 9] = A[22];
+ A[22] = A[14];
+ A[14] = A[20];
+ A[20] = A[ 2];
+ A[ 2] = A[12];
+ A[12] = A[13];
+ A[13] = A[19];
+ A[19] = A[23];
+ A[23] = A[15];
+ A[15] = A[ 4];
+ A[ 4] = A[24];
+ A[24] = A[21];
+ A[21] = A[ 8];
+ A[ 8] = A[16];
+ A[16] = A[ 5];
+ A[ 5] = A[ 3];
+ A[ 3] = A[18];
+ A[18] = A[17];
+ A[17] = A[11];
+ A[11] = A[ 7];
+ A[ 7] = A[10];
+ A[10] = A1;
+ /* note: A[ 0] is left as is */
+}
+
+/* Keccak chi() transformation */
+static void keccak_chi(uint64_t *A)
+{
+ int i;
+ for (i = 0; i < 25; i += 5) {
+ uint64_t A0 = A[0 + i], A1 = A[1 + i];
+ A[0 + i] ^= ~A1 & A[2 + i];
+ A[1 + i] ^= ~A[2 + i] & A[3 + i];
+ A[2 + i] ^= ~A[3 + i] & A[4 + i];
+ A[3 + i] ^= ~A[4 + i] & A0;
+ A[4 + i] ^= ~A0 & A1;
+ }
+}
+
+static void rhash_sha3_permutation(uint64_t *state)
+{
+ int round;
+ for (round = 0; round < NumberOfRounds; round++)
+ {
+ keccak_theta(state);
+
+ /* apply Keccak rho() transformation */
+ state[ 1] = ROTL64(state[ 1], 1);
+ state[ 2] = ROTL64(state[ 2], 62);
+ state[ 3] = ROTL64(state[ 3], 28);
+ state[ 4] = ROTL64(state[ 4], 27);
+ state[ 5] = ROTL64(state[ 5], 36);
+ state[ 6] = ROTL64(state[ 6], 44);
+ state[ 7] = ROTL64(state[ 7], 6);
+ state[ 8] = ROTL64(state[ 8], 55);
+ state[ 9] = ROTL64(state[ 9], 20);
+ state[10] = ROTL64(state[10], 3);
+ state[11] = ROTL64(state[11], 10);
+ state[12] = ROTL64(state[12], 43);
+ state[13] = ROTL64(state[13], 25);
+ state[14] = ROTL64(state[14], 39);
+ state[15] = ROTL64(state[15], 41);
+ state[16] = ROTL64(state[16], 45);
+ state[17] = ROTL64(state[17], 15);
+ state[18] = ROTL64(state[18], 21);
+ state[19] = ROTL64(state[19], 8);
+ state[20] = ROTL64(state[20], 18);
+ state[21] = ROTL64(state[21], 2);
+ state[22] = ROTL64(state[22], 61);
+ state[23] = ROTL64(state[23], 56);
+ state[24] = ROTL64(state[24], 14);
+
+ keccak_pi(state);
+ keccak_chi(state);
+
+ /* apply iota(state, round) */
+ *state ^= keccak_round_constants[round];
+ }
+}
+
+/**
+ * The core transformation. Process the specified block of data.
+ *
+ * @param hash the algorithm state
+ * @param block the message block to process
+ * @param block_size the size of the processed block in bytes
+ */
+static void rhash_sha3_process_block(uint64_t hash[25], const uint64_t *block, size_t block_size)
+{
+ /* expanded loop */
+ hash[ 0] ^= le2me_64(block[ 0]);
+ hash[ 1] ^= le2me_64(block[ 1]);
+ hash[ 2] ^= le2me_64(block[ 2]);
+ hash[ 3] ^= le2me_64(block[ 3]);
+ hash[ 4] ^= le2me_64(block[ 4]);
+ hash[ 5] ^= le2me_64(block[ 5]);
+ hash[ 6] ^= le2me_64(block[ 6]);
+ hash[ 7] ^= le2me_64(block[ 7]);
+ hash[ 8] ^= le2me_64(block[ 8]);
+ /* if not sha3-512 */
+ if (block_size > 72) {
+ hash[ 9] ^= le2me_64(block[ 9]);
+ hash[10] ^= le2me_64(block[10]);
+ hash[11] ^= le2me_64(block[11]);
+ hash[12] ^= le2me_64(block[12]);
+ /* if not sha3-384 */
+ if (block_size > 104) {
+ hash[13] ^= le2me_64(block[13]);
+ hash[14] ^= le2me_64(block[14]);
+ hash[15] ^= le2me_64(block[15]);
+ hash[16] ^= le2me_64(block[16]);
+ /* if not sha3-256 */
+ if (block_size > 136) {
+ hash[17] ^= le2me_64(block[17]);
+#ifdef FULL_SHA3_FAMILY_SUPPORT
+ /* if not sha3-224 */
+ if (block_size > 144) {
+ hash[18] ^= le2me_64(block[18]);
+ hash[19] ^= le2me_64(block[19]);
+ hash[20] ^= le2me_64(block[20]);
+ hash[21] ^= le2me_64(block[21]);
+ hash[22] ^= le2me_64(block[22]);
+ hash[23] ^= le2me_64(block[23]);
+ hash[24] ^= le2me_64(block[24]);
+ }
+#endif
+ }
+ }
+ }
+ /* make a permutation of the hash */
+ rhash_sha3_permutation(hash);
+}
+
+#define SHA3_FINALIZED 0x80000000
+
+/**
+ * Calculate message hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+void rhash_sha3_update(sha3_ctx *ctx, const unsigned char *msg, size_t size)
+{
+ size_t index = (size_t)ctx->rest;
+ size_t block_size = (size_t)ctx->block_size;
+
+ if (ctx->rest & SHA3_FINALIZED) return; /* too late for additional input */
+ ctx->rest = (unsigned)((ctx->rest + size) % block_size);
+
+ /* fill partial block */
+ if (index) {
+ size_t left = block_size - index;
+ memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
+ if (size < left) return;
+
+ /* process partial block */
+ rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
+ msg += left;
+ size -= left;
+ }
+ while (size >= block_size) {
+ uint64_t* aligned_message_block;
+ if (IS_ALIGNED_64(msg)) {
+ /* the most common case is processing of an already aligned message
+ without copying it */
+ aligned_message_block = (uint64_t*)msg;
+ } else {
+ memcpy(ctx->message, msg, block_size);
+ aligned_message_block = ctx->message;
+ }
+
+ rhash_sha3_process_block(ctx->hash, aligned_message_block, block_size);
+ msg += block_size;
+ size -= block_size;
+ }
+ if (size) {
+ memcpy(ctx->message, msg, size); /* save leftovers */
+ }
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param result calculated hash in binary form
+ */
+void rhash_sha3_final(sha3_ctx *ctx, unsigned char* result)
+{
+ size_t digest_length = 100 - ctx->block_size / 2;
+ const size_t block_size = ctx->block_size;
+
+ if (!(ctx->rest & SHA3_FINALIZED))
+ {
+ /* clear the rest of the data queue */
+ memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest);
+ ((char*)ctx->message)[ctx->rest] |= 0x06;
+ ((char*)ctx->message)[block_size - 1] |= 0x80;
+
+ /* process final block */
+ rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
+ ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
+ }
+
+ assert(block_size > digest_length);
+ if (result) me64_to_le_str(result, ctx->hash, digest_length);
+}
+
+#ifdef USE_KECCAK
+/**
+* Store calculated hash into the given array.
+*
+* @param ctx the algorithm context containing current hashing state
+* @param result calculated hash in binary form
+*/
+void rhash_keccak_final(sha3_ctx *ctx, unsigned char* result)
+{
+ size_t digest_length = 100 - ctx->block_size / 2;
+ const size_t block_size = ctx->block_size;
+
+ if (!(ctx->rest & SHA3_FINALIZED))
+ {
+ /* clear the rest of the data queue */
+ memset((char*)ctx->message + ctx->rest, 0, block_size - ctx->rest);
+ ((char*)ctx->message)[ctx->rest] |= 0x01;
+ ((char*)ctx->message)[block_size - 1] |= 0x80;
+
+ /* process final block */
+ rhash_sha3_process_block(ctx->hash, ctx->message, block_size);
+ ctx->rest = SHA3_FINALIZED; /* mark context as finalized */
+ }
+
+ assert(block_size > digest_length);
+ if (result) me64_to_le_str(result, ctx->hash, digest_length);
+}
+#endif /* USE_KECCAK */
diff --git a/Utilities/cmlibrhash/librhash/sha3.h b/Utilities/cmlibrhash/librhash/sha3.h
new file mode 100644
index 000000000..28319978d
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha3.h
@@ -0,0 +1,54 @@
+/* sha3.h */
+#ifndef RHASH_SHA3_H
+#define RHASH_SHA3_H
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sha3_224_hash_size 28
+#define sha3_256_hash_size 32
+#define sha3_384_hash_size 48
+#define sha3_512_hash_size 64
+#define sha3_max_permutation_size 25
+#define sha3_max_rate_in_qwords 24
+
+/**
+ * SHA3 Algorithm context.
+ */
+typedef struct sha3_ctx
+{
+ /* 1600 bits algorithm hashing state */
+ uint64_t hash[sha3_max_permutation_size];
+ /* 1536-bit buffer for leftovers */
+ uint64_t message[sha3_max_rate_in_qwords];
+ /* count of bytes in the message[] buffer */
+ unsigned rest;
+ /* size of a message block processed at once */
+ unsigned block_size;
+} sha3_ctx;
+
+/* methods for calculating the hash function */
+
+void rhash_sha3_224_init(sha3_ctx *ctx);
+void rhash_sha3_256_init(sha3_ctx *ctx);
+void rhash_sha3_384_init(sha3_ctx *ctx);
+void rhash_sha3_512_init(sha3_ctx *ctx);
+void rhash_sha3_update(sha3_ctx *ctx, const unsigned char* msg, size_t size);
+void rhash_sha3_final(sha3_ctx *ctx, unsigned char* result);
+
+#ifdef USE_KECCAK
+#define rhash_keccak_224_init rhash_sha3_224_init
+#define rhash_keccak_256_init rhash_sha3_256_init
+#define rhash_keccak_384_init rhash_sha3_384_init
+#define rhash_keccak_512_init rhash_sha3_512_init
+#define rhash_keccak_update rhash_sha3_update
+void rhash_keccak_final(sha3_ctx *ctx, unsigned char* result);
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* RHASH_SHA3_H */
diff --git a/Utilities/cmlibrhash/librhash/sha512.c b/Utilities/cmlibrhash/librhash/sha512.c
new file mode 100644
index 000000000..a3e681d1f
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha512.c
@@ -0,0 +1,255 @@
+/* sha512.c - an implementation of SHA-384/512 hash functions
+ * based on FIPS 180-3 (Federal Information Processing Standart).
+ *
+ * Copyright: 2010-2012 Aleksey Kravchenko <rhash.admin@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk!
+ */
+
+#include <string.h>
+#include "byte_order.h"
+#include "sha512.h"
+
+/* SHA-384 and SHA-512 constants for 80 rounds. These qwords represent
+ * the first 64 bits of the fractional parts of the cube
+ * roots of the first 80 prime numbers. */
+static const uint64_t rhash_k512[80] = {
+ I64(0x428a2f98d728ae22), I64(0x7137449123ef65cd), I64(0xb5c0fbcfec4d3b2f),
+ I64(0xe9b5dba58189dbbc), I64(0x3956c25bf348b538), I64(0x59f111f1b605d019),
+ I64(0x923f82a4af194f9b), I64(0xab1c5ed5da6d8118), I64(0xd807aa98a3030242),
+ I64(0x12835b0145706fbe), I64(0x243185be4ee4b28c), I64(0x550c7dc3d5ffb4e2),
+ I64(0x72be5d74f27b896f), I64(0x80deb1fe3b1696b1), I64(0x9bdc06a725c71235),
+ I64(0xc19bf174cf692694), I64(0xe49b69c19ef14ad2), I64(0xefbe4786384f25e3),
+ I64(0x0fc19dc68b8cd5b5), I64(0x240ca1cc77ac9c65), I64(0x2de92c6f592b0275),
+ I64(0x4a7484aa6ea6e483), I64(0x5cb0a9dcbd41fbd4), I64(0x76f988da831153b5),
+ I64(0x983e5152ee66dfab), I64(0xa831c66d2db43210), I64(0xb00327c898fb213f),
+ I64(0xbf597fc7beef0ee4), I64(0xc6e00bf33da88fc2), I64(0xd5a79147930aa725),
+ I64(0x06ca6351e003826f), I64(0x142929670a0e6e70), I64(0x27b70a8546d22ffc),
+ I64(0x2e1b21385c26c926), I64(0x4d2c6dfc5ac42aed), I64(0x53380d139d95b3df),
+ I64(0x650a73548baf63de), I64(0x766a0abb3c77b2a8), I64(0x81c2c92e47edaee6),
+ I64(0x92722c851482353b), I64(0xa2bfe8a14cf10364), I64(0xa81a664bbc423001),
+ I64(0xc24b8b70d0f89791), I64(0xc76c51a30654be30), I64(0xd192e819d6ef5218),
+ I64(0xd69906245565a910), I64(0xf40e35855771202a), I64(0x106aa07032bbd1b8),
+ I64(0x19a4c116b8d2d0c8), I64(0x1e376c085141ab53), I64(0x2748774cdf8eeb99),
+ I64(0x34b0bcb5e19b48a8), I64(0x391c0cb3c5c95a63), I64(0x4ed8aa4ae3418acb),
+ I64(0x5b9cca4f7763e373), I64(0x682e6ff3d6b2b8a3), I64(0x748f82ee5defb2fc),
+ I64(0x78a5636f43172f60), I64(0x84c87814a1f0ab72), I64(0x8cc702081a6439ec),
+ I64(0x90befffa23631e28), I64(0xa4506cebde82bde9), I64(0xbef9a3f7b2c67915),
+ I64(0xc67178f2e372532b), I64(0xca273eceea26619c), I64(0xd186b8c721c0c207),
+ I64(0xeada7dd6cde0eb1e), I64(0xf57d4f7fee6ed178), I64(0x06f067aa72176fba),
+ I64(0x0a637dc5a2c898a6), I64(0x113f9804bef90dae), I64(0x1b710b35131c471b),
+ I64(0x28db77f523047d84), I64(0x32caab7b40c72493), I64(0x3c9ebe0a15c9bebc),
+ I64(0x431d67c49c100d4c), I64(0x4cc5d4becb3e42b6), I64(0x597f299cfc657e2a),
+ I64(0x5fcb6fab3ad6faec), I64(0x6c44198c4a475817)
+};
+
+/* The SHA512/384 functions defined by FIPS 180-3, 4.1.3 */
+/* Optimized version of Ch(x,y,z)=((x & y) | (~x & z)) */
+#define Ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z))))
+/* Optimized version of Maj(x,y,z)=((x & y) ^ (x & z) ^ (y & z)) */
+#define Maj(x,y,z) (((x) & (y)) ^ ((z) & ((x) ^ (y))))
+
+#define Sigma0(x) (ROTR64((x), 28) ^ ROTR64((x), 34) ^ ROTR64((x), 39))
+#define Sigma1(x) (ROTR64((x), 14) ^ ROTR64((x), 18) ^ ROTR64((x), 41))
+#define sigma0(x) (ROTR64((x), 1) ^ ROTR64((x), 8) ^ ((x) >> 7))
+#define sigma1(x) (ROTR64((x), 19) ^ ROTR64((x), 61) ^ ((x) >> 6))
+
+/* Recalculate element n-th of circular buffer W using formula
+ * W[n] = sigma1(W[n - 2]) + W[n - 7] + sigma0(W[n - 15]) + W[n - 16]; */
+#define RECALCULATE_W(W,n) (W[n] += \
+ (sigma1(W[(n - 2) & 15]) + W[(n - 7) & 15] + sigma0(W[(n - 15) & 15])))
+
+#define ROUND(a,b,c,d,e,f,g,h,k,data) { \
+ uint64_t T1 = h + Sigma1(e) + Ch(e,f,g) + k + (data); \
+ d += T1, h = T1 + Sigma0(a) + Maj(a,b,c); }
+#define ROUND_1_16(a,b,c,d,e,f,g,h,n) \
+ ROUND(a,b,c,d,e,f,g,h, rhash_k512[n], W[n] = be2me_64(block[n]))
+#define ROUND_17_80(a,b,c,d,e,f,g,h,n) \
+ ROUND(a,b,c,d,e,f,g,h, k[n], RECALCULATE_W(W, n))
+
+/**
+ * Initialize context before calculating hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha512_init(sha512_ctx *ctx)
+{
+ /* Initial values. These words were obtained by taking the first 32
+ * bits of the fractional parts of the square roots of the first
+ * eight prime numbers. */
+ static const uint64_t SHA512_H0[8] = {
+ I64(0x6a09e667f3bcc908), I64(0xbb67ae8584caa73b), I64(0x3c6ef372fe94f82b),
+ I64(0xa54ff53a5f1d36f1), I64(0x510e527fade682d1), I64(0x9b05688c2b3e6c1f),
+ I64(0x1f83d9abfb41bd6b), I64(0x5be0cd19137e2179)
+ };
+
+ ctx->length = 0;
+ ctx->digest_length = sha512_hash_size;
+
+ /* initialize algorithm state */
+ memcpy(ctx->hash, SHA512_H0, sizeof(ctx->hash));
+}
+
+/**
+ * Initialize context before calculaing hash.
+ *
+ * @param ctx context to initialize
+ */
+void rhash_sha384_init(struct sha512_ctx *ctx)
+{
+ /* Initial values from FIPS 180-3. These words were obtained by taking
+ * the first sixty-four bits of the fractional parts of the square
+ * roots of ninth through sixteenth prime numbers. */
+ static const uint64_t SHA384_H0[8] = {
+ I64(0xcbbb9d5dc1059ed8), I64(0x629a292a367cd507), I64(0x9159015a3070dd17),
+ I64(0x152fecd8f70e5939), I64(0x67332667ffc00b31), I64(0x8eb44a8768581511),
+ I64(0xdb0c2e0d64f98fa7), I64(0x47b5481dbefa4fa4)
+ };
+
+ ctx->length = 0;
+ ctx->digest_length = sha384_hash_size;
+
+ memcpy(ctx->hash, SHA384_H0, sizeof(ctx->hash));
+}
+
+/**
+ * The core transformation. Process a 512-bit block.
+ *
+ * @param hash algorithm state
+ * @param block the message block to process
+ */
+static void rhash_sha512_process_block(uint64_t hash[8], uint64_t block[16])
+{
+ uint64_t A, B, C, D, E, F, G, H;
+ uint64_t W[16];
+ const uint64_t *k;
+ int i;
+
+ A = hash[0], B = hash[1], C = hash[2], D = hash[3];
+ E = hash[4], F = hash[5], G = hash[6], H = hash[7];
+
+ /* Compute SHA using alternate Method: FIPS 180-3 6.1.3 */
+ ROUND_1_16(A, B, C, D, E, F, G, H, 0);
+ ROUND_1_16(H, A, B, C, D, E, F, G, 1);
+ ROUND_1_16(G, H, A, B, C, D, E, F, 2);
+ ROUND_1_16(F, G, H, A, B, C, D, E, 3);
+ ROUND_1_16(E, F, G, H, A, B, C, D, 4);
+ ROUND_1_16(D, E, F, G, H, A, B, C, 5);
+ ROUND_1_16(C, D, E, F, G, H, A, B, 6);
+ ROUND_1_16(B, C, D, E, F, G, H, A, 7);
+ ROUND_1_16(A, B, C, D, E, F, G, H, 8);
+ ROUND_1_16(H, A, B, C, D, E, F, G, 9);
+ ROUND_1_16(G, H, A, B, C, D, E, F, 10);
+ ROUND_1_16(F, G, H, A, B, C, D, E, 11);
+ ROUND_1_16(E, F, G, H, A, B, C, D, 12);
+ ROUND_1_16(D, E, F, G, H, A, B, C, 13);
+ ROUND_1_16(C, D, E, F, G, H, A, B, 14);
+ ROUND_1_16(B, C, D, E, F, G, H, A, 15);
+
+ for (i = 16, k = &rhash_k512[16]; i < 80; i += 16, k += 16) {
+ ROUND_17_80(A, B, C, D, E, F, G, H, 0);
+ ROUND_17_80(H, A, B, C, D, E, F, G, 1);
+ ROUND_17_80(G, H, A, B, C, D, E, F, 2);
+ ROUND_17_80(F, G, H, A, B, C, D, E, 3);
+ ROUND_17_80(E, F, G, H, A, B, C, D, 4);
+ ROUND_17_80(D, E, F, G, H, A, B, C, 5);
+ ROUND_17_80(C, D, E, F, G, H, A, B, 6);
+ ROUND_17_80(B, C, D, E, F, G, H, A, 7);
+ ROUND_17_80(A, B, C, D, E, F, G, H, 8);
+ ROUND_17_80(H, A, B, C, D, E, F, G, 9);
+ ROUND_17_80(G, H, A, B, C, D, E, F, 10);
+ ROUND_17_80(F, G, H, A, B, C, D, E, 11);
+ ROUND_17_80(E, F, G, H, A, B, C, D, 12);
+ ROUND_17_80(D, E, F, G, H, A, B, C, 13);
+ ROUND_17_80(C, D, E, F, G, H, A, B, 14);
+ ROUND_17_80(B, C, D, E, F, G, H, A, 15);
+ }
+
+ hash[0] += A, hash[1] += B, hash[2] += C, hash[3] += D;
+ hash[4] += E, hash[5] += F, hash[6] += G, hash[7] += H;
+}
+
+/**
+ * Calculate message hash.
+ * Can be called repeatedly with chunks of the message to be hashed.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param msg message chunk
+ * @param size length of the message chunk
+ */
+void rhash_sha512_update(sha512_ctx *ctx, const unsigned char *msg, size_t size)
+{
+ size_t index = (size_t)ctx->length & 127;
+ ctx->length += size;
+
+ /* fill partial block */
+ if (index) {
+ size_t left = sha512_block_size - index;
+ memcpy((char*)ctx->message + index, msg, (size < left ? size : left));
+ if (size < left) return;
+
+ /* process partial block */
+ rhash_sha512_process_block(ctx->hash, ctx->message);
+ msg += left;
+ size -= left;
+ }
+ while (size >= sha512_block_size) {
+ uint64_t* aligned_message_block;
+ if (IS_ALIGNED_64(msg)) {
+ /* the most common case is processing of an already aligned message
+ without copying it */
+ aligned_message_block = (uint64_t*)msg;
+ } else {
+ memcpy(ctx->message, msg, sha512_block_size);
+ aligned_message_block = ctx->message;
+ }
+
+ rhash_sha512_process_block(ctx->hash, aligned_message_block);
+ msg += sha512_block_size;
+ size -= sha512_block_size;
+ }
+ if (size) {
+ memcpy(ctx->message, msg, size); /* save leftovers */
+ }
+}
+
+/**
+ * Store calculated hash into the given array.
+ *
+ * @param ctx the algorithm context containing current hashing state
+ * @param result calculated hash in binary form
+ */
+void rhash_sha512_final(sha512_ctx *ctx, unsigned char* result)
+{
+ size_t index = ((unsigned)ctx->length & 127) >> 3;
+ unsigned shift = ((unsigned)ctx->length & 7) * 8;
+
+ /* pad message and process the last block */
+
+ /* append the byte 0x80 to the message */
+ ctx->message[index] &= le2me_64( ~(I64(0xFFFFFFFFFFFFFFFF) << shift) );
+ ctx->message[index++] ^= le2me_64( I64(0x80) << shift );
+
+ /* if no room left in the message to store 128-bit message length */
+ if (index >= 15) {
+ if (index == 15) ctx->message[index] = 0;
+ rhash_sha512_process_block(ctx->hash, ctx->message);
+ index = 0;
+ }
+ while (index < 15) {
+ ctx->message[index++] = 0;
+ }
+ ctx->message[15] = be2me_64(ctx->length << 3);
+ rhash_sha512_process_block(ctx->hash, ctx->message);
+
+ if (result) be64_copy(result, 0, ctx->hash, ctx->digest_length);
+}
diff --git a/Utilities/cmlibrhash/librhash/sha512.h b/Utilities/cmlibrhash/librhash/sha512.h
new file mode 100644
index 000000000..7c689bea1
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/sha512.h
@@ -0,0 +1,32 @@
+/* sha.h sha512 and sha384 hash functions */
+#ifndef SHA512_H
+#define SHA512_H
+#include "ustd.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define sha512_block_size 128
+#define sha512_hash_size 64
+#define sha384_hash_size 48
+
+/* algorithm context */
+typedef struct sha512_ctx
+{
+ uint64_t message[16]; /* 1024-bit buffer for leftovers */
+ uint64_t length; /* number of processed bytes */
+ uint64_t hash[8]; /* 512-bit algorithm internal hashing state */
+ unsigned digest_length; /* length of the algorithm digest in bytes */
+} sha512_ctx;
+
+void rhash_sha384_init(sha512_ctx *ctx);
+void rhash_sha512_init(sha512_ctx *ctx);
+void rhash_sha512_update(sha512_ctx *ctx, const unsigned char* data, size_t length);
+void rhash_sha512_final(sha512_ctx *ctx, unsigned char* result);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* SHA512_H */
diff --git a/Utilities/cmlibrhash/librhash/ustd.h b/Utilities/cmlibrhash/librhash/ustd.h
new file mode 100644
index 000000000..019b93193
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/ustd.h
@@ -0,0 +1,39 @@
+/* ustd.h common macros and includes */
+#ifndef LIBRHASH_USTD_H
+#define LIBRHASH_USTD_H
+
+/* Include KWSys Large File Support configuration. */
+#include <cmsys/Configure.h>
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+#endif
+
+#include <cm_kwiml.h>
+
+#ifndef KWIML_INT_HAVE_INT64_T
+# define int64_t KWIML_INT_int64_t
+#endif
+#ifndef KWIML_INT_HAVE_INT32_T
+# define int32_t KWIML_INT_int32_t
+#endif
+#ifndef KWIML_INT_HAVE_INT16_T
+# define int16_t KWIML_INT_int16_t
+#endif
+#ifndef KWIML_INT_HAVE_INT8_T
+# define int8_t KWIML_INT_int8_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT64_T
+# define uint64_t KWIML_INT_uint64_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT32_T
+# define uint32_t KWIML_INT_uint32_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT16_T
+# define uint16_t KWIML_INT_uint16_t
+#endif
+#ifndef KWIML_INT_HAVE_UINT8_T
+# define uint8_t KWIML_INT_uint8_t
+#endif
+
+#endif /* LIBRHASH_USTD_H */
diff --git a/Utilities/cmlibrhash/librhash/util.h b/Utilities/cmlibrhash/librhash/util.h
new file mode 100644
index 000000000..9f371574a
--- /dev/null
+++ b/Utilities/cmlibrhash/librhash/util.h
@@ -0,0 +1,31 @@
+/* util.h */
+#ifndef UTIL_H
+#define UTIL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if (defined(__GNUC__) && __GNUC__ >= 4 && (__GNUC__ > 4 || __GNUC_MINOR__ >= 1) \
+ && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4)) \
+ || (defined(__INTEL_COMPILER) && !defined(_WIN32))
+/* atomic operations are defined by ICC and GCC >= 4.1, but by the later one supposedly not for ARM */
+/* note: ICC on ia64 platform possibly require ia64intrin.h, need testing */
+# define atomic_compare_and_swap(ptr, oldval, newval) __sync_val_compare_and_swap(ptr, oldval, newval)
+#elif defined(_MSC_VER)
+# include <windows.h>
+# define atomic_compare_and_swap(ptr, oldval, newval) InterlockedCompareExchange(ptr, newval, oldval)
+#elif defined(__sun)
+# include <atomic.h>
+# define atomic_compare_and_swap(ptr, oldval, newval) atomic_cas_32(ptr, oldval, newval)
+#else
+/* pray that it will work */
+# define atomic_compare_and_swap(ptr, oldval, newval) { if(*(ptr) == (oldval)) *(ptr) = (newval); }
+# define NO_ATOMIC_BUILTINS
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif /* UTIL_H */
diff --git a/Utilities/cmlibuv/.gitattributes b/Utilities/cmlibuv/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmlibuv/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmlibuv/CMakeLists.txt b/Utilities/cmlibuv/CMakeLists.txt
new file mode 100644
index 000000000..4c8e2289d
--- /dev/null
+++ b/Utilities/cmlibuv/CMakeLists.txt
@@ -0,0 +1,289 @@
+project(libuv C)
+
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
+find_package(Threads)
+
+set(uv_libraries ${CMAKE_THREAD_LIBS_INIT})
+set(uv_includes include src)
+set(uv_headers
+ include/uv.h
+ include/uv-errno.h
+ include/uv-threadpool.h
+ include/uv-version.h
+ )
+set(uv_sources
+ src/fs-poll.c
+ src/heap-inl.h
+ src/inet.c
+ src/queue.h
+ src/threadpool.c
+ src/uv-common.c
+ src/uv-common.h
+ src/version.c
+ )
+if(WIN32)
+ list(APPEND uv_libraries
+ ws2_32
+ psapi
+ iphlpapi
+ shell32
+ userenv
+ )
+ list(APPEND uv_includes
+ src/win
+ )
+ list(APPEND uv_defines
+ WIN32_LEAN_AND_MEAN
+ _WIN32_WINNT=0x0600
+ )
+ list(APPEND uv_headers
+ include/uv-win.h
+ include/tree.h
+ )
+ list(APPEND uv_sources
+ src/win/async.c
+ src/win/atomicops-inl.h
+ src/win/core.c
+ src/win/detect-wakeup.c
+ src/win/dl.c
+ src/win/error.c
+ src/win/fs-event.c
+ src/win/fs.c
+ src/win/getaddrinfo.c
+ src/win/getnameinfo.c
+ src/win/handle.c
+ src/win/handle-inl.h
+ src/win/internal.h
+ src/win/loop-watcher.c
+ src/win/pipe.c
+ src/win/poll.c
+ src/win/process-stdio.c
+ src/win/process.c
+ src/win/req.c
+ src/win/req-inl.h
+ src/win/signal.c
+ src/win/snprintf.c
+ src/win/stream.c
+ src/win/stream-inl.h
+ src/win/tcp.c
+ src/win/thread.c
+ src/win/timer.c
+ src/win/tty.c
+ src/win/udp.c
+ src/win/util.c
+ src/win/winapi.c
+ src/win/winapi.h
+ src/win/winsock.c
+ src/win/winsock.h
+ )
+else()
+ list(APPEND uv_includes
+ src/unix
+ )
+ list(APPEND uv_headers
+ include/uv-unix.h
+ )
+ list(APPEND uv_sources
+ src/unix/async.c
+ src/unix/atomic-ops.h
+ src/unix/core.c
+ src/unix/dl.c
+ src/unix/fs.c
+ src/unix/getaddrinfo.c
+ src/unix/getnameinfo.c
+ src/unix/internal.h
+ src/unix/loop-watcher.c
+ src/unix/loop.c
+ src/unix/pipe.c
+ src/unix/poll.c
+ src/unix/process.c
+ src/unix/signal.c
+ src/unix/spinlock.h
+ src/unix/stream.c
+ src/unix/tcp.c
+ src/unix/thread.c
+ src/unix/timer.c
+ src/unix/tty.c
+ src/unix/udp.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ list(APPEND uv_libraries
+ perfstat
+ )
+ list(APPEND uv_headers
+ include/uv-aix.h
+ )
+ list(APPEND uv_defines
+ _ALL_SOURCE
+ _XOPEN_SOURCE=500
+ _LINUX_SOURCE_COMPAT
+ _THREAD_SAFE
+ )
+ list(APPEND uv_sources
+ src/unix/aix.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME MATCHES "CYGWIN")
+ list(APPEND uv_libraries
+ )
+ list(APPEND uv_headers
+ include/uv-posix.h
+ )
+ list(APPEND uv_defines
+ )
+ list(APPEND uv_sources
+ src/unix/cygwin.c
+ src/unix/bsd-ifaddrs.c
+ src/unix/no-fsevents.c
+ src/unix/no-proctitle.c
+ src/unix/posix-hrtime.c
+ src/unix/posix-poll.c
+ src/unix/procfs-exepath.c
+ src/unix/sysinfo-loadavg.c
+ src/unix/sysinfo-memory.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
+ list(APPEND uv_headers
+ include/uv-darwin.h
+ include/pthread-barrier.h
+ )
+ list(APPEND uv_defines
+ _DARWIN_USE_64_BIT_INODE=1
+ _DARWIN_UNLIMITED_SELECT=1
+ )
+ list(APPEND uv_sources
+ src/unix/bsd-ifaddrs.c
+ src/unix/darwin.c
+ src/unix/darwin-proctitle.c
+ src/unix/fsevents.c
+ src/unix/kqueue.c
+ src/unix/proctitle.c
+ src/unix/pthread-barrier.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
+ list(APPEND uv_libraries dl rt)
+ list(APPEND uv_headers
+ include/uv-linux.h
+ )
+ list(APPEND uv_defines _GNU_SOURCE)
+ list(APPEND uv_sources
+ src/unix/linux-core.c
+ src/unix/linux-inotify.c
+ src/unix/linux-syscalls.c
+ src/unix/linux-syscalls.h
+ src/unix/procfs-exepath.c
+ src/unix/proctitle.c
+ src/unix/sysinfo-loadavg.c
+ src/unix/sysinfo-memory.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+ list(APPEND uv_libraries
+ kvm
+ )
+ list(APPEND uv_headers
+ include/uv-bsd.h
+ )
+ list(APPEND uv_sources
+ src/unix/bsd-ifaddrs.c
+ src/unix/freebsd.c
+ src/unix/kqueue.c
+ src/unix/posix-hrtime.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "NetBSD")
+ list(APPEND uv_libraries
+ kvm
+ )
+ list(APPEND uv_headers
+ include/uv-bsd.h
+ )
+ list(APPEND uv_sources
+ src/unix/bsd-ifaddrs.c
+ src/unix/netbsd.c
+ src/unix/kqueue.c
+ src/unix/posix-hrtime.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "OpenBSD")
+ list(APPEND uv_libraries
+ kvm
+ )
+ list(APPEND uv_headers
+ include/uv-bsd.h
+ )
+ list(APPEND uv_sources
+ src/unix/bsd-ifaddrs.c
+ src/unix/openbsd.c
+ src/unix/kqueue.c
+ src/unix/posix-hrtime.c
+ )
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
+ list(APPEND uv_libraries
+ kstat
+ nsl
+ sendfile
+ socket
+ rt
+ )
+ list(APPEND uv_headers
+ include/uv-sunos.h
+ )
+ list(APPEND uv_defines
+ __EXTENSIONS__
+ )
+ if(CMAKE_SYSTEM_VERSION STREQUAL "5.10")
+ set(CMAKE_C_STANDARD 90)
+ if(CMAKE_VERSION VERSION_LESS 3.8.20170504 AND CMAKE_C_COMPILER_ID STREQUAL "SunPro" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.14)
+ # The running version of CMake does not know how to add this flag.
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c90")
+ endif()
+ list(APPEND uv_defines
+ _XOPEN_SOURCE=500
+ )
+ else()
+ if(NOT CMAKE_C_STANDARD OR CMAKE_C_STANDARD EQUAL 90)
+ set(CMAKE_C_STANDARD 11)
+ endif()
+ if(CMAKE_VERSION VERSION_LESS 3.8.20170505 AND CMAKE_C_COMPILER_ID STREQUAL "SunPro" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.14)
+ # The running version of CMake does not know how to add this flag.
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -xc99")
+ endif()
+ list(APPEND uv_defines
+ _XOPEN_SOURCE=600
+ )
+ endif()
+ list(APPEND uv_sources
+ src/unix/no-proctitle.c
+ src/unix/sunos.c
+ )
+endif()
+
+include_directories(
+ ${uv_includes}
+ ${KWSYS_HEADER_ROOT}
+ )
+add_library(cmlibuv STATIC ${uv_sources})
+target_link_libraries(cmlibuv ${uv_libraries})
+set_property(TARGET cmlibuv PROPERTY COMPILE_DEFINITIONS ${uv_defines})
+
+install(FILES LICENSE DESTINATION ${CMAKE_DOC_DIR}/cmlibuv)
diff --git a/Utilities/cmlibuv/LICENSE b/Utilities/cmlibuv/LICENSE
new file mode 100644
index 000000000..41ba44c28
--- /dev/null
+++ b/Utilities/cmlibuv/LICENSE
@@ -0,0 +1,70 @@
+libuv is licensed for use as follows:
+
+====
+Copyright (c) 2015-present libuv project contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+====
+
+This license applies to parts of libuv originating from the
+https://github.com/joyent/libuv repository:
+
+====
+
+Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+IN THE SOFTWARE.
+
+====
+
+This license applies to all parts of libuv that are not externally
+maintained libraries.
+
+The externally maintained libraries used by libuv are:
+
+ - tree.h (from FreeBSD), copyright Niels Provos. Two clause BSD license.
+
+ - inet_pton and inet_ntop implementations, contained in src/inet.c, are
+ copyright the Internet Systems Consortium, Inc., and licensed under the ISC
+ license.
+
+ - stdint-msvc2008.h (from msinttypes), copyright Alexander Chemeris. Three
+ clause BSD license.
+
+ - pthread-fixes.h, pthread-fixes.c, copyright Google Inc. and Sony Mobile
+ Communications AB. Three clause BSD license.
+
+ - android-ifaddrs.h, android-ifaddrs.c, copyright Berkeley Software Design
+ Inc, Kenneth MacKay and Emergya (Cloud4all, FP7/2007-2013, grant agreement
+ n° 289016). Three clause BSD license.
diff --git a/Utilities/cmlibuv/include/android-ifaddrs.h b/Utilities/cmlibuv/include/android-ifaddrs.h
new file mode 100644
index 000000000..9cd19fec1
--- /dev/null
+++ b/Utilities/cmlibuv/include/android-ifaddrs.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 1995, 1999
+ * Berkeley Software Design, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``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 Berkeley Software Design, Inc. 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.
+ *
+ * BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
+ */
+
+#ifndef _IFADDRS_H_
+#define _IFADDRS_H_
+
+struct ifaddrs {
+ struct ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ struct sockaddr *ifa_addr;
+ struct sockaddr *ifa_netmask;
+ struct sockaddr *ifa_dstaddr;
+ void *ifa_data;
+};
+
+/*
+ * This may have been defined in <net/if.h>. Note that if <net/if.h> is
+ * to be included it must be included before this header file.
+ */
+#ifndef ifa_broadaddr
+#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
+#endif
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+extern int getifaddrs(struct ifaddrs **ifap);
+extern void freeifaddrs(struct ifaddrs *ifa);
+__END_DECLS
+
+#endif
diff --git a/Utilities/cmlibuv/include/pthread-barrier.h b/Utilities/cmlibuv/include/pthread-barrier.h
new file mode 100644
index 000000000..900ebedd3
--- /dev/null
+++ b/Utilities/cmlibuv/include/pthread-barrier.h
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+
+#ifndef _UV_PTHREAD_BARRIER_
+#define _UV_PTHREAD_BARRIER_
+#include <errno.h>
+#include <pthread.h>
+#if !defined(__MVS__)
+#include <semaphore.h> /* sem_t */
+#endif
+
+#define PTHREAD_BARRIER_SERIAL_THREAD 0x12345
+
+/*
+ * To maintain ABI compatibility with
+ * libuv v1.x struct is padded according
+ * to target platform
+ */
+#if defined(__ANDROID__)
+# define UV_BARRIER_STRUCT_PADDING \
+ sizeof(pthread_mutex_t) + \
+ sizeof(pthread_cond_t) + \
+ sizeof(unsigned int) - \
+ sizeof(void *)
+#elif defined(__APPLE__)
+# define UV_BARRIER_STRUCT_PADDING \
+ sizeof(pthread_mutex_t) + \
+ 2 * sizeof(sem_t) + \
+ 2 * sizeof(unsigned int) - \
+ sizeof(void *)
+#else
+# define UV_BARRIER_STRUCT_PADDING 0
+#endif
+
+typedef struct {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ unsigned threshold;
+ unsigned in;
+ unsigned out;
+} _uv_barrier;
+
+typedef struct {
+ _uv_barrier* b;
+ char _pad[UV_BARRIER_STRUCT_PADDING];
+} pthread_barrier_t;
+
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count);
+
+int pthread_barrier_wait(pthread_barrier_t* barrier);
+int pthread_barrier_destroy(pthread_barrier_t *barrier);
+
+#endif /* _UV_PTHREAD_BARRIER_ */
diff --git a/Utilities/cmlibuv/include/stdint-msvc2008.h b/Utilities/cmlibuv/include/stdint-msvc2008.h
new file mode 100644
index 000000000..d02608a59
--- /dev/null
+++ b/Utilities/cmlibuv/include/stdint-msvc2008.h
@@ -0,0 +1,247 @@
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2008 Alexander Chemeris
+//
+// 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.
+//
+// 3. The name of the author may be used to endorse or promote products
+// derived from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+#define INTMAX_C INT64_C
+#define UINTMAX_C UINT64_C
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/Utilities/cmlibuv/include/tree.h b/Utilities/cmlibuv/include/tree.h
new file mode 100644
index 000000000..f936416e3
--- /dev/null
+++ b/Utilities/cmlibuv/include/tree.h
@@ -0,0 +1,768 @@
+/*-
+ * Copyright 2002 Niels Provos <provos@citi.umich.edu>
+ * 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 ``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 BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UV_TREE_H_
+#define UV_TREE_H_
+
+#ifndef UV__UNUSED
+# if __GNUC__
+# define UV__UNUSED __attribute__((unused))
+# else
+# define UV__UNUSED
+# endif
+#endif
+
+/*
+ * This file defines data structures for different types of trees:
+ * splay trees and red-black trees.
+ *
+ * A splay tree is a self-organizing data structure. Every operation
+ * on the tree causes a splay to happen. The splay moves the requested
+ * node to the root of the tree and partly rebalances it.
+ *
+ * This has the benefit that request locality causes faster lookups as
+ * the requested nodes move to the top of the tree. On the other hand,
+ * every lookup causes memory writes.
+ *
+ * The Balance Theorem bounds the total access time for m operations
+ * and n inserts on an initially empty tree as O((m + n)lg n). The
+ * amortized cost for a sequence of m accesses to a splay tree is O(lg n);
+ *
+ * A red-black tree is a binary search tree with the node color as an
+ * extra attribute. It fulfills a set of conditions:
+ * - every search path from the root to a leaf consists of the
+ * same number of black nodes,
+ * - each red node (except for the root) has a black parent,
+ * - each leaf node is black.
+ *
+ * Every operation on a red-black tree is bounded as O(lg n).
+ * The maximum height of a red-black tree is 2lg (n+1).
+ */
+
+#define SPLAY_HEAD(name, type) \
+struct name { \
+ struct type *sph_root; /* root of the tree */ \
+}
+
+#define SPLAY_INITIALIZER(root) \
+ { NULL }
+
+#define SPLAY_INIT(root) do { \
+ (root)->sph_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ENTRY(type) \
+struct { \
+ struct type *spe_left; /* left element */ \
+ struct type *spe_right; /* right element */ \
+}
+
+#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
+#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
+#define SPLAY_ROOT(head) (head)->sph_root
+#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
+
+/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
+#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ (head)->sph_root = tmp; \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKLEFT(head, tmp, field) do { \
+ SPLAY_LEFT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_LINKRIGHT(head, tmp, field) do { \
+ SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
+ tmp = (head)->sph_root; \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+} while (/*CONSTCOND*/ 0)
+
+#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
+ SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
+ SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+
+#define SPLAY_PROTOTYPE(name, type, field, cmp) \
+void name##_SPLAY(struct name *, struct type *); \
+void name##_SPLAY_MINMAX(struct name *, int); \
+struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
+struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
+ \
+/* Finds the node with the same key as elm */ \
+static __inline struct type * \
+name##_SPLAY_FIND(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) \
+ return(NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) \
+ return (head->sph_root); \
+ return (NULL); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_NEXT(struct name *head, struct type *elm) \
+{ \
+ name##_SPLAY(head, elm); \
+ if (SPLAY_RIGHT(elm, field) != NULL) { \
+ elm = SPLAY_RIGHT(elm, field); \
+ while (SPLAY_LEFT(elm, field) != NULL) { \
+ elm = SPLAY_LEFT(elm, field); \
+ } \
+ } else \
+ elm = NULL; \
+ return (elm); \
+} \
+ \
+static __inline struct type * \
+name##_SPLAY_MIN_MAX(struct name *head, int val) \
+{ \
+ name##_SPLAY_MINMAX(head, val); \
+ return (SPLAY_ROOT(head)); \
+}
+
+/* Main splay operation.
+ * Moves node close to the key of elm to top
+ */
+#define SPLAY_GENERATE(name, type, field, cmp) \
+struct type * \
+name##_SPLAY_INSERT(struct name *head, struct type *elm) \
+{ \
+ if (SPLAY_EMPTY(head)) { \
+ SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
+ } else { \
+ int __comp; \
+ name##_SPLAY(head, elm); \
+ __comp = (cmp)(elm, (head)->sph_root); \
+ if(__comp < 0) { \
+ SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field); \
+ SPLAY_RIGHT(elm, field) = (head)->sph_root; \
+ SPLAY_LEFT((head)->sph_root, field) = NULL; \
+ } else if (__comp > 0) { \
+ SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field); \
+ SPLAY_LEFT(elm, field) = (head)->sph_root; \
+ SPLAY_RIGHT((head)->sph_root, field) = NULL; \
+ } else \
+ return ((head)->sph_root); \
+ } \
+ (head)->sph_root = (elm); \
+ return (NULL); \
+} \
+ \
+struct type * \
+name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *__tmp; \
+ if (SPLAY_EMPTY(head)) \
+ return (NULL); \
+ name##_SPLAY(head, elm); \
+ if ((cmp)(elm, (head)->sph_root) == 0) { \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
+ (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
+ } else { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
+ name##_SPLAY(head, elm); \
+ SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
+ } \
+ return (elm); \
+ } \
+ return (NULL); \
+} \
+ \
+void \
+name##_SPLAY(struct name *head, struct type *elm) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ int __comp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if ((cmp)(elm, __tmp) > 0){ \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+} \
+ \
+/* Splay with either the minimum or the maximum element \
+ * Used to find minimum or maximum element in tree. \
+ */ \
+void name##_SPLAY_MINMAX(struct name *head, int __comp) \
+{ \
+ struct type __node, *__left, *__right, *__tmp; \
+ \
+ SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL; \
+ __left = __right = &__node; \
+ \
+ while (1) { \
+ if (__comp < 0) { \
+ __tmp = SPLAY_LEFT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp < 0){ \
+ SPLAY_ROTATE_RIGHT(head, __tmp, field); \
+ if (SPLAY_LEFT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKLEFT(head, __right, field); \
+ } else if (__comp > 0) { \
+ __tmp = SPLAY_RIGHT((head)->sph_root, field); \
+ if (__tmp == NULL) \
+ break; \
+ if (__comp > 0) { \
+ SPLAY_ROTATE_LEFT(head, __tmp, field); \
+ if (SPLAY_RIGHT((head)->sph_root, field) == NULL) \
+ break; \
+ } \
+ SPLAY_LINKRIGHT(head, __left, field); \
+ } \
+ } \
+ SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
+}
+
+#define SPLAY_NEGINF -1
+#define SPLAY_INF 1
+
+#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
+#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
+#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
+#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
+#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
+#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
+ : name##_SPLAY_MIN_MAX(x, SPLAY_INF))
+
+#define SPLAY_FOREACH(x, name, head) \
+ for ((x) = SPLAY_MIN(name, head); \
+ (x) != NULL; \
+ (x) = SPLAY_NEXT(name, head, x))
+
+/* Macros that define a red-black tree */
+#define RB_HEAD(name, type) \
+struct name { \
+ struct type *rbh_root; /* root of the tree */ \
+}
+
+#define RB_INITIALIZER(root) \
+ { NULL }
+
+#define RB_INIT(root) do { \
+ (root)->rbh_root = NULL; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_BLACK 0
+#define RB_RED 1
+#define RB_ENTRY(type) \
+struct { \
+ struct type *rbe_left; /* left element */ \
+ struct type *rbe_right; /* right element */ \
+ struct type *rbe_parent; /* parent element */ \
+ int rbe_color; /* node color */ \
+}
+
+#define RB_LEFT(elm, field) (elm)->field.rbe_left
+#define RB_RIGHT(elm, field) (elm)->field.rbe_right
+#define RB_PARENT(elm, field) (elm)->field.rbe_parent
+#define RB_COLOR(elm, field) (elm)->field.rbe_color
+#define RB_ROOT(head) (head)->rbh_root
+#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
+
+#define RB_SET(elm, parent, field) do { \
+ RB_PARENT(elm, field) = parent; \
+ RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
+ RB_COLOR(elm, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_SET_BLACKRED(black, red, field) do { \
+ RB_COLOR(black, field) = RB_BLACK; \
+ RB_COLOR(red, field) = RB_RED; \
+} while (/*CONSTCOND*/ 0)
+
+#ifndef RB_AUGMENT
+#define RB_AUGMENT(x) do {} while (0)
+#endif
+
+#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
+ (tmp) = RB_RIGHT(elm, field); \
+ if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_LEFT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
+ (tmp) = RB_LEFT(elm, field); \
+ if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
+ RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
+ } \
+ RB_AUGMENT(elm); \
+ if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
+ if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
+ RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
+ else \
+ RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
+ } else \
+ (head)->rbh_root = (tmp); \
+ RB_RIGHT(tmp, field) = (elm); \
+ RB_PARENT(elm, field) = (tmp); \
+ RB_AUGMENT(tmp); \
+ if ((RB_PARENT(tmp, field))) \
+ RB_AUGMENT(RB_PARENT(tmp, field)); \
+} while (/*CONSTCOND*/ 0)
+
+/* Generates prototypes and inline functions */
+#define RB_PROTOTYPE(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
+#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
+ RB_PROTOTYPE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
+attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
+attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
+attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
+attr struct type *name##_RB_INSERT(struct name *, struct type *); \
+attr struct type *name##_RB_FIND(struct name *, struct type *); \
+attr struct type *name##_RB_NFIND(struct name *, struct type *); \
+attr struct type *name##_RB_NEXT(struct type *); \
+attr struct type *name##_RB_PREV(struct type *); \
+attr struct type *name##_RB_MINMAX(struct name *, int); \
+ \
+
+/* Main rb operation.
+ * Moves node close to the key of elm to top
+ */
+#define RB_GENERATE(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp,)
+#define RB_GENERATE_STATIC(name, type, field, cmp) \
+ RB_GENERATE_INTERNAL(name, type, field, cmp, UV__UNUSED static)
+#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
+attr void \
+name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
+{ \
+ struct type *parent, *gparent, *tmp; \
+ while ((parent = RB_PARENT(elm, field)) != NULL && \
+ RB_COLOR(parent, field) == RB_RED) { \
+ gparent = RB_PARENT(parent, field); \
+ if (parent == RB_LEFT(gparent, field)) { \
+ tmp = RB_RIGHT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_RIGHT(parent, field) == elm) { \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_RIGHT(head, gparent, tmp, field); \
+ } else { \
+ tmp = RB_LEFT(gparent, field); \
+ if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
+ RB_COLOR(tmp, field) = RB_BLACK; \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ elm = gparent; \
+ continue; \
+ } \
+ if (RB_LEFT(parent, field) == elm) { \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = parent; \
+ parent = elm; \
+ elm = tmp; \
+ } \
+ RB_SET_BLACKRED(parent, gparent, field); \
+ RB_ROTATE_LEFT(head, gparent, tmp, field); \
+ } \
+ } \
+ RB_COLOR(head->rbh_root, field) = RB_BLACK; \
+} \
+ \
+attr void \
+name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, \
+ struct type *elm) \
+{ \
+ struct type *tmp; \
+ while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
+ elm != RB_ROOT(head)) { \
+ if (RB_LEFT(parent, field) == elm) { \
+ tmp = RB_RIGHT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) { \
+ struct type *oleft; \
+ if ((oleft = RB_LEFT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oleft, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_RIGHT(head, tmp, oleft, field); \
+ tmp = RB_RIGHT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_RIGHT(tmp, field)) \
+ RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_LEFT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } else { \
+ tmp = RB_LEFT(parent, field); \
+ if (RB_COLOR(tmp, field) == RB_RED) { \
+ RB_SET_BLACKRED(tmp, parent, field); \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ if ((RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) && \
+ (RB_RIGHT(tmp, field) == NULL || \
+ RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) { \
+ RB_COLOR(tmp, field) = RB_RED; \
+ elm = parent; \
+ parent = RB_PARENT(elm, field); \
+ } else { \
+ if (RB_LEFT(tmp, field) == NULL || \
+ RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) { \
+ struct type *oright; \
+ if ((oright = RB_RIGHT(tmp, field)) \
+ != NULL) \
+ RB_COLOR(oright, field) = RB_BLACK; \
+ RB_COLOR(tmp, field) = RB_RED; \
+ RB_ROTATE_LEFT(head, tmp, oright, field); \
+ tmp = RB_LEFT(parent, field); \
+ } \
+ RB_COLOR(tmp, field) = RB_COLOR(parent, field); \
+ RB_COLOR(parent, field) = RB_BLACK; \
+ if (RB_LEFT(tmp, field)) \
+ RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK; \
+ RB_ROTATE_RIGHT(head, parent, tmp, field); \
+ elm = RB_ROOT(head); \
+ break; \
+ } \
+ } \
+ } \
+ if (elm) \
+ RB_COLOR(elm, field) = RB_BLACK; \
+} \
+ \
+attr struct type * \
+name##_RB_REMOVE(struct name *head, struct type *elm) \
+{ \
+ struct type *child, *parent, *old = elm; \
+ int color; \
+ if (RB_LEFT(elm, field) == NULL) \
+ child = RB_RIGHT(elm, field); \
+ else if (RB_RIGHT(elm, field) == NULL) \
+ child = RB_LEFT(elm, field); \
+ else { \
+ struct type *left; \
+ elm = RB_RIGHT(elm, field); \
+ while ((left = RB_LEFT(elm, field)) != NULL) \
+ elm = left; \
+ child = RB_RIGHT(elm, field); \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+ if (RB_PARENT(elm, field) == old) \
+ parent = elm; \
+ (elm)->field = (old)->field; \
+ if (RB_PARENT(old, field)) { \
+ if (RB_LEFT(RB_PARENT(old, field), field) == old) \
+ RB_LEFT(RB_PARENT(old, field), field) = elm; \
+ else \
+ RB_RIGHT(RB_PARENT(old, field), field) = elm; \
+ RB_AUGMENT(RB_PARENT(old, field)); \
+ } else \
+ RB_ROOT(head) = elm; \
+ RB_PARENT(RB_LEFT(old, field), field) = elm; \
+ if (RB_RIGHT(old, field)) \
+ RB_PARENT(RB_RIGHT(old, field), field) = elm; \
+ if (parent) { \
+ left = parent; \
+ do { \
+ RB_AUGMENT(left); \
+ } while ((left = RB_PARENT(left, field)) != NULL); \
+ } \
+ goto color; \
+ } \
+ parent = RB_PARENT(elm, field); \
+ color = RB_COLOR(elm, field); \
+ if (child) \
+ RB_PARENT(child, field) = parent; \
+ if (parent) { \
+ if (RB_LEFT(parent, field) == elm) \
+ RB_LEFT(parent, field) = child; \
+ else \
+ RB_RIGHT(parent, field) = child; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = child; \
+color: \
+ if (color == RB_BLACK) \
+ name##_RB_REMOVE_COLOR(head, parent, child); \
+ return (old); \
+} \
+ \
+/* Inserts a node into the RB tree */ \
+attr struct type * \
+name##_RB_INSERT(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp; \
+ struct type *parent = NULL; \
+ int comp = 0; \
+ tmp = RB_ROOT(head); \
+ while (tmp) { \
+ parent = tmp; \
+ comp = (cmp)(elm, parent); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ RB_SET(elm, parent, field); \
+ if (parent != NULL) { \
+ if (comp < 0) \
+ RB_LEFT(parent, field) = elm; \
+ else \
+ RB_RIGHT(parent, field) = elm; \
+ RB_AUGMENT(parent); \
+ } else \
+ RB_ROOT(head) = elm; \
+ name##_RB_INSERT_COLOR(head, elm); \
+ return (NULL); \
+} \
+ \
+/* Finds the node with the same key as elm */ \
+attr struct type * \
+name##_RB_FIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (NULL); \
+} \
+ \
+/* Finds the first node greater than or equal to the search key */ \
+attr struct type * \
+name##_RB_NFIND(struct name *head, struct type *elm) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *res = NULL; \
+ int comp; \
+ while (tmp) { \
+ comp = cmp(elm, tmp); \
+ if (comp < 0) { \
+ res = tmp; \
+ tmp = RB_LEFT(tmp, field); \
+ } \
+ else if (comp > 0) \
+ tmp = RB_RIGHT(tmp, field); \
+ else \
+ return (tmp); \
+ } \
+ return (res); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_NEXT(struct type *elm) \
+{ \
+ if (RB_RIGHT(elm, field)) { \
+ elm = RB_RIGHT(elm, field); \
+ while (RB_LEFT(elm, field)) \
+ elm = RB_LEFT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+/* ARGSUSED */ \
+attr struct type * \
+name##_RB_PREV(struct type *elm) \
+{ \
+ if (RB_LEFT(elm, field)) { \
+ elm = RB_LEFT(elm, field); \
+ while (RB_RIGHT(elm, field)) \
+ elm = RB_RIGHT(elm, field); \
+ } else { \
+ if (RB_PARENT(elm, field) && \
+ (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ else { \
+ while (RB_PARENT(elm, field) && \
+ (elm == RB_LEFT(RB_PARENT(elm, field), field))) \
+ elm = RB_PARENT(elm, field); \
+ elm = RB_PARENT(elm, field); \
+ } \
+ } \
+ return (elm); \
+} \
+ \
+attr struct type * \
+name##_RB_MINMAX(struct name *head, int val) \
+{ \
+ struct type *tmp = RB_ROOT(head); \
+ struct type *parent = NULL; \
+ while (tmp) { \
+ parent = tmp; \
+ if (val < 0) \
+ tmp = RB_LEFT(tmp, field); \
+ else \
+ tmp = RB_RIGHT(tmp, field); \
+ } \
+ return (parent); \
+}
+
+#define RB_NEGINF -1
+#define RB_INF 1
+
+#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
+#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
+#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
+#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
+#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
+#define RB_PREV(name, x, y) name##_RB_PREV(y)
+#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
+#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
+
+#define RB_FOREACH(x, name, head) \
+ for ((x) = RB_MIN(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_NEXT(x))
+
+#define RB_FOREACH_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_SAFE(x, name, head, y) \
+ for ((x) = RB_MIN(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE(x, name, head) \
+ for ((x) = RB_MAX(name, head); \
+ (x) != NULL; \
+ (x) = name##_RB_PREV(x))
+
+#define RB_FOREACH_REVERSE_FROM(x, name, y) \
+ for ((x) = (y); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
+ for ((x) = RB_MAX(name, head); \
+ ((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
+ (x) = (y))
+
+#endif /* UV_TREE_H_ */
diff --git a/Utilities/cmlibuv/include/uv-aix.h b/Utilities/cmlibuv/include/uv-aix.h
new file mode 100644
index 000000000..7dc992fa6
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-aix.h
@@ -0,0 +1,32 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_AIX_H
+#define UV_AIX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ int fs_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char *dir_filename; \
+
+#endif /* UV_AIX_H */
diff --git a/Utilities/cmlibuv/include/uv-bsd.h b/Utilities/cmlibuv/include/uv-bsd.h
new file mode 100644
index 000000000..2d72b3d77
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-bsd.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_BSD_H
+#define UV_BSD_H
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_BSD_H */
diff --git a/Utilities/cmlibuv/include/uv-darwin.h b/Utilities/cmlibuv/include/uv-darwin.h
new file mode 100644
index 000000000..d22641582
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-darwin.h
@@ -0,0 +1,61 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_DARWIN_H
+#define UV_DARWIN_H
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach/mach.h>
+# include <mach/task.h>
+# include <mach/semaphore.h>
+# include <TargetConditionals.h>
+# define UV_PLATFORM_SEM_T semaphore_t
+#endif
+
+#define UV_IO_PRIVATE_PLATFORM_FIELDS \
+ int rcount; \
+ int wcount; \
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv_thread_t cf_thread; \
+ void* _cf_reserved; \
+ void* cf_state; \
+ uv_mutex_t cf_mutex; \
+ uv_sem_t cf_sem; \
+ void* cf_signals[2]; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ uv__io_t event_watcher; \
+ char* realpath; \
+ int realpath_len; \
+ int cf_flags; \
+ uv_async_t* cf_cb; \
+ void* cf_events[2]; \
+ void* cf_member[2]; \
+ int cf_error; \
+ uv_mutex_t cf_mutex; \
+
+#define UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+ void* select; \
+
+#define UV_HAVE_KQUEUE 1
+
+#endif /* UV_DARWIN_H */
diff --git a/Utilities/cmlibuv/include/uv-errno.h b/Utilities/cmlibuv/include/uv-errno.h
new file mode 100644
index 000000000..f1371517c
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-errno.h
@@ -0,0 +1,419 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_ERRNO_H_
+#define UV_ERRNO_H_
+
+#include <errno.h>
+
+#define UV__EOF (-4095)
+#define UV__UNKNOWN (-4094)
+
+#define UV__EAI_ADDRFAMILY (-3000)
+#define UV__EAI_AGAIN (-3001)
+#define UV__EAI_BADFLAGS (-3002)
+#define UV__EAI_CANCELED (-3003)
+#define UV__EAI_FAIL (-3004)
+#define UV__EAI_FAMILY (-3005)
+#define UV__EAI_MEMORY (-3006)
+#define UV__EAI_NODATA (-3007)
+#define UV__EAI_NONAME (-3008)
+#define UV__EAI_OVERFLOW (-3009)
+#define UV__EAI_SERVICE (-3010)
+#define UV__EAI_SOCKTYPE (-3011)
+#define UV__EAI_BADHINTS (-3013)
+#define UV__EAI_PROTOCOL (-3014)
+
+/* Only map to the system errno on non-Windows platforms. It's apparently
+ * a fairly common practice for Windows programmers to redefine errno codes.
+ */
+#if defined(E2BIG) && !defined(_WIN32)
+# define UV__E2BIG (-E2BIG)
+#else
+# define UV__E2BIG (-4093)
+#endif
+
+#if defined(EACCES) && !defined(_WIN32)
+# define UV__EACCES (-EACCES)
+#else
+# define UV__EACCES (-4092)
+#endif
+
+#if defined(EADDRINUSE) && !defined(_WIN32)
+# define UV__EADDRINUSE (-EADDRINUSE)
+#else
+# define UV__EADDRINUSE (-4091)
+#endif
+
+#if defined(EADDRNOTAVAIL) && !defined(_WIN32)
+# define UV__EADDRNOTAVAIL (-EADDRNOTAVAIL)
+#else
+# define UV__EADDRNOTAVAIL (-4090)
+#endif
+
+#if defined(EAFNOSUPPORT) && !defined(_WIN32)
+# define UV__EAFNOSUPPORT (-EAFNOSUPPORT)
+#else
+# define UV__EAFNOSUPPORT (-4089)
+#endif
+
+#if defined(EAGAIN) && !defined(_WIN32)
+# define UV__EAGAIN (-EAGAIN)
+#else
+# define UV__EAGAIN (-4088)
+#endif
+
+#if defined(EALREADY) && !defined(_WIN32)
+# define UV__EALREADY (-EALREADY)
+#else
+# define UV__EALREADY (-4084)
+#endif
+
+#if defined(EBADF) && !defined(_WIN32)
+# define UV__EBADF (-EBADF)
+#else
+# define UV__EBADF (-4083)
+#endif
+
+#if defined(EBUSY) && !defined(_WIN32)
+# define UV__EBUSY (-EBUSY)
+#else
+# define UV__EBUSY (-4082)
+#endif
+
+#if defined(ECANCELED) && !defined(_WIN32)
+# define UV__ECANCELED (-ECANCELED)
+#else
+# define UV__ECANCELED (-4081)
+#endif
+
+#if defined(ECHARSET) && !defined(_WIN32)
+# define UV__ECHARSET (-ECHARSET)
+#else
+# define UV__ECHARSET (-4080)
+#endif
+
+#if defined(ECONNABORTED) && !defined(_WIN32)
+# define UV__ECONNABORTED (-ECONNABORTED)
+#else
+# define UV__ECONNABORTED (-4079)
+#endif
+
+#if defined(ECONNREFUSED) && !defined(_WIN32)
+# define UV__ECONNREFUSED (-ECONNREFUSED)
+#else
+# define UV__ECONNREFUSED (-4078)
+#endif
+
+#if defined(ECONNRESET) && !defined(_WIN32)
+# define UV__ECONNRESET (-ECONNRESET)
+#else
+# define UV__ECONNRESET (-4077)
+#endif
+
+#if defined(EDESTADDRREQ) && !defined(_WIN32)
+# define UV__EDESTADDRREQ (-EDESTADDRREQ)
+#else
+# define UV__EDESTADDRREQ (-4076)
+#endif
+
+#if defined(EEXIST) && !defined(_WIN32)
+# define UV__EEXIST (-EEXIST)
+#else
+# define UV__EEXIST (-4075)
+#endif
+
+#if defined(EFAULT) && !defined(_WIN32)
+# define UV__EFAULT (-EFAULT)
+#else
+# define UV__EFAULT (-4074)
+#endif
+
+#if defined(EHOSTUNREACH) && !defined(_WIN32)
+# define UV__EHOSTUNREACH (-EHOSTUNREACH)
+#else
+# define UV__EHOSTUNREACH (-4073)
+#endif
+
+#if defined(EINTR) && !defined(_WIN32)
+# define UV__EINTR (-EINTR)
+#else
+# define UV__EINTR (-4072)
+#endif
+
+#if defined(EINVAL) && !defined(_WIN32)
+# define UV__EINVAL (-EINVAL)
+#else
+# define UV__EINVAL (-4071)
+#endif
+
+#if defined(EIO) && !defined(_WIN32)
+# define UV__EIO (-EIO)
+#else
+# define UV__EIO (-4070)
+#endif
+
+#if defined(EISCONN) && !defined(_WIN32)
+# define UV__EISCONN (-EISCONN)
+#else
+# define UV__EISCONN (-4069)
+#endif
+
+#if defined(EISDIR) && !defined(_WIN32)
+# define UV__EISDIR (-EISDIR)
+#else
+# define UV__EISDIR (-4068)
+#endif
+
+#if defined(ELOOP) && !defined(_WIN32)
+# define UV__ELOOP (-ELOOP)
+#else
+# define UV__ELOOP (-4067)
+#endif
+
+#if defined(EMFILE) && !defined(_WIN32)
+# define UV__EMFILE (-EMFILE)
+#else
+# define UV__EMFILE (-4066)
+#endif
+
+#if defined(EMSGSIZE) && !defined(_WIN32)
+# define UV__EMSGSIZE (-EMSGSIZE)
+#else
+# define UV__EMSGSIZE (-4065)
+#endif
+
+#if defined(ENAMETOOLONG) && !defined(_WIN32)
+# define UV__ENAMETOOLONG (-ENAMETOOLONG)
+#else
+# define UV__ENAMETOOLONG (-4064)
+#endif
+
+#if defined(ENETDOWN) && !defined(_WIN32)
+# define UV__ENETDOWN (-ENETDOWN)
+#else
+# define UV__ENETDOWN (-4063)
+#endif
+
+#if defined(ENETUNREACH) && !defined(_WIN32)
+# define UV__ENETUNREACH (-ENETUNREACH)
+#else
+# define UV__ENETUNREACH (-4062)
+#endif
+
+#if defined(ENFILE) && !defined(_WIN32)
+# define UV__ENFILE (-ENFILE)
+#else
+# define UV__ENFILE (-4061)
+#endif
+
+#if defined(ENOBUFS) && !defined(_WIN32)
+# define UV__ENOBUFS (-ENOBUFS)
+#else
+# define UV__ENOBUFS (-4060)
+#endif
+
+#if defined(ENODEV) && !defined(_WIN32)
+# define UV__ENODEV (-ENODEV)
+#else
+# define UV__ENODEV (-4059)
+#endif
+
+#if defined(ENOENT) && !defined(_WIN32)
+# define UV__ENOENT (-ENOENT)
+#else
+# define UV__ENOENT (-4058)
+#endif
+
+#if defined(ENOMEM) && !defined(_WIN32)
+# define UV__ENOMEM (-ENOMEM)
+#else
+# define UV__ENOMEM (-4057)
+#endif
+
+#if defined(ENONET) && !defined(_WIN32)
+# define UV__ENONET (-ENONET)
+#else
+# define UV__ENONET (-4056)
+#endif
+
+#if defined(ENOSPC) && !defined(_WIN32)
+# define UV__ENOSPC (-ENOSPC)
+#else
+# define UV__ENOSPC (-4055)
+#endif
+
+#if defined(ENOSYS) && !defined(_WIN32)
+# define UV__ENOSYS (-ENOSYS)
+#else
+# define UV__ENOSYS (-4054)
+#endif
+
+#if defined(ENOTCONN) && !defined(_WIN32)
+# define UV__ENOTCONN (-ENOTCONN)
+#else
+# define UV__ENOTCONN (-4053)
+#endif
+
+#if defined(ENOTDIR) && !defined(_WIN32)
+# define UV__ENOTDIR (-ENOTDIR)
+#else
+# define UV__ENOTDIR (-4052)
+#endif
+
+#if defined(ENOTEMPTY) && !defined(_WIN32)
+# define UV__ENOTEMPTY (-ENOTEMPTY)
+#else
+# define UV__ENOTEMPTY (-4051)
+#endif
+
+#if defined(ENOTSOCK) && !defined(_WIN32)
+# define UV__ENOTSOCK (-ENOTSOCK)
+#else
+# define UV__ENOTSOCK (-4050)
+#endif
+
+#if defined(ENOTSUP) && !defined(_WIN32)
+# define UV__ENOTSUP (-ENOTSUP)
+#else
+# define UV__ENOTSUP (-4049)
+#endif
+
+#if defined(EPERM) && !defined(_WIN32)
+# define UV__EPERM (-EPERM)
+#else
+# define UV__EPERM (-4048)
+#endif
+
+#if defined(EPIPE) && !defined(_WIN32)
+# define UV__EPIPE (-EPIPE)
+#else
+# define UV__EPIPE (-4047)
+#endif
+
+#if defined(EPROTO) && !defined(_WIN32)
+# define UV__EPROTO (-EPROTO)
+#else
+# define UV__EPROTO (-4046)
+#endif
+
+#if defined(EPROTONOSUPPORT) && !defined(_WIN32)
+# define UV__EPROTONOSUPPORT (-EPROTONOSUPPORT)
+#else
+# define UV__EPROTONOSUPPORT (-4045)
+#endif
+
+#if defined(EPROTOTYPE) && !defined(_WIN32)
+# define UV__EPROTOTYPE (-EPROTOTYPE)
+#else
+# define UV__EPROTOTYPE (-4044)
+#endif
+
+#if defined(EROFS) && !defined(_WIN32)
+# define UV__EROFS (-EROFS)
+#else
+# define UV__EROFS (-4043)
+#endif
+
+#if defined(ESHUTDOWN) && !defined(_WIN32)
+# define UV__ESHUTDOWN (-ESHUTDOWN)
+#else
+# define UV__ESHUTDOWN (-4042)
+#endif
+
+#if defined(ESPIPE) && !defined(_WIN32)
+# define UV__ESPIPE (-ESPIPE)
+#else
+# define UV__ESPIPE (-4041)
+#endif
+
+#if defined(ESRCH) && !defined(_WIN32)
+# define UV__ESRCH (-ESRCH)
+#else
+# define UV__ESRCH (-4040)
+#endif
+
+#if defined(ETIMEDOUT) && !defined(_WIN32)
+# define UV__ETIMEDOUT (-ETIMEDOUT)
+#else
+# define UV__ETIMEDOUT (-4039)
+#endif
+
+#if defined(ETXTBSY) && !defined(_WIN32)
+# define UV__ETXTBSY (-ETXTBSY)
+#else
+# define UV__ETXTBSY (-4038)
+#endif
+
+#if defined(EXDEV) && !defined(_WIN32)
+# define UV__EXDEV (-EXDEV)
+#else
+# define UV__EXDEV (-4037)
+#endif
+
+#if defined(EFBIG) && !defined(_WIN32)
+# define UV__EFBIG (-EFBIG)
+#else
+# define UV__EFBIG (-4036)
+#endif
+
+#if defined(ENOPROTOOPT) && !defined(_WIN32)
+# define UV__ENOPROTOOPT (-ENOPROTOOPT)
+#else
+# define UV__ENOPROTOOPT (-4035)
+#endif
+
+#if defined(ERANGE) && !defined(_WIN32)
+# define UV__ERANGE (-ERANGE)
+#else
+# define UV__ERANGE (-4034)
+#endif
+
+#if defined(ENXIO) && !defined(_WIN32)
+# define UV__ENXIO (-ENXIO)
+#else
+# define UV__ENXIO (-4033)
+#endif
+
+#if defined(EMLINK) && !defined(_WIN32)
+# define UV__EMLINK (-EMLINK)
+#else
+# define UV__EMLINK (-4032)
+#endif
+
+/* EHOSTDOWN is not visible on BSD-like systems when _POSIX_C_SOURCE is
+ * defined. Fortunately, its value is always 64 so it's possible albeit
+ * icky to hard-code it.
+ */
+#if defined(EHOSTDOWN) && !defined(_WIN32)
+# define UV__EHOSTDOWN (-EHOSTDOWN)
+#elif defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || \
+ defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define UV__EHOSTDOWN (-64)
+#else
+# define UV__EHOSTDOWN (-4031)
+#endif
+
+#endif /* UV_ERRNO_H_ */
diff --git a/Utilities/cmlibuv/include/uv-linux.h b/Utilities/cmlibuv/include/uv-linux.h
new file mode 100644
index 000000000..9b38405a1
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-linux.h
@@ -0,0 +1,34 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_H
+#define UV_LINUX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t inotify_read_watcher; \
+ void* inotify_watchers; \
+ int inotify_fd; \
+
+#define UV_PLATFORM_FS_EVENT_FIELDS \
+ void* watchers[2]; \
+ int wd; \
+
+#endif /* UV_LINUX_H */
diff --git a/Utilities/cmlibuv/include/uv-os390.h b/Utilities/cmlibuv/include/uv-os390.h
new file mode 100644
index 000000000..58f926111
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-os390.h
@@ -0,0 +1,30 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_MVS_H
+#define UV_MVS_H
+
+#define UV_PLATFORM_SEM_T int
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ void* ep; \
+
+#endif /* UV_MVS_H */
diff --git a/Utilities/cmlibuv/include/uv-posix.h b/Utilities/cmlibuv/include/uv-posix.h
new file mode 100644
index 000000000..9a96634db
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-posix.h
@@ -0,0 +1,31 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_POSIX_H
+#define UV_POSIX_H
+
+#define UV_PLATFORM_LOOP_FIELDS \
+ struct pollfd* poll_fds; \
+ size_t poll_fds_used; \
+ size_t poll_fds_size; \
+ unsigned char poll_fds_iterating; \
+
+#endif /* UV_POSIX_H */
diff --git a/Utilities/cmlibuv/include/uv-sunos.h b/Utilities/cmlibuv/include/uv-sunos.h
new file mode 100644
index 000000000..042166424
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-sunos.h
@@ -0,0 +1,44 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_SUNOS_H
+#define UV_SUNOS_H
+
+#include <sys/port.h>
+#include <port.h>
+
+/* For the sake of convenience and reduced #ifdef-ery in src/unix/sunos.c,
+ * add the fs_event fields even when this version of SunOS doesn't support
+ * file watching.
+ */
+#define UV_PLATFORM_LOOP_FIELDS \
+ uv__io_t fs_event_watcher; \
+ int fs_fd; \
+
+#if defined(PORT_SOURCE_FILE)
+
+# define UV_PLATFORM_FS_EVENT_FIELDS \
+ file_obj_t fo; \
+ int fd; \
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+#endif /* UV_SUNOS_H */
diff --git a/Utilities/cmlibuv/include/uv-threadpool.h b/Utilities/cmlibuv/include/uv-threadpool.h
new file mode 100644
index 000000000..9708ebdd5
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-threadpool.h
@@ -0,0 +1,37 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_THREADPOOL_H_
+#define UV_THREADPOOL_H_
+
+struct uv__work {
+ void (*work)(struct uv__work *w);
+ void (*done)(struct uv__work *w, int status);
+ struct uv_loop_s* loop;
+ void* wq[2];
+};
+
+#endif /* UV_THREADPOOL_H_ */
diff --git a/Utilities/cmlibuv/include/uv-unix.h b/Utilities/cmlibuv/include/uv-unix.h
new file mode 100644
index 000000000..d7754509b
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-unix.h
@@ -0,0 +1,368 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_H
+#define UV_UNIX_H
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <termios.h>
+#include <pwd.h>
+
+#if !defined(__MVS__)
+#include <semaphore.h>
+#endif
+#include <pthread.h>
+#include <signal.h>
+
+#include "uv-threadpool.h"
+
+#if defined(__linux__)
+# include "uv-linux.h"
+#elif defined (__MVS__)
+# include "uv-os390.h"
+#elif defined(_AIX)
+# include "uv-aix.h"
+#elif defined(__sun)
+# include "uv-sunos.h"
+#elif defined(__APPLE__)
+# include "uv-darwin.h"
+#elif defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# include "uv-bsd.h"
+#elif defined(__CYGWIN__) || defined(__MSYS__)
+# include "uv-posix.h"
+#endif
+
+#ifndef PTHREAD_BARRIER_SERIAL_THREAD
+# include "pthread-barrier.h"
+#endif
+
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif
+
+#ifndef UV_IO_PRIVATE_PLATFORM_FIELDS
+# define UV_IO_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+struct uv__io_s;
+struct uv_loop_s;
+
+typedef void (*uv__io_cb)(struct uv_loop_s* loop,
+ struct uv__io_s* w,
+ unsigned int events);
+typedef struct uv__io_s uv__io_t;
+
+struct uv__io_s {
+ uv__io_cb cb;
+ void* pending_queue[2];
+ void* watcher_queue[2];
+ unsigned int pevents; /* Pending event mask i.e. mask at next tick. */
+ unsigned int events; /* Current event mask. */
+ int fd;
+ UV_IO_PRIVATE_PLATFORM_FIELDS
+};
+
+#ifndef UV_PLATFORM_SEM_T
+# define UV_PLATFORM_SEM_T sem_t
+#endif
+
+#ifndef UV_PLATFORM_LOOP_FIELDS
+# define UV_PLATFORM_LOOP_FIELDS /* empty */
+#endif
+
+#ifndef UV_PLATFORM_FS_EVENT_FIELDS
+# define UV_PLATFORM_FS_EVENT_FIELDS /* empty */
+#endif
+
+#ifndef UV_STREAM_PRIVATE_PLATFORM_FIELDS
+# define UV_STREAM_PRIVATE_PLATFORM_FIELDS /* empty */
+#endif
+
+/* Note: May be cast to struct iovec. See writev(2). */
+typedef struct uv_buf_t {
+ char* base;
+ size_t len;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef int uv_os_sock_t;
+typedef int uv_os_fd_t;
+
+#define UV_ONCE_INIT PTHREAD_ONCE_INIT
+
+typedef pthread_once_t uv_once_t;
+typedef pthread_t uv_thread_t;
+typedef pthread_mutex_t uv_mutex_t;
+typedef pthread_rwlock_t uv_rwlock_t;
+typedef UV_PLATFORM_SEM_T uv_sem_t;
+typedef pthread_cond_t uv_cond_t;
+typedef pthread_key_t uv_key_t;
+typedef pthread_barrier_t uv_barrier_t;
+
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef gid_t uv_gid_t;
+typedef uid_t uv_uid_t;
+
+typedef struct dirent uv__dirent_t;
+
+#if defined(DT_UNKNOWN)
+# define HAVE_DIRENT_TYPES
+# if defined(DT_REG)
+# define UV__DT_FILE DT_REG
+# else
+# define UV__DT_FILE -1
+# endif
+# if defined(DT_DIR)
+# define UV__DT_DIR DT_DIR
+# else
+# define UV__DT_DIR -2
+# endif
+# if defined(DT_LNK)
+# define UV__DT_LINK DT_LNK
+# else
+# define UV__DT_LINK -3
+# endif
+# if defined(DT_FIFO)
+# define UV__DT_FIFO DT_FIFO
+# else
+# define UV__DT_FIFO -4
+# endif
+# if defined(DT_SOCK)
+# define UV__DT_SOCKET DT_SOCK
+# else
+# define UV__DT_SOCKET -5
+# endif
+# if defined(DT_CHR)
+# define UV__DT_CHAR DT_CHR
+# else
+# define UV__DT_CHAR -6
+# endif
+# if defined(DT_BLK)
+# define UV__DT_BLOCK DT_BLK
+# else
+# define UV__DT_BLOCK -7
+# endif
+#endif
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC /* empty */
+
+typedef struct {
+ void* handle;
+ char* errmsg;
+} uv_lib_t;
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ unsigned long flags; \
+ int backend_fd; \
+ void* pending_queue[2]; \
+ void* watcher_queue[2]; \
+ uv__io_t** watchers; \
+ unsigned int nwatchers; \
+ unsigned int nfds; \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async; \
+ uv_rwlock_t cloexec_lock; \
+ uv_handle_t* closing_handles; \
+ void* process_handles[2]; \
+ void* prepare_handles[2]; \
+ void* check_handles[2]; \
+ void* idle_handles[2]; \
+ void* async_handles[2]; \
+ void (*async_unused)(void); /* TODO(bnoordhuis) Remove in libuv v2. */ \
+ uv__io_t async_io_watcher; \
+ int async_wfd; \
+ struct { \
+ void* min; \
+ unsigned int nelts; \
+ } timer_heap; \
+ uint64_t timer_counter; \
+ uint64_t time; \
+ int signal_pipefd[2]; \
+ uv__io_t signal_io_watcher; \
+ uv_signal_t child_watcher; \
+ int emfile_fd; \
+ UV_PLATFORM_LOOP_FIELDS \
+
+#define UV_REQ_TYPE_PRIVATE /* empty */
+
+#define UV_REQ_PRIVATE_FIELDS /* empty */
+
+#define UV_PRIVATE_REQ_TYPES /* empty */
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ void* queue[2]; \
+ unsigned int write_index; \
+ uv_buf_t* bufs; \
+ unsigned int nbufs; \
+ int error; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ void* queue[2]; \
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ void* queue[2]; \
+ struct sockaddr_storage addr; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ ssize_t status; \
+ uv_udp_send_cb send_cb; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* next_closing; \
+ unsigned int flags; \
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ uv_connect_t *connect_req; \
+ uv_shutdown_t *shutdown_req; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+ uv_connection_cb connection_cb; \
+ int delayed_error; \
+ int accepted_fd; \
+ void* queued_fds; \
+ UV_STREAM_PRIVATE_PLATFORM_FIELDS \
+
+#define UV_TCP_PRIVATE_FIELDS /* empty */
+
+#define UV_UDP_PRIVATE_FIELDS \
+ uv_alloc_cb alloc_cb; \
+ uv_udp_recv_cb recv_cb; \
+ uv__io_t io_watcher; \
+ void* write_queue[2]; \
+ void* write_completed_queue[2]; \
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ const char* pipe_fname; /* strdup'ed */
+
+#define UV_POLL_PRIVATE_FIELDS \
+ uv__io_t io_watcher;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_cb prepare_cb; \
+ void* queue[2]; \
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_cb check_cb; \
+ void* queue[2]; \
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_cb idle_cb; \
+ void* queue[2]; \
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ uv_async_cb async_cb; \
+ void* queue[2]; \
+ int pending; \
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ uv_timer_cb timer_cb; \
+ void* heap_node[3]; \
+ uint64_t timeout; \
+ uint64_t repeat; \
+ uint64_t start_id;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb cb; \
+ struct addrinfo* hints; \
+ char* hostname; \
+ char* service; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ void* queue[2]; \
+ int status; \
+
+#define UV_FS_PRIVATE_FIELDS \
+ const char *new_path; \
+ uv_file file; \
+ int flags; \
+ mode_t mode; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ off_t off; \
+ uv_uid_t uid; \
+ uv_gid_t gid; \
+ double atime; \
+ double mtime; \
+ struct uv__work work_req; \
+ uv_buf_t bufsml[4]; \
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_TTY_PRIVATE_FIELDS \
+ struct termios orig_termios; \
+ int mode;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ /* RB_ENTRY(uv_signal_s) tree_entry; */ \
+ struct { \
+ struct uv_signal_s* rbe_left; \
+ struct uv_signal_s* rbe_right; \
+ struct uv_signal_s* rbe_parent; \
+ int rbe_color; \
+ } tree_entry; \
+ /* Use two counters here so we don have to fiddle with atomics. */ \
+ unsigned int caught_signals; \
+ unsigned int dispatched_signals;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ uv_fs_event_cb cb; \
+ UV_PLATFORM_FS_EVENT_FIELDS \
+
+#endif /* UV_UNIX_H */
diff --git a/Utilities/cmlibuv/include/uv-version.h b/Utilities/cmlibuv/include/uv-version.h
new file mode 100644
index 000000000..e16580903
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-version.h
@@ -0,0 +1,43 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_VERSION_H
+#define UV_VERSION_H
+
+ /*
+ * Versions with the same major number are ABI stable. API is allowed to
+ * evolve between minor releases, but only in a backwards compatible way.
+ * Make sure you update the -soname directives in configure.ac
+ * and uv.gyp whenever you bump UV_VERSION_MAJOR or UV_VERSION_MINOR (but
+ * not UV_VERSION_PATCH.)
+ */
+
+#define UV_VERSION_MAJOR 1
+#define UV_VERSION_MINOR 11
+#define UV_VERSION_PATCH 1
+#define UV_VERSION_IS_RELEASE 0
+#define UV_VERSION_SUFFIX "dev"
+
+#define UV_VERSION_HEX ((UV_VERSION_MAJOR << 16) | \
+ (UV_VERSION_MINOR << 8) | \
+ (UV_VERSION_PATCH))
+
+#endif /* UV_VERSION_H */
diff --git a/Utilities/cmlibuv/include/uv-win.h b/Utilities/cmlibuv/include/uv-win.h
new file mode 100644
index 000000000..d3e32a508
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv-win.h
@@ -0,0 +1,661 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0502
+#endif
+
+#if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED)
+typedef intptr_t ssize_t;
+# define _SSIZE_T_
+# define _SSIZE_T_DEFINED
+#endif
+
+#include <winsock2.h>
+
+#if defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+typedef struct pollfd {
+ SOCKET fd;
+ short events;
+ short revents;
+} WSAPOLLFD, *PWSAPOLLFD, *LPWSAPOLLFD;
+#endif
+
+#ifndef LOCALE_INVARIANT
+# define LOCALE_INVARIANT 0x007f
+#endif
+
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include <process.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "tree.h"
+#include "uv-threadpool.h"
+
+#define MAX_PIPENAME_LEN 256
+
+#ifndef S_IFLNK
+# define S_IFLNK 0xA000
+#endif
+
+/* Additional signals supported by uv_signal and or uv_kill. The CRT defines
+ * the following signals already:
+ *
+ * #define SIGINT 2
+ * #define SIGILL 4
+ * #define SIGABRT_COMPAT 6
+ * #define SIGFPE 8
+ * #define SIGSEGV 11
+ * #define SIGTERM 15
+ * #define SIGBREAK 21
+ * #define SIGABRT 22
+ *
+ * The additional signals have values that are common on other Unix
+ * variants (Linux and Darwin)
+ */
+#define SIGHUP 1
+#define SIGKILL 9
+#define SIGWINCH 28
+
+/* The CRT defines SIGABRT_COMPAT as 6, which equals SIGABRT on many */
+/* unix-like platforms. However MinGW doesn't define it, so we do. */
+#ifndef SIGABRT_COMPAT
+# define SIGABRT_COMPAT 6
+#endif
+
+/*
+ * Guids and typedefs for winsock extension functions
+ * Mingw32 doesn't have these :-(
+ */
+#ifndef WSAID_ACCEPTEX
+# define WSAID_ACCEPTEX \
+ {0xb5367df1, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+#endif
+
+#ifndef WSAID_CONNECTEX
+# define WSAID_CONNECTEX \
+ {0x25a207b9, 0xddf3, 0x4660, \
+ {0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e}}
+#endif
+
+#ifndef WSAID_GETACCEPTEXSOCKADDRS
+# define WSAID_GETACCEPTEXSOCKADDRS \
+ {0xb5367df2, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+#endif
+
+#ifndef WSAID_DISCONNECTEX
+# define WSAID_DISCONNECTEX \
+ {0x7fda2e11, 0x8630, 0x436f, \
+ {0xa0, 0x31, 0xf5, 0x36, 0xa6, 0xee, 0xc1, 0x57}}
+#endif
+
+#ifndef WSAID_TRANSMITFILE
+# define WSAID_TRANSMITFILE \
+ {0xb5367df0, 0xcbac, 0x11cf, \
+ {0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}}
+#endif
+
+#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \
+ || (defined(_MSC_VER) && _MSC_VER < 1500)
+ typedef BOOL (PASCAL *LPFN_ACCEPTEX)
+ (SOCKET sListenSocket,
+ SOCKET sAcceptSocket,
+ PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPDWORD lpdwBytesReceived,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef BOOL (PASCAL *LPFN_CONNECTEX)
+ (SOCKET s,
+ const struct sockaddr* name,
+ int namelen,
+ PVOID lpSendBuffer,
+ DWORD dwSendDataLength,
+ LPDWORD lpdwBytesSent,
+ LPOVERLAPPED lpOverlapped);
+
+ typedef void (PASCAL *LPFN_GETACCEPTEXSOCKADDRS)
+ (PVOID lpOutputBuffer,
+ DWORD dwReceiveDataLength,
+ DWORD dwLocalAddressLength,
+ DWORD dwRemoteAddressLength,
+ LPSOCKADDR* LocalSockaddr,
+ LPINT LocalSockaddrLength,
+ LPSOCKADDR* RemoteSockaddr,
+ LPINT RemoteSockaddrLength);
+
+ typedef BOOL (PASCAL *LPFN_DISCONNECTEX)
+ (SOCKET hSocket,
+ LPOVERLAPPED lpOverlapped,
+ DWORD dwFlags,
+ DWORD reserved);
+
+ typedef BOOL (PASCAL *LPFN_TRANSMITFILE)
+ (SOCKET hSocket,
+ HANDLE hFile,
+ DWORD nNumberOfBytesToWrite,
+ DWORD nNumberOfBytesPerSend,
+ LPOVERLAPPED lpOverlapped,
+ LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers,
+ DWORD dwFlags);
+
+ typedef PVOID RTL_SRWLOCK;
+ typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+#endif
+
+typedef int (WSAAPI* LPFN_WSARECV)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+typedef int (WSAAPI* LPFN_WSARECVFROM)
+ (SOCKET socket,
+ LPWSABUF buffers,
+ DWORD buffer_count,
+ LPDWORD bytes,
+ LPDWORD flags,
+ struct sockaddr* addr,
+ LPINT addr_len,
+ LPWSAOVERLAPPED overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+#ifndef _NTDEF_
+ typedef LONG NTSTATUS;
+ typedef NTSTATUS *PNTSTATUS;
+#endif
+
+#ifndef RTL_CONDITION_VARIABLE_INIT
+ typedef PVOID CONDITION_VARIABLE, *PCONDITION_VARIABLE;
+#endif
+
+typedef struct _AFD_POLL_HANDLE_INFO {
+ HANDLE Handle;
+ ULONG Events;
+ NTSTATUS Status;
+} AFD_POLL_HANDLE_INFO, *PAFD_POLL_HANDLE_INFO;
+
+typedef struct _AFD_POLL_INFO {
+ LARGE_INTEGER Timeout;
+ ULONG NumberOfHandles;
+ ULONG Exclusive;
+ AFD_POLL_HANDLE_INFO Handles[1];
+} AFD_POLL_INFO, *PAFD_POLL_INFO;
+
+#define UV_MSAFD_PROVIDER_COUNT 3
+
+
+/**
+ * It should be possible to cast uv_buf_t[] to WSABUF[]
+ * see http://msdn.microsoft.com/en-us/library/ms741542(v=vs.85).aspx
+ */
+typedef struct uv_buf_t {
+ ULONG len;
+ char* base;
+} uv_buf_t;
+
+typedef int uv_file;
+typedef SOCKET uv_os_sock_t;
+typedef HANDLE uv_os_fd_t;
+
+typedef HANDLE uv_thread_t;
+
+typedef HANDLE uv_sem_t;
+
+typedef CRITICAL_SECTION uv_mutex_t;
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+typedef union {
+ CONDITION_VARIABLE cond_var;
+ struct {
+ unsigned int waiters_count;
+ CRITICAL_SECTION waiters_count_lock;
+ HANDLE signal_event;
+ HANDLE broadcast_event;
+ } fallback;
+} uv_cond_t;
+
+typedef union {
+ struct {
+ unsigned int num_readers_;
+ CRITICAL_SECTION num_readers_lock_;
+ HANDLE write_semaphore_;
+ } state_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ SRWLOCK unused_;
+ } unused1_;
+ /* TODO: remove me in v2.x. */
+ struct {
+ uv_mutex_t unused1_;
+ uv_mutex_t unused2_;
+ } unused2_;
+} uv_rwlock_t;
+
+typedef struct {
+ unsigned int n;
+ unsigned int count;
+ uv_mutex_t mutex;
+ uv_sem_t turnstile1;
+ uv_sem_t turnstile2;
+} uv_barrier_t;
+
+typedef struct {
+ DWORD tls_index;
+} uv_key_t;
+
+#define UV_ONCE_INIT { 0, NULL }
+
+typedef struct uv_once_s {
+ unsigned char ran;
+ HANDLE event;
+} uv_once_t;
+
+/* Platform-specific definitions for uv_spawn support. */
+typedef unsigned char uv_uid_t;
+typedef unsigned char uv_gid_t;
+
+typedef struct uv__dirent_s {
+ int d_type;
+ char d_name[1];
+} uv__dirent_t;
+
+#define HAVE_DIRENT_TYPES
+#define UV__DT_DIR UV_DIRENT_DIR
+#define UV__DT_FILE UV_DIRENT_FILE
+#define UV__DT_LINK UV_DIRENT_LINK
+#define UV__DT_FIFO UV_DIRENT_FIFO
+#define UV__DT_SOCKET UV_DIRENT_SOCKET
+#define UV__DT_CHAR UV_DIRENT_CHAR
+#define UV__DT_BLOCK UV_DIRENT_BLOCK
+
+/* Platform-specific definitions for uv_dlopen support. */
+#define UV_DYNAMIC FAR WINAPI
+typedef struct {
+ HMODULE handle;
+ char* errmsg;
+} uv_lib_t;
+
+RB_HEAD(uv_timer_tree_s, uv_timer_s);
+
+#define UV_LOOP_PRIVATE_FIELDS \
+ /* The loop's I/O completion port */ \
+ HANDLE iocp; \
+ /* The current time according to the event loop. in msecs. */ \
+ uint64_t time; \
+ /* Tail of a single-linked circular queue of pending reqs. If the queue */ \
+ /* is empty, tail_ is NULL. If there is only one item, */ \
+ /* tail_->next_req == tail_ */ \
+ uv_req_t* pending_reqs_tail; \
+ /* Head of a single-linked list of closed handles */ \
+ uv_handle_t* endgame_handles; \
+ /* The head of the timers tree */ \
+ struct uv_timer_tree_s timers; \
+ /* Lists of active loop (prepare / check / idle) watchers */ \
+ uv_prepare_t* prepare_handles; \
+ uv_check_t* check_handles; \
+ uv_idle_t* idle_handles; \
+ /* This pointer will refer to the prepare/check/idle handle whose */ \
+ /* callback is scheduled to be called next. This is needed to allow */ \
+ /* safe removal from one of the lists above while that list being */ \
+ /* iterated over. */ \
+ uv_prepare_t* next_prepare_handle; \
+ uv_check_t* next_check_handle; \
+ uv_idle_t* next_idle_handle; \
+ /* This handle holds the peer sockets for the fast variant of uv_poll_t */ \
+ SOCKET poll_peer_sockets[UV_MSAFD_PROVIDER_COUNT]; \
+ /* Counter to keep track of active tcp streams */ \
+ unsigned int active_tcp_streams; \
+ /* Counter to keep track of active udp streams */ \
+ unsigned int active_udp_streams; \
+ /* Counter to started timer */ \
+ uint64_t timer_counter; \
+ /* Threadpool */ \
+ void* wq[2]; \
+ uv_mutex_t wq_mutex; \
+ uv_async_t wq_async;
+
+#define UV_REQ_TYPE_PRIVATE \
+ /* TODO: remove the req suffix */ \
+ UV_ACCEPT, \
+ UV_FS_EVENT_REQ, \
+ UV_POLL_REQ, \
+ UV_PROCESS_EXIT, \
+ UV_READ, \
+ UV_UDP_RECV, \
+ UV_WAKEUP, \
+ UV_SIGNAL_REQ,
+
+#define UV_REQ_PRIVATE_FIELDS \
+ union { \
+ /* Used by I/O operations */ \
+ struct { \
+ OVERLAPPED overlapped; \
+ size_t queued_bytes; \
+ } io; \
+ } u; \
+ struct uv_req_s* next_req;
+
+#define UV_WRITE_PRIVATE_FIELDS \
+ int ipc_header; \
+ uv_buf_t write_buffer; \
+ HANDLE event_handle; \
+ HANDLE wait_handle;
+
+#define UV_CONNECT_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_SHUTDOWN_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_UDP_SEND_PRIVATE_FIELDS \
+ /* empty */
+
+#define UV_PRIVATE_REQ_TYPES \
+ typedef struct uv_pipe_accept_s { \
+ UV_REQ_FIELDS \
+ HANDLE pipeHandle; \
+ struct uv_pipe_accept_s* next_pending; \
+ } uv_pipe_accept_t; \
+ \
+ typedef struct uv_tcp_accept_s { \
+ UV_REQ_FIELDS \
+ SOCKET accept_socket; \
+ char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ struct uv_tcp_accept_s* next_pending; \
+ } uv_tcp_accept_t; \
+ \
+ typedef struct uv_read_s { \
+ UV_REQ_FIELDS \
+ HANDLE event_handle; \
+ HANDLE wait_handle; \
+ } uv_read_t;
+
+#define uv_stream_connection_fields \
+ unsigned int write_reqs_pending; \
+ uv_shutdown_t* shutdown_req;
+
+#define uv_stream_server_fields \
+ uv_connection_cb connection_cb;
+
+#define UV_STREAM_PRIVATE_FIELDS \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_read_t read_req; \
+ union { \
+ struct { uv_stream_connection_fields } conn; \
+ struct { uv_stream_server_fields } serv; \
+ } stream;
+
+#define uv_tcp_server_fields \
+ uv_tcp_accept_t* accept_reqs; \
+ unsigned int processed_accepts; \
+ uv_tcp_accept_t* pending_accepts; \
+ LPFN_ACCEPTEX func_acceptex;
+
+#define uv_tcp_connection_fields \
+ uv_buf_t read_buffer; \
+ LPFN_CONNECTEX func_connectex;
+
+#define UV_TCP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ int delayed_error; \
+ union { \
+ struct { uv_tcp_server_fields } serv; \
+ struct { uv_tcp_connection_fields } conn; \
+ } tcp;
+
+#define UV_UDP_PRIVATE_FIELDS \
+ SOCKET socket; \
+ unsigned int reqs_pending; \
+ int activecnt; \
+ uv_req_t recv_req; \
+ uv_buf_t recv_buffer; \
+ struct sockaddr_storage recv_from; \
+ int recv_from_len; \
+ uv_udp_recv_cb recv_cb; \
+ uv_alloc_cb alloc_cb; \
+ LPFN_WSARECV func_wsarecv; \
+ LPFN_WSARECVFROM func_wsarecvfrom;
+
+#define uv_pipe_server_fields \
+ int pending_instances; \
+ uv_pipe_accept_t* accept_reqs; \
+ uv_pipe_accept_t* pending_accepts;
+
+#define uv_pipe_connection_fields \
+ uv_timer_t* eof_timer; \
+ uv_write_t ipc_header_write_req; \
+ int ipc_pid; \
+ uint64_t remaining_ipc_rawdata_bytes; \
+ struct { \
+ void* queue[2]; \
+ int queue_len; \
+ } pending_ipc_info; \
+ uv_write_t* non_overlapped_writes_tail; \
+ uv_mutex_t readfile_mutex; \
+ volatile HANDLE readfile_thread;
+
+#define UV_PIPE_PRIVATE_FIELDS \
+ HANDLE handle; \
+ WCHAR* name; \
+ union { \
+ struct { uv_pipe_server_fields } serv; \
+ struct { uv_pipe_connection_fields } conn; \
+ } pipe;
+
+/* TODO: put the parser states in an union - TTY handles are always */
+/* half-duplex so read-state can safely overlap write-state. */
+#define UV_TTY_PRIVATE_FIELDS \
+ HANDLE handle; \
+ union { \
+ struct { \
+ /* Used for readable TTY handles */ \
+ /* TODO: remove me in v2.x. */ \
+ HANDLE unused_; \
+ uv_buf_t read_line_buffer; \
+ HANDLE read_raw_wait; \
+ /* Fields used for translating win keystrokes into vt100 characters */ \
+ char last_key[8]; \
+ unsigned char last_key_offset; \
+ unsigned char last_key_len; \
+ WCHAR last_utf16_high_surrogate; \
+ INPUT_RECORD last_input_record; \
+ } rd; \
+ struct { \
+ /* Used for writable TTY handles */ \
+ /* utf8-to-utf16 conversion state */ \
+ unsigned int utf8_codepoint; \
+ unsigned char utf8_bytes_left; \
+ /* eol conversion state */ \
+ unsigned char previous_eol; \
+ /* ansi parser state */ \
+ unsigned char ansi_parser_state; \
+ unsigned char ansi_csi_argc; \
+ unsigned short ansi_csi_argv[4]; \
+ COORD saved_position; \
+ WORD saved_attributes; \
+ } wr; \
+ } tty;
+
+#define UV_POLL_PRIVATE_FIELDS \
+ SOCKET socket; \
+ /* Used in fast mode */ \
+ SOCKET peer_socket; \
+ AFD_POLL_INFO afd_poll_info_1; \
+ AFD_POLL_INFO afd_poll_info_2; \
+ /* Used in fast and slow mode. */ \
+ uv_req_t poll_req_1; \
+ uv_req_t poll_req_2; \
+ unsigned char submitted_events_1; \
+ unsigned char submitted_events_2; \
+ unsigned char mask_events_1; \
+ unsigned char mask_events_2; \
+ unsigned char events;
+
+#define UV_TIMER_PRIVATE_FIELDS \
+ RB_ENTRY(uv_timer_s) tree_entry; \
+ uint64_t due; \
+ uint64_t repeat; \
+ uint64_t start_id; \
+ uv_timer_cb timer_cb;
+
+#define UV_ASYNC_PRIVATE_FIELDS \
+ struct uv_req_s async_req; \
+ uv_async_cb async_cb; \
+ /* char to avoid alignment issues */ \
+ char volatile async_sent;
+
+#define UV_PREPARE_PRIVATE_FIELDS \
+ uv_prepare_t* prepare_prev; \
+ uv_prepare_t* prepare_next; \
+ uv_prepare_cb prepare_cb;
+
+#define UV_CHECK_PRIVATE_FIELDS \
+ uv_check_t* check_prev; \
+ uv_check_t* check_next; \
+ uv_check_cb check_cb;
+
+#define UV_IDLE_PRIVATE_FIELDS \
+ uv_idle_t* idle_prev; \
+ uv_idle_t* idle_next; \
+ uv_idle_cb idle_cb;
+
+#define UV_HANDLE_PRIVATE_FIELDS \
+ uv_handle_t* endgame_next; \
+ unsigned int flags;
+
+#define UV_GETADDRINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getaddrinfo_cb getaddrinfo_cb; \
+ void* alloc; \
+ WCHAR* node; \
+ WCHAR* service; \
+ /* The addrinfoW field is used to store a pointer to the hints, and */ \
+ /* later on to store the result of GetAddrInfoW. The final result will */ \
+ /* be converted to struct addrinfo* and stored in the addrinfo field. */ \
+ struct addrinfoW* addrinfow; \
+ struct addrinfo* addrinfo; \
+ int retcode;
+
+#define UV_GETNAMEINFO_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ uv_getnameinfo_cb getnameinfo_cb; \
+ struct sockaddr_storage storage; \
+ int flags; \
+ char host[NI_MAXHOST]; \
+ char service[NI_MAXSERV]; \
+ int retcode;
+
+#define UV_PROCESS_PRIVATE_FIELDS \
+ struct uv_process_exit_s { \
+ UV_REQ_FIELDS \
+ } exit_req; \
+ BYTE* child_stdio_buffer; \
+ int exit_signal; \
+ HANDLE wait_handle; \
+ HANDLE process_handle; \
+ volatile char exit_cb_pending;
+
+#define UV_FS_PRIVATE_FIELDS \
+ struct uv__work work_req; \
+ int flags; \
+ DWORD sys_errno_; \
+ union { \
+ /* TODO: remove me in 0.9. */ \
+ WCHAR* pathw; \
+ int fd; \
+ } file; \
+ union { \
+ struct { \
+ int mode; \
+ WCHAR* new_pathw; \
+ int file_flags; \
+ int fd_out; \
+ unsigned int nbufs; \
+ uv_buf_t* bufs; \
+ int64_t offset; \
+ uv_buf_t bufsml[4]; \
+ } info; \
+ struct { \
+ double atime; \
+ double mtime; \
+ } time; \
+ } fs;
+
+#define UV_WORK_PRIVATE_FIELDS \
+ struct uv__work work_req;
+
+#define UV_FS_EVENT_PRIVATE_FIELDS \
+ struct uv_fs_event_req_s { \
+ UV_REQ_FIELDS \
+ } req; \
+ HANDLE dir_handle; \
+ int req_pending; \
+ uv_fs_event_cb cb; \
+ WCHAR* filew; \
+ WCHAR* short_filew; \
+ WCHAR* dirw; \
+ char* buffer;
+
+#define UV_SIGNAL_PRIVATE_FIELDS \
+ RB_ENTRY(uv_signal_s) tree_entry; \
+ struct uv_req_s signal_req; \
+ unsigned long pending_signum;
+
+#ifndef F_OK
+#define F_OK 0
+#endif
+#ifndef R_OK
+#define R_OK 4
+#endif
+#ifndef W_OK
+#define W_OK 2
+#endif
+#ifndef X_OK
+#define X_OK 1
+#endif
diff --git a/Utilities/cmlibuv/include/uv.h b/Utilities/cmlibuv/include/uv.h
new file mode 100644
index 000000000..38f567644
--- /dev/null
+++ b/Utilities/cmlibuv/include/uv.h
@@ -0,0 +1,1511 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* See https://github.com/libuv/libuv#documentation for documentation. */
+
+#ifndef UV_H
+#define UV_H
+
+/* Include KWSys Large File Support configuration. */
+#include <cmsys/Configure.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32
+ /* Windows - set up dll import/export decorators. */
+# if defined(BUILDING_UV_SHARED)
+ /* Building shared library. */
+# define UV_EXTERN __declspec(dllexport)
+# elif defined(USING_UV_SHARED)
+ /* Using shared library. */
+# define UV_EXTERN __declspec(dllimport)
+# else
+ /* Building static library. */
+# define UV_EXTERN /* nothing */
+# endif
+#elif __GNUC__ >= 4
+# define UV_EXTERN __attribute__((visibility("default")))
+#else
+# define UV_EXTERN /* nothing */
+#endif
+
+#include "uv-errno.h"
+#include "uv-version.h"
+#include <stddef.h>
+#include <stdio.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#if defined(_WIN32)
+# include "uv-win.h"
+#else
+# include "uv-unix.h"
+#endif
+
+/* Expand this list if necessary. */
+#define UV_ERRNO_MAP(XX) \
+ XX(E2BIG, "argument list too long") \
+ XX(EACCES, "permission denied") \
+ XX(EADDRINUSE, "address already in use") \
+ XX(EADDRNOTAVAIL, "address not available") \
+ XX(EAFNOSUPPORT, "address family not supported") \
+ XX(EAGAIN, "resource temporarily unavailable") \
+ XX(EAI_ADDRFAMILY, "address family not supported") \
+ XX(EAI_AGAIN, "temporary failure") \
+ XX(EAI_BADFLAGS, "bad ai_flags value") \
+ XX(EAI_BADHINTS, "invalid value for hints") \
+ XX(EAI_CANCELED, "request canceled") \
+ XX(EAI_FAIL, "permanent failure") \
+ XX(EAI_FAMILY, "ai_family not supported") \
+ XX(EAI_MEMORY, "out of memory") \
+ XX(EAI_NODATA, "no address") \
+ XX(EAI_NONAME, "unknown node or service") \
+ XX(EAI_OVERFLOW, "argument buffer overflow") \
+ XX(EAI_PROTOCOL, "resolved protocol is unknown") \
+ XX(EAI_SERVICE, "service not available for socket type") \
+ XX(EAI_SOCKTYPE, "socket type not supported") \
+ XX(EALREADY, "connection already in progress") \
+ XX(EBADF, "bad file descriptor") \
+ XX(EBUSY, "resource busy or locked") \
+ XX(ECANCELED, "operation canceled") \
+ XX(ECHARSET, "invalid Unicode character") \
+ XX(ECONNABORTED, "software caused connection abort") \
+ XX(ECONNREFUSED, "connection refused") \
+ XX(ECONNRESET, "connection reset by peer") \
+ XX(EDESTADDRREQ, "destination address required") \
+ XX(EEXIST, "file already exists") \
+ XX(EFAULT, "bad address in system call argument") \
+ XX(EFBIG, "file too large") \
+ XX(EHOSTUNREACH, "host is unreachable") \
+ XX(EINTR, "interrupted system call") \
+ XX(EINVAL, "invalid argument") \
+ XX(EIO, "i/o error") \
+ XX(EISCONN, "socket is already connected") \
+ XX(EISDIR, "illegal operation on a directory") \
+ XX(ELOOP, "too many symbolic links encountered") \
+ XX(EMFILE, "too many open files") \
+ XX(EMSGSIZE, "message too long") \
+ XX(ENAMETOOLONG, "name too long") \
+ XX(ENETDOWN, "network is down") \
+ XX(ENETUNREACH, "network is unreachable") \
+ XX(ENFILE, "file table overflow") \
+ XX(ENOBUFS, "no buffer space available") \
+ XX(ENODEV, "no such device") \
+ XX(ENOENT, "no such file or directory") \
+ XX(ENOMEM, "not enough memory") \
+ XX(ENONET, "machine is not on the network") \
+ XX(ENOPROTOOPT, "protocol not available") \
+ XX(ENOSPC, "no space left on device") \
+ XX(ENOSYS, "function not implemented") \
+ XX(ENOTCONN, "socket is not connected") \
+ XX(ENOTDIR, "not a directory") \
+ XX(ENOTEMPTY, "directory not empty") \
+ XX(ENOTSOCK, "socket operation on non-socket") \
+ XX(ENOTSUP, "operation not supported on socket") \
+ XX(EPERM, "operation not permitted") \
+ XX(EPIPE, "broken pipe") \
+ XX(EPROTO, "protocol error") \
+ XX(EPROTONOSUPPORT, "protocol not supported") \
+ XX(EPROTOTYPE, "protocol wrong type for socket") \
+ XX(ERANGE, "result too large") \
+ XX(EROFS, "read-only file system") \
+ XX(ESHUTDOWN, "cannot send after transport endpoint shutdown") \
+ XX(ESPIPE, "invalid seek") \
+ XX(ESRCH, "no such process") \
+ XX(ETIMEDOUT, "connection timed out") \
+ XX(ETXTBSY, "text file is busy") \
+ XX(EXDEV, "cross-device link not permitted") \
+ XX(UNKNOWN, "unknown error") \
+ XX(EOF, "end of file") \
+ XX(ENXIO, "no such device or address") \
+ XX(EMLINK, "too many links") \
+ XX(EHOSTDOWN, "host is down") \
+
+#define UV_HANDLE_TYPE_MAP(XX) \
+ XX(ASYNC, async) \
+ XX(CHECK, check) \
+ XX(FS_EVENT, fs_event) \
+ XX(FS_POLL, fs_poll) \
+ XX(HANDLE, handle) \
+ XX(IDLE, idle) \
+ XX(NAMED_PIPE, pipe) \
+ XX(POLL, poll) \
+ XX(PREPARE, prepare) \
+ XX(PROCESS, process) \
+ XX(STREAM, stream) \
+ XX(TCP, tcp) \
+ XX(TIMER, timer) \
+ XX(TTY, tty) \
+ XX(UDP, udp) \
+ XX(SIGNAL, signal) \
+
+#define UV_REQ_TYPE_MAP(XX) \
+ XX(REQ, req) \
+ XX(CONNECT, connect) \
+ XX(WRITE, write) \
+ XX(SHUTDOWN, shutdown) \
+ XX(UDP_SEND, udp_send) \
+ XX(FS, fs) \
+ XX(WORK, work) \
+ XX(GETADDRINFO, getaddrinfo) \
+ XX(GETNAMEINFO, getnameinfo) \
+
+typedef enum {
+#define XX(code, _) UV_ ## code = UV__ ## code,
+ UV_ERRNO_MAP(XX)
+#undef XX
+ UV_ERRNO_MAX = UV__EOF - 1
+} uv_errno_t;
+
+typedef enum {
+ UV_UNKNOWN_HANDLE = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_HANDLE_TYPE_MAP(XX)
+#undef XX
+ UV_FILE,
+ UV_HANDLE_TYPE_MAX
+} uv_handle_type;
+
+typedef enum {
+ UV_UNKNOWN_REQ = 0,
+#define XX(uc, lc) UV_##uc,
+ UV_REQ_TYPE_MAP(XX)
+#undef XX
+ UV_REQ_TYPE_PRIVATE
+ UV_REQ_TYPE_MAX
+} uv_req_type;
+
+
+/* Handle types. */
+typedef struct uv_loop_s uv_loop_t;
+typedef struct uv_handle_s uv_handle_t;
+typedef struct uv_stream_s uv_stream_t;
+typedef struct uv_tcp_s uv_tcp_t;
+typedef struct uv_udp_s uv_udp_t;
+typedef struct uv_pipe_s uv_pipe_t;
+typedef struct uv_tty_s uv_tty_t;
+typedef struct uv_poll_s uv_poll_t;
+typedef struct uv_timer_s uv_timer_t;
+typedef struct uv_prepare_s uv_prepare_t;
+typedef struct uv_check_s uv_check_t;
+typedef struct uv_idle_s uv_idle_t;
+typedef struct uv_async_s uv_async_t;
+typedef struct uv_process_s uv_process_t;
+typedef struct uv_fs_event_s uv_fs_event_t;
+typedef struct uv_fs_poll_s uv_fs_poll_t;
+typedef struct uv_signal_s uv_signal_t;
+
+/* Request types. */
+typedef struct uv_req_s uv_req_t;
+typedef struct uv_getaddrinfo_s uv_getaddrinfo_t;
+typedef struct uv_getnameinfo_s uv_getnameinfo_t;
+typedef struct uv_shutdown_s uv_shutdown_t;
+typedef struct uv_write_s uv_write_t;
+typedef struct uv_connect_s uv_connect_t;
+typedef struct uv_udp_send_s uv_udp_send_t;
+typedef struct uv_fs_s uv_fs_t;
+typedef struct uv_work_s uv_work_t;
+
+/* None of the above. */
+typedef struct uv_cpu_info_s uv_cpu_info_t;
+typedef struct uv_interface_address_s uv_interface_address_t;
+typedef struct uv_dirent_s uv_dirent_t;
+typedef struct uv_passwd_s uv_passwd_t;
+
+typedef enum {
+ UV_LOOP_BLOCK_SIGNAL
+} uv_loop_option;
+
+typedef enum {
+ UV_RUN_DEFAULT = 0,
+ UV_RUN_ONCE,
+ UV_RUN_NOWAIT
+} uv_run_mode;
+
+
+UV_EXTERN unsigned int uv_version(void);
+UV_EXTERN const char* uv_version_string(void);
+
+typedef void* (*uv_malloc_func)(size_t size);
+typedef void* (*uv_realloc_func)(void* ptr, size_t size);
+typedef void* (*uv_calloc_func)(size_t count, size_t size);
+typedef void (*uv_free_func)(void* ptr);
+
+UV_EXTERN int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func);
+
+UV_EXTERN uv_loop_t* uv_default_loop(void);
+UV_EXTERN int uv_loop_init(uv_loop_t* loop);
+UV_EXTERN int uv_loop_close(uv_loop_t* loop);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12), users should
+ * allocate the loop manually and use uv_loop_init instead.
+ */
+UV_EXTERN uv_loop_t* uv_loop_new(void);
+/*
+ * NOTE:
+ * This function is DEPRECATED (to be removed after 0.12). Users should use
+ * uv_loop_close and free the memory manually instead.
+ */
+UV_EXTERN void uv_loop_delete(uv_loop_t*);
+UV_EXTERN size_t uv_loop_size(void);
+UV_EXTERN int uv_loop_alive(const uv_loop_t* loop);
+UV_EXTERN int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...);
+UV_EXTERN int uv_loop_fork(uv_loop_t* loop);
+
+UV_EXTERN int uv_run(uv_loop_t*, uv_run_mode mode);
+UV_EXTERN void uv_stop(uv_loop_t*);
+
+UV_EXTERN void uv_ref(uv_handle_t*);
+UV_EXTERN void uv_unref(uv_handle_t*);
+UV_EXTERN int uv_has_ref(const uv_handle_t*);
+
+UV_EXTERN void uv_update_time(uv_loop_t*);
+UV_EXTERN uint64_t uv_now(const uv_loop_t*);
+
+UV_EXTERN int uv_backend_fd(const uv_loop_t*);
+UV_EXTERN int uv_backend_timeout(const uv_loop_t*);
+
+typedef void (*uv_alloc_cb)(uv_handle_t* handle,
+ size_t suggested_size,
+ uv_buf_t* buf);
+typedef void (*uv_read_cb)(uv_stream_t* stream,
+ ssize_t nread,
+ const uv_buf_t* buf);
+typedef void (*uv_write_cb)(uv_write_t* req, int status);
+typedef void (*uv_connect_cb)(uv_connect_t* req, int status);
+typedef void (*uv_shutdown_cb)(uv_shutdown_t* req, int status);
+typedef void (*uv_connection_cb)(uv_stream_t* server, int status);
+typedef void (*uv_close_cb)(uv_handle_t* handle);
+typedef void (*uv_poll_cb)(uv_poll_t* handle, int status, int events);
+typedef void (*uv_timer_cb)(uv_timer_t* handle);
+typedef void (*uv_async_cb)(uv_async_t* handle);
+typedef void (*uv_prepare_cb)(uv_prepare_t* handle);
+typedef void (*uv_check_cb)(uv_check_t* handle);
+typedef void (*uv_idle_cb)(uv_idle_t* handle);
+typedef void (*uv_exit_cb)(uv_process_t*, int64_t exit_status, int term_signal);
+typedef void (*uv_walk_cb)(uv_handle_t* handle, void* arg);
+typedef void (*uv_fs_cb)(uv_fs_t* req);
+typedef void (*uv_work_cb)(uv_work_t* req);
+typedef void (*uv_after_work_cb)(uv_work_t* req, int status);
+typedef void (*uv_getaddrinfo_cb)(uv_getaddrinfo_t* req,
+ int status,
+ struct addrinfo* res);
+typedef void (*uv_getnameinfo_cb)(uv_getnameinfo_t* req,
+ int status,
+ const char* hostname,
+ const char* service);
+
+typedef struct {
+ long tv_sec;
+ long tv_nsec;
+} uv_timespec_t;
+
+
+typedef struct {
+ uint64_t st_dev;
+ uint64_t st_mode;
+ uint64_t st_nlink;
+ uint64_t st_uid;
+ uint64_t st_gid;
+ uint64_t st_rdev;
+ uint64_t st_ino;
+ uint64_t st_size;
+ uint64_t st_blksize;
+ uint64_t st_blocks;
+ uint64_t st_flags;
+ uint64_t st_gen;
+ uv_timespec_t st_atim;
+ uv_timespec_t st_mtim;
+ uv_timespec_t st_ctim;
+ uv_timespec_t st_birthtim;
+} uv_stat_t;
+
+
+typedef void (*uv_fs_event_cb)(uv_fs_event_t* handle,
+ const char* filename,
+ int events,
+ int status);
+
+typedef void (*uv_fs_poll_cb)(uv_fs_poll_t* handle,
+ int status,
+ const uv_stat_t* prev,
+ const uv_stat_t* curr);
+
+typedef void (*uv_signal_cb)(uv_signal_t* handle, int signum);
+
+
+typedef enum {
+ UV_LEAVE_GROUP = 0,
+ UV_JOIN_GROUP
+} uv_membership;
+
+
+UV_EXTERN int uv_translate_sys_error(int sys_errno);
+
+UV_EXTERN const char* uv_strerror(int err);
+UV_EXTERN const char* uv_err_name(int err);
+
+
+#define UV_REQ_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_req_type type; \
+ /* private */ \
+ void* active_queue[2]; \
+ void* reserved[4]; \
+ UV_REQ_PRIVATE_FIELDS \
+
+/* Abstract base class of all requests. */
+struct uv_req_s {
+ UV_REQ_FIELDS
+};
+
+
+/* Platform-specific request types. */
+UV_PRIVATE_REQ_TYPES
+
+
+UV_EXTERN int uv_shutdown(uv_shutdown_t* req,
+ uv_stream_t* handle,
+ uv_shutdown_cb cb);
+
+struct uv_shutdown_s {
+ UV_REQ_FIELDS
+ uv_stream_t* handle;
+ uv_shutdown_cb cb;
+ UV_SHUTDOWN_PRIVATE_FIELDS
+};
+
+
+#define UV_HANDLE_FIELDS \
+ /* public */ \
+ void* data; \
+ /* read-only */ \
+ uv_loop_t* loop; \
+ uv_handle_type type; \
+ /* private */ \
+ uv_close_cb close_cb; \
+ void* handle_queue[2]; \
+ union { \
+ int fd; \
+ void* reserved[4]; \
+ } u; \
+ UV_HANDLE_PRIVATE_FIELDS \
+
+/* The abstract base class of all handles. */
+struct uv_handle_s {
+ UV_HANDLE_FIELDS
+};
+
+UV_EXTERN size_t uv_handle_size(uv_handle_type type);
+UV_EXTERN size_t uv_req_size(uv_req_type type);
+
+UV_EXTERN int uv_is_active(const uv_handle_t* handle);
+
+UV_EXTERN void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg);
+
+/* Helpers for ad hoc debugging, no API/ABI stability guaranteed. */
+UV_EXTERN void uv_print_all_handles(uv_loop_t* loop, FILE* stream);
+UV_EXTERN void uv_print_active_handles(uv_loop_t* loop, FILE* stream);
+
+UV_EXTERN void uv_close(uv_handle_t* handle, uv_close_cb close_cb);
+
+UV_EXTERN int uv_send_buffer_size(uv_handle_t* handle, int* value);
+UV_EXTERN int uv_recv_buffer_size(uv_handle_t* handle, int* value);
+
+UV_EXTERN int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd);
+
+UV_EXTERN uv_buf_t uv_buf_init(char* base, unsigned int len);
+
+
+#define UV_STREAM_FIELDS \
+ /* number of bytes queued for writing */ \
+ size_t write_queue_size; \
+ uv_alloc_cb alloc_cb; \
+ uv_read_cb read_cb; \
+ /* private */ \
+ UV_STREAM_PRIVATE_FIELDS
+
+/*
+ * uv_stream_t is a subclass of uv_handle_t.
+ *
+ * uv_stream is an abstract class.
+ *
+ * uv_stream_t is the parent class of uv_tcp_t, uv_pipe_t and uv_tty_t.
+ */
+struct uv_stream_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+};
+
+UV_EXTERN int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb);
+UV_EXTERN int uv_accept(uv_stream_t* server, uv_stream_t* client);
+
+UV_EXTERN int uv_read_start(uv_stream_t*,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+UV_EXTERN int uv_read_stop(uv_stream_t*);
+
+UV_EXTERN int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb);
+UV_EXTERN int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb);
+UV_EXTERN int uv_try_write(uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+/* uv_write_t is a subclass of uv_req_t. */
+struct uv_write_s {
+ UV_REQ_FIELDS
+ uv_write_cb cb;
+ uv_stream_t* send_handle;
+ uv_stream_t* handle;
+ UV_WRITE_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_is_readable(const uv_stream_t* handle);
+UV_EXTERN int uv_is_writable(const uv_stream_t* handle);
+
+UV_EXTERN int uv_stream_set_blocking(uv_stream_t* handle, int blocking);
+
+UV_EXTERN int uv_is_closing(const uv_handle_t* handle);
+
+
+/*
+ * uv_tcp_t is a subclass of uv_stream_t.
+ *
+ * Represents a TCP stream or TCP server.
+ */
+struct uv_tcp_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TCP_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_tcp_init(uv_loop_t*, uv_tcp_t* handle);
+UV_EXTERN int uv_tcp_init_ex(uv_loop_t*, uv_tcp_t* handle, unsigned int flags);
+UV_EXTERN int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_tcp_nodelay(uv_tcp_t* handle, int enable);
+UV_EXTERN int uv_tcp_keepalive(uv_tcp_t* handle,
+ int enable,
+ unsigned int delay);
+UV_EXTERN int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable);
+
+enum uv_tcp_flags {
+ /* Used with uv_tcp_bind, when an IPv6 address is used. */
+ UV_TCP_IPV6ONLY = 1
+};
+
+UV_EXTERN int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+UV_EXTERN int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb);
+
+/* uv_connect_t is a subclass of uv_req_t. */
+struct uv_connect_s {
+ UV_REQ_FIELDS
+ uv_connect_cb cb;
+ uv_stream_t* handle;
+ UV_CONNECT_PRIVATE_FIELDS
+};
+
+
+/*
+ * UDP support.
+ */
+
+enum uv_udp_flags {
+ /* Disables dual stack mode. */
+ UV_UDP_IPV6ONLY = 1,
+ /*
+ * Indicates message was truncated because read buffer was too small. The
+ * remainder was discarded by the OS. Used in uv_udp_recv_cb.
+ */
+ UV_UDP_PARTIAL = 2,
+ /*
+ * Indicates if SO_REUSEADDR will be set when binding the handle.
+ * This sets the SO_REUSEPORT socket flag on the BSDs and OS X. On other
+ * Unix platforms, it sets the SO_REUSEADDR flag. What that means is that
+ * multiple threads or processes can bind to the same address without error
+ * (provided they all set the flag) but only the last one to bind will receive
+ * any traffic, in effect "stealing" the port from the previous listener.
+ */
+ UV_UDP_REUSEADDR = 4
+};
+
+typedef void (*uv_udp_send_cb)(uv_udp_send_t* req, int status);
+typedef void (*uv_udp_recv_cb)(uv_udp_t* handle,
+ ssize_t nread,
+ const uv_buf_t* buf,
+ const struct sockaddr* addr,
+ unsigned flags);
+
+/* uv_udp_t is a subclass of uv_handle_t. */
+struct uv_udp_s {
+ UV_HANDLE_FIELDS
+ /* read-only */
+ /*
+ * Number of bytes queued for sending. This field strictly shows how much
+ * information is currently queued.
+ */
+ size_t send_queue_size;
+ /*
+ * Number of send requests currently in the queue awaiting to be processed.
+ */
+ size_t send_queue_count;
+ UV_UDP_PRIVATE_FIELDS
+};
+
+/* uv_udp_send_t is a subclass of uv_req_t. */
+struct uv_udp_send_s {
+ UV_REQ_FIELDS
+ uv_udp_t* handle;
+ uv_udp_send_cb cb;
+ UV_UDP_SEND_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_udp_init(uv_loop_t*, uv_udp_t* handle);
+UV_EXTERN int uv_udp_init_ex(uv_loop_t*, uv_udp_t* handle, unsigned int flags);
+UV_EXTERN int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock);
+UV_EXTERN int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags);
+
+UV_EXTERN int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen);
+UV_EXTERN int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership);
+UV_EXTERN int uv_udp_set_multicast_loop(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_set_multicast_interface(uv_udp_t* handle,
+ const char* interface_addr);
+UV_EXTERN int uv_udp_set_broadcast(uv_udp_t* handle, int on);
+UV_EXTERN int uv_udp_set_ttl(uv_udp_t* handle, int ttl);
+UV_EXTERN int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb);
+UV_EXTERN int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr);
+UV_EXTERN int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb);
+UV_EXTERN int uv_udp_recv_stop(uv_udp_t* handle);
+
+
+/*
+ * uv_tty_t is a subclass of uv_stream_t.
+ *
+ * Representing a stream for the console.
+ */
+struct uv_tty_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ UV_TTY_PRIVATE_FIELDS
+};
+
+typedef enum {
+ /* Initial/normal terminal mode */
+ UV_TTY_MODE_NORMAL,
+ /* Raw input mode (On Windows, ENABLE_WINDOW_INPUT is also enabled) */
+ UV_TTY_MODE_RAW,
+ /* Binary-safe I/O mode for IPC (Unix-only) */
+ UV_TTY_MODE_IO
+} uv_tty_mode_t;
+
+UV_EXTERN int uv_tty_init(uv_loop_t*, uv_tty_t*, uv_file fd, int readable);
+UV_EXTERN int uv_tty_set_mode(uv_tty_t*, uv_tty_mode_t mode);
+UV_EXTERN int uv_tty_reset_mode(void);
+UV_EXTERN int uv_tty_get_winsize(uv_tty_t*, int* width, int* height);
+
+#ifdef __cplusplus
+extern "C++" {
+
+inline int uv_tty_set_mode(uv_tty_t* handle, int mode) {
+ return uv_tty_set_mode(handle, static_cast<uv_tty_mode_t>(mode));
+}
+
+}
+#endif
+
+UV_EXTERN uv_handle_type uv_guess_handle(uv_file file);
+
+/*
+ * uv_pipe_t is a subclass of uv_stream_t.
+ *
+ * Representing a pipe stream or pipe server. On Windows this is a Named
+ * Pipe. On Unix this is a Unix domain socket.
+ */
+struct uv_pipe_s {
+ UV_HANDLE_FIELDS
+ UV_STREAM_FIELDS
+ int ipc; /* non-zero if this pipe is used for passing handles */
+ UV_PIPE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_pipe_init(uv_loop_t*, uv_pipe_t* handle, int ipc);
+UV_EXTERN int uv_pipe_open(uv_pipe_t*, uv_file file);
+UV_EXTERN int uv_pipe_bind(uv_pipe_t* handle, const char* name);
+UV_EXTERN void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb);
+UV_EXTERN int uv_pipe_getsockname(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN int uv_pipe_getpeername(const uv_pipe_t* handle,
+ char* buffer,
+ size_t* size);
+UV_EXTERN void uv_pipe_pending_instances(uv_pipe_t* handle, int count);
+UV_EXTERN int uv_pipe_pending_count(uv_pipe_t* handle);
+UV_EXTERN uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle);
+
+
+struct uv_poll_s {
+ UV_HANDLE_FIELDS
+ uv_poll_cb poll_cb;
+ UV_POLL_PRIVATE_FIELDS
+};
+
+enum uv_poll_event {
+ UV_READABLE = 1,
+ UV_WRITABLE = 2,
+ UV_DISCONNECT = 4
+};
+
+UV_EXTERN int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd);
+UV_EXTERN int uv_poll_init_socket(uv_loop_t* loop,
+ uv_poll_t* handle,
+ uv_os_sock_t socket);
+UV_EXTERN int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb);
+UV_EXTERN int uv_poll_stop(uv_poll_t* handle);
+
+
+struct uv_prepare_s {
+ UV_HANDLE_FIELDS
+ UV_PREPARE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_prepare_init(uv_loop_t*, uv_prepare_t* prepare);
+UV_EXTERN int uv_prepare_start(uv_prepare_t* prepare, uv_prepare_cb cb);
+UV_EXTERN int uv_prepare_stop(uv_prepare_t* prepare);
+
+
+struct uv_check_s {
+ UV_HANDLE_FIELDS
+ UV_CHECK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_check_init(uv_loop_t*, uv_check_t* check);
+UV_EXTERN int uv_check_start(uv_check_t* check, uv_check_cb cb);
+UV_EXTERN int uv_check_stop(uv_check_t* check);
+
+
+struct uv_idle_s {
+ UV_HANDLE_FIELDS
+ UV_IDLE_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_idle_init(uv_loop_t*, uv_idle_t* idle);
+UV_EXTERN int uv_idle_start(uv_idle_t* idle, uv_idle_cb cb);
+UV_EXTERN int uv_idle_stop(uv_idle_t* idle);
+
+
+struct uv_async_s {
+ UV_HANDLE_FIELDS
+ UV_ASYNC_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_async_init(uv_loop_t*,
+ uv_async_t* async,
+ uv_async_cb async_cb);
+UV_EXTERN int uv_async_send(uv_async_t* async);
+
+
+/*
+ * uv_timer_t is a subclass of uv_handle_t.
+ *
+ * Used to get woken up at a specified time in the future.
+ */
+struct uv_timer_s {
+ UV_HANDLE_FIELDS
+ UV_TIMER_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_timer_init(uv_loop_t*, uv_timer_t* handle);
+UV_EXTERN int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat);
+UV_EXTERN int uv_timer_stop(uv_timer_t* handle);
+UV_EXTERN int uv_timer_again(uv_timer_t* handle);
+UV_EXTERN void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat);
+UV_EXTERN uint64_t uv_timer_get_repeat(const uv_timer_t* handle);
+
+
+/*
+ * uv_getaddrinfo_t is a subclass of uv_req_t.
+ *
+ * Request object for uv_getaddrinfo.
+ */
+struct uv_getaddrinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* struct addrinfo* addrinfo is marked as private, but it really isn't. */
+ UV_GETADDRINFO_PRIVATE_FIELDS
+};
+
+
+UV_EXTERN int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints);
+UV_EXTERN void uv_freeaddrinfo(struct addrinfo* ai);
+
+
+/*
+* uv_getnameinfo_t is a subclass of uv_req_t.
+*
+* Request object for uv_getnameinfo.
+*/
+struct uv_getnameinfo_s {
+ UV_REQ_FIELDS
+ /* read-only */
+ uv_loop_t* loop;
+ /* host and service are marked as private, but they really aren't. */
+ UV_GETNAMEINFO_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags);
+
+
+/* uv_spawn() options. */
+typedef enum {
+ UV_IGNORE = 0x00,
+ UV_CREATE_PIPE = 0x01,
+ UV_INHERIT_FD = 0x02,
+ UV_INHERIT_STREAM = 0x04,
+
+ /*
+ * When UV_CREATE_PIPE is specified, UV_READABLE_PIPE and UV_WRITABLE_PIPE
+ * determine the direction of flow, from the child process' perspective. Both
+ * flags may be specified to create a duplex data stream.
+ */
+ UV_READABLE_PIPE = 0x10,
+ UV_WRITABLE_PIPE = 0x20
+} uv_stdio_flags;
+
+typedef struct uv_stdio_container_s {
+ uv_stdio_flags flags;
+
+ union {
+ uv_stream_t* stream;
+ int fd;
+ } data;
+} uv_stdio_container_t;
+
+typedef struct uv_process_options_s {
+ uv_exit_cb exit_cb; /* Called after the process exits. */
+ const char* file; /* Path to program to execute. */
+ /*
+ * Command line arguments. args[0] should be the path to the program. On
+ * Windows this uses CreateProcess which concatenates the arguments into a
+ * string this can cause some strange errors. See the note at
+ * windows_verbatim_arguments.
+ */
+ char** args;
+ /*
+ * This will be set as the environ variable in the subprocess. If this is
+ * NULL then the parents environ will be used.
+ */
+ char** env;
+ /*
+ * If non-null this represents a directory the subprocess should execute
+ * in. Stands for current working directory.
+ */
+ const char* cwd;
+ /*
+ * Various flags that control how uv_spawn() behaves. See the definition of
+ * `enum uv_process_flags` below.
+ */
+ unsigned int flags;
+ /*
+ * The `stdio` field points to an array of uv_stdio_container_t structs that
+ * describe the file descriptors that will be made available to the child
+ * process. The convention is that stdio[0] points to stdin, fd 1 is used for
+ * stdout, and fd 2 is stderr.
+ *
+ * Note that on windows file descriptors greater than 2 are available to the
+ * child process only if the child processes uses the MSVCRT runtime.
+ */
+ int stdio_count;
+ uv_stdio_container_t* stdio;
+ /*
+ * Libuv can change the child process' user/group id. This happens only when
+ * the appropriate bits are set in the flags fields. This is not supported on
+ * windows; uv_spawn() will fail and set the error to UV_ENOTSUP.
+ */
+ uv_uid_t uid;
+ uv_gid_t gid;
+} uv_process_options_t;
+
+/*
+ * These are the flags that can be used for the uv_process_options.flags field.
+ */
+enum uv_process_flags {
+ /*
+ * Set the child process' user id. The user id is supplied in the `uid` field
+ * of the options struct. This does not work on windows; setting this flag
+ * will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETUID = (1 << 0),
+ /*
+ * Set the child process' group id. The user id is supplied in the `gid`
+ * field of the options struct. This does not work on windows; setting this
+ * flag will cause uv_spawn() to fail.
+ */
+ UV_PROCESS_SETGID = (1 << 1),
+ /*
+ * Do not wrap any arguments in quotes, or perform any other escaping, when
+ * converting the argument list into a command line string. This option is
+ * only meaningful on Windows systems. On Unix it is silently ignored.
+ */
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS = (1 << 2),
+ /*
+ * Spawn the child process in a detached state - this will make it a process
+ * group leader, and will effectively enable the child to keep running after
+ * the parent exits. Note that the child process will still keep the
+ * parent's event loop alive unless the parent process calls uv_unref() on
+ * the child's process handle.
+ */
+ UV_PROCESS_DETACHED = (1 << 3),
+ /*
+ * Hide the subprocess console window that would normally be created. This
+ * option is only meaningful on Windows systems. On Unix it is silently
+ * ignored.
+ */
+ UV_PROCESS_WINDOWS_HIDE = (1 << 4)
+};
+
+/*
+ * uv_process_t is a subclass of uv_handle_t.
+ */
+struct uv_process_s {
+ UV_HANDLE_FIELDS
+ uv_exit_cb exit_cb;
+ int pid;
+ UV_PROCESS_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_spawn(uv_loop_t* loop,
+ uv_process_t* handle,
+ const uv_process_options_t* options);
+UV_EXTERN int uv_process_kill(uv_process_t*, int signum);
+UV_EXTERN int uv_kill(int pid, int signum);
+
+
+/*
+ * uv_work_t is a subclass of uv_req_t.
+ */
+struct uv_work_s {
+ UV_REQ_FIELDS
+ uv_loop_t* loop;
+ uv_work_cb work_cb;
+ uv_after_work_cb after_work_cb;
+ UV_WORK_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb);
+
+UV_EXTERN int uv_cancel(uv_req_t* req);
+
+
+struct uv_cpu_info_s {
+ char* model;
+ int speed;
+ struct uv_cpu_times_s {
+ uint64_t user;
+ uint64_t nice;
+ uint64_t sys;
+ uint64_t idle;
+ uint64_t irq;
+ } cpu_times;
+};
+
+struct uv_interface_address_s {
+ char* name;
+ char phys_addr[6];
+ int is_internal;
+ union {
+ struct sockaddr_in address4;
+ struct sockaddr_in6 address6;
+ } address;
+ union {
+ struct sockaddr_in netmask4;
+ struct sockaddr_in6 netmask6;
+ } netmask;
+};
+
+struct uv_passwd_s {
+ char* username;
+ long uid;
+ long gid;
+ char* shell;
+ char* homedir;
+};
+
+typedef enum {
+ UV_DIRENT_UNKNOWN,
+ UV_DIRENT_FILE,
+ UV_DIRENT_DIR,
+ UV_DIRENT_LINK,
+ UV_DIRENT_FIFO,
+ UV_DIRENT_SOCKET,
+ UV_DIRENT_CHAR,
+ UV_DIRENT_BLOCK
+} uv_dirent_type_t;
+
+struct uv_dirent_s {
+ const char* name;
+ uv_dirent_type_t type;
+};
+
+UV_EXTERN char** uv_setup_args(int argc, char** argv);
+UV_EXTERN int uv_get_process_title(char* buffer, size_t size);
+UV_EXTERN int uv_set_process_title(const char* title);
+UV_EXTERN int uv_resident_set_memory(size_t* rss);
+UV_EXTERN int uv_uptime(double* uptime);
+
+typedef struct {
+ long tv_sec;
+ long tv_usec;
+} uv_timeval_t;
+
+typedef struct {
+ uv_timeval_t ru_utime; /* user CPU time used */
+ uv_timeval_t ru_stime; /* system CPU time used */
+ uint64_t ru_maxrss; /* maximum resident set size */
+ uint64_t ru_ixrss; /* integral shared memory size */
+ uint64_t ru_idrss; /* integral unshared data size */
+ uint64_t ru_isrss; /* integral unshared stack size */
+ uint64_t ru_minflt; /* page reclaims (soft page faults) */
+ uint64_t ru_majflt; /* page faults (hard page faults) */
+ uint64_t ru_nswap; /* swaps */
+ uint64_t ru_inblock; /* block input operations */
+ uint64_t ru_oublock; /* block output operations */
+ uint64_t ru_msgsnd; /* IPC messages sent */
+ uint64_t ru_msgrcv; /* IPC messages received */
+ uint64_t ru_nsignals; /* signals received */
+ uint64_t ru_nvcsw; /* voluntary context switches */
+ uint64_t ru_nivcsw; /* involuntary context switches */
+} uv_rusage_t;
+
+UV_EXTERN int uv_getrusage(uv_rusage_t* rusage);
+
+UV_EXTERN int uv_os_homedir(char* buffer, size_t* size);
+UV_EXTERN int uv_os_tmpdir(char* buffer, size_t* size);
+UV_EXTERN int uv_os_get_passwd(uv_passwd_t* pwd);
+UV_EXTERN void uv_os_free_passwd(uv_passwd_t* pwd);
+
+UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
+UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
+
+UV_EXTERN int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count);
+UV_EXTERN void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count);
+
+UV_EXTERN int uv_os_getenv(const char* name, char* buffer, size_t* size);
+UV_EXTERN int uv_os_setenv(const char* name, const char* value);
+UV_EXTERN int uv_os_unsetenv(const char* name);
+
+UV_EXTERN int uv_os_gethostname(char* buffer, size_t* size);
+
+
+typedef enum {
+ UV_FS_UNKNOWN = -1,
+ UV_FS_CUSTOM,
+ UV_FS_OPEN,
+ UV_FS_CLOSE,
+ UV_FS_READ,
+ UV_FS_WRITE,
+ UV_FS_SENDFILE,
+ UV_FS_STAT,
+ UV_FS_LSTAT,
+ UV_FS_FSTAT,
+ UV_FS_FTRUNCATE,
+ UV_FS_UTIME,
+ UV_FS_FUTIME,
+ UV_FS_ACCESS,
+ UV_FS_CHMOD,
+ UV_FS_FCHMOD,
+ UV_FS_FSYNC,
+ UV_FS_FDATASYNC,
+ UV_FS_UNLINK,
+ UV_FS_RMDIR,
+ UV_FS_MKDIR,
+ UV_FS_MKDTEMP,
+ UV_FS_RENAME,
+ UV_FS_SCANDIR,
+ UV_FS_LINK,
+ UV_FS_SYMLINK,
+ UV_FS_READLINK,
+ UV_FS_CHOWN,
+ UV_FS_FCHOWN,
+ UV_FS_REALPATH
+} uv_fs_type;
+
+/* uv_fs_t is a subclass of uv_req_t. */
+struct uv_fs_s {
+ UV_REQ_FIELDS
+ uv_fs_type fs_type;
+ uv_loop_t* loop;
+ uv_fs_cb cb;
+ ssize_t result;
+ void* ptr;
+ const char* path;
+ uv_stat_t statbuf; /* Stores the result of uv_fs_stat() and uv_fs_fstat(). */
+ UV_FS_PRIVATE_FIELDS
+};
+
+UV_EXTERN void uv_fs_req_cleanup(uv_fs_t* req);
+UV_EXTERN int uv_fs_close(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_unlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rmdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_scandir_next(uv_fs_t* req,
+ uv_dirent_t* ent);
+UV_EXTERN int uv_fs_stat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fsync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fdatasync(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t offset,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t in_offset,
+ size_t length,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_lstat(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb);
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * path argument points to a directory.
+ */
+#define UV_FS_SYMLINK_DIR 0x0001
+
+/*
+ * This flag can be used with uv_fs_symlink() on Windows to specify whether
+ * the symlink is to be created using junction points.
+ */
+#define UV_FS_SYMLINK_JUNCTION 0x0002
+
+UV_EXTERN int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+UV_EXTERN int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb);
+
+
+enum uv_fs_event {
+ UV_RENAME = 1,
+ UV_CHANGE = 2
+};
+
+
+struct uv_fs_event_s {
+ UV_HANDLE_FIELDS
+ /* private */
+ char* path;
+ UV_FS_EVENT_PRIVATE_FIELDS
+};
+
+
+/*
+ * uv_fs_stat() based polling file watcher.
+ */
+struct uv_fs_poll_s {
+ UV_HANDLE_FIELDS
+ /* Private, don't touch. */
+ void* poll_ctx;
+};
+
+UV_EXTERN int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb poll_cb,
+ const char* path,
+ unsigned int interval);
+UV_EXTERN int uv_fs_poll_stop(uv_fs_poll_t* handle);
+UV_EXTERN int uv_fs_poll_getpath(uv_fs_poll_t* handle,
+ char* buffer,
+ size_t* size);
+
+
+struct uv_signal_s {
+ UV_HANDLE_FIELDS
+ uv_signal_cb signal_cb;
+ int signum;
+ UV_SIGNAL_PRIVATE_FIELDS
+};
+
+UV_EXTERN int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle);
+UV_EXTERN int uv_signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum);
+UV_EXTERN int uv_signal_start_oneshot(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum);
+UV_EXTERN int uv_signal_stop(uv_signal_t* handle);
+
+UV_EXTERN void uv_loadavg(double avg[3]);
+
+
+/*
+ * Flags to be passed to uv_fs_event_start().
+ */
+enum uv_fs_event_flags {
+ /*
+ * By default, if the fs event watcher is given a directory name, we will
+ * watch for all events in that directory. This flags overrides this behavior
+ * and makes fs_event report only changes to the directory entry itself. This
+ * flag does not affect individual files watched.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_WATCH_ENTRY = 1,
+
+ /*
+ * By default uv_fs_event will try to use a kernel interface such as inotify
+ * or kqueue to detect events. This may not work on remote filesystems such
+ * as NFS mounts. This flag makes fs_event fall back to calling stat() on a
+ * regular interval.
+ * This flag is currently not implemented yet on any backend.
+ */
+ UV_FS_EVENT_STAT = 2,
+
+ /*
+ * By default, event watcher, when watching directory, is not registering
+ * (is ignoring) changes in it's subdirectories.
+ * This flag will override this behaviour on platforms that support it.
+ */
+ UV_FS_EVENT_RECURSIVE = 4
+};
+
+
+UV_EXTERN int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags);
+UV_EXTERN int uv_fs_event_stop(uv_fs_event_t* handle);
+UV_EXTERN int uv_fs_event_getpath(uv_fs_event_t* handle,
+ char* buffer,
+ size_t* size);
+
+UV_EXTERN int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr);
+UV_EXTERN int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr);
+
+UV_EXTERN int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size);
+UV_EXTERN int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size);
+
+UV_EXTERN int uv_inet_ntop(int af, const void* src, char* dst, size_t size);
+UV_EXTERN int uv_inet_pton(int af, const char* src, void* dst);
+
+UV_EXTERN int uv_exepath(char* buffer, size_t* size);
+
+UV_EXTERN int uv_cwd(char* buffer, size_t* size);
+
+UV_EXTERN int uv_chdir(const char* dir);
+
+UV_EXTERN uint64_t uv_get_free_memory(void);
+UV_EXTERN uint64_t uv_get_total_memory(void);
+
+UV_EXTERN uint64_t uv_hrtime(void);
+
+UV_EXTERN void uv_disable_stdio_inheritance(void);
+
+UV_EXTERN int uv_dlopen(const char* filename, uv_lib_t* lib);
+UV_EXTERN void uv_dlclose(uv_lib_t* lib);
+UV_EXTERN int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr);
+UV_EXTERN const char* uv_dlerror(const uv_lib_t* lib);
+
+UV_EXTERN int uv_mutex_init(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_destroy(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_lock(uv_mutex_t* handle);
+UV_EXTERN int uv_mutex_trylock(uv_mutex_t* handle);
+UV_EXTERN void uv_mutex_unlock(uv_mutex_t* handle);
+
+UV_EXTERN int uv_rwlock_init(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_destroy(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_rdunlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrlock(uv_rwlock_t* rwlock);
+UV_EXTERN int uv_rwlock_trywrlock(uv_rwlock_t* rwlock);
+UV_EXTERN void uv_rwlock_wrunlock(uv_rwlock_t* rwlock);
+
+UV_EXTERN int uv_sem_init(uv_sem_t* sem, unsigned int value);
+UV_EXTERN void uv_sem_destroy(uv_sem_t* sem);
+UV_EXTERN void uv_sem_post(uv_sem_t* sem);
+UV_EXTERN void uv_sem_wait(uv_sem_t* sem);
+UV_EXTERN int uv_sem_trywait(uv_sem_t* sem);
+
+UV_EXTERN int uv_cond_init(uv_cond_t* cond);
+UV_EXTERN void uv_cond_destroy(uv_cond_t* cond);
+UV_EXTERN void uv_cond_signal(uv_cond_t* cond);
+UV_EXTERN void uv_cond_broadcast(uv_cond_t* cond);
+
+UV_EXTERN int uv_barrier_init(uv_barrier_t* barrier, unsigned int count);
+UV_EXTERN void uv_barrier_destroy(uv_barrier_t* barrier);
+UV_EXTERN int uv_barrier_wait(uv_barrier_t* barrier);
+
+UV_EXTERN void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+UV_EXTERN int uv_cond_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex,
+ uint64_t timeout);
+
+UV_EXTERN void uv_once(uv_once_t* guard, void (*callback)(void));
+
+UV_EXTERN int uv_key_create(uv_key_t* key);
+UV_EXTERN void uv_key_delete(uv_key_t* key);
+UV_EXTERN void* uv_key_get(uv_key_t* key);
+UV_EXTERN void uv_key_set(uv_key_t* key, void* value);
+
+typedef void (*uv_thread_cb)(void* arg);
+
+UV_EXTERN int uv_thread_create(uv_thread_t* tid, uv_thread_cb entry, void* arg);
+UV_EXTERN uv_thread_t uv_thread_self(void);
+UV_EXTERN int uv_thread_join(uv_thread_t *tid);
+UV_EXTERN int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2);
+
+/* The presence of these unions force similar struct layout. */
+#define XX(_, name) uv_ ## name ## _t name;
+union uv_any_handle {
+ UV_HANDLE_TYPE_MAP(XX)
+};
+
+union uv_any_req {
+ UV_REQ_TYPE_MAP(XX)
+};
+#undef XX
+
+
+struct uv_loop_s {
+ /* User data - use this for whatever. */
+ void* data;
+ /* Loop reference counting. */
+ unsigned int active_handles;
+ void* handle_queue[2];
+ void* active_reqs[2];
+ /* Internal flag to signal loop stop. */
+ unsigned int stop_flag;
+ UV_LOOP_PRIVATE_FIELDS
+};
+
+
+/* Don't export the private CPP symbols. */
+#undef UV_HANDLE_TYPE_PRIVATE
+#undef UV_REQ_TYPE_PRIVATE
+#undef UV_REQ_PRIVATE_FIELDS
+#undef UV_STREAM_PRIVATE_FIELDS
+#undef UV_TCP_PRIVATE_FIELDS
+#undef UV_PREPARE_PRIVATE_FIELDS
+#undef UV_CHECK_PRIVATE_FIELDS
+#undef UV_IDLE_PRIVATE_FIELDS
+#undef UV_ASYNC_PRIVATE_FIELDS
+#undef UV_TIMER_PRIVATE_FIELDS
+#undef UV_GETADDRINFO_PRIVATE_FIELDS
+#undef UV_GETNAMEINFO_PRIVATE_FIELDS
+#undef UV_FS_REQ_PRIVATE_FIELDS
+#undef UV_WORK_PRIVATE_FIELDS
+#undef UV_FS_EVENT_PRIVATE_FIELDS
+#undef UV_SIGNAL_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_FIELDS
+#undef UV_LOOP_PRIVATE_PLATFORM_FIELDS
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* UV_H */
diff --git a/Utilities/cmlibuv/src/fs-poll.c b/Utilities/cmlibuv/src/fs-poll.c
new file mode 100644
index 000000000..ee73d5a2e
--- /dev/null
+++ b/Utilities/cmlibuv/src/fs-poll.c
@@ -0,0 +1,256 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+struct poll_ctx {
+ uv_fs_poll_t* parent_handle; /* NULL if parent has been stopped or closed */
+ int busy_polling;
+ unsigned int interval;
+ uint64_t start_time;
+ uv_loop_t* loop;
+ uv_fs_poll_cb poll_cb;
+ uv_timer_t timer_handle;
+ uv_fs_t fs_req; /* TODO(bnoordhuis) mark fs_req internal */
+ uv_stat_t statbuf;
+ char path[1]; /* variable length */
+};
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b);
+static void poll_cb(uv_fs_t* req);
+static void timer_cb(uv_timer_t* timer);
+static void timer_close_cb(uv_handle_t* handle);
+
+static uv_stat_t zero_statbuf;
+
+
+int uv_fs_poll_init(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_POLL);
+ return 0;
+}
+
+
+int uv_fs_poll_start(uv_fs_poll_t* handle,
+ uv_fs_poll_cb cb,
+ const char* path,
+ unsigned int interval) {
+ struct poll_ctx* ctx;
+ uv_loop_t* loop;
+ size_t len;
+ int err;
+
+ if (uv__is_active(handle))
+ return 0;
+
+ loop = handle->loop;
+ len = strlen(path);
+ ctx = uv__calloc(1, sizeof(*ctx) + len);
+
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->loop = loop;
+ ctx->poll_cb = cb;
+ ctx->interval = interval ? interval : 1;
+ ctx->start_time = uv_now(loop);
+ ctx->parent_handle = handle;
+ memcpy(ctx->path, path, len + 1);
+
+ err = uv_timer_init(loop, &ctx->timer_handle);
+ if (err < 0)
+ goto error;
+
+ ctx->timer_handle.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&ctx->timer_handle);
+
+ err = uv_fs_stat(loop, &ctx->fs_req, ctx->path, poll_cb);
+ if (err < 0)
+ goto error;
+
+ handle->poll_ctx = ctx;
+ uv__handle_start(handle);
+
+ return 0;
+
+error:
+ uv__free(ctx);
+ return err;
+}
+
+
+int uv_fs_poll_stop(uv_fs_poll_t* handle) {
+ struct poll_ctx* ctx;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+ assert(ctx->parent_handle != NULL);
+ ctx->parent_handle = NULL;
+ handle->poll_ctx = NULL;
+
+ /* Close the timer if it's active. If it's inactive, there's a stat request
+ * in progress and poll_cb will take care of the cleanup.
+ */
+ if (uv__is_active(&ctx->timer_handle))
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_fs_poll_getpath(uv_fs_poll_t* handle, char* buffer, size_t* size) {
+ struct poll_ctx* ctx;
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ ctx = handle->poll_ctx;
+ assert(ctx != NULL);
+
+ required_len = strlen(ctx->path);
+ if (required_len >= *size) {
+ *size = required_len + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, ctx->path, required_len);
+ *size = required_len;
+ buffer[required_len] = '\0';
+
+ return 0;
+}
+
+
+void uv__fs_poll_close(uv_fs_poll_t* handle) {
+ uv_fs_poll_stop(handle);
+}
+
+
+static void timer_cb(uv_timer_t* timer) {
+ struct poll_ctx* ctx;
+
+ ctx = container_of(timer, struct poll_ctx, timer_handle);
+ assert(ctx->parent_handle != NULL);
+ assert(ctx->parent_handle->poll_ctx == ctx);
+ ctx->start_time = uv_now(ctx->loop);
+
+ if (uv_fs_stat(ctx->loop, &ctx->fs_req, ctx->path, poll_cb))
+ abort();
+}
+
+
+static void poll_cb(uv_fs_t* req) {
+ uv_stat_t* statbuf;
+ struct poll_ctx* ctx;
+ uint64_t interval;
+
+ ctx = container_of(req, struct poll_ctx, fs_req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped or closed */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ uv_fs_req_cleanup(req);
+ return;
+ }
+
+ if (req->result != 0) {
+ if (ctx->busy_polling != req->result) {
+ ctx->poll_cb(ctx->parent_handle,
+ req->result,
+ &ctx->statbuf,
+ &zero_statbuf);
+ ctx->busy_polling = req->result;
+ }
+ goto out;
+ }
+
+ statbuf = &req->statbuf;
+
+ if (ctx->busy_polling != 0)
+ if (ctx->busy_polling < 0 || !statbuf_eq(&ctx->statbuf, statbuf))
+ ctx->poll_cb(ctx->parent_handle, 0, &ctx->statbuf, statbuf);
+
+ ctx->statbuf = *statbuf;
+ ctx->busy_polling = 1;
+
+out:
+ uv_fs_req_cleanup(req);
+
+ if (ctx->parent_handle == NULL) { /* handle has been stopped by callback */
+ uv_close((uv_handle_t*)&ctx->timer_handle, timer_close_cb);
+ return;
+ }
+
+ /* Reschedule timer, subtract the delay from doing the stat(). */
+ interval = ctx->interval;
+ interval -= (uv_now(ctx->loop) - ctx->start_time) % interval;
+
+ if (uv_timer_start(&ctx->timer_handle, timer_cb, interval, 0))
+ abort();
+}
+
+
+static void timer_close_cb(uv_handle_t* handle) {
+ uv__free(container_of(handle, struct poll_ctx, timer_handle));
+}
+
+
+static int statbuf_eq(const uv_stat_t* a, const uv_stat_t* b) {
+ return a->st_ctim.tv_nsec == b->st_ctim.tv_nsec
+ && a->st_mtim.tv_nsec == b->st_mtim.tv_nsec
+ && a->st_birthtim.tv_nsec == b->st_birthtim.tv_nsec
+ && a->st_ctim.tv_sec == b->st_ctim.tv_sec
+ && a->st_mtim.tv_sec == b->st_mtim.tv_sec
+ && a->st_birthtim.tv_sec == b->st_birthtim.tv_sec
+ && a->st_size == b->st_size
+ && a->st_mode == b->st_mode
+ && a->st_uid == b->st_uid
+ && a->st_gid == b->st_gid
+ && a->st_ino == b->st_ino
+ && a->st_dev == b->st_dev
+ && a->st_flags == b->st_flags
+ && a->st_gen == b->st_gen;
+}
+
+
+#if defined(_WIN32)
+
+#include "win/internal.h"
+#include "win/handle-inl.h"
+
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+}
+
+#endif /* _WIN32 */
diff --git a/Utilities/cmlibuv/src/heap-inl.h b/Utilities/cmlibuv/src/heap-inl.h
new file mode 100644
index 000000000..1e2ed60e0
--- /dev/null
+++ b/Utilities/cmlibuv/src/heap-inl.h
@@ -0,0 +1,245 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SRC_HEAP_H_
+#define UV_SRC_HEAP_H_
+
+#include <stddef.h> /* NULL */
+
+#if defined(__GNUC__)
+# define HEAP_EXPORT(declaration) __attribute__((unused)) static declaration
+#else
+# define HEAP_EXPORT(declaration) static declaration
+#endif
+
+struct heap_node {
+ struct heap_node* left;
+ struct heap_node* right;
+ struct heap_node* parent;
+};
+
+/* A binary min heap. The usual properties hold: the root is the lowest
+ * element in the set, the height of the tree is at most log2(nodes) and
+ * it's always a complete binary tree.
+ *
+ * The heap function try hard to detect corrupted tree nodes at the cost
+ * of a minor reduction in performance. Compile with -DNDEBUG to disable.
+ */
+struct heap {
+ struct heap_node* min;
+ unsigned int nelts;
+};
+
+/* Return non-zero if a < b. */
+typedef int (*heap_compare_fn)(const struct heap_node* a,
+ const struct heap_node* b);
+
+/* Public functions. */
+HEAP_EXPORT(void heap_init(struct heap* heap));
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap));
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than));
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than));
+
+/* Implementation follows. */
+
+HEAP_EXPORT(void heap_init(struct heap* heap)) {
+ heap->min = NULL;
+ heap->nelts = 0;
+}
+
+HEAP_EXPORT(struct heap_node* heap_min(const struct heap* heap)) {
+ return heap->min;
+}
+
+/* Swap parent with child. Child moves closer to the root, parent moves away. */
+static void heap_node_swap(struct heap* heap,
+ struct heap_node* parent,
+ struct heap_node* child) {
+ struct heap_node* sibling;
+ struct heap_node t;
+
+ t = *parent;
+ *parent = *child;
+ *child = t;
+
+ parent->parent = child;
+ if (child->left == child) {
+ child->left = parent;
+ sibling = child->right;
+ } else {
+ child->right = parent;
+ sibling = child->left;
+ }
+ if (sibling != NULL)
+ sibling->parent = child;
+
+ if (parent->left != NULL)
+ parent->left->parent = parent;
+ if (parent->right != NULL)
+ parent->right->parent = parent;
+
+ if (child->parent == NULL)
+ heap->min = child;
+ else if (child->parent->left == parent)
+ child->parent->left = child;
+ else
+ child->parent->right = child;
+}
+
+HEAP_EXPORT(void heap_insert(struct heap* heap,
+ struct heap_node* newnode,
+ heap_compare_fn less_than)) {
+ struct heap_node** parent;
+ struct heap_node** child;
+ unsigned int path;
+ unsigned int n;
+ unsigned int k;
+
+ newnode->left = NULL;
+ newnode->right = NULL;
+ newnode->parent = NULL;
+
+ /* Calculate the path from the root to the insertion point. This is a min
+ * heap so we always insert at the left-most free node of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = 1 + heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ parent = child = &heap->min;
+ while (k > 0) {
+ parent = child;
+ if (path & 1)
+ child = &(*child)->right;
+ else
+ child = &(*child)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ /* Insert the new node. */
+ newnode->parent = *parent;
+ *child = newnode;
+ heap->nelts += 1;
+
+ /* Walk up the tree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true.
+ */
+ while (newnode->parent != NULL && less_than(newnode, newnode->parent))
+ heap_node_swap(heap, newnode->parent, newnode);
+}
+
+HEAP_EXPORT(void heap_remove(struct heap* heap,
+ struct heap_node* node,
+ heap_compare_fn less_than)) {
+ struct heap_node* smallest;
+ struct heap_node** max;
+ struct heap_node* child;
+ unsigned int path;
+ unsigned int k;
+ unsigned int n;
+
+ if (heap->nelts == 0)
+ return;
+
+ /* Calculate the path from the min (the root) to the max, the left-most node
+ * of the bottom row.
+ */
+ path = 0;
+ for (k = 0, n = heap->nelts; n >= 2; k += 1, n /= 2)
+ path = (path << 1) | (n & 1);
+
+ /* Now traverse the heap using the path we calculated in the previous step. */
+ max = &heap->min;
+ while (k > 0) {
+ if (path & 1)
+ max = &(*max)->right;
+ else
+ max = &(*max)->left;
+ path >>= 1;
+ k -= 1;
+ }
+
+ heap->nelts -= 1;
+
+ /* Unlink the max node. */
+ child = *max;
+ *max = NULL;
+
+ if (child == node) {
+ /* We're removing either the max or the last node in the tree. */
+ if (child == heap->min) {
+ heap->min = NULL;
+ }
+ return;
+ }
+
+ /* Replace the to be deleted node with the max node. */
+ child->left = node->left;
+ child->right = node->right;
+ child->parent = node->parent;
+
+ if (child->left != NULL) {
+ child->left->parent = child;
+ }
+
+ if (child->right != NULL) {
+ child->right->parent = child;
+ }
+
+ if (node->parent == NULL) {
+ heap->min = child;
+ } else if (node->parent->left == node) {
+ node->parent->left = child;
+ } else {
+ node->parent->right = child;
+ }
+
+ /* Walk down the subtree and check at each node if the heap property holds.
+ * It's a min heap so parent < child must be true. If the parent is bigger,
+ * swap it with the smallest child.
+ */
+ for (;;) {
+ smallest = child;
+ if (child->left != NULL && less_than(child->left, smallest))
+ smallest = child->left;
+ if (child->right != NULL && less_than(child->right, smallest))
+ smallest = child->right;
+ if (smallest == child)
+ break;
+ heap_node_swap(heap, child, smallest);
+ }
+
+ /* Walk up the subtree and check that each parent is less than the node
+ * this is required, because `max` node is not guaranteed to be the
+ * actual maximum in tree
+ */
+ while (child->parent != NULL && less_than(child, child->parent))
+ heap_node_swap(heap, child->parent, child);
+}
+
+HEAP_EXPORT(void heap_dequeue(struct heap* heap, heap_compare_fn less_than)) {
+ heap_remove(heap, heap->min, less_than);
+}
+
+#undef HEAP_EXPORT
+
+#endif /* UV_SRC_HEAP_H_ */
diff --git a/Utilities/cmlibuv/src/inet.c b/Utilities/cmlibuv/src/inet.c
new file mode 100644
index 000000000..7c75e4373
--- /dev/null
+++ b/Utilities/cmlibuv/src/inet.c
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996-1999 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
+ * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#define UV__INET_ADDRSTRLEN 16
+#define UV__INET6_ADDRSTRLEN 46
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size);
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size);
+static int inet_pton4(const char *src, unsigned char *dst);
+static int inet_pton6(const char *src, unsigned char *dst);
+
+
+int uv_inet_ntop(int af, const void* src, char* dst, size_t size) {
+ switch (af) {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_ntop4(const unsigned char *src, char *dst, size_t size) {
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[UV__INET_ADDRSTRLEN];
+ int l;
+
+ l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
+ if (l <= 0 || (size_t) l >= size) {
+ return UV_ENOSPC;
+ }
+ strncpy(dst, tmp, size);
+ dst[size - 1] = '\0';
+ return 0;
+}
+
+
+static int inet_ntop6(const unsigned char *src, char *dst, size_t size) {
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[UV__INET6_ADDRSTRLEN], *tp;
+ struct { int base, len; } best, cur;
+ unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof words);
+ for (i = 0; i < (int) sizeof(struct in6_addr); i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+ best.base = -1;
+ best.len = 0;
+ cur.base = -1;
+ cur.len = 0;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ if (words[i] == 0) {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ } else {
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1) {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (int) ARRAY_SIZE(words); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len)) {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 && (best.len == 6 ||
+ (best.len == 7 && words[7] != 0x0001) ||
+ (best.len == 5 && words[5] == 0xffff))) {
+ int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp));
+ if (err)
+ return err;
+ tp += strlen(tp);
+ break;
+ }
+ tp += sprintf(tp, "%x", words[i]);
+ }
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size) {
+ return UV_ENOSPC;
+ }
+ strcpy(dst, tmp);
+ return 0;
+}
+
+
+int uv_inet_pton(int af, const char* src, void* dst) {
+ if (src == NULL || dst == NULL)
+ return UV_EINVAL;
+
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, dst));
+ case AF_INET6: {
+ int len;
+ char tmp[UV__INET6_ADDRSTRLEN], *s, *p;
+ s = (char*) src;
+ p = strchr(src, '%');
+ if (p != NULL) {
+ s = tmp;
+ len = p - src;
+ if (len > UV__INET6_ADDRSTRLEN-1)
+ return UV_EINVAL;
+ memcpy(s, src, len);
+ s[len] = '\0';
+ }
+ return inet_pton6(s, dst);
+ }
+ default:
+ return UV_EAFNOSUPPORT;
+ }
+ /* NOTREACHED */
+}
+
+
+static int inet_pton4(const char *src, unsigned char *dst) {
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[sizeof(struct in_addr)], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ *(tp = tmp) = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr(digits, ch)) != NULL) {
+ unsigned int nw = *tp * 10 + (pch - digits);
+
+ if (saw_digit && *tp == 0)
+ return UV_EINVAL;
+ if (nw > 255)
+ return UV_EINVAL;
+ *tp = nw;
+ if (!saw_digit) {
+ if (++octets > 4)
+ return UV_EINVAL;
+ saw_digit = 1;
+ }
+ } else if (ch == '.' && saw_digit) {
+ if (octets == 4)
+ return UV_EINVAL;
+ *++tp = 0;
+ saw_digit = 0;
+ } else
+ return UV_EINVAL;
+ }
+ if (octets < 4)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof(struct in_addr));
+ return 0;
+}
+
+
+static int inet_pton6(const char *src, unsigned char *dst) {
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, seen_xdigits;
+ unsigned int val;
+
+ memset((tp = tmp), '\0', sizeof tmp);
+ endp = tp + sizeof tmp;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ return UV_EINVAL;
+ curtok = src;
+ seen_xdigits = 0;
+ val = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++seen_xdigits > 4)
+ return UV_EINVAL;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!seen_xdigits) {
+ if (colonp)
+ return UV_EINVAL;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0') {
+ return UV_EINVAL;
+ }
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ seen_xdigits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) {
+ int err = inet_pton4(curtok, tp);
+ if (err == 0) {
+ tp += sizeof(struct in_addr);
+ seen_xdigits = 0;
+ break; /*%< '\\0' was seen by inet_pton4(). */
+ }
+ }
+ return UV_EINVAL;
+ }
+ if (seen_xdigits) {
+ if (tp + sizeof(uint16_t) > endp)
+ return UV_EINVAL;
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const int n = tp - colonp;
+ int i;
+
+ if (tp == endp)
+ return UV_EINVAL;
+ for (i = 1; i <= n; i++) {
+ endp[- i] = colonp[n - i];
+ colonp[n - i] = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ return UV_EINVAL;
+ memcpy(dst, tmp, sizeof tmp);
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/queue.h b/Utilities/cmlibuv/src/queue.h
new file mode 100644
index 000000000..ff3540a0a
--- /dev/null
+++ b/Utilities/cmlibuv/src/queue.h
@@ -0,0 +1,108 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef QUEUE_H_
+#define QUEUE_H_
+
+#include <stddef.h>
+
+typedef void *QUEUE[2];
+
+/* Private macros. */
+#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0]))
+#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1]))
+#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q)))
+#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q)))
+
+/* Public macros. */
+#define QUEUE_DATA(ptr, type, field) \
+ ((type *) ((char *) (ptr) - offsetof(type, field)))
+
+/* Important note: mutating the list while QUEUE_FOREACH is
+ * iterating over its elements results in undefined behavior.
+ */
+#define QUEUE_FOREACH(q, h) \
+ for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q))
+
+#define QUEUE_EMPTY(q) \
+ ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q))
+
+#define QUEUE_HEAD(q) \
+ (QUEUE_NEXT(q))
+
+#define QUEUE_INIT(q) \
+ do { \
+ QUEUE_NEXT(q) = (q); \
+ QUEUE_PREV(q) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_ADD(h, n) \
+ do { \
+ QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \
+ QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV(h) = QUEUE_PREV(n); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ } \
+ while (0)
+
+#define QUEUE_SPLIT(h, q, n) \
+ do { \
+ QUEUE_PREV(n) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(n) = (n); \
+ QUEUE_NEXT(n) = (q); \
+ QUEUE_PREV(h) = QUEUE_PREV(q); \
+ QUEUE_PREV_NEXT(h) = (h); \
+ QUEUE_PREV(q) = (n); \
+ } \
+ while (0)
+
+#define QUEUE_MOVE(h, n) \
+ do { \
+ if (QUEUE_EMPTY(h)) \
+ QUEUE_INIT(n); \
+ else { \
+ QUEUE* q = QUEUE_HEAD(h); \
+ QUEUE_SPLIT(h, q, n); \
+ } \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_HEAD(h, q) \
+ do { \
+ QUEUE_NEXT(q) = QUEUE_NEXT(h); \
+ QUEUE_PREV(q) = (h); \
+ QUEUE_NEXT_PREV(q) = (q); \
+ QUEUE_NEXT(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_INSERT_TAIL(h, q) \
+ do { \
+ QUEUE_NEXT(q) = (h); \
+ QUEUE_PREV(q) = QUEUE_PREV(h); \
+ QUEUE_PREV_NEXT(q) = (q); \
+ QUEUE_PREV(h) = (q); \
+ } \
+ while (0)
+
+#define QUEUE_REMOVE(q) \
+ do { \
+ QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \
+ QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \
+ } \
+ while (0)
+
+#endif /* QUEUE_H_ */
diff --git a/Utilities/cmlibuv/src/threadpool.c b/Utilities/cmlibuv/src/threadpool.c
new file mode 100644
index 000000000..108934112
--- /dev/null
+++ b/Utilities/cmlibuv/src/threadpool.c
@@ -0,0 +1,312 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv-common.h"
+
+#if !defined(_WIN32)
+# include "unix/internal.h"
+#endif
+
+#include <stdlib.h>
+
+#define MAX_THREADPOOL_SIZE 128
+
+static uv_once_t once = UV_ONCE_INIT;
+static uv_cond_t cond;
+static uv_mutex_t mutex;
+static unsigned int idle_threads;
+static unsigned int nthreads;
+static uv_thread_t* threads;
+static uv_thread_t default_threads[4];
+static QUEUE exit_message;
+static QUEUE wq;
+static volatile int initialized;
+
+
+static void uv__cancelled(struct uv__work* w) {
+ abort();
+}
+
+
+/* To avoid deadlock with uv_cancel() it's crucial that the worker
+ * never holds the global mutex and the loop-local mutex at the same time.
+ */
+static void worker(void* arg) {
+ struct uv__work* w;
+ QUEUE* q;
+
+ (void) arg;
+
+ for (;;) {
+ uv_mutex_lock(&mutex);
+
+ while (QUEUE_EMPTY(&wq)) {
+ idle_threads += 1;
+ uv_cond_wait(&cond, &mutex);
+ idle_threads -= 1;
+ }
+
+ q = QUEUE_HEAD(&wq);
+
+ if (q == &exit_message)
+ uv_cond_signal(&cond);
+ else {
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q); /* Signal uv_cancel() that the work req is
+ executing. */
+ }
+
+ uv_mutex_unlock(&mutex);
+
+ if (q == &exit_message)
+ break;
+
+ w = QUEUE_DATA(q, struct uv__work, wq);
+ w->work(w);
+
+ uv_mutex_lock(&w->loop->wq_mutex);
+ w->work = NULL; /* Signal uv_cancel() that the work req is done
+ executing. */
+ QUEUE_INSERT_TAIL(&w->loop->wq, &w->wq);
+ uv_async_send(&w->loop->wq_async);
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ }
+}
+
+
+static void post(QUEUE* q) {
+ uv_mutex_lock(&mutex);
+ QUEUE_INSERT_TAIL(&wq, q);
+ if (idle_threads > 0)
+ uv_cond_signal(&cond);
+ uv_mutex_unlock(&mutex);
+}
+
+
+#ifndef _WIN32
+UV_DESTRUCTOR(static void cleanup(void)) {
+ unsigned int i;
+
+ if (initialized == 0)
+ return;
+
+ post(&exit_message);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_join(threads + i))
+ abort();
+
+ if (threads != default_threads)
+ uv__free(threads);
+
+ uv_mutex_destroy(&mutex);
+ uv_cond_destroy(&cond);
+
+ threads = NULL;
+ nthreads = 0;
+ initialized = 0;
+}
+#endif
+
+
+static void init_threads(void) {
+ unsigned int i;
+ const char* val;
+
+ nthreads = ARRAY_SIZE(default_threads);
+ val = getenv("UV_THREADPOOL_SIZE");
+ if (val != NULL)
+ nthreads = atoi(val);
+ if (nthreads == 0)
+ nthreads = 1;
+ if (nthreads > MAX_THREADPOOL_SIZE)
+ nthreads = MAX_THREADPOOL_SIZE;
+
+ threads = default_threads;
+ if (nthreads > ARRAY_SIZE(default_threads)) {
+ threads = uv__malloc(nthreads * sizeof(threads[0]));
+ if (threads == NULL) {
+ nthreads = ARRAY_SIZE(default_threads);
+ threads = default_threads;
+ }
+ }
+
+ if (uv_cond_init(&cond))
+ abort();
+
+ if (uv_mutex_init(&mutex))
+ abort();
+
+ QUEUE_INIT(&wq);
+
+ for (i = 0; i < nthreads; i++)
+ if (uv_thread_create(threads + i, worker, NULL))
+ abort();
+
+ initialized = 1;
+}
+
+
+#ifndef _WIN32
+static void reset_once(void) {
+ uv_once_t child_once = UV_ONCE_INIT;
+ memcpy(&once, &child_once, sizeof(child_once));
+}
+#endif
+
+
+static void init_once(void) {
+#ifndef _WIN32
+ /* Re-initialize the threadpool after fork.
+ * Note that this discards the global mutex and condition as well
+ * as the work queue.
+ */
+ if (pthread_atfork(NULL, NULL, &reset_once))
+ abort();
+#endif
+ init_threads();
+}
+
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work* w,
+ void (*work)(struct uv__work* w),
+ void (*done)(struct uv__work* w, int status)) {
+ uv_once(&once, init_once);
+ w->loop = loop;
+ w->work = work;
+ w->done = done;
+ post(&w->wq);
+}
+
+
+static int uv__work_cancel(uv_loop_t* loop, uv_req_t* req, struct uv__work* w) {
+ int cancelled;
+
+ uv_mutex_lock(&mutex);
+ uv_mutex_lock(&w->loop->wq_mutex);
+
+ cancelled = !QUEUE_EMPTY(&w->wq) && w->work != NULL;
+ if (cancelled)
+ QUEUE_REMOVE(&w->wq);
+
+ uv_mutex_unlock(&w->loop->wq_mutex);
+ uv_mutex_unlock(&mutex);
+
+ if (!cancelled)
+ return UV_EBUSY;
+
+ w->work = uv__cancelled;
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_INSERT_TAIL(&loop->wq, &w->wq);
+ uv_async_send(&loop->wq_async);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ return 0;
+}
+
+
+void uv__work_done(uv_async_t* handle) {
+ struct uv__work* w;
+ uv_loop_t* loop;
+ QUEUE* q;
+ QUEUE wq;
+ int err;
+
+ loop = container_of(handle, uv_loop_t, wq_async);
+ uv_mutex_lock(&loop->wq_mutex);
+ QUEUE_MOVE(&loop->wq, &wq);
+ uv_mutex_unlock(&loop->wq_mutex);
+
+ while (!QUEUE_EMPTY(&wq)) {
+ q = QUEUE_HEAD(&wq);
+ QUEUE_REMOVE(q);
+
+ w = container_of(q, struct uv__work, wq);
+ err = (w->work == uv__cancelled) ? UV_ECANCELED : 0;
+ w->done(w, err);
+ }
+}
+
+
+static void uv__queue_work(struct uv__work* w) {
+ uv_work_t* req = container_of(w, uv_work_t, work_req);
+
+ req->work_cb(req);
+}
+
+
+static void uv__queue_done(struct uv__work* w, int err) {
+ uv_work_t* req;
+
+ req = container_of(w, uv_work_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (req->after_work_cb == NULL)
+ return;
+
+ req->after_work_cb(req, err);
+}
+
+
+int uv_queue_work(uv_loop_t* loop,
+ uv_work_t* req,
+ uv_work_cb work_cb,
+ uv_after_work_cb after_work_cb) {
+ if (work_cb == NULL)
+ return UV_EINVAL;
+
+ uv__req_init(loop, req, UV_WORK);
+ req->loop = loop;
+ req->work_cb = work_cb;
+ req->after_work_cb = after_work_cb;
+ uv__work_submit(loop, &req->work_req, uv__queue_work, uv__queue_done);
+ return 0;
+}
+
+
+int uv_cancel(uv_req_t* req) {
+ struct uv__work* wreq;
+ uv_loop_t* loop;
+
+ switch (req->type) {
+ case UV_FS:
+ loop = ((uv_fs_t*) req)->loop;
+ wreq = &((uv_fs_t*) req)->work_req;
+ break;
+ case UV_GETADDRINFO:
+ loop = ((uv_getaddrinfo_t*) req)->loop;
+ wreq = &((uv_getaddrinfo_t*) req)->work_req;
+ break;
+ case UV_GETNAMEINFO:
+ loop = ((uv_getnameinfo_t*) req)->loop;
+ wreq = &((uv_getnameinfo_t*) req)->work_req;
+ break;
+ case UV_WORK:
+ loop = ((uv_work_t*) req)->loop;
+ wreq = &((uv_work_t*) req)->work_req;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ return uv__work_cancel(loop, req, wreq);
+}
diff --git a/Utilities/cmlibuv/src/unix/aix.c b/Utilities/cmlibuv/src/unix/aix.c
new file mode 100644
index 000000000..388c9cca9
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/aix.c
@@ -0,0 +1,1243 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utmp.h>
+#include <libgen.h>
+
+#include <sys/protosw.h>
+#include <libperfstat.h>
+#include <procinfo.h>
+#include <sys/proc.h>
+#include <sys/procfs.h>
+
+#include <sys/poll.h>
+
+#include <sys/pollset.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+#include <sys/ahafs_evProds.h>
+#endif
+
+#include <sys/mntctl.h>
+#include <sys/vmount.h>
+#include <limits.h>
+#include <strings.h>
+#include <sys/vnode.h>
+
+#define RDWR_BUF_SIZE 4096
+#define EQ(a,b) (strcmp(a,b) == 0)
+
+static void* args_mem = NULL;
+static char** process_argv = NULL;
+static int process_argc = 0;
+static char* process_title_ptr = NULL;
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->fs_fd = -1;
+
+ /* Passing maxfd of -1 should mean the limit is determined
+ * by the user's ulimit or the global limit as per the doc */
+ loop->backend_fd = pollset_create(-1);
+
+ if (loop->backend_fd == -1)
+ return -1;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ pollset_destroy(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+int uv__io_fork(uv_loop_t* loop) {
+ uv__platform_loop_delete(loop);
+
+ return uv__platform_loop_init(loop);
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct poll_ctl pc;
+
+ pc.events = POLLIN;
+ pc.cmd = PS_MOD; /* Equivalent to PS_ADD if the fd is not in the pollset. */
+ pc.fd = fd;
+
+ if (pollset_ctl(loop->backend_fd, &pc, 1))
+ return -errno;
+
+ pc.cmd = PS_DELETE;
+ if (pollset_ctl(loop->backend_fd, &pc, 1))
+ abort();
+
+ return 0;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct pollfd events[1024];
+ struct pollfd pqry;
+ struct pollfd* pe;
+ struct poll_ctl pc;
+ QUEUE* q;
+ uv__io_t* w;
+ uint64_t base;
+ uint64_t diff;
+ int have_signals;
+ int nevents;
+ int count;
+ int nfds;
+ int i;
+ int rc;
+ int add_failed;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ pc.events = w->pevents;
+ pc.fd = w->fd;
+
+ add_failed = 0;
+ if (w->events == 0) {
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ if (errno != EINVAL) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ /* Check if the fd is already in the pollset */
+ pqry.fd = pc.fd;
+ rc = pollset_query(loop->backend_fd, &pqry);
+ switch (rc) {
+ case -1:
+ assert(0 && "Failed to query pollset for file descriptor");
+ abort();
+ case 0:
+ assert(0 && "Pollset does not contain file descriptor");
+ abort();
+ }
+ /* If we got here then the pollset already contained the file descriptor even though
+ * we didn't think it should. This probably shouldn't happen, but we can continue. */
+ add_failed = 1;
+ }
+ }
+ if (w->events != 0 || add_failed) {
+ /* Modify, potentially removing events -- need to delete then add.
+ * Could maybe mod if we knew for sure no events are removed, but
+ * content of w->events is handled above as not reliable (falls back)
+ * so may require a pollset_query() which would have to be pretty cheap
+ * compared to a PS_DELETE to be worth optimizing. Alternatively, could
+ * lazily remove events, squelching them in the mean time. */
+ pc.cmd = PS_DELETE;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to delete file descriptor (pc.fd) from pollset");
+ abort();
+ }
+ pc.cmd = PS_ADD;
+ if (pollset_ctl(loop->backend_fd, &pc, 1)) {
+ assert(0 && "Failed to add file descriptor (pc.fd) to pollset");
+ abort();
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ nfds = pollset_poll(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR) {
+ abort();
+ }
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ have_signals = 0;
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ pc.cmd = PS_DELETE;
+ pc.fd = pe->fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (pc.fd == -1)
+ continue;
+
+ assert(pc.fd >= 0);
+ assert((unsigned) pc.fd < loop->nwatchers);
+
+ w = loop->watchers[pc.fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ pollset_ctl(loop->backend_fd, &pc, 1);
+ continue;
+ }
+
+ /* Run signal watchers last. This also affects child process watchers
+ * because those are implemented in terms of signal watchers.
+ */
+ if (w == &loop->signal_io_watcher)
+ have_signals = 1;
+ else
+ w->cb(loop, w, pe->revents);
+
+ nevents++;
+ }
+
+ if (have_signals != 0)
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ uint64_t G = 1000000000;
+ timebasestruct_t t;
+ read_wall_time(&t, TIMEBASE_SZ);
+ time_base_to_time(&t, TIMEBASE_SZ);
+ return (uint64_t) t.tb_high * G + t.tb_low;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in AIX - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ struct procsinfo pi;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pi.pi_pid = getpid();
+ res = getargs(&pi, sizeof(pi), args, sizeof(args));
+ if (res < 0)
+ return -EINVAL;
+
+ /*
+ * Possibilities for args:
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
+ * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+ * iii) a bare filename such as "node", after exporting PATH variable
+ * to its location.
+ */
+
+ /* Case i) and ii) absolute or relative paths */
+ if (strchr(args, '/') != NULL) {
+ if (realpath(args, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+ } else {
+ /* Case iii). Search PATH environment variable */
+ char trypath[PATH_MAX];
+ char *clonedpath = NULL;
+ char *token = NULL;
+ char *path = getenv("PATH");
+
+ if (path == NULL)
+ return -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -ENOMEM;
+
+ token = strtok(clonedpath, ":");
+ while (token != NULL) {
+ snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+ if (realpath(trypath, abspath) == abspath) {
+ /* Check the match is executable */
+ if (access(abspath, X_OK) == 0) {
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ uv__free(clonedpath);
+ return 0;
+ }
+ }
+ token = strtok(NULL, ":");
+ }
+ uv__free(clonedpath);
+
+ /* Out of tokens (path entries), and no match found */
+ return -EINVAL;
+ }
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_free * 4096;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ perfstat_memory_total_t mem_total;
+ int result = perfstat_memory_total(NULL, &mem_total, sizeof(mem_total), 1);
+ if (result == -1) {
+ return 0;
+ }
+ return mem_total.real_total * 4096;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ perfstat_cpu_total_t ps_total;
+ int result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ avg[0] = 0.; avg[1] = 0.; avg[2] = 0.;
+ return;
+ }
+ avg[0] = ps_total.loadavg[0] / (double)(1 << SBITS);
+ avg[1] = ps_total.loadavg[1] / (double)(1 << SBITS);
+ avg[2] = ps_total.loadavg[2] / (double)(1 << SBITS);
+}
+
+
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+static char *uv__rawname(char *cp) {
+ static char rawbuf[FILENAME_MAX+1];
+ char *dp = rindex(cp, '/');
+
+ if (dp == 0)
+ return 0;
+
+ *dp = 0;
+ strcpy(rawbuf, cp);
+ *dp = '/';
+ strcat(rawbuf, "/r");
+ strcat(rawbuf, dp+1);
+ return rawbuf;
+}
+
+
+/*
+ * Determine whether given pathname is a directory
+ * Returns 0 if the path is a directory, -1 if not
+ *
+ * Note: Opportunity here for more detailed error information but
+ * that requires changing callers of this function as well
+ */
+static int uv__path_is_a_directory(char* filename) {
+ struct stat statbuf;
+
+ if (stat(filename, &statbuf) < 0)
+ return -1; /* failed: not a directory, assume it is a file */
+
+ if (statbuf.st_type == VDIR)
+ return 0;
+
+ return -1;
+}
+
+
+/*
+ * Check whether AHAFS is mounted.
+ * Returns 0 if AHAFS is mounted, or an error code < 0 on failure
+ */
+static int uv__is_ahafs_mounted(void){
+ int rv, i = 2;
+ struct vmount *p;
+ int size_multiplier = 10;
+ size_t siz = sizeof(struct vmount)*size_multiplier;
+ struct vmount *vmt;
+ const char *dev = "/aha";
+ char *obj, *stub;
+
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+
+ /* Retrieve all mounted filesystems */
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ if (rv == 0) {
+ /* buffer was not large enough, reallocate to correct size */
+ siz = *(int*)p;
+ uv__free(p);
+ p = uv__malloc(siz);
+ if (p == NULL)
+ return -errno;
+ rv = mntctl(MCTL_QUERY, siz, (char*)p);
+ if (rv < 0)
+ return -errno;
+ }
+
+ /* Look for dev in filesystems mount info */
+ for(vmt = p, i = 0; i < rv; i++) {
+ obj = vmt2dataptr(vmt, VMT_OBJECT); /* device */
+ stub = vmt2dataptr(vmt, VMT_STUB); /* mount point */
+
+ if (EQ(obj, dev) || EQ(uv__rawname(obj), dev) || EQ(stub, dev)) {
+ uv__free(p); /* Found a match */
+ return 0;
+ }
+ vmt = (struct vmount *) ((char *) vmt + vmt->vmt_length);
+ }
+
+ /* /aha is required for monitoring filesystem changes */
+ return -1;
+}
+
+/*
+ * Recursive call to mkdir() to create intermediate folders, if any
+ * Returns code from mkdir call
+ */
+static int uv__makedir_p(const char *dir) {
+ char tmp[256];
+ char *p = NULL;
+ size_t len;
+ int err;
+
+ snprintf(tmp, sizeof(tmp),"%s",dir);
+ len = strlen(tmp);
+ if (tmp[len - 1] == '/')
+ tmp[len - 1] = 0;
+ for (p = tmp + 1; *p; p++) {
+ if (*p == '/') {
+ *p = 0;
+ err = mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+ if (err != 0 && errno != EEXIST)
+ return err;
+ *p = '/';
+ }
+ }
+ return mkdir(tmp, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
+}
+
+/*
+ * Creates necessary subdirectories in the AIX Event Infrastructure
+ * file system for monitoring the object specified.
+ * Returns code from mkdir call
+ */
+static int uv__make_subdirs_p(const char *filename) {
+ char cmd[2048];
+ char *p;
+ int rc = 0;
+
+ /* Strip off the monitor file name */
+ p = strrchr(filename, '/');
+
+ if (p == NULL)
+ return 0;
+
+ if (uv__path_is_a_directory((char*)filename) == 0) {
+ sprintf(cmd, "/aha/fs/modDir.monFactory");
+ } else {
+ sprintf(cmd, "/aha/fs/modFile.monFactory");
+ }
+
+ strncat(cmd, filename, (p - filename));
+ rc = uv__makedir_p(cmd);
+
+ if (rc == -1 && errno != EEXIST){
+ return -errno;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Checks if /aha is mounted, then proceeds to set up the monitoring
+ * objects for the specified file.
+ * Returns 0 on success, or an error code < 0 on failure
+ */
+static int uv__setup_ahafs(const char* filename, int *fd) {
+ int rc = 0;
+ char mon_file_write_string[RDWR_BUF_SIZE];
+ char mon_file[PATH_MAX];
+ int file_is_directory = 0; /* -1 == NO, 0 == YES */
+
+ /* Create monitor file name for object */
+ file_is_directory = uv__path_is_a_directory((char*)filename);
+
+ if (file_is_directory == 0)
+ sprintf(mon_file, "/aha/fs/modDir.monFactory");
+ else
+ sprintf(mon_file, "/aha/fs/modFile.monFactory");
+
+ if ((strlen(mon_file) + strlen(filename) + 5) > PATH_MAX)
+ return -ENAMETOOLONG;
+
+ /* Make the necessary subdirectories for the monitor file */
+ rc = uv__make_subdirs_p(filename);
+ if (rc == -1 && errno != EEXIST)
+ return rc;
+
+ strcat(mon_file, filename);
+ strcat(mon_file, ".mon");
+
+ *fd = 0; errno = 0;
+
+ /* Open the monitor file, creating it if necessary */
+ *fd = open(mon_file, O_CREAT|O_RDWR);
+ if (*fd < 0)
+ return -errno;
+
+ /* Write out the monitoring specifications.
+ * In this case, we are monitoring for a state change event type
+ * CHANGED=YES
+ * We will be waiting in select call, rather than a read:
+ * WAIT_TYPE=WAIT_IN_SELECT
+ * We only want minimal information for files:
+ * INFO_LVL=1
+ * For directories, we want more information to track what file
+ * caused the change
+ * INFO_LVL=2
+ */
+
+ if (file_is_directory == 0)
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=2");
+ else
+ sprintf(mon_file_write_string, "CHANGED=YES;WAIT_TYPE=WAIT_IN_SELECT;INFO_LVL=1");
+
+ rc = write(*fd, mon_file_write_string, strlen(mon_file_write_string)+1);
+ if (rc < 0)
+ return -errno;
+
+ return 0;
+}
+
+/*
+ * Skips a specified number of lines in the buffer passed in.
+ * Walks the buffer pointed to by p and attempts to skip n lines.
+ * Returns the total number of lines skipped
+ */
+static int uv__skip_lines(char **p, int n) {
+ int lines = 0;
+
+ while(n > 0) {
+ *p = strchr(*p, '\n');
+ if (!p)
+ return lines;
+
+ (*p)++;
+ n--;
+ lines++;
+ }
+ return lines;
+}
+
+
+/*
+ * Parse the event occurrence data to figure out what event just occurred
+ * and take proper action.
+ *
+ * The buf is a pointer to the buffer containing the event occurrence data
+ * Returns 0 on success, -1 if unrecoverable error in parsing
+ *
+ */
+static int uv__parse_data(char *buf, int *events, uv_fs_event_t* handle) {
+ int evp_rc, i;
+ char *p;
+ char filename[PATH_MAX]; /* To be used when handling directories */
+
+ p = buf;
+ *events = 0;
+
+ /* Clean the filename buffer*/
+ for(i = 0; i < PATH_MAX; i++) {
+ filename[i] = 0;
+ }
+ i = 0;
+
+ /* Check for BUF_WRAP */
+ if (strncmp(buf, "BUF_WRAP", strlen("BUF_WRAP")) == 0) {
+ assert(0 && "Buffer wrap detected, Some event occurrences lost!");
+ return 0;
+ }
+
+ /* Since we are using the default buffer size (4K), and have specified
+ * INFO_LVL=1, we won't see any EVENT_OVERFLOW conditions. Applications
+ * should check for this keyword if they are using an INFO_LVL of 2 or
+ * higher, and have a buffer size of <= 4K
+ */
+
+ /* Skip to RC_FROM_EVPROD */
+ if (uv__skip_lines(&p, 9) != 9)
+ return -1;
+
+ if (sscanf(p, "RC_FROM_EVPROD=%d\nEND_EVENT_DATA", &evp_rc) == 1) {
+ if (uv__path_is_a_directory(handle->path) == 0) { /* Directory */
+ if (evp_rc == AHAFS_MODDIR_UNMOUNT || evp_rc == AHAFS_MODDIR_REMOVE_SELF) {
+ /* The directory is no longer available for monitoring */
+ *events = UV_RENAME;
+ handle->dir_filename = NULL;
+ } else {
+ /* A file was added/removed inside the directory */
+ *events = UV_CHANGE;
+
+ /* Get the EVPROD_INFO */
+ if (uv__skip_lines(&p, 1) != 1)
+ return -1;
+
+ /* Scan out the name of the file that triggered the event*/
+ if (sscanf(p, "BEGIN_EVPROD_INFO\n%sEND_EVPROD_INFO", filename) == 1) {
+ handle->dir_filename = uv__strdup((const char*)&filename);
+ } else
+ return -1;
+ }
+ } else { /* Regular File */
+ if (evp_rc == AHAFS_MODFILE_RENAME)
+ *events = UV_RENAME;
+ else
+ *events = UV_CHANGE;
+ }
+ }
+ else
+ return -1;
+
+ return 0;
+}
+
+
+/* This is the internal callback */
+static void uv__ahafs_event(uv_loop_t* loop, uv__io_t* event_watch, unsigned int fflags) {
+ char result_data[RDWR_BUF_SIZE];
+ int bytes, rc = 0;
+ uv_fs_event_t* handle;
+ int events = 0;
+ char fname[PATH_MAX];
+ char *p;
+
+ handle = container_of(event_watch, uv_fs_event_t, event_watcher);
+
+ /* At this point, we assume that polling has been done on the
+ * file descriptor, so we can just read the AHAFS event occurrence
+ * data and parse its results without having to block anything
+ */
+ bytes = pread(event_watch->fd, result_data, RDWR_BUF_SIZE, 0);
+
+ assert((bytes >= 0) && "uv__ahafs_event - Error reading monitor file");
+
+ /* In file / directory move cases, AIX Event infrastructure
+ * produces a second event with no data.
+ * Ignore it and return gracefully.
+ */
+ if(bytes == 0)
+ return;
+
+ /* Parse the data */
+ if(bytes > 0)
+ rc = uv__parse_data(result_data, &events, handle);
+
+ /* Unrecoverable error */
+ if (rc == -1)
+ return;
+
+ /* For directory changes, the name of the files that triggered the change
+ * are never absolute pathnames
+ */
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ p = handle->dir_filename;
+ } else {
+ p = strrchr(handle->path, '/');
+ if (p == NULL)
+ p = handle->path;
+ else
+ p++;
+ }
+ strncpy(fname, p, sizeof(fname) - 1);
+ /* Just in case */
+ fname[sizeof(fname) - 1] = '\0';
+
+ handle->cb(handle, fname, events, 0);
+}
+#endif
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ int fd, rc, str_offset = 0;
+ char cwd[PATH_MAX];
+ char absolute_path[PATH_MAX];
+ char readlink_cwd[PATH_MAX];
+
+
+ /* Figure out whether filename is absolute or not */
+ if (filename[0] == '/') {
+ /* We have absolute pathname */
+ snprintf(absolute_path, sizeof(absolute_path), "%s", filename);
+ } else {
+ /* We have a relative pathname, compose the absolute pathname */
+ snprintf(cwd, sizeof(cwd), "/proc/%lu/cwd", (unsigned long) getpid());
+ rc = readlink(cwd, readlink_cwd, sizeof(readlink_cwd) - 1);
+ if (rc < 0)
+ return rc;
+ /* readlink does not null terminate our string */
+ readlink_cwd[rc] = '\0';
+
+ if (filename[0] == '.' && filename[1] == '/')
+ str_offset = 2;
+
+ snprintf(absolute_path, sizeof(absolute_path), "%s%s", readlink_cwd,
+ filename + str_offset);
+ }
+
+ if (uv__is_ahafs_mounted() < 0) /* /aha checks failed */
+ return UV_ENOSYS;
+
+ /* Setup ahafs */
+ rc = uv__setup_ahafs((const char *)absolute_path, &fd);
+ if (rc != 0)
+ return rc;
+
+ /* Setup/Initialize all the libuv routines */
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__ahafs_event, fd);
+ handle->path = uv__strdup(filename);
+ handle->cb = cb;
+
+ uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__io_close(handle->loop, &handle->event_watcher);
+ uv__handle_stop(handle);
+
+ if (uv__path_is_a_directory(handle->path) == 0) {
+ uv__free(handle->dir_filename);
+ handle->dir_filename = NULL;
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+
+ return 0;
+#else
+ return -ENOSYS;
+#endif
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+#ifdef HAVE_SYS_AHAFS_EVPRODS_H
+ uv_fs_event_stop(handle);
+#else
+ UNREACHABLE();
+#endif
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ char** new_argv;
+ size_t size;
+ char* s;
+ int i;
+
+ if (argc <= 0)
+ return argv;
+
+ /* Save the original pointer to argv.
+ * AIX uses argv to read the process name.
+ * (Not the memory pointed to by argv[0..n] as on Linux.)
+ */
+ process_argv = argv;
+ process_argc = argc;
+
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
+
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
+
+ new_argv = uv__malloc(size);
+ if (new_argv == NULL)
+ return argv;
+ args_mem = new_argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
+ }
+ new_argv[i] = NULL;
+
+ return new_argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ char* new_title;
+
+ /* We cannot free this pointer when libuv shuts down,
+ * the process may still be using it.
+ */
+ new_title = uv__strdup(title);
+ if (new_title == NULL)
+ return -ENOMEM;
+
+ /* If this is the first time this is set,
+ * don't free and set argv[1] to NULL.
+ */
+ if (process_title_ptr != NULL)
+ uv__free(process_title_ptr);
+
+ process_title_ptr = new_title;
+
+ process_argv[0] = process_title_ptr;
+ if (process_argc > 1)
+ process_argv[1] = NULL;
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+ len = strlen(process_argv[0]);
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+ else if (size <= len)
+ return -ENOBUFS;
+
+ memcpy(buffer, process_argv[0], len + 1);
+
+ return 0;
+}
+
+
+UV_DESTRUCTOR(static void free_args_mem(void)) {
+ uv__free(args_mem); /* Keep valgrind happy. */
+ args_mem = NULL;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char pp[64];
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ snprintf(pp, sizeof(pp), "/proc/%lu/psinfo", (unsigned long) getpid());
+
+ fd = open(pp, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ struct utmp *utmp_buf;
+ size_t entries = 0;
+ time_t boot_time;
+
+ utmpname(UTMP_FILE);
+
+ setutent();
+
+ while ((utmp_buf = getutent()) != NULL) {
+ if (utmp_buf->ut_user[0] && utmp_buf->ut_type == USER_PROCESS)
+ ++entries;
+ if (utmp_buf->ut_type == BOOT_TIME)
+ boot_time = utmp_buf->ut_time;
+ }
+
+ endutent();
+
+ if (boot_time == 0)
+ return -ENOSYS;
+
+ *uptime = time(NULL) - boot_time;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ uv_cpu_info_t* cpu_info;
+ perfstat_cpu_total_t ps_total;
+ perfstat_cpu_t* ps_cpus;
+ perfstat_id_t cpu_id;
+ int result, ncpus, idx = 0;
+
+ result = perfstat_cpu_total(NULL, &ps_total, sizeof(ps_total), 1);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ncpus = result = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
+ if (result == -1) {
+ return -ENOSYS;
+ }
+
+ ps_cpus = (perfstat_cpu_t*) uv__malloc(ncpus * sizeof(perfstat_cpu_t));
+ if (!ps_cpus) {
+ return -ENOMEM;
+ }
+
+ strcpy(cpu_id.name, FIRST_CPU);
+ result = perfstat_cpu(&cpu_id, ps_cpus, sizeof(perfstat_cpu_t), ncpus);
+ if (result == -1) {
+ uv__free(ps_cpus);
+ return -ENOSYS;
+ }
+
+ *cpu_infos = (uv_cpu_info_t*) uv__malloc(ncpus * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos) {
+ uv__free(ps_cpus);
+ return -ENOMEM;
+ }
+
+ *count = ncpus;
+
+ cpu_info = *cpu_infos;
+ while (idx < ncpus) {
+ cpu_info->speed = (int)(ps_total.processorHZ / 1000000);
+ cpu_info->model = uv__strdup(ps_total.description);
+ cpu_info->cpu_times.user = ps_cpus[idx].user;
+ cpu_info->cpu_times.sys = ps_cpus[idx].sys;
+ cpu_info->cpu_times.idle = ps_cpus[idx].idle;
+ cpu_info->cpu_times.irq = ps_cpus[idx].wait;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info++;
+ idx++;
+ }
+
+ uv__free(ps_cpus);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd, size = 1;
+ struct ifconf ifc;
+ struct ifreq *ifr, *p, flg;
+
+ *count = 0;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP))) {
+ return -errno;
+ }
+
+ if (ioctl(sockfd, SIOCGSIZIFCONF, &size) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ ifc.ifc_req = (struct ifreq*)uv__malloc(size);
+ ifc.ifc_len = size;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = (uv_interface_address_t*)
+ uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (p->ifr_addr.sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+ }
+
+ /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+#undef ADDR_SIZE
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct pollfd* events;
+ uintptr_t i;
+ uintptr_t nfds;
+ struct poll_ctl pc;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct pollfd*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].fd == fd)
+ events[i].fd = -1;
+
+ /* Remove the file descriptor from the poll set */
+ pc.events = 0;
+ pc.cmd = PS_DELETE;
+ pc.fd = fd;
+ if(loop->backend_fd >= 0)
+ pollset_ctl(loop->backend_fd, &pc, 1);
+}
diff --git a/Utilities/cmlibuv/src/unix/android-ifaddrs.c b/Utilities/cmlibuv/src/unix/android-ifaddrs.c
new file mode 100644
index 000000000..30f681b7d
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/android-ifaddrs.c
@@ -0,0 +1,703 @@
+/*
+Copyright (c) 2013, Kenneth MacKay
+Copyright (c) 2014, Emergya (Cloud4all, FP7/2007-2013 grant agreement #289016)
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification,
+are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+ * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "android-ifaddrs.h"
+#include "uv-common.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <net/if_arp.h>
+#include <netinet/in.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+typedef struct NetlinkList
+{
+ struct NetlinkList *m_next;
+ struct nlmsghdr *m_data;
+ unsigned int m_size;
+} NetlinkList;
+
+static int netlink_socket(void)
+{
+ struct sockaddr_nl l_addr;
+
+ int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ return l_socket;
+}
+
+static int netlink_send(int p_socket, int p_request)
+{
+ char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
+
+ struct nlmsghdr *l_hdr;
+ struct rtgenmsg *l_msg;
+ struct sockaddr_nl l_addr;
+
+ memset(l_buffer, 0, sizeof(l_buffer));
+
+ l_hdr = (struct nlmsghdr *)l_buffer;
+ l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
+
+ l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
+ l_hdr->nlmsg_type = p_request;
+ l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
+ l_hdr->nlmsg_pid = 0;
+ l_hdr->nlmsg_seq = p_socket;
+ l_msg->rtgen_family = AF_UNSPEC;
+
+ memset(&l_addr, 0, sizeof(l_addr));
+ l_addr.nl_family = AF_NETLINK;
+ return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
+}
+
+static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
+{
+ struct sockaddr_nl l_addr;
+ struct msghdr l_msg;
+
+ struct iovec l_iov;
+ l_iov.iov_base = p_buffer;
+ l_iov.iov_len = p_len;
+
+ for(;;)
+ {
+ int l_result;
+ l_msg.msg_name = (void *)&l_addr;
+ l_msg.msg_namelen = sizeof(l_addr);
+ l_msg.msg_iov = &l_iov;
+ l_msg.msg_iovlen = 1;
+ l_msg.msg_control = NULL;
+ l_msg.msg_controllen = 0;
+ l_msg.msg_flags = 0;
+ l_result = recvmsg(p_socket, &l_msg, 0);
+
+ if(l_result < 0)
+ {
+ if(errno == EINTR)
+ {
+ continue;
+ }
+ return -2;
+ }
+
+ /* Buffer was too small */
+ if(l_msg.msg_flags & MSG_TRUNC)
+ {
+ return -1;
+ }
+ return l_result;
+ }
+}
+
+static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
+{
+ size_t l_size = 4096;
+ void *l_buffer = NULL;
+
+ for(;;)
+ {
+ int l_read;
+
+ uv__free(l_buffer);
+ l_buffer = uv__malloc(l_size);
+ if (l_buffer == NULL)
+ {
+ return NULL;
+ }
+
+ l_read = netlink_recv(p_socket, l_buffer, l_size);
+ *p_size = l_read;
+ if(l_read == -2)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ if(l_read >= 0)
+ {
+ pid_t l_pid = getpid();
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ *p_done = 1;
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_ERROR)
+ {
+ uv__free(l_buffer);
+ return NULL;
+ }
+ }
+ return l_buffer;
+ }
+
+ l_size *= 2;
+ }
+}
+
+static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
+{
+ NetlinkList *l_item = uv__malloc(sizeof(NetlinkList));
+ if (l_item == NULL)
+ {
+ return NULL;
+ }
+
+ l_item->m_next = NULL;
+ l_item->m_data = p_data;
+ l_item->m_size = p_size;
+ return l_item;
+}
+
+static void freeResultList(NetlinkList *p_list)
+{
+ NetlinkList *l_cur;
+ while(p_list)
+ {
+ l_cur = p_list;
+ p_list = p_list->m_next;
+ uv__free(l_cur->m_data);
+ uv__free(l_cur);
+ }
+}
+
+static NetlinkList *getResultList(int p_socket, int p_request)
+{
+ int l_size;
+ int l_done;
+ NetlinkList *l_list;
+ NetlinkList *l_end;
+
+ if(netlink_send(p_socket, p_request) < 0)
+ {
+ return NULL;
+ }
+
+ l_list = NULL;
+ l_end = NULL;
+
+ l_done = 0;
+ while(!l_done)
+ {
+ NetlinkList *l_item;
+
+ struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
+ /* Error */
+ if(!l_hdr)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+
+ l_item = newListItem(l_hdr, l_size);
+ if (!l_item)
+ {
+ freeResultList(l_list);
+ return NULL;
+ }
+ if(!l_list)
+ {
+ l_list = l_item;
+ }
+ else
+ {
+ l_end->m_next = l_item;
+ }
+ l_end = l_item;
+ }
+ return l_list;
+}
+
+static size_t maxSize(size_t a, size_t b)
+{
+ return (a > b ? a : b);
+}
+
+static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ case AF_PACKET:
+ return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
+ default:
+ return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
+ }
+}
+
+static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
+{
+ switch(p_family)
+ {
+ case AF_INET:
+ memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
+ break;
+ case AF_INET6:
+ memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
+ break;
+ case AF_PACKET:
+ memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
+ ((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
+ break;
+ default:
+ memcpy(p_dest->sa_data, p_data, p_size);
+ break;
+ }
+ p_dest->sa_family = p_family;
+}
+
+static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
+{
+ if(!*p_resultList)
+ {
+ *p_resultList = p_entry;
+ }
+ else
+ {
+ struct ifaddrs *l_cur = *p_resultList;
+ while(l_cur->ifa_next)
+ {
+ l_cur = l_cur->ifa_next;
+ }
+ l_cur->ifa_next = p_entry;
+ }
+}
+
+static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
+{
+ struct ifaddrs *l_entry;
+
+ char *l_index;
+ char *l_name;
+ char *l_addr;
+ char *l_data;
+
+ struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+ size_t l_dataSize = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ struct rtattr *l_rta;
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
+ break;
+ case IFLA_IFNAME:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ case IFLA_STATS:
+ l_dataSize += NLMSG_ALIGN(l_rtaSize);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = "";
+
+ l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_name = l_index + sizeof(int);
+ l_addr = l_name + l_nameSize;
+ l_data = l_addr + l_addrSize;
+
+ /* Save the interface index so we can look it up when handling the
+ * addresses.
+ */
+ memcpy(l_index, &l_info->ifi_index, sizeof(int));
+
+ l_entry->ifa_flags = l_info->ifi_flags;
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFLA_ADDRESS:
+ case IFLA_BROADCAST:
+ {
+ size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
+ makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ ((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
+ ((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
+ if(l_rta->rta_type == IFLA_ADDRESS)
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFLA_IFNAME:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ case IFLA_STATS:
+ memcpy(l_data, l_rtaData, l_rtaDataSize);
+ l_entry->ifa_data = l_data;
+ break;
+ default:
+ break;
+ }
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
+{
+ int l_num = 0;
+ struct ifaddrs *l_cur = *p_links;
+ while(l_cur && l_num < p_numLinks)
+ {
+ char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
+ int l_index;
+ memcpy(&l_index, l_indexPtr, sizeof(int));
+ if(l_index == p_index)
+ {
+ return l_cur;
+ }
+
+ l_cur = l_cur->ifa_next;
+ ++l_num;
+ }
+ return NULL;
+}
+
+static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
+ struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
+
+ size_t l_nameSize = 0;
+ size_t l_addrSize = 0;
+
+ int l_addedNetmask = 0;
+
+ size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ struct rtattr *l_rta;
+ struct ifaddrs *l_entry;
+
+ char *l_name;
+ char *l_addr;
+
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ if(l_info->ifa_family == AF_PACKET)
+ {
+ continue;
+ }
+
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_LOCAL:
+ if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
+ {
+ /* Make room for netmask */
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ l_addedNetmask = 1;
+ }
+ case IFA_BROADCAST:
+ l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
+ break;
+ case IFA_LABEL:
+ l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
+ break;
+ default:
+ break;
+ }
+ }
+
+ l_entry = uv__malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
+ if (l_entry == NULL)
+ {
+ return -1;
+ }
+ memset(l_entry, 0, sizeof(struct ifaddrs));
+ l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
+
+ l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
+ l_addr = l_name + l_nameSize;
+
+ l_entry->ifa_flags = l_info->ifa_flags;
+ if(l_interface)
+ {
+ l_entry->ifa_flags |= l_interface->ifa_flags;
+ }
+
+ l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
+ for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
+ {
+ void *l_rtaData = RTA_DATA(l_rta);
+ size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
+ switch(l_rta->rta_type)
+ {
+ case IFA_ADDRESS:
+ case IFA_BROADCAST:
+ case IFA_LOCAL:
+ {
+ size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
+ makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
+ if(l_info->ifa_family == AF_INET6)
+ {
+ if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
+ {
+ ((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
+ }
+ }
+
+ /* Apparently in a point-to-point network IFA_ADDRESS contains
+ * the dest address and IFA_LOCAL contains the local address
+ */
+ if(l_rta->rta_type == IFA_ADDRESS)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ }
+ else if(l_rta->rta_type == IFA_LOCAL)
+ {
+ if(l_entry->ifa_addr)
+ {
+ l_entry->ifa_dstaddr = l_entry->ifa_addr;
+ }
+ l_entry->ifa_addr = (struct sockaddr *)l_addr;
+ }
+ else
+ {
+ l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
+ }
+ l_addr += NLMSG_ALIGN(l_addrLen);
+ break;
+ }
+ case IFA_LABEL:
+ strncpy(l_name, l_rtaData, l_rtaDataSize);
+ l_name[l_rtaDataSize] = '\0';
+ l_entry->ifa_name = l_name;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
+ {
+ unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
+ unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
+ char l_mask[16] = {0};
+ unsigned i;
+ for(i=0; i<(l_prefix/8); ++i)
+ {
+ l_mask[i] = 0xff;
+ }
+ if(l_prefix % 8)
+ {
+ l_mask[i] = 0xff << (8 - (l_prefix % 8));
+ }
+
+ makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
+ l_entry->ifa_netmask = (struct sockaddr *)l_addr;
+ }
+
+ addToEnd(p_resultList, l_entry);
+ return 0;
+}
+
+static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
+{
+
+ int l_numLinks = 0;
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWLINK)
+ {
+ if(interpretLink(l_hdr, p_resultList) == -1)
+ {
+ return -1;
+ }
+ ++l_numLinks;
+ }
+ }
+ }
+ return l_numLinks;
+}
+
+static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
+{
+ pid_t l_pid = getpid();
+ for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
+ {
+ unsigned int l_nlsize = p_netlinkList->m_size;
+ struct nlmsghdr *l_hdr;
+ for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
+ {
+ if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
+ {
+ continue;
+ }
+
+ if(l_hdr->nlmsg_type == NLMSG_DONE)
+ {
+ break;
+ }
+
+ if(l_hdr->nlmsg_type == RTM_NEWADDR)
+ {
+ if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
+ {
+ return -1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+ int l_socket;
+ int l_result;
+ int l_numLinks;
+ NetlinkList *l_linkResults;
+ NetlinkList *l_addrResults;
+
+ if(!ifap)
+ {
+ return -1;
+ }
+ *ifap = NULL;
+
+ l_socket = netlink_socket();
+ if(l_socket < 0)
+ {
+ return -1;
+ }
+
+ l_linkResults = getResultList(l_socket, RTM_GETLINK);
+ if(!l_linkResults)
+ {
+ close(l_socket);
+ return -1;
+ }
+
+ l_addrResults = getResultList(l_socket, RTM_GETADDR);
+ if(!l_addrResults)
+ {
+ close(l_socket);
+ freeResultList(l_linkResults);
+ return -1;
+ }
+
+ l_result = 0;
+ l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
+ if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
+ {
+ l_result = -1;
+ }
+
+ freeResultList(l_linkResults);
+ freeResultList(l_addrResults);
+ close(l_socket);
+ return l_result;
+}
+
+void freeifaddrs(struct ifaddrs *ifa)
+{
+ struct ifaddrs *l_cur;
+ while(ifa)
+ {
+ l_cur = ifa;
+ ifa = ifa->ifa_next;
+ uv__free(l_cur);
+ }
+}
diff --git a/Utilities/cmlibuv/src/unix/async.c b/Utilities/cmlibuv/src/unix/async.c
new file mode 100644
index 000000000..45c088ea1
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/async.c
@@ -0,0 +1,269 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* This file contains both the uv__async internal infrastructure and the
+ * user-facing uv_async_t functions.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "atomic-ops.h"
+
+#include <errno.h>
+#include <stdio.h> /* snprintf() */
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static void uv__async_send(uv_loop_t* loop);
+static int uv__async_start(uv_loop_t* loop);
+static int uv__async_eventfd(void);
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ int err;
+
+ err = uv__async_start(loop);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_ASYNC);
+ handle->async_cb = async_cb;
+ handle->pending = 0;
+
+ QUEUE_INSERT_TAIL(&loop->async_handles, &handle->queue);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ /* Do a cheap read first. */
+ if (ACCESS_ONCE(int, handle->pending) != 0)
+ return 0;
+
+ if (cmpxchgi(&handle->pending, 0, 1) == 0)
+ uv__async_send(handle->loop);
+
+ return 0;
+}
+
+
+void uv__async_close(uv_async_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+}
+
+
+static void uv__async_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ char buf[1024];
+ ssize_t r;
+ QUEUE queue;
+ QUEUE* q;
+ uv_async_t* h;
+
+ assert(w == &loop->async_io_watcher);
+
+ for (;;) {
+ r = read(w->fd, buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ QUEUE_MOVE(&loop->async_handles, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_async_t, queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->async_handles, q);
+
+ if (cmpxchgi(&h->pending, 1, 0) == 0)
+ continue;
+
+ if (h->async_cb == NULL)
+ continue;
+
+ h->async_cb(h);
+ }
+}
+
+
+static void uv__async_send(uv_loop_t* loop) {
+ const void* buf;
+ ssize_t len;
+ int fd;
+ int r;
+
+ buf = "";
+ len = 1;
+ fd = loop->async_wfd;
+
+#if defined(__linux__)
+ if (fd == -1) {
+ static const uint64_t val = 1;
+ buf = &val;
+ len = sizeof(val);
+ fd = loop->async_io_watcher.fd; /* eventfd */
+ }
+#endif
+
+ do
+ r = write(fd, buf, len);
+ while (r == -1 && errno == EINTR);
+
+ if (r == len)
+ return;
+
+ if (r == -1)
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return;
+
+ abort();
+}
+
+
+static int uv__async_start(uv_loop_t* loop) {
+ int pipefd[2];
+ int err;
+
+ if (loop->async_io_watcher.fd != -1)
+ return 0;
+
+ err = uv__async_eventfd();
+ if (err >= 0) {
+ pipefd[0] = err;
+ pipefd[1] = -1;
+ }
+ else if (err == -ENOSYS) {
+ err = uv__make_pipe(pipefd, UV__F_NONBLOCK);
+#if defined(__linux__)
+ /* Save a file descriptor by opening one of the pipe descriptors as
+ * read/write through the procfs. That file descriptor can then
+ * function as both ends of the pipe.
+ */
+ if (err == 0) {
+ char buf[32];
+ int fd;
+
+ snprintf(buf, sizeof(buf), "/proc/self/fd/%d", pipefd[0]);
+ fd = uv__open_cloexec(buf, O_RDWR);
+ if (fd >= 0) {
+ uv__close(pipefd[0]);
+ uv__close(pipefd[1]);
+ pipefd[0] = fd;
+ pipefd[1] = fd;
+ }
+ }
+#endif
+ }
+
+ if (err < 0)
+ return err;
+
+ uv__io_init(&loop->async_io_watcher, uv__async_io, pipefd[0]);
+ uv__io_start(loop, &loop->async_io_watcher, POLLIN);
+ loop->async_wfd = pipefd[1];
+
+ return 0;
+}
+
+
+int uv__async_fork(uv_loop_t* loop) {
+ if (loop->async_io_watcher.fd == -1) /* never started */
+ return 0;
+
+ uv__async_stop(loop);
+
+ return uv__async_start(loop);
+}
+
+
+void uv__async_stop(uv_loop_t* loop) {
+ if (loop->async_io_watcher.fd == -1)
+ return;
+
+ if (loop->async_wfd != -1) {
+ if (loop->async_wfd != loop->async_io_watcher.fd)
+ uv__close(loop->async_wfd);
+ loop->async_wfd = -1;
+ }
+
+ uv__io_stop(loop, &loop->async_io_watcher, POLLIN);
+ uv__close(loop->async_io_watcher.fd);
+ loop->async_io_watcher.fd = -1;
+}
+
+
+static int uv__async_eventfd(void) {
+#if defined(__linux__)
+ static int no_eventfd2;
+ static int no_eventfd;
+ int fd;
+
+ if (no_eventfd2)
+ goto skip_eventfd2;
+
+ fd = uv__eventfd2(0, UV__EFD_CLOEXEC | UV__EFD_NONBLOCK);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd2 = 1;
+
+skip_eventfd2:
+
+ if (no_eventfd)
+ goto skip_eventfd;
+
+ fd = uv__eventfd(0);
+ if (fd != -1) {
+ uv__cloexec(fd, 1);
+ uv__nonblock(fd, 1);
+ return fd;
+ }
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_eventfd = 1;
+
+skip_eventfd:
+
+#endif
+
+ return -ENOSYS;
+}
diff --git a/Utilities/cmlibuv/src/unix/atomic-ops.h b/Utilities/cmlibuv/src/unix/atomic-ops.h
new file mode 100644
index 000000000..9dac2557f
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/atomic-ops.h
@@ -0,0 +1,97 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_ATOMIC_OPS_H_
+#define UV_ATOMIC_OPS_H_
+
+#include "internal.h" /* UV_UNUSED */
+
+#if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+#include <atomic.h>
+#define __sync_val_compare_and_swap(p, o, n) atomic_cas_ptr(p, o, n)
+#endif
+
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval));
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval));
+UV_UNUSED(static void cpu_relax(void));
+
+/* Prefer hand-rolled assembly over the gcc builtins because the latter also
+ * issue full memory barriers.
+ */
+UV_UNUSED(static int cmpxchgi(int* ptr, int oldval, int newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ int out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile int*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const int out = (*(volatile int*) ptr);
+ __compare_and_swap(ptr, &oldval, newval);
+ return out;
+#elif defined(__MVS__)
+ unsigned int op4;
+ if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
+ (unsigned int*) ptr, *ptr, &op4))
+ return oldval;
+ else
+ return op4;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static long cmpxchgl(long* ptr, long oldval, long newval)) {
+#if defined(__i386__) || defined(__x86_64__)
+ long out;
+ __asm__ __volatile__ ("lock; cmpxchg %2, %1;"
+ : "=a" (out), "+m" (*(volatile long*) ptr)
+ : "r" (newval), "0" (oldval)
+ : "memory");
+ return out;
+#elif defined(_AIX) && defined(__xlC__)
+ const long out = (*(volatile int*) ptr);
+# if defined(__64BIT__)
+ __compare_and_swaplp(ptr, &oldval, newval);
+# else
+ __compare_and_swap(ptr, &oldval, newval);
+# endif /* if defined(__64BIT__) */
+ return out;
+#elif defined (__MVS__)
+#ifdef _LP64
+ unsigned long long op4;
+ if (__plo_CSSTGR(ptr, (unsigned long long*) &oldval, newval,
+ (unsigned long long*) ptr, *ptr, &op4))
+#else
+ unsigned long op4;
+ if (__plo_CSST(ptr, (unsigned int*) &oldval, newval,
+ (unsigned int*) ptr, *ptr, &op4))
+#endif
+ return oldval;
+ else
+ return op4;
+#else
+ return __sync_val_compare_and_swap(ptr, oldval, newval);
+#endif
+}
+
+UV_UNUSED(static void cpu_relax(void)) {
+#if defined(__i386__) || defined(__x86_64__)
+ __asm__ __volatile__ ("rep; nop"); /* a.k.a. PAUSE */
+#endif
+}
+
+#endif /* UV_ATOMIC_OPS_H_ */
diff --git a/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
new file mode 100644
index 000000000..414789451
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/bsd-ifaddrs.c
@@ -0,0 +1,139 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#if !defined(__CYGWIN__) && !defined(__MSYS__)
+#include <net/if_dl.h>
+#endif
+
+static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ return 1;
+ if (ent->ifa_addr == NULL)
+ return 1;
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__)
+ /*
+ * On BSD getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information.
+ */
+ if (ent->ifa_addr->sa_family == AF_LINK)
+ return 1;
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+ if (ent->ifa_addr->sa_family != PF_INET)
+ return 1;
+#endif
+ return 0;
+}
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ struct ifaddrs* addrs;
+ struct ifaddrs* ent;
+ uv_interface_address_t* address;
+ int i;
+
+ if (getifaddrs(&addrs) != 0)
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+
+ if (*addresses == NULL) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ address = *addresses;
+
+ for (i = 0; i < *count; i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+#if defined(__CYGWIN__) || defined(__MSYS__)
+ memset(address->phys_addr, 0, sizeof(address->phys_addr));
+#else
+ struct sockaddr_dl* sa_addr;
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+#endif
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/Utilities/cmlibuv/src/unix/core.c b/Utilities/cmlibuv/src/unix/core.c
new file mode 100644
index 000000000..30cdaef7b
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/core.c
@@ -0,0 +1,1326 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stddef.h> /* NULL */
+#include <stdio.h> /* printf */
+#include <stdlib.h>
+#include <string.h> /* strerror */
+#include <errno.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/param.h> /* MAXHOSTNAMELEN on Linux and the BSDs */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <limits.h> /* INT_MAX, PATH_MAX, IOV_MAX */
+#include <sys/uio.h> /* writev */
+#include <sys/resource.h> /* getrusage */
+#include <pwd.h>
+
+#ifdef __sun
+# include <netdb.h> /* MAXHOSTNAMELEN on Solaris */
+# include <sys/filio.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+#endif
+
+#ifdef __APPLE__
+# include <mach-o/dyld.h> /* _NSGetExecutablePath */
+# include <sys/filio.h>
+# if defined(O_CLOEXEC)
+# define UV__O_CLOEXEC O_CLOEXEC
+# endif
+#endif
+
+#if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__)
+# include <sys/sysctl.h>
+# include <sys/filio.h>
+# include <sys/wait.h>
+# define UV__O_CLOEXEC O_CLOEXEC
+# if defined(__FreeBSD__) && __FreeBSD__ >= 10
+# define uv__accept4 accept4
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+# define UV__SOCK_CLOEXEC SOCK_CLOEXEC
+# endif
+# if !defined(F_DUP2FD_CLOEXEC) && defined(_F_DUP2FD_CLOEXEC)
+# define F_DUP2FD_CLOEXEC _F_DUP2FD_CLOEXEC
+# endif
+#endif
+
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+# include <dlfcn.h> /* for dlsym */
+#endif
+
+#if defined(__MVS__)
+#include <sys/ioctl.h>
+#endif
+
+/* Fallback for the maximum hostname length */
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 256
+#endif
+
+static int uv__run_pending(uv_loop_t* loop);
+
+/* Verify that uv_buf_t is ABI-compatible with struct iovec. */
+STATIC_ASSERT(sizeof(uv_buf_t) == sizeof(struct iovec));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->base) ==
+ sizeof(((struct iovec*) 0)->iov_base));
+STATIC_ASSERT(sizeof(&((uv_buf_t*) 0)->len) ==
+ sizeof(((struct iovec*) 0)->iov_len));
+STATIC_ASSERT(offsetof(uv_buf_t, base) == offsetof(struct iovec, iov_base));
+STATIC_ASSERT(offsetof(uv_buf_t, len) == offsetof(struct iovec, iov_len));
+
+
+uint64_t uv_hrtime(void) {
+ return uv__hrtime(UV_CLOCK_PRECISE);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb close_cb) {
+ assert(!uv__is_closing(handle));
+
+ handle->flags |= UV_CLOSING;
+ handle->close_cb = close_cb;
+
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ uv__pipe_close((uv_pipe_t*)handle);
+ break;
+
+ case UV_TTY:
+ uv__stream_close((uv_stream_t*)handle);
+ break;
+
+ case UV_TCP:
+ uv__tcp_close((uv_tcp_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_close((uv_udp_t*)handle);
+ break;
+
+ case UV_PREPARE:
+ uv__prepare_close((uv_prepare_t*)handle);
+ break;
+
+ case UV_CHECK:
+ uv__check_close((uv_check_t*)handle);
+ break;
+
+ case UV_IDLE:
+ uv__idle_close((uv_idle_t*)handle);
+ break;
+
+ case UV_ASYNC:
+ uv__async_close((uv_async_t*)handle);
+ break;
+
+ case UV_TIMER:
+ uv__timer_close((uv_timer_t*)handle);
+ break;
+
+ case UV_PROCESS:
+ uv__process_close((uv_process_t*)handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv__fs_event_close((uv_fs_event_t*)handle);
+ break;
+
+ case UV_POLL:
+ uv__poll_close((uv_poll_t*)handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*)handle);
+ break;
+
+ case UV_SIGNAL:
+ uv__signal_close((uv_signal_t*) handle);
+ /* Signal handles may not be closed immediately. The signal code will */
+ /* itself close uv__make_close_pending whenever appropriate. */
+ return;
+
+ default:
+ assert(0);
+ }
+
+ uv__make_close_pending(handle);
+}
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int fd;
+ socklen_t len;
+
+ if (handle == NULL || value == NULL)
+ return -EINVAL;
+
+ if (handle->type == UV_TCP || handle->type == UV_NAMED_PIPE)
+ fd = uv__stream_fd((uv_stream_t*) handle);
+ else if (handle->type == UV_UDP)
+ fd = ((uv_udp_t *) handle)->io_watcher.fd;
+ else
+ return -ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(fd, SOL_SOCKET, optname, value, &len);
+ else
+ r = setsockopt(fd, SOL_SOCKET, optname, (const void*) value, len);
+
+ if (r < 0)
+ return -errno;
+
+ return 0;
+}
+
+void uv__make_close_pending(uv_handle_t* handle) {
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->next_closing = handle->loop->closing_handles;
+ handle->loop->closing_handles = handle;
+}
+
+int uv__getiovmax(void) {
+#if defined(IOV_MAX)
+ return IOV_MAX;
+#elif defined(_SC_IOV_MAX)
+ static int iovmax = -1;
+ if (iovmax == -1) {
+ iovmax = sysconf(_SC_IOV_MAX);
+ /* On some embedded devices (arm-linux-uclibc based ip camera),
+ * sysconf(_SC_IOV_MAX) can not get the correct value. The return
+ * value is -1 and the errno is EINPROGRESS. Degrade the value to 1.
+ */
+ if (iovmax == -1) iovmax = 1;
+ }
+ return iovmax;
+#else
+ return 1024;
+#endif
+}
+
+
+static void uv__finish_close(uv_handle_t* handle) {
+ /* Note: while the handle is in the UV_CLOSING state now, it's still possible
+ * for it to be active in the sense that uv__is_active() returns true.
+ * A good example is when the user calls uv_shutdown(), immediately followed
+ * by uv_close(). The handle is considered active at this point because the
+ * completion of the shutdown req is still pending.
+ */
+ assert(handle->flags & UV_CLOSING);
+ assert(!(handle->flags & UV_CLOSED));
+ handle->flags |= UV_CLOSED;
+
+ switch (handle->type) {
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ case UV_ASYNC:
+ case UV_TIMER:
+ case UV_PROCESS:
+ case UV_FS_EVENT:
+ case UV_FS_POLL:
+ case UV_POLL:
+ case UV_SIGNAL:
+ break;
+
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ case UV_TTY:
+ uv__stream_destroy((uv_stream_t*)handle);
+ break;
+
+ case UV_UDP:
+ uv__udp_finish_close((uv_udp_t*)handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+
+ uv__handle_unref(handle);
+ QUEUE_REMOVE(&handle->handle_queue);
+
+ if (handle->close_cb) {
+ handle->close_cb(handle);
+ }
+}
+
+
+static void uv__run_closing_handles(uv_loop_t* loop) {
+ uv_handle_t* p;
+ uv_handle_t* q;
+
+ p = loop->closing_handles;
+ loop->closing_handles = NULL;
+
+ while (p) {
+ q = p->next_closing;
+ uv__finish_close(p);
+ p = q;
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return uv__is_closing(handle);
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return loop->backend_fd;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->idle_handles))
+ return 0;
+
+ if (!QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ if (loop->closing_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return uv__has_active_handles(loop) ||
+ uv__has_active_reqs(loop) ||
+ loop->closing_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t* loop, uv_run_mode mode) {
+ int timeout;
+ int r;
+ int ran_pending;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv__update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ ran_pending = uv__run_pending(loop);
+ uv__run_idle(loop);
+ uv__run_prepare(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ uv__io_poll(loop, timeout);
+ uv__run_check(loop);
+ uv__run_closing_handles(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv__update_time(loop);
+ uv__run_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets gcc compile it to a conditional store. Avoids
+ * dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uv__update_time(loop);
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return uv__is_active(handle);
+}
+
+
+/* Open a socket in non-blocking close-on-exec mode, atomically if possible. */
+int uv__socket(int domain, int type, int protocol) {
+ int sockfd;
+ int err;
+
+#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
+ sockfd = socket(domain, type | SOCK_NONBLOCK | SOCK_CLOEXEC, protocol);
+ if (sockfd != -1)
+ return sockfd;
+
+ if (errno != EINVAL)
+ return -errno;
+#endif
+
+ sockfd = socket(domain, type, protocol);
+ if (sockfd == -1)
+ return -errno;
+
+ err = uv__nonblock(sockfd, 1);
+ if (err == 0)
+ err = uv__cloexec(sockfd, 1);
+
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+#if defined(SO_NOSIGPIPE)
+ {
+ int on = 1;
+ setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
+ }
+#endif
+
+ return sockfd;
+}
+
+/* get a file pointer to a file in read-only and close-on-exec mode */
+FILE* uv__open_file(const char* path) {
+ int fd;
+ FILE* fp;
+
+ fd = uv__open_cloexec(path, O_RDONLY);
+ if (fd < 0)
+ return NULL;
+
+ fp = fdopen(fd, "r");
+ if (fp == NULL)
+ uv__close(fd);
+
+ return fp;
+}
+
+
+int uv__accept(int sockfd) {
+ int peerfd;
+ int err;
+
+ assert(sockfd >= 0);
+
+ while (1) {
+#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD__ >= 10)
+ static int no_accept4;
+
+ if (no_accept4)
+ goto skip;
+
+ peerfd = uv__accept4(sockfd,
+ NULL,
+ NULL,
+ UV__SOCK_NONBLOCK|UV__SOCK_CLOEXEC);
+ if (peerfd != -1)
+ return peerfd;
+
+ if (errno == EINTR)
+ continue;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_accept4 = 1;
+skip:
+#endif
+
+ peerfd = accept(sockfd, NULL, NULL);
+ if (peerfd == -1) {
+ if (errno == EINTR)
+ continue;
+ return -errno;
+ }
+
+ err = uv__cloexec(peerfd, 1);
+ if (err == 0)
+ err = uv__nonblock(peerfd, 1);
+
+ if (err) {
+ uv__close(peerfd);
+ return err;
+ }
+
+ return peerfd;
+ }
+}
+
+
+int uv__close_nocheckstdio(int fd) {
+ int saved_errno;
+ int rc;
+
+ assert(fd > -1); /* Catch uninitialized io_watcher.fd bugs. */
+
+ saved_errno = errno;
+ rc = close(fd);
+ if (rc == -1) {
+ rc = -errno;
+ if (rc == -EINTR || rc == -EINPROGRESS)
+ rc = 0; /* The close is in progress, not an error. */
+ errno = saved_errno;
+ }
+
+ return rc;
+}
+
+
+int uv__close(int fd) {
+ assert(fd > STDERR_FILENO); /* Catch stdio close bugs. */
+#if defined(__MVS__)
+ epoll_file_close(fd);
+#endif
+ return uv__close_nocheckstdio(fd);
+}
+
+
+int uv__nonblock_ioctl(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, FIONBIO, &set);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+#if !defined(__CYGWIN__) && !defined(__MSYS__)
+int uv__cloexec_ioctl(int fd, int set) {
+ int r;
+
+ do
+ r = ioctl(fd, set ? FIOCLEX : FIONCLEX);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+#endif
+
+
+int uv__nonblock_fcntl(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFL);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & O_NONBLOCK) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | O_NONBLOCK;
+ else
+ flags = r & ~O_NONBLOCK;
+
+ do
+ r = fcntl(fd, F_SETFL, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__cloexec_fcntl(int fd, int set) {
+ int flags;
+ int r;
+
+ do
+ r = fcntl(fd, F_GETFD);
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1)
+ return -errno;
+
+ /* Bail out now if already set/clear. */
+ if (!!(r & FD_CLOEXEC) == !!set)
+ return 0;
+
+ if (set)
+ flags = r | FD_CLOEXEC;
+ else
+ flags = r & ~FD_CLOEXEC;
+
+ do
+ r = fcntl(fd, F_SETFD, flags);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+
+/* This function is not execve-safe, there is a race window
+ * between the call to dup() and fcntl(FD_CLOEXEC).
+ */
+int uv__dup(int fd) {
+ int err;
+
+ fd = dup(fd);
+
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+ssize_t uv__recvmsg(int fd, struct msghdr* msg, int flags) {
+ struct cmsghdr* cmsg;
+ ssize_t rc;
+ int* pfd;
+ int* end;
+#if defined(__linux__)
+ static int no_msg_cmsg_cloexec;
+ if (no_msg_cmsg_cloexec == 0) {
+ rc = recvmsg(fd, msg, flags | 0x40000000); /* MSG_CMSG_CLOEXEC */
+ if (rc != -1)
+ return rc;
+ if (errno != EINVAL)
+ return -errno;
+ rc = recvmsg(fd, msg, flags);
+ if (rc == -1)
+ return -errno;
+ no_msg_cmsg_cloexec = 1;
+ } else {
+ rc = recvmsg(fd, msg, flags);
+ }
+#else
+ rc = recvmsg(fd, msg, flags);
+#endif
+ if (rc == -1)
+ return -errno;
+ if (msg->msg_controllen == 0)
+ return rc;
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg))
+ if (cmsg->cmsg_type == SCM_RIGHTS)
+ for (pfd = (int*) CMSG_DATA(cmsg),
+ end = (int*) ((char*) cmsg + cmsg->cmsg_len);
+ pfd < end;
+ pfd += 1)
+ uv__cloexec(*pfd, 1);
+ return rc;
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ if (buffer == NULL || size == NULL)
+ return -EINVAL;
+
+ if (getcwd(buffer, *size) == NULL)
+ return -errno;
+
+ *size = strlen(buffer);
+ if (*size > 1 && buffer[*size - 1] == '/') {
+ buffer[*size-1] = '\0';
+ (*size)--;
+ }
+
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ if (chdir(dir))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv_disable_stdio_inheritance(void) {
+ int fd;
+
+ /* Set the CLOEXEC flag on all open descriptors. Unconditionally try the
+ * first 16 file descriptors. After that, bail out after the first error.
+ */
+ for (fd = 0; ; fd++)
+ if (uv__cloexec(fd, 1) && fd > 15)
+ break;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ int fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ case UV_NAMED_PIPE:
+ case UV_TTY:
+ fd_out = uv__stream_fd((uv_stream_t*) handle);
+ break;
+
+ case UV_UDP:
+ fd_out = ((uv_udp_t *) handle)->io_watcher.fd;
+ break;
+
+ case UV_POLL:
+ fd_out = ((uv_poll_t *) handle)->io_watcher.fd;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (uv__is_closing(handle) || fd_out == -1)
+ return -EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+static int uv__run_pending(uv_loop_t* loop) {
+ QUEUE* q;
+ QUEUE pq;
+ uv__io_t* w;
+
+ if (QUEUE_EMPTY(&loop->pending_queue))
+ return 0;
+
+ QUEUE_MOVE(&loop->pending_queue, &pq);
+
+ while (!QUEUE_EMPTY(&pq)) {
+ q = QUEUE_HEAD(&pq);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+ w = QUEUE_DATA(q, uv__io_t, pending_queue);
+ w->cb(loop, w, POLLOUT);
+ }
+
+ return 1;
+}
+
+
+static unsigned int next_power_of_two(unsigned int val) {
+ val -= 1;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val += 1;
+ return val;
+}
+
+static void maybe_resize(uv_loop_t* loop, unsigned int len) {
+ uv__io_t** watchers;
+ void* fake_watcher_list;
+ void* fake_watcher_count;
+ unsigned int nwatchers;
+ unsigned int i;
+
+ if (len <= loop->nwatchers)
+ return;
+
+ /* Preserve fake watcher list and count at the end of the watchers */
+ if (loop->watchers != NULL) {
+ fake_watcher_list = loop->watchers[loop->nwatchers];
+ fake_watcher_count = loop->watchers[loop->nwatchers + 1];
+ } else {
+ fake_watcher_list = NULL;
+ fake_watcher_count = NULL;
+ }
+
+ nwatchers = next_power_of_two(len + 2) - 2;
+ watchers = uv__realloc(loop->watchers,
+ (nwatchers + 2) * sizeof(loop->watchers[0]));
+
+ if (watchers == NULL)
+ abort();
+ for (i = loop->nwatchers; i < nwatchers; i++)
+ watchers[i] = NULL;
+ watchers[nwatchers] = fake_watcher_list;
+ watchers[nwatchers + 1] = fake_watcher_count;
+
+ loop->watchers = watchers;
+ loop->nwatchers = nwatchers;
+}
+
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd) {
+ assert(cb != NULL);
+ assert(fd >= -1);
+ QUEUE_INIT(&w->pending_queue);
+ QUEUE_INIT(&w->watcher_queue);
+ w->cb = cb;
+ w->fd = fd;
+ w->events = 0;
+ w->pevents = 0;
+
+#if defined(UV_HAVE_KQUEUE)
+ w->rcount = 0;
+ w->wcount = 0;
+#endif /* defined(UV_HAVE_KQUEUE) */
+}
+
+
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 != events);
+ assert(w->fd >= 0);
+ assert(w->fd < INT_MAX);
+
+ w->pevents |= events;
+ maybe_resize(loop, w->fd + 1);
+
+#if !defined(__sun)
+ /* The event ports backend needs to rearm all file descriptors on each and
+ * every tick of the event loop but the other backends allow us to
+ * short-circuit here if the event mask is unchanged.
+ */
+ if (w->events == w->pevents)
+ return;
+#endif
+
+ if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+
+ if (loop->watchers[w->fd] == NULL) {
+ loop->watchers[w->fd] = w;
+ loop->nfds++;
+ }
+}
+
+
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 != events);
+
+ if (w->fd == -1)
+ return;
+
+ assert(w->fd >= 0);
+
+ /* Happens when uv__io_stop() is called on a handle that was never started. */
+ if ((unsigned) w->fd >= loop->nwatchers)
+ return;
+
+ w->pevents &= ~events;
+
+ if (w->pevents == 0) {
+ QUEUE_REMOVE(&w->watcher_queue);
+ QUEUE_INIT(&w->watcher_queue);
+
+ if (loop->watchers[w->fd] != NULL) {
+ assert(loop->watchers[w->fd] == w);
+ assert(loop->nfds > 0);
+ loop->watchers[w->fd] = NULL;
+ loop->nfds--;
+ w->events = 0;
+ }
+ }
+ else if (QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+}
+
+
+void uv__io_close(uv_loop_t* loop, uv__io_t* w) {
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ QUEUE_REMOVE(&w->pending_queue);
+
+ /* Remove stale events for this file descriptor */
+ uv__platform_invalidate_fd(loop, w->fd);
+}
+
+
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w) {
+ if (QUEUE_EMPTY(&w->pending_queue))
+ QUEUE_INSERT_TAIL(&loop->pending_queue, &w->pending_queue);
+}
+
+
+int uv__io_active(const uv__io_t* w, unsigned int events) {
+ assert(0 == (events & ~(POLLIN | POLLOUT | UV__POLLRDHUP)));
+ assert(0 != events);
+ return 0 != (w->pevents & events);
+}
+
+
+int uv_getrusage(uv_rusage_t* rusage) {
+ struct rusage usage;
+
+ if (getrusage(RUSAGE_SELF, &usage))
+ return -errno;
+
+ rusage->ru_utime.tv_sec = usage.ru_utime.tv_sec;
+ rusage->ru_utime.tv_usec = usage.ru_utime.tv_usec;
+
+ rusage->ru_stime.tv_sec = usage.ru_stime.tv_sec;
+ rusage->ru_stime.tv_usec = usage.ru_stime.tv_usec;
+
+#if !defined(__MVS__)
+ rusage->ru_maxrss = usage.ru_maxrss;
+ rusage->ru_ixrss = usage.ru_ixrss;
+ rusage->ru_idrss = usage.ru_idrss;
+ rusage->ru_isrss = usage.ru_isrss;
+ rusage->ru_minflt = usage.ru_minflt;
+ rusage->ru_majflt = usage.ru_majflt;
+ rusage->ru_nswap = usage.ru_nswap;
+ rusage->ru_inblock = usage.ru_inblock;
+ rusage->ru_oublock = usage.ru_oublock;
+ rusage->ru_msgsnd = usage.ru_msgsnd;
+ rusage->ru_msgrcv = usage.ru_msgrcv;
+ rusage->ru_nsignals = usage.ru_nsignals;
+ rusage->ru_nvcsw = usage.ru_nvcsw;
+ rusage->ru_nivcsw = usage.ru_nivcsw;
+#endif
+
+ return 0;
+}
+
+
+int uv__open_cloexec(const char* path, int flags) {
+ int err;
+ int fd;
+
+#if defined(UV__O_CLOEXEC)
+ static int no_cloexec;
+
+ if (!no_cloexec) {
+ fd = open(path, flags | UV__O_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != EINVAL)
+ return -errno;
+
+ /* O_CLOEXEC not supported. */
+ no_cloexec = 1;
+ }
+#endif
+
+ fd = open(path, flags);
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+int uv__dup2_cloexec(int oldfd, int newfd) {
+ int r;
+#if defined(__FreeBSD__) && __FreeBSD__ >= 10
+ r = dup3(oldfd, newfd, O_CLOEXEC);
+ if (r == -1)
+ return -errno;
+ return r;
+#elif defined(__FreeBSD__) && defined(F_DUP2FD_CLOEXEC)
+ r = fcntl(oldfd, F_DUP2FD_CLOEXEC, newfd);
+ if (r != -1)
+ return r;
+ if (errno != EINVAL)
+ return -errno;
+ /* Fall through. */
+#elif defined(__linux__)
+ static int no_dup3;
+ if (!no_dup3) {
+ do
+ r = uv__dup3(oldfd, newfd, UV__O_CLOEXEC);
+ while (r == -1 && errno == EBUSY);
+ if (r != -1)
+ return r;
+ if (errno != ENOSYS)
+ return -errno;
+ /* Fall through. */
+ no_dup3 = 1;
+ }
+#endif
+ {
+ int err;
+ do
+ r = dup2(oldfd, newfd);
+#if defined(__linux__)
+ while (r == -1 && errno == EBUSY);
+#else
+ while (0); /* Never retry. */
+#endif
+
+ if (r == -1)
+ return -errno;
+
+ err = uv__cloexec(newfd, 1);
+ if (err) {
+ uv__close(newfd);
+ return err;
+ }
+
+ return r;
+ }
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ uv_passwd_t pwd;
+ char* buf;
+ size_t len;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ /* Check if the HOME environment variable is set first */
+ buf = getenv("HOME");
+
+ if (buf != NULL) {
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len + 1;
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ *size = len;
+
+ return 0;
+ }
+
+ /* HOME is not set, so call uv__getpwuid_r() */
+ r = uv__getpwuid_r(&pwd);
+
+ if (r != 0) {
+ return r;
+ }
+
+ len = strlen(pwd.homedir);
+
+ if (len >= *size) {
+ *size = len + 1;
+ uv_os_free_passwd(&pwd);
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, pwd.homedir, len + 1);
+ *size = len;
+ uv_os_free_passwd(&pwd);
+
+ return 0;
+}
+
+
+int uv_os_tmpdir(char* buffer, size_t* size) {
+ const char* buf;
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+#define CHECK_ENV_VAR(name) \
+ do { \
+ buf = getenv(name); \
+ if (buf != NULL) \
+ goto return_buffer; \
+ } \
+ while (0)
+
+ /* Check the TMPDIR, TMP, TEMP, and TEMPDIR environment variables in order */
+ CHECK_ENV_VAR("TMPDIR");
+ CHECK_ENV_VAR("TMP");
+ CHECK_ENV_VAR("TEMP");
+ CHECK_ENV_VAR("TEMPDIR");
+
+#undef CHECK_ENV_VAR
+
+ /* No temp environment variables defined */
+ #if defined(__ANDROID__)
+ buf = "/data/local/tmp";
+ #else
+ buf = "/tmp";
+ #endif
+
+return_buffer:
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len + 1;
+ return -ENOBUFS;
+ }
+
+ /* The returned directory should not have a trailing slash. */
+ if (len > 1 && buf[len - 1] == '/') {
+ len--;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ buffer[len] = '\0';
+ *size = len;
+
+ return 0;
+}
+
+
+int uv__getpwuid_r(uv_passwd_t* pwd) {
+ struct passwd pw;
+ struct passwd* result;
+ char* buf;
+ uid_t uid;
+ size_t bufsize;
+ size_t name_size;
+ size_t homedir_size;
+ size_t shell_size;
+ long initsize;
+ int r;
+#if defined(__ANDROID_API__) && __ANDROID_API__ < 21
+ int (*getpwuid_r)(uid_t, struct passwd*, char*, size_t, struct passwd**);
+
+ getpwuid_r = dlsym(RTLD_DEFAULT, "getpwuid_r");
+ if (getpwuid_r == NULL)
+ return -ENOSYS;
+#endif
+
+ if (pwd == NULL)
+ return -EINVAL;
+
+ initsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if (initsize <= 0)
+ bufsize = 4096;
+ else
+ bufsize = (size_t) initsize;
+
+ uid = geteuid();
+ buf = NULL;
+
+ for (;;) {
+ uv__free(buf);
+ buf = uv__malloc(bufsize);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ r = getpwuid_r(uid, &pw, buf, bufsize, &result);
+
+ if (r != ERANGE)
+ break;
+
+ bufsize *= 2;
+ }
+
+ if (r != 0) {
+ uv__free(buf);
+ return -r;
+ }
+
+ if (result == NULL) {
+ uv__free(buf);
+ return -ENOENT;
+ }
+
+ /* Allocate memory for the username, shell, and home directory */
+ name_size = strlen(pw.pw_name) + 1;
+ homedir_size = strlen(pw.pw_dir) + 1;
+ shell_size = strlen(pw.pw_shell) + 1;
+ pwd->username = uv__malloc(name_size + homedir_size + shell_size);
+
+ if (pwd->username == NULL) {
+ uv__free(buf);
+ return -ENOMEM;
+ }
+
+ /* Copy the username */
+ memcpy(pwd->username, pw.pw_name, name_size);
+
+ /* Copy the home directory */
+ pwd->homedir = pwd->username + name_size;
+ memcpy(pwd->homedir, pw.pw_dir, homedir_size);
+
+ /* Copy the shell */
+ pwd->shell = pwd->homedir + homedir_size;
+ memcpy(pwd->shell, pw.pw_shell, shell_size);
+
+ /* Copy the uid and gid */
+ pwd->uid = pw.pw_uid;
+ pwd->gid = pw.pw_gid;
+
+ uv__free(buf);
+
+ return 0;
+}
+
+
+void uv_os_free_passwd(uv_passwd_t* pwd) {
+ if (pwd == NULL)
+ return;
+
+ /*
+ The memory for name, shell, and homedir are allocated in a single
+ uv__malloc() call. The base of the pointer is stored in pwd->username, so
+ that is the field that needs to be freed.
+ */
+ uv__free(pwd->username);
+ pwd->username = NULL;
+ pwd->shell = NULL;
+ pwd->homedir = NULL;
+}
+
+
+int uv_os_get_passwd(uv_passwd_t* pwd) {
+ return uv__getpwuid_r(pwd);
+}
+
+
+int uv_translate_sys_error(int sys_errno) {
+ /* If < 0 then it's already a libuv error. */
+ return sys_errno <= 0 ? sys_errno : -sys_errno;
+}
+
+
+int uv_os_getenv(const char* name, char* buffer, size_t* size) {
+ char* var;
+ size_t len;
+
+ if (name == NULL || buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ var = getenv(name);
+
+ if (var == NULL)
+ return -ENOENT;
+
+ len = strlen(var);
+
+ if (len >= *size) {
+ *size = len + 1;
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, var, len + 1);
+ *size = len;
+
+ return 0;
+}
+
+
+int uv_os_setenv(const char* name, const char* value) {
+ if (name == NULL || value == NULL)
+ return -EINVAL;
+
+ if (setenv(name, value, 1) != 0)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv_os_unsetenv(const char* name) {
+ if (unsetenv(name) != 0)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv_os_gethostname(char* buffer, size_t* size) {
+ /*
+ On some platforms, if the input buffer is not large enough, gethostname()
+ succeeds, but truncates the result. libuv can detect this and return ENOBUFS
+ instead by creating a large enough buffer and comparing the hostname length
+ to the size input.
+ */
+ char buf[MAXHOSTNAMELEN + 1];
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ if (gethostname(buf, sizeof(buf)) != 0)
+ return -errno;
+
+ buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len + 1;
+ return -ENOBUFS;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ *size = len;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/cygwin.c b/Utilities/cmlibuv/src/unix/cygwin.c
new file mode 100644
index 000000000..5a887dd4c
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/cygwin.c
@@ -0,0 +1,54 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <sys/sysinfo.h>
+#include <unistd.h>
+
+int uv_uptime(double* uptime) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) < 0)
+ return -errno;
+
+ *uptime = info.uptime;
+ return 0;
+}
+
+int uv_resident_set_memory(size_t* rss) {
+ /* FIXME: read /proc/meminfo? */
+ *rss = 0;
+ return UV_ENOSYS;
+}
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ /* FIXME: read /proc/stat? */
+ *cpu_infos = NULL;
+ *count = 0;
+ return UV_ENOSYS;
+}
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ (void)cpu_infos;
+ (void)count;
+}
diff --git a/Utilities/cmlibuv/src/unix/darwin-proctitle.c b/Utilities/cmlibuv/src/unix/darwin-proctitle.c
new file mode 100644
index 000000000..114231160
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/darwin-proctitle.c
@@ -0,0 +1,206 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <TargetConditionals.h>
+
+#if !TARGET_OS_IPHONE
+# include <CoreFoundation/CoreFoundation.h>
+# include <ApplicationServices/ApplicationServices.h>
+#endif
+
+
+static int uv__pthread_setname_np(const char* name) {
+ int (*dynamic_pthread_setname_np)(const char* name);
+ char namebuf[64]; /* MAXTHREADNAMESIZE */
+ int err;
+
+ /* pthread_setname_np() first appeared in OS X 10.6 and iOS 3.2. */
+ *(void **)(&dynamic_pthread_setname_np) =
+ dlsym(RTLD_DEFAULT, "pthread_setname_np");
+
+ if (dynamic_pthread_setname_np == NULL)
+ return -ENOSYS;
+
+ strncpy(namebuf, name, sizeof(namebuf) - 1);
+ namebuf[sizeof(namebuf) - 1] = '\0';
+
+ err = dynamic_pthread_setname_np(namebuf);
+ if (err)
+ return -err;
+
+ return 0;
+}
+
+
+int uv__set_process_title(const char* title) {
+#if TARGET_OS_IPHONE
+ return uv__pthread_setname_np(title);
+#else
+ CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
+ const char*,
+ CFStringEncoding);
+ CFBundleRef (*pCFBundleGetBundleWithIdentifier)(CFStringRef);
+ void *(*pCFBundleGetDataPointerForName)(CFBundleRef, CFStringRef);
+ void *(*pCFBundleGetFunctionPointerForName)(CFBundleRef, CFStringRef);
+ CFTypeRef (*pLSGetCurrentApplicationASN)(void);
+ OSStatus (*pLSSetApplicationInformationItem)(int,
+ CFTypeRef,
+ CFStringRef,
+ CFStringRef,
+ CFDictionaryRef*);
+ void* application_services_handle;
+ void* core_foundation_handle;
+ CFBundleRef launch_services_bundle;
+ CFStringRef* display_name_key;
+ CFDictionaryRef (*pCFBundleGetInfoDictionary)(CFBundleRef);
+ CFBundleRef (*pCFBundleGetMainBundle)(void);
+ CFBundleRef hi_services_bundle;
+ OSStatus (*pSetApplicationIsDaemon)(int);
+ CFDictionaryRef (*pLSApplicationCheckIn)(int, CFDictionaryRef);
+ void (*pLSSetApplicationLaunchServicesServerConnectionStatus)(uint64_t,
+ void*);
+ CFTypeRef asn;
+ int err;
+
+ err = -ENOENT;
+ application_services_handle = dlopen("/System/Library/Frameworks/"
+ "ApplicationServices.framework/"
+ "Versions/A/ApplicationServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+
+ if (application_services_handle == NULL || core_foundation_handle == NULL)
+ goto out;
+
+ *(void **)(&pCFStringCreateWithCString) =
+ dlsym(core_foundation_handle, "CFStringCreateWithCString");
+ *(void **)(&pCFBundleGetBundleWithIdentifier) =
+ dlsym(core_foundation_handle, "CFBundleGetBundleWithIdentifier");
+ *(void **)(&pCFBundleGetDataPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetDataPointerForName");
+ *(void **)(&pCFBundleGetFunctionPointerForName) =
+ dlsym(core_foundation_handle, "CFBundleGetFunctionPointerForName");
+
+ if (pCFStringCreateWithCString == NULL ||
+ pCFBundleGetBundleWithIdentifier == NULL ||
+ pCFBundleGetDataPointerForName == NULL ||
+ pCFBundleGetFunctionPointerForName == NULL) {
+ goto out;
+ }
+
+#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)
+
+ launch_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.LaunchServices"));
+
+ if (launch_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pLSGetCurrentApplicationASN) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSGetCurrentApplicationASN"));
+
+ if (pLSGetCurrentApplicationASN == NULL)
+ goto out;
+
+ *(void **)(&pLSSetApplicationInformationItem) =
+ pCFBundleGetFunctionPointerForName(launch_services_bundle,
+ S("_LSSetApplicationInformationItem"));
+
+ if (pLSSetApplicationInformationItem == NULL)
+ goto out;
+
+ display_name_key = pCFBundleGetDataPointerForName(launch_services_bundle,
+ S("_kLSDisplayNameKey"));
+
+ if (display_name_key == NULL || *display_name_key == NULL)
+ goto out;
+
+ *(void **)(&pCFBundleGetInfoDictionary) = dlsym(core_foundation_handle,
+ "CFBundleGetInfoDictionary");
+ *(void **)(&pCFBundleGetMainBundle) = dlsym(core_foundation_handle,
+ "CFBundleGetMainBundle");
+ if (pCFBundleGetInfoDictionary == NULL || pCFBundleGetMainBundle == NULL)
+ goto out;
+
+ /* Black 10.9 magic, to remove (Not responding) mark in Activity Monitor */
+ hi_services_bundle =
+ pCFBundleGetBundleWithIdentifier(S("com.apple.HIServices"));
+ err = -ENOENT;
+ if (hi_services_bundle == NULL)
+ goto out;
+
+ *(void **)(&pSetApplicationIsDaemon) = pCFBundleGetFunctionPointerForName(
+ hi_services_bundle,
+ S("SetApplicationIsDaemon"));
+ *(void **)(&pLSApplicationCheckIn) = pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSApplicationCheckIn"));
+ *(void **)(&pLSSetApplicationLaunchServicesServerConnectionStatus) =
+ pCFBundleGetFunctionPointerForName(
+ launch_services_bundle,
+ S("_LSSetApplicationLaunchServicesServerConnectionStatus"));
+ if (pSetApplicationIsDaemon == NULL ||
+ pLSApplicationCheckIn == NULL ||
+ pLSSetApplicationLaunchServicesServerConnectionStatus == NULL) {
+ goto out;
+ }
+
+ if (pSetApplicationIsDaemon(1) != noErr)
+ goto out;
+
+ pLSSetApplicationLaunchServicesServerConnectionStatus(0, NULL);
+
+ /* Check into process manager?! */
+ pLSApplicationCheckIn(-2,
+ pCFBundleGetInfoDictionary(pCFBundleGetMainBundle()));
+
+ asn = pLSGetCurrentApplicationASN();
+
+ err = -EINVAL;
+ if (pLSSetApplicationInformationItem(-2, /* Magic value. */
+ asn,
+ *display_name_key,
+ S(title),
+ NULL) != noErr) {
+ goto out;
+ }
+
+ uv__pthread_setname_np(title); /* Don't care if it fails. */
+ err = 0;
+
+out:
+ if (core_foundation_handle != NULL)
+ dlclose(core_foundation_handle);
+
+ if (application_services_handle != NULL)
+ dlclose(application_services_handle);
+
+ return err;
+#endif /* !TARGET_OS_IPHONE */
+}
diff --git a/Utilities/cmlibuv/src/unix/darwin.c b/Utilities/cmlibuv/src/unix/darwin.c
new file mode 100644
index 000000000..df6dd1c61
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/darwin.c
@@ -0,0 +1,231 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach-o/dyld.h> /* _NSGetExecutablePath */
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <unistd.h> /* sysconf */
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->cf_state = NULL;
+
+ if (uv__kqueue_init(loop))
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ uv__fsevents_loop_delete(loop);
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static mach_timebase_info_data_t info;
+
+ if ((ACCESS_ONCE(uint32_t, info.numer) == 0 ||
+ ACCESS_ONCE(uint32_t, info.denom) == 0) &&
+ mach_timebase_info(&info) != KERN_SUCCESS)
+ abort();
+
+ return mach_absolute_time() * info.numer / info.denom;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ /* realpath(exepath) may be > PATH_MAX so double it to be on the safe side. */
+ char abspath[PATH_MAX * 2 + 1];
+ char exepath[PATH_MAX + 1];
+ uint32_t exepath_size;
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ exepath_size = sizeof(exepath);
+ if (_NSGetExecutablePath(exepath, &exepath_size))
+ return -EIO;
+
+ if (realpath(exepath, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+ if (abspath_size == 0)
+ return -EIO;
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ vm_statistics_data_t info;
+ mach_msg_type_number_t count = sizeof(info) / sizeof(integer_t);
+
+ if (host_statistics(mach_host_self(), HOST_VM_INFO,
+ (host_info_t)&info, &count) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ return (uint64_t) info.free_count * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_MEMSIZE};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ mach_msg_type_number_t count;
+ task_basic_info_data_t info;
+ kern_return_t err;
+
+ count = TASK_BASIC_INFO_COUNT;
+ err = task_info(mach_task_self(),
+ TASK_BASIC_INFO,
+ (task_info_t) &info,
+ &count);
+ (void) &err;
+ /* task_info(TASK_BASIC_INFO) cannot really fail. Anything other than
+ * KERN_SUCCESS implies a libuv bug.
+ */
+ assert(err == KERN_SUCCESS);
+ *rss = info.resident_size;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+ *uptime = now - info.tv_sec;
+
+ return 0;
+}
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks);
+ char model[512];
+ uint64_t cpuspeed;
+ size_t size;
+ unsigned int i;
+ natural_t numcpus;
+ mach_msg_type_number_t msg_type;
+ processor_cpu_load_info_data_t *info;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu.brand_string", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.cpufrequency", &cpuspeed, &size, NULL, 0))
+ return -errno;
+
+ if (host_processor_info(mach_host_self(), PROCESSOR_CPU_LOAD_INFO, &numcpus,
+ (processor_info_array_t*)&info,
+ &msg_type) != KERN_SUCCESS) {
+ return -EINVAL; /* FIXME(bnoordhuis) Translate error. */
+ }
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+ return -ENOMEM;
+ }
+
+ *count = numcpus;
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[i].cpu_ticks[0]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[i].cpu_ticks[3]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[i].cpu_ticks[1]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[i].cpu_ticks[2]) * multiplier;
+ cpu_info->cpu_times.irq = 0;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed/1000000;
+ }
+ vm_deallocate(mach_task_self(), (vm_address_t)info, msg_type);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
diff --git a/Utilities/cmlibuv/src/unix/dl.c b/Utilities/cmlibuv/src/unix/dl.c
new file mode 100644
index 000000000..fc1c052bb
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/dl.c
@@ -0,0 +1,80 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <string.h>
+#include <locale.h>
+
+static int uv__dlerror(uv_lib_t* lib);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ dlerror(); /* Reset error status. */
+ lib->errmsg = NULL;
+ lib->handle = dlopen(filename, RTLD_LAZY);
+ return lib->handle ? 0 : uv__dlerror(lib);
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ uv__free(lib->errmsg);
+ lib->errmsg = NULL;
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ dlclose(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ dlerror(); /* Reset error status. */
+ *ptr = dlsym(lib->handle, name);
+ return uv__dlerror(lib);
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static int uv__dlerror(uv_lib_t* lib) {
+ const char* errmsg;
+
+ uv__free(lib->errmsg);
+
+ errmsg = dlerror();
+
+ if (errmsg) {
+ lib->errmsg = uv__strdup(errmsg);
+ return -1;
+ }
+ else {
+ lib->errmsg = NULL;
+ return 0;
+ }
+}
diff --git a/Utilities/cmlibuv/src/unix/freebsd.c b/Utilities/cmlibuv/src/unix/freebsd.c
new file mode 100644
index 000000000..e52ae99db
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/freebsd.c
@@ -0,0 +1,346 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <sys/user.h>
+#include <sys/types.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <vm/vm_param.h> /* VM_LOADAVG */
+#include <time.h>
+#include <stdlib.h>
+#include <unistd.h> /* sysconf */
+#include <fcntl.h>
+
+#ifndef CPUSTATES
+# define CPUSTATES 5U
+#endif
+#ifndef CP_USER
+# define CP_USER 0
+# define CP_NICE 1
+# define CP_SYS 2
+# define CP_IDLE 3
+# define CP_INTR 4
+#endif
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+#ifdef __DragonFly__
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ ssize_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ abspath_size = readlink("/proc/curproc/file", abspath, sizeof(abspath));
+ if (abspath_size < 0)
+ return -errno;
+
+ assert(abspath_size > 0);
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#else
+int uv_exepath(char* buffer, size_t* size) {
+ char abspath[PATH_MAX * 2 + 1];
+ int mib[4];
+ size_t abspath_size;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+
+ abspath_size = sizeof abspath;
+ if (sysctl(mib, 4, abspath, &abspath_size, NULL, 0))
+ return -errno;
+
+ assert(abspath_size > 0);
+ abspath_size -= 1;
+ *size -= 1;
+
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+}
+#endif
+
+uint64_t uv_get_free_memory(void) {
+ int freecount;
+ size_t size = sizeof(freecount);
+
+ if (sysctlbyname("vm.stats.vm.v_free_count", &freecount, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) freecount * sysconf(_SC_PAGESIZE);
+
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ unsigned long info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int oid[4];
+
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+
+ oid[0] = CTL_KERN;
+ oid[1] = KERN_PROC;
+ oid[2] = KERN_PROC_ARGS;
+ oid[3] = getpid();
+
+ sysctl(oid,
+ ARRAY_SIZE(oid),
+ NULL,
+ NULL,
+ process_title,
+ strlen(process_title) + 1);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+
+ if (process_title) {
+ len = strlen(process_title) + 1;
+
+ if (size < len)
+ return -ENOBUFS;
+
+ memcpy(buffer, process_title, len);
+ } else {
+ len = 0;
+ }
+
+ buffer[len] = '\0';
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ size_t page_size = getpagesize();
+
+ pid = getpid();
+
+ kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getprocs(kd, KERN_PROC_PID, pid, &nprocs);
+ if (kinfo == NULL) goto error;
+
+#ifdef __DragonFly__
+ *rss = kinfo->kp_vm_rssize * page_size;
+#else
+ *rss = kinfo->ki_rssize * page_size;
+#endif
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ int r;
+ struct timespec sp;
+ r = clock_gettime(CLOCK_MONOTONIC, &sp);
+ if (r)
+ return -errno;
+
+ *uptime = sp.tv_sec;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed, maxcpus,
+ cur = 0;
+ uv_cpu_info_t* cpu_info;
+ const char* maxcpus_key;
+ const char* cptimes_key;
+ char model[512];
+ long* cp_times;
+ int numcpus;
+ size_t size;
+ int i;
+
+#if defined(__DragonFly__)
+ /* This is not quite correct but DragonFlyBSD doesn't seem to have anything
+ * comparable to kern.smp.maxcpus or kern.cp_times (kern.cp_time is a total,
+ * not per CPU). At least this stops uv_cpu_info() from failing completely.
+ */
+ maxcpus_key = "hw.ncpu";
+ cptimes_key = "kern.cp_time";
+#else
+ maxcpus_key = "kern.smp.maxcpus";
+ cptimes_key = "kern.cp_times";
+#endif
+
+ size = sizeof(model);
+ if (sysctlbyname("hw.model", &model, &size, NULL, 0))
+ return -errno;
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("hw.clockrate", &cpuspeed, &size, NULL, 0)) {
+ uv__free(*cpu_infos);
+ return -errno;
+ }
+
+ /* kern.cp_times on FreeBSD i386 gives an array up to maxcpus instead of
+ * ncpu.
+ */
+ size = sizeof(maxcpus);
+ if (sysctlbyname(maxcpus_key, &maxcpus, &size, NULL, 0)) {
+ uv__free(*cpu_infos);
+ return -errno;
+ }
+
+ size = maxcpus * CPUSTATES * sizeof(long);
+
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL) {
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ if (sysctlbyname(cptimes_key, cp_times, &size, NULL, 0)) {
+ uv__free(cp_times);
+ uv__free(*cpu_infos);
+ return -errno;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+
+ cur+=CPUSTATES;
+ }
+
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
diff --git a/Utilities/cmlibuv/src/unix/fs.c b/Utilities/cmlibuv/src/unix/fs.c
new file mode 100644
index 000000000..8a4ba7a2f
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/fs.c
@@ -0,0 +1,1379 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Caveat emptor: this file deviates from the libuv convention of returning
+ * negated errno codes. Most uv_fs_*() functions map directly to the system
+ * call of the same name. For more complex wrappers, it's easier to just
+ * return -1 with errno set. The dispatcher in uv__fs_work() takes care of
+ * getting the errno to the right place (req->result or as the return value.)
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h> /* PATH_MAX */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <utime.h>
+#include <poll.h>
+
+#if defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel_) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__)
+# define HAVE_PREADV 1
+#else
+# define HAVE_PREADV 0
+#endif
+
+#if defined(__linux__) || defined(__sun)
+# include <sys/sendfile.h>
+#endif
+
+#define INIT(subtype) \
+ do { \
+ req->type = UV_FS; \
+ if (cb != NULL) \
+ uv__req_init(loop, req, UV_FS); \
+ req->fs_type = UV_FS_ ## subtype; \
+ req->result = 0; \
+ req->ptr = NULL; \
+ req->loop = loop; \
+ req->path = NULL; \
+ req->new_path = NULL; \
+ req->cb = cb; \
+ } \
+ while (0)
+
+#define PATH \
+ do { \
+ assert(path != NULL); \
+ if (cb == NULL) { \
+ req->path = path; \
+ } else { \
+ req->path = uv__strdup(path); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ } \
+ } \
+ while (0)
+
+#define PATH2 \
+ do { \
+ if (cb == NULL) { \
+ req->path = path; \
+ req->new_path = new_path; \
+ } else { \
+ size_t path_len; \
+ size_t new_path_len; \
+ path_len = strlen(path) + 1; \
+ new_path_len = strlen(new_path) + 1; \
+ req->path = uv__malloc(path_len + new_path_len); \
+ if (req->path == NULL) { \
+ uv__req_unregister(loop, req); \
+ return -ENOMEM; \
+ } \
+ req->new_path = req->path + path_len; \
+ memcpy((void*) req->path, path, path_len); \
+ memcpy((void*) req->new_path, new_path, new_path_len); \
+ } \
+ } \
+ while (0)
+
+#define POST \
+ do { \
+ if (cb != NULL) { \
+ uv__work_submit(loop, &req->work_req, uv__fs_work, uv__fs_done); \
+ return 0; \
+ } \
+ else { \
+ uv__fs_work(&req->work_req); \
+ return req->result; \
+ } \
+ } \
+ while (0)
+
+
+static ssize_t uv__fs_fdatasync(uv_fs_t* req) {
+#if defined(__linux__) || defined(__sun) || defined(__NetBSD__)
+ return fdatasync(req->file);
+#elif defined(__APPLE__)
+ /* Apple's fdatasync and fsync explicitly do NOT flush the drive write cache
+ * to the drive platters. This is in contrast to Linux's fdatasync and fsync
+ * which do, according to recent man pages. F_FULLFSYNC is Apple's equivalent
+ * for flushing buffered data to permanent storage.
+ */
+ return fcntl(req->file, F_FULLFSYNC);
+#else
+ return fsync(req->file);
+#endif
+}
+
+
+static ssize_t uv__fs_fsync(uv_fs_t* req) {
+#if defined(__APPLE__)
+ /* See the comment in uv__fs_fdatasync. */
+ return fcntl(req->file, F_FULLFSYNC);
+#else
+ return fsync(req->file);
+#endif
+}
+
+
+static ssize_t uv__fs_futime(uv_fs_t* req) {
+#if defined(__linux__)
+ /* utimesat() has nanosecond resolution but we stick to microseconds
+ * for the sake of consistency with other platforms.
+ */
+ static int no_utimesat;
+ struct timespec ts[2];
+ struct timeval tv[2];
+ char path[sizeof("/proc/self/fd/") + 3 * sizeof(int)];
+ int r;
+
+ if (no_utimesat)
+ goto skip;
+
+ ts[0].tv_sec = req->atime;
+ ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
+ ts[1].tv_sec = req->mtime;
+ ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
+
+ r = uv__utimesat(req->file, NULL, ts, 0);
+ if (r == 0)
+ return r;
+
+ if (errno != ENOSYS)
+ return r;
+
+ no_utimesat = 1;
+
+skip:
+
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
+ snprintf(path, sizeof(path), "/proc/self/fd/%d", (int) req->file);
+
+ r = utimes(path, tv);
+ if (r == 0)
+ return r;
+
+ switch (errno) {
+ case ENOENT:
+ if (fcntl(req->file, F_GETFL) == -1 && errno == EBADF)
+ break;
+ /* Fall through. */
+
+ case EACCES:
+ case ENOTDIR:
+ errno = ENOSYS;
+ break;
+ }
+
+ return r;
+
+#elif defined(__APPLE__) \
+ || defined(__DragonFly__) \
+ || defined(__FreeBSD__) \
+ || defined(__FreeBSD_kernel__) \
+ || defined(__NetBSD__) \
+ || defined(__OpenBSD__) \
+ || defined(__sun)
+ struct timeval tv[2];
+ tv[0].tv_sec = req->atime;
+ tv[0].tv_usec = (uint64_t)(req->atime * 1000000) % 1000000;
+ tv[1].tv_sec = req->mtime;
+ tv[1].tv_usec = (uint64_t)(req->mtime * 1000000) % 1000000;
+# if defined(__sun)
+ return futimesat(req->file, NULL, tv);
+# else
+ return futimes(req->file, tv);
+# endif
+#elif defined(_AIX71)
+ struct timespec ts[2];
+ ts[0].tv_sec = req->atime;
+ ts[0].tv_nsec = (uint64_t)(req->atime * 1000000) % 1000000 * 1000;
+ ts[1].tv_sec = req->mtime;
+ ts[1].tv_nsec = (uint64_t)(req->mtime * 1000000) % 1000000 * 1000;
+ return futimens(req->file, ts);
+#elif defined(__MVS__)
+ attrib_t atr;
+ memset(&atr, 0, sizeof(atr));
+ atr.att_mtimechg = 1;
+ atr.att_atimechg = 1;
+ atr.att_mtime = req->mtime;
+ atr.att_atime = req->atime;
+ return __fchattr(req->file, &atr, sizeof(atr));
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+#if defined(__sun) && _XOPEN_SOURCE < 600
+static char* uv__mkdtemp(char *template)
+{
+ if (!mktemp(template) || mkdir(template, 0700))
+ return NULL;
+ return template;
+}
+#else
+#define uv__mkdtemp mkdtemp
+#endif
+
+static ssize_t uv__fs_mkdtemp(uv_fs_t* req) {
+ return uv__mkdtemp((char*) req->path) ? 0 : -1;
+}
+
+
+static ssize_t uv__fs_open(uv_fs_t* req) {
+ static int no_cloexec_support;
+ int r;
+
+ /* Try O_CLOEXEC before entering locks */
+ if (no_cloexec_support == 0) {
+#ifdef O_CLOEXEC
+ r = open(req->path, req->flags | O_CLOEXEC, req->mode);
+ if (r >= 0)
+ return r;
+ if (errno != EINVAL)
+ return r;
+ no_cloexec_support = 1;
+#endif /* O_CLOEXEC */
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdlock(&req->loop->cloexec_lock);
+
+ r = open(req->path, req->flags, req->mode);
+
+ /* In case of failure `uv__cloexec` will leave error in `errno`,
+ * so it is enough to just set `r` to `-1`.
+ */
+ if (r >= 0 && uv__cloexec(r, 1) != 0) {
+ r = uv__close(r);
+ if (r != 0)
+ abort();
+ r = -1;
+ }
+
+ if (req->cb != NULL)
+ uv_rwlock_rdunlock(&req->loop->cloexec_lock);
+
+ return r;
+}
+
+
+static ssize_t uv__fs_read(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_preadv;
+#endif
+ ssize_t result;
+
+#if defined(_AIX)
+ struct stat buf;
+ if(fstat(req->file, &buf))
+ return -1;
+ if(S_ISDIR(buf.st_mode)) {
+ errno = EISDIR;
+ return -1;
+ }
+#endif /* defined(_AIX) */
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ result = read(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ result = readv(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ result = pread(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+
+#if HAVE_PREADV
+ result = preadv(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_preadv) retry:
+# endif
+ {
+ off_t nread;
+ size_t index;
+
+ nread = 0;
+ index = 0;
+ result = 1;
+ do {
+ if (req->bufs[index].len > 0) {
+ result = pread(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + nread);
+ if (result > 0)
+ nread += result;
+ }
+ index++;
+ } while (index < req->nbufs && result > 0);
+ if (nread > 0)
+ result = nread;
+ }
+# if defined(__linux__)
+ else {
+ result = uv__preadv(req->file,
+ (struct iovec*)req->bufs,
+ req->nbufs,
+ req->off);
+ if (result == -1 && errno == ENOSYS) {
+ no_preadv = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+ return result;
+}
+
+
+#if defined(__APPLE__) && !defined(MAC_OS_X_VERSION_10_8)
+#define UV_CONST_DIRENT uv__dirent_t
+#else
+#define UV_CONST_DIRENT const uv__dirent_t
+#endif
+
+
+static int uv__fs_scandir_filter(UV_CONST_DIRENT* dent) {
+ return strcmp(dent->d_name, ".") != 0 && strcmp(dent->d_name, "..") != 0;
+}
+
+
+static int uv__fs_scandir_sort(UV_CONST_DIRENT** a, UV_CONST_DIRENT** b) {
+ return strcmp((*a)->d_name, (*b)->d_name);
+}
+
+
+static ssize_t uv__fs_scandir(uv_fs_t* req) {
+ uv__dirent_t **dents;
+ int n;
+
+ dents = NULL;
+ n = scandir(req->path, &dents, uv__fs_scandir_filter, uv__fs_scandir_sort);
+
+ /* NOTE: We will use nbufs as an index field */
+ req->nbufs = 0;
+
+ if (n == 0) {
+ /* OS X still needs to deallocate some memory.
+ * Memory was allocated using the system allocator, so use free() here.
+ */
+ free(dents);
+ dents = NULL;
+ } else if (n == -1) {
+ return n;
+ }
+
+ req->ptr = dents;
+
+ return n;
+}
+
+
+static ssize_t uv__fs_pathmax_size(const char* path) {
+ ssize_t pathmax;
+
+ pathmax = pathconf(path, _PC_PATH_MAX);
+
+ if (pathmax == -1) {
+#if defined(PATH_MAX)
+ return PATH_MAX;
+#else
+#error "PATH_MAX undefined in the current platform"
+#endif
+ }
+
+ return pathmax;
+}
+
+static ssize_t uv__fs_readlink(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ len = readlink(req->path, buf, len);
+
+ if (len == -1) {
+ uv__free(buf);
+ return -1;
+ }
+
+ buf[len] = '\0';
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_realpath(uv_fs_t* req) {
+ ssize_t len;
+ char* buf;
+
+ len = uv__fs_pathmax_size(req->path);
+ buf = uv__malloc(len + 1);
+
+ if (buf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (realpath(req->path, buf) == NULL) {
+ uv__free(buf);
+ return -1;
+ }
+
+ req->ptr = buf;
+
+ return 0;
+}
+
+static ssize_t uv__fs_sendfile_emul(uv_fs_t* req) {
+ struct pollfd pfd;
+ int use_pread;
+ off_t offset;
+ ssize_t nsent;
+ ssize_t nread;
+ ssize_t nwritten;
+ size_t buflen;
+ size_t len;
+ ssize_t n;
+ int in_fd;
+ int out_fd;
+ char buf[8192];
+
+ len = req->bufsml[0].len;
+ in_fd = req->flags;
+ out_fd = req->file;
+ offset = req->off;
+ use_pread = 1;
+
+ /* Here are the rules regarding errors:
+ *
+ * 1. Read errors are reported only if nsent==0, otherwise we return nsent.
+ * The user needs to know that some data has already been sent, to stop
+ * them from sending it twice.
+ *
+ * 2. Write errors are always reported. Write errors are bad because they
+ * mean data loss: we've read data but now we can't write it out.
+ *
+ * We try to use pread() and fall back to regular read() if the source fd
+ * doesn't support positional reads, for example when it's a pipe fd.
+ *
+ * If we get EAGAIN when writing to the target fd, we poll() on it until
+ * it becomes writable again.
+ *
+ * FIXME: If we get a write error when use_pread==1, it should be safe to
+ * return the number of sent bytes instead of an error because pread()
+ * is, in theory, idempotent. However, special files in /dev or /proc
+ * may support pread() but not necessarily return the same data on
+ * successive reads.
+ *
+ * FIXME: There is no way now to signal that we managed to send *some* data
+ * before a write error.
+ */
+ for (nsent = 0; (size_t) nsent < len; ) {
+ buflen = len - nsent;
+
+ if (buflen > sizeof(buf))
+ buflen = sizeof(buf);
+
+ do
+ if (use_pread)
+ nread = pread(in_fd, buf, buflen, offset);
+ else
+ nread = read(in_fd, buf, buflen);
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == 0)
+ goto out;
+
+ if (nread == -1) {
+ if (use_pread && nsent == 0 && (errno == EIO || errno == ESPIPE)) {
+ use_pread = 0;
+ continue;
+ }
+
+ if (nsent == 0)
+ nsent = -1;
+
+ goto out;
+ }
+
+ for (nwritten = 0; nwritten < nread; ) {
+ do
+ n = write(out_fd, buf + nwritten, nread - nwritten);
+ while (n == -1 && errno == EINTR);
+
+ if (n != -1) {
+ nwritten += n;
+ continue;
+ }
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ nsent = -1;
+ goto out;
+ }
+
+ pfd.fd = out_fd;
+ pfd.events = POLLOUT;
+ pfd.revents = 0;
+
+ do
+ n = poll(&pfd, 1, -1);
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 || (pfd.revents & ~POLLOUT) != 0) {
+ errno = EIO;
+ nsent = -1;
+ goto out;
+ }
+ }
+
+ offset += nread;
+ nsent += nread;
+ }
+
+out:
+ if (nsent != -1)
+ req->off = offset;
+
+ return nsent;
+}
+
+
+static ssize_t uv__fs_sendfile(uv_fs_t* req) {
+ int in_fd;
+ int out_fd;
+
+ in_fd = req->flags;
+ out_fd = req->file;
+
+#if defined(__linux__) || defined(__sun)
+ {
+ off_t off;
+ ssize_t r;
+
+ off = req->off;
+ r = sendfile(out_fd, in_fd, &off, req->bufsml[0].len);
+
+ /* sendfile() on SunOS returns EINVAL if the target fd is not a socket but
+ * it still writes out data. Fortunately, we can detect it by checking if
+ * the offset has been updated.
+ */
+ if (r != -1 || off > req->off) {
+ r = off - req->off;
+ req->off = off;
+ return r;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#elif defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__)
+ {
+ off_t len;
+ ssize_t r;
+
+ /* sendfile() on FreeBSD and Darwin returns EAGAIN if the target fd is in
+ * non-blocking mode and not all data could be written. If a non-zero
+ * number of bytes have been sent, we don't consider it an error.
+ */
+
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ len = 0;
+ r = sendfile(in_fd, out_fd, req->off, req->bufsml[0].len, NULL, &len, 0);
+#elif defined(__FreeBSD_kernel__)
+ len = 0;
+ r = bsd_sendfile(in_fd,
+ out_fd,
+ req->off,
+ req->bufsml[0].len,
+ NULL,
+ &len,
+ 0);
+#else
+ /* The darwin sendfile takes len as an input for the length to send,
+ * so make sure to initialize it with the caller's value. */
+ len = req->bufsml[0].len;
+ r = sendfile(in_fd, out_fd, req->off, &len, NULL, 0);
+#endif
+
+ /*
+ * The man page for sendfile(2) on DragonFly states that `len` contains
+ * a meaningful value ONLY in case of EAGAIN and EINTR.
+ * Nothing is said about it's value in case of other errors, so better
+ * not depend on the potential wrong assumption that is was not modified
+ * by the syscall.
+ */
+ if (r == 0 || ((errno == EAGAIN || errno == EINTR) && len != 0)) {
+ req->off += len;
+ return (ssize_t) len;
+ }
+
+ if (errno == EINVAL ||
+ errno == EIO ||
+ errno == ENOTSOCK ||
+ errno == EXDEV) {
+ errno = 0;
+ return uv__fs_sendfile_emul(req);
+ }
+
+ return -1;
+ }
+#else
+ /* Squelch compiler warnings. */
+ (void) &in_fd;
+ (void) &out_fd;
+
+ return uv__fs_sendfile_emul(req);
+#endif
+}
+
+
+static ssize_t uv__fs_utime(uv_fs_t* req) {
+ struct utimbuf buf;
+ buf.actime = req->atime;
+ buf.modtime = req->mtime;
+ return utime(req->path, &buf); /* TODO use utimes() where available */
+}
+
+
+static ssize_t uv__fs_write(uv_fs_t* req) {
+#if defined(__linux__)
+ static int no_pwritev;
+#endif
+ ssize_t r;
+
+ /* Serialize writes on OS X, concurrent write() and pwrite() calls result in
+ * data loss. We can't use a per-file descriptor lock, the descriptor may be
+ * a dup().
+ */
+#if defined(__APPLE__)
+ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+ if (pthread_mutex_lock(&lock))
+ abort();
+#endif
+
+ if (req->off < 0) {
+ if (req->nbufs == 1)
+ r = write(req->file, req->bufs[0].base, req->bufs[0].len);
+ else
+ r = writev(req->file, (struct iovec*) req->bufs, req->nbufs);
+ } else {
+ if (req->nbufs == 1) {
+ r = pwrite(req->file, req->bufs[0].base, req->bufs[0].len, req->off);
+ goto done;
+ }
+#if HAVE_PREADV
+ r = pwritev(req->file, (struct iovec*) req->bufs, req->nbufs, req->off);
+#else
+# if defined(__linux__)
+ if (no_pwritev) retry:
+# endif
+ {
+ off_t written;
+ size_t index;
+
+ written = 0;
+ index = 0;
+ r = 0;
+ do {
+ if (req->bufs[index].len > 0) {
+ r = pwrite(req->file,
+ req->bufs[index].base,
+ req->bufs[index].len,
+ req->off + written);
+ if (r > 0)
+ written += r;
+ }
+ index++;
+ } while (index < req->nbufs && r >= 0);
+ if (written > 0)
+ r = written;
+ }
+# if defined(__linux__)
+ else {
+ r = uv__pwritev(req->file,
+ (struct iovec*) req->bufs,
+ req->nbufs,
+ req->off);
+ if (r == -1 && errno == ENOSYS) {
+ no_pwritev = 1;
+ goto retry;
+ }
+ }
+# endif
+#endif
+ }
+
+done:
+#if defined(__APPLE__)
+ if (pthread_mutex_unlock(&lock))
+ abort();
+#endif
+
+ return r;
+}
+
+static void uv__to_stat(struct stat* src, uv_stat_t* dst) {
+ dst->st_dev = src->st_dev;
+ dst->st_mode = src->st_mode;
+ dst->st_nlink = src->st_nlink;
+ dst->st_uid = src->st_uid;
+ dst->st_gid = src->st_gid;
+ dst->st_rdev = src->st_rdev;
+ dst->st_ino = src->st_ino;
+ dst->st_size = src->st_size;
+ dst->st_blksize = src->st_blksize;
+ dst->st_blocks = src->st_blocks;
+
+#if defined(__APPLE__)
+ dst->st_atim.tv_sec = src->st_atimespec.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atimespec.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtimespec.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtimespec.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctimespec.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctimespec.tv_nsec;
+ dst->st_birthtim.tv_sec = src->st_birthtimespec.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtimespec.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+#elif defined(__ANDROID__)
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = src->st_atimensec;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = src->st_mtimensec;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = src->st_ctimensec;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = src->st_ctimensec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#elif !defined(_AIX) && ( \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__OpenBSD__) || \
+ defined(__NetBSD__) || \
+ defined(_GNU_SOURCE) || \
+ defined(_BSD_SOURCE) || \
+ defined(_SVID_SOURCE) || \
+ defined(_XOPEN_SOURCE) || \
+ defined(_DEFAULT_SOURCE))
+ dst->st_atim.tv_sec = src->st_atim.tv_sec;
+ dst->st_atim.tv_nsec = src->st_atim.tv_nsec;
+ dst->st_mtim.tv_sec = src->st_mtim.tv_sec;
+ dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec;
+ dst->st_ctim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec;
+# if defined(__FreeBSD__) || \
+ defined(__NetBSD__)
+ dst->st_birthtim.tv_sec = src->st_birthtim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_birthtim.tv_nsec;
+ dst->st_flags = src->st_flags;
+ dst->st_gen = src->st_gen;
+# else
+ dst->st_birthtim.tv_sec = src->st_ctim.tv_sec;
+ dst->st_birthtim.tv_nsec = src->st_ctim.tv_nsec;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+# endif
+#else
+ dst->st_atim.tv_sec = src->st_atime;
+ dst->st_atim.tv_nsec = 0;
+ dst->st_mtim.tv_sec = src->st_mtime;
+ dst->st_mtim.tv_nsec = 0;
+ dst->st_ctim.tv_sec = src->st_ctime;
+ dst->st_ctim.tv_nsec = 0;
+ dst->st_birthtim.tv_sec = src->st_ctime;
+ dst->st_birthtim.tv_nsec = 0;
+ dst->st_flags = 0;
+ dst->st_gen = 0;
+#endif
+}
+
+
+static int uv__fs_stat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+
+ ret = stat(path, &pbuf);
+ if (ret == 0)
+ uv__to_stat(&pbuf, buf);
+
+ return ret;
+}
+
+
+static int uv__fs_lstat(const char *path, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+
+ ret = lstat(path, &pbuf);
+ if (ret == 0)
+ uv__to_stat(&pbuf, buf);
+
+ return ret;
+}
+
+
+static int uv__fs_fstat(int fd, uv_stat_t *buf) {
+ struct stat pbuf;
+ int ret;
+
+ ret = fstat(fd, &pbuf);
+ if (ret == 0)
+ uv__to_stat(&pbuf, buf);
+
+ return ret;
+}
+
+
+typedef ssize_t (*uv__fs_buf_iter_processor)(uv_fs_t* req);
+static ssize_t uv__fs_buf_iter(uv_fs_t* req, uv__fs_buf_iter_processor process) {
+ unsigned int iovmax;
+ unsigned int nbufs;
+ uv_buf_t* bufs;
+ ssize_t total;
+ ssize_t result;
+
+ iovmax = uv__getiovmax();
+ nbufs = req->nbufs;
+ bufs = req->bufs;
+ total = 0;
+
+ while (nbufs > 0) {
+ req->nbufs = nbufs;
+ if (req->nbufs > iovmax)
+ req->nbufs = iovmax;
+
+ result = process(req);
+ if (result <= 0) {
+ if (total == 0)
+ total = result;
+ break;
+ }
+
+ if (req->off >= 0)
+ req->off += result;
+
+ req->bufs += req->nbufs;
+ nbufs -= req->nbufs;
+ total += result;
+ }
+
+ if (errno == EINTR && total == -1)
+ return total;
+
+ if (bufs != req->bufsml)
+ uv__free(bufs);
+
+ req->bufs = NULL;
+ req->nbufs = 0;
+
+ return total;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ int retry_on_eintr;
+ uv_fs_t* req;
+ ssize_t r;
+
+ req = container_of(w, uv_fs_t, work_req);
+ retry_on_eintr = !(req->fs_type == UV_FS_CLOSE);
+
+ do {
+ errno = 0;
+
+#define X(type, action) \
+ case UV_FS_ ## type: \
+ r = action; \
+ break;
+
+ switch (req->fs_type) {
+ X(ACCESS, access(req->path, req->flags));
+ X(CHMOD, chmod(req->path, req->mode));
+ X(CHOWN, chown(req->path, req->uid, req->gid));
+ X(CLOSE, close(req->file));
+ X(FCHMOD, fchmod(req->file, req->mode));
+ X(FCHOWN, fchown(req->file, req->uid, req->gid));
+ X(FDATASYNC, uv__fs_fdatasync(req));
+ X(FSTAT, uv__fs_fstat(req->file, &req->statbuf));
+ X(FSYNC, uv__fs_fsync(req));
+ X(FTRUNCATE, ftruncate(req->file, req->off));
+ X(FUTIME, uv__fs_futime(req));
+ X(LSTAT, uv__fs_lstat(req->path, &req->statbuf));
+ X(LINK, link(req->path, req->new_path));
+ X(MKDIR, mkdir(req->path, req->mode));
+ X(MKDTEMP, uv__fs_mkdtemp(req));
+ X(OPEN, uv__fs_open(req));
+ X(READ, uv__fs_buf_iter(req, uv__fs_read));
+ X(SCANDIR, uv__fs_scandir(req));
+ X(READLINK, uv__fs_readlink(req));
+ X(REALPATH, uv__fs_realpath(req));
+ X(RENAME, rename(req->path, req->new_path));
+ X(RMDIR, rmdir(req->path));
+ X(SENDFILE, uv__fs_sendfile(req));
+ X(STAT, uv__fs_stat(req->path, &req->statbuf));
+ X(SYMLINK, symlink(req->path, req->new_path));
+ X(UNLINK, unlink(req->path));
+ X(UTIME, uv__fs_utime(req));
+ X(WRITE, uv__fs_buf_iter(req, uv__fs_write));
+ default: abort();
+ }
+#undef X
+ } while (r == -1 && errno == EINTR && retry_on_eintr);
+
+ if (r == -1)
+ req->result = -errno;
+ else
+ req->result = r;
+
+ if (r == 0 && (req->fs_type == UV_FS_STAT ||
+ req->fs_type == UV_FS_FSTAT ||
+ req->fs_type == UV_FS_LSTAT)) {
+ req->ptr = &req->statbuf;
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == -ECANCELED) {
+ assert(req->result == 0);
+ req->result = -ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(ACCESS);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(CHMOD);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_chown(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(CHOWN);
+ PATH;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(CLOSE);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(FCHMOD);
+ req->file = file;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ uv_uid_t uid,
+ uv_gid_t gid,
+ uv_fs_cb cb) {
+ INIT(FCHOWN);
+ req->file = file;
+ req->uid = uid;
+ req->gid = gid;
+ POST;
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FDATASYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSTAT);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file file, uv_fs_cb cb) {
+ INIT(FSYNC);
+ req->file = file;
+ POST;
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ int64_t off,
+ uv_fs_cb cb) {
+ INIT(FTRUNCATE);
+ req->file = file;
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_futime(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(FUTIME);
+ req->file = file;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(LSTAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_link(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(LINK);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(MKDIR);
+ PATH;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* tpl,
+ uv_fs_cb cb) {
+ INIT(MKDTEMP);
+ req->path = uv__strdup(tpl);
+ if (req->path == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+ POST;
+}
+
+
+int uv_fs_open(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ int mode,
+ uv_fs_cb cb) {
+ INIT(OPEN);
+ PATH;
+ req->flags = flags;
+ req->mode = mode;
+ POST;
+}
+
+
+int uv_fs_read(uv_loop_t* loop, uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(READ);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SCANDIR);
+ PATH;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ uv_fs_cb cb) {
+ INIT(READLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char * path,
+ uv_fs_cb cb) {
+ INIT(REALPATH);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_rename(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ uv_fs_cb cb) {
+ INIT(RENAME);
+ PATH2;
+ POST;
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(RMDIR);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_sendfile(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file out_fd,
+ uv_file in_fd,
+ int64_t off,
+ size_t len,
+ uv_fs_cb cb) {
+ INIT(SENDFILE);
+ req->flags = in_fd; /* hack */
+ req->file = out_fd;
+ req->off = off;
+ req->bufsml[0].len = len;
+ POST;
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(STAT);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ const char* new_path,
+ int flags,
+ uv_fs_cb cb) {
+ INIT(SYMLINK);
+ PATH2;
+ req->flags = flags;
+ POST;
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ INIT(UNLINK);
+ PATH;
+ POST;
+}
+
+
+int uv_fs_utime(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ double atime,
+ double mtime,
+ uv_fs_cb cb) {
+ INIT(UTIME);
+ PATH;
+ req->atime = atime;
+ req->mtime = mtime;
+ POST;
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file file,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t off,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return -EINVAL;
+
+ INIT(WRITE);
+ req->file = file;
+
+ req->nbufs = nbufs;
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->bufs == NULL) {
+ if (cb != NULL)
+ uv__req_unregister(loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->off = off;
+ POST;
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ /* Only necessary for asychronous requests, i.e., requests with a callback.
+ * Synchronous ones don't copy their arguments and have req->path and
+ * req->new_path pointing to user-owned memory. UV_FS_MKDTEMP is the
+ * exception to the rule, it always allocates memory.
+ */
+ if (req->path != NULL && (req->cb != NULL || req->fs_type == UV_FS_MKDTEMP))
+ uv__free((void*) req->path); /* Memory is shared with req->new_path. */
+
+ req->path = NULL;
+ req->new_path = NULL;
+
+ if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
+ uv__fs_scandir_cleanup(req);
+
+ if (req->ptr != &req->statbuf)
+ uv__free(req->ptr);
+ req->ptr = NULL;
+}
diff --git a/Utilities/cmlibuv/src/unix/fsevents.c b/Utilities/cmlibuv/src/unix/fsevents.c
new file mode 100644
index 000000000..643e233cf
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/fsevents.c
@@ -0,0 +1,901 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#if TARGET_OS_IPHONE
+
+/* iOS (currently) doesn't provide the FSEvents-API (nor CoreServices) */
+
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ return 0;
+}
+
+
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+}
+
+#else /* TARGET_OS_IPHONE */
+
+#include <dlfcn.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreServices/CoreServices.h>
+
+/* These are macros to avoid "initializer element is not constant" errors
+ * with old versions of gcc.
+ */
+#define kFSEventsModified (kFSEventStreamEventFlagItemFinderInfoMod | \
+ kFSEventStreamEventFlagItemModified | \
+ kFSEventStreamEventFlagItemInodeMetaMod | \
+ kFSEventStreamEventFlagItemChangeOwner | \
+ kFSEventStreamEventFlagItemXattrMod)
+
+#define kFSEventsRenamed (kFSEventStreamEventFlagItemCreated | \
+ kFSEventStreamEventFlagItemRemoved | \
+ kFSEventStreamEventFlagItemRenamed)
+
+#define kFSEventsSystem (kFSEventStreamEventFlagUserDropped | \
+ kFSEventStreamEventFlagKernelDropped | \
+ kFSEventStreamEventFlagEventIdsWrapped | \
+ kFSEventStreamEventFlagHistoryDone | \
+ kFSEventStreamEventFlagMount | \
+ kFSEventStreamEventFlagUnmount | \
+ kFSEventStreamEventFlagRootChanged)
+
+typedef struct uv__fsevents_event_s uv__fsevents_event_t;
+typedef struct uv__cf_loop_signal_s uv__cf_loop_signal_t;
+typedef struct uv__cf_loop_state_s uv__cf_loop_state_t;
+
+enum uv__cf_loop_signal_type_e {
+ kUVCFLoopSignalRegular,
+ kUVCFLoopSignalClosing
+};
+typedef enum uv__cf_loop_signal_type_e uv__cf_loop_signal_type_t;
+
+struct uv__cf_loop_signal_s {
+ QUEUE member;
+ uv_fs_event_t* handle;
+ uv__cf_loop_signal_type_t type;
+};
+
+struct uv__fsevents_event_s {
+ QUEUE member;
+ int events;
+ char path[1];
+};
+
+struct uv__cf_loop_state_s {
+ CFRunLoopRef loop;
+ CFRunLoopSourceRef signal_source;
+ int fsevent_need_reschedule;
+ FSEventStreamRef fsevent_stream;
+ uv_sem_t fsevent_sem;
+ uv_mutex_t fsevent_mutex;
+ void* fsevent_handles[2];
+ unsigned int fsevent_handle_count;
+};
+
+/* Forward declarations */
+static void uv__cf_loop_cb(void* arg);
+static void* uv__cf_loop_runner(void* arg);
+static int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type);
+
+/* Lazy-loaded by uv__fsevents_global_init(). */
+static CFArrayRef (*pCFArrayCreate)(CFAllocatorRef,
+ const void**,
+ CFIndex,
+ const CFArrayCallBacks*);
+static void (*pCFRelease)(CFTypeRef);
+static void (*pCFRunLoopAddSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static CFRunLoopRef (*pCFRunLoopGetCurrent)(void);
+static void (*pCFRunLoopRemoveSource)(CFRunLoopRef,
+ CFRunLoopSourceRef,
+ CFStringRef);
+static void (*pCFRunLoopRun)(void);
+static CFRunLoopSourceRef (*pCFRunLoopSourceCreate)(CFAllocatorRef,
+ CFIndex,
+ CFRunLoopSourceContext*);
+static void (*pCFRunLoopSourceSignal)(CFRunLoopSourceRef);
+static void (*pCFRunLoopStop)(CFRunLoopRef);
+static void (*pCFRunLoopWakeUp)(CFRunLoopRef);
+static CFStringRef (*pCFStringCreateWithFileSystemRepresentation)(
+ CFAllocatorRef,
+ const char*);
+static CFStringEncoding (*pCFStringGetSystemEncoding)(void);
+static CFStringRef (*pkCFRunLoopDefaultMode);
+static FSEventStreamRef (*pFSEventStreamCreate)(CFAllocatorRef,
+ FSEventStreamCallback,
+ FSEventStreamContext*,
+ CFArrayRef,
+ FSEventStreamEventId,
+ CFTimeInterval,
+ FSEventStreamCreateFlags);
+static void (*pFSEventStreamFlushSync)(FSEventStreamRef);
+static void (*pFSEventStreamInvalidate)(FSEventStreamRef);
+static void (*pFSEventStreamRelease)(FSEventStreamRef);
+static void (*pFSEventStreamScheduleWithRunLoop)(FSEventStreamRef,
+ CFRunLoopRef,
+ CFStringRef);
+static Boolean (*pFSEventStreamStart)(FSEventStreamRef);
+static void (*pFSEventStreamStop)(FSEventStreamRef);
+
+#define UV__FSEVENTS_PROCESS(handle, block) \
+ do { \
+ QUEUE events; \
+ QUEUE* q; \
+ uv__fsevents_event_t* event; \
+ int err; \
+ uv_mutex_lock(&(handle)->cf_mutex); \
+ /* Split-off all events and empty original queue */ \
+ QUEUE_MOVE(&(handle)->cf_events, &events); \
+ /* Get error (if any) and zero original one */ \
+ err = (handle)->cf_error; \
+ (handle)->cf_error = 0; \
+ uv_mutex_unlock(&(handle)->cf_mutex); \
+ /* Loop through events, deallocating each after processing */ \
+ while (!QUEUE_EMPTY(&events)) { \
+ q = QUEUE_HEAD(&events); \
+ event = QUEUE_DATA(q, uv__fsevents_event_t, member); \
+ QUEUE_REMOVE(q); \
+ /* NOTE: Checking uv__is_active() is required here, because handle \
+ * callback may close handle and invoking it after it will lead to \
+ * incorrect behaviour */ \
+ if (!uv__is_closing((handle)) && uv__is_active((handle))) \
+ block \
+ /* Free allocated data */ \
+ uv__free(event); \
+ } \
+ if (err != 0 && !uv__is_closing((handle)) && uv__is_active((handle))) \
+ (handle)->cb((handle), NULL, 0, err); \
+ } while (0)
+
+
+/* Runs in UV loop's thread, when there're events to report to handle */
+static void uv__fsevents_cb(uv_async_t* cb) {
+ uv_fs_event_t* handle;
+
+ handle = cb->data;
+
+ UV__FSEVENTS_PROCESS(handle, {
+ handle->cb(handle, event->path[0] ? event->path : NULL, event->events, 0);
+ });
+}
+
+
+/* Runs in CF thread, pushed event into handle's event list */
+static void uv__fsevents_push_event(uv_fs_event_t* handle,
+ QUEUE* events,
+ int err) {
+ assert(events != NULL || err != 0);
+ uv_mutex_lock(&handle->cf_mutex);
+
+ /* Concatenate two queues */
+ if (events != NULL)
+ QUEUE_ADD(&handle->cf_events, events);
+
+ /* Propagate error */
+ if (err != 0)
+ handle->cf_error = err;
+ uv_mutex_unlock(&handle->cf_mutex);
+
+ uv_async_send(handle->cf_cb);
+}
+
+
+/* Runs in CF thread, when there're events in FSEventStream */
+static void uv__fsevents_event_cb(ConstFSEventStreamRef streamRef,
+ void* info,
+ size_t numEvents,
+ void* eventPaths,
+ const FSEventStreamEventFlags eventFlags[],
+ const FSEventStreamEventId eventIds[]) {
+ size_t i;
+ int len;
+ char** paths;
+ char* path;
+ char* pos;
+ uv_fs_event_t* handle;
+ QUEUE* q;
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ uv__fsevents_event_t* event;
+ QUEUE head;
+
+ loop = info;
+ state = loop->cf_state;
+ assert(state != NULL);
+ paths = eventPaths;
+
+ /* For each handle */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ handle = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ QUEUE_INIT(&head);
+
+ /* Process and filter out events */
+ for (i = 0; i < numEvents; i++) {
+ /* Ignore system events */
+ if (eventFlags[i] & kFSEventsSystem)
+ continue;
+
+ path = paths[i];
+ len = strlen(path);
+
+ /* Filter out paths that are outside handle's request */
+ if (strncmp(path, handle->realpath, handle->realpath_len) != 0)
+ continue;
+
+ if (handle->realpath_len > 1 || *handle->realpath != '/') {
+ path += handle->realpath_len;
+ len -= handle->realpath_len;
+
+ /* Skip forward slash */
+ if (*path != '\0') {
+ path++;
+ len--;
+ }
+ }
+
+#ifdef MAC_OS_X_VERSION_10_7
+ /* Ignore events with path equal to directory itself */
+ if (len == 0)
+ continue;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ /* Do not emit events from subdirectories (without option set) */
+ if ((handle->cf_flags & UV_FS_EVENT_RECURSIVE) == 0 && *path != 0) {
+ pos = strchr(path + 1, '/');
+ if (pos != NULL)
+ continue;
+ }
+
+#ifndef MAC_OS_X_VERSION_10_7
+ path = "";
+ len = 0;
+#endif /* MAC_OS_X_VERSION_10_7 */
+
+ event = uv__malloc(sizeof(*event) + len);
+ if (event == NULL)
+ break;
+
+ memset(event, 0, sizeof(*event));
+ memcpy(event->path, path, len + 1);
+
+ if ((eventFlags[i] & kFSEventsModified) != 0 &&
+ (eventFlags[i] & kFSEventsRenamed) == 0)
+ event->events = UV_CHANGE;
+ else
+ event->events = UV_RENAME;
+
+ QUEUE_INSERT_TAIL(&head, &event->member);
+ }
+
+ if (!QUEUE_EMPTY(&head))
+ uv__fsevents_push_event(handle, &head, 0);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+}
+
+
+/* Runs in CF thread */
+static int uv__fsevents_create_stream(uv_loop_t* loop, CFArrayRef paths) {
+ uv__cf_loop_state_t* state;
+ FSEventStreamContext ctx;
+ FSEventStreamRef ref;
+ CFAbsoluteTime latency;
+ FSEventStreamCreateFlags flags;
+
+ /* Initialize context */
+ ctx.version = 0;
+ ctx.info = loop;
+ ctx.retain = NULL;
+ ctx.release = NULL;
+ ctx.copyDescription = NULL;
+
+ latency = 0.05;
+
+ /* Explanation of selected flags:
+ * 1. NoDefer - without this flag, events that are happening continuously
+ * (i.e. each event is happening after time interval less than `latency`,
+ * counted from previous event), will be deferred and passed to callback
+ * once they'll either fill whole OS buffer, or when this continuous stream
+ * will stop (i.e. there'll be delay between events, bigger than
+ * `latency`).
+ * Specifying this flag will invoke callback after `latency` time passed
+ * since event.
+ * 2. FileEvents - fire callback for file changes too (by default it is firing
+ * it only for directory changes).
+ */
+ flags = kFSEventStreamCreateFlagNoDefer | kFSEventStreamCreateFlagFileEvents;
+
+ /*
+ * NOTE: It might sound like a good idea to remember last seen StreamEventId,
+ * but in reality one dir might have last StreamEventId less than, the other,
+ * that is being watched now. Which will cause FSEventStream API to report
+ * changes to files from the past.
+ */
+ ref = pFSEventStreamCreate(NULL,
+ &uv__fsevents_event_cb,
+ &ctx,
+ paths,
+ kFSEventStreamEventIdSinceNow,
+ latency,
+ flags);
+ assert(ref != NULL);
+
+ state = loop->cf_state;
+ pFSEventStreamScheduleWithRunLoop(ref,
+ state->loop,
+ *pkCFRunLoopDefaultMode);
+ if (!pFSEventStreamStart(ref)) {
+ pFSEventStreamInvalidate(ref);
+ pFSEventStreamRelease(ref);
+ return -EMFILE;
+ }
+
+ state->fsevent_stream = ref;
+ return 0;
+}
+
+
+/* Runs in CF thread */
+static void uv__fsevents_destroy_stream(uv_loop_t* loop) {
+ uv__cf_loop_state_t* state;
+
+ state = loop->cf_state;
+
+ if (state->fsevent_stream == NULL)
+ return;
+
+ /* Stop emitting events */
+ pFSEventStreamStop(state->fsevent_stream);
+
+ /* Release stream */
+ pFSEventStreamInvalidate(state->fsevent_stream);
+ pFSEventStreamRelease(state->fsevent_stream);
+ state->fsevent_stream = NULL;
+}
+
+
+/* Runs in CF thread, when there're new fsevent handles to add to stream */
+static void uv__fsevents_reschedule(uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+ uv_fs_event_t* curr;
+ CFArrayRef cf_paths;
+ CFStringRef* paths;
+ unsigned int i;
+ int err;
+ unsigned int path_count;
+
+ state = handle->loop->cf_state;
+ paths = NULL;
+ cf_paths = NULL;
+ err = 0;
+ /* NOTE: `i` is used in deallocation loop below */
+ i = 0;
+
+ /* Optimization to prevent O(n^2) time spent when starting to watch
+ * many files simultaneously
+ */
+ uv_mutex_lock(&state->fsevent_mutex);
+ if (state->fsevent_need_reschedule == 0) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ state->fsevent_need_reschedule = 0;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Destroy previous FSEventStream */
+ uv__fsevents_destroy_stream(handle->loop);
+
+ /* Any failure below will be a memory failure */
+ err = -ENOMEM;
+
+ /* Create list of all watched paths */
+ uv_mutex_lock(&state->fsevent_mutex);
+ path_count = state->fsevent_handle_count;
+ if (path_count != 0) {
+ paths = uv__malloc(sizeof(*paths) * path_count);
+ if (paths == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+
+ q = &state->fsevent_handles;
+ for (; i < path_count; i++) {
+ q = QUEUE_NEXT(q);
+ assert(q != &state->fsevent_handles);
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+
+ assert(curr->realpath != NULL);
+ paths[i] =
+ pCFStringCreateWithFileSystemRepresentation(NULL, curr->realpath);
+ if (paths[i] == NULL) {
+ uv_mutex_unlock(&state->fsevent_mutex);
+ goto final;
+ }
+ }
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ err = 0;
+
+ if (path_count != 0) {
+ /* Create new FSEventStream */
+ cf_paths = pCFArrayCreate(NULL, (const void**) paths, path_count, NULL);
+ if (cf_paths == NULL) {
+ err = -ENOMEM;
+ goto final;
+ }
+ err = uv__fsevents_create_stream(handle->loop, cf_paths);
+ }
+
+final:
+ /* Deallocate all paths in case of failure */
+ if (err != 0) {
+ if (cf_paths == NULL) {
+ while (i != 0)
+ pCFRelease(paths[--i]);
+ uv__free(paths);
+ } else {
+ /* CFArray takes ownership of both strings and original C-array */
+ pCFRelease(cf_paths);
+ }
+
+ /* Broadcast error to all handles */
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_FOREACH(q, &state->fsevent_handles) {
+ curr = QUEUE_DATA(q, uv_fs_event_t, cf_member);
+ uv__fsevents_push_event(curr, NULL, err);
+ }
+ uv_mutex_unlock(&state->fsevent_mutex);
+ }
+
+ /*
+ * Main thread will block until the removal of handle from the list,
+ * we must tell it when we're ready.
+ *
+ * NOTE: This is coupled with `uv_sem_wait()` in `uv__fsevents_close`
+ */
+ if (type == kUVCFLoopSignalClosing)
+ uv_sem_post(&state->fsevent_sem);
+}
+
+
+static int uv__fsevents_global_init(void) {
+ static pthread_mutex_t global_init_mutex = PTHREAD_MUTEX_INITIALIZER;
+ static void* core_foundation_handle;
+ static void* core_services_handle;
+ int err;
+
+ err = 0;
+ pthread_mutex_lock(&global_init_mutex);
+ if (core_foundation_handle != NULL)
+ goto out;
+
+ /* The libraries are never unloaded because we currently don't have a good
+ * mechanism for keeping a reference count. It's unlikely to be an issue
+ * but if it ever becomes one, we can turn the dynamic library handles into
+ * per-event loop properties and have the dynamic linker keep track for us.
+ */
+ err = -ENOSYS;
+ core_foundation_handle = dlopen("/System/Library/Frameworks/"
+ "CoreFoundation.framework/"
+ "Versions/A/CoreFoundation",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_foundation_handle == NULL)
+ goto out;
+
+ core_services_handle = dlopen("/System/Library/Frameworks/"
+ "CoreServices.framework/"
+ "Versions/A/CoreServices",
+ RTLD_LAZY | RTLD_LOCAL);
+ if (core_services_handle == NULL)
+ goto out;
+
+ err = -ENOENT;
+#define V(handle, symbol) \
+ do { \
+ *(void **)(&p ## symbol) = dlsym((handle), #symbol); \
+ if (p ## symbol == NULL) \
+ goto out; \
+ } \
+ while (0)
+ V(core_foundation_handle, CFArrayCreate);
+ V(core_foundation_handle, CFRelease);
+ V(core_foundation_handle, CFRunLoopAddSource);
+ V(core_foundation_handle, CFRunLoopGetCurrent);
+ V(core_foundation_handle, CFRunLoopRemoveSource);
+ V(core_foundation_handle, CFRunLoopRun);
+ V(core_foundation_handle, CFRunLoopSourceCreate);
+ V(core_foundation_handle, CFRunLoopSourceSignal);
+ V(core_foundation_handle, CFRunLoopStop);
+ V(core_foundation_handle, CFRunLoopWakeUp);
+ V(core_foundation_handle, CFStringCreateWithFileSystemRepresentation);
+ V(core_foundation_handle, CFStringGetSystemEncoding);
+ V(core_foundation_handle, kCFRunLoopDefaultMode);
+ V(core_services_handle, FSEventStreamCreate);
+ V(core_services_handle, FSEventStreamFlushSync);
+ V(core_services_handle, FSEventStreamInvalidate);
+ V(core_services_handle, FSEventStreamRelease);
+ V(core_services_handle, FSEventStreamScheduleWithRunLoop);
+ V(core_services_handle, FSEventStreamStart);
+ V(core_services_handle, FSEventStreamStop);
+#undef V
+ err = 0;
+
+out:
+ if (err && core_services_handle != NULL) {
+ dlclose(core_services_handle);
+ core_services_handle = NULL;
+ }
+
+ if (err && core_foundation_handle != NULL) {
+ dlclose(core_foundation_handle);
+ core_foundation_handle = NULL;
+ }
+
+ pthread_mutex_unlock(&global_init_mutex);
+ return err;
+}
+
+
+/* Runs in UV loop */
+static int uv__fsevents_loop_init(uv_loop_t* loop) {
+ CFRunLoopSourceContext ctx;
+ uv__cf_loop_state_t* state;
+ pthread_attr_t attr_storage;
+ pthread_attr_t* attr;
+ int err;
+
+ if (loop->cf_state != NULL)
+ return 0;
+
+ err = uv__fsevents_global_init();
+ if (err)
+ return err;
+
+ state = uv__calloc(1, sizeof(*state));
+ if (state == NULL)
+ return -ENOMEM;
+
+ err = uv_mutex_init(&loop->cf_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_sem_init(&loop->cf_sem, 0);
+ if (err)
+ goto fail_sem_init;
+
+ QUEUE_INIT(&loop->cf_signals);
+
+ err = uv_sem_init(&state->fsevent_sem, 0);
+ if (err)
+ goto fail_fsevent_sem_init;
+
+ err = uv_mutex_init(&state->fsevent_mutex);
+ if (err)
+ goto fail_fsevent_mutex_init;
+
+ QUEUE_INIT(&state->fsevent_handles);
+ state->fsevent_need_reschedule = 0;
+ state->fsevent_handle_count = 0;
+
+ memset(&ctx, 0, sizeof(ctx));
+ ctx.info = loop;
+ ctx.perform = uv__cf_loop_cb;
+ state->signal_source = pCFRunLoopSourceCreate(NULL, 0, &ctx);
+ if (state->signal_source == NULL) {
+ err = -ENOMEM;
+ goto fail_signal_source_create;
+ }
+
+ /* In the unlikely event that pthread_attr_init() fails, create the thread
+ * with the default stack size. We'll use a little more address space but
+ * that in itself is not a fatal error.
+ */
+ attr = &attr_storage;
+ if (pthread_attr_init(attr))
+ attr = NULL;
+
+ if (attr != NULL)
+ if (pthread_attr_setstacksize(attr, 4 * PTHREAD_STACK_MIN))
+ abort();
+
+ loop->cf_state = state;
+
+ /* uv_thread_t is an alias for pthread_t. */
+ err = -pthread_create(&loop->cf_thread, attr, uv__cf_loop_runner, loop);
+
+ if (attr != NULL)
+ pthread_attr_destroy(attr);
+
+ if (err)
+ goto fail_thread_create;
+
+ /* Synchronize threads */
+ uv_sem_wait(&loop->cf_sem);
+ return 0;
+
+fail_thread_create:
+ loop->cf_state = NULL;
+
+fail_signal_source_create:
+ uv_mutex_destroy(&state->fsevent_mutex);
+
+fail_fsevent_mutex_init:
+ uv_sem_destroy(&state->fsevent_sem);
+
+fail_fsevent_sem_init:
+ uv_sem_destroy(&loop->cf_sem);
+
+fail_sem_init:
+ uv_mutex_destroy(&loop->cf_mutex);
+
+fail_mutex_init:
+ uv__free(state);
+ return err;
+}
+
+
+/* Runs in UV loop */
+void uv__fsevents_loop_delete(uv_loop_t* loop) {
+ uv__cf_loop_signal_t* s;
+ uv__cf_loop_state_t* state;
+ QUEUE* q;
+
+ if (loop->cf_state == NULL)
+ return;
+
+ if (uv__cf_loop_signal(loop, NULL, kUVCFLoopSignalRegular) != 0)
+ abort();
+
+ uv_thread_join(&loop->cf_thread);
+ uv_sem_destroy(&loop->cf_sem);
+ uv_mutex_destroy(&loop->cf_mutex);
+
+ /* Free any remaining data */
+ while (!QUEUE_EMPTY(&loop->cf_signals)) {
+ q = QUEUE_HEAD(&loop->cf_signals);
+ s = QUEUE_DATA(q, uv__cf_loop_signal_t, member);
+ QUEUE_REMOVE(q);
+ uv__free(s);
+ }
+
+ /* Destroy state */
+ state = loop->cf_state;
+ uv_sem_destroy(&state->fsevent_sem);
+ uv_mutex_destroy(&state->fsevent_mutex);
+ pCFRelease(state->signal_source);
+ uv__free(state);
+ loop->cf_state = NULL;
+}
+
+
+/* Runs in CF thread. This is the CF loop's body */
+static void* uv__cf_loop_runner(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+
+ loop = arg;
+ state = loop->cf_state;
+ state->loop = pCFRunLoopGetCurrent();
+
+ pCFRunLoopAddSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ uv_sem_post(&loop->cf_sem);
+
+ pCFRunLoopRun();
+ pCFRunLoopRemoveSource(state->loop,
+ state->signal_source,
+ *pkCFRunLoopDefaultMode);
+
+ return NULL;
+}
+
+
+/* Runs in CF thread, executed after `uv__cf_loop_signal()` */
+static void uv__cf_loop_cb(void* arg) {
+ uv_loop_t* loop;
+ uv__cf_loop_state_t* state;
+ QUEUE* item;
+ QUEUE split_head;
+ uv__cf_loop_signal_t* s;
+
+ loop = arg;
+ state = loop->cf_state;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_MOVE(&loop->cf_signals, &split_head);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ while (!QUEUE_EMPTY(&split_head)) {
+ item = QUEUE_HEAD(&split_head);
+ QUEUE_REMOVE(item);
+
+ s = QUEUE_DATA(item, uv__cf_loop_signal_t, member);
+
+ /* This was a termination signal */
+ if (s->handle == NULL)
+ pCFRunLoopStop(state->loop);
+ else
+ uv__fsevents_reschedule(s->handle, s->type);
+
+ uv__free(s);
+ }
+}
+
+
+/* Runs in UV loop to notify CF thread */
+int uv__cf_loop_signal(uv_loop_t* loop,
+ uv_fs_event_t* handle,
+ uv__cf_loop_signal_type_t type) {
+ uv__cf_loop_signal_t* item;
+ uv__cf_loop_state_t* state;
+
+ item = uv__malloc(sizeof(*item));
+ if (item == NULL)
+ return -ENOMEM;
+
+ item->handle = handle;
+ item->type = type;
+
+ uv_mutex_lock(&loop->cf_mutex);
+ QUEUE_INSERT_TAIL(&loop->cf_signals, &item->member);
+ uv_mutex_unlock(&loop->cf_mutex);
+
+ state = loop->cf_state;
+ assert(state != NULL);
+ pCFRunLoopSourceSignal(state->signal_source);
+ pCFRunLoopWakeUp(state->loop);
+
+ return 0;
+}
+
+
+/* Runs in UV loop to initialize handle */
+int uv__fsevents_init(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ err = uv__fsevents_loop_init(handle->loop);
+ if (err)
+ return err;
+
+ /* Get absolute path to file */
+ handle->realpath = realpath(handle->path, NULL);
+ if (handle->realpath == NULL)
+ return -errno;
+ handle->realpath_len = strlen(handle->realpath);
+
+ /* Initialize event queue */
+ QUEUE_INIT(&handle->cf_events);
+ handle->cf_error = 0;
+
+ /*
+ * Events will occur in other thread.
+ * Initialize callback for getting them back into event loop's thread
+ */
+ handle->cf_cb = uv__malloc(sizeof(*handle->cf_cb));
+ if (handle->cf_cb == NULL) {
+ err = -ENOMEM;
+ goto fail_cf_cb_malloc;
+ }
+
+ handle->cf_cb->data = handle;
+ uv_async_init(handle->loop, handle->cf_cb, uv__fsevents_cb);
+ handle->cf_cb->flags |= UV__HANDLE_INTERNAL;
+ uv_unref((uv_handle_t*) handle->cf_cb);
+
+ err = uv_mutex_init(&handle->cf_mutex);
+ if (err)
+ goto fail_cf_mutex_init;
+
+ /* Insert handle into the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_INSERT_TAIL(&state->fsevent_handles, &handle->cf_member);
+ state->fsevent_handle_count++;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalRegular);
+ if (err)
+ goto fail_loop_signal;
+
+ return 0;
+
+fail_loop_signal:
+ uv_mutex_destroy(&handle->cf_mutex);
+
+fail_cf_mutex_init:
+ uv__free(handle->cf_cb);
+ handle->cf_cb = NULL;
+
+fail_cf_cb_malloc:
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return err;
+}
+
+
+/* Runs in UV loop to de-initialize handle */
+int uv__fsevents_close(uv_fs_event_t* handle) {
+ int err;
+ uv__cf_loop_state_t* state;
+
+ if (handle->cf_cb == NULL)
+ return -EINVAL;
+
+ /* Remove handle from the list */
+ state = handle->loop->cf_state;
+ uv_mutex_lock(&state->fsevent_mutex);
+ QUEUE_REMOVE(&handle->cf_member);
+ state->fsevent_handle_count--;
+ state->fsevent_need_reschedule = 1;
+ uv_mutex_unlock(&state->fsevent_mutex);
+
+ /* Reschedule FSEventStream */
+ assert(handle != NULL);
+ err = uv__cf_loop_signal(handle->loop, handle, kUVCFLoopSignalClosing);
+ if (err)
+ return -err;
+
+ /* Wait for deinitialization */
+ uv_sem_wait(&state->fsevent_sem);
+
+ uv_close((uv_handle_t*) handle->cf_cb, (uv_close_cb) uv__free);
+ handle->cf_cb = NULL;
+
+ /* Free data in queue */
+ UV__FSEVENTS_PROCESS(handle, {
+ /* NOP */
+ });
+
+ uv_mutex_destroy(&handle->cf_mutex);
+ uv__free(handle->realpath);
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+
+ return 0;
+}
+
+#endif /* TARGET_OS_IPHONE */
diff --git a/Utilities/cmlibuv/src/unix/getaddrinfo.c b/Utilities/cmlibuv/src/unix/getaddrinfo.c
new file mode 100644
index 000000000..2049aea2f
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/getaddrinfo.c
@@ -0,0 +1,202 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* Expose glibc-specific EAI_* error codes. Needs to be defined before we
+ * include any headers.
+ */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE
+#endif
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stddef.h> /* NULL */
+#include <stdlib.h>
+#include <string.h>
+
+/* EAI_* constants. */
+#include <netdb.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+#if defined(EAI_ADDRFAMILY)
+ case EAI_ADDRFAMILY: return UV_EAI_ADDRFAMILY;
+#endif
+#if defined(EAI_AGAIN)
+ case EAI_AGAIN: return UV_EAI_AGAIN;
+#endif
+#if defined(EAI_BADFLAGS)
+ case EAI_BADFLAGS: return UV_EAI_BADFLAGS;
+#endif
+#if defined(EAI_BADHINTS)
+ case EAI_BADHINTS: return UV_EAI_BADHINTS;
+#endif
+#if defined(EAI_CANCELED)
+ case EAI_CANCELED: return UV_EAI_CANCELED;
+#endif
+#if defined(EAI_FAIL)
+ case EAI_FAIL: return UV_EAI_FAIL;
+#endif
+#if defined(EAI_FAMILY)
+ case EAI_FAMILY: return UV_EAI_FAMILY;
+#endif
+#if defined(EAI_MEMORY)
+ case EAI_MEMORY: return UV_EAI_MEMORY;
+#endif
+#if defined(EAI_NODATA)
+ case EAI_NODATA: return UV_EAI_NODATA;
+#endif
+#if defined(EAI_NONAME)
+# if !defined(EAI_NODATA) || EAI_NODATA != EAI_NONAME
+ case EAI_NONAME: return UV_EAI_NONAME;
+# endif
+#endif
+#if defined(EAI_OVERFLOW)
+ case EAI_OVERFLOW: return UV_EAI_OVERFLOW;
+#endif
+#if defined(EAI_PROTOCOL)
+ case EAI_PROTOCOL: return UV_EAI_PROTOCOL;
+#endif
+#if defined(EAI_SERVICE)
+ case EAI_SERVICE: return UV_EAI_SERVICE;
+#endif
+#if defined(EAI_SOCKTYPE)
+ case EAI_SOCKTYPE: return UV_EAI_SOCKTYPE;
+#endif
+#if defined(EAI_SYSTEM)
+ case EAI_SYSTEM: return -errno;
+#endif
+ }
+ assert(!"unknown EAI_* error code");
+ abort();
+ return 0; /* Pacify compiler. */
+}
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ err = getaddrinfo(req->hostname, req->service, req->hints, &req->addrinfo);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ /* See initialization in uv_getaddrinfo(). */
+ if (req->hints)
+ uv__free(req->hints);
+ else if (req->service)
+ uv__free(req->service);
+ else if (req->hostname)
+ uv__free(req->hostname);
+ else
+ assert(0);
+
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ }
+
+ if (req->cb)
+ req->cb(req, req->retcode, req->addrinfo);
+}
+
+
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb cb,
+ const char* hostname,
+ const char* service,
+ const struct addrinfo* hints) {
+ size_t hostname_len;
+ size_t service_len;
+ size_t hints_len;
+ size_t len;
+ char* buf;
+
+ if (req == NULL || (hostname == NULL && service == NULL))
+ return -EINVAL;
+
+ hostname_len = hostname ? strlen(hostname) + 1 : 0;
+ service_len = service ? strlen(service) + 1 : 0;
+ hints_len = hints ? sizeof(*hints) : 0;
+ buf = uv__malloc(hostname_len + service_len + hints_len);
+
+ if (buf == NULL)
+ return -ENOMEM;
+
+ uv__req_init(loop, req, UV_GETADDRINFO);
+ req->loop = loop;
+ req->cb = cb;
+ req->addrinfo = NULL;
+ req->hints = NULL;
+ req->service = NULL;
+ req->hostname = NULL;
+ req->retcode = 0;
+
+ /* order matters, see uv_getaddrinfo_done() */
+ len = 0;
+
+ if (hints) {
+ req->hints = memcpy(buf + len, hints, sizeof(*hints));
+ len += sizeof(*hints);
+ }
+
+ if (service) {
+ req->service = memcpy(buf + len, service, service_len);
+ len += service_len;
+ }
+
+ if (hostname)
+ req->hostname = memcpy(buf + len, hostname, hostname_len);
+
+ if (cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ if (ai)
+ freeaddrinfo(ai);
+}
diff --git a/Utilities/cmlibuv/src/unix/getnameinfo.c b/Utilities/cmlibuv/src/unix/getnameinfo.c
new file mode 100644
index 000000000..b2879d69b
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/getnameinfo.c
@@ -0,0 +1,120 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ int err;
+ socklen_t salen;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+
+ if (req->storage.ss_family == AF_INET)
+ salen = sizeof(struct sockaddr_in);
+ else if (req->storage.ss_family == AF_INET6)
+ salen = sizeof(struct sockaddr_in6);
+ else
+ abort();
+
+ err = getnameinfo((struct sockaddr*) &req->storage,
+ salen,
+ req->host,
+ sizeof(req->host),
+ req->service,
+ sizeof(req->service),
+ req->flags);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == -ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ uv__req_init(loop, (uv_req_t*)req, UV_GETNAMEINFO);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->type = UV_GETNAMEINFO;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/Utilities/cmlibuv/src/unix/internal.h b/Utilities/cmlibuv/src/unix/internal.h
new file mode 100644
index 000000000..2e3afa6c8
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/internal.h
@@ -0,0 +1,326 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_UNIX_INTERNAL_H_
+#define UV_UNIX_INTERNAL_H_
+
+#include "uv-common.h"
+
+#include <assert.h>
+#include <stdlib.h> /* abort */
+#include <string.h> /* strrchr */
+#include <fcntl.h> /* O_CLOEXEC, may be */
+#include <stdio.h>
+
+#if defined(__STRICT_ANSI__)
+# define inline __inline
+#endif
+
+#if defined(__linux__)
+# include "linux-syscalls.h"
+#endif /* __linux__ */
+
+#if defined(__MVS__)
+# include "os390-syscalls.h"
+#endif /* __MVS__ */
+
+#if defined(__sun)
+# include <sys/port.h>
+# include <port.h>
+#endif /* __sun */
+
+#if defined(_AIX)
+# define reqevents events
+# define rtnevents revents
+# include <sys/poll.h>
+#else
+# include <poll.h>
+#endif /* _AIX */
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <AvailabilityMacros.h>
+#endif
+
+#if defined(__ANDROID__)
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset);
+# ifdef pthread_sigmask
+# undef pthread_sigmask
+# endif
+# define pthread_sigmask(how, set, oldset) uv__pthread_sigmask(how, set, oldset)
+#endif
+
+#define ACCESS_ONCE(type, var) \
+ (*(volatile type*) &(var))
+
+#define ROUND_UP(a, b) \
+ ((a) % (b) ? ((a) + (b)) - ((a) % (b)) : (a))
+
+#define UNREACHABLE() \
+ do { \
+ assert(0 && "unreachable code"); \
+ abort(); \
+ } \
+ while (0)
+
+#define SAVE_ERRNO(block) \
+ do { \
+ int _saved_errno = errno; \
+ do { block; } while (0); \
+ errno = _saved_errno; \
+ } \
+ while (0)
+
+/* The __clang__ and __INTEL_COMPILER checks are superfluous because they
+ * define __GNUC__. They are here to convey to you, dear reader, that these
+ * macros are enabled when compiling with clang or icc.
+ */
+#if defined(__clang__) || \
+ defined(__GNUC__) || \
+ defined(__INTEL_COMPILER) || \
+ defined(__SUNPRO_C)
+# define UV_DESTRUCTOR(declaration) __attribute__((destructor)) declaration
+# define UV_UNUSED(declaration) __attribute__((unused)) declaration
+#else
+# define UV_DESTRUCTOR(declaration) declaration
+# define UV_UNUSED(declaration) declaration
+#endif
+
+/* Leans on the fact that, on Linux, POLLRDHUP == EPOLLRDHUP. */
+#ifdef POLLRDHUP
+# define UV__POLLRDHUP POLLRDHUP
+#else
+# define UV__POLLRDHUP 0x2000
+#endif
+
+#if !defined(O_CLOEXEC) && defined(__FreeBSD__)
+/*
+ * It may be that we are just missing `__POSIX_VISIBLE >= 200809`.
+ * Try using fixed value const and give up, if it doesn't work
+ */
+# define O_CLOEXEC 0x00100000
+#endif
+
+typedef struct uv__stream_queued_fds_s uv__stream_queued_fds_t;
+
+/* handle flags */
+enum {
+ UV_CLOSING = 0x01, /* uv_close() called but not finished. */
+ UV_CLOSED = 0x02, /* close(2) finished. */
+ UV_STREAM_READING = 0x04, /* uv_read_start() called. */
+ UV_STREAM_SHUTTING = 0x08, /* uv_shutdown() called but not complete. */
+ UV_STREAM_SHUT = 0x10, /* Write side closed. */
+ UV_STREAM_READABLE = 0x20, /* The stream is readable */
+ UV_STREAM_WRITABLE = 0x40, /* The stream is writable */
+ UV_STREAM_BLOCKING = 0x80, /* Synchronous writes. */
+ UV_STREAM_READ_PARTIAL = 0x100, /* read(2) read less than requested. */
+ UV_STREAM_READ_EOF = 0x200, /* read(2) read EOF. */
+ UV_TCP_NODELAY = 0x400, /* Disable Nagle. */
+ UV_TCP_KEEPALIVE = 0x800, /* Turn on keep-alive. */
+ UV_TCP_SINGLE_ACCEPT = 0x1000, /* Only accept() when idle. */
+ UV_HANDLE_IPV6 = 0x10000, /* Handle is bound to a IPv6 socket. */
+ UV_UDP_PROCESSING = 0x20000, /* Handle is running the send callback queue. */
+ UV_HANDLE_BOUND = 0x40000 /* Handle is bound to an address and port */
+};
+
+/* loop flags */
+enum {
+ UV_LOOP_BLOCK_SIGPROF = 1
+};
+
+typedef enum {
+ UV_CLOCK_PRECISE = 0, /* Use the highest resolution clock available. */
+ UV_CLOCK_FAST = 1 /* Use the fastest clock with <= 1ms granularity. */
+} uv_clocktype_t;
+
+struct uv__stream_queued_fds_s {
+ unsigned int size;
+ unsigned int offset;
+ int fds[1];
+};
+
+
+#if defined(_AIX) || \
+ defined(__APPLE__) || \
+ defined(__DragonFly__) || \
+ defined(__FreeBSD__) || \
+ defined(__FreeBSD_kernel__) || \
+ defined(__linux__) || \
+ defined(__OpenBSD__)
+#define uv__cloexec uv__cloexec_ioctl
+#define uv__nonblock uv__nonblock_ioctl
+#else
+#define uv__cloexec uv__cloexec_fcntl
+#define uv__nonblock uv__nonblock_fcntl
+#endif
+
+/* core */
+int uv__cloexec_ioctl(int fd, int set);
+int uv__cloexec_fcntl(int fd, int set);
+int uv__nonblock_ioctl(int fd, int set);
+int uv__nonblock_fcntl(int fd, int set);
+int uv__close(int fd);
+int uv__close_nocheckstdio(int fd);
+int uv__socket(int domain, int type, int protocol);
+int uv__dup(int fd);
+ssize_t uv__recvmsg(int fd, struct msghdr *msg, int flags);
+void uv__make_close_pending(uv_handle_t* handle);
+int uv__getiovmax(void);
+
+void uv__io_init(uv__io_t* w, uv__io_cb cb, int fd);
+void uv__io_start(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_stop(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+void uv__io_close(uv_loop_t* loop, uv__io_t* w);
+void uv__io_feed(uv_loop_t* loop, uv__io_t* w);
+int uv__io_active(const uv__io_t* w, unsigned int events);
+int uv__io_check_fd(uv_loop_t* loop, int fd);
+void uv__io_poll(uv_loop_t* loop, int timeout); /* in milliseconds or -1 */
+int uv__io_fork(uv_loop_t* loop);
+
+/* async */
+void uv__async_stop(uv_loop_t* loop);
+int uv__async_fork(uv_loop_t* loop);
+
+
+/* loop */
+void uv__run_idle(uv_loop_t* loop);
+void uv__run_check(uv_loop_t* loop);
+void uv__run_prepare(uv_loop_t* loop);
+
+/* stream */
+void uv__stream_init(uv_loop_t* loop, uv_stream_t* stream,
+ uv_handle_type type);
+int uv__stream_open(uv_stream_t*, int fd, int flags);
+void uv__stream_destroy(uv_stream_t* stream);
+#if defined(__APPLE__)
+int uv__stream_try_select(uv_stream_t* stream, int* fd);
+#endif /* defined(__APPLE__) */
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+int uv__accept(int sockfd);
+int uv__dup2_cloexec(int oldfd, int newfd);
+int uv__open_cloexec(const char* path, int flags);
+
+/* tcp */
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb);
+int uv__tcp_nodelay(int fd, int on);
+int uv__tcp_keepalive(int fd, int on, unsigned int delay);
+
+/* pipe */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+
+/* timer */
+void uv__run_timers(uv_loop_t* loop);
+int uv__next_timeout(const uv_loop_t* loop);
+
+/* signal */
+void uv__signal_close(uv_signal_t* handle);
+void uv__signal_global_once_init(void);
+void uv__signal_loop_cleanup(uv_loop_t* loop);
+int uv__signal_loop_fork(uv_loop_t* loop);
+
+/* platform specific */
+uint64_t uv__hrtime(uv_clocktype_t type);
+int uv__kqueue_init(uv_loop_t* loop);
+int uv__platform_loop_init(uv_loop_t* loop);
+void uv__platform_loop_delete(uv_loop_t* loop);
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd);
+
+/* various */
+void uv__async_close(uv_async_t* handle);
+void uv__check_close(uv_check_t* handle);
+void uv__fs_event_close(uv_fs_event_t* handle);
+void uv__idle_close(uv_idle_t* handle);
+void uv__pipe_close(uv_pipe_t* handle);
+void uv__poll_close(uv_poll_t* handle);
+void uv__prepare_close(uv_prepare_t* handle);
+void uv__process_close(uv_process_t* handle);
+void uv__stream_close(uv_stream_t* handle);
+void uv__tcp_close(uv_tcp_t* handle);
+void uv__timer_close(uv_timer_t* handle);
+void uv__udp_close(uv_udp_t* handle);
+void uv__udp_finish_close(uv_udp_t* handle);
+uv_handle_type uv__handle_type(int fd);
+FILE* uv__open_file(const char* path);
+int uv__getpwuid_r(uv_passwd_t* pwd);
+
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle);
+#define uv__stream_fd(handle) (uv___stream_fd((const uv_stream_t*) (handle)))
+#else
+#define uv__stream_fd(handle) ((handle)->io_watcher.fd)
+#endif /* defined(__APPLE__) */
+
+#ifdef UV__O_NONBLOCK
+# define UV__F_NONBLOCK UV__O_NONBLOCK
+#else
+# define UV__F_NONBLOCK 1
+#endif
+
+int uv__make_socketpair(int fds[2], int flags);
+int uv__make_pipe(int fds[2], int flags);
+
+#if defined(__APPLE__)
+
+int uv__fsevents_init(uv_fs_event_t* handle);
+int uv__fsevents_close(uv_fs_event_t* handle);
+void uv__fsevents_loop_delete(uv_loop_t* loop);
+
+/* OSX < 10.7 has no file events, polyfill them */
+#ifndef MAC_OS_X_VERSION_10_7
+
+static const int kFSEventStreamCreateFlagFileEvents = 0x00000010;
+static const int kFSEventStreamEventFlagItemCreated = 0x00000100;
+static const int kFSEventStreamEventFlagItemRemoved = 0x00000200;
+static const int kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400;
+static const int kFSEventStreamEventFlagItemRenamed = 0x00000800;
+static const int kFSEventStreamEventFlagItemModified = 0x00001000;
+static const int kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000;
+static const int kFSEventStreamEventFlagItemChangeOwner = 0x00004000;
+static const int kFSEventStreamEventFlagItemXattrMod = 0x00008000;
+static const int kFSEventStreamEventFlagItemIsFile = 0x00010000;
+static const int kFSEventStreamEventFlagItemIsDir = 0x00020000;
+static const int kFSEventStreamEventFlagItemIsSymlink = 0x00040000;
+
+#endif /* __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070 */
+
+#endif /* defined(__APPLE__) */
+
+UV_UNUSED(static void uv__update_time(uv_loop_t* loop)) {
+ /* Use a fast time source if available. We only need millisecond precision.
+ */
+ loop->time = uv__hrtime(UV_CLOCK_FAST) / 1000000;
+}
+
+UV_UNUSED(static char* uv__basename_r(const char* path)) {
+ char* s;
+
+ s = strrchr(path, '/');
+ if (s == NULL)
+ return (char*) path;
+
+ return s + 1;
+}
+
+#if defined(__linux__)
+int uv__inotify_fork(uv_loop_t* loop, void* old_watchers);
+#endif
+
+#endif /* UV_UNIX_INTERNAL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/kqueue.c b/Utilities/cmlibuv/src/unix/kqueue.c
new file mode 100644
index 000000000..6bc60bbe4
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/kqueue.c
@@ -0,0 +1,497 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags);
+
+
+int uv__kqueue_init(uv_loop_t* loop) {
+ loop->backend_fd = kqueue();
+ if (loop->backend_fd == -1)
+ return -errno;
+
+ uv__cloexec(loop->backend_fd, 1);
+
+ return 0;
+}
+
+
+static int uv__has_forked_with_cfrunloop;
+
+int uv__io_fork(uv_loop_t* loop) {
+ int err;
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ err = uv__kqueue_init(loop);
+ if (err)
+ return err;
+
+#if defined(__APPLE__)
+ if (loop->cf_state != NULL) {
+ /* We cannot start another CFRunloop and/or thread in the child
+ process; CF aborts if you try or if you try to touch the thread
+ at all to kill it. So the best we can do is ignore it from now
+ on. This means we can't watch directories in the same way
+ anymore (like other BSDs). It also means we cannot properly
+ clean up the allocated resources; calling
+ uv__fsevents_loop_delete from uv_loop_close will crash the
+ process. So we sidestep the issue by pretending like we never
+ started it in the first place.
+ */
+ uv__has_forked_with_cfrunloop = 1;
+ uv__free(loop->cf_state);
+ loop->cf_state = NULL;
+ }
+#endif
+ return err;
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct kevent ev;
+ int rc;
+
+ rc = 0;
+ EV_SET(&ev, fd, EVFILT_READ, EV_ADD, 0, 0, 0);
+ if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
+ rc = -errno;
+
+ EV_SET(&ev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0);
+ if (rc == 0)
+ if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
+ abort();
+
+ return rc;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct kevent events[1024];
+ struct kevent* ev;
+ struct timespec spec;
+ unsigned int nevents;
+ unsigned int revents;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ int have_signals;
+ int filter;
+ int fflags;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ nevents = 0;
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ if ((w->events & POLLIN) == 0 && (w->pevents & POLLIN) != 0) {
+ filter = EVFILT_READ;
+ fflags = 0;
+ op = EV_ADD;
+
+ if (w->cb == uv__fs_event) {
+ filter = EVFILT_VNODE;
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+ op = EV_ADD | EV_ONESHOT; /* Stop the event from firing repeatedly. */
+ }
+
+ EV_SET(events + nevents, w->fd, filter, op, fflags, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ if ((w->events & POLLOUT) == 0 && (w->pevents & POLLOUT) != 0) {
+ EV_SET(events + nevents, w->fd, EVFILT_WRITE, EV_ADD, 0, 0, 0);
+
+ if (++nevents == ARRAY_SIZE(events)) {
+ if (kevent(loop->backend_fd, events, nevents, NULL, 0, NULL))
+ abort();
+ nevents = 0;
+ }
+ }
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;; nevents = 0) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ nfds = kevent(loop->backend_fd,
+ events,
+ nevents,
+ events,
+ ARRAY_SIZE(events),
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ have_signals = 0;
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ ev = events + i;
+ fd = ev->ident;
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it. */
+ /* TODO batch up */
+ struct kevent events[1];
+
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != EBADF && errno != ENOENT)
+ abort();
+
+ continue;
+ }
+
+ if (ev->filter == EVFILT_VNODE) {
+ assert(w->events == POLLIN);
+ assert(w->pevents == POLLIN);
+ w->cb(loop, w, ev->fflags); /* XXX always uv__fs_event() */
+ nevents++;
+ continue;
+ }
+
+ revents = 0;
+
+ if (ev->filter == EVFILT_READ) {
+ if (w->pevents & POLLIN) {
+ revents |= POLLIN;
+ w->rcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->filter == EVFILT_WRITE) {
+ if (w->pevents & POLLOUT) {
+ revents |= POLLOUT;
+ w->wcount = ev->data;
+ } else {
+ /* TODO batch up */
+ struct kevent events[1];
+ EV_SET(events + 0, fd, ev->filter, EV_DELETE, 0, 0, 0);
+ if (kevent(loop->backend_fd, events, 1, NULL, 0, NULL))
+ if (errno != ENOENT)
+ abort();
+ }
+ }
+
+ if (ev->flags & EV_ERROR)
+ revents |= POLLERR;
+
+ if ((ev->flags & EV_EOF) && (w->pevents & UV__POLLRDHUP))
+ revents |= UV__POLLRDHUP;
+
+ if (revents == 0)
+ continue;
+
+ /* Run signal watchers last. This also affects child process watchers
+ * because those are implemented in terms of signal watchers.
+ */
+ if (w == &loop->signal_io_watcher)
+ have_signals = 1;
+ else
+ w->cb(loop, w, revents);
+
+ nevents++;
+ }
+
+ if (have_signals != 0)
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct kevent* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct kevent*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].ident == fd)
+ events[i].ident = -1;
+}
+
+
+static void uv__fs_event(uv_loop_t* loop, uv__io_t* w, unsigned int fflags) {
+ uv_fs_event_t* handle;
+ struct kevent ev;
+ int events;
+ const char* path;
+#if defined(F_GETPATH)
+ /* MAXPATHLEN == PATH_MAX but the former is what XNU calls it internally. */
+ char pathbuf[MAXPATHLEN];
+#endif
+
+ handle = container_of(w, uv_fs_event_t, event_watcher);
+
+ if (fflags & (NOTE_ATTRIB | NOTE_EXTEND))
+ events = UV_CHANGE;
+ else
+ events = UV_RENAME;
+
+ path = NULL;
+#if defined(F_GETPATH)
+ /* Also works when the file has been unlinked from the file system. Passing
+ * in the path when the file has been deleted is arguably a little strange
+ * but it's consistent with what the inotify backend does.
+ */
+ if (fcntl(handle->event_watcher.fd, F_GETPATH, pathbuf) == 0)
+ path = uv__basename_r(pathbuf);
+#endif
+ handle->cb(handle, path, events, 0);
+
+ if (handle->event_watcher.fd == -1)
+ return;
+
+ /* Watcher operates in one-shot mode, re-arm it. */
+ fflags = NOTE_ATTRIB | NOTE_WRITE | NOTE_RENAME
+ | NOTE_DELETE | NOTE_EXTEND | NOTE_REVOKE;
+
+ EV_SET(&ev, w->fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, fflags, 0, 0);
+
+ if (kevent(loop->backend_fd, &ev, 1, NULL, 0, NULL))
+ abort();
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+#if defined(__APPLE__)
+ struct stat statbuf;
+#endif /* defined(__APPLE__) */
+ int fd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ /* TODO open asynchronously - but how do we report back errors? */
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ uv__handle_start(handle);
+ uv__io_init(&handle->event_watcher, uv__fs_event, fd);
+ handle->path = uv__strdup(path);
+ handle->cb = cb;
+
+#if defined(__APPLE__)
+ if (uv__has_forked_with_cfrunloop)
+ goto fallback;
+
+ /* Nullify field to perform checks later */
+ handle->cf_cb = NULL;
+ handle->realpath = NULL;
+ handle->realpath_len = 0;
+ handle->cf_flags = flags;
+
+ if (fstat(fd, &statbuf))
+ goto fallback;
+ /* FSEvents works only with directories */
+ if (!(statbuf.st_mode & S_IFDIR))
+ goto fallback;
+
+ /* The fallback fd is no longer needed */
+ uv__close(fd);
+ handle->event_watcher.fd = -1;
+
+ return uv__fsevents_init(handle);
+
+fallback:
+#endif /* defined(__APPLE__) */
+
+ uv__io_start(handle->loop, &handle->event_watcher, POLLIN);
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ uv__handle_stop(handle);
+
+#if defined(__APPLE__)
+ if (uv__has_forked_with_cfrunloop || uv__fsevents_close(handle))
+#endif /* defined(__APPLE__) */
+ {
+ uv__io_close(handle->loop, &handle->event_watcher);
+ }
+
+ uv__free(handle->path);
+ handle->path = NULL;
+
+ if (handle->event_watcher.fd != -1) {
+ /* When FSEvents is used, we don't use the event_watcher's fd under certain
+ * confitions. (see uv_fs_event_start) */
+ uv__close(handle->event_watcher.fd);
+ handle->event_watcher.fd = -1;
+ }
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/linux-core.c b/Utilities/cmlibuv/src/unix/linux-core.c
new file mode 100644
index 000000000..2866e9385
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/linux-core.c
@@ -0,0 +1,951 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/* We lean on the fact that POLL{IN,OUT,ERR,HUP} correspond with their
+ * EPOLL* counterparts. We use the POLL* variants in this file because that
+ * is what libuv uses elsewhere and it avoids a dependency on <sys/epoll.h>.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <net/if.h>
+#include <sys/param.h>
+#include <sys/prctl.h>
+#include <sys/sysinfo.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+
+#define HAVE_IFADDRS_H 1
+
+#ifdef __UCLIBC__
+# if __UCLIBC_MAJOR__ < 0 && __UCLIBC_MINOR__ < 9 && __UCLIBC_SUBLEVEL__ < 32
+# undef HAVE_IFADDRS_H
+# endif
+#endif
+
+#ifdef HAVE_IFADDRS_H
+# if defined(__ANDROID__)
+# include "android-ifaddrs.h"
+# else
+# include <ifaddrs.h>
+# endif
+# include <sys/socket.h>
+# include <net/ethernet.h>
+# include <netpacket/packet.h>
+#endif /* HAVE_IFADDRS_H */
+
+/* Available from 2.6.32 onwards. */
+#ifndef CLOCK_MONOTONIC_COARSE
+# define CLOCK_MONOTONIC_COARSE 6
+#endif
+
+/* This is rather annoying: CLOCK_BOOTTIME lives in <linux/time.h> but we can't
+ * include that file because it conflicts with <time.h>. We'll just have to
+ * define it ourselves.
+ */
+#ifndef CLOCK_BOOTTIME
+# define CLOCK_BOOTTIME 7
+#endif
+
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci);
+static int read_times(FILE* statfile_fp,
+ unsigned int numcpus,
+ uv_cpu_info_t* ci);
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci);
+static unsigned long read_cpufreq(unsigned int cpunum);
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int fd;
+
+ fd = uv__epoll_create1(UV__EPOLL_CLOEXEC);
+
+ /* epoll_create1() can fail either because it's not implemented (old kernel)
+ * or because it doesn't understand the EPOLL_CLOEXEC flag.
+ */
+ if (fd == -1 && (errno == ENOSYS || errno == EINVAL)) {
+ fd = uv__epoll_create(256);
+
+ if (fd != -1)
+ uv__cloexec(fd, 1);
+ }
+
+ loop->backend_fd = fd;
+ loop->inotify_fd = -1;
+ loop->inotify_watchers = NULL;
+
+ if (fd == -1)
+ return -errno;
+
+ return 0;
+}
+
+
+int uv__io_fork(uv_loop_t* loop) {
+ int err;
+ void* old_watchers;
+
+ old_watchers = loop->inotify_watchers;
+
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ uv__platform_loop_delete(loop);
+
+ err = uv__platform_loop_init(loop);
+ if (err)
+ return err;
+
+ return uv__inotify_fork(loop, old_watchers);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->inotify_fd == -1) return;
+ uv__io_stop(loop, &loop->inotify_read_watcher, POLLIN);
+ uv__close(loop->inotify_fd);
+ loop->inotify_fd = -1;
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct uv__epoll_event* events;
+ struct uv__epoll_event dummy;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct uv__epoll_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].data == fd)
+ events[i].data = -1;
+
+ /* Remove the file descriptor from the epoll.
+ * This avoids a problem where the same file description remains open
+ * in another process, causing repeated junk epoll events.
+ *
+ * We pass in a dummy epoll_event, to work around a bug in old kernels.
+ */
+ if (loop->backend_fd >= 0) {
+ /* Work around a bug in kernels 3.10 to 3.19 where passing a struct that
+ * has the EPOLLWAKEUP flag set generates spurious audit syslog warnings.
+ */
+ memset(&dummy, 0, sizeof(dummy));
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &dummy);
+ }
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct uv__epoll_event e;
+ int rc;
+
+ e.events = POLLIN;
+ e.data = -1;
+
+ rc = 0;
+ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_ADD, fd, &e))
+ if (errno != EEXIST)
+ rc = -errno;
+
+ if (rc == 0)
+ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, &e))
+ abort();
+
+ return rc;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ /* A bug in kernels < 2.6.37 makes timeouts larger than ~30 minutes
+ * effectively infinite on 32 bits architectures. To avoid blocking
+ * indefinitely, we cap the timeout and poll again if necessary.
+ *
+ * Note that "30 minutes" is a simplification because it depends on
+ * the value of CONFIG_HZ. The magic constant assumes CONFIG_HZ=1200,
+ * that being the largest value I have seen in the wild (and only once.)
+ */
+ static const int max_safe_timeout = 1789569;
+ static int no_epoll_pwait;
+ static int no_epoll_wait;
+ struct uv__epoll_event events[1024];
+ struct uv__epoll_event* pe;
+ struct uv__epoll_event e;
+ int real_timeout;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t sigset;
+ uint64_t sigmask;
+ uint64_t base;
+ int have_signals;
+ int nevents;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ e.events = w->pevents;
+ e.data = w->fd;
+
+ if (w->events == 0)
+ op = UV__EPOLL_CTL_ADD;
+ else
+ op = UV__EPOLL_CTL_MOD;
+
+ /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+ * events, skip the syscall and squelch the events after epoll_wait().
+ */
+ if (uv__epoll_ctl(loop->backend_fd, op, w->fd, &e)) {
+ if (errno != EEXIST)
+ abort();
+
+ assert(op == UV__EPOLL_CTL_ADD);
+
+ /* We've reactivated a file descriptor that's been watched before. */
+ if (uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_MOD, w->fd, &e))
+ abort();
+ }
+
+ w->events = w->pevents;
+ }
+
+ sigmask = 0;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGPROF);
+ sigmask |= 1 << (SIGPROF - 1);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+ real_timeout = timeout;
+
+ for (;;) {
+ /* See the comment for max_safe_timeout for an explanation of why
+ * this is necessary. Executive summary: kernel bug workaround.
+ */
+ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+ timeout = max_safe_timeout;
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_BLOCK, &sigset, NULL))
+ abort();
+
+ if (no_epoll_wait != 0 || (sigmask != 0 && no_epoll_pwait == 0)) {
+ nfds = uv__epoll_pwait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout,
+ sigmask);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_pwait = 1;
+ } else {
+ nfds = uv__epoll_wait(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ timeout);
+ if (nfds == -1 && errno == ENOSYS)
+ no_epoll_wait = 1;
+ }
+
+ if (sigmask != 0 && no_epoll_pwait != 0)
+ if (pthread_sigmask(SIG_UNBLOCK, &sigset, NULL))
+ abort();
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+
+ if (timeout == 0)
+ return;
+
+ /* We may have been inside the system call for longer than |timeout|
+ * milliseconds so we need to update the timestamp to avoid drift.
+ */
+ goto update_timeout;
+ }
+
+ if (nfds == -1) {
+ if (errno == ENOSYS) {
+ /* epoll_wait() or epoll_pwait() failed, try the other system call. */
+ assert(no_epoll_wait == 0 || no_epoll_pwait == 0);
+ continue;
+ }
+
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ have_signals = 0;
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->data;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ uv__epoll_ctl(loop->backend_fd, UV__EPOLL_CTL_DEL, fd, pe);
+ continue;
+ }
+
+ /* Give users only events they're interested in. Prevents spurious
+ * callbacks when previous callback invocation in this loop has stopped
+ * the current watcher. Also, filters out events that users has not
+ * requested us to watch.
+ */
+ pe->events &= w->pevents | POLLERR | POLLHUP;
+
+ /* Work around an epoll quirk where it sometimes reports just the
+ * EPOLLERR or EPOLLHUP event. In order to force the event loop to
+ * move forward, we merge in the read/write events that the watcher
+ * is interested in; uv__read() and uv__write() will then deal with
+ * the error or hangup in the usual fashion.
+ *
+ * Note to self: happens when epoll reports EPOLLIN|EPOLLHUP, the user
+ * reads the available data, calls uv_read_stop(), then sometime later
+ * calls uv_read_start() again. By then, libuv has forgotten about the
+ * hangup and the kernel won't report EPOLLIN again because there's
+ * nothing left to read. If anything, libuv is to blame here. The
+ * current hack is just a quick bandaid; to properly fix it, libuv
+ * needs to remember the error/hangup event. We should get that for
+ * free when we switch over to edge-triggered I/O.
+ */
+ if (pe->events == POLLERR || pe->events == POLLHUP)
+ pe->events |= w->pevents & (POLLIN | POLLOUT);
+
+ if (pe->events != 0) {
+ /* Run signal watchers last. This also affects child process watchers
+ * because those are implemented in terms of signal watchers.
+ */
+ if (w == &loop->signal_io_watcher)
+ have_signals = 1;
+ else
+ w->cb(loop, w, pe->events);
+
+ nevents++;
+ }
+ }
+
+ if (have_signals != 0)
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ real_timeout -= (loop->time - base);
+ if (real_timeout <= 0)
+ return;
+
+ timeout = real_timeout;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ static clock_t fast_clock_id = -1;
+ struct timespec t;
+ clock_t clock_id;
+
+ /* Prefer CLOCK_MONOTONIC_COARSE if available but only when it has
+ * millisecond granularity or better. CLOCK_MONOTONIC_COARSE is
+ * serviced entirely from the vDSO, whereas CLOCK_MONOTONIC may
+ * decide to make a costly system call.
+ */
+ /* TODO(bnoordhuis) Use CLOCK_MONOTONIC_COARSE for UV_CLOCK_PRECISE
+ * when it has microsecond granularity or better (unlikely).
+ */
+ if (type == UV_CLOCK_FAST && fast_clock_id == -1) {
+ if (clock_getres(CLOCK_MONOTONIC_COARSE, &t) == 0 &&
+ t.tv_nsec <= 1 * 1000 * 1000) {
+ fast_clock_id = CLOCK_MONOTONIC_COARSE;
+ } else {
+ fast_clock_id = CLOCK_MONOTONIC;
+ }
+ }
+
+ clock_id = CLOCK_MONOTONIC;
+ if (type == UV_CLOCK_FAST)
+ clock_id = fast_clock_id;
+
+ if (clock_gettime(clock_id, &t))
+ return 0; /* Not really possible. */
+
+ return t.tv_sec * (uint64_t) 1e9 + t.tv_nsec;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ char buf[1024];
+ const char* s;
+ ssize_t n;
+ long val;
+ int fd;
+ int i;
+
+ do
+ fd = open("/proc/self/stat", O_RDONLY);
+ while (fd == -1 && errno == EINTR);
+
+ if (fd == -1)
+ return -errno;
+
+ do
+ n = read(fd, buf, sizeof(buf) - 1);
+ while (n == -1 && errno == EINTR);
+
+ uv__close(fd);
+ if (n == -1)
+ return -errno;
+ buf[n] = '\0';
+
+ s = strchr(buf, ' ');
+ if (s == NULL)
+ goto err;
+
+ s += 1;
+ if (*s != '(')
+ goto err;
+
+ s = strchr(s, ')');
+ if (s == NULL)
+ goto err;
+
+ for (i = 1; i <= 22; i++) {
+ s = strchr(s + 1, ' ');
+ if (s == NULL)
+ goto err;
+ }
+
+ errno = 0;
+ val = strtol(s, NULL, 10);
+ if (errno != 0)
+ goto err;
+ if (val < 0)
+ goto err;
+
+ *rss = val * getpagesize();
+ return 0;
+
+err:
+ return -EINVAL;
+}
+
+
+int uv_uptime(double* uptime) {
+ static volatile int no_clock_boottime;
+ struct timespec now;
+ int r;
+
+ /* Try CLOCK_BOOTTIME first, fall back to CLOCK_MONOTONIC if not available
+ * (pre-2.6.39 kernels). CLOCK_MONOTONIC doesn't increase when the system
+ * is suspended.
+ */
+ if (no_clock_boottime) {
+ retry: r = clock_gettime(CLOCK_MONOTONIC, &now);
+ }
+ else if ((r = clock_gettime(CLOCK_BOOTTIME, &now)) && errno == EINVAL) {
+ no_clock_boottime = 1;
+ goto retry;
+ }
+
+ if (r)
+ return -errno;
+
+ *uptime = now.tv_sec;
+ return 0;
+}
+
+
+static int uv__cpu_num(FILE* statfile_fp, unsigned int* numcpus) {
+ unsigned int num;
+ char buf[1024];
+
+ if (!fgets(buf, sizeof(buf), statfile_fp))
+ return -EIO;
+
+ num = 0;
+ while (fgets(buf, sizeof(buf), statfile_fp)) {
+ if (strncmp(buf, "cpu", 3))
+ break;
+ num++;
+ }
+
+ if (num == 0)
+ return -EIO;
+
+ *numcpus = num;
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int numcpus;
+ uv_cpu_info_t* ci;
+ int err;
+ FILE* statfile_fp;
+
+ *cpu_infos = NULL;
+ *count = 0;
+
+ statfile_fp = uv__open_file("/proc/stat");
+ if (statfile_fp == NULL)
+ return -errno;
+
+ err = uv__cpu_num(statfile_fp, &numcpus);
+ if (err < 0)
+ goto out;
+
+ err = -ENOMEM;
+ ci = uv__calloc(numcpus, sizeof(*ci));
+ if (ci == NULL)
+ goto out;
+
+ err = read_models(numcpus, ci);
+ if (err == 0)
+ err = read_times(statfile_fp, numcpus, ci);
+
+ if (err) {
+ uv_free_cpu_info(ci, numcpus);
+ goto out;
+ }
+
+ /* read_models() on x86 also reads the CPU speed from /proc/cpuinfo.
+ * We don't check for errors here. Worst case, the field is left zero.
+ */
+ if (ci[0].speed == 0)
+ read_speeds(numcpus, ci);
+
+ *cpu_infos = ci;
+ *count = numcpus;
+ err = 0;
+
+out:
+
+ if (fclose(statfile_fp))
+ if (errno != EINTR && errno != EINPROGRESS)
+ abort();
+
+ return err;
+}
+
+
+static void read_speeds(unsigned int numcpus, uv_cpu_info_t* ci) {
+ unsigned int num;
+
+ for (num = 0; num < numcpus; num++)
+ ci[num].speed = read_cpufreq(num) / 1000;
+}
+
+
+/* Also reads the CPU frequency on x86. The other architectures only have
+ * a BogoMIPS field, which may not be very accurate.
+ *
+ * Note: Simply returns on error, uv_cpu_info() takes care of the cleanup.
+ */
+static int read_models(unsigned int numcpus, uv_cpu_info_t* ci) {
+ static const char model_marker[] = "model name\t: ";
+ static const char speed_marker[] = "cpu MHz\t\t: ";
+ const char* inferred_model;
+ unsigned int model_idx;
+ unsigned int speed_idx;
+ char buf[1024];
+ char* model;
+ FILE* fp;
+
+ /* Most are unused on non-ARM, non-MIPS and non-x86 architectures. */
+ (void) &model_marker;
+ (void) &speed_marker;
+ (void) &speed_idx;
+ (void) &model;
+ (void) &buf;
+ (void) &fp;
+
+ model_idx = 0;
+ speed_idx = 0;
+
+#if defined(__arm__) || \
+ defined(__i386__) || \
+ defined(__mips__) || \
+ defined(__x86_64__)
+ fp = uv__open_file("/proc/cpuinfo");
+ if (fp == NULL)
+ return -errno;
+
+ while (fgets(buf, sizeof(buf), fp)) {
+ if (model_idx < numcpus) {
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#if defined(__arm__) || defined(__mips__)
+ if (model_idx < numcpus) {
+#if defined(__arm__)
+ /* Fallback for pre-3.8 kernels. */
+ static const char model_marker[] = "Processor\t: ";
+#else /* defined(__mips__) */
+ static const char model_marker[] = "cpu model\t\t: ";
+#endif
+ if (strncmp(buf, model_marker, sizeof(model_marker) - 1) == 0) {
+ model = buf + sizeof(model_marker) - 1;
+ model = uv__strndup(model, strlen(model) - 1); /* Strip newline. */
+ if (model == NULL) {
+ fclose(fp);
+ return -ENOMEM;
+ }
+ ci[model_idx++].model = model;
+ continue;
+ }
+ }
+#else /* !__arm__ && !__mips__ */
+ if (speed_idx < numcpus) {
+ if (strncmp(buf, speed_marker, sizeof(speed_marker) - 1) == 0) {
+ ci[speed_idx++].speed = atoi(buf + sizeof(speed_marker) - 1);
+ continue;
+ }
+ }
+#endif /* __arm__ || __mips__ */
+ }
+
+ fclose(fp);
+#endif /* __arm__ || __i386__ || __mips__ || __x86_64__ */
+
+ /* Now we want to make sure that all the models contain *something* because
+ * it's not safe to leave them as null. Copy the last entry unless there
+ * isn't one, in that case we simply put "unknown" into everything.
+ */
+ inferred_model = "unknown";
+ if (model_idx > 0)
+ inferred_model = ci[model_idx - 1].model;
+
+ while (model_idx < numcpus) {
+ model = uv__strndup(inferred_model, strlen(inferred_model));
+ if (model == NULL)
+ return -ENOMEM;
+ ci[model_idx++].model = model;
+ }
+
+ return 0;
+}
+
+
+static int read_times(FILE* statfile_fp,
+ unsigned int numcpus,
+ uv_cpu_info_t* ci) {
+ unsigned long clock_ticks;
+ struct uv_cpu_times_s ts;
+ unsigned long user;
+ unsigned long nice;
+ unsigned long sys;
+ unsigned long idle;
+ unsigned long dummy;
+ unsigned long irq;
+ unsigned int num;
+ unsigned int len;
+ char buf[1024];
+
+ clock_ticks = sysconf(_SC_CLK_TCK);
+ assert(clock_ticks != (unsigned long) -1);
+ assert(clock_ticks != 0);
+
+ rewind(statfile_fp);
+
+ if (!fgets(buf, sizeof(buf), statfile_fp))
+ abort();
+
+ num = 0;
+
+ while (fgets(buf, sizeof(buf), statfile_fp)) {
+ if (num >= numcpus)
+ break;
+
+ if (strncmp(buf, "cpu", 3))
+ break;
+
+ /* skip "cpu<num> " marker */
+ {
+ unsigned int n;
+ int r = sscanf(buf, "cpu%u ", &n);
+ assert(r == 1);
+ (void) r; /* silence build warning */
+ for (len = sizeof("cpu0"); n /= 10; len++);
+ }
+
+ /* Line contains user, nice, system, idle, iowait, irq, softirq, steal,
+ * guest, guest_nice but we're only interested in the first four + irq.
+ *
+ * Don't use %*s to skip fields or %ll to read straight into the uint64_t
+ * fields, they're not allowed in C89 mode.
+ */
+ if (6 != sscanf(buf + len,
+ "%lu %lu %lu %lu %lu %lu",
+ &user,
+ &nice,
+ &sys,
+ &idle,
+ &dummy,
+ &irq))
+ abort();
+
+ ts.user = clock_ticks * user;
+ ts.nice = clock_ticks * nice;
+ ts.sys = clock_ticks * sys;
+ ts.idle = clock_ticks * idle;
+ ts.irq = clock_ticks * irq;
+ ci[num++].cpu_times = ts;
+ }
+ assert(num == numcpus);
+
+ return 0;
+}
+
+
+static unsigned long read_cpufreq(unsigned int cpunum) {
+ unsigned long val;
+ char buf[1024];
+ FILE* fp;
+
+ snprintf(buf,
+ sizeof(buf),
+ "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq",
+ cpunum);
+
+ fp = uv__open_file(buf);
+ if (fp == NULL)
+ return 0;
+
+ if (fscanf(fp, "%lu", &val) != 1)
+ val = 0;
+
+ fclose(fp);
+
+ return val;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ return 1;
+ if (ent->ifa_addr == NULL)
+ return 1;
+ /*
+ * On Linux getifaddrs returns information related to the raw underlying
+ * devices. We're not interested in this information yet.
+ */
+ if (ent->ifa_addr->sa_family == PF_PACKET)
+ return 1;
+ return 0;
+}
+
+int uv_interface_addresses(uv_interface_address_t** addresses,
+ int* count) {
+#ifndef HAVE_IFADDRS_H
+ return -ENOSYS;
+#else
+ struct ifaddrs *addrs, *ent;
+ uv_interface_address_t* address;
+ int i;
+ struct sockaddr_ll *sll;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+ *addresses = NULL;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ (*count)++;
+ }
+
+ if (*count == 0)
+ return 0;
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!(ent->ifa_flags & IFF_LOOPBACK);
+
+ address++;
+ }
+
+ /* Fill in physical addresses for each interface */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ address = *addresses;
+
+ for (i = 0; i < (*count); i++) {
+ if (strcmp(address->name, ent->ifa_name) == 0) {
+ sll = (struct sockaddr_ll*)ent->ifa_addr;
+ memcpy(address->phys_addr, sll->sll_addr, sizeof(address->phys_addr));
+ }
+ address++;
+ }
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+#endif
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
+
+
+void uv__set_process_title(const char* title) {
+#if defined(PR_SET_NAME)
+ prctl(PR_SET_NAME, title); /* Only copies first 16 characters. */
+#endif
+}
diff --git a/Utilities/cmlibuv/src/unix/linux-inotify.c b/Utilities/cmlibuv/src/unix/linux-inotify.c
new file mode 100644
index 000000000..5934c5d8c
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/linux-inotify.c
@@ -0,0 +1,352 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <unistd.h>
+
+struct watcher_list {
+ RB_ENTRY(watcher_list) entry;
+ QUEUE watchers;
+ int iterating;
+ char* path;
+ int wd;
+};
+
+struct watcher_root {
+ struct watcher_list* rbh_root;
+};
+#define CAST(p) ((struct watcher_root*)(p))
+
+
+static int compare_watchers(const struct watcher_list* a,
+ const struct watcher_list* b) {
+ if (a->wd < b->wd) return -1;
+ if (a->wd > b->wd) return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(watcher_root, watcher_list, entry, compare_watchers)
+
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents);
+
+static void maybe_free_watcher_list(struct watcher_list* w,
+ uv_loop_t* loop);
+
+static int new_inotify_fd(void) {
+ int err;
+ int fd;
+
+ fd = uv__inotify_init1(UV__IN_NONBLOCK | UV__IN_CLOEXEC);
+ if (fd != -1)
+ return fd;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ fd = uv__inotify_init();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err == 0)
+ err = uv__nonblock(fd, 1);
+
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+
+ return fd;
+}
+
+
+static int init_inotify(uv_loop_t* loop) {
+ int err;
+
+ if (loop->inotify_fd != -1)
+ return 0;
+
+ err = new_inotify_fd();
+ if (err < 0)
+ return err;
+
+ loop->inotify_fd = err;
+ uv__io_init(&loop->inotify_read_watcher, uv__inotify_read, loop->inotify_fd);
+ uv__io_start(loop, &loop->inotify_read_watcher, POLLIN);
+
+ return 0;
+}
+
+
+int uv__inotify_fork(uv_loop_t* loop, void* old_watchers) {
+ /* Open the inotify_fd, and re-arm all the inotify watchers. */
+ int err;
+ struct watcher_list* tmp_watcher_list_iter;
+ struct watcher_list* watcher_list;
+ struct watcher_list tmp_watcher_list;
+ QUEUE queue;
+ QUEUE* q;
+ uv_fs_event_t* handle;
+ char* tmp_path;
+
+ if (old_watchers != NULL) {
+ /* We must restore the old watcher list to be able to close items
+ * out of it.
+ */
+ loop->inotify_watchers = old_watchers;
+
+ QUEUE_INIT(&tmp_watcher_list.watchers);
+ /* Note that the queue we use is shared with the start and stop()
+ * functions, making QUEUE_FOREACH unsafe to use. So we use the
+ * QUEUE_MOVE trick to safely iterate. Also don't free the watcher
+ * list until we're done iterating. c.f. uv__inotify_read.
+ */
+ RB_FOREACH_SAFE(watcher_list, watcher_root,
+ CAST(&old_watchers), tmp_watcher_list_iter) {
+ watcher_list->iterating = 1;
+ QUEUE_MOVE(&watcher_list->watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
+ /* It's critical to keep a copy of path here, because it
+ * will be set to NULL by stop() and then deallocated by
+ * maybe_free_watcher_list
+ */
+ tmp_path = uv__strdup(handle->path);
+ assert(tmp_path != NULL);
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&watcher_list->watchers, q);
+ uv_fs_event_stop(handle);
+
+ QUEUE_INSERT_TAIL(&tmp_watcher_list.watchers, &handle->watchers);
+ handle->path = tmp_path;
+ }
+ watcher_list->iterating = 0;
+ maybe_free_watcher_list(watcher_list, loop);
+ }
+
+ QUEUE_MOVE(&tmp_watcher_list.watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ QUEUE_REMOVE(q);
+ handle = QUEUE_DATA(q, uv_fs_event_t, watchers);
+ tmp_path = handle->path;
+ handle->path = NULL;
+ err = uv_fs_event_start(handle, handle->cb, tmp_path, 0);
+ uv__free(tmp_path);
+ if (err)
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
+static struct watcher_list* find_watcher(uv_loop_t* loop, int wd) {
+ struct watcher_list w;
+ w.wd = wd;
+ return RB_FIND(watcher_root, CAST(&loop->inotify_watchers), &w);
+}
+
+static void maybe_free_watcher_list(struct watcher_list* w, uv_loop_t* loop) {
+ /* if the watcher_list->watchers is being iterated over, we can't free it. */
+ if ((!w->iterating) && QUEUE_EMPTY(&w->watchers)) {
+ /* No watchers left for this path. Clean up. */
+ RB_REMOVE(watcher_root, CAST(&loop->inotify_watchers), w);
+ uv__inotify_rm_watch(loop->inotify_fd, w->wd);
+ uv__free(w);
+ }
+}
+
+static void uv__inotify_read(uv_loop_t* loop,
+ uv__io_t* dummy,
+ unsigned int events) {
+ const struct uv__inotify_event* e;
+ struct watcher_list* w;
+ uv_fs_event_t* h;
+ QUEUE queue;
+ QUEUE* q;
+ const char* path;
+ ssize_t size;
+ const char *p;
+ /* needs to be large enough for sizeof(inotify_event) + strlen(path) */
+ char buf[4096];
+
+ while (1) {
+ do
+ size = read(loop->inotify_fd, buf, sizeof(buf));
+ while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ assert(errno == EAGAIN || errno == EWOULDBLOCK);
+ break;
+ }
+
+ assert(size > 0); /* pre-2.6.21 thing, size=0 == read buffer too small */
+
+ /* Now we have one or more inotify_event structs. */
+ for (p = buf; p < buf + size; p += sizeof(*e) + e->len) {
+ e = (const struct uv__inotify_event*)p;
+
+ events = 0;
+ if (e->mask & (UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_CHANGE;
+ if (e->mask & ~(UV__IN_ATTRIB|UV__IN_MODIFY))
+ events |= UV_RENAME;
+
+ w = find_watcher(loop, e->wd);
+ if (w == NULL)
+ continue; /* Stale event, no watchers left. */
+
+ /* inotify does not return the filename when monitoring a single file
+ * for modifications. Repurpose the filename for API compatibility.
+ * I'm not convinced this is a good thing, maybe it should go.
+ */
+ path = e->len ? (const char*) (e + 1) : uv__basename_r(w->path);
+
+ /* We're about to iterate over the queue and call user's callbacks.
+ * What can go wrong?
+ * A callback could call uv_fs_event_stop()
+ * and the queue can change under our feet.
+ * So, we use QUEUE_MOVE() trick to safely iterate over the queue.
+ * And we don't free the watcher_list until we're done iterating.
+ *
+ * First,
+ * tell uv_fs_event_stop() (that could be called from a user's callback)
+ * not to free watcher_list.
+ */
+ w->iterating = 1;
+ QUEUE_MOVE(&w->watchers, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_fs_event_t, watchers);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&w->watchers, q);
+
+ h->cb(h, path, events, 0);
+ }
+ /* done iterating, time to (maybe) free empty watcher_list */
+ w->iterating = 0;
+ maybe_free_watcher_list(w, loop);
+ }
+ }
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ struct watcher_list* w;
+ int events;
+ int err;
+ int wd;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ err = init_inotify(handle->loop);
+ if (err)
+ return err;
+
+ events = UV__IN_ATTRIB
+ | UV__IN_CREATE
+ | UV__IN_MODIFY
+ | UV__IN_DELETE
+ | UV__IN_DELETE_SELF
+ | UV__IN_MOVE_SELF
+ | UV__IN_MOVED_FROM
+ | UV__IN_MOVED_TO;
+
+ wd = uv__inotify_add_watch(handle->loop->inotify_fd, path, events);
+ if (wd == -1)
+ return -errno;
+
+ w = find_watcher(handle->loop, wd);
+ if (w)
+ goto no_insert;
+
+ w = uv__malloc(sizeof(*w) + strlen(path) + 1);
+ if (w == NULL)
+ return -ENOMEM;
+
+ w->wd = wd;
+ w->path = strcpy((char*)(w + 1), path);
+ QUEUE_INIT(&w->watchers);
+ w->iterating = 0;
+ RB_INSERT(watcher_root, CAST(&handle->loop->inotify_watchers), w);
+
+no_insert:
+ uv__handle_start(handle);
+ QUEUE_INSERT_TAIL(&w->watchers, &handle->watchers);
+ handle->path = w->path;
+ handle->cb = cb;
+ handle->wd = wd;
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ struct watcher_list* w;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ w = find_watcher(handle->loop, handle->wd);
+ assert(w != NULL);
+
+ handle->wd = -1;
+ handle->path = NULL;
+ uv__handle_stop(handle);
+ QUEUE_REMOVE(&handle->watchers);
+
+ maybe_free_watcher_list(w, handle->loop);
+
+ return 0;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.c b/Utilities/cmlibuv/src/unix/linux-syscalls.c
new file mode 100644
index 000000000..89998ded2
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/linux-syscalls.c
@@ -0,0 +1,471 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "linux-syscalls.h"
+#include <unistd.h>
+#include <signal.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#if defined(__has_feature)
+# if __has_feature(memory_sanitizer)
+# define MSAN_ACTIVE 1
+# include <sanitizer/msan_interface.h>
+# endif
+#endif
+
+#if defined(__i386__)
+# ifndef __NR_socketcall
+# define __NR_socketcall 102
+# endif
+#endif
+
+#if defined(__arm__)
+# if defined(__thumb__) || defined(__ARM_EABI__)
+# define UV_SYSCALL_BASE 0
+# else
+# define UV_SYSCALL_BASE 0x900000
+# endif
+#endif /* __arm__ */
+
+#ifndef __NR_accept4
+# if defined(__x86_64__)
+# define __NR_accept4 288
+# elif defined(__i386__)
+ /* Nothing. Handled through socketcall(). */
+# elif defined(__arm__)
+# define __NR_accept4 (UV_SYSCALL_BASE + 366)
+# endif
+#endif /* __NR_accept4 */
+
+#ifndef __NR_eventfd
+# if defined(__x86_64__)
+# define __NR_eventfd 284
+# elif defined(__i386__)
+# define __NR_eventfd 323
+# elif defined(__arm__)
+# define __NR_eventfd (UV_SYSCALL_BASE + 351)
+# endif
+#endif /* __NR_eventfd */
+
+#ifndef __NR_eventfd2
+# if defined(__x86_64__)
+# define __NR_eventfd2 290
+# elif defined(__i386__)
+# define __NR_eventfd2 328
+# elif defined(__arm__)
+# define __NR_eventfd2 (UV_SYSCALL_BASE + 356)
+# endif
+#endif /* __NR_eventfd2 */
+
+#ifndef __NR_epoll_create
+# if defined(__x86_64__)
+# define __NR_epoll_create 213
+# elif defined(__i386__)
+# define __NR_epoll_create 254
+# elif defined(__arm__)
+# define __NR_epoll_create (UV_SYSCALL_BASE + 250)
+# endif
+#endif /* __NR_epoll_create */
+
+#ifndef __NR_epoll_create1
+# if defined(__x86_64__)
+# define __NR_epoll_create1 291
+# elif defined(__i386__)
+# define __NR_epoll_create1 329
+# elif defined(__arm__)
+# define __NR_epoll_create1 (UV_SYSCALL_BASE + 357)
+# endif
+#endif /* __NR_epoll_create1 */
+
+#ifndef __NR_epoll_ctl
+# if defined(__x86_64__)
+# define __NR_epoll_ctl 233 /* used to be 214 */
+# elif defined(__i386__)
+# define __NR_epoll_ctl 255
+# elif defined(__arm__)
+# define __NR_epoll_ctl (UV_SYSCALL_BASE + 251)
+# endif
+#endif /* __NR_epoll_ctl */
+
+#ifndef __NR_epoll_wait
+# if defined(__x86_64__)
+# define __NR_epoll_wait 232 /* used to be 215 */
+# elif defined(__i386__)
+# define __NR_epoll_wait 256
+# elif defined(__arm__)
+# define __NR_epoll_wait (UV_SYSCALL_BASE + 252)
+# endif
+#endif /* __NR_epoll_wait */
+
+#ifndef __NR_epoll_pwait
+# if defined(__x86_64__)
+# define __NR_epoll_pwait 281
+# elif defined(__i386__)
+# define __NR_epoll_pwait 319
+# elif defined(__arm__)
+# define __NR_epoll_pwait (UV_SYSCALL_BASE + 346)
+# endif
+#endif /* __NR_epoll_pwait */
+
+#ifndef __NR_inotify_init
+# if defined(__x86_64__)
+# define __NR_inotify_init 253
+# elif defined(__i386__)
+# define __NR_inotify_init 291
+# elif defined(__arm__)
+# define __NR_inotify_init (UV_SYSCALL_BASE + 316)
+# endif
+#endif /* __NR_inotify_init */
+
+#ifndef __NR_inotify_init1
+# if defined(__x86_64__)
+# define __NR_inotify_init1 294
+# elif defined(__i386__)
+# define __NR_inotify_init1 332
+# elif defined(__arm__)
+# define __NR_inotify_init1 (UV_SYSCALL_BASE + 360)
+# endif
+#endif /* __NR_inotify_init1 */
+
+#ifndef __NR_inotify_add_watch
+# if defined(__x86_64__)
+# define __NR_inotify_add_watch 254
+# elif defined(__i386__)
+# define __NR_inotify_add_watch 292
+# elif defined(__arm__)
+# define __NR_inotify_add_watch (UV_SYSCALL_BASE + 317)
+# endif
+#endif /* __NR_inotify_add_watch */
+
+#ifndef __NR_inotify_rm_watch
+# if defined(__x86_64__)
+# define __NR_inotify_rm_watch 255
+# elif defined(__i386__)
+# define __NR_inotify_rm_watch 293
+# elif defined(__arm__)
+# define __NR_inotify_rm_watch (UV_SYSCALL_BASE + 318)
+# endif
+#endif /* __NR_inotify_rm_watch */
+
+#ifndef __NR_pipe2
+# if defined(__x86_64__)
+# define __NR_pipe2 293
+# elif defined(__i386__)
+# define __NR_pipe2 331
+# elif defined(__arm__)
+# define __NR_pipe2 (UV_SYSCALL_BASE + 359)
+# endif
+#endif /* __NR_pipe2 */
+
+#ifndef __NR_recvmmsg
+# if defined(__x86_64__)
+# define __NR_recvmmsg 299
+# elif defined(__i386__)
+# define __NR_recvmmsg 337
+# elif defined(__arm__)
+# define __NR_recvmmsg (UV_SYSCALL_BASE + 365)
+# endif
+#endif /* __NR_recvmsg */
+
+#ifndef __NR_sendmmsg
+# if defined(__x86_64__)
+# define __NR_sendmmsg 307
+# elif defined(__i386__)
+# define __NR_sendmmsg 345
+# elif defined(__arm__)
+# define __NR_sendmmsg (UV_SYSCALL_BASE + 374)
+# endif
+#endif /* __NR_sendmmsg */
+
+#ifndef __NR_utimensat
+# if defined(__x86_64__)
+# define __NR_utimensat 280
+# elif defined(__i386__)
+# define __NR_utimensat 320
+# elif defined(__arm__)
+# define __NR_utimensat (UV_SYSCALL_BASE + 348)
+# endif
+#endif /* __NR_utimensat */
+
+#ifndef __NR_preadv
+# if defined(__x86_64__)
+# define __NR_preadv 295
+# elif defined(__i386__)
+# define __NR_preadv 333
+# elif defined(__arm__)
+# define __NR_preadv (UV_SYSCALL_BASE + 361)
+# endif
+#endif /* __NR_preadv */
+
+#ifndef __NR_pwritev
+# if defined(__x86_64__)
+# define __NR_pwritev 296
+# elif defined(__i386__)
+# define __NR_pwritev 334
+# elif defined(__arm__)
+# define __NR_pwritev (UV_SYSCALL_BASE + 362)
+# endif
+#endif /* __NR_pwritev */
+
+#ifndef __NR_dup3
+# if defined(__x86_64__)
+# define __NR_dup3 292
+# elif defined(__i386__)
+# define __NR_dup3 330
+# elif defined(__arm__)
+# define __NR_dup3 (UV_SYSCALL_BASE + 358)
+# endif
+#endif /* __NR_pwritev */
+
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags) {
+#if defined(__i386__)
+ unsigned long args[4];
+ int r;
+
+ args[0] = (unsigned long) fd;
+ args[1] = (unsigned long) addr;
+ args[2] = (unsigned long) addrlen;
+ args[3] = (unsigned long) flags;
+
+ r = syscall(__NR_socketcall, 18 /* SYS_ACCEPT4 */, args);
+
+ /* socketcall() raises EINVAL when SYS_ACCEPT4 is not supported but so does
+ * a bad flags argument. Try to distinguish between the two cases.
+ */
+ if (r == -1)
+ if (errno == EINVAL)
+ if ((flags & ~(UV__SOCK_CLOEXEC|UV__SOCK_NONBLOCK)) == 0)
+ errno = ENOSYS;
+
+ return r;
+#elif defined(__NR_accept4)
+ return syscall(__NR_accept4, fd, addr, addrlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd(unsigned int count) {
+#if defined(__NR_eventfd)
+ return syscall(__NR_eventfd, count);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__eventfd2(unsigned int count, int flags) {
+#if defined(__NR_eventfd2)
+ return syscall(__NR_eventfd2, count, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create(int size) {
+#if defined(__NR_epoll_create)
+ return syscall(__NR_epoll_create, size);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_create1(int flags) {
+#if defined(__NR_epoll_create1)
+ return syscall(__NR_epoll_create1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event* events) {
+#if defined(__NR_epoll_ctl)
+ return syscall(__NR_epoll_ctl, epfd, op, fd, events);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout) {
+#if defined(__NR_epoll_wait)
+ int result;
+ result = syscall(__NR_epoll_wait, epfd, events, nevents, timeout);
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask) {
+#if defined(__NR_epoll_pwait)
+ int result;
+ result = syscall(__NR_epoll_pwait,
+ epfd,
+ events,
+ nevents,
+ timeout,
+ &sigmask,
+ sizeof(sigmask));
+#if MSAN_ACTIVE
+ if (result > 0)
+ __msan_unpoison(events, sizeof(events[0]) * result);
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init(void) {
+#if defined(__NR_inotify_init)
+ return syscall(__NR_inotify_init);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_init1(int flags) {
+#if defined(__NR_inotify_init1)
+ return syscall(__NR_inotify_init1, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask) {
+#if defined(__NR_inotify_add_watch)
+ return syscall(__NR_inotify_add_watch, fd, path, mask);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__inotify_rm_watch(int fd, int32_t wd) {
+#if defined(__NR_inotify_rm_watch)
+ return syscall(__NR_inotify_rm_watch, fd, wd);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__pipe2(int pipefd[2], int flags) {
+#if defined(__NR_pipe2)
+ int result;
+ result = syscall(__NR_pipe2, pipefd, flags);
+#if MSAN_ACTIVE
+ if (!result)
+ __msan_unpoison(pipefd, sizeof(int[2]));
+#endif
+ return result;
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags) {
+#if defined(__NR_sendmmsg)
+ return syscall(__NR_sendmmsg, fd, mmsg, vlen, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout) {
+#if defined(__NR_recvmmsg)
+ return syscall(__NR_recvmmsg, fd, mmsg, vlen, flags, timeout);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags)
+{
+#if defined(__NR_utimensat)
+ return syscall(__NR_utimensat, dirfd, path, times, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_preadv)
+ return syscall(__NR_preadv, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset) {
+#if defined(__NR_pwritev)
+ return syscall(__NR_pwritev, fd, iov, iovcnt, (long)offset, (long)(offset >> 32));
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
+
+
+int uv__dup3(int oldfd, int newfd, int flags) {
+#if defined(__NR_dup3)
+ return syscall(__NR_dup3, oldfd, newfd, flags);
+#else
+ return errno = ENOSYS, -1;
+#endif
+}
diff --git a/Utilities/cmlibuv/src/unix/linux-syscalls.h b/Utilities/cmlibuv/src/unix/linux-syscalls.h
new file mode 100644
index 000000000..4c095e9b5
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/linux-syscalls.h
@@ -0,0 +1,151 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_LINUX_SYSCALL_H_
+#define UV_LINUX_SYSCALL_H_
+
+#undef _GNU_SOURCE
+#define _GNU_SOURCE
+
+#include <stdint.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#if defined(__alpha__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__hppa__)
+# define UV__O_CLOEXEC 0x200000
+#elif defined(__sparc__)
+# define UV__O_CLOEXEC 0x400000
+#else
+# define UV__O_CLOEXEC 0x80000
+#endif
+
+#if defined(__alpha__)
+# define UV__O_NONBLOCK 0x4
+#elif defined(__hppa__)
+# define UV__O_NONBLOCK O_NONBLOCK
+#elif defined(__mips__)
+# define UV__O_NONBLOCK 0x80
+#elif defined(__sparc__)
+# define UV__O_NONBLOCK 0x4000
+#else
+# define UV__O_NONBLOCK 0x800
+#endif
+
+#define UV__EFD_CLOEXEC UV__O_CLOEXEC
+#define UV__EFD_NONBLOCK UV__O_NONBLOCK
+
+#define UV__IN_CLOEXEC UV__O_CLOEXEC
+#define UV__IN_NONBLOCK UV__O_NONBLOCK
+
+#define UV__SOCK_CLOEXEC UV__O_CLOEXEC
+#if defined(SOCK_NONBLOCK)
+# define UV__SOCK_NONBLOCK SOCK_NONBLOCK
+#else
+# define UV__SOCK_NONBLOCK UV__O_NONBLOCK
+#endif
+
+/* epoll flags */
+#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
+#define UV__EPOLL_CTL_ADD 1
+#define UV__EPOLL_CTL_DEL 2
+#define UV__EPOLL_CTL_MOD 3
+
+/* inotify flags */
+#define UV__IN_ACCESS 0x001
+#define UV__IN_MODIFY 0x002
+#define UV__IN_ATTRIB 0x004
+#define UV__IN_CLOSE_WRITE 0x008
+#define UV__IN_CLOSE_NOWRITE 0x010
+#define UV__IN_OPEN 0x020
+#define UV__IN_MOVED_FROM 0x040
+#define UV__IN_MOVED_TO 0x080
+#define UV__IN_CREATE 0x100
+#define UV__IN_DELETE 0x200
+#define UV__IN_DELETE_SELF 0x400
+#define UV__IN_MOVE_SELF 0x800
+
+#if defined(__x86_64__)
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+} __attribute__((packed));
+#else
+struct uv__epoll_event {
+ uint32_t events;
+ uint64_t data;
+};
+#endif
+
+struct uv__inotify_event {
+ int32_t wd;
+ uint32_t mask;
+ uint32_t cookie;
+ uint32_t len;
+ /* char name[0]; */
+};
+
+struct uv__mmsghdr {
+ struct msghdr msg_hdr;
+ unsigned int msg_len;
+};
+
+int uv__accept4(int fd, struct sockaddr* addr, socklen_t* addrlen, int flags);
+int uv__eventfd(unsigned int count);
+int uv__epoll_create(int size);
+int uv__epoll_create1(int flags);
+int uv__epoll_ctl(int epfd, int op, int fd, struct uv__epoll_event *ev);
+int uv__epoll_wait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout);
+int uv__epoll_pwait(int epfd,
+ struct uv__epoll_event* events,
+ int nevents,
+ int timeout,
+ uint64_t sigmask);
+int uv__eventfd2(unsigned int count, int flags);
+int uv__inotify_init(void);
+int uv__inotify_init1(int flags);
+int uv__inotify_add_watch(int fd, const char* path, uint32_t mask);
+int uv__inotify_rm_watch(int fd, int32_t wd);
+int uv__pipe2(int pipefd[2], int flags);
+int uv__recvmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags,
+ struct timespec* timeout);
+int uv__sendmmsg(int fd,
+ struct uv__mmsghdr* mmsg,
+ unsigned int vlen,
+ unsigned int flags);
+int uv__utimesat(int dirfd,
+ const char* path,
+ const struct timespec times[2],
+ int flags);
+ssize_t uv__preadv(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+ssize_t uv__pwritev(int fd, const struct iovec *iov, int iovcnt, int64_t offset);
+int uv__dup3(int oldfd, int newfd, int flags);
+
+#endif /* UV_LINUX_SYSCALL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/loop-watcher.c b/Utilities/cmlibuv/src/unix/loop-watcher.c
new file mode 100644
index 000000000..340bb0dfa
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/loop-watcher.c
@@ -0,0 +1,68 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#define UV_LOOP_WATCHER_DEFINE(name, type) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_##type); \
+ handle->name##_cb = NULL; \
+ return 0; \
+ } \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ if (uv__is_active(handle)) return 0; \
+ if (cb == NULL) return -EINVAL; \
+ QUEUE_INSERT_HEAD(&handle->loop->name##_handles, &handle->queue); \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ return 0; \
+ } \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ if (!uv__is_active(handle)) return 0; \
+ QUEUE_REMOVE(&handle->queue); \
+ uv__handle_stop(handle); \
+ return 0; \
+ } \
+ \
+ void uv__run_##name(uv_loop_t* loop) { \
+ uv_##name##_t* h; \
+ QUEUE queue; \
+ QUEUE* q; \
+ QUEUE_MOVE(&loop->name##_handles, &queue); \
+ while (!QUEUE_EMPTY(&queue)) { \
+ q = QUEUE_HEAD(&queue); \
+ h = QUEUE_DATA(q, uv_##name##_t, queue); \
+ QUEUE_REMOVE(q); \
+ QUEUE_INSERT_TAIL(&loop->name##_handles, q); \
+ h->name##_cb(h); \
+ } \
+ } \
+ \
+ void uv__##name##_close(uv_##name##_t* handle) { \
+ uv_##name##_stop(handle); \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/Utilities/cmlibuv/src/unix/loop.c b/Utilities/cmlibuv/src/unix/loop.c
new file mode 100644
index 000000000..bcd49242c
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/loop.c
@@ -0,0 +1,193 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "tree.h"
+#include "internal.h"
+#include "heap-inl.h"
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int uv_loop_init(uv_loop_t* loop) {
+ void* saved_data;
+ int err;
+
+ uv__signal_global_once_init();
+
+ saved_data = loop->data;
+ memset(loop, 0, sizeof(*loop));
+ loop->data = saved_data;
+
+ heap_init((struct heap*) &loop->timer_heap);
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->active_reqs);
+ QUEUE_INIT(&loop->idle_handles);
+ QUEUE_INIT(&loop->async_handles);
+ QUEUE_INIT(&loop->check_handles);
+ QUEUE_INIT(&loop->prepare_handles);
+ QUEUE_INIT(&loop->handle_queue);
+
+ loop->nfds = 0;
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+ QUEUE_INIT(&loop->pending_queue);
+ QUEUE_INIT(&loop->watcher_queue);
+
+ loop->closing_handles = NULL;
+ uv__update_time(loop);
+ loop->async_io_watcher.fd = -1;
+ loop->async_wfd = -1;
+ loop->signal_pipefd[0] = -1;
+ loop->signal_pipefd[1] = -1;
+ loop->backend_fd = -1;
+ loop->emfile_fd = -1;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv__platform_loop_init(loop);
+ if (err)
+ return err;
+
+ err = uv_signal_init(loop, &loop->child_watcher);
+ if (err)
+ goto fail_signal_init;
+
+ uv__handle_unref(&loop->child_watcher);
+ loop->child_watcher.flags |= UV__HANDLE_INTERNAL;
+ QUEUE_INIT(&loop->process_handles);
+
+ err = uv_rwlock_init(&loop->cloexec_lock);
+ if (err)
+ goto fail_rwlock_init;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+fail_rwlock_init:
+ uv__signal_loop_cleanup(loop);
+
+fail_signal_init:
+ uv__platform_loop_delete(loop);
+
+ return err;
+}
+
+
+int uv_loop_fork(uv_loop_t* loop) {
+ int err;
+ unsigned int i;
+ uv__io_t* w;
+
+ err = uv__io_fork(loop);
+ if (err)
+ return err;
+
+ err = uv__async_fork(loop);
+ if (err)
+ return err;
+
+ err = uv__signal_loop_fork(loop);
+ if (err)
+ return err;
+
+ /* Rearm all the watchers that aren't re-queued by the above. */
+ for (i = 0; i < loop->nwatchers; i++) {
+ w = loop->watchers[i];
+ if (w == NULL)
+ continue;
+
+ if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue)) {
+ w->events = 0; /* Force re-registration in uv__io_poll. */
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+ }
+ }
+
+ return 0;
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ uv__signal_loop_cleanup(loop);
+ uv__platform_loop_delete(loop);
+ uv__async_stop(loop);
+
+ if (loop->emfile_fd != -1) {
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ /*
+ * Note that all thread pool stuff is finished at this point and
+ * it is safe to just destroy rw lock
+ */
+ uv_rwlock_destroy(&loop->cloexec_lock);
+
+#if 0
+ assert(QUEUE_EMPTY(&loop->pending_queue));
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ assert(loop->nfds == 0);
+#endif
+
+ uv__free(loop->watchers);
+ loop->watchers = NULL;
+ loop->nwatchers = 0;
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ if (option != UV_LOOP_BLOCK_SIGNAL)
+ return UV_ENOSYS;
+
+ if (va_arg(ap, int) != SIGPROF)
+ return UV_EINVAL;
+
+ loop->flags |= UV_LOOP_BLOCK_SIGPROF;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/netbsd.c b/Utilities/cmlibuv/src/unix/netbsd.c
new file mode 100644
index 000000000..9b5546b7e
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/netbsd.c
@@ -0,0 +1,272 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+
+#include <kvm.h>
+#include <paths.h>
+#include <unistd.h>
+#include <time.h>
+#include <stdlib.h>
+#include <fcntl.h>
+
+#include <sys/resource.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <uvm/uvm_extern.h>
+
+#include <unistd.h>
+#include <time.h>
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) == -1) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ size_t cb;
+ pid_t mypid;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+
+ cb = *size;
+ if (sysctl(mib, 4, buffer, &cb, NULL, 0))
+ return -errno;
+ *size = strlen(buffer);
+
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+#if defined(HW_PHYSMEM64)
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+#else
+ unsigned int info;
+ int which[] = {CTL_HW, HW_PHYSMEM};
+#endif
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title) uv__free(process_title);
+
+ process_title = uv__strdup(title);
+ setproctitle("%s", title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+
+ if (process_title) {
+ len = strlen(process_title) + 1;
+
+ if (size < len)
+ return -ENOBUFS;
+
+ memcpy(buffer, process_title, len);
+ } else {
+ len = 0;
+ }
+
+ buffer[len] = '\0';
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ kvm_t *kd = NULL;
+ struct kinfo_proc2 *kinfo = NULL;
+ pid_t pid;
+ int nprocs;
+ int max_size = sizeof(struct kinfo_proc2);
+ int page_size;
+
+ page_size = getpagesize();
+ pid = getpid();
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+
+ if (kd == NULL) goto error;
+
+ kinfo = kvm_getproc2(kd, KERN_PROC_PID, pid, max_size, &nprocs);
+ if (kinfo == NULL) goto error;
+
+ *rss = kinfo->p_vm_rssize * page_size;
+
+ kvm_close(kd);
+
+ return 0;
+
+error:
+ if (kd) kvm_close(kd);
+ return -EPERM;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK);
+ unsigned int multiplier = ((uint64_t)1000L / ticks);
+ unsigned int cur = 0;
+ uv_cpu_info_t* cpu_info;
+ u_int64_t* cp_times;
+ char model[512];
+ u_int64_t cpuspeed;
+ int numcpus;
+ size_t size;
+ int i;
+
+ size = sizeof(model);
+ if (sysctlbyname("machdep.cpu_brand", &model, &size, NULL, 0) &&
+ sysctlbyname("hw.model", &model, &size, NULL, 0)) {
+ return -errno;
+ }
+
+ size = sizeof(numcpus);
+ if (sysctlbyname("hw.ncpu", &numcpus, &size, NULL, 0))
+ return -errno;
+ *count = numcpus;
+
+ /* Only i386 and amd64 have machdep.tsc_freq */
+ size = sizeof(cpuspeed);
+ if (sysctlbyname("machdep.tsc_freq", &cpuspeed, &size, NULL, 0))
+ cpuspeed = 0;
+
+ size = numcpus * CPUSTATES * sizeof(*cp_times);
+ cp_times = uv__malloc(size);
+ if (cp_times == NULL)
+ return -ENOMEM;
+
+ if (sysctlbyname("kern.cp_time", cp_times, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ uv__free(cp_times);
+ uv__free(*cpu_infos);
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < numcpus; i++) {
+ cpu_info = &(*cpu_infos)[i];
+ cpu_info->cpu_times.user = (uint64_t)(cp_times[CP_USER+cur]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(cp_times[CP_NICE+cur]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(cp_times[CP_SYS+cur]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(cp_times[CP_IDLE+cur]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(cp_times[CP_INTR+cur]) * multiplier;
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = (int)(cpuspeed/(uint64_t) 1e6);
+ cur += CPUSTATES;
+ }
+ uv__free(cp_times);
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
diff --git a/Utilities/cmlibuv/src/unix/no-fsevents.c b/Utilities/cmlibuv/src/unix/no-fsevents.c
new file mode 100644
index 000000000..38fb6ab0b
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/no-fsevents.c
@@ -0,0 +1,42 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+int uv_fs_event_start(uv_fs_event_t* handle, uv_fs_event_cb cb,
+ const char* filename, unsigned int flags) {
+ return -ENOSYS;
+}
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ UNREACHABLE();
+}
diff --git a/Utilities/cmlibuv/src/unix/no-proctitle.c b/Utilities/cmlibuv/src/unix/no-proctitle.c
new file mode 100644
index 000000000..a5c19fbff
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/no-proctitle.c
@@ -0,0 +1,42 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <errno.h>
+#include <stddef.h>
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+int uv_set_process_title(const char* title) {
+ return 0;
+}
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+
+ buffer[0] = '\0';
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/openbsd.c b/Utilities/cmlibuv/src/unix/openbsd.c
new file mode 100644
index 000000000..56f0af15c
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/openbsd.c
@@ -0,0 +1,284 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/sched.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <paths.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+static char *process_title;
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ return uv__kqueue_init(loop);
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+}
+
+
+void uv_loadavg(double avg[3]) {
+ struct loadavg info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_LOADAVG};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0) < 0) return;
+
+ avg[0] = (double) info.ldavg[0] / info.fscale;
+ avg[1] = (double) info.ldavg[1] / info.fscale;
+ avg[2] = (double) info.ldavg[2] / info.fscale;
+}
+
+
+int uv_exepath(char* buffer, size_t* size) {
+ int mib[4];
+ char **argsbuf = NULL;
+ char **argsbuf_tmp;
+ size_t argsbuf_size = 100U;
+ size_t exepath_size;
+ pid_t mypid;
+ int err;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ mypid = getpid();
+ for (;;) {
+ err = -ENOMEM;
+ argsbuf_tmp = uv__realloc(argsbuf, argsbuf_size);
+ if (argsbuf_tmp == NULL)
+ goto out;
+ argsbuf = argsbuf_tmp;
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC_ARGS;
+ mib[2] = mypid;
+ mib[3] = KERN_PROC_ARGV;
+ if (sysctl(mib, 4, argsbuf, &argsbuf_size, NULL, 0) == 0) {
+ break;
+ }
+ if (errno != ENOMEM) {
+ err = -errno;
+ goto out;
+ }
+ argsbuf_size *= 2U;
+ }
+
+ if (argsbuf[0] == NULL) {
+ err = -EINVAL; /* FIXME(bnoordhuis) More appropriate error. */
+ goto out;
+ }
+
+ *size -= 1;
+ exepath_size = strlen(argsbuf[0]);
+ if (*size > exepath_size)
+ *size = exepath_size;
+
+ memcpy(buffer, argsbuf[0], *size);
+ buffer[*size] = '\0';
+ err = 0;
+
+out:
+ uv__free(argsbuf);
+
+ return err;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ struct uvmexp info;
+ size_t size = sizeof(info);
+ int which[] = {CTL_VM, VM_UVMEXP};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info.free * sysconf(_SC_PAGESIZE);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t info;
+ int which[] = {CTL_HW, HW_PHYSMEM64};
+ size_t size = sizeof(info);
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ return (uint64_t) info;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ process_title = argc ? uv__strdup(argv[0]) : NULL;
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ setproctitle("%s", title);
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+
+ if (process_title) {
+ len = strlen(process_title) + 1;
+
+ if (size < len)
+ return -ENOBUFS;
+
+ memcpy(buffer, process_title, len);
+ } else {
+ len = 0;
+ }
+
+ buffer[len] = '\0';
+
+ return 0;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ struct kinfo_proc kinfo;
+ size_t page_size = getpagesize();
+ size_t size = sizeof(struct kinfo_proc);
+ int mib[6];
+
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PID;
+ mib[3] = getpid();
+ mib[4] = sizeof(struct kinfo_proc);
+ mib[5] = 1;
+
+ if (sysctl(mib, 6, &kinfo, &size, NULL, 0) < 0)
+ return -errno;
+
+ *rss = kinfo.p_vm_rssize * page_size;
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ time_t now;
+ struct timeval info;
+ size_t size = sizeof(info);
+ static int which[] = {CTL_KERN, KERN_BOOTTIME};
+
+ if (sysctl(which, 2, &info, &size, NULL, 0))
+ return -errno;
+
+ now = time(NULL);
+
+ *uptime = (double)(now - info.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ unsigned int ticks = (unsigned int)sysconf(_SC_CLK_TCK),
+ multiplier = ((uint64_t)1000L / ticks), cpuspeed;
+ uint64_t info[CPUSTATES];
+ char model[512];
+ int numcpus = 1;
+ int which[] = {CTL_HW,HW_MODEL,0};
+ size_t size;
+ int i;
+ uv_cpu_info_t* cpu_info;
+
+ size = sizeof(model);
+ if (sysctl(which, 2, &model, &size, NULL, 0))
+ return -errno;
+
+ which[1] = HW_NCPU;
+ size = sizeof(numcpus);
+ if (sysctl(which, 2, &numcpus, &size, NULL, 0))
+ return -errno;
+
+ *cpu_infos = uv__malloc(numcpus * sizeof(**cpu_infos));
+ if (!(*cpu_infos))
+ return -ENOMEM;
+
+ *count = numcpus;
+
+ which[1] = HW_CPUSPEED;
+ size = sizeof(cpuspeed);
+ if (sysctl(which, 2, &cpuspeed, &size, NULL, 0)) {
+ uv__free(*cpu_infos);
+ return -errno;
+ }
+
+ size = sizeof(info);
+ which[0] = CTL_KERN;
+ which[1] = KERN_CPTIME2;
+ for (i = 0; i < numcpus; i++) {
+ which[2] = i;
+ size = sizeof(info);
+ if (sysctl(which, 3, &info, &size, NULL, 0)) {
+ uv__free(*cpu_infos);
+ return -errno;
+ }
+
+ cpu_info = &(*cpu_infos)[i];
+
+ cpu_info->cpu_times.user = (uint64_t)(info[CP_USER]) * multiplier;
+ cpu_info->cpu_times.nice = (uint64_t)(info[CP_NICE]) * multiplier;
+ cpu_info->cpu_times.sys = (uint64_t)(info[CP_SYS]) * multiplier;
+ cpu_info->cpu_times.idle = (uint64_t)(info[CP_IDLE]) * multiplier;
+ cpu_info->cpu_times.irq = (uint64_t)(info[CP_INTR]) * multiplier;
+
+ cpu_info->model = uv__strdup(model);
+ cpu_info->speed = cpuspeed;
+ }
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.c b/Utilities/cmlibuv/src/unix/os390-syscalls.c
new file mode 100644
index 000000000..7edf2358d
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.c
@@ -0,0 +1,334 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#include "os390-syscalls.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <search.h>
+
+#define CW_CONDVAR 32
+
+#pragma linkage(BPX4CTW, OS)
+#pragma linkage(BPX1CTW, OS)
+
+static int number_of_epolls;
+static QUEUE global_epoll_queue;
+static uv_mutex_t global_epoll_lock;
+static uv_once_t once = UV_ONCE_INIT;
+
+int scandir(const char* maindir, struct dirent*** namelist,
+ int (*filter)(const struct dirent*),
+ int (*compar)(const struct dirent**,
+ const struct dirent **)) {
+ struct dirent** nl;
+ struct dirent* dirent;
+ unsigned count;
+ size_t allocated;
+ DIR* mdir;
+
+ nl = NULL;
+ count = 0;
+ allocated = 0;
+ mdir = opendir(maindir);
+ if (!mdir)
+ return -1;
+
+ while (1) {
+ dirent = readdir(mdir);
+ if (!dirent)
+ break;
+ if (!filter || filter(dirent)) {
+ struct dirent* copy;
+ copy = uv__malloc(sizeof(*copy));
+ if (!copy) {
+ while (count) {
+ dirent = nl[--count];
+ uv__free(dirent);
+ }
+ uv__free(nl);
+ closedir(mdir);
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(copy, dirent, sizeof(*copy));
+
+ nl = uv__realloc(nl, sizeof(*copy) * (count + 1));
+ nl[count++] = copy;
+ }
+ }
+
+ qsort(nl, count, sizeof(struct dirent *),
+ (int (*)(const void *, const void *)) compar);
+
+ closedir(mdir);
+
+ *namelist = nl;
+ return count;
+}
+
+
+static unsigned int next_power_of_two(unsigned int val) {
+ val -= 1;
+ val |= val >> 1;
+ val |= val >> 2;
+ val |= val >> 4;
+ val |= val >> 8;
+ val |= val >> 16;
+ val += 1;
+ return val;
+}
+
+
+static void maybe_resize(uv__os390_epoll* lst, unsigned int len) {
+ unsigned int newsize;
+ unsigned int i;
+ struct pollfd* newlst;
+
+ if (len <= lst->size)
+ return;
+
+ newsize = next_power_of_two(len);
+ newlst = uv__realloc(lst->items, newsize * sizeof(lst->items[0]));
+
+ if (newlst == NULL)
+ abort();
+ for (i = lst->size; i < newsize; ++i)
+ newlst[i].fd = -1;
+
+ lst->items = newlst;
+ lst->size = newsize;
+}
+
+
+static void epoll_init(void) {
+ QUEUE_INIT(&global_epoll_queue);
+ if (uv_mutex_init(&global_epoll_lock))
+ abort();
+}
+
+
+uv__os390_epoll* epoll_create1(int flags) {
+ uv__os390_epoll* lst;
+
+ uv_once(&once, epoll_init);
+ uv_mutex_lock(&global_epoll_lock);
+ lst = uv__malloc(sizeof(*lst));
+ if (lst == -1)
+ return NULL;
+ QUEUE_INSERT_TAIL(&global_epoll_queue, &lst->member);
+ uv_mutex_unlock(&global_epoll_lock);
+
+ /* initialize list */
+ lst->size = 0;
+ lst->items = NULL;
+ return lst;
+}
+
+
+int epoll_ctl(uv__os390_epoll* lst,
+ int op,
+ int fd,
+ struct epoll_event *event) {
+ if(op == EPOLL_CTL_DEL) {
+ if (fd >= lst->size || lst->items[fd].fd == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+ lst->items[fd].fd = -1;
+ } else if(op == EPOLL_CTL_ADD) {
+ maybe_resize(lst, fd + 1);
+ if (lst->items[fd].fd != -1) {
+ errno = EEXIST;
+ return -1;
+ }
+ lst->items[fd].fd = fd;
+ lst->items[fd].events = event->events;
+ } else if(op == EPOLL_CTL_MOD) {
+ if (fd >= lst->size || lst->items[fd].fd == -1) {
+ errno = ENOENT;
+ return -1;
+ }
+ lst->items[fd].events = event->events;
+ } else
+ abort();
+
+ return 0;
+}
+
+
+int epoll_wait(uv__os390_epoll* lst, struct epoll_event* events,
+ int maxevents, int timeout) {
+ size_t size;
+ struct pollfd* pfds;
+ int pollret;
+ int reventcount;
+
+ uv_mutex_lock(&global_epoll_lock);
+ uv_mutex_unlock(&global_epoll_lock);
+ size = lst->size;
+ pfds = lst->items;
+ pollret = poll(pfds, size, timeout);
+ if(pollret == -1)
+ return pollret;
+
+ reventcount = 0;
+ for (int i = 0; i < lst->size && i < maxevents; ++i) {
+ struct epoll_event ev;
+
+ ev.events = 0;
+ ev.fd = pfds[i].fd;
+ if(!pfds[i].revents)
+ continue;
+
+ if(pfds[i].revents & POLLRDNORM)
+ ev.events = ev.events | POLLIN;
+
+ if(pfds[i].revents & POLLWRNORM)
+ ev.events = ev.events | POLLOUT;
+
+ if(pfds[i].revents & POLLHUP)
+ ev.events = ev.events | POLLHUP;
+
+ pfds[i].revents = 0;
+ events[reventcount++] = ev;
+ }
+
+ return reventcount;
+}
+
+
+int epoll_file_close(int fd) {
+ QUEUE* q;
+
+ uv_once(&once, epoll_init);
+ uv_mutex_lock(&global_epoll_lock);
+ QUEUE_FOREACH(q, &global_epoll_queue) {
+ uv__os390_epoll* lst;
+
+ lst = QUEUE_DATA(q, uv__os390_epoll, member);
+ if (fd < lst->size && lst->items != NULL && lst->items[fd].fd != -1)
+ lst->items[fd].fd = -1;
+ }
+
+ uv_mutex_unlock(&global_epoll_lock);
+ return 0;
+}
+
+void epoll_queue_close(uv__os390_epoll* lst) {
+ uv_mutex_lock(&global_epoll_lock);
+ QUEUE_REMOVE(&lst->member);
+ uv_mutex_unlock(&global_epoll_lock);
+ uv__free(lst->items);
+ lst->items = NULL;
+}
+
+
+int nanosleep(const struct timespec* req, struct timespec* rem) {
+ unsigned nano;
+ unsigned seconds;
+ unsigned events;
+ unsigned secrem;
+ unsigned nanorem;
+ int rv;
+ int rc;
+ int rsn;
+
+ nano = (int)req->tv_nsec;
+ seconds = req->tv_sec;
+ events = CW_CONDVAR;
+
+#if defined(_LP64)
+ BPX4CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
+#else
+ BPX1CTW(&seconds, &nano, &events, &secrem, &nanorem, &rv, &rc, &rsn);
+#endif
+
+ assert(rv == -1 && errno == EAGAIN);
+
+ if(rem != NULL) {
+ rem->tv_nsec = nanorem;
+ rem->tv_sec = secrem;
+ }
+
+ return 0;
+}
+
+
+char* mkdtemp(char* path) {
+ static const char* tempchars =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static const size_t num_chars = 62;
+ static const size_t num_x = 6;
+ char *ep, *cp;
+ unsigned int tries, i;
+ size_t len;
+ uint64_t v;
+ int fd;
+ int retval;
+ int saved_errno;
+
+ len = strlen(path);
+ ep = path + len;
+ if (len < num_x || strncmp(ep - num_x, "XXXXXX", num_x)) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ fd = open("/dev/urandom", O_RDONLY);
+ if (fd == -1)
+ return NULL;
+
+ tries = TMP_MAX;
+ retval = -1;
+ do {
+ if (read(fd, &v, sizeof(v)) != sizeof(v))
+ break;
+
+ cp = ep - num_x;
+ for (i = 0; i < num_x; i++) {
+ *cp++ = tempchars[v % num_chars];
+ v /= num_chars;
+ }
+
+ if (mkdir(path, S_IRWXU) == 0) {
+ retval = 0;
+ break;
+ }
+ else if (errno != EEXIST)
+ break;
+ } while (--tries);
+
+ saved_errno = errno;
+ uv__close(fd);
+ if (tries == 0) {
+ errno = EEXIST;
+ return NULL;
+ }
+
+ if (retval == -1) {
+ errno = saved_errno;
+ return NULL;
+ }
+
+ return path;
+}
diff --git a/Utilities/cmlibuv/src/unix/os390-syscalls.h b/Utilities/cmlibuv/src/unix/os390-syscalls.h
new file mode 100644
index 000000000..61a7cee83
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/os390-syscalls.h
@@ -0,0 +1,69 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+
+#ifndef UV_OS390_SYSCALL_H_
+#define UV_OS390_SYSCALL_H_
+
+#include "uv.h"
+#include "internal.h"
+#include <dirent.h>
+#include <poll.h>
+#include <pthread.h>
+
+#define EPOLL_CTL_ADD 1
+#define EPOLL_CTL_DEL 2
+#define EPOLL_CTL_MOD 3
+#define MAX_EPOLL_INSTANCES 256
+#define MAX_ITEMS_PER_EPOLL 1024
+
+#define UV__O_CLOEXEC 0x80000
+#define UV__EPOLL_CLOEXEC UV__O_CLOEXEC
+#define UV__EPOLL_CTL_ADD EPOLL_CTL_ADD
+#define UV__EPOLL_CTL_DEL EPOLL_CTL_DEL
+#define UV__EPOLL_CTL_MOD EPOLL_CTL_MOD
+
+struct epoll_event {
+ int events;
+ int fd;
+};
+
+typedef struct {
+ QUEUE member;
+ struct pollfd* items;
+ unsigned long size;
+} uv__os390_epoll;
+
+/* epoll api */
+uv__os390_epoll* epoll_create1(int flags);
+int epoll_ctl(uv__os390_epoll* ep, int op, int fd, struct epoll_event *event);
+int epoll_wait(uv__os390_epoll* ep, struct epoll_event *events, int maxevents, int timeout);
+int epoll_file_close(int fd);
+
+/* utility functions */
+int nanosleep(const struct timespec* req, struct timespec* rem);
+int scandir(const char* maindir, struct dirent*** namelist,
+ int (*filter)(const struct dirent *),
+ int (*compar)(const struct dirent **,
+ const struct dirent **));
+char *mkdtemp(char* path);
+
+#endif /* UV_OS390_SYSCALL_H_ */
diff --git a/Utilities/cmlibuv/src/unix/os390.c b/Utilities/cmlibuv/src/unix/os390.c
new file mode 100644
index 000000000..2ba5abf35
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/os390.c
@@ -0,0 +1,849 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "internal.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <utmpx.h>
+#include <unistd.h>
+#include <sys/ps.h>
+#if defined(__clang__)
+#include "csrsic.h"
+#else
+#include "//'SYS1.SAMPLIB(CSRSIC)'"
+#endif
+
+#define CVT_PTR 0x10
+#define CSD_OFFSET 0x294
+
+/*
+ Long-term average CPU service used by this logical partition,
+ in millions of service units per hour. If this value is above
+ the partition's defined capacity, the partition will be capped.
+ It is calculated using the physical CPU adjustment factor
+ (RCTPCPUA) so it may not match other measures of service which
+ are based on the logical CPU adjustment factor. It is available
+ if the hardware supports LPAR cluster.
+*/
+#define RCTLACS_OFFSET 0xC4
+
+/* 32-bit count of alive CPUs. This includes both CPs and IFAs */
+#define CSD_NUMBER_ONLINE_CPUS 0xD4
+
+/* Address of system resources manager (SRM) control table */
+#define CVTOPCTP_OFFSET 0x25C
+
+/* Address of the RCT table */
+#define RMCTRCT_OFFSET 0xE4
+
+/* Address of the rsm control and enumeration area. */
+#define CVTRCEP_OFFSET 0x490
+
+/*
+ Number of frames currently available to system.
+ Excluded are frames backing perm storage, frames offline, and bad frames.
+*/
+#define RCEPOOL_OFFSET 0x004
+
+/* Total number of frames currently on all available frame queues. */
+#define RCEAFC_OFFSET 0x088
+
+/* CPC model length from the CSRSI Service. */
+#define CPCMODEL_LENGTH 16
+
+/* Thread Entry constants */
+#define PGTH_CURRENT 1
+#define PGTH_LEN 26
+#define PGTHAPATH 0x20
+#pragma linkage(BPX4GTH, OS)
+#pragma linkage(BPX1GTH, OS)
+
+typedef unsigned data_area_ptr_assign_type;
+
+typedef union {
+ struct {
+#if defined(_LP64)
+ data_area_ptr_assign_type lower;
+#endif
+ data_area_ptr_assign_type assign;
+ };
+ char* deref;
+} data_area_ptr;
+
+
+void uv_loadavg(double avg[3]) {
+ /* TODO: implement the following */
+ avg[0] = 0;
+ avg[1] = 0;
+ avg[2] = 0;
+}
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ uv__os390_epoll* ep;
+
+ ep = epoll_create1(UV__EPOLL_CLOEXEC);
+ loop->ep = ep;
+ if (ep == NULL)
+ return -errno;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->ep != NULL) {
+ epoll_queue_close(loop->ep);
+ loop->ep = NULL;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timeval time;
+ gettimeofday(&time, NULL);
+ return (uint64_t) time.tv_sec * 1e9 + time.tv_usec * 1e3;
+}
+
+
+/*
+ Get the exe path using the thread entry information
+ in the address space.
+*/
+static int getexe(const int pid, char* buf, size_t len) {
+ struct {
+ int pid;
+ int thid[2];
+ char accesspid;
+ char accessthid;
+ char asid[2];
+ char loginname[8];
+ char flag;
+ char len;
+ } Input_data;
+
+ union {
+ struct {
+ char gthb[4];
+ int pid;
+ int thid[2];
+ char accesspid;
+ char accessthid[3];
+ int lenused;
+ int offsetProcess;
+ int offsetConTTY;
+ int offsetPath;
+ int offsetCommand;
+ int offsetFileData;
+ int offsetThread;
+ } Output_data;
+ char buf[2048];
+ } Output_buf;
+
+ struct Output_path_type {
+ char gthe[4];
+ short int len;
+ char path[1024];
+ };
+
+ int Input_length;
+ int Output_length;
+ void* Input_address;
+ void* Output_address;
+ struct Output_path_type* Output_path;
+ int rv;
+ int rc;
+ int rsn;
+
+ Input_length = PGTH_LEN;
+ Output_length = sizeof(Output_buf);
+ Output_address = &Output_buf;
+ Input_address = &Input_data;
+ memset(&Input_data, 0, sizeof Input_data);
+ Input_data.flag |= PGTHAPATH;
+ Input_data.pid = pid;
+ Input_data.accesspid = PGTH_CURRENT;
+
+#ifdef _LP64
+ BPX4GTH(&Input_length,
+ &Input_address,
+ &Output_length,
+ &Output_address,
+ &rv,
+ &rc,
+ &rsn);
+#else
+ BPX1GTH(&Input_length,
+ &Input_address,
+ &Output_length,
+ &Output_address,
+ &rv,
+ &rc,
+ &rsn);
+#endif
+
+ if (rv == -1) {
+ errno = rc;
+ return -1;
+ }
+
+ /* Check highest byte to ensure data availability */
+ assert(((Output_buf.Output_data.offsetPath >>24) & 0xFF) == 'A');
+
+ /* Get the offset from the lowest 3 bytes */
+ Output_path = (char*)(&Output_buf) +
+ (Output_buf.Output_data.offsetPath & 0x00FFFFFF);
+
+ if (Output_path->len >= len) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ strncpy(buf, Output_path->path, len);
+
+ return 0;
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ * There is no direct way of getting the exe path in zOS - either through /procfs
+ * or through some libc APIs. The below approach is to parse the argv[0]'s pattern
+ * and use it in conjunction with PATH environment variable to craft one.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ int res;
+ char args[PATH_MAX];
+ char abspath[PATH_MAX];
+ size_t abspath_size;
+ int pid;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ pid = getpid();
+ res = getexe(pid, args, sizeof(args));
+ if (res < 0)
+ return -EINVAL;
+
+ /*
+ * Possibilities for args:
+ * i) an absolute path such as: /home/user/myprojects/nodejs/node
+ * ii) a relative path such as: ./node or ../myprojects/nodejs/node
+ * iii) a bare filename such as "node", after exporting PATH variable
+ * to its location.
+ */
+
+ /* Case i) and ii) absolute or relative paths */
+ if (strchr(args, '/') != NULL) {
+ if (realpath(args, abspath) != abspath)
+ return -errno;
+
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ return 0;
+ } else {
+ /* Case iii). Search PATH environment variable */
+ char trypath[PATH_MAX];
+ char* clonedpath = NULL;
+ char* token = NULL;
+ char* path = getenv("PATH");
+
+ if (path == NULL)
+ return -EINVAL;
+
+ clonedpath = uv__strdup(path);
+ if (clonedpath == NULL)
+ return -ENOMEM;
+
+ token = strtok(clonedpath, ":");
+ while (token != NULL) {
+ snprintf(trypath, sizeof(trypath) - 1, "%s/%s", token, args);
+ if (realpath(trypath, abspath) == abspath) {
+ /* Check the match is executable */
+ if (access(abspath, X_OK) == 0) {
+ abspath_size = strlen(abspath);
+
+ *size -= 1;
+ if (*size > abspath_size)
+ *size = abspath_size;
+
+ memcpy(buffer, abspath, *size);
+ buffer[*size] = '\0';
+
+ uv__free(clonedpath);
+ return 0;
+ }
+ }
+ token = strtok(NULL, ":");
+ }
+ uv__free(clonedpath);
+
+ /* Out of tokens (path entries), and no match found */
+ return -EINVAL;
+ }
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ uint64_t freeram;
+
+ data_area_ptr cvt = {0};
+ data_area_ptr rcep = {0};
+ cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+ rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
+ freeram = *((uint64_t*)(rcep.deref + RCEAFC_OFFSET)) * 4;
+ return freeram;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ uint64_t totalram;
+
+ data_area_ptr cvt = {0};
+ data_area_ptr rcep = {0};
+ cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+ rcep.assign = *(data_area_ptr_assign_type*)(cvt.deref + CVTRCEP_OFFSET);
+ totalram = *((uint64_t*)(rcep.deref + RCEPOOL_OFFSET)) * 4;
+ return totalram;
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ W_PSPROC buf;
+
+ memset(&buf, 0, sizeof(buf));
+ if (w_getpsent(0, &buf, sizeof(W_PSPROC)) == -1)
+ return -EINVAL;
+
+ *rss = buf.ps_size;
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ struct utmpx u ;
+ struct utmpx *v;
+ time64_t t;
+
+ u.ut_type = BOOT_TIME;
+ v = getutxid(&u);
+ if (v == NULL)
+ return -1;
+ *uptime = difftime64(time64(&t), v->ut_tv.tv_sec);
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ uv_cpu_info_t* cpu_info;
+ int result;
+ int idx;
+ siv1v2 info;
+ data_area_ptr cvt = {0};
+ data_area_ptr csd = {0};
+ data_area_ptr rmctrct = {0};
+ data_area_ptr cvtopctp = {0};
+ int cpu_usage_avg;
+
+ cvt.assign = *(data_area_ptr_assign_type*)(CVT_PTR);
+
+ csd.assign = *((data_area_ptr_assign_type *) (cvt.deref + CSD_OFFSET));
+ cvtopctp.assign = *((data_area_ptr_assign_type *) (cvt.deref + CVTOPCTP_OFFSET));
+ rmctrct.assign = *((data_area_ptr_assign_type *) (cvtopctp.deref + RMCTRCT_OFFSET));
+
+ *count = *((int*) (csd.deref + CSD_NUMBER_ONLINE_CPUS));
+ cpu_usage_avg = *((unsigned short int*) (rmctrct.deref + RCTLACS_OFFSET));
+
+ *cpu_infos = uv__malloc(*count * sizeof(uv_cpu_info_t));
+ if (!*cpu_infos)
+ return -ENOMEM;
+
+ cpu_info = *cpu_infos;
+ idx = 0;
+ while (idx < *count) {
+ cpu_info->speed = *(int*)(info.siv1v2si22v1.si22v1cpucapability);
+ cpu_info->model = uv__malloc(CPCMODEL_LENGTH + 1);
+ memset(cpu_info->model, '\0', CPCMODEL_LENGTH + 1);
+ memcpy(cpu_info->model, info.siv1v2si11v1.si11v1cpcmodel, CPCMODEL_LENGTH);
+ cpu_info->cpu_times.user = cpu_usage_avg;
+ /* TODO: implement the following */
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ cpu_info->cpu_times.nice = 0;
+ ++cpu_info;
+ ++idx;
+ }
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ for (int i = 0; i < count; ++i)
+ uv__free(cpu_infos[i].model);
+ uv__free(cpu_infos);
+}
+
+
+static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
+ int* count) {
+ uv_interface_address_t* address;
+ int sockfd;
+ int maxsize;
+ __net_ifconf6header_t ifc;
+ __net_ifconf6entry_t* ifr;
+ __net_ifconf6entry_t* p;
+ __net_ifconf6entry_t flg;
+
+ *count = 0;
+ /* Assume maximum buffer size allowable */
+ maxsize = 16384;
+
+ if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
+ return -errno;
+
+ ifc.__nif6h_version = 1;
+ ifc.__nif6h_buflen = maxsize;
+ ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
+
+ if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+
+ *count = 0;
+ ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
+ while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
+ p = ifr;
+ ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
+
+ if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
+ p->__nif6e_addr.sin6_family == AF_INET))
+ continue;
+
+ if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
+ continue;
+
+ ++(*count);
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
+ while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
+ p = ifr;
+ ifr = (__net_ifconf6entry_t*)((char*)ifr + ifc.__nif6h_entrylen);
+
+ if (!(p->__nif6e_addr.sin6_family == AF_INET6 ||
+ p->__nif6e_addr.sin6_family == AF_INET))
+ continue;
+
+ if (!(p->__nif6e_flags & _NIF6E_FLAGS_ON_LINK_ACTIVE))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->__nif6e_name);
+
+ if (p->__nif6e_addr.sin6_family == AF_INET6)
+ address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
+ else
+ address->address.address4 = *((struct sockaddr_in*) &p->__nif6e_addr);
+
+ /* TODO: Retrieve netmask using SIOCGIFNETMASK ioctl */
+
+ address->is_internal = flg.__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
+
+ address++;
+ }
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ uv_interface_address_t* address;
+ int sockfd;
+ int maxsize;
+ struct ifconf ifc;
+ struct ifreq flg;
+ struct ifreq* ifr;
+ struct ifreq* p;
+ int count_v6;
+
+ /* get the ipv6 addresses first */
+ uv_interface_address_t* addresses_v6;
+ uv__interface_addresses_v6(&addresses_v6, &count_v6);
+
+ /* now get the ipv4 addresses */
+ *count = 0;
+
+ /* Assume maximum buffer size allowable */
+ maxsize = 16384;
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
+ if (0 > sockfd)
+ return -errno;
+
+ ifc.ifc_req = uv__calloc(1, maxsize);
+ ifc.ifc_len = maxsize;
+ if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
+
+ /* Count all up and running ipv4/ipv6 addresses */
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ (*count)++;
+ }
+
+ /* Alloc the return interface structs */
+ *addresses = uv__malloc((*count + count_v6) *
+ sizeof(uv_interface_address_t));
+
+ if (!(*addresses)) {
+ uv__close(sockfd);
+ return -ENOMEM;
+ }
+ address = *addresses;
+
+ /* copy over the ipv6 addresses */
+ memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
+ address += count_v6;
+ *count += count_v6;
+ uv__free(addresses_v6);
+
+ ifr = ifc.ifc_req;
+ while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
+ p = ifr;
+ ifr = (struct ifreq*)
+ ((char*)ifr + sizeof(ifr->ifr_name) + ADDR_SIZE(ifr->ifr_addr));
+
+ if (!(p->ifr_addr.sa_family == AF_INET6 ||
+ p->ifr_addr.sa_family == AF_INET))
+ continue;
+
+ memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
+ if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
+ uv__close(sockfd);
+ return -ENOSYS;
+ }
+
+ if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
+ continue;
+
+ /* All conditions above must match count loop */
+
+ address->name = uv__strdup(p->ifr_name);
+
+ if (p->ifr_addr.sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
+ }
+
+ address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
+ address++;
+ }
+
+#undef ADDR_SIZE
+#undef MAX
+
+ uv__close(sockfd);
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+ for (i = 0; i < count; ++i)
+ uv__free(addresses[i].name);
+ uv__free(addresses);
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct epoll_event* events;
+ struct epoll_event dummy;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct epoll_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events != NULL)
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].fd == fd)
+ events[i].fd = -1;
+
+ /* Remove the file descriptor from the epoll. */
+ if (loop->ep != NULL)
+ epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, &dummy);
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct pollfd p[1];
+ int rv;
+
+ p[0].fd = fd;
+ p[0].events = POLLIN;
+
+ do
+ rv = poll(p, 1, 0);
+ while (rv == -1 && errno == EINTR);
+
+ if (rv == -1)
+ abort();
+
+ if (p[0].revents & POLLNVAL)
+ return -1;
+
+ return 0;
+}
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ static const int max_safe_timeout = 1789569;
+ struct epoll_event events[1024];
+ struct epoll_event* pe;
+ struct epoll_event e;
+ int real_timeout;
+ QUEUE* q;
+ uv__io_t* w;
+ uint64_t base;
+ int count;
+ int nfds;
+ int fd;
+ int op;
+ int i;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ uv_stream_t* stream;
+
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+
+ stream= container_of(w, uv_stream_t, io_watcher);
+
+ assert(w->fd < (int) loop->nwatchers);
+
+ e.events = w->pevents;
+ e.fd = w->fd;
+
+ if (w->events == 0)
+ op = UV__EPOLL_CTL_ADD;
+ else
+ op = UV__EPOLL_CTL_MOD;
+
+ /* XXX Future optimization: do EPOLL_CTL_MOD lazily if we stop watching
+ * events, skip the syscall and squelch the events after epoll_wait().
+ */
+ if (epoll_ctl(loop->ep, op, w->fd, &e)) {
+ if (errno != EEXIST)
+ abort();
+
+ assert(op == UV__EPOLL_CTL_ADD);
+
+ /* We've reactivated a file descriptor that's been watched before. */
+ if (epoll_ctl(loop->ep, UV__EPOLL_CTL_MOD, w->fd, &e))
+ abort();
+ }
+
+ w->events = w->pevents;
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+ real_timeout = timeout;
+ int nevents = 0;
+
+ nfds = 0;
+ for (;;) {
+ if (sizeof(int32_t) == sizeof(long) && timeout >= max_safe_timeout)
+ timeout = max_safe_timeout;
+
+ nfds = epoll_wait(loop->ep, events,
+ ARRAY_SIZE(events), timeout);
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ base = loop->time;
+ SAVE_ERRNO(uv__update_time(loop));
+ if (nfds == 0) {
+ assert(timeout != -1);
+ timeout = real_timeout - timeout;
+ if (timeout > 0)
+ continue;
+
+ return;
+ }
+
+ if (nfds == -1) {
+
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, disarm it.
+ *
+ * Ignore all errors because we may be racing with another thread
+ * when the file descriptor is closed.
+ */
+ epoll_ctl(loop->ep, UV__EPOLL_CTL_DEL, fd, pe);
+ continue;
+ }
+
+ /* Give users only events they're interested in. Prevents spurious
+ * callbacks when previous callback invocation in this loop has stopped
+ * the current watcher. Also, filters out events that users has not
+ * requested us to watch.
+ */
+ pe->events &= w->pevents | POLLERR | POLLHUP;
+
+ if (pe->events == POLLERR || pe->events == POLLHUP)
+ pe->events |= w->pevents & (POLLIN | POLLOUT);
+
+ if (pe->events != 0) {
+ w->cb(loop, w, pe->events);
+ nevents++;
+ }
+ }
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ real_timeout -= (loop->time - base);
+ if (real_timeout <= 0)
+ return;
+
+ timeout = real_timeout;
+ }
+}
+
+void uv__set_process_title(const char* title) {
+ /* do nothing */
+}
+
+int uv__io_fork(uv_loop_t* loop) {
+ uv__platform_loop_delete(loop);
+
+ return uv__platform_loop_init(loop);
+}
diff --git a/Utilities/cmlibuv/src/unix/pipe.c b/Utilities/cmlibuv/src/unix/pipe.c
new file mode 100644
index 000000000..7ba1bf879
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/pipe.c
@@ -0,0 +1,302 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv__stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+ handle->shutdown_req = NULL;
+ handle->connect_req = NULL;
+ handle->pipe_fname = NULL;
+ handle->ipc = ipc;
+ return 0;
+}
+
+
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ struct sockaddr_un saddr;
+ const char* pipe_fname = NULL;
+ int sockfd = -1;
+ int err;
+
+ /* Already bound? */
+ if (uv__stream_fd(handle) >= 0)
+ return -EINVAL;
+
+ /* Make a copy of the file name, it outlives this function's scope. */
+ pipe_fname = uv__strdup(name);
+ if (pipe_fname == NULL)
+ return -ENOMEM;
+
+ /* We've got a copy, don't touch the original any more. */
+ name = NULL;
+
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto err_socket;
+ sockfd = err;
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, pipe_fname, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ if (bind(sockfd, (struct sockaddr*)&saddr, sizeof saddr)) {
+ err = -errno;
+ /* Convert ENOENT to EACCES for compatibility with Windows. */
+ if (err == -ENOENT)
+ err = -EACCES;
+
+ uv__close(sockfd);
+ goto err_socket;
+ }
+
+ /* Success. */
+ handle->flags |= UV_HANDLE_BOUND;
+ handle->pipe_fname = pipe_fname; /* Is a strdup'ed copy. */
+ handle->io_watcher.fd = sockfd;
+ return 0;
+
+err_socket:
+ uv__free((void*)pipe_fname);
+ return err;
+}
+
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ if (uv__stream_fd(handle) == -1)
+ return -EINVAL;
+
+#if defined(__MVS__)
+ /* On zOS, backlog=0 has undefined behaviour */
+ if (backlog == 0)
+ backlog = 1;
+ else if (backlog < 0)
+ backlog = SOMAXCONN;
+#endif
+
+ if (listen(uv__stream_fd(handle), backlog))
+ return -errno;
+
+ handle->connection_cb = cb;
+ handle->io_watcher.cb = uv__server_io;
+ uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
+ return 0;
+}
+
+
+void uv__pipe_close(uv_pipe_t* handle) {
+ if (handle->pipe_fname) {
+ /*
+ * Unlink the file system entity before closing the file descriptor.
+ * Doing it the other way around introduces a race where our process
+ * unlinks a socket with the same name that's just been created by
+ * another thread or process.
+ */
+ unlink(handle->pipe_fname);
+ uv__free((void*)handle->pipe_fname);
+ handle->pipe_fname = NULL;
+ }
+
+ uv__stream_close((uv_stream_t*)handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* handle, uv_file fd) {
+ int err;
+
+ err = uv__nonblock(fd, 1);
+ if (err)
+ return err;
+
+#if defined(__APPLE__)
+ err = uv__stream_try_select((uv_stream_t*) handle, &fd);
+ if (err)
+ return err;
+#endif /* defined(__APPLE__) */
+
+ return uv__stream_open((uv_stream_t*)handle,
+ fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+void uv_pipe_connect(uv_connect_t* req,
+ uv_pipe_t* handle,
+ const char* name,
+ uv_connect_cb cb) {
+ struct sockaddr_un saddr;
+ int new_sock;
+ int err;
+ int r;
+
+ new_sock = (uv__stream_fd(handle) == -1);
+
+ if (new_sock) {
+ err = uv__socket(AF_UNIX, SOCK_STREAM, 0);
+ if (err < 0)
+ goto out;
+ handle->io_watcher.fd = err;
+ }
+
+ memset(&saddr, 0, sizeof saddr);
+ strncpy(saddr.sun_path, name, sizeof(saddr.sun_path) - 1);
+ saddr.sun_path[sizeof(saddr.sun_path) - 1] = '\0';
+ saddr.sun_family = AF_UNIX;
+
+ do {
+ r = connect(uv__stream_fd(handle),
+ (struct sockaddr*)&saddr, sizeof saddr);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if (r == -1 && errno != EINPROGRESS) {
+ err = -errno;
+#if defined(__CYGWIN__) || defined(__MSYS__)
+ /* EBADF is supposed to mean that the socket fd is bad, but
+ Cygwin reports EBADF instead of ENOTSOCK when the file is
+ not a socket. We do not expect to see a bad fd here
+ (e.g. due to new_sock), so translate the error. */
+ if (err == -EBADF)
+ err = -ENOTSOCK;
+#endif
+ goto out;
+ }
+
+ err = 0;
+ if (new_sock) {
+ err = uv__stream_open((uv_stream_t*)handle,
+ uv__stream_fd(handle),
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ }
+
+ if (err == 0)
+ uv__io_start(handle->loop, &handle->io_watcher, POLLIN | POLLOUT);
+
+out:
+ handle->delayed_error = err;
+ handle->connect_req = req;
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->handle = (uv_stream_t*)handle;
+ req->cb = cb;
+ QUEUE_INIT(&req->queue);
+
+ /* Force callback to run on next tick in case of error. */
+ if (err)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+}
+
+
+typedef int (*uv__peersockfunc)(int, struct sockaddr*, socklen_t*);
+
+
+static int uv__pipe_getsockpeername(const uv_pipe_t* handle,
+ uv__peersockfunc func,
+ char* buffer,
+ size_t* size) {
+ struct sockaddr_un sa;
+ socklen_t addrlen;
+ int err;
+
+ addrlen = sizeof(sa);
+ memset(&sa, 0, addrlen);
+ err = func(uv__stream_fd(handle), (struct sockaddr*) &sa, &addrlen);
+ if (err < 0) {
+ *size = 0;
+ return -errno;
+ }
+
+#if defined(__linux__)
+ if (sa.sun_path[0] == 0)
+ /* Linux abstract namespace */
+ addrlen -= offsetof(struct sockaddr_un, sun_path);
+ else
+#endif
+ addrlen = strlen(sa.sun_path);
+
+
+ if (addrlen >= *size) {
+ *size = addrlen + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, sa.sun_path, addrlen);
+ *size = addrlen;
+
+ /* only null-terminate if it's not an abstract socket */
+ if (buffer[0] != '\0')
+ buffer[addrlen] = '\0';
+
+ return 0;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getsockname, buffer, size);
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ return uv__pipe_getsockpeername(handle, getpeername, buffer, size);
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ if (!handle->ipc)
+ return 0;
+
+ if (handle->accepted_fd == -1)
+ return 0;
+
+ if (handle->queued_fds == NULL)
+ return 1;
+
+ queued_fds = handle->queued_fds;
+ return queued_fds->offset + 1;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+
+ if (handle->accepted_fd == -1)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return uv__handle_type(handle->accepted_fd);
+}
diff --git a/Utilities/cmlibuv/src/unix/poll.c b/Utilities/cmlibuv/src/unix/poll.c
new file mode 100644
index 000000000..370994bd5
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/poll.c
@@ -0,0 +1,130 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static void uv__poll_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_poll_t* handle;
+ int pevents;
+
+ handle = container_of(w, uv_poll_t, io_watcher);
+
+ if (events & POLLERR) {
+ uv__io_stop(loop, w, POLLIN | POLLOUT | UV__POLLRDHUP);
+ uv__handle_stop(handle);
+ handle->poll_cb(handle, -EBADF, 0);
+ return;
+ }
+
+ pevents = 0;
+ if (events & POLLIN)
+ pevents |= UV_READABLE;
+ if (events & POLLOUT)
+ pevents |= UV_WRITABLE;
+ if (events & UV__POLLRDHUP)
+ pevents |= UV_DISCONNECT;
+
+ handle->poll_cb(handle, 0, pevents);
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ int err;
+
+ err = uv__io_check_fd(loop, fd);
+ if (err)
+ return err;
+
+ /* If ioctl(FIONBIO) reports ENOTTY, try fcntl(F_GETFL) + fcntl(F_SETFL).
+ * Workaround for e.g. kqueue fds not supporting ioctls.
+ */
+ err = uv__nonblock(fd, 1);
+ if (err == -ENOTTY)
+ if (uv__nonblock == uv__nonblock_ioctl)
+ err = uv__nonblock_fcntl(fd, 1);
+
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ uv__io_init(&handle->io_watcher, uv__poll_io, fd);
+ handle->poll_cb = NULL;
+ return 0;
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ return uv_poll_init(loop, handle, socket);
+}
+
+
+static void uv__poll_stop(uv_poll_t* handle) {
+ uv__io_stop(handle->loop,
+ &handle->io_watcher,
+ POLLIN | POLLOUT | UV__POLLRDHUP);
+ uv__handle_stop(handle);
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ assert(!uv__is_closing(handle));
+ uv__poll_stop(handle);
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int pevents, uv_poll_cb poll_cb) {
+ int events;
+
+ assert((pevents & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+ assert(!uv__is_closing(handle));
+
+ uv__poll_stop(handle);
+
+ if (pevents == 0)
+ return 0;
+
+ events = 0;
+ if (pevents & UV_READABLE)
+ events |= POLLIN;
+ if (pevents & UV_WRITABLE)
+ events |= POLLOUT;
+ if (pevents & UV_DISCONNECT)
+ events |= UV__POLLRDHUP;
+
+ uv__io_start(handle->loop, &handle->io_watcher, events);
+ uv__handle_start(handle);
+ handle->poll_cb = poll_cb;
+
+ return 0;
+}
+
+
+void uv__poll_close(uv_poll_t* handle) {
+ uv__poll_stop(handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/posix-hrtime.c b/Utilities/cmlibuv/src/unix/posix-hrtime.c
new file mode 100644
index 000000000..323dfc203
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/posix-hrtime.c
@@ -0,0 +1,35 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <time.h>
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (((uint64_t) ts.tv_sec) * NANOSEC + ts.tv_nsec);
+}
diff --git a/Utilities/cmlibuv/src/unix/posix-poll.c b/Utilities/cmlibuv/src/unix/posix-poll.c
new file mode 100644
index 000000000..3fba96e1b
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/posix-poll.c
@@ -0,0 +1,324 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+/* POSIX defines poll() as a portable way to wait on file descriptors.
+ * Here we maintain a dynamically sized array of file descriptors and
+ * events to pass as the first argument to poll().
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ loop->poll_fds = NULL;
+ loop->poll_fds_used = 0;
+ loop->poll_fds_size = 0;
+ loop->poll_fds_iterating = 0;
+ return 0;
+}
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ uv__free(loop->poll_fds);
+ loop->poll_fds = NULL;
+}
+
+int uv__io_fork(uv_loop_t* loop) {
+ uv__platform_loop_delete(loop);
+ return uv__platform_loop_init(loop);
+}
+
+/* Allocate or dynamically resize our poll fds array. */
+static void uv__pollfds_maybe_resize(uv_loop_t* loop) {
+ size_t i;
+ size_t n;
+ struct pollfd* p;
+
+ if (loop->poll_fds_used < loop->poll_fds_size)
+ return;
+
+ n = loop->poll_fds_size ? loop->poll_fds_size * 2 : 64;
+ p = uv__realloc(loop->poll_fds, n * sizeof(*loop->poll_fds));
+ if (p == NULL)
+ abort();
+
+ loop->poll_fds = p;
+ for (i = loop->poll_fds_size; i < n; i++) {
+ loop->poll_fds[i].fd = -1;
+ loop->poll_fds[i].events = 0;
+ loop->poll_fds[i].revents = 0;
+ }
+ loop->poll_fds_size = n;
+}
+
+/* Primitive swap operation on poll fds array elements. */
+static void uv__pollfds_swap(uv_loop_t* loop, size_t l, size_t r) {
+ struct pollfd pfd;
+ pfd = loop->poll_fds[l];
+ loop->poll_fds[l] = loop->poll_fds[r];
+ loop->poll_fds[r] = pfd;
+}
+
+/* Add a watcher's fd to our poll fds array with its pending events. */
+static void uv__pollfds_add(uv_loop_t* loop, uv__io_t* w) {
+ size_t i;
+ struct pollfd* pe;
+
+ /* If the fd is already in the set just update its events. */
+ assert(!loop->poll_fds_iterating);
+ for (i = 0; i < loop->poll_fds_used; ++i) {
+ if (loop->poll_fds[i].fd == w->fd) {
+ loop->poll_fds[i].events = w->pevents;
+ return;
+ }
+ }
+
+ /* Otherwise, allocate a new slot in the set for the fd. */
+ uv__pollfds_maybe_resize(loop);
+ pe = &loop->poll_fds[loop->poll_fds_used++];
+ pe->fd = w->fd;
+ pe->events = w->pevents;
+}
+
+/* Remove a watcher's fd from our poll fds array. */
+static void uv__pollfds_del(uv_loop_t* loop, int fd) {
+ size_t i;
+ assert(!loop->poll_fds_iterating);
+ for (i = 0; i < loop->poll_fds_used; ++i) {
+ if (loop->poll_fds[i].fd == fd) {
+ /* swap to last position and remove */
+ --loop->poll_fds_used;
+ uv__pollfds_swap(loop, i, loop->poll_fds_used);
+ loop->poll_fds[loop->poll_fds_used].fd = -1;
+ loop->poll_fds[loop->poll_fds_used].events = 0;
+ loop->poll_fds[loop->poll_fds_used].revents = 0;
+ return;
+ }
+ }
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t time_base;
+ uint64_t time_diff;
+ QUEUE* q;
+ uv__io_t* w;
+ size_t i;
+ unsigned int nevents;
+ int nfds;
+ int have_signals;
+ struct pollfd* pe;
+ int fd;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ /* Take queued watchers and add their fds to our poll fds array. */
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+ assert(w->fd >= 0);
+ assert(w->fd < (int) loop->nwatchers);
+
+ uv__pollfds_add(loop, w);
+
+ w->events = w->pevents;
+ }
+
+ /* Prepare a set of signals to block around poll(), if any. */
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ time_base = loop->time;
+
+ /* Loop calls to poll() and processing of results. If we get some
+ * results from poll() but they turn out not to be interesting to
+ * our caller then we need to loop around and poll() again.
+ */
+ for (;;) {
+ if (pset != NULL)
+ if (pthread_sigmask(SIG_BLOCK, pset, NULL))
+ abort();
+ nfds = poll(loop->poll_fds, (nfds_t)loop->poll_fds_used, timeout);
+ if (pset != NULL)
+ if (pthread_sigmask(SIG_UNBLOCK, pset, NULL))
+ abort();
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (nfds == -1) {
+ if (errno != EINTR)
+ abort();
+
+ if (timeout == -1)
+ continue;
+
+ if (timeout == 0)
+ return;
+
+ /* Interrupted by a signal. Update timeout and poll again. */
+ goto update_timeout;
+ }
+
+ /* Tell uv__platform_invalidate_fd not to manipulate our array
+ * while we are iterating over it.
+ */
+ loop->poll_fds_iterating = 1;
+
+ /* Initialize a count of events that we care about. */
+ nevents = 0;
+ have_signals = 0;
+
+ /* Loop over the entire poll fds array looking for returned events. */
+ for (i = 0; i < loop->poll_fds_used; i++) {
+ pe = loop->poll_fds + i;
+ fd = pe->fd;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd. */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ if (w == NULL) {
+ /* File descriptor that we've stopped watching, ignore. */
+ uv__platform_invalidate_fd(loop, fd);
+ continue;
+ }
+
+ /* Filter out events that user has not requested us to watch
+ * (e.g. POLLNVAL).
+ */
+ pe->revents &= w->pevents | POLLERR | POLLHUP;
+
+ if (pe->revents != 0) {
+ /* Run signal watchers last. */
+ if (w == &loop->signal_io_watcher) {
+ have_signals = 1;
+ } else {
+ w->cb(loop, w, pe->revents);
+ }
+
+ nevents++;
+ }
+ }
+
+ if (have_signals != 0)
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+
+ loop->poll_fds_iterating = 0;
+
+ /* Purge invalidated fds from our poll fds array. */
+ uv__pollfds_del(loop, -1);
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0)
+ return;
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ time_diff = loop->time - time_base;
+ if (time_diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= time_diff;
+ }
+}
+
+/* Remove the given fd from our poll fds array because no one
+ * is interested in its events anymore.
+ */
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ size_t i;
+
+ if (loop->poll_fds_iterating) {
+ /* uv__io_poll is currently iterating. Just invalidate fd. */
+ for (i = 0; i < loop->poll_fds_used; i++)
+ if (loop->poll_fds[i].fd == fd) {
+ loop->poll_fds[i].fd = -1;
+ loop->poll_fds[i].events = 0;
+ loop->poll_fds[i].revents = 0;
+ }
+ } else {
+ /* uv__io_poll is not iterating. Delete fd from the set. */
+ uv__pollfds_del(loop, fd);
+ }
+}
+
+/* Check whether the given fd is supported by poll(). */
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ struct pollfd p[1];
+ int rv;
+
+ p[0].fd = fd;
+ p[0].events = POLLIN;
+
+ do
+ rv = poll(p, 1, 0);
+ while (rv == -1 && (errno == EINTR || errno == EAGAIN));
+
+ if (rv == -1)
+ return -errno;
+
+ if (p[0].revents & POLLNVAL)
+ return -EINVAL;
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/process.c b/Utilities/cmlibuv/src/unix/process.c
new file mode 100644
index 000000000..f2fe30521
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/process.c
@@ -0,0 +1,563 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#if defined(__APPLE__) && !TARGET_OS_IPHONE
+# include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#else
+extern char **environ;
+#endif
+
+#if defined(__linux__) || defined(__GLIBC__)
+# include <grp.h>
+#endif
+
+
+static void uv__chld(uv_signal_t* handle, int signum) {
+ uv_process_t* process;
+ uv_loop_t* loop;
+ int exit_status;
+ int term_signal;
+ int status;
+ pid_t pid;
+ QUEUE pending;
+ QUEUE* q;
+ QUEUE* h;
+
+ assert(signum == SIGCHLD);
+
+ QUEUE_INIT(&pending);
+ loop = handle->loop;
+
+ h = &loop->process_handles;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ do
+ pid = waitpid(process->pid, &status, WNOHANG);
+ while (pid == -1 && errno == EINTR);
+
+ if (pid == 0)
+ continue;
+
+ if (pid == -1) {
+ if (errno != ECHILD)
+ abort();
+ continue;
+ }
+
+ process->status = status;
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INSERT_TAIL(&pending, &process->queue);
+ }
+
+ h = &pending;
+ q = QUEUE_HEAD(h);
+ while (q != h) {
+ process = QUEUE_DATA(q, uv_process_t, queue);
+ q = QUEUE_NEXT(q);
+
+ QUEUE_REMOVE(&process->queue);
+ QUEUE_INIT(&process->queue);
+ uv__handle_stop(process);
+
+ if (process->exit_cb == NULL)
+ continue;
+
+ exit_status = 0;
+ if (WIFEXITED(process->status))
+ exit_status = WEXITSTATUS(process->status);
+
+ term_signal = 0;
+ if (WIFSIGNALED(process->status))
+ term_signal = WTERMSIG(process->status);
+
+ process->exit_cb(process, exit_status, term_signal);
+ }
+ assert(QUEUE_EMPTY(&pending));
+}
+
+
+int uv__make_socketpair(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_cloexec;
+
+ if (no_cloexec)
+ goto skip;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | UV__SOCK_CLOEXEC | flags, 0, fds) == 0)
+ return 0;
+
+ /* Retry on EINVAL, it means SOCK_CLOEXEC is not supported.
+ * Anything else is a genuine error.
+ */
+ if (errno != EINVAL)
+ return -errno;
+
+ no_cloexec = 1;
+
+skip:
+#endif
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+int uv__make_pipe(int fds[2], int flags) {
+#if defined(__linux__)
+ static int no_pipe2;
+
+ if (no_pipe2)
+ goto skip;
+
+ if (uv__pipe2(fds, flags | UV__O_CLOEXEC) == 0)
+ return 0;
+
+ if (errno != ENOSYS)
+ return -errno;
+
+ no_pipe2 = 1;
+
+skip:
+#endif
+
+ if (pipe(fds))
+ return -errno;
+
+ uv__cloexec(fds[0], 1);
+ uv__cloexec(fds[1], 1);
+
+ if (flags & UV__F_NONBLOCK) {
+ uv__nonblock(fds[0], 1);
+ uv__nonblock(fds[1], 1);
+ }
+
+ return 0;
+}
+
+
+/*
+ * Used for initializing stdio streams like options.stdin_stream. Returns
+ * zero on success. See also the cleanup section in uv_spawn().
+ */
+static int uv__process_init_stdio(uv_stdio_container_t* container, int fds[2]) {
+ int mask;
+ int fd;
+
+ mask = UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | UV_INHERIT_STREAM;
+
+ switch (container->flags & mask) {
+ case UV_IGNORE:
+ return 0;
+
+ case UV_CREATE_PIPE:
+ assert(container->data.stream != NULL);
+ if (container->data.stream->type != UV_NAMED_PIPE)
+ return -EINVAL;
+ else
+ return uv__make_socketpair(fds, 0);
+
+ case UV_INHERIT_FD:
+ case UV_INHERIT_STREAM:
+ if (container->flags & UV_INHERIT_FD)
+ fd = container->data.fd;
+ else
+ fd = uv__stream_fd(container->data.stream);
+
+ if (fd == -1)
+ return -EINVAL;
+
+ fds[1] = fd;
+ return 0;
+
+ default:
+ assert(0 && "Unexpected flags");
+ return -EINVAL;
+ }
+}
+
+
+static int uv__process_open_stream(uv_stdio_container_t* container,
+ int pipefds[2],
+ int writable) {
+ int flags;
+ int err;
+
+ if (!(container->flags & UV_CREATE_PIPE) || pipefds[0] < 0)
+ return 0;
+
+ err = uv__close(pipefds[1]);
+ if (err != 0)
+ abort();
+
+ pipefds[1] = -1;
+ uv__nonblock(pipefds[0], 1);
+
+ if (container->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*)container->data.stream)->ipc)
+ flags = UV_STREAM_READABLE | UV_STREAM_WRITABLE;
+ else if (writable)
+ flags = UV_STREAM_WRITABLE;
+ else
+ flags = UV_STREAM_READABLE;
+
+ return uv__stream_open(container->data.stream, pipefds[0], flags);
+}
+
+
+static void uv__process_close_stream(uv_stdio_container_t* container) {
+ if (!(container->flags & UV_CREATE_PIPE)) return;
+ uv__stream_close((uv_stream_t*)container->data.stream);
+}
+
+
+static void uv__write_int(int fd, int val) {
+ ssize_t n;
+
+ do
+ n = write(fd, &val, sizeof(val));
+ while (n == -1 && errno == EINTR);
+
+ if (n == -1 && errno == EPIPE)
+ return; /* parent process has quit */
+
+ assert(n == sizeof(val));
+}
+
+
+#if !(defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH))
+/* execvp is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED, so must be
+ * avoided. Since this isn't called on those targets, the function
+ * doesn't even need to be defined for them.
+ */
+static void uv__process_child_init(const uv_process_options_t* options,
+ int stdio_count,
+ int (*pipes)[2],
+ int error_fd) {
+ int close_fd;
+ int use_fd;
+ int fd;
+
+ if (options->flags & UV_PROCESS_DETACHED)
+ setsid();
+
+ /* First duplicate low numbered fds, since it's not safe to duplicate them,
+ * they could get replaced. Example: swapping stdout and stderr; without
+ * this fd 2 (stderr) would be duplicated into fd 1, thus making both
+ * stdout and stderr go to the same fd, which was not the intention. */
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+ if (use_fd < 0 || use_fd >= fd)
+ continue;
+ pipes[fd][1] = fcntl(use_fd, F_DUPFD, stdio_count);
+ if (pipes[fd][1] == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ close_fd = pipes[fd][0];
+ use_fd = pipes[fd][1];
+
+ if (use_fd < 0) {
+ if (fd >= 3)
+ continue;
+ else {
+ /* redirect stdin, stdout and stderr to /dev/null even if UV_IGNORE is
+ * set
+ */
+ use_fd = open("/dev/null", fd == 0 ? O_RDONLY : O_RDWR);
+ close_fd = use_fd;
+
+ if (use_fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+ }
+ }
+
+ if (fd == use_fd)
+ uv__cloexec_fcntl(use_fd, 0);
+ else
+ fd = dup2(use_fd, fd);
+
+ if (fd == -1) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (fd <= 2)
+ uv__nonblock_fcntl(fd, 0);
+
+ if (close_fd >= stdio_count)
+ uv__close(close_fd);
+ }
+
+ for (fd = 0; fd < stdio_count; fd++) {
+ use_fd = pipes[fd][1];
+
+ if (use_fd >= stdio_count)
+ uv__close(use_fd);
+ }
+
+ if (options->cwd != NULL && chdir(options->cwd)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->flags & (UV_PROCESS_SETUID | UV_PROCESS_SETGID)) {
+ /* When dropping privileges from root, the `setgroups` call will
+ * remove any extraneous groups. If we don't call this, then
+ * even though our uid has dropped, we may still have groups
+ * that enable us to do super-user things. This will fail if we
+ * aren't root, so don't bother checking the return value, this
+ * is just done as an optimistic privilege dropping function.
+ */
+ SAVE_ERRNO(setgroups(0, NULL));
+ }
+
+ if ((options->flags & UV_PROCESS_SETGID) && setgid(options->gid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if ((options->flags & UV_PROCESS_SETUID) && setuid(options->uid)) {
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+ }
+
+ if (options->env != NULL) {
+ environ = options->env;
+ }
+
+ execvp(options->file, options->args);
+ uv__write_int(error_fd, -errno);
+ _exit(127);
+}
+#endif
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+#if defined(__APPLE__) && (TARGET_OS_TV || TARGET_OS_WATCH)
+ /* fork is marked __WATCHOS_PROHIBITED __TVOS_PROHIBITED. */
+ return -ENOSYS;
+#else
+ int signal_pipe[2] = { -1, -1 };
+ int (*pipes)[2];
+ int stdio_count;
+ ssize_t r;
+ pid_t pid;
+ int err;
+ int exec_errorno;
+ int i;
+ int status;
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ uv__handle_init(loop, (uv_handle_t*)process, UV_PROCESS);
+ QUEUE_INIT(&process->queue);
+
+ stdio_count = options->stdio_count;
+ if (stdio_count < 3)
+ stdio_count = 3;
+
+ err = -ENOMEM;
+ pipes = uv__malloc(stdio_count * sizeof(*pipes));
+ if (pipes == NULL)
+ goto error;
+
+ for (i = 0; i < stdio_count; i++) {
+ pipes[i][0] = -1;
+ pipes[i][1] = -1;
+ }
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_init_stdio(options->stdio + i, pipes[i]);
+ if (err)
+ goto error;
+ }
+
+ /* This pipe is used by the parent to wait until
+ * the child has called `execve()`. We need this
+ * to avoid the following race condition:
+ *
+ * if ((pid = fork()) > 0) {
+ * kill(pid, SIGTERM);
+ * }
+ * else if (pid == 0) {
+ * execve("/bin/cat", argp, envp);
+ * }
+ *
+ * The parent sends a signal immediately after forking.
+ * Since the child may not have called `execve()` yet,
+ * there is no telling what process receives the signal,
+ * our fork or /bin/cat.
+ *
+ * To avoid ambiguity, we create a pipe with both ends
+ * marked close-on-exec. Then, after the call to `fork()`,
+ * the parent polls the read end until it EOFs or errors with EPIPE.
+ */
+ err = uv__make_pipe(signal_pipe, 0);
+ if (err)
+ goto error;
+
+ uv_signal_start(&loop->child_watcher, uv__chld, SIGCHLD);
+
+ /* Acquire write lock to prevent opening new fds in worker threads */
+ uv_rwlock_wrlock(&loop->cloexec_lock);
+ pid = fork();
+
+ if (pid == -1) {
+ err = -errno;
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[0]);
+ uv__close(signal_pipe[1]);
+ goto error;
+ }
+
+ if (pid == 0) {
+ uv__process_child_init(options, stdio_count, pipes, signal_pipe[1]);
+ abort();
+ }
+
+ /* Release lock in parent process */
+ uv_rwlock_wrunlock(&loop->cloexec_lock);
+ uv__close(signal_pipe[1]);
+
+ process->status = 0;
+ exec_errorno = 0;
+ do
+ r = read(signal_pipe[0], &exec_errorno, sizeof(exec_errorno));
+ while (r == -1 && errno == EINTR);
+
+ if (r == 0)
+ ; /* okay, EOF */
+ else if (r == sizeof(exec_errorno)) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, read errorno */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else if (r == -1 && errno == EPIPE) {
+ do
+ err = waitpid(pid, &status, 0); /* okay, got EPIPE */
+ while (err == -1 && errno == EINTR);
+ assert(err == pid);
+ } else
+ abort();
+
+ uv__close_nocheckstdio(signal_pipe[0]);
+
+ for (i = 0; i < options->stdio_count; i++) {
+ err = uv__process_open_stream(options->stdio + i, pipes[i], i == 0);
+ if (err == 0)
+ continue;
+
+ while (i--)
+ uv__process_close_stream(options->stdio + i);
+
+ goto error;
+ }
+
+ /* Only activate this handle if exec() happened successfully */
+ if (exec_errorno == 0) {
+ QUEUE_INSERT_TAIL(&loop->process_handles, &process->queue);
+ uv__handle_start(process);
+ }
+
+ process->pid = pid;
+ process->exit_cb = options->exit_cb;
+
+ uv__free(pipes);
+ return exec_errorno;
+
+error:
+ if (pipes != NULL) {
+ for (i = 0; i < stdio_count; i++) {
+ if (i < options->stdio_count)
+ if (options->stdio[i].flags & (UV_INHERIT_FD | UV_INHERIT_STREAM))
+ continue;
+ if (pipes[i][0] != -1)
+ uv__close_nocheckstdio(pipes[i][0]);
+ if (pipes[i][1] != -1)
+ uv__close_nocheckstdio(pipes[i][1]);
+ }
+ uv__free(pipes);
+ }
+
+ return err;
+#endif
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ return uv_kill(process->pid, signum);
+}
+
+
+int uv_kill(int pid, int signum) {
+ if (kill(pid, signum))
+ return -errno;
+ else
+ return 0;
+}
+
+
+void uv__process_close(uv_process_t* handle) {
+ QUEUE_REMOVE(&handle->queue);
+ uv__handle_stop(handle);
+ if (QUEUE_EMPTY(&handle->loop->process_handles))
+ uv_signal_stop(&handle->loop->child_watcher);
+}
diff --git a/Utilities/cmlibuv/src/unix/procfs-exepath.c b/Utilities/cmlibuv/src/unix/procfs-exepath.c
new file mode 100644
index 000000000..5fdb61155
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/procfs-exepath.c
@@ -0,0 +1,45 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stddef.h>
+#include <unistd.h>
+
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t n;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ n = *size - 1;
+ if (n > 0)
+ n = readlink("/proc/self/exe", buffer, n);
+
+ if (n == -1)
+ return -errno;
+
+ buffer[n] = '\0';
+ *size = n;
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/proctitle.c b/Utilities/cmlibuv/src/unix/proctitle.c
new file mode 100644
index 000000000..9160f7eaf
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/proctitle.c
@@ -0,0 +1,111 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+extern void uv__set_process_title(const char* title);
+
+static void* args_mem;
+
+static struct {
+ char* str;
+ size_t len;
+} process_title;
+
+
+char** uv_setup_args(int argc, char** argv) {
+ char** new_argv;
+ size_t size;
+ char* s;
+ int i;
+
+ if (argc <= 0)
+ return argv;
+
+ /* Calculate how much memory we need for the argv strings. */
+ size = 0;
+ for (i = 0; i < argc; i++)
+ size += strlen(argv[i]) + 1;
+
+#if defined(__MVS__)
+ /* argv is not adjacent. So just use argv[0] */
+ process_title.str = argv[0];
+ process_title.len = strlen(argv[0]);
+#else
+ process_title.str = argv[0];
+ process_title.len = argv[argc - 1] + strlen(argv[argc - 1]) - argv[0];
+ assert(process_title.len + 1 == size); /* argv memory should be adjacent. */
+#endif
+
+ /* Add space for the argv pointers. */
+ size += (argc + 1) * sizeof(char*);
+
+ new_argv = uv__malloc(size);
+ if (new_argv == NULL)
+ return argv;
+ args_mem = new_argv;
+
+ /* Copy over the strings and set up the pointer table. */
+ s = (char*) &new_argv[argc + 1];
+ for (i = 0; i < argc; i++) {
+ size = strlen(argv[i]) + 1;
+ memcpy(s, argv[i], size);
+ new_argv[i] = s;
+ s += size;
+ }
+ new_argv[i] = NULL;
+
+ return new_argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ if (process_title.len == 0)
+ return 0;
+
+ /* No need to terminate, byte after is always '\0'. */
+ strncpy(process_title.str, title, process_title.len);
+ uv__set_process_title(title);
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ if (buffer == NULL || size == 0)
+ return -EINVAL;
+ else if (size <= process_title.len)
+ return -ENOBUFS;
+
+ memcpy(buffer, process_title.str, process_title.len + 1);
+ buffer[process_title.len] = '\0';
+
+ return 0;
+}
+
+
+UV_DESTRUCTOR(static void free_args_mem(void)) {
+ uv__free(args_mem); /* Keep valgrind happy. */
+ args_mem = NULL;
+}
diff --git a/Utilities/cmlibuv/src/unix/pthread-barrier.c b/Utilities/cmlibuv/src/unix/pthread-barrier.c
new file mode 100644
index 000000000..b6e604d46
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/pthread-barrier.c
@@ -0,0 +1,121 @@
+/*
+Copyright (c) 2016, Kari Tristan Helgason <kthelgason@gmail.com>
+
+Permission to use, copy, modify, and/or distribute this software for any
+purpose with or without fee is hereby granted, provided that the above
+copyright notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+*/
+#include "uv-common.h"
+#include "pthread-barrier.h"
+
+#include <stdlib.h>
+#include <assert.h>
+
+/* TODO: support barrier_attr */
+int pthread_barrier_init(pthread_barrier_t* barrier,
+ const void* barrier_attr,
+ unsigned count) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || count == 0)
+ return EINVAL;
+
+ if (barrier_attr != NULL)
+ return ENOTSUP;
+
+ b = uv__malloc(sizeof(*b));
+ if (b == NULL)
+ return ENOMEM;
+
+ b->in = 0;
+ b->out = 0;
+ b->threshold = count;
+
+ if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
+ goto error2;
+ if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
+ goto error;
+
+ barrier->b = b;
+ return 0;
+
+error:
+ pthread_mutex_destroy(&b->mutex);
+error2:
+ uv__free(b);
+ return rc;
+}
+
+int pthread_barrier_wait(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+ /* Lock the mutex*/
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ /* Increment the count. If this is the first thread to reach the threshold,
+ wake up waiters, unlock the mutex, then return
+ PTHREAD_BARRIER_SERIAL_THREAD. */
+ if (++b->in == b->threshold) {
+ b->in = 0;
+ b->out = b->threshold - 1;
+ rc = pthread_cond_signal(&b->cond);
+ assert(rc == 0);
+
+ pthread_mutex_unlock(&b->mutex);
+ return PTHREAD_BARRIER_SERIAL_THREAD;
+ }
+ /* Otherwise, wait for other threads until in is set to 0,
+ then return 0 to indicate this is not the first thread. */
+ do {
+ if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
+ break;
+ } while (b->in != 0);
+
+ /* mark thread exit */
+ b->out--;
+ pthread_cond_signal(&b->cond);
+ pthread_mutex_unlock(&b->mutex);
+ return rc;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t* barrier) {
+ int rc;
+ _uv_barrier* b;
+
+ if (barrier == NULL || barrier->b == NULL)
+ return EINVAL;
+
+ b = barrier->b;
+
+ if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
+ return rc;
+
+ if (b->in > 0 || b->out > 0)
+ rc = EBUSY;
+
+ pthread_mutex_unlock(&b->mutex);
+
+ if (rc)
+ return rc;
+
+ pthread_cond_destroy(&b->cond);
+ pthread_mutex_destroy(&b->mutex);
+ uv__free(barrier->b);
+ barrier->b = NULL;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/pthread-fixes.c b/Utilities/cmlibuv/src/unix/pthread-fixes.c
new file mode 100644
index 000000000..fb1799584
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/pthread-fixes.c
@@ -0,0 +1,56 @@
+/* Copyright (c) 2013, Sony Mobile Communications AB
+ * Copyright (c) 2012, Google 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:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Android versions < 4.1 have a broken pthread_sigmask. */
+#include <errno.h>
+#include <pthread.h>
+#include <signal.h>
+
+int uv__pthread_sigmask(int how, const sigset_t* set, sigset_t* oset) {
+ static int workaround;
+ int err;
+
+ if (workaround) {
+ return sigprocmask(how, set, oset);
+ } else {
+ err = pthread_sigmask(how, set, oset);
+ if (err) {
+ if (err == EINVAL && sigprocmask(how, set, oset) == 0) {
+ workaround = 1;
+ return 0;
+ } else {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/signal.c b/Utilities/cmlibuv/src/unix/signal.c
new file mode 100644
index 000000000..cb09ead50
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/signal.c
@@ -0,0 +1,559 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+
+typedef struct {
+ uv_signal_t* handle;
+ int signum;
+} uv__signal_msg_t;
+
+RB_HEAD(uv__signal_tree_s, uv_signal_s);
+
+
+static int uv__signal_unlock(void);
+static int uv__signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum,
+ int oneshot);
+static void uv__signal_event(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2);
+static void uv__signal_stop(uv_signal_t* handle);
+static void uv__signal_unregister_handler(int signum);
+
+
+static uv_once_t uv__signal_global_init_guard = UV_ONCE_INIT;
+static struct uv__signal_tree_s uv__signal_tree =
+ RB_INITIALIZER(uv__signal_tree);
+static int uv__signal_lock_pipefd[2];
+
+
+RB_GENERATE_STATIC(uv__signal_tree_s,
+ uv_signal_s, tree_entry,
+ uv__signal_compare)
+
+static void uv__signal_global_reinit(void);
+
+static void uv__signal_global_init(void) {
+ if (!uv__signal_lock_pipefd[0])
+ /* pthread_atfork can register before and after handlers, one
+ * for each child. This only registers one for the child. That
+ * state is both persistent and cumulative, so if we keep doing
+ * it the handler functions will be called multiple times. Thus
+ * we only want to do it once.
+ */
+ if (pthread_atfork(NULL, NULL, &uv__signal_global_reinit))
+ abort();
+
+ if (uv__make_pipe(uv__signal_lock_pipefd, 0))
+ abort();
+
+ if (uv__signal_unlock())
+ abort();
+}
+
+
+static void uv__signal_global_reinit(void) {
+ /* We can only use signal-safe functions here.
+ * That includes read/write and close, fortunately.
+ * We do all of this directly here instead of resetting
+ * uv__signal_global_init_guard because
+ * uv__signal_global_once_init is only called from uv_loop_init
+ * and this needs to function in existing loops.
+ */
+ uv__close(uv__signal_lock_pipefd[0]);
+ uv__signal_lock_pipefd[0] = -1;
+ uv__close(uv__signal_lock_pipefd[1]);
+ uv__signal_lock_pipefd[1] = -1;
+ uv__signal_global_init();
+}
+
+
+void uv__signal_global_once_init(void) {
+ uv_once(&uv__signal_global_init_guard, uv__signal_global_init);
+}
+
+
+
+static int uv__signal_lock(void) {
+ int r;
+ char data;
+
+ do {
+ r = read(uv__signal_lock_pipefd[0], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static int uv__signal_unlock(void) {
+ int r;
+ char data = 42;
+
+ do {
+ r = write(uv__signal_lock_pipefd[1], &data, sizeof data);
+ } while (r < 0 && errno == EINTR);
+
+ return (r < 0) ? -1 : 0;
+}
+
+
+static void uv__signal_block_and_lock(sigset_t* saved_sigmask) {
+ sigset_t new_mask;
+
+ if (sigfillset(&new_mask))
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, &new_mask, saved_sigmask))
+ abort();
+
+ if (uv__signal_lock())
+ abort();
+}
+
+
+static void uv__signal_unlock_and_unblock(sigset_t* saved_sigmask) {
+ if (uv__signal_unlock())
+ abort();
+
+ if (pthread_sigmask(SIG_SETMASK, saved_sigmask, NULL))
+ abort();
+}
+
+
+static uv_signal_t* uv__signal_first_handle(int signum) {
+ /* This function must be called with the signal lock held. */
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+
+ lookup.signum = signum;
+ lookup.flags = 0;
+ lookup.loop = NULL;
+
+ handle = RB_NFIND(uv__signal_tree_s, &uv__signal_tree, &lookup);
+
+ if (handle != NULL && handle->signum == signum)
+ return handle;
+
+ return NULL;
+}
+
+
+static void uv__signal_handler(int signum) {
+ uv__signal_msg_t msg;
+ uv_signal_t* handle;
+ int saved_errno;
+
+ saved_errno = errno;
+ memset(&msg, 0, sizeof msg);
+
+ if (uv__signal_lock()) {
+ errno = saved_errno;
+ return;
+ }
+
+ for (handle = uv__signal_first_handle(signum);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv__signal_tree_s, &uv__signal_tree, handle)) {
+ int r;
+
+ msg.signum = signum;
+ msg.handle = handle;
+
+ /* write() should be atomic for small data chunks, so the entire message
+ * should be written at once. In theory the pipe could become full, in
+ * which case the user is out of luck.
+ */
+ do {
+ r = write(handle->loop->signal_pipefd[1], &msg, sizeof msg);
+ } while (r == -1 && errno == EINTR);
+
+ assert(r == sizeof msg ||
+ (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)));
+
+ if (r != -1)
+ handle->caught_signals++;
+ }
+
+ uv__signal_unlock();
+ errno = saved_errno;
+}
+
+
+static int uv__signal_register_handler(int signum, int oneshot) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ /* XXX use a separate signal stack? */
+ memset(&sa, 0, sizeof(sa));
+ if (sigfillset(&sa.sa_mask))
+ abort();
+ sa.sa_handler = uv__signal_handler;
+ sa.sa_flags = oneshot ? SA_RESETHAND : 0;
+
+ /* XXX save old action so we can restore it later on? */
+ if (sigaction(signum, &sa, NULL))
+ return -errno;
+
+ return 0;
+}
+
+
+static void uv__signal_unregister_handler(int signum) {
+ /* When this function is called, the signal lock must be held. */
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof(sa));
+ sa.sa_handler = SIG_DFL;
+
+ /* sigaction can only fail with EINVAL or EFAULT; an attempt to deregister a
+ * signal implies that it was successfully registered earlier, so EINVAL
+ * should never happen.
+ */
+ if (sigaction(signum, &sa, NULL))
+ abort();
+}
+
+
+static int uv__signal_loop_once_init(uv_loop_t* loop) {
+ int err;
+
+ /* Return if already initialized. */
+ if (loop->signal_pipefd[0] != -1)
+ return 0;
+
+ err = uv__make_pipe(loop->signal_pipefd, UV__F_NONBLOCK);
+ if (err)
+ return err;
+
+ uv__io_init(&loop->signal_io_watcher,
+ uv__signal_event,
+ loop->signal_pipefd[0]);
+ uv__io_start(loop, &loop->signal_io_watcher, POLLIN);
+
+ return 0;
+}
+
+
+int uv__signal_loop_fork(uv_loop_t* loop) {
+ uv__io_stop(loop, &loop->signal_io_watcher, POLLIN);
+ uv__close(loop->signal_pipefd[0]);
+ uv__close(loop->signal_pipefd[1]);
+ loop->signal_pipefd[0] = -1;
+ loop->signal_pipefd[1] = -1;
+ return uv__signal_loop_once_init(loop);
+}
+
+
+void uv__signal_loop_cleanup(uv_loop_t* loop) {
+ QUEUE* q;
+
+ /* Stop all the signal watchers that are still attached to this loop. This
+ * ensures that the (shared) signal tree doesn't contain any invalid entries
+ * entries, and that signal handlers are removed when appropriate.
+ * It's safe to use QUEUE_FOREACH here because the handles and the handle
+ * queue are not modified by uv__signal_stop().
+ */
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ uv_handle_t* handle = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (handle->type == UV_SIGNAL)
+ uv__signal_stop((uv_signal_t*) handle);
+ }
+
+ if (loop->signal_pipefd[0] != -1) {
+ uv__close(loop->signal_pipefd[0]);
+ loop->signal_pipefd[0] = -1;
+ }
+
+ if (loop->signal_pipefd[1] != -1) {
+ uv__close(loop->signal_pipefd[1]);
+ loop->signal_pipefd[1] = -1;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ int err;
+
+ err = uv__signal_loop_once_init(loop);
+ if (err)
+ return err;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->signum = 0;
+ handle->caught_signals = 0;
+ handle->dispatched_signals = 0;
+
+ return 0;
+}
+
+
+void uv__signal_close(uv_signal_t* handle) {
+
+ uv__signal_stop(handle);
+
+ /* If there are any caught signals "trapped" in the signal pipe, we can't
+ * call the close callback yet. Otherwise, add the handle to the finish_close
+ * queue.
+ */
+ if (handle->caught_signals == handle->dispatched_signals) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ return uv__signal_start(handle, signal_cb, signum, 0);
+}
+
+
+int uv_signal_start_oneshot(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum) {
+ return uv__signal_start(handle, signal_cb, signum, 1);
+}
+
+
+static int uv__signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum,
+ int oneshot) {
+ sigset_t saved_sigmask;
+ int err;
+ uv_signal_t* first_handle;
+
+ assert(!uv__is_closing(handle));
+
+ /* If the user supplies signum == 0, then return an error already. If the
+ * signum is otherwise invalid then uv__signal_register will find out
+ * eventually.
+ */
+ if (signum == 0)
+ return -EINVAL;
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't
+ * go through the process of deregistering and registering the handler.
+ * Additionally, this avoids pending signals getting lost in the small time
+ * time frame that handle->signum == 0.
+ */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ uv__signal_stop(handle);
+ }
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ /* If at this point there are no active signal watchers for this signum (in
+ * any of the loops), it's time to try and register a handler for it here.
+ * Also in case there's only one-shot handlers and a regular handler comes in.
+ */
+ first_handle = uv__signal_first_handle(signum);
+ if (first_handle == NULL ||
+ (!oneshot && (first_handle->flags & UV__SIGNAL_ONE_SHOT))) {
+ err = uv__signal_register_handler(signum, oneshot);
+ if (err) {
+ /* Registering the signal handler failed. Must be an invalid signal. */
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+ return err;
+ }
+ }
+
+ handle->signum = signum;
+ if (oneshot)
+ handle->flags |= UV__SIGNAL_ONE_SHOT;
+
+ RB_INSERT(uv__signal_tree_s, &uv__signal_tree, handle);
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+static void uv__signal_event(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int events) {
+ uv__signal_msg_t* msg;
+ uv_signal_t* handle;
+ char buf[sizeof(uv__signal_msg_t) * 32];
+ size_t bytes, end, i;
+ int r;
+
+ bytes = 0;
+ end = 0;
+
+ do {
+ r = read(loop->signal_pipefd[0], buf + bytes, sizeof(buf) - bytes);
+
+ if (r == -1 && errno == EINTR)
+ continue;
+
+ if (r == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
+ /* If there are bytes in the buffer already (which really is extremely
+ * unlikely if possible at all) we can't exit the function here. We'll
+ * spin until more bytes are read instead.
+ */
+ if (bytes > 0)
+ continue;
+
+ /* Otherwise, there was nothing there. */
+ return;
+ }
+
+ /* Other errors really should never happen. */
+ if (r == -1)
+ abort();
+
+ bytes += r;
+
+ /* `end` is rounded down to a multiple of sizeof(uv__signal_msg_t). */
+ end = (bytes / sizeof(uv__signal_msg_t)) * sizeof(uv__signal_msg_t);
+
+ for (i = 0; i < end; i += sizeof(uv__signal_msg_t)) {
+ msg = (uv__signal_msg_t*) (buf + i);
+ handle = msg->handle;
+
+ if (msg->signum == handle->signum) {
+ assert(!(handle->flags & UV_CLOSING));
+ handle->signal_cb(handle, handle->signum);
+ }
+
+ handle->dispatched_signals++;
+
+ if (handle->flags & UV__SIGNAL_ONE_SHOT)
+ uv__signal_stop(handle);
+
+ /* If uv_close was called while there were caught signals that were not
+ * yet dispatched, the uv__finish_close was deferred. Make close pending
+ * now if this has happened.
+ */
+ if ((handle->flags & UV_CLOSING) &&
+ (handle->caught_signals == handle->dispatched_signals)) {
+ uv__make_close_pending((uv_handle_t*) handle);
+ }
+ }
+
+ bytes -= end;
+
+ /* If there are any "partial" messages left, move them to the start of the
+ * the buffer, and spin. This should not happen.
+ */
+ if (bytes) {
+ memmove(buf, buf + end, bytes);
+ continue;
+ }
+ } while (end == sizeof buf);
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ int f1;
+ int f2;
+ /* Compare signums first so all watchers with the same signnum end up
+ * adjacent.
+ */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Handlers without UV__SIGNAL_ONE_SHOT set will come first, so if the first
+ * handler returned is a one-shot handler, the rest will be too.
+ */
+ f1 = w1->flags & UV__SIGNAL_ONE_SHOT;
+ f2 = w2->flags & UV__SIGNAL_ONE_SHOT;
+ if (f1 < f2) return -1;
+ if (f1 > f2) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after
+ * { .signum = x, .loop = NULL }.
+ */
+ if (w1->loop < w2->loop) return -1;
+ if (w1->loop > w2->loop) return 1;
+
+ if (w1 < w2) return -1;
+ if (w1 > w2) return 1;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ assert(!uv__is_closing(handle));
+ uv__signal_stop(handle);
+ return 0;
+}
+
+
+static void uv__signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+ sigset_t saved_sigmask;
+ uv_signal_t* first_handle;
+ int rem_oneshot;
+ int first_oneshot;
+ int ret;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return;
+
+ uv__signal_block_and_lock(&saved_sigmask);
+
+ removed_handle = RB_REMOVE(uv__signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+ (void) removed_handle;
+
+ /* Check if there are other active signal watchers observing this signal. If
+ * not, unregister the signal handler.
+ */
+ first_handle = uv__signal_first_handle(handle->signum);
+ if (first_handle == NULL) {
+ uv__signal_unregister_handler(handle->signum);
+ } else {
+ rem_oneshot = handle->flags & UV__SIGNAL_ONE_SHOT;
+ first_oneshot = first_handle->flags & UV__SIGNAL_ONE_SHOT;
+ if (first_oneshot && !rem_oneshot) {
+ ret = uv__signal_register_handler(handle->signum, 1);
+ assert(ret == 0);
+ }
+ }
+
+ uv__signal_unlock_and_unblock(&saved_sigmask);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/spinlock.h b/Utilities/cmlibuv/src/unix/spinlock.h
new file mode 100644
index 000000000..a20c83cc6
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/spinlock.h
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013, Ben Noordhuis <info@bnoordhuis.nl>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UV_SPINLOCK_H_
+#define UV_SPINLOCK_H_
+
+#include "internal.h" /* ACCESS_ONCE, UV_UNUSED */
+#include "atomic-ops.h"
+
+#define UV_SPINLOCK_INITIALIZER { 0 }
+
+typedef struct {
+ int lock;
+} uv_spinlock_t;
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock));
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock));
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock));
+
+UV_UNUSED(static void uv_spinlock_init(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static void uv_spinlock_lock(uv_spinlock_t* spinlock)) {
+ while (!uv_spinlock_trylock(spinlock)) cpu_relax();
+}
+
+UV_UNUSED(static void uv_spinlock_unlock(uv_spinlock_t* spinlock)) {
+ ACCESS_ONCE(int, spinlock->lock) = 0;
+}
+
+UV_UNUSED(static int uv_spinlock_trylock(uv_spinlock_t* spinlock)) {
+ /* TODO(bnoordhuis) Maybe change to a ticket lock to guarantee fair queueing.
+ * Not really critical until we have locks that are (frequently) contended
+ * for by several threads.
+ */
+ return 0 == cmpxchgi(&spinlock->lock, 0, 1);
+}
+
+#endif /* UV_SPINLOCK_H_ */
diff --git a/Utilities/cmlibuv/src/unix/stream.c b/Utilities/cmlibuv/src/unix/stream.c
new file mode 100644
index 000000000..7b23d16ec
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/stream.c
@@ -0,0 +1,1677 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <limits.h> /* IOV_MAX */
+
+#if defined(__APPLE__)
+# include <sys/event.h>
+# include <sys/time.h>
+# include <sys/select.h>
+
+/* Forward declaration */
+typedef struct uv__stream_select_s uv__stream_select_t;
+
+struct uv__stream_select_s {
+ uv_stream_t* stream;
+ uv_thread_t thread;
+ uv_sem_t close_sem;
+ uv_sem_t async_sem;
+ uv_async_t async;
+ int events;
+ int fake_fd;
+ int int_fd;
+ int fd;
+ fd_set* sread;
+ size_t sread_sz;
+ fd_set* swrite;
+ size_t swrite_sz;
+};
+#endif /* defined(__APPLE__) */
+
+static void uv__stream_connect(uv_stream_t*);
+static void uv__write(uv_stream_t* stream);
+static void uv__read(uv_stream_t* stream);
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events);
+static void uv__write_callbacks(uv_stream_t* stream);
+static size_t uv__write_req_size(uv_write_t* req);
+
+
+void uv__stream_init(uv_loop_t* loop,
+ uv_stream_t* stream,
+ uv_handle_type type) {
+ int err;
+
+ uv__handle_init(loop, (uv_handle_t*)stream, type);
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ stream->close_cb = NULL;
+ stream->connection_cb = NULL;
+ stream->connect_req = NULL;
+ stream->shutdown_req = NULL;
+ stream->accepted_fd = -1;
+ stream->queued_fds = NULL;
+ stream->delayed_error = 0;
+ QUEUE_INIT(&stream->write_queue);
+ QUEUE_INIT(&stream->write_completed_queue);
+ stream->write_queue_size = 0;
+
+ if (loop->emfile_fd == -1) {
+ err = uv__open_cloexec("/dev/null", O_RDONLY);
+ if (err < 0)
+ /* In the rare case that "/dev/null" isn't mounted open "/"
+ * instead.
+ */
+ err = uv__open_cloexec("/", O_RDONLY);
+ if (err >= 0)
+ loop->emfile_fd = err;
+ }
+
+#if defined(__APPLE__)
+ stream->select = NULL;
+#endif /* defined(__APPLE_) */
+
+ uv__io_init(&stream->io_watcher, uv__stream_io, -1);
+}
+
+
+static void uv__stream_osx_interrupt_select(uv_stream_t* stream) {
+#if defined(__APPLE__)
+ /* Notify select() thread about state change */
+ uv__stream_select_t* s;
+ int r;
+
+ s = stream->select;
+ if (s == NULL)
+ return;
+
+ /* Interrupt select() loop
+ * NOTE: fake_fd and int_fd are socketpair(), thus writing to one will
+ * emit read event on other side
+ */
+ do
+ r = write(s->fake_fd, "x", 1);
+ while (r == -1 && errno == EINTR);
+
+ assert(r == 1);
+#else /* !defined(__APPLE__) */
+ /* No-op on any other platform */
+#endif /* !defined(__APPLE__) */
+}
+
+
+#if defined(__APPLE__)
+static void uv__stream_osx_select(void* arg) {
+ uv_stream_t* stream;
+ uv__stream_select_t* s;
+ char buf[1024];
+ int events;
+ int fd;
+ int r;
+ int max_fd;
+
+ stream = arg;
+ s = stream->select;
+ fd = s->fd;
+
+ if (fd > s->int_fd)
+ max_fd = fd;
+ else
+ max_fd = s->int_fd;
+
+ while (1) {
+ /* Terminate on semaphore */
+ if (uv_sem_trywait(&s->close_sem) == 0)
+ break;
+
+ /* Watch fd using select(2) */
+ memset(s->sread, 0, s->sread_sz);
+ memset(s->swrite, 0, s->swrite_sz);
+
+ if (uv__io_active(&stream->io_watcher, POLLIN))
+ FD_SET(fd, s->sread);
+ if (uv__io_active(&stream->io_watcher, POLLOUT))
+ FD_SET(fd, s->swrite);
+ FD_SET(s->int_fd, s->sread);
+
+ /* Wait indefinitely for fd events */
+ r = select(max_fd + 1, s->sread, s->swrite, NULL, NULL);
+ if (r == -1) {
+ if (errno == EINTR)
+ continue;
+
+ /* XXX: Possible?! */
+ abort();
+ }
+
+ /* Ignore timeouts */
+ if (r == 0)
+ continue;
+
+ /* Empty socketpair's buffer in case of interruption */
+ if (FD_ISSET(s->int_fd, s->sread))
+ while (1) {
+ r = read(s->int_fd, buf, sizeof(buf));
+
+ if (r == sizeof(buf))
+ continue;
+
+ if (r != -1)
+ break;
+
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ break;
+
+ if (errno == EINTR)
+ continue;
+
+ abort();
+ }
+
+ /* Handle events */
+ events = 0;
+ if (FD_ISSET(fd, s->sread))
+ events |= POLLIN;
+ if (FD_ISSET(fd, s->swrite))
+ events |= POLLOUT;
+
+ assert(events != 0 || FD_ISSET(s->int_fd, s->sread));
+ if (events != 0) {
+ ACCESS_ONCE(int, s->events) = events;
+
+ uv_async_send(&s->async);
+ uv_sem_wait(&s->async_sem);
+
+ /* Should be processed at this stage */
+ assert((s->events == 0) || (stream->flags & UV_CLOSING));
+ }
+ }
+}
+
+
+static void uv__stream_osx_select_cb(uv_async_t* handle) {
+ uv__stream_select_t* s;
+ uv_stream_t* stream;
+ int events;
+
+ s = container_of(handle, uv__stream_select_t, async);
+ stream = s->stream;
+
+ /* Get and reset stream's events */
+ events = s->events;
+ ACCESS_ONCE(int, s->events) = 0;
+
+ assert(events != 0);
+ assert(events == (events & (POLLIN | POLLOUT)));
+
+ /* Invoke callback on event-loop */
+ if ((events & POLLIN) && uv__io_active(&stream->io_watcher, POLLIN))
+ uv__stream_io(stream->loop, &stream->io_watcher, POLLIN);
+
+ if ((events & POLLOUT) && uv__io_active(&stream->io_watcher, POLLOUT))
+ uv__stream_io(stream->loop, &stream->io_watcher, POLLOUT);
+
+ if (stream->flags & UV_CLOSING)
+ return;
+
+ /* NOTE: It is important to do it here, otherwise `select()` might be called
+ * before the actual `uv__read()`, leading to the blocking syscall
+ */
+ uv_sem_post(&s->async_sem);
+}
+
+
+static void uv__stream_osx_cb_close(uv_handle_t* async) {
+ uv__stream_select_t* s;
+
+ s = container_of(async, uv__stream_select_t, async);
+ uv__free(s);
+}
+
+
+int uv__stream_try_select(uv_stream_t* stream, int* fd) {
+ /*
+ * kqueue doesn't work with some files from /dev mount on osx.
+ * select(2) in separate thread for those fds
+ */
+
+ struct kevent filter[1];
+ struct kevent events[1];
+ struct timespec timeout;
+ uv__stream_select_t* s;
+ int fds[2];
+ int err;
+ int ret;
+ int kq;
+ int old_fd;
+ int max_fd;
+ size_t sread_sz;
+ size_t swrite_sz;
+
+ kq = kqueue();
+ if (kq == -1) {
+ perror("(libuv) kqueue()");
+ return -errno;
+ }
+
+ EV_SET(&filter[0], *fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0);
+
+ /* Use small timeout, because we only want to capture EINVALs */
+ timeout.tv_sec = 0;
+ timeout.tv_nsec = 1;
+
+ do
+ ret = kevent(kq, filter, 1, events, 1, &timeout);
+ while (ret == -1 && errno == EINTR);
+
+ uv__close(kq);
+
+ if (ret == -1)
+ return -errno;
+
+ if (ret == 0 || (events[0].flags & EV_ERROR) == 0 || events[0].data != EINVAL)
+ return 0;
+
+ /* At this point we definitely know that this fd won't work with kqueue */
+
+ /*
+ * Create fds for io watcher and to interrupt the select() loop.
+ * NOTE: do it ahead of malloc below to allocate enough space for fd_sets
+ */
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
+ return -errno;
+
+ max_fd = *fd;
+ if (fds[1] > max_fd)
+ max_fd = fds[1];
+
+ sread_sz = ROUND_UP(max_fd + 1, sizeof(uint32_t) * NBBY) / NBBY;
+ swrite_sz = sread_sz;
+
+ s = uv__malloc(sizeof(*s) + sread_sz + swrite_sz);
+ if (s == NULL) {
+ err = -ENOMEM;
+ goto failed_malloc;
+ }
+
+ s->events = 0;
+ s->fd = *fd;
+ s->sread = (fd_set*) ((char*) s + sizeof(*s));
+ s->sread_sz = sread_sz;
+ s->swrite = (fd_set*) ((char*) s->sread + sread_sz);
+ s->swrite_sz = swrite_sz;
+
+ err = uv_async_init(stream->loop, &s->async, uv__stream_osx_select_cb);
+ if (err)
+ goto failed_async_init;
+
+ s->async.flags |= UV__HANDLE_INTERNAL;
+ uv__handle_unref(&s->async);
+
+ err = uv_sem_init(&s->close_sem, 0);
+ if (err != 0)
+ goto failed_close_sem_init;
+
+ err = uv_sem_init(&s->async_sem, 0);
+ if (err != 0)
+ goto failed_async_sem_init;
+
+ s->fake_fd = fds[0];
+ s->int_fd = fds[1];
+
+ old_fd = *fd;
+ s->stream = stream;
+ stream->select = s;
+ *fd = s->fake_fd;
+
+ err = uv_thread_create(&s->thread, uv__stream_osx_select, stream);
+ if (err != 0)
+ goto failed_thread_create;
+
+ return 0;
+
+failed_thread_create:
+ s->stream = NULL;
+ stream->select = NULL;
+ *fd = old_fd;
+
+ uv_sem_destroy(&s->async_sem);
+
+failed_async_sem_init:
+ uv_sem_destroy(&s->close_sem);
+
+failed_close_sem_init:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+ return err;
+
+failed_async_init:
+ uv__free(s);
+
+failed_malloc:
+ uv__close(fds[0]);
+ uv__close(fds[1]);
+
+ return err;
+}
+#endif /* defined(__APPLE__) */
+
+
+int uv__stream_open(uv_stream_t* stream, int fd, int flags) {
+#if defined(__APPLE__)
+ int enable;
+#endif
+
+ if (!(stream->io_watcher.fd == -1 || stream->io_watcher.fd == fd))
+ return -EBUSY;
+
+ assert(fd >= 0);
+ stream->flags |= flags;
+
+ if (stream->type == UV_TCP) {
+ if ((stream->flags & UV_TCP_NODELAY) && uv__tcp_nodelay(fd, 1))
+ return -errno;
+
+ /* TODO Use delay the user passed in. */
+ if ((stream->flags & UV_TCP_KEEPALIVE) && uv__tcp_keepalive(fd, 1, 60))
+ return -errno;
+ }
+
+#if defined(__APPLE__)
+ enable = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_OOBINLINE, &enable, sizeof(enable)) &&
+ errno != ENOTSOCK &&
+ errno != EINVAL) {
+ return -errno;
+ }
+#endif
+
+ stream->io_watcher.fd = fd;
+
+ return 0;
+}
+
+
+void uv__stream_flush_write_queue(uv_stream_t* stream, int error) {
+ uv_write_t* req;
+ QUEUE* q;
+ while (!QUEUE_EMPTY(&stream->write_queue)) {
+ q = QUEUE_HEAD(&stream->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ req->error = error;
+
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ }
+}
+
+
+void uv__stream_destroy(uv_stream_t* stream) {
+ assert(!uv__io_active(&stream->io_watcher, POLLIN | POLLOUT));
+ assert(stream->flags & UV_CLOSED);
+
+ if (stream->connect_req) {
+ uv__req_unregister(stream->loop, stream->connect_req);
+ stream->connect_req->cb(stream->connect_req, -ECANCELED);
+ stream->connect_req = NULL;
+ }
+
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+
+ if (stream->shutdown_req) {
+ /* The ECANCELED error code is a lie, the shutdown(2) syscall is a
+ * fait accompli at this point. Maybe we should revisit this in v0.11.
+ * A possible reason for leaving it unchanged is that it informs the
+ * callee that the handle has been destroyed.
+ */
+ uv__req_unregister(stream->loop, stream->shutdown_req);
+ stream->shutdown_req->cb(stream->shutdown_req, -ECANCELED);
+ stream->shutdown_req = NULL;
+ }
+
+ assert(stream->write_queue_size == 0);
+}
+
+
+/* Implements a best effort approach to mitigating accept() EMFILE errors.
+ * We have a spare file descriptor stashed away that we close to get below
+ * the EMFILE limit. Next, we accept all pending connections and close them
+ * immediately to signal the clients that we're overloaded - and we are, but
+ * we still keep on trucking.
+ *
+ * There is one caveat: it's not reliable in a multi-threaded environment.
+ * The file descriptor limit is per process. Our party trick fails if another
+ * thread opens a file or creates a socket in the time window between us
+ * calling close() and accept().
+ */
+static int uv__emfile_trick(uv_loop_t* loop, int accept_fd) {
+ int err;
+ int emfile_fd;
+
+ if (loop->emfile_fd == -1)
+ return -EMFILE;
+
+ uv__close(loop->emfile_fd);
+ loop->emfile_fd = -1;
+
+ do {
+ err = uv__accept(accept_fd);
+ if (err >= 0)
+ uv__close(err);
+ } while (err >= 0 || err == -EINTR);
+
+ emfile_fd = uv__open_cloexec("/", O_RDONLY);
+ if (emfile_fd >= 0)
+ loop->emfile_fd = emfile_fd;
+
+ return err;
+}
+
+
+#if defined(UV_HAVE_KQUEUE)
+# define UV_DEC_BACKLOG(w) w->rcount--;
+#else
+# define UV_DEC_BACKLOG(w) /* no-op */
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+
+void uv__server_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+ int err;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+ assert(events == POLLIN);
+ assert(stream->accepted_fd == -1);
+ assert(!(stream->flags & UV_CLOSING));
+
+ uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
+
+ /* connection_cb can close the server socket while we're
+ * in the loop so check it on each iteration.
+ */
+ while (uv__stream_fd(stream) != -1) {
+ assert(stream->accepted_fd == -1);
+
+#if defined(UV_HAVE_KQUEUE)
+ if (w->rcount <= 0)
+ return;
+#endif /* defined(UV_HAVE_KQUEUE) */
+
+ err = uv__accept(uv__stream_fd(stream));
+ if (err < 0) {
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ return; /* Not an error. */
+
+ if (err == -ECONNABORTED)
+ continue; /* Ignore. Nothing we can do about that. */
+
+ if (err == -EMFILE || err == -ENFILE) {
+ err = uv__emfile_trick(loop, uv__stream_fd(stream));
+ if (err == -EAGAIN || err == -EWOULDBLOCK)
+ break;
+ }
+
+ stream->connection_cb(stream, err);
+ continue;
+ }
+
+ UV_DEC_BACKLOG(w)
+ stream->accepted_fd = err;
+ stream->connection_cb(stream, 0);
+
+ if (stream->accepted_fd != -1) {
+ /* The user hasn't yet accepted called uv_accept() */
+ uv__io_stop(loop, &stream->io_watcher, POLLIN);
+ return;
+ }
+
+ if (stream->type == UV_TCP && (stream->flags & UV_TCP_SINGLE_ACCEPT)) {
+ /* Give other processes a chance to accept connections. */
+ struct timespec timeout = { 0, 1 };
+ nanosleep(&timeout, NULL);
+ }
+ }
+}
+
+
+#undef UV_DEC_BACKLOG
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ assert(server->loop == client->loop);
+
+ if (server->accepted_fd == -1)
+ return -EAGAIN;
+
+ switch (client->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ err = uv__stream_open(client,
+ server->accepted_fd,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err) {
+ /* TODO handle error */
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ case UV_UDP:
+ err = uv_udp_open((uv_udp_t*) client, server->accepted_fd);
+ if (err) {
+ uv__close(server->accepted_fd);
+ goto done;
+ }
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ client->flags |= UV_HANDLE_BOUND;
+
+done:
+ /* Process queued fds */
+ if (server->queued_fds != NULL) {
+ uv__stream_queued_fds_t* queued_fds;
+
+ queued_fds = server->queued_fds;
+
+ /* Read first */
+ server->accepted_fd = queued_fds->fds[0];
+
+ /* All read, free */
+ assert(queued_fds->offset > 0);
+ if (--queued_fds->offset == 0) {
+ uv__free(queued_fds);
+ server->queued_fds = NULL;
+ } else {
+ /* Shift rest */
+ memmove(queued_fds->fds,
+ queued_fds->fds + 1,
+ queued_fds->offset * sizeof(*queued_fds->fds));
+ }
+ } else {
+ server->accepted_fd = -1;
+ if (err == 0)
+ uv__io_start(server->loop, &server->io_watcher, POLLIN);
+ }
+ return err;
+}
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+
+ default:
+ err = -EINVAL;
+ }
+
+ if (err == 0)
+ uv__handle_start(stream);
+
+ return err;
+}
+
+
+static void uv__drain(uv_stream_t* stream) {
+ uv_shutdown_t* req;
+ int err;
+
+ assert(QUEUE_EMPTY(&stream->write_queue));
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ /* Shutdown? */
+ if ((stream->flags & UV_STREAM_SHUTTING) &&
+ !(stream->flags & UV_CLOSING) &&
+ !(stream->flags & UV_STREAM_SHUT)) {
+ assert(stream->shutdown_req);
+
+ req = stream->shutdown_req;
+ stream->shutdown_req = NULL;
+ stream->flags &= ~UV_STREAM_SHUTTING;
+ uv__req_unregister(stream->loop, req);
+
+ err = 0;
+ if (shutdown(uv__stream_fd(stream), SHUT_WR))
+ err = -errno;
+
+ if (err == 0)
+ stream->flags |= UV_STREAM_SHUT;
+
+ if (req->cb != NULL)
+ req->cb(req, err);
+ }
+}
+
+
+static size_t uv__write_req_size(uv_write_t* req) {
+ size_t size;
+
+ assert(req->bufs != NULL);
+ size = uv__count_bufs(req->bufs + req->write_index,
+ req->nbufs - req->write_index);
+ assert(req->handle->write_queue_size >= size);
+
+ return size;
+}
+
+
+static void uv__write_req_finish(uv_write_t* req) {
+ uv_stream_t* stream = req->handle;
+
+ /* Pop the req off tcp->write_queue. */
+ QUEUE_REMOVE(&req->queue);
+
+ /* Only free when there was no error. On error, we touch up write_queue_size
+ * right before making the callback. The reason we don't do that right away
+ * is that a write_queue_size > 0 is our only way to signal to the user that
+ * they should stop writing - which they should if we got an error. Something
+ * to revisit in future revisions of the libuv API.
+ */
+ if (req->error == 0) {
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* Add it to the write_completed_queue where it will have its
+ * callback called in the near future.
+ */
+ QUEUE_INSERT_TAIL(&stream->write_completed_queue, &req->queue);
+ uv__io_feed(stream->loop, &stream->io_watcher);
+}
+
+
+static int uv__handle_fd(uv_handle_t* handle) {
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ case UV_TCP:
+ return ((uv_stream_t*) handle)->io_watcher.fd;
+
+ case UV_UDP:
+ return ((uv_udp_t*) handle)->io_watcher.fd;
+
+ default:
+ return -1;
+ }
+}
+
+static void uv__write(uv_stream_t* stream) {
+ struct iovec* iov;
+ QUEUE* q;
+ uv_write_t* req;
+ int iovmax;
+ int iovcnt;
+ ssize_t n;
+
+start:
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (QUEUE_EMPTY(&stream->write_queue))
+ return;
+
+ q = QUEUE_HEAD(&stream->write_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ assert(req->handle == stream);
+
+ /*
+ * Cast to iovec. We had to have our own uv_buf_t instead of iovec
+ * because Windows's WSABUF is not an iovec.
+ */
+ assert(sizeof(uv_buf_t) == sizeof(struct iovec));
+ iov = (struct iovec*) &(req->bufs[req->write_index]);
+ iovcnt = req->nbufs - req->write_index;
+
+ iovmax = uv__getiovmax();
+
+ /* Limit iov count to avoid EINVALs from writev() */
+ if (iovcnt > iovmax)
+ iovcnt = iovmax;
+
+ /*
+ * Now do the actual writev. Note that we've been updating the pointers
+ * inside the iov each time we write. So there is no need to offset it.
+ */
+
+ if (req->send_handle) {
+ struct msghdr msg;
+ struct cmsghdr *cmsg;
+ int fd_to_send = uv__handle_fd((uv_handle_t*) req->send_handle);
+ union {
+ char data[64];
+ struct cmsghdr alias;
+ } scratch;
+
+ memset(&scratch, 0, sizeof(scratch));
+
+ assert(fd_to_send >= 0);
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = iovcnt;
+ msg.msg_flags = 0;
+
+ msg.msg_control = &scratch.alias;
+ msg.msg_controllen = CMSG_SPACE(sizeof(fd_to_send));
+
+ cmsg = CMSG_FIRSTHDR(&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd_to_send));
+
+ /* silence aliasing warning */
+ {
+ void* pv = CMSG_DATA(cmsg);
+ int* pi = pv;
+ *pi = fd_to_send;
+ }
+
+ do {
+ n = sendmsg(uv__stream_fd(stream), &msg, 0);
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ } else {
+ do {
+ if (iovcnt == 1) {
+ n = write(uv__stream_fd(stream), iov[0].iov_base, iov[0].iov_len);
+ } else {
+ n = writev(uv__stream_fd(stream), iov, iovcnt);
+ }
+ }
+#if defined(__APPLE__)
+ /*
+ * Due to a possible kernel bug at least in OS X 10.10 "Yosemite",
+ * EPROTOTYPE can be returned while trying to write to a socket that is
+ * shutting down. If we retry the write, we should get the expected EPIPE
+ * instead.
+ */
+ while (n == -1 && (errno == EINTR || errno == EPROTOTYPE));
+#else
+ while (n == -1 && errno == EINTR);
+#endif
+ }
+
+ if (n < 0) {
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ /* Error */
+ req->error = -errno;
+ uv__write_req_finish(req);
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ if (!uv__io_active(&stream->io_watcher, POLLIN))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ return;
+ } else if (stream->flags & UV_STREAM_BLOCKING) {
+ /* If this is a blocking stream, try again. */
+ goto start;
+ }
+ } else {
+ /* Successful write */
+
+ while (n >= 0) {
+ uv_buf_t* buf = &(req->bufs[req->write_index]);
+ size_t len = buf->len;
+
+ assert(req->write_index < req->nbufs);
+
+ if ((size_t)n < len) {
+ buf->base += n;
+ buf->len -= n;
+ stream->write_queue_size -= n;
+ n = 0;
+
+ /* There is more to write. */
+ if (stream->flags & UV_STREAM_BLOCKING) {
+ /*
+ * If we're blocking then we should not be enabling the write
+ * watcher - instead we need to try again.
+ */
+ goto start;
+ } else {
+ /* Break loop and ensure the watcher is pending. */
+ break;
+ }
+
+ } else {
+ /* Finished writing the buf at index req->write_index. */
+ req->write_index++;
+
+ assert((size_t)n >= len);
+ n -= len;
+
+ assert(stream->write_queue_size >= len);
+ stream->write_queue_size -= len;
+
+ if (req->write_index == req->nbufs) {
+ /* Then we're done! */
+ assert(n == 0);
+ uv__write_req_finish(req);
+ /* TODO: start trying to write the next request. */
+ return;
+ }
+ }
+ }
+ }
+
+ /* Either we've counted n down to zero or we've got EAGAIN. */
+ assert(n == 0 || n == -1);
+
+ /* Only non-blocking streams should use the write_watcher. */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+
+ /* We're not done. */
+ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
+
+ /* Notify select() thread about state change */
+ uv__stream_osx_interrupt_select(stream);
+}
+
+
+static void uv__write_callbacks(uv_stream_t* stream) {
+ uv_write_t* req;
+ QUEUE* q;
+
+ while (!QUEUE_EMPTY(&stream->write_completed_queue)) {
+ /* Pop a req off write_completed_queue. */
+ q = QUEUE_HEAD(&stream->write_completed_queue);
+ req = QUEUE_DATA(q, uv_write_t, queue);
+ QUEUE_REMOVE(q);
+ uv__req_unregister(stream->loop, req);
+
+ if (req->bufs != NULL) {
+ stream->write_queue_size -= uv__write_req_size(req);
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+ }
+
+ /* NOTE: call callback AFTER freeing the request data. */
+ if (req->cb)
+ req->cb(req, req->error);
+ }
+
+ assert(QUEUE_EMPTY(&stream->write_completed_queue));
+}
+
+
+uv_handle_type uv__handle_type(int fd) {
+ struct sockaddr_storage ss;
+ socklen_t sslen;
+ socklen_t len;
+ int type;
+
+ memset(&ss, 0, sizeof(ss));
+ sslen = sizeof(ss);
+
+ if (getsockname(fd, (struct sockaddr*)&ss, &sslen))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof type;
+
+ if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_STREAM) {
+#if defined(_AIX) || defined(__DragonFly__)
+ /* on AIX/DragonFly the getsockname call returns an empty sa structure
+ * for sockets of type AF_UNIX. For all other types it will
+ * return a properly filled in structure.
+ */
+ if (sslen == 0)
+ return UV_NAMED_PIPE;
+#endif
+ switch (ss.ss_family) {
+ case AF_UNIX:
+ return UV_NAMED_PIPE;
+ case AF_INET:
+ case AF_INET6:
+ return UV_TCP;
+ }
+ }
+
+ if (type == SOCK_DGRAM &&
+ (ss.ss_family == AF_INET || ss.ss_family == AF_INET6))
+ return UV_UDP;
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+static void uv__stream_eof(uv_stream_t* stream, const uv_buf_t* buf) {
+ stream->flags |= UV_STREAM_READ_EOF;
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
+ if (!uv__io_active(&stream->io_watcher, POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ stream->read_cb(stream, UV_EOF, buf);
+ stream->flags &= ~UV_STREAM_READING;
+}
+
+
+static int uv__stream_queue_fd(uv_stream_t* stream, int fd) {
+ uv__stream_queued_fds_t* queued_fds;
+ unsigned int queue_size;
+
+ queued_fds = stream->queued_fds;
+ if (queued_fds == NULL) {
+ queue_size = 8;
+ queued_fds = uv__malloc((queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ queued_fds->offset = 0;
+ stream->queued_fds = queued_fds;
+
+ /* Grow */
+ } else if (queued_fds->size == queued_fds->offset) {
+ queue_size = queued_fds->size + 8;
+ queued_fds = uv__realloc(queued_fds,
+ (queue_size - 1) * sizeof(*queued_fds->fds) +
+ sizeof(*queued_fds));
+
+ /*
+ * Allocation failure, report back.
+ * NOTE: if it is fatal - sockets will be closed in uv__stream_close
+ */
+ if (queued_fds == NULL)
+ return -ENOMEM;
+ queued_fds->size = queue_size;
+ stream->queued_fds = queued_fds;
+ }
+
+ /* Put fd in a queue */
+ queued_fds->fds[queued_fds->offset++] = fd;
+
+ return 0;
+}
+
+
+#define UV__CMSG_FD_COUNT 64
+#define UV__CMSG_FD_SIZE (UV__CMSG_FD_COUNT * sizeof(int))
+
+
+static int uv__stream_recv_cmsg(uv_stream_t* stream, struct msghdr* msg) {
+ struct cmsghdr* cmsg;
+
+ for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+ char* start;
+ char* end;
+ int err;
+ void* pv;
+ int* pi;
+ unsigned int i;
+ unsigned int count;
+
+ if (cmsg->cmsg_type != SCM_RIGHTS) {
+ fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n",
+ cmsg->cmsg_type);
+ continue;
+ }
+
+ /* silence aliasing warning */
+ pv = CMSG_DATA(cmsg);
+ pi = pv;
+
+ /* Count available fds */
+ start = (char*) cmsg;
+ end = (char*) cmsg + cmsg->cmsg_len;
+ count = 0;
+ while (start + CMSG_LEN(count * sizeof(*pi)) < end)
+ count++;
+ assert(start + CMSG_LEN(count * sizeof(*pi)) == end);
+
+ for (i = 0; i < count; i++) {
+ /* Already has accepted fd, queue now */
+ if (stream->accepted_fd != -1) {
+ err = uv__stream_queue_fd(stream, pi[i]);
+ if (err != 0) {
+ /* Close rest */
+ for (; i < count; i++)
+ uv__close(pi[i]);
+ return err;
+ }
+ } else {
+ stream->accepted_fd = pi[i];
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wgnu-folding-constant"
+#endif
+
+static void uv__read(uv_stream_t* stream) {
+ uv_buf_t buf;
+ ssize_t nread;
+ struct msghdr msg;
+ char cmsg_space[CMSG_SPACE(UV__CMSG_FD_SIZE)];
+ int count;
+ int err;
+ int is_ipc;
+
+ stream->flags &= ~UV_STREAM_READ_PARTIAL;
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ is_ipc = stream->type == UV_NAMED_PIPE && ((uv_pipe_t*) stream)->ipc;
+
+ /* XXX: Maybe instead of having UV_STREAM_READING we just test if
+ * tcp->read_cb is NULL or not?
+ */
+ while (stream->read_cb
+ && (stream->flags & UV_STREAM_READING)
+ && (count-- > 0)) {
+ assert(stream->alloc_cb != NULL);
+
+ buf = uv_buf_init(NULL, 0);
+ stream->alloc_cb((uv_handle_t*)stream, 64 * 1024, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ /* User indicates it can't or won't handle the read. */
+ stream->read_cb(stream, UV_ENOBUFS, &buf);
+ return;
+ }
+
+ assert(buf.base != NULL);
+ assert(uv__stream_fd(stream) >= 0);
+
+ if (!is_ipc) {
+ do {
+ nread = read(uv__stream_fd(stream), buf.base, buf.len);
+ }
+ while (nread < 0 && errno == EINTR);
+ } else {
+ /* ipc uses recvmsg */
+ msg.msg_flags = 0;
+ msg.msg_iov = (struct iovec*) &buf;
+ msg.msg_iovlen = 1;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ /* Set up to receive a descriptor even if one isn't in the message */
+ msg.msg_controllen = sizeof(cmsg_space);
+ msg.msg_control = cmsg_space;
+
+ do {
+ nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
+ }
+ while (nread < 0 && errno == EINTR);
+ }
+
+ if (nread < 0) {
+ /* Error */
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ /* Wait for the next one. */
+ if (stream->flags & UV_STREAM_READING) {
+ uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ stream->read_cb(stream, 0, &buf);
+#if defined(__CYGWIN__) || defined(__MSYS__)
+ } else if (errno == ECONNRESET && stream->type == UV_NAMED_PIPE) {
+ uv__stream_eof(stream, &buf);
+ return;
+#endif
+ } else {
+ /* Error. User should call uv_close(). */
+ stream->read_cb(stream, -errno, &buf);
+ if (stream->flags & UV_STREAM_READING) {
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
+ if (!uv__io_active(&stream->io_watcher, POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+ }
+ }
+ return;
+ } else if (nread == 0) {
+ uv__stream_eof(stream, &buf);
+ return;
+ } else {
+ /* Successful read */
+ ssize_t buflen = buf.len;
+
+ if (is_ipc) {
+ err = uv__stream_recv_cmsg(stream, &msg);
+ if (err != 0) {
+ stream->read_cb(stream, err, &buf);
+ return;
+ }
+ }
+
+#if defined(__MVS__)
+ if (is_ipc && msg.msg_controllen > 0) {
+ uv_buf_t blankbuf;
+ int nread;
+ struct iovec *old;
+
+ blankbuf.base = 0;
+ blankbuf.len = 0;
+ old = msg.msg_iov;
+ msg.msg_iov = (struct iovec*) &blankbuf;
+ nread = 0;
+ do {
+ nread = uv__recvmsg(uv__stream_fd(stream), &msg, 0);
+ err = uv__stream_recv_cmsg(stream, &msg);
+ if (err != 0) {
+ stream->read_cb(stream, err, &buf);
+ msg.msg_iov = old;
+ return;
+ }
+ } while (nread == 0 && msg.msg_controllen > 0);
+ msg.msg_iov = old;
+ }
+#endif
+ stream->read_cb(stream, nread, &buf);
+
+ /* Return if we didn't fill the buffer, there is no more data to read. */
+ if (nread < buflen) {
+ stream->flags |= UV_STREAM_READ_PARTIAL;
+ return;
+ }
+ }
+ }
+}
+
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#undef UV__CMSG_FD_COUNT
+#undef UV__CMSG_FD_SIZE
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* stream, uv_shutdown_cb cb) {
+ assert((stream->type == UV_TCP || stream->type == UV_NAMED_PIPE) &&
+ "uv_shutdown (unix) only supports uv_handle_t right now");
+
+ if (!(stream->flags & UV_STREAM_WRITABLE) ||
+ stream->flags & UV_STREAM_SHUT ||
+ stream->flags & UV_STREAM_SHUTTING ||
+ uv__is_closing(stream)) {
+ return -ENOTCONN;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Initialize request */
+ uv__req_init(stream->loop, req, UV_SHUTDOWN);
+ req->handle = stream;
+ req->cb = cb;
+ stream->shutdown_req = req;
+ stream->flags |= UV_STREAM_SHUTTING;
+
+ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+static void uv__stream_io(uv_loop_t* loop, uv__io_t* w, unsigned int events) {
+ uv_stream_t* stream;
+
+ stream = container_of(w, uv_stream_t, io_watcher);
+
+ assert(stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+ assert(!(stream->flags & UV_CLOSING));
+
+ if (stream->connect_req) {
+ uv__stream_connect(stream);
+ return;
+ }
+
+ assert(uv__stream_fd(stream) >= 0);
+
+ /* Ignore POLLHUP here. Even it it's set, there may still be data to read. */
+ if (events & (POLLIN | POLLERR | POLLHUP))
+ uv__read(stream);
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ /* Short-circuit iff POLLHUP is set, the user is still interested in read
+ * events and uv__read() reported a partial read but not EOF. If the EOF
+ * flag is set, uv__read() called read_cb with err=UV_EOF and we don't
+ * have to do anything. If the partial read flag is not set, we can't
+ * report the EOF yet because there is still data to read.
+ */
+ if ((events & POLLHUP) &&
+ (stream->flags & UV_STREAM_READING) &&
+ (stream->flags & UV_STREAM_READ_PARTIAL) &&
+ !(stream->flags & UV_STREAM_READ_EOF)) {
+ uv_buf_t buf = { NULL, 0 };
+ uv__stream_eof(stream, &buf);
+ }
+
+ if (uv__stream_fd(stream) == -1)
+ return; /* read_cb closed stream. */
+
+ if (events & (POLLOUT | POLLERR | POLLHUP)) {
+ uv__write(stream);
+ uv__write_callbacks(stream);
+
+ /* Write queue drained. */
+ if (QUEUE_EMPTY(&stream->write_queue))
+ uv__drain(stream);
+ }
+}
+
+
+/**
+ * We get called here from directly following a call to connect(2).
+ * In order to determine if we've errored out or succeeded must call
+ * getsockopt.
+ */
+static void uv__stream_connect(uv_stream_t* stream) {
+ int error;
+ uv_connect_t* req = stream->connect_req;
+ socklen_t errorsize = sizeof(int);
+
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE);
+ assert(req);
+
+ if (stream->delayed_error) {
+ /* To smooth over the differences between unixes errors that
+ * were reported synchronously on the first connect can be delayed
+ * until the next tick--which is now.
+ */
+ error = stream->delayed_error;
+ stream->delayed_error = 0;
+ } else {
+ /* Normal situation: we need to get the socket error from the kernel. */
+ assert(uv__stream_fd(stream) >= 0);
+ getsockopt(uv__stream_fd(stream),
+ SOL_SOCKET,
+ SO_ERROR,
+ &error,
+ &errorsize);
+ error = -error;
+ }
+
+ if (error == -EINPROGRESS)
+ return;
+
+ stream->connect_req = NULL;
+ uv__req_unregister(stream->loop, req);
+
+ if (error < 0 || QUEUE_EMPTY(&stream->write_queue)) {
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ }
+
+ if (req->cb)
+ req->cb(req, error);
+
+ if (uv__stream_fd(stream) == -1)
+ return;
+
+ if (error < 0) {
+ uv__stream_flush_write_queue(stream, -ECANCELED);
+ uv__write_callbacks(stream);
+ }
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int empty_queue;
+
+ assert(nbufs > 0);
+ assert((stream->type == UV_TCP ||
+ stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY) &&
+ "uv_write (unix) does not yet support other types of streams");
+
+ if (uv__stream_fd(stream) < 0)
+ return -EBADF;
+
+ if (send_handle) {
+ if (stream->type != UV_NAMED_PIPE || !((uv_pipe_t*)stream)->ipc)
+ return -EINVAL;
+
+ /* XXX We abuse uv_write2() to send over UDP handles to child processes.
+ * Don't call uv__stream_fd() on those handles, it's a macro that on OS X
+ * evaluates to a function that operates on a uv_stream_t with a couple of
+ * OS X specific fields. On other Unices it does (handle)->io_watcher.fd,
+ * which works but only by accident.
+ */
+ if (uv__handle_fd((uv_handle_t*) send_handle) < 0)
+ return -EBADF;
+
+#if defined(__CYGWIN__) || defined(__MSYS__)
+ /* Cygwin recvmsg always sets msg_controllen to zero, so we cannot send it.
+ See https://github.com/mirror/newlib-cygwin/blob/86fc4bf0/winsup/cygwin/fhandler_socket.cc#L1736-L1743 */
+ return -ENOSYS;
+#endif
+ }
+
+ /* It's legal for write_queue_size > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up write_queue_size later, see also uv__write_req_finish().
+ * We could check that write_queue is empty instead but that implies making
+ * a write() syscall when we know that the handle is in error mode.
+ */
+ empty_queue = (stream->write_queue_size == 0);
+
+ /* Initialize the req */
+ uv__req_init(stream->loop, req, UV_WRITE);
+ req->cb = cb;
+ req->handle = stream;
+ req->error = 0;
+ req->send_handle = send_handle;
+ QUEUE_INIT(&req->queue);
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL)
+ return -ENOMEM;
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ req->nbufs = nbufs;
+ req->write_index = 0;
+ stream->write_queue_size += uv__count_bufs(bufs, nbufs);
+
+ /* Append the request to write_queue. */
+ QUEUE_INSERT_TAIL(&stream->write_queue, &req->queue);
+
+ /* If the queue was empty when this function began, we should attempt to
+ * do the write immediately. Otherwise start the write_watcher and wait
+ * for the fd to become writable.
+ */
+ if (stream->connect_req) {
+ /* Still connecting, do nothing. */
+ }
+ else if (empty_queue) {
+ uv__write(stream);
+ }
+ else {
+ /*
+ * blocking streams should never have anything in the queue.
+ * if this assert fires then somehow the blocking stream isn't being
+ * sufficiently flushed in uv__write.
+ */
+ assert(!(stream->flags & UV_STREAM_BLOCKING));
+ uv__io_start(stream->loop, &stream->io_watcher, POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ return 0;
+}
+
+
+/* The buffers to be written must remain valid until the callback is called.
+ * This is not required for the uv_buf_t array.
+ */
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_write2(req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+void uv_try_write_cb(uv_write_t* req, int status) {
+ /* Should not be called */
+ abort();
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int r;
+ int has_pollout;
+ size_t written;
+ size_t req_size;
+ uv_write_t req;
+
+ /* Connecting or already writing some data */
+ if (stream->connect_req != NULL || stream->write_queue_size != 0)
+ return -EAGAIN;
+
+ has_pollout = uv__io_active(&stream->io_watcher, POLLOUT);
+
+ r = uv_write(&req, stream, bufs, nbufs, uv_try_write_cb);
+ if (r != 0)
+ return r;
+
+ /* Remove not written bytes from write queue size */
+ written = uv__count_bufs(bufs, nbufs);
+ if (req.bufs != NULL)
+ req_size = uv__write_req_size(&req);
+ else
+ req_size = 0;
+ written -= req_size;
+ stream->write_queue_size -= req_size;
+
+ /* Unqueue request, regardless of immediateness */
+ QUEUE_REMOVE(&req.queue);
+ uv__req_unregister(stream->loop, &req);
+ if (req.bufs != req.bufsml)
+ uv__free(req.bufs);
+ req.bufs = NULL;
+
+ /* Do not poll for writable, if we wasn't before calling this */
+ if (!has_pollout) {
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLOUT);
+ uv__stream_osx_interrupt_select(stream);
+ }
+
+ if (written == 0 && req_size != 0)
+ return -EAGAIN;
+ else
+ return written;
+}
+
+
+int uv_read_start(uv_stream_t* stream,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ assert(stream->type == UV_TCP || stream->type == UV_NAMED_PIPE ||
+ stream->type == UV_TTY);
+
+ if (stream->flags & UV_CLOSING)
+ return -EINVAL;
+
+ /* The UV_STREAM_READING flag is irrelevant of the state of the tcp - it just
+ * expresses the desired state of the user.
+ */
+ stream->flags |= UV_STREAM_READING;
+
+ /* TODO: try to do the read inline? */
+ /* TODO: keep track of tcp state. If we've gotten a EOF then we should
+ * not start the IO watcher.
+ */
+ assert(uv__stream_fd(stream) >= 0);
+ assert(alloc_cb);
+
+ stream->read_cb = read_cb;
+ stream->alloc_cb = alloc_cb;
+
+ uv__io_start(stream->loop, &stream->io_watcher, POLLIN);
+ uv__handle_start(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ return 0;
+}
+
+
+int uv_read_stop(uv_stream_t* stream) {
+ if (!(stream->flags & UV_STREAM_READING))
+ return 0;
+
+ stream->flags &= ~UV_STREAM_READING;
+ uv__io_stop(stream->loop, &stream->io_watcher, POLLIN);
+ if (!uv__io_active(&stream->io_watcher, POLLOUT))
+ uv__handle_stop(stream);
+ uv__stream_osx_interrupt_select(stream);
+
+ stream->read_cb = NULL;
+ stream->alloc_cb = NULL;
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* stream) {
+ return !!(stream->flags & UV_STREAM_WRITABLE);
+}
+
+
+#if defined(__APPLE__)
+int uv___stream_fd(const uv_stream_t* handle) {
+ const uv__stream_select_t* s;
+
+ assert(handle->type == UV_TCP ||
+ handle->type == UV_TTY ||
+ handle->type == UV_NAMED_PIPE);
+
+ s = handle->select;
+ if (s != NULL)
+ return s->fd;
+
+ return handle->io_watcher.fd;
+}
+#endif /* defined(__APPLE__) */
+
+
+void uv__stream_close(uv_stream_t* handle) {
+ unsigned int i;
+ uv__stream_queued_fds_t* queued_fds;
+
+#if defined(__APPLE__)
+ /* Terminate select loop first */
+ if (handle->select != NULL) {
+ uv__stream_select_t* s;
+
+ s = handle->select;
+
+ uv_sem_post(&s->close_sem);
+ uv_sem_post(&s->async_sem);
+ uv__stream_osx_interrupt_select(handle);
+ uv_thread_join(&s->thread);
+ uv_sem_destroy(&s->close_sem);
+ uv_sem_destroy(&s->async_sem);
+ uv__close(s->fake_fd);
+ uv__close(s->int_fd);
+ uv_close((uv_handle_t*) &s->async, uv__stream_osx_cb_close);
+
+ handle->select = NULL;
+ }
+#endif /* defined(__APPLE__) */
+
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv_read_stop(handle);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ /* Don't close stdio file descriptors. Nothing good comes from it. */
+ if (handle->io_watcher.fd > STDERR_FILENO)
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+
+ if (handle->accepted_fd != -1) {
+ uv__close(handle->accepted_fd);
+ handle->accepted_fd = -1;
+ }
+
+ /* Close all queued fds */
+ if (handle->queued_fds != NULL) {
+ queued_fds = handle->queued_fds;
+ for (i = 0; i < queued_fds->offset; i++)
+ uv__close(queued_fds->fds[i]);
+ uv__free(handle->queued_fds);
+ handle->queued_fds = NULL;
+ }
+
+ assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ /* Don't need to check the file descriptor, uv__nonblock()
+ * will fail with EBADF if it's not valid.
+ */
+ return uv__nonblock(uv__stream_fd(handle), !blocking);
+}
diff --git a/Utilities/cmlibuv/src/unix/sunos.c b/Utilities/cmlibuv/src/unix/sunos.c
new file mode 100644
index 000000000..041f3f336
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/sunos.c
@@ -0,0 +1,825 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#if !defined(SUNOS_NO_IFADDRS) && _XOPEN_SOURCE < 600
+#define SUNOS_NO_IFADDRS
+#endif
+
+#ifndef SUNOS_NO_IFADDRS
+# include <ifaddrs.h>
+#endif
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_arp.h>
+#include <sys/sockio.h>
+
+#include <sys/loadavg.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <kstat.h>
+#include <fcntl.h>
+
+#include <sys/port.h>
+#include <port.h>
+
+#define PORT_FIRED 0x69
+#define PORT_UNUSED 0x0
+#define PORT_LOADED 0x99
+#define PORT_DELETED -1
+
+#if (!defined(_LP64)) && (_FILE_OFFSET_BITS - 0 == 64)
+#define PROCFS_FILE_OFFSET_BITS_HACK 1
+#undef _FILE_OFFSET_BITS
+#else
+#define PROCFS_FILE_OFFSET_BITS_HACK 0
+#endif
+
+#include <procfs.h>
+
+#if (PROCFS_FILE_OFFSET_BITS_HACK - 0 == 1)
+#define _FILE_OFFSET_BITS 64
+#endif
+
+
+int uv__platform_loop_init(uv_loop_t* loop) {
+ int err;
+ int fd;
+
+ loop->fs_fd = -1;
+ loop->backend_fd = -1;
+
+ fd = port_create();
+ if (fd == -1)
+ return -errno;
+
+ err = uv__cloexec(fd, 1);
+ if (err) {
+ uv__close(fd);
+ return err;
+ }
+ loop->backend_fd = fd;
+
+ return 0;
+}
+
+
+void uv__platform_loop_delete(uv_loop_t* loop) {
+ if (loop->fs_fd != -1) {
+ uv__close(loop->fs_fd);
+ loop->fs_fd = -1;
+ }
+
+ if (loop->backend_fd != -1) {
+ uv__close(loop->backend_fd);
+ loop->backend_fd = -1;
+ }
+}
+
+
+int uv__io_fork(uv_loop_t* loop) {
+#if defined(PORT_SOURCE_FILE)
+ if (loop->fs_fd != -1) {
+ /* stop the watcher before we blow away its fileno */
+ uv__io_stop(loop, &loop->fs_event_watcher, POLLIN);
+ }
+#endif
+ uv__platform_loop_delete(loop);
+ return uv__platform_loop_init(loop);
+}
+
+
+void uv__platform_invalidate_fd(uv_loop_t* loop, int fd) {
+ struct port_event* events;
+ uintptr_t i;
+ uintptr_t nfds;
+
+ assert(loop->watchers != NULL);
+
+ events = (struct port_event*) loop->watchers[loop->nwatchers];
+ nfds = (uintptr_t) loop->watchers[loop->nwatchers + 1];
+ if (events == NULL)
+ return;
+
+ /* Invalidate events with same file descriptor */
+ for (i = 0; i < nfds; i++)
+ if ((int) events[i].portev_object == fd)
+ events[i].portev_object = -1;
+}
+
+
+int uv__io_check_fd(uv_loop_t* loop, int fd) {
+ if (port_associate(loop->backend_fd, PORT_SOURCE_FD, fd, POLLIN, 0))
+ return -errno;
+
+ if (port_dissociate(loop->backend_fd, PORT_SOURCE_FD, fd))
+ abort();
+
+ return 0;
+}
+
+
+void uv__io_poll(uv_loop_t* loop, int timeout) {
+ struct port_event events[1024];
+ struct port_event* pe;
+ struct timespec spec;
+ QUEUE* q;
+ uv__io_t* w;
+ sigset_t* pset;
+ sigset_t set;
+ uint64_t base;
+ uint64_t diff;
+ unsigned int nfds;
+ unsigned int i;
+ int saved_errno;
+ int have_signals;
+ int nevents;
+ int count;
+ int err;
+ int fd;
+
+ if (loop->nfds == 0) {
+ assert(QUEUE_EMPTY(&loop->watcher_queue));
+ return;
+ }
+
+ while (!QUEUE_EMPTY(&loop->watcher_queue)) {
+ q = QUEUE_HEAD(&loop->watcher_queue);
+ QUEUE_REMOVE(q);
+ QUEUE_INIT(q);
+
+ w = QUEUE_DATA(q, uv__io_t, watcher_queue);
+ assert(w->pevents != 0);
+
+ if (port_associate(loop->backend_fd, PORT_SOURCE_FD, w->fd, w->pevents, 0))
+ abort();
+
+ w->events = w->pevents;
+ }
+
+ pset = NULL;
+ if (loop->flags & UV_LOOP_BLOCK_SIGPROF) {
+ pset = &set;
+ sigemptyset(pset);
+ sigaddset(pset, SIGPROF);
+ }
+
+ assert(timeout >= -1);
+ base = loop->time;
+ count = 48; /* Benchmarks suggest this gives the best throughput. */
+
+ for (;;) {
+ if (timeout != -1) {
+ spec.tv_sec = timeout / 1000;
+ spec.tv_nsec = (timeout % 1000) * 1000000;
+ }
+
+ /* Work around a kernel bug where nfds is not updated. */
+ events[0].portev_source = 0;
+
+ nfds = 1;
+ saved_errno = 0;
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_BLOCK, pset, NULL);
+
+ err = port_getn(loop->backend_fd,
+ events,
+ ARRAY_SIZE(events),
+ &nfds,
+ timeout == -1 ? NULL : &spec);
+
+ if (pset != NULL)
+ pthread_sigmask(SIG_UNBLOCK, pset, NULL);
+
+ if (err) {
+ /* Work around another kernel bug: port_getn() may return events even
+ * on error.
+ */
+ if (errno == EINTR || errno == ETIME)
+ saved_errno = errno;
+ else
+ abort();
+ }
+
+ /* Update loop->time unconditionally. It's tempting to skip the update when
+ * timeout == 0 (i.e. non-blocking poll) but there is no guarantee that the
+ * operating system didn't reschedule our process while in the syscall.
+ */
+ SAVE_ERRNO(uv__update_time(loop));
+
+ if (events[0].portev_source == 0) {
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+ goto update_timeout;
+ }
+
+ if (nfds == 0) {
+ assert(timeout != -1);
+ return;
+ }
+
+ have_signals = 0;
+ nevents = 0;
+
+ assert(loop->watchers != NULL);
+ loop->watchers[loop->nwatchers] = (void*) events;
+ loop->watchers[loop->nwatchers + 1] = (void*) (uintptr_t) nfds;
+ for (i = 0; i < nfds; i++) {
+ pe = events + i;
+ fd = pe->portev_object;
+
+ /* Skip invalidated events, see uv__platform_invalidate_fd */
+ if (fd == -1)
+ continue;
+
+ assert(fd >= 0);
+ assert((unsigned) fd < loop->nwatchers);
+
+ w = loop->watchers[fd];
+
+ /* File descriptor that we've stopped watching, ignore. */
+ if (w == NULL)
+ continue;
+
+ /* Run signal watchers last. This also affects child process watchers
+ * because those are implemented in terms of signal watchers.
+ */
+ if (w == &loop->signal_io_watcher)
+ have_signals = 1;
+ else
+ w->cb(loop, w, pe->portev_events);
+
+ nevents++;
+
+ if (w != loop->watchers[fd])
+ continue; /* Disabled by callback. */
+
+ /* Events Ports operates in oneshot mode, rearm timer on next run. */
+ if (w->pevents != 0 && QUEUE_EMPTY(&w->watcher_queue))
+ QUEUE_INSERT_TAIL(&loop->watcher_queue, &w->watcher_queue);
+ }
+
+ if (have_signals != 0)
+ loop->signal_io_watcher.cb(loop, &loop->signal_io_watcher, POLLIN);
+
+ loop->watchers[loop->nwatchers] = NULL;
+ loop->watchers[loop->nwatchers + 1] = NULL;
+
+ if (have_signals != 0)
+ return; /* Event loop should cycle now so don't poll again. */
+
+ if (nevents != 0) {
+ if (nfds == ARRAY_SIZE(events) && --count != 0) {
+ /* Poll for more events but don't block this time. */
+ timeout = 0;
+ continue;
+ }
+ return;
+ }
+
+ if (saved_errno == ETIME) {
+ assert(timeout != -1);
+ return;
+ }
+
+ if (timeout == 0)
+ return;
+
+ if (timeout == -1)
+ continue;
+
+update_timeout:
+ assert(timeout > 0);
+
+ diff = loop->time - base;
+ if (diff >= (uint64_t) timeout)
+ return;
+
+ timeout -= diff;
+ }
+}
+
+
+uint64_t uv__hrtime(uv_clocktype_t type) {
+ return gethrtime();
+}
+
+
+/*
+ * We could use a static buffer for the path manipulations that we need outside
+ * of the function, but this function could be called by multiple consumers and
+ * we don't want to potentially create a race condition in the use of snprintf.
+ */
+int uv_exepath(char* buffer, size_t* size) {
+ ssize_t res;
+ char buf[128];
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return -EINVAL;
+
+ snprintf(buf, sizeof(buf), "/proc/%lu/path/a.out", (unsigned long) getpid());
+
+ res = *size - 1;
+ if (res > 0)
+ res = readlink(buf, buffer, res);
+
+ if (res == -1)
+ return -errno;
+
+ buffer[res] = '\0';
+ *size = res;
+ return 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_AVPHYS_PAGES);
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ return (uint64_t) sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
+}
+
+
+void uv_loadavg(double avg[3]) {
+ (void) getloadavg(avg, 3);
+}
+
+
+#if defined(PORT_SOURCE_FILE)
+
+static int uv__fs_event_rearm(uv_fs_event_t *handle) {
+ if (handle->fd == -1)
+ return -EBADF;
+
+ if (port_associate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo,
+ FILE_ATTRIB | FILE_MODIFIED,
+ handle) == -1) {
+ return -errno;
+ }
+ handle->fd = PORT_LOADED;
+
+ return 0;
+}
+
+
+static void uv__fs_event_read(uv_loop_t* loop,
+ uv__io_t* w,
+ unsigned int revents) {
+ uv_fs_event_t *handle = NULL;
+ timespec_t timeout;
+ port_event_t pe;
+ int events;
+ int r;
+
+ (void) w;
+ (void) revents;
+
+ do {
+ uint_t n = 1;
+
+ /*
+ * Note that our use of port_getn() here (and not port_get()) is deliberate:
+ * there is a bug in event ports (Sun bug 6456558) whereby a zeroed timeout
+ * causes port_get() to return success instead of ETIME when there aren't
+ * actually any events (!); by using port_getn() in lieu of port_get(),
+ * we can at least workaround the bug by checking for zero returned events
+ * and treating it as we would ETIME.
+ */
+ do {
+ memset(&timeout, 0, sizeof timeout);
+ r = port_getn(loop->fs_fd, &pe, 1, &n, &timeout);
+ }
+ while (r == -1 && errno == EINTR);
+
+ if ((r == -1 && errno == ETIME) || n == 0)
+ break;
+
+ handle = (uv_fs_event_t*) pe.portev_user;
+ assert((r == 0) && "unexpected port_get() error");
+
+ events = 0;
+ if (pe.portev_events & (FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_CHANGE;
+ if (pe.portev_events & ~(FILE_ATTRIB | FILE_MODIFIED))
+ events |= UV_RENAME;
+ assert(events != 0);
+ handle->fd = PORT_FIRED;
+ handle->cb(handle, NULL, events, 0);
+
+ if (handle->fd != PORT_DELETED) {
+ r = uv__fs_event_rearm(handle);
+ if (r != 0)
+ handle->cb(handle, NULL, 0, r);
+ }
+ }
+ while (handle->fd != PORT_DELETED);
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_FS_EVENT);
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int portfd;
+ int first_run;
+ int err;
+
+ if (uv__is_active(handle))
+ return -EINVAL;
+
+ first_run = 0;
+ if (handle->loop->fs_fd == -1) {
+ portfd = port_create();
+ if (portfd == -1)
+ return -errno;
+ handle->loop->fs_fd = portfd;
+ first_run = 1;
+ }
+
+ uv__handle_start(handle);
+ handle->path = uv__strdup(path);
+ handle->fd = PORT_UNUSED;
+ handle->cb = cb;
+
+ memset(&handle->fo, 0, sizeof handle->fo);
+ handle->fo.fo_name = handle->path;
+ err = uv__fs_event_rearm(handle);
+ if (err != 0) {
+ uv_fs_event_stop(handle);
+ return err;
+ }
+
+ if (first_run) {
+ uv__io_init(&handle->loop->fs_event_watcher, uv__fs_event_read, portfd);
+ uv__io_start(handle->loop, &handle->loop->fs_event_watcher, POLLIN);
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->fd == PORT_FIRED || handle->fd == PORT_LOADED) {
+ port_dissociate(handle->loop->fs_fd,
+ PORT_SOURCE_FILE,
+ (uintptr_t) &handle->fo);
+ }
+
+ handle->fd = PORT_DELETED;
+ uv__free(handle->path);
+ handle->path = NULL;
+ handle->fo.fo_name = NULL;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+}
+
+#else /* !defined(PORT_SOURCE_FILE) */
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* filename,
+ unsigned int flags) {
+ return -ENOSYS;
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ return -ENOSYS;
+}
+
+
+void uv__fs_event_close(uv_fs_event_t* handle) {
+ UNREACHABLE();
+}
+
+#endif /* defined(PORT_SOURCE_FILE) */
+
+
+int uv_resident_set_memory(size_t* rss) {
+ psinfo_t psinfo;
+ int err;
+ int fd;
+
+ fd = open("/proc/self/psinfo", O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ /* FIXME(bnoordhuis) Handle EINTR. */
+ err = -EINVAL;
+ if (read(fd, &psinfo, sizeof(psinfo)) == sizeof(psinfo)) {
+ *rss = (size_t)psinfo.pr_rssize * 1024;
+ err = 0;
+ }
+ uv__close(fd);
+
+ return err;
+}
+
+
+int uv_uptime(double* uptime) {
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+
+ long hz = sysconf(_SC_CLK_TCK);
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ ksp = kstat_lookup(kc, (char*) "unix", 0, (char*) "system_misc");
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ *uptime = -1;
+ } else {
+ knp = (kstat_named_t*) kstat_data_lookup(ksp, (char*) "clk_intr");
+ *uptime = knp->value.ul / hz;
+ }
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count) {
+ int lookup_instance;
+ kstat_ctl_t *kc;
+ kstat_t *ksp;
+ kstat_named_t *knp;
+ uv_cpu_info_t* cpu_info;
+
+ kc = kstat_open();
+ if (kc == NULL)
+ return -EPERM;
+
+ /* Get count of cpus */
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ lookup_instance++;
+ }
+
+ *cpu_infos = uv__malloc(lookup_instance * sizeof(**cpu_infos));
+ if (!(*cpu_infos)) {
+ kstat_close(kc);
+ return -ENOMEM;
+ }
+
+ *count = lookup_instance;
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ while ((ksp = kstat_lookup(kc, (char*) "cpu_info", lookup_instance, NULL))) {
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->speed = 0;
+ cpu_info->model = NULL;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "clock_MHz");
+ assert(knp->data_type == KSTAT_DATA_INT32 ||
+ knp->data_type == KSTAT_DATA_INT64);
+ cpu_info->speed = (knp->data_type == KSTAT_DATA_INT32) ? knp->value.i32
+ : knp->value.i64;
+
+ knp = kstat_data_lookup(ksp, (char*) "brand");
+ assert(knp->data_type == KSTAT_DATA_STRING);
+ cpu_info->model = uv__strdup(KSTAT_NAMED_STR_PTR(knp));
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ cpu_info = *cpu_infos;
+ lookup_instance = 0;
+ for (;;) {
+ ksp = kstat_lookup(kc, (char*) "cpu", lookup_instance, (char*) "sys");
+
+ if (ksp == NULL)
+ break;
+
+ if (kstat_read(kc, ksp, NULL) == -1) {
+ cpu_info->cpu_times.user = 0;
+ cpu_info->cpu_times.nice = 0;
+ cpu_info->cpu_times.sys = 0;
+ cpu_info->cpu_times.idle = 0;
+ cpu_info->cpu_times.irq = 0;
+ } else {
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_user");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.user = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_kernel");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.sys = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "cpu_ticks_idle");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.idle = knp->value.ui64;
+
+ knp = kstat_data_lookup(ksp, (char*) "intr");
+ assert(knp->data_type == KSTAT_DATA_UINT64);
+ cpu_info->cpu_times.irq = knp->value.ui64;
+ cpu_info->cpu_times.nice = 0;
+ }
+
+ lookup_instance++;
+ cpu_info++;
+ }
+
+ kstat_close(kc);
+
+ return 0;
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+#ifdef SUNOS_NO_IFADDRS
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ return -ENOSYS;
+}
+#else /* SUNOS_NO_IFADDRS */
+/*
+ * Inspired By:
+ * https://blogs.oracle.com/paulie/entry/retrieving_mac_address_in_solaris
+ * http://www.pauliesworld.org/project/getmac.c
+ */
+static int uv__set_phys_addr(uv_interface_address_t* address,
+ struct ifaddrs* ent) {
+
+ struct sockaddr_dl* sa_addr;
+ int sockfd;
+ int i;
+ struct arpreq arpreq;
+
+ /* This appears to only work as root */
+ sa_addr = (struct sockaddr_dl*)(ent->ifa_addr);
+ memcpy(address->phys_addr, LLADDR(sa_addr), sizeof(address->phys_addr));
+ for (i = 0; i < sizeof(address->phys_addr); i++) {
+ if (address->phys_addr[i] != 0)
+ return 0;
+ }
+ memset(&arpreq, 0, sizeof(arpreq));
+ if (address->address.address4.sin_family == AF_INET) {
+ struct sockaddr_in* sin = ((struct sockaddr_in*)&arpreq.arp_pa);
+ sin->sin_addr.s_addr = address->address.address4.sin_addr.s_addr;
+ } else if (address->address.address4.sin_family == AF_INET6) {
+ struct sockaddr_in6* sin = ((struct sockaddr_in6*)&arpreq.arp_pa);
+ memcpy(sin->sin6_addr.s6_addr,
+ address->address.address6.sin6_addr.s6_addr,
+ sizeof(address->address.address6.sin6_addr.s6_addr));
+ } else {
+ return 0;
+ }
+
+ sockfd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sockfd < 0)
+ return -errno;
+
+ if (ioctl(sockfd, SIOCGARP, (char*)&arpreq) == -1) {
+ uv__close(sockfd);
+ return -errno;
+ }
+ memcpy(address->phys_addr, arpreq.arp_ha.sa_data, sizeof(address->phys_addr));
+ uv__close(sockfd);
+ return 0;
+}
+
+
+static int uv__ifaddr_exclude(struct ifaddrs *ent) {
+ if (!((ent->ifa_flags & IFF_UP) && (ent->ifa_flags & IFF_RUNNING)))
+ return 1;
+ if (ent->ifa_addr == NULL)
+ return 1;
+ if (ent->ifa_addr->sa_family == PF_PACKET)
+ return 1;
+ return 0;
+}
+
+int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
+ uv_interface_address_t* address;
+ struct ifaddrs* addrs;
+ struct ifaddrs* ent;
+ int i;
+
+ if (getifaddrs(&addrs))
+ return -errno;
+
+ *count = 0;
+
+ /* Count the number of interfaces */
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+ (*count)++;
+ }
+
+ *addresses = uv__malloc(*count * sizeof(**addresses));
+ if (!(*addresses)) {
+ freeifaddrs(addrs);
+ return -ENOMEM;
+ }
+
+ address = *addresses;
+
+ for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
+ if (uv__ifaddr_exclude(ent))
+ continue;
+
+ address->name = uv__strdup(ent->ifa_name);
+
+ if (ent->ifa_addr->sa_family == AF_INET6) {
+ address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
+ } else {
+ address->address.address4 = *((struct sockaddr_in*) ent->ifa_addr);
+ }
+
+ if (ent->ifa_netmask->sa_family == AF_INET6) {
+ address->netmask.netmask6 = *((struct sockaddr_in6*) ent->ifa_netmask);
+ } else {
+ address->netmask.netmask4 = *((struct sockaddr_in*) ent->ifa_netmask);
+ }
+
+ address->is_internal = !!((ent->ifa_flags & IFF_PRIVATE) ||
+ (ent->ifa_flags & IFF_LOOPBACK));
+
+ uv__set_phys_addr(address, ent);
+ address++;
+ }
+
+ freeifaddrs(addrs);
+
+ return 0;
+}
+#endif /* SUNOS_NO_IFADDRS */
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(addresses[i].name);
+ }
+
+ uv__free(addresses);
+}
diff --git a/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c b/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c
new file mode 100644
index 000000000..ebad0e89d
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/sysinfo-loadavg.c
@@ -0,0 +1,36 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <sys/sysinfo.h>
+
+void uv_loadavg(double avg[3]) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) < 0) return;
+
+ avg[0] = (double) info.loads[0] / 65536.0;
+ avg[1] = (double) info.loads[1] / 65536.0;
+ avg[2] = (double) info.loads[2] / 65536.0;
+}
diff --git a/Utilities/cmlibuv/src/unix/sysinfo-memory.c b/Utilities/cmlibuv/src/unix/sysinfo-memory.c
new file mode 100644
index 000000000..23b4fc6e9
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/sysinfo-memory.c
@@ -0,0 +1,42 @@
+/* Copyright libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdint.h>
+#include <sys/sysinfo.h>
+
+uint64_t uv_get_free_memory(void) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) == 0)
+ return (uint64_t) info.freeram * info.mem_unit;
+ return 0;
+}
+
+uint64_t uv_get_total_memory(void) {
+ struct sysinfo info;
+
+ if (sysinfo(&info) == 0)
+ return (uint64_t) info.totalram * info.mem_unit;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/unix/tcp.c b/Utilities/cmlibuv/src/unix/tcp.c
new file mode 100644
index 000000000..c423dcb15
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/tcp.c
@@ -0,0 +1,395 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+
+static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
+ int sockfd;
+ int err;
+
+ if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
+ handle->flags |= flags;
+ return 0;
+ }
+
+ err = uv__socket(domain, SOCK_STREAM, 0);
+ if (err < 0)
+ return err;
+ sockfd = err;
+
+ err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
+ if (err) {
+ uv__close(sockfd);
+ return err;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ int err = maybe_new_socket(tcp, domain, 0);
+ if (err) {
+ QUEUE_REMOVE(&tcp->handle_queue);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
+ return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
+}
+
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int on;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ err = maybe_new_socket(tcp,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ on = 1;
+ if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
+ return -errno;
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+ if (setsockopt(tcp->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ &on,
+ sizeof on) == -1) {
+#if defined(__MVS__)
+ if (errno == EOPNOTSUPP)
+ return -EINVAL;
+#endif
+ return -errno;
+ }
+ }
+#endif
+
+ errno = 0;
+ if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ return -EINVAL;
+ return -errno;
+ }
+ tcp->delayed_error = -errno;
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ if (addr->sa_family == AF_INET6)
+ tcp->flags |= UV_HANDLE_IPV6;
+
+ return 0;
+}
+
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+ int r;
+
+ assert(handle->type == UV_TCP);
+
+ if (handle->connect_req != NULL)
+ return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
+
+ err = maybe_new_socket(handle,
+ addr->sa_family,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+ if (err)
+ return err;
+
+ handle->delayed_error = 0;
+
+ do {
+ errno = 0;
+ r = connect(uv__stream_fd(handle), addr, addrlen);
+ } while (r == -1 && errno == EINTR);
+
+ /* We not only check the return value, but also check the errno != 0.
+ * Because in rare cases connect() will return -1 but the errno
+ * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
+ * and actually the tcp three-way handshake is completed.
+ */
+ if (r == -1 && errno != 0) {
+ if (errno == EINPROGRESS)
+ ; /* not an error */
+ else if (errno == ECONNREFUSED)
+ /* If we get a ECONNREFUSED wait until the next tick to report the
+ * error. Solaris wants to report immediately--other unixes want to
+ * wait.
+ */
+ handle->delayed_error = -errno;
+ else
+ return -errno;
+ }
+
+ uv__req_init(handle->loop, req, UV_CONNECT);
+ req->cb = cb;
+ req->handle = (uv_stream_t*) handle;
+ QUEUE_INIT(&req->queue);
+ handle->connect_req = req;
+
+ uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
+
+ if (handle->delayed_error)
+ uv__io_feed(handle->loop, &handle->io_watcher);
+
+ return 0;
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ return uv__stream_open((uv_stream_t*)handle,
+ sock,
+ UV_STREAM_READABLE | UV_STREAM_WRITABLE);
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->delayed_error)
+ return handle->delayed_error;
+
+ if (uv__stream_fd(handle) < 0)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getpeername(uv__stream_fd(handle), name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
+ static int single_accept = -1;
+ int err;
+
+ if (tcp->delayed_error)
+ return tcp->delayed_error;
+
+ if (single_accept == -1) {
+ const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
+ single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
+ }
+
+ if (single_accept)
+ tcp->flags |= UV_TCP_SINGLE_ACCEPT;
+
+ err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
+ if (err)
+ return err;
+
+#ifdef __MVS__
+ /* on zOS the listen call does not bind automatically
+ if the socket is unbound. Hence the manual binding to
+ an arbitrary port is required to be done manually
+ */
+
+ if (!(tcp->flags & UV_HANDLE_BOUND)) {
+ struct sockaddr_storage saddr;
+ socklen_t slen = sizeof(saddr);
+ memset(&saddr, 0, sizeof(saddr));
+
+ if (getsockname(tcp->io_watcher.fd, (struct sockaddr*) &saddr, &slen))
+ return -errno;
+
+ if (bind(tcp->io_watcher.fd, (struct sockaddr*) &saddr, slen))
+ return -errno;
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ }
+#endif
+
+ if (listen(tcp->io_watcher.fd, backlog))
+ return -errno;
+
+ tcp->connection_cb = cb;
+ tcp->flags |= UV_HANDLE_BOUND;
+
+ /* Start listening for connections. */
+ tcp->io_watcher.cb = uv__server_io;
+ uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
+
+ return 0;
+}
+
+
+int uv__tcp_nodelay(int fd, int on) {
+ if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
+ return -errno;
+ return 0;
+}
+
+
+int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
+ if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
+ return -errno;
+
+#ifdef TCP_KEEPIDLE
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ /* Solaris/SmartOS, if you don't support keep-alive,
+ * then don't advertise it in your system headers...
+ */
+ /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
+#if defined(TCP_KEEPALIVE) && !defined(__sun)
+ if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err = uv__tcp_nodelay(uv__stream_fd(handle), on);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_NODELAY;
+ else
+ handle->flags &= ~UV_TCP_NODELAY;
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
+ int err;
+
+ if (uv__stream_fd(handle) != -1) {
+ err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
+ if (err)
+ return err;
+ }
+
+ if (on)
+ handle->flags |= UV_TCP_KEEPALIVE;
+ else
+ handle->flags &= ~UV_TCP_KEEPALIVE;
+
+ /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
+ * uv_tcp_t with an int that's almost never used...
+ */
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (enable)
+ handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
+ else
+ handle->flags |= UV_TCP_SINGLE_ACCEPT;
+ return 0;
+}
+
+
+void uv__tcp_close(uv_tcp_t* handle) {
+ uv__stream_close((uv_stream_t*)handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/thread.c b/Utilities/cmlibuv/src/unix/thread.c
new file mode 100644
index 000000000..a9b5e4c02
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/thread.c
@@ -0,0 +1,575 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <pthread.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/time.h>
+#include <sys/resource.h> /* getrlimit() */
+#include <unistd.h> /* getpagesize() */
+
+#include <limits.h>
+
+#ifdef __MVS__
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#endif
+
+#undef NANOSEC
+#define NANOSEC ((uint64_t) 1e9)
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ int err;
+ pthread_attr_t* attr;
+#if defined(__APPLE__)
+ pthread_attr_t attr_storage;
+ struct rlimit lim;
+#endif
+
+ /* On OSX threads other than the main thread are created with a reduced stack
+ * size by default, adjust it to RLIMIT_STACK.
+ */
+#if defined(__APPLE__)
+ if (getrlimit(RLIMIT_STACK, &lim))
+ abort();
+
+ attr = &attr_storage;
+ if (pthread_attr_init(attr))
+ abort();
+
+ if (lim.rlim_cur != RLIM_INFINITY) {
+ /* pthread_attr_setstacksize() expects page-aligned values. */
+ lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
+
+ if (lim.rlim_cur >= PTHREAD_STACK_MIN)
+ if (pthread_attr_setstacksize(attr, lim.rlim_cur))
+ abort();
+ }
+#else
+ attr = NULL;
+#endif
+
+ err = pthread_create(tid, attr, (void*(*)(void*)) entry, arg);
+
+ if (attr != NULL)
+ pthread_attr_destroy(attr);
+
+ return -err;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ return pthread_self();
+}
+
+int uv_thread_join(uv_thread_t *tid) {
+ return -pthread_join(*tid, NULL);
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return pthread_equal(*t1, *t2);
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+#if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
+ return -pthread_mutex_init(mutex, NULL);
+#else
+ pthread_mutexattr_t attr;
+ int err;
+
+ if (pthread_mutexattr_init(&attr))
+ abort();
+
+ if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
+ abort();
+
+ err = pthread_mutex_init(mutex, &attr);
+
+ if (pthread_mutexattr_destroy(&attr))
+ abort();
+
+ return -err;
+#endif
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ if (pthread_mutex_destroy(mutex))
+ abort();
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ if (pthread_mutex_lock(mutex))
+ abort();
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ int err;
+
+ err = pthread_mutex_trylock(mutex);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ if (pthread_mutex_unlock(mutex))
+ abort();
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ return -pthread_rwlock_init(rwlock, NULL);
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_destroy(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_rdlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_tryrdlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_wrlock(rwlock))
+ abort();
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ err = pthread_rwlock_trywrlock(rwlock);
+ if (err) {
+ if (err != EBUSY && err != EAGAIN)
+ abort();
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (pthread_rwlock_unlock(rwlock))
+ abort();
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ if (pthread_once(guard, callback))
+ abort();
+}
+
+#if defined(__APPLE__) && defined(__MACH__)
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ kern_return_t err;
+
+ err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_INVALID_ARGUMENT)
+ return -EINVAL;
+ if (err == KERN_RESOURCE_SHORTAGE)
+ return -ENOMEM;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (semaphore_destroy(mach_task_self(), *sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (semaphore_signal(*sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = semaphore_wait(*sem);
+ while (r == KERN_ABORTED);
+
+ if (r != KERN_SUCCESS)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ mach_timespec_t interval;
+ kern_return_t err;
+
+ interval.tv_sec = 0;
+ interval.tv_nsec = 0;
+
+ err = semaphore_timedwait(*sem, interval);
+ if (err == KERN_SUCCESS)
+ return 0;
+ if (err == KERN_OPERATION_TIMED_OUT)
+ return -EAGAIN;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+#elif defined(__MVS__)
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ uv_sem_t semid;
+ struct sembuf buf;
+ int err;
+
+ buf.sem_num = 0;
+ buf.sem_op = value;
+ buf.sem_flg = 0;
+
+ semid = semget(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR);
+ if (semid == -1)
+ return -errno;
+
+ if (-1 == semop(semid, &buf, 1)) {
+ err = errno;
+ if (-1 == semctl(*sem, 0, IPC_RMID))
+ abort();
+ return -err;
+ }
+
+ *sem = semid;
+ return 0;
+}
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (-1 == semctl(*sem, 0, IPC_RMID))
+ abort();
+}
+
+void uv_sem_post(uv_sem_t* sem) {
+ struct sembuf buf;
+
+ buf.sem_num = 0;
+ buf.sem_op = 1;
+ buf.sem_flg = 0;
+
+ if (-1 == semop(*sem, &buf, 1))
+ abort();
+}
+
+void uv_sem_wait(uv_sem_t* sem) {
+ struct sembuf buf;
+ int op_status;
+
+ buf.sem_num = 0;
+ buf.sem_op = -1;
+ buf.sem_flg = 0;
+
+ do
+ op_status = semop(*sem, &buf, 1);
+ while (op_status == -1 && errno == EINTR);
+
+ if (op_status)
+ abort();
+}
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ struct sembuf buf;
+ int op_status;
+
+ buf.sem_num = 0;
+ buf.sem_op = -1;
+ buf.sem_flg = IPC_NOWAIT;
+
+ do
+ op_status = semop(*sem, &buf, 1);
+ while (op_status == -1 && errno == EINTR);
+
+ if (op_status) {
+ if (errno == EAGAIN)
+ return -EAGAIN;
+ abort();
+ }
+
+ return 0;
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ if (sem_init(sem, 0, value))
+ return -errno;
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (sem_destroy(sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (sem_post(sem))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_wait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ int r;
+
+ do
+ r = sem_trywait(sem);
+ while (r == -1 && errno == EINTR);
+
+ if (r) {
+ if (errno == EAGAIN)
+ return -EAGAIN;
+ abort();
+ }
+
+ return 0;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+
+#if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
+
+int uv_cond_init(uv_cond_t* cond) {
+ return -pthread_cond_init(cond, NULL);
+}
+
+#else /* !(defined(__APPLE__) && defined(__MACH__)) */
+
+int uv_cond_init(uv_cond_t* cond) {
+ pthread_condattr_t attr;
+ int err;
+
+ err = pthread_condattr_init(&attr);
+ if (err)
+ return -err;
+
+#if !(defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC))
+ err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
+ if (err)
+ goto error2;
+#endif
+
+ err = pthread_cond_init(cond, &attr);
+ if (err)
+ goto error2;
+
+ err = pthread_condattr_destroy(&attr);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ pthread_cond_destroy(cond);
+error2:
+ pthread_condattr_destroy(&attr);
+ return -err;
+}
+
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+void uv_cond_destroy(uv_cond_t* cond) {
+#if defined(__APPLE__) && defined(__MACH__)
+ /* It has been reported that destroying condition variables that have been
+ * signalled but not waited on can sometimes result in application crashes.
+ * See https://codereview.chromium.org/1323293005.
+ */
+ pthread_mutex_t mutex;
+ struct timespec ts;
+ int err;
+
+ if (pthread_mutex_init(&mutex, NULL))
+ abort();
+
+ if (pthread_mutex_lock(&mutex))
+ abort();
+
+ ts.tv_sec = 0;
+ ts.tv_nsec = 1;
+
+ err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
+ if (err != 0 && err != ETIMEDOUT)
+ abort();
+
+ if (pthread_mutex_unlock(&mutex))
+ abort();
+
+ if (pthread_mutex_destroy(&mutex))
+ abort();
+#endif /* defined(__APPLE__) && defined(__MACH__) */
+
+ if (pthread_cond_destroy(cond))
+ abort();
+}
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (pthread_cond_signal(cond))
+ abort();
+}
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (pthread_cond_broadcast(cond))
+ abort();
+}
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (pthread_cond_wait(cond, mutex))
+ abort();
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
+ int r;
+ struct timespec ts;
+
+#if defined(__APPLE__) && defined(__MACH__)
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+ r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
+#else
+ timeout += uv__hrtime(UV_CLOCK_PRECISE);
+ ts.tv_sec = timeout / NANOSEC;
+ ts.tv_nsec = timeout % NANOSEC;
+#if defined(__ANDROID__) && defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
+ /*
+ * The bionic pthread implementation doesn't support CLOCK_MONOTONIC,
+ * but has this alternative function instead.
+ */
+ r = pthread_cond_timedwait_monotonic_np(cond, mutex, &ts);
+#else
+ r = pthread_cond_timedwait(cond, mutex, &ts);
+#endif /* __ANDROID__ */
+#endif
+
+
+ if (r == 0)
+ return 0;
+
+ if (r == ETIMEDOUT)
+ return -ETIMEDOUT;
+
+ abort();
+ return -EINVAL; /* Satisfy the compiler. */
+}
+
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ return -pthread_barrier_init(barrier, NULL, count);
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ if (pthread_barrier_destroy(barrier))
+ abort();
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int r = pthread_barrier_wait(barrier);
+ if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
+ abort();
+ return r == PTHREAD_BARRIER_SERIAL_THREAD;
+}
+
+
+int uv_key_create(uv_key_t* key) {
+ return -pthread_key_create(key, NULL);
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (pthread_key_delete(*key))
+ abort();
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ return pthread_getspecific(*key);
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (pthread_setspecific(*key, value))
+ abort();
+}
diff --git a/Utilities/cmlibuv/src/unix/timer.c b/Utilities/cmlibuv/src/unix/timer.c
new file mode 100644
index 000000000..f46bdf4bf
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/timer.c
@@ -0,0 +1,172 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "heap-inl.h"
+
+#include <assert.h>
+#include <limits.h>
+
+
+static int timer_less_than(const struct heap_node* ha,
+ const struct heap_node* hb) {
+ const uv_timer_t* a;
+ const uv_timer_t* b;
+
+ a = container_of(ha, uv_timer_t, heap_node);
+ b = container_of(hb, uv_timer_t, heap_node);
+
+ if (a->timeout < b->timeout)
+ return 1;
+ if (b->timeout < a->timeout)
+ return 0;
+
+ /* Compare start_id when both have the same timeout. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return 1;
+ if (b->start_id < a->start_id)
+ return 0;
+
+ return 0;
+}
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+ return 0;
+}
+
+
+int uv_timer_start(uv_timer_t* handle,
+ uv_timer_cb cb,
+ uint64_t timeout,
+ uint64_t repeat) {
+ uint64_t clamped_timeout;
+
+ if (cb == NULL)
+ return -EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ clamped_timeout = handle->loop->time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ handle->timer_cb = cb;
+ handle->timeout = clamped_timeout;
+ handle->repeat = repeat;
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ heap_insert((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ heap_remove((struct heap*) &handle->loop->timer_heap,
+ (struct heap_node*) &handle->heap_node,
+ timer_less_than);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ if (handle->timer_cb == NULL)
+ return -EINVAL;
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ return handle->repeat;
+}
+
+
+int uv__next_timeout(const uv_loop_t* loop) {
+ const struct heap_node* heap_node;
+ const uv_timer_t* handle;
+ uint64_t diff;
+
+ heap_node = heap_min((const struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ return -1; /* block indefinitely */
+
+ handle = container_of(heap_node, uv_timer_t, heap_node);
+ if (handle->timeout <= loop->time)
+ return 0;
+
+ diff = handle->timeout - loop->time;
+ if (diff > INT_MAX)
+ diff = INT_MAX;
+
+ return diff;
+}
+
+
+void uv__run_timers(uv_loop_t* loop) {
+ struct heap_node* heap_node;
+ uv_timer_t* handle;
+
+ for (;;) {
+ heap_node = heap_min((struct heap*) &loop->timer_heap);
+ if (heap_node == NULL)
+ break;
+
+ handle = container_of(heap_node, uv_timer_t, heap_node);
+ if (handle->timeout > loop->time)
+ break;
+
+ uv_timer_stop(handle);
+ uv_timer_again(handle);
+ handle->timer_cb(handle);
+ }
+}
+
+
+void uv__timer_close(uv_timer_t* handle) {
+ uv_timer_stop(handle);
+}
diff --git a/Utilities/cmlibuv/src/unix/tty.c b/Utilities/cmlibuv/src/unix/tty.c
new file mode 100644
index 000000000..ae1018fc4
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/tty.c
@@ -0,0 +1,333 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+#include "spinlock.h"
+
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <termios.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+
+#if defined(__MVS__) && !defined(IMAXBEL)
+#define IMAXBEL 0
+#endif
+
+static int orig_termios_fd = -1;
+static struct termios orig_termios;
+static uv_spinlock_t termios_spinlock = UV_SPINLOCK_INITIALIZER;
+
+static int uv__tty_is_slave(const int fd) {
+ int result;
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+ int dummy;
+
+ result = ioctl(fd, TIOCGPTN, &dummy) != 0;
+#elif defined(__APPLE__)
+ char dummy[256];
+
+ result = ioctl(fd, TIOCPTYGNAME, &dummy) != 0;
+#else
+ /* Fallback to ptsname
+ */
+ result = ptsname(fd) == NULL;
+#endif
+ return result;
+}
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, int fd, int readable) {
+ uv_handle_type type;
+ int flags = 0;
+ int newfd = -1;
+ int r;
+ int saved_flags;
+ char path[256];
+
+ /* File descriptors that refer to files cannot be monitored with epoll.
+ * That restriction also applies to character devices like /dev/random
+ * (but obviously not /dev/tty.)
+ */
+ type = uv_guess_handle(fd);
+ if (type == UV_FILE || type == UV_UNKNOWN_HANDLE)
+ return -EINVAL;
+
+ /* Reopen the file descriptor when it refers to a tty. This lets us put the
+ * tty in non-blocking mode without affecting other processes that share it
+ * with us.
+ *
+ * Example: `node | cat` - if we put our fd 0 in non-blocking mode, it also
+ * affects fd 1 of `cat` because both file descriptors refer to the same
+ * struct file in the kernel. When we reopen our fd 0, it points to a
+ * different struct file, hence changing its properties doesn't affect
+ * other processes.
+ */
+ if (type == UV_TTY) {
+ /* Reopening a pty in master mode won't work either because the reopened
+ * pty will be in slave mode (*BSD) or reopening will allocate a new
+ * master/slave pair (Linux). Therefore check if the fd points to a
+ * slave device.
+ */
+ if (uv__tty_is_slave(fd) && ttyname_r(fd, path, sizeof(path)) == 0)
+ r = uv__open_cloexec(path, O_RDWR);
+ else
+ r = -1;
+
+ if (r < 0) {
+ /* fallback to using blocking writes */
+ if (!readable)
+ flags |= UV_STREAM_BLOCKING;
+ goto skip;
+ }
+
+ newfd = r;
+
+ r = uv__dup2_cloexec(newfd, fd);
+ if (r < 0 && r != -EINVAL) {
+ /* EINVAL means newfd == fd which could conceivably happen if another
+ * thread called close(fd) between our calls to isatty() and open().
+ * That's a rather unlikely event but let's handle it anyway.
+ */
+ uv__close(newfd);
+ return r;
+ }
+
+ fd = newfd;
+ }
+
+#if defined(__APPLE__)
+ /* Save the fd flags in case we need to restore them due to an error. */
+ do
+ saved_flags = fcntl(fd, F_GETFL);
+ while (saved_flags == -1 && errno == EINTR);
+
+ if (saved_flags == -1) {
+ if (newfd != -1)
+ uv__close(newfd);
+ return -errno;
+ }
+#endif
+
+ /* Pacify the compiler. */
+ (void) &saved_flags;
+
+skip:
+ uv__stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (!(flags & UV_STREAM_BLOCKING))
+ uv__nonblock(fd, 1);
+
+#if defined(__APPLE__)
+ r = uv__stream_try_select((uv_stream_t*) tty, &fd);
+ if (r) {
+ int rc = r;
+ if (newfd != -1)
+ uv__close(newfd);
+ QUEUE_REMOVE(&tty->handle_queue);
+ do
+ r = fcntl(fd, F_SETFL, saved_flags);
+ while (r == -1 && errno == EINTR);
+ return rc;
+ }
+#endif
+
+ if (readable)
+ flags |= UV_STREAM_READABLE;
+ else
+ flags |= UV_STREAM_WRITABLE;
+
+ uv__stream_open((uv_stream_t*) tty, fd, flags);
+ tty->mode = UV_TTY_MODE_NORMAL;
+
+ return 0;
+}
+
+static void uv__tty_make_raw(struct termios* tio) {
+ assert(tio != NULL);
+
+#if defined __sun || defined __MVS__
+ /*
+ * This implementation of cfmakeraw for Solaris and derivatives is taken from
+ * http://www.perkin.org.uk/posts/solaris-portability-cfmakeraw.html.
+ */
+ tio->c_iflag &= ~(IMAXBEL | IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR |
+ IGNCR | ICRNL | IXON);
+ tio->c_oflag &= ~OPOST;
+ tio->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
+ tio->c_cflag &= ~(CSIZE | PARENB);
+ tio->c_cflag |= CS8;
+#else
+ cfmakeraw(tio);
+#endif /* #ifdef __sun */
+}
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ struct termios tmp;
+ int fd;
+
+ if (tty->mode == (int) mode)
+ return 0;
+
+ fd = uv__stream_fd(tty);
+ if (tty->mode == UV_TTY_MODE_NORMAL && mode != UV_TTY_MODE_NORMAL) {
+ if (tcgetattr(fd, &tty->orig_termios))
+ return -errno;
+
+ /* This is used for uv_tty_reset_mode() */
+ uv_spinlock_lock(&termios_spinlock);
+ if (orig_termios_fd == -1) {
+ orig_termios = tty->orig_termios;
+ orig_termios_fd = fd;
+ }
+ uv_spinlock_unlock(&termios_spinlock);
+ }
+
+ tmp = tty->orig_termios;
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ break;
+ case UV_TTY_MODE_RAW:
+ tmp.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
+ tmp.c_oflag |= (ONLCR);
+ tmp.c_cflag |= (CS8);
+ tmp.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
+ tmp.c_cc[VMIN] = 1;
+ tmp.c_cc[VTIME] = 0;
+ break;
+ case UV_TTY_MODE_IO:
+ uv__tty_make_raw(&tmp);
+ break;
+ }
+
+ /* Apply changes after draining */
+ if (tcsetattr(fd, TCSADRAIN, &tmp))
+ return -errno;
+
+ tty->mode = mode;
+ return 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ struct winsize ws;
+ int err;
+
+ do
+ err = ioctl(uv__stream_fd(tty), TIOCGWINSZ, &ws);
+ while (err == -1 && errno == EINTR);
+
+ if (err == -1)
+ return -errno;
+
+ *width = ws.ws_col;
+ *height = ws.ws_row;
+
+ return 0;
+}
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ struct sockaddr sa;
+ struct stat s;
+ socklen_t len;
+ int type;
+
+ if (file < 0)
+ return UV_UNKNOWN_HANDLE;
+
+ if (isatty(file))
+ return UV_TTY;
+
+ if (fstat(file, &s))
+ return UV_UNKNOWN_HANDLE;
+
+ if (S_ISREG(s.st_mode))
+ return UV_FILE;
+
+ if (S_ISCHR(s.st_mode))
+ return UV_FILE; /* XXX UV_NAMED_PIPE? */
+
+ if (S_ISFIFO(s.st_mode))
+ return UV_NAMED_PIPE;
+
+ if (!S_ISSOCK(s.st_mode))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(type);
+ if (getsockopt(file, SOL_SOCKET, SO_TYPE, &type, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ len = sizeof(sa);
+ if (getsockname(file, &sa, &len))
+ return UV_UNKNOWN_HANDLE;
+
+ if (type == SOCK_DGRAM)
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_UDP;
+
+ if (type == SOCK_STREAM) {
+#if defined(_AIX) || defined(__DragonFly__)
+ /* on AIX/DragonFly the getsockname call returns an empty sa structure
+ * for sockets of type AF_UNIX. For all other types it will
+ * return a properly filled in structure.
+ */
+ if (len == 0)
+ return UV_NAMED_PIPE;
+#endif /* defined(_AIX) || defined(__DragonFly__) */
+
+ if (sa.sa_family == AF_INET || sa.sa_family == AF_INET6)
+ return UV_TCP;
+ if (sa.sa_family == AF_UNIX)
+ return UV_NAMED_PIPE;
+ }
+
+ return UV_UNKNOWN_HANDLE;
+}
+
+
+/* This function is async signal-safe, meaning that it's safe to call from
+ * inside a signal handler _unless_ execution was inside uv_tty_set_mode()'s
+ * critical section when the signal was raised.
+ */
+int uv_tty_reset_mode(void) {
+ int saved_errno;
+ int err;
+
+ saved_errno = errno;
+ if (!uv_spinlock_trylock(&termios_spinlock))
+ return -EBUSY; /* In uv_tty_set_mode(). */
+
+ err = 0;
+ if (orig_termios_fd != -1)
+ if (tcsetattr(orig_termios_fd, TCSANOW, &orig_termios))
+ err = -errno;
+
+ uv_spinlock_unlock(&termios_spinlock);
+ errno = saved_errno;
+
+ return err;
+}
diff --git a/Utilities/cmlibuv/src/unix/udp.c b/Utilities/cmlibuv/src/unix/udp.c
new file mode 100644
index 000000000..c556325de
--- /dev/null
+++ b/Utilities/cmlibuv/src/unix/udp.c
@@ -0,0 +1,900 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#if defined(__MVS__)
+#include <xti.h>
+#endif
+
+#if defined(IPV6_JOIN_GROUP) && !defined(IPV6_ADD_MEMBERSHIP)
+# define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
+#endif
+
+#if defined(IPV6_LEAVE_GROUP) && !defined(IPV6_DROP_MEMBERSHIP)
+# define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP
+#endif
+
+
+static void uv__udp_run_completed(uv_udp_t* handle);
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents);
+static void uv__udp_recvmsg(uv_udp_t* handle);
+static void uv__udp_sendmsg(uv_udp_t* handle);
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags);
+
+
+void uv__udp_close(uv_udp_t* handle) {
+ uv__io_close(handle->loop, &handle->io_watcher);
+ uv__handle_stop(handle);
+
+ if (handle->io_watcher.fd != -1) {
+ uv__close(handle->io_watcher.fd);
+ handle->io_watcher.fd = -1;
+ }
+}
+
+
+void uv__udp_finish_close(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!uv__io_active(&handle->io_watcher, POLLIN | POLLOUT));
+ assert(handle->io_watcher.fd == -1);
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ req->status = -ECANCELED;
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ }
+
+ uv__udp_run_completed(handle);
+
+ assert(handle->send_queue_size == 0);
+ assert(handle->send_queue_count == 0);
+
+ /* Now tear down the handle. */
+ handle->recv_cb = NULL;
+ handle->alloc_cb = NULL;
+ /* but _do not_ touch close_cb */
+}
+
+
+static void uv__udp_run_completed(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+
+ assert(!(handle->flags & UV_UDP_PROCESSING));
+ handle->flags |= UV_UDP_PROCESSING;
+
+ while (!QUEUE_EMPTY(&handle->write_completed_queue)) {
+ q = QUEUE_HEAD(&handle->write_completed_queue);
+ QUEUE_REMOVE(q);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ uv__req_unregister(handle->loop, req);
+
+ handle->send_queue_size -= uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count--;
+
+ if (req->bufs != req->bufsml)
+ uv__free(req->bufs);
+ req->bufs = NULL;
+
+ if (req->send_cb == NULL)
+ continue;
+
+ /* req->status >= 0 == bytes written
+ * req->status < 0 == errno
+ */
+ if (req->status >= 0)
+ req->send_cb(req, 0);
+ else
+ req->send_cb(req, req->status);
+ }
+
+ if (QUEUE_EMPTY(&handle->write_queue)) {
+ /* Pending queue and completion queue empty, stop watcher. */
+ uv__io_stop(handle->loop, &handle->io_watcher, POLLOUT);
+ if (!uv__io_active(&handle->io_watcher, POLLIN))
+ uv__handle_stop(handle);
+ }
+
+ handle->flags &= ~UV_UDP_PROCESSING;
+}
+
+
+static void uv__udp_io(uv_loop_t* loop, uv__io_t* w, unsigned int revents) {
+ uv_udp_t* handle;
+
+ handle = container_of(w, uv_udp_t, io_watcher);
+ assert(handle->type == UV_UDP);
+
+ if (revents & POLLIN)
+ uv__udp_recvmsg(handle);
+
+ if (revents & POLLOUT) {
+ uv__udp_sendmsg(handle);
+ uv__udp_run_completed(handle);
+ }
+}
+
+
+static void uv__udp_recvmsg(uv_udp_t* handle) {
+ struct sockaddr_storage peer;
+ struct msghdr h;
+ ssize_t nread;
+ uv_buf_t buf;
+ int flags;
+ int count;
+
+ assert(handle->recv_cb != NULL);
+ assert(handle->alloc_cb != NULL);
+
+ /* Prevent loop starvation when the data comes in as fast as (or faster than)
+ * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O.
+ */
+ count = 32;
+
+ memset(&h, 0, sizeof(h));
+ h.msg_name = &peer;
+
+ do {
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 64 * 1024, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ return;
+ }
+ assert(buf.base != NULL);
+
+ h.msg_namelen = sizeof(peer);
+ h.msg_iov = (void*) &buf;
+ h.msg_iovlen = 1;
+
+ do {
+ nread = recvmsg(handle->io_watcher.fd, &h, 0);
+ }
+ while (nread == -1 && errno == EINTR);
+
+ if (nread == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ else
+ handle->recv_cb(handle, -errno, &buf, NULL, 0);
+ }
+ else {
+ const struct sockaddr *addr;
+ if (h.msg_namelen == 0)
+ addr = NULL;
+ else
+ addr = (const struct sockaddr*) &peer;
+
+ flags = 0;
+ if (h.msg_flags & MSG_TRUNC)
+ flags |= UV_UDP_PARTIAL;
+
+ handle->recv_cb(handle, nread, &buf, addr, flags);
+ }
+ }
+ /* recv_cb callback may decide to pause or close the handle */
+ while (nread != -1
+ && count-- > 0
+ && handle->io_watcher.fd != -1
+ && handle->recv_cb != NULL);
+}
+
+
+static void uv__udp_sendmsg(uv_udp_t* handle) {
+ uv_udp_send_t* req;
+ QUEUE* q;
+ struct msghdr h;
+ ssize_t size;
+
+ while (!QUEUE_EMPTY(&handle->write_queue)) {
+ q = QUEUE_HEAD(&handle->write_queue);
+ assert(q != NULL);
+
+ req = QUEUE_DATA(q, uv_udp_send_t, queue);
+ assert(req != NULL);
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = &req->addr;
+ h.msg_namelen = (req->addr.ss_family == AF_INET6 ?
+ sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in));
+ h.msg_iov = (struct iovec*) req->bufs;
+ h.msg_iovlen = req->nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ break;
+
+ req->status = (size == -1 ? -errno : size);
+
+ /* Sending a datagram is an atomic operation: either all data
+ * is written or nothing is (and EMSGSIZE is raised). That is
+ * why we don't handle partial writes. Just pop the request
+ * off the write queue and onto the completed queue, done.
+ */
+ QUEUE_REMOVE(&req->queue);
+ QUEUE_INSERT_TAIL(&handle->write_completed_queue, &req->queue);
+ uv__io_feed(handle->loop, &handle->io_watcher);
+ }
+}
+
+
+/* On the BSDs, SO_REUSEPORT implies SO_REUSEADDR but with some additional
+ * refinements for programs that use multicast.
+ *
+ * Linux as of 3.9 has a SO_REUSEPORT socket option but with semantics that
+ * are different from the BSDs: it _shares_ the port rather than steal it
+ * from the current listener. While useful, it's not something we can emulate
+ * on other platforms so we don't enable it.
+ */
+static int uv__set_reuse(int fd) {
+ int yes;
+
+#if defined(SO_REUSEPORT) && !defined(__linux__)
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &yes, sizeof(yes)))
+ return -errno;
+#else
+ yes = 1;
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)))
+ return -errno;
+#endif
+
+ return 0;
+}
+
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+ int yes;
+ int fd;
+
+ /* Check for bad flags. */
+ if (flags & ~(UV_UDP_IPV6ONLY | UV_UDP_REUSEADDR))
+ return -EINVAL;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return -EINVAL;
+
+ fd = handle->io_watcher.fd;
+ if (fd == -1) {
+ err = uv__socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ handle->io_watcher.fd = fd;
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ err = uv__set_reuse(fd);
+ if (err)
+ return err;
+ }
+
+ if (flags & UV_UDP_IPV6ONLY) {
+#ifdef IPV6_V6ONLY
+ yes = 1;
+ if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof yes) == -1) {
+ err = -errno;
+ return err;
+ }
+#else
+ err = -ENOTSUP;
+ return err;
+#endif
+ }
+
+ if (bind(fd, addr, addrlen)) {
+ err = -errno;
+ if (errno == EAFNOSUPPORT)
+ /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
+ * socket created with AF_INET to an AF_INET6 address or vice versa. */
+ err = -EINVAL;
+ return err;
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ handle->flags |= UV_HANDLE_BOUND;
+ return 0;
+}
+
+
+static int uv__udp_maybe_deferred_bind(uv_udp_t* handle,
+ int domain,
+ unsigned int flags) {
+ union {
+ struct sockaddr_in6 in6;
+ struct sockaddr_in in;
+ struct sockaddr addr;
+ } taddr;
+ socklen_t addrlen;
+
+ if (handle->io_watcher.fd != -1)
+ return 0;
+
+ switch (domain) {
+ case AF_INET:
+ {
+ struct sockaddr_in* addr = &taddr.in;
+ memset(addr, 0, sizeof *addr);
+ addr->sin_family = AF_INET;
+ addr->sin_addr.s_addr = INADDR_ANY;
+ addrlen = sizeof *addr;
+ break;
+ }
+ case AF_INET6:
+ {
+ struct sockaddr_in6* addr = &taddr.in6;
+ memset(addr, 0, sizeof *addr);
+ addr->sin6_family = AF_INET6;
+ addr->sin6_addr = in6addr_any;
+ addrlen = sizeof *addr;
+ break;
+ }
+ default:
+ assert(0 && "unsupported address family");
+ abort();
+ }
+
+ return uv__udp_bind(handle, &taddr.addr, addrlen, flags);
+}
+
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ int err;
+ int empty_queue;
+
+ assert(nbufs > 0);
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ /* It's legal for send_queue_count > 0 even when the write_queue is empty;
+ * it means there are error-state requests in the write_completed_queue that
+ * will touch up send_queue_size/count later.
+ */
+ empty_queue = (handle->send_queue_count == 0);
+
+ uv__req_init(handle->loop, req, UV_UDP_SEND);
+ assert(addrlen <= sizeof(req->addr));
+ memcpy(&req->addr, addr, addrlen);
+ req->send_cb = send_cb;
+ req->handle = handle;
+ req->nbufs = nbufs;
+
+ req->bufs = req->bufsml;
+ if (nbufs > ARRAY_SIZE(req->bufsml))
+ req->bufs = uv__malloc(nbufs * sizeof(bufs[0]));
+
+ if (req->bufs == NULL) {
+ uv__req_unregister(handle->loop, req);
+ return -ENOMEM;
+ }
+
+ memcpy(req->bufs, bufs, nbufs * sizeof(bufs[0]));
+ handle->send_queue_size += uv__count_bufs(req->bufs, req->nbufs);
+ handle->send_queue_count++;
+ QUEUE_INSERT_TAIL(&handle->write_queue, &req->queue);
+ uv__handle_start(handle);
+
+ if (empty_queue && !(handle->flags & UV_UDP_PROCESSING)) {
+ uv__udp_sendmsg(handle);
+
+ /* `uv__udp_sendmsg` may not be able to do non-blocking write straight
+ * away. In such cases the `io_watcher` has to be queued for asynchronous
+ * write.
+ */
+ if (!QUEUE_EMPTY(&handle->write_queue))
+ uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
+ } else {
+ uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
+ }
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ int err;
+ struct msghdr h;
+ ssize_t size;
+
+ assert(nbufs > 0);
+
+ /* already sending a message */
+ if (handle->send_queue_count != 0)
+ return -EAGAIN;
+
+ err = uv__udp_maybe_deferred_bind(handle, addr->sa_family, 0);
+ if (err)
+ return err;
+
+ memset(&h, 0, sizeof h);
+ h.msg_name = (struct sockaddr*) addr;
+ h.msg_namelen = addrlen;
+ h.msg_iov = (struct iovec*) bufs;
+ h.msg_iovlen = nbufs;
+
+ do {
+ size = sendmsg(handle->io_watcher.fd, &h, 0);
+ } while (size == -1 && errno == EINTR);
+
+ if (size == -1) {
+ if (errno == EAGAIN || errno == EWOULDBLOCK)
+ return -EAGAIN;
+ else
+ return -errno;
+ }
+
+ return size;
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct ip_mreq mreq;
+ int optname;
+ int err;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+#if defined(__MVS__)
+ if (errno == ENXIO)
+ return -ENODEV;
+#endif
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+static int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return -EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ optname,
+ &mreq,
+ sizeof(mreq))) {
+#if defined(__MVS__)
+ if (errno == ENXIO)
+ return -ENODEV;
+#endif
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+ int err;
+ int fd;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return -EINVAL;
+
+ if (flags & ~0xFF)
+ return -EINVAL;
+
+ if (domain != AF_UNSPEC) {
+ err = uv__socket(domain, SOCK_DGRAM, 0);
+ if (err < 0)
+ return err;
+ fd = err;
+ } else {
+ fd = -1;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*)handle, UV_UDP);
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ uv__io_init(&handle->io_watcher, uv__udp_io, fd);
+ QUEUE_INIT(&handle->write_queue);
+ QUEUE_INIT(&handle->write_completed_queue);
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ int err;
+
+ /* Check for already active socket. */
+ if (handle->io_watcher.fd != -1)
+ return -EBUSY;
+
+ err = uv__nonblock(sock, 1);
+ if (err)
+ return err;
+
+ err = uv__set_reuse(sock);
+ if (err)
+ return err;
+
+ handle->io_watcher.fd = sock;
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ } else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0) {
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET6, UV_UDP_REUSEADDR);
+ if (err)
+ return err;
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ } else {
+ return -EINVAL;
+ }
+}
+
+static int uv__setsockopt(uv_udp_t* handle,
+ int option4,
+ int option6,
+ const void* val,
+ size_t size) {
+ int r;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ option6,
+ val,
+ size);
+ else
+ r = setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ option4,
+ val,
+ size);
+ if (r)
+ return -errno;
+
+ return 0;
+}
+
+static int uv__setsockopt_maybe_char(uv_udp_t* handle,
+ int option4,
+ int option6,
+ int val) {
+#if defined(__sun) || defined(_AIX) || defined(__MVS__)
+ char arg = val;
+#elif defined(__OpenBSD__)
+ unsigned char arg = val;
+#else
+ int arg = val;
+#endif
+
+ if (val < 0 || val > 255)
+ return -EINVAL;
+
+ return uv__setsockopt(handle, option4, option6, &arg, sizeof(arg));
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int on) {
+ if (setsockopt(handle->io_watcher.fd,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ &on,
+ sizeof(on))) {
+ return -errno;
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_ttl(uv_udp_t* handle, int ttl) {
+ if (ttl < 1 || ttl > 255)
+ return -EINVAL;
+
+#if defined(__MVS__)
+ if (!(handle->flags & UV_HANDLE_IPV6))
+ return -ENOTSUP; /* zOS does not support setting ttl for IPv4 */
+#endif
+
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IP_TTL and IPV6_UNICAST_HOPS,
+ * so hardcode the size of these options on this platform,
+ * and use the general uv__setsockopt_maybe_char call on other platforms.
+ */
+#if defined(__sun) || defined(_AIX) || defined(__OpenBSD__) || \
+ defined(__MVS__)
+
+ return uv__setsockopt(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) || defined (__OpenBSD__) ||
+ defined(__MVS__) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_TTL,
+ IPV6_UNICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_ttl(uv_udp_t* handle, int ttl) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_HOPS and sizeof(char) for
+ * IP_MULTICAST_TTL, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX) || defined(__MVS__)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ &ttl,
+ sizeof(ttl));
+#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ ttl);
+}
+
+
+int uv_udp_set_multicast_loop(uv_udp_t* handle, int on) {
+/*
+ * On Solaris and derivatives such as SmartOS, the length of socket options
+ * is sizeof(int) for IPV6_MULTICAST_LOOP and sizeof(char) for
+ * IP_MULTICAST_LOOP, so hardcode the size of the option in the IPv6 case,
+ * and use the general uv__setsockopt_maybe_char call otherwise.
+ */
+#if defined(__sun) || defined(_AIX) || defined(__MVS__)
+ if (handle->flags & UV_HANDLE_IPV6)
+ return uv__setsockopt(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ &on,
+ sizeof(on));
+#endif /* defined(__sun) || defined(_AIX) || defined(__MVS__) */
+
+ return uv__setsockopt_maybe_char(handle,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ on);
+}
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return -EINVAL;
+ }
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (void*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == -1) {
+ return -errno;
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->io_watcher.fd,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == -1) {
+ return -errno;
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ socklen_t socklen;
+
+ if (handle->io_watcher.fd == -1)
+ return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
+
+ /* sizeof(socklen_t) != sizeof(int) on some systems. */
+ socklen = (socklen_t) *namelen;
+
+ if (getsockname(handle->io_watcher.fd, name, &socklen))
+ return -errno;
+
+ *namelen = (int) socklen;
+ return 0;
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ int err;
+
+ if (alloc_cb == NULL || recv_cb == NULL)
+ return -EINVAL;
+
+ if (uv__io_active(&handle->io_watcher, POLLIN))
+ return -EALREADY; /* FIXME(bnoordhuis) Should be -EBUSY. */
+
+ err = uv__udp_maybe_deferred_bind(handle, AF_INET, 0);
+ if (err)
+ return err;
+
+ handle->alloc_cb = alloc_cb;
+ handle->recv_cb = recv_cb;
+
+ uv__io_start(handle->loop, &handle->io_watcher, POLLIN);
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ uv__io_stop(handle->loop, &handle->io_watcher, POLLIN);
+
+ if (!uv__io_active(&handle->io_watcher, POLLOUT))
+ uv__handle_stop(handle);
+
+ handle->alloc_cb = NULL;
+ handle->recv_cb = NULL;
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/uv-common.c b/Utilities/cmlibuv/src/uv-common.c
new file mode 100644
index 000000000..bc7d1379d
--- /dev/null
+++ b/Utilities/cmlibuv/src/uv-common.c
@@ -0,0 +1,664 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "uv-common.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stddef.h> /* NULL */
+#include <stdio.h>
+#include <stdlib.h> /* malloc */
+#include <string.h> /* memset */
+
+#if defined(_WIN32)
+# include <malloc.h> /* malloc */
+#else
+# include <net/if.h> /* if_nametoindex */
+#endif
+
+
+typedef struct {
+ uv_malloc_func local_malloc;
+ uv_realloc_func local_realloc;
+ uv_calloc_func local_calloc;
+ uv_free_func local_free;
+} uv__allocator_t;
+
+static uv__allocator_t uv__allocator = {
+ malloc,
+ realloc,
+ calloc,
+ free,
+};
+
+char* uv__strdup(const char* s) {
+ size_t len = strlen(s) + 1;
+ char* m = uv__malloc(len);
+ if (m == NULL)
+ return NULL;
+ return memcpy(m, s, len);
+}
+
+char* uv__strndup(const char* s, size_t n) {
+ char* m;
+ size_t len = strlen(s);
+ if (n < len)
+ len = n;
+ m = uv__malloc(len + 1);
+ if (m == NULL)
+ return NULL;
+ m[len] = '\0';
+ return memcpy(m, s, len);
+}
+
+void* uv__malloc(size_t size) {
+ return uv__allocator.local_malloc(size);
+}
+
+void uv__free(void* ptr) {
+ int saved_errno;
+
+ /* Libuv expects that free() does not clobber errno. The system allocator
+ * honors that assumption but custom allocators may not be so careful.
+ */
+ saved_errno = errno;
+ uv__allocator.local_free(ptr);
+ errno = saved_errno;
+}
+
+void* uv__calloc(size_t count, size_t size) {
+ return uv__allocator.local_calloc(count, size);
+}
+
+void* uv__realloc(void* ptr, size_t size) {
+ return uv__allocator.local_realloc(ptr, size);
+}
+
+int uv_replace_allocator(uv_malloc_func malloc_func,
+ uv_realloc_func realloc_func,
+ uv_calloc_func calloc_func,
+ uv_free_func free_func) {
+ if (malloc_func == NULL || realloc_func == NULL ||
+ calloc_func == NULL || free_func == NULL) {
+ return UV_EINVAL;
+ }
+
+ uv__allocator.local_malloc = malloc_func;
+ uv__allocator.local_realloc = realloc_func;
+ uv__allocator.local_calloc = calloc_func;
+ uv__allocator.local_free = free_func;
+
+ return 0;
+}
+
+#define XX(uc, lc) case UV_##uc: return sizeof(uv_##lc##_t);
+
+size_t uv_handle_size(uv_handle_type type) {
+ switch (type) {
+ UV_HANDLE_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+size_t uv_req_size(uv_req_type type) {
+ switch(type) {
+ UV_REQ_TYPE_MAP(XX)
+ default:
+ return -1;
+ }
+}
+
+#undef XX
+
+
+size_t uv_loop_size(void) {
+ return sizeof(uv_loop_t);
+}
+
+
+uv_buf_t uv_buf_init(char* base, unsigned int len) {
+ uv_buf_t buf;
+ buf.base = base;
+ buf.len = len;
+ return buf;
+}
+
+
+static const char* uv__unknown_err_code(int err) {
+ char buf[32];
+ char* copy;
+
+ snprintf(buf, sizeof(buf), "Unknown system error %d", err);
+ copy = uv__strdup(buf);
+
+ return copy != NULL ? copy : "Unknown system error";
+}
+
+
+#define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name;
+const char* uv_err_name(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_ERR_NAME_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_ERR_NAME_GEN
+
+
+#define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg;
+const char* uv_strerror(int err) {
+ switch (err) {
+ UV_ERRNO_MAP(UV_STRERROR_GEN)
+ }
+ return uv__unknown_err_code(err);
+}
+#undef UV_STRERROR_GEN
+
+
+int uv_ip4_addr(const char* ip, int port, struct sockaddr_in* addr) {
+ memset(addr, 0, sizeof(*addr));
+ addr->sin_family = AF_INET;
+ addr->sin_port = htons(port);
+ return uv_inet_pton(AF_INET, ip, &(addr->sin_addr.s_addr));
+}
+
+
+int uv_ip6_addr(const char* ip, int port, struct sockaddr_in6* addr) {
+ char address_part[40];
+ size_t address_part_size;
+ const char* zone_index;
+
+ memset(addr, 0, sizeof(*addr));
+ addr->sin6_family = AF_INET6;
+ addr->sin6_port = htons(port);
+
+ zone_index = strchr(ip, '%');
+ if (zone_index != NULL) {
+ address_part_size = zone_index - ip;
+ if (address_part_size >= sizeof(address_part))
+ address_part_size = sizeof(address_part) - 1;
+
+ memcpy(address_part, ip, address_part_size);
+ address_part[address_part_size] = '\0';
+ ip = address_part;
+
+ zone_index++; /* skip '%' */
+ /* NOTE: unknown interface (id=0) is silently ignored */
+#ifdef _WIN32
+ addr->sin6_scope_id = atoi(zone_index);
+#else
+ addr->sin6_scope_id = if_nametoindex(zone_index);
+#endif
+ }
+
+ return uv_inet_pton(AF_INET6, ip, &addr->sin6_addr);
+}
+
+
+int uv_ip4_name(const struct sockaddr_in* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET, &src->sin_addr, dst, size);
+}
+
+
+int uv_ip6_name(const struct sockaddr_in6* src, char* dst, size_t size) {
+ return uv_inet_ntop(AF_INET6, &src->sin6_addr, dst, size);
+}
+
+
+int uv_tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int flags) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_bind(handle, addr, addrlen, flags);
+}
+
+
+int uv_tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ uv_connect_cb cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_TCP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__tcp_connect(req, handle, addr, addrlen, cb);
+}
+
+
+int uv_udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ uv_udp_send_cb send_cb) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+}
+
+
+int uv_udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr) {
+ unsigned int addrlen;
+
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
+ else if (addr->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
+ else
+ return UV_EINVAL;
+
+ return uv__udp_try_send(handle, bufs, nbufs, addr, addrlen);
+}
+
+
+int uv_udp_recv_start(uv_udp_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ if (handle->type != UV_UDP || alloc_cb == NULL || recv_cb == NULL)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_start(handle, alloc_cb, recv_cb);
+}
+
+
+int uv_udp_recv_stop(uv_udp_t* handle) {
+ if (handle->type != UV_UDP)
+ return UV_EINVAL;
+ else
+ return uv__udp_recv_stop(handle);
+}
+
+
+void uv_walk(uv_loop_t* loop, uv_walk_cb walk_cb, void* arg) {
+ QUEUE queue;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ QUEUE_MOVE(&loop->handle_queue, &queue);
+ while (!QUEUE_EMPTY(&queue)) {
+ q = QUEUE_HEAD(&queue);
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ QUEUE_REMOVE(q);
+ QUEUE_INSERT_TAIL(&loop->handle_queue, q);
+
+ if (h->flags & UV__HANDLE_INTERNAL) continue;
+ walk_cb(h, arg);
+ }
+}
+
+
+static void uv__print_handles(uv_loop_t* loop, int only_active, FILE* stream) {
+ const char* type;
+ QUEUE* q;
+ uv_handle_t* h;
+
+ if (loop == NULL)
+ loop = uv_default_loop();
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+
+ if (only_active && !uv__is_active(h))
+ continue;
+
+ switch (h->type) {
+#define X(uc, lc) case UV_##uc: type = #lc; break;
+ UV_HANDLE_TYPE_MAP(X)
+#undef X
+ default: type = "<unknown>";
+ }
+
+ fprintf(stream,
+ "[%c%c%c] %-8s %p\n",
+ "R-"[!(h->flags & UV__HANDLE_REF)],
+ "A-"[!(h->flags & UV__HANDLE_ACTIVE)],
+ "I-"[!(h->flags & UV__HANDLE_INTERNAL)],
+ type,
+ (void*)h);
+ }
+}
+
+
+void uv_print_all_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 0, stream);
+}
+
+
+void uv_print_active_handles(uv_loop_t* loop, FILE* stream) {
+ uv__print_handles(loop, 1, stream);
+}
+
+
+void uv_ref(uv_handle_t* handle) {
+ uv__handle_ref(handle);
+}
+
+
+void uv_unref(uv_handle_t* handle) {
+ uv__handle_unref(handle);
+}
+
+
+int uv_has_ref(const uv_handle_t* handle) {
+ return uv__has_ref(handle);
+}
+
+
+void uv_stop(uv_loop_t* loop) {
+ loop->stop_flag = 1;
+}
+
+
+uint64_t uv_now(const uv_loop_t* loop) {
+ return loop->time;
+}
+
+
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs) {
+ unsigned int i;
+ size_t bytes;
+
+ bytes = 0;
+ for (i = 0; i < nbufs; i++)
+ bytes += (size_t) bufs[i].len;
+
+ return bytes;
+}
+
+int uv_recv_buffer_size(uv_handle_t* handle, int* value) {
+ return uv__socket_sockopt(handle, SO_RCVBUF, value);
+}
+
+int uv_send_buffer_size(uv_handle_t* handle, int *value) {
+ return uv__socket_sockopt(handle, SO_SNDBUF, value);
+}
+
+int uv_fs_event_getpath(uv_fs_event_t* handle, char* buffer, size_t* size) {
+ size_t required_len;
+
+ if (!uv__is_active(handle)) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ required_len = strlen(handle->path);
+ if (required_len >= *size) {
+ *size = required_len + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, handle->path, required_len);
+ *size = required_len;
+ buffer[required_len] = '\0';
+
+ return 0;
+}
+
+/* The windows implementation does not have the same structure layout as
+ * the unix implementation (nbufs is not directly inside req but is
+ * contained in a nested union/struct) so this function locates it.
+*/
+static unsigned int* uv__get_nbufs(uv_fs_t* req) {
+#ifdef _WIN32
+ return &req->fs.info.nbufs;
+#else
+ return &req->nbufs;
+#endif
+}
+
+/* uv_fs_scandir() uses the system allocator to allocate memory on non-Windows
+ * systems. So, the memory should be released using free(). On Windows,
+ * uv__malloc() is used, so use uv__free() to free memory.
+*/
+#ifdef _WIN32
+# define uv__fs_scandir_free uv__free
+#else
+# define uv__fs_scandir_free free
+#endif
+
+void uv__fs_scandir_cleanup(uv_fs_t* req) {
+ uv__dirent_t** dents;
+
+ unsigned int* nbufs = uv__get_nbufs(req);
+
+ dents = req->ptr;
+ if (*nbufs > 0 && *nbufs != (unsigned int) req->result)
+ (*nbufs)--;
+ for (; *nbufs < (unsigned int) req->result; (*nbufs)++)
+ uv__fs_scandir_free(dents[*nbufs]);
+
+ uv__fs_scandir_free(req->ptr);
+ req->ptr = NULL;
+}
+
+
+int uv_fs_scandir_next(uv_fs_t* req, uv_dirent_t* ent) {
+ uv__dirent_t** dents;
+ uv__dirent_t* dent;
+ unsigned int* nbufs;
+
+ /* Check to see if req passed */
+ if (req->result < 0)
+ return req->result;
+
+ /* Ptr will be null if req was canceled or no files found */
+ if (!req->ptr)
+ return UV_EOF;
+
+ nbufs = uv__get_nbufs(req);
+ assert(nbufs);
+
+ dents = req->ptr;
+
+ /* Free previous entity */
+ if (*nbufs > 0)
+ uv__fs_scandir_free(dents[*nbufs - 1]);
+
+ /* End was already reached */
+ if (*nbufs == (unsigned int) req->result) {
+ uv__fs_scandir_free(dents);
+ req->ptr = NULL;
+ return UV_EOF;
+ }
+
+ dent = dents[(*nbufs)++];
+
+ ent->name = dent->d_name;
+#ifdef HAVE_DIRENT_TYPES
+ switch (dent->d_type) {
+ case UV__DT_DIR:
+ ent->type = UV_DIRENT_DIR;
+ break;
+ case UV__DT_FILE:
+ ent->type = UV_DIRENT_FILE;
+ break;
+ case UV__DT_LINK:
+ ent->type = UV_DIRENT_LINK;
+ break;
+ case UV__DT_FIFO:
+ ent->type = UV_DIRENT_FIFO;
+ break;
+ case UV__DT_SOCKET:
+ ent->type = UV_DIRENT_SOCKET;
+ break;
+ case UV__DT_CHAR:
+ ent->type = UV_DIRENT_CHAR;
+ break;
+ case UV__DT_BLOCK:
+ ent->type = UV_DIRENT_BLOCK;
+ break;
+ default:
+ ent->type = UV_DIRENT_UNKNOWN;
+ }
+#else
+ ent->type = UV_DIRENT_UNKNOWN;
+#endif
+
+ return 0;
+}
+
+
+int uv_loop_configure(uv_loop_t* loop, uv_loop_option option, ...) {
+ va_list ap;
+ int err;
+
+ va_start(ap, option);
+ /* Any platform-agnostic options should be handled here. */
+ err = uv__loop_configure(loop, option, ap);
+ va_end(ap);
+
+ return err;
+}
+
+
+static uv_loop_t default_loop_struct;
+static uv_loop_t* default_loop_ptr;
+
+
+uv_loop_t* uv_default_loop(void) {
+ if (default_loop_ptr != NULL)
+ return default_loop_ptr;
+
+ if (uv_loop_init(&default_loop_struct))
+ return NULL;
+
+ default_loop_ptr = &default_loop_struct;
+ return default_loop_ptr;
+}
+
+
+uv_loop_t* uv_loop_new(void) {
+ uv_loop_t* loop;
+
+ loop = uv__malloc(sizeof(*loop));
+ if (loop == NULL)
+ return NULL;
+
+ if (uv_loop_init(loop)) {
+ uv__free(loop);
+ return NULL;
+ }
+
+ return loop;
+}
+
+
+int uv_loop_close(uv_loop_t* loop) {
+ QUEUE* q;
+ uv_handle_t* h;
+#ifndef NDEBUG
+ void* saved_data;
+#endif
+
+ if (!QUEUE_EMPTY(&(loop)->active_reqs))
+ return UV_EBUSY;
+
+ QUEUE_FOREACH(q, &loop->handle_queue) {
+ h = QUEUE_DATA(q, uv_handle_t, handle_queue);
+ if (!(h->flags & UV__HANDLE_INTERNAL))
+ return UV_EBUSY;
+ }
+
+ uv__loop_close(loop);
+
+#ifndef NDEBUG
+ saved_data = loop->data;
+ memset(loop, -1, sizeof(*loop));
+ loop->data = saved_data;
+#endif
+ if (loop == default_loop_ptr)
+ default_loop_ptr = NULL;
+
+ return 0;
+}
+
+
+void uv_loop_delete(uv_loop_t* loop) {
+ uv_loop_t* default_loop;
+ int err;
+
+ default_loop = default_loop_ptr;
+
+ err = uv_loop_close(loop);
+ (void) err; /* Squelch compiler warnings. */
+ assert(err == 0);
+ if (loop != default_loop)
+ uv__free(loop);
+}
diff --git a/Utilities/cmlibuv/src/uv-common.h b/Utilities/cmlibuv/src/uv-common.h
new file mode 100644
index 000000000..781a8559d
--- /dev/null
+++ b/Utilities/cmlibuv/src/uv-common.h
@@ -0,0 +1,254 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+/*
+ * This file is private to libuv. It provides common functionality to both
+ * Windows and Unix backends.
+ */
+
+#ifndef UV_COMMON_H_
+#define UV_COMMON_H_
+
+#include <assert.h>
+#include <stdarg.h>
+#include <stddef.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#include "uv.h"
+#include "tree.h"
+#include "queue.h"
+
+#if !defined(snprintf) && defined(_MSC_VER) && _MSC_VER < 1900
+extern int snprintf(char*, size_t, const char*, ...);
+#endif
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+#define container_of(ptr, type, member) \
+ ((type *) ((char *) (ptr) - offsetof(type, member)))
+
+#define STATIC_ASSERT(expr) \
+ void uv__static_assert(int static_assert_failed[1 - 2 * !(expr)])
+
+#ifndef _WIN32
+enum {
+ UV__SIGNAL_ONE_SHOT = 0x80000, /* On signal reception remove sighandler */
+ UV__HANDLE_INTERNAL = 0x8000,
+ UV__HANDLE_ACTIVE = 0x4000,
+ UV__HANDLE_REF = 0x2000,
+ UV__HANDLE_CLOSING = 0 /* no-op on unix */
+};
+#else
+# define UV__SIGNAL_ONE_SHOT_DISPATCHED 0x200
+# define UV__SIGNAL_ONE_SHOT 0x100
+# define UV__HANDLE_INTERNAL 0x80
+# define UV__HANDLE_ACTIVE 0x40
+# define UV__HANDLE_REF 0x20
+# define UV__HANDLE_CLOSING 0x01
+#endif
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap);
+
+void uv__loop_close(uv_loop_t* loop);
+
+int uv__tcp_bind(uv_tcp_t* tcp,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb);
+
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags);
+
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb);
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen);
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloccb,
+ uv_udp_recv_cb recv_cb);
+
+int uv__udp_recv_stop(uv_udp_t* handle);
+
+void uv__fs_poll_close(uv_fs_poll_t* handle);
+
+int uv__getaddrinfo_translate_error(int sys_err); /* EAI_* error. */
+
+void uv__work_submit(uv_loop_t* loop,
+ struct uv__work *w,
+ void (*work)(struct uv__work *w),
+ void (*done)(struct uv__work *w, int status));
+
+void uv__work_done(uv_async_t* handle);
+
+size_t uv__count_bufs(const uv_buf_t bufs[], unsigned int nbufs);
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value);
+
+void uv__fs_scandir_cleanup(uv_fs_t* req);
+
+#define uv__has_active_reqs(loop) \
+ (QUEUE_EMPTY(&(loop)->active_reqs) == 0)
+
+#define uv__req_register(loop, req) \
+ do { \
+ QUEUE_INSERT_TAIL(&(loop)->active_reqs, &(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__req_unregister(loop, req) \
+ do { \
+ assert(uv__has_active_reqs(loop)); \
+ QUEUE_REMOVE(&(req)->active_queue); \
+ } \
+ while (0)
+
+#define uv__has_active_handles(loop) \
+ ((loop)->active_handles > 0)
+
+#define uv__active_handle_add(h) \
+ do { \
+ (h)->loop->active_handles++; \
+ } \
+ while (0)
+
+#define uv__active_handle_rm(h) \
+ do { \
+ (h)->loop->active_handles--; \
+ } \
+ while (0)
+
+#define uv__is_active(h) \
+ (((h)->flags & UV__HANDLE_ACTIVE) != 0)
+
+#define uv__is_closing(h) \
+ (((h)->flags & (UV_CLOSING | UV_CLOSED)) != 0)
+
+#define uv__handle_start(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) break; \
+ (h)->flags |= UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_stop(h) \
+ do { \
+ assert(((h)->flags & UV__HANDLE_CLOSING) == 0); \
+ if (((h)->flags & UV__HANDLE_ACTIVE) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_ACTIVE; \
+ if (((h)->flags & UV__HANDLE_REF) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__handle_ref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) != 0) break; \
+ (h)->flags |= UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_add(h); \
+ } \
+ while (0)
+
+#define uv__handle_unref(h) \
+ do { \
+ if (((h)->flags & UV__HANDLE_REF) == 0) break; \
+ (h)->flags &= ~UV__HANDLE_REF; \
+ if (((h)->flags & UV__HANDLE_CLOSING) != 0) break; \
+ if (((h)->flags & UV__HANDLE_ACTIVE) != 0) uv__active_handle_rm(h); \
+ } \
+ while (0)
+
+#define uv__has_ref(h) \
+ (((h)->flags & UV__HANDLE_REF) != 0)
+
+#if defined(_WIN32)
+# define uv__handle_platform_init(h) ((h)->u.fd = -1)
+#else
+# define uv__handle_platform_init(h) ((h)->next_closing = NULL)
+#endif
+
+#define uv__handle_init(loop_, h, type_) \
+ do { \
+ (h)->loop = (loop_); \
+ (h)->type = (type_); \
+ (h)->flags = UV__HANDLE_REF; /* Ref the loop when active. */ \
+ QUEUE_INSERT_TAIL(&(loop_)->handle_queue, &(h)->handle_queue); \
+ uv__handle_platform_init(h); \
+ } \
+ while (0)
+
+/* Note: uses an open-coded version of SET_REQ_SUCCESS() because of
+ * a circular dependency between src/uv-common.h and src/win/internal.h.
+ */
+#if defined(_WIN32)
+# define UV_REQ_INIT(req, typ) \
+ do { \
+ (req)->type = (typ); \
+ (req)->u.io.overlapped.Internal = 0; /* SET_REQ_SUCCESS() */ \
+ } \
+ while (0)
+#else
+# define UV_REQ_INIT(req, typ) \
+ do { \
+ (req)->type = (typ); \
+ } \
+ while (0)
+#endif
+
+#define uv__req_init(loop, req, typ) \
+ do { \
+ UV_REQ_INIT(req, typ); \
+ uv__req_register(loop, req); \
+ } \
+ while (0)
+
+/* Allocator prototypes */
+void *uv__calloc(size_t count, size_t size);
+char *uv__strdup(const char* s);
+char *uv__strndup(const char* s, size_t n);
+void* uv__malloc(size_t size);
+void uv__free(void* ptr);
+void* uv__realloc(void* ptr, size_t size);
+
+#endif /* UV_COMMON_H_ */
diff --git a/Utilities/cmlibuv/src/version.c b/Utilities/cmlibuv/src/version.c
new file mode 100644
index 000000000..686dedd98
--- /dev/null
+++ b/Utilities/cmlibuv/src/version.c
@@ -0,0 +1,45 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+
+#define UV_STRINGIFY(v) UV_STRINGIFY_HELPER(v)
+#define UV_STRINGIFY_HELPER(v) #v
+
+#define UV_VERSION_STRING_BASE UV_STRINGIFY(UV_VERSION_MAJOR) "." \
+ UV_STRINGIFY(UV_VERSION_MINOR) "." \
+ UV_STRINGIFY(UV_VERSION_PATCH)
+
+#if UV_VERSION_IS_RELEASE
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE
+#else
+# define UV_VERSION_STRING UV_VERSION_STRING_BASE "-" UV_VERSION_SUFFIX
+#endif
+
+
+unsigned int uv_version(void) {
+ return UV_VERSION_HEX;
+}
+
+
+const char* uv_version_string(void) {
+ return UV_VERSION_STRING;
+}
diff --git a/Utilities/cmlibuv/src/win/async.c b/Utilities/cmlibuv/src/win/async.c
new file mode 100644
index 000000000..0b636ed1e
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/async.c
@@ -0,0 +1,98 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "atomicops-inl.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ !handle->async_sent) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+int uv_async_init(uv_loop_t* loop, uv_async_t* handle, uv_async_cb async_cb) {
+ uv_req_t* req;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_ASYNC);
+ handle->async_sent = 0;
+ handle->async_cb = async_cb;
+
+ req = &handle->async_req;
+ UV_REQ_INIT(req, UV_WAKEUP);
+ req->data = handle;
+
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle) {
+ if (!((uv_async_t*)handle)->async_sent) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ uv__handle_closing(handle);
+}
+
+
+int uv_async_send(uv_async_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->type != UV_ASYNC) {
+ /* Can't set errno because that's not thread-safe. */
+ return -1;
+ }
+
+ /* The user should make sure never to call uv_async_send to a closing */
+ /* or closed handle. */
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+
+ if (!uv__atomic_exchange_set(&handle->async_sent)) {
+ POST_COMPLETION_FOR_REQ(loop, &handle->async_req);
+ }
+
+ return 0;
+}
+
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_ASYNC);
+ assert(req->type == UV_WAKEUP);
+
+ handle->async_sent = 0;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ } else if (handle->async_cb != NULL) {
+ handle->async_cb(handle);
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/atomicops-inl.h b/Utilities/cmlibuv/src/win/atomicops-inl.h
new file mode 100644
index 000000000..6d8126f69
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/atomicops-inl.h
@@ -0,0 +1,57 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_ATOMICOPS_INL_H_
+#define UV_WIN_ATOMICOPS_INL_H_
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Atomic set operation on char */
+#ifdef _MSC_VER /* MSVC */
+
+/* _InterlockedOr8 is supported by MSVC on x32 and x64. It is slightly less */
+/* efficient than InterlockedExchange, but InterlockedExchange8 does not */
+/* exist, and interlocked operations on larger targets might require the */
+/* target to be aligned. */
+#pragma intrinsic(_InterlockedOr8)
+
+static char INLINE uv__atomic_exchange_set(char volatile* target) {
+ return _InterlockedOr8(target, 1);
+}
+
+#else /* GCC */
+
+/* Mingw-32 version, hopefully this works for 64-bit gcc as well. */
+static inline char uv__atomic_exchange_set(char volatile* target) {
+ const char one = 1;
+ char old_value;
+ __asm__ __volatile__ ("lock xchgb %0, %1\n\t"
+ : "=r"(old_value), "=m"(*target)
+ : "0"(one), "m"(*target)
+ : "memory");
+ return old_value;
+}
+
+#endif
+
+#endif /* UV_WIN_ATOMICOPS_INL_H_ */
diff --git a/Utilities/cmlibuv/src/win/core.c b/Utilities/cmlibuv/src/win/core.c
new file mode 100644
index 000000000..9ed4e824c
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/core.c
@@ -0,0 +1,605 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+#include <crtdbg.h>
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "queue.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+/* uv_once initialization guards */
+static uv_once_t uv_init_guard_ = UV_ONCE_INIT;
+
+
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+/* Our crt debug report handler allows us to temporarily disable asserts
+ * just for the current thread.
+ */
+
+UV_THREAD_LOCAL int uv__crt_assert_enabled = TRUE;
+
+static int uv__crt_dbg_report_handler(int report_type, char *message, int *ret_val) {
+ if (uv__crt_assert_enabled || report_type != _CRT_ASSERT)
+ return FALSE;
+
+ if (ret_val) {
+ /* Set ret_val to 0 to continue with normal execution.
+ * Set ret_val to 1 to trigger a breakpoint.
+ */
+
+ if(IsDebuggerPresent())
+ *ret_val = 1;
+ else
+ *ret_val = 0;
+ }
+
+ /* Don't call _CrtDbgReport. */
+ return TRUE;
+}
+#else
+UV_THREAD_LOCAL int uv__crt_assert_enabled = FALSE;
+#endif
+
+
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+static void uv__crt_invalid_parameter_handler(const wchar_t* expression,
+ const wchar_t* function, const wchar_t * file, unsigned int line,
+ uintptr_t reserved) {
+ /* No-op. */
+}
+#endif
+
+static uv_loop_t** uv__loops;
+static int uv__loops_size;
+static int uv__loops_capacity;
+#define UV__LOOPS_CHUNK_SIZE 8
+static uv_mutex_t uv__loops_lock;
+
+static void uv__loops_init(void) {
+ uv_mutex_init(&uv__loops_lock);
+}
+
+static int uv__loops_add(uv_loop_t* loop) {
+ uv_loop_t** new_loops;
+ int new_capacity, i;
+
+ uv_mutex_lock(&uv__loops_lock);
+
+ if (uv__loops_size == uv__loops_capacity) {
+ new_capacity = uv__loops_capacity + UV__LOOPS_CHUNK_SIZE;
+ new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * new_capacity);
+ if (!new_loops)
+ goto failed_loops_realloc;
+ uv__loops = new_loops;
+ for (i = uv__loops_capacity; i < new_capacity; ++i)
+ uv__loops[i] = NULL;
+ uv__loops_capacity = new_capacity;
+ }
+ uv__loops[uv__loops_size] = loop;
+ ++uv__loops_size;
+
+ uv_mutex_unlock(&uv__loops_lock);
+ return 0;
+
+failed_loops_realloc:
+ uv_mutex_unlock(&uv__loops_lock);
+ return ERROR_OUTOFMEMORY;
+}
+
+static void uv__loops_remove(uv_loop_t* loop) {
+ int loop_index;
+ int smaller_capacity;
+ uv_loop_t** new_loops;
+
+ uv_mutex_lock(&uv__loops_lock);
+
+ for (loop_index = 0; loop_index < uv__loops_size; ++loop_index) {
+ if (uv__loops[loop_index] == loop)
+ break;
+ }
+ /* If loop was not found, ignore */
+ if (loop_index == uv__loops_size)
+ goto loop_removed;
+
+ uv__loops[loop_index] = uv__loops[uv__loops_size - 1];
+ uv__loops[uv__loops_size - 1] = NULL;
+ --uv__loops_size;
+
+ if (uv__loops_size == 0) {
+ uv__loops_capacity = 0;
+ uv__free(uv__loops);
+ uv__loops = NULL;
+ goto loop_removed;
+ }
+
+ /* If we didn't grow to big skip downsizing */
+ if (uv__loops_capacity < 4 * UV__LOOPS_CHUNK_SIZE)
+ goto loop_removed;
+
+ /* Downsize only if more than half of buffer is free */
+ smaller_capacity = uv__loops_capacity / 2;
+ if (uv__loops_size >= smaller_capacity)
+ goto loop_removed;
+ new_loops = uv__realloc(uv__loops, sizeof(uv_loop_t*) * smaller_capacity);
+ if (!new_loops)
+ goto loop_removed;
+ uv__loops = new_loops;
+ uv__loops_capacity = smaller_capacity;
+
+loop_removed:
+ uv_mutex_unlock(&uv__loops_lock);
+}
+
+void uv__wake_all_loops(void) {
+ int i;
+ uv_loop_t* loop;
+
+ uv_mutex_lock(&uv__loops_lock);
+ for (i = 0; i < uv__loops_size; ++i) {
+ loop = uv__loops[i];
+ assert(loop);
+ if (loop->iocp != INVALID_HANDLE_VALUE)
+ PostQueuedCompletionStatus(loop->iocp, 0, 0, NULL);
+ }
+ uv_mutex_unlock(&uv__loops_lock);
+}
+
+static void uv_init(void) {
+ /* Tell Windows that we will handle critical errors. */
+ SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX |
+ SEM_NOOPENFILEERRORBOX);
+
+ /* Tell the CRT to not exit the application when an invalid parameter is
+ * passed. The main issue is that invalid FDs will trigger this behavior.
+ */
+#if !defined(__MINGW32__) || __MSVCRT_VERSION__ >= 0x800
+ _set_invalid_parameter_handler(uv__crt_invalid_parameter_handler);
+#endif
+
+ /* We also need to setup our debug report handler because some CRT
+ * functions (eg _get_osfhandle) raise an assert when called with invalid
+ * FDs even though they return the proper error code in the release build.
+ */
+#if defined(_DEBUG) && (defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR))
+ _CrtSetReportHook(uv__crt_dbg_report_handler);
+#endif
+
+ /* Initialize tracking of all uv loops */
+ uv__loops_init();
+
+ /* Fetch winapi function pointers. This must be done first because other
+ * initialization code might need these function pointers to be loaded.
+ */
+ uv_winapi_init();
+
+ /* Initialize winsock */
+ uv_winsock_init();
+
+ /* Initialize FS */
+ uv_fs_init();
+
+ /* Initialize signal stuff */
+ uv_signals_init();
+
+ /* Initialize console */
+ uv_console_init();
+
+ /* Initialize utilities */
+ uv__util_init();
+
+ /* Initialize system wakeup detection */
+ uv__init_detect_system_wakeup();
+}
+
+
+int uv_loop_init(uv_loop_t* loop) {
+ int err;
+
+ /* Initialize libuv itself first */
+ uv__once_init();
+
+ /* Create an I/O completion port */
+ loop->iocp = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 1);
+ if (loop->iocp == NULL)
+ return uv_translate_sys_error(GetLastError());
+
+ /* To prevent uninitialized memory access, loop->time must be initialized
+ * to zero before calling uv_update_time for the first time.
+ */
+ loop->time = 0;
+ uv_update_time(loop);
+
+ QUEUE_INIT(&loop->wq);
+ QUEUE_INIT(&loop->handle_queue);
+ QUEUE_INIT(&loop->active_reqs);
+ loop->active_handles = 0;
+
+ loop->pending_reqs_tail = NULL;
+
+ loop->endgame_handles = NULL;
+
+ RB_INIT(&loop->timers);
+
+ loop->check_handles = NULL;
+ loop->prepare_handles = NULL;
+ loop->idle_handles = NULL;
+
+ loop->next_prepare_handle = NULL;
+ loop->next_check_handle = NULL;
+ loop->next_idle_handle = NULL;
+
+ memset(&loop->poll_peer_sockets, 0, sizeof loop->poll_peer_sockets);
+
+ loop->active_tcp_streams = 0;
+ loop->active_udp_streams = 0;
+
+ loop->timer_counter = 0;
+ loop->stop_flag = 0;
+
+ err = uv_mutex_init(&loop->wq_mutex);
+ if (err)
+ goto fail_mutex_init;
+
+ err = uv_async_init(loop, &loop->wq_async, uv__work_done);
+ if (err)
+ goto fail_async_init;
+
+ uv__handle_unref(&loop->wq_async);
+ loop->wq_async.flags |= UV__HANDLE_INTERNAL;
+
+ err = uv__loops_add(loop);
+ if (err)
+ goto fail_async_init;
+
+ return 0;
+
+fail_async_init:
+ uv_mutex_destroy(&loop->wq_mutex);
+
+fail_mutex_init:
+ CloseHandle(loop->iocp);
+ loop->iocp = INVALID_HANDLE_VALUE;
+
+ return err;
+}
+
+
+void uv__once_init(void) {
+ uv_once(&uv_init_guard_, uv_init);
+}
+
+
+void uv__loop_close(uv_loop_t* loop) {
+ size_t i;
+
+ uv__loops_remove(loop);
+
+ /* close the async handle without needing an extra loop iteration */
+ assert(!loop->wq_async.async_sent);
+ loop->wq_async.close_cb = NULL;
+ uv__handle_closing(&loop->wq_async);
+ uv__handle_close(&loop->wq_async);
+
+ for (i = 0; i < ARRAY_SIZE(loop->poll_peer_sockets); i++) {
+ SOCKET sock = loop->poll_peer_sockets[i];
+ if (sock != 0 && sock != INVALID_SOCKET)
+ closesocket(sock);
+ }
+
+ uv_mutex_lock(&loop->wq_mutex);
+ assert(QUEUE_EMPTY(&loop->wq) && "thread pool work queue not empty!");
+ assert(!uv__has_active_reqs(loop));
+ uv_mutex_unlock(&loop->wq_mutex);
+ uv_mutex_destroy(&loop->wq_mutex);
+
+ CloseHandle(loop->iocp);
+}
+
+
+int uv__loop_configure(uv_loop_t* loop, uv_loop_option option, va_list ap) {
+ return UV_ENOSYS;
+}
+
+
+int uv_backend_fd(const uv_loop_t* loop) {
+ return -1;
+}
+
+
+int uv_loop_fork(uv_loop_t* loop) {
+ return UV_ENOSYS;
+}
+
+
+int uv_backend_timeout(const uv_loop_t* loop) {
+ if (loop->stop_flag != 0)
+ return 0;
+
+ if (!uv__has_active_handles(loop) && !uv__has_active_reqs(loop))
+ return 0;
+
+ if (loop->pending_reqs_tail)
+ return 0;
+
+ if (loop->endgame_handles)
+ return 0;
+
+ if (loop->idle_handles)
+ return 0;
+
+ return uv__next_timeout(loop);
+}
+
+
+static void uv_poll(uv_loop_t* loop, DWORD timeout) {
+ DWORD bytes;
+ ULONG_PTR key;
+ OVERLAPPED* overlapped;
+ uv_req_t* req;
+ int repeat;
+ uint64_t timeout_time;
+
+ timeout_time = loop->time + timeout;
+
+ for (repeat = 0; ; repeat++) {
+ GetQueuedCompletionStatus(loop->iocp,
+ &bytes,
+ &key,
+ &overlapped,
+ timeout);
+
+ if (overlapped) {
+ /* Package was dequeued */
+ req = uv_overlapped_to_req(overlapped);
+ uv_insert_pending_req(loop, req);
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatus");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout target time is reached.
+ */
+ uv_update_time(loop);
+ if (timeout_time > loop->time) {
+ timeout = (DWORD)(timeout_time - loop->time);
+ /* The first call to GetQueuedCompletionStatus should return very
+ * close to the target time and the second should reach it, but
+ * this is not stated in the documentation. To make sure a busy
+ * loop cannot happen, the timeout is increased exponentially
+ * starting on the third round.
+ */
+ timeout += repeat ? (1 << (repeat - 1)) : 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+
+static void uv_poll_ex(uv_loop_t* loop, DWORD timeout) {
+ BOOL success;
+ uv_req_t* req;
+ OVERLAPPED_ENTRY overlappeds[128];
+ ULONG count;
+ ULONG i;
+ int repeat;
+ uint64_t timeout_time;
+
+ timeout_time = loop->time + timeout;
+
+ for (repeat = 0; ; repeat++) {
+ success = pGetQueuedCompletionStatusEx(loop->iocp,
+ overlappeds,
+ ARRAY_SIZE(overlappeds),
+ &count,
+ timeout,
+ FALSE);
+
+ if (success) {
+ for (i = 0; i < count; i++) {
+ /* Package was dequeued, but see if it is not a empty package
+ * meant only to wake us up.
+ */
+ if (overlappeds[i].lpOverlapped) {
+ req = uv_overlapped_to_req(overlappeds[i].lpOverlapped);
+ uv_insert_pending_req(loop, req);
+ }
+ }
+
+ /* Some time might have passed waiting for I/O,
+ * so update the loop time here.
+ */
+ uv_update_time(loop);
+ } else if (GetLastError() != WAIT_TIMEOUT) {
+ /* Serious error */
+ uv_fatal_error(GetLastError(), "GetQueuedCompletionStatusEx");
+ } else if (timeout > 0) {
+ /* GetQueuedCompletionStatus can occasionally return a little early.
+ * Make sure that the desired timeout target time is reached.
+ */
+ uv_update_time(loop);
+ if (timeout_time > loop->time) {
+ timeout = (DWORD)(timeout_time - loop->time);
+ /* The first call to GetQueuedCompletionStatus should return very
+ * close to the target time and the second should reach it, but
+ * this is not stated in the documentation. To make sure a busy
+ * loop cannot happen, the timeout is increased exponentially
+ * starting on the third round.
+ */
+ timeout += repeat ? (1 << (repeat - 1)) : 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+
+static int uv__loop_alive(const uv_loop_t* loop) {
+ return loop->active_handles > 0 ||
+ !QUEUE_EMPTY(&loop->active_reqs) ||
+ loop->endgame_handles != NULL;
+}
+
+
+int uv_loop_alive(const uv_loop_t* loop) {
+ return uv__loop_alive(loop);
+}
+
+
+int uv_run(uv_loop_t *loop, uv_run_mode mode) {
+ DWORD timeout;
+ int r;
+ int ran_pending;
+ void (*poll)(uv_loop_t* loop, DWORD timeout);
+
+ if (pGetQueuedCompletionStatusEx)
+ poll = &uv_poll_ex;
+ else
+ poll = &uv_poll;
+
+ r = uv__loop_alive(loop);
+ if (!r)
+ uv_update_time(loop);
+
+ while (r != 0 && loop->stop_flag == 0) {
+ uv_update_time(loop);
+ uv_process_timers(loop);
+
+ ran_pending = uv_process_reqs(loop);
+ uv_idle_invoke(loop);
+ uv_prepare_invoke(loop);
+
+ timeout = 0;
+ if ((mode == UV_RUN_ONCE && !ran_pending) || mode == UV_RUN_DEFAULT)
+ timeout = uv_backend_timeout(loop);
+
+ (*poll)(loop, timeout);
+
+ uv_check_invoke(loop);
+ uv_process_endgames(loop);
+
+ if (mode == UV_RUN_ONCE) {
+ /* UV_RUN_ONCE implies forward progress: at least one callback must have
+ * been invoked when it returns. uv__io_poll() can return without doing
+ * I/O (meaning: no callbacks) when its timeout expires - which means we
+ * have pending timers that satisfy the forward progress constraint.
+ *
+ * UV_RUN_NOWAIT makes no guarantees about progress so it's omitted from
+ * the check.
+ */
+ uv_process_timers(loop);
+ }
+
+ r = uv__loop_alive(loop);
+ if (mode == UV_RUN_ONCE || mode == UV_RUN_NOWAIT)
+ break;
+ }
+
+ /* The if statement lets the compiler compile it to a conditional store.
+ * Avoids dirtying a cache line.
+ */
+ if (loop->stop_flag != 0)
+ loop->stop_flag = 0;
+
+ return r;
+}
+
+
+int uv_fileno(const uv_handle_t* handle, uv_os_fd_t* fd) {
+ uv_os_fd_t fd_out;
+
+ switch (handle->type) {
+ case UV_TCP:
+ fd_out = (uv_os_fd_t)((uv_tcp_t*) handle)->socket;
+ break;
+
+ case UV_NAMED_PIPE:
+ fd_out = ((uv_pipe_t*) handle)->handle;
+ break;
+
+ case UV_TTY:
+ fd_out = ((uv_tty_t*) handle)->handle;
+ break;
+
+ case UV_UDP:
+ fd_out = (uv_os_fd_t)((uv_udp_t*) handle)->socket;
+ break;
+
+ case UV_POLL:
+ fd_out = (uv_os_fd_t)((uv_poll_t*) handle)->socket;
+ break;
+
+ default:
+ return UV_EINVAL;
+ }
+
+ if (uv_is_closing(handle) || fd_out == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ *fd = fd_out;
+ return 0;
+}
+
+
+int uv__socket_sockopt(uv_handle_t* handle, int optname, int* value) {
+ int r;
+ int len;
+ SOCKET socket;
+
+ if (handle == NULL || value == NULL)
+ return UV_EINVAL;
+
+ if (handle->type == UV_TCP)
+ socket = ((uv_tcp_t*) handle)->socket;
+ else if (handle->type == UV_UDP)
+ socket = ((uv_udp_t*) handle)->socket;
+ else
+ return UV_ENOTSUP;
+
+ len = sizeof(*value);
+
+ if (*value == 0)
+ r = getsockopt(socket, SOL_SOCKET, optname, (char*) value, &len);
+ else
+ r = setsockopt(socket, SOL_SOCKET, optname, (const char*) value, len);
+
+ if (r == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/win/detect-wakeup.c b/Utilities/cmlibuv/src/win/detect-wakeup.c
new file mode 100644
index 000000000..72dfb7a17
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/detect-wakeup.c
@@ -0,0 +1,35 @@
+#include "uv.h"
+#include "internal.h"
+#include "winapi.h"
+
+static void uv__register_system_resume_callback(void);
+
+void uv__init_detect_system_wakeup(void) {
+ /* Try registering system power event callback. This is the cleanest
+ * method, but it will only work on Win8 and above.
+ */
+ uv__register_system_resume_callback();
+}
+
+static ULONG CALLBACK uv__system_resume_callback(PVOID Context,
+ ULONG Type,
+ PVOID Setting) {
+ if (Type == PBT_APMRESUMESUSPEND || Type == PBT_APMRESUMEAUTOMATIC)
+ uv__wake_all_loops();
+
+ return 0;
+}
+
+static void uv__register_system_resume_callback(void) {
+ _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS recipient;
+ _HPOWERNOTIFY registration_handle;
+
+ if (pPowerRegisterSuspendResumeNotification == NULL)
+ return;
+
+ recipient.Callback = uv__system_resume_callback;
+ recipient.Context = NULL;
+ (*pPowerRegisterSuspendResumeNotification)(DEVICE_NOTIFY_CALLBACK,
+ &recipient,
+ &registration_handle);
+}
diff --git a/Utilities/cmlibuv/src/win/dl.c b/Utilities/cmlibuv/src/win/dl.c
new file mode 100644
index 000000000..39e400ab2
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/dl.c
@@ -0,0 +1,118 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include "uv.h"
+#include "internal.h"
+
+static int uv__dlerror(uv_lib_t* lib, int errorno);
+
+
+int uv_dlopen(const char* filename, uv_lib_t* lib) {
+ WCHAR filename_w[32768];
+
+ lib->handle = NULL;
+ lib->errmsg = NULL;
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ filename,
+ -1,
+ filename_w,
+ ARRAY_SIZE(filename_w))) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ lib->handle = LoadLibraryExW(filename_w, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (lib->handle == NULL) {
+ return uv__dlerror(lib, GetLastError());
+ }
+
+ return 0;
+}
+
+
+void uv_dlclose(uv_lib_t* lib) {
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (lib->handle) {
+ /* Ignore errors. No good way to signal them without leaking memory. */
+ FreeLibrary(lib->handle);
+ lib->handle = NULL;
+ }
+}
+
+
+int uv_dlsym(uv_lib_t* lib, const char* name, void** ptr) {
+ *ptr = (void*) GetProcAddress(lib->handle, name);
+ return uv__dlerror(lib, *ptr ? 0 : GetLastError());
+}
+
+
+const char* uv_dlerror(const uv_lib_t* lib) {
+ return lib->errmsg ? lib->errmsg : "no error";
+}
+
+
+static void uv__format_fallback_error(uv_lib_t* lib, int errorno){
+ DWORD_PTR args[1] = { (DWORD_PTR) errorno };
+ LPSTR fallback_error = "error: %1!d!";
+
+ FormatMessageA(FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ fallback_error, 0, 0,
+ (LPSTR) &lib->errmsg,
+ 0, (va_list*) args);
+}
+
+
+
+static int uv__dlerror(uv_lib_t* lib, int errorno) {
+ DWORD res;
+
+ if (lib->errmsg) {
+ LocalFree((void*)lib->errmsg);
+ lib->errmsg = NULL;
+ }
+
+ if (errorno) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ (LPSTR) &lib->errmsg, 0, NULL);
+ if (!res && GetLastError() == ERROR_MUI_FILE_NOT_FOUND) {
+ res = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ 0, (LPSTR) &lib->errmsg, 0, NULL);
+ }
+
+ if (!res) {
+ uv__format_fallback_error(lib, errorno);
+ }
+ }
+
+ return errorno ? -1 : 0;
+}
diff --git a/Utilities/cmlibuv/src/win/error.c b/Utilities/cmlibuv/src/win/error.c
new file mode 100644
index 000000000..642d1112e
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/error.c
@@ -0,0 +1,171 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/*
+ * Display an error message and abort the event loop.
+ */
+void uv_fatal_error(const int errorno, const char* syscall) {
+ char* buf = NULL;
+ const char* errmsg;
+
+ FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorno,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&buf, 0, NULL);
+
+ if (buf) {
+ errmsg = buf;
+ } else {
+ errmsg = "Unknown error";
+ }
+
+ /* FormatMessage messages include a newline character already, */
+ /* so don't add another. */
+ if (syscall) {
+ fprintf(stderr, "%s: (%d) %s", syscall, errorno, errmsg);
+ } else {
+ fprintf(stderr, "(%d) %s", errorno, errmsg);
+ }
+
+ if (buf) {
+ LocalFree(buf);
+ }
+
+ *((char*)NULL) = 0xff; /* Force debug break */
+ abort();
+}
+
+
+int uv_translate_sys_error(int sys_errno) {
+ if (sys_errno <= 0) {
+ return sys_errno; /* If < 0 then it's already a libuv error. */
+ }
+
+ switch (sys_errno) {
+ case ERROR_NOACCESS: return UV_EACCES;
+ case WSAEACCES: return UV_EACCES;
+ case ERROR_ELEVATION_REQUIRED: return UV_EACCES;
+ case ERROR_ADDRESS_ALREADY_ASSOCIATED: return UV_EADDRINUSE;
+ case WSAEADDRINUSE: return UV_EADDRINUSE;
+ case WSAEADDRNOTAVAIL: return UV_EADDRNOTAVAIL;
+ case WSAEAFNOSUPPORT: return UV_EAFNOSUPPORT;
+ case WSAEWOULDBLOCK: return UV_EAGAIN;
+ case WSAEALREADY: return UV_EALREADY;
+ case ERROR_INVALID_FLAGS: return UV_EBADF;
+ case ERROR_INVALID_HANDLE: return UV_EBADF;
+ case ERROR_LOCK_VIOLATION: return UV_EBUSY;
+ case ERROR_PIPE_BUSY: return UV_EBUSY;
+ case ERROR_SHARING_VIOLATION: return UV_EBUSY;
+ case ERROR_OPERATION_ABORTED: return UV_ECANCELED;
+ case WSAEINTR: return UV_ECANCELED;
+ case ERROR_NO_UNICODE_TRANSLATION: return UV_ECHARSET;
+ case ERROR_CONNECTION_ABORTED: return UV_ECONNABORTED;
+ case WSAECONNABORTED: return UV_ECONNABORTED;
+ case ERROR_CONNECTION_REFUSED: return UV_ECONNREFUSED;
+ case WSAECONNREFUSED: return UV_ECONNREFUSED;
+ case ERROR_NETNAME_DELETED: return UV_ECONNRESET;
+ case WSAECONNRESET: return UV_ECONNRESET;
+ case ERROR_ALREADY_EXISTS: return UV_EEXIST;
+ case ERROR_FILE_EXISTS: return UV_EEXIST;
+ case ERROR_BUFFER_OVERFLOW: return UV_EFAULT;
+ case WSAEFAULT: return UV_EFAULT;
+ case ERROR_HOST_UNREACHABLE: return UV_EHOSTUNREACH;
+ case WSAEHOSTUNREACH: return UV_EHOSTUNREACH;
+ case ERROR_INSUFFICIENT_BUFFER: return UV_EINVAL;
+ case ERROR_INVALID_DATA: return UV_EINVAL;
+ case ERROR_INVALID_PARAMETER: return UV_EINVAL;
+ case ERROR_SYMLINK_NOT_SUPPORTED: return UV_EINVAL;
+ case WSAEINVAL: return UV_EINVAL;
+ case WSAEPFNOSUPPORT: return UV_EINVAL;
+ case WSAESOCKTNOSUPPORT: return UV_EINVAL;
+ case ERROR_BEGINNING_OF_MEDIA: return UV_EIO;
+ case ERROR_BUS_RESET: return UV_EIO;
+ case ERROR_CRC: return UV_EIO;
+ case ERROR_DEVICE_DOOR_OPEN: return UV_EIO;
+ case ERROR_DEVICE_REQUIRES_CLEANING: return UV_EIO;
+ case ERROR_DISK_CORRUPT: return UV_EIO;
+ case ERROR_EOM_OVERFLOW: return UV_EIO;
+ case ERROR_FILEMARK_DETECTED: return UV_EIO;
+ case ERROR_GEN_FAILURE: return UV_EIO;
+ case ERROR_INVALID_BLOCK_LENGTH: return UV_EIO;
+ case ERROR_IO_DEVICE: return UV_EIO;
+ case ERROR_NO_DATA_DETECTED: return UV_EIO;
+ case ERROR_NO_SIGNAL_SENT: return UV_EIO;
+ case ERROR_OPEN_FAILED: return UV_EIO;
+ case ERROR_SETMARK_DETECTED: return UV_EIO;
+ case ERROR_SIGNAL_REFUSED: return UV_EIO;
+ case WSAEISCONN: return UV_EISCONN;
+ case ERROR_CANT_RESOLVE_FILENAME: return UV_ELOOP;
+ case ERROR_TOO_MANY_OPEN_FILES: return UV_EMFILE;
+ case WSAEMFILE: return UV_EMFILE;
+ case WSAEMSGSIZE: return UV_EMSGSIZE;
+ case ERROR_FILENAME_EXCED_RANGE: return UV_ENAMETOOLONG;
+ case ERROR_NETWORK_UNREACHABLE: return UV_ENETUNREACH;
+ case WSAENETUNREACH: return UV_ENETUNREACH;
+ case WSAENOBUFS: return UV_ENOBUFS;
+ case ERROR_BAD_PATHNAME: return UV_ENOENT;
+ case ERROR_DIRECTORY: return UV_ENOENT;
+ case ERROR_FILE_NOT_FOUND: return UV_ENOENT;
+ case ERROR_INVALID_NAME: return UV_ENOENT;
+ case ERROR_INVALID_DRIVE: return UV_ENOENT;
+ case ERROR_INVALID_REPARSE_DATA: return UV_ENOENT;
+ case ERROR_MOD_NOT_FOUND: return UV_ENOENT;
+ case ERROR_PATH_NOT_FOUND: return UV_ENOENT;
+ case WSAHOST_NOT_FOUND: return UV_ENOENT;
+ case WSANO_DATA: return UV_ENOENT;
+ case ERROR_NOT_ENOUGH_MEMORY: return UV_ENOMEM;
+ case ERROR_OUTOFMEMORY: return UV_ENOMEM;
+ case ERROR_CANNOT_MAKE: return UV_ENOSPC;
+ case ERROR_DISK_FULL: return UV_ENOSPC;
+ case ERROR_EA_TABLE_FULL: return UV_ENOSPC;
+ case ERROR_END_OF_MEDIA: return UV_ENOSPC;
+ case ERROR_HANDLE_DISK_FULL: return UV_ENOSPC;
+ case ERROR_NOT_CONNECTED: return UV_ENOTCONN;
+ case WSAENOTCONN: return UV_ENOTCONN;
+ case ERROR_DIR_NOT_EMPTY: return UV_ENOTEMPTY;
+ case WSAENOTSOCK: return UV_ENOTSOCK;
+ case ERROR_NOT_SUPPORTED: return UV_ENOTSUP;
+ case ERROR_BROKEN_PIPE: return UV_EOF;
+ case ERROR_ACCESS_DENIED: return UV_EPERM;
+ case ERROR_PRIVILEGE_NOT_HELD: return UV_EPERM;
+ case ERROR_BAD_PIPE: return UV_EPIPE;
+ case ERROR_NO_DATA: return UV_EPIPE;
+ case ERROR_PIPE_NOT_CONNECTED: return UV_EPIPE;
+ case WSAESHUTDOWN: return UV_EPIPE;
+ case WSAEPROTONOSUPPORT: return UV_EPROTONOSUPPORT;
+ case ERROR_WRITE_PROTECT: return UV_EROFS;
+ case ERROR_SEM_TIMEOUT: return UV_ETIMEDOUT;
+ case WSAETIMEDOUT: return UV_ETIMEDOUT;
+ case ERROR_NOT_SAME_DEVICE: return UV_EXDEV;
+ case ERROR_INVALID_FUNCTION: return UV_EISDIR;
+ case ERROR_META_EXPANSION_TOO_LONG: return UV_E2BIG;
+ default: return UV_UNKNOWN;
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/fs-event.c b/Utilities/cmlibuv/src/win/fs-event.c
new file mode 100644
index 000000000..95f843ad0
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/fs-event.c
@@ -0,0 +1,561 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+const unsigned int uv_directory_watcher_buffer_size = 4096;
+
+
+static void uv_fs_event_queue_readdirchanges(uv_loop_t* loop,
+ uv_fs_event_t* handle) {
+ assert(handle->dir_handle != INVALID_HANDLE_VALUE);
+ assert(!handle->req_pending);
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (handle->flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(&handle->req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)&handle->req);
+ }
+
+ handle->req_pending = 1;
+}
+
+static void uv_relative_path(const WCHAR* filename,
+ const WCHAR* dir,
+ WCHAR** relpath) {
+ size_t relpathlen;
+ size_t filenamelen = wcslen(filename);
+ size_t dirlen = wcslen(dir);
+ if (dirlen > 0 && dir[dirlen - 1] == '\\')
+ dirlen--;
+ relpathlen = filenamelen - dirlen - 1;
+ *relpath = uv__malloc((relpathlen + 1) * sizeof(WCHAR));
+ if (!*relpath)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ wcsncpy(*relpath, filename + dirlen + 1, relpathlen);
+ (*relpath)[relpathlen] = L'\0';
+}
+
+static int uv_split_path(const WCHAR* filename, WCHAR** dir,
+ WCHAR** file) {
+ size_t len, i;
+
+ if (filename == NULL) {
+ if (dir != NULL)
+ *dir = NULL;
+ *file = NULL;
+ return 0;
+ }
+
+ len = wcslen(filename);
+ i = len;
+ while (i > 0 && filename[--i] != '\\' && filename[i] != '/');
+
+ if (i == 0) {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((MAX_PATH + 1) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!GetCurrentDirectoryW(MAX_PATH, *dir)) {
+ uv__free(*dir);
+ *dir = NULL;
+ return -1;
+ }
+ }
+
+ *file = wcsdup(filename);
+ } else {
+ if (dir) {
+ *dir = (WCHAR*)uv__malloc((i + 2) * sizeof(WCHAR));
+ if (!*dir) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*dir, filename, i + 1);
+ (*dir)[i + 1] = L'\0';
+ }
+
+ *file = (WCHAR*)uv__malloc((len - i) * sizeof(WCHAR));
+ if (!*file) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ wcsncpy(*file, filename + i + 1, len - i - 1);
+ (*file)[len - i - 1] = L'\0';
+ }
+
+ return 0;
+}
+
+
+int uv_fs_event_init(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_FS_EVENT);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ handle->buffer = NULL;
+ handle->req_pending = 0;
+ handle->filew = NULL;
+ handle->short_filew = NULL;
+ handle->dirw = NULL;
+
+ UV_REQ_INIT(&handle->req, UV_FS_EVENT_REQ);
+ handle->req.data = handle;
+
+ return 0;
+}
+
+
+int uv_fs_event_start(uv_fs_event_t* handle,
+ uv_fs_event_cb cb,
+ const char* path,
+ unsigned int flags) {
+ int name_size, is_path_dir;
+ DWORD attr, last_error;
+ WCHAR* dir = NULL, *dir_to_watch, *pathw = NULL;
+ WCHAR short_path_buffer[MAX_PATH];
+ WCHAR* short_path;
+
+ if (uv__is_active(handle))
+ return UV_EINVAL;
+
+ handle->cb = cb;
+ handle->path = uv__strdup(path);
+ if (!handle->path) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ uv__handle_start(handle);
+
+ /* Convert name to UTF16. */
+
+ name_size = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0) *
+ sizeof(WCHAR);
+ pathw = (WCHAR*)uv__malloc(name_size);
+ if (!pathw) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ pathw,
+ name_size / sizeof(WCHAR))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Determine whether path is a file or a directory. */
+ attr = GetFileAttributesW(pathw);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ is_path_dir = (attr & FILE_ATTRIBUTE_DIRECTORY) ? 1 : 0;
+
+ if (is_path_dir) {
+ /* path is a directory, so that's the directory that we will watch. */
+ dir_to_watch = pathw;
+ } else {
+ /*
+ * path is a file. So we split path into dir & file parts, and
+ * watch the dir directory.
+ */
+
+ /* Convert to short path. */
+ short_path = short_path_buffer;
+ if (!GetShortPathNameW(pathw, short_path, ARRAY_SIZE(short_path))) {
+ short_path = NULL;
+ }
+
+ if (uv_split_path(pathw, &dir, &handle->filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (uv_split_path(short_path, NULL, &handle->short_filew) != 0) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ dir_to_watch = dir;
+ uv__free(pathw);
+ pathw = NULL;
+ }
+
+ handle->dir_handle = CreateFileW(dir_to_watch,
+ FILE_LIST_DIRECTORY,
+ FILE_SHARE_READ | FILE_SHARE_DELETE |
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (dir) {
+ uv__free(dir);
+ dir = NULL;
+ }
+
+ if (handle->dir_handle == INVALID_HANDLE_VALUE) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (CreateIoCompletionPort(handle->dir_handle,
+ handle->loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ if (!handle->buffer) {
+ handle->buffer = (char*)uv__malloc(uv_directory_watcher_buffer_size);
+ }
+ if (!handle->buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ memset(&(handle->req.u.io.overlapped), 0,
+ sizeof(handle->req.u.io.overlapped));
+
+ if (!ReadDirectoryChangesW(handle->dir_handle,
+ handle->buffer,
+ uv_directory_watcher_buffer_size,
+ (flags & UV_FS_EVENT_RECURSIVE) ? TRUE : FALSE,
+ FILE_NOTIFY_CHANGE_FILE_NAME |
+ FILE_NOTIFY_CHANGE_DIR_NAME |
+ FILE_NOTIFY_CHANGE_ATTRIBUTES |
+ FILE_NOTIFY_CHANGE_SIZE |
+ FILE_NOTIFY_CHANGE_LAST_WRITE |
+ FILE_NOTIFY_CHANGE_LAST_ACCESS |
+ FILE_NOTIFY_CHANGE_CREATION |
+ FILE_NOTIFY_CHANGE_SECURITY,
+ NULL,
+ &handle->req.u.io.overlapped,
+ NULL)) {
+ last_error = GetLastError();
+ goto error;
+ }
+
+ assert(is_path_dir ? pathw != NULL : pathw == NULL);
+ handle->dirw = pathw;
+ handle->req_pending = 1;
+ return 0;
+
+error:
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ uv__free(pathw);
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
+
+ return uv_translate_sys_error(last_error);
+}
+
+
+int uv_fs_event_stop(uv_fs_event_t* handle) {
+ if (!uv__is_active(handle))
+ return 0;
+
+ if (handle->dir_handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->dir_handle);
+ handle->dir_handle = INVALID_HANDLE_VALUE;
+ }
+
+ uv__handle_stop(handle);
+
+ if (handle->filew) {
+ uv__free(handle->filew);
+ handle->filew = NULL;
+ }
+
+ if (handle->short_filew) {
+ uv__free(handle->short_filew);
+ handle->short_filew = NULL;
+ }
+
+ if (handle->path) {
+ uv__free(handle->path);
+ handle->path = NULL;
+ }
+
+ if (handle->dirw) {
+ uv__free(handle->dirw);
+ handle->dirw = NULL;
+ }
+
+ return 0;
+}
+
+
+static int file_info_cmp(WCHAR* str, WCHAR* file_name, size_t file_name_len) {
+ size_t str_len;
+
+ if (str == NULL)
+ return -1;
+
+ str_len = wcslen(str);
+
+ /*
+ Since we only care about equality, return early if the strings
+ aren't the same length
+ */
+ if (str_len != (file_name_len / sizeof(WCHAR)))
+ return -1;
+
+ return _wcsnicmp(str, file_name, str_len);
+}
+
+
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle) {
+ FILE_NOTIFY_INFORMATION* file_info;
+ int err, sizew, size;
+ char* filename = NULL;
+ WCHAR* filenamew = NULL;
+ WCHAR* long_filenamew = NULL;
+ DWORD offset = 0;
+
+ assert(req->type == UV_FS_EVENT_REQ);
+ assert(handle->req_pending);
+ handle->req_pending = 0;
+
+ /* Don't report any callbacks if:
+ * - We're closing, just push the handle onto the endgame queue
+ * - We are not active, just ignore the callback
+ */
+ if (!uv__is_active(handle)) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+ return;
+ }
+
+ file_info = (FILE_NOTIFY_INFORMATION*)(handle->buffer + offset);
+
+ if (REQ_SUCCESS(req)) {
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ do {
+ file_info = (FILE_NOTIFY_INFORMATION*)((char*)file_info + offset);
+ assert(!filename);
+ assert(!filenamew);
+ assert(!long_filenamew);
+
+ /*
+ * Fire the event only if we were asked to watch a directory,
+ * or if the filename filter matches.
+ */
+ if (handle->dirw ||
+ file_info_cmp(handle->filew,
+ file_info->FileName,
+ file_info->FileNameLength) == 0 ||
+ file_info_cmp(handle->short_filew,
+ file_info->FileName,
+ file_info->FileNameLength) == 0) {
+
+ if (handle->dirw) {
+ /*
+ * We attempt to resolve the long form of the file name explicitly.
+ * We only do this for file names that might still exist on disk.
+ * If this fails, we use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ if (file_info->Action != FILE_ACTION_REMOVED &&
+ file_info->Action != FILE_ACTION_RENAMED_OLD_NAME) {
+ /* Construct a full path to the file. */
+ size = wcslen(handle->dirw) +
+ file_info->FileNameLength / sizeof(WCHAR) + 2;
+
+ filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ _snwprintf(filenamew, size, L"%s\\%.*s", handle->dirw,
+ file_info->FileNameLength / (DWORD)sizeof(WCHAR),
+ file_info->FileName);
+
+ filenamew[size - 1] = L'\0';
+
+ /* Convert to long name. */
+ size = GetLongPathNameW(filenamew, NULL, 0);
+
+ if (size) {
+ long_filenamew = (WCHAR*)uv__malloc(size * sizeof(WCHAR));
+ if (!long_filenamew) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ size = GetLongPathNameW(filenamew, long_filenamew, size);
+ if (size) {
+ long_filenamew[size] = '\0';
+ } else {
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ }
+ }
+
+ uv__free(filenamew);
+
+ if (long_filenamew) {
+ /* Get the file name out of the long path. */
+ uv_relative_path(long_filenamew,
+ handle->dirw,
+ &filenamew);
+ uv__free(long_filenamew);
+ long_filenamew = filenamew;
+ sizew = -1;
+ } else {
+ /* We couldn't get the long filename, use the one reported. */
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /*
+ * Removed or renamed events cannot be resolved to the long form.
+ * We therefore use the name given by ReadDirectoryChangesW.
+ * This may be the long form or the 8.3 short name in some cases.
+ */
+ filenamew = file_info->FileName;
+ sizew = file_info->FileNameLength / sizeof(WCHAR);
+ }
+ } else {
+ /* We already have the long name of the file, so just use it. */
+ filenamew = handle->filew;
+ sizew = -1;
+ }
+
+ /* Convert the filename to utf8. */
+ uv__convert_utf16_to_utf8(filenamew, sizew, &filename);
+
+ switch (file_info->Action) {
+ case FILE_ACTION_ADDED:
+ case FILE_ACTION_REMOVED:
+ case FILE_ACTION_RENAMED_OLD_NAME:
+ case FILE_ACTION_RENAMED_NEW_NAME:
+ handle->cb(handle, filename, UV_RENAME, 0);
+ break;
+
+ case FILE_ACTION_MODIFIED:
+ handle->cb(handle, filename, UV_CHANGE, 0);
+ break;
+ }
+
+ uv__free(filename);
+ filename = NULL;
+ uv__free(long_filenamew);
+ long_filenamew = NULL;
+ filenamew = NULL;
+ }
+
+ offset = file_info->NextEntryOffset;
+ } while (offset && !(handle->flags & UV__HANDLE_CLOSING));
+ } else {
+ handle->cb(handle, NULL, UV_CHANGE, 0);
+ }
+ } else {
+ err = GET_REQ_ERROR(req);
+ handle->cb(handle, NULL, 0, uv_translate_sys_error(err));
+ }
+
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_fs_event_queue_readdirchanges(loop, handle);
+ } else {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle) {
+ uv_fs_event_stop(handle);
+
+ uv__handle_closing(handle);
+
+ if (!handle->req_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+}
+
+
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle) {
+ if ((handle->flags & UV__HANDLE_CLOSING) && !handle->req_pending) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->buffer) {
+ uv__free(handle->buffer);
+ handle->buffer = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/fs.c b/Utilities/cmlibuv/src/win/fs.c
new file mode 100644
index 000000000..2d72cdc70
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/fs.c
@@ -0,0 +1,2492 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <sys/utime.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+#include "handle-inl.h"
+
+#include <wincrypt.h>
+
+
+#define UV_FS_FREE_PATHS 0x0002
+#define UV_FS_FREE_PTR 0x0008
+#define UV_FS_CLEANEDUP 0x0010
+
+
+#define QUEUE_FS_TP_JOB(loop, req) \
+ do { \
+ uv__req_register(loop, req); \
+ uv__work_submit((loop), &(req)->work_req, uv__fs_work, uv__fs_done); \
+ } while (0)
+
+#define SET_REQ_RESULT(req, result_value) \
+ do { \
+ req->result = (result_value); \
+ if (req->result == -1) { \
+ req->sys_errno_ = _doserrno; \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } \
+ } while (0)
+
+#define SET_REQ_WIN32_ERROR(req, sys_errno) \
+ do { \
+ req->sys_errno_ = (sys_errno); \
+ req->result = uv_translate_sys_error(req->sys_errno_); \
+ } while (0)
+
+#define SET_REQ_UV_ERROR(req, uv_errno, sys_errno) \
+ do { \
+ req->result = (uv_errno); \
+ req->sys_errno_ = (sys_errno); \
+ } while (0)
+
+#define VERIFY_FD(fd, req) \
+ if (fd == -1) { \
+ req->result = UV_EBADF; \
+ req->sys_errno_ = ERROR_INVALID_HANDLE; \
+ return; \
+ }
+
+#define FILETIME_TO_UINT(filetime) \
+ (*((uint64_t*) &(filetime)) - 116444736000000000ULL)
+
+#define FILETIME_TO_TIME_T(filetime) \
+ (FILETIME_TO_UINT(filetime) / 10000000ULL)
+
+#define FILETIME_TO_TIME_NS(filetime, secs) \
+ ((FILETIME_TO_UINT(filetime) - (secs * 10000000ULL)) * 100)
+
+#define FILETIME_TO_TIMESPEC(ts, filetime) \
+ do { \
+ (ts).tv_sec = (long) FILETIME_TO_TIME_T(filetime); \
+ (ts).tv_nsec = (long) FILETIME_TO_TIME_NS(filetime, (ts).tv_sec); \
+ } while(0)
+
+#define TIME_T_TO_FILETIME(time, filetime_ptr) \
+ do { \
+ uint64_t bigtime = ((uint64_t) ((time) * 10000000ULL)) + \
+ 116444736000000000ULL; \
+ (filetime_ptr)->dwLowDateTime = bigtime & 0xFFFFFFFF; \
+ (filetime_ptr)->dwHighDateTime = bigtime >> 32; \
+ } while(0)
+
+#define IS_SLASH(c) ((c) == L'\\' || (c) == L'/')
+#define IS_LETTER(c) (((c) >= L'a' && (c) <= L'z') || \
+ ((c) >= L'A' && (c) <= L'Z'))
+
+const WCHAR JUNCTION_PREFIX[] = L"\\??\\";
+const WCHAR JUNCTION_PREFIX_LEN = 4;
+
+const WCHAR LONG_PATH_PREFIX[] = L"\\\\?\\";
+const WCHAR LONG_PATH_PREFIX_LEN = 4;
+
+const WCHAR UNC_PATH_PREFIX[] = L"\\\\?\\UNC\\";
+const WCHAR UNC_PATH_PREFIX_LEN = 8;
+
+
+void uv_fs_init(void) {
+ _fmode = _O_BINARY;
+}
+
+
+INLINE static int fs__capture_path(uv_fs_t* req, const char* path,
+ const char* new_path, const int copy_path) {
+ char* buf;
+ char* pos;
+ ssize_t buf_sz = 0, path_len = 0, pathw_len = 0, new_pathw_len = 0;
+
+ /* new_path can only be set if path is also set. */
+ assert(new_path == NULL || path != NULL);
+
+ if (path != NULL) {
+ pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ NULL,
+ 0);
+ if (pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += pathw_len * sizeof(WCHAR);
+ }
+
+ if (path != NULL && copy_path) {
+ path_len = 1 + strlen(path);
+ buf_sz += path_len;
+ }
+
+ if (new_path != NULL) {
+ new_pathw_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ NULL,
+ 0);
+ if (new_pathw_len == 0) {
+ return GetLastError();
+ }
+
+ buf_sz += new_pathw_len * sizeof(WCHAR);
+ }
+
+
+ if (buf_sz == 0) {
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->path = NULL;
+ return 0;
+ }
+
+ buf = (char*) uv__malloc(buf_sz);
+ if (buf == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pos = buf;
+
+ if (path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ path,
+ -1,
+ (WCHAR*) pos,
+ pathw_len);
+ assert(r == (DWORD) pathw_len);
+ req->file.pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->file.pathw = NULL;
+ }
+
+ if (new_path != NULL) {
+ DWORD r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ new_path,
+ -1,
+ (WCHAR*) pos,
+ new_pathw_len);
+ assert(r == (DWORD) new_pathw_len);
+ req->fs.info.new_pathw = (WCHAR*) pos;
+ pos += r * sizeof(WCHAR);
+ } else {
+ req->fs.info.new_pathw = NULL;
+ }
+
+ req->path = path;
+ if (path != NULL && copy_path) {
+ memcpy(pos, path, path_len);
+ assert(path_len == buf_sz - (pos - buf));
+ req->path = pos;
+ }
+
+ req->flags |= UV_FS_FREE_PATHS;
+
+ return 0;
+}
+
+
+
+INLINE static void uv_fs_req_init(uv_loop_t* loop, uv_fs_t* req,
+ uv_fs_type fs_type, const uv_fs_cb cb) {
+ UV_REQ_INIT(req, UV_FS);
+ req->loop = loop;
+ req->flags = 0;
+ req->fs_type = fs_type;
+ req->result = 0;
+ req->ptr = NULL;
+ req->path = NULL;
+ req->cb = cb;
+ memset(&req->fs, 0, sizeof(req->fs));
+}
+
+
+static int fs__wide_to_utf8(WCHAR* w_source_ptr,
+ DWORD w_source_len,
+ char** target_ptr,
+ uint64_t* target_len_ptr) {
+ int r;
+ int target_len;
+ char* target;
+ target_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (target_len == 0) {
+ return -1;
+ }
+
+ if (target_len_ptr != NULL) {
+ *target_len_ptr = target_len;
+ }
+
+ if (target_ptr == NULL) {
+ return 0;
+ }
+
+ target = uv__malloc(target_len + 1);
+ if (target == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ w_source_ptr,
+ w_source_len,
+ target,
+ target_len,
+ NULL,
+ NULL);
+ assert(r == target_len);
+ target[target_len] = '\0';
+ *target_ptr = target;
+ return 0;
+}
+
+
+INLINE static int fs__readlink_handle(HANDLE handle, char** target_ptr,
+ uint64_t* target_len_ptr) {
+ char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER* reparse_data = (REPARSE_DATA_BUFFER*) buffer;
+ WCHAR* w_target;
+ DWORD w_target_len;
+ DWORD bytes;
+
+ if (!DeviceIoControl(handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL,
+ 0,
+ buffer,
+ sizeof buffer,
+ &bytes,
+ NULL)) {
+ return -1;
+ }
+
+ if (reparse_data->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ /* Real symlink */
+ w_target = reparse_data->SymbolicLinkReparseBuffer.PathBuffer +
+ (reparse_data->SymbolicLinkReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len =
+ reparse_data->SymbolicLinkReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Real symlinks can contain pretty much everything, but the only thing */
+ /* we really care about is undoing the implicit conversion to an NT */
+ /* namespaced path that CreateSymbolicLink will perform on absolute */
+ /* paths. If the path is win32-namespaced then the user must have */
+ /* explicitly made it so, and we better just return the unmodified */
+ /* reparse data. */
+ if (w_target_len >= 4 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\') {
+ /* Starts with \??\ */
+ if (w_target_len >= 6 &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\')) {
+ /* \??\<drive>:\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else if (w_target_len >= 8 &&
+ (w_target[4] == L'U' || w_target[4] == L'u') &&
+ (w_target[5] == L'N' || w_target[5] == L'n') &&
+ (w_target[6] == L'C' || w_target[6] == L'c') &&
+ w_target[7] == L'\\') {
+ /* \??\UNC\<server>\<share>\ - make sure the final path looks like */
+ /* \\<server>\<share>\ */
+ w_target += 6;
+ w_target[0] = L'\\';
+ w_target_len -= 6;
+ }
+ }
+
+ } else if (reparse_data->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT) {
+ /* Junction. */
+ w_target = reparse_data->MountPointReparseBuffer.PathBuffer +
+ (reparse_data->MountPointReparseBuffer.SubstituteNameOffset /
+ sizeof(WCHAR));
+ w_target_len = reparse_data->MountPointReparseBuffer.SubstituteNameLength /
+ sizeof(WCHAR);
+
+ /* Only treat junctions that look like \??\<drive>:\ as symlink. */
+ /* Junctions can also be used as mount points, like \??\Volume{<guid>}, */
+ /* but that's confusing for programs since they wouldn't be able to */
+ /* actually understand such a path when returned by uv_readlink(). */
+ /* UNC paths are never valid for junctions so we don't care about them. */
+ if (!(w_target_len >= 6 &&
+ w_target[0] == L'\\' &&
+ w_target[1] == L'?' &&
+ w_target[2] == L'?' &&
+ w_target[3] == L'\\' &&
+ ((w_target[4] >= L'A' && w_target[4] <= L'Z') ||
+ (w_target[4] >= L'a' && w_target[4] <= L'z')) &&
+ w_target[5] == L':' &&
+ (w_target_len == 6 || w_target[6] == L'\\'))) {
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ /* Remove leading \??\ */
+ w_target += 4;
+ w_target_len -= 4;
+
+ } else {
+ /* Reparse tag does not indicate a symlink. */
+ SetLastError(ERROR_SYMLINK_NOT_SUPPORTED);
+ return -1;
+ }
+
+ return fs__wide_to_utf8(w_target, w_target_len, target_ptr, target_len_ptr);
+}
+
+
+void fs__open(uv_fs_t* req) {
+ DWORD access;
+ DWORD share;
+ DWORD disposition;
+ DWORD attributes = 0;
+ HANDLE file;
+ int fd, current_umask;
+ int flags = req->fs.info.file_flags;
+
+ /* Obtain the active umask. umask() never fails and returns the previous */
+ /* umask. */
+ current_umask = umask(0);
+ umask(current_umask);
+
+ /* convert flags and mode to CreateFile parameters */
+ switch (flags & (_O_RDONLY | _O_WRONLY | _O_RDWR)) {
+ case _O_RDONLY:
+ access = FILE_GENERIC_READ;
+ break;
+ case _O_WRONLY:
+ access = FILE_GENERIC_WRITE;
+ break;
+ case _O_RDWR:
+ access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ break;
+ default:
+ goto einval;
+ }
+
+ if (flags & _O_APPEND) {
+ access &= ~FILE_WRITE_DATA;
+ access |= FILE_APPEND_DATA;
+ }
+
+ /*
+ * Here is where we deviate significantly from what CRT's _open()
+ * does. We indiscriminately use all the sharing modes, to match
+ * UNIX semantics. In particular, this ensures that the file can
+ * be deleted even whilst it's open, fixing issue #1449.
+ */
+ share = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
+
+ switch (flags & (_O_CREAT | _O_EXCL | _O_TRUNC)) {
+ case 0:
+ case _O_EXCL:
+ disposition = OPEN_EXISTING;
+ break;
+ case _O_CREAT:
+ disposition = OPEN_ALWAYS;
+ break;
+ case _O_CREAT | _O_EXCL:
+ case _O_CREAT | _O_TRUNC | _O_EXCL:
+ disposition = CREATE_NEW;
+ break;
+ case _O_TRUNC:
+ case _O_TRUNC | _O_EXCL:
+ disposition = TRUNCATE_EXISTING;
+ break;
+ case _O_CREAT | _O_TRUNC:
+ disposition = CREATE_ALWAYS;
+ break;
+ default:
+ goto einval;
+ }
+
+ attributes |= FILE_ATTRIBUTE_NORMAL;
+ if (flags & _O_CREAT) {
+ if (!((req->fs.info.mode & ~current_umask) & _S_IWRITE)) {
+ attributes |= FILE_ATTRIBUTE_READONLY;
+ }
+ }
+
+ if (flags & _O_TEMPORARY ) {
+ attributes |= FILE_FLAG_DELETE_ON_CLOSE | FILE_ATTRIBUTE_TEMPORARY;
+ access |= DELETE;
+ }
+
+ if (flags & _O_SHORT_LIVED) {
+ attributes |= FILE_ATTRIBUTE_TEMPORARY;
+ }
+
+ switch (flags & (_O_SEQUENTIAL | _O_RANDOM)) {
+ case 0:
+ break;
+ case _O_SEQUENTIAL:
+ attributes |= FILE_FLAG_SEQUENTIAL_SCAN;
+ break;
+ case _O_RANDOM:
+ attributes |= FILE_FLAG_RANDOM_ACCESS;
+ break;
+ default:
+ goto einval;
+ }
+
+ /* Setting this flag makes it possible to open a directory. */
+ attributes |= FILE_FLAG_BACKUP_SEMANTICS;
+
+ file = CreateFileW(req->file.pathw,
+ access,
+ share,
+ NULL,
+ disposition,
+ attributes,
+ NULL);
+ if (file == INVALID_HANDLE_VALUE) {
+ DWORD error = GetLastError();
+ if (error == ERROR_FILE_EXISTS && (flags & _O_CREAT) &&
+ !(flags & _O_EXCL)) {
+ /* Special case: when ERROR_FILE_EXISTS happens and O_CREAT was */
+ /* specified, it means the path referred to a directory. */
+ SET_REQ_UV_ERROR(req, UV_EISDIR, error);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+ return;
+ }
+
+ fd = _open_osfhandle((intptr_t) file, flags);
+ if (fd < 0) {
+ /* The only known failure mode for _open_osfhandle() is EMFILE, in which
+ * case GetLastError() will return zero. However we'll try to handle other
+ * errors as well, should they ever occur.
+ */
+ if (errno == EMFILE)
+ SET_REQ_UV_ERROR(req, UV_EMFILE, ERROR_TOO_MANY_OPEN_FILES);
+ else if (GetLastError() != ERROR_SUCCESS)
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ else
+ SET_REQ_WIN32_ERROR(req, UV_UNKNOWN);
+ CloseHandle(file);
+ return;
+ }
+
+ SET_REQ_RESULT(req, fd);
+ return;
+
+ einval:
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+}
+
+void fs__close(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ if (fd > 2)
+ result = _close(fd);
+ else
+ result = 0;
+
+ /* _close doesn't set _doserrno on failure, but it does always set errno
+ * to EBADF on failure.
+ */
+ if (result == -1) {
+ assert(errno == EBADF);
+ SET_REQ_UV_ERROR(req, UV_EBADF, ERROR_INVALID_HANDLE);
+ } else {
+ req->result = 0;
+ }
+}
+
+
+void fs__read(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ DWORD error;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = ReadFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ error = GetLastError();
+ if (error == ERROR_HANDLE_EOF) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, error);
+ }
+ }
+}
+
+
+void fs__write(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int64_t offset = req->fs.info.offset;
+ HANDLE handle;
+ OVERLAPPED overlapped, *overlapped_ptr;
+ LARGE_INTEGER offset_;
+ DWORD bytes;
+ int result;
+ unsigned int index;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (offset != -1) {
+ memset(&overlapped, 0, sizeof overlapped);
+ overlapped_ptr = &overlapped;
+ } else {
+ overlapped_ptr = NULL;
+ }
+
+ index = 0;
+ bytes = 0;
+ do {
+ DWORD incremental_bytes;
+
+ if (offset != -1) {
+ offset_.QuadPart = offset + bytes;
+ overlapped.Offset = offset_.LowPart;
+ overlapped.OffsetHigh = offset_.HighPart;
+ }
+
+ result = WriteFile(handle,
+ req->fs.info.bufs[index].base,
+ req->fs.info.bufs[index].len,
+ &incremental_bytes,
+ overlapped_ptr);
+ bytes += incremental_bytes;
+ ++index;
+ } while (result && index < req->fs.info.nbufs);
+
+ if (result || bytes > 0) {
+ SET_REQ_RESULT(req, bytes);
+ } else {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+}
+
+
+void fs__rmdir(uv_fs_t* req) {
+ int result = _wrmdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+void fs__unlink(uv_fs_t* req) {
+ const WCHAR* pathw = req->file.pathw;
+ HANDLE handle;
+ BY_HANDLE_FILE_INFORMATION info;
+ FILE_DISPOSITION_INFORMATION disposition;
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ handle = CreateFileW(pathw,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | DELETE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (!GetFileInformationByHandle(handle, &info)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ /* Do not allow deletion of directories, unless it is a symlink. When */
+ /* the path refers to a non-symlink directory, report EPERM as mandated */
+ /* by POSIX.1. */
+
+ /* Check if it is a reparse point. If it's not, it's a normal directory. */
+ if (!(info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ SET_REQ_WIN32_ERROR(req, ERROR_ACCESS_DENIED);
+ CloseHandle(handle);
+ return;
+ }
+
+ /* Read the reparse point and check if it is a valid symlink. */
+ /* If not, don't unlink. */
+ if (fs__readlink_handle(handle, NULL, NULL) < 0) {
+ DWORD error = GetLastError();
+ if (error == ERROR_SYMLINK_NOT_SUPPORTED)
+ error = ERROR_ACCESS_DENIED;
+ SET_REQ_WIN32_ERROR(req, error);
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_READONLY) {
+ /* Remove read-only attribute */
+ FILE_BASIC_INFORMATION basic = { 0 };
+
+ basic.FileAttributes = info.dwFileAttributes & ~(FILE_ATTRIBUTE_READONLY);
+
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &basic,
+ sizeof basic,
+ FileBasicInformation);
+ if (!NT_SUCCESS(status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ CloseHandle(handle);
+ return;
+ }
+ }
+
+ /* Try to set the delete flag. */
+ disposition.DeleteFile = TRUE;
+ status = pNtSetInformationFile(handle,
+ &iosb,
+ &disposition,
+ sizeof disposition,
+ FileDispositionInformation);
+ if (NT_SUCCESS(status)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+
+ CloseHandle(handle);
+}
+
+
+void fs__mkdir(uv_fs_t* req) {
+ /* TODO: use req->mode. */
+ int result = _wmkdir(req->file.pathw);
+ SET_REQ_RESULT(req, result);
+}
+
+
+/* OpenBSD original: lib/libc/stdio/mktemp.c */
+void fs__mkdtemp(uv_fs_t* req) {
+ static const WCHAR *tempchars =
+ L"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ static const size_t num_chars = 62;
+ static const size_t num_x = 6;
+ WCHAR *cp, *ep;
+ unsigned int tries, i;
+ size_t len;
+ HCRYPTPROV h_crypt_prov;
+ uint64_t v;
+ BOOL released;
+
+ len = wcslen(req->file.pathw);
+ ep = req->file.pathw + len;
+ if (len < num_x || wcsncmp(ep - num_x, L"XXXXXX", num_x)) {
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_INVALID_PARAMETER);
+ return;
+ }
+
+ if (!CryptAcquireContext(&h_crypt_prov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ tries = TMP_MAX;
+ do {
+ if (!CryptGenRandom(h_crypt_prov, sizeof(v), (BYTE*) &v)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ break;
+ }
+
+ cp = ep - num_x;
+ for (i = 0; i < num_x; i++) {
+ *cp++ = tempchars[v % num_chars];
+ v /= num_chars;
+ }
+
+ if (_wmkdir(req->file.pathw) == 0) {
+ len = strlen(req->path);
+ wcstombs((char*) req->path + len - num_x, ep - num_x, num_x);
+ SET_REQ_RESULT(req, 0);
+ break;
+ } else if (errno != EEXIST) {
+ SET_REQ_RESULT(req, -1);
+ break;
+ }
+ } while (--tries);
+
+ released = CryptReleaseContext(h_crypt_prov, 0);
+ assert(released);
+ if (tries == 0) {
+ SET_REQ_RESULT(req, -1);
+ }
+}
+
+
+void fs__scandir(uv_fs_t* req) {
+ static const size_t dirents_initial_size = 32;
+
+ HANDLE dir_handle = INVALID_HANDLE_VALUE;
+
+ uv__dirent_t** dirents = NULL;
+ size_t dirents_size = 0;
+ size_t dirents_used = 0;
+
+ IO_STATUS_BLOCK iosb;
+ NTSTATUS status;
+
+ /* Buffer to hold directory entries returned by NtQueryDirectoryFile.
+ * It's important that this buffer can hold at least one entry, regardless
+ * of the length of the file names present in the enumerated directory.
+ * A file name is at most 256 WCHARs long.
+ * According to MSDN, the buffer must be aligned at an 8-byte boundary.
+ */
+#if _MSC_VER
+ __declspec(align(8)) char buffer[8192];
+#else
+ __attribute__ ((aligned (8))) char buffer[8192];
+#endif
+
+ STATIC_ASSERT(sizeof buffer >=
+ sizeof(FILE_DIRECTORY_INFORMATION) + 256 * sizeof(WCHAR));
+
+ /* Open the directory. */
+ dir_handle =
+ CreateFileW(req->file.pathw,
+ FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (dir_handle == INVALID_HANDLE_VALUE)
+ goto win32_error;
+
+ /* Read the first chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ TRUE);
+
+ /* If the handle is not a directory, we'll get STATUS_INVALID_PARAMETER.
+ * This should be reported back as UV_ENOTDIR.
+ */
+ if (status == STATUS_INVALID_PARAMETER)
+ goto not_a_directory_error;
+
+ while (NT_SUCCESS(status)) {
+ char* position = buffer;
+ size_t next_entry_offset = 0;
+
+ do {
+ FILE_DIRECTORY_INFORMATION* info;
+ uv__dirent_t* dirent;
+
+ size_t wchar_len;
+ size_t utf8_len;
+
+ /* Obtain a pointer to the current directory entry. */
+ position += next_entry_offset;
+ info = (FILE_DIRECTORY_INFORMATION*) position;
+
+ /* Fetch the offset to the next directory entry. */
+ next_entry_offset = info->NextEntryOffset;
+
+ /* Compute the length of the filename in WCHARs. */
+ wchar_len = info->FileNameLength / sizeof info->FileName[0];
+
+ /* Skip over '.' and '..' entries. It has been reported that
+ * the SharePoint driver includes the terminating zero byte in
+ * the filename length. Strip those first.
+ */
+ while (wchar_len > 0 && info->FileName[wchar_len - 1] == L'\0')
+ wchar_len -= 1;
+
+ if (wchar_len == 0)
+ continue;
+ if (wchar_len == 1 && info->FileName[0] == L'.')
+ continue;
+ if (wchar_len == 2 && info->FileName[0] == L'.' &&
+ info->FileName[1] == L'.')
+ continue;
+
+ /* Compute the space required to store the filename as UTF-8. */
+ utf8_len = WideCharToMultiByte(
+ CP_UTF8, 0, &info->FileName[0], wchar_len, NULL, 0, NULL, NULL);
+ if (utf8_len == 0)
+ goto win32_error;
+
+ /* Resize the dirent array if needed. */
+ if (dirents_used >= dirents_size) {
+ size_t new_dirents_size =
+ dirents_size == 0 ? dirents_initial_size : dirents_size << 1;
+ uv__dirent_t** new_dirents =
+ uv__realloc(dirents, new_dirents_size * sizeof *dirents);
+
+ if (new_dirents == NULL)
+ goto out_of_memory_error;
+
+ dirents_size = new_dirents_size;
+ dirents = new_dirents;
+ }
+
+ /* Allocate space for the uv dirent structure. The dirent structure
+ * includes room for the first character of the filename, but `utf8_len`
+ * doesn't count the NULL terminator at this point.
+ */
+ dirent = uv__malloc(sizeof *dirent + utf8_len);
+ if (dirent == NULL)
+ goto out_of_memory_error;
+
+ dirents[dirents_used++] = dirent;
+
+ /* Convert file name to UTF-8. */
+ if (WideCharToMultiByte(CP_UTF8,
+ 0,
+ &info->FileName[0],
+ wchar_len,
+ &dirent->d_name[0],
+ utf8_len,
+ NULL,
+ NULL) == 0)
+ goto win32_error;
+
+ /* Add a null terminator to the filename. */
+ dirent->d_name[utf8_len] = '\0';
+
+ /* Fill out the type field. */
+ if (info->FileAttributes & FILE_ATTRIBUTE_DEVICE)
+ dirent->d_type = UV__DT_CHAR;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ dirent->d_type = UV__DT_LINK;
+ else if (info->FileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ dirent->d_type = UV__DT_DIR;
+ else
+ dirent->d_type = UV__DT_FILE;
+ } while (next_entry_offset != 0);
+
+ /* Read the next chunk. */
+ status = pNtQueryDirectoryFile(dir_handle,
+ NULL,
+ NULL,
+ NULL,
+ &iosb,
+ &buffer,
+ sizeof buffer,
+ FileDirectoryInformation,
+ FALSE,
+ NULL,
+ FALSE);
+
+ /* After the first pNtQueryDirectoryFile call, the function may return
+ * STATUS_SUCCESS even if the buffer was too small to hold at least one
+ * directory entry.
+ */
+ if (status == STATUS_SUCCESS && iosb.Information == 0)
+ status = STATUS_BUFFER_OVERFLOW;
+ }
+
+ if (status != STATUS_NO_MORE_FILES)
+ goto nt_error;
+
+ CloseHandle(dir_handle);
+
+ /* Store the result in the request object. */
+ req->ptr = dirents;
+ if (dirents != NULL)
+ req->flags |= UV_FS_FREE_PTR;
+
+ SET_REQ_RESULT(req, dirents_used);
+
+ /* `nbufs` will be used as index by uv_fs_scandir_next. */
+ req->fs.info.nbufs = 0;
+
+ return;
+
+nt_error:
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ goto cleanup;
+
+win32_error:
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto cleanup;
+
+not_a_directory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOTDIR, ERROR_DIRECTORY);
+ goto cleanup;
+
+out_of_memory_error:
+ SET_REQ_UV_ERROR(req, UV_ENOMEM, ERROR_OUTOFMEMORY);
+ goto cleanup;
+
+cleanup:
+ if (dir_handle != INVALID_HANDLE_VALUE)
+ CloseHandle(dir_handle);
+ while (dirents_used > 0)
+ uv__free(dirents[--dirents_used]);
+ if (dirents != NULL)
+ uv__free(dirents);
+}
+
+
+INLINE static int fs__stat_handle(HANDLE handle, uv_stat_t* statbuf) {
+ FILE_ALL_INFORMATION file_info;
+ FILE_FS_VOLUME_INFORMATION volume_info;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileAllInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ }
+
+ nt_status = pNtQueryVolumeInformationFile(handle,
+ &io_status,
+ &volume_info,
+ sizeof volume_info,
+ FileFsVolumeInformation);
+
+ /* Buffer overflow (a warning status code) is expected here. */
+ if (io_status.Status == STATUS_NOT_IMPLEMENTED) {
+ statbuf->st_dev = 0;
+ } else if (NT_ERROR(nt_status)) {
+ SetLastError(pRtlNtStatusToDosError(nt_status));
+ return -1;
+ } else {
+ statbuf->st_dev = volume_info.VolumeSerialNumber;
+ }
+
+ /* Todo: st_mode should probably always be 0666 for everyone. We might also
+ * want to report 0777 if the file is a .exe or a directory.
+ *
+ * Currently it's based on whether the 'readonly' attribute is set, which
+ * makes little sense because the semantics are so different: the 'read-only'
+ * flag is just a way for a user to protect against accidental deletion, and
+ * serves no security purpose. Windows uses ACLs for that.
+ *
+ * Also people now use uv_fs_chmod() to take away the writable bit for good
+ * reasons. Windows however just makes the file read-only, which makes it
+ * impossible to delete the file afterwards, since read-only files can't be
+ * deleted.
+ *
+ * IOW it's all just a clusterfuck and we should think of something that
+ * makes slightly more sense.
+ *
+ * And uv_fs_chmod should probably just fail on windows or be a total no-op.
+ * There's nothing sensible it can do anyway.
+ */
+ statbuf->st_mode = 0;
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /*
+ * It is possible for a file to have FILE_ATTRIBUTE_REPARSE_POINT but not have
+ * any link data. In that case DeviceIoControl() in fs__readlink_handle() sets
+ * the last error to ERROR_NOT_A_REPARSE_POINT. Then the stat result mode
+ * calculated below will indicate a normal directory or file, as if
+ * FILE_ATTRIBUTE_REPARSE_POINT was not present.
+ */
+ if (fs__readlink_handle(handle, NULL, &statbuf->st_size) == 0) {
+ statbuf->st_mode |= S_IFLNK;
+ } else if (GetLastError() != ERROR_NOT_A_REPARSE_POINT) {
+ return -1;
+ }
+ }
+
+ if (statbuf->st_mode == 0) {
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ statbuf->st_mode |= _S_IFDIR;
+ statbuf->st_size = 0;
+ } else {
+ statbuf->st_mode |= _S_IFREG;
+ statbuf->st_size = file_info.StandardInformation.EndOfFile.QuadPart;
+ }
+ }
+
+ if (file_info.BasicInformation.FileAttributes & FILE_ATTRIBUTE_READONLY)
+ statbuf->st_mode |= _S_IREAD | (_S_IREAD >> 3) | (_S_IREAD >> 6);
+ else
+ statbuf->st_mode |= (_S_IREAD | _S_IWRITE) | ((_S_IREAD | _S_IWRITE) >> 3) |
+ ((_S_IREAD | _S_IWRITE) >> 6);
+
+ FILETIME_TO_TIMESPEC(statbuf->st_atim, file_info.BasicInformation.LastAccessTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_ctim, file_info.BasicInformation.ChangeTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_mtim, file_info.BasicInformation.LastWriteTime);
+ FILETIME_TO_TIMESPEC(statbuf->st_birthtim, file_info.BasicInformation.CreationTime);
+
+ statbuf->st_ino = file_info.InternalInformation.IndexNumber.QuadPart;
+
+ /* st_blocks contains the on-disk allocation size in 512-byte units. */
+ statbuf->st_blocks =
+ file_info.StandardInformation.AllocationSize.QuadPart >> 9ULL;
+
+ statbuf->st_nlink = file_info.StandardInformation.NumberOfLinks;
+
+ /* The st_blksize is supposed to be the 'optimal' number of bytes for reading
+ * and writing to the disk. That is, for any definition of 'optimal' - it's
+ * supposed to at least avoid read-update-write behavior when writing to the
+ * disk.
+ *
+ * However nobody knows this and even fewer people actually use this value,
+ * and in order to fill it out we'd have to make another syscall to query the
+ * volume for FILE_FS_SECTOR_SIZE_INFORMATION.
+ *
+ * Therefore we'll just report a sensible value that's quite commonly okay
+ * on modern hardware.
+ */
+ statbuf->st_blksize = 2048;
+
+ /* Todo: set st_flags to something meaningful. Also provide a wrapper for
+ * chattr(2).
+ */
+ statbuf->st_flags = 0;
+
+ /* Windows has nothing sensible to say about these values, so they'll just
+ * remain empty.
+ */
+ statbuf->st_gid = 0;
+ statbuf->st_uid = 0;
+ statbuf->st_rdev = 0;
+ statbuf->st_gen = 0;
+
+ return 0;
+}
+
+
+INLINE static void fs__stat_prepare_path(WCHAR* pathw) {
+ size_t len = wcslen(pathw);
+
+ /* TODO: ignore namespaced paths. */
+ if (len > 1 && pathw[len - 2] != L':' &&
+ (pathw[len - 1] == L'\\' || pathw[len - 1] == L'/')) {
+ pathw[len - 1] = '\0';
+ }
+}
+
+
+INLINE static void fs__stat_impl(uv_fs_t* req, int do_lstat) {
+ HANDLE handle;
+ DWORD flags;
+
+ flags = FILE_FLAG_BACKUP_SEMANTICS;
+ if (do_lstat) {
+ flags |= FILE_FLAG_OPEN_REPARSE_POINT;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ flags,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ DWORD error = GetLastError();
+ if (do_lstat && error == ERROR_SYMLINK_NOT_SUPPORTED) {
+ /* We opened a reparse point but it was not a symlink. Try again. */
+ fs__stat_impl(req, 0);
+
+ } else {
+ /* Stat failed. */
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ }
+
+ CloseHandle(handle);
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+ CloseHandle(handle);
+}
+
+
+static void fs__stat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 0);
+}
+
+
+static void fs__lstat(uv_fs_t* req) {
+ fs__stat_prepare_path(req->file.pathw);
+ fs__stat_impl(req, 1);
+}
+
+
+static void fs__fstat(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__stat_handle(handle, &req->statbuf) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->ptr = &req->statbuf;
+ req->result = 0;
+}
+
+
+static void fs__rename(uv_fs_t* req) {
+ if (!MoveFileExW(req->file.pathw, req->fs.info.new_pathw, MOVEFILE_REPLACE_EXISTING)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ SET_REQ_RESULT(req, 0);
+}
+
+
+INLINE static void fs__sync_impl(uv_fs_t* req) {
+ int fd = req->file.fd;
+ int result;
+
+ VERIFY_FD(fd, req);
+
+ result = FlushFileBuffers(uv__get_osfhandle(fd)) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+}
+
+
+static void fs__fsync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__fdatasync(uv_fs_t* req) {
+ fs__sync_impl(req);
+}
+
+
+static void fs__ftruncate(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status;
+ FILE_END_OF_FILE_INFORMATION eof_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ eof_info.EndOfFile.QuadPart = req->fs.info.offset;
+
+ status = pNtSetInformationFile(handle,
+ &io_status,
+ &eof_info,
+ sizeof eof_info,
+ FileEndOfFileInformation);
+
+ if (NT_SUCCESS(status)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(status));
+ }
+}
+
+
+static void fs__sendfile(uv_fs_t* req) {
+ int fd_in = req->file.fd, fd_out = req->fs.info.fd_out;
+ size_t length = req->fs.info.bufsml[0].len;
+ int64_t offset = req->fs.info.offset;
+ const size_t max_buf_size = 65536;
+ size_t buf_size = length < max_buf_size ? length : max_buf_size;
+ int n, result = 0;
+ int64_t result_offset = 0;
+ char* buf = (char*) uv__malloc(buf_size);
+ if (!buf) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (offset != -1) {
+ result_offset = _lseeki64(fd_in, offset, SEEK_SET);
+ }
+
+ if (result_offset == -1) {
+ result = -1;
+ } else {
+ while (length > 0) {
+ n = _read(fd_in, buf, length < buf_size ? length : buf_size);
+ if (n == 0) {
+ break;
+ } else if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ length -= n;
+
+ n = _write(fd_out, buf, n);
+ if (n == -1) {
+ result = -1;
+ break;
+ }
+
+ result += n;
+ }
+ }
+
+ uv__free(buf);
+
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__access(uv_fs_t* req) {
+ DWORD attr = GetFileAttributesW(req->file.pathw);
+
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ /*
+ * Access is possible if
+ * - write access wasn't requested,
+ * - or the file isn't read-only,
+ * - or it's a directory.
+ * (Directories cannot be read-only on Windows.)
+ */
+ if (!(req->fs.info.mode & W_OK) ||
+ !(attr & FILE_ATTRIBUTE_READONLY) ||
+ (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ SET_REQ_RESULT(req, 0);
+ } else {
+ SET_REQ_WIN32_ERROR(req, UV_EPERM);
+ }
+
+}
+
+
+static void fs__chmod(uv_fs_t* req) {
+ int result = _wchmod(req->file.pathw, req->fs.info.mode);
+ SET_REQ_RESULT(req, result);
+}
+
+
+static void fs__fchmod(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_BASIC_INFORMATION file_info;
+
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ nt_status = pNtQueryInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ if (req->fs.info.mode & _S_IWRITE) {
+ file_info.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+ } else {
+ file_info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ nt_status = pNtSetInformationFile(handle,
+ &io_status,
+ &file_info,
+ sizeof file_info,
+ FileBasicInformation);
+
+ if (!NT_SUCCESS(nt_status)) {
+ SET_REQ_WIN32_ERROR(req, pRtlNtStatusToDosError(nt_status));
+ return;
+ }
+
+ SET_REQ_SUCCESS(req);
+}
+
+
+INLINE static int fs__utime_handle(HANDLE handle, double atime, double mtime) {
+ FILETIME filetime_a, filetime_m;
+
+ TIME_T_TO_FILETIME(atime, &filetime_a);
+ TIME_T_TO_FILETIME(mtime, &filetime_m);
+
+ if (!SetFileTime(handle, NULL, &filetime_a, &filetime_m)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void fs__utime(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ CloseHandle(handle);
+
+ req->result = 0;
+}
+
+
+static void fs__futime(uv_fs_t* req) {
+ int fd = req->file.fd;
+ HANDLE handle;
+ VERIFY_FD(fd, req);
+
+ handle = uv__get_osfhandle(fd);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, ERROR_INVALID_HANDLE);
+ return;
+ }
+
+ if (fs__utime_handle(handle, req->fs.time.atime, req->fs.time.mtime) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ req->result = 0;
+}
+
+
+static void fs__link(uv_fs_t* req) {
+ DWORD r = CreateHardLinkW(req->fs.info.new_pathw, req->file.pathw, NULL);
+ if (r == 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ req->result = 0;
+ }
+}
+
+
+static void fs__create_junction(uv_fs_t* req, const WCHAR* path,
+ const WCHAR* new_path) {
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ int created = 0;
+ int target_len;
+ int is_absolute, is_long_path;
+ int needed_buf_size, used_buf_size, used_data_size, path_buf_len;
+ int start, len, i;
+ int add_slash;
+ DWORD bytes;
+ WCHAR* path_buf;
+
+ target_len = wcslen(path);
+ is_long_path = wcsncmp(path, LONG_PATH_PREFIX, LONG_PATH_PREFIX_LEN) == 0;
+
+ if (is_long_path) {
+ is_absolute = 1;
+ } else {
+ is_absolute = target_len >= 3 && IS_LETTER(path[0]) &&
+ path[1] == L':' && IS_SLASH(path[2]);
+ }
+
+ if (!is_absolute) {
+ /* Not supporting relative paths */
+ SET_REQ_UV_ERROR(req, UV_EINVAL, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ /* Do a pessimistic calculation of the required buffer size */
+ needed_buf_size =
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ JUNCTION_PREFIX_LEN * sizeof(WCHAR) +
+ 2 * (target_len + 2) * sizeof(WCHAR);
+
+ /* Allocate the buffer */
+ buffer = (REPARSE_DATA_BUFFER*)uv__malloc(needed_buf_size);
+ if (!buffer) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ /* Grab a pointer to the part of the buffer where filenames go */
+ path_buf = (WCHAR*)&(buffer->MountPointReparseBuffer.PathBuffer);
+ path_buf_len = 0;
+
+ /* Copy the substitute (internal) target path */
+ start = path_buf_len;
+
+ wcsncpy((WCHAR*)&path_buf[path_buf_len], JUNCTION_PREFIX,
+ JUNCTION_PREFIX_LEN);
+ path_buf_len += JUNCTION_PREFIX_LEN;
+
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ path_buf[path_buf_len++] = L'\\';
+ len = path_buf_len - start;
+
+ /* Set the info about the substitute name */
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.SubstituteNameLength = len * sizeof(WCHAR);
+
+ /* Insert null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Copy the print name of the target path */
+ start = path_buf_len;
+ add_slash = 0;
+ for (i = is_long_path ? LONG_PATH_PREFIX_LEN : 0; path[i] != L'\0'; i++) {
+ if (IS_SLASH(path[i])) {
+ add_slash = 1;
+ continue;
+ }
+
+ if (add_slash) {
+ path_buf[path_buf_len++] = L'\\';
+ add_slash = 0;
+ }
+
+ path_buf[path_buf_len++] = path[i];
+ }
+ len = path_buf_len - start;
+ if (len == 2) {
+ path_buf[path_buf_len++] = L'\\';
+ len++;
+ }
+
+ /* Set the info about the print name */
+ buffer->MountPointReparseBuffer.PrintNameOffset = start * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = len * sizeof(WCHAR);
+
+ /* Insert another null terminator */
+ path_buf[path_buf_len++] = L'\0';
+
+ /* Calculate how much buffer space was actually used */
+ used_buf_size = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer) +
+ path_buf_len * sizeof(WCHAR);
+ used_data_size = used_buf_size -
+ FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer);
+
+ /* Put general info in the data buffer */
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = used_data_size;
+ buffer->Reserved = 0;
+
+ /* Create a new directory */
+ if (!CreateDirectoryW(new_path, NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+ created = 1;
+
+ /* Open the directory */
+ handle = CreateFileW(new_path,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS |
+ FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Create the actual reparse point */
+ if (!DeviceIoControl(handle,
+ FSCTL_SET_REPARSE_POINT,
+ buffer,
+ used_buf_size,
+ NULL,
+ 0,
+ &bytes,
+ NULL)) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ /* Clean up */
+ CloseHandle(handle);
+ uv__free(buffer);
+
+ SET_REQ_RESULT(req, 0);
+ return;
+
+error:
+ uv__free(buffer);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+
+ if (created) {
+ RemoveDirectoryW(new_path);
+ }
+}
+
+
+static void fs__symlink(uv_fs_t* req) {
+ WCHAR* pathw = req->file.pathw;
+ WCHAR* new_pathw = req->fs.info.new_pathw;
+ int flags = req->fs.info.file_flags;
+ int result;
+
+
+ if (flags & UV_FS_SYMLINK_JUNCTION) {
+ fs__create_junction(req, pathw, new_pathw);
+ } else if (pCreateSymbolicLinkW) {
+ result = pCreateSymbolicLinkW(new_pathw,
+ pathw,
+ flags & UV_FS_SYMLINK_DIR ? SYMBOLIC_LINK_FLAG_DIRECTORY : 0) ? 0 : -1;
+ if (result == -1) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ } else {
+ SET_REQ_RESULT(req, result);
+ }
+ } else {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ }
+}
+
+
+static void fs__readlink(uv_fs_t* req) {
+ HANDLE handle;
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__readlink_handle(handle, (char**) &req->ptr, NULL) != 0) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ CloseHandle(handle);
+ return;
+ }
+
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+
+ CloseHandle(handle);
+}
+
+
+static size_t fs__realpath_handle(HANDLE handle, char** realpath_ptr) {
+ int r;
+ DWORD w_realpath_len;
+ WCHAR* w_realpath_ptr = NULL;
+ WCHAR* w_realpath_buf;
+
+ w_realpath_len = pGetFinalPathNameByHandleW(handle, NULL, 0, VOLUME_NAME_DOS);
+ if (w_realpath_len == 0) {
+ return -1;
+ }
+
+ w_realpath_buf = uv__malloc((w_realpath_len + 1) * sizeof(WCHAR));
+ if (w_realpath_buf == NULL) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+ w_realpath_ptr = w_realpath_buf;
+
+ if (pGetFinalPathNameByHandleW(handle,
+ w_realpath_ptr,
+ w_realpath_len,
+ VOLUME_NAME_DOS) == 0) {
+ uv__free(w_realpath_buf);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ /* convert UNC path to long path */
+ if (wcsncmp(w_realpath_ptr,
+ UNC_PATH_PREFIX,
+ UNC_PATH_PREFIX_LEN) == 0) {
+ w_realpath_ptr += 6;
+ *w_realpath_ptr = L'\\';
+ w_realpath_len -= 6;
+ } else if (wcsncmp(w_realpath_ptr,
+ LONG_PATH_PREFIX,
+ LONG_PATH_PREFIX_LEN) == 0) {
+ w_realpath_ptr += 4;
+ w_realpath_len -= 4;
+ } else {
+ uv__free(w_realpath_buf);
+ SetLastError(ERROR_INVALID_HANDLE);
+ return -1;
+ }
+
+ r = fs__wide_to_utf8(w_realpath_ptr, w_realpath_len, realpath_ptr, NULL);
+ uv__free(w_realpath_buf);
+ return r;
+}
+
+static void fs__realpath(uv_fs_t* req) {
+ HANDLE handle;
+
+ if (!pGetFinalPathNameByHandleW) {
+ SET_REQ_UV_ERROR(req, UV_ENOSYS, ERROR_NOT_SUPPORTED);
+ return;
+ }
+
+ handle = CreateFileW(req->file.pathw,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ if (fs__realpath_handle(handle, (char**) &req->ptr) == -1) {
+ CloseHandle(handle);
+ SET_REQ_WIN32_ERROR(req, GetLastError());
+ return;
+ }
+
+ CloseHandle(handle);
+ req->flags |= UV_FS_FREE_PTR;
+ SET_REQ_RESULT(req, 0);
+}
+
+
+static void fs__chown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void fs__fchown(uv_fs_t* req) {
+ req->result = 0;
+}
+
+
+static void uv__fs_work(struct uv__work* w) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ assert(req->type == UV_FS);
+
+#define XX(uc, lc) case UV_FS_##uc: fs__##lc(req); break;
+ switch (req->fs_type) {
+ XX(OPEN, open)
+ XX(CLOSE, close)
+ XX(READ, read)
+ XX(WRITE, write)
+ XX(SENDFILE, sendfile)
+ XX(STAT, stat)
+ XX(LSTAT, lstat)
+ XX(FSTAT, fstat)
+ XX(FTRUNCATE, ftruncate)
+ XX(UTIME, utime)
+ XX(FUTIME, futime)
+ XX(ACCESS, access)
+ XX(CHMOD, chmod)
+ XX(FCHMOD, fchmod)
+ XX(FSYNC, fsync)
+ XX(FDATASYNC, fdatasync)
+ XX(UNLINK, unlink)
+ XX(RMDIR, rmdir)
+ XX(MKDIR, mkdir)
+ XX(MKDTEMP, mkdtemp)
+ XX(RENAME, rename)
+ XX(SCANDIR, scandir)
+ XX(LINK, link)
+ XX(SYMLINK, symlink)
+ XX(READLINK, readlink)
+ XX(REALPATH, realpath)
+ XX(CHOWN, chown)
+ XX(FCHOWN, fchown);
+ default:
+ assert(!"bad uv_fs_type");
+ }
+}
+
+
+static void uv__fs_done(struct uv__work* w, int status) {
+ uv_fs_t* req;
+
+ req = container_of(w, uv_fs_t, work_req);
+ uv__req_unregister(req->loop, req);
+
+ if (status == UV_ECANCELED) {
+ assert(req->result == 0);
+ req->result = UV_ECANCELED;
+ }
+
+ req->cb(req);
+}
+
+
+void uv_fs_req_cleanup(uv_fs_t* req) {
+ if (req->flags & UV_FS_CLEANEDUP)
+ return;
+
+ if (req->flags & UV_FS_FREE_PATHS)
+ uv__free(req->file.pathw);
+
+ if (req->flags & UV_FS_FREE_PTR) {
+ if (req->fs_type == UV_FS_SCANDIR && req->ptr != NULL)
+ uv__fs_scandir_cleanup(req);
+ else
+ uv__free(req->ptr);
+ }
+
+ if (req->fs.info.bufs != req->fs.info.bufsml)
+ uv__free(req->fs.info.bufs);
+
+ req->path = NULL;
+ req->file.pathw = NULL;
+ req->fs.info.new_pathw = NULL;
+ req->fs.info.bufs = NULL;
+ req->ptr = NULL;
+
+ req->flags |= UV_FS_CLEANEDUP;
+}
+
+
+int uv_fs_open(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ int mode, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_OPEN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__open(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_close(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_CLOSE, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__close(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_read(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_READ, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__read(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_write(uv_loop_t* loop,
+ uv_fs_t* req,
+ uv_file fd,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ int64_t offset,
+ uv_fs_cb cb) {
+ if (bufs == NULL || nbufs == 0)
+ return UV_EINVAL;
+
+ uv_fs_req_init(loop, req, UV_FS_WRITE, cb);
+
+ req->file.fd = fd;
+
+ req->fs.info.nbufs = nbufs;
+ req->fs.info.bufs = req->fs.info.bufsml;
+ if (nbufs > ARRAY_SIZE(req->fs.info.bufsml))
+ req->fs.info.bufs = uv__malloc(nbufs * sizeof(*bufs));
+
+ if (req->fs.info.bufs == NULL)
+ return UV_ENOMEM;
+
+ memcpy(req->fs.info.bufs, bufs, nbufs * sizeof(*bufs));
+
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__write(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_unlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UNLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__unlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdir(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_mkdtemp(uv_loop_t* loop, uv_fs_t* req, const char* tpl,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_MKDTEMP, cb);
+
+ err = fs__capture_path(req, tpl, NULL, TRUE);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__mkdtemp(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rmdir(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RMDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rmdir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_scandir(uv_loop_t* loop, uv_fs_t* req, const char* path, int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SCANDIR, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__scandir(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_link(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__link(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_symlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, int flags, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_SYMLINK, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.file_flags = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__symlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_readlink(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_READLINK, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__readlink(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_realpath(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ uv_fs_cb cb) {
+ int err;
+
+ if (!req || !path) {
+ return UV_EINVAL;
+ }
+
+ uv_fs_req_init(loop, req, UV_FS_REALPATH, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__realpath(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_chown(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHOWN, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchown(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_uid_t uid,
+ uv_gid_t gid, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHOWN, cb);
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchown(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_stat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_STAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__stat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_lstat(uv_loop_t* loop, uv_fs_t* req, const char* path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_LSTAT, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__lstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fstat(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSTAT, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fstat(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_rename(uv_loop_t* loop, uv_fs_t* req, const char* path,
+ const char* new_path, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_RENAME, cb);
+
+ err = fs__capture_path(req, path, new_path, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__rename(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fsync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FSYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fsync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fdatasync(uv_loop_t* loop, uv_fs_t* req, uv_file fd, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FDATASYNC, cb);
+ req->file.fd = fd;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fdatasync(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_ftruncate(uv_loop_t* loop, uv_fs_t* req, uv_file fd,
+ int64_t offset, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FTRUNCATE, cb);
+
+ req->file.fd = fd;
+ req->fs.info.offset = offset;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__ftruncate(req);
+ return req->result;
+ }
+}
+
+
+
+int uv_fs_sendfile(uv_loop_t* loop, uv_fs_t* req, uv_file fd_out,
+ uv_file fd_in, int64_t in_offset, size_t length, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_SENDFILE, cb);
+
+ req->file.fd = fd_in;
+ req->fs.info.fd_out = fd_out;
+ req->fs.info.offset = in_offset;
+ req->fs.info.bufsml[0].len = length;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__sendfile(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_access(uv_loop_t* loop,
+ uv_fs_t* req,
+ const char* path,
+ int flags,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_ACCESS, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ req->fs.info.mode = flags;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ }
+
+ fs__access(req);
+ return req->result;
+}
+
+
+int uv_fs_chmod(uv_loop_t* loop, uv_fs_t* req, const char* path, int mode,
+ uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_CHMOD, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__chmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_fchmod(uv_loop_t* loop, uv_fs_t* req, uv_file fd, int mode,
+ uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FCHMOD, cb);
+
+ req->file.fd = fd;
+ req->fs.info.mode = mode;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__fchmod(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_utime(uv_loop_t* loop, uv_fs_t* req, const char* path, double atime,
+ double mtime, uv_fs_cb cb) {
+ int err;
+
+ uv_fs_req_init(loop, req, UV_FS_UTIME, cb);
+
+ err = fs__capture_path(req, path, NULL, cb != NULL);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__utime(req);
+ return req->result;
+ }
+}
+
+
+int uv_fs_futime(uv_loop_t* loop, uv_fs_t* req, uv_file fd, double atime,
+ double mtime, uv_fs_cb cb) {
+ uv_fs_req_init(loop, req, UV_FS_FUTIME, cb);
+
+ req->file.fd = fd;
+ req->fs.time.atime = atime;
+ req->fs.time.mtime = mtime;
+
+ if (cb) {
+ QUEUE_FS_TP_JOB(loop, req);
+ return 0;
+ } else {
+ fs__futime(req);
+ return req->result;
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/getaddrinfo.c b/Utilities/cmlibuv/src/win/getaddrinfo.c
new file mode 100644
index 000000000..baab83889
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/getaddrinfo.c
@@ -0,0 +1,382 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+/* EAI_* constants. */
+#include <winsock2.h>
+
+
+int uv__getaddrinfo_translate_error(int sys_err) {
+ switch (sys_err) {
+ case 0: return 0;
+ case WSATRY_AGAIN: return UV_EAI_AGAIN;
+ case WSAEINVAL: return UV_EAI_BADFLAGS;
+ case WSANO_RECOVERY: return UV_EAI_FAIL;
+ case WSAEAFNOSUPPORT: return UV_EAI_FAMILY;
+ case WSA_NOT_ENOUGH_MEMORY: return UV_EAI_MEMORY;
+ case WSAHOST_NOT_FOUND: return UV_EAI_NONAME;
+ case WSATYPE_NOT_FOUND: return UV_EAI_SERVICE;
+ case WSAESOCKTNOSUPPORT: return UV_EAI_SOCKTYPE;
+ default: return uv_translate_sys_error(sys_err);
+ }
+}
+
+
+/*
+ * MinGW is missing this
+ */
+#if !defined(_MSC_VER) && !defined(__MINGW64_VERSION_MAJOR)
+ typedef struct addrinfoW {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ WCHAR* ai_canonname;
+ struct sockaddr* ai_addr;
+ struct addrinfoW* ai_next;
+ } ADDRINFOW, *PADDRINFOW;
+
+ DECLSPEC_IMPORT int WSAAPI GetAddrInfoW(const WCHAR* node,
+ const WCHAR* service,
+ const ADDRINFOW* hints,
+ PADDRINFOW* result);
+
+ DECLSPEC_IMPORT void WSAAPI FreeAddrInfoW(PADDRINFOW pAddrInfo);
+#endif
+
+
+/* adjust size value to be multiple of 4. Use to keep pointer aligned */
+/* Do we need different versions of this for different architectures? */
+#define ALIGNED_SIZE(X) ((((X) + 3) >> 2) << 2)
+
+
+static void uv__getaddrinfo_work(struct uv__work* w) {
+ uv_getaddrinfo_t* req;
+ struct addrinfoW* hints;
+ int err;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+ hints = req->addrinfow;
+ req->addrinfow = NULL;
+ err = GetAddrInfoW(req->node, req->service, hints, &req->addrinfow);
+ req->retcode = uv__getaddrinfo_translate_error(err);
+}
+
+
+/*
+ * Called from uv_run when complete. Call user specified callback
+ * then free returned addrinfo
+ * Returned addrinfo strings are converted from UTF-16 to UTF-8.
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+static void uv__getaddrinfo_done(struct uv__work* w, int status) {
+ uv_getaddrinfo_t* req;
+ int addrinfo_len = 0;
+ int name_len = 0;
+ size_t addrinfo_struct_len = ALIGNED_SIZE(sizeof(struct addrinfo));
+ struct addrinfoW* addrinfow_ptr;
+ struct addrinfo* addrinfo_ptr;
+ char* alloc_ptr = NULL;
+ char* cur_ptr = NULL;
+
+ req = container_of(w, uv_getaddrinfo_t, work_req);
+
+ /* release input parameter memory */
+ uv__free(req->alloc);
+ req->alloc = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ goto complete;
+ }
+
+ if (req->retcode == 0) {
+ /* convert addrinfoW to addrinfo */
+ /* first calculate required length */
+ addrinfow_ptr = req->addrinfow;
+ while (addrinfow_ptr != NULL) {
+ addrinfo_len += addrinfo_struct_len +
+ ALIGNED_SIZE(addrinfow_ptr->ai_addrlen);
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (name_len == 0) {
+ req->retcode = uv_translate_sys_error(GetLastError());
+ goto complete;
+ }
+ addrinfo_len += ALIGNED_SIZE(name_len);
+ }
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ }
+
+ /* allocate memory for addrinfo results */
+ alloc_ptr = (char*)uv__malloc(addrinfo_len);
+
+ /* do conversions */
+ if (alloc_ptr != NULL) {
+ cur_ptr = alloc_ptr;
+ addrinfow_ptr = req->addrinfow;
+
+ while (addrinfow_ptr != NULL) {
+ /* copy addrinfo struct data */
+ assert(cur_ptr + addrinfo_struct_len <= alloc_ptr + addrinfo_len);
+ addrinfo_ptr = (struct addrinfo*)cur_ptr;
+ addrinfo_ptr->ai_family = addrinfow_ptr->ai_family;
+ addrinfo_ptr->ai_socktype = addrinfow_ptr->ai_socktype;
+ addrinfo_ptr->ai_protocol = addrinfow_ptr->ai_protocol;
+ addrinfo_ptr->ai_flags = addrinfow_ptr->ai_flags;
+ addrinfo_ptr->ai_addrlen = addrinfow_ptr->ai_addrlen;
+ addrinfo_ptr->ai_canonname = NULL;
+ addrinfo_ptr->ai_addr = NULL;
+ addrinfo_ptr->ai_next = NULL;
+
+ cur_ptr += addrinfo_struct_len;
+
+ /* copy sockaddr */
+ if (addrinfo_ptr->ai_addrlen > 0) {
+ assert(cur_ptr + addrinfo_ptr->ai_addrlen <=
+ alloc_ptr + addrinfo_len);
+ memcpy(cur_ptr, addrinfow_ptr->ai_addr, addrinfo_ptr->ai_addrlen);
+ addrinfo_ptr->ai_addr = (struct sockaddr*)cur_ptr;
+ cur_ptr += ALIGNED_SIZE(addrinfo_ptr->ai_addrlen);
+ }
+
+ /* convert canonical name to UTF-8 */
+ if (addrinfow_ptr->ai_canonname != NULL) {
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ assert(name_len > 0);
+ assert(cur_ptr + name_len <= alloc_ptr + addrinfo_len);
+ name_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ addrinfow_ptr->ai_canonname,
+ -1,
+ cur_ptr,
+ name_len,
+ NULL,
+ NULL);
+ assert(name_len > 0);
+ addrinfo_ptr->ai_canonname = cur_ptr;
+ cur_ptr += ALIGNED_SIZE(name_len);
+ }
+ assert(cur_ptr <= alloc_ptr + addrinfo_len);
+
+ /* set next ptr */
+ addrinfow_ptr = addrinfow_ptr->ai_next;
+ if (addrinfow_ptr != NULL) {
+ addrinfo_ptr->ai_next = (struct addrinfo*)cur_ptr;
+ }
+ }
+ req->addrinfo = (struct addrinfo*)alloc_ptr;
+ } else {
+ req->retcode = UV_EAI_MEMORY;
+ }
+ }
+
+ /* return memory to system */
+ if (req->addrinfow != NULL) {
+ FreeAddrInfoW(req->addrinfow);
+ req->addrinfow = NULL;
+ }
+
+complete:
+ uv__req_unregister(req->loop, req);
+
+ /* finally do callback with converted result */
+ if (req->getaddrinfo_cb)
+ req->getaddrinfo_cb(req, req->retcode, req->addrinfo);
+}
+
+
+void uv_freeaddrinfo(struct addrinfo* ai) {
+ char* alloc_ptr = (char*)ai;
+
+ /* release copied result memory */
+ uv__free(alloc_ptr);
+}
+
+
+/*
+ * Entry point for getaddrinfo
+ * we convert the UTF-8 strings to UNICODE
+ * and save the UNICODE string pointers in the req
+ * We also copy hints so that caller does not need to keep memory until the
+ * callback.
+ * return 0 if a callback will be made
+ * return error code if validation fails
+ *
+ * To minimize allocation we calculate total size required,
+ * and copy all structs and referenced strings into the one block.
+ * Each size calculation is adjusted to avoid unaligned pointers.
+ */
+int uv_getaddrinfo(uv_loop_t* loop,
+ uv_getaddrinfo_t* req,
+ uv_getaddrinfo_cb getaddrinfo_cb,
+ const char* node,
+ const char* service,
+ const struct addrinfo* hints) {
+ int nodesize = 0;
+ int servicesize = 0;
+ int hintssize = 0;
+ char* alloc_ptr = NULL;
+ int err;
+
+ if (req == NULL || (node == NULL && service == NULL)) {
+ return UV_EINVAL;
+ }
+
+ UV_REQ_INIT(req, UV_GETADDRINFO);
+ req->getaddrinfo_cb = getaddrinfo_cb;
+ req->addrinfo = NULL;
+ req->loop = loop;
+ req->retcode = 0;
+
+ /* calculate required memory size for all input values */
+ if (node != NULL) {
+ nodesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8, 0, node, -1, NULL, 0) *
+ sizeof(WCHAR));
+ if (nodesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ if (service != NULL) {
+ servicesize = ALIGNED_SIZE(MultiByteToWideChar(CP_UTF8,
+ 0,
+ service,
+ -1,
+ NULL,
+ 0) *
+ sizeof(WCHAR));
+ if (servicesize == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+ if (hints != NULL) {
+ hintssize = ALIGNED_SIZE(sizeof(struct addrinfoW));
+ }
+
+ /* allocate memory for inputs, and partition it as needed */
+ alloc_ptr = (char*)uv__malloc(nodesize + servicesize + hintssize);
+ if (!alloc_ptr) {
+ err = WSAENOBUFS;
+ goto error;
+ }
+
+ /* save alloc_ptr now so we can free if error */
+ req->alloc = (void*)alloc_ptr;
+
+ /* convert node string to UTF16 into allocated memory and save pointer in */
+ /* the request. */
+ if (node != NULL) {
+ req->node = (WCHAR*)alloc_ptr;
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ node,
+ -1,
+ (WCHAR*) alloc_ptr,
+ nodesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += nodesize;
+ } else {
+ req->node = NULL;
+ }
+
+ /* convert service string to UTF16 into allocated memory and save pointer */
+ /* in the req. */
+ if (service != NULL) {
+ req->service = (WCHAR*)alloc_ptr;
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ service,
+ -1,
+ (WCHAR*) alloc_ptr,
+ servicesize / sizeof(WCHAR)) == 0) {
+ err = GetLastError();
+ goto error;
+ }
+ alloc_ptr += servicesize;
+ } else {
+ req->service = NULL;
+ }
+
+ /* copy hints to allocated memory and save pointer in req */
+ if (hints != NULL) {
+ req->addrinfow = (struct addrinfoW*)alloc_ptr;
+ req->addrinfow->ai_family = hints->ai_family;
+ req->addrinfow->ai_socktype = hints->ai_socktype;
+ req->addrinfow->ai_protocol = hints->ai_protocol;
+ req->addrinfow->ai_flags = hints->ai_flags;
+ req->addrinfow->ai_addrlen = 0;
+ req->addrinfow->ai_canonname = NULL;
+ req->addrinfow->ai_addr = NULL;
+ req->addrinfow->ai_next = NULL;
+ } else {
+ req->addrinfow = NULL;
+ }
+
+ uv__req_register(loop, req);
+
+ if (getaddrinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getaddrinfo_work,
+ uv__getaddrinfo_done);
+ return 0;
+ } else {
+ uv__getaddrinfo_work(&req->work_req);
+ uv__getaddrinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+
+error:
+ if (req != NULL) {
+ uv__free(req->alloc);
+ req->alloc = NULL;
+ }
+ return uv_translate_sys_error(err);
+}
diff --git a/Utilities/cmlibuv/src/win/getnameinfo.c b/Utilities/cmlibuv/src/win/getnameinfo.c
new file mode 100644
index 000000000..9f10cd2a5
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/getnameinfo.c
@@ -0,0 +1,149 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy
+* of this software and associated documentation files (the "Software"), to
+* deal in the Software without restriction, including without limitation the
+* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+* sell copies of the Software, and to permit persons to whom the Software is
+* furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in
+* all copies or substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+* IN THE SOFTWARE.
+*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "req-inl.h"
+
+#ifndef GetNameInfo
+int WSAAPI GetNameInfoW(
+ const SOCKADDR *pSockaddr,
+ socklen_t SockaddrLength,
+ PWCHAR pNodeBuffer,
+ DWORD NodeBufferSize,
+ PWCHAR pServiceBuffer,
+ DWORD ServiceBufferSize,
+ INT Flags
+);
+#endif
+
+static void uv__getnameinfo_work(struct uv__work* w) {
+ uv_getnameinfo_t* req;
+ WCHAR host[NI_MAXHOST];
+ WCHAR service[NI_MAXSERV];
+ int ret = 0;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ if (GetNameInfoW((struct sockaddr*)&req->storage,
+ sizeof(req->storage),
+ host,
+ ARRAY_SIZE(host),
+ service,
+ ARRAY_SIZE(service),
+ req->flags)) {
+ ret = WSAGetLastError();
+ }
+ req->retcode = uv__getaddrinfo_translate_error(ret);
+
+ /* convert results to UTF-8 */
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ host,
+ -1,
+ req->host,
+ sizeof(req->host),
+ NULL,
+ NULL);
+
+ WideCharToMultiByte(CP_UTF8,
+ 0,
+ service,
+ -1,
+ req->service,
+ sizeof(req->service),
+ NULL,
+ NULL);
+}
+
+
+/*
+* Called from uv_run when complete.
+*/
+static void uv__getnameinfo_done(struct uv__work* w, int status) {
+ uv_getnameinfo_t* req;
+ char* host;
+ char* service;
+
+ req = container_of(w, uv_getnameinfo_t, work_req);
+ uv__req_unregister(req->loop, req);
+ host = service = NULL;
+
+ if (status == UV_ECANCELED) {
+ assert(req->retcode == 0);
+ req->retcode = UV_EAI_CANCELED;
+ } else if (req->retcode == 0) {
+ host = req->host;
+ service = req->service;
+ }
+
+ if (req->getnameinfo_cb)
+ req->getnameinfo_cb(req, req->retcode, host, service);
+}
+
+
+/*
+* Entry point for getnameinfo
+* return 0 if a callback will be made
+* return error code if validation fails
+*/
+int uv_getnameinfo(uv_loop_t* loop,
+ uv_getnameinfo_t* req,
+ uv_getnameinfo_cb getnameinfo_cb,
+ const struct sockaddr* addr,
+ int flags) {
+ if (req == NULL || addr == NULL)
+ return UV_EINVAL;
+
+ if (addr->sa_family == AF_INET) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in));
+ } else if (addr->sa_family == AF_INET6) {
+ memcpy(&req->storage,
+ addr,
+ sizeof(struct sockaddr_in6));
+ } else {
+ return UV_EINVAL;
+ }
+
+ UV_REQ_INIT(req, UV_GETNAMEINFO);
+ uv__req_register(loop, req);
+
+ req->getnameinfo_cb = getnameinfo_cb;
+ req->flags = flags;
+ req->loop = loop;
+ req->retcode = 0;
+
+ if (getnameinfo_cb) {
+ uv__work_submit(loop,
+ &req->work_req,
+ uv__getnameinfo_work,
+ uv__getnameinfo_done);
+ return 0;
+ } else {
+ uv__getnameinfo_work(&req->work_req);
+ uv__getnameinfo_done(&req->work_req, 0);
+ return req->retcode;
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/handle-inl.h b/Utilities/cmlibuv/src/win/handle-inl.h
new file mode 100644
index 000000000..8d0334cc5
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/handle-inl.h
@@ -0,0 +1,179 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_HANDLE_INL_H_
+#define UV_WIN_HANDLE_INL_H_
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define DECREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if (--(handle)->activecnt == 0 && \
+ !((handle)->flags & UV__HANDLE_CLOSING)) { \
+ uv__handle_stop((handle)); \
+ } \
+ assert((handle)->activecnt >= 0); \
+ } while (0)
+
+
+#define INCREASE_ACTIVE_COUNT(loop, handle) \
+ do { \
+ if ((handle)->activecnt++ == 0) { \
+ uv__handle_start((handle)); \
+ } \
+ assert((handle)->activecnt > 0); \
+ } while (0)
+
+
+#define DECREASE_PENDING_REQ_COUNT(handle) \
+ do { \
+ assert(handle->reqs_pending > 0); \
+ handle->reqs_pending--; \
+ \
+ if (handle->flags & UV__HANDLE_CLOSING && \
+ handle->reqs_pending == 0) { \
+ uv_want_endgame(loop, (uv_handle_t*)handle); \
+ } \
+ } while (0)
+
+
+#define uv__handle_closing(handle) \
+ do { \
+ assert(!((handle)->flags & UV__HANDLE_CLOSING)); \
+ \
+ if (!(((handle)->flags & UV__HANDLE_ACTIVE) && \
+ ((handle)->flags & UV__HANDLE_REF))) \
+ uv__active_handle_add((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV__HANDLE_CLOSING; \
+ (handle)->flags &= ~UV__HANDLE_ACTIVE; \
+ } while (0)
+
+
+#define uv__handle_close(handle) \
+ do { \
+ QUEUE_REMOVE(&(handle)->handle_queue); \
+ uv__active_handle_rm((uv_handle_t*) (handle)); \
+ \
+ (handle)->flags |= UV_HANDLE_CLOSED; \
+ \
+ if ((handle)->close_cb) \
+ (handle)->close_cb((uv_handle_t*) (handle)); \
+ } while (0)
+
+
+INLINE static void uv_want_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (!(handle->flags & UV_HANDLE_ENDGAME_QUEUED)) {
+ handle->flags |= UV_HANDLE_ENDGAME_QUEUED;
+
+ handle->endgame_next = loop->endgame_handles;
+ loop->endgame_handles = handle;
+ }
+}
+
+
+INLINE static void uv_process_endgames(uv_loop_t* loop) {
+ uv_handle_t* handle;
+
+ while (loop->endgame_handles) {
+ handle = loop->endgame_handles;
+ loop->endgame_handles = handle->endgame_next;
+
+ handle->flags &= ~UV_HANDLE_ENDGAME_QUEUED;
+
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_endgame(loop, (uv_tcp_t*) handle);
+ break;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_endgame(loop, (uv_pipe_t*) handle);
+ break;
+
+ case UV_TTY:
+ uv_tty_endgame(loop, (uv_tty_t*) handle);
+ break;
+
+ case UV_UDP:
+ uv_udp_endgame(loop, (uv_udp_t*) handle);
+ break;
+
+ case UV_POLL:
+ uv_poll_endgame(loop, (uv_poll_t*) handle);
+ break;
+
+ case UV_TIMER:
+ uv_timer_endgame(loop, (uv_timer_t*) handle);
+ break;
+
+ case UV_PREPARE:
+ case UV_CHECK:
+ case UV_IDLE:
+ uv_loop_watcher_endgame(loop, handle);
+ break;
+
+ case UV_ASYNC:
+ uv_async_endgame(loop, (uv_async_t*) handle);
+ break;
+
+ case UV_SIGNAL:
+ uv_signal_endgame(loop, (uv_signal_t*) handle);
+ break;
+
+ case UV_PROCESS:
+ uv_process_endgame(loop, (uv_process_t*) handle);
+ break;
+
+ case UV_FS_EVENT:
+ uv_fs_event_endgame(loop, (uv_fs_event_t*) handle);
+ break;
+
+ case UV_FS_POLL:
+ uv__fs_poll_endgame(loop, (uv_fs_poll_t*) handle);
+ break;
+
+ default:
+ assert(0);
+ break;
+ }
+ }
+}
+
+INLINE static HANDLE uv__get_osfhandle(int fd)
+{
+ /* _get_osfhandle() raises an assert in debug builds if the FD is invalid. */
+ /* But it also correctly checks the FD and returns INVALID_HANDLE_VALUE */
+ /* for invalid FDs in release builds (or if you let the assert continue). */
+ /* So this wrapper function disables asserts when calling _get_osfhandle. */
+
+ HANDLE handle;
+ UV_BEGIN_DISABLE_CRT_ASSERT();
+ handle = (HANDLE) _get_osfhandle(fd);
+ UV_END_DISABLE_CRT_ASSERT();
+ return handle;
+}
+
+#endif /* UV_WIN_HANDLE_INL_H_ */
diff --git a/Utilities/cmlibuv/src/win/handle.c b/Utilities/cmlibuv/src/win/handle.c
new file mode 100644
index 000000000..72b49d979
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/handle.c
@@ -0,0 +1,154 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+uv_handle_type uv_guess_handle(uv_file file) {
+ HANDLE handle;
+ DWORD mode;
+
+ if (file < 0) {
+ return UV_UNKNOWN_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(file);
+
+ switch (GetFileType(handle)) {
+ case FILE_TYPE_CHAR:
+ if (GetConsoleMode(handle, &mode)) {
+ return UV_TTY;
+ } else {
+ return UV_FILE;
+ }
+
+ case FILE_TYPE_PIPE:
+ return UV_NAMED_PIPE;
+
+ case FILE_TYPE_DISK:
+ return UV_FILE;
+
+ default:
+ return UV_UNKNOWN_HANDLE;
+ }
+}
+
+
+int uv_is_active(const uv_handle_t* handle) {
+ return (handle->flags & UV__HANDLE_ACTIVE) &&
+ !(handle->flags & UV__HANDLE_CLOSING);
+}
+
+
+void uv_close(uv_handle_t* handle, uv_close_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(0);
+ return;
+ }
+
+ handle->close_cb = cb;
+
+ /* Handle-specific close actions */
+ switch (handle->type) {
+ case UV_TCP:
+ uv_tcp_close(loop, (uv_tcp_t*)handle);
+ return;
+
+ case UV_NAMED_PIPE:
+ uv_pipe_close(loop, (uv_pipe_t*) handle);
+ return;
+
+ case UV_TTY:
+ uv_tty_close((uv_tty_t*) handle);
+ return;
+
+ case UV_UDP:
+ uv_udp_close(loop, (uv_udp_t*) handle);
+ return;
+
+ case UV_POLL:
+ uv_poll_close(loop, (uv_poll_t*) handle);
+ return;
+
+ case UV_TIMER:
+ uv_timer_stop((uv_timer_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_PREPARE:
+ uv_prepare_stop((uv_prepare_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_CHECK:
+ uv_check_stop((uv_check_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_IDLE:
+ uv_idle_stop((uv_idle_t*)handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ case UV_ASYNC:
+ uv_async_close(loop, (uv_async_t*) handle);
+ return;
+
+ case UV_SIGNAL:
+ uv_signal_close(loop, (uv_signal_t*) handle);
+ return;
+
+ case UV_PROCESS:
+ uv_process_close(loop, (uv_process_t*) handle);
+ return;
+
+ case UV_FS_EVENT:
+ uv_fs_event_close(loop, (uv_fs_event_t*) handle);
+ return;
+
+ case UV_FS_POLL:
+ uv__fs_poll_close((uv_fs_poll_t*) handle);
+ uv__handle_closing(handle);
+ uv_want_endgame(loop, handle);
+ return;
+
+ default:
+ /* Not supported */
+ abort();
+ }
+}
+
+
+int uv_is_closing(const uv_handle_t* handle) {
+ return !!(handle->flags & (UV__HANDLE_CLOSING | UV_HANDLE_CLOSED));
+}
diff --git a/Utilities/cmlibuv/src/win/internal.h b/Utilities/cmlibuv/src/win/internal.h
new file mode 100644
index 000000000..83601d57a
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/internal.h
@@ -0,0 +1,399 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_INTERNAL_H_
+#define UV_WIN_INTERNAL_H_
+
+#if defined(_MSC_VER)
+# pragma warning(push,1)
+#endif
+
+#include "uv.h"
+#include "../uv-common.h"
+
+#include "tree.h"
+#include "winapi.h"
+#include "winsock.h"
+
+#ifdef _MSC_VER
+# define INLINE __inline
+# define UV_THREAD_LOCAL __declspec( thread )
+#else
+# define INLINE inline
+# define UV_THREAD_LOCAL __thread
+#endif
+
+
+#ifdef _DEBUG
+
+extern UV_THREAD_LOCAL int uv__crt_assert_enabled;
+
+#define UV_BEGIN_DISABLE_CRT_ASSERT() \
+ { \
+ int uv__saved_crt_assert_enabled = uv__crt_assert_enabled; \
+ uv__crt_assert_enabled = FALSE;
+
+
+#define UV_END_DISABLE_CRT_ASSERT() \
+ uv__crt_assert_enabled = uv__saved_crt_assert_enabled; \
+ }
+
+#else
+#define UV_BEGIN_DISABLE_CRT_ASSERT()
+#define UV_END_DISABLE_CRT_ASSERT()
+#endif
+
+/*
+ * Handles
+ * (also see handle-inl.h)
+ */
+
+/* Used by all handles. */
+#define UV_HANDLE_CLOSED 0x00000002
+#define UV_HANDLE_ENDGAME_QUEUED 0x00000008
+
+/* uv-common.h: #define UV__HANDLE_CLOSING 0x00000001 */
+/* uv-common.h: #define UV__HANDLE_ACTIVE 0x00000040 */
+/* uv-common.h: #define UV__HANDLE_REF 0x00000020 */
+/* uv-common.h: #define UV_HANDLE_INTERNAL 0x00000080 */
+
+/* Used by streams and UDP handles. */
+#define UV_HANDLE_READING 0x00000100
+#define UV_HANDLE_BOUND 0x00000200
+#define UV_HANDLE_LISTENING 0x00000800
+#define UV_HANDLE_CONNECTION 0x00001000
+#define UV_HANDLE_READABLE 0x00008000
+#define UV_HANDLE_WRITABLE 0x00010000
+#define UV_HANDLE_READ_PENDING 0x00020000
+#define UV_HANDLE_SYNC_BYPASS_IOCP 0x00040000
+#define UV_HANDLE_ZERO_READ 0x00080000
+#define UV_HANDLE_EMULATE_IOCP 0x00100000
+#define UV_HANDLE_BLOCKING_WRITES 0x00200000
+#define UV_HANDLE_CANCELLATION_PENDING 0x00400000
+
+/* Used by uv_tcp_t and uv_udp_t handles */
+#define UV_HANDLE_IPV6 0x01000000
+
+/* Only used by uv_tcp_t handles. */
+#define UV_HANDLE_TCP_NODELAY 0x02000000
+#define UV_HANDLE_TCP_KEEPALIVE 0x04000000
+#define UV_HANDLE_TCP_SINGLE_ACCEPT 0x08000000
+#define UV_HANDLE_TCP_ACCEPT_STATE_CHANGING 0x10000000
+#define UV_HANDLE_TCP_SOCKET_CLOSED 0x20000000
+#define UV_HANDLE_SHARED_TCP_SOCKET 0x40000000
+
+/* Only used by uv_pipe_t handles. */
+#define UV_HANDLE_NON_OVERLAPPED_PIPE 0x01000000
+#define UV_HANDLE_PIPESERVER 0x02000000
+#define UV_HANDLE_PIPE_READ_CANCELABLE 0x04000000
+
+/* Only used by uv_tty_t handles. */
+#define UV_HANDLE_TTY_READABLE 0x01000000
+#define UV_HANDLE_TTY_RAW 0x02000000
+#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
+#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
+
+/* Only used by uv_poll_t handles. */
+#define UV_HANDLE_POLL_SLOW 0x02000000
+
+
+/*
+ * Requests: see req-inl.h
+ */
+
+
+/*
+ * Streams: see stream-inl.h
+ */
+
+
+/*
+ * TCP
+ */
+
+typedef struct {
+ WSAPROTOCOL_INFOW socket_info;
+ int delayed_error;
+} uv__ipc_socket_info_ex;
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb);
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client);
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tcp_write(uv_loop_t* loop, uv_write_t* req, uv_tcp_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tcp_try_write(uv_tcp_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle, uv_req_t* req);
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req);
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req);
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req);
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp);
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle);
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection);
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info);
+
+
+/*
+ * UDP
+ */
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle, uv_req_t* req);
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req);
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle);
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle);
+
+
+/*
+ * Pipes
+ */
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize);
+
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb);
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client);
+int uv_pipe_read_start(uv_pipe_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_pipe_write(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv_pipe_write2(uv_loop_t* loop, uv_write_t* req, uv_pipe_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_stream_t* send_handle,
+ uv_write_cb cb);
+void uv__pipe_pause_read(uv_pipe_t* handle);
+void uv__pipe_unpause_read(uv_pipe_t* handle);
+void uv__pipe_stop_read(uv_pipe_t* handle);
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req);
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req);
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req);
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req);
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req);
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle);
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle);
+
+
+/*
+ * TTY
+ */
+void uv_console_init(void);
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb);
+int uv_tty_read_stop(uv_tty_t* handle);
+int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
+ const uv_buf_t bufs[], unsigned int nbufs, uv_write_cb cb);
+int uv__tty_try_write(uv_tty_t* handle, const uv_buf_t bufs[],
+ unsigned int nbufs);
+void uv_tty_close(uv_tty_t* handle);
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req);
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req);
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req);
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req);
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle);
+
+
+/*
+ * Poll watchers
+ */
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req);
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle);
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle);
+
+
+/*
+ * Timers
+ */
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle);
+
+DWORD uv__next_timeout(const uv_loop_t* loop);
+void uv_process_timers(uv_loop_t* loop);
+
+
+/*
+ * Loop watchers
+ */
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle);
+
+void uv_prepare_invoke(uv_loop_t* loop);
+void uv_check_invoke(uv_loop_t* loop);
+void uv_idle_invoke(uv_loop_t* loop);
+
+void uv__once_init(void);
+
+
+/*
+ * Async watcher
+ */
+void uv_async_close(uv_loop_t* loop, uv_async_t* handle);
+void uv_async_endgame(uv_loop_t* loop, uv_async_t* handle);
+
+void uv_process_async_wakeup_req(uv_loop_t* loop, uv_async_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Signal watcher
+ */
+void uv_signals_init(void);
+int uv__signal_dispatch(int signum);
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle);
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle);
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req);
+
+
+/*
+ * Spawn
+ */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle);
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle);
+
+
+/*
+ * Error
+ */
+int uv_translate_sys_error(int sys_errno);
+
+
+/*
+ * FS
+ */
+void uv_fs_init(void);
+
+
+/*
+ * FS Event
+ */
+void uv_process_fs_event_req(uv_loop_t* loop, uv_req_t* req,
+ uv_fs_event_t* handle);
+void uv_fs_event_close(uv_loop_t* loop, uv_fs_event_t* handle);
+void uv_fs_event_endgame(uv_loop_t* loop, uv_fs_event_t* handle);
+
+
+/*
+ * Stat poller.
+ */
+void uv__fs_poll_endgame(uv_loop_t* loop, uv_fs_poll_t* handle);
+
+
+/*
+ * Utilities.
+ */
+void uv__util_init(void);
+
+uint64_t uv__hrtime(double scale);
+int uv_parent_pid(void);
+int uv_current_pid(void);
+__declspec(noreturn) void uv_fatal_error(const int errorno, const char* syscall);
+int uv__getpwuid_r(uv_passwd_t* pwd);
+int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8);
+int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16);
+
+
+/*
+ * Process stdio handles.
+ */
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr);
+void uv__stdio_destroy(BYTE* buffer);
+void uv__stdio_noinherit(BYTE* buffer);
+int uv__stdio_verify(BYTE* buffer, WORD size);
+WORD uv__stdio_size(BYTE* buffer);
+HANDLE uv__stdio_handle(BYTE* buffer, int fd);
+
+
+/*
+ * Winapi and ntapi utility functions
+ */
+void uv_winapi_init(void);
+
+
+/*
+ * Winsock utility functions
+ */
+void uv_winsock_init(void);
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status);
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target);
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target);
+
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine);
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped);
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+extern int uv_tcp_non_ifs_lsp_ipv4;
+extern int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+extern struct sockaddr_in uv_addr_ip4_any_;
+extern struct sockaddr_in6 uv_addr_ip6_any_;
+
+/*
+ * Wake all loops with fake message
+ */
+void uv__wake_all_loops(void);
+
+/*
+ * Init system wake-up detection
+ */
+void uv__init_detect_system_wakeup(void);
+
+#endif /* UV_WIN_INTERNAL_H_ */
diff --git a/Utilities/cmlibuv/src/win/loop-watcher.c b/Utilities/cmlibuv/src/win/loop-watcher.c
new file mode 100644
index 000000000..20e4509f8
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/loop-watcher.c
@@ -0,0 +1,122 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+void uv_loop_watcher_endgame(uv_loop_t* loop, uv_handle_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ handle->flags |= UV_HANDLE_CLOSED;
+ uv__handle_close(handle);
+ }
+}
+
+
+#define UV_LOOP_WATCHER_DEFINE(name, NAME) \
+ int uv_##name##_init(uv_loop_t* loop, uv_##name##_t* handle) { \
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_##NAME); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_start(uv_##name##_t* handle, uv_##name##_cb cb) { \
+ uv_loop_t* loop = handle->loop; \
+ uv_##name##_t* old_head; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (uv__is_active(handle)) \
+ return 0; \
+ \
+ if (cb == NULL) \
+ return UV_EINVAL; \
+ \
+ old_head = loop->name##_handles; \
+ \
+ handle->name##_next = old_head; \
+ handle->name##_prev = NULL; \
+ \
+ if (old_head) { \
+ old_head->name##_prev = handle; \
+ } \
+ \
+ loop->name##_handles = handle; \
+ \
+ handle->name##_cb = cb; \
+ uv__handle_start(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ int uv_##name##_stop(uv_##name##_t* handle) { \
+ uv_loop_t* loop = handle->loop; \
+ \
+ assert(handle->type == UV_##NAME); \
+ \
+ if (!uv__is_active(handle)) \
+ return 0; \
+ \
+ /* Update loop head if needed */ \
+ if (loop->name##_handles == handle) { \
+ loop->name##_handles = handle->name##_next; \
+ } \
+ \
+ /* Update the iterator-next pointer of needed */ \
+ if (loop->next_##name##_handle == handle) { \
+ loop->next_##name##_handle = handle->name##_next; \
+ } \
+ \
+ if (handle->name##_prev) { \
+ handle->name##_prev->name##_next = handle->name##_next; \
+ } \
+ if (handle->name##_next) { \
+ handle->name##_next->name##_prev = handle->name##_prev; \
+ } \
+ \
+ uv__handle_stop(handle); \
+ \
+ return 0; \
+ } \
+ \
+ \
+ void uv_##name##_invoke(uv_loop_t* loop) { \
+ uv_##name##_t* handle; \
+ \
+ (loop)->next_##name##_handle = (loop)->name##_handles; \
+ \
+ while ((loop)->next_##name##_handle != NULL) { \
+ handle = (loop)->next_##name##_handle; \
+ (loop)->next_##name##_handle = handle->name##_next; \
+ \
+ handle->name##_cb(handle); \
+ } \
+ }
+
+UV_LOOP_WATCHER_DEFINE(prepare, PREPARE)
+UV_LOOP_WATCHER_DEFINE(check, CHECK)
+UV_LOOP_WATCHER_DEFINE(idle, IDLE)
diff --git a/Utilities/cmlibuv/src/win/pipe.c b/Utilities/cmlibuv/src/win/pipe.c
new file mode 100644
index 000000000..edf300212
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/pipe.c
@@ -0,0 +1,2125 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+typedef struct uv__ipc_queue_item_s uv__ipc_queue_item_t;
+
+struct uv__ipc_queue_item_s {
+ /*
+ * NOTE: It is important for socket_info_ex to be the first field,
+ * because we will we assigning it to the pending_ipc_info.socket_info
+ */
+ uv__ipc_socket_info_ex socket_info_ex;
+ QUEUE member;
+ int tcp_connection;
+};
+
+/* A zero-size buffer for use by uv_pipe_read */
+static char uv_zero_[] = "";
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+/* The timeout that the pipe will wait for the remote end to write data */
+/* when the local ends wants to shut it down. */
+static const int64_t eof_timeout = 50; /* ms */
+
+static const int default_pending_pipe_instances = 4;
+
+/* Pipe prefix */
+static char pipe_prefix[] = "\\\\?\\pipe";
+static const int pipe_prefix_len = sizeof(pipe_prefix) - 1;
+
+/* IPC protocol flags. */
+#define UV_IPC_RAW_DATA 0x0001
+#define UV_IPC_TCP_SERVER 0x0002
+#define UV_IPC_TCP_CONNECTION 0x0004
+
+/* IPC frame header. */
+typedef struct {
+ int flags;
+ uint64_t raw_data_length;
+} uv_ipc_frame_header_t;
+
+/* IPC frame, which contains an imported TCP socket stream. */
+typedef struct {
+ uv_ipc_frame_header_t header;
+ uv__ipc_socket_info_ex socket_info_ex;
+} uv_ipc_frame_uv_stream;
+
+static void eof_timer_init(uv_pipe_t* pipe);
+static void eof_timer_start(uv_pipe_t* pipe);
+static void eof_timer_stop(uv_pipe_t* pipe);
+static void eof_timer_cb(uv_timer_t* timer);
+static void eof_timer_destroy(uv_pipe_t* pipe);
+static void eof_timer_close_cb(uv_handle_t* handle);
+
+
+static void uv_unique_pipe_name(char* ptr, char* name, size_t size) {
+ snprintf(name, size, "\\\\?\\pipe\\uv\\%p-%lu", ptr, GetCurrentProcessId());
+}
+
+
+int uv_pipe_init(uv_loop_t* loop, uv_pipe_t* handle, int ipc) {
+ uv_stream_init(loop, (uv_stream_t*)handle, UV_NAMED_PIPE);
+
+ handle->reqs_pending = 0;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->name = NULL;
+ handle->pipe.conn.ipc_pid = 0;
+ handle->pipe.conn.remaining_ipc_rawdata_bytes = 0;
+ QUEUE_INIT(&handle->pipe.conn.pending_ipc_info.queue);
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+ handle->ipc = ipc;
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ handle->pipe.conn.readfile_thread = NULL;
+
+ UV_REQ_INIT(&handle->pipe.conn.ipc_header_write_req, UV_UNKNOWN_REQ);
+
+ return 0;
+}
+
+
+static void uv_pipe_connection_init(uv_pipe_t* handle) {
+ uv_connection_init((uv_stream_t*) handle);
+ handle->read_req.data = handle;
+ handle->pipe.conn.eof_timer = NULL;
+ assert(!(handle->flags & UV_HANDLE_PIPESERVER));
+ if (pCancelSynchronousIo &&
+ handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ uv_mutex_init(&handle->pipe.conn.readfile_mutex);
+ handle->flags |= UV_HANDLE_PIPE_READ_CANCELABLE;
+ }
+}
+
+
+static HANDLE open_named_pipe(const WCHAR* name, DWORD* duplex_flags) {
+ HANDLE pipeHandle;
+
+ /*
+ * Assume that we have a duplex pipe first, so attempt to
+ * connect with GENERIC_READ | GENERIC_WRITE.
+ */
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+
+ /*
+ * If the pipe is not duplex CreateFileW fails with
+ * ERROR_ACCESS_DENIED. In that case try to connect
+ * as a read-only or write-only.
+ */
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_READABLE;
+ return pipeHandle;
+ }
+ }
+
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ pipeHandle = CreateFileW(name,
+ GENERIC_WRITE | FILE_READ_ATTRIBUTES,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ *duplex_flags = UV_HANDLE_WRITABLE;
+ return pipeHandle;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+}
+
+
+static void close_pipe(uv_pipe_t* pipe) {
+ assert(pipe->u.fd == -1 || pipe->u.fd > 2);
+ if (pipe->u.fd == -1)
+ CloseHandle(pipe->handle);
+ else
+ close(pipe->u.fd);
+
+ pipe->u.fd = -1;
+ pipe->handle = INVALID_HANDLE_VALUE;
+}
+
+
+int uv_stdio_pipe_server(uv_loop_t* loop, uv_pipe_t* handle, DWORD access,
+ char* name, size_t nameSize) {
+ HANDLE pipeHandle;
+ int err;
+ char* ptr = (char*)handle;
+
+ for (;;) {
+ uv_unique_pipe_name(ptr, name, nameSize);
+
+ pipeHandle = CreateNamedPipeA(name,
+ access | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 65536, 65536, 0,
+ NULL);
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ /* No name collisions. We're done. */
+ break;
+ }
+
+ err = GetLastError();
+ if (err != ERROR_PIPE_BUSY && err != ERROR_ACCESS_DENIED) {
+ goto error;
+ }
+
+ /* Pipe name collision. Increment the pointer and try again. */
+ ptr++;
+ }
+
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv_pipe_connection_init(handle);
+ handle->handle = pipeHandle;
+
+ return 0;
+
+ error:
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ return err;
+}
+
+
+static int uv_set_pipe_handle(uv_loop_t* loop,
+ uv_pipe_t* handle,
+ HANDLE pipeHandle,
+ int fd,
+ DWORD duplex_flags) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_MODE_INFORMATION mode_info;
+ DWORD mode = PIPE_READMODE_BYTE | PIPE_WAIT;
+ DWORD current_mode = 0;
+ DWORD err = 0;
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER) &&
+ handle->handle != INVALID_HANDLE_VALUE)
+ return UV_EBUSY;
+
+ if (!SetNamedPipeHandleState(pipeHandle, &mode, NULL, NULL)) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ /*
+ * SetNamedPipeHandleState can fail if the handle doesn't have either
+ * GENERIC_WRITE or FILE_WRITE_ATTRIBUTES.
+ * But if the handle already has the desired wait and blocking modes
+ * we can continue.
+ */
+ if (!GetNamedPipeHandleState(pipeHandle, &current_mode, NULL, NULL,
+ NULL, NULL, 0)) {
+ return -1;
+ } else if (current_mode & PIPE_NOWAIT) {
+ SetLastError(ERROR_ACCESS_DENIED);
+ return -1;
+ }
+ } else {
+ /* If this returns ERROR_INVALID_PARAMETER we probably opened
+ * something that is not a pipe. */
+ if (err == ERROR_INVALID_PARAMETER) {
+ SetLastError(WSAENOTSOCK);
+ }
+ return -1;
+ }
+ }
+
+ /* Check if the pipe was created with FILE_FLAG_OVERLAPPED. */
+ nt_status = pNtQueryInformationFile(pipeHandle,
+ &io_status,
+ &mode_info,
+ sizeof(mode_info),
+ FileModeInformation);
+ if (nt_status != STATUS_SUCCESS) {
+ return -1;
+ }
+
+ if (mode_info.Mode & FILE_SYNCHRONOUS_IO_ALERT ||
+ mode_info.Mode & FILE_SYNCHRONOUS_IO_NONALERT) {
+ /* Non-overlapped pipe. */
+ handle->flags |= UV_HANDLE_NON_OVERLAPPED_PIPE;
+ } else {
+ /* Overlapped pipe. Try to associate with IOCP. */
+ if (CreateIoCompletionPort(pipeHandle,
+ loop->iocp,
+ (ULONG_PTR)handle,
+ 0) == NULL) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ }
+ }
+
+ handle->handle = pipeHandle;
+ handle->u.fd = fd;
+ handle->flags |= duplex_flags;
+
+ return 0;
+}
+
+
+static DWORD WINAPI pipe_shutdown_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_shutdown_t* req;
+
+ req = (uv_shutdown_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ FlushFileBuffers(handle->handle);
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) {
+ int err;
+ DWORD result;
+ uv_shutdown_t* req;
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_PIPE_LOCAL_INFORMATION pipe_info;
+ uv__ipc_queue_item_t* item;
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ handle->flags &= ~UV_HANDLE_PIPE_READ_CANCELABLE;
+ uv_mutex_destroy(&handle->pipe.conn.readfile_mutex);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ req = handle->stream.conn.shutdown_req;
+
+ /* Clear the shutdown_req field so we don't go here again. */
+ handle->stream.conn.shutdown_req = NULL;
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ /* Already closing. Cancel the shutdown. */
+ if (req->cb) {
+ req->cb(req, UV_ECANCELED);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ /* Try to avoid flushing the pipe buffer in the thread pool. */
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &pipe_info,
+ sizeof pipe_info,
+ FilePipeLocalInformation);
+
+ if (nt_status != STATUS_SUCCESS) {
+ /* Failure */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = pRtlNtStatusToDosError(nt_status);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (pipe_info.OutboundQuota == pipe_info.WriteQuotaAvailable) {
+ /* Short-circuit, no need to call FlushFileBuffers. */
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ return;
+ }
+
+ /* Run FlushFileBuffers in the thread pool. */
+ result = QueueUserWorkItem(pipe_shutdown_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION);
+ if (result) {
+ return;
+
+ } else {
+ /* Failure. */
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ handle->flags |= UV_HANDLE_WRITABLE; /* Questionable */
+ if (req->cb) {
+ err = GetLastError();
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ /* Free pending sockets */
+ while (!QUEUE_EMPTY(&handle->pipe.conn.pending_ipc_info.queue)) {
+ QUEUE* q;
+ SOCKET socket;
+
+ q = QUEUE_HEAD(&handle->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ /* Materialize socket and close it */
+ socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &item->socket_info_ex.socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ uv__free(item);
+
+ if (socket != INVALID_SOCKET)
+ closesocket(socket);
+ }
+ handle->pipe.conn.pending_ipc_info.queue_len = 0;
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ assert(handle->pipe.serv.accept_reqs);
+ uv__free(handle->pipe.serv.accept_reqs);
+ handle->pipe.serv.accept_reqs = NULL;
+ }
+
+ uv__handle_close(handle);
+ }
+}
+
+
+void uv_pipe_pending_instances(uv_pipe_t* handle, int count) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return;
+ handle->pipe.serv.pending_instances = count;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+}
+
+
+/* Creates a pipe server. */
+int uv_pipe_bind(uv_pipe_t* handle, const char* name) {
+ uv_loop_t* loop = handle->loop;
+ int i, err, nameSize;
+ uv_pipe_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_BOUND) {
+ return UV_EINVAL;
+ }
+
+ if (!name) {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ handle->pipe.serv.pending_instances = default_pending_pipe_instances;
+ }
+
+ handle->pipe.serv.accept_reqs = (uv_pipe_accept_t*)
+ uv__malloc(sizeof(uv_pipe_accept_t) * handle->pipe.serv.pending_instances);
+ if (!handle->pipe.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ req = &handle->pipe.serv.accept_reqs[i];
+ UV_REQ_INIT(req, UV_ACCEPT);
+ req->data = handle;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ req->next_pending = NULL;
+ }
+
+ /* Convert name to UTF16. */
+ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ name,
+ -1,
+ handle->name,
+ nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /*
+ * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE.
+ * If this fails then there's already a pipe server for the given pipe name.
+ */
+ handle->pipe.serv.accept_reqs[0].pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED |
+ FILE_FLAG_FIRST_PIPE_INSTANCE,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED) {
+ err = WSAEADDRINUSE; /* Translates to UV_EADDRINUSE. */
+ } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) {
+ err = WSAEACCES; /* Translates to UV_EACCES. */
+ }
+ goto error;
+ }
+
+ if (uv_set_pipe_handle(loop,
+ handle,
+ handle->pipe.serv.accept_reqs[0].pipeHandle,
+ -1,
+ 0)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ handle->pipe.serv.pending_accepts = NULL;
+ handle->flags |= UV_HANDLE_PIPESERVER;
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle->pipe.serv.accept_reqs[0].pipeHandle);
+ handle->pipe.serv.accept_reqs[0].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static DWORD WINAPI pipe_connect_thread_proc(void* parameter) {
+ uv_loop_t* loop;
+ uv_pipe_t* handle;
+ uv_connect_t* req;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ req = (uv_connect_t*) parameter;
+ assert(req);
+ handle = (uv_pipe_t*) req->handle;
+ assert(handle);
+ loop = handle->loop;
+ assert(loop);
+
+ /* We're here because CreateFile on a pipe returned ERROR_PIPE_BUSY. */
+ /* We wait for the pipe to become available with WaitNamedPipe. */
+ while (WaitNamedPipeW(handle->name, 30000)) {
+ /* The pipe is now available, try to connect. */
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ SwitchToThread();
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE &&
+ !uv_set_pipe_handle(loop, handle, pipeHandle, -1, duplex_flags)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, req);
+
+ return 0;
+}
+
+
+void uv_pipe_connect(uv_connect_t* req, uv_pipe_t* handle,
+ const char* name, uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err, nameSize;
+ HANDLE pipeHandle = INVALID_HANDLE_VALUE;
+ DWORD duplex_flags;
+
+ UV_REQ_INIT(req, UV_CONNECT);
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Convert name to UTF16. */
+ nameSize = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0) * sizeof(WCHAR);
+ handle->name = (WCHAR*)uv__malloc(nameSize);
+ if (!handle->name) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ name,
+ -1,
+ handle->name,
+ nameSize / sizeof(WCHAR))) {
+ err = GetLastError();
+ goto error;
+ }
+
+ pipeHandle = open_named_pipe(handle->name, &duplex_flags);
+ if (pipeHandle == INVALID_HANDLE_VALUE) {
+ if (GetLastError() == ERROR_PIPE_BUSY) {
+ /* Wait for the server to make a pipe instance available. */
+ if (!QueueUserWorkItem(&pipe_connect_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+
+ return;
+ }
+
+ err = GetLastError();
+ goto error;
+ }
+
+ assert(pipeHandle != INVALID_HANDLE_VALUE);
+
+ if (uv_set_pipe_handle(loop,
+ (uv_pipe_t*) req->handle,
+ pipeHandle,
+ -1,
+ duplex_flags)) {
+ err = GetLastError();
+ goto error;
+ }
+
+ SET_REQ_SUCCESS(req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+
+error:
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ }
+
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, err);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ return;
+}
+
+
+void uv__pipe_pause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ /* Pause the ReadFile task briefly, to work
+ around the Windows kernel bug that causes
+ any access to a NamedPipe to deadlock if
+ any process has called ReadFile */
+ HANDLE h;
+ uv_mutex_lock(&handle->pipe.conn.readfile_mutex);
+ h = handle->pipe.conn.readfile_thread;
+ while (h) {
+ /* spinlock: we expect this to finish quickly,
+ or we are probably about to deadlock anyways
+ (in the kernel), so it doesn't matter */
+ pCancelSynchronousIo(h);
+ SwitchToThread(); /* yield thread control briefly */
+ h = handle->pipe.conn.readfile_thread;
+ }
+ }
+}
+
+
+void uv__pipe_unpause_read(uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_unlock(&handle->pipe.conn.readfile_mutex);
+ }
+}
+
+
+void uv__pipe_stop_read(uv_pipe_t* handle) {
+ handle->flags &= ~UV_HANDLE_READING;
+ uv__pipe_pause_read((uv_pipe_t*)handle);
+ uv__pipe_unpause_read((uv_pipe_t*)handle);
+}
+
+
+/* Cleans up uv_pipe_t (server or connection) and all resources associated */
+/* with it. */
+void uv_pipe_cleanup(uv_loop_t* loop, uv_pipe_t* handle) {
+ int i;
+ HANDLE pipeHandle;
+
+ uv__pipe_stop_read(handle);
+
+ if (handle->name) {
+ uv__free(handle->name);
+ handle->name = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_PIPESERVER) {
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ pipeHandle = handle->pipe.serv.accept_reqs[i].pipeHandle;
+ if (pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(pipeHandle);
+ handle->pipe.serv.accept_reqs[i].pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ handle->handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ eof_timer_destroy(handle);
+ }
+
+ if ((handle->flags & UV_HANDLE_CONNECTION)
+ && handle->handle != INVALID_HANDLE_VALUE)
+ close_pipe(handle);
+}
+
+
+void uv_pipe_close(uv_loop_t* loop, uv_pipe_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ uv_pipe_cleanup(loop, handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+}
+
+
+static void uv_pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_pipe_accept_t* req, BOOL firstInstance) {
+ assert(handle->flags & UV_HANDLE_LISTENING);
+
+ if (!firstInstance) {
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+
+ req->pipeHandle = CreateNamedPipeW(handle->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES, 65536, 65536, 0, NULL);
+
+ if (req->pipeHandle == INVALID_HANDLE_VALUE) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ if (uv_set_pipe_handle(loop, handle, req->pipeHandle, -1, 0)) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+ }
+
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+
+ if (!ConnectNamedPipe(req->pipeHandle, &req->u.io.overlapped) &&
+ GetLastError() != ERROR_IO_PENDING) {
+ if (GetLastError() == ERROR_PIPE_CONNECTED) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ }
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_accept(uv_pipe_t* server, uv_stream_t* client) {
+ uv_loop_t* loop = server->loop;
+ uv_pipe_t* pipe_client;
+ uv_pipe_accept_t* req;
+ QUEUE* q;
+ uv__ipc_queue_item_t* item;
+ int err;
+
+ if (server->ipc) {
+ if (QUEUE_EMPTY(&server->pipe.conn.pending_ipc_info.queue)) {
+ /* No valid pending sockets. */
+ return WSAEWOULDBLOCK;
+ }
+
+ q = QUEUE_HEAD(&server->pipe.conn.pending_ipc_info.queue);
+ QUEUE_REMOVE(q);
+ server->pipe.conn.pending_ipc_info.queue_len--;
+ item = QUEUE_DATA(q, uv__ipc_queue_item_t, member);
+
+ err = uv_tcp_import((uv_tcp_t*)client,
+ &item->socket_info_ex,
+ item->tcp_connection);
+ if (err != 0)
+ return err;
+
+ uv__free(item);
+
+ } else {
+ pipe_client = (uv_pipe_t*)client;
+
+ /* Find a connection instance that has been connected, but not yet */
+ /* accepted. */
+ req = server->pipe.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ /* Initialize the client handle and copy the pipeHandle to the client */
+ uv_pipe_connection_init(pipe_client);
+ pipe_client->handle = req->pipeHandle;
+ pipe_client->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+
+ /* Prepare the req to pick up a new connection */
+ server->pipe.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, server, req, FALSE);
+ }
+ }
+
+ return 0;
+}
+
+
+/* Starts listening for connections for the given pipe. */
+int uv_pipe_listen(uv_pipe_t* handle, int backlog, uv_connection_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int i;
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return WSAEINVAL;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (!(handle->flags & UV_HANDLE_PIPESERVER)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->stream.serv.connection_cb = cb;
+
+ /* First pipe handle should have already been created in uv_pipe_bind */
+ assert(handle->pipe.serv.accept_reqs[0].pipeHandle != INVALID_HANDLE_VALUE);
+
+ for (i = 0; i < handle->pipe.serv.pending_instances; i++) {
+ uv_pipe_queue_accept(loop, handle, &handle->pipe.serv.accept_reqs[i], i == 0);
+ }
+
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_zero_readfile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_read_t* req = (uv_read_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->data;
+ uv_loop_t* loop = handle->loop;
+ HANDLE hThread = NULL;
+ DWORD err;
+ uv_mutex_t *m = &handle->pipe.conn.readfile_mutex;
+
+ assert(req != NULL);
+ assert(req->type == UV_READ);
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ uv_mutex_lock(m); /* mutex controls *setting* of readfile_thread */
+ if (DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+ GetCurrentProcess(), &hThread,
+ 0, FALSE, DUPLICATE_SAME_ACCESS)) {
+ handle->pipe.conn.readfile_thread = hThread;
+ } else {
+ hThread = NULL;
+ }
+ uv_mutex_unlock(m);
+ }
+restart_readfile:
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ &bytes,
+ NULL);
+ if (!result) {
+ err = GetLastError();
+ if (err == ERROR_OPERATION_ABORTED &&
+ handle->flags & UV_HANDLE_PIPE_READ_CANCELABLE) {
+ if (handle->flags & UV_HANDLE_READING) {
+ /* just a brief break to do something else */
+ handle->pipe.conn.readfile_thread = NULL;
+ /* resume after it is finished */
+ uv_mutex_lock(m);
+ handle->pipe.conn.readfile_thread = hThread;
+ uv_mutex_unlock(m);
+ goto restart_readfile;
+ } else {
+ result = 1; /* successfully stopped reading */
+ }
+ }
+ }
+ if (hThread) {
+ assert(hThread == handle->pipe.conn.readfile_thread);
+ /* mutex does not control clearing readfile_thread */
+ handle->pipe.conn.readfile_thread = NULL;
+ uv_mutex_lock(m);
+ /* only when we hold the mutex lock is it safe to
+ open or close the handle */
+ CloseHandle(hThread);
+ uv_mutex_unlock(m);
+ }
+
+ if (!result) {
+ SET_REQ_ERROR(req, err);
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static DWORD WINAPI uv_pipe_writefile_thread_proc(void* parameter) {
+ int result;
+ DWORD bytes;
+ uv_write_t* req = (uv_write_t*) parameter;
+ uv_pipe_t* handle = (uv_pipe_t*) req->handle;
+ uv_loop_t* loop = handle->loop;
+
+ assert(req != NULL);
+ assert(req->type == UV_WRITE);
+ assert(handle->type == UV_NAMED_PIPE);
+ assert(req->write_buffer.base);
+
+ result = WriteFile(handle->handle,
+ req->write_buffer.base,
+ req->write_buffer.len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void CALLBACK post_completion_read_wait(void* context, BOOLEAN timed_out) {
+ uv_read_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_read_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_completion_write_wait(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_pipe_queue_read(uv_loop_t* loop, uv_pipe_t* handle) {
+ uv_read_t* req;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ if (!QueueUserWorkItem(&uv_pipe_zero_readfile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ } else {
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((uintptr_t) req->event_handle | 1);
+ }
+
+ /* Do 0-read */
+ result = ReadFile(handle->handle,
+ &uv_zero_,
+ 0,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (!req->event_handle) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ if (req->wait_handle == INVALID_HANDLE_VALUE) {
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_read_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ goto error;
+ }
+ }
+ }
+ }
+
+ /* Start the eof timer if there is one */
+ eof_timer_start(handle);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return;
+
+error:
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+int uv_pipe_read_start(uv_pipe_t* handle,
+ uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_pipe_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+static void uv_insert_non_overlapped_write_req(uv_pipe_t* handle,
+ uv_write_t* req) {
+ req->next_req = NULL;
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req->next_req =
+ handle->pipe.conn.non_overlapped_writes_tail->next_req;
+ handle->pipe.conn.non_overlapped_writes_tail->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ } else {
+ req->next_req = (uv_req_t*)req;
+ handle->pipe.conn.non_overlapped_writes_tail = req;
+ }
+}
+
+
+static uv_write_t* uv_remove_non_overlapped_write_req(uv_pipe_t* handle) {
+ uv_write_t* req;
+
+ if (handle->pipe.conn.non_overlapped_writes_tail) {
+ req = (uv_write_t*)handle->pipe.conn.non_overlapped_writes_tail->next_req;
+
+ if (req == handle->pipe.conn.non_overlapped_writes_tail) {
+ handle->pipe.conn.non_overlapped_writes_tail = NULL;
+ } else {
+ handle->pipe.conn.non_overlapped_writes_tail->next_req =
+ req->next_req;
+ }
+
+ return req;
+ } else {
+ /* queue empty */
+ return NULL;
+ }
+}
+
+
+static void uv_queue_non_overlapped_write(uv_pipe_t* handle) {
+ uv_write_t* req = uv_remove_non_overlapped_write_req(handle);
+ if (req) {
+ if (!QueueUserWorkItem(&uv_pipe_writefile_thread_proc,
+ req,
+ WT_EXECUTELONGFUNCTION)) {
+ uv_fatal_error(GetLastError(), "QueueUserWorkItem");
+ }
+ }
+}
+
+
+static int uv_pipe_write_impl(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ int err;
+ int result;
+ uv_tcp_t* tcp_send_handle;
+ uv_write_t* ipc_header_req = NULL;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ if (nbufs != 1 && (nbufs != 0 || !send_handle)) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ /* Only TCP handles are supported for sharing. */
+ if (send_handle && ((send_handle->type != UV_TCP) ||
+ (!(send_handle->flags & UV_HANDLE_BOUND) &&
+ !(send_handle->flags & UV_HANDLE_CONNECTION)))) {
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ assert(handle->handle != INVALID_HANDLE_VALUE);
+
+ UV_REQ_INIT(req, UV_WRITE);
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ req->ipc_header = 0;
+ req->event_handle = NULL;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ if (handle->ipc) {
+ assert(!(handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ ipc_frame.header.flags = 0;
+
+ /* Use the IPC framing protocol. */
+ if (send_handle) {
+ tcp_send_handle = (uv_tcp_t*)send_handle;
+
+ if (handle->pipe.conn.ipc_pid == 0) {
+ handle->pipe.conn.ipc_pid = uv_current_pid();
+ }
+
+ err = uv_tcp_duplicate_socket(tcp_send_handle, handle->pipe.conn.ipc_pid,
+ &ipc_frame.socket_info_ex.socket_info);
+ if (err) {
+ return err;
+ }
+
+ ipc_frame.socket_info_ex.delayed_error = tcp_send_handle->delayed_error;
+
+ ipc_frame.header.flags |= UV_IPC_TCP_SERVER;
+
+ if (tcp_send_handle->flags & UV_HANDLE_CONNECTION) {
+ ipc_frame.header.flags |= UV_IPC_TCP_CONNECTION;
+ }
+ }
+
+ if (nbufs == 1) {
+ ipc_frame.header.flags |= UV_IPC_RAW_DATA;
+ ipc_frame.header.raw_data_length = bufs[0].len;
+ }
+
+ /*
+ * Use the provided req if we're only doing a single write.
+ * If we're doing multiple writes, use ipc_header_write_req to do
+ * the first write, and then use the provided req for the second write.
+ */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ ipc_header_req = req;
+ } else {
+ /*
+ * Try to use the preallocated write req if it's available.
+ * Otherwise allocate a new one.
+ */
+ if (handle->pipe.conn.ipc_header_write_req.type != UV_WRITE) {
+ ipc_header_req = (uv_write_t*)&handle->pipe.conn.ipc_header_write_req;
+ } else {
+ ipc_header_req = (uv_write_t*)uv__malloc(sizeof(uv_write_t));
+ if (!ipc_header_req) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+ }
+
+ UV_REQ_INIT(ipc_header_req, UV_WRITE);
+ ipc_header_req->handle = (uv_stream_t*) handle;
+ ipc_header_req->cb = NULL;
+ ipc_header_req->ipc_header = 1;
+ }
+
+ /* Write the header or the whole frame. */
+ memset(&ipc_header_req->u.io.overlapped, 0,
+ sizeof(ipc_header_req->u.io.overlapped));
+
+ /* Using overlapped IO, but wait for completion before returning.
+ This write is blocking because ipc_frame is on stack. */
+ ipc_header_req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!ipc_header_req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ &ipc_frame,
+ ipc_frame.header.flags & UV_IPC_TCP_SERVER ?
+ sizeof(ipc_frame) : sizeof(ipc_frame.header),
+ NULL,
+ &ipc_header_req->u.io.overlapped);
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (!result) {
+ /* Request not completed immediately. Wait for it.*/
+ if (WaitForSingleObject(ipc_header_req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ return err;
+ }
+ }
+ ipc_header_req->u.io.queued_bytes = 0;
+ CloseHandle(ipc_header_req->u.io.overlapped.hEvent);
+ ipc_header_req->u.io.overlapped.hEvent = NULL;
+
+ REGISTER_HANDLE_REQ(loop, handle, ipc_header_req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ /* If we don't have any raw data to write - we're done. */
+ if (!(ipc_frame.header.flags & UV_IPC_RAW_DATA)) {
+ return 0;
+ }
+ }
+
+ if ((handle->flags &
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) ==
+ (UV_HANDLE_BLOCKING_WRITES | UV_HANDLE_NON_OVERLAPPED_PIPE)) {
+ DWORD bytes;
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ &bytes,
+ NULL);
+
+ if (!result) {
+ err = GetLastError();
+ return err;
+ } else {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ } else if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE) {
+ req->write_buffer = bufs[0];
+ uv_insert_non_overlapped_write_req(handle, req);
+ if (handle->stream.conn.write_reqs_pending == 0) {
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ } else if (handle->flags & UV_HANDLE_BLOCKING_WRITES) {
+ /* Using overlapped IO, but wait for completion before returning */
+ req->u.io.overlapped.hEvent = CreateEvent(NULL, 1, 0, NULL);
+ if (!req->u.io.overlapped.hEvent) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return err;
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (WaitForSingleObject(req->u.io.overlapped.hEvent, INFINITE) !=
+ WAIT_OBJECT_0) {
+ err = GetLastError();
+ CloseHandle(req->u.io.overlapped.hEvent);
+ return uv_translate_sys_error(err);
+ }
+ }
+ CloseHandle(req->u.io.overlapped.hEvent);
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ return 0;
+ } else {
+ result = WriteFile(handle->handle,
+ bufs[0].base,
+ bufs[0].len,
+ NULL,
+ &req->u.io.overlapped);
+
+ if (!result && GetLastError() != ERROR_IO_PENDING) {
+ return GetLastError();
+ }
+
+ if (result) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ } else {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = bufs[0].len;
+ handle->write_queue_size += req->u.io.queued_bytes;
+ }
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ if (!RegisterWaitForSingleObject(&req->wait_handle,
+ req->u.io.overlapped.hEvent, post_completion_write_wait, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ return GetLastError();
+ }
+ }
+ }
+
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+
+ return 0;
+}
+
+
+int uv_pipe_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, NULL, cb);
+}
+
+
+int uv_pipe_write2(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_pipe_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ if (!handle->ipc) {
+ return WSAEINVAL;
+ }
+
+ return uv_pipe_write_impl(loop, req, handle, bufs, nbufs, send_handle, cb);
+}
+
+
+static void uv_pipe_read_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ handle->flags &= ~UV_HANDLE_READABLE;
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*) handle, UV_EOF, &buf);
+}
+
+
+static void uv_pipe_read_error(uv_loop_t* loop, uv_pipe_t* handle, int error,
+ uv_buf_t buf) {
+ /* If there is an eof timer running, we don't need it any more, */
+ /* so discard it. */
+ eof_timer_destroy(handle);
+
+ uv_read_stop((uv_stream_t*) handle);
+
+ handle->read_cb((uv_stream_t*)handle, uv_translate_sys_error(error), &buf);
+}
+
+
+static void uv_pipe_read_error_or_eof(uv_loop_t* loop, uv_pipe_t* handle,
+ int error, uv_buf_t buf) {
+ if (error == ERROR_BROKEN_PIPE) {
+ uv_pipe_read_eof(loop, handle, buf);
+ } else {
+ uv_pipe_read_error(loop, handle, error, buf);
+ }
+}
+
+
+void uv__pipe_insert_pending_socket(uv_pipe_t* handle,
+ uv__ipc_socket_info_ex* info,
+ int tcp_connection) {
+ uv__ipc_queue_item_t* item;
+
+ item = (uv__ipc_queue_item_t*) uv__malloc(sizeof(*item));
+ if (item == NULL)
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+
+ memcpy(&item->socket_info_ex, info, sizeof(item->socket_info_ex));
+ item->tcp_connection = tcp_connection;
+ QUEUE_INSERT_TAIL(&handle->pipe.conn.pending_ipc_info.queue, &item->member);
+ handle->pipe.conn.pending_ipc_info.queue_len++;
+}
+
+
+void uv_process_pipe_read_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, avail;
+ uv_buf_t buf;
+ uv_ipc_frame_uv_stream ipc_frame;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ eof_timer_stop(handle);
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the 0-read. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_pipe_read_error_or_eof(loop,
+ handle,
+ GET_REQ_ERROR(req),
+ uv_null_buf_);
+ }
+ } else {
+ /* Do non-blocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ if (!PeekNamedPipe(handle->handle,
+ NULL,
+ 0,
+ NULL,
+ &avail,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), uv_null_buf_);
+ break;
+ }
+
+ if (avail == 0) {
+ /* There is nothing to read after all. */
+ break;
+ }
+
+ if (handle->ipc) {
+ /* Use the IPC framing protocol to read the incoming data. */
+ if (handle->pipe.conn.remaining_ipc_rawdata_bytes == 0) {
+ /* We're reading a new frame. First, read the header. */
+ assert(avail >= sizeof(ipc_frame.header));
+
+ if (!ReadFile(handle->handle,
+ &ipc_frame.header,
+ sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame.header));
+ assert(ipc_frame.header.flags <= (UV_IPC_TCP_SERVER | UV_IPC_RAW_DATA |
+ UV_IPC_TCP_CONNECTION));
+
+ if (ipc_frame.header.flags & UV_IPC_TCP_SERVER) {
+ assert(avail - sizeof(ipc_frame.header) >=
+ sizeof(ipc_frame.socket_info_ex));
+
+ /* Read the TCP socket info. */
+ if (!ReadFile(handle->handle,
+ &ipc_frame.socket_info_ex,
+ sizeof(ipc_frame) - sizeof(ipc_frame.header),
+ &bytes,
+ NULL)) {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(),
+ uv_null_buf_);
+ break;
+ }
+
+ assert(bytes == sizeof(ipc_frame) - sizeof(ipc_frame.header));
+
+ /* Store the pending socket info. */
+ uv__pipe_insert_pending_socket(
+ handle,
+ &ipc_frame.socket_info_ex,
+ ipc_frame.header.flags & UV_IPC_TCP_CONNECTION);
+ }
+
+ if (ipc_frame.header.flags & UV_IPC_RAW_DATA) {
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ ipc_frame.header.raw_data_length;
+ continue;
+ }
+ } else {
+ avail = min(avail, (DWORD)handle->pipe.conn.remaining_ipc_rawdata_bytes);
+ }
+ }
+
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, avail, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ if (ReadFile(handle->handle,
+ buf.base,
+ min(buf.len, avail),
+ &bytes,
+ NULL)) {
+ /* Successful read */
+ if (handle->ipc) {
+ assert(handle->pipe.conn.remaining_ipc_rawdata_bytes >= bytes);
+ handle->pipe.conn.remaining_ipc_rawdata_bytes =
+ handle->pipe.conn.remaining_ipc_rawdata_bytes - bytes;
+ }
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+
+ /* Read again only if bytes == buf.len */
+ if (bytes <= buf.len) {
+ break;
+ }
+ } else {
+ uv_pipe_read_error_or_eof(loop, handle, GetLastError(), buf);
+ break;
+ }
+ }
+
+ /* Post another 0-read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_pipe_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_write_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->ipc_header) {
+ if (req == &handle->pipe.conn.ipc_header_write_req) {
+ req->type = UV_UNKNOWN_REQ;
+ } else {
+ uv__free(req);
+ }
+ } else {
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+
+ if (handle->flags & UV_HANDLE_NON_OVERLAPPED_PIPE &&
+ handle->pipe.conn.non_overlapped_writes_tail) {
+ assert(handle->stream.conn.write_reqs_pending > 0);
+ uv_queue_non_overlapped_write(handle);
+ }
+
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_accept_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_req_t* raw_req) {
+ uv_pipe_accept_t* req = (uv_pipe_accept_t*) raw_req;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* The req->pipeHandle should be freed already in uv_pipe_cleanup(). */
+ assert(req->pipeHandle == INVALID_HANDLE_VALUE);
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (REQ_SUCCESS(req)) {
+ assert(req->pipeHandle != INVALID_HANDLE_VALUE);
+ req->next_pending = handle->pipe.serv.pending_accepts;
+ handle->pipe.serv.pending_accepts = req;
+
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ if (req->pipeHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(req->pipeHandle);
+ req->pipeHandle = INVALID_HANDLE_VALUE;
+ }
+ if (!(handle->flags & UV__HANDLE_CLOSING)) {
+ uv_pipe_queue_accept(loop, handle, req, FALSE);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_connect_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ uv_pipe_connection_init(handle);
+ } else {
+ err = GET_REQ_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_pipe_shutdown_req(uv_loop_t* loop, uv_pipe_t* handle,
+ uv_shutdown_t* req) {
+ assert(handle->type == UV_NAMED_PIPE);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_READABLE) {
+ /* Initialize and optionally start the eof timer. Only do this if the */
+ /* pipe is readable and we haven't seen EOF come in ourselves. */
+ eof_timer_init(handle);
+
+ /* If reading start the timer right now. */
+ /* Otherwise uv_pipe_queue_read will start it. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ eof_timer_start(handle);
+ }
+
+ } else {
+ /* This pipe is not readable. We can just close it to let the other end */
+ /* know that we're done writing. */
+ close_pipe(handle);
+ }
+
+ if (req->cb) {
+ req->cb(req, 0);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static void eof_timer_init(uv_pipe_t* pipe) {
+ int r;
+
+ assert(pipe->pipe.conn.eof_timer == NULL);
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ pipe->pipe.conn.eof_timer = (uv_timer_t*) uv__malloc(sizeof *pipe->pipe.conn.eof_timer);
+
+ r = uv_timer_init(pipe->loop, pipe->pipe.conn.eof_timer);
+ assert(r == 0); /* timers can't fail */
+ pipe->pipe.conn.eof_timer->data = pipe;
+ uv_unref((uv_handle_t*) pipe->pipe.conn.eof_timer);
+}
+
+
+static void eof_timer_start(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_start(pipe->pipe.conn.eof_timer, eof_timer_cb, eof_timeout, 0);
+ }
+}
+
+
+static void eof_timer_stop(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer != NULL) {
+ uv_timer_stop(pipe->pipe.conn.eof_timer);
+ }
+}
+
+
+static void eof_timer_cb(uv_timer_t* timer) {
+ uv_pipe_t* pipe = (uv_pipe_t*) timer->data;
+ uv_loop_t* loop = timer->loop;
+
+ assert(pipe->type == UV_NAMED_PIPE);
+
+ /* This should always be true, since we start the timer only */
+ /* in uv_pipe_queue_read after successfully calling ReadFile, */
+ /* or in uv_process_pipe_shutdown_req if a read is pending, */
+ /* and we always immediately stop the timer in */
+ /* uv_process_pipe_read_req. */
+ assert(pipe->flags & UV_HANDLE_READ_PENDING);
+
+ /* If there are many packets coming off the iocp then the timer callback */
+ /* may be called before the read request is coming off the queue. */
+ /* Therefore we check here if the read request has completed but will */
+ /* be processed later. */
+ if ((pipe->flags & UV_HANDLE_READ_PENDING) &&
+ HasOverlappedIoCompleted(&pipe->read_req.u.io.overlapped)) {
+ return;
+ }
+
+ /* Force both ends off the pipe. */
+ close_pipe(pipe);
+
+ /* Stop reading, so the pending read that is going to fail will */
+ /* not be reported to the user. */
+ uv_read_stop((uv_stream_t*) pipe);
+
+ /* Report the eof and update flags. This will get reported even if the */
+ /* user stopped reading in the meantime. TODO: is that okay? */
+ uv_pipe_read_eof(loop, pipe, uv_null_buf_);
+}
+
+
+static void eof_timer_destroy(uv_pipe_t* pipe) {
+ assert(pipe->flags & UV_HANDLE_CONNECTION);
+
+ if (pipe->pipe.conn.eof_timer) {
+ uv_close((uv_handle_t*) pipe->pipe.conn.eof_timer, eof_timer_close_cb);
+ pipe->pipe.conn.eof_timer = NULL;
+ }
+}
+
+
+static void eof_timer_close_cb(uv_handle_t* handle) {
+ assert(handle->type == UV_TIMER);
+ uv__free(handle);
+}
+
+
+int uv_pipe_open(uv_pipe_t* pipe, uv_file file) {
+ HANDLE os_handle = uv__get_osfhandle(file);
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_ACCESS_INFORMATION access;
+ DWORD duplex_flags = 0;
+
+ if (os_handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (file <= 2) {
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ os_handle,
+ INVALID_HANDLE_VALUE,
+ &os_handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ file = -1;
+ }
+
+ /* Determine what kind of permissions we have on this handle.
+ * Cygwin opens the pipe in message mode, but we can support it,
+ * just query the access flags and set the stream flags accordingly.
+ */
+ nt_status = pNtQueryInformationFile(os_handle,
+ &io_status,
+ &access,
+ sizeof(access),
+ FileAccessInformation);
+ if (nt_status != STATUS_SUCCESS)
+ return UV_EINVAL;
+
+ if (pipe->ipc) {
+ if (!(access.AccessFlags & FILE_WRITE_DATA) ||
+ !(access.AccessFlags & FILE_READ_DATA)) {
+ return UV_EINVAL;
+ }
+ }
+
+ if (access.AccessFlags & FILE_WRITE_DATA)
+ duplex_flags |= UV_HANDLE_WRITABLE;
+ if (access.AccessFlags & FILE_READ_DATA)
+ duplex_flags |= UV_HANDLE_READABLE;
+
+ if (os_handle == INVALID_HANDLE_VALUE ||
+ uv_set_pipe_handle(pipe->loop,
+ pipe,
+ os_handle,
+ file,
+ duplex_flags) == -1) {
+ return UV_EINVAL;
+ }
+
+ uv_pipe_connection_init(pipe);
+
+ if (pipe->ipc) {
+ assert(!(pipe->flags & UV_HANDLE_NON_OVERLAPPED_PIPE));
+ pipe->pipe.conn.ipc_pid = uv_parent_pid();
+ assert(pipe->pipe.conn.ipc_pid != -1);
+ }
+ return 0;
+}
+
+
+static int uv__pipe_getname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ NTSTATUS nt_status;
+ IO_STATUS_BLOCK io_status;
+ FILE_NAME_INFORMATION tmp_name_info;
+ FILE_NAME_INFORMATION* name_info;
+ WCHAR* name_buf;
+ unsigned int addrlen;
+ unsigned int name_size;
+ unsigned int name_len;
+ int err;
+
+ name_info = NULL;
+
+ if (handle->handle == INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return UV_EINVAL;
+ }
+
+ uv__pipe_pause_read((uv_pipe_t*)handle); /* cast away const warning */
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ &tmp_name_info,
+ sizeof tmp_name_info,
+ FileNameInformation);
+ if (nt_status == STATUS_BUFFER_OVERFLOW) {
+ name_size = sizeof(*name_info) + tmp_name_info.FileNameLength;
+ name_info = uv__malloc(name_size);
+ if (!name_info) {
+ *size = 0;
+ err = UV_ENOMEM;
+ goto cleanup;
+ }
+
+ nt_status = pNtQueryInformationFile(handle->handle,
+ &io_status,
+ name_info,
+ name_size,
+ FileNameInformation);
+ }
+
+ if (nt_status != STATUS_SUCCESS) {
+ *size = 0;
+ err = uv_translate_sys_error(pRtlNtStatusToDosError(nt_status));
+ goto error;
+ }
+
+ if (!name_info) {
+ /* the struct on stack was used */
+ name_buf = tmp_name_info.FileName;
+ name_len = tmp_name_info.FileNameLength;
+ } else {
+ name_buf = name_info->FileName;
+ name_len = name_info->FileNameLength;
+ }
+
+ if (name_len == 0) {
+ *size = 0;
+ err = 0;
+ goto error;
+ }
+
+ name_len /= sizeof(WCHAR);
+
+ /* check how much space we need */
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ } else if (pipe_prefix_len + addrlen >= *size) {
+ /* "\\\\.\\pipe" + name */
+ *size = pipe_prefix_len + addrlen + 1;
+ err = UV_ENOBUFS;
+ goto error;
+ }
+
+ memcpy(buffer, pipe_prefix, pipe_prefix_len);
+ addrlen = WideCharToMultiByte(CP_UTF8,
+ 0,
+ name_buf,
+ name_len,
+ buffer+pipe_prefix_len,
+ *size-pipe_prefix_len,
+ NULL,
+ NULL);
+ if (!addrlen) {
+ *size = 0;
+ err = uv_translate_sys_error(GetLastError());
+ goto error;
+ }
+
+ addrlen += pipe_prefix_len;
+ *size = addrlen;
+ buffer[addrlen] = '\0';
+
+ err = 0;
+
+error:
+ uv__free(name_info);
+
+cleanup:
+ uv__pipe_unpause_read((uv_pipe_t*)handle); /* cast away const warning */
+ return err;
+}
+
+
+int uv_pipe_pending_count(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return 0;
+ return handle->pipe.conn.pending_ipc_info.queue_len;
+}
+
+
+int uv_pipe_getsockname(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ if (handle->flags & UV_HANDLE_BOUND)
+ return uv__pipe_getname(handle, buffer, size);
+
+ if (handle->flags & UV_HANDLE_CONNECTION ||
+ handle->handle != INVALID_HANDLE_VALUE) {
+ *size = 0;
+ return 0;
+ }
+
+ return UV_EBADF;
+}
+
+
+int uv_pipe_getpeername(const uv_pipe_t* handle, char* buffer, size_t* size) {
+ /* emulate unix behaviour */
+ if (handle->flags & UV_HANDLE_BOUND)
+ return UV_ENOTCONN;
+
+ if (handle->handle != INVALID_HANDLE_VALUE)
+ return uv__pipe_getname(handle, buffer, size);
+
+ return UV_EBADF;
+}
+
+
+uv_handle_type uv_pipe_pending_type(uv_pipe_t* handle) {
+ if (!handle->ipc)
+ return UV_UNKNOWN_HANDLE;
+ if (handle->pipe.conn.pending_ipc_info.queue_len == 0)
+ return UV_UNKNOWN_HANDLE;
+ else
+ return UV_TCP;
+}
diff --git a/Utilities/cmlibuv/src/win/poll.c b/Utilities/cmlibuv/src/win/poll.c
new file mode 100644
index 000000000..a648ba711
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/poll.c
@@ -0,0 +1,644 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+static const GUID uv_msafd_provider_ids[UV_MSAFD_PROVIDER_COUNT] = {
+ {0xe70f1aa0, 0xab8b, 0x11cf,
+ {0x8c, 0xa3, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92}},
+ {0xf9eab0c0, 0x26d4, 0x11d0,
+ {0xbb, 0xbf, 0x00, 0xaa, 0x00, 0x6c, 0x34, 0xe4}},
+ {0x9fc48064, 0x7298, 0x43e4,
+ {0xb7, 0xbd, 0x18, 0x1f, 0x20, 0x89, 0x79, 0x2a}}
+};
+
+typedef struct uv_single_fd_set_s {
+ unsigned int fd_count;
+ SOCKET fd_array[1];
+} uv_single_fd_set_t;
+
+
+static OVERLAPPED overlapped_dummy_;
+static uv_once_t overlapped_dummy_init_guard_ = UV_ONCE_INIT;
+
+static AFD_POLL_INFO afd_poll_info_dummy_;
+
+
+static void uv__init_overlapped_dummy(void) {
+ HANDLE event;
+
+ event = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (event == NULL)
+ uv_fatal_error(GetLastError(), "CreateEvent");
+
+ memset(&overlapped_dummy_, 0, sizeof overlapped_dummy_);
+ overlapped_dummy_.hEvent = (HANDLE) ((uintptr_t) event | 1);
+}
+
+
+static OVERLAPPED* uv__get_overlapped_dummy(void) {
+ uv_once(&overlapped_dummy_init_guard_, uv__init_overlapped_dummy);
+ return &overlapped_dummy_;
+}
+
+
+static AFD_POLL_INFO* uv__get_afd_poll_info_dummy(void) {
+ return &afd_poll_info_dummy_;
+}
+
+
+static void uv__fast_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+ AFD_POLL_INFO* afd_poll_info;
+ DWORD result;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ /* Just wait until there's an unsubmitted req. */
+ /* This will happen almost immediately as one of the 2 outstanding */
+ /* requests is about to return. When this happens, */
+ /* uv__fast_poll_process_poll_req will be called, and the pending */
+ /* events, if needed, will be processed in a subsequent request. */
+ return;
+ }
+
+ /* Setting Exclusive to TRUE makes the other poll request return if there */
+ /* is any. */
+ afd_poll_info->Exclusive = TRUE;
+ afd_poll_info->NumberOfHandles = 1;
+ afd_poll_info->Timeout.QuadPart = INT64_MAX;
+ afd_poll_info->Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info->Handles[0].Status = 0;
+ afd_poll_info->Handles[0].Events = 0;
+
+ if (handle->events & UV_READABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT;
+ } else {
+ if (handle->events & UV_DISCONNECT) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_DISCONNECT;
+ }
+ }
+ if (handle->events & UV_WRITABLE) {
+ afd_poll_info->Handles[0].Events |= AFD_POLL_SEND | AFD_POLL_CONNECT_FAIL;
+ }
+
+ memset(&req->u.io.overlapped, 0, sizeof req->u.io.overlapped);
+
+ result = uv_msafd_poll((SOCKET) handle->peer_socket,
+ afd_poll_info,
+ afd_poll_info,
+ &req->u.io.overlapped);
+ if (result != 0 && WSAGetLastError() != WSA_IO_PENDING) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+static int uv__fast_poll_cancel_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ AFD_POLL_INFO afd_poll_info;
+ DWORD result;
+
+ afd_poll_info.Exclusive = TRUE;
+ afd_poll_info.NumberOfHandles = 1;
+ afd_poll_info.Timeout.QuadPart = INT64_MAX;
+ afd_poll_info.Handles[0].Handle = (HANDLE) handle->socket;
+ afd_poll_info.Handles[0].Status = 0;
+ afd_poll_info.Handles[0].Events = AFD_POLL_ALL;
+
+ result = uv_msafd_poll(handle->socket,
+ &afd_poll_info,
+ uv__get_afd_poll_info_dummy(),
+ uv__get_overlapped_dummy());
+
+ if (result == SOCKET_ERROR) {
+ DWORD error = WSAGetLastError();
+ if (error != WSA_IO_PENDING)
+ return error;
+ }
+
+ return 0;
+}
+
+
+static void uv__fast_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ AFD_POLL_INFO* afd_poll_info;
+
+ if (req == &handle->poll_req_1) {
+ afd_poll_info = &handle->afd_poll_info_1;
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ afd_poll_info = &handle->afd_poll_info_2;
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ /* Report an error unless the select was just interrupted. */
+ if (!REQ_SUCCESS(req)) {
+ DWORD error = GET_REQ_SOCK_ERROR(req);
+ if (error != WSAEINTR && handle->events != 0) {
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(error), 0);
+ }
+
+ } else if (afd_poll_info->NumberOfHandles >= 1) {
+ unsigned char events = 0;
+
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_RECEIVE |
+ AFD_POLL_DISCONNECT | AFD_POLL_ACCEPT | AFD_POLL_ABORT)) != 0) {
+ events |= UV_READABLE;
+ if ((afd_poll_info->Handles[0].Events & AFD_POLL_DISCONNECT) != 0) {
+ events |= UV_DISCONNECT;
+ }
+ }
+ if ((afd_poll_info->Handles[0].Events & (AFD_POLL_SEND |
+ AFD_POLL_CONNECT_FAIL)) != 0) {
+ events |= UV_WRITABLE;
+ }
+
+ events &= handle->events & ~mask_events;
+
+ if (afd_poll_info->Handles[0].Events & AFD_POLL_LOCAL_CLOSE) {
+ /* Stop polling. */
+ handle->events = 0;
+ if (uv__is_active(handle))
+ uv__handle_stop(handle);
+ }
+
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__fast_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE | UV_DISCONNECT)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__fast_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__fast_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return 0;
+ } else {
+ /* Cancel outstanding poll requests by executing another, unique poll */
+ /* request that forces the outstanding ones to return. */
+ return uv__fast_poll_cancel_poll_req(loop, handle);
+ }
+}
+
+
+static SOCKET uv__fast_poll_create_peer_socket(HANDLE iocp,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ SOCKET sock = 0;
+
+ sock = WSASocketW(protocol_info->iAddressFamily,
+ protocol_info->iSocketType,
+ protocol_info->iProtocol,
+ protocol_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+ if (sock == INVALID_SOCKET) {
+ return INVALID_SOCKET;
+ }
+
+ if (!SetHandleInformation((HANDLE) sock, HANDLE_FLAG_INHERIT, 0)) {
+ goto error;
+ };
+
+ if (CreateIoCompletionPort((HANDLE) sock,
+ iocp,
+ (ULONG_PTR) sock,
+ 0) == NULL) {
+ goto error;
+ }
+
+ return sock;
+
+ error:
+ closesocket(sock);
+ return INVALID_SOCKET;
+}
+
+
+static SOCKET uv__fast_poll_get_peer_socket(uv_loop_t* loop,
+ WSAPROTOCOL_INFOW* protocol_info) {
+ int index, i;
+ SOCKET peer_socket;
+
+ index = -1;
+ for (i = 0; (size_t) i < ARRAY_SIZE(uv_msafd_provider_ids); i++) {
+ if (memcmp((void*) &protocol_info->ProviderId,
+ (void*) &uv_msafd_provider_ids[i],
+ sizeof protocol_info->ProviderId) == 0) {
+ index = i;
+ }
+ }
+
+ /* Check if the protocol uses an msafd socket. */
+ if (index < 0) {
+ return INVALID_SOCKET;
+ }
+
+ /* If we didn't (try) to create a peer socket yet, try to make one. Don't */
+ /* try again if the peer socket creation failed earlier for the same */
+ /* protocol. */
+ peer_socket = loop->poll_peer_sockets[index];
+ if (peer_socket == 0) {
+ peer_socket = uv__fast_poll_create_peer_socket(loop->iocp, protocol_info);
+ loop->poll_peer_sockets[index] = peer_socket;
+ }
+
+ return peer_socket;
+}
+
+
+static DWORD WINAPI uv__slow_poll_thread_proc(void* arg) {
+ uv_req_t* req = (uv_req_t*) arg;
+ uv_poll_t* handle = (uv_poll_t*) req->data;
+ unsigned char reported_events;
+ int r;
+ uv_single_fd_set_t rfds, wfds, efds;
+ struct timeval timeout;
+
+ assert(handle->type == UV_POLL);
+ assert(req->type == UV_POLL_REQ);
+
+ if (handle->events & UV_READABLE) {
+ rfds.fd_count = 1;
+ rfds.fd_array[0] = handle->socket;
+ } else {
+ rfds.fd_count = 0;
+ }
+
+ if (handle->events & UV_WRITABLE) {
+ wfds.fd_count = 1;
+ wfds.fd_array[0] = handle->socket;
+ efds.fd_count = 1;
+ efds.fd_array[0] = handle->socket;
+ } else {
+ wfds.fd_count = 0;
+ efds.fd_count = 0;
+ }
+
+ /* Make the select() time out after 3 minutes. If select() hangs because */
+ /* the user closed the socket, we will at least not hang indefinitely. */
+ timeout.tv_sec = 3 * 60;
+ timeout.tv_usec = 0;
+
+ r = select(1, (fd_set*) &rfds, (fd_set*) &wfds, (fd_set*) &efds, &timeout);
+ if (r == SOCKET_ERROR) {
+ /* Queue this req, reporting an error. */
+ SET_REQ_ERROR(&handle->poll_req_1, WSAGetLastError());
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+ return 0;
+ }
+
+ reported_events = 0;
+
+ if (r > 0) {
+ if (rfds.fd_count > 0) {
+ assert(rfds.fd_count == 1);
+ assert(rfds.fd_array[0] == handle->socket);
+ reported_events |= UV_READABLE;
+ }
+
+ if (wfds.fd_count > 0) {
+ assert(wfds.fd_count == 1);
+ assert(wfds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ } else if (efds.fd_count > 0) {
+ assert(efds.fd_count == 1);
+ assert(efds.fd_array[0] == handle->socket);
+ reported_events |= UV_WRITABLE;
+ }
+ }
+
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = (DWORD) reported_events;
+ POST_COMPLETION_FOR_REQ(handle->loop, req);
+
+ return 0;
+}
+
+
+static void uv__slow_poll_submit_poll_req(uv_loop_t* loop, uv_poll_t* handle) {
+ uv_req_t* req;
+
+ /* Find a yet unsubmitted req to submit. */
+ if (handle->submitted_events_1 == 0) {
+ req = &handle->poll_req_1;
+ handle->submitted_events_1 = handle->events;
+ handle->mask_events_1 = 0;
+ handle->mask_events_2 = handle->events;
+ } else if (handle->submitted_events_2 == 0) {
+ req = &handle->poll_req_2;
+ handle->submitted_events_2 = handle->events;
+ handle->mask_events_1 = handle->events;
+ handle->mask_events_2 = 0;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!QueueUserWorkItem(uv__slow_poll_thread_proc,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION)) {
+ /* Make this req pending, reporting an error. */
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, req);
+ }
+}
+
+
+
+static void uv__slow_poll_process_poll_req(uv_loop_t* loop, uv_poll_t* handle,
+ uv_req_t* req) {
+ unsigned char mask_events;
+ int err;
+
+ if (req == &handle->poll_req_1) {
+ handle->submitted_events_1 = 0;
+ mask_events = handle->mask_events_1;
+ } else if (req == &handle->poll_req_2) {
+ handle->submitted_events_2 = 0;
+ mask_events = handle->mask_events_2;
+ } else {
+ assert(0);
+ return;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* Error. */
+ if (handle->events != 0) {
+ err = GET_REQ_ERROR(req);
+ handle->events = 0; /* Stop the watcher */
+ handle->poll_cb(handle, uv_translate_sys_error(err), 0);
+ }
+ } else {
+ /* Got some events. */
+ int events = req->u.io.overlapped.InternalHigh & handle->events & ~mask_events;
+ if (events != 0) {
+ handle->poll_cb(handle, 0, events);
+ }
+ }
+
+ if ((handle->events & ~(handle->submitted_events_1 |
+ handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(loop, handle);
+ } else if ((handle->flags & UV__HANDLE_CLOSING) &&
+ handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+static int uv__slow_poll_set(uv_loop_t* loop, uv_poll_t* handle, int events) {
+ assert(handle->type == UV_POLL);
+ assert(!(handle->flags & UV__HANDLE_CLOSING));
+ assert((events & ~(UV_READABLE | UV_WRITABLE)) == 0);
+
+ handle->events = events;
+
+ if (handle->events != 0) {
+ uv__handle_start(handle);
+ } else {
+ uv__handle_stop(handle);
+ }
+
+ if ((handle->events &
+ ~(handle->submitted_events_1 | handle->submitted_events_2)) != 0) {
+ uv__slow_poll_submit_poll_req(handle->loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__slow_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ handle->events = 0;
+ uv__handle_closing(handle);
+
+ if (handle->submitted_events_1 == 0 &&
+ handle->submitted_events_2 == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+
+ return 0;
+}
+
+
+int uv_poll_init(uv_loop_t* loop, uv_poll_t* handle, int fd) {
+ return uv_poll_init_socket(loop, handle, (SOCKET) uv__get_osfhandle(fd));
+}
+
+
+int uv_poll_init_socket(uv_loop_t* loop, uv_poll_t* handle,
+ uv_os_sock_t socket) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int len;
+ SOCKET peer_socket, base_socket;
+ DWORD bytes;
+ DWORD yes = 1;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ /* Try to obtain a base handle for the socket. This increases this chances */
+ /* that we find an AFD handle and are able to use the fast poll mechanism. */
+ /* This will always fail on windows XP/2k3, since they don't support the */
+ /* SIO_BASE_HANDLE ioctl. */
+#ifndef NDEBUG
+ base_socket = INVALID_SOCKET;
+#endif
+
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &base_socket,
+ sizeof base_socket,
+ &bytes,
+ NULL,
+ NULL) == 0) {
+ assert(base_socket != 0 && base_socket != INVALID_SOCKET);
+ socket = base_socket;
+ }
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_POLL);
+ handle->socket = socket;
+ handle->events = 0;
+
+ /* Obtain protocol information about the socket. */
+ len = sizeof protocol_info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &len) != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ /* Get the peer socket that is needed to enable fast poll. If the returned */
+ /* value is NULL, the protocol is not implemented by MSAFD and we'll have */
+ /* to use slow mode. */
+ peer_socket = uv__fast_poll_get_peer_socket(loop, &protocol_info);
+
+ if (peer_socket != INVALID_SOCKET) {
+ /* Initialize fast poll specific fields. */
+ handle->peer_socket = peer_socket;
+ } else {
+ /* Initialize slow poll specific fields. */
+ handle->flags |= UV_HANDLE_POLL_SLOW;
+ }
+
+ /* Initialize 2 poll reqs. */
+ handle->submitted_events_1 = 0;
+ UV_REQ_INIT(&handle->poll_req_1, UV_POLL_REQ);
+ handle->poll_req_1.data = handle;
+
+ handle->submitted_events_2 = 0;
+ UV_REQ_INIT(&handle->poll_req_2, UV_POLL_REQ);
+ handle->poll_req_2.data = handle;
+
+ return 0;
+}
+
+
+int uv_poll_start(uv_poll_t* handle, int events, uv_poll_cb cb) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, events);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, events);
+ }
+
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ handle->poll_cb = cb;
+
+ return 0;
+}
+
+
+int uv_poll_stop(uv_poll_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ err = uv__fast_poll_set(handle->loop, handle, 0);
+ } else {
+ err = uv__slow_poll_set(handle->loop, handle, 0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_process_poll_req(uv_loop_t* loop, uv_poll_t* handle, uv_req_t* req) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ uv__fast_poll_process_poll_req(loop, handle, req);
+ } else {
+ uv__slow_poll_process_poll_req(loop, handle, req);
+ }
+}
+
+
+int uv_poll_close(uv_loop_t* loop, uv_poll_t* handle) {
+ if (!(handle->flags & UV_HANDLE_POLL_SLOW)) {
+ return uv__fast_poll_close(loop, handle);
+ } else {
+ return uv__slow_poll_close(loop, handle);
+ }
+}
+
+
+void uv_poll_endgame(uv_loop_t* loop, uv_poll_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->submitted_events_1 == 0);
+ assert(handle->submitted_events_2 == 0);
+
+ uv__handle_close(handle);
+}
diff --git a/Utilities/cmlibuv/src/win/process-stdio.c b/Utilities/cmlibuv/src/win/process-stdio.c
new file mode 100644
index 000000000..032e30935
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/process-stdio.c
@@ -0,0 +1,511 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+
+
+/*
+ * The `child_stdio_buffer` buffer has the following layout:
+ * int number_of_fds
+ * unsigned char crt_flags[number_of_fds]
+ * HANDLE os_handle[number_of_fds]
+ */
+#define CHILD_STDIO_SIZE(count) \
+ (sizeof(int) + \
+ sizeof(unsigned char) * (count) + \
+ sizeof(uintptr_t) * (count))
+
+#define CHILD_STDIO_COUNT(buffer) \
+ *((unsigned int*) (buffer))
+
+#define CHILD_STDIO_CRT_FLAGS(buffer, fd) \
+ *((unsigned char*) (buffer) + sizeof(int) + fd)
+
+#define CHILD_STDIO_HANDLE(buffer, fd) \
+ *((HANDLE*) ((unsigned char*) (buffer) + \
+ sizeof(int) + \
+ sizeof(unsigned char) * \
+ CHILD_STDIO_COUNT((buffer)) + \
+ sizeof(HANDLE) * (fd)))
+
+
+/* CRT file descriptor mode flags */
+#define FOPEN 0x01
+#define FEOFLAG 0x02
+#define FCRLF 0x04
+#define FPIPE 0x08
+#define FNOINHERIT 0x10
+#define FAPPEND 0x20
+#define FDEV 0x40
+#define FTEXT 0x80
+
+
+/*
+ * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited
+ * the parent process. Don't check for errors - the stdio handles may not be
+ * valid, or may be closed already. There is no guarantee that this function
+ * does a perfect job.
+ */
+void uv_disable_stdio_inheritance(void) {
+ HANDLE handle;
+ STARTUPINFOW si;
+
+ /* Make the windows stdio handles non-inheritable. */
+ handle = GetStdHandle(STD_INPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ handle = GetStdHandle(STD_ERROR_HANDLE);
+ if (handle != NULL && handle != INVALID_HANDLE_VALUE)
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+
+ /* Make inherited CRT FDs non-inheritable. */
+ GetStartupInfoW(&si);
+ if (uv__stdio_verify(si.lpReserved2, si.cbReserved2))
+ uv__stdio_noinherit(si.lpReserved2);
+}
+
+
+static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
+ uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
+ char pipe_name[64];
+ SECURITY_ATTRIBUTES sa;
+ DWORD server_access = 0;
+ DWORD client_access = 0;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+ int err;
+
+ if (flags & UV_READABLE_PIPE) {
+ /* The server needs inbound access too, otherwise CreateNamedPipe() */
+ /* won't give us the FILE_READ_ATTRIBUTES permission. We need that to */
+ /* probe the state of the write buffer when we're trying to shutdown */
+ /* the pipe. */
+ server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
+ }
+ if (flags & UV_WRITABLE_PIPE) {
+ server_access |= PIPE_ACCESS_INBOUND;
+ client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+ }
+
+ /* Create server pipe handle. */
+ err = uv_stdio_pipe_server(loop,
+ server_pipe,
+ server_access,
+ pipe_name,
+ sizeof(pipe_name));
+ if (err)
+ goto error;
+
+ /* Create child pipe handle. */
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ child_pipe = CreateFileA(pipe_name,
+ client_access,
+ 0,
+ &sa,
+ OPEN_EXISTING,
+ server_pipe->ipc ? FILE_FLAG_OVERLAPPED : 0,
+ NULL);
+ if (child_pipe == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ goto error;
+ }
+
+#ifndef NDEBUG
+ /* Validate that the pipe was opened in the right mode. */
+ {
+ DWORD mode;
+ BOOL r = GetNamedPipeHandleState(child_pipe,
+ &mode,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ 0);
+ assert(r == TRUE);
+ assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
+ }
+#endif
+
+ /* Do a blocking ConnectNamedPipe. This should not block because we have */
+ /* both ends of the pipe created. */
+ if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
+ if (GetLastError() != ERROR_PIPE_CONNECTED) {
+ err = GetLastError();
+ goto error;
+ }
+ }
+
+ /* The server end is now readable and/or writable. */
+ if (flags & UV_READABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_WRITABLE;
+ if (flags & UV_WRITABLE_PIPE)
+ server_pipe->flags |= UV_HANDLE_READABLE;
+
+ *child_pipe_ptr = child_pipe;
+ return 0;
+
+ error:
+ if (server_pipe->handle != INVALID_HANDLE_VALUE) {
+ uv_pipe_cleanup(loop, server_pipe);
+ }
+
+ if (child_pipe != INVALID_HANDLE_VALUE) {
+ CloseHandle(child_pipe);
+ }
+
+ return err;
+}
+
+
+static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
+ HANDLE current_process;
+
+
+ /* _get_osfhandle will sometimes return -2 in case of an error. This seems */
+ /* to happen when fd <= 2 and the process' corresponding stdio handle is */
+ /* set to NULL. Unfortunately DuplicateHandle will happily duplicate */
+ /* (HANDLE) -2, so this situation goes unnoticed until someone tries to */
+ /* use the duplicate. Therefore we filter out known-invalid handles here. */
+ if (handle == INVALID_HANDLE_VALUE ||
+ handle == NULL ||
+ handle == (HANDLE) -2) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ current_process = GetCurrentProcess();
+
+ if (!DuplicateHandle(current_process,
+ handle,
+ current_process,
+ dup,
+ 0,
+ TRUE,
+ DUPLICATE_SAME_ACCESS)) {
+ *dup = INVALID_HANDLE_VALUE;
+ return GetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
+ HANDLE handle;
+
+ if (fd == -1) {
+ *dup = INVALID_HANDLE_VALUE;
+ return ERROR_INVALID_HANDLE;
+ }
+
+ handle = uv__get_osfhandle(fd);
+ return uv__duplicate_handle(loop, handle, dup);
+}
+
+
+int uv__create_nul_handle(HANDLE* handle_ptr,
+ DWORD access) {
+ HANDLE handle;
+ SECURITY_ATTRIBUTES sa;
+
+ sa.nLength = sizeof sa;
+ sa.lpSecurityDescriptor = NULL;
+ sa.bInheritHandle = TRUE;
+
+ handle = CreateFileW(L"NUL",
+ access,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ &sa,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ return GetLastError();
+ }
+
+ *handle_ptr = handle;
+ return 0;
+}
+
+
+int uv__stdio_create(uv_loop_t* loop,
+ const uv_process_options_t* options,
+ BYTE** buffer_ptr) {
+ BYTE* buffer;
+ int count, i;
+ int err;
+
+ count = options->stdio_count;
+
+ if (count < 0 || count > 255) {
+ /* Only support FDs 0-255 */
+ return ERROR_NOT_SUPPORTED;
+ } else if (count < 3) {
+ /* There should always be at least 3 stdio handles. */
+ count = 3;
+ }
+
+ /* Allocate the child stdio buffer */
+ buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
+ if (buffer == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can */
+ /* clean up on failure. */
+ CHILD_STDIO_COUNT(buffer) = count;
+ for (i = 0; i < count; i++) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ }
+
+ for (i = 0; i < count; i++) {
+ uv_stdio_container_t fdopt;
+ if (i < options->stdio_count) {
+ fdopt = options->stdio[i];
+ } else {
+ fdopt.flags = UV_IGNORE;
+ }
+
+ switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
+ UV_INHERIT_STREAM)) {
+ case UV_IGNORE:
+ /* Starting a process with no stdin/stout/stderr can confuse it. */
+ /* So no matter what the user specified, we make sure the first */
+ /* three FDs are always open in their typical modes, e.g. stdin */
+ /* be readable and stdout/err should be writable. For FDs > 2, don't */
+ /* do anything - all handles in the stdio buffer are initialized with */
+ /* INVALID_HANDLE_VALUE, which should be okay. */
+ if (i <= 2) {
+ DWORD access = (i == 0) ? FILE_GENERIC_READ :
+ FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
+
+ err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
+ access);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ }
+ break;
+
+ case UV_CREATE_PIPE: {
+ /* Create a pair of two connected pipe ends; one end is turned into */
+ /* an uv_pipe_t for use by the parent. The other one is given to */
+ /* the child. */
+ uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
+ HANDLE child_pipe = INVALID_HANDLE_VALUE;
+
+ /* Create a new, connected pipe pair. stdio[i].stream should point */
+ /* to an uninitialized, but not connected pipe handle. */
+ assert(fdopt.data.stream->type == UV_NAMED_PIPE);
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
+ assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
+
+ err = uv__create_stdio_pipe_pair(loop,
+ parent_pipe,
+ &child_pipe,
+ fdopt.flags);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+ }
+
+ case UV_INHERIT_FD: {
+ /* Inherit a raw FD. */
+ HANDLE child_handle;
+
+ /* Make an inheritable duplicate of the handle. */
+ err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
+ if (err) {
+ /* If fdopt.data.fd is not valid and fd fd <= 2, then ignore the */
+ /* error. */
+ if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
+ CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
+ break;
+ }
+ goto error;
+ }
+
+ /* Figure out what the type is. */
+ switch (GetFileType(child_handle)) {
+ case FILE_TYPE_DISK:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
+ break;
+
+ case FILE_TYPE_PIPE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
+ break;
+
+ case FILE_TYPE_CHAR:
+ case FILE_TYPE_REMOTE:
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ case FILE_TYPE_UNKNOWN:
+ if (GetLastError() != 0) {
+ err = GetLastError();
+ CloseHandle(child_handle);
+ goto error;
+ }
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
+ break;
+
+ default:
+ assert(0);
+ return -1;
+ }
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ break;
+ }
+
+ case UV_INHERIT_STREAM: {
+ /* Use an existing stream as the stdio handle for the child. */
+ HANDLE stream_handle, child_handle;
+ unsigned char crt_flags;
+ uv_stream_t* stream = fdopt.data.stream;
+
+ /* Leech the handle out of the stream. */
+ if (stream->type == UV_TTY) {
+ stream_handle = ((uv_tty_t*) stream)->handle;
+ crt_flags = FOPEN | FDEV;
+ } else if (stream->type == UV_NAMED_PIPE &&
+ stream->flags & UV_HANDLE_CONNECTION) {
+ stream_handle = ((uv_pipe_t*) stream)->handle;
+ crt_flags = FOPEN | FPIPE;
+ } else {
+ stream_handle = INVALID_HANDLE_VALUE;
+ crt_flags = 0;
+ }
+
+ if (stream_handle == NULL ||
+ stream_handle == INVALID_HANDLE_VALUE) {
+ /* The handle is already closed, or not yet created, or the */
+ /* stream type is not supported. */
+ err = ERROR_NOT_SUPPORTED;
+ goto error;
+ }
+
+ /* Make an inheritable copy of the handle. */
+ err = uv__duplicate_handle(loop, stream_handle, &child_handle);
+ if (err)
+ goto error;
+
+ CHILD_STDIO_HANDLE(buffer, i) = child_handle;
+ CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
+ break;
+ }
+
+ default:
+ assert(0);
+ return -1;
+ }
+ }
+
+ *buffer_ptr = buffer;
+ return 0;
+
+ error:
+ uv__stdio_destroy(buffer);
+ return err;
+}
+
+
+void uv__stdio_destroy(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ CloseHandle(handle);
+ }
+ }
+
+ uv__free(buffer);
+}
+
+
+void uv__stdio_noinherit(BYTE* buffer) {
+ int i, count;
+
+ count = CHILD_STDIO_COUNT(buffer);
+ for (i = 0; i < count; i++) {
+ HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
+ if (handle != INVALID_HANDLE_VALUE) {
+ SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
+ }
+ }
+}
+
+
+int uv__stdio_verify(BYTE* buffer, WORD size) {
+ unsigned int count;
+
+ /* Check the buffer pointer. */
+ if (buffer == NULL)
+ return 0;
+
+ /* Verify that the buffer is at least big enough to hold the count. */
+ if (size < CHILD_STDIO_SIZE(0))
+ return 0;
+
+ /* Verify if the count is within range. */
+ count = CHILD_STDIO_COUNT(buffer);
+ if (count > 256)
+ return 0;
+
+ /* Verify that the buffer size is big enough to hold info for N FDs. */
+ if (size < CHILD_STDIO_SIZE(count))
+ return 0;
+
+ return 1;
+}
+
+
+WORD uv__stdio_size(BYTE* buffer) {
+ return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
+}
+
+
+HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
+ return CHILD_STDIO_HANDLE(buffer, fd);
+}
diff --git a/Utilities/cmlibuv/src/win/process.c b/Utilities/cmlibuv/src/win/process.c
new file mode 100644
index 000000000..d14160160
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/process.c
@@ -0,0 +1,1246 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <limits.h>
+#include <wchar.h>
+#include <malloc.h> /* alloca */
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+#define SIGKILL 9
+
+
+typedef struct env_var {
+ const WCHAR* const wide;
+ const WCHAR* const wide_eq;
+ const size_t len; /* including null or '=' */
+} env_var_t;
+
+#define E_V(str) { L##str, L##str L"=", sizeof(str) }
+
+static const env_var_t required_vars[] = { /* keep me sorted */
+ E_V("HOMEDRIVE"),
+ E_V("HOMEPATH"),
+ E_V("LOGONSERVER"),
+ E_V("PATH"),
+ E_V("SYSTEMDRIVE"),
+ E_V("SYSTEMROOT"),
+ E_V("TEMP"),
+ E_V("USERDOMAIN"),
+ E_V("USERNAME"),
+ E_V("USERPROFILE"),
+ E_V("WINDIR"),
+};
+static size_t n_required_vars = ARRAY_SIZE(required_vars);
+
+
+static HANDLE uv_global_job_handle_;
+static uv_once_t uv_global_job_handle_init_guard_ = UV_ONCE_INIT;
+
+
+static void uv__init_global_job_handle(void) {
+ /* Create a job object and set it up to kill all contained processes when
+ * it's closed. Since this handle is made non-inheritable and we're not
+ * giving it to anyone, we're the only process holding a reference to it.
+ * That means that if this process exits it is closed and all the processes
+ * it contains are killed. All processes created with uv_spawn that are not
+ * spawned with the UV_PROCESS_DETACHED flag are assigned to this job.
+ *
+ * We're setting the JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag so only the
+ * processes that we explicitly add are affected, and *their* subprocesses
+ * are not. This ensures that our child processes are not limited in their
+ * ability to use job control on Windows versions that don't deal with
+ * nested jobs (prior to Windows 8 / Server 2012). It also lets our child
+ * processes created detached processes without explicitly breaking away
+ * from job control (which uv_spawn doesn't, either).
+ */
+ SECURITY_ATTRIBUTES attr;
+ JOBOBJECT_EXTENDED_LIMIT_INFORMATION info;
+
+ memset(&attr, 0, sizeof attr);
+ attr.bInheritHandle = FALSE;
+
+ memset(&info, 0, sizeof info);
+ info.BasicLimitInformation.LimitFlags =
+ JOB_OBJECT_LIMIT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK |
+ JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION |
+ JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
+
+ uv_global_job_handle_ = CreateJobObjectW(&attr, NULL);
+ if (uv_global_job_handle_ == NULL)
+ uv_fatal_error(GetLastError(), "CreateJobObjectW");
+
+ if (!SetInformationJobObject(uv_global_job_handle_,
+ JobObjectExtendedLimitInformation,
+ &info,
+ sizeof info))
+ uv_fatal_error(GetLastError(), "SetInformationJobObject");
+}
+
+
+static int uv_utf8_to_utf16_alloc(const char* s, WCHAR** ws_ptr) {
+ int ws_len, r;
+ WCHAR* ws;
+
+ ws_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ NULL,
+ 0);
+ if (ws_len <= 0) {
+ return GetLastError();
+ }
+
+ ws = (WCHAR*) uv__malloc(ws_len * sizeof(WCHAR));
+ if (ws == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ r = MultiByteToWideChar(CP_UTF8,
+ 0,
+ s,
+ -1,
+ ws,
+ ws_len);
+ assert(r == ws_len);
+
+ *ws_ptr = ws;
+ return 0;
+}
+
+
+static void uv_process_init(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_PROCESS);
+ handle->exit_cb = NULL;
+ handle->pid = 0;
+ handle->exit_signal = 0;
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ handle->process_handle = INVALID_HANDLE_VALUE;
+ handle->child_stdio_buffer = NULL;
+ handle->exit_cb_pending = 0;
+
+ UV_REQ_INIT(&handle->exit_req, UV_PROCESS_EXIT);
+ handle->exit_req.data = handle;
+}
+
+
+/*
+ * Path search functions
+ */
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* search_path_join_test(const WCHAR* dir,
+ size_t dir_len,
+ const WCHAR* name,
+ size_t name_len,
+ const WCHAR* ext,
+ size_t ext_len,
+ const WCHAR* cwd,
+ size_t cwd_len) {
+ WCHAR *result, *result_pos;
+ DWORD attrs;
+ if (dir_len > 2 && dir[0] == L'\\' && dir[1] == L'\\') {
+ /* It's a UNC path so ignore cwd */
+ cwd_len = 0;
+ } else if (dir_len >= 1 && (dir[0] == L'/' || dir[0] == L'\\')) {
+ /* It's a full path without drive letter, use cwd's drive letter only */
+ cwd_len = 2;
+ } else if (dir_len >= 2 && dir[1] == L':' &&
+ (dir_len < 3 || (dir[2] != L'/' && dir[2] != L'\\'))) {
+ /* It's a relative path with drive letter (ext.g. D:../some/file)
+ * Replace drive letter in dir by full cwd if it points to the same drive,
+ * otherwise use the dir only.
+ */
+ if (cwd_len < 2 || _wcsnicmp(cwd, dir, 2) != 0) {
+ cwd_len = 0;
+ } else {
+ dir += 2;
+ dir_len -= 2;
+ }
+ } else if (dir_len > 2 && dir[1] == L':') {
+ /* It's an absolute path with drive letter
+ * Don't use the cwd at all
+ */
+ cwd_len = 0;
+ }
+
+ /* Allocate buffer for output */
+ result = result_pos = (WCHAR*)uv__malloc(sizeof(WCHAR) *
+ (cwd_len + 1 + dir_len + 1 + name_len + 1 + ext_len + 1));
+
+ /* Copy cwd */
+ wcsncpy(result_pos, cwd, cwd_len);
+ result_pos += cwd_len;
+
+ /* Add a path separator if cwd didn't end with one */
+ if (cwd_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy dir */
+ wcsncpy(result_pos, dir, dir_len);
+ result_pos += dir_len;
+
+ /* Add a separator if the dir didn't end with one */
+ if (dir_len && wcsrchr(L"\\/:", result_pos[-1]) == NULL) {
+ result_pos[0] = L'\\';
+ result_pos++;
+ }
+
+ /* Copy filename */
+ wcsncpy(result_pos, name, name_len);
+ result_pos += name_len;
+
+ if (ext_len) {
+ /* Add a dot if the filename didn't end with one */
+ if (name_len && result_pos[-1] != '.') {
+ result_pos[0] = L'.';
+ result_pos++;
+ }
+
+ /* Copy extension */
+ wcsncpy(result_pos, ext, ext_len);
+ result_pos += ext_len;
+ }
+
+ /* Null terminator */
+ result_pos[0] = L'\0';
+
+ attrs = GetFileAttributesW(result);
+
+ if (attrs != INVALID_FILE_ATTRIBUTES &&
+ !(attrs & FILE_ATTRIBUTE_DIRECTORY)) {
+ return result;
+ }
+
+ uv__free(result);
+ return NULL;
+}
+
+
+/*
+ * Helper function for search_path
+ */
+static WCHAR* path_search_walk_ext(const WCHAR *dir,
+ size_t dir_len,
+ const WCHAR *name,
+ size_t name_len,
+ WCHAR *cwd,
+ size_t cwd_len,
+ int name_has_ext) {
+ WCHAR* result;
+
+ /* If the name itself has a nonempty extension, try this extension first */
+ if (name_has_ext) {
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"", 0,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+ }
+
+ /* Try .com extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"com", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ /* Try .exe extension */
+ result = search_path_join_test(dir, dir_len,
+ name, name_len,
+ L"exe", 3,
+ cwd, cwd_len);
+ if (result != NULL) {
+ return result;
+ }
+
+ return NULL;
+}
+
+
+/*
+ * search_path searches the system path for an executable filename -
+ * the windows API doesn't provide this as a standalone function nor as an
+ * option to CreateProcess.
+ *
+ * It tries to return an absolute filename.
+ *
+ * Furthermore, it tries to follow the semantics that cmd.exe, with this
+ * exception that PATHEXT environment variable isn't used. Since CreateProcess
+ * can start only .com and .exe files, only those extensions are tried. This
+ * behavior equals that of msvcrt's spawn functions.
+ *
+ * - Do not search the path if the filename already contains a path (either
+ * relative or absolute).
+ *
+ * - If there's really only a filename, check the current directory for file,
+ * then search all path directories.
+ *
+ * - If filename specified has *any* extension, search for the file with the
+ * specified extension first.
+ *
+ * - If the literal filename is not found in a directory, try *appending*
+ * (not replacing) .com first and then .exe.
+ *
+ * - The path variable may contain relative paths; relative paths are relative
+ * to the cwd.
+ *
+ * - Directories in path may or may not end with a trailing backslash.
+ *
+ * - CMD does not trim leading/trailing whitespace from path/pathex entries
+ * nor from the environment variables as a whole.
+ *
+ * - When cmd.exe cannot read a directory, it will just skip it and go on
+ * searching. However, unlike posix-y systems, it will happily try to run a
+ * file that is not readable/executable; if the spawn fails it will not
+ * continue searching.
+ *
+ * UNC path support: we are dealing with UNC paths in both the path and the
+ * filename. This is a deviation from what cmd.exe does (it does not let you
+ * start a program by specifying an UNC path on the command line) but this is
+ * really a pointless restriction.
+ *
+ */
+static WCHAR* search_path(const WCHAR *file,
+ WCHAR *cwd,
+ const WCHAR *path) {
+ int file_has_dir;
+ WCHAR* result = NULL;
+ WCHAR *file_name_start;
+ WCHAR *dot;
+ const WCHAR *dir_start, *dir_end, *dir_path;
+ size_t dir_len;
+ int name_has_ext;
+
+ size_t file_len = wcslen(file);
+ size_t cwd_len = wcslen(cwd);
+
+ /* If the caller supplies an empty filename,
+ * we're not gonna return c:\windows\.exe -- GFY!
+ */
+ if (file_len == 0
+ || (file_len == 1 && file[0] == L'.')) {
+ return NULL;
+ }
+
+ /* Find the start of the filename so we can split the directory from the */
+ /* name. */
+ for (file_name_start = (WCHAR*)file + file_len;
+ file_name_start > file
+ && file_name_start[-1] != L'\\'
+ && file_name_start[-1] != L'/'
+ && file_name_start[-1] != L':';
+ file_name_start--);
+
+ file_has_dir = file_name_start != file;
+
+ /* Check if the filename includes an extension */
+ dot = wcschr(file_name_start, L'.');
+ name_has_ext = (dot != NULL && dot[1] != L'\0');
+
+ if (file_has_dir) {
+ /* The file has a path inside, don't use path */
+ result = path_search_walk_ext(
+ file, file_name_start - file,
+ file_name_start, file_len - (file_name_start - file),
+ cwd, cwd_len,
+ name_has_ext);
+
+ } else {
+ dir_end = path;
+
+ /* The file is really only a name; look in cwd first, then scan path */
+ result = path_search_walk_ext(L"", 0,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+
+ while (result == NULL) {
+ if (*dir_end == L'\0') {
+ break;
+ }
+
+ /* Skip the separator that dir_end now points to */
+ if (dir_end != path || *path == L';') {
+ dir_end++;
+ }
+
+ /* Next slice starts just after where the previous one ended */
+ dir_start = dir_end;
+
+ /* Slice until the next ; or \0 is found */
+ dir_end = wcschr(dir_start, L';');
+ if (dir_end == NULL) {
+ dir_end = wcschr(dir_start, L'\0');
+ }
+
+ /* If the slice is zero-length, don't bother */
+ if (dir_end - dir_start == 0) {
+ continue;
+ }
+
+ dir_path = dir_start;
+ dir_len = dir_end - dir_start;
+
+ /* Adjust if the path is quoted. */
+ if (dir_path[0] == '"' || dir_path[0] == '\'') {
+ ++dir_path;
+ --dir_len;
+ }
+
+ if (dir_path[dir_len - 1] == '"' || dir_path[dir_len - 1] == '\'') {
+ --dir_len;
+ }
+
+ result = path_search_walk_ext(dir_path, dir_len,
+ file, file_len,
+ cwd, cwd_len,
+ name_has_ext);
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Quotes command line arguments
+ * Returns a pointer to the end (next char to be written) of the buffer
+ */
+WCHAR* quote_cmd_arg(const WCHAR *source, WCHAR *target) {
+ size_t len = wcslen(source);
+ size_t i;
+ int quote_hit;
+ WCHAR* start;
+
+ if (len == 0) {
+ /* Need double quotation for empty argument */
+ *(target++) = L'"';
+ *(target++) = L'"';
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L" \t\"")) {
+ /* No quotation needed */
+ wcsncpy(target, source, len);
+ target += len;
+ return target;
+ }
+
+ if (NULL == wcspbrk(source, L"\"\\")) {
+ /*
+ * No embedded double quotes or backlashes, so I can just wrap
+ * quote marks around the whole thing.
+ */
+ *(target++) = L'"';
+ wcsncpy(target, source, len);
+ target += len;
+ *(target++) = L'"';
+ return target;
+ }
+
+ /*
+ * Expected input/output:
+ * input : hello"world
+ * output: "hello\"world"
+ * input : hello""world
+ * output: "hello\"\"world"
+ * input : hello\world
+ * output: hello\world
+ * input : hello\\world
+ * output: hello\\world
+ * input : hello\"world
+ * output: "hello\\\"world"
+ * input : hello\\"world
+ * output: "hello\\\\\"world"
+ * input : hello world\
+ * output: "hello world\\"
+ */
+
+ *(target++) = L'"';
+ start = target;
+ quote_hit = 1;
+
+ for (i = len; i > 0; --i) {
+ *(target++) = source[i - 1];
+
+ if (quote_hit && source[i - 1] == L'\\') {
+ *(target++) = L'\\';
+ } else if(source[i - 1] == L'"') {
+ quote_hit = 1;
+ *(target++) = L'\\';
+ } else {
+ quote_hit = 0;
+ }
+ }
+ target[0] = L'\0';
+ wcsrev(start);
+ *(target++) = L'"';
+ return target;
+}
+
+
+int make_program_args(char** args, int verbatim_arguments, WCHAR** dst_ptr) {
+ char** arg;
+ WCHAR* dst = NULL;
+ WCHAR* temp_buffer = NULL;
+ size_t dst_len = 0;
+ size_t temp_buffer_len = 0;
+ WCHAR* pos;
+ int arg_count = 0;
+ int err = 0;
+
+ /* Count the required size. */
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ NULL,
+ 0);
+ if (arg_len == 0) {
+ return GetLastError();
+ }
+
+ dst_len += arg_len;
+
+ if (arg_len > temp_buffer_len)
+ temp_buffer_len = arg_len;
+
+ arg_count++;
+ }
+
+ /* Adjust for potential quotes. Also assume the worst-case scenario */
+ /* that every character needs escaping, so we need twice as much space. */
+ dst_len = dst_len * 2 + arg_count * 2;
+
+ /* Allocate buffer for the final command line. */
+ dst = (WCHAR*) uv__malloc(dst_len * sizeof(WCHAR));
+ if (dst == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ /* Allocate temporary working buffer. */
+ temp_buffer = (WCHAR*) uv__malloc(temp_buffer_len * sizeof(WCHAR));
+ if (temp_buffer == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ pos = dst;
+ for (arg = args; *arg; arg++) {
+ DWORD arg_len;
+
+ /* Convert argument to wide char. */
+ arg_len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *arg,
+ -1,
+ temp_buffer,
+ (int) (dst + dst_len - pos));
+ if (arg_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (verbatim_arguments) {
+ /* Copy verbatim. */
+ wcscpy(pos, temp_buffer);
+ pos += arg_len - 1;
+ } else {
+ /* Quote/escape, if needed. */
+ pos = quote_cmd_arg(temp_buffer, pos);
+ }
+
+ *pos++ = *(arg + 1) ? L' ' : L'\0';
+ }
+
+ uv__free(temp_buffer);
+
+ *dst_ptr = dst;
+ return 0;
+
+error:
+ uv__free(dst);
+ uv__free(temp_buffer);
+ return err;
+}
+
+
+int env_strncmp(const wchar_t* a, int na, const wchar_t* b) {
+ wchar_t* a_eq;
+ wchar_t* b_eq;
+ wchar_t* A;
+ wchar_t* B;
+ int nb;
+ int r;
+
+ if (na < 0) {
+ a_eq = wcschr(a, L'=');
+ assert(a_eq);
+ na = (int)(long)(a_eq - a);
+ } else {
+ na--;
+ }
+ b_eq = wcschr(b, L'=');
+ assert(b_eq);
+ nb = b_eq - b;
+
+ A = alloca((na+1) * sizeof(wchar_t));
+ B = alloca((nb+1) * sizeof(wchar_t));
+
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, a, na, A, na);
+ assert(r==na);
+ A[na] = L'\0';
+ r = LCMapStringW(LOCALE_INVARIANT, LCMAP_UPPERCASE, b, nb, B, nb);
+ assert(r==nb);
+ B[nb] = L'\0';
+
+ while (1) {
+ wchar_t AA = *A++;
+ wchar_t BB = *B++;
+ if (AA < BB) {
+ return -1;
+ } else if (AA > BB) {
+ return 1;
+ } else if (!AA && !BB) {
+ return 0;
+ }
+ }
+}
+
+
+static int qsort_wcscmp(const void *a, const void *b) {
+ wchar_t* astr = *(wchar_t* const*)a;
+ wchar_t* bstr = *(wchar_t* const*)b;
+ return env_strncmp(astr, -1, bstr);
+}
+
+
+/*
+ * The way windows takes environment variables is different than what C does;
+ * Windows wants a contiguous block of null-terminated strings, terminated
+ * with an additional null.
+ *
+ * Windows has a few "essential" environment variables. winsock will fail
+ * to initialize if SYSTEMROOT is not defined; some APIs make reference to
+ * TEMP. SYSTEMDRIVE is probably also important. We therefore ensure that
+ * these get defined if the input environment block does not contain any
+ * values for them.
+ *
+ * Also add variables known to Cygwin to be required for correct
+ * subprocess operation in many cases:
+ * https://github.com/Alexpux/Cygwin/blob/b266b04fbbd3a595f02ea149e4306d3ab9b1fe3d/winsup/cygwin/environ.cc#L955
+ *
+ */
+int make_program_env(char* env_block[], WCHAR** dst_ptr) {
+ WCHAR* dst;
+ WCHAR* ptr;
+ char** env;
+ size_t env_len = 0;
+ int len;
+ size_t i;
+ DWORD var_size;
+ size_t env_block_count = 1; /* 1 for null-terminator */
+ WCHAR* dst_copy;
+ WCHAR** ptr_copy;
+ WCHAR** env_copy;
+ DWORD* required_vars_value_len = alloca(n_required_vars * sizeof(DWORD*));
+
+ /* first pass: determine size in UTF-16 */
+ for (env = env_block; *env; env++) {
+ int len;
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ NULL,
+ 0);
+ if (len <= 0) {
+ return GetLastError();
+ }
+ env_len += len;
+ env_block_count++;
+ }
+ }
+
+ /* second pass: copy to UTF-16 environment block */
+ dst_copy = (WCHAR*)uv__malloc(env_len * sizeof(WCHAR));
+ if (!dst_copy) {
+ return ERROR_OUTOFMEMORY;
+ }
+ env_copy = alloca(env_block_count * sizeof(WCHAR*));
+
+ ptr = dst_copy;
+ ptr_copy = env_copy;
+ for (env = env_block; *env; env++) {
+ if (strchr(*env, '=')) {
+ len = MultiByteToWideChar(CP_UTF8,
+ 0,
+ *env,
+ -1,
+ ptr,
+ (int) (env_len - (ptr - dst_copy)));
+ if (len <= 0) {
+ DWORD err = GetLastError();
+ uv__free(dst_copy);
+ return err;
+ }
+ *ptr_copy++ = ptr;
+ ptr += len;
+ }
+ }
+ *ptr_copy = NULL;
+ assert(env_len == ptr - dst_copy);
+
+ /* sort our (UTF-16) copy */
+ qsort(env_copy, env_block_count-1, sizeof(wchar_t*), qsort_wcscmp);
+
+ /* third pass: check for required variables */
+ for (ptr_copy = env_copy, i = 0; i < n_required_vars; ) {
+ int cmp;
+ if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ var_size = GetEnvironmentVariableW(required_vars[i].wide, NULL, 0);
+ required_vars_value_len[i] = var_size;
+ if (var_size != 0) {
+ env_len += required_vars[i].len;
+ env_len += var_size;
+ }
+ i++;
+ } else {
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* final pass: copy, in sort order, and inserting required variables */
+ dst = uv__malloc((1+env_len) * sizeof(WCHAR));
+ if (!dst) {
+ uv__free(dst_copy);
+ return ERROR_OUTOFMEMORY;
+ }
+
+ for (ptr = dst, ptr_copy = env_copy, i = 0;
+ *ptr_copy || i < n_required_vars;
+ ptr += len) {
+ int cmp;
+ if (i >= n_required_vars) {
+ cmp = 1;
+ } else if (!*ptr_copy) {
+ cmp = -1;
+ } else {
+ cmp = env_strncmp(required_vars[i].wide_eq,
+ required_vars[i].len,
+ *ptr_copy);
+ }
+ if (cmp < 0) {
+ /* missing required var */
+ len = required_vars_value_len[i];
+ if (len) {
+ wcscpy(ptr, required_vars[i].wide_eq);
+ ptr += required_vars[i].len;
+ var_size = GetEnvironmentVariableW(required_vars[i].wide,
+ ptr,
+ (int) (env_len - (ptr - dst)));
+ if (var_size != len-1) { /* race condition? */
+ uv_fatal_error(GetLastError(), "GetEnvironmentVariableW");
+ }
+ }
+ i++;
+ } else {
+ /* copy var from env_block */
+ len = wcslen(*ptr_copy) + 1;
+ wmemcpy(ptr, *ptr_copy, len);
+ ptr_copy++;
+ if (cmp == 0)
+ i++;
+ }
+ }
+
+ /* Terminate with an extra NULL. */
+ assert(env_len == (ptr - dst));
+ *ptr = L'\0';
+
+ uv__free(dst_copy);
+ *dst_ptr = dst;
+ return 0;
+}
+
+/*
+ * Attempt to find the value of the PATH environment variable in the child's
+ * preprocessed environment.
+ *
+ * If found, a pointer into `env` is returned. If not found, NULL is returned.
+ */
+static WCHAR* find_path(WCHAR *env) {
+ for (; env != NULL && *env != 0; env += wcslen(env) + 1) {
+ if (wcsncmp(env, L"PATH=", 5) == 0)
+ return &env[5];
+ }
+
+ return NULL;
+}
+
+/*
+ * Called on Windows thread-pool thread to indicate that
+ * a child process has exited.
+ */
+static void CALLBACK exit_wait_callback(void* data, BOOLEAN didTimeout) {
+ uv_process_t* process = (uv_process_t*) data;
+ uv_loop_t* loop = process->loop;
+
+ assert(didTimeout == FALSE);
+ assert(process);
+ assert(!process->exit_cb_pending);
+
+ process->exit_cb_pending = 1;
+
+ /* Post completed */
+ POST_COMPLETION_FOR_REQ(loop, &process->exit_req);
+}
+
+
+/* Called on main thread after a child process has exited. */
+void uv_process_proc_exit(uv_loop_t* loop, uv_process_t* handle) {
+ int64_t exit_code;
+ DWORD status;
+
+ assert(handle->exit_cb_pending);
+ handle->exit_cb_pending = 0;
+
+ /* If we're closing, don't call the exit callback. Just schedule a close */
+ /* callback now. */
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ return;
+ }
+
+ /* Unregister from process notification. */
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->wait_handle);
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ /* Set the handle to inactive: no callbacks will be made after the exit */
+ /* callback.*/
+ uv__handle_stop(handle);
+
+ if (GetExitCodeProcess(handle->process_handle, &status)) {
+ exit_code = status;
+ } else {
+ /* Unable to to obtain the exit code. This should never happen. */
+ exit_code = uv_translate_sys_error(GetLastError());
+ }
+
+ /* Fire the exit callback. */
+ if (handle->exit_cb) {
+ handle->exit_cb(handle, exit_code, handle->exit_signal);
+ }
+}
+
+
+void uv_process_close(uv_loop_t* loop, uv_process_t* handle) {
+ uv__handle_closing(handle);
+
+ if (handle->wait_handle != INVALID_HANDLE_VALUE) {
+ /* This blocks until either the wait was cancelled, or the callback has */
+ /* completed. */
+ BOOL r = UnregisterWaitEx(handle->wait_handle, INVALID_HANDLE_VALUE);
+ if (!r) {
+ /* This should never happen, and if it happens, we can't recover... */
+ uv_fatal_error(GetLastError(), "UnregisterWaitEx");
+ }
+
+ handle->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ if (!handle->exit_cb_pending) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+}
+
+
+void uv_process_endgame(uv_loop_t* loop, uv_process_t* handle) {
+ assert(!handle->exit_cb_pending);
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ /* Clean-up the process handle. */
+ CloseHandle(handle->process_handle);
+
+ uv__handle_close(handle);
+}
+
+
+int uv_spawn(uv_loop_t* loop,
+ uv_process_t* process,
+ const uv_process_options_t* options) {
+ int i;
+ int err = 0;
+ WCHAR* path = NULL, *alloc_path = NULL;
+ BOOL result;
+ WCHAR* application_path = NULL, *application = NULL, *arguments = NULL,
+ *env = NULL, *cwd = NULL;
+ STARTUPINFOW startup;
+ PROCESS_INFORMATION info;
+ DWORD process_flags;
+
+ uv_process_init(loop, process);
+ process->exit_cb = options->exit_cb;
+
+ if (options->flags & (UV_PROCESS_SETGID | UV_PROCESS_SETUID)) {
+ return UV_ENOTSUP;
+ }
+
+ if (options->file == NULL ||
+ options->args == NULL) {
+ return UV_EINVAL;
+ }
+
+ assert(options->file != NULL);
+ assert(!(options->flags & ~(UV_PROCESS_DETACHED |
+ UV_PROCESS_SETGID |
+ UV_PROCESS_SETUID |
+ UV_PROCESS_WINDOWS_HIDE |
+ UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS)));
+
+ err = uv_utf8_to_utf16_alloc(options->file, &application);
+ if (err)
+ goto done;
+
+ err = make_program_args(
+ options->args,
+ options->flags & UV_PROCESS_WINDOWS_VERBATIM_ARGUMENTS,
+ &arguments);
+ if (err)
+ goto done;
+
+ if (options->env) {
+ err = make_program_env(options->env, &env);
+ if (err)
+ goto done;
+ }
+
+ if (options->cwd) {
+ /* Explicit cwd */
+ err = uv_utf8_to_utf16_alloc(options->cwd, &cwd);
+ if (err)
+ goto done;
+
+ } else {
+ /* Inherit cwd */
+ DWORD cwd_len, r;
+
+ cwd_len = GetCurrentDirectoryW(0, NULL);
+ if (!cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+
+ cwd = (WCHAR*) uv__malloc(cwd_len * sizeof(WCHAR));
+ if (cwd == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+
+ r = GetCurrentDirectoryW(cwd_len, cwd);
+ if (r == 0 || r >= cwd_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ /* Get PATH environment variable. */
+ path = find_path(env);
+ if (path == NULL) {
+ DWORD path_len, r;
+
+ path_len = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ if (path_len == 0) {
+ err = GetLastError();
+ goto done;
+ }
+
+ alloc_path = (WCHAR*) uv__malloc(path_len * sizeof(WCHAR));
+ if (alloc_path == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto done;
+ }
+ path = alloc_path;
+
+ r = GetEnvironmentVariableW(L"PATH", path, path_len);
+ if (r == 0 || r >= path_len) {
+ err = GetLastError();
+ goto done;
+ }
+ }
+
+ err = uv__stdio_create(loop, options, &process->child_stdio_buffer);
+ if (err)
+ goto done;
+
+ application_path = search_path(application,
+ cwd,
+ path);
+ if (application_path == NULL) {
+ /* Not found. */
+ err = ERROR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ startup.cb = sizeof(startup);
+ startup.lpReserved = NULL;
+ startup.lpDesktop = NULL;
+ startup.lpTitle = NULL;
+ startup.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+ startup.cbReserved2 = uv__stdio_size(process->child_stdio_buffer);
+ startup.lpReserved2 = (BYTE*) process->child_stdio_buffer;
+
+ startup.hStdInput = uv__stdio_handle(process->child_stdio_buffer, 0);
+ startup.hStdOutput = uv__stdio_handle(process->child_stdio_buffer, 1);
+ startup.hStdError = uv__stdio_handle(process->child_stdio_buffer, 2);
+
+ if (options->flags & UV_PROCESS_WINDOWS_HIDE) {
+ /* Use SW_HIDE to avoid any potential process window. */
+ startup.wShowWindow = SW_HIDE;
+ } else {
+ startup.wShowWindow = SW_SHOWDEFAULT;
+ }
+
+ process_flags = CREATE_UNICODE_ENVIRONMENT;
+
+ if (options->flags & UV_PROCESS_DETACHED) {
+ /* Note that we're not setting the CREATE_BREAKAWAY_FROM_JOB flag. That
+ * means that libuv might not let you create a fully daemonized process
+ * when run under job control. However the type of job control that libuv
+ * itself creates doesn't trickle down to subprocesses so they can still
+ * daemonize.
+ *
+ * A reason to not do this is that CREATE_BREAKAWAY_FROM_JOB makes the
+ * CreateProcess call fail if we're under job control that doesn't allow
+ * breakaway.
+ */
+ process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ }
+
+ if (!CreateProcessW(application_path,
+ arguments,
+ NULL,
+ NULL,
+ 1,
+ process_flags,
+ env,
+ cwd,
+ &startup,
+ &info)) {
+ /* CreateProcessW failed. */
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Spawn succeeded */
+ /* Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
+ /* If the process isn't spawned as detached, assign to the global job */
+ /* object so windows will kill it when the parent process dies. */
+ if (!(options->flags & UV_PROCESS_DETACHED)) {
+ uv_once(&uv_global_job_handle_init_guard_, uv__init_global_job_handle);
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, info.hProcess)) {
+ /* AssignProcessToJobObject might fail if this process is under job
+ * control and the job doesn't have the
+ * JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK flag set, on a Windows version
+ * that doesn't support nested jobs.
+ *
+ * When that happens we just swallow the error and continue without
+ * establishing a kill-child-on-parent-exit relationship, otherwise
+ * there would be no way for libuv applications run under job control
+ * to spawn processes at all.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
+ }
+
+ /* Set IPC pid to all IPC pipes. */
+ for (i = 0; i < options->stdio_count; i++) {
+ const uv_stdio_container_t* fdopt = &options->stdio[i];
+ if (fdopt->flags & UV_CREATE_PIPE &&
+ fdopt->data.stream->type == UV_NAMED_PIPE &&
+ ((uv_pipe_t*) fdopt->data.stream)->ipc) {
+ ((uv_pipe_t*) fdopt->data.stream)->pipe.conn.ipc_pid = info.dwProcessId;
+ }
+ }
+
+ /* Setup notifications for when the child process exits. */
+ result = RegisterWaitForSingleObject(&process->wait_handle,
+ process->process_handle, exit_wait_callback, (void*)process, INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!result) {
+ uv_fatal_error(GetLastError(), "RegisterWaitForSingleObject");
+ }
+
+ CloseHandle(info.hThread);
+
+ assert(!err);
+
+ /* Make the handle active. It will remain active until the exit callback */
+ /* is made or the handle is closed, whichever happens first. */
+ uv__handle_start(process);
+
+ /* Cleanup, whether we succeeded or failed. */
+ done:
+ uv__free(application);
+ uv__free(application_path);
+ uv__free(arguments);
+ uv__free(cwd);
+ uv__free(env);
+ uv__free(alloc_path);
+
+ if (process->child_stdio_buffer != NULL) {
+ /* Clean up child stdio handles. */
+ uv__stdio_destroy(process->child_stdio_buffer);
+ process->child_stdio_buffer = NULL;
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__kill(HANDLE process_handle, int signum) {
+ switch (signum) {
+ case SIGTERM:
+ case SIGKILL:
+ case SIGINT: {
+ /* Unconditionally terminate the process. On Windows, killed processes */
+ /* normally return 1. */
+ DWORD status;
+ int err;
+
+ if (TerminateProcess(process_handle, 1))
+ return 0;
+
+ /* If the process already exited before TerminateProcess was called, */
+ /* TerminateProcess will fail with ERROR_ACCESS_DENIED. */
+ err = GetLastError();
+ if (err == ERROR_ACCESS_DENIED &&
+ GetExitCodeProcess(process_handle, &status) &&
+ status != STILL_ACTIVE) {
+ return UV_ESRCH;
+ }
+
+ return uv_translate_sys_error(err);
+ }
+
+ case 0: {
+ /* Health check: is the process still alive? */
+ DWORD status;
+
+ if (!GetExitCodeProcess(process_handle, &status))
+ return uv_translate_sys_error(GetLastError());
+
+ if (status != STILL_ACTIVE)
+ return UV_ESRCH;
+
+ return 0;
+ }
+
+ default:
+ /* Unsupported signal. */
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_process_kill(uv_process_t* process, int signum) {
+ int err;
+
+ if (process->process_handle == INVALID_HANDLE_VALUE) {
+ return UV_EINVAL;
+ }
+
+ err = uv__kill(process->process_handle, signum);
+ if (err) {
+ return err; /* err is already translated. */
+ }
+
+ process->exit_signal = signum;
+
+ return 0;
+}
+
+
+int uv_kill(int pid, int signum) {
+ int err;
+ HANDLE process_handle = OpenProcess(PROCESS_TERMINATE |
+ PROCESS_QUERY_INFORMATION, FALSE, pid);
+
+ if (process_handle == NULL) {
+ err = GetLastError();
+ if (err == ERROR_INVALID_PARAMETER) {
+ return UV_ESRCH;
+ } else {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ err = uv__kill(process_handle, signum);
+ CloseHandle(process_handle);
+
+ return err; /* err is already translated. */
+}
diff --git a/Utilities/cmlibuv/src/win/req-inl.h b/Utilities/cmlibuv/src/win/req-inl.h
new file mode 100644
index 000000000..f2513b7d3
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/req-inl.h
@@ -0,0 +1,221 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_REQ_INL_H_
+#define UV_WIN_REQ_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define SET_REQ_STATUS(req, status) \
+ (req)->u.io.overlapped.Internal = (ULONG_PTR) (status)
+
+#define SET_REQ_ERROR(req, error) \
+ SET_REQ_STATUS((req), NTSTATUS_FROM_WIN32((error)))
+
+/* Note: used open-coded in UV_REQ_INIT() because of a circular dependency
+ * between src/uv-common.h and src/win/internal.h.
+ */
+#define SET_REQ_SUCCESS(req) \
+ SET_REQ_STATUS((req), STATUS_SUCCESS)
+
+#define GET_REQ_STATUS(req) \
+ ((NTSTATUS) (req)->u.io.overlapped.Internal)
+
+#define REQ_SUCCESS(req) \
+ (NT_SUCCESS(GET_REQ_STATUS((req))))
+
+#define GET_REQ_ERROR(req) \
+ (pRtlNtStatusToDosError(GET_REQ_STATUS((req))))
+
+#define GET_REQ_SOCK_ERROR(req) \
+ (uv_ntstatus_to_winsock_error(GET_REQ_STATUS((req))))
+
+
+#define REGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ INCREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_register((loop), (req)); \
+ } while (0)
+
+#define UNREGISTER_HANDLE_REQ(loop, handle, req) \
+ do { \
+ DECREASE_ACTIVE_COUNT((loop), (handle)); \
+ uv__req_unregister((loop), (req)); \
+ } while (0)
+
+
+#define UV_SUCCEEDED_WITHOUT_IOCP(result) \
+ ((result) && (handle->flags & UV_HANDLE_SYNC_BYPASS_IOCP))
+
+#define UV_SUCCEEDED_WITH_IOCP(result) \
+ ((result) || (GetLastError() == ERROR_IO_PENDING))
+
+
+#define POST_COMPLETION_FOR_REQ(loop, req) \
+ if (!PostQueuedCompletionStatus((loop)->iocp, \
+ 0, \
+ 0, \
+ &((req)->u.io.overlapped))) { \
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus"); \
+ }
+
+
+INLINE static uv_req_t* uv_overlapped_to_req(OVERLAPPED* overlapped) {
+ return CONTAINING_RECORD(overlapped, uv_req_t, u.io.overlapped);
+}
+
+
+INLINE static void uv_insert_pending_req(uv_loop_t* loop, uv_req_t* req) {
+ req->next_req = NULL;
+ if (loop->pending_reqs_tail) {
+#ifdef _DEBUG
+ /* Ensure the request is not already in the queue, or the queue
+ * will get corrupted.
+ */
+ uv_req_t* current = loop->pending_reqs_tail;
+ do {
+ assert(req != current);
+ current = current->next_req;
+ } while(current != loop->pending_reqs_tail);
+#endif
+
+ req->next_req = loop->pending_reqs_tail->next_req;
+ loop->pending_reqs_tail->next_req = req;
+ loop->pending_reqs_tail = req;
+ } else {
+ req->next_req = req;
+ loop->pending_reqs_tail = req;
+ }
+}
+
+
+#define DELEGATE_STREAM_REQ(loop, req, method, handle_at) \
+ do { \
+ switch (((uv_handle_t*) (req)->handle_at)->type) { \
+ case UV_TCP: \
+ uv_process_tcp_##method##_req(loop, \
+ (uv_tcp_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_NAMED_PIPE: \
+ uv_process_pipe_##method##_req(loop, \
+ (uv_pipe_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ case UV_TTY: \
+ uv_process_tty_##method##_req(loop, \
+ (uv_tty_t*) ((req)->handle_at), \
+ req); \
+ break; \
+ \
+ default: \
+ assert(0); \
+ } \
+ } while (0)
+
+
+INLINE static int uv_process_reqs(uv_loop_t* loop) {
+ uv_req_t* req;
+ uv_req_t* first;
+ uv_req_t* next;
+
+ if (loop->pending_reqs_tail == NULL)
+ return 0;
+
+ first = loop->pending_reqs_tail->next_req;
+ next = first;
+ loop->pending_reqs_tail = NULL;
+
+ while (next != NULL) {
+ req = next;
+ next = req->next_req != first ? req->next_req : NULL;
+
+ switch (req->type) {
+ case UV_READ:
+ DELEGATE_STREAM_REQ(loop, req, read, data);
+ break;
+
+ case UV_WRITE:
+ DELEGATE_STREAM_REQ(loop, (uv_write_t*) req, write, handle);
+ break;
+
+ case UV_ACCEPT:
+ DELEGATE_STREAM_REQ(loop, req, accept, data);
+ break;
+
+ case UV_CONNECT:
+ DELEGATE_STREAM_REQ(loop, (uv_connect_t*) req, connect, handle);
+ break;
+
+ case UV_SHUTDOWN:
+ /* Tcp shutdown requests don't come here. */
+ assert(((uv_shutdown_t*) req)->handle->type == UV_NAMED_PIPE);
+ uv_process_pipe_shutdown_req(
+ loop,
+ (uv_pipe_t*) ((uv_shutdown_t*) req)->handle,
+ (uv_shutdown_t*) req);
+ break;
+
+ case UV_UDP_RECV:
+ uv_process_udp_recv_req(loop, (uv_udp_t*) req->data, req);
+ break;
+
+ case UV_UDP_SEND:
+ uv_process_udp_send_req(loop,
+ ((uv_udp_send_t*) req)->handle,
+ (uv_udp_send_t*) req);
+ break;
+
+ case UV_WAKEUP:
+ uv_process_async_wakeup_req(loop, (uv_async_t*) req->data, req);
+ break;
+
+ case UV_SIGNAL_REQ:
+ uv_process_signal_req(loop, (uv_signal_t*) req->data, req);
+ break;
+
+ case UV_POLL_REQ:
+ uv_process_poll_req(loop, (uv_poll_t*) req->data, req);
+ break;
+
+ case UV_PROCESS_EXIT:
+ uv_process_proc_exit(loop, (uv_process_t*) req->data);
+ break;
+
+ case UV_FS_EVENT_REQ:
+ uv_process_fs_event_req(loop, req, (uv_fs_event_t*) req->data);
+ break;
+
+ default:
+ assert(0);
+ }
+ }
+
+ return 1;
+}
+
+#endif /* UV_WIN_REQ_INL_H_ */
diff --git a/Utilities/cmlibuv/src/win/req.c b/Utilities/cmlibuv/src/win/req.c
new file mode 100644
index 000000000..111cc5e28
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/req.c
@@ -0,0 +1,25 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
diff --git a/Utilities/cmlibuv/src/win/signal.c b/Utilities/cmlibuv/src/win/signal.c
new file mode 100644
index 000000000..7b42dd992
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/signal.c
@@ -0,0 +1,277 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <signal.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+RB_HEAD(uv_signal_tree_s, uv_signal_s);
+
+static struct uv_signal_tree_s uv__signal_tree = RB_INITIALIZER(uv__signal_tree);
+static CRITICAL_SECTION uv__signal_lock;
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type);
+
+int uv__signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum,
+ int oneshot);
+
+void uv_signals_init(void) {
+ InitializeCriticalSection(&uv__signal_lock);
+ if (!SetConsoleCtrlHandler(uv__signal_control_handler, TRUE))
+ abort();
+}
+
+
+static int uv__signal_compare(uv_signal_t* w1, uv_signal_t* w2) {
+ /* Compare signums first so all watchers with the same signnum end up */
+ /* adjacent. */
+ if (w1->signum < w2->signum) return -1;
+ if (w1->signum > w2->signum) return 1;
+
+ /* Sort by loop pointer, so we can easily look up the first item after */
+ /* { .signum = x, .loop = NULL } */
+ if ((uintptr_t) w1->loop < (uintptr_t) w2->loop) return -1;
+ if ((uintptr_t) w1->loop > (uintptr_t) w2->loop) return 1;
+
+ if ((uintptr_t) w1 < (uintptr_t) w2) return -1;
+ if ((uintptr_t) w1 > (uintptr_t) w2) return 1;
+
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_signal_tree_s, uv_signal_s, tree_entry, uv__signal_compare);
+
+
+/*
+ * Dispatches signal {signum} to all active uv_signal_t watchers in all loops.
+ * Returns 1 if the signal was dispatched to any watcher, or 0 if there were
+ * no active signal watchers observing this signal.
+ */
+int uv__signal_dispatch(int signum) {
+ uv_signal_t lookup;
+ uv_signal_t* handle;
+ int dispatched;
+
+ dispatched = 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ lookup.signum = signum;
+ lookup.loop = NULL;
+
+ for (handle = RB_NFIND(uv_signal_tree_s, &uv__signal_tree, &lookup);
+ handle != NULL && handle->signum == signum;
+ handle = RB_NEXT(uv_signal_tree_s, &uv__signal_tree, handle)) {
+ unsigned long previous = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, signum);
+
+ if (handle->flags & UV__SIGNAL_ONE_SHOT_DISPATCHED)
+ continue;
+
+ if (!previous) {
+ POST_COMPLETION_FOR_REQ(handle->loop, &handle->signal_req);
+ }
+
+ dispatched = 1;
+ if (handle->flags & UV__SIGNAL_ONE_SHOT)
+ handle->flags |= UV__SIGNAL_ONE_SHOT_DISPATCHED;
+ }
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ return dispatched;
+}
+
+
+static BOOL WINAPI uv__signal_control_handler(DWORD type) {
+ switch (type) {
+ case CTRL_C_EVENT:
+ return uv__signal_dispatch(SIGINT);
+
+ case CTRL_BREAK_EVENT:
+ return uv__signal_dispatch(SIGBREAK);
+
+ case CTRL_CLOSE_EVENT:
+ if (uv__signal_dispatch(SIGHUP)) {
+ /* Windows will terminate the process after the control handler */
+ /* returns. After that it will just terminate our process. Therefore */
+ /* block the signal handler so the main loop has some time to pick */
+ /* up the signal and do something for a few seconds. */
+ Sleep(INFINITE);
+ return TRUE;
+ }
+ return FALSE;
+
+ case CTRL_LOGOFF_EVENT:
+ case CTRL_SHUTDOWN_EVENT:
+ /* These signals are only sent to services. Services have their own */
+ /* notification mechanism, so there's no point in handling these. */
+
+ default:
+ /* We don't handle these. */
+ return FALSE;
+ }
+}
+
+
+int uv_signal_init(uv_loop_t* loop, uv_signal_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_SIGNAL);
+ handle->pending_signum = 0;
+ handle->signum = 0;
+ handle->signal_cb = NULL;
+
+ UV_REQ_INIT(&handle->signal_req, UV_SIGNAL_REQ);
+ handle->signal_req.data = handle;
+
+ return 0;
+}
+
+
+int uv_signal_stop(uv_signal_t* handle) {
+ uv_signal_t* removed_handle;
+
+ /* If the watcher wasn't started, this is a no-op. */
+ if (handle->signum == 0)
+ return 0;
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ removed_handle = RB_REMOVE(uv_signal_tree_s, &uv__signal_tree, handle);
+ assert(removed_handle == handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signum = 0;
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_signal_start(uv_signal_t* handle, uv_signal_cb signal_cb, int signum) {
+ return uv__signal_start(handle, signal_cb, signum, 0);
+}
+
+
+int uv_signal_start_oneshot(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum) {
+ return uv__signal_start(handle, signal_cb, signum, 1);
+}
+
+
+int uv__signal_start(uv_signal_t* handle,
+ uv_signal_cb signal_cb,
+ int signum,
+ int oneshot) {
+ /* Test for invalid signal values. */
+ if (signum != SIGWINCH && (signum <= 0 || signum >= NSIG))
+ return UV_EINVAL;
+
+ /* Short circuit: if the signal watcher is already watching {signum} don't */
+ /* go through the process of deregistering and registering the handler. */
+ /* Additionally, this avoids pending signals getting lost in the (small) */
+ /* time frame that handle->signum == 0. */
+ if (signum == handle->signum) {
+ handle->signal_cb = signal_cb;
+ return 0;
+ }
+
+ /* If the signal handler was already active, stop it first. */
+ if (handle->signum != 0) {
+ int r = uv_signal_stop(handle);
+ /* uv_signal_stop is infallible. */
+ assert(r == 0);
+ }
+
+ EnterCriticalSection(&uv__signal_lock);
+
+ handle->signum = signum;
+ if (oneshot)
+ handle->flags |= UV__SIGNAL_ONE_SHOT;
+
+ RB_INSERT(uv_signal_tree_s, &uv__signal_tree, handle);
+
+ LeaveCriticalSection(&uv__signal_lock);
+
+ handle->signal_cb = signal_cb;
+ uv__handle_start(handle);
+
+ return 0;
+}
+
+
+void uv_process_signal_req(uv_loop_t* loop, uv_signal_t* handle,
+ uv_req_t* req) {
+ long dispatched_signum;
+
+ assert(handle->type == UV_SIGNAL);
+ assert(req->type == UV_SIGNAL_REQ);
+
+ dispatched_signum = InterlockedExchange(
+ (volatile LONG*) &handle->pending_signum, 0);
+ assert(dispatched_signum != 0);
+
+ /* Check if the pending signal equals the signum that we are watching for. */
+ /* These can get out of sync when the handler is stopped and restarted */
+ /* while the signal_req is pending. */
+ if (dispatched_signum == handle->signum)
+ handle->signal_cb(handle, dispatched_signum);
+
+ if (handle->flags & UV__SIGNAL_ONE_SHOT)
+ uv_signal_stop(handle);
+
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ /* When it is closing, it must be stopped at this point. */
+ assert(handle->signum == 0);
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_close(uv_loop_t* loop, uv_signal_t* handle) {
+ uv_signal_stop(handle);
+ uv__handle_closing(handle);
+
+ if (handle->pending_signum == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_signal_endgame(uv_loop_t* loop, uv_signal_t* handle) {
+ assert(handle->flags & UV__HANDLE_CLOSING);
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ assert(handle->signum == 0);
+ assert(handle->pending_signum == 0);
+
+ handle->flags |= UV_HANDLE_CLOSED;
+
+ uv__handle_close(handle);
+}
diff --git a/Utilities/cmlibuv/src/win/snprintf.c b/Utilities/cmlibuv/src/win/snprintf.c
new file mode 100644
index 000000000..776c0e392
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/snprintf.c
@@ -0,0 +1,42 @@
+/* Copyright the libuv project contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#if defined(_MSC_VER) && _MSC_VER < 1900
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Emulate snprintf() on MSVC<2015, _snprintf() doesn't zero-terminate the buffer
+ * on overflow...
+ */
+int snprintf(char* buf, size_t len, const char* fmt, ...) {
+ int n;
+ va_list ap;
+ va_start(ap, fmt);
+
+ n = _vscprintf(fmt, ap);
+ vsnprintf_s(buf, len, _TRUNCATE, fmt, ap);
+
+ va_end(ap);
+ return n;
+}
+
+#endif
diff --git a/Utilities/cmlibuv/src/win/stream-inl.h b/Utilities/cmlibuv/src/win/stream-inl.h
new file mode 100644
index 000000000..bf12148af
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/stream-inl.h
@@ -0,0 +1,55 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_STREAM_INL_H_
+#define UV_WIN_STREAM_INL_H_
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+INLINE static void uv_stream_init(uv_loop_t* loop,
+ uv_stream_t* handle,
+ uv_handle_type type) {
+ uv__handle_init(loop, (uv_handle_t*) handle, type);
+ handle->write_queue_size = 0;
+ handle->activecnt = 0;
+}
+
+
+INLINE static void uv_connection_init(uv_stream_t* handle) {
+ handle->flags |= UV_HANDLE_CONNECTION;
+ handle->stream.conn.write_reqs_pending = 0;
+
+ UV_REQ_INIT(&handle->read_req, UV_READ);
+ handle->read_req.event_handle = NULL;
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ handle->read_req.data = handle;
+
+ handle->stream.conn.shutdown_req = NULL;
+}
+
+
+#endif /* UV_WIN_STREAM_INL_H_ */
diff --git a/Utilities/cmlibuv/src/win/stream.c b/Utilities/cmlibuv/src/win/stream.c
new file mode 100644
index 000000000..13cbfdcb9
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/stream.c
@@ -0,0 +1,248 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "req-inl.h"
+
+
+int uv_listen(uv_stream_t* stream, int backlog, uv_connection_cb cb) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (stream->type) {
+ case UV_TCP:
+ err = uv_tcp_listen((uv_tcp_t*)stream, backlog, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_listen((uv_pipe_t*)stream, backlog, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_accept(uv_stream_t* server, uv_stream_t* client) {
+ int err;
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (server->type) {
+ case UV_TCP:
+ err = uv_tcp_accept((uv_tcp_t*)server, (uv_tcp_t*)client);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_accept((uv_pipe_t*)server, client);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_start(uv_stream_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return UV_EALREADY;
+ }
+
+ if (!(handle->flags & UV_HANDLE_READABLE)) {
+ return UV_ENOTCONN;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_read_start((uv_tcp_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_read_start((uv_pipe_t*)handle, alloc_cb, read_cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_read_start((uv_tty_t*) handle, alloc_cb, read_cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_read_stop(uv_stream_t* handle) {
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_READING))
+ return 0;
+
+ err = 0;
+ if (handle->type == UV_TTY) {
+ err = uv_tty_read_stop((uv_tty_t*) handle);
+ } else {
+ if (handle->type == UV_NAMED_PIPE) {
+ uv__pipe_stop_read((uv_pipe_t*) handle);
+ } else {
+ handle->flags &= ~UV_HANDLE_READING;
+ }
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_TCP:
+ err = uv_tcp_write(loop, req, (uv_tcp_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write(loop, req, (uv_pipe_t*) handle, bufs, nbufs, cb);
+ break;
+ case UV_TTY:
+ err = uv_tty_write(loop, req, (uv_tty_t*) handle, bufs, nbufs, cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_write2(uv_write_t* req,
+ uv_stream_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_stream_t* send_handle,
+ uv_write_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ err = ERROR_INVALID_PARAMETER;
+ switch (handle->type) {
+ case UV_NAMED_PIPE:
+ err = uv_pipe_write2(loop,
+ req,
+ (uv_pipe_t*) handle,
+ bufs,
+ nbufs,
+ send_handle,
+ cb);
+ break;
+ default:
+ assert(0);
+ }
+
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_try_write(uv_stream_t* stream,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ if (stream->flags & UV__HANDLE_CLOSING)
+ return UV_EBADF;
+ if (!(stream->flags & UV_HANDLE_WRITABLE))
+ return UV_EPIPE;
+
+ switch (stream->type) {
+ case UV_TCP:
+ return uv__tcp_try_write((uv_tcp_t*) stream, bufs, nbufs);
+ case UV_TTY:
+ return uv__tty_try_write((uv_tty_t*) stream, bufs, nbufs);
+ case UV_NAMED_PIPE:
+ return UV_EAGAIN;
+ default:
+ assert(0);
+ return UV_ENOSYS;
+ }
+}
+
+
+int uv_shutdown(uv_shutdown_t* req, uv_stream_t* handle, uv_shutdown_cb cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_WRITABLE)) {
+ return UV_EPIPE;
+ }
+
+ UV_REQ_INIT(req, UV_SHUTDOWN);
+ req->handle = handle;
+ req->cb = cb;
+
+ handle->flags &= ~UV_HANDLE_WRITABLE;
+ handle->stream.conn.shutdown_req = req;
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+
+ return 0;
+}
+
+
+int uv_is_readable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_READABLE);
+}
+
+
+int uv_is_writable(const uv_stream_t* handle) {
+ return !!(handle->flags & UV_HANDLE_WRITABLE);
+}
+
+
+int uv_stream_set_blocking(uv_stream_t* handle, int blocking) {
+ if (handle->type != UV_NAMED_PIPE)
+ return UV_EINVAL;
+
+ if (blocking != 0)
+ handle->flags |= UV_HANDLE_BLOCKING_WRITES;
+ else
+ handle->flags &= ~UV_HANDLE_BLOCKING_WRITES;
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/win/tcp.c b/Utilities/cmlibuv/src/win/tcp.c
new file mode 100644
index 000000000..972539f4d
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/tcp.c
@@ -0,0 +1,1505 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active tcp streams for which to preallocate tcp read buffers.
+ * (Due to node slab allocator performing poorly under this pattern,
+ * the optimization is temporarily disabled (threshold=0). This will be
+ * revisited once node allocator is improved.)
+ */
+const unsigned int uv_active_tcp_streams_threshold = 0;
+
+/*
+ * Number of simultaneous pending AcceptEx calls.
+ */
+const unsigned int uv_simultaneous_server_accepts = 32;
+
+/* A zero-size buffer for use by uv_tcp_read */
+static char uv_zero_[] = "";
+
+static int uv__tcp_nodelay(uv_tcp_t* handle, SOCKET socket, int enable) {
+ if (setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_NODELAY,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+ return 0;
+}
+
+
+static int uv__tcp_keepalive(uv_tcp_t* handle, SOCKET socket, int enable, unsigned int delay) {
+ if (setsockopt(socket,
+ SOL_SOCKET,
+ SO_KEEPALIVE,
+ (const char*)&enable,
+ sizeof enable) == -1) {
+ return WSAGetLastError();
+ }
+
+ if (enable && setsockopt(socket,
+ IPPROTO_TCP,
+ TCP_KEEPALIVE,
+ (const char*)&delay,
+ sizeof delay) == -1) {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_set_socket(uv_loop_t* loop,
+ uv_tcp_t* handle,
+ SOCKET socket,
+ int family,
+ int imported) {
+ DWORD yes = 1;
+ int non_ifs_lsp;
+ int err;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) socket, HANDLE_FLAG_INHERIT, 0))
+ return GetLastError();
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ if (imported) {
+ handle->flags |= UV_HANDLE_EMULATE_IOCP;
+ } else {
+ return GetLastError();
+ }
+ }
+
+ if (family == AF_INET6) {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv6;
+ } else {
+ non_ifs_lsp = uv_tcp_non_ifs_lsp_ipv4;
+ }
+
+ if (pSetFileCompletionNotificationModes &&
+ !(handle->flags & UV_HANDLE_EMULATE_IOCP) && !non_ifs_lsp) {
+ if (pSetFileCompletionNotificationModes((HANDLE) socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+
+ if (handle->flags & UV_HANDLE_TCP_NODELAY) {
+ err = uv__tcp_nodelay(handle, socket, 1);
+ if (err)
+ return err;
+ }
+
+ /* TODO: Use stored delay. */
+ if (handle->flags & UV_HANDLE_TCP_KEEPALIVE) {
+ err = uv__tcp_keepalive(handle, socket, 1, 60);
+ if (err)
+ return err;
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv_stream_init(loop, (uv_stream_t*) handle, UV_TCP);
+ handle->tcp.serv.accept_reqs = NULL;
+ handle->tcp.serv.pending_accepts = NULL;
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->tcp.serv.func_acceptex = NULL;
+ handle->tcp.conn.func_connectex = NULL;
+ handle->tcp.serv.processed_accepts = 0;
+ handle->delayed_error = 0;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init in uv_stream_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, domain, 0);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* handle) {
+ return uv_tcp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_tcp_endgame(uv_loop_t* loop, uv_tcp_t* handle) {
+ int err;
+ unsigned int i;
+ uv_tcp_accept_t* req;
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ err = 0;
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ err = ERROR_OPERATION_ABORTED;
+ } else if (shutdown(handle->socket, SD_SEND) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ }
+
+ if (handle->stream.conn.shutdown_req->cb) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req,
+ uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+
+ if (!(handle->flags & UV_HANDLE_TCP_SOCKET_CLOSED)) {
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+ handle->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ if (!(handle->flags & UV_HANDLE_CONNECTION) && handle->tcp.serv.accept_reqs) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+ }
+
+ uv__free(handle->tcp.serv.accept_reqs);
+ handle->tcp.serv.accept_reqs = NULL;
+ }
+
+ if (handle->flags & UV_HANDLE_CONNECTION &&
+ handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (handle->read_req.wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(handle->read_req.wait_handle);
+ handle->read_req.wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (handle->read_req.event_handle) {
+ CloseHandle(handle->read_req.event_handle);
+ handle->read_req.event_handle = NULL;
+ }
+ }
+
+ uv__handle_close(handle);
+ loop->active_tcp_streams--;
+ }
+}
+
+
+/* Unlike on Unix, here we don't set SO_REUSEADDR, because it doesn't just
+ * allow binding to addresses that are in use by sockets in TIME_WAIT, it
+ * effectively allows 'stealing' a port which is in use by another application.
+ *
+ * SO_EXCLUSIVEADDRUSE is also not good here because it does check all sockets,
+ * regardless of state, so we'd get an error even if the port is in use by a
+ * socket in TIME_WAIT state.
+ *
+ * See issue #1360.
+ *
+ */
+static int uv_tcp_try_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ DWORD err;
+ int r;
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock;
+
+ /* Cannot set IPv6-only mode on non-IPv6 socket. */
+ if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
+ return ERROR_INVALID_PARAMETER;
+
+ sock = socket(addr->sa_family, SOCK_STREAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(handle->loop, handle, sock, addr->sa_family, 0);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+#ifdef IPV6_V6ONLY
+ if (addr->sa_family == AF_INET6) {
+ int on;
+
+ on = (flags & UV_TCP_IPV6ONLY) != 0;
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (const char*)&on,
+ sizeof on);
+ }
+#endif
+
+ r = bind(handle->socket, addr, addrlen);
+
+ if (r == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ if (err == WSAEADDRINUSE) {
+ /* Some errors are not to be reported until connect() or listen() */
+ handle->delayed_error = err;
+ } else {
+ return err;
+ }
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void CALLBACK post_completion(void* context, BOOLEAN timed_out) {
+ uv_req_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_req_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->data;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void CALLBACK post_write_completion(void* context, BOOLEAN timed_out) {
+ uv_write_t* req;
+ uv_tcp_t* handle;
+
+ req = (uv_write_t*) context;
+ assert(req != NULL);
+ handle = (uv_tcp_t*)req->handle;
+ assert(handle != NULL);
+ assert(!timed_out);
+
+ if (!PostQueuedCompletionStatus(handle->loop->iocp,
+ req->u.io.overlapped.InternalHigh,
+ 0,
+ &req->u.io.overlapped)) {
+ uv_fatal_error(GetLastError(), "PostQueuedCompletionStatus");
+ }
+}
+
+
+static void uv_tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) {
+ uv_loop_t* loop = handle->loop;
+ BOOL success;
+ DWORD bytes;
+ SOCKET accept_socket;
+ short family;
+
+ assert(handle->flags & UV_HANDLE_LISTENING);
+ assert(req->accept_socket == INVALID_SOCKET);
+
+ /* choose family and extension function */
+ if (handle->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ /* Open a socket for the accepted connection. */
+ accept_socket = socket(family, SOCK_STREAM, 0);
+ if (accept_socket == INVALID_SOCKET) {
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE) accept_socket, HANDLE_FLAG_INHERIT, 0)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ closesocket(accept_socket);
+ return;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ success = handle->tcp.serv.func_acceptex(handle->socket,
+ accept_socket,
+ (void*)req->accept_buffer,
+ 0,
+ sizeof(struct sockaddr_storage),
+ sizeof(struct sockaddr_storage),
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ req->accept_socket = accept_socket;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ return;
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ /* Destroy the preallocated client socket. */
+ closesocket(accept_socket);
+ /* Destroy the event handle */
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ CloseHandle(req->u.io.overlapped.hEvent);
+ req->event_handle = NULL;
+ }
+ }
+}
+
+
+static void uv_tcp_queue_read(uv_loop_t* loop, uv_tcp_t* handle) {
+ uv_read_t* req;
+ uv_buf_t buf;
+ int result;
+ DWORD bytes, flags;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_tcp_streams < uv_active_tcp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+ handle->tcp.conn.read_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->tcp.conn.read_buffer);
+ if (handle->tcp.conn.read_buffer.base == NULL ||
+ handle->tcp.conn.read_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &handle->tcp.conn.read_buffer);
+ return;
+ }
+ assert(handle->tcp.conn.read_buffer.base != NULL);
+ buf = handle->tcp.conn.read_buffer;
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+ buf.base = (char*) &uv_zero_;
+ buf.len = 0;
+ }
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ assert(req->event_handle);
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ }
+
+ flags = 0;
+ result = WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ req->wait_handle == INVALID_HANDLE_VALUE &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ handle->reqs_pending++;
+ }
+}
+
+
+int uv_tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) {
+ unsigned int i, simultaneous_accepts;
+ uv_tcp_accept_t* req;
+ int err;
+
+ assert(backlog > 0);
+
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->stream.serv.connection_cb = cb;
+ }
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEISCONN;
+ }
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ err = uv_tcp_try_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.serv.func_acceptex) {
+ if (!uv_get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ listen(handle->socket, backlog) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_LISTENING;
+ handle->stream.serv.connection_cb = cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ simultaneous_accepts = handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT ? 1
+ : uv_simultaneous_server_accepts;
+
+ if(!handle->tcp.serv.accept_reqs) {
+ handle->tcp.serv.accept_reqs = (uv_tcp_accept_t*)
+ uv__malloc(uv_simultaneous_server_accepts * sizeof(uv_tcp_accept_t));
+ if (!handle->tcp.serv.accept_reqs) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ for (i = 0; i < simultaneous_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ UV_REQ_INIT(req, UV_ACCEPT);
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ } else {
+ req->event_handle = NULL;
+ }
+
+ uv_tcp_queue_accept(handle, req);
+ }
+
+ /* Initialize other unused requests too, because uv_tcp_endgame */
+ /* doesn't know how how many requests were initialized, so it will */
+ /* try to clean up {uv_simultaneous_server_accepts} requests. */
+ for (i = simultaneous_accepts; i < uv_simultaneous_server_accepts; i++) {
+ req = &handle->tcp.serv.accept_reqs[i];
+ UV_REQ_INIT(req, UV_ACCEPT);
+ req->accept_socket = INVALID_SOCKET;
+ req->data = handle;
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ req->event_handle = NULL;
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_accept(uv_tcp_t* server, uv_tcp_t* client) {
+ uv_loop_t* loop = server->loop;
+ int err = 0;
+ int family;
+
+ uv_tcp_accept_t* req = server->tcp.serv.pending_accepts;
+
+ if (!req) {
+ /* No valid connections found, so we error out. */
+ return WSAEWOULDBLOCK;
+ }
+
+ if (req->accept_socket == INVALID_SOCKET) {
+ return WSAENOTCONN;
+ }
+
+ if (server->flags & UV_HANDLE_IPV6) {
+ family = AF_INET6;
+ } else {
+ family = AF_INET;
+ }
+
+ err = uv_tcp_set_socket(client->loop,
+ client,
+ req->accept_socket,
+ family,
+ 0);
+ if (err) {
+ closesocket(req->accept_socket);
+ } else {
+ uv_connection_init((uv_stream_t*) client);
+ /* AcceptEx() implicitly binds the accepted socket. */
+ client->flags |= UV_HANDLE_BOUND | UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ /* Prepare the req to pick up a new connection */
+ server->tcp.serv.pending_accepts = req->next_pending;
+ req->next_pending = NULL;
+ req->accept_socket = INVALID_SOCKET;
+
+ if (!(server->flags & UV__HANDLE_CLOSING)) {
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (!(server->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING)) {
+ uv_tcp_queue_accept(server, req);
+ } else {
+ /* We better be switching to a single pending accept. */
+ assert(server->flags & UV_HANDLE_TCP_SINGLE_ACCEPT);
+
+ server->tcp.serv.processed_accepts++;
+
+ if (server->tcp.serv.processed_accepts >= uv_simultaneous_server_accepts) {
+ server->tcp.serv.processed_accepts = 0;
+ /*
+ * All previously queued accept requests are now processed.
+ * We now switch to queueing just a single accept.
+ */
+ uv_tcp_queue_accept(server, &server->tcp.serv.accept_reqs[0]);
+ server->flags &= ~UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ server->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+ }
+ }
+ }
+
+ loop->active_tcp_streams++;
+
+ return err;
+}
+
+
+int uv_tcp_read_start(uv_tcp_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ handle->flags |= UV_HANDLE_READING;
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING)) {
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !handle->read_req.event_handle) {
+ handle->read_req.event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!handle->read_req.event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ }
+ uv_tcp_queue_read(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ const struct sockaddr* bind_addr;
+ BOOL success;
+ DWORD bytes;
+ int err;
+
+ if (handle->delayed_error) {
+ return handle->delayed_error;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_tcp_try_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return err;
+ if (handle->delayed_error)
+ return handle->delayed_error;
+ }
+
+ if (!handle->tcp.conn.func_connectex) {
+ if (!uv_get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) {
+ return WSAEAFNOSUPPORT;
+ }
+ }
+
+ UV_REQ_INIT(req, UV_CONNECT);
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ success = handle->tcp.conn.func_connectex(handle->socket,
+ addr,
+ addrlen,
+ NULL,
+ 0,
+ &bytes,
+ &req->u.io.overlapped);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(success)) {
+ /* Process the req without IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(success)) {
+ /* The req will be processed with IOCP. */
+ handle->reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getsockname(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_getpeername(const uv_tcp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ if (handle->delayed_error) {
+ return uv_translate_sys_error(handle->delayed_error);
+ }
+
+ result = getpeername(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ int result;
+ DWORD bytes;
+
+ UV_REQ_INIT(req, UV_WRITE);
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ /* Prepare the overlapped structure. */
+ memset(&(req->u.io.overlapped), 0, sizeof(req->u.io.overlapped));
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ req->event_handle = CreateEvent(NULL, 0, 0, NULL);
+ if (!req->event_handle) {
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+ req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ handle->write_queue_size += req->u.io.queued_bytes;
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP &&
+ !RegisterWaitForSingleObject(&req->wait_handle,
+ req->event_handle, post_write_completion, (void*) req,
+ INFINITE, WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE)) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+ } else {
+ /* Send failed due to an error, report it later */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+ }
+
+ return 0;
+}
+
+
+int uv__tcp_try_write(uv_tcp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ int result;
+ DWORD bytes;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ result = WSASend(handle->socket,
+ (WSABUF*) bufs,
+ nbufs,
+ &bytes,
+ 0,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR)
+ return uv_translate_sys_error(WSAGetLastError());
+ else
+ return bytes;
+}
+
+
+void uv_process_tcp_read_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* req) {
+ DWORD bytes, flags, err;
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TCP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred doing the read. */
+ if ((handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_ZERO_READ)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->tcp.conn.read_buffer;
+
+ err = GET_REQ_SOCK_ERROR(req);
+
+ if (err == WSAECONNABORTED) {
+ /*
+ * Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with Unix.
+ */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ } else {
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* The read was done with a non-zero buffer length. */
+ if (req->u.io.overlapped.InternalHigh > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->tcp.conn.read_buffer);
+ /* Read again only if bytes == buf.len */
+ if (req->u.io.overlapped.InternalHigh < handle->tcp.conn.read_buffer.len) {
+ goto done;
+ }
+ } else {
+ /* Connection closed */
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+ handle->flags &= ~UV_HANDLE_READABLE;
+
+ buf.base = 0;
+ buf.len = 0;
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &handle->tcp.conn.read_buffer);
+ goto done;
+ }
+ }
+
+ /* Do nonblocking reads until the buffer is empty */
+ while (handle->flags & UV_HANDLE_READING) {
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ break;
+ }
+ assert(buf.base != NULL);
+
+ flags = 0;
+ if (WSARecv(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+ if (bytes > 0) {
+ /* Successful read */
+ handle->read_cb((uv_stream_t*)handle, bytes, &buf);
+ /* Read again only if bytes == buf.len */
+ if (bytes < buf.len) {
+ break;
+ }
+ } else {
+ /* Connection closed */
+ handle->flags &= ~(UV_HANDLE_READING | UV_HANDLE_READABLE);
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ handle->read_cb((uv_stream_t*)handle, UV_EOF, &buf);
+ break;
+ }
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEWOULDBLOCK) {
+ /* Read buffer was completely empty, report a 0-byte read. */
+ handle->read_cb((uv_stream_t*)handle, 0, &buf);
+ } else {
+ /* Ouch! serious error. */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+
+ if (err == WSAECONNABORTED) {
+ /* Turn WSAECONNABORTED into UV_ECONNRESET to be consistent with */
+ /* Unix. */
+ err = WSAECONNRESET;
+ }
+
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err),
+ &buf);
+ }
+ break;
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tcp_queue_read(loop, handle);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_write_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ assert(handle->write_queue_size >= req->u.io.queued_bytes);
+ handle->write_queue_size -= req->u.io.queued_bytes;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (handle->flags & UV_HANDLE_EMULATE_IOCP) {
+ if (req->wait_handle != INVALID_HANDLE_VALUE) {
+ UnregisterWait(req->wait_handle);
+ req->wait_handle = INVALID_HANDLE_VALUE;
+ }
+ if (req->event_handle) {
+ CloseHandle(req->event_handle);
+ req->event_handle = NULL;
+ }
+ }
+
+ if (req->cb) {
+ err = uv_translate_sys_error(GET_REQ_SOCK_ERROR(req));
+ if (err == UV_ECONNABORTED) {
+ /* use UV_ECANCELED for consistency with Unix */
+ err = UV_ECANCELED;
+ }
+ req->cb(req, err);
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_accept_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_req_t* raw_req) {
+ uv_tcp_accept_t* req = (uv_tcp_accept_t*) raw_req;
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ /* If handle->accepted_socket is not a valid socket, then */
+ /* uv_queue_accept must have failed. This is a serious error. We stop */
+ /* accepting connections and report this error to the connection */
+ /* callback. */
+ if (req->accept_socket == INVALID_SOCKET) {
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ if (handle->stream.serv.connection_cb) {
+ err = GET_REQ_SOCK_ERROR(req);
+ handle->stream.serv.connection_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(err));
+ }
+ }
+ } else if (REQ_SUCCESS(req) &&
+ setsockopt(req->accept_socket,
+ SOL_SOCKET,
+ SO_UPDATE_ACCEPT_CONTEXT,
+ (char*)&handle->socket,
+ sizeof(handle->socket)) == 0) {
+ req->next_pending = handle->tcp.serv.pending_accepts;
+ handle->tcp.serv.pending_accepts = req;
+
+ /* Accept and SO_UPDATE_ACCEPT_CONTEXT were successful. */
+ if (handle->stream.serv.connection_cb) {
+ handle->stream.serv.connection_cb((uv_stream_t*)handle, 0);
+ }
+ } else {
+ /* Error related to accepted socket is ignored because the server */
+ /* socket may still be healthy. If the server socket is broken */
+ /* uv_queue_accept will detect it. */
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ uv_tcp_queue_accept(handle, req);
+ }
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tcp_connect_req(uv_loop_t* loop, uv_tcp_t* handle,
+ uv_connect_t* req) {
+ int err;
+
+ assert(handle->type == UV_TCP);
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ err = 0;
+ if (REQ_SUCCESS(req)) {
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_UPDATE_CONNECT_CONTEXT,
+ NULL,
+ 0) == 0) {
+ uv_connection_init((uv_stream_t*)handle);
+ handle->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ loop->active_tcp_streams++;
+ } else {
+ err = WSAGetLastError();
+ }
+ } else {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+int uv_tcp_import(uv_tcp_t* tcp, uv__ipc_socket_info_ex* socket_info_ex,
+ int tcp_connection) {
+ int err;
+ SOCKET socket = WSASocketW(FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ FROM_PROTOCOL_INFO,
+ &socket_info_ex->socket_info,
+ 0,
+ WSA_FLAG_OVERLAPPED);
+
+ if (socket == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_tcp_set_socket(tcp->loop,
+ tcp,
+ socket,
+ socket_info_ex->socket_info.iAddressFamily,
+ 1);
+ if (err) {
+ closesocket(socket);
+ return err;
+ }
+
+ if (tcp_connection) {
+ uv_connection_init((uv_stream_t*)tcp);
+ tcp->flags |= UV_HANDLE_READABLE | UV_HANDLE_WRITABLE;
+ }
+
+ tcp->flags |= UV_HANDLE_BOUND;
+ tcp->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ tcp->delayed_error = socket_info_ex->delayed_error;
+
+ tcp->loop->active_tcp_streams++;
+ return 0;
+}
+
+
+int uv_tcp_nodelay(uv_tcp_t* handle, int enable) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_nodelay(handle, handle->socket, enable);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_NODELAY;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_NODELAY;
+ }
+
+ return 0;
+}
+
+
+int uv_tcp_keepalive(uv_tcp_t* handle, int enable, unsigned int delay) {
+ int err;
+
+ if (handle->socket != INVALID_SOCKET) {
+ err = uv__tcp_keepalive(handle, handle->socket, enable, delay);
+ if (err)
+ return err;
+ }
+
+ if (enable) {
+ handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
+ } else {
+ handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
+ }
+
+ /* TODO: Store delay if handle->socket isn't created yet. */
+
+ return 0;
+}
+
+
+int uv_tcp_duplicate_socket(uv_tcp_t* handle, int pid,
+ LPWSAPROTOCOL_INFOW protocol_info) {
+ if (!(handle->flags & UV_HANDLE_CONNECTION)) {
+ /*
+ * We're about to share the socket with another process. Because
+ * this is a listening socket, we assume that the other process will
+ * be accepting connections on it. So, before sharing the socket
+ * with another process, we call listen here in the parent process.
+ */
+
+ if (!(handle->flags & UV_HANDLE_LISTENING)) {
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (!(handle->delayed_error)) {
+ if (listen(handle->socket, SOMAXCONN) == SOCKET_ERROR) {
+ handle->delayed_error = WSAGetLastError();
+ }
+ }
+ }
+ }
+
+ if (WSADuplicateSocketW(handle->socket, pid, protocol_info)) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_SHARED_TCP_SOCKET;
+
+ return 0;
+}
+
+
+int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
+ if (handle->flags & UV_HANDLE_CONNECTION) {
+ return UV_EINVAL;
+ }
+
+ /* Check if we're already in the desired mode. */
+ if ((enable && !(handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) ||
+ (!enable && handle->flags & UV_HANDLE_TCP_SINGLE_ACCEPT)) {
+ return 0;
+ }
+
+ /* Don't allow switching from single pending accept to many. */
+ if (enable) {
+ return UV_ENOTSUP;
+ }
+
+ /* Check if we're in a middle of changing the number of pending accepts. */
+ if (handle->flags & UV_HANDLE_TCP_ACCEPT_STATE_CHANGING) {
+ return 0;
+ }
+
+ handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
+
+ /* Flip the changing flag if we have already queued multiple accepts. */
+ if (handle->flags & UV_HANDLE_LISTENING) {
+ handle->flags |= UV_HANDLE_TCP_ACCEPT_STATE_CHANGING;
+ }
+
+ return 0;
+}
+
+
+static int uv_tcp_try_cancel_io(uv_tcp_t* tcp) {
+ SOCKET socket = tcp->socket;
+ int non_ifs_lsp;
+
+ /* Check if we have any non-IFS LSPs stacked on top of TCP */
+ non_ifs_lsp = (tcp->flags & UV_HANDLE_IPV6) ? uv_tcp_non_ifs_lsp_ipv6 :
+ uv_tcp_non_ifs_lsp_ipv4;
+
+ /* If there are non-ifs LSPs then try to obtain a base handle for the */
+ /* socket. This will always fail on Windows XP/3k. */
+ if (non_ifs_lsp) {
+ DWORD bytes;
+ if (WSAIoctl(socket,
+ SIO_BASE_HANDLE,
+ NULL,
+ 0,
+ &socket,
+ sizeof socket,
+ &bytes,
+ NULL,
+ NULL) != 0) {
+ /* Failed. We can't do CancelIo. */
+ return -1;
+ }
+ }
+
+ assert(socket != 0 && socket != INVALID_SOCKET);
+
+ if (!CancelIo((HANDLE) socket)) {
+ return GetLastError();
+ }
+
+ /* It worked. */
+ return 0;
+}
+
+
+void uv_tcp_close(uv_loop_t* loop, uv_tcp_t* tcp) {
+ int close_socket = 1;
+
+ if (tcp->flags & UV_HANDLE_READ_PENDING) {
+ /* In order for winsock to do a graceful close there must not be any */
+ /* any pending reads, or the socket must be shut down for writing */
+ if (!(tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET)) {
+ /* Just do shutdown on non-shared sockets, which ensures graceful close. */
+ shutdown(tcp->socket, SD_SEND);
+
+ } else if (uv_tcp_try_cancel_io(tcp) == 0) {
+ /* In case of a shared socket, we try to cancel all outstanding I/O, */
+ /* If that works, don't close the socket yet - wait for the read req to */
+ /* return and close the socket in uv_tcp_endgame. */
+ close_socket = 0;
+
+ } else {
+ /* When cancelling isn't possible - which could happen when an LSP is */
+ /* present on an old Windows version, we will have to close the socket */
+ /* with a read pending. That is not nice because trailing sent bytes */
+ /* may not make it to the other side. */
+ }
+
+ } else if ((tcp->flags & UV_HANDLE_SHARED_TCP_SOCKET) &&
+ tcp->tcp.serv.accept_reqs != NULL) {
+ /* Under normal circumstances closesocket() will ensure that all pending */
+ /* accept reqs are canceled. However, when the socket is shared the */
+ /* presence of another reference to the socket in another process will */
+ /* keep the accept reqs going, so we have to ensure that these are */
+ /* canceled. */
+ if (uv_tcp_try_cancel_io(tcp) != 0) {
+ /* When cancellation is not possible, there is another option: we can */
+ /* close the incoming sockets, which will also cancel the accept */
+ /* operations. However this is not cool because we might inadvertently */
+ /* close a socket that just accepted a new connection, which will */
+ /* cause the connection to be aborted. */
+ unsigned int i;
+ for (i = 0; i < uv_simultaneous_server_accepts; i++) {
+ uv_tcp_accept_t* req = &tcp->tcp.serv.accept_reqs[i];
+ if (req->accept_socket != INVALID_SOCKET &&
+ !HasOverlappedIoCompleted(&req->u.io.overlapped)) {
+ closesocket(req->accept_socket);
+ req->accept_socket = INVALID_SOCKET;
+ }
+ }
+ }
+ }
+
+ if (tcp->flags & UV_HANDLE_READING) {
+ tcp->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (tcp->flags & UV_HANDLE_LISTENING) {
+ tcp->flags &= ~UV_HANDLE_LISTENING;
+ DECREASE_ACTIVE_COUNT(loop, tcp);
+ }
+
+ if (close_socket) {
+ closesocket(tcp->socket);
+ tcp->socket = INVALID_SOCKET;
+ tcp->flags |= UV_HANDLE_TCP_SOCKET_CLOSED;
+ }
+
+ tcp->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(tcp);
+
+ if (tcp->reqs_pending == 0) {
+ uv_want_endgame(tcp->loop, (uv_handle_t*)tcp);
+ }
+}
+
+
+int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_tcp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily,
+ 1);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_bind(uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_tcp_try_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__tcp_connect(uv_connect_t* req,
+ uv_tcp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_connect_cb cb) {
+ int err;
+
+ err = uv_tcp_try_connect(req, handle, addr, addrlen, cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/win/thread.c b/Utilities/cmlibuv/src/win/thread.c
new file mode 100644
index 000000000..91684e938
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/thread.c
@@ -0,0 +1,697 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+#define HAVE_CONDVAR_API() (pInitializeConditionVariable != NULL)
+
+static int uv_cond_fallback_init(uv_cond_t* cond);
+static void uv_cond_fallback_destroy(uv_cond_t* cond);
+static void uv_cond_fallback_signal(uv_cond_t* cond);
+static void uv_cond_fallback_broadcast(uv_cond_t* cond);
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+static int uv_cond_condvar_init(uv_cond_t* cond);
+static void uv_cond_condvar_destroy(uv_cond_t* cond);
+static void uv_cond_condvar_signal(uv_cond_t* cond);
+static void uv_cond_condvar_broadcast(uv_cond_t* cond);
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex);
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout);
+
+
+static void uv__once_inner(uv_once_t* guard, void (*callback)(void)) {
+ DWORD result;
+ HANDLE existing_event, created_event;
+
+ created_event = CreateEvent(NULL, 1, 0, NULL);
+ if (created_event == 0) {
+ /* Could fail in a low-memory situation? */
+ uv_fatal_error(GetLastError(), "CreateEvent");
+ }
+
+ existing_event = InterlockedCompareExchangePointer(&guard->event,
+ created_event,
+ NULL);
+
+ if (existing_event == NULL) {
+ /* We won the race */
+ callback();
+
+ result = SetEvent(created_event);
+ assert(result);
+ guard->ran = 1;
+
+ } else {
+ /* We lost the race. Destroy the event we created and wait for the */
+ /* existing one to become signaled. */
+ CloseHandle(created_event);
+ result = WaitForSingleObject(existing_event, INFINITE);
+ assert(result == WAIT_OBJECT_0);
+ }
+}
+
+
+void uv_once(uv_once_t* guard, void (*callback)(void)) {
+ /* Fast case - avoid WaitForSingleObject. */
+ if (guard->ran) {
+ return;
+ }
+
+ uv__once_inner(guard, callback);
+}
+
+
+/* Verify that uv_thread_t can be stored in a TLS slot. */
+STATIC_ASSERT(sizeof(uv_thread_t) <= sizeof(void*));
+
+static uv_key_t uv__current_thread_key;
+static uv_once_t uv__current_thread_init_guard = UV_ONCE_INIT;
+
+
+static void uv__init_current_thread_key(void) {
+ if (uv_key_create(&uv__current_thread_key))
+ abort();
+}
+
+
+struct thread_ctx {
+ void (*entry)(void* arg);
+ void* arg;
+ uv_thread_t self;
+};
+
+
+static UINT __stdcall uv__thread_start(void* arg) {
+ struct thread_ctx *ctx_p;
+ struct thread_ctx ctx;
+
+ ctx_p = arg;
+ ctx = *ctx_p;
+ uv__free(ctx_p);
+
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ uv_key_set(&uv__current_thread_key, (void*) ctx.self);
+
+ ctx.entry(ctx.arg);
+
+ return 0;
+}
+
+
+int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
+ struct thread_ctx* ctx;
+ int err;
+ HANDLE thread;
+
+ ctx = uv__malloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return UV_ENOMEM;
+
+ ctx->entry = entry;
+ ctx->arg = arg;
+
+ /* Create the thread in suspended state so we have a chance to pass
+ * its own creation handle to it */
+ thread = (HANDLE) _beginthreadex(NULL,
+ 0,
+ uv__thread_start,
+ ctx,
+ CREATE_SUSPENDED,
+ NULL);
+ if (thread == NULL) {
+ err = errno;
+ uv__free(ctx);
+ } else {
+ err = 0;
+ *tid = thread;
+ ctx->self = thread;
+ ResumeThread(thread);
+ }
+
+ switch (err) {
+ case 0:
+ return 0;
+ case EACCES:
+ return UV_EACCES;
+ case EAGAIN:
+ return UV_EAGAIN;
+ case EINVAL:
+ return UV_EINVAL;
+ }
+
+ return UV_EIO;
+}
+
+
+uv_thread_t uv_thread_self(void) {
+ uv_once(&uv__current_thread_init_guard, uv__init_current_thread_key);
+ return (uv_thread_t) uv_key_get(&uv__current_thread_key);
+}
+
+
+int uv_thread_join(uv_thread_t *tid) {
+ if (WaitForSingleObject(*tid, INFINITE))
+ return uv_translate_sys_error(GetLastError());
+ else {
+ CloseHandle(*tid);
+ *tid = 0;
+ return 0;
+ }
+}
+
+
+int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
+ return *t1 == *t2;
+}
+
+
+int uv_mutex_init(uv_mutex_t* mutex) {
+ InitializeCriticalSection(mutex);
+ return 0;
+}
+
+
+void uv_mutex_destroy(uv_mutex_t* mutex) {
+ DeleteCriticalSection(mutex);
+}
+
+
+void uv_mutex_lock(uv_mutex_t* mutex) {
+ EnterCriticalSection(mutex);
+}
+
+
+int uv_mutex_trylock(uv_mutex_t* mutex) {
+ if (TryEnterCriticalSection(mutex))
+ return 0;
+ else
+ return UV_EBUSY;
+}
+
+
+void uv_mutex_unlock(uv_mutex_t* mutex) {
+ LeaveCriticalSection(mutex);
+}
+
+
+int uv_rwlock_init(uv_rwlock_t* rwlock) {
+ /* Initialize the semaphore that acts as the write lock. */
+ HANDLE handle = CreateSemaphoreW(NULL, 1, 1, NULL);
+ if (handle == NULL)
+ return uv_translate_sys_error(GetLastError());
+ rwlock->state_.write_semaphore_ = handle;
+
+ /* Initialize the critical section protecting the reader count. */
+ InitializeCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Initialize the reader count. */
+ rwlock->state_.num_readers_ = 0;
+
+ return 0;
+}
+
+
+void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
+ DeleteCriticalSection(&rwlock->state_.num_readers_lock_);
+ CloseHandle(rwlock->state_.write_semaphore_);
+}
+
+
+void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
+ /* Acquire the lock that protects the reader count. */
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ /* Increase the reader count, and lock for write if this is the first
+ * reader.
+ */
+ if (++rwlock->state_.num_readers_ == 1) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+ }
+
+ /* Release the lock that protects the reader count. */
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
+ int err;
+
+ if (!TryEnterCriticalSection(&rwlock->state_.num_readers_lock_))
+ return UV_EBUSY;
+
+ err = 0;
+
+ if (rwlock->state_.num_readers_ == 0) {
+ /* Currently there are no other readers, which means that the write lock
+ * needs to be acquired.
+ */
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ rwlock->state_.num_readers_++;
+ else if (r == WAIT_TIMEOUT)
+ err = UV_EBUSY;
+ else if (r == WAIT_FAILED)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+
+ } else {
+ /* The write lock has already been acquired because there are other
+ * active readers.
+ */
+ rwlock->state_.num_readers_++;
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+ return err;
+}
+
+
+void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
+ EnterCriticalSection(&rwlock->state_.num_readers_lock_);
+
+ if (--rwlock->state_.num_readers_ == 0) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+ }
+
+ LeaveCriticalSection(&rwlock->state_.num_readers_lock_);
+}
+
+
+void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, INFINITE);
+ if (r != WAIT_OBJECT_0)
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
+ DWORD r = WaitForSingleObject(rwlock->state_.write_semaphore_, 0);
+ if (r == WAIT_OBJECT_0)
+ return 0;
+ else if (r == WAIT_TIMEOUT)
+ return UV_EBUSY;
+ else
+ uv_fatal_error(GetLastError(), "WaitForSingleObject");
+}
+
+
+void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
+ if (!ReleaseSemaphore(rwlock->state_.write_semaphore_, 1, NULL))
+ uv_fatal_error(GetLastError(), "ReleaseSemaphore");
+}
+
+
+int uv_sem_init(uv_sem_t* sem, unsigned int value) {
+ *sem = CreateSemaphore(NULL, value, INT_MAX, NULL);
+ if (*sem == NULL)
+ return uv_translate_sys_error(GetLastError());
+ else
+ return 0;
+}
+
+
+void uv_sem_destroy(uv_sem_t* sem) {
+ if (!CloseHandle(*sem))
+ abort();
+}
+
+
+void uv_sem_post(uv_sem_t* sem) {
+ if (!ReleaseSemaphore(*sem, 1, NULL))
+ abort();
+}
+
+
+void uv_sem_wait(uv_sem_t* sem) {
+ if (WaitForSingleObject(*sem, INFINITE) != WAIT_OBJECT_0)
+ abort();
+}
+
+
+int uv_sem_trywait(uv_sem_t* sem) {
+ DWORD r = WaitForSingleObject(*sem, 0);
+
+ if (r == WAIT_OBJECT_0)
+ return 0;
+
+ if (r == WAIT_TIMEOUT)
+ return UV_EAGAIN;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+/* This condition variable implementation is based on the SetEvent solution
+ * (section 3.2) at http://www.cs.wustl.edu/~schmidt/win32-cv-1.html
+ * We could not use the SignalObjectAndWait solution (section 3.4) because
+ * it want the 2nd argument (type uv_mutex_t) of uv_cond_wait() and
+ * uv_cond_timedwait() to be HANDLEs, but we use CRITICAL_SECTIONs.
+ */
+
+static int uv_cond_fallback_init(uv_cond_t* cond) {
+ int err;
+
+ /* Initialize the count to 0. */
+ cond->fallback.waiters_count = 0;
+
+ InitializeCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Create an auto-reset event. */
+ cond->fallback.signal_event = CreateEvent(NULL, /* no security */
+ FALSE, /* auto-reset event */
+ FALSE, /* non-signaled initially */
+ NULL); /* unnamed */
+ if (!cond->fallback.signal_event) {
+ err = GetLastError();
+ goto error2;
+ }
+
+ /* Create a manual-reset event. */
+ cond->fallback.broadcast_event = CreateEvent(NULL, /* no security */
+ TRUE, /* manual-reset */
+ FALSE, /* non-signaled */
+ NULL); /* unnamed */
+ if (!cond->fallback.broadcast_event) {
+ err = GetLastError();
+ goto error;
+ }
+
+ return 0;
+
+error:
+ CloseHandle(cond->fallback.signal_event);
+error2:
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv_cond_condvar_init(uv_cond_t* cond) {
+ pInitializeConditionVariable(&cond->cond_var);
+ return 0;
+}
+
+
+int uv_cond_init(uv_cond_t* cond) {
+ uv__once_init();
+
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_init(cond);
+ else
+ return uv_cond_fallback_init(cond);
+}
+
+
+static void uv_cond_fallback_destroy(uv_cond_t* cond) {
+ if (!CloseHandle(cond->fallback.broadcast_event))
+ abort();
+ if (!CloseHandle(cond->fallback.signal_event))
+ abort();
+ DeleteCriticalSection(&cond->fallback.waiters_count_lock);
+}
+
+
+static void uv_cond_condvar_destroy(uv_cond_t* cond) {
+ /* nothing to do */
+}
+
+
+void uv_cond_destroy(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_destroy(cond);
+ else
+ uv_cond_fallback_destroy(cond);
+}
+
+
+static void uv_cond_fallback_signal(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.signal_event);
+}
+
+
+static void uv_cond_condvar_signal(uv_cond_t* cond) {
+ pWakeConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_signal(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_signal(cond);
+ else
+ uv_cond_fallback_signal(cond);
+}
+
+
+static void uv_cond_fallback_broadcast(uv_cond_t* cond) {
+ int have_waiters;
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ have_waiters = cond->fallback.waiters_count > 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ if (have_waiters)
+ SetEvent(cond->fallback.broadcast_event);
+}
+
+
+static void uv_cond_condvar_broadcast(uv_cond_t* cond) {
+ pWakeAllConditionVariable(&cond->cond_var);
+}
+
+
+void uv_cond_broadcast(uv_cond_t* cond) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_broadcast(cond);
+ else
+ uv_cond_fallback_broadcast(cond);
+}
+
+
+static int uv_cond_wait_helper(uv_cond_t* cond, uv_mutex_t* mutex,
+ DWORD dwMilliseconds) {
+ DWORD result;
+ int last_waiter;
+ HANDLE handles[2] = {
+ cond->fallback.signal_event,
+ cond->fallback.broadcast_event
+ };
+
+ /* Avoid race conditions. */
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count++;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* It's ok to release the <mutex> here since Win32 manual-reset events */
+ /* maintain state when used with <SetEvent>. This avoids the "lost wakeup" */
+ /* bug. */
+ uv_mutex_unlock(mutex);
+
+ /* Wait for either event to become signaled due to <uv_cond_signal> being */
+ /* called or <uv_cond_broadcast> being called. */
+ result = WaitForMultipleObjects(2, handles, FALSE, dwMilliseconds);
+
+ EnterCriticalSection(&cond->fallback.waiters_count_lock);
+ cond->fallback.waiters_count--;
+ last_waiter = result == WAIT_OBJECT_0 + 1
+ && cond->fallback.waiters_count == 0;
+ LeaveCriticalSection(&cond->fallback.waiters_count_lock);
+
+ /* Some thread called <pthread_cond_broadcast>. */
+ if (last_waiter) {
+ /* We're the last waiter to be notified or to stop waiting, so reset the */
+ /* the manual-reset event. */
+ ResetEvent(cond->fallback.broadcast_event);
+ }
+
+ /* Reacquire the <mutex>. */
+ uv_mutex_lock(mutex);
+
+ if (result == WAIT_OBJECT_0 || result == WAIT_OBJECT_0 + 1)
+ return 0;
+
+ if (result == WAIT_TIMEOUT)
+ return UV_ETIMEDOUT;
+
+ abort();
+ return -1; /* Satisfy the compiler. */
+}
+
+
+static void uv_cond_fallback_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (uv_cond_wait_helper(cond, mutex, INFINITE))
+ abort();
+}
+
+
+static void uv_cond_condvar_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (!pSleepConditionVariableCS(&cond->cond_var, mutex, INFINITE))
+ abort();
+}
+
+
+void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
+ if (HAVE_CONDVAR_API())
+ uv_cond_condvar_wait(cond, mutex);
+ else
+ uv_cond_fallback_wait(cond, mutex);
+}
+
+
+static int uv_cond_fallback_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ return uv_cond_wait_helper(cond, mutex, (DWORD)(timeout / 1e6));
+}
+
+
+static int uv_cond_condvar_timedwait(uv_cond_t* cond,
+ uv_mutex_t* mutex, uint64_t timeout) {
+ if (pSleepConditionVariableCS(&cond->cond_var, mutex, (DWORD)(timeout / 1e6)))
+ return 0;
+ if (GetLastError() != ERROR_TIMEOUT)
+ abort();
+ return UV_ETIMEDOUT;
+}
+
+
+int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex,
+ uint64_t timeout) {
+ if (HAVE_CONDVAR_API())
+ return uv_cond_condvar_timedwait(cond, mutex, timeout);
+ else
+ return uv_cond_fallback_timedwait(cond, mutex, timeout);
+}
+
+
+int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
+ int err;
+
+ barrier->n = count;
+ barrier->count = 0;
+
+ err = uv_mutex_init(&barrier->mutex);
+ if (err)
+ return err;
+
+ err = uv_sem_init(&barrier->turnstile1, 0);
+ if (err)
+ goto error2;
+
+ err = uv_sem_init(&barrier->turnstile2, 1);
+ if (err)
+ goto error;
+
+ return 0;
+
+error:
+ uv_sem_destroy(&barrier->turnstile1);
+error2:
+ uv_mutex_destroy(&barrier->mutex);
+ return err;
+
+}
+
+
+void uv_barrier_destroy(uv_barrier_t* barrier) {
+ uv_sem_destroy(&barrier->turnstile2);
+ uv_sem_destroy(&barrier->turnstile1);
+ uv_mutex_destroy(&barrier->mutex);
+}
+
+
+int uv_barrier_wait(uv_barrier_t* barrier) {
+ int serial_thread;
+
+ uv_mutex_lock(&barrier->mutex);
+ if (++barrier->count == barrier->n) {
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile1);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile1);
+
+ uv_mutex_lock(&barrier->mutex);
+ serial_thread = (--barrier->count == 0);
+ if (serial_thread) {
+ uv_sem_wait(&barrier->turnstile1);
+ uv_sem_post(&barrier->turnstile2);
+ }
+ uv_mutex_unlock(&barrier->mutex);
+
+ uv_sem_wait(&barrier->turnstile2);
+ uv_sem_post(&barrier->turnstile2);
+ return serial_thread;
+}
+
+
+int uv_key_create(uv_key_t* key) {
+ key->tls_index = TlsAlloc();
+ if (key->tls_index == TLS_OUT_OF_INDEXES)
+ return UV_ENOMEM;
+ return 0;
+}
+
+
+void uv_key_delete(uv_key_t* key) {
+ if (TlsFree(key->tls_index) == FALSE)
+ abort();
+ key->tls_index = TLS_OUT_OF_INDEXES;
+}
+
+
+void* uv_key_get(uv_key_t* key) {
+ void* value;
+
+ value = TlsGetValue(key->tls_index);
+ if (value == NULL)
+ if (GetLastError() != ERROR_SUCCESS)
+ abort();
+
+ return value;
+}
+
+
+void uv_key_set(uv_key_t* key, void* value) {
+ if (TlsSetValue(key->tls_index, value) == FALSE)
+ abort();
+}
diff --git a/Utilities/cmlibuv/src/win/timer.c b/Utilities/cmlibuv/src/win/timer.c
new file mode 100644
index 000000000..27ca7716a
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/timer.c
@@ -0,0 +1,195 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <limits.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "tree.h"
+#include "handle-inl.h"
+
+
+/* The number of milliseconds in one second. */
+#define UV__MILLISEC 1000
+
+
+void uv_update_time(uv_loop_t* loop) {
+ uint64_t new_time = uv__hrtime(UV__MILLISEC);
+ assert(new_time >= loop->time);
+ loop->time = new_time;
+}
+
+
+static int uv_timer_compare(uv_timer_t* a, uv_timer_t* b) {
+ if (a->due < b->due)
+ return -1;
+ if (a->due > b->due)
+ return 1;
+ /*
+ * compare start_id when both has the same due. start_id is
+ * allocated with loop->timer_counter in uv_timer_start().
+ */
+ if (a->start_id < b->start_id)
+ return -1;
+ if (a->start_id > b->start_id)
+ return 1;
+ return 0;
+}
+
+
+RB_GENERATE_STATIC(uv_timer_tree_s, uv_timer_s, tree_entry, uv_timer_compare);
+
+
+int uv_timer_init(uv_loop_t* loop, uv_timer_t* handle) {
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_TIMER);
+ handle->timer_cb = NULL;
+ handle->repeat = 0;
+
+ return 0;
+}
+
+
+void uv_timer_endgame(uv_loop_t* loop, uv_timer_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static uint64_t get_clamped_due_time(uint64_t loop_time, uint64_t timeout) {
+ uint64_t clamped_timeout;
+
+ clamped_timeout = loop_time + timeout;
+ if (clamped_timeout < timeout)
+ clamped_timeout = (uint64_t) -1;
+
+ return clamped_timeout;
+}
+
+
+int uv_timer_start(uv_timer_t* handle, uv_timer_cb timer_cb, uint64_t timeout,
+ uint64_t repeat) {
+ uv_loop_t* loop = handle->loop;
+ uv_timer_t* old;
+
+ if (timer_cb == NULL)
+ return UV_EINVAL;
+
+ if (uv__is_active(handle))
+ uv_timer_stop(handle);
+
+ handle->timer_cb = timer_cb;
+ handle->due = get_clamped_due_time(loop->time, timeout);
+ handle->repeat = repeat;
+ uv__handle_start(handle);
+
+ /* start_id is the second index to be compared in uv__timer_cmp() */
+ handle->start_id = handle->loop->timer_counter++;
+
+ old = RB_INSERT(uv_timer_tree_s, &loop->timers, handle);
+ assert(old == NULL);
+
+ return 0;
+}
+
+
+int uv_timer_stop(uv_timer_t* handle) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!uv__is_active(handle))
+ return 0;
+
+ RB_REMOVE(uv_timer_tree_s, &loop->timers, handle);
+ uv__handle_stop(handle);
+
+ return 0;
+}
+
+
+int uv_timer_again(uv_timer_t* handle) {
+ /* If timer_cb is NULL that means that the timer was never started. */
+ if (!handle->timer_cb) {
+ return UV_EINVAL;
+ }
+
+ if (handle->repeat) {
+ uv_timer_stop(handle);
+ uv_timer_start(handle, handle->timer_cb, handle->repeat, handle->repeat);
+ }
+
+ return 0;
+}
+
+
+void uv_timer_set_repeat(uv_timer_t* handle, uint64_t repeat) {
+ assert(handle->type == UV_TIMER);
+ handle->repeat = repeat;
+}
+
+
+uint64_t uv_timer_get_repeat(const uv_timer_t* handle) {
+ assert(handle->type == UV_TIMER);
+ return handle->repeat;
+}
+
+
+DWORD uv__next_timeout(const uv_loop_t* loop) {
+ uv_timer_t* timer;
+ int64_t delta;
+
+ /* Check if there are any running timers
+ * Need to cast away const first, since RB_MIN doesn't know what we are
+ * going to do with this return value, it can't be marked const
+ */
+ timer = RB_MIN(uv_timer_tree_s, &((uv_loop_t*)loop)->timers);
+ if (timer) {
+ delta = timer->due - loop->time;
+ if (delta >= UINT_MAX - 1) {
+ /* A timeout value of UINT_MAX means infinite, so that's no good. */
+ return UINT_MAX - 1;
+ } else if (delta < 0) {
+ /* Negative timeout values are not allowed */
+ return 0;
+ } else {
+ return (DWORD)delta;
+ }
+ } else {
+ /* No timers */
+ return INFINITE;
+ }
+}
+
+
+void uv_process_timers(uv_loop_t* loop) {
+ uv_timer_t* timer;
+
+ /* Call timer callbacks */
+ for (timer = RB_MIN(uv_timer_tree_s, &loop->timers);
+ timer != NULL && timer->due <= loop->time;
+ timer = RB_MIN(uv_timer_tree_s, &loop->timers)) {
+
+ uv_timer_stop(timer);
+ uv_timer_again(timer);
+ timer->timer_cb((uv_timer_t*) timer);
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/tty.c b/Utilities/cmlibuv/src/win/tty.c
new file mode 100644
index 000000000..a6f583956
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/tty.c
@@ -0,0 +1,2281 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <io.h>
+#include <string.h>
+#include <stdlib.h>
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+# include "stdint-msvc2008.h"
+#else
+# include <stdint.h>
+#endif
+
+#ifndef COMMON_LVB_REVERSE_VIDEO
+# define COMMON_LVB_REVERSE_VIDEO 0x4000
+#endif
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+#ifndef InterlockedOr
+# define InterlockedOr _InterlockedOr
+#endif
+
+#define UNICODE_REPLACEMENT_CHARACTER (0xfffd)
+
+#define ANSI_NORMAL 0x00
+#define ANSI_ESCAPE_SEEN 0x02
+#define ANSI_CSI 0x04
+#define ANSI_ST_CONTROL 0x08
+#define ANSI_IGNORE 0x10
+#define ANSI_IN_ARG 0x20
+#define ANSI_IN_STRING 0x40
+#define ANSI_BACKSLASH_SEEN 0x80
+
+#define MAX_INPUT_BUFFER_LENGTH 8192
+#define MAX_CONSOLE_CHAR 8192
+
+#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
+#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
+#endif
+
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info);
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info);
+static int uv__cancel_read_console(uv_tty_t* handle);
+
+
+/* Null uv_buf_t */
+static const uv_buf_t uv_null_buf_ = { 0, NULL };
+
+enum uv__read_console_status_e {
+ NOT_STARTED,
+ IN_PROGRESS,
+ TRAP_REQUESTED,
+ COMPLETED
+};
+
+static volatile LONG uv__read_console_status = NOT_STARTED;
+static volatile LONG uv__restore_screen_state;
+static CONSOLE_SCREEN_BUFFER_INFO uv__saved_screen_state;
+
+
+/*
+ * The console virtual window.
+ *
+ * Normally cursor movement in windows is relative to the console screen buffer,
+ * e.g. the application is allowed to overwrite the 'history'. This is very
+ * inconvenient, it makes absolute cursor movement pretty useless. There is
+ * also the concept of 'client rect' which is defined by the actual size of
+ * the console window and the scroll position of the screen buffer, but it's
+ * very volatile because it changes when the user scrolls.
+ *
+ * To make cursor movement behave sensibly we define a virtual window to which
+ * cursor movement is confined. The virtual window is always as wide as the
+ * console screen buffer, but it's height is defined by the size of the
+ * console window. The top of the virtual window aligns with the position
+ * of the caret when the first stdout/err handle is created, unless that would
+ * mean that it would extend beyond the bottom of the screen buffer - in that
+ * that case it's located as far down as possible.
+ *
+ * When the user writes a long text or many newlines, such that the output
+ * reaches beyond the bottom of the virtual window, the virtual window is
+ * shifted downwards, but not resized.
+ *
+ * Since all tty i/o happens on the same console, this window is shared
+ * between all stdout/stderr handles.
+ */
+
+static int uv_tty_virtual_offset = -1;
+static int uv_tty_virtual_height = -1;
+static int uv_tty_virtual_width = -1;
+
+/* We use a semaphore rather than a mutex or critical section because in some
+ cases (uv__cancel_read_console) we need take the lock in the main thread and
+ release it in another thread. Using a semaphore ensures that in such
+ scenario the main thread will still block when trying to acquire the lock. */
+static uv_sem_t uv_tty_output_lock;
+
+static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
+
+static WORD uv_tty_default_text_attributes =
+ FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+static char uv_tty_default_fg_color = 7;
+static char uv_tty_default_bg_color = 0;
+static char uv_tty_default_fg_bright = 0;
+static char uv_tty_default_bg_bright = 0;
+static char uv_tty_default_inverse = 0;
+
+typedef enum {
+ UV_SUPPORTED,
+ UV_UNCHECKED,
+ UV_UNSUPPORTED
+} uv_vtermstate_t;
+/* Determine whether or not ANSI support is enabled. */
+static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
+static void uv__determine_vterm_state(HANDLE handle);
+
+void uv_console_init(void) {
+ if (uv_sem_init(&uv_tty_output_lock, 1))
+ abort();
+}
+
+
+int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
+ HANDLE handle;
+ CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
+
+ handle = (HANDLE) uv__get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return UV_EBADF;
+
+ if (fd <= 2) {
+ /* In order to avoid closing a stdio file descriptor 0-2, duplicate the
+ * underlying OS handle and forget about the original fd.
+ * We could also opt to use the original OS handle and just never close it,
+ * but then there would be no reliable way to cancel pending read operations
+ * upon close.
+ */
+ if (!DuplicateHandle(INVALID_HANDLE_VALUE,
+ handle,
+ INVALID_HANDLE_VALUE,
+ &handle,
+ 0,
+ FALSE,
+ DUPLICATE_SAME_ACCESS))
+ return uv_translate_sys_error(GetLastError());
+ fd = -1;
+ }
+
+ if (!readable) {
+ /* Obtain the screen buffer info with the output handle. */
+ if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Obtain the the tty_output_lock because the virtual window state is */
+ /* shared between all uv_tty_t handles. */
+ uv_sem_wait(&uv_tty_output_lock);
+
+ if (uv__vterm_state == UV_UNCHECKED)
+ uv__determine_vterm_state(handle);
+
+ /* Store the global tty output handle. This handle is used by TTY read */
+ /* streams to update the virtual window when a CONSOLE_BUFFER_SIZE_EVENT */
+ /* is received. */
+ uv_tty_output_handle = handle;
+
+ /* Remember the original console text attributes. */
+ uv_tty_capture_initial_style(&screen_buffer_info);
+
+ uv_tty_update_virtual_window(&screen_buffer_info);
+
+ uv_sem_post(&uv_tty_output_lock);
+ }
+
+
+ uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
+ uv_connection_init((uv_stream_t*) tty);
+
+ tty->handle = handle;
+ tty->u.fd = fd;
+ tty->reqs_pending = 0;
+ tty->flags |= UV_HANDLE_BOUND;
+
+ if (readable) {
+ /* Initialize TTY input specific fields. */
+ tty->flags |= UV_HANDLE_TTY_READABLE | UV_HANDLE_READABLE;
+ /* TODO: remove me in v2.x. */
+ tty->tty.rd.unused_ = NULL;
+ tty->tty.rd.read_line_buffer = uv_null_buf_;
+ tty->tty.rd.read_raw_wait = NULL;
+
+ /* Init keycode-to-vt100 mapper state. */
+ tty->tty.rd.last_key_len = 0;
+ tty->tty.rd.last_key_offset = 0;
+ tty->tty.rd.last_utf16_high_surrogate = 0;
+ memset(&tty->tty.rd.last_input_record, 0, sizeof tty->tty.rd.last_input_record);
+ } else {
+ /* TTY output specific fields. */
+ tty->flags |= UV_HANDLE_WRITABLE;
+
+ /* Init utf8-to-utf16 conversion state. */
+ tty->tty.wr.utf8_bytes_left = 0;
+ tty->tty.wr.utf8_codepoint = 0;
+
+ /* Initialize eol conversion state */
+ tty->tty.wr.previous_eol = 0;
+
+ /* Init ANSI parser state. */
+ tty->tty.wr.ansi_parser_state = ANSI_NORMAL;
+ }
+
+ return 0;
+}
+
+
+/* Set the default console text attributes based on how the console was
+ * configured when libuv started.
+ */
+static void uv_tty_capture_initial_style(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ static int style_captured = 0;
+
+ /* Only do this once.
+ Assumption: Caller has acquired uv_tty_output_lock. */
+ if (style_captured)
+ return;
+
+ /* Save raw win32 attributes. */
+ uv_tty_default_text_attributes = info->wAttributes;
+
+ /* Convert black text on black background to use white text. */
+ if (uv_tty_default_text_attributes == 0)
+ uv_tty_default_text_attributes = 7;
+
+ /* Convert Win32 attributes to ANSI colors. */
+ uv_tty_default_fg_color = 0;
+ uv_tty_default_bg_color = 0;
+ uv_tty_default_fg_bright = 0;
+ uv_tty_default_bg_bright = 0;
+ uv_tty_default_inverse = 0;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_RED)
+ uv_tty_default_fg_color |= 1;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_GREEN)
+ uv_tty_default_fg_color |= 2;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_BLUE)
+ uv_tty_default_fg_color |= 4;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_RED)
+ uv_tty_default_bg_color |= 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_GREEN)
+ uv_tty_default_bg_color |= 2;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_BLUE)
+ uv_tty_default_bg_color |= 4;
+
+ if (uv_tty_default_text_attributes & FOREGROUND_INTENSITY)
+ uv_tty_default_fg_bright = 1;
+
+ if (uv_tty_default_text_attributes & BACKGROUND_INTENSITY)
+ uv_tty_default_bg_bright = 1;
+
+ if (uv_tty_default_text_attributes & COMMON_LVB_REVERSE_VIDEO)
+ uv_tty_default_inverse = 1;
+
+ style_captured = 1;
+}
+
+
+int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
+ DWORD flags;
+ unsigned char was_reading;
+ uv_alloc_cb alloc_cb;
+ uv_read_cb read_cb;
+ int err;
+
+ if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
+ return UV_EINVAL;
+ }
+
+ if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
+ return 0;
+ }
+
+ switch (mode) {
+ case UV_TTY_MODE_NORMAL:
+ flags = ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ break;
+ case UV_TTY_MODE_RAW:
+ flags = ENABLE_WINDOW_INPUT;
+ break;
+ case UV_TTY_MODE_IO:
+ return UV_ENOTSUP;
+ default:
+ return UV_EINVAL;
+ }
+
+ /* If currently reading, stop, and restart reading. */
+ if (tty->flags & UV_HANDLE_READING) {
+ was_reading = 1;
+ alloc_cb = tty->alloc_cb;
+ read_cb = tty->read_cb;
+ err = uv_tty_read_stop(tty);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ } else {
+ was_reading = 0;
+ }
+
+ uv_sem_wait(&uv_tty_output_lock);
+ if (!SetConsoleMode(tty->handle, flags)) {
+ err = uv_translate_sys_error(GetLastError());
+ uv_sem_post(&uv_tty_output_lock);
+ return err;
+ }
+ uv_sem_post(&uv_tty_output_lock);
+
+ /* Update flag. */
+ tty->flags &= ~UV_HANDLE_TTY_RAW;
+ tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
+
+ /* If we just stopped reading, restart. */
+ if (was_reading) {
+ err = uv_tty_read_start(tty, alloc_cb, read_cb);
+ if (err) {
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_is_tty(uv_file file) {
+ DWORD result;
+ return GetConsoleMode((HANDLE) _get_osfhandle(file), &result) != 0;
+}
+
+
+int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (!GetConsoleScreenBufferInfo(tty->handle, &info)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ uv_sem_wait(&uv_tty_output_lock);
+ uv_tty_update_virtual_window(&info);
+ uv_sem_post(&uv_tty_output_lock);
+
+ *width = uv_tty_virtual_width;
+ *height = uv_tty_virtual_height;
+
+ return 0;
+}
+
+
+static void CALLBACK uv_tty_post_raw_read(void* data, BOOLEAN didTimeout) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+
+ assert(data);
+ assert(!didTimeout);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ UnregisterWait(handle->tty.rd.read_raw_wait);
+ handle->tty.rd.read_raw_wait = NULL;
+
+ SET_REQ_SUCCESS(req);
+ POST_COMPLETION_FOR_REQ(loop, req);
+}
+
+
+static void uv_tty_queue_read_raw(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ r = RegisterWaitForSingleObject(&handle->tty.rd.read_raw_wait,
+ handle->handle,
+ uv_tty_post_raw_read,
+ (void*) req,
+ INFINITE,
+ WT_EXECUTEINWAITTHREAD | WT_EXECUTEONLYONCE);
+ if (!r) {
+ handle->tty.rd.read_raw_wait = NULL;
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
+ uv_loop_t* loop;
+ uv_tty_t* handle;
+ uv_req_t* req;
+ DWORD bytes, read_bytes;
+ WCHAR utf16[MAX_INPUT_BUFFER_LENGTH / 3];
+ DWORD chars, read_chars;
+ LONG status;
+ COORD pos;
+ BOOL read_console_success;
+
+ assert(data);
+
+ req = (uv_req_t*) data;
+ handle = (uv_tty_t*) req->data;
+ loop = handle->loop;
+
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+ assert(handle->tty.rd.read_line_buffer.len > 0);
+
+ /* ReadConsole can't handle big buffers. */
+ if (handle->tty.rd.read_line_buffer.len < MAX_INPUT_BUFFER_LENGTH) {
+ bytes = handle->tty.rd.read_line_buffer.len;
+ } else {
+ bytes = MAX_INPUT_BUFFER_LENGTH;
+ }
+
+ /* At last, unicode! */
+ /* One utf-16 codeunit never takes more than 3 utf-8 codeunits to encode */
+ chars = bytes / 3;
+
+ status = InterlockedExchange(&uv__read_console_status, IN_PROGRESS);
+ if (status == TRAP_REQUESTED) {
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = 0;
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+ }
+
+ read_console_success = ReadConsoleW(handle->handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
+ NULL);
+
+ if (read_console_success) {
+ read_bytes = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ read_chars,
+ handle->tty.rd.read_line_buffer.base,
+ bytes,
+ NULL,
+ NULL);
+ SET_REQ_SUCCESS(req);
+ req->u.io.overlapped.InternalHigh = read_bytes;
+ } else {
+ SET_REQ_ERROR(req, GetLastError());
+ }
+
+ status = InterlockedExchange(&uv__read_console_status, COMPLETED);
+
+ if (status == TRAP_REQUESTED) {
+ /* If we canceled the read by sending a VK_RETURN event, restore the
+ screen state to undo the visual effect of the VK_RETURN */
+ if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
+ HANDLE active_screen_buffer;
+ active_screen_buffer = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (active_screen_buffer != INVALID_HANDLE_VALUE) {
+ pos = uv__saved_screen_state.dwCursorPosition;
+
+ /* If the cursor was at the bottom line of the screen buffer, the
+ VK_RETURN would have caused the buffer contents to scroll up by one
+ line. The right position to reset the cursor to is therefore one line
+ higher */
+ if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
+ pos.Y--;
+
+ SetConsoleCursorPosition(active_screen_buffer, pos);
+ CloseHandle(active_screen_buffer);
+ }
+ }
+ uv_sem_post(&uv_tty_output_lock);
+ }
+ POST_COMPLETION_FOR_REQ(loop, req);
+ return 0;
+}
+
+
+static void uv_tty_queue_read_line(uv_loop_t* loop, uv_tty_t* handle) {
+ uv_read_t* req;
+ BOOL r;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+ assert(handle->handle && handle->handle != INVALID_HANDLE_VALUE);
+
+ req = &handle->read_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ handle->tty.rd.read_line_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 8192, &handle->tty.rd.read_line_buffer);
+ if (handle->tty.rd.read_line_buffer.base == NULL ||
+ handle->tty.rd.read_line_buffer.len == 0) {
+ handle->read_cb((uv_stream_t*) handle,
+ UV_ENOBUFS,
+ &handle->tty.rd.read_line_buffer);
+ return;
+ }
+ assert(handle->tty.rd.read_line_buffer.base != NULL);
+
+ /* Reset flags No locking is required since there cannot be a line read
+ in progress. We are also relying on the memory barrier provided by
+ QueueUserWorkItem*/
+ uv__restore_screen_state = FALSE;
+ uv__read_console_status = NOT_STARTED;
+ r = QueueUserWorkItem(uv_tty_line_read_thread,
+ (void*) req,
+ WT_EXECUTELONGFUNCTION);
+ if (!r) {
+ SET_REQ_ERROR(req, GetLastError());
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ }
+
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+}
+
+
+static void uv_tty_queue_read(uv_loop_t* loop, uv_tty_t* handle) {
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ uv_tty_queue_read_raw(loop, handle);
+ } else {
+ uv_tty_queue_read_line(loop, handle);
+ }
+}
+
+
+static const char* get_vt100_fn_key(DWORD code, char shift, char ctrl,
+ size_t* len) {
+#define VK_CASE(vk, normal_str, shift_str, ctrl_str, shift_ctrl_str) \
+ case (vk): \
+ if (shift && ctrl) { \
+ *len = sizeof shift_ctrl_str; \
+ return "\033" shift_ctrl_str; \
+ } else if (shift) { \
+ *len = sizeof shift_str ; \
+ return "\033" shift_str; \
+ } else if (ctrl) { \
+ *len = sizeof ctrl_str; \
+ return "\033" ctrl_str; \
+ } else { \
+ *len = sizeof normal_str; \
+ return "\033" normal_str; \
+ }
+
+ switch (code) {
+ /* These mappings are the same as Cygwin's. Unmodified and alt-modified */
+ /* keypad keys comply with linux console, modifiers comply with xterm */
+ /* modifier usage. F1..f12 and shift-f1..f10 comply with linux console, */
+ /* f6..f12 with and without modifiers comply with rxvt. */
+ VK_CASE(VK_INSERT, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_END, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_DOWN, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NEXT, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_LEFT, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_CLEAR, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_RIGHT, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_UP, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_HOME, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_PRIOR, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DELETE, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_NUMPAD0, "[2~", "[2;2~", "[2;5~", "[2;6~")
+ VK_CASE(VK_NUMPAD1, "[4~", "[4;2~", "[4;5~", "[4;6~")
+ VK_CASE(VK_NUMPAD2, "[B", "[1;2B", "[1;5B", "[1;6B")
+ VK_CASE(VK_NUMPAD3, "[6~", "[6;2~", "[6;5~", "[6;6~")
+ VK_CASE(VK_NUMPAD4, "[D", "[1;2D", "[1;5D", "[1;6D")
+ VK_CASE(VK_NUMPAD5, "[G", "[1;2G", "[1;5G", "[1;6G")
+ VK_CASE(VK_NUMPAD6, "[C", "[1;2C", "[1;5C", "[1;6C")
+ VK_CASE(VK_NUMPAD7, "[A", "[1;2A", "[1;5A", "[1;6A")
+ VK_CASE(VK_NUMPAD8, "[1~", "[1;2~", "[1;5~", "[1;6~")
+ VK_CASE(VK_NUMPAD9, "[5~", "[5;2~", "[5;5~", "[5;6~")
+ VK_CASE(VK_DECIMAL, "[3~", "[3;2~", "[3;5~", "[3;6~")
+ VK_CASE(VK_F1, "[[A", "[23~", "[11^", "[23^" )
+ VK_CASE(VK_F2, "[[B", "[24~", "[12^", "[24^" )
+ VK_CASE(VK_F3, "[[C", "[25~", "[13^", "[25^" )
+ VK_CASE(VK_F4, "[[D", "[26~", "[14^", "[26^" )
+ VK_CASE(VK_F5, "[[E", "[28~", "[15^", "[28^" )
+ VK_CASE(VK_F6, "[17~", "[29~", "[17^", "[29^" )
+ VK_CASE(VK_F7, "[18~", "[31~", "[18^", "[31^" )
+ VK_CASE(VK_F8, "[19~", "[32~", "[19^", "[32^" )
+ VK_CASE(VK_F9, "[20~", "[33~", "[20^", "[33^" )
+ VK_CASE(VK_F10, "[21~", "[34~", "[21^", "[34^" )
+ VK_CASE(VK_F11, "[23~", "[23$", "[23^", "[23@" )
+ VK_CASE(VK_F12, "[24~", "[24$", "[24^", "[24@" )
+
+ default:
+ *len = 0;
+ return NULL;
+ }
+#undef VK_CASE
+}
+
+
+void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ /* Shortcut for handle->tty.rd.last_input_record.Event.KeyEvent. */
+#define KEV handle->tty.rd.last_input_record.Event.KeyEvent
+
+ DWORD records_left, records_read;
+ uv_buf_t buf;
+ off_t buf_used;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!(handle->flags & UV_HANDLE_READING) ||
+ !(handle->flags & UV_HANDLE_TTY_RAW)) {
+ goto out;
+ }
+
+ if (!REQ_SUCCESS(req)) {
+ /* An error occurred while waiting for the event. */
+ if ((handle->flags & UV_HANDLE_READING)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &uv_null_buf_);
+ }
+ goto out;
+ }
+
+ /* Fetch the number of events */
+ if (!GetNumberOfConsoleInputEvents(handle->handle, &records_left)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*)handle,
+ uv_translate_sys_error(GetLastError()),
+ &uv_null_buf_);
+ goto out;
+ }
+
+ /* Windows sends a lot of events that we're not interested in, so buf */
+ /* will be allocated on demand, when there's actually something to emit. */
+ buf = uv_null_buf_;
+ buf_used = 0;
+
+ while ((records_left > 0 || handle->tty.rd.last_key_len > 0) &&
+ (handle->flags & UV_HANDLE_READING)) {
+ if (handle->tty.rd.last_key_len == 0) {
+ /* Read the next input record */
+ if (!ReadConsoleInputW(handle->handle,
+ &handle->tty.rd.last_input_record,
+ 1,
+ &records_read)) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+ records_left--;
+
+ /* If the window was resized, recompute the virtual window size. This */
+ /* will trigger a SIGWINCH signal if the window size changed in an */
+ /* way that matters to libuv. */
+ if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ uv_sem_wait(&uv_tty_output_lock);
+
+ if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
+ uv_tty_update_virtual_window(&info);
+ }
+
+ uv_sem_post(&uv_tty_output_lock);
+
+ continue;
+ }
+
+ /* Ignore other events that are not key or resize events. */
+ if (handle->tty.rd.last_input_record.EventType != KEY_EVENT) {
+ continue;
+ }
+
+ /* Ignore keyup events, unless the left alt key was held and a valid */
+ /* unicode character was emitted. */
+ if (!KEV.bKeyDown && !(((KEV.dwControlKeyState & LEFT_ALT_PRESSED) ||
+ KEV.wVirtualKeyCode==VK_MENU) && KEV.uChar.UnicodeChar != 0)) {
+ continue;
+ }
+
+ /* Ignore keypresses to numpad number keys if the left alt is held */
+ /* because the user is composing a character, or windows simulating */
+ /* this. */
+ if ((KEV.dwControlKeyState & LEFT_ALT_PRESSED) &&
+ !(KEV.dwControlKeyState & ENHANCED_KEY) &&
+ (KEV.wVirtualKeyCode == VK_INSERT ||
+ KEV.wVirtualKeyCode == VK_END ||
+ KEV.wVirtualKeyCode == VK_DOWN ||
+ KEV.wVirtualKeyCode == VK_NEXT ||
+ KEV.wVirtualKeyCode == VK_LEFT ||
+ KEV.wVirtualKeyCode == VK_CLEAR ||
+ KEV.wVirtualKeyCode == VK_RIGHT ||
+ KEV.wVirtualKeyCode == VK_HOME ||
+ KEV.wVirtualKeyCode == VK_UP ||
+ KEV.wVirtualKeyCode == VK_PRIOR ||
+ KEV.wVirtualKeyCode == VK_NUMPAD0 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD1 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD2 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD3 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD4 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD5 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD6 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD7 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD8 ||
+ KEV.wVirtualKeyCode == VK_NUMPAD9)) {
+ continue;
+ }
+
+ if (KEV.uChar.UnicodeChar != 0) {
+ int prefix_len, char_len;
+
+ /* Character key pressed */
+ if (KEV.uChar.UnicodeChar >= 0xD800 &&
+ KEV.uChar.UnicodeChar < 0xDC00) {
+ /* UTF-16 high surrogate */
+ handle->tty.rd.last_utf16_high_surrogate = KEV.uChar.UnicodeChar;
+ continue;
+ }
+
+ /* Prefix with \u033 if alt was held, but alt was not used as part */
+ /* a compose sequence. */
+ if ((KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ && !(KEV.dwControlKeyState & (LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)) && KEV.bKeyDown) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ if (KEV.uChar.UnicodeChar >= 0xDC00 &&
+ KEV.uChar.UnicodeChar < 0xE000) {
+ /* UTF-16 surrogate pair */
+ WCHAR utf16_buffer[2] = { handle->tty.rd.last_utf16_high_surrogate,
+ KEV.uChar.UnicodeChar};
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ 2,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ } else {
+ /* Single UTF-16 character */
+ char_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ &KEV.uChar.UnicodeChar,
+ 1,
+ &handle->tty.rd.last_key[prefix_len],
+ sizeof handle->tty.rd.last_key,
+ NULL,
+ NULL);
+ }
+
+ /* Whatever happened, the last character wasn't a high surrogate. */
+ handle->tty.rd.last_utf16_high_surrogate = 0;
+
+ /* If the utf16 character(s) couldn't be converted something must */
+ /* be wrong. */
+ if (!char_len) {
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GetLastError()),
+ &buf);
+ goto out;
+ }
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + char_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+
+ } else {
+ /* Function key pressed */
+ const char* vt100;
+ size_t prefix_len, vt100_len;
+
+ vt100 = get_vt100_fn_key(KEV.wVirtualKeyCode,
+ !!(KEV.dwControlKeyState & SHIFT_PRESSED),
+ !!(KEV.dwControlKeyState & (
+ LEFT_CTRL_PRESSED |
+ RIGHT_CTRL_PRESSED)),
+ &vt100_len);
+
+ /* If we were unable to map to a vt100 sequence, just ignore. */
+ if (!vt100) {
+ continue;
+ }
+
+ /* Prefix with \x033 when the alt key was held. */
+ if (KEV.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
+ handle->tty.rd.last_key[0] = '\033';
+ prefix_len = 1;
+ } else {
+ prefix_len = 0;
+ }
+
+ /* Copy the vt100 sequence to the handle buffer. */
+ assert(prefix_len + vt100_len < sizeof handle->tty.rd.last_key);
+ memcpy(&handle->tty.rd.last_key[prefix_len], vt100, vt100_len);
+
+ handle->tty.rd.last_key_len = (unsigned char) (prefix_len + vt100_len);
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+ } else {
+ /* Copy any bytes left from the last keypress to the user buffer. */
+ if (handle->tty.rd.last_key_offset < handle->tty.rd.last_key_len) {
+ /* Allocate a buffer if needed */
+ if (buf_used == 0) {
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 1024, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->read_cb((uv_stream_t*) handle, UV_ENOBUFS, &buf);
+ goto out;
+ }
+ assert(buf.base != NULL);
+ }
+
+ buf.base[buf_used++] = handle->tty.rd.last_key[handle->tty.rd.last_key_offset++];
+
+ /* If the buffer is full, emit it */
+ if ((size_t) buf_used == buf.len) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ buf = uv_null_buf_;
+ buf_used = 0;
+ }
+
+ continue;
+ }
+
+ /* Apply dwRepeat from the last input record. */
+ if (--KEV.wRepeatCount > 0) {
+ handle->tty.rd.last_key_offset = 0;
+ continue;
+ }
+
+ handle->tty.rd.last_key_len = 0;
+ continue;
+ }
+ }
+
+ /* Send the buffer back to the user */
+ if (buf_used > 0) {
+ handle->read_cb((uv_stream_t*) handle, buf_used, &buf);
+ }
+
+ out:
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+
+#undef KEV
+}
+
+
+
+void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ buf = handle->tty.rd.read_line_buffer;
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+ handle->tty.rd.read_line_buffer = uv_null_buf_;
+
+ if (!REQ_SUCCESS(req)) {
+ /* Read was not successful */
+ if (handle->flags & UV_HANDLE_READING) {
+ /* Real error */
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb((uv_stream_t*) handle,
+ uv_translate_sys_error(GET_REQ_ERROR(req)),
+ &buf);
+ } else {
+ /* The read was cancelled, or whatever we don't care */
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+
+ } else {
+ if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
+ /* Read successful */
+ /* TODO: read unicode, convert to utf-8 */
+ DWORD bytes = req->u.io.overlapped.InternalHigh;
+ handle->read_cb((uv_stream_t*) handle, bytes, &buf);
+ } else {
+ handle->flags &= ~UV_HANDLE_CANCELLATION_PENDING;
+ handle->read_cb((uv_stream_t*) handle, 0, &buf);
+ }
+ }
+
+ /* Wait for more input events. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_tty_queue_read(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* req) {
+ assert(handle->type == UV_TTY);
+ assert(handle->flags & UV_HANDLE_TTY_READABLE);
+
+ /* If the read_line_buffer member is zero, it must have been an raw read. */
+ /* Otherwise it was a line-buffered read. */
+ /* FIXME: This is quite obscure. Use a flag or something. */
+ if (handle->tty.rd.read_line_buffer.len == 0) {
+ uv_process_tty_read_raw_req(loop, handle, req);
+ } else {
+ uv_process_tty_read_line_req(loop, handle, req);
+ }
+}
+
+
+int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
+ uv_read_cb read_cb) {
+ uv_loop_t* loop = handle->loop;
+
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ handle->read_cb = read_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* read request pending. */
+ if (handle->flags & UV_HANDLE_READ_PENDING) {
+ return 0;
+ }
+
+ /* Maybe the user stopped reading half-way while processing key events. */
+ /* Short-circuit if this could be the case. */
+ if (handle->tty.rd.last_key_len > 0) {
+ SET_REQ_SUCCESS(&handle->read_req);
+ uv_insert_pending_req(handle->loop, (uv_req_t*) &handle->read_req);
+ /* Make sure no attempt is made to insert it again until it's handled. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ return 0;
+ }
+
+ uv_tty_queue_read(loop, handle);
+
+ return 0;
+}
+
+
+int uv_tty_read_stop(uv_tty_t* handle) {
+ INPUT_RECORD record;
+ DWORD written, err;
+
+ handle->flags &= ~UV_HANDLE_READING;
+ DECREASE_ACTIVE_COUNT(handle->loop, handle);
+
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ return 0;
+
+ if (handle->flags & UV_HANDLE_TTY_RAW) {
+ /* Cancel raw read */
+ /* Write some bullshit event to force the console wait to return. */
+ memset(&record, 0, sizeof record);
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written)) {
+ return GetLastError();
+ }
+ } else if (!(handle->flags & UV_HANDLE_CANCELLATION_PENDING)) {
+ /* Cancel line-buffered read if not already pending */
+ err = uv__cancel_read_console(handle);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_CANCELLATION_PENDING;
+ }
+
+ return 0;
+}
+
+static int uv__cancel_read_console(uv_tty_t* handle) {
+ HANDLE active_screen_buffer = INVALID_HANDLE_VALUE;
+ INPUT_RECORD record;
+ DWORD written;
+ DWORD err = 0;
+ LONG status;
+
+ assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
+
+ /* Hold the output lock during the cancellation, to ensure that further
+ writes don't interfere with the screen state. It will be the ReadConsole
+ thread's responsibility to release the lock. */
+ uv_sem_wait(&uv_tty_output_lock);
+ status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
+ if (status != IN_PROGRESS) {
+ /* Either we have managed to set a trap for the other thread before
+ ReadConsole is called, or ReadConsole has returned because the user
+ has pressed ENTER. In either case, there is nothing else to do. */
+ uv_sem_post(&uv_tty_output_lock);
+ return 0;
+ }
+
+ /* Save screen state before sending the VK_RETURN event */
+ active_screen_buffer = CreateFileA("conout$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (active_screen_buffer != INVALID_HANDLE_VALUE &&
+ GetConsoleScreenBufferInfo(active_screen_buffer,
+ &uv__saved_screen_state)) {
+ InterlockedOr(&uv__restore_screen_state, 1);
+ }
+
+ /* Write enter key event to force the console wait to return. */
+ record.EventType = KEY_EVENT;
+ record.Event.KeyEvent.bKeyDown = TRUE;
+ record.Event.KeyEvent.wRepeatCount = 1;
+ record.Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
+ record.Event.KeyEvent.wVirtualScanCode =
+ MapVirtualKeyW(VK_RETURN, MAPVK_VK_TO_VSC);
+ record.Event.KeyEvent.uChar.UnicodeChar = L'\r';
+ record.Event.KeyEvent.dwControlKeyState = 0;
+ if (!WriteConsoleInputW(handle->handle, &record, 1, &written))
+ err = GetLastError();
+
+ if (active_screen_buffer != INVALID_HANDLE_VALUE)
+ CloseHandle(active_screen_buffer);
+
+ return err;
+}
+
+
+static void uv_tty_update_virtual_window(CONSOLE_SCREEN_BUFFER_INFO* info) {
+ int old_virtual_width = uv_tty_virtual_width;
+ int old_virtual_height = uv_tty_virtual_height;
+
+ uv_tty_virtual_width = info->dwSize.X;
+ uv_tty_virtual_height = info->srWindow.Bottom - info->srWindow.Top + 1;
+
+ /* Recompute virtual window offset row. */
+ if (uv_tty_virtual_offset == -1) {
+ uv_tty_virtual_offset = info->dwCursorPosition.Y;
+ } else if (uv_tty_virtual_offset < info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1) {
+ /* If suddenly find the cursor outside of the virtual window, it must */
+ /* have somehow scrolled. Update the virtual window offset. */
+ uv_tty_virtual_offset = info->dwCursorPosition.Y -
+ uv_tty_virtual_height + 1;
+ }
+ if (uv_tty_virtual_offset + uv_tty_virtual_height > info->dwSize.Y) {
+ uv_tty_virtual_offset = info->dwSize.Y - uv_tty_virtual_height;
+ }
+ if (uv_tty_virtual_offset < 0) {
+ uv_tty_virtual_offset = 0;
+ }
+
+ /* If the virtual window size changed, emit a SIGWINCH signal. Don't emit */
+ /* if this was the first time the virtual window size was computed. */
+ if (old_virtual_width != -1 && old_virtual_height != -1 &&
+ (uv_tty_virtual_width != old_virtual_width ||
+ uv_tty_virtual_height != old_virtual_height)) {
+ uv__signal_dispatch(SIGWINCH);
+ }
+}
+
+
+static COORD uv_tty_make_real_coord(uv_tty_t* handle,
+ CONSOLE_SCREEN_BUFFER_INFO* info, int x, unsigned char x_relative, int y,
+ unsigned char y_relative) {
+ COORD result;
+
+ uv_tty_update_virtual_window(info);
+
+ /* Adjust y position */
+ if (y_relative) {
+ y = info->dwCursorPosition.Y + y;
+ } else {
+ y = uv_tty_virtual_offset + y;
+ }
+ /* Clip y to virtual client rectangle */
+ if (y < uv_tty_virtual_offset) {
+ y = uv_tty_virtual_offset;
+ } else if (y >= uv_tty_virtual_offset + uv_tty_virtual_height) {
+ y = uv_tty_virtual_offset + uv_tty_virtual_height - 1;
+ }
+
+ /* Adjust x */
+ if (x_relative) {
+ x = info->dwCursorPosition.X + x;
+ }
+ /* Clip x */
+ if (x < 0) {
+ x = 0;
+ } else if (x >= uv_tty_virtual_width) {
+ x = uv_tty_virtual_width - 1;
+ }
+
+ result.X = (unsigned short) x;
+ result.Y = (unsigned short) y;
+ return result;
+}
+
+
+static int uv_tty_emit_text(uv_tty_t* handle, WCHAR buffer[], DWORD length,
+ DWORD* error) {
+ DWORD written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!WriteConsoleW(handle->handle,
+ (void*) buffer,
+ length,
+ &written,
+ NULL)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_move_caret(uv_tty_t* handle, int x, unsigned char x_relative,
+ int y, unsigned char y_relative, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD pos;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ }
+
+ pos = uv_tty_make_real_coord(handle, &info, x, x_relative, y, y_relative);
+
+ if (!SetConsoleCursorPosition(handle->handle, pos)) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_reset(uv_tty_t* handle, DWORD* error) {
+ const COORD origin = {0, 0};
+ const WORD char_attrs = uv_tty_default_text_attributes;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ DWORD count, written;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ /* Reset original text attributes. */
+ if (!SetConsoleTextAttribute(handle->handle, char_attrs)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Move the cursor position to (0, 0). */
+ if (!SetConsoleCursorPosition(handle->handle, origin)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ /* Clear the screen buffer. */
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ count = info.dwSize.X * info.dwSize.Y;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ origin,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ char_attrs,
+ written,
+ origin,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ /* Move the virtual window up to the top. */
+ uv_tty_virtual_offset = 0;
+ uv_tty_update_virtual_window(&info);
+
+ return 0;
+}
+
+
+static int uv_tty_clear(uv_tty_t* handle, int dir, char entire_screen,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ COORD start, end;
+ DWORD count, written;
+
+ int x1, x2, y1, y2;
+ int x1r, x2r, y1r, y2r;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (dir == 0) {
+ /* Clear from current position */
+ x1 = 0;
+ x1r = 1;
+ } else {
+ /* Clear from column 0 */
+ x1 = 0;
+ x1r = 0;
+ }
+
+ if (dir == 1) {
+ /* Clear to current position */
+ x2 = 0;
+ x2r = 1;
+ } else {
+ /* Clear to end of row. We pretend the console is 65536 characters wide, */
+ /* uv_tty_make_real_coord will clip it to the actual console width. */
+ x2 = 0xffff;
+ x2r = 0;
+ }
+
+ if (!entire_screen) {
+ /* Stay on our own row */
+ y1 = y2 = 0;
+ y1r = y2r = 1;
+ } else {
+ /* Apply columns direction to row */
+ y1 = x1;
+ y1r = x1r;
+ y2 = x2;
+ y2r = x2r;
+ }
+
+ retry:
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ start = uv_tty_make_real_coord(handle, &info, x1, x1r, y1, y1r);
+ end = uv_tty_make_real_coord(handle, &info, x2, x2r, y2, y2r);
+ count = (end.Y * info.dwSize.X + end.X) -
+ (start.Y * info.dwSize.X + start.X) + 1;
+
+ if (!(FillConsoleOutputCharacterW(handle->handle,
+ L'\x20',
+ count,
+ start,
+ &written) &&
+ FillConsoleOutputAttribute(handle->handle,
+ info.wAttributes,
+ written,
+ start,
+ &written))) {
+ if (GetLastError() == ERROR_INVALID_PARAMETER) {
+ /* The console may be resized - retry */
+ goto retry;
+ } else {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#define FLIP_FGBG \
+ do { \
+ WORD fg = info.wAttributes & 0xF; \
+ WORD bg = info.wAttributes & 0xF0; \
+ info.wAttributes &= 0xFF00; \
+ info.wAttributes |= fg << 4; \
+ info.wAttributes |= bg >> 4; \
+ } while (0)
+
+static int uv_tty_set_style(uv_tty_t* handle, DWORD* error) {
+ unsigned short argc = handle->tty.wr.ansi_csi_argc;
+ unsigned short* argv = handle->tty.wr.ansi_csi_argv;
+ int i;
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ char fg_color = -1, bg_color = -1;
+ char fg_bright = -1, bg_bright = -1;
+ char inverse = -1;
+
+ if (argc == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+ }
+
+ for (i = 0; i < argc; i++) {
+ short arg = argv[i];
+
+ if (arg == 0) {
+ /* Reset mode */
+ fg_color = uv_tty_default_fg_color;
+ bg_color = uv_tty_default_bg_color;
+ fg_bright = uv_tty_default_fg_bright;
+ bg_bright = uv_tty_default_bg_bright;
+ inverse = uv_tty_default_inverse;
+
+ } else if (arg == 1) {
+ /* Foreground bright on */
+ fg_bright = 1;
+
+ } else if (arg == 2) {
+ /* Both bright off */
+ fg_bright = 0;
+ bg_bright = 0;
+
+ } else if (arg == 5) {
+ /* Background bright on */
+ bg_bright = 1;
+
+ } else if (arg == 7) {
+ /* Inverse: on */
+ inverse = 1;
+
+ } else if (arg == 21 || arg == 22) {
+ /* Foreground bright off */
+ fg_bright = 0;
+
+ } else if (arg == 25) {
+ /* Background bright off */
+ bg_bright = 0;
+
+ } else if (arg == 27) {
+ /* Inverse: off */
+ inverse = 0;
+
+ } else if (arg >= 30 && arg <= 37) {
+ /* Set foreground color */
+ fg_color = arg - 30;
+
+ } else if (arg == 39) {
+ /* Default text color */
+ fg_color = uv_tty_default_fg_color;
+ fg_bright = uv_tty_default_fg_bright;
+
+ } else if (arg >= 40 && arg <= 47) {
+ /* Set background color */
+ bg_color = arg - 40;
+
+ } else if (arg == 49) {
+ /* Default background color */
+ bg_color = uv_tty_default_bg_color;
+ bg_bright = uv_tty_default_bg_bright;
+
+ } else if (arg >= 90 && arg <= 97) {
+ /* Set bold foreground color */
+ fg_bright = 1;
+ fg_color = arg - 90;
+
+ } else if (arg >= 100 && arg <= 107) {
+ /* Set bold background color */
+ bg_bright = 1;
+ bg_color = arg - 100;
+
+ }
+ }
+
+ if (fg_color == -1 && bg_color == -1 && fg_bright == -1 &&
+ bg_bright == -1 && inverse == -1) {
+ /* Nothing changed */
+ return 0;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (fg_color != -1) {
+ info.wAttributes &= ~(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
+ if (fg_color & 1) info.wAttributes |= FOREGROUND_RED;
+ if (fg_color & 2) info.wAttributes |= FOREGROUND_GREEN;
+ if (fg_color & 4) info.wAttributes |= FOREGROUND_BLUE;
+ }
+
+ if (fg_bright != -1) {
+ if (fg_bright) {
+ info.wAttributes |= FOREGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~FOREGROUND_INTENSITY;
+ }
+ }
+
+ if (bg_color != -1) {
+ info.wAttributes &= ~(BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE);
+ if (bg_color & 1) info.wAttributes |= BACKGROUND_RED;
+ if (bg_color & 2) info.wAttributes |= BACKGROUND_GREEN;
+ if (bg_color & 4) info.wAttributes |= BACKGROUND_BLUE;
+ }
+
+ if (bg_bright != -1) {
+ if (bg_bright) {
+ info.wAttributes |= BACKGROUND_INTENSITY;
+ } else {
+ info.wAttributes &= ~BACKGROUND_INTENSITY;
+ }
+ }
+
+ if (inverse != -1) {
+ if (inverse) {
+ info.wAttributes |= COMMON_LVB_REVERSE_VIDEO;
+ } else {
+ info.wAttributes &= ~COMMON_LVB_REVERSE_VIDEO;
+ }
+ }
+
+ if ((info.wAttributes & COMMON_LVB_REVERSE_VIDEO) > 0) {
+ FLIP_FGBG;
+ }
+
+ if (!SetConsoleTextAttribute(handle->handle, info.wAttributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_save_state(uv_tty_t* handle, unsigned char save_attributes,
+ DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ uv_tty_update_virtual_window(&info);
+
+ handle->tty.wr.saved_position.X = info.dwCursorPosition.X;
+ handle->tty.wr.saved_position.Y = info.dwCursorPosition.Y - uv_tty_virtual_offset;
+ handle->flags |= UV_HANDLE_TTY_SAVED_POSITION;
+
+ if (save_attributes) {
+ handle->tty.wr.saved_attributes = info.wAttributes &
+ (FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ handle->flags |= UV_HANDLE_TTY_SAVED_ATTRIBUTES;
+ }
+
+ return 0;
+}
+
+
+static int uv_tty_restore_state(uv_tty_t* handle,
+ unsigned char restore_attributes, DWORD* error) {
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ WORD new_attributes;
+
+ if (*error != ERROR_SUCCESS) {
+ return -1;
+ }
+
+ if (handle->flags & UV_HANDLE_TTY_SAVED_POSITION) {
+ if (uv_tty_move_caret(handle,
+ handle->tty.wr.saved_position.X,
+ 0,
+ handle->tty.wr.saved_position.Y,
+ 0,
+ error) != 0) {
+ return -1;
+ }
+ }
+
+ if (restore_attributes &&
+ (handle->flags & UV_HANDLE_TTY_SAVED_ATTRIBUTES)) {
+ if (!GetConsoleScreenBufferInfo(handle->handle, &info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ new_attributes = info.wAttributes;
+ new_attributes &= ~(FOREGROUND_INTENSITY | BACKGROUND_INTENSITY);
+ new_attributes |= handle->tty.wr.saved_attributes;
+
+ if (!SetConsoleTextAttribute(handle->handle, new_attributes)) {
+ *error = GetLastError();
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static int uv_tty_set_cursor_visibility(uv_tty_t* handle,
+ BOOL visible,
+ DWORD* error) {
+ CONSOLE_CURSOR_INFO cursor_info;
+
+ if (!GetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ cursor_info.bVisible = visible;
+
+ if (!SetConsoleCursorInfo(handle->handle, &cursor_info)) {
+ *error = GetLastError();
+ return -1;
+ }
+
+ return 0;
+}
+
+static int uv_tty_write_bufs(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ DWORD* error) {
+ /* We can only write 8k characters at a time. Windows can't handle */
+ /* much more characters in a single console write anyway. */
+ WCHAR utf16_buf[MAX_CONSOLE_CHAR];
+ WCHAR* utf16_buffer;
+ DWORD utf16_buf_used = 0;
+ unsigned int i, len, max_len, pos;
+ int allocate = 0;
+
+#define FLUSH_TEXT() \
+ do { \
+ pos = 0; \
+ do { \
+ len = utf16_buf_used - pos; \
+ if (len > MAX_CONSOLE_CHAR) \
+ len = MAX_CONSOLE_CHAR; \
+ uv_tty_emit_text(handle, &utf16_buffer[pos], len, error); \
+ pos += len; \
+ } while (pos < utf16_buf_used); \
+ if (allocate) { \
+ uv__free(utf16_buffer); \
+ allocate = 0; \
+ utf16_buffer = utf16_buf; \
+ } \
+ utf16_buf_used = 0; \
+ } while (0)
+
+#define ENSURE_BUFFER_SPACE(wchars_needed) \
+ if (wchars_needed > ARRAY_SIZE(utf16_buf) - utf16_buf_used) { \
+ FLUSH_TEXT(); \
+ }
+
+ /* Cache for fast access */
+ unsigned char utf8_bytes_left = handle->tty.wr.utf8_bytes_left;
+ unsigned int utf8_codepoint = handle->tty.wr.utf8_codepoint;
+ unsigned char previous_eol = handle->tty.wr.previous_eol;
+ unsigned char ansi_parser_state = handle->tty.wr.ansi_parser_state;
+
+ /* Store the error here. If we encounter an error, stop trying to do i/o */
+ /* but keep parsing the buffer so we leave the parser in a consistent */
+ /* state. */
+ *error = ERROR_SUCCESS;
+
+ utf16_buffer = utf16_buf;
+
+ uv_sem_wait(&uv_tty_output_lock);
+
+ for (i = 0; i < nbufs; i++) {
+ uv_buf_t buf = bufs[i];
+ unsigned int j;
+
+ if (uv__vterm_state == UV_SUPPORTED && buf.len > 0) {
+ utf16_buf_used = MultiByteToWideChar(CP_UTF8,
+ 0,
+ buf.base,
+ buf.len,
+ NULL,
+ 0);
+
+ if (utf16_buf_used == 0) {
+ *error = GetLastError();
+ break;
+ }
+
+ max_len = (utf16_buf_used + 1) * sizeof(WCHAR);
+ allocate = max_len > MAX_CONSOLE_CHAR;
+ if (allocate)
+ utf16_buffer = uv__malloc(max_len);
+ if (!MultiByteToWideChar(CP_UTF8,
+ 0,
+ buf.base,
+ buf.len,
+ utf16_buffer,
+ utf16_buf_used)) {
+ if (allocate)
+ uv__free(utf16_buffer);
+ *error = GetLastError();
+ break;
+ }
+
+ FLUSH_TEXT();
+
+ continue;
+ }
+
+ for (j = 0; j < buf.len; j++) {
+ unsigned char c = buf.base[j];
+
+ /* Run the character through the utf8 decoder We happily accept non */
+ /* shortest form encodings and invalid code points - there's no real */
+ /* harm that can be done. */
+ if (utf8_bytes_left == 0) {
+ /* Read utf-8 start byte */
+ DWORD first_zero_bit;
+ unsigned char not_c = ~c;
+#ifdef _MSC_VER /* msvc */
+ if (_BitScanReverse(&first_zero_bit, not_c)) {
+#else /* assume gcc */
+ if (c != 0) {
+ first_zero_bit = (sizeof(int) * 8) - 1 - __builtin_clz(not_c);
+#endif
+ if (first_zero_bit == 7) {
+ /* Ascii - pass right through */
+ utf8_codepoint = (unsigned int) c;
+
+ } else if (first_zero_bit <= 5) {
+ /* Multibyte sequence */
+ utf8_codepoint = (0xff >> (8 - first_zero_bit)) & c;
+ utf8_bytes_left = (char) (6 - first_zero_bit);
+
+ } else {
+ /* Invalid continuation */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else {
+ /* 0xff -- invalid */
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ } else if ((c & 0xc0) == 0x80) {
+ /* Valid continuation of utf-8 multibyte sequence */
+ utf8_bytes_left--;
+ utf8_codepoint <<= 6;
+ utf8_codepoint |= ((unsigned int) c & 0x3f);
+
+ } else {
+ /* Start byte where continuation was expected. */
+ utf8_bytes_left = 0;
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ /* Patch buf offset so this character will be parsed again as a */
+ /* start byte. */
+ j--;
+ }
+
+ /* Maybe we need to parse more bytes to find a character. */
+ if (utf8_bytes_left != 0) {
+ continue;
+ }
+
+ /* Parse vt100/ansi escape codes */
+ if (ansi_parser_state == ANSI_NORMAL) {
+ switch (utf8_codepoint) {
+ case '\033':
+ ansi_parser_state = ANSI_ESCAPE_SEEN;
+ continue;
+
+ case 0233:
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+ }
+
+ } else if (ansi_parser_state == ANSI_ESCAPE_SEEN) {
+ switch (utf8_codepoint) {
+ case '[':
+ ansi_parser_state = ANSI_CSI;
+ handle->tty.wr.ansi_csi_argc = 0;
+ continue;
+
+ case '^':
+ case '_':
+ case 'P':
+ case ']':
+ /* Not supported, but we'll have to parse until we see a stop */
+ /* code, e.g. ESC \ or BEL. */
+ ansi_parser_state = ANSI_ST_CONTROL;
+ continue;
+
+ case '\033':
+ /* Ignore double escape. */
+ continue;
+
+ case 'c':
+ /* Full console reset. */
+ FLUSH_TEXT();
+ uv_tty_reset(handle, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '7':
+ /* Save the cursor position and text attributes. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ case '8':
+ /* Restore the cursor position and text attributes */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 1, error);
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ default:
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '_') {
+ /* Single-char control. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+ } else {
+ /* Invalid - proceed as normal, */
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ }
+
+ } else if (ansi_parser_state & ANSI_CSI) {
+ if (!(ansi_parser_state & ANSI_IGNORE)) {
+ if (utf8_codepoint >= '0' && utf8_codepoint <= '9') {
+ /* Parsing a numerical argument */
+
+ if (!(ansi_parser_state & ANSI_IN_ARG)) {
+ /* We were not currently parsing a number */
+
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ ansi_parser_state |= ANSI_IN_ARG;
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) utf8_codepoint - '0';
+ continue;
+ } else {
+ /* We were already parsing a number. Parse next digit. */
+ uint32_t value = 10 *
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1];
+
+ /* Check for overflow. */
+ if (value > UINT16_MAX) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] =
+ (unsigned short) value + (utf8_codepoint - '0');
+ continue;
+ }
+
+ } else if (utf8_codepoint == ';') {
+ /* Denotes the end of an argument. */
+ if (ansi_parser_state & ANSI_IN_ARG) {
+ ansi_parser_state &= ~ANSI_IN_ARG;
+ continue;
+
+ } else {
+ /* If ANSI_IN_ARG is not set, add another argument and */
+ /* default it to 0. */
+ /* Check for too many arguments */
+ if (handle->tty.wr.ansi_csi_argc >= ARRAY_SIZE(handle->tty.wr.ansi_csi_argv)) {
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+
+ handle->tty.wr.ansi_csi_argc++;
+ handle->tty.wr.ansi_csi_argv[handle->tty.wr.ansi_csi_argc - 1] = 0;
+ continue;
+ }
+
+ } else if (utf8_codepoint == '?' && !(ansi_parser_state & ANSI_IN_ARG) &&
+ handle->tty.wr.ansi_csi_argc == 0) {
+ /* Ignores '?' if it is the first character after CSI[ */
+ /* This is an extension character from the VT100 codeset */
+ /* that is supported and used by most ANSI terminals today. */
+ continue;
+
+ } else if (utf8_codepoint >= '@' && utf8_codepoint <= '~' &&
+ (handle->tty.wr.ansi_csi_argc > 0 || utf8_codepoint != '[')) {
+ int x, y, d;
+
+ /* Command byte */
+ switch (utf8_codepoint) {
+ case 'A':
+ /* cursor up */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'B':
+ /* cursor down */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 1, y, 1, error);
+ break;
+
+ case 'C':
+ /* cursor forward */
+ FLUSH_TEXT();
+ x = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'D':
+ /* cursor back */
+ FLUSH_TEXT();
+ x = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, x, 1, 0, 1, error);
+ break;
+
+ case 'E':
+ /* cursor next line */
+ FLUSH_TEXT();
+ y = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1;
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'F':
+ /* cursor previous line */
+ FLUSH_TEXT();
+ y = -(handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 1);
+ uv_tty_move_caret(handle, 0, 0, y, 1, error);
+ break;
+
+ case 'G':
+ /* cursor horizontal move absolute */
+ FLUSH_TEXT();
+ x = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, 0, 1, error);
+ break;
+
+ case 'H':
+ case 'f':
+ /* cursor move absolute */
+ FLUSH_TEXT();
+ y = (handle->tty.wr.ansi_csi_argc >= 1 && handle->tty.wr.ansi_csi_argv[0])
+ ? handle->tty.wr.ansi_csi_argv[0] - 1 : 0;
+ x = (handle->tty.wr.ansi_csi_argc >= 2 && handle->tty.wr.ansi_csi_argv[1])
+ ? handle->tty.wr.ansi_csi_argv[1] - 1 : 0;
+ uv_tty_move_caret(handle, x, 0, y, 0, error);
+ break;
+
+ case 'J':
+ /* Erase screen */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 1, error);
+ }
+ break;
+
+ case 'K':
+ /* Erase line */
+ FLUSH_TEXT();
+ d = handle->tty.wr.ansi_csi_argc ? handle->tty.wr.ansi_csi_argv[0] : 0;
+ if (d >= 0 && d <= 2) {
+ uv_tty_clear(handle, d, 0, error);
+ }
+ break;
+
+ case 'm':
+ /* Set style */
+ FLUSH_TEXT();
+ uv_tty_set_style(handle, error);
+ break;
+
+ case 's':
+ /* Save the cursor position. */
+ FLUSH_TEXT();
+ uv_tty_save_state(handle, 0, error);
+ break;
+
+ case 'u':
+ /* Restore the cursor position */
+ FLUSH_TEXT();
+ uv_tty_restore_state(handle, 0, error);
+ break;
+
+ case 'l':
+ /* Hide the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 0, error);
+ }
+ break;
+
+ case 'h':
+ /* Show the cursor */
+ if (handle->tty.wr.ansi_csi_argc == 1 &&
+ handle->tty.wr.ansi_csi_argv[0] == 25) {
+ FLUSH_TEXT();
+ uv_tty_set_cursor_visibility(handle, 1, error);
+ }
+ break;
+ }
+
+ /* Sequence ended - go back to normal state. */
+ ansi_parser_state = ANSI_NORMAL;
+ continue;
+
+ } else {
+ /* We don't support commands that use private mode characters or */
+ /* intermediaries. Ignore the rest of the sequence. */
+ ansi_parser_state |= ANSI_IGNORE;
+ continue;
+ }
+ } else {
+ /* We're ignoring this command. Stop only on command character. */
+ if (utf8_codepoint >= '@' && utf8_codepoint <= '~') {
+ ansi_parser_state = ANSI_NORMAL;
+ }
+ continue;
+ }
+
+ } else if (ansi_parser_state & ANSI_ST_CONTROL) {
+ /* Unsupported control code */
+ /* Ignore everything until we see BEL or ESC \ */
+ if (ansi_parser_state & ANSI_IN_STRING) {
+ if (!(ansi_parser_state & ANSI_BACKSLASH_SEEN)) {
+ if (utf8_codepoint == '"') {
+ ansi_parser_state &= ~ANSI_IN_STRING;
+ } else if (utf8_codepoint == '\\') {
+ ansi_parser_state |= ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ }
+ } else {
+ if (utf8_codepoint == '\007' || (utf8_codepoint == '\\' &&
+ (ansi_parser_state & ANSI_ESCAPE_SEEN))) {
+ /* End of sequence */
+ ansi_parser_state = ANSI_NORMAL;
+ } else if (utf8_codepoint == '\033') {
+ /* Escape character */
+ ansi_parser_state |= ANSI_ESCAPE_SEEN;
+ } else if (utf8_codepoint == '"') {
+ /* String starting */
+ ansi_parser_state |= ANSI_IN_STRING;
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ ansi_parser_state &= ~ANSI_BACKSLASH_SEEN;
+ } else {
+ ansi_parser_state &= ~ANSI_ESCAPE_SEEN;
+ }
+ }
+ continue;
+ } else {
+ /* Inconsistent state */
+ abort();
+ }
+
+ /* We wouldn't mind emitting utf-16 surrogate pairs. Too bad, the */
+ /* windows console doesn't really support UTF-16, so just emit the */
+ /* replacement character. */
+ if (utf8_codepoint > 0xffff) {
+ utf8_codepoint = UNICODE_REPLACEMENT_CHARACTER;
+ }
+
+ if (utf8_codepoint == 0x0a || utf8_codepoint == 0x0d) {
+ /* EOL conversion - emit \r\n when we see \n. */
+
+ if (utf8_codepoint == 0x0a && previous_eol != 0x0d) {
+ /* \n was not preceded by \r; print \r\n. */
+ ENSURE_BUFFER_SPACE(2);
+ utf16_buf[utf16_buf_used++] = L'\r';
+ utf16_buf[utf16_buf_used++] = L'\n';
+ } else if (utf8_codepoint == 0x0d && previous_eol == 0x0a) {
+ /* \n was followed by \r; do not print the \r, since */
+ /* the source was either \r\n\r (so the second \r is */
+ /* redundant) or was \n\r (so the \n was processed */
+ /* by the last case and an \r automatically inserted). */
+ } else {
+ /* \r without \n; print \r as-is. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ }
+
+ previous_eol = (char) utf8_codepoint;
+
+ } else if (utf8_codepoint <= 0xffff) {
+ /* Encode character into utf-16 buffer. */
+ ENSURE_BUFFER_SPACE(1);
+ utf16_buf[utf16_buf_used++] = (WCHAR) utf8_codepoint;
+ previous_eol = 0;
+ }
+ }
+ }
+
+ /* Flush remaining characters */
+ FLUSH_TEXT();
+
+ /* Copy cached values back to struct. */
+ handle->tty.wr.utf8_bytes_left = utf8_bytes_left;
+ handle->tty.wr.utf8_codepoint = utf8_codepoint;
+ handle->tty.wr.previous_eol = previous_eol;
+ handle->tty.wr.ansi_parser_state = ansi_parser_state;
+
+ uv_sem_post(&uv_tty_output_lock);
+
+ if (*error == STATUS_SUCCESS) {
+ return 0;
+ } else {
+ return -1;
+ }
+
+#undef FLUSH_TEXT
+}
+
+
+int uv_tty_write(uv_loop_t* loop,
+ uv_write_t* req,
+ uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ uv_write_cb cb) {
+ DWORD error;
+
+ UV_REQ_INIT(req, UV_WRITE);
+ req->handle = (uv_stream_t*) handle;
+ req->cb = cb;
+
+ handle->reqs_pending++;
+ handle->stream.conn.write_reqs_pending++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+
+ req->u.io.queued_bytes = 0;
+
+ if (!uv_tty_write_bufs(handle, bufs, nbufs, &error)) {
+ SET_REQ_SUCCESS(req);
+ } else {
+ SET_REQ_ERROR(req, error);
+ }
+
+ uv_insert_pending_req(loop, (uv_req_t*) req);
+
+ return 0;
+}
+
+
+int uv__tty_try_write(uv_tty_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs) {
+ DWORD error;
+
+ if (handle->stream.conn.write_reqs_pending > 0)
+ return UV_EAGAIN;
+
+ if (uv_tty_write_bufs(handle, bufs, nbufs, &error))
+ return uv_translate_sys_error(error);
+
+ return uv__count_bufs(bufs, nbufs);
+}
+
+
+void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_write_t* req) {
+ int err;
+
+ handle->write_queue_size -= req->u.io.queued_bytes;
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = GET_REQ_ERROR(req);
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ handle->stream.conn.write_reqs_pending--;
+ if (handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*)handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_tty_close(uv_tty_t* handle) {
+ assert(handle->u.fd == -1 || handle->u.fd > 2);
+ if (handle->u.fd == -1)
+ CloseHandle(handle->handle);
+ else
+ close(handle->u.fd);
+
+ if (handle->flags & UV_HANDLE_READING)
+ uv_tty_read_stop(handle);
+
+ handle->u.fd = -1;
+ handle->handle = INVALID_HANDLE_VALUE;
+ handle->flags &= ~(UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(handle->loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
+ if (!(handle->flags & UV_HANDLE_TTY_READABLE) &&
+ handle->stream.conn.shutdown_req != NULL &&
+ handle->stream.conn.write_reqs_pending == 0) {
+ UNREGISTER_HANDLE_REQ(loop, handle, handle->stream.conn.shutdown_req);
+
+ /* TTY shutdown is really just a no-op */
+ if (handle->stream.conn.shutdown_req->cb) {
+ if (handle->flags & UV__HANDLE_CLOSING) {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, UV_ECANCELED);
+ } else {
+ handle->stream.conn.shutdown_req->cb(handle->stream.conn.shutdown_req, 0);
+ }
+ }
+
+ handle->stream.conn.shutdown_req = NULL;
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+ return;
+ }
+
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ /* The wait handle used for raw reading should be unregistered when the */
+ /* wait callback runs. */
+ assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
+ handle->tty.rd.read_raw_wait == NULL);
+
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_accept_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_req_t* raw_req) {
+ abort();
+}
+
+
+/* TODO: remove me */
+void uv_process_tty_connect_req(uv_loop_t* loop, uv_tty_t* handle,
+ uv_connect_t* req) {
+ abort();
+}
+
+
+int uv_tty_reset_mode(void) {
+ /* Not necessary to do anything. */
+ return 0;
+}
+
+/* Determine whether or not this version of windows supports
+ * proper ANSI color codes. Should be supported as of windows
+ * 10 version 1511, build number 10.0.10586.
+ */
+static void uv__determine_vterm_state(HANDLE handle) {
+ DWORD dwMode = 0;
+
+ if (!GetConsoleMode(handle, &dwMode)) {
+ uv__vterm_state = UV_UNSUPPORTED;
+ return;
+ }
+
+ dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
+ if (!SetConsoleMode(handle, dwMode)) {
+ uv__vterm_state = UV_UNSUPPORTED;
+ return;
+ }
+
+ uv__vterm_state = UV_SUPPORTED;
+}
diff --git a/Utilities/cmlibuv/src/win/udp.c b/Utilities/cmlibuv/src/win/udp.c
new file mode 100644
index 000000000..2fd15cfa9
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/udp.c
@@ -0,0 +1,926 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+#include "handle-inl.h"
+#include "stream-inl.h"
+#include "req-inl.h"
+
+
+/*
+ * Threshold of active udp streams for which to preallocate udp read buffers.
+ */
+const unsigned int uv_active_udp_streams_threshold = 0;
+
+/* A zero-size buffer for use by uv_udp_read */
+static char uv_zero_[] = "";
+
+int uv_udp_getsockname(const uv_udp_t* handle,
+ struct sockaddr* name,
+ int* namelen) {
+ int result;
+
+ if (handle->socket == INVALID_SOCKET) {
+ return UV_EINVAL;
+ }
+
+ result = getsockname(handle->socket, name, namelen);
+ if (result != 0) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+static int uv_udp_set_socket(uv_loop_t* loop, uv_udp_t* handle, SOCKET socket,
+ int family) {
+ DWORD yes = 1;
+ WSAPROTOCOL_INFOW info;
+ int opt_len;
+
+ if (handle->socket != INVALID_SOCKET)
+ return UV_EBUSY;
+
+ /* Set the socket to nonblocking mode */
+ if (ioctlsocket(socket, FIONBIO, &yes) == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ /* Make the socket non-inheritable */
+ if (!SetHandleInformation((HANDLE)socket, HANDLE_FLAG_INHERIT, 0)) {
+ return GetLastError();
+ }
+
+ /* Associate it with the I/O completion port. */
+ /* Use uv_handle_t pointer as completion key. */
+ if (CreateIoCompletionPort((HANDLE)socket,
+ loop->iocp,
+ (ULONG_PTR)socket,
+ 0) == NULL) {
+ return GetLastError();
+ }
+
+ if (pSetFileCompletionNotificationModes) {
+ /* All known Windows that support SetFileCompletionNotificationModes */
+ /* have a bug that makes it impossible to use this function in */
+ /* conjunction with datagram sockets. We can work around that but only */
+ /* if the user is using the default UDP driver (AFD) and has no other */
+ /* LSPs stacked on top. Here we check whether that is the case. */
+ opt_len = (int) sizeof info;
+ if (getsockopt(socket,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &info,
+ &opt_len) == SOCKET_ERROR) {
+ return GetLastError();
+ }
+
+ if (info.ProtocolChain.ChainLen == 1) {
+ if (pSetFileCompletionNotificationModes((HANDLE)socket,
+ FILE_SKIP_SET_EVENT_ON_HANDLE |
+ FILE_SKIP_COMPLETION_PORT_ON_SUCCESS)) {
+ handle->flags |= UV_HANDLE_SYNC_BYPASS_IOCP;
+ handle->func_wsarecv = uv_wsarecv_workaround;
+ handle->func_wsarecvfrom = uv_wsarecvfrom_workaround;
+ } else if (GetLastError() != ERROR_INVALID_FUNCTION) {
+ return GetLastError();
+ }
+ }
+ }
+
+ handle->socket = socket;
+
+ if (family == AF_INET6) {
+ handle->flags |= UV_HANDLE_IPV6;
+ } else {
+ assert(!(handle->flags & UV_HANDLE_IPV6));
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init_ex(uv_loop_t* loop, uv_udp_t* handle, unsigned int flags) {
+ int domain;
+
+ /* Use the lower 8 bits for the domain */
+ domain = flags & 0xFF;
+ if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
+ return UV_EINVAL;
+
+ if (flags & ~0xFF)
+ return UV_EINVAL;
+
+ uv__handle_init(loop, (uv_handle_t*) handle, UV_UDP);
+ handle->socket = INVALID_SOCKET;
+ handle->reqs_pending = 0;
+ handle->activecnt = 0;
+ handle->func_wsarecv = WSARecv;
+ handle->func_wsarecvfrom = WSARecvFrom;
+ handle->send_queue_size = 0;
+ handle->send_queue_count = 0;
+ UV_REQ_INIT(&handle->recv_req, UV_UDP_RECV);
+ handle->recv_req.data = handle;
+
+ /* If anything fails beyond this point we need to remove the handle from
+ * the handle queue, since it was added by uv__handle_init.
+ */
+
+ if (domain != AF_UNSPEC) {
+ SOCKET sock;
+ DWORD err;
+
+ sock = socket(domain, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ err = WSAGetLastError();
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, domain);
+ if (err) {
+ closesocket(sock);
+ QUEUE_REMOVE(&handle->handle_queue);
+ return uv_translate_sys_error(err);
+ }
+ }
+
+ return 0;
+}
+
+
+int uv_udp_init(uv_loop_t* loop, uv_udp_t* handle) {
+ return uv_udp_init_ex(loop, handle, AF_UNSPEC);
+}
+
+
+void uv_udp_close(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_udp_recv_stop(handle);
+ closesocket(handle->socket);
+ handle->socket = INVALID_SOCKET;
+
+ uv__handle_closing(handle);
+
+ if (handle->reqs_pending == 0) {
+ uv_want_endgame(loop, (uv_handle_t*) handle);
+ }
+}
+
+
+void uv_udp_endgame(uv_loop_t* loop, uv_udp_t* handle) {
+ if (handle->flags & UV__HANDLE_CLOSING &&
+ handle->reqs_pending == 0) {
+ assert(!(handle->flags & UV_HANDLE_CLOSED));
+ uv__handle_close(handle);
+ }
+}
+
+
+static int uv_udp_maybe_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int r;
+ int err;
+ DWORD no = 0;
+
+ if (handle->flags & UV_HANDLE_BOUND)
+ return 0;
+
+ if ((flags & UV_UDP_IPV6ONLY) && addr->sa_family != AF_INET6) {
+ /* UV_UDP_IPV6ONLY is supported only for IPV6 sockets */
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->socket == INVALID_SOCKET) {
+ SOCKET sock = socket(addr->sa_family, SOCK_DGRAM, 0);
+ if (sock == INVALID_SOCKET) {
+ return WSAGetLastError();
+ }
+
+ err = uv_udp_set_socket(handle->loop, handle, sock, addr->sa_family);
+ if (err) {
+ closesocket(sock);
+ return err;
+ }
+ }
+
+ if (flags & UV_UDP_REUSEADDR) {
+ DWORD yes = 1;
+ /* Set SO_REUSEADDR on the socket. */
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_REUSEADDR,
+ (char*) &yes,
+ sizeof yes) == SOCKET_ERROR) {
+ err = WSAGetLastError();
+ return err;
+ }
+ }
+
+ if (addr->sa_family == AF_INET6)
+ handle->flags |= UV_HANDLE_IPV6;
+
+ if (addr->sa_family == AF_INET6 && !(flags & UV_UDP_IPV6ONLY)) {
+ /* On windows IPV6ONLY is on by default. */
+ /* If the user doesn't specify it libuv turns it off. */
+
+ /* TODO: how to handle errors? This may fail if there is no ipv4 stack */
+ /* available, or when run on XP/2003 which have no support for dualstack */
+ /* sockets. For now we're silently ignoring the error. */
+ setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_V6ONLY,
+ (char*) &no,
+ sizeof no);
+ }
+
+ r = bind(handle->socket, addr, addrlen);
+ if (r == SOCKET_ERROR) {
+ return WSAGetLastError();
+ }
+
+ handle->flags |= UV_HANDLE_BOUND;
+
+ return 0;
+}
+
+
+static void uv_udp_queue_recv(uv_loop_t* loop, uv_udp_t* handle) {
+ uv_req_t* req;
+ uv_buf_t buf;
+ DWORD bytes, flags;
+ int result;
+
+ assert(handle->flags & UV_HANDLE_READING);
+ assert(!(handle->flags & UV_HANDLE_READ_PENDING));
+
+ req = &handle->recv_req;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ /*
+ * Preallocate a read buffer if the number of active streams is below
+ * the threshold.
+ */
+ if (loop->active_udp_streams < uv_active_udp_streams_threshold) {
+ handle->flags &= ~UV_HANDLE_ZERO_READ;
+
+ handle->recv_buffer = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &handle->recv_buffer);
+ if (handle->recv_buffer.base == NULL || handle->recv_buffer.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &handle->recv_buffer, NULL, 0);
+ return;
+ }
+ assert(handle->recv_buffer.base != NULL);
+
+ buf = handle->recv_buffer;
+ memset(&handle->recv_from, 0, sizeof handle->recv_from);
+ handle->recv_from_len = sizeof handle->recv_from;
+ flags = 0;
+
+ result = handle->func_wsarecvfrom(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &handle->recv_from,
+ &handle->recv_from_len,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+
+ } else {
+ handle->flags |= UV_HANDLE_ZERO_READ;
+
+ buf.base = (char*) uv_zero_;
+ buf.len = 0;
+ flags = MSG_PEEK;
+
+ result = handle->func_wsarecv(handle->socket,
+ (WSABUF*) &buf,
+ 1,
+ &bytes,
+ &flags,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Process the req without IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ req->u.io.overlapped.InternalHigh = bytes;
+ handle->reqs_pending++;
+ uv_insert_pending_req(loop, req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* The req will be processed with IOCP. */
+ handle->flags |= UV_HANDLE_READ_PENDING;
+ handle->reqs_pending++;
+ } else {
+ /* Make this req pending reporting an error. */
+ SET_REQ_ERROR(req, WSAGetLastError());
+ uv_insert_pending_req(loop, req);
+ handle->reqs_pending++;
+ }
+ }
+}
+
+
+int uv__udp_recv_start(uv_udp_t* handle, uv_alloc_cb alloc_cb,
+ uv_udp_recv_cb recv_cb) {
+ uv_loop_t* loop = handle->loop;
+ int err;
+
+ if (handle->flags & UV_HANDLE_READING) {
+ return WSAEALREADY;
+ }
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ 0);
+ if (err)
+ return err;
+
+ handle->flags |= UV_HANDLE_READING;
+ INCREASE_ACTIVE_COUNT(loop, handle);
+ loop->active_udp_streams++;
+
+ handle->recv_cb = recv_cb;
+ handle->alloc_cb = alloc_cb;
+
+ /* If reading was stopped and then started again, there could still be a */
+ /* recv request pending. */
+ if (!(handle->flags & UV_HANDLE_READ_PENDING))
+ uv_udp_queue_recv(loop, handle);
+
+ return 0;
+}
+
+
+int uv__udp_recv_stop(uv_udp_t* handle) {
+ if (handle->flags & UV_HANDLE_READING) {
+ handle->flags &= ~UV_HANDLE_READING;
+ handle->loop->active_udp_streams--;
+ DECREASE_ACTIVE_COUNT(loop, handle);
+ }
+
+ return 0;
+}
+
+
+static int uv__send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb cb) {
+ uv_loop_t* loop = handle->loop;
+ DWORD result, bytes;
+
+ UV_REQ_INIT(req, UV_UDP_SEND);
+ req->handle = handle;
+ req->cb = cb;
+ memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped));
+
+ result = WSASendTo(handle->socket,
+ (WSABUF*)bufs,
+ nbufs,
+ &bytes,
+ 0,
+ addr,
+ addrlen,
+ &req->u.io.overlapped,
+ NULL);
+
+ if (UV_SUCCEEDED_WITHOUT_IOCP(result == 0)) {
+ /* Request completed immediately. */
+ req->u.io.queued_bytes = 0;
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ uv_insert_pending_req(loop, (uv_req_t*)req);
+ } else if (UV_SUCCEEDED_WITH_IOCP(result == 0)) {
+ /* Request queued by the kernel. */
+ req->u.io.queued_bytes = uv__count_bufs(bufs, nbufs);
+ handle->reqs_pending++;
+ handle->send_queue_size += req->u.io.queued_bytes;
+ handle->send_queue_count++;
+ REGISTER_HANDLE_REQ(loop, handle, req);
+ } else {
+ /* Send failed due to an error. */
+ return WSAGetLastError();
+ }
+
+ return 0;
+}
+
+
+void uv_process_udp_recv_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_req_t* req) {
+ uv_buf_t buf;
+ int partial;
+
+ assert(handle->type == UV_UDP);
+
+ handle->flags &= ~UV_HANDLE_READ_PENDING;
+
+ if (!REQ_SUCCESS(req)) {
+ DWORD err = GET_REQ_SOCK_ERROR(req);
+ if (err == WSAEMSGSIZE) {
+ /* Not a real error, it just indicates that the received packet */
+ /* was bigger than the receive buffer. */
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* A previous sendto operation failed; ignore this error. If */
+ /* zero-reading we need to call WSARecv/WSARecvFrom _without_ the */
+ /* MSG_PEEK flag to clear out the error queue. For nonzero reads, */
+ /* immediately queue a new receive. */
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ goto done;
+ }
+ } else {
+ /* A real error occurred. Report the error to the user only if we're */
+ /* currently reading. */
+ if (handle->flags & UV_HANDLE_READING) {
+ uv_udp_recv_stop(handle);
+ buf = (handle->flags & UV_HANDLE_ZERO_READ) ?
+ uv_buf_init(NULL, 0) : handle->recv_buffer;
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ goto done;
+ }
+ }
+
+ if (!(handle->flags & UV_HANDLE_ZERO_READ)) {
+ /* Successful read */
+ partial = !REQ_SUCCESS(req);
+ handle->recv_cb(handle,
+ req->u.io.overlapped.InternalHigh,
+ &handle->recv_buffer,
+ (const struct sockaddr*) &handle->recv_from,
+ partial ? UV_UDP_PARTIAL : 0);
+ } else if (handle->flags & UV_HANDLE_READING) {
+ DWORD bytes, err, flags;
+ struct sockaddr_storage from;
+ int from_len;
+
+ /* Do a nonblocking receive */
+ /* TODO: try to read multiple datagrams at once. FIONREAD maybe? */
+ buf = uv_buf_init(NULL, 0);
+ handle->alloc_cb((uv_handle_t*) handle, 65536, &buf);
+ if (buf.base == NULL || buf.len == 0) {
+ handle->recv_cb(handle, UV_ENOBUFS, &buf, NULL, 0);
+ goto done;
+ }
+ assert(buf.base != NULL);
+
+ memset(&from, 0, sizeof from);
+ from_len = sizeof from;
+
+ flags = 0;
+
+ if (WSARecvFrom(handle->socket,
+ (WSABUF*)&buf,
+ 1,
+ &bytes,
+ &flags,
+ (struct sockaddr*) &from,
+ &from_len,
+ NULL,
+ NULL) != SOCKET_ERROR) {
+
+ /* Message received */
+ handle->recv_cb(handle, bytes, &buf, (const struct sockaddr*) &from, 0);
+ } else {
+ err = WSAGetLastError();
+ if (err == WSAEMSGSIZE) {
+ /* Message truncated */
+ handle->recv_cb(handle,
+ bytes,
+ &buf,
+ (const struct sockaddr*) &from,
+ UV_UDP_PARTIAL);
+ } else if (err == WSAEWOULDBLOCK) {
+ /* Kernel buffer empty */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else if (err == WSAECONNRESET || err == WSAENETRESET) {
+ /* WSAECONNRESET/WSANETRESET is ignored because this just indicates
+ * that a previous sendto operation failed.
+ */
+ handle->recv_cb(handle, 0, &buf, NULL, 0);
+ } else {
+ /* Any other error that we want to report back to the user. */
+ uv_udp_recv_stop(handle);
+ handle->recv_cb(handle, uv_translate_sys_error(err), &buf, NULL, 0);
+ }
+ }
+ }
+
+done:
+ /* Post another read if still reading and not closing. */
+ if ((handle->flags & UV_HANDLE_READING) &&
+ !(handle->flags & UV_HANDLE_READ_PENDING)) {
+ uv_udp_queue_recv(loop, handle);
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+void uv_process_udp_send_req(uv_loop_t* loop, uv_udp_t* handle,
+ uv_udp_send_t* req) {
+ int err;
+
+ assert(handle->type == UV_UDP);
+
+ assert(handle->send_queue_size >= req->u.io.queued_bytes);
+ assert(handle->send_queue_count >= 1);
+ handle->send_queue_size -= req->u.io.queued_bytes;
+ handle->send_queue_count--;
+
+ UNREGISTER_HANDLE_REQ(loop, handle, req);
+
+ if (req->cb) {
+ err = 0;
+ if (!REQ_SUCCESS(req)) {
+ err = GET_REQ_SOCK_ERROR(req);
+ }
+ req->cb(req, uv_translate_sys_error(err));
+ }
+
+ DECREASE_PENDING_REQ_COUNT(handle);
+}
+
+
+static int uv__udp_set_membership4(uv_udp_t* handle,
+ const struct sockaddr_in* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int err;
+ int optname;
+ struct ip_mreq mreq;
+
+ if (handle->flags & UV_HANDLE_IPV6)
+ return UV_EINVAL;
+
+ /* If the socket is unbound, bind to inaddr_any. */
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip4_any_,
+ sizeof(uv_addr_ip4_any_),
+ UV_UDP_REUSEADDR);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof mreq);
+
+ if (interface_addr) {
+ err = uv_inet_pton(AF_INET, interface_addr, &mreq.imr_interface.s_addr);
+ if (err)
+ return err;
+ } else {
+ mreq.imr_interface.s_addr = htonl(INADDR_ANY);
+ }
+
+ mreq.imr_multiaddr.s_addr = multicast_addr->sin_addr.s_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IP_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IP_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv__udp_set_membership6(uv_udp_t* handle,
+ const struct sockaddr_in6* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ int optname;
+ int err;
+ struct ipv6_mreq mreq;
+ struct sockaddr_in6 addr6;
+
+ if ((handle->flags & UV_HANDLE_BOUND) && !(handle->flags & UV_HANDLE_IPV6))
+ return UV_EINVAL;
+
+ err = uv_udp_maybe_bind(handle,
+ (const struct sockaddr*) &uv_addr_ip6_any_,
+ sizeof(uv_addr_ip6_any_),
+ UV_UDP_REUSEADDR);
+
+ if (err)
+ return uv_translate_sys_error(err);
+
+ memset(&mreq, 0, sizeof(mreq));
+
+ if (interface_addr) {
+ if (uv_ip6_addr(interface_addr, 0, &addr6))
+ return UV_EINVAL;
+ mreq.ipv6mr_interface = addr6.sin6_scope_id;
+ } else {
+ mreq.ipv6mr_interface = 0;
+ }
+
+ mreq.ipv6mr_multiaddr = multicast_addr->sin6_addr;
+
+ switch (membership) {
+ case UV_JOIN_GROUP:
+ optname = IPV6_ADD_MEMBERSHIP;
+ break;
+ case UV_LEAVE_GROUP:
+ optname = IPV6_DROP_MEMBERSHIP;
+ break;
+ default:
+ return UV_EINVAL;
+ }
+
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ optname,
+ (char*) &mreq,
+ sizeof mreq) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_membership(uv_udp_t* handle,
+ const char* multicast_addr,
+ const char* interface_addr,
+ uv_membership membership) {
+ struct sockaddr_in addr4;
+ struct sockaddr_in6 addr6;
+
+ if (uv_ip4_addr(multicast_addr, 0, &addr4) == 0)
+ return uv__udp_set_membership4(handle, &addr4, interface_addr, membership);
+ else if (uv_ip6_addr(multicast_addr, 0, &addr6) == 0)
+ return uv__udp_set_membership6(handle, &addr6, interface_addr, membership);
+ else
+ return UV_EINVAL;
+}
+
+
+int uv_udp_set_multicast_interface(uv_udp_t* handle, const char* interface_addr) {
+ struct sockaddr_storage addr_st;
+ struct sockaddr_in* addr4;
+ struct sockaddr_in6* addr6;
+
+ addr4 = (struct sockaddr_in*) &addr_st;
+ addr6 = (struct sockaddr_in6*) &addr_st;
+
+ if (!interface_addr) {
+ memset(&addr_st, 0, sizeof addr_st);
+ if (handle->flags & UV_HANDLE_IPV6) {
+ addr_st.ss_family = AF_INET6;
+ addr6->sin6_scope_id = 0;
+ } else {
+ addr_st.ss_family = AF_INET;
+ addr4->sin_addr.s_addr = htonl(INADDR_ANY);
+ }
+ } else if (uv_ip4_addr(interface_addr, 0, addr4) == 0) {
+ /* nothing, address was parsed */
+ } else if (uv_ip6_addr(interface_addr, 0, addr6) == 0) {
+ /* nothing, address was parsed */
+ } else {
+ return UV_EINVAL;
+ }
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (addr_st.ss_family == AF_INET) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IP,
+ IP_MULTICAST_IF,
+ (char*) &addr4->sin_addr,
+ sizeof(addr4->sin_addr)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else if (addr_st.ss_family == AF_INET6) {
+ if (setsockopt(handle->socket,
+ IPPROTO_IPV6,
+ IPV6_MULTICAST_IF,
+ (char*) &addr6->sin6_scope_id,
+ sizeof(addr6->sin6_scope_id)) == SOCKET_ERROR) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+ } else {
+ assert(0 && "unexpected address family");
+ abort();
+ }
+
+ return 0;
+}
+
+
+int uv_udp_set_broadcast(uv_udp_t* handle, int value) {
+ BOOL optval = (BOOL) value;
+
+ if (!(handle->flags & UV_HANDLE_BOUND))
+ return UV_EBADF;
+
+ if (setsockopt(handle->socket,
+ SOL_SOCKET,
+ SO_BROADCAST,
+ (char*) &optval,
+ sizeof optval)) {
+ return uv_translate_sys_error(WSAGetLastError());
+ }
+
+ return 0;
+}
+
+
+int uv_udp_open(uv_udp_t* handle, uv_os_sock_t sock) {
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+ int err;
+
+ /* Detect the address family of the socket. */
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(sock,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ err = uv_udp_set_socket(handle->loop,
+ handle,
+ sock,
+ protocol_info.iAddressFamily);
+ return uv_translate_sys_error(err);
+}
+
+
+#define SOCKOPT_SETTER(name, option4, option6, validate) \
+ int uv_udp_set_##name(uv_udp_t* handle, int value) { \
+ DWORD optval = (DWORD) value; \
+ \
+ if (!(validate(value))) { \
+ return UV_EINVAL; \
+ } \
+ \
+ if (!(handle->flags & UV_HANDLE_BOUND)) \
+ return UV_EBADF; \
+ \
+ if (!(handle->flags & UV_HANDLE_IPV6)) { \
+ /* Set IPv4 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IP, \
+ option4, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } else { \
+ /* Set IPv6 socket option */ \
+ if (setsockopt(handle->socket, \
+ IPPROTO_IPV6, \
+ option6, \
+ (char*) &optval, \
+ sizeof optval)) { \
+ return uv_translate_sys_error(WSAGetLastError()); \
+ } \
+ } \
+ return 0; \
+ }
+
+#define VALIDATE_TTL(value) ((value) >= 1 && (value) <= 255)
+#define VALIDATE_MULTICAST_TTL(value) ((value) >= -1 && (value) <= 255)
+#define VALIDATE_MULTICAST_LOOP(value) (1)
+
+SOCKOPT_SETTER(ttl,
+ IP_TTL,
+ IPV6_HOPLIMIT,
+ VALIDATE_TTL)
+SOCKOPT_SETTER(multicast_ttl,
+ IP_MULTICAST_TTL,
+ IPV6_MULTICAST_HOPS,
+ VALIDATE_MULTICAST_TTL)
+SOCKOPT_SETTER(multicast_loop,
+ IP_MULTICAST_LOOP,
+ IPV6_MULTICAST_LOOP,
+ VALIDATE_MULTICAST_LOOP)
+
+#undef SOCKOPT_SETTER
+#undef VALIDATE_TTL
+#undef VALIDATE_MULTICAST_TTL
+#undef VALIDATE_MULTICAST_LOOP
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_bind(uv_udp_t* handle,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ unsigned int flags) {
+ int err;
+
+ err = uv_udp_maybe_bind(handle, addr, addrlen, flags);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+/* This function is an egress point, i.e. it returns libuv errors rather than
+ * system errors.
+ */
+int uv__udp_send(uv_udp_send_t* req,
+ uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen,
+ uv_udp_send_cb send_cb) {
+ const struct sockaddr* bind_addr;
+ int err;
+
+ if (!(handle->flags & UV_HANDLE_BOUND)) {
+ if (addrlen == sizeof(uv_addr_ip4_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip4_any_;
+ } else if (addrlen == sizeof(uv_addr_ip6_any_)) {
+ bind_addr = (const struct sockaddr*) &uv_addr_ip6_any_;
+ } else {
+ abort();
+ }
+ err = uv_udp_maybe_bind(handle, bind_addr, addrlen, 0);
+ if (err)
+ return uv_translate_sys_error(err);
+ }
+
+ err = uv__send(req, handle, bufs, nbufs, addr, addrlen, send_cb);
+ if (err)
+ return uv_translate_sys_error(err);
+
+ return 0;
+}
+
+
+int uv__udp_try_send(uv_udp_t* handle,
+ const uv_buf_t bufs[],
+ unsigned int nbufs,
+ const struct sockaddr* addr,
+ unsigned int addrlen) {
+ return UV_ENOSYS;
+}
diff --git a/Utilities/cmlibuv/src/win/util.c b/Utilities/cmlibuv/src/win/util.c
new file mode 100644
index 000000000..d2e7f772c
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/util.c
@@ -0,0 +1,1576 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <direct.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <wchar.h>
+
+#include "uv.h"
+#include "internal.h"
+
+#include <winsock2.h>
+#include <winperf.h>
+#include <iphlpapi.h>
+#include <psapi.h>
+#include <tlhelp32.h>
+#include <windows.h>
+#include <userenv.h>
+
+
+/*
+ * Max title length; the only thing MSDN tells us about the maximum length
+ * of the console title is that it is smaller than 64K. However in practice
+ * it is much smaller, and there is no way to figure out what the exact length
+ * of the title is or can be, at least not on XP. To make it even more
+ * annoying, GetConsoleTitle fails when the buffer to be read into is bigger
+ * than the actual maximum length. So we make a conservative guess here;
+ * just don't put the novel you're writing in the title, unless the plot
+ * survives truncation.
+ */
+#define MAX_TITLE_LENGTH 8192
+
+/* The number of nanoseconds in one second. */
+#define UV__NANOSEC 1000000000
+
+/* Max user name length, from iphlpapi.h */
+#ifndef UNLEN
+# define UNLEN 256
+#endif
+
+/*
+ Max hostname length. The Windows gethostname() documentation states that 256
+ bytes will always be large enough to hold the null-terminated hostname.
+*/
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 256
+#endif
+
+/* Maximum environment variable size, including the terminating null */
+#define MAX_ENV_VAR_LENGTH 32767
+
+/* Cached copy of the process title, plus a mutex guarding it. */
+static char *process_title;
+static CRITICAL_SECTION process_title_lock;
+
+/* Cached copy of the process id, written once. */
+static DWORD current_pid = 0;
+
+
+/* Interval (in seconds) of the high-resolution clock. */
+static double hrtime_interval_ = 0;
+
+
+/*
+ * One-time initialization code for functionality defined in util.c.
+ */
+void uv__util_init(void) {
+ LARGE_INTEGER perf_frequency;
+
+ /* Initialize process title access mutex. */
+ InitializeCriticalSection(&process_title_lock);
+
+ /* Retrieve high-resolution timer frequency
+ * and precompute its reciprocal.
+ */
+ if (QueryPerformanceFrequency(&perf_frequency)) {
+ hrtime_interval_ = 1.0 / perf_frequency.QuadPart;
+ } else {
+ hrtime_interval_= 0;
+ }
+}
+
+
+int uv_exepath(char* buffer, size_t* size_ptr) {
+ int utf8_len, utf16_buffer_len, utf16_len;
+ WCHAR* utf16_buffer;
+ int err;
+
+ if (buffer == NULL || size_ptr == NULL || *size_ptr == 0) {
+ return UV_EINVAL;
+ }
+
+ if (*size_ptr > 32768) {
+ /* Windows paths can never be longer than this. */
+ utf16_buffer_len = 32768;
+ } else {
+ utf16_buffer_len = (int) *size_ptr;
+ }
+
+ utf16_buffer = (WCHAR*) uv__malloc(sizeof(WCHAR) * utf16_buffer_len);
+ if (!utf16_buffer) {
+ return UV_ENOMEM;
+ }
+
+ /* Get the path as UTF-16. */
+ utf16_len = GetModuleFileNameW(NULL, utf16_buffer, utf16_buffer_len);
+ if (utf16_len <= 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* Convert to UTF-8 */
+ utf8_len = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ (int) *size_ptr,
+ NULL,
+ NULL);
+ if (utf8_len == 0) {
+ err = GetLastError();
+ goto error;
+ }
+
+ uv__free(utf16_buffer);
+
+ /* utf8_len *does* include the terminating null at this point, but the */
+ /* returned size shouldn't. */
+ *size_ptr = utf8_len - 1;
+ return 0;
+
+ error:
+ uv__free(utf16_buffer);
+ return uv_translate_sys_error(err);
+}
+
+
+int uv_cwd(char* buffer, size_t* size) {
+ DWORD utf16_len;
+ WCHAR utf16_buffer[MAX_PATH];
+ int r;
+
+ if (buffer == NULL || size == NULL) {
+ return UV_EINVAL;
+ }
+
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ /* This should be impossible; however the CRT has a code path to deal */
+ /* with this scenario, so I added a check anyway. */
+ return UV_EIO;
+ }
+
+ /* utf16_len contains the length, *not* including the terminating null. */
+ utf16_buffer[utf16_len] = L'\0';
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (r > (int) *size) {
+ *size = r;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ r = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16_buffer,
+ -1,
+ buffer,
+ *size > INT_MAX ? INT_MAX : (int) *size,
+ NULL,
+ NULL);
+ if (r == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *size = r - 1;
+ return 0;
+}
+
+
+int uv_chdir(const char* dir) {
+ WCHAR utf16_buffer[MAX_PATH];
+ size_t utf16_len;
+ WCHAR drive_letter, env_var[4];
+
+ if (dir == NULL) {
+ return UV_EINVAL;
+ }
+
+ if (MultiByteToWideChar(CP_UTF8,
+ 0,
+ dir,
+ -1,
+ utf16_buffer,
+ MAX_PATH) == 0) {
+ DWORD error = GetLastError();
+ /* The maximum length of the current working directory is 260 chars, */
+ /* including terminating null. If it doesn't fit, the path name must be */
+ /* too long. */
+ if (error == ERROR_INSUFFICIENT_BUFFER) {
+ return UV_ENAMETOOLONG;
+ } else {
+ return uv_translate_sys_error(error);
+ }
+ }
+
+ if (!SetCurrentDirectoryW(utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Windows stores the drive-local path in an "hidden" environment variable, */
+ /* which has the form "=C:=C:\Windows". SetCurrentDirectory does not */
+ /* update this, so we'll have to do it. */
+ utf16_len = GetCurrentDirectoryW(MAX_PATH, utf16_buffer);
+ if (utf16_len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (utf16_len > MAX_PATH) {
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed. */
+ if (utf16_buffer[utf16_len - 1] == L'\\' &&
+ !(utf16_len == 3 && utf16_buffer[1] == L':')) {
+ utf16_len--;
+ utf16_buffer[utf16_len] = L'\0';
+ }
+
+ if (utf16_len < 2 || utf16_buffer[1] != L':') {
+ /* Doesn't look like a drive letter could be there - probably an UNC */
+ /* path. TODO: Need to handle win32 namespaces like \\?\C:\ ? */
+ drive_letter = 0;
+ } else if (utf16_buffer[0] >= L'A' && utf16_buffer[0] <= L'Z') {
+ drive_letter = utf16_buffer[0];
+ } else if (utf16_buffer[0] >= L'a' && utf16_buffer[0] <= L'z') {
+ /* Convert to uppercase. */
+ drive_letter = utf16_buffer[0] - L'a' + L'A';
+ } else {
+ /* Not valid. */
+ drive_letter = 0;
+ }
+
+ if (drive_letter != 0) {
+ /* Construct the environment variable name and set it. */
+ env_var[0] = L'=';
+ env_var[1] = drive_letter;
+ env_var[2] = L':';
+ env_var[3] = L'\0';
+
+ if (!SetEnvironmentVariableW(env_var, utf16_buffer)) {
+ return uv_translate_sys_error(GetLastError());
+ }
+ }
+
+ return 0;
+}
+
+
+void uv_loadavg(double avg[3]) {
+ /* Can't be implemented */
+ avg[0] = avg[1] = avg[2] = 0;
+}
+
+
+uint64_t uv_get_free_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullAvailPhys;
+}
+
+
+uint64_t uv_get_total_memory(void) {
+ MEMORYSTATUSEX memory_status;
+ memory_status.dwLength = sizeof(memory_status);
+
+ if (!GlobalMemoryStatusEx(&memory_status)) {
+ return -1;
+ }
+
+ return (uint64_t)memory_status.ullTotalPhys;
+}
+
+
+int uv_parent_pid(void) {
+ int parent_pid = -1;
+ HANDLE handle;
+ PROCESSENTRY32 pe;
+ DWORD current_pid = GetCurrentProcessId();
+
+ pe.dwSize = sizeof(PROCESSENTRY32);
+ handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ if (Process32First(handle, &pe)) {
+ do {
+ if (pe.th32ProcessID == current_pid) {
+ parent_pid = pe.th32ParentProcessID;
+ break;
+ }
+ } while( Process32Next(handle, &pe));
+ }
+
+ CloseHandle(handle);
+ return parent_pid;
+}
+
+
+int uv_current_pid(void) {
+ if (current_pid == 0) {
+ current_pid = GetCurrentProcessId();
+ }
+ return current_pid;
+}
+
+
+char** uv_setup_args(int argc, char** argv) {
+ return argv;
+}
+
+
+int uv_set_process_title(const char* title) {
+ int err;
+ int length;
+ WCHAR* title_w = NULL;
+
+ uv__once_init();
+
+ /* Find out how big the buffer for the wide-char title must be */
+ length = MultiByteToWideChar(CP_UTF8, 0, title, -1, NULL, 0);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* Convert to wide-char string */
+ title_w = (WCHAR*)uv__malloc(sizeof(WCHAR) * length);
+ if (!title_w) {
+ uv_fatal_error(ERROR_OUTOFMEMORY, "uv__malloc");
+ }
+
+ length = MultiByteToWideChar(CP_UTF8, 0, title, -1, title_w, length);
+ if (!length) {
+ err = GetLastError();
+ goto done;
+ }
+
+ /* If the title must be truncated insert a \0 terminator there */
+ if (length > MAX_TITLE_LENGTH) {
+ title_w[MAX_TITLE_LENGTH - 1] = L'\0';
+ }
+
+ if (!SetConsoleTitleW(title_w)) {
+ err = GetLastError();
+ goto done;
+ }
+
+ EnterCriticalSection(&process_title_lock);
+ uv__free(process_title);
+ process_title = uv__strdup(title);
+ LeaveCriticalSection(&process_title_lock);
+
+ err = 0;
+
+done:
+ uv__free(title_w);
+ return uv_translate_sys_error(err);
+}
+
+
+static int uv__get_process_title(void) {
+ WCHAR title_w[MAX_TITLE_LENGTH];
+
+ if (!GetConsoleTitleW(title_w, sizeof(title_w) / sizeof(WCHAR))) {
+ return -1;
+ }
+
+ if (uv__convert_utf16_to_utf8(title_w, -1, &process_title) != 0)
+ return -1;
+
+ return 0;
+}
+
+
+int uv_get_process_title(char* buffer, size_t size) {
+ size_t len;
+
+ if (buffer == NULL || size == 0)
+ return UV_EINVAL;
+
+ uv__once_init();
+
+ EnterCriticalSection(&process_title_lock);
+ /*
+ * If the process_title was never read before nor explicitly set,
+ * we must query it with getConsoleTitleW
+ */
+ if (!process_title && uv__get_process_title() == -1) {
+ LeaveCriticalSection(&process_title_lock);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ assert(process_title);
+ len = strlen(process_title) + 1;
+
+ if (size < len) {
+ LeaveCriticalSection(&process_title_lock);
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, process_title, len);
+ LeaveCriticalSection(&process_title_lock);
+
+ return 0;
+}
+
+
+uint64_t uv_hrtime(void) {
+ uv__once_init();
+ return uv__hrtime(UV__NANOSEC);
+}
+
+uint64_t uv__hrtime(double scale) {
+ LARGE_INTEGER counter;
+
+ /* If the performance interval is zero, there's no support. */
+ if (hrtime_interval_ == 0) {
+ return 0;
+ }
+
+ if (!QueryPerformanceCounter(&counter)) {
+ return 0;
+ }
+
+ /* Because we have no guarantee about the order of magnitude of the
+ * performance counter interval, integer math could cause this computation
+ * to overflow. Therefore we resort to floating point math.
+ */
+ return (uint64_t) ((double) counter.QuadPart * hrtime_interval_ * scale);
+}
+
+
+int uv_resident_set_memory(size_t* rss) {
+ HANDLE current_process;
+ PROCESS_MEMORY_COUNTERS pmc;
+
+ current_process = GetCurrentProcess();
+
+ if (!GetProcessMemoryInfo(current_process, &pmc, sizeof(pmc))) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ *rss = pmc.WorkingSetSize;
+
+ return 0;
+}
+
+
+int uv_uptime(double* uptime) {
+ BYTE stack_buffer[4096];
+ BYTE* malloced_buffer = NULL;
+ BYTE* buffer = (BYTE*) stack_buffer;
+ size_t buffer_size = sizeof(stack_buffer);
+ DWORD data_size;
+
+ PERF_DATA_BLOCK* data_block;
+ PERF_OBJECT_TYPE* object_type;
+ PERF_COUNTER_DEFINITION* counter_definition;
+
+ DWORD i;
+
+ for (;;) {
+ LONG result;
+
+ data_size = (DWORD) buffer_size;
+ result = RegQueryValueExW(HKEY_PERFORMANCE_DATA,
+ L"2",
+ NULL,
+ NULL,
+ buffer,
+ &data_size);
+ if (result == ERROR_SUCCESS) {
+ break;
+ } else if (result != ERROR_MORE_DATA) {
+ *uptime = 0;
+ return uv_translate_sys_error(result);
+ }
+
+ buffer_size *= 2;
+ /* Don't let the buffer grow infinitely. */
+ if (buffer_size > 1 << 20) {
+ goto internalError;
+ }
+
+ uv__free(malloced_buffer);
+
+ buffer = malloced_buffer = (BYTE*) uv__malloc(buffer_size);
+ if (malloced_buffer == NULL) {
+ *uptime = 0;
+ return UV_ENOMEM;
+ }
+ }
+
+ if (data_size < sizeof(*data_block))
+ goto internalError;
+
+ data_block = (PERF_DATA_BLOCK*) buffer;
+
+ if (wmemcmp(data_block->Signature, L"PERF", 4) != 0)
+ goto internalError;
+
+ if (data_size < data_block->HeaderLength + sizeof(*object_type))
+ goto internalError;
+
+ object_type = (PERF_OBJECT_TYPE*) (buffer + data_block->HeaderLength);
+
+ if (object_type->NumInstances != PERF_NO_INSTANCES)
+ goto internalError;
+
+ counter_definition = (PERF_COUNTER_DEFINITION*) (buffer +
+ data_block->HeaderLength + object_type->HeaderLength);
+ for (i = 0; i < object_type->NumCounters; i++) {
+ if ((BYTE*) counter_definition + sizeof(*counter_definition) >
+ buffer + data_size) {
+ break;
+ }
+
+ if (counter_definition->CounterNameTitleIndex == 674 &&
+ counter_definition->CounterSize == sizeof(uint64_t)) {
+ if (counter_definition->CounterOffset + sizeof(uint64_t) > data_size ||
+ !(counter_definition->CounterType & PERF_OBJECT_TIMER)) {
+ goto internalError;
+ } else {
+ BYTE* address = (BYTE*) object_type + object_type->DefinitionLength +
+ counter_definition->CounterOffset;
+ uint64_t value = *((uint64_t*) address);
+ *uptime = (double) (object_type->PerfTime.QuadPart - value) /
+ (double) object_type->PerfFreq.QuadPart;
+ uv__free(malloced_buffer);
+ return 0;
+ }
+ }
+
+ counter_definition = (PERF_COUNTER_DEFINITION*)
+ ((BYTE*) counter_definition + counter_definition->ByteLength);
+ }
+
+ /* If we get here, the uptime value was not found. */
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_ENOSYS;
+
+ internalError:
+ uv__free(malloced_buffer);
+ *uptime = 0;
+ return UV_EIO;
+}
+
+
+int uv_cpu_info(uv_cpu_info_t** cpu_infos_ptr, int* cpu_count_ptr) {
+ uv_cpu_info_t* cpu_infos;
+ SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION* sppi;
+ DWORD sppi_size;
+ SYSTEM_INFO system_info;
+ DWORD cpu_count, r, i;
+ NTSTATUS status;
+ ULONG result_size;
+ int err;
+ uv_cpu_info_t* cpu_info;
+
+ cpu_infos = NULL;
+ cpu_count = 0;
+ sppi = NULL;
+
+ uv__once_init();
+
+ GetSystemInfo(&system_info);
+ cpu_count = system_info.dwNumberOfProcessors;
+
+ cpu_infos = uv__calloc(cpu_count, sizeof *cpu_infos);
+ if (cpu_infos == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ sppi_size = cpu_count * sizeof(*sppi);
+ sppi = uv__malloc(sppi_size);
+ if (sppi == NULL) {
+ err = ERROR_OUTOFMEMORY;
+ goto error;
+ }
+
+ status = pNtQuerySystemInformation(SystemProcessorPerformanceInformation,
+ sppi,
+ sppi_size,
+ &result_size);
+ if (!NT_SUCCESS(status)) {
+ err = pRtlNtStatusToDosError(status);
+ goto error;
+ }
+
+ assert(result_size == sppi_size);
+
+ for (i = 0; i < cpu_count; i++) {
+ WCHAR key_name[128];
+ HKEY processor_key;
+ DWORD cpu_speed;
+ DWORD cpu_speed_size = sizeof(cpu_speed);
+ WCHAR cpu_brand[256];
+ DWORD cpu_brand_size = sizeof(cpu_brand);
+ size_t len;
+
+ len = _snwprintf(key_name,
+ ARRAY_SIZE(key_name),
+ L"HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\%d",
+ i);
+
+ assert(len > 0 && len < ARRAY_SIZE(key_name));
+
+ r = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &processor_key);
+ if (r != ERROR_SUCCESS) {
+ err = GetLastError();
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"~MHz",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_speed,
+ &cpu_speed_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ if (RegQueryValueExW(processor_key,
+ L"ProcessorNameString",
+ NULL,
+ NULL,
+ (BYTE*) &cpu_brand,
+ &cpu_brand_size) != ERROR_SUCCESS) {
+ err = GetLastError();
+ RegCloseKey(processor_key);
+ goto error;
+ }
+
+ RegCloseKey(processor_key);
+
+ cpu_info = &cpu_infos[i];
+ cpu_info->speed = cpu_speed;
+ cpu_info->cpu_times.user = sppi[i].UserTime.QuadPart / 10000;
+ cpu_info->cpu_times.sys = (sppi[i].KernelTime.QuadPart -
+ sppi[i].IdleTime.QuadPart) / 10000;
+ cpu_info->cpu_times.idle = sppi[i].IdleTime.QuadPart / 10000;
+ cpu_info->cpu_times.irq = sppi[i].InterruptTime.QuadPart / 10000;
+ cpu_info->cpu_times.nice = 0;
+
+ uv__convert_utf16_to_utf8(cpu_brand,
+ cpu_brand_size / sizeof(WCHAR),
+ &(cpu_info->model));
+ }
+
+ uv__free(sppi);
+
+ *cpu_count_ptr = cpu_count;
+ *cpu_infos_ptr = cpu_infos;
+
+ return 0;
+
+ error:
+ /* This is safe because the cpu_infos array is zeroed on allocation. */
+ for (i = 0; i < cpu_count; i++)
+ uv__free(cpu_infos[i].model);
+
+ uv__free(cpu_infos);
+ uv__free(sppi);
+
+ return uv_translate_sys_error(err);
+}
+
+
+void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count) {
+ int i;
+
+ for (i = 0; i < count; i++) {
+ uv__free(cpu_infos[i].model);
+ }
+
+ uv__free(cpu_infos);
+}
+
+
+static int is_windows_version_or_greater(DWORD os_major,
+ DWORD os_minor,
+ WORD service_pack_major,
+ WORD service_pack_minor) {
+ OSVERSIONINFOEX osvi;
+ DWORDLONG condition_mask = 0;
+ int op = VER_GREATER_EQUAL;
+
+ /* Initialize the OSVERSIONINFOEX structure. */
+ ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
+ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ osvi.dwMajorVersion = os_major;
+ osvi.dwMinorVersion = os_minor;
+ osvi.wServicePackMajor = service_pack_major;
+ osvi.wServicePackMinor = service_pack_minor;
+
+ /* Initialize the condition mask. */
+ VER_SET_CONDITION(condition_mask, VER_MAJORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_MINORVERSION, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMAJOR, op);
+ VER_SET_CONDITION(condition_mask, VER_SERVICEPACKMINOR, op);
+
+ /* Perform the test. */
+ return (int) VerifyVersionInfo(
+ &osvi,
+ VER_MAJORVERSION | VER_MINORVERSION |
+ VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR,
+ condition_mask);
+}
+
+
+static int address_prefix_match(int family,
+ struct sockaddr* address,
+ struct sockaddr* prefix_address,
+ int prefix_len) {
+ uint8_t* address_data;
+ uint8_t* prefix_address_data;
+ int i;
+
+ assert(address->sa_family == family);
+ assert(prefix_address->sa_family == family);
+
+ if (family == AF_INET6) {
+ address_data = (uint8_t*) &(((struct sockaddr_in6 *) address)->sin6_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in6 *) prefix_address)->sin6_addr);
+ } else {
+ address_data = (uint8_t*) &(((struct sockaddr_in *) address)->sin_addr);
+ prefix_address_data =
+ (uint8_t*) &(((struct sockaddr_in *) prefix_address)->sin_addr);
+ }
+
+ for (i = 0; i < prefix_len >> 3; i++) {
+ if (address_data[i] != prefix_address_data[i])
+ return 0;
+ }
+
+ if (prefix_len % 8)
+ return prefix_address_data[i] ==
+ (address_data[i] & (0xff << (8 - prefix_len % 8)));
+
+ return 1;
+}
+
+
+int uv_interface_addresses(uv_interface_address_t** addresses_ptr,
+ int* count_ptr) {
+ IP_ADAPTER_ADDRESSES* win_address_buf;
+ ULONG win_address_buf_size;
+ IP_ADAPTER_ADDRESSES* adapter;
+
+ uv_interface_address_t* uv_address_buf;
+ char* name_buf;
+ size_t uv_address_buf_size;
+ uv_interface_address_t* uv_address;
+
+ int count;
+
+ int is_vista_or_greater;
+ ULONG flags;
+
+ is_vista_or_greater = is_windows_version_or_greater(6, 0, 0, 0);
+ if (is_vista_or_greater) {
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER;
+ } else {
+ /* We need at least XP SP1. */
+ if (!is_windows_version_or_greater(5, 1, 1, 0))
+ return UV_ENOTSUP;
+
+ flags = GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST |
+ GAA_FLAG_SKIP_DNS_SERVER | GAA_FLAG_INCLUDE_PREFIX;
+ }
+
+
+ /* Fetch the size of the adapters reported by windows, and then get the */
+ /* list itself. */
+ win_address_buf_size = 0;
+ win_address_buf = NULL;
+
+ for (;;) {
+ ULONG r;
+
+ /* If win_address_buf is 0, then GetAdaptersAddresses will fail with */
+ /* ERROR_BUFFER_OVERFLOW, and the required buffer size will be stored in */
+ /* win_address_buf_size. */
+ r = GetAdaptersAddresses(AF_UNSPEC,
+ flags,
+ NULL,
+ win_address_buf,
+ &win_address_buf_size);
+
+ if (r == ERROR_SUCCESS)
+ break;
+
+ uv__free(win_address_buf);
+
+ switch (r) {
+ case ERROR_BUFFER_OVERFLOW:
+ /* This happens when win_address_buf is NULL or too small to hold */
+ /* all adapters. */
+ win_address_buf = uv__malloc(win_address_buf_size);
+ if (win_address_buf == NULL)
+ return UV_ENOMEM;
+
+ continue;
+
+ case ERROR_NO_DATA: {
+ /* No adapters were found. */
+ uv_address_buf = uv__malloc(1);
+ if (uv_address_buf == NULL)
+ return UV_ENOMEM;
+
+ *count_ptr = 0;
+ *addresses_ptr = uv_address_buf;
+
+ return 0;
+ }
+
+ case ERROR_ADDRESS_NOT_ASSOCIATED:
+ return UV_EAGAIN;
+
+ case ERROR_INVALID_PARAMETER:
+ /* MSDN says:
+ * "This error is returned for any of the following conditions: the
+ * SizePointer parameter is NULL, the Address parameter is not
+ * AF_INET, AF_INET6, or AF_UNSPEC, or the address information for
+ * the parameters requested is greater than ULONG_MAX."
+ * Since the first two conditions are not met, it must be that the
+ * adapter data is too big.
+ */
+ return UV_ENOBUFS;
+
+ default:
+ /* Other (unspecified) errors can happen, but we don't have any */
+ /* special meaning for them. */
+ assert(r != ERROR_SUCCESS);
+ return uv_translate_sys_error(r);
+ }
+ }
+
+ /* Count the number of enabled interfaces and compute how much space is */
+ /* needed to store their info. */
+ count = 0;
+ uv_address_buf_size = 0;
+
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+
+ /* Interfaces that are not 'up' should not be reported. Also skip */
+ /* interfaces that have no associated unicast address, as to avoid */
+ /* allocating space for the name for this interface. */
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Compute the size of the interface name. */
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ NULL,
+ 0,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+ uv_address_buf_size += name_size;
+
+ /* Count the number of addresses associated with this interface, and */
+ /* compute the size. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ count++;
+ uv_address_buf_size += sizeof(uv_interface_address_t);
+ }
+ }
+
+ /* Allocate space to store interface data plus adapter names. */
+ uv_address_buf = uv__malloc(uv_address_buf_size);
+ if (uv_address_buf == NULL) {
+ uv__free(win_address_buf);
+ return UV_ENOMEM;
+ }
+
+ /* Compute the start of the uv_interface_address_t array, and the place in */
+ /* the buffer where the interface names will be stored. */
+ uv_address = uv_address_buf;
+ name_buf = (char*) (uv_address_buf + count);
+
+ /* Fill out the output buffer. */
+ for (adapter = win_address_buf;
+ adapter != NULL;
+ adapter = adapter->Next) {
+ IP_ADAPTER_UNICAST_ADDRESS* unicast_address;
+ int name_size;
+ size_t max_name_size;
+
+ if (adapter->OperStatus != IfOperStatusUp ||
+ adapter->FirstUnicastAddress == NULL)
+ continue;
+
+ /* Convert the interface name to UTF8. */
+ max_name_size = (char*) uv_address_buf + uv_address_buf_size - name_buf;
+ if (max_name_size > (size_t) INT_MAX)
+ max_name_size = INT_MAX;
+ name_size = WideCharToMultiByte(CP_UTF8,
+ 0,
+ adapter->FriendlyName,
+ -1,
+ name_buf,
+ (int) max_name_size,
+ NULL,
+ FALSE);
+ if (name_size <= 0) {
+ uv__free(win_address_buf);
+ uv__free(uv_address_buf);
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ /* Add an uv_interface_address_t element for every unicast address. */
+ for (unicast_address = (IP_ADAPTER_UNICAST_ADDRESS*)
+ adapter->FirstUnicastAddress;
+ unicast_address != NULL;
+ unicast_address = unicast_address->Next) {
+ struct sockaddr* sa;
+ ULONG prefix_len;
+
+ sa = unicast_address->Address.lpSockaddr;
+
+ /* XP has no OnLinkPrefixLength field. */
+ if (is_vista_or_greater) {
+ prefix_len =
+ ((IP_ADAPTER_UNICAST_ADDRESS_LH*) unicast_address)->OnLinkPrefixLength;
+ } else {
+ /* Prior to Windows Vista the FirstPrefix pointed to the list with
+ * single prefix for each IP address assigned to the adapter.
+ * Order of FirstPrefix does not match order of FirstUnicastAddress,
+ * so we need to find corresponding prefix.
+ */
+ IP_ADAPTER_PREFIX* prefix;
+ prefix_len = 0;
+
+ for (prefix = adapter->FirstPrefix; prefix; prefix = prefix->Next) {
+ /* We want the longest matching prefix. */
+ if (prefix->Address.lpSockaddr->sa_family != sa->sa_family ||
+ prefix->PrefixLength <= prefix_len)
+ continue;
+
+ if (address_prefix_match(sa->sa_family, sa,
+ prefix->Address.lpSockaddr, prefix->PrefixLength)) {
+ prefix_len = prefix->PrefixLength;
+ }
+ }
+
+ /* If there is no matching prefix information, return a single-host
+ * subnet mask (e.g. 255.255.255.255 for IPv4).
+ */
+ if (!prefix_len)
+ prefix_len = (sa->sa_family == AF_INET6) ? 128 : 32;
+ }
+
+ memset(uv_address, 0, sizeof *uv_address);
+
+ uv_address->name = name_buf;
+
+ if (adapter->PhysicalAddressLength == sizeof(uv_address->phys_addr)) {
+ memcpy(uv_address->phys_addr,
+ adapter->PhysicalAddress,
+ sizeof(uv_address->phys_addr));
+ }
+
+ uv_address->is_internal =
+ (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK);
+
+ if (sa->sa_family == AF_INET6) {
+ uv_address->address.address6 = *((struct sockaddr_in6 *) sa);
+
+ uv_address->netmask.netmask6.sin6_family = AF_INET6;
+ memset(uv_address->netmask.netmask6.sin6_addr.s6_addr, 0xff, prefix_len >> 3);
+ /* This check ensures that we don't write past the size of the data. */
+ if (prefix_len % 8) {
+ uv_address->netmask.netmask6.sin6_addr.s6_addr[prefix_len >> 3] =
+ 0xff << (8 - prefix_len % 8);
+ }
+
+ } else {
+ uv_address->address.address4 = *((struct sockaddr_in *) sa);
+
+ uv_address->netmask.netmask4.sin_family = AF_INET;
+ uv_address->netmask.netmask4.sin_addr.s_addr = (prefix_len > 0) ?
+ htonl(0xffffffff << (32 - prefix_len)) : 0;
+ }
+
+ uv_address++;
+ }
+
+ name_buf += name_size;
+ }
+
+ uv__free(win_address_buf);
+
+ *addresses_ptr = uv_address_buf;
+ *count_ptr = count;
+
+ return 0;
+}
+
+
+void uv_free_interface_addresses(uv_interface_address_t* addresses,
+ int count) {
+ uv__free(addresses);
+}
+
+
+int uv_getrusage(uv_rusage_t *uv_rusage) {
+ FILETIME createTime, exitTime, kernelTime, userTime;
+ SYSTEMTIME kernelSystemTime, userSystemTime;
+ PROCESS_MEMORY_COUNTERS memCounters;
+ IO_COUNTERS ioCounters;
+ int ret;
+
+ ret = GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &kernelTime, &userTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&kernelTime, &kernelSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = FileTimeToSystemTime(&userTime, &userSystemTime);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = GetProcessMemoryInfo(GetCurrentProcess(),
+ &memCounters,
+ sizeof(memCounters));
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ ret = GetProcessIoCounters(GetCurrentProcess(), &ioCounters);
+ if (ret == 0) {
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ memset(uv_rusage, 0, sizeof(*uv_rusage));
+
+ uv_rusage->ru_utime.tv_sec = userSystemTime.wHour * 3600 +
+ userSystemTime.wMinute * 60 +
+ userSystemTime.wSecond;
+ uv_rusage->ru_utime.tv_usec = userSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_stime.tv_sec = kernelSystemTime.wHour * 3600 +
+ kernelSystemTime.wMinute * 60 +
+ kernelSystemTime.wSecond;
+ uv_rusage->ru_stime.tv_usec = kernelSystemTime.wMilliseconds * 1000;
+
+ uv_rusage->ru_majflt = (uint64_t) memCounters.PageFaultCount;
+ uv_rusage->ru_maxrss = (uint64_t) memCounters.PeakWorkingSetSize / 1024;
+
+ uv_rusage->ru_oublock = (uint64_t) ioCounters.WriteOperationCount;
+ uv_rusage->ru_inblock = (uint64_t) ioCounters.ReadOperationCount;
+
+ return 0;
+}
+
+
+int uv_os_homedir(char* buffer, size_t* size) {
+ uv_passwd_t pwd;
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ size_t len;
+ int r;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ /* Check if the USERPROFILE environment variable is set first */
+ len = GetEnvironmentVariableW(L"USERPROFILE", path, MAX_PATH);
+
+ if (len == 0) {
+ r = GetLastError();
+
+ /* Don't return an error if USERPROFILE was not found */
+ if (r != ERROR_ENVVAR_NOT_FOUND)
+ return uv_translate_sys_error(r);
+ } else if (len > MAX_PATH) {
+ /* This should not be possible */
+ return UV_EIO;
+ } else {
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ path,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+ }
+
+ /* USERPROFILE is not set, so call uv__getpwuid_r() */
+ r = uv__getpwuid_r(&pwd);
+
+ if (r != 0) {
+ return r;
+ }
+
+ len = strlen(pwd.homedir);
+
+ if (len >= *size) {
+ *size = len + 1;
+ uv_os_free_passwd(&pwd);
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, pwd.homedir, len + 1);
+ *size = len;
+ uv_os_free_passwd(&pwd);
+
+ return 0;
+}
+
+
+int uv_os_tmpdir(char* buffer, size_t* size) {
+ wchar_t path[MAX_PATH + 1];
+ DWORD bufsize;
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ len = GetTempPathW(MAX_PATH + 1, path);
+
+ if (len == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (len > MAX_PATH + 1) {
+ /* This should not be possible */
+ return UV_EIO;
+ }
+
+ /* The returned directory should not have a trailing slash, unless it */
+ /* points at a drive root, like c:\. Remove it if needed.*/
+ if (path[len - 1] == L'\\' &&
+ !(len == 3 && path[1] == L':')) {
+ len--;
+ path[len] = L'\0';
+ }
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, path, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ path,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
+
+
+void uv_os_free_passwd(uv_passwd_t* pwd) {
+ if (pwd == NULL)
+ return;
+
+ uv__free(pwd->username);
+ uv__free(pwd->homedir);
+ pwd->username = NULL;
+ pwd->homedir = NULL;
+}
+
+
+/*
+ * Converts a UTF-16 string into a UTF-8 one. The resulting string is
+ * null-terminated.
+ *
+ * If utf16 is null terminated, utf16len can be set to -1, otherwise it must
+ * be specified.
+ */
+int uv__convert_utf16_to_utf8(const WCHAR* utf16, int utf16len, char** utf8) {
+ DWORD bufsize;
+
+ if (utf16 == NULL)
+ return UV_EINVAL;
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ /* Allocate the destination buffer adding an extra byte for the terminating
+ * NULL. If utf16len is not -1 WideCharToMultiByte will not add it, so
+ * we do it ourselves always, just in case. */
+ *utf8 = uv__malloc(bufsize + 1);
+
+ if (*utf8 == NULL)
+ return UV_ENOMEM;
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ utf16,
+ utf16len,
+ *utf8,
+ bufsize,
+ NULL,
+ NULL);
+
+ if (bufsize == 0) {
+ uv__free(*utf8);
+ *utf8 = NULL;
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ (*utf8)[bufsize] = '\0';
+ return 0;
+}
+
+
+/*
+ * Converts a UTF-8 string into a UTF-16 one. The resulting string is
+ * null-terminated.
+ *
+ * If utf8 is null terminated, utf8len can be set to -1, otherwise it must
+ * be specified.
+ */
+int uv__convert_utf8_to_utf16(const char* utf8, int utf8len, WCHAR** utf16) {
+ int bufsize;
+
+ if (utf8 == NULL)
+ return UV_EINVAL;
+
+ /* Check how much space we need */
+ bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, NULL, 0);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ /* Allocate the destination buffer adding an extra byte for the terminating
+ * NULL. If utf8len is not -1 MultiByteToWideChar will not add it, so
+ * we do it ourselves always, just in case. */
+ *utf16 = uv__malloc(sizeof(WCHAR) * (bufsize + 1));
+
+ if (*utf16 == NULL)
+ return UV_ENOMEM;
+
+ /* Convert to UTF-16 */
+ bufsize = MultiByteToWideChar(CP_UTF8, 0, utf8, utf8len, *utf16, bufsize);
+
+ if (bufsize == 0) {
+ uv__free(*utf16);
+ *utf16 = NULL;
+ return uv_translate_sys_error(GetLastError());
+ }
+
+ (*utf16)[bufsize] = '\0';
+ return 0;
+}
+
+
+int uv__getpwuid_r(uv_passwd_t* pwd) {
+ HANDLE token;
+ wchar_t username[UNLEN + 1];
+ wchar_t path[MAX_PATH];
+ DWORD bufsize;
+ int r;
+
+ if (pwd == NULL)
+ return UV_EINVAL;
+
+ /* Get the home directory using GetUserProfileDirectoryW() */
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_READ, &token) == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ bufsize = sizeof(path);
+ if (!GetUserProfileDirectoryW(token, path, &bufsize)) {
+ r = GetLastError();
+ CloseHandle(token);
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_ENOMEM;
+
+ return uv_translate_sys_error(r);
+ }
+
+ CloseHandle(token);
+
+ /* Get the username using GetUserNameW() */
+ bufsize = sizeof(username);
+ if (!GetUserNameW(username, &bufsize)) {
+ r = GetLastError();
+
+ /* This should not be possible */
+ if (r == ERROR_INSUFFICIENT_BUFFER)
+ return UV_ENOMEM;
+
+ return uv_translate_sys_error(r);
+ }
+
+ pwd->homedir = NULL;
+ r = uv__convert_utf16_to_utf8(path, -1, &pwd->homedir);
+
+ if (r != 0)
+ return r;
+
+ pwd->username = NULL;
+ r = uv__convert_utf16_to_utf8(username, -1, &pwd->username);
+
+ if (r != 0) {
+ uv__free(pwd->homedir);
+ return r;
+ }
+
+ pwd->shell = NULL;
+ pwd->uid = -1;
+ pwd->gid = -1;
+
+ return 0;
+}
+
+
+int uv_os_get_passwd(uv_passwd_t* pwd) {
+ return uv__getpwuid_r(pwd);
+}
+
+
+int uv_os_getenv(const char* name, char* buffer, size_t* size) {
+ wchar_t var[MAX_ENV_VAR_LENGTH];
+ wchar_t* name_w;
+ DWORD bufsize;
+ size_t len;
+ int r;
+
+ if (name == NULL || buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+ if (r != 0)
+ return r;
+
+ len = GetEnvironmentVariableW(name_w, var, MAX_ENV_VAR_LENGTH);
+ uv__free(name_w);
+ assert(len < MAX_ENV_VAR_LENGTH); /* len does not include the null */
+
+ if (len == 0) {
+ r = GetLastError();
+
+ if (r == ERROR_ENVVAR_NOT_FOUND)
+ return UV_ENOENT;
+
+ return uv_translate_sys_error(r);
+ }
+
+ /* Check how much space we need */
+ bufsize = WideCharToMultiByte(CP_UTF8, 0, var, -1, NULL, 0, NULL, NULL);
+
+ if (bufsize == 0) {
+ return uv_translate_sys_error(GetLastError());
+ } else if (bufsize > *size) {
+ *size = bufsize;
+ return UV_ENOBUFS;
+ }
+
+ /* Convert to UTF-8 */
+ bufsize = WideCharToMultiByte(CP_UTF8,
+ 0,
+ var,
+ -1,
+ buffer,
+ *size,
+ NULL,
+ NULL);
+
+ if (bufsize == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ *size = bufsize - 1;
+ return 0;
+}
+
+
+int uv_os_setenv(const char* name, const char* value) {
+ wchar_t* name_w;
+ wchar_t* value_w;
+ int r;
+
+ if (name == NULL || value == NULL)
+ return UV_EINVAL;
+
+ r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+ if (r != 0)
+ return r;
+
+ r = uv__convert_utf8_to_utf16(value, -1, &value_w);
+
+ if (r != 0) {
+ uv__free(name_w);
+ return r;
+ }
+
+ r = SetEnvironmentVariableW(name_w, value_w);
+ uv__free(name_w);
+ uv__free(value_w);
+
+ if (r == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ return 0;
+}
+
+
+int uv_os_unsetenv(const char* name) {
+ wchar_t* name_w;
+ int r;
+
+ if (name == NULL)
+ return UV_EINVAL;
+
+ r = uv__convert_utf8_to_utf16(name, -1, &name_w);
+
+ if (r != 0)
+ return r;
+
+ r = SetEnvironmentVariableW(name_w, NULL);
+ uv__free(name_w);
+
+ if (r == 0)
+ return uv_translate_sys_error(GetLastError());
+
+ return 0;
+}
+
+
+int uv_os_gethostname(char* buffer, size_t* size) {
+ char buf[MAXHOSTNAMELEN + 1];
+ size_t len;
+
+ if (buffer == NULL || size == NULL || *size == 0)
+ return UV_EINVAL;
+
+ uv__once_init(); /* Initialize winsock */
+
+ if (gethostname(buf, sizeof(buf)) != 0)
+ return uv_translate_sys_error(WSAGetLastError());
+
+ buf[sizeof(buf) - 1] = '\0'; /* Null terminate, just to be safe. */
+ len = strlen(buf);
+
+ if (len >= *size) {
+ *size = len + 1;
+ return UV_ENOBUFS;
+ }
+
+ memcpy(buffer, buf, len + 1);
+ *size = len;
+ return 0;
+}
diff --git a/Utilities/cmlibuv/src/win/winapi.c b/Utilities/cmlibuv/src/win/winapi.c
new file mode 100644
index 000000000..aa5d719fb
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/winapi.c
@@ -0,0 +1,159 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Ntdll function pointers */
+sRtlNtStatusToDosError pRtlNtStatusToDosError;
+sNtDeviceIoControlFile pNtDeviceIoControlFile;
+sNtQueryInformationFile pNtQueryInformationFile;
+sNtSetInformationFile pNtSetInformationFile;
+sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+sNtQueryDirectoryFile pNtQueryDirectoryFile;
+sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+sCreateSymbolicLinkW pCreateSymbolicLinkW;
+sCancelIoEx pCancelIoEx;
+sInitializeConditionVariable pInitializeConditionVariable;
+sSleepConditionVariableCS pSleepConditionVariableCS;
+sSleepConditionVariableSRW pSleepConditionVariableSRW;
+sWakeAllConditionVariable pWakeAllConditionVariable;
+sWakeConditionVariable pWakeConditionVariable;
+sCancelSynchronousIo pCancelSynchronousIo;
+sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+/* Powrprof.dll function pointer */
+sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+
+
+void uv_winapi_init(void) {
+ HMODULE ntdll_module;
+ HMODULE kernel32_module;
+ HMODULE powrprof_module;
+
+ ntdll_module = GetModuleHandleA("ntdll.dll");
+ if (ntdll_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pRtlNtStatusToDosError = (sRtlNtStatusToDosError) GetProcAddress(
+ ntdll_module,
+ "RtlNtStatusToDosError");
+ if (pRtlNtStatusToDosError == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtDeviceIoControlFile = (sNtDeviceIoControlFile) GetProcAddress(
+ ntdll_module,
+ "NtDeviceIoControlFile");
+ if (pNtDeviceIoControlFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryInformationFile = (sNtQueryInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtQueryInformationFile");
+ if (pNtQueryInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtSetInformationFile = (sNtSetInformationFile) GetProcAddress(
+ ntdll_module,
+ "NtSetInformationFile");
+ if (pNtSetInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryVolumeInformationFile = (sNtQueryVolumeInformationFile)
+ GetProcAddress(ntdll_module, "NtQueryVolumeInformationFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQueryDirectoryFile = (sNtQueryDirectoryFile)
+ GetProcAddress(ntdll_module, "NtQueryDirectoryFile");
+ if (pNtQueryVolumeInformationFile == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ pNtQuerySystemInformation = (sNtQuerySystemInformation) GetProcAddress(
+ ntdll_module,
+ "NtQuerySystemInformation");
+ if (pNtQuerySystemInformation == NULL) {
+ uv_fatal_error(GetLastError(), "GetProcAddress");
+ }
+
+ kernel32_module = GetModuleHandleA("kernel32.dll");
+ if (kernel32_module == NULL) {
+ uv_fatal_error(GetLastError(), "GetModuleHandleA");
+ }
+
+ pGetQueuedCompletionStatusEx = (sGetQueuedCompletionStatusEx) GetProcAddress(
+ kernel32_module,
+ "GetQueuedCompletionStatusEx");
+
+ pSetFileCompletionNotificationModes = (sSetFileCompletionNotificationModes)
+ GetProcAddress(kernel32_module, "SetFileCompletionNotificationModes");
+
+ pCreateSymbolicLinkW = (sCreateSymbolicLinkW)
+ GetProcAddress(kernel32_module, "CreateSymbolicLinkW");
+
+ pCancelIoEx = (sCancelIoEx)
+ GetProcAddress(kernel32_module, "CancelIoEx");
+
+ pInitializeConditionVariable = (sInitializeConditionVariable)
+ GetProcAddress(kernel32_module, "InitializeConditionVariable");
+
+ pSleepConditionVariableCS = (sSleepConditionVariableCS)
+ GetProcAddress(kernel32_module, "SleepConditionVariableCS");
+
+ pSleepConditionVariableSRW = (sSleepConditionVariableSRW)
+ GetProcAddress(kernel32_module, "SleepConditionVariableSRW");
+
+ pWakeAllConditionVariable = (sWakeAllConditionVariable)
+ GetProcAddress(kernel32_module, "WakeAllConditionVariable");
+
+ pWakeConditionVariable = (sWakeConditionVariable)
+ GetProcAddress(kernel32_module, "WakeConditionVariable");
+
+ pCancelSynchronousIo = (sCancelSynchronousIo)
+ GetProcAddress(kernel32_module, "CancelSynchronousIo");
+
+ pGetFinalPathNameByHandleW = (sGetFinalPathNameByHandleW)
+ GetProcAddress(kernel32_module, "GetFinalPathNameByHandleW");
+
+
+ powrprof_module = LoadLibraryA("powrprof.dll");
+ if (powrprof_module != NULL) {
+ pPowerRegisterSuspendResumeNotification = (sPowerRegisterSuspendResumeNotification)
+ GetProcAddress(powrprof_module, "PowerRegisterSuspendResumeNotification");
+ }
+
+}
diff --git a/Utilities/cmlibuv/src/win/winapi.h b/Utilities/cmlibuv/src/win/winapi.h
new file mode 100644
index 000000000..4b0eeca15
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/winapi.h
@@ -0,0 +1,4761 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINAPI_H_
+#define UV_WIN_WINAPI_H_
+
+#include <windows.h>
+
+
+/*
+ * Ntdll headers
+ */
+#ifndef STATUS_SEVERITY_SUCCESS
+# define STATUS_SEVERITY_SUCCESS 0x0
+#endif
+
+#ifndef STATUS_SEVERITY_INFORMATIONAL
+# define STATUS_SEVERITY_INFORMATIONAL 0x1
+#endif
+
+#ifndef STATUS_SEVERITY_WARNING
+# define STATUS_SEVERITY_WARNING 0x2
+#endif
+
+#ifndef STATUS_SEVERITY_ERROR
+# define STATUS_SEVERITY_ERROR 0x3
+#endif
+
+#ifndef FACILITY_NTWIN32
+# define FACILITY_NTWIN32 0x7
+#endif
+
+#ifndef NT_SUCCESS
+# define NT_SUCCESS(status) (((NTSTATUS) (status)) >= 0)
+#endif
+
+#ifndef NT_INFORMATION
+# define NT_INFORMATION(status) ((((ULONG) (status)) >> 30) == 1)
+#endif
+
+#ifndef NT_WARNING
+# define NT_WARNING(status) ((((ULONG) (status)) >> 30) == 2)
+#endif
+
+#ifndef NT_ERROR
+# define NT_ERROR(status) ((((ULONG) (status)) >> 30) == 3)
+#endif
+
+#ifndef STATUS_SUCCESS
+# define STATUS_SUCCESS ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_0
+# define STATUS_WAIT_0 ((NTSTATUS) 0x00000000L)
+#endif
+
+#ifndef STATUS_WAIT_1
+# define STATUS_WAIT_1 ((NTSTATUS) 0x00000001L)
+#endif
+
+#ifndef STATUS_WAIT_2
+# define STATUS_WAIT_2 ((NTSTATUS) 0x00000002L)
+#endif
+
+#ifndef STATUS_WAIT_3
+# define STATUS_WAIT_3 ((NTSTATUS) 0x00000003L)
+#endif
+
+#ifndef STATUS_WAIT_63
+# define STATUS_WAIT_63 ((NTSTATUS) 0x0000003FL)
+#endif
+
+#ifndef STATUS_ABANDONED
+# define STATUS_ABANDONED ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_0
+# define STATUS_ABANDONED_WAIT_0 ((NTSTATUS) 0x00000080L)
+#endif
+
+#ifndef STATUS_ABANDONED_WAIT_63
+# define STATUS_ABANDONED_WAIT_63 ((NTSTATUS) 0x000000BFL)
+#endif
+
+#ifndef STATUS_USER_APC
+# define STATUS_USER_APC ((NTSTATUS) 0x000000C0L)
+#endif
+
+#ifndef STATUS_KERNEL_APC
+# define STATUS_KERNEL_APC ((NTSTATUS) 0x00000100L)
+#endif
+
+#ifndef STATUS_ALERTED
+# define STATUS_ALERTED ((NTSTATUS) 0x00000101L)
+#endif
+
+#ifndef STATUS_TIMEOUT
+# define STATUS_TIMEOUT ((NTSTATUS) 0x00000102L)
+#endif
+
+#ifndef STATUS_PENDING
+# define STATUS_PENDING ((NTSTATUS) 0x00000103L)
+#endif
+
+#ifndef STATUS_REPARSE
+# define STATUS_REPARSE ((NTSTATUS) 0x00000104L)
+#endif
+
+#ifndef STATUS_MORE_ENTRIES
+# define STATUS_MORE_ENTRIES ((NTSTATUS) 0x00000105L)
+#endif
+
+#ifndef STATUS_NOT_ALL_ASSIGNED
+# define STATUS_NOT_ALL_ASSIGNED ((NTSTATUS) 0x00000106L)
+#endif
+
+#ifndef STATUS_SOME_NOT_MAPPED
+# define STATUS_SOME_NOT_MAPPED ((NTSTATUS) 0x00000107L)
+#endif
+
+#ifndef STATUS_OPLOCK_BREAK_IN_PROGRESS
+# define STATUS_OPLOCK_BREAK_IN_PROGRESS ((NTSTATUS) 0x00000108L)
+#endif
+
+#ifndef STATUS_VOLUME_MOUNTED
+# define STATUS_VOLUME_MOUNTED ((NTSTATUS) 0x00000109L)
+#endif
+
+#ifndef STATUS_RXACT_COMMITTED
+# define STATUS_RXACT_COMMITTED ((NTSTATUS) 0x0000010AL)
+#endif
+
+#ifndef STATUS_NOTIFY_CLEANUP
+# define STATUS_NOTIFY_CLEANUP ((NTSTATUS) 0x0000010BL)
+#endif
+
+#ifndef STATUS_NOTIFY_ENUM_DIR
+# define STATUS_NOTIFY_ENUM_DIR ((NTSTATUS) 0x0000010CL)
+#endif
+
+#ifndef STATUS_NO_QUOTAS_FOR_ACCOUNT
+# define STATUS_NO_QUOTAS_FOR_ACCOUNT ((NTSTATUS) 0x0000010DL)
+#endif
+
+#ifndef STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED
+# define STATUS_PRIMARY_TRANSPORT_CONNECT_FAILED ((NTSTATUS) 0x0000010EL)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_TRANSITION
+# define STATUS_PAGE_FAULT_TRANSITION ((NTSTATUS) 0x00000110L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_DEMAND_ZERO
+# define STATUS_PAGE_FAULT_DEMAND_ZERO ((NTSTATUS) 0x00000111L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_COPY_ON_WRITE
+# define STATUS_PAGE_FAULT_COPY_ON_WRITE ((NTSTATUS) 0x00000112L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_GUARD_PAGE
+# define STATUS_PAGE_FAULT_GUARD_PAGE ((NTSTATUS) 0x00000113L)
+#endif
+
+#ifndef STATUS_PAGE_FAULT_PAGING_FILE
+# define STATUS_PAGE_FAULT_PAGING_FILE ((NTSTATUS) 0x00000114L)
+#endif
+
+#ifndef STATUS_CACHE_PAGE_LOCKED
+# define STATUS_CACHE_PAGE_LOCKED ((NTSTATUS) 0x00000115L)
+#endif
+
+#ifndef STATUS_CRASH_DUMP
+# define STATUS_CRASH_DUMP ((NTSTATUS) 0x00000116L)
+#endif
+
+#ifndef STATUS_BUFFER_ALL_ZEROS
+# define STATUS_BUFFER_ALL_ZEROS ((NTSTATUS) 0x00000117L)
+#endif
+
+#ifndef STATUS_REPARSE_OBJECT
+# define STATUS_REPARSE_OBJECT ((NTSTATUS) 0x00000118L)
+#endif
+
+#ifndef STATUS_RESOURCE_REQUIREMENTS_CHANGED
+# define STATUS_RESOURCE_REQUIREMENTS_CHANGED ((NTSTATUS) 0x00000119L)
+#endif
+
+#ifndef STATUS_TRANSLATION_COMPLETE
+# define STATUS_TRANSLATION_COMPLETE ((NTSTATUS) 0x00000120L)
+#endif
+
+#ifndef STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY
+# define STATUS_DS_MEMBERSHIP_EVALUATED_LOCALLY ((NTSTATUS) 0x00000121L)
+#endif
+
+#ifndef STATUS_NOTHING_TO_TERMINATE
+# define STATUS_NOTHING_TO_TERMINATE ((NTSTATUS) 0x00000122L)
+#endif
+
+#ifndef STATUS_PROCESS_NOT_IN_JOB
+# define STATUS_PROCESS_NOT_IN_JOB ((NTSTATUS) 0x00000123L)
+#endif
+
+#ifndef STATUS_PROCESS_IN_JOB
+# define STATUS_PROCESS_IN_JOB ((NTSTATUS) 0x00000124L)
+#endif
+
+#ifndef STATUS_VOLSNAP_HIBERNATE_READY
+# define STATUS_VOLSNAP_HIBERNATE_READY ((NTSTATUS) 0x00000125L)
+#endif
+
+#ifndef STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY
+# define STATUS_FSFILTER_OP_COMPLETED_SUCCESSFULLY ((NTSTATUS) 0x00000126L)
+#endif
+
+#ifndef STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED
+# define STATUS_INTERRUPT_VECTOR_ALREADY_CONNECTED ((NTSTATUS) 0x00000127L)
+#endif
+
+#ifndef STATUS_INTERRUPT_STILL_CONNECTED
+# define STATUS_INTERRUPT_STILL_CONNECTED ((NTSTATUS) 0x00000128L)
+#endif
+
+#ifndef STATUS_PROCESS_CLONED
+# define STATUS_PROCESS_CLONED ((NTSTATUS) 0x00000129L)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_ONLY_READERS
+# define STATUS_FILE_LOCKED_WITH_ONLY_READERS ((NTSTATUS) 0x0000012AL)
+#endif
+
+#ifndef STATUS_FILE_LOCKED_WITH_WRITERS
+# define STATUS_FILE_LOCKED_WITH_WRITERS ((NTSTATUS) 0x0000012BL)
+#endif
+
+#ifndef STATUS_RESOURCEMANAGER_READ_ONLY
+# define STATUS_RESOURCEMANAGER_READ_ONLY ((NTSTATUS) 0x00000202L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_EMPTY
+# define STATUS_RING_PREVIOUSLY_EMPTY ((NTSTATUS) 0x00000210L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_FULL
+# define STATUS_RING_PREVIOUSLY_FULL ((NTSTATUS) 0x00000211L)
+#endif
+
+#ifndef STATUS_RING_PREVIOUSLY_ABOVE_QUOTA
+# define STATUS_RING_PREVIOUSLY_ABOVE_QUOTA ((NTSTATUS) 0x00000212L)
+#endif
+
+#ifndef STATUS_RING_NEWLY_EMPTY
+# define STATUS_RING_NEWLY_EMPTY ((NTSTATUS) 0x00000213L)
+#endif
+
+#ifndef STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT
+# define STATUS_RING_SIGNAL_OPPOSITE_ENDPOINT ((NTSTATUS) 0x00000214L)
+#endif
+
+#ifndef STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE
+# define STATUS_OPLOCK_SWITCHED_TO_NEW_HANDLE ((NTSTATUS) 0x00000215L)
+#endif
+
+#ifndef STATUS_OPLOCK_HANDLE_CLOSED
+# define STATUS_OPLOCK_HANDLE_CLOSED ((NTSTATUS) 0x00000216L)
+#endif
+
+#ifndef STATUS_WAIT_FOR_OPLOCK
+# define STATUS_WAIT_FOR_OPLOCK ((NTSTATUS) 0x00000367L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_EXISTS
+# define STATUS_OBJECT_NAME_EXISTS ((NTSTATUS) 0x40000000L)
+#endif
+
+#ifndef STATUS_THREAD_WAS_SUSPENDED
+# define STATUS_THREAD_WAS_SUSPENDED ((NTSTATUS) 0x40000001L)
+#endif
+
+#ifndef STATUS_WORKING_SET_LIMIT_RANGE
+# define STATUS_WORKING_SET_LIMIT_RANGE ((NTSTATUS) 0x40000002L)
+#endif
+
+#ifndef STATUS_IMAGE_NOT_AT_BASE
+# define STATUS_IMAGE_NOT_AT_BASE ((NTSTATUS) 0x40000003L)
+#endif
+
+#ifndef STATUS_RXACT_STATE_CREATED
+# define STATUS_RXACT_STATE_CREATED ((NTSTATUS) 0x40000004L)
+#endif
+
+#ifndef STATUS_SEGMENT_NOTIFICATION
+# define STATUS_SEGMENT_NOTIFICATION ((NTSTATUS) 0x40000005L)
+#endif
+
+#ifndef STATUS_LOCAL_USER_SESSION_KEY
+# define STATUS_LOCAL_USER_SESSION_KEY ((NTSTATUS) 0x40000006L)
+#endif
+
+#ifndef STATUS_BAD_CURRENT_DIRECTORY
+# define STATUS_BAD_CURRENT_DIRECTORY ((NTSTATUS) 0x40000007L)
+#endif
+
+#ifndef STATUS_SERIAL_MORE_WRITES
+# define STATUS_SERIAL_MORE_WRITES ((NTSTATUS) 0x40000008L)
+#endif
+
+#ifndef STATUS_REGISTRY_RECOVERED
+# define STATUS_REGISTRY_RECOVERED ((NTSTATUS) 0x40000009L)
+#endif
+
+#ifndef STATUS_FT_READ_RECOVERY_FROM_BACKUP
+# define STATUS_FT_READ_RECOVERY_FROM_BACKUP ((NTSTATUS) 0x4000000AL)
+#endif
+
+#ifndef STATUS_FT_WRITE_RECOVERY
+# define STATUS_FT_WRITE_RECOVERY ((NTSTATUS) 0x4000000BL)
+#endif
+
+#ifndef STATUS_SERIAL_COUNTER_TIMEOUT
+# define STATUS_SERIAL_COUNTER_TIMEOUT ((NTSTATUS) 0x4000000CL)
+#endif
+
+#ifndef STATUS_NULL_LM_PASSWORD
+# define STATUS_NULL_LM_PASSWORD ((NTSTATUS) 0x4000000DL)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH ((NTSTATUS) 0x4000000EL)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL
+# define STATUS_RECEIVE_PARTIAL ((NTSTATUS) 0x4000000FL)
+#endif
+
+#ifndef STATUS_RECEIVE_EXPEDITED
+# define STATUS_RECEIVE_EXPEDITED ((NTSTATUS) 0x40000010L)
+#endif
+
+#ifndef STATUS_RECEIVE_PARTIAL_EXPEDITED
+# define STATUS_RECEIVE_PARTIAL_EXPEDITED ((NTSTATUS) 0x40000011L)
+#endif
+
+#ifndef STATUS_EVENT_DONE
+# define STATUS_EVENT_DONE ((NTSTATUS) 0x40000012L)
+#endif
+
+#ifndef STATUS_EVENT_PENDING
+# define STATUS_EVENT_PENDING ((NTSTATUS) 0x40000013L)
+#endif
+
+#ifndef STATUS_CHECKING_FILE_SYSTEM
+# define STATUS_CHECKING_FILE_SYSTEM ((NTSTATUS) 0x40000014L)
+#endif
+
+#ifndef STATUS_FATAL_APP_EXIT
+# define STATUS_FATAL_APP_EXIT ((NTSTATUS) 0x40000015L)
+#endif
+
+#ifndef STATUS_PREDEFINED_HANDLE
+# define STATUS_PREDEFINED_HANDLE ((NTSTATUS) 0x40000016L)
+#endif
+
+#ifndef STATUS_WAS_UNLOCKED
+# define STATUS_WAS_UNLOCKED ((NTSTATUS) 0x40000017L)
+#endif
+
+#ifndef STATUS_SERVICE_NOTIFICATION
+# define STATUS_SERVICE_NOTIFICATION ((NTSTATUS) 0x40000018L)
+#endif
+
+#ifndef STATUS_WAS_LOCKED
+# define STATUS_WAS_LOCKED ((NTSTATUS) 0x40000019L)
+#endif
+
+#ifndef STATUS_LOG_HARD_ERROR
+# define STATUS_LOG_HARD_ERROR ((NTSTATUS) 0x4000001AL)
+#endif
+
+#ifndef STATUS_ALREADY_WIN32
+# define STATUS_ALREADY_WIN32 ((NTSTATUS) 0x4000001BL)
+#endif
+
+#ifndef STATUS_WX86_UNSIMULATE
+# define STATUS_WX86_UNSIMULATE ((NTSTATUS) 0x4000001CL)
+#endif
+
+#ifndef STATUS_WX86_CONTINUE
+# define STATUS_WX86_CONTINUE ((NTSTATUS) 0x4000001DL)
+#endif
+
+#ifndef STATUS_WX86_SINGLE_STEP
+# define STATUS_WX86_SINGLE_STEP ((NTSTATUS) 0x4000001EL)
+#endif
+
+#ifndef STATUS_WX86_BREAKPOINT
+# define STATUS_WX86_BREAKPOINT ((NTSTATUS) 0x4000001FL)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CONTINUE
+# define STATUS_WX86_EXCEPTION_CONTINUE ((NTSTATUS) 0x40000020L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_LASTCHANCE
+# define STATUS_WX86_EXCEPTION_LASTCHANCE ((NTSTATUS) 0x40000021L)
+#endif
+
+#ifndef STATUS_WX86_EXCEPTION_CHAIN
+# define STATUS_WX86_EXCEPTION_CHAIN ((NTSTATUS) 0x40000022L)
+#endif
+
+#ifndef STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE
+# define STATUS_IMAGE_MACHINE_TYPE_MISMATCH_EXE ((NTSTATUS) 0x40000023L)
+#endif
+
+#ifndef STATUS_NO_YIELD_PERFORMED
+# define STATUS_NO_YIELD_PERFORMED ((NTSTATUS) 0x40000024L)
+#endif
+
+#ifndef STATUS_TIMER_RESUME_IGNORED
+# define STATUS_TIMER_RESUME_IGNORED ((NTSTATUS) 0x40000025L)
+#endif
+
+#ifndef STATUS_ARBITRATION_UNHANDLED
+# define STATUS_ARBITRATION_UNHANDLED ((NTSTATUS) 0x40000026L)
+#endif
+
+#ifndef STATUS_CARDBUS_NOT_SUPPORTED
+# define STATUS_CARDBUS_NOT_SUPPORTED ((NTSTATUS) 0x40000027L)
+#endif
+
+#ifndef STATUS_WX86_CREATEWX86TIB
+# define STATUS_WX86_CREATEWX86TIB ((NTSTATUS) 0x40000028L)
+#endif
+
+#ifndef STATUS_MP_PROCESSOR_MISMATCH
+# define STATUS_MP_PROCESSOR_MISMATCH ((NTSTATUS) 0x40000029L)
+#endif
+
+#ifndef STATUS_HIBERNATED
+# define STATUS_HIBERNATED ((NTSTATUS) 0x4000002AL)
+#endif
+
+#ifndef STATUS_RESUME_HIBERNATION
+# define STATUS_RESUME_HIBERNATION ((NTSTATUS) 0x4000002BL)
+#endif
+
+#ifndef STATUS_FIRMWARE_UPDATED
+# define STATUS_FIRMWARE_UPDATED ((NTSTATUS) 0x4000002CL)
+#endif
+
+#ifndef STATUS_DRIVERS_LEAKING_LOCKED_PAGES
+# define STATUS_DRIVERS_LEAKING_LOCKED_PAGES ((NTSTATUS) 0x4000002DL)
+#endif
+
+#ifndef STATUS_MESSAGE_RETRIEVED
+# define STATUS_MESSAGE_RETRIEVED ((NTSTATUS) 0x4000002EL)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_TRANSITION ((NTSTATUS) 0x4000002FL)
+#endif
+
+#ifndef STATUS_ALPC_CHECK_COMPLETION_LIST
+# define STATUS_ALPC_CHECK_COMPLETION_LIST ((NTSTATUS) 0x40000030L)
+#endif
+
+#ifndef STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION
+# define STATUS_SYSTEM_POWERSTATE_COMPLEX_TRANSITION ((NTSTATUS) 0x40000031L)
+#endif
+
+#ifndef STATUS_ACCESS_AUDIT_BY_POLICY
+# define STATUS_ACCESS_AUDIT_BY_POLICY ((NTSTATUS) 0x40000032L)
+#endif
+
+#ifndef STATUS_ABANDON_HIBERFILE
+# define STATUS_ABANDON_HIBERFILE ((NTSTATUS) 0x40000033L)
+#endif
+
+#ifndef STATUS_BIZRULES_NOT_ENABLED
+# define STATUS_BIZRULES_NOT_ENABLED ((NTSTATUS) 0x40000034L)
+#endif
+
+#ifndef STATUS_GUARD_PAGE_VIOLATION
+# define STATUS_GUARD_PAGE_VIOLATION ((NTSTATUS) 0x80000001L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT
+# define STATUS_DATATYPE_MISALIGNMENT ((NTSTATUS) 0x80000002L)
+#endif
+
+#ifndef STATUS_BREAKPOINT
+# define STATUS_BREAKPOINT ((NTSTATUS) 0x80000003L)
+#endif
+
+#ifndef STATUS_SINGLE_STEP
+# define STATUS_SINGLE_STEP ((NTSTATUS) 0x80000004L)
+#endif
+
+#ifndef STATUS_BUFFER_OVERFLOW
+# define STATUS_BUFFER_OVERFLOW ((NTSTATUS) 0x80000005L)
+#endif
+
+#ifndef STATUS_NO_MORE_FILES
+# define STATUS_NO_MORE_FILES ((NTSTATUS) 0x80000006L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM_DEBUGGER
+# define STATUS_WAKE_SYSTEM_DEBUGGER ((NTSTATUS) 0x80000007L)
+#endif
+
+#ifndef STATUS_HANDLES_CLOSED
+# define STATUS_HANDLES_CLOSED ((NTSTATUS) 0x8000000AL)
+#endif
+
+#ifndef STATUS_NO_INHERITANCE
+# define STATUS_NO_INHERITANCE ((NTSTATUS) 0x8000000BL)
+#endif
+
+#ifndef STATUS_GUID_SUBSTITUTION_MADE
+# define STATUS_GUID_SUBSTITUTION_MADE ((NTSTATUS) 0x8000000CL)
+#endif
+
+#ifndef STATUS_PARTIAL_COPY
+# define STATUS_PARTIAL_COPY ((NTSTATUS) 0x8000000DL)
+#endif
+
+#ifndef STATUS_DEVICE_PAPER_EMPTY
+# define STATUS_DEVICE_PAPER_EMPTY ((NTSTATUS) 0x8000000EL)
+#endif
+
+#ifndef STATUS_DEVICE_POWERED_OFF
+# define STATUS_DEVICE_POWERED_OFF ((NTSTATUS) 0x8000000FL)
+#endif
+
+#ifndef STATUS_DEVICE_OFF_LINE
+# define STATUS_DEVICE_OFF_LINE ((NTSTATUS) 0x80000010L)
+#endif
+
+#ifndef STATUS_DEVICE_BUSY
+# define STATUS_DEVICE_BUSY ((NTSTATUS) 0x80000011L)
+#endif
+
+#ifndef STATUS_NO_MORE_EAS
+# define STATUS_NO_MORE_EAS ((NTSTATUS) 0x80000012L)
+#endif
+
+#ifndef STATUS_INVALID_EA_NAME
+# define STATUS_INVALID_EA_NAME ((NTSTATUS) 0x80000013L)
+#endif
+
+#ifndef STATUS_EA_LIST_INCONSISTENT
+# define STATUS_EA_LIST_INCONSISTENT ((NTSTATUS) 0x80000014L)
+#endif
+
+#ifndef STATUS_INVALID_EA_FLAG
+# define STATUS_INVALID_EA_FLAG ((NTSTATUS) 0x80000015L)
+#endif
+
+#ifndef STATUS_VERIFY_REQUIRED
+# define STATUS_VERIFY_REQUIRED ((NTSTATUS) 0x80000016L)
+#endif
+
+#ifndef STATUS_EXTRANEOUS_INFORMATION
+# define STATUS_EXTRANEOUS_INFORMATION ((NTSTATUS) 0x80000017L)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_NECESSARY
+# define STATUS_RXACT_COMMIT_NECESSARY ((NTSTATUS) 0x80000018L)
+#endif
+
+#ifndef STATUS_NO_MORE_ENTRIES
+# define STATUS_NO_MORE_ENTRIES ((NTSTATUS) 0x8000001AL)
+#endif
+
+#ifndef STATUS_FILEMARK_DETECTED
+# define STATUS_FILEMARK_DETECTED ((NTSTATUS) 0x8000001BL)
+#endif
+
+#ifndef STATUS_MEDIA_CHANGED
+# define STATUS_MEDIA_CHANGED ((NTSTATUS) 0x8000001CL)
+#endif
+
+#ifndef STATUS_BUS_RESET
+# define STATUS_BUS_RESET ((NTSTATUS) 0x8000001DL)
+#endif
+
+#ifndef STATUS_END_OF_MEDIA
+# define STATUS_END_OF_MEDIA ((NTSTATUS) 0x8000001EL)
+#endif
+
+#ifndef STATUS_BEGINNING_OF_MEDIA
+# define STATUS_BEGINNING_OF_MEDIA ((NTSTATUS) 0x8000001FL)
+#endif
+
+#ifndef STATUS_MEDIA_CHECK
+# define STATUS_MEDIA_CHECK ((NTSTATUS) 0x80000020L)
+#endif
+
+#ifndef STATUS_SETMARK_DETECTED
+# define STATUS_SETMARK_DETECTED ((NTSTATUS) 0x80000021L)
+#endif
+
+#ifndef STATUS_NO_DATA_DETECTED
+# define STATUS_NO_DATA_DETECTED ((NTSTATUS) 0x80000022L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_HAS_OPEN_HANDLES
+# define STATUS_REDIRECTOR_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000023L)
+#endif
+
+#ifndef STATUS_SERVER_HAS_OPEN_HANDLES
+# define STATUS_SERVER_HAS_OPEN_HANDLES ((NTSTATUS) 0x80000024L)
+#endif
+
+#ifndef STATUS_ALREADY_DISCONNECTED
+# define STATUS_ALREADY_DISCONNECTED ((NTSTATUS) 0x80000025L)
+#endif
+
+#ifndef STATUS_LONGJUMP
+# define STATUS_LONGJUMP ((NTSTATUS) 0x80000026L)
+#endif
+
+#ifndef STATUS_CLEANER_CARTRIDGE_INSTALLED
+# define STATUS_CLEANER_CARTRIDGE_INSTALLED ((NTSTATUS) 0x80000027L)
+#endif
+
+#ifndef STATUS_PLUGPLAY_QUERY_VETOED
+# define STATUS_PLUGPLAY_QUERY_VETOED ((NTSTATUS) 0x80000028L)
+#endif
+
+#ifndef STATUS_UNWIND_CONSOLIDATE
+# define STATUS_UNWIND_CONSOLIDATE ((NTSTATUS) 0x80000029L)
+#endif
+
+#ifndef STATUS_REGISTRY_HIVE_RECOVERED
+# define STATUS_REGISTRY_HIVE_RECOVERED ((NTSTATUS) 0x8000002AL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INSECURE
+# define STATUS_DLL_MIGHT_BE_INSECURE ((NTSTATUS) 0x8000002BL)
+#endif
+
+#ifndef STATUS_DLL_MIGHT_BE_INCOMPATIBLE
+# define STATUS_DLL_MIGHT_BE_INCOMPATIBLE ((NTSTATUS) 0x8000002CL)
+#endif
+
+#ifndef STATUS_STOPPED_ON_SYMLINK
+# define STATUS_STOPPED_ON_SYMLINK ((NTSTATUS) 0x8000002DL)
+#endif
+
+#ifndef STATUS_CANNOT_GRANT_REQUESTED_OPLOCK
+# define STATUS_CANNOT_GRANT_REQUESTED_OPLOCK ((NTSTATUS) 0x8000002EL)
+#endif
+
+#ifndef STATUS_NO_ACE_CONDITION
+# define STATUS_NO_ACE_CONDITION ((NTSTATUS) 0x8000002FL)
+#endif
+
+#ifndef STATUS_UNSUCCESSFUL
+# define STATUS_UNSUCCESSFUL ((NTSTATUS) 0xC0000001L)
+#endif
+
+#ifndef STATUS_NOT_IMPLEMENTED
+# define STATUS_NOT_IMPLEMENTED ((NTSTATUS) 0xC0000002L)
+#endif
+
+#ifndef STATUS_INVALID_INFO_CLASS
+# define STATUS_INVALID_INFO_CLASS ((NTSTATUS) 0xC0000003L)
+#endif
+
+#ifndef STATUS_INFO_LENGTH_MISMATCH
+# define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xC0000004L)
+#endif
+
+#ifndef STATUS_ACCESS_VIOLATION
+# define STATUS_ACCESS_VIOLATION ((NTSTATUS) 0xC0000005L)
+#endif
+
+#ifndef STATUS_IN_PAGE_ERROR
+# define STATUS_IN_PAGE_ERROR ((NTSTATUS) 0xC0000006L)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA
+# define STATUS_PAGEFILE_QUOTA ((NTSTATUS) 0xC0000007L)
+#endif
+
+#ifndef STATUS_INVALID_HANDLE
+# define STATUS_INVALID_HANDLE ((NTSTATUS) 0xC0000008L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_STACK
+# define STATUS_BAD_INITIAL_STACK ((NTSTATUS) 0xC0000009L)
+#endif
+
+#ifndef STATUS_BAD_INITIAL_PC
+# define STATUS_BAD_INITIAL_PC ((NTSTATUS) 0xC000000AL)
+#endif
+
+#ifndef STATUS_INVALID_CID
+# define STATUS_INVALID_CID ((NTSTATUS) 0xC000000BL)
+#endif
+
+#ifndef STATUS_TIMER_NOT_CANCELED
+# define STATUS_TIMER_NOT_CANCELED ((NTSTATUS) 0xC000000CL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER
+# define STATUS_INVALID_PARAMETER ((NTSTATUS) 0xC000000DL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DEVICE
+# define STATUS_NO_SUCH_DEVICE ((NTSTATUS) 0xC000000EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_FILE
+# define STATUS_NO_SUCH_FILE ((NTSTATUS) 0xC000000FL)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_REQUEST
+# define STATUS_INVALID_DEVICE_REQUEST ((NTSTATUS) 0xC0000010L)
+#endif
+
+#ifndef STATUS_END_OF_FILE
+# define STATUS_END_OF_FILE ((NTSTATUS) 0xC0000011L)
+#endif
+
+#ifndef STATUS_WRONG_VOLUME
+# define STATUS_WRONG_VOLUME ((NTSTATUS) 0xC0000012L)
+#endif
+
+#ifndef STATUS_NO_MEDIA_IN_DEVICE
+# define STATUS_NO_MEDIA_IN_DEVICE ((NTSTATUS) 0xC0000013L)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_MEDIA
+# define STATUS_UNRECOGNIZED_MEDIA ((NTSTATUS) 0xC0000014L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_SECTOR
+# define STATUS_NONEXISTENT_SECTOR ((NTSTATUS) 0xC0000015L)
+#endif
+
+#ifndef STATUS_MORE_PROCESSING_REQUIRED
+# define STATUS_MORE_PROCESSING_REQUIRED ((NTSTATUS) 0xC0000016L)
+#endif
+
+#ifndef STATUS_NO_MEMORY
+# define STATUS_NO_MEMORY ((NTSTATUS) 0xC0000017L)
+#endif
+
+#ifndef STATUS_CONFLICTING_ADDRESSES
+# define STATUS_CONFLICTING_ADDRESSES ((NTSTATUS) 0xC0000018L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_VIEW
+# define STATUS_NOT_MAPPED_VIEW ((NTSTATUS) 0xC0000019L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_FREE_VM
+# define STATUS_UNABLE_TO_FREE_VM ((NTSTATUS) 0xC000001AL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DELETE_SECTION
+# define STATUS_UNABLE_TO_DELETE_SECTION ((NTSTATUS) 0xC000001BL)
+#endif
+
+#ifndef STATUS_INVALID_SYSTEM_SERVICE
+# define STATUS_INVALID_SYSTEM_SERVICE ((NTSTATUS) 0xC000001CL)
+#endif
+
+#ifndef STATUS_ILLEGAL_INSTRUCTION
+# define STATUS_ILLEGAL_INSTRUCTION ((NTSTATUS) 0xC000001DL)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_SEQUENCE
+# define STATUS_INVALID_LOCK_SEQUENCE ((NTSTATUS) 0xC000001EL)
+#endif
+
+#ifndef STATUS_INVALID_VIEW_SIZE
+# define STATUS_INVALID_VIEW_SIZE ((NTSTATUS) 0xC000001FL)
+#endif
+
+#ifndef STATUS_INVALID_FILE_FOR_SECTION
+# define STATUS_INVALID_FILE_FOR_SECTION ((NTSTATUS) 0xC0000020L)
+#endif
+
+#ifndef STATUS_ALREADY_COMMITTED
+# define STATUS_ALREADY_COMMITTED ((NTSTATUS) 0xC0000021L)
+#endif
+
+#ifndef STATUS_ACCESS_DENIED
+# define STATUS_ACCESS_DENIED ((NTSTATUS) 0xC0000022L)
+#endif
+
+#ifndef STATUS_BUFFER_TOO_SMALL
+# define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xC0000023L)
+#endif
+
+#ifndef STATUS_OBJECT_TYPE_MISMATCH
+# define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS) 0xC0000024L)
+#endif
+
+#ifndef STATUS_NONCONTINUABLE_EXCEPTION
+# define STATUS_NONCONTINUABLE_EXCEPTION ((NTSTATUS) 0xC0000025L)
+#endif
+
+#ifndef STATUS_INVALID_DISPOSITION
+# define STATUS_INVALID_DISPOSITION ((NTSTATUS) 0xC0000026L)
+#endif
+
+#ifndef STATUS_UNWIND
+# define STATUS_UNWIND ((NTSTATUS) 0xC0000027L)
+#endif
+
+#ifndef STATUS_BAD_STACK
+# define STATUS_BAD_STACK ((NTSTATUS) 0xC0000028L)
+#endif
+
+#ifndef STATUS_INVALID_UNWIND_TARGET
+# define STATUS_INVALID_UNWIND_TARGET ((NTSTATUS) 0xC0000029L)
+#endif
+
+#ifndef STATUS_NOT_LOCKED
+# define STATUS_NOT_LOCKED ((NTSTATUS) 0xC000002AL)
+#endif
+
+#ifndef STATUS_PARITY_ERROR
+# define STATUS_PARITY_ERROR ((NTSTATUS) 0xC000002BL)
+#endif
+
+#ifndef STATUS_UNABLE_TO_DECOMMIT_VM
+# define STATUS_UNABLE_TO_DECOMMIT_VM ((NTSTATUS) 0xC000002CL)
+#endif
+
+#ifndef STATUS_NOT_COMMITTED
+# define STATUS_NOT_COMMITTED ((NTSTATUS) 0xC000002DL)
+#endif
+
+#ifndef STATUS_INVALID_PORT_ATTRIBUTES
+# define STATUS_INVALID_PORT_ATTRIBUTES ((NTSTATUS) 0xC000002EL)
+#endif
+
+#ifndef STATUS_PORT_MESSAGE_TOO_LONG
+# define STATUS_PORT_MESSAGE_TOO_LONG ((NTSTATUS) 0xC000002FL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_MIX
+# define STATUS_INVALID_PARAMETER_MIX ((NTSTATUS) 0xC0000030L)
+#endif
+
+#ifndef STATUS_INVALID_QUOTA_LOWER
+# define STATUS_INVALID_QUOTA_LOWER ((NTSTATUS) 0xC0000031L)
+#endif
+
+#ifndef STATUS_DISK_CORRUPT_ERROR
+# define STATUS_DISK_CORRUPT_ERROR ((NTSTATUS) 0xC0000032L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_INVALID
+# define STATUS_OBJECT_NAME_INVALID ((NTSTATUS) 0xC0000033L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_NOT_FOUND
+# define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS) 0xC0000034L)
+#endif
+
+#ifndef STATUS_OBJECT_NAME_COLLISION
+# define STATUS_OBJECT_NAME_COLLISION ((NTSTATUS) 0xC0000035L)
+#endif
+
+#ifndef STATUS_PORT_DISCONNECTED
+# define STATUS_PORT_DISCONNECTED ((NTSTATUS) 0xC0000037L)
+#endif
+
+#ifndef STATUS_DEVICE_ALREADY_ATTACHED
+# define STATUS_DEVICE_ALREADY_ATTACHED ((NTSTATUS) 0xC0000038L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_INVALID
+# define STATUS_OBJECT_PATH_INVALID ((NTSTATUS) 0xC0000039L)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_NOT_FOUND
+# define STATUS_OBJECT_PATH_NOT_FOUND ((NTSTATUS) 0xC000003AL)
+#endif
+
+#ifndef STATUS_OBJECT_PATH_SYNTAX_BAD
+# define STATUS_OBJECT_PATH_SYNTAX_BAD ((NTSTATUS) 0xC000003BL)
+#endif
+
+#ifndef STATUS_DATA_OVERRUN
+# define STATUS_DATA_OVERRUN ((NTSTATUS) 0xC000003CL)
+#endif
+
+#ifndef STATUS_DATA_LATE_ERROR
+# define STATUS_DATA_LATE_ERROR ((NTSTATUS) 0xC000003DL)
+#endif
+
+#ifndef STATUS_DATA_ERROR
+# define STATUS_DATA_ERROR ((NTSTATUS) 0xC000003EL)
+#endif
+
+#ifndef STATUS_CRC_ERROR
+# define STATUS_CRC_ERROR ((NTSTATUS) 0xC000003FL)
+#endif
+
+#ifndef STATUS_SECTION_TOO_BIG
+# define STATUS_SECTION_TOO_BIG ((NTSTATUS) 0xC0000040L)
+#endif
+
+#ifndef STATUS_PORT_CONNECTION_REFUSED
+# define STATUS_PORT_CONNECTION_REFUSED ((NTSTATUS) 0xC0000041L)
+#endif
+
+#ifndef STATUS_INVALID_PORT_HANDLE
+# define STATUS_INVALID_PORT_HANDLE ((NTSTATUS) 0xC0000042L)
+#endif
+
+#ifndef STATUS_SHARING_VIOLATION
+# define STATUS_SHARING_VIOLATION ((NTSTATUS) 0xC0000043L)
+#endif
+
+#ifndef STATUS_QUOTA_EXCEEDED
+# define STATUS_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000044L)
+#endif
+
+#ifndef STATUS_INVALID_PAGE_PROTECTION
+# define STATUS_INVALID_PAGE_PROTECTION ((NTSTATUS) 0xC0000045L)
+#endif
+
+#ifndef STATUS_MUTANT_NOT_OWNED
+# define STATUS_MUTANT_NOT_OWNED ((NTSTATUS) 0xC0000046L)
+#endif
+
+#ifndef STATUS_SEMAPHORE_LIMIT_EXCEEDED
+# define STATUS_SEMAPHORE_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000047L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_SET
+# define STATUS_PORT_ALREADY_SET ((NTSTATUS) 0xC0000048L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_IMAGE
+# define STATUS_SECTION_NOT_IMAGE ((NTSTATUS) 0xC0000049L)
+#endif
+
+#ifndef STATUS_SUSPEND_COUNT_EXCEEDED
+# define STATUS_SUSPEND_COUNT_EXCEEDED ((NTSTATUS) 0xC000004AL)
+#endif
+
+#ifndef STATUS_THREAD_IS_TERMINATING
+# define STATUS_THREAD_IS_TERMINATING ((NTSTATUS) 0xC000004BL)
+#endif
+
+#ifndef STATUS_BAD_WORKING_SET_LIMIT
+# define STATUS_BAD_WORKING_SET_LIMIT ((NTSTATUS) 0xC000004CL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_FILE_MAP
+# define STATUS_INCOMPATIBLE_FILE_MAP ((NTSTATUS) 0xC000004DL)
+#endif
+
+#ifndef STATUS_SECTION_PROTECTION
+# define STATUS_SECTION_PROTECTION ((NTSTATUS) 0xC000004EL)
+#endif
+
+#ifndef STATUS_EAS_NOT_SUPPORTED
+# define STATUS_EAS_NOT_SUPPORTED ((NTSTATUS) 0xC000004FL)
+#endif
+
+#ifndef STATUS_EA_TOO_LARGE
+# define STATUS_EA_TOO_LARGE ((NTSTATUS) 0xC0000050L)
+#endif
+
+#ifndef STATUS_NONEXISTENT_EA_ENTRY
+# define STATUS_NONEXISTENT_EA_ENTRY ((NTSTATUS) 0xC0000051L)
+#endif
+
+#ifndef STATUS_NO_EAS_ON_FILE
+# define STATUS_NO_EAS_ON_FILE ((NTSTATUS) 0xC0000052L)
+#endif
+
+#ifndef STATUS_EA_CORRUPT_ERROR
+# define STATUS_EA_CORRUPT_ERROR ((NTSTATUS) 0xC0000053L)
+#endif
+
+#ifndef STATUS_FILE_LOCK_CONFLICT
+# define STATUS_FILE_LOCK_CONFLICT ((NTSTATUS) 0xC0000054L)
+#endif
+
+#ifndef STATUS_LOCK_NOT_GRANTED
+# define STATUS_LOCK_NOT_GRANTED ((NTSTATUS) 0xC0000055L)
+#endif
+
+#ifndef STATUS_DELETE_PENDING
+# define STATUS_DELETE_PENDING ((NTSTATUS) 0xC0000056L)
+#endif
+
+#ifndef STATUS_CTL_FILE_NOT_SUPPORTED
+# define STATUS_CTL_FILE_NOT_SUPPORTED ((NTSTATUS) 0xC0000057L)
+#endif
+
+#ifndef STATUS_UNKNOWN_REVISION
+# define STATUS_UNKNOWN_REVISION ((NTSTATUS) 0xC0000058L)
+#endif
+
+#ifndef STATUS_REVISION_MISMATCH
+# define STATUS_REVISION_MISMATCH ((NTSTATUS) 0xC0000059L)
+#endif
+
+#ifndef STATUS_INVALID_OWNER
+# define STATUS_INVALID_OWNER ((NTSTATUS) 0xC000005AL)
+#endif
+
+#ifndef STATUS_INVALID_PRIMARY_GROUP
+# define STATUS_INVALID_PRIMARY_GROUP ((NTSTATUS) 0xC000005BL)
+#endif
+
+#ifndef STATUS_NO_IMPERSONATION_TOKEN
+# define STATUS_NO_IMPERSONATION_TOKEN ((NTSTATUS) 0xC000005CL)
+#endif
+
+#ifndef STATUS_CANT_DISABLE_MANDATORY
+# define STATUS_CANT_DISABLE_MANDATORY ((NTSTATUS) 0xC000005DL)
+#endif
+
+#ifndef STATUS_NO_LOGON_SERVERS
+# define STATUS_NO_LOGON_SERVERS ((NTSTATUS) 0xC000005EL)
+#endif
+
+#ifndef STATUS_NO_SUCH_LOGON_SESSION
+# define STATUS_NO_SUCH_LOGON_SESSION ((NTSTATUS) 0xC000005FL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PRIVILEGE
+# define STATUS_NO_SUCH_PRIVILEGE ((NTSTATUS) 0xC0000060L)
+#endif
+
+#ifndef STATUS_PRIVILEGE_NOT_HELD
+# define STATUS_PRIVILEGE_NOT_HELD ((NTSTATUS) 0xC0000061L)
+#endif
+
+#ifndef STATUS_INVALID_ACCOUNT_NAME
+# define STATUS_INVALID_ACCOUNT_NAME ((NTSTATUS) 0xC0000062L)
+#endif
+
+#ifndef STATUS_USER_EXISTS
+# define STATUS_USER_EXISTS ((NTSTATUS) 0xC0000063L)
+#endif
+
+#ifndef STATUS_NO_SUCH_USER
+# define STATUS_NO_SUCH_USER ((NTSTATUS) 0xC0000064L)
+#endif
+
+#ifndef STATUS_GROUP_EXISTS
+# define STATUS_GROUP_EXISTS ((NTSTATUS) 0xC0000065L)
+#endif
+
+#ifndef STATUS_NO_SUCH_GROUP
+# define STATUS_NO_SUCH_GROUP ((NTSTATUS) 0xC0000066L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_GROUP
+# define STATUS_MEMBER_IN_GROUP ((NTSTATUS) 0xC0000067L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_GROUP
+# define STATUS_MEMBER_NOT_IN_GROUP ((NTSTATUS) 0xC0000068L)
+#endif
+
+#ifndef STATUS_LAST_ADMIN
+# define STATUS_LAST_ADMIN ((NTSTATUS) 0xC0000069L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD
+# define STATUS_WRONG_PASSWORD ((NTSTATUS) 0xC000006AL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_PASSWORD
+# define STATUS_ILL_FORMED_PASSWORD ((NTSTATUS) 0xC000006BL)
+#endif
+
+#ifndef STATUS_PASSWORD_RESTRICTION
+# define STATUS_PASSWORD_RESTRICTION ((NTSTATUS) 0xC000006CL)
+#endif
+
+#ifndef STATUS_LOGON_FAILURE
+# define STATUS_LOGON_FAILURE ((NTSTATUS) 0xC000006DL)
+#endif
+
+#ifndef STATUS_ACCOUNT_RESTRICTION
+# define STATUS_ACCOUNT_RESTRICTION ((NTSTATUS) 0xC000006EL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_HOURS
+# define STATUS_INVALID_LOGON_HOURS ((NTSTATUS) 0xC000006FL)
+#endif
+
+#ifndef STATUS_INVALID_WORKSTATION
+# define STATUS_INVALID_WORKSTATION ((NTSTATUS) 0xC0000070L)
+#endif
+
+#ifndef STATUS_PASSWORD_EXPIRED
+# define STATUS_PASSWORD_EXPIRED ((NTSTATUS) 0xC0000071L)
+#endif
+
+#ifndef STATUS_ACCOUNT_DISABLED
+# define STATUS_ACCOUNT_DISABLED ((NTSTATUS) 0xC0000072L)
+#endif
+
+#ifndef STATUS_NONE_MAPPED
+# define STATUS_NONE_MAPPED ((NTSTATUS) 0xC0000073L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LUIDS_REQUESTED
+# define STATUS_TOO_MANY_LUIDS_REQUESTED ((NTSTATUS) 0xC0000074L)
+#endif
+
+#ifndef STATUS_LUIDS_EXHAUSTED
+# define STATUS_LUIDS_EXHAUSTED ((NTSTATUS) 0xC0000075L)
+#endif
+
+#ifndef STATUS_INVALID_SUB_AUTHORITY
+# define STATUS_INVALID_SUB_AUTHORITY ((NTSTATUS) 0xC0000076L)
+#endif
+
+#ifndef STATUS_INVALID_ACL
+# define STATUS_INVALID_ACL ((NTSTATUS) 0xC0000077L)
+#endif
+
+#ifndef STATUS_INVALID_SID
+# define STATUS_INVALID_SID ((NTSTATUS) 0xC0000078L)
+#endif
+
+#ifndef STATUS_INVALID_SECURITY_DESCR
+# define STATUS_INVALID_SECURITY_DESCR ((NTSTATUS) 0xC0000079L)
+#endif
+
+#ifndef STATUS_PROCEDURE_NOT_FOUND
+# define STATUS_PROCEDURE_NOT_FOUND ((NTSTATUS) 0xC000007AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_FORMAT
+# define STATUS_INVALID_IMAGE_FORMAT ((NTSTATUS) 0xC000007BL)
+#endif
+
+#ifndef STATUS_NO_TOKEN
+# define STATUS_NO_TOKEN ((NTSTATUS) 0xC000007CL)
+#endif
+
+#ifndef STATUS_BAD_INHERITANCE_ACL
+# define STATUS_BAD_INHERITANCE_ACL ((NTSTATUS) 0xC000007DL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_LOCKED
+# define STATUS_RANGE_NOT_LOCKED ((NTSTATUS) 0xC000007EL)
+#endif
+
+#ifndef STATUS_DISK_FULL
+# define STATUS_DISK_FULL ((NTSTATUS) 0xC000007FL)
+#endif
+
+#ifndef STATUS_SERVER_DISABLED
+# define STATUS_SERVER_DISABLED ((NTSTATUS) 0xC0000080L)
+#endif
+
+#ifndef STATUS_SERVER_NOT_DISABLED
+# define STATUS_SERVER_NOT_DISABLED ((NTSTATUS) 0xC0000081L)
+#endif
+
+#ifndef STATUS_TOO_MANY_GUIDS_REQUESTED
+# define STATUS_TOO_MANY_GUIDS_REQUESTED ((NTSTATUS) 0xC0000082L)
+#endif
+
+#ifndef STATUS_GUIDS_EXHAUSTED
+# define STATUS_GUIDS_EXHAUSTED ((NTSTATUS) 0xC0000083L)
+#endif
+
+#ifndef STATUS_INVALID_ID_AUTHORITY
+# define STATUS_INVALID_ID_AUTHORITY ((NTSTATUS) 0xC0000084L)
+#endif
+
+#ifndef STATUS_AGENTS_EXHAUSTED
+# define STATUS_AGENTS_EXHAUSTED ((NTSTATUS) 0xC0000085L)
+#endif
+
+#ifndef STATUS_INVALID_VOLUME_LABEL
+# define STATUS_INVALID_VOLUME_LABEL ((NTSTATUS) 0xC0000086L)
+#endif
+
+#ifndef STATUS_SECTION_NOT_EXTENDED
+# define STATUS_SECTION_NOT_EXTENDED ((NTSTATUS) 0xC0000087L)
+#endif
+
+#ifndef STATUS_NOT_MAPPED_DATA
+# define STATUS_NOT_MAPPED_DATA ((NTSTATUS) 0xC0000088L)
+#endif
+
+#ifndef STATUS_RESOURCE_DATA_NOT_FOUND
+# define STATUS_RESOURCE_DATA_NOT_FOUND ((NTSTATUS) 0xC0000089L)
+#endif
+
+#ifndef STATUS_RESOURCE_TYPE_NOT_FOUND
+# define STATUS_RESOURCE_TYPE_NOT_FOUND ((NTSTATUS) 0xC000008AL)
+#endif
+
+#ifndef STATUS_RESOURCE_NAME_NOT_FOUND
+# define STATUS_RESOURCE_NAME_NOT_FOUND ((NTSTATUS) 0xC000008BL)
+#endif
+
+#ifndef STATUS_ARRAY_BOUNDS_EXCEEDED
+# define STATUS_ARRAY_BOUNDS_EXCEEDED ((NTSTATUS) 0xC000008CL)
+#endif
+
+#ifndef STATUS_FLOAT_DENORMAL_OPERAND
+# define STATUS_FLOAT_DENORMAL_OPERAND ((NTSTATUS) 0xC000008DL)
+#endif
+
+#ifndef STATUS_FLOAT_DIVIDE_BY_ZERO
+# define STATUS_FLOAT_DIVIDE_BY_ZERO ((NTSTATUS) 0xC000008EL)
+#endif
+
+#ifndef STATUS_FLOAT_INEXACT_RESULT
+# define STATUS_FLOAT_INEXACT_RESULT ((NTSTATUS) 0xC000008FL)
+#endif
+
+#ifndef STATUS_FLOAT_INVALID_OPERATION
+# define STATUS_FLOAT_INVALID_OPERATION ((NTSTATUS) 0xC0000090L)
+#endif
+
+#ifndef STATUS_FLOAT_OVERFLOW
+# define STATUS_FLOAT_OVERFLOW ((NTSTATUS) 0xC0000091L)
+#endif
+
+#ifndef STATUS_FLOAT_STACK_CHECK
+# define STATUS_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000092L)
+#endif
+
+#ifndef STATUS_FLOAT_UNDERFLOW
+# define STATUS_FLOAT_UNDERFLOW ((NTSTATUS) 0xC0000093L)
+#endif
+
+#ifndef STATUS_INTEGER_DIVIDE_BY_ZERO
+# define STATUS_INTEGER_DIVIDE_BY_ZERO ((NTSTATUS) 0xC0000094L)
+#endif
+
+#ifndef STATUS_INTEGER_OVERFLOW
+# define STATUS_INTEGER_OVERFLOW ((NTSTATUS) 0xC0000095L)
+#endif
+
+#ifndef STATUS_PRIVILEGED_INSTRUCTION
+# define STATUS_PRIVILEGED_INSTRUCTION ((NTSTATUS) 0xC0000096L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PAGING_FILES
+# define STATUS_TOO_MANY_PAGING_FILES ((NTSTATUS) 0xC0000097L)
+#endif
+
+#ifndef STATUS_FILE_INVALID
+# define STATUS_FILE_INVALID ((NTSTATUS) 0xC0000098L)
+#endif
+
+#ifndef STATUS_ALLOTTED_SPACE_EXCEEDED
+# define STATUS_ALLOTTED_SPACE_EXCEEDED ((NTSTATUS) 0xC0000099L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCES
+# define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS) 0xC000009AL)
+#endif
+
+#ifndef STATUS_DFS_EXIT_PATH_FOUND
+# define STATUS_DFS_EXIT_PATH_FOUND ((NTSTATUS) 0xC000009BL)
+#endif
+
+#ifndef STATUS_DEVICE_DATA_ERROR
+# define STATUS_DEVICE_DATA_ERROR ((NTSTATUS) 0xC000009CL)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_CONNECTED
+# define STATUS_DEVICE_NOT_CONNECTED ((NTSTATUS) 0xC000009DL)
+#endif
+
+#ifndef STATUS_DEVICE_POWER_FAILURE
+# define STATUS_DEVICE_POWER_FAILURE ((NTSTATUS) 0xC000009EL)
+#endif
+
+#ifndef STATUS_FREE_VM_NOT_AT_BASE
+# define STATUS_FREE_VM_NOT_AT_BASE ((NTSTATUS) 0xC000009FL)
+#endif
+
+#ifndef STATUS_MEMORY_NOT_ALLOCATED
+# define STATUS_MEMORY_NOT_ALLOCATED ((NTSTATUS) 0xC00000A0L)
+#endif
+
+#ifndef STATUS_WORKING_SET_QUOTA
+# define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xC00000A1L)
+#endif
+
+#ifndef STATUS_MEDIA_WRITE_PROTECTED
+# define STATUS_MEDIA_WRITE_PROTECTED ((NTSTATUS) 0xC00000A2L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_READY
+# define STATUS_DEVICE_NOT_READY ((NTSTATUS) 0xC00000A3L)
+#endif
+
+#ifndef STATUS_INVALID_GROUP_ATTRIBUTES
+# define STATUS_INVALID_GROUP_ATTRIBUTES ((NTSTATUS) 0xC00000A4L)
+#endif
+
+#ifndef STATUS_BAD_IMPERSONATION_LEVEL
+# define STATUS_BAD_IMPERSONATION_LEVEL ((NTSTATUS) 0xC00000A5L)
+#endif
+
+#ifndef STATUS_CANT_OPEN_ANONYMOUS
+# define STATUS_CANT_OPEN_ANONYMOUS ((NTSTATUS) 0xC00000A6L)
+#endif
+
+#ifndef STATUS_BAD_VALIDATION_CLASS
+# define STATUS_BAD_VALIDATION_CLASS ((NTSTATUS) 0xC00000A7L)
+#endif
+
+#ifndef STATUS_BAD_TOKEN_TYPE
+# define STATUS_BAD_TOKEN_TYPE ((NTSTATUS) 0xC00000A8L)
+#endif
+
+#ifndef STATUS_BAD_MASTER_BOOT_RECORD
+# define STATUS_BAD_MASTER_BOOT_RECORD ((NTSTATUS) 0xC00000A9L)
+#endif
+
+#ifndef STATUS_INSTRUCTION_MISALIGNMENT
+# define STATUS_INSTRUCTION_MISALIGNMENT ((NTSTATUS) 0xC00000AAL)
+#endif
+
+#ifndef STATUS_INSTANCE_NOT_AVAILABLE
+# define STATUS_INSTANCE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ABL)
+#endif
+
+#ifndef STATUS_PIPE_NOT_AVAILABLE
+# define STATUS_PIPE_NOT_AVAILABLE ((NTSTATUS) 0xC00000ACL)
+#endif
+
+#ifndef STATUS_INVALID_PIPE_STATE
+# define STATUS_INVALID_PIPE_STATE ((NTSTATUS) 0xC00000ADL)
+#endif
+
+#ifndef STATUS_PIPE_BUSY
+# define STATUS_PIPE_BUSY ((NTSTATUS) 0xC00000AEL)
+#endif
+
+#ifndef STATUS_ILLEGAL_FUNCTION
+# define STATUS_ILLEGAL_FUNCTION ((NTSTATUS) 0xC00000AFL)
+#endif
+
+#ifndef STATUS_PIPE_DISCONNECTED
+# define STATUS_PIPE_DISCONNECTED ((NTSTATUS) 0xC00000B0L)
+#endif
+
+#ifndef STATUS_PIPE_CLOSING
+# define STATUS_PIPE_CLOSING ((NTSTATUS) 0xC00000B1L)
+#endif
+
+#ifndef STATUS_PIPE_CONNECTED
+# define STATUS_PIPE_CONNECTED ((NTSTATUS) 0xC00000B2L)
+#endif
+
+#ifndef STATUS_PIPE_LISTENING
+# define STATUS_PIPE_LISTENING ((NTSTATUS) 0xC00000B3L)
+#endif
+
+#ifndef STATUS_INVALID_READ_MODE
+# define STATUS_INVALID_READ_MODE ((NTSTATUS) 0xC00000B4L)
+#endif
+
+#ifndef STATUS_IO_TIMEOUT
+# define STATUS_IO_TIMEOUT ((NTSTATUS) 0xC00000B5L)
+#endif
+
+#ifndef STATUS_FILE_FORCED_CLOSED
+# define STATUS_FILE_FORCED_CLOSED ((NTSTATUS) 0xC00000B6L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STARTED
+# define STATUS_PROFILING_NOT_STARTED ((NTSTATUS) 0xC00000B7L)
+#endif
+
+#ifndef STATUS_PROFILING_NOT_STOPPED
+# define STATUS_PROFILING_NOT_STOPPED ((NTSTATUS) 0xC00000B8L)
+#endif
+
+#ifndef STATUS_COULD_NOT_INTERPRET
+# define STATUS_COULD_NOT_INTERPRET ((NTSTATUS) 0xC00000B9L)
+#endif
+
+#ifndef STATUS_FILE_IS_A_DIRECTORY
+# define STATUS_FILE_IS_A_DIRECTORY ((NTSTATUS) 0xC00000BAL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED
+# define STATUS_NOT_SUPPORTED ((NTSTATUS) 0xC00000BBL)
+#endif
+
+#ifndef STATUS_REMOTE_NOT_LISTENING
+# define STATUS_REMOTE_NOT_LISTENING ((NTSTATUS) 0xC00000BCL)
+#endif
+
+#ifndef STATUS_DUPLICATE_NAME
+# define STATUS_DUPLICATE_NAME ((NTSTATUS) 0xC00000BDL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_PATH
+# define STATUS_BAD_NETWORK_PATH ((NTSTATUS) 0xC00000BEL)
+#endif
+
+#ifndef STATUS_NETWORK_BUSY
+# define STATUS_NETWORK_BUSY ((NTSTATUS) 0xC00000BFL)
+#endif
+
+#ifndef STATUS_DEVICE_DOES_NOT_EXIST
+# define STATUS_DEVICE_DOES_NOT_EXIST ((NTSTATUS) 0xC00000C0L)
+#endif
+
+#ifndef STATUS_TOO_MANY_COMMANDS
+# define STATUS_TOO_MANY_COMMANDS ((NTSTATUS) 0xC00000C1L)
+#endif
+
+#ifndef STATUS_ADAPTER_HARDWARE_ERROR
+# define STATUS_ADAPTER_HARDWARE_ERROR ((NTSTATUS) 0xC00000C2L)
+#endif
+
+#ifndef STATUS_INVALID_NETWORK_RESPONSE
+# define STATUS_INVALID_NETWORK_RESPONSE ((NTSTATUS) 0xC00000C3L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_NETWORK_ERROR
+# define STATUS_UNEXPECTED_NETWORK_ERROR ((NTSTATUS) 0xC00000C4L)
+#endif
+
+#ifndef STATUS_BAD_REMOTE_ADAPTER
+# define STATUS_BAD_REMOTE_ADAPTER ((NTSTATUS) 0xC00000C5L)
+#endif
+
+#ifndef STATUS_PRINT_QUEUE_FULL
+# define STATUS_PRINT_QUEUE_FULL ((NTSTATUS) 0xC00000C6L)
+#endif
+
+#ifndef STATUS_NO_SPOOL_SPACE
+# define STATUS_NO_SPOOL_SPACE ((NTSTATUS) 0xC00000C7L)
+#endif
+
+#ifndef STATUS_PRINT_CANCELLED
+# define STATUS_PRINT_CANCELLED ((NTSTATUS) 0xC00000C8L)
+#endif
+
+#ifndef STATUS_NETWORK_NAME_DELETED
+# define STATUS_NETWORK_NAME_DELETED ((NTSTATUS) 0xC00000C9L)
+#endif
+
+#ifndef STATUS_NETWORK_ACCESS_DENIED
+# define STATUS_NETWORK_ACCESS_DENIED ((NTSTATUS) 0xC00000CAL)
+#endif
+
+#ifndef STATUS_BAD_DEVICE_TYPE
+# define STATUS_BAD_DEVICE_TYPE ((NTSTATUS) 0xC00000CBL)
+#endif
+
+#ifndef STATUS_BAD_NETWORK_NAME
+# define STATUS_BAD_NETWORK_NAME ((NTSTATUS) 0xC00000CCL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NAMES
+# define STATUS_TOO_MANY_NAMES ((NTSTATUS) 0xC00000CDL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SESSIONS
+# define STATUS_TOO_MANY_SESSIONS ((NTSTATUS) 0xC00000CEL)
+#endif
+
+#ifndef STATUS_SHARING_PAUSED
+# define STATUS_SHARING_PAUSED ((NTSTATUS) 0xC00000CFL)
+#endif
+
+#ifndef STATUS_REQUEST_NOT_ACCEPTED
+# define STATUS_REQUEST_NOT_ACCEPTED ((NTSTATUS) 0xC00000D0L)
+#endif
+
+#ifndef STATUS_REDIRECTOR_PAUSED
+# define STATUS_REDIRECTOR_PAUSED ((NTSTATUS) 0xC00000D1L)
+#endif
+
+#ifndef STATUS_NET_WRITE_FAULT
+# define STATUS_NET_WRITE_FAULT ((NTSTATUS) 0xC00000D2L)
+#endif
+
+#ifndef STATUS_PROFILING_AT_LIMIT
+# define STATUS_PROFILING_AT_LIMIT ((NTSTATUS) 0xC00000D3L)
+#endif
+
+#ifndef STATUS_NOT_SAME_DEVICE
+# define STATUS_NOT_SAME_DEVICE ((NTSTATUS) 0xC00000D4L)
+#endif
+
+#ifndef STATUS_FILE_RENAMED
+# define STATUS_FILE_RENAMED ((NTSTATUS) 0xC00000D5L)
+#endif
+
+#ifndef STATUS_VIRTUAL_CIRCUIT_CLOSED
+# define STATUS_VIRTUAL_CIRCUIT_CLOSED ((NTSTATUS) 0xC00000D6L)
+#endif
+
+#ifndef STATUS_NO_SECURITY_ON_OBJECT
+# define STATUS_NO_SECURITY_ON_OBJECT ((NTSTATUS) 0xC00000D7L)
+#endif
+
+#ifndef STATUS_CANT_WAIT
+# define STATUS_CANT_WAIT ((NTSTATUS) 0xC00000D8L)
+#endif
+
+#ifndef STATUS_PIPE_EMPTY
+# define STATUS_PIPE_EMPTY ((NTSTATUS) 0xC00000D9L)
+#endif
+
+#ifndef STATUS_CANT_ACCESS_DOMAIN_INFO
+# define STATUS_CANT_ACCESS_DOMAIN_INFO ((NTSTATUS) 0xC00000DAL)
+#endif
+
+#ifndef STATUS_CANT_TERMINATE_SELF
+# define STATUS_CANT_TERMINATE_SELF ((NTSTATUS) 0xC00000DBL)
+#endif
+
+#ifndef STATUS_INVALID_SERVER_STATE
+# define STATUS_INVALID_SERVER_STATE ((NTSTATUS) 0xC00000DCL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_STATE
+# define STATUS_INVALID_DOMAIN_STATE ((NTSTATUS) 0xC00000DDL)
+#endif
+
+#ifndef STATUS_INVALID_DOMAIN_ROLE
+# define STATUS_INVALID_DOMAIN_ROLE ((NTSTATUS) 0xC00000DEL)
+#endif
+
+#ifndef STATUS_NO_SUCH_DOMAIN
+# define STATUS_NO_SUCH_DOMAIN ((NTSTATUS) 0xC00000DFL)
+#endif
+
+#ifndef STATUS_DOMAIN_EXISTS
+# define STATUS_DOMAIN_EXISTS ((NTSTATUS) 0xC00000E0L)
+#endif
+
+#ifndef STATUS_DOMAIN_LIMIT_EXCEEDED
+# define STATUS_DOMAIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00000E1L)
+#endif
+
+#ifndef STATUS_OPLOCK_NOT_GRANTED
+# define STATUS_OPLOCK_NOT_GRANTED ((NTSTATUS) 0xC00000E2L)
+#endif
+
+#ifndef STATUS_INVALID_OPLOCK_PROTOCOL
+# define STATUS_INVALID_OPLOCK_PROTOCOL ((NTSTATUS) 0xC00000E3L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_CORRUPTION
+# define STATUS_INTERNAL_DB_CORRUPTION ((NTSTATUS) 0xC00000E4L)
+#endif
+
+#ifndef STATUS_INTERNAL_ERROR
+# define STATUS_INTERNAL_ERROR ((NTSTATUS) 0xC00000E5L)
+#endif
+
+#ifndef STATUS_GENERIC_NOT_MAPPED
+# define STATUS_GENERIC_NOT_MAPPED ((NTSTATUS) 0xC00000E6L)
+#endif
+
+#ifndef STATUS_BAD_DESCRIPTOR_FORMAT
+# define STATUS_BAD_DESCRIPTOR_FORMAT ((NTSTATUS) 0xC00000E7L)
+#endif
+
+#ifndef STATUS_INVALID_USER_BUFFER
+# define STATUS_INVALID_USER_BUFFER ((NTSTATUS) 0xC00000E8L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_IO_ERROR
+# define STATUS_UNEXPECTED_IO_ERROR ((NTSTATUS) 0xC00000E9L)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_CREATE_ERR
+# define STATUS_UNEXPECTED_MM_CREATE_ERR ((NTSTATUS) 0xC00000EAL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_MAP_ERROR
+# define STATUS_UNEXPECTED_MM_MAP_ERROR ((NTSTATUS) 0xC00000EBL)
+#endif
+
+#ifndef STATUS_UNEXPECTED_MM_EXTEND_ERR
+# define STATUS_UNEXPECTED_MM_EXTEND_ERR ((NTSTATUS) 0xC00000ECL)
+#endif
+
+#ifndef STATUS_NOT_LOGON_PROCESS
+# define STATUS_NOT_LOGON_PROCESS ((NTSTATUS) 0xC00000EDL)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_EXISTS
+# define STATUS_LOGON_SESSION_EXISTS ((NTSTATUS) 0xC00000EEL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_1
+# define STATUS_INVALID_PARAMETER_1 ((NTSTATUS) 0xC00000EFL)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_2
+# define STATUS_INVALID_PARAMETER_2 ((NTSTATUS) 0xC00000F0L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_3
+# define STATUS_INVALID_PARAMETER_3 ((NTSTATUS) 0xC00000F1L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_4
+# define STATUS_INVALID_PARAMETER_4 ((NTSTATUS) 0xC00000F2L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_5
+# define STATUS_INVALID_PARAMETER_5 ((NTSTATUS) 0xC00000F3L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_6
+# define STATUS_INVALID_PARAMETER_6 ((NTSTATUS) 0xC00000F4L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_7
+# define STATUS_INVALID_PARAMETER_7 ((NTSTATUS) 0xC00000F5L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_8
+# define STATUS_INVALID_PARAMETER_8 ((NTSTATUS) 0xC00000F6L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_9
+# define STATUS_INVALID_PARAMETER_9 ((NTSTATUS) 0xC00000F7L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_10
+# define STATUS_INVALID_PARAMETER_10 ((NTSTATUS) 0xC00000F8L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_11
+# define STATUS_INVALID_PARAMETER_11 ((NTSTATUS) 0xC00000F9L)
+#endif
+
+#ifndef STATUS_INVALID_PARAMETER_12
+# define STATUS_INVALID_PARAMETER_12 ((NTSTATUS) 0xC00000FAL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_NOT_STARTED
+# define STATUS_REDIRECTOR_NOT_STARTED ((NTSTATUS) 0xC00000FBL)
+#endif
+
+#ifndef STATUS_REDIRECTOR_STARTED
+# define STATUS_REDIRECTOR_STARTED ((NTSTATUS) 0xC00000FCL)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW
+# define STATUS_STACK_OVERFLOW ((NTSTATUS) 0xC00000FDL)
+#endif
+
+#ifndef STATUS_NO_SUCH_PACKAGE
+# define STATUS_NO_SUCH_PACKAGE ((NTSTATUS) 0xC00000FEL)
+#endif
+
+#ifndef STATUS_BAD_FUNCTION_TABLE
+# define STATUS_BAD_FUNCTION_TABLE ((NTSTATUS) 0xC00000FFL)
+#endif
+
+#ifndef STATUS_VARIABLE_NOT_FOUND
+# define STATUS_VARIABLE_NOT_FOUND ((NTSTATUS) 0xC0000100L)
+#endif
+
+#ifndef STATUS_DIRECTORY_NOT_EMPTY
+# define STATUS_DIRECTORY_NOT_EMPTY ((NTSTATUS) 0xC0000101L)
+#endif
+
+#ifndef STATUS_FILE_CORRUPT_ERROR
+# define STATUS_FILE_CORRUPT_ERROR ((NTSTATUS) 0xC0000102L)
+#endif
+
+#ifndef STATUS_NOT_A_DIRECTORY
+# define STATUS_NOT_A_DIRECTORY ((NTSTATUS) 0xC0000103L)
+#endif
+
+#ifndef STATUS_BAD_LOGON_SESSION_STATE
+# define STATUS_BAD_LOGON_SESSION_STATE ((NTSTATUS) 0xC0000104L)
+#endif
+
+#ifndef STATUS_LOGON_SESSION_COLLISION
+# define STATUS_LOGON_SESSION_COLLISION ((NTSTATUS) 0xC0000105L)
+#endif
+
+#ifndef STATUS_NAME_TOO_LONG
+# define STATUS_NAME_TOO_LONG ((NTSTATUS) 0xC0000106L)
+#endif
+
+#ifndef STATUS_FILES_OPEN
+# define STATUS_FILES_OPEN ((NTSTATUS) 0xC0000107L)
+#endif
+
+#ifndef STATUS_CONNECTION_IN_USE
+# define STATUS_CONNECTION_IN_USE ((NTSTATUS) 0xC0000108L)
+#endif
+
+#ifndef STATUS_MESSAGE_NOT_FOUND
+# define STATUS_MESSAGE_NOT_FOUND ((NTSTATUS) 0xC0000109L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_TERMINATING
+# define STATUS_PROCESS_IS_TERMINATING ((NTSTATUS) 0xC000010AL)
+#endif
+
+#ifndef STATUS_INVALID_LOGON_TYPE
+# define STATUS_INVALID_LOGON_TYPE ((NTSTATUS) 0xC000010BL)
+#endif
+
+#ifndef STATUS_NO_GUID_TRANSLATION
+# define STATUS_NO_GUID_TRANSLATION ((NTSTATUS) 0xC000010CL)
+#endif
+
+#ifndef STATUS_CANNOT_IMPERSONATE
+# define STATUS_CANNOT_IMPERSONATE ((NTSTATUS) 0xC000010DL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED
+# define STATUS_IMAGE_ALREADY_LOADED ((NTSTATUS) 0xC000010EL)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_PRESENT
+# define STATUS_ABIOS_NOT_PRESENT ((NTSTATUS) 0xC000010FL)
+#endif
+
+#ifndef STATUS_ABIOS_LID_NOT_EXIST
+# define STATUS_ABIOS_LID_NOT_EXIST ((NTSTATUS) 0xC0000110L)
+#endif
+
+#ifndef STATUS_ABIOS_LID_ALREADY_OWNED
+# define STATUS_ABIOS_LID_ALREADY_OWNED ((NTSTATUS) 0xC0000111L)
+#endif
+
+#ifndef STATUS_ABIOS_NOT_LID_OWNER
+# define STATUS_ABIOS_NOT_LID_OWNER ((NTSTATUS) 0xC0000112L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_COMMAND
+# define STATUS_ABIOS_INVALID_COMMAND ((NTSTATUS) 0xC0000113L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_LID
+# define STATUS_ABIOS_INVALID_LID ((NTSTATUS) 0xC0000114L)
+#endif
+
+#ifndef STATUS_ABIOS_SELECTOR_NOT_AVAILABLE
+# define STATUS_ABIOS_SELECTOR_NOT_AVAILABLE ((NTSTATUS) 0xC0000115L)
+#endif
+
+#ifndef STATUS_ABIOS_INVALID_SELECTOR
+# define STATUS_ABIOS_INVALID_SELECTOR ((NTSTATUS) 0xC0000116L)
+#endif
+
+#ifndef STATUS_NO_LDT
+# define STATUS_NO_LDT ((NTSTATUS) 0xC0000117L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_SIZE
+# define STATUS_INVALID_LDT_SIZE ((NTSTATUS) 0xC0000118L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_OFFSET
+# define STATUS_INVALID_LDT_OFFSET ((NTSTATUS) 0xC0000119L)
+#endif
+
+#ifndef STATUS_INVALID_LDT_DESCRIPTOR
+# define STATUS_INVALID_LDT_DESCRIPTOR ((NTSTATUS) 0xC000011AL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NE_FORMAT
+# define STATUS_INVALID_IMAGE_NE_FORMAT ((NTSTATUS) 0xC000011BL)
+#endif
+
+#ifndef STATUS_RXACT_INVALID_STATE
+# define STATUS_RXACT_INVALID_STATE ((NTSTATUS) 0xC000011CL)
+#endif
+
+#ifndef STATUS_RXACT_COMMIT_FAILURE
+# define STATUS_RXACT_COMMIT_FAILURE ((NTSTATUS) 0xC000011DL)
+#endif
+
+#ifndef STATUS_MAPPED_FILE_SIZE_ZERO
+# define STATUS_MAPPED_FILE_SIZE_ZERO ((NTSTATUS) 0xC000011EL)
+#endif
+
+#ifndef STATUS_TOO_MANY_OPENED_FILES
+# define STATUS_TOO_MANY_OPENED_FILES ((NTSTATUS) 0xC000011FL)
+#endif
+
+#ifndef STATUS_CANCELLED
+# define STATUS_CANCELLED ((NTSTATUS) 0xC0000120L)
+#endif
+
+#ifndef STATUS_CANNOT_DELETE
+# define STATUS_CANNOT_DELETE ((NTSTATUS) 0xC0000121L)
+#endif
+
+#ifndef STATUS_INVALID_COMPUTER_NAME
+# define STATUS_INVALID_COMPUTER_NAME ((NTSTATUS) 0xC0000122L)
+#endif
+
+#ifndef STATUS_FILE_DELETED
+# define STATUS_FILE_DELETED ((NTSTATUS) 0xC0000123L)
+#endif
+
+#ifndef STATUS_SPECIAL_ACCOUNT
+# define STATUS_SPECIAL_ACCOUNT ((NTSTATUS) 0xC0000124L)
+#endif
+
+#ifndef STATUS_SPECIAL_GROUP
+# define STATUS_SPECIAL_GROUP ((NTSTATUS) 0xC0000125L)
+#endif
+
+#ifndef STATUS_SPECIAL_USER
+# define STATUS_SPECIAL_USER ((NTSTATUS) 0xC0000126L)
+#endif
+
+#ifndef STATUS_MEMBERS_PRIMARY_GROUP
+# define STATUS_MEMBERS_PRIMARY_GROUP ((NTSTATUS) 0xC0000127L)
+#endif
+
+#ifndef STATUS_FILE_CLOSED
+# define STATUS_FILE_CLOSED ((NTSTATUS) 0xC0000128L)
+#endif
+
+#ifndef STATUS_TOO_MANY_THREADS
+# define STATUS_TOO_MANY_THREADS ((NTSTATUS) 0xC0000129L)
+#endif
+
+#ifndef STATUS_THREAD_NOT_IN_PROCESS
+# define STATUS_THREAD_NOT_IN_PROCESS ((NTSTATUS) 0xC000012AL)
+#endif
+
+#ifndef STATUS_TOKEN_ALREADY_IN_USE
+# define STATUS_TOKEN_ALREADY_IN_USE ((NTSTATUS) 0xC000012BL)
+#endif
+
+#ifndef STATUS_PAGEFILE_QUOTA_EXCEEDED
+# define STATUS_PAGEFILE_QUOTA_EXCEEDED ((NTSTATUS) 0xC000012CL)
+#endif
+
+#ifndef STATUS_COMMITMENT_LIMIT
+# define STATUS_COMMITMENT_LIMIT ((NTSTATUS) 0xC000012DL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_LE_FORMAT
+# define STATUS_INVALID_IMAGE_LE_FORMAT ((NTSTATUS) 0xC000012EL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_NOT_MZ
+# define STATUS_INVALID_IMAGE_NOT_MZ ((NTSTATUS) 0xC000012FL)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_PROTECT
+# define STATUS_INVALID_IMAGE_PROTECT ((NTSTATUS) 0xC0000130L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_16
+# define STATUS_INVALID_IMAGE_WIN_16 ((NTSTATUS) 0xC0000131L)
+#endif
+
+#ifndef STATUS_LOGON_SERVER_CONFLICT
+# define STATUS_LOGON_SERVER_CONFLICT ((NTSTATUS) 0xC0000132L)
+#endif
+
+#ifndef STATUS_TIME_DIFFERENCE_AT_DC
+# define STATUS_TIME_DIFFERENCE_AT_DC ((NTSTATUS) 0xC0000133L)
+#endif
+
+#ifndef STATUS_SYNCHRONIZATION_REQUIRED
+# define STATUS_SYNCHRONIZATION_REQUIRED ((NTSTATUS) 0xC0000134L)
+#endif
+
+#ifndef STATUS_DLL_NOT_FOUND
+# define STATUS_DLL_NOT_FOUND ((NTSTATUS) 0xC0000135L)
+#endif
+
+#ifndef STATUS_OPEN_FAILED
+# define STATUS_OPEN_FAILED ((NTSTATUS) 0xC0000136L)
+#endif
+
+#ifndef STATUS_IO_PRIVILEGE_FAILED
+# define STATUS_IO_PRIVILEGE_FAILED ((NTSTATUS) 0xC0000137L)
+#endif
+
+#ifndef STATUS_ORDINAL_NOT_FOUND
+# define STATUS_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000138L)
+#endif
+
+#ifndef STATUS_ENTRYPOINT_NOT_FOUND
+# define STATUS_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000139L)
+#endif
+
+#ifndef STATUS_CONTROL_C_EXIT
+# define STATUS_CONTROL_C_EXIT ((NTSTATUS) 0xC000013AL)
+#endif
+
+#ifndef STATUS_LOCAL_DISCONNECT
+# define STATUS_LOCAL_DISCONNECT ((NTSTATUS) 0xC000013BL)
+#endif
+
+#ifndef STATUS_REMOTE_DISCONNECT
+# define STATUS_REMOTE_DISCONNECT ((NTSTATUS) 0xC000013CL)
+#endif
+
+#ifndef STATUS_REMOTE_RESOURCES
+# define STATUS_REMOTE_RESOURCES ((NTSTATUS) 0xC000013DL)
+#endif
+
+#ifndef STATUS_LINK_FAILED
+# define STATUS_LINK_FAILED ((NTSTATUS) 0xC000013EL)
+#endif
+
+#ifndef STATUS_LINK_TIMEOUT
+# define STATUS_LINK_TIMEOUT ((NTSTATUS) 0xC000013FL)
+#endif
+
+#ifndef STATUS_INVALID_CONNECTION
+# define STATUS_INVALID_CONNECTION ((NTSTATUS) 0xC0000140L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS
+# define STATUS_INVALID_ADDRESS ((NTSTATUS) 0xC0000141L)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED
+# define STATUS_DLL_INIT_FAILED ((NTSTATUS) 0xC0000142L)
+#endif
+
+#ifndef STATUS_MISSING_SYSTEMFILE
+# define STATUS_MISSING_SYSTEMFILE ((NTSTATUS) 0xC0000143L)
+#endif
+
+#ifndef STATUS_UNHANDLED_EXCEPTION
+# define STATUS_UNHANDLED_EXCEPTION ((NTSTATUS) 0xC0000144L)
+#endif
+
+#ifndef STATUS_APP_INIT_FAILURE
+# define STATUS_APP_INIT_FAILURE ((NTSTATUS) 0xC0000145L)
+#endif
+
+#ifndef STATUS_PAGEFILE_CREATE_FAILED
+# define STATUS_PAGEFILE_CREATE_FAILED ((NTSTATUS) 0xC0000146L)
+#endif
+
+#ifndef STATUS_NO_PAGEFILE
+# define STATUS_NO_PAGEFILE ((NTSTATUS) 0xC0000147L)
+#endif
+
+#ifndef STATUS_INVALID_LEVEL
+# define STATUS_INVALID_LEVEL ((NTSTATUS) 0xC0000148L)
+#endif
+
+#ifndef STATUS_WRONG_PASSWORD_CORE
+# define STATUS_WRONG_PASSWORD_CORE ((NTSTATUS) 0xC0000149L)
+#endif
+
+#ifndef STATUS_ILLEGAL_FLOAT_CONTEXT
+# define STATUS_ILLEGAL_FLOAT_CONTEXT ((NTSTATUS) 0xC000014AL)
+#endif
+
+#ifndef STATUS_PIPE_BROKEN
+# define STATUS_PIPE_BROKEN ((NTSTATUS) 0xC000014BL)
+#endif
+
+#ifndef STATUS_REGISTRY_CORRUPT
+# define STATUS_REGISTRY_CORRUPT ((NTSTATUS) 0xC000014CL)
+#endif
+
+#ifndef STATUS_REGISTRY_IO_FAILED
+# define STATUS_REGISTRY_IO_FAILED ((NTSTATUS) 0xC000014DL)
+#endif
+
+#ifndef STATUS_NO_EVENT_PAIR
+# define STATUS_NO_EVENT_PAIR ((NTSTATUS) 0xC000014EL)
+#endif
+
+#ifndef STATUS_UNRECOGNIZED_VOLUME
+# define STATUS_UNRECOGNIZED_VOLUME ((NTSTATUS) 0xC000014FL)
+#endif
+
+#ifndef STATUS_SERIAL_NO_DEVICE_INITED
+# define STATUS_SERIAL_NO_DEVICE_INITED ((NTSTATUS) 0xC0000150L)
+#endif
+
+#ifndef STATUS_NO_SUCH_ALIAS
+# define STATUS_NO_SUCH_ALIAS ((NTSTATUS) 0xC0000151L)
+#endif
+
+#ifndef STATUS_MEMBER_NOT_IN_ALIAS
+# define STATUS_MEMBER_NOT_IN_ALIAS ((NTSTATUS) 0xC0000152L)
+#endif
+
+#ifndef STATUS_MEMBER_IN_ALIAS
+# define STATUS_MEMBER_IN_ALIAS ((NTSTATUS) 0xC0000153L)
+#endif
+
+#ifndef STATUS_ALIAS_EXISTS
+# define STATUS_ALIAS_EXISTS ((NTSTATUS) 0xC0000154L)
+#endif
+
+#ifndef STATUS_LOGON_NOT_GRANTED
+# define STATUS_LOGON_NOT_GRANTED ((NTSTATUS) 0xC0000155L)
+#endif
+
+#ifndef STATUS_TOO_MANY_SECRETS
+# define STATUS_TOO_MANY_SECRETS ((NTSTATUS) 0xC0000156L)
+#endif
+
+#ifndef STATUS_SECRET_TOO_LONG
+# define STATUS_SECRET_TOO_LONG ((NTSTATUS) 0xC0000157L)
+#endif
+
+#ifndef STATUS_INTERNAL_DB_ERROR
+# define STATUS_INTERNAL_DB_ERROR ((NTSTATUS) 0xC0000158L)
+#endif
+
+#ifndef STATUS_FULLSCREEN_MODE
+# define STATUS_FULLSCREEN_MODE ((NTSTATUS) 0xC0000159L)
+#endif
+
+#ifndef STATUS_TOO_MANY_CONTEXT_IDS
+# define STATUS_TOO_MANY_CONTEXT_IDS ((NTSTATUS) 0xC000015AL)
+#endif
+
+#ifndef STATUS_LOGON_TYPE_NOT_GRANTED
+# define STATUS_LOGON_TYPE_NOT_GRANTED ((NTSTATUS) 0xC000015BL)
+#endif
+
+#ifndef STATUS_NOT_REGISTRY_FILE
+# define STATUS_NOT_REGISTRY_FILE ((NTSTATUS) 0xC000015CL)
+#endif
+
+#ifndef STATUS_NT_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_NT_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000015DL)
+#endif
+
+#ifndef STATUS_DOMAIN_CTRLR_CONFIG_ERROR
+# define STATUS_DOMAIN_CTRLR_CONFIG_ERROR ((NTSTATUS) 0xC000015EL)
+#endif
+
+#ifndef STATUS_FT_MISSING_MEMBER
+# define STATUS_FT_MISSING_MEMBER ((NTSTATUS) 0xC000015FL)
+#endif
+
+#ifndef STATUS_ILL_FORMED_SERVICE_ENTRY
+# define STATUS_ILL_FORMED_SERVICE_ENTRY ((NTSTATUS) 0xC0000160L)
+#endif
+
+#ifndef STATUS_ILLEGAL_CHARACTER
+# define STATUS_ILLEGAL_CHARACTER ((NTSTATUS) 0xC0000161L)
+#endif
+
+#ifndef STATUS_UNMAPPABLE_CHARACTER
+# define STATUS_UNMAPPABLE_CHARACTER ((NTSTATUS) 0xC0000162L)
+#endif
+
+#ifndef STATUS_UNDEFINED_CHARACTER
+# define STATUS_UNDEFINED_CHARACTER ((NTSTATUS) 0xC0000163L)
+#endif
+
+#ifndef STATUS_FLOPPY_VOLUME
+# define STATUS_FLOPPY_VOLUME ((NTSTATUS) 0xC0000164L)
+#endif
+
+#ifndef STATUS_FLOPPY_ID_MARK_NOT_FOUND
+# define STATUS_FLOPPY_ID_MARK_NOT_FOUND ((NTSTATUS) 0xC0000165L)
+#endif
+
+#ifndef STATUS_FLOPPY_WRONG_CYLINDER
+# define STATUS_FLOPPY_WRONG_CYLINDER ((NTSTATUS) 0xC0000166L)
+#endif
+
+#ifndef STATUS_FLOPPY_UNKNOWN_ERROR
+# define STATUS_FLOPPY_UNKNOWN_ERROR ((NTSTATUS) 0xC0000167L)
+#endif
+
+#ifndef STATUS_FLOPPY_BAD_REGISTERS
+# define STATUS_FLOPPY_BAD_REGISTERS ((NTSTATUS) 0xC0000168L)
+#endif
+
+#ifndef STATUS_DISK_RECALIBRATE_FAILED
+# define STATUS_DISK_RECALIBRATE_FAILED ((NTSTATUS) 0xC0000169L)
+#endif
+
+#ifndef STATUS_DISK_OPERATION_FAILED
+# define STATUS_DISK_OPERATION_FAILED ((NTSTATUS) 0xC000016AL)
+#endif
+
+#ifndef STATUS_DISK_RESET_FAILED
+# define STATUS_DISK_RESET_FAILED ((NTSTATUS) 0xC000016BL)
+#endif
+
+#ifndef STATUS_SHARED_IRQ_BUSY
+# define STATUS_SHARED_IRQ_BUSY ((NTSTATUS) 0xC000016CL)
+#endif
+
+#ifndef STATUS_FT_ORPHANING
+# define STATUS_FT_ORPHANING ((NTSTATUS) 0xC000016DL)
+#endif
+
+#ifndef STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT
+# define STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT ((NTSTATUS) 0xC000016EL)
+#endif
+
+#ifndef STATUS_PARTITION_FAILURE
+# define STATUS_PARTITION_FAILURE ((NTSTATUS) 0xC0000172L)
+#endif
+
+#ifndef STATUS_INVALID_BLOCK_LENGTH
+# define STATUS_INVALID_BLOCK_LENGTH ((NTSTATUS) 0xC0000173L)
+#endif
+
+#ifndef STATUS_DEVICE_NOT_PARTITIONED
+# define STATUS_DEVICE_NOT_PARTITIONED ((NTSTATUS) 0xC0000174L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_LOCK_MEDIA
+# define STATUS_UNABLE_TO_LOCK_MEDIA ((NTSTATUS) 0xC0000175L)
+#endif
+
+#ifndef STATUS_UNABLE_TO_UNLOAD_MEDIA
+# define STATUS_UNABLE_TO_UNLOAD_MEDIA ((NTSTATUS) 0xC0000176L)
+#endif
+
+#ifndef STATUS_EOM_OVERFLOW
+# define STATUS_EOM_OVERFLOW ((NTSTATUS) 0xC0000177L)
+#endif
+
+#ifndef STATUS_NO_MEDIA
+# define STATUS_NO_MEDIA ((NTSTATUS) 0xC0000178L)
+#endif
+
+#ifndef STATUS_NO_SUCH_MEMBER
+# define STATUS_NO_SUCH_MEMBER ((NTSTATUS) 0xC000017AL)
+#endif
+
+#ifndef STATUS_INVALID_MEMBER
+# define STATUS_INVALID_MEMBER ((NTSTATUS) 0xC000017BL)
+#endif
+
+#ifndef STATUS_KEY_DELETED
+# define STATUS_KEY_DELETED ((NTSTATUS) 0xC000017CL)
+#endif
+
+#ifndef STATUS_NO_LOG_SPACE
+# define STATUS_NO_LOG_SPACE ((NTSTATUS) 0xC000017DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_SIDS
+# define STATUS_TOO_MANY_SIDS ((NTSTATUS) 0xC000017EL)
+#endif
+
+#ifndef STATUS_LM_CROSS_ENCRYPTION_REQUIRED
+# define STATUS_LM_CROSS_ENCRYPTION_REQUIRED ((NTSTATUS) 0xC000017FL)
+#endif
+
+#ifndef STATUS_KEY_HAS_CHILDREN
+# define STATUS_KEY_HAS_CHILDREN ((NTSTATUS) 0xC0000180L)
+#endif
+
+#ifndef STATUS_CHILD_MUST_BE_VOLATILE
+# define STATUS_CHILD_MUST_BE_VOLATILE ((NTSTATUS) 0xC0000181L)
+#endif
+
+#ifndef STATUS_DEVICE_CONFIGURATION_ERROR
+# define STATUS_DEVICE_CONFIGURATION_ERROR ((NTSTATUS) 0xC0000182L)
+#endif
+
+#ifndef STATUS_DRIVER_INTERNAL_ERROR
+# define STATUS_DRIVER_INTERNAL_ERROR ((NTSTATUS) 0xC0000183L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_STATE
+# define STATUS_INVALID_DEVICE_STATE ((NTSTATUS) 0xC0000184L)
+#endif
+
+#ifndef STATUS_IO_DEVICE_ERROR
+# define STATUS_IO_DEVICE_ERROR ((NTSTATUS) 0xC0000185L)
+#endif
+
+#ifndef STATUS_DEVICE_PROTOCOL_ERROR
+# define STATUS_DEVICE_PROTOCOL_ERROR ((NTSTATUS) 0xC0000186L)
+#endif
+
+#ifndef STATUS_BACKUP_CONTROLLER
+# define STATUS_BACKUP_CONTROLLER ((NTSTATUS) 0xC0000187L)
+#endif
+
+#ifndef STATUS_LOG_FILE_FULL
+# define STATUS_LOG_FILE_FULL ((NTSTATUS) 0xC0000188L)
+#endif
+
+#ifndef STATUS_TOO_LATE
+# define STATUS_TOO_LATE ((NTSTATUS) 0xC0000189L)
+#endif
+
+#ifndef STATUS_NO_TRUST_LSA_SECRET
+# define STATUS_NO_TRUST_LSA_SECRET ((NTSTATUS) 0xC000018AL)
+#endif
+
+#ifndef STATUS_NO_TRUST_SAM_ACCOUNT
+# define STATUS_NO_TRUST_SAM_ACCOUNT ((NTSTATUS) 0xC000018BL)
+#endif
+
+#ifndef STATUS_TRUSTED_DOMAIN_FAILURE
+# define STATUS_TRUSTED_DOMAIN_FAILURE ((NTSTATUS) 0xC000018CL)
+#endif
+
+#ifndef STATUS_TRUSTED_RELATIONSHIP_FAILURE
+# define STATUS_TRUSTED_RELATIONSHIP_FAILURE ((NTSTATUS) 0xC000018DL)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CORRUPT
+# define STATUS_EVENTLOG_FILE_CORRUPT ((NTSTATUS) 0xC000018EL)
+#endif
+
+#ifndef STATUS_EVENTLOG_CANT_START
+# define STATUS_EVENTLOG_CANT_START ((NTSTATUS) 0xC000018FL)
+#endif
+
+#ifndef STATUS_TRUST_FAILURE
+# define STATUS_TRUST_FAILURE ((NTSTATUS) 0xC0000190L)
+#endif
+
+#ifndef STATUS_MUTANT_LIMIT_EXCEEDED
+# define STATUS_MUTANT_LIMIT_EXCEEDED ((NTSTATUS) 0xC0000191L)
+#endif
+
+#ifndef STATUS_NETLOGON_NOT_STARTED
+# define STATUS_NETLOGON_NOT_STARTED ((NTSTATUS) 0xC0000192L)
+#endif
+
+#ifndef STATUS_ACCOUNT_EXPIRED
+# define STATUS_ACCOUNT_EXPIRED ((NTSTATUS) 0xC0000193L)
+#endif
+
+#ifndef STATUS_POSSIBLE_DEADLOCK
+# define STATUS_POSSIBLE_DEADLOCK ((NTSTATUS) 0xC0000194L)
+#endif
+
+#ifndef STATUS_NETWORK_CREDENTIAL_CONFLICT
+# define STATUS_NETWORK_CREDENTIAL_CONFLICT ((NTSTATUS) 0xC0000195L)
+#endif
+
+#ifndef STATUS_REMOTE_SESSION_LIMIT
+# define STATUS_REMOTE_SESSION_LIMIT ((NTSTATUS) 0xC0000196L)
+#endif
+
+#ifndef STATUS_EVENTLOG_FILE_CHANGED
+# define STATUS_EVENTLOG_FILE_CHANGED ((NTSTATUS) 0xC0000197L)
+#endif
+
+#ifndef STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT
+# define STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT ((NTSTATUS) 0xC0000198L)
+#endif
+
+#ifndef STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT
+# define STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT ((NTSTATUS) 0xC0000199L)
+#endif
+
+#ifndef STATUS_NOLOGON_SERVER_TRUST_ACCOUNT
+# define STATUS_NOLOGON_SERVER_TRUST_ACCOUNT ((NTSTATUS) 0xC000019AL)
+#endif
+
+#ifndef STATUS_DOMAIN_TRUST_INCONSISTENT
+# define STATUS_DOMAIN_TRUST_INCONSISTENT ((NTSTATUS) 0xC000019BL)
+#endif
+
+#ifndef STATUS_FS_DRIVER_REQUIRED
+# define STATUS_FS_DRIVER_REQUIRED ((NTSTATUS) 0xC000019CL)
+#endif
+
+#ifndef STATUS_IMAGE_ALREADY_LOADED_AS_DLL
+# define STATUS_IMAGE_ALREADY_LOADED_AS_DLL ((NTSTATUS) 0xC000019DL)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING
+# define STATUS_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING ((NTSTATUS) 0xC000019EL)
+#endif
+
+#ifndef STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME
+# define STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME ((NTSTATUS) 0xC000019FL)
+#endif
+
+#ifndef STATUS_SECURITY_STREAM_IS_INCONSISTENT
+# define STATUS_SECURITY_STREAM_IS_INCONSISTENT ((NTSTATUS) 0xC00001A0L)
+#endif
+
+#ifndef STATUS_INVALID_LOCK_RANGE
+# define STATUS_INVALID_LOCK_RANGE ((NTSTATUS) 0xC00001A1L)
+#endif
+
+#ifndef STATUS_INVALID_ACE_CONDITION
+# define STATUS_INVALID_ACE_CONDITION ((NTSTATUS) 0xC00001A2L)
+#endif
+
+#ifndef STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT
+# define STATUS_IMAGE_SUBSYSTEM_NOT_PRESENT ((NTSTATUS) 0xC00001A3L)
+#endif
+
+#ifndef STATUS_NOTIFICATION_GUID_ALREADY_DEFINED
+# define STATUS_NOTIFICATION_GUID_ALREADY_DEFINED ((NTSTATUS) 0xC00001A4L)
+#endif
+
+#ifndef STATUS_NETWORK_OPEN_RESTRICTION
+# define STATUS_NETWORK_OPEN_RESTRICTION ((NTSTATUS) 0xC0000201L)
+#endif
+
+#ifndef STATUS_NO_USER_SESSION_KEY
+# define STATUS_NO_USER_SESSION_KEY ((NTSTATUS) 0xC0000202L)
+#endif
+
+#ifndef STATUS_USER_SESSION_DELETED
+# define STATUS_USER_SESSION_DELETED ((NTSTATUS) 0xC0000203L)
+#endif
+
+#ifndef STATUS_RESOURCE_LANG_NOT_FOUND
+# define STATUS_RESOURCE_LANG_NOT_FOUND ((NTSTATUS) 0xC0000204L)
+#endif
+
+#ifndef STATUS_INSUFF_SERVER_RESOURCES
+# define STATUS_INSUFF_SERVER_RESOURCES ((NTSTATUS) 0xC0000205L)
+#endif
+
+#ifndef STATUS_INVALID_BUFFER_SIZE
+# define STATUS_INVALID_BUFFER_SIZE ((NTSTATUS) 0xC0000206L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_COMPONENT
+# define STATUS_INVALID_ADDRESS_COMPONENT ((NTSTATUS) 0xC0000207L)
+#endif
+
+#ifndef STATUS_INVALID_ADDRESS_WILDCARD
+# define STATUS_INVALID_ADDRESS_WILDCARD ((NTSTATUS) 0xC0000208L)
+#endif
+
+#ifndef STATUS_TOO_MANY_ADDRESSES
+# define STATUS_TOO_MANY_ADDRESSES ((NTSTATUS) 0xC0000209L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_EXISTS
+# define STATUS_ADDRESS_ALREADY_EXISTS ((NTSTATUS) 0xC000020AL)
+#endif
+
+#ifndef STATUS_ADDRESS_CLOSED
+# define STATUS_ADDRESS_CLOSED ((NTSTATUS) 0xC000020BL)
+#endif
+
+#ifndef STATUS_CONNECTION_DISCONNECTED
+# define STATUS_CONNECTION_DISCONNECTED ((NTSTATUS) 0xC000020CL)
+#endif
+
+#ifndef STATUS_CONNECTION_RESET
+# define STATUS_CONNECTION_RESET ((NTSTATUS) 0xC000020DL)
+#endif
+
+#ifndef STATUS_TOO_MANY_NODES
+# define STATUS_TOO_MANY_NODES ((NTSTATUS) 0xC000020EL)
+#endif
+
+#ifndef STATUS_TRANSACTION_ABORTED
+# define STATUS_TRANSACTION_ABORTED ((NTSTATUS) 0xC000020FL)
+#endif
+
+#ifndef STATUS_TRANSACTION_TIMED_OUT
+# define STATUS_TRANSACTION_TIMED_OUT ((NTSTATUS) 0xC0000210L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_RELEASE
+# define STATUS_TRANSACTION_NO_RELEASE ((NTSTATUS) 0xC0000211L)
+#endif
+
+#ifndef STATUS_TRANSACTION_NO_MATCH
+# define STATUS_TRANSACTION_NO_MATCH ((NTSTATUS) 0xC0000212L)
+#endif
+
+#ifndef STATUS_TRANSACTION_RESPONDED
+# define STATUS_TRANSACTION_RESPONDED ((NTSTATUS) 0xC0000213L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_ID
+# define STATUS_TRANSACTION_INVALID_ID ((NTSTATUS) 0xC0000214L)
+#endif
+
+#ifndef STATUS_TRANSACTION_INVALID_TYPE
+# define STATUS_TRANSACTION_INVALID_TYPE ((NTSTATUS) 0xC0000215L)
+#endif
+
+#ifndef STATUS_NOT_SERVER_SESSION
+# define STATUS_NOT_SERVER_SESSION ((NTSTATUS) 0xC0000216L)
+#endif
+
+#ifndef STATUS_NOT_CLIENT_SESSION
+# define STATUS_NOT_CLIENT_SESSION ((NTSTATUS) 0xC0000217L)
+#endif
+
+#ifndef STATUS_CANNOT_LOAD_REGISTRY_FILE
+# define STATUS_CANNOT_LOAD_REGISTRY_FILE ((NTSTATUS) 0xC0000218L)
+#endif
+
+#ifndef STATUS_DEBUG_ATTACH_FAILED
+# define STATUS_DEBUG_ATTACH_FAILED ((NTSTATUS) 0xC0000219L)
+#endif
+
+#ifndef STATUS_SYSTEM_PROCESS_TERMINATED
+# define STATUS_SYSTEM_PROCESS_TERMINATED ((NTSTATUS) 0xC000021AL)
+#endif
+
+#ifndef STATUS_DATA_NOT_ACCEPTED
+# define STATUS_DATA_NOT_ACCEPTED ((NTSTATUS) 0xC000021BL)
+#endif
+
+#ifndef STATUS_NO_BROWSER_SERVERS_FOUND
+# define STATUS_NO_BROWSER_SERVERS_FOUND ((NTSTATUS) 0xC000021CL)
+#endif
+
+#ifndef STATUS_VDM_HARD_ERROR
+# define STATUS_VDM_HARD_ERROR ((NTSTATUS) 0xC000021DL)
+#endif
+
+#ifndef STATUS_DRIVER_CANCEL_TIMEOUT
+# define STATUS_DRIVER_CANCEL_TIMEOUT ((NTSTATUS) 0xC000021EL)
+#endif
+
+#ifndef STATUS_REPLY_MESSAGE_MISMATCH
+# define STATUS_REPLY_MESSAGE_MISMATCH ((NTSTATUS) 0xC000021FL)
+#endif
+
+#ifndef STATUS_MAPPED_ALIGNMENT
+# define STATUS_MAPPED_ALIGNMENT ((NTSTATUS) 0xC0000220L)
+#endif
+
+#ifndef STATUS_IMAGE_CHECKSUM_MISMATCH
+# define STATUS_IMAGE_CHECKSUM_MISMATCH ((NTSTATUS) 0xC0000221L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA
+# define STATUS_LOST_WRITEBEHIND_DATA ((NTSTATUS) 0xC0000222L)
+#endif
+
+#ifndef STATUS_CLIENT_SERVER_PARAMETERS_INVALID
+# define STATUS_CLIENT_SERVER_PARAMETERS_INVALID ((NTSTATUS) 0xC0000223L)
+#endif
+
+#ifndef STATUS_PASSWORD_MUST_CHANGE
+# define STATUS_PASSWORD_MUST_CHANGE ((NTSTATUS) 0xC0000224L)
+#endif
+
+#ifndef STATUS_NOT_FOUND
+# define STATUS_NOT_FOUND ((NTSTATUS) 0xC0000225L)
+#endif
+
+#ifndef STATUS_NOT_TINY_STREAM
+# define STATUS_NOT_TINY_STREAM ((NTSTATUS) 0xC0000226L)
+#endif
+
+#ifndef STATUS_RECOVERY_FAILURE
+# define STATUS_RECOVERY_FAILURE ((NTSTATUS) 0xC0000227L)
+#endif
+
+#ifndef STATUS_STACK_OVERFLOW_READ
+# define STATUS_STACK_OVERFLOW_READ ((NTSTATUS) 0xC0000228L)
+#endif
+
+#ifndef STATUS_FAIL_CHECK
+# define STATUS_FAIL_CHECK ((NTSTATUS) 0xC0000229L)
+#endif
+
+#ifndef STATUS_DUPLICATE_OBJECTID
+# define STATUS_DUPLICATE_OBJECTID ((NTSTATUS) 0xC000022AL)
+#endif
+
+#ifndef STATUS_OBJECTID_EXISTS
+# define STATUS_OBJECTID_EXISTS ((NTSTATUS) 0xC000022BL)
+#endif
+
+#ifndef STATUS_CONVERT_TO_LARGE
+# define STATUS_CONVERT_TO_LARGE ((NTSTATUS) 0xC000022CL)
+#endif
+
+#ifndef STATUS_RETRY
+# define STATUS_RETRY ((NTSTATUS) 0xC000022DL)
+#endif
+
+#ifndef STATUS_FOUND_OUT_OF_SCOPE
+# define STATUS_FOUND_OUT_OF_SCOPE ((NTSTATUS) 0xC000022EL)
+#endif
+
+#ifndef STATUS_ALLOCATE_BUCKET
+# define STATUS_ALLOCATE_BUCKET ((NTSTATUS) 0xC000022FL)
+#endif
+
+#ifndef STATUS_PROPSET_NOT_FOUND
+# define STATUS_PROPSET_NOT_FOUND ((NTSTATUS) 0xC0000230L)
+#endif
+
+#ifndef STATUS_MARSHALL_OVERFLOW
+# define STATUS_MARSHALL_OVERFLOW ((NTSTATUS) 0xC0000231L)
+#endif
+
+#ifndef STATUS_INVALID_VARIANT
+# define STATUS_INVALID_VARIANT ((NTSTATUS) 0xC0000232L)
+#endif
+
+#ifndef STATUS_DOMAIN_CONTROLLER_NOT_FOUND
+# define STATUS_DOMAIN_CONTROLLER_NOT_FOUND ((NTSTATUS) 0xC0000233L)
+#endif
+
+#ifndef STATUS_ACCOUNT_LOCKED_OUT
+# define STATUS_ACCOUNT_LOCKED_OUT ((NTSTATUS) 0xC0000234L)
+#endif
+
+#ifndef STATUS_HANDLE_NOT_CLOSABLE
+# define STATUS_HANDLE_NOT_CLOSABLE ((NTSTATUS) 0xC0000235L)
+#endif
+
+#ifndef STATUS_CONNECTION_REFUSED
+# define STATUS_CONNECTION_REFUSED ((NTSTATUS) 0xC0000236L)
+#endif
+
+#ifndef STATUS_GRACEFUL_DISCONNECT
+# define STATUS_GRACEFUL_DISCONNECT ((NTSTATUS) 0xC0000237L)
+#endif
+
+#ifndef STATUS_ADDRESS_ALREADY_ASSOCIATED
+# define STATUS_ADDRESS_ALREADY_ASSOCIATED ((NTSTATUS) 0xC0000238L)
+#endif
+
+#ifndef STATUS_ADDRESS_NOT_ASSOCIATED
+# define STATUS_ADDRESS_NOT_ASSOCIATED ((NTSTATUS) 0xC0000239L)
+#endif
+
+#ifndef STATUS_CONNECTION_INVALID
+# define STATUS_CONNECTION_INVALID ((NTSTATUS) 0xC000023AL)
+#endif
+
+#ifndef STATUS_CONNECTION_ACTIVE
+# define STATUS_CONNECTION_ACTIVE ((NTSTATUS) 0xC000023BL)
+#endif
+
+#ifndef STATUS_NETWORK_UNREACHABLE
+# define STATUS_NETWORK_UNREACHABLE ((NTSTATUS) 0xC000023CL)
+#endif
+
+#ifndef STATUS_HOST_UNREACHABLE
+# define STATUS_HOST_UNREACHABLE ((NTSTATUS) 0xC000023DL)
+#endif
+
+#ifndef STATUS_PROTOCOL_UNREACHABLE
+# define STATUS_PROTOCOL_UNREACHABLE ((NTSTATUS) 0xC000023EL)
+#endif
+
+#ifndef STATUS_PORT_UNREACHABLE
+# define STATUS_PORT_UNREACHABLE ((NTSTATUS) 0xC000023FL)
+#endif
+
+#ifndef STATUS_REQUEST_ABORTED
+# define STATUS_REQUEST_ABORTED ((NTSTATUS) 0xC0000240L)
+#endif
+
+#ifndef STATUS_CONNECTION_ABORTED
+# define STATUS_CONNECTION_ABORTED ((NTSTATUS) 0xC0000241L)
+#endif
+
+#ifndef STATUS_BAD_COMPRESSION_BUFFER
+# define STATUS_BAD_COMPRESSION_BUFFER ((NTSTATUS) 0xC0000242L)
+#endif
+
+#ifndef STATUS_USER_MAPPED_FILE
+# define STATUS_USER_MAPPED_FILE ((NTSTATUS) 0xC0000243L)
+#endif
+
+#ifndef STATUS_AUDIT_FAILED
+# define STATUS_AUDIT_FAILED ((NTSTATUS) 0xC0000244L)
+#endif
+
+#ifndef STATUS_TIMER_RESOLUTION_NOT_SET
+# define STATUS_TIMER_RESOLUTION_NOT_SET ((NTSTATUS) 0xC0000245L)
+#endif
+
+#ifndef STATUS_CONNECTION_COUNT_LIMIT
+# define STATUS_CONNECTION_COUNT_LIMIT ((NTSTATUS) 0xC0000246L)
+#endif
+
+#ifndef STATUS_LOGIN_TIME_RESTRICTION
+# define STATUS_LOGIN_TIME_RESTRICTION ((NTSTATUS) 0xC0000247L)
+#endif
+
+#ifndef STATUS_LOGIN_WKSTA_RESTRICTION
+# define STATUS_LOGIN_WKSTA_RESTRICTION ((NTSTATUS) 0xC0000248L)
+#endif
+
+#ifndef STATUS_IMAGE_MP_UP_MISMATCH
+# define STATUS_IMAGE_MP_UP_MISMATCH ((NTSTATUS) 0xC0000249L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_LOGON_INFO
+# define STATUS_INSUFFICIENT_LOGON_INFO ((NTSTATUS) 0xC0000250L)
+#endif
+
+#ifndef STATUS_BAD_DLL_ENTRYPOINT
+# define STATUS_BAD_DLL_ENTRYPOINT ((NTSTATUS) 0xC0000251L)
+#endif
+
+#ifndef STATUS_BAD_SERVICE_ENTRYPOINT
+# define STATUS_BAD_SERVICE_ENTRYPOINT ((NTSTATUS) 0xC0000252L)
+#endif
+
+#ifndef STATUS_LPC_REPLY_LOST
+# define STATUS_LPC_REPLY_LOST ((NTSTATUS) 0xC0000253L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT1
+# define STATUS_IP_ADDRESS_CONFLICT1 ((NTSTATUS) 0xC0000254L)
+#endif
+
+#ifndef STATUS_IP_ADDRESS_CONFLICT2
+# define STATUS_IP_ADDRESS_CONFLICT2 ((NTSTATUS) 0xC0000255L)
+#endif
+
+#ifndef STATUS_REGISTRY_QUOTA_LIMIT
+# define STATUS_REGISTRY_QUOTA_LIMIT ((NTSTATUS) 0xC0000256L)
+#endif
+
+#ifndef STATUS_PATH_NOT_COVERED
+# define STATUS_PATH_NOT_COVERED ((NTSTATUS) 0xC0000257L)
+#endif
+
+#ifndef STATUS_NO_CALLBACK_ACTIVE
+# define STATUS_NO_CALLBACK_ACTIVE ((NTSTATUS) 0xC0000258L)
+#endif
+
+#ifndef STATUS_LICENSE_QUOTA_EXCEEDED
+# define STATUS_LICENSE_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000259L)
+#endif
+
+#ifndef STATUS_PWD_TOO_SHORT
+# define STATUS_PWD_TOO_SHORT ((NTSTATUS) 0xC000025AL)
+#endif
+
+#ifndef STATUS_PWD_TOO_RECENT
+# define STATUS_PWD_TOO_RECENT ((NTSTATUS) 0xC000025BL)
+#endif
+
+#ifndef STATUS_PWD_HISTORY_CONFLICT
+# define STATUS_PWD_HISTORY_CONFLICT ((NTSTATUS) 0xC000025CL)
+#endif
+
+#ifndef STATUS_PLUGPLAY_NO_DEVICE
+# define STATUS_PLUGPLAY_NO_DEVICE ((NTSTATUS) 0xC000025EL)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_COMPRESSION
+# define STATUS_UNSUPPORTED_COMPRESSION ((NTSTATUS) 0xC000025FL)
+#endif
+
+#ifndef STATUS_INVALID_HW_PROFILE
+# define STATUS_INVALID_HW_PROFILE ((NTSTATUS) 0xC0000260L)
+#endif
+
+#ifndef STATUS_INVALID_PLUGPLAY_DEVICE_PATH
+# define STATUS_INVALID_PLUGPLAY_DEVICE_PATH ((NTSTATUS) 0xC0000261L)
+#endif
+
+#ifndef STATUS_DRIVER_ORDINAL_NOT_FOUND
+# define STATUS_DRIVER_ORDINAL_NOT_FOUND ((NTSTATUS) 0xC0000262L)
+#endif
+
+#ifndef STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+# define STATUS_DRIVER_ENTRYPOINT_NOT_FOUND ((NTSTATUS) 0xC0000263L)
+#endif
+
+#ifndef STATUS_RESOURCE_NOT_OWNED
+# define STATUS_RESOURCE_NOT_OWNED ((NTSTATUS) 0xC0000264L)
+#endif
+
+#ifndef STATUS_TOO_MANY_LINKS
+# define STATUS_TOO_MANY_LINKS ((NTSTATUS) 0xC0000265L)
+#endif
+
+#ifndef STATUS_QUOTA_LIST_INCONSISTENT
+# define STATUS_QUOTA_LIST_INCONSISTENT ((NTSTATUS) 0xC0000266L)
+#endif
+
+#ifndef STATUS_FILE_IS_OFFLINE
+# define STATUS_FILE_IS_OFFLINE ((NTSTATUS) 0xC0000267L)
+#endif
+
+#ifndef STATUS_EVALUATION_EXPIRATION
+# define STATUS_EVALUATION_EXPIRATION ((NTSTATUS) 0xC0000268L)
+#endif
+
+#ifndef STATUS_ILLEGAL_DLL_RELOCATION
+# define STATUS_ILLEGAL_DLL_RELOCATION ((NTSTATUS) 0xC0000269L)
+#endif
+
+#ifndef STATUS_LICENSE_VIOLATION
+# define STATUS_LICENSE_VIOLATION ((NTSTATUS) 0xC000026AL)
+#endif
+
+#ifndef STATUS_DLL_INIT_FAILED_LOGOFF
+# define STATUS_DLL_INIT_FAILED_LOGOFF ((NTSTATUS) 0xC000026BL)
+#endif
+
+#ifndef STATUS_DRIVER_UNABLE_TO_LOAD
+# define STATUS_DRIVER_UNABLE_TO_LOAD ((NTSTATUS) 0xC000026CL)
+#endif
+
+#ifndef STATUS_DFS_UNAVAILABLE
+# define STATUS_DFS_UNAVAILABLE ((NTSTATUS) 0xC000026DL)
+#endif
+
+#ifndef STATUS_VOLUME_DISMOUNTED
+# define STATUS_VOLUME_DISMOUNTED ((NTSTATUS) 0xC000026EL)
+#endif
+
+#ifndef STATUS_WX86_INTERNAL_ERROR
+# define STATUS_WX86_INTERNAL_ERROR ((NTSTATUS) 0xC000026FL)
+#endif
+
+#ifndef STATUS_WX86_FLOAT_STACK_CHECK
+# define STATUS_WX86_FLOAT_STACK_CHECK ((NTSTATUS) 0xC0000270L)
+#endif
+
+#ifndef STATUS_VALIDATE_CONTINUE
+# define STATUS_VALIDATE_CONTINUE ((NTSTATUS) 0xC0000271L)
+#endif
+
+#ifndef STATUS_NO_MATCH
+# define STATUS_NO_MATCH ((NTSTATUS) 0xC0000272L)
+#endif
+
+#ifndef STATUS_NO_MORE_MATCHES
+# define STATUS_NO_MORE_MATCHES ((NTSTATUS) 0xC0000273L)
+#endif
+
+#ifndef STATUS_NOT_A_REPARSE_POINT
+# define STATUS_NOT_A_REPARSE_POINT ((NTSTATUS) 0xC0000275L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_INVALID
+# define STATUS_IO_REPARSE_TAG_INVALID ((NTSTATUS) 0xC0000276L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_MISMATCH
+# define STATUS_IO_REPARSE_TAG_MISMATCH ((NTSTATUS) 0xC0000277L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_DATA_INVALID
+# define STATUS_IO_REPARSE_DATA_INVALID ((NTSTATUS) 0xC0000278L)
+#endif
+
+#ifndef STATUS_IO_REPARSE_TAG_NOT_HANDLED
+# define STATUS_IO_REPARSE_TAG_NOT_HANDLED ((NTSTATUS) 0xC0000279L)
+#endif
+
+#ifndef STATUS_REPARSE_POINT_NOT_RESOLVED
+# define STATUS_REPARSE_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000280L)
+#endif
+
+#ifndef STATUS_DIRECTORY_IS_A_REPARSE_POINT
+# define STATUS_DIRECTORY_IS_A_REPARSE_POINT ((NTSTATUS) 0xC0000281L)
+#endif
+
+#ifndef STATUS_RANGE_LIST_CONFLICT
+# define STATUS_RANGE_LIST_CONFLICT ((NTSTATUS) 0xC0000282L)
+#endif
+
+#ifndef STATUS_SOURCE_ELEMENT_EMPTY
+# define STATUS_SOURCE_ELEMENT_EMPTY ((NTSTATUS) 0xC0000283L)
+#endif
+
+#ifndef STATUS_DESTINATION_ELEMENT_FULL
+# define STATUS_DESTINATION_ELEMENT_FULL ((NTSTATUS) 0xC0000284L)
+#endif
+
+#ifndef STATUS_ILLEGAL_ELEMENT_ADDRESS
+# define STATUS_ILLEGAL_ELEMENT_ADDRESS ((NTSTATUS) 0xC0000285L)
+#endif
+
+#ifndef STATUS_MAGAZINE_NOT_PRESENT
+# define STATUS_MAGAZINE_NOT_PRESENT ((NTSTATUS) 0xC0000286L)
+#endif
+
+#ifndef STATUS_REINITIALIZATION_NEEDED
+# define STATUS_REINITIALIZATION_NEEDED ((NTSTATUS) 0xC0000287L)
+#endif
+
+#ifndef STATUS_DEVICE_REQUIRES_CLEANING
+# define STATUS_DEVICE_REQUIRES_CLEANING ((NTSTATUS) 0x80000288L)
+#endif
+
+#ifndef STATUS_DEVICE_DOOR_OPEN
+# define STATUS_DEVICE_DOOR_OPEN ((NTSTATUS) 0x80000289L)
+#endif
+
+#ifndef STATUS_ENCRYPTION_FAILED
+# define STATUS_ENCRYPTION_FAILED ((NTSTATUS) 0xC000028AL)
+#endif
+
+#ifndef STATUS_DECRYPTION_FAILED
+# define STATUS_DECRYPTION_FAILED ((NTSTATUS) 0xC000028BL)
+#endif
+
+#ifndef STATUS_RANGE_NOT_FOUND
+# define STATUS_RANGE_NOT_FOUND ((NTSTATUS) 0xC000028CL)
+#endif
+
+#ifndef STATUS_NO_RECOVERY_POLICY
+# define STATUS_NO_RECOVERY_POLICY ((NTSTATUS) 0xC000028DL)
+#endif
+
+#ifndef STATUS_NO_EFS
+# define STATUS_NO_EFS ((NTSTATUS) 0xC000028EL)
+#endif
+
+#ifndef STATUS_WRONG_EFS
+# define STATUS_WRONG_EFS ((NTSTATUS) 0xC000028FL)
+#endif
+
+#ifndef STATUS_NO_USER_KEYS
+# define STATUS_NO_USER_KEYS ((NTSTATUS) 0xC0000290L)
+#endif
+
+#ifndef STATUS_FILE_NOT_ENCRYPTED
+# define STATUS_FILE_NOT_ENCRYPTED ((NTSTATUS) 0xC0000291L)
+#endif
+
+#ifndef STATUS_NOT_EXPORT_FORMAT
+# define STATUS_NOT_EXPORT_FORMAT ((NTSTATUS) 0xC0000292L)
+#endif
+
+#ifndef STATUS_FILE_ENCRYPTED
+# define STATUS_FILE_ENCRYPTED ((NTSTATUS) 0xC0000293L)
+#endif
+
+#ifndef STATUS_WAKE_SYSTEM
+# define STATUS_WAKE_SYSTEM ((NTSTATUS) 0x40000294L)
+#endif
+
+#ifndef STATUS_WMI_GUID_NOT_FOUND
+# define STATUS_WMI_GUID_NOT_FOUND ((NTSTATUS) 0xC0000295L)
+#endif
+
+#ifndef STATUS_WMI_INSTANCE_NOT_FOUND
+# define STATUS_WMI_INSTANCE_NOT_FOUND ((NTSTATUS) 0xC0000296L)
+#endif
+
+#ifndef STATUS_WMI_ITEMID_NOT_FOUND
+# define STATUS_WMI_ITEMID_NOT_FOUND ((NTSTATUS) 0xC0000297L)
+#endif
+
+#ifndef STATUS_WMI_TRY_AGAIN
+# define STATUS_WMI_TRY_AGAIN ((NTSTATUS) 0xC0000298L)
+#endif
+
+#ifndef STATUS_SHARED_POLICY
+# define STATUS_SHARED_POLICY ((NTSTATUS) 0xC0000299L)
+#endif
+
+#ifndef STATUS_POLICY_OBJECT_NOT_FOUND
+# define STATUS_POLICY_OBJECT_NOT_FOUND ((NTSTATUS) 0xC000029AL)
+#endif
+
+#ifndef STATUS_POLICY_ONLY_IN_DS
+# define STATUS_POLICY_ONLY_IN_DS ((NTSTATUS) 0xC000029BL)
+#endif
+
+#ifndef STATUS_VOLUME_NOT_UPGRADED
+# define STATUS_VOLUME_NOT_UPGRADED ((NTSTATUS) 0xC000029CL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_NOT_ACTIVE
+# define STATUS_REMOTE_STORAGE_NOT_ACTIVE ((NTSTATUS) 0xC000029DL)
+#endif
+
+#ifndef STATUS_REMOTE_STORAGE_MEDIA_ERROR
+# define STATUS_REMOTE_STORAGE_MEDIA_ERROR ((NTSTATUS) 0xC000029EL)
+#endif
+
+#ifndef STATUS_NO_TRACKING_SERVICE
+# define STATUS_NO_TRACKING_SERVICE ((NTSTATUS) 0xC000029FL)
+#endif
+
+#ifndef STATUS_SERVER_SID_MISMATCH
+# define STATUS_SERVER_SID_MISMATCH ((NTSTATUS) 0xC00002A0L)
+#endif
+
+#ifndef STATUS_DS_NO_ATTRIBUTE_OR_VALUE
+# define STATUS_DS_NO_ATTRIBUTE_OR_VALUE ((NTSTATUS) 0xC00002A1L)
+#endif
+
+#ifndef STATUS_DS_INVALID_ATTRIBUTE_SYNTAX
+# define STATUS_DS_INVALID_ATTRIBUTE_SYNTAX ((NTSTATUS) 0xC00002A2L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED
+# define STATUS_DS_ATTRIBUTE_TYPE_UNDEFINED ((NTSTATUS) 0xC00002A3L)
+#endif
+
+#ifndef STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS
+# define STATUS_DS_ATTRIBUTE_OR_VALUE_EXISTS ((NTSTATUS) 0xC00002A4L)
+#endif
+
+#ifndef STATUS_DS_BUSY
+# define STATUS_DS_BUSY ((NTSTATUS) 0xC00002A5L)
+#endif
+
+#ifndef STATUS_DS_UNAVAILABLE
+# define STATUS_DS_UNAVAILABLE ((NTSTATUS) 0xC00002A6L)
+#endif
+
+#ifndef STATUS_DS_NO_RIDS_ALLOCATED
+# define STATUS_DS_NO_RIDS_ALLOCATED ((NTSTATUS) 0xC00002A7L)
+#endif
+
+#ifndef STATUS_DS_NO_MORE_RIDS
+# define STATUS_DS_NO_MORE_RIDS ((NTSTATUS) 0xC00002A8L)
+#endif
+
+#ifndef STATUS_DS_INCORRECT_ROLE_OWNER
+# define STATUS_DS_INCORRECT_ROLE_OWNER ((NTSTATUS) 0xC00002A9L)
+#endif
+
+#ifndef STATUS_DS_RIDMGR_INIT_ERROR
+# define STATUS_DS_RIDMGR_INIT_ERROR ((NTSTATUS) 0xC00002AAL)
+#endif
+
+#ifndef STATUS_DS_OBJ_CLASS_VIOLATION
+# define STATUS_DS_OBJ_CLASS_VIOLATION ((NTSTATUS) 0xC00002ABL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_NON_LEAF
+# define STATUS_DS_CANT_ON_NON_LEAF ((NTSTATUS) 0xC00002ACL)
+#endif
+
+#ifndef STATUS_DS_CANT_ON_RDN
+# define STATUS_DS_CANT_ON_RDN ((NTSTATUS) 0xC00002ADL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_OBJ_CLASS
+# define STATUS_DS_CANT_MOD_OBJ_CLASS ((NTSTATUS) 0xC00002AEL)
+#endif
+
+#ifndef STATUS_DS_CROSS_DOM_MOVE_FAILED
+# define STATUS_DS_CROSS_DOM_MOVE_FAILED ((NTSTATUS) 0xC00002AFL)
+#endif
+
+#ifndef STATUS_DS_GC_NOT_AVAILABLE
+# define STATUS_DS_GC_NOT_AVAILABLE ((NTSTATUS) 0xC00002B0L)
+#endif
+
+#ifndef STATUS_DIRECTORY_SERVICE_REQUIRED
+# define STATUS_DIRECTORY_SERVICE_REQUIRED ((NTSTATUS) 0xC00002B1L)
+#endif
+
+#ifndef STATUS_REPARSE_ATTRIBUTE_CONFLICT
+# define STATUS_REPARSE_ATTRIBUTE_CONFLICT ((NTSTATUS) 0xC00002B2L)
+#endif
+
+#ifndef STATUS_CANT_ENABLE_DENY_ONLY
+# define STATUS_CANT_ENABLE_DENY_ONLY ((NTSTATUS) 0xC00002B3L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_FAULTS
+# define STATUS_FLOAT_MULTIPLE_FAULTS ((NTSTATUS) 0xC00002B4L)
+#endif
+
+#ifndef STATUS_FLOAT_MULTIPLE_TRAPS
+# define STATUS_FLOAT_MULTIPLE_TRAPS ((NTSTATUS) 0xC00002B5L)
+#endif
+
+#ifndef STATUS_DEVICE_REMOVED
+# define STATUS_DEVICE_REMOVED ((NTSTATUS) 0xC00002B6L)
+#endif
+
+#ifndef STATUS_JOURNAL_DELETE_IN_PROGRESS
+# define STATUS_JOURNAL_DELETE_IN_PROGRESS ((NTSTATUS) 0xC00002B7L)
+#endif
+
+#ifndef STATUS_JOURNAL_NOT_ACTIVE
+# define STATUS_JOURNAL_NOT_ACTIVE ((NTSTATUS) 0xC00002B8L)
+#endif
+
+#ifndef STATUS_NOINTERFACE
+# define STATUS_NOINTERFACE ((NTSTATUS) 0xC00002B9L)
+#endif
+
+#ifndef STATUS_DS_ADMIN_LIMIT_EXCEEDED
+# define STATUS_DS_ADMIN_LIMIT_EXCEEDED ((NTSTATUS) 0xC00002C1L)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_SLEEP
+# define STATUS_DRIVER_FAILED_SLEEP ((NTSTATUS) 0xC00002C2L)
+#endif
+
+#ifndef STATUS_MUTUAL_AUTHENTICATION_FAILED
+# define STATUS_MUTUAL_AUTHENTICATION_FAILED ((NTSTATUS) 0xC00002C3L)
+#endif
+
+#ifndef STATUS_CORRUPT_SYSTEM_FILE
+# define STATUS_CORRUPT_SYSTEM_FILE ((NTSTATUS) 0xC00002C4L)
+#endif
+
+#ifndef STATUS_DATATYPE_MISALIGNMENT_ERROR
+# define STATUS_DATATYPE_MISALIGNMENT_ERROR ((NTSTATUS) 0xC00002C5L)
+#endif
+
+#ifndef STATUS_WMI_READ_ONLY
+# define STATUS_WMI_READ_ONLY ((NTSTATUS) 0xC00002C6L)
+#endif
+
+#ifndef STATUS_WMI_SET_FAILURE
+# define STATUS_WMI_SET_FAILURE ((NTSTATUS) 0xC00002C7L)
+#endif
+
+#ifndef STATUS_COMMITMENT_MINIMUM
+# define STATUS_COMMITMENT_MINIMUM ((NTSTATUS) 0xC00002C8L)
+#endif
+
+#ifndef STATUS_REG_NAT_CONSUMPTION
+# define STATUS_REG_NAT_CONSUMPTION ((NTSTATUS) 0xC00002C9L)
+#endif
+
+#ifndef STATUS_TRANSPORT_FULL
+# define STATUS_TRANSPORT_FULL ((NTSTATUS) 0xC00002CAL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE
+# define STATUS_DS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002CBL)
+#endif
+
+#ifndef STATUS_ONLY_IF_CONNECTED
+# define STATUS_ONLY_IF_CONNECTED ((NTSTATUS) 0xC00002CCL)
+#endif
+
+#ifndef STATUS_DS_SENSITIVE_GROUP_VIOLATION
+# define STATUS_DS_SENSITIVE_GROUP_VIOLATION ((NTSTATUS) 0xC00002CDL)
+#endif
+
+#ifndef STATUS_PNP_RESTART_ENUMERATION
+# define STATUS_PNP_RESTART_ENUMERATION ((NTSTATUS) 0xC00002CEL)
+#endif
+
+#ifndef STATUS_JOURNAL_ENTRY_DELETED
+# define STATUS_JOURNAL_ENTRY_DELETED ((NTSTATUS) 0xC00002CFL)
+#endif
+
+#ifndef STATUS_DS_CANT_MOD_PRIMARYGROUPID
+# define STATUS_DS_CANT_MOD_PRIMARYGROUPID ((NTSTATUS) 0xC00002D0L)
+#endif
+
+#ifndef STATUS_SYSTEM_IMAGE_BAD_SIGNATURE
+# define STATUS_SYSTEM_IMAGE_BAD_SIGNATURE ((NTSTATUS) 0xC00002D1L)
+#endif
+
+#ifndef STATUS_PNP_REBOOT_REQUIRED
+# define STATUS_PNP_REBOOT_REQUIRED ((NTSTATUS) 0xC00002D2L)
+#endif
+
+#ifndef STATUS_POWER_STATE_INVALID
+# define STATUS_POWER_STATE_INVALID ((NTSTATUS) 0xC00002D3L)
+#endif
+
+#ifndef STATUS_DS_INVALID_GROUP_TYPE
+# define STATUS_DS_INVALID_GROUP_TYPE ((NTSTATUS) 0xC00002D4L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_GLOBALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D5L)
+#endif
+
+#ifndef STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN
+# define STATUS_DS_NO_NEST_LOCALGROUP_IN_MIXEDDOMAIN ((NTSTATUS) 0xC00002D6L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D7L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC00002D8L)
+#endif
+
+#ifndef STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER
+# define STATUS_DS_UNIVERSAL_CANT_HAVE_LOCAL_MEMBER ((NTSTATUS) 0xC00002D9L)
+#endif
+
+#ifndef STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER
+# define STATUS_DS_GLOBAL_CANT_HAVE_CROSSDOMAIN_MEMBER ((NTSTATUS) 0xC00002DAL)
+#endif
+
+#ifndef STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER
+# define STATUS_DS_LOCAL_CANT_HAVE_CROSSDOMAIN_LOCAL_MEMBER ((NTSTATUS) 0xC00002DBL)
+#endif
+
+#ifndef STATUS_DS_HAVE_PRIMARY_MEMBERS
+# define STATUS_DS_HAVE_PRIMARY_MEMBERS ((NTSTATUS) 0xC00002DCL)
+#endif
+
+#ifndef STATUS_WMI_NOT_SUPPORTED
+# define STATUS_WMI_NOT_SUPPORTED ((NTSTATUS) 0xC00002DDL)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_POWER
+# define STATUS_INSUFFICIENT_POWER ((NTSTATUS) 0xC00002DEL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_PASSWORD
+# define STATUS_SAM_NEED_BOOTKEY_PASSWORD ((NTSTATUS) 0xC00002DFL)
+#endif
+
+#ifndef STATUS_SAM_NEED_BOOTKEY_FLOPPY
+# define STATUS_SAM_NEED_BOOTKEY_FLOPPY ((NTSTATUS) 0xC00002E0L)
+#endif
+
+#ifndef STATUS_DS_CANT_START
+# define STATUS_DS_CANT_START ((NTSTATUS) 0xC00002E1L)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE
+# define STATUS_DS_INIT_FAILURE ((NTSTATUS) 0xC00002E2L)
+#endif
+
+#ifndef STATUS_SAM_INIT_FAILURE
+# define STATUS_SAM_INIT_FAILURE ((NTSTATUS) 0xC00002E3L)
+#endif
+
+#ifndef STATUS_DS_GC_REQUIRED
+# define STATUS_DS_GC_REQUIRED ((NTSTATUS) 0xC00002E4L)
+#endif
+
+#ifndef STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY
+# define STATUS_DS_LOCAL_MEMBER_OF_LOCAL_ONLY ((NTSTATUS) 0xC00002E5L)
+#endif
+
+#ifndef STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS
+# define STATUS_DS_NO_FPO_IN_UNIVERSAL_GROUPS ((NTSTATUS) 0xC00002E6L)
+#endif
+
+#ifndef STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED
+# define STATUS_DS_MACHINE_ACCOUNT_QUOTA_EXCEEDED ((NTSTATUS) 0xC00002E7L)
+#endif
+
+#ifndef STATUS_MULTIPLE_FAULT_VIOLATION
+# define STATUS_MULTIPLE_FAULT_VIOLATION ((NTSTATUS) 0xC00002E8L)
+#endif
+
+#ifndef STATUS_CURRENT_DOMAIN_NOT_ALLOWED
+# define STATUS_CURRENT_DOMAIN_NOT_ALLOWED ((NTSTATUS) 0xC00002E9L)
+#endif
+
+#ifndef STATUS_CANNOT_MAKE
+# define STATUS_CANNOT_MAKE ((NTSTATUS) 0xC00002EAL)
+#endif
+
+#ifndef STATUS_SYSTEM_SHUTDOWN
+# define STATUS_SYSTEM_SHUTDOWN ((NTSTATUS) 0xC00002EBL)
+#endif
+
+#ifndef STATUS_DS_INIT_FAILURE_CONSOLE
+# define STATUS_DS_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002ECL)
+#endif
+
+#ifndef STATUS_DS_SAM_INIT_FAILURE_CONSOLE
+# define STATUS_DS_SAM_INIT_FAILURE_CONSOLE ((NTSTATUS) 0xC00002EDL)
+#endif
+
+#ifndef STATUS_UNFINISHED_CONTEXT_DELETED
+# define STATUS_UNFINISHED_CONTEXT_DELETED ((NTSTATUS) 0xC00002EEL)
+#endif
+
+#ifndef STATUS_NO_TGT_REPLY
+# define STATUS_NO_TGT_REPLY ((NTSTATUS) 0xC00002EFL)
+#endif
+
+#ifndef STATUS_OBJECTID_NOT_FOUND
+# define STATUS_OBJECTID_NOT_FOUND ((NTSTATUS) 0xC00002F0L)
+#endif
+
+#ifndef STATUS_NO_IP_ADDRESSES
+# define STATUS_NO_IP_ADDRESSES ((NTSTATUS) 0xC00002F1L)
+#endif
+
+#ifndef STATUS_WRONG_CREDENTIAL_HANDLE
+# define STATUS_WRONG_CREDENTIAL_HANDLE ((NTSTATUS) 0xC00002F2L)
+#endif
+
+#ifndef STATUS_CRYPTO_SYSTEM_INVALID
+# define STATUS_CRYPTO_SYSTEM_INVALID ((NTSTATUS) 0xC00002F3L)
+#endif
+
+#ifndef STATUS_MAX_REFERRALS_EXCEEDED
+# define STATUS_MAX_REFERRALS_EXCEEDED ((NTSTATUS) 0xC00002F4L)
+#endif
+
+#ifndef STATUS_MUST_BE_KDC
+# define STATUS_MUST_BE_KDC ((NTSTATUS) 0xC00002F5L)
+#endif
+
+#ifndef STATUS_STRONG_CRYPTO_NOT_SUPPORTED
+# define STATUS_STRONG_CRYPTO_NOT_SUPPORTED ((NTSTATUS) 0xC00002F6L)
+#endif
+
+#ifndef STATUS_TOO_MANY_PRINCIPALS
+# define STATUS_TOO_MANY_PRINCIPALS ((NTSTATUS) 0xC00002F7L)
+#endif
+
+#ifndef STATUS_NO_PA_DATA
+# define STATUS_NO_PA_DATA ((NTSTATUS) 0xC00002F8L)
+#endif
+
+#ifndef STATUS_PKINIT_NAME_MISMATCH
+# define STATUS_PKINIT_NAME_MISMATCH ((NTSTATUS) 0xC00002F9L)
+#endif
+
+#ifndef STATUS_SMARTCARD_LOGON_REQUIRED
+# define STATUS_SMARTCARD_LOGON_REQUIRED ((NTSTATUS) 0xC00002FAL)
+#endif
+
+#ifndef STATUS_KDC_INVALID_REQUEST
+# define STATUS_KDC_INVALID_REQUEST ((NTSTATUS) 0xC00002FBL)
+#endif
+
+#ifndef STATUS_KDC_UNABLE_TO_REFER
+# define STATUS_KDC_UNABLE_TO_REFER ((NTSTATUS) 0xC00002FCL)
+#endif
+
+#ifndef STATUS_KDC_UNKNOWN_ETYPE
+# define STATUS_KDC_UNKNOWN_ETYPE ((NTSTATUS) 0xC00002FDL)
+#endif
+
+#ifndef STATUS_SHUTDOWN_IN_PROGRESS
+# define STATUS_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FEL)
+#endif
+
+#ifndef STATUS_SERVER_SHUTDOWN_IN_PROGRESS
+# define STATUS_SERVER_SHUTDOWN_IN_PROGRESS ((NTSTATUS) 0xC00002FFL)
+#endif
+
+#ifndef STATUS_NOT_SUPPORTED_ON_SBS
+# define STATUS_NOT_SUPPORTED_ON_SBS ((NTSTATUS) 0xC0000300L)
+#endif
+
+#ifndef STATUS_WMI_GUID_DISCONNECTED
+# define STATUS_WMI_GUID_DISCONNECTED ((NTSTATUS) 0xC0000301L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_DISABLED
+# define STATUS_WMI_ALREADY_DISABLED ((NTSTATUS) 0xC0000302L)
+#endif
+
+#ifndef STATUS_WMI_ALREADY_ENABLED
+# define STATUS_WMI_ALREADY_ENABLED ((NTSTATUS) 0xC0000303L)
+#endif
+
+#ifndef STATUS_MFT_TOO_FRAGMENTED
+# define STATUS_MFT_TOO_FRAGMENTED ((NTSTATUS) 0xC0000304L)
+#endif
+
+#ifndef STATUS_COPY_PROTECTION_FAILURE
+# define STATUS_COPY_PROTECTION_FAILURE ((NTSTATUS) 0xC0000305L)
+#endif
+
+#ifndef STATUS_CSS_AUTHENTICATION_FAILURE
+# define STATUS_CSS_AUTHENTICATION_FAILURE ((NTSTATUS) 0xC0000306L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_PRESENT
+# define STATUS_CSS_KEY_NOT_PRESENT ((NTSTATUS) 0xC0000307L)
+#endif
+
+#ifndef STATUS_CSS_KEY_NOT_ESTABLISHED
+# define STATUS_CSS_KEY_NOT_ESTABLISHED ((NTSTATUS) 0xC0000308L)
+#endif
+
+#ifndef STATUS_CSS_SCRAMBLED_SECTOR
+# define STATUS_CSS_SCRAMBLED_SECTOR ((NTSTATUS) 0xC0000309L)
+#endif
+
+#ifndef STATUS_CSS_REGION_MISMATCH
+# define STATUS_CSS_REGION_MISMATCH ((NTSTATUS) 0xC000030AL)
+#endif
+
+#ifndef STATUS_CSS_RESETS_EXHAUSTED
+# define STATUS_CSS_RESETS_EXHAUSTED ((NTSTATUS) 0xC000030BL)
+#endif
+
+#ifndef STATUS_PKINIT_FAILURE
+# define STATUS_PKINIT_FAILURE ((NTSTATUS) 0xC0000320L)
+#endif
+
+#ifndef STATUS_SMARTCARD_SUBSYSTEM_FAILURE
+# define STATUS_SMARTCARD_SUBSYSTEM_FAILURE ((NTSTATUS) 0xC0000321L)
+#endif
+
+#ifndef STATUS_NO_KERB_KEY
+# define STATUS_NO_KERB_KEY ((NTSTATUS) 0xC0000322L)
+#endif
+
+#ifndef STATUS_HOST_DOWN
+# define STATUS_HOST_DOWN ((NTSTATUS) 0xC0000350L)
+#endif
+
+#ifndef STATUS_UNSUPPORTED_PREAUTH
+# define STATUS_UNSUPPORTED_PREAUTH ((NTSTATUS) 0xC0000351L)
+#endif
+
+#ifndef STATUS_EFS_ALG_BLOB_TOO_BIG
+# define STATUS_EFS_ALG_BLOB_TOO_BIG ((NTSTATUS) 0xC0000352L)
+#endif
+
+#ifndef STATUS_PORT_NOT_SET
+# define STATUS_PORT_NOT_SET ((NTSTATUS) 0xC0000353L)
+#endif
+
+#ifndef STATUS_DEBUGGER_INACTIVE
+# define STATUS_DEBUGGER_INACTIVE ((NTSTATUS) 0xC0000354L)
+#endif
+
+#ifndef STATUS_DS_VERSION_CHECK_FAILURE
+# define STATUS_DS_VERSION_CHECK_FAILURE ((NTSTATUS) 0xC0000355L)
+#endif
+
+#ifndef STATUS_AUDITING_DISABLED
+# define STATUS_AUDITING_DISABLED ((NTSTATUS) 0xC0000356L)
+#endif
+
+#ifndef STATUS_PRENT4_MACHINE_ACCOUNT
+# define STATUS_PRENT4_MACHINE_ACCOUNT ((NTSTATUS) 0xC0000357L)
+#endif
+
+#ifndef STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER
+# define STATUS_DS_AG_CANT_HAVE_UNIVERSAL_MEMBER ((NTSTATUS) 0xC0000358L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_32
+# define STATUS_INVALID_IMAGE_WIN_32 ((NTSTATUS) 0xC0000359L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_WIN_64
+# define STATUS_INVALID_IMAGE_WIN_64 ((NTSTATUS) 0xC000035AL)
+#endif
+
+#ifndef STATUS_BAD_BINDINGS
+# define STATUS_BAD_BINDINGS ((NTSTATUS) 0xC000035BL)
+#endif
+
+#ifndef STATUS_NETWORK_SESSION_EXPIRED
+# define STATUS_NETWORK_SESSION_EXPIRED ((NTSTATUS) 0xC000035CL)
+#endif
+
+#ifndef STATUS_APPHELP_BLOCK
+# define STATUS_APPHELP_BLOCK ((NTSTATUS) 0xC000035DL)
+#endif
+
+#ifndef STATUS_ALL_SIDS_FILTERED
+# define STATUS_ALL_SIDS_FILTERED ((NTSTATUS) 0xC000035EL)
+#endif
+
+#ifndef STATUS_NOT_SAFE_MODE_DRIVER
+# define STATUS_NOT_SAFE_MODE_DRIVER ((NTSTATUS) 0xC000035FL)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT
+# define STATUS_ACCESS_DISABLED_BY_POLICY_DEFAULT ((NTSTATUS) 0xC0000361L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PATH
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PATH ((NTSTATUS) 0xC0000362L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_PUBLISHER ((NTSTATUS) 0xC0000363L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_BY_POLICY_OTHER
+# define STATUS_ACCESS_DISABLED_BY_POLICY_OTHER ((NTSTATUS) 0xC0000364L)
+#endif
+
+#ifndef STATUS_FAILED_DRIVER_ENTRY
+# define STATUS_FAILED_DRIVER_ENTRY ((NTSTATUS) 0xC0000365L)
+#endif
+
+#ifndef STATUS_DEVICE_ENUMERATION_ERROR
+# define STATUS_DEVICE_ENUMERATION_ERROR ((NTSTATUS) 0xC0000366L)
+#endif
+
+#ifndef STATUS_MOUNT_POINT_NOT_RESOLVED
+# define STATUS_MOUNT_POINT_NOT_RESOLVED ((NTSTATUS) 0xC0000368L)
+#endif
+
+#ifndef STATUS_INVALID_DEVICE_OBJECT_PARAMETER
+# define STATUS_INVALID_DEVICE_OBJECT_PARAMETER ((NTSTATUS) 0xC0000369L)
+#endif
+
+#ifndef STATUS_MCA_OCCURED
+# define STATUS_MCA_OCCURED ((NTSTATUS) 0xC000036AL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED_CRITICAL
+# define STATUS_DRIVER_BLOCKED_CRITICAL ((NTSTATUS) 0xC000036BL)
+#endif
+
+#ifndef STATUS_DRIVER_BLOCKED
+# define STATUS_DRIVER_BLOCKED ((NTSTATUS) 0xC000036CL)
+#endif
+
+#ifndef STATUS_DRIVER_DATABASE_ERROR
+# define STATUS_DRIVER_DATABASE_ERROR ((NTSTATUS) 0xC000036DL)
+#endif
+
+#ifndef STATUS_SYSTEM_HIVE_TOO_LARGE
+# define STATUS_SYSTEM_HIVE_TOO_LARGE ((NTSTATUS) 0xC000036EL)
+#endif
+
+#ifndef STATUS_INVALID_IMPORT_OF_NON_DLL
+# define STATUS_INVALID_IMPORT_OF_NON_DLL ((NTSTATUS) 0xC000036FL)
+#endif
+
+#ifndef STATUS_DS_SHUTTING_DOWN
+# define STATUS_DS_SHUTTING_DOWN ((NTSTATUS) 0x40000370L)
+#endif
+
+#ifndef STATUS_NO_SECRETS
+# define STATUS_NO_SECRETS ((NTSTATUS) 0xC0000371L)
+#endif
+
+#ifndef STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY
+# define STATUS_ACCESS_DISABLED_NO_SAFER_UI_BY_POLICY ((NTSTATUS) 0xC0000372L)
+#endif
+
+#ifndef STATUS_FAILED_STACK_SWITCH
+# define STATUS_FAILED_STACK_SWITCH ((NTSTATUS) 0xC0000373L)
+#endif
+
+#ifndef STATUS_HEAP_CORRUPTION
+# define STATUS_HEAP_CORRUPTION ((NTSTATUS) 0xC0000374L)
+#endif
+
+#ifndef STATUS_SMARTCARD_WRONG_PIN
+# define STATUS_SMARTCARD_WRONG_PIN ((NTSTATUS) 0xC0000380L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_BLOCKED
+# define STATUS_SMARTCARD_CARD_BLOCKED ((NTSTATUS) 0xC0000381L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED
+# define STATUS_SMARTCARD_CARD_NOT_AUTHENTICATED ((NTSTATUS) 0xC0000382L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CARD
+# define STATUS_SMARTCARD_NO_CARD ((NTSTATUS) 0xC0000383L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEY_CONTAINER
+# define STATUS_SMARTCARD_NO_KEY_CONTAINER ((NTSTATUS) 0xC0000384L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_CERTIFICATE
+# define STATUS_SMARTCARD_NO_CERTIFICATE ((NTSTATUS) 0xC0000385L)
+#endif
+
+#ifndef STATUS_SMARTCARD_NO_KEYSET
+# define STATUS_SMARTCARD_NO_KEYSET ((NTSTATUS) 0xC0000386L)
+#endif
+
+#ifndef STATUS_SMARTCARD_IO_ERROR
+# define STATUS_SMARTCARD_IO_ERROR ((NTSTATUS) 0xC0000387L)
+#endif
+
+#ifndef STATUS_DOWNGRADE_DETECTED
+# define STATUS_DOWNGRADE_DETECTED ((NTSTATUS) 0xC0000388L)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_REVOKED
+# define STATUS_SMARTCARD_CERT_REVOKED ((NTSTATUS) 0xC0000389L)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED
+# define STATUS_ISSUING_CA_UNTRUSTED ((NTSTATUS) 0xC000038AL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_C
+# define STATUS_REVOCATION_OFFLINE_C ((NTSTATUS) 0xC000038BL)
+#endif
+
+#ifndef STATUS_PKINIT_CLIENT_FAILURE
+# define STATUS_PKINIT_CLIENT_FAILURE ((NTSTATUS) 0xC000038CL)
+#endif
+
+#ifndef STATUS_SMARTCARD_CERT_EXPIRED
+# define STATUS_SMARTCARD_CERT_EXPIRED ((NTSTATUS) 0xC000038DL)
+#endif
+
+#ifndef STATUS_DRIVER_FAILED_PRIOR_UNLOAD
+# define STATUS_DRIVER_FAILED_PRIOR_UNLOAD ((NTSTATUS) 0xC000038EL)
+#endif
+
+#ifndef STATUS_SMARTCARD_SILENT_CONTEXT
+# define STATUS_SMARTCARD_SILENT_CONTEXT ((NTSTATUS) 0xC000038FL)
+#endif
+
+#ifndef STATUS_PER_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_PER_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000401L)
+#endif
+
+#ifndef STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED
+# define STATUS_ALL_USER_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000402L)
+#endif
+
+#ifndef STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED
+# define STATUS_USER_DELETE_TRUST_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000403L)
+#endif
+
+#ifndef STATUS_DS_NAME_NOT_UNIQUE
+# define STATUS_DS_NAME_NOT_UNIQUE ((NTSTATUS) 0xC0000404L)
+#endif
+
+#ifndef STATUS_DS_DUPLICATE_ID_FOUND
+# define STATUS_DS_DUPLICATE_ID_FOUND ((NTSTATUS) 0xC0000405L)
+#endif
+
+#ifndef STATUS_DS_GROUP_CONVERSION_ERROR
+# define STATUS_DS_GROUP_CONVERSION_ERROR ((NTSTATUS) 0xC0000406L)
+#endif
+
+#ifndef STATUS_VOLSNAP_PREPARE_HIBERNATE
+# define STATUS_VOLSNAP_PREPARE_HIBERNATE ((NTSTATUS) 0xC0000407L)
+#endif
+
+#ifndef STATUS_USER2USER_REQUIRED
+# define STATUS_USER2USER_REQUIRED ((NTSTATUS) 0xC0000408L)
+#endif
+
+#ifndef STATUS_STACK_BUFFER_OVERRUN
+# define STATUS_STACK_BUFFER_OVERRUN ((NTSTATUS) 0xC0000409L)
+#endif
+
+#ifndef STATUS_NO_S4U_PROT_SUPPORT
+# define STATUS_NO_S4U_PROT_SUPPORT ((NTSTATUS) 0xC000040AL)
+#endif
+
+#ifndef STATUS_CROSSREALM_DELEGATION_FAILURE
+# define STATUS_CROSSREALM_DELEGATION_FAILURE ((NTSTATUS) 0xC000040BL)
+#endif
+
+#ifndef STATUS_REVOCATION_OFFLINE_KDC
+# define STATUS_REVOCATION_OFFLINE_KDC ((NTSTATUS) 0xC000040CL)
+#endif
+
+#ifndef STATUS_ISSUING_CA_UNTRUSTED_KDC
+# define STATUS_ISSUING_CA_UNTRUSTED_KDC ((NTSTATUS) 0xC000040DL)
+#endif
+
+#ifndef STATUS_KDC_CERT_EXPIRED
+# define STATUS_KDC_CERT_EXPIRED ((NTSTATUS) 0xC000040EL)
+#endif
+
+#ifndef STATUS_KDC_CERT_REVOKED
+# define STATUS_KDC_CERT_REVOKED ((NTSTATUS) 0xC000040FL)
+#endif
+
+#ifndef STATUS_PARAMETER_QUOTA_EXCEEDED
+# define STATUS_PARAMETER_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000410L)
+#endif
+
+#ifndef STATUS_HIBERNATION_FAILURE
+# define STATUS_HIBERNATION_FAILURE ((NTSTATUS) 0xC0000411L)
+#endif
+
+#ifndef STATUS_DELAY_LOAD_FAILED
+# define STATUS_DELAY_LOAD_FAILED ((NTSTATUS) 0xC0000412L)
+#endif
+
+#ifndef STATUS_AUTHENTICATION_FIREWALL_FAILED
+# define STATUS_AUTHENTICATION_FIREWALL_FAILED ((NTSTATUS) 0xC0000413L)
+#endif
+
+#ifndef STATUS_VDM_DISALLOWED
+# define STATUS_VDM_DISALLOWED ((NTSTATUS) 0xC0000414L)
+#endif
+
+#ifndef STATUS_HUNG_DISPLAY_DRIVER_THREAD
+# define STATUS_HUNG_DISPLAY_DRIVER_THREAD ((NTSTATUS) 0xC0000415L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE
+# define STATUS_INSUFFICIENT_RESOURCE_FOR_SPECIFIED_SHARED_SECTION_SIZE ((NTSTATUS) 0xC0000416L)
+#endif
+
+#ifndef STATUS_INVALID_CRUNTIME_PARAMETER
+# define STATUS_INVALID_CRUNTIME_PARAMETER ((NTSTATUS) 0xC0000417L)
+#endif
+
+#ifndef STATUS_NTLM_BLOCKED
+# define STATUS_NTLM_BLOCKED ((NTSTATUS) 0xC0000418L)
+#endif
+
+#ifndef STATUS_DS_SRC_SID_EXISTS_IN_FOREST
+# define STATUS_DS_SRC_SID_EXISTS_IN_FOREST ((NTSTATUS) 0xC0000419L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_DOMAIN_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041AL)
+#endif
+
+#ifndef STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST
+# define STATUS_DS_FLAT_NAME_EXISTS_IN_FOREST ((NTSTATUS) 0xC000041BL)
+#endif
+
+#ifndef STATUS_INVALID_USER_PRINCIPAL_NAME
+# define STATUS_INVALID_USER_PRINCIPAL_NAME ((NTSTATUS) 0xC000041CL)
+#endif
+
+#ifndef STATUS_FATAL_USER_CALLBACK_EXCEPTION
+# define STATUS_FATAL_USER_CALLBACK_EXCEPTION ((NTSTATUS) 0xC000041DL)
+#endif
+
+#ifndef STATUS_ASSERTION_FAILURE
+# define STATUS_ASSERTION_FAILURE ((NTSTATUS) 0xC0000420L)
+#endif
+
+#ifndef STATUS_VERIFIER_STOP
+# define STATUS_VERIFIER_STOP ((NTSTATUS) 0xC0000421L)
+#endif
+
+#ifndef STATUS_CALLBACK_POP_STACK
+# define STATUS_CALLBACK_POP_STACK ((NTSTATUS) 0xC0000423L)
+#endif
+
+#ifndef STATUS_INCOMPATIBLE_DRIVER_BLOCKED
+# define STATUS_INCOMPATIBLE_DRIVER_BLOCKED ((NTSTATUS) 0xC0000424L)
+#endif
+
+#ifndef STATUS_HIVE_UNLOADED
+# define STATUS_HIVE_UNLOADED ((NTSTATUS) 0xC0000425L)
+#endif
+
+#ifndef STATUS_COMPRESSION_DISABLED
+# define STATUS_COMPRESSION_DISABLED ((NTSTATUS) 0xC0000426L)
+#endif
+
+#ifndef STATUS_FILE_SYSTEM_LIMITATION
+# define STATUS_FILE_SYSTEM_LIMITATION ((NTSTATUS) 0xC0000427L)
+#endif
+
+#ifndef STATUS_INVALID_IMAGE_HASH
+# define STATUS_INVALID_IMAGE_HASH ((NTSTATUS) 0xC0000428L)
+#endif
+
+#ifndef STATUS_NOT_CAPABLE
+# define STATUS_NOT_CAPABLE ((NTSTATUS) 0xC0000429L)
+#endif
+
+#ifndef STATUS_REQUEST_OUT_OF_SEQUENCE
+# define STATUS_REQUEST_OUT_OF_SEQUENCE ((NTSTATUS) 0xC000042AL)
+#endif
+
+#ifndef STATUS_IMPLEMENTATION_LIMIT
+# define STATUS_IMPLEMENTATION_LIMIT ((NTSTATUS) 0xC000042BL)
+#endif
+
+#ifndef STATUS_ELEVATION_REQUIRED
+# define STATUS_ELEVATION_REQUIRED ((NTSTATUS) 0xC000042CL)
+#endif
+
+#ifndef STATUS_NO_SECURITY_CONTEXT
+# define STATUS_NO_SECURITY_CONTEXT ((NTSTATUS) 0xC000042DL)
+#endif
+
+#ifndef STATUS_PKU2U_CERT_FAILURE
+# define STATUS_PKU2U_CERT_FAILURE ((NTSTATUS) 0xC000042FL)
+#endif
+
+#ifndef STATUS_BEYOND_VDL
+# define STATUS_BEYOND_VDL ((NTSTATUS) 0xC0000432L)
+#endif
+
+#ifndef STATUS_ENCOUNTERED_WRITE_IN_PROGRESS
+# define STATUS_ENCOUNTERED_WRITE_IN_PROGRESS ((NTSTATUS) 0xC0000433L)
+#endif
+
+#ifndef STATUS_PTE_CHANGED
+# define STATUS_PTE_CHANGED ((NTSTATUS) 0xC0000434L)
+#endif
+
+#ifndef STATUS_PURGE_FAILED
+# define STATUS_PURGE_FAILED ((NTSTATUS) 0xC0000435L)
+#endif
+
+#ifndef STATUS_CRED_REQUIRES_CONFIRMATION
+# define STATUS_CRED_REQUIRES_CONFIRMATION ((NTSTATUS) 0xC0000440L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE
+# define STATUS_CS_ENCRYPTION_INVALID_SERVER_RESPONSE ((NTSTATUS) 0xC0000441L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER
+# define STATUS_CS_ENCRYPTION_UNSUPPORTED_SERVER ((NTSTATUS) 0xC0000442L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_EXISTING_ENCRYPTED_FILE ((NTSTATUS) 0xC0000443L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE
+# define STATUS_CS_ENCRYPTION_NEW_ENCRYPTED_FILE ((NTSTATUS) 0xC0000444L)
+#endif
+
+#ifndef STATUS_CS_ENCRYPTION_FILE_NOT_CSE
+# define STATUS_CS_ENCRYPTION_FILE_NOT_CSE ((NTSTATUS) 0xC0000445L)
+#endif
+
+#ifndef STATUS_INVALID_LABEL
+# define STATUS_INVALID_LABEL ((NTSTATUS) 0xC0000446L)
+#endif
+
+#ifndef STATUS_DRIVER_PROCESS_TERMINATED
+# define STATUS_DRIVER_PROCESS_TERMINATED ((NTSTATUS) 0xC0000450L)
+#endif
+
+#ifndef STATUS_AMBIGUOUS_SYSTEM_DEVICE
+# define STATUS_AMBIGUOUS_SYSTEM_DEVICE ((NTSTATUS) 0xC0000451L)
+#endif
+
+#ifndef STATUS_SYSTEM_DEVICE_NOT_FOUND
+# define STATUS_SYSTEM_DEVICE_NOT_FOUND ((NTSTATUS) 0xC0000452L)
+#endif
+
+#ifndef STATUS_RESTART_BOOT_APPLICATION
+# define STATUS_RESTART_BOOT_APPLICATION ((NTSTATUS) 0xC0000453L)
+#endif
+
+#ifndef STATUS_INSUFFICIENT_NVRAM_RESOURCES
+# define STATUS_INSUFFICIENT_NVRAM_RESOURCES ((NTSTATUS) 0xC0000454L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_NAME
+# define STATUS_INVALID_TASK_NAME ((NTSTATUS) 0xC0000500L)
+#endif
+
+#ifndef STATUS_INVALID_TASK_INDEX
+# define STATUS_INVALID_TASK_INDEX ((NTSTATUS) 0xC0000501L)
+#endif
+
+#ifndef STATUS_THREAD_ALREADY_IN_TASK
+# define STATUS_THREAD_ALREADY_IN_TASK ((NTSTATUS) 0xC0000502L)
+#endif
+
+#ifndef STATUS_CALLBACK_BYPASS
+# define STATUS_CALLBACK_BYPASS ((NTSTATUS) 0xC0000503L)
+#endif
+
+#ifndef STATUS_FAIL_FAST_EXCEPTION
+# define STATUS_FAIL_FAST_EXCEPTION ((NTSTATUS) 0xC0000602L)
+#endif
+
+#ifndef STATUS_IMAGE_CERT_REVOKED
+# define STATUS_IMAGE_CERT_REVOKED ((NTSTATUS) 0xC0000603L)
+#endif
+
+#ifndef STATUS_PORT_CLOSED
+# define STATUS_PORT_CLOSED ((NTSTATUS) 0xC0000700L)
+#endif
+
+#ifndef STATUS_MESSAGE_LOST
+# define STATUS_MESSAGE_LOST ((NTSTATUS) 0xC0000701L)
+#endif
+
+#ifndef STATUS_INVALID_MESSAGE
+# define STATUS_INVALID_MESSAGE ((NTSTATUS) 0xC0000702L)
+#endif
+
+#ifndef STATUS_REQUEST_CANCELED
+# define STATUS_REQUEST_CANCELED ((NTSTATUS) 0xC0000703L)
+#endif
+
+#ifndef STATUS_RECURSIVE_DISPATCH
+# define STATUS_RECURSIVE_DISPATCH ((NTSTATUS) 0xC0000704L)
+#endif
+
+#ifndef STATUS_LPC_RECEIVE_BUFFER_EXPECTED
+# define STATUS_LPC_RECEIVE_BUFFER_EXPECTED ((NTSTATUS) 0xC0000705L)
+#endif
+
+#ifndef STATUS_LPC_INVALID_CONNECTION_USAGE
+# define STATUS_LPC_INVALID_CONNECTION_USAGE ((NTSTATUS) 0xC0000706L)
+#endif
+
+#ifndef STATUS_LPC_REQUESTS_NOT_ALLOWED
+# define STATUS_LPC_REQUESTS_NOT_ALLOWED ((NTSTATUS) 0xC0000707L)
+#endif
+
+#ifndef STATUS_RESOURCE_IN_USE
+# define STATUS_RESOURCE_IN_USE ((NTSTATUS) 0xC0000708L)
+#endif
+
+#ifndef STATUS_HARDWARE_MEMORY_ERROR
+# define STATUS_HARDWARE_MEMORY_ERROR ((NTSTATUS) 0xC0000709L)
+#endif
+
+#ifndef STATUS_THREADPOOL_HANDLE_EXCEPTION
+# define STATUS_THREADPOOL_HANDLE_EXCEPTION ((NTSTATUS) 0xC000070AL)
+#endif
+
+#ifndef STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_SET_EVENT_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070BL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_SEMAPHORE_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070CL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_RELEASE_MUTEX_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070DL)
+#endif
+
+#ifndef STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED
+# define STATUS_THREADPOOL_FREE_LIBRARY_ON_COMPLETION_FAILED ((NTSTATUS) 0xC000070EL)
+#endif
+
+#ifndef STATUS_THREADPOOL_RELEASED_DURING_OPERATION
+# define STATUS_THREADPOOL_RELEASED_DURING_OPERATION ((NTSTATUS) 0xC000070FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING
+# define STATUS_CALLBACK_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000710L)
+#endif
+
+#ifndef STATUS_APC_RETURNED_WHILE_IMPERSONATING
+# define STATUS_APC_RETURNED_WHILE_IMPERSONATING ((NTSTATUS) 0xC0000711L)
+#endif
+
+#ifndef STATUS_PROCESS_IS_PROTECTED
+# define STATUS_PROCESS_IS_PROTECTED ((NTSTATUS) 0xC0000712L)
+#endif
+
+#ifndef STATUS_MCA_EXCEPTION
+# define STATUS_MCA_EXCEPTION ((NTSTATUS) 0xC0000713L)
+#endif
+
+#ifndef STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE
+# define STATUS_CERTIFICATE_MAPPING_NOT_UNIQUE ((NTSTATUS) 0xC0000714L)
+#endif
+
+#ifndef STATUS_SYMLINK_CLASS_DISABLED
+# define STATUS_SYMLINK_CLASS_DISABLED ((NTSTATUS) 0xC0000715L)
+#endif
+
+#ifndef STATUS_INVALID_IDN_NORMALIZATION
+# define STATUS_INVALID_IDN_NORMALIZATION ((NTSTATUS) 0xC0000716L)
+#endif
+
+#ifndef STATUS_NO_UNICODE_TRANSLATION
+# define STATUS_NO_UNICODE_TRANSLATION ((NTSTATUS) 0xC0000717L)
+#endif
+
+#ifndef STATUS_ALREADY_REGISTERED
+# define STATUS_ALREADY_REGISTERED ((NTSTATUS) 0xC0000718L)
+#endif
+
+#ifndef STATUS_CONTEXT_MISMATCH
+# define STATUS_CONTEXT_MISMATCH ((NTSTATUS) 0xC0000719L)
+#endif
+
+#ifndef STATUS_PORT_ALREADY_HAS_COMPLETION_LIST
+# define STATUS_PORT_ALREADY_HAS_COMPLETION_LIST ((NTSTATUS) 0xC000071AL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_PRIORITY
+# define STATUS_CALLBACK_RETURNED_THREAD_PRIORITY ((NTSTATUS) 0xC000071BL)
+#endif
+
+#ifndef STATUS_INVALID_THREAD
+# define STATUS_INVALID_THREAD ((NTSTATUS) 0xC000071CL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_TRANSACTION
+# define STATUS_CALLBACK_RETURNED_TRANSACTION ((NTSTATUS) 0xC000071DL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LDR_LOCK
+# define STATUS_CALLBACK_RETURNED_LDR_LOCK ((NTSTATUS) 0xC000071EL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_LANG
+# define STATUS_CALLBACK_RETURNED_LANG ((NTSTATUS) 0xC000071FL)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_PRI_BACK
+# define STATUS_CALLBACK_RETURNED_PRI_BACK ((NTSTATUS) 0xC0000720L)
+#endif
+
+#ifndef STATUS_CALLBACK_RETURNED_THREAD_AFFINITY
+# define STATUS_CALLBACK_RETURNED_THREAD_AFFINITY ((NTSTATUS) 0xC0000721L)
+#endif
+
+#ifndef STATUS_DISK_REPAIR_DISABLED
+# define STATUS_DISK_REPAIR_DISABLED ((NTSTATUS) 0xC0000800L)
+#endif
+
+#ifndef STATUS_DS_DOMAIN_RENAME_IN_PROGRESS
+# define STATUS_DS_DOMAIN_RENAME_IN_PROGRESS ((NTSTATUS) 0xC0000801L)
+#endif
+
+#ifndef STATUS_DISK_QUOTA_EXCEEDED
+# define STATUS_DISK_QUOTA_EXCEEDED ((NTSTATUS) 0xC0000802L)
+#endif
+
+#ifndef STATUS_DATA_LOST_REPAIR
+# define STATUS_DATA_LOST_REPAIR ((NTSTATUS) 0x80000803L)
+#endif
+
+#ifndef STATUS_CONTENT_BLOCKED
+# define STATUS_CONTENT_BLOCKED ((NTSTATUS) 0xC0000804L)
+#endif
+
+#ifndef STATUS_BAD_CLUSTERS
+# define STATUS_BAD_CLUSTERS ((NTSTATUS) 0xC0000805L)
+#endif
+
+#ifndef STATUS_VOLUME_DIRTY
+# define STATUS_VOLUME_DIRTY ((NTSTATUS) 0xC0000806L)
+#endif
+
+#ifndef STATUS_FILE_CHECKED_OUT
+# define STATUS_FILE_CHECKED_OUT ((NTSTATUS) 0xC0000901L)
+#endif
+
+#ifndef STATUS_CHECKOUT_REQUIRED
+# define STATUS_CHECKOUT_REQUIRED ((NTSTATUS) 0xC0000902L)
+#endif
+
+#ifndef STATUS_BAD_FILE_TYPE
+# define STATUS_BAD_FILE_TYPE ((NTSTATUS) 0xC0000903L)
+#endif
+
+#ifndef STATUS_FILE_TOO_LARGE
+# define STATUS_FILE_TOO_LARGE ((NTSTATUS) 0xC0000904L)
+#endif
+
+#ifndef STATUS_FORMS_AUTH_REQUIRED
+# define STATUS_FORMS_AUTH_REQUIRED ((NTSTATUS) 0xC0000905L)
+#endif
+
+#ifndef STATUS_VIRUS_INFECTED
+# define STATUS_VIRUS_INFECTED ((NTSTATUS) 0xC0000906L)
+#endif
+
+#ifndef STATUS_VIRUS_DELETED
+# define STATUS_VIRUS_DELETED ((NTSTATUS) 0xC0000907L)
+#endif
+
+#ifndef STATUS_BAD_MCFG_TABLE
+# define STATUS_BAD_MCFG_TABLE ((NTSTATUS) 0xC0000908L)
+#endif
+
+#ifndef STATUS_CANNOT_BREAK_OPLOCK
+# define STATUS_CANNOT_BREAK_OPLOCK ((NTSTATUS) 0xC0000909L)
+#endif
+
+#ifndef STATUS_WOW_ASSERTION
+# define STATUS_WOW_ASSERTION ((NTSTATUS) 0xC0009898L)
+#endif
+
+#ifndef STATUS_INVALID_SIGNATURE
+# define STATUS_INVALID_SIGNATURE ((NTSTATUS) 0xC000A000L)
+#endif
+
+#ifndef STATUS_HMAC_NOT_SUPPORTED
+# define STATUS_HMAC_NOT_SUPPORTED ((NTSTATUS) 0xC000A001L)
+#endif
+
+#ifndef STATUS_AUTH_TAG_MISMATCH
+# define STATUS_AUTH_TAG_MISMATCH ((NTSTATUS) 0xC000A002L)
+#endif
+
+#ifndef STATUS_IPSEC_QUEUE_OVERFLOW
+# define STATUS_IPSEC_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A010L)
+#endif
+
+#ifndef STATUS_ND_QUEUE_OVERFLOW
+# define STATUS_ND_QUEUE_OVERFLOW ((NTSTATUS) 0xC000A011L)
+#endif
+
+#ifndef STATUS_HOPLIMIT_EXCEEDED
+# define STATUS_HOPLIMIT_EXCEEDED ((NTSTATUS) 0xC000A012L)
+#endif
+
+#ifndef STATUS_PROTOCOL_NOT_SUPPORTED
+# define STATUS_PROTOCOL_NOT_SUPPORTED ((NTSTATUS) 0xC000A013L)
+#endif
+
+#ifndef STATUS_FASTPATH_REJECTED
+# define STATUS_FASTPATH_REJECTED ((NTSTATUS) 0xC000A014L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_DISCONNECTED ((NTSTATUS) 0xC000A080L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_NETWORK_SERVER_ERROR ((NTSTATUS) 0xC000A081L)
+#endif
+
+#ifndef STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR
+# define STATUS_LOST_WRITEBEHIND_DATA_LOCAL_DISK_ERROR ((NTSTATUS) 0xC000A082L)
+#endif
+
+#ifndef STATUS_XML_PARSE_ERROR
+# define STATUS_XML_PARSE_ERROR ((NTSTATUS) 0xC000A083L)
+#endif
+
+#ifndef STATUS_XMLDSIG_ERROR
+# define STATUS_XMLDSIG_ERROR ((NTSTATUS) 0xC000A084L)
+#endif
+
+#ifndef STATUS_WRONG_COMPARTMENT
+# define STATUS_WRONG_COMPARTMENT ((NTSTATUS) 0xC000A085L)
+#endif
+
+#ifndef STATUS_AUTHIP_FAILURE
+# define STATUS_AUTHIP_FAILURE ((NTSTATUS) 0xC000A086L)
+#endif
+
+#ifndef STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS
+# define STATUS_DS_OID_MAPPED_GROUP_CANT_HAVE_MEMBERS ((NTSTATUS) 0xC000A087L)
+#endif
+
+#ifndef STATUS_DS_OID_NOT_FOUND
+# define STATUS_DS_OID_NOT_FOUND ((NTSTATUS) 0xC000A088L)
+#endif
+
+#ifndef STATUS_HASH_NOT_SUPPORTED
+# define STATUS_HASH_NOT_SUPPORTED ((NTSTATUS) 0xC000A100L)
+#endif
+
+#ifndef STATUS_HASH_NOT_PRESENT
+# define STATUS_HASH_NOT_PRESENT ((NTSTATUS) 0xC000A101L)
+#endif
+
+/* This is not the NTSTATUS_FROM_WIN32 that the DDK provides, because the */
+/* DDK got it wrong! */
+#ifdef NTSTATUS_FROM_WIN32
+# undef NTSTATUS_FROM_WIN32
+#endif
+#define NTSTATUS_FROM_WIN32(error) ((NTSTATUS) (error) <= 0 ? \
+ ((NTSTATUS) (error)) : ((NTSTATUS) (((error) & 0x0000FFFF) | \
+ (FACILITY_NTWIN32 << 16) | ERROR_SEVERITY_WARNING)))
+
+#ifndef JOB_OBJECT_LIMIT_PROCESS_MEMORY
+# define JOB_OBJECT_LIMIT_PROCESS_MEMORY 0x00000100
+#endif
+#ifndef JOB_OBJECT_LIMIT_JOB_MEMORY
+# define JOB_OBJECT_LIMIT_JOB_MEMORY 0x00000200
+#endif
+#ifndef JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION
+# define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x00000400
+#endif
+#ifndef JOB_OBJECT_LIMIT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_BREAKAWAY_OK 0x00000800
+#endif
+#ifndef JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK
+# define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK 0x00001000
+#endif
+#ifndef JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
+# define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE 0x00002000
+#endif
+
+/* from winternl.h */
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+ PWSTR Buffer;
+} UNICODE_STRING, *PUNICODE_STRING;
+
+typedef const UNICODE_STRING *PCUNICODE_STRING;
+
+/* from ntifs.h */
+#ifndef DEVICE_TYPE
+# define DEVICE_TYPE DWORD
+#endif
+
+#ifndef VOLUME_NAME_DOS
+# define VOLUME_NAME_DOS 0x0
+#endif
+
+#ifndef MAPVK_VK_TO_VSC
+# define MAPVK_VK_TO_VSC (0)
+#endif
+
+/* MinGW already has a definition for REPARSE_DATA_BUFFER, but mingw-w64 does
+ * not.
+ */
+#if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
+ typedef struct _REPARSE_DATA_BUFFER {
+ ULONG ReparseTag;
+ USHORT ReparseDataLength;
+ USHORT Reserved;
+ union {
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ ULONG Flags;
+ WCHAR PathBuffer[1];
+ } SymbolicLinkReparseBuffer;
+ struct {
+ USHORT SubstituteNameOffset;
+ USHORT SubstituteNameLength;
+ USHORT PrintNameOffset;
+ USHORT PrintNameLength;
+ WCHAR PathBuffer[1];
+ } MountPointReparseBuffer;
+ struct {
+ UCHAR DataBuffer[1];
+ } GenericReparseBuffer;
+ };
+ } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
+#endif
+
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+
+typedef enum _FILE_INFORMATION_CLASS {
+ FileDirectoryInformation = 1,
+ FileFullDirectoryInformation,
+ FileBothDirectoryInformation,
+ FileBasicInformation,
+ FileStandardInformation,
+ FileInternalInformation,
+ FileEaInformation,
+ FileAccessInformation,
+ FileNameInformation,
+ FileRenameInformation,
+ FileLinkInformation,
+ FileNamesInformation,
+ FileDispositionInformation,
+ FilePositionInformation,
+ FileFullEaInformation,
+ FileModeInformation,
+ FileAlignmentInformation,
+ FileAllInformation,
+ FileAllocationInformation,
+ FileEndOfFileInformation,
+ FileAlternateNameInformation,
+ FileStreamInformation,
+ FilePipeInformation,
+ FilePipeLocalInformation,
+ FilePipeRemoteInformation,
+ FileMailslotQueryInformation,
+ FileMailslotSetInformation,
+ FileCompressionInformation,
+ FileObjectIdInformation,
+ FileCompletionInformation,
+ FileMoveClusterInformation,
+ FileQuotaInformation,
+ FileReparsePointInformation,
+ FileNetworkOpenInformation,
+ FileAttributeTagInformation,
+ FileTrackingInformation,
+ FileIdBothDirectoryInformation,
+ FileIdFullDirectoryInformation,
+ FileValidDataLengthInformation,
+ FileShortNameInformation,
+ FileIoCompletionNotificationInformation,
+ FileIoStatusBlockRangeInformation,
+ FileIoPriorityHintInformation,
+ FileSfioReserveInformation,
+ FileSfioVolumeInformation,
+ FileHardLinkInformation,
+ FileProcessIdsUsingFileInformation,
+ FileNormalizedNameInformation,
+ FileNetworkPhysicalNameInformation,
+ FileIdGlobalTxDirectoryInformation,
+ FileIsRemoteDeviceInformation,
+ FileAttributeCacheInformation,
+ FileNumaNodeInformation,
+ FileStandardLinkInformation,
+ FileRemoteProtocolInformation,
+ FileMaximumInformation
+} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
+
+typedef struct _FILE_DIRECTORY_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_DIRECTORY_INFORMATION, *PFILE_DIRECTORY_INFORMATION;
+
+typedef struct _FILE_BOTH_DIR_INFORMATION {
+ ULONG NextEntryOffset;
+ ULONG FileIndex;
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ LARGE_INTEGER EndOfFile;
+ LARGE_INTEGER AllocationSize;
+ ULONG FileAttributes;
+ ULONG FileNameLength;
+ ULONG EaSize;
+ CCHAR ShortNameLength;
+ WCHAR ShortName[12];
+ WCHAR FileName[1];
+} FILE_BOTH_DIR_INFORMATION, *PFILE_BOTH_DIR_INFORMATION;
+
+typedef struct _FILE_BASIC_INFORMATION {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+} FILE_BASIC_INFORMATION, *PFILE_BASIC_INFORMATION;
+
+typedef struct _FILE_STANDARD_INFORMATION {
+ LARGE_INTEGER AllocationSize;
+ LARGE_INTEGER EndOfFile;
+ ULONG NumberOfLinks;
+ BOOLEAN DeletePending;
+ BOOLEAN Directory;
+} FILE_STANDARD_INFORMATION, *PFILE_STANDARD_INFORMATION;
+
+typedef struct _FILE_INTERNAL_INFORMATION {
+ LARGE_INTEGER IndexNumber;
+} FILE_INTERNAL_INFORMATION, *PFILE_INTERNAL_INFORMATION;
+
+typedef struct _FILE_EA_INFORMATION {
+ ULONG EaSize;
+} FILE_EA_INFORMATION, *PFILE_EA_INFORMATION;
+
+typedef struct _FILE_ACCESS_INFORMATION {
+ ACCESS_MASK AccessFlags;
+} FILE_ACCESS_INFORMATION, *PFILE_ACCESS_INFORMATION;
+
+typedef struct _FILE_POSITION_INFORMATION {
+ LARGE_INTEGER CurrentByteOffset;
+} FILE_POSITION_INFORMATION, *PFILE_POSITION_INFORMATION;
+
+typedef struct _FILE_MODE_INFORMATION {
+ ULONG Mode;
+} FILE_MODE_INFORMATION, *PFILE_MODE_INFORMATION;
+
+typedef struct _FILE_ALIGNMENT_INFORMATION {
+ ULONG AlignmentRequirement;
+} FILE_ALIGNMENT_INFORMATION, *PFILE_ALIGNMENT_INFORMATION;
+
+typedef struct _FILE_NAME_INFORMATION {
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
+
+typedef struct _FILE_END_OF_FILE_INFORMATION {
+ LARGE_INTEGER EndOfFile;
+} FILE_END_OF_FILE_INFORMATION, *PFILE_END_OF_FILE_INFORMATION;
+
+typedef struct _FILE_ALL_INFORMATION {
+ FILE_BASIC_INFORMATION BasicInformation;
+ FILE_STANDARD_INFORMATION StandardInformation;
+ FILE_INTERNAL_INFORMATION InternalInformation;
+ FILE_EA_INFORMATION EaInformation;
+ FILE_ACCESS_INFORMATION AccessInformation;
+ FILE_POSITION_INFORMATION PositionInformation;
+ FILE_MODE_INFORMATION ModeInformation;
+ FILE_ALIGNMENT_INFORMATION AlignmentInformation;
+ FILE_NAME_INFORMATION NameInformation;
+} FILE_ALL_INFORMATION, *PFILE_ALL_INFORMATION;
+
+typedef struct _FILE_DISPOSITION_INFORMATION {
+ BOOLEAN DeleteFile;
+} FILE_DISPOSITION_INFORMATION, *PFILE_DISPOSITION_INFORMATION;
+
+typedef struct _FILE_PIPE_LOCAL_INFORMATION {
+ ULONG NamedPipeType;
+ ULONG NamedPipeConfiguration;
+ ULONG MaximumInstances;
+ ULONG CurrentInstances;
+ ULONG InboundQuota;
+ ULONG ReadDataAvailable;
+ ULONG OutboundQuota;
+ ULONG WriteQuotaAvailable;
+ ULONG NamedPipeState;
+ ULONG NamedPipeEnd;
+} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
+
+#define FILE_SYNCHRONOUS_IO_ALERT 0x00000010
+#define FILE_SYNCHRONOUS_IO_NONALERT 0x00000020
+
+typedef enum _FS_INFORMATION_CLASS {
+ FileFsVolumeInformation = 1,
+ FileFsLabelInformation = 2,
+ FileFsSizeInformation = 3,
+ FileFsDeviceInformation = 4,
+ FileFsAttributeInformation = 5,
+ FileFsControlInformation = 6,
+ FileFsFullSizeInformation = 7,
+ FileFsObjectIdInformation = 8,
+ FileFsDriverPathInformation = 9,
+ FileFsVolumeFlagsInformation = 10,
+ FileFsSectorSizeInformation = 11
+} FS_INFORMATION_CLASS, *PFS_INFORMATION_CLASS;
+
+typedef struct _FILE_FS_VOLUME_INFORMATION {
+ LARGE_INTEGER VolumeCreationTime;
+ ULONG VolumeSerialNumber;
+ ULONG VolumeLabelLength;
+ BOOLEAN SupportsObjects;
+ WCHAR VolumeLabel[1];
+} FILE_FS_VOLUME_INFORMATION, *PFILE_FS_VOLUME_INFORMATION;
+
+typedef struct _FILE_FS_LABEL_INFORMATION {
+ ULONG VolumeLabelLength;
+ WCHAR VolumeLabel[1];
+} FILE_FS_LABEL_INFORMATION, *PFILE_FS_LABEL_INFORMATION;
+
+typedef struct _FILE_FS_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER AvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_SIZE_INFORMATION, *PFILE_FS_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_DEVICE_INFORMATION {
+ DEVICE_TYPE DeviceType;
+ ULONG Characteristics;
+} FILE_FS_DEVICE_INFORMATION, *PFILE_FS_DEVICE_INFORMATION;
+
+typedef struct _FILE_FS_ATTRIBUTE_INFORMATION {
+ ULONG FileSystemAttributes;
+ LONG MaximumComponentNameLength;
+ ULONG FileSystemNameLength;
+ WCHAR FileSystemName[1];
+} FILE_FS_ATTRIBUTE_INFORMATION, *PFILE_FS_ATTRIBUTE_INFORMATION;
+
+typedef struct _FILE_FS_CONTROL_INFORMATION {
+ LARGE_INTEGER FreeSpaceStartFiltering;
+ LARGE_INTEGER FreeSpaceThreshold;
+ LARGE_INTEGER FreeSpaceStopFiltering;
+ LARGE_INTEGER DefaultQuotaThreshold;
+ LARGE_INTEGER DefaultQuotaLimit;
+ ULONG FileSystemControlFlags;
+} FILE_FS_CONTROL_INFORMATION, *PFILE_FS_CONTROL_INFORMATION;
+
+typedef struct _FILE_FS_FULL_SIZE_INFORMATION {
+ LARGE_INTEGER TotalAllocationUnits;
+ LARGE_INTEGER CallerAvailableAllocationUnits;
+ LARGE_INTEGER ActualAvailableAllocationUnits;
+ ULONG SectorsPerAllocationUnit;
+ ULONG BytesPerSector;
+} FILE_FS_FULL_SIZE_INFORMATION, *PFILE_FS_FULL_SIZE_INFORMATION;
+
+typedef struct _FILE_FS_OBJECTID_INFORMATION {
+ UCHAR ObjectId[16];
+ UCHAR ExtendedInfo[48];
+} FILE_FS_OBJECTID_INFORMATION, *PFILE_FS_OBJECTID_INFORMATION;
+
+typedef struct _FILE_FS_DRIVER_PATH_INFORMATION {
+ BOOLEAN DriverInPath;
+ ULONG DriverNameLength;
+ WCHAR DriverName[1];
+} FILE_FS_DRIVER_PATH_INFORMATION, *PFILE_FS_DRIVER_PATH_INFORMATION;
+
+typedef struct _FILE_FS_VOLUME_FLAGS_INFORMATION {
+ ULONG Flags;
+} FILE_FS_VOLUME_FLAGS_INFORMATION, *PFILE_FS_VOLUME_FLAGS_INFORMATION;
+
+typedef struct _FILE_FS_SECTOR_SIZE_INFORMATION {
+ ULONG LogicalBytesPerSector;
+ ULONG PhysicalBytesPerSectorForAtomicity;
+ ULONG PhysicalBytesPerSectorForPerformance;
+ ULONG FileSystemEffectivePhysicalBytesPerSectorForAtomicity;
+ ULONG Flags;
+ ULONG ByteOffsetForSectorAlignment;
+ ULONG ByteOffsetForPartitionAlignment;
+} FILE_FS_SECTOR_SIZE_INFORMATION, *PFILE_FS_SECTOR_SIZE_INFORMATION;
+
+typedef struct _SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION {
+ LARGE_INTEGER IdleTime;
+ LARGE_INTEGER KernelTime;
+ LARGE_INTEGER UserTime;
+ LARGE_INTEGER DpcTime;
+ LARGE_INTEGER InterruptTime;
+ ULONG InterruptCount;
+} SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION, *PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION;
+
+#ifndef SystemProcessorPerformanceInformation
+# define SystemProcessorPerformanceInformation 8
+#endif
+
+#ifndef FILE_DEVICE_FILE_SYSTEM
+# define FILE_DEVICE_FILE_SYSTEM 0x00000009
+#endif
+
+#ifndef FILE_DEVICE_NETWORK
+# define FILE_DEVICE_NETWORK 0x00000012
+#endif
+
+#ifndef METHOD_BUFFERED
+# define METHOD_BUFFERED 0
+#endif
+
+#ifndef METHOD_IN_DIRECT
+# define METHOD_IN_DIRECT 1
+#endif
+
+#ifndef METHOD_OUT_DIRECT
+# define METHOD_OUT_DIRECT 2
+#endif
+
+#ifndef METHOD_NEITHER
+#define METHOD_NEITHER 3
+#endif
+
+#ifndef METHOD_DIRECT_TO_HARDWARE
+# define METHOD_DIRECT_TO_HARDWARE METHOD_IN_DIRECT
+#endif
+
+#ifndef METHOD_DIRECT_FROM_HARDWARE
+# define METHOD_DIRECT_FROM_HARDWARE METHOD_OUT_DIRECT
+#endif
+
+#ifndef FILE_ANY_ACCESS
+# define FILE_ANY_ACCESS 0
+#endif
+
+#ifndef FILE_SPECIAL_ACCESS
+# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
+#endif
+
+#ifndef FILE_READ_ACCESS
+# define FILE_READ_ACCESS 0x0001
+#endif
+
+#ifndef FILE_WRITE_ACCESS
+# define FILE_WRITE_ACCESS 0x0002
+#endif
+
+#ifndef CTL_CODE
+# define CTL_CODE(device_type, function, method, access) \
+ (((device_type) << 16) | ((access) << 14) | ((function) << 2) | (method))
+#endif
+
+#ifndef FSCTL_SET_REPARSE_POINT
+# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 41, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef FSCTL_GET_REPARSE_POINT
+# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 42, \
+ METHOD_BUFFERED, \
+ FILE_ANY_ACCESS)
+#endif
+
+#ifndef FSCTL_DELETE_REPARSE_POINT
+# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, \
+ 43, \
+ METHOD_BUFFERED, \
+ FILE_SPECIAL_ACCESS)
+#endif
+
+#ifndef IO_REPARSE_TAG_SYMLINK
+# define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
+
+typedef VOID (NTAPI *PIO_APC_ROUTINE)
+ (PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG Reserved);
+
+typedef ULONG (NTAPI *sRtlNtStatusToDosError)
+ (NTSTATUS Status);
+
+typedef NTSTATUS (NTAPI *sNtDeviceIoControlFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ ULONG IoControlCode,
+ PVOID InputBuffer,
+ ULONG InputBufferLength,
+ PVOID OutputBuffer,
+ ULONG OutputBufferLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtSetInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQueryVolumeInformationFile)
+ (HANDLE FileHandle,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FsInformation,
+ ULONG Length,
+ FS_INFORMATION_CLASS FsInformationClass);
+
+typedef NTSTATUS (NTAPI *sNtQuerySystemInformation)
+ (UINT SystemInformationClass,
+ PVOID SystemInformation,
+ ULONG SystemInformationLength,
+ PULONG ReturnLength);
+
+typedef NTSTATUS (NTAPI *sNtQueryDirectoryFile)
+ (HANDLE FileHandle,
+ HANDLE Event,
+ PIO_APC_ROUTINE ApcRoutine,
+ PVOID ApcContext,
+ PIO_STATUS_BLOCK IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ FILE_INFORMATION_CLASS FileInformationClass,
+ BOOLEAN ReturnSingleEntry,
+ PUNICODE_STRING FileName,
+ BOOLEAN RestartScan
+ );
+
+/*
+ * Kernel32 headers
+ */
+#ifndef FILE_SKIP_COMPLETION_PORT_ON_SUCCESS
+# define FILE_SKIP_COMPLETION_PORT_ON_SUCCESS 0x1
+#endif
+
+#ifndef FILE_SKIP_SET_EVENT_ON_HANDLE
+# define FILE_SKIP_SET_EVENT_ON_HANDLE 0x2
+#endif
+
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+# define SYMBOLIC_LINK_FLAG_DIRECTORY 0x1
+#endif
+
+#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \
+ || (defined(_MSC_VER) && _MSC_VER < 1500)
+ typedef struct _OVERLAPPED_ENTRY {
+ ULONG_PTR lpCompletionKey;
+ LPOVERLAPPED lpOverlapped;
+ ULONG_PTR Internal;
+ DWORD dwNumberOfBytesTransferred;
+ } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;
+#endif
+
+/* from wincon.h */
+#ifndef ENABLE_INSERT_MODE
+# define ENABLE_INSERT_MODE 0x20
+#endif
+
+#ifndef ENABLE_QUICK_EDIT_MODE
+# define ENABLE_QUICK_EDIT_MODE 0x40
+#endif
+
+#ifndef ENABLE_EXTENDED_FLAGS
+# define ENABLE_EXTENDED_FLAGS 0x80
+#endif
+
+/* from winerror.h */
+#ifndef ERROR_ELEVATION_REQUIRED
+# define ERROR_ELEVATION_REQUIRED 740
+#endif
+
+#ifndef ERROR_SYMLINK_NOT_SUPPORTED
+# define ERROR_SYMLINK_NOT_SUPPORTED 1464
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_FOUND
+# define ERROR_MUI_FILE_NOT_FOUND 15100
+#endif
+
+#ifndef ERROR_MUI_INVALID_FILE
+# define ERROR_MUI_INVALID_FILE 15101
+#endif
+
+#ifndef ERROR_MUI_INVALID_RC_CONFIG
+# define ERROR_MUI_INVALID_RC_CONFIG 15102
+#endif
+
+#ifndef ERROR_MUI_INVALID_LOCALE_NAME
+# define ERROR_MUI_INVALID_LOCALE_NAME 15103
+#endif
+
+#ifndef ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME
+# define ERROR_MUI_INVALID_ULTIMATEFALLBACK_NAME 15104
+#endif
+
+#ifndef ERROR_MUI_FILE_NOT_LOADED
+# define ERROR_MUI_FILE_NOT_LOADED 15105
+#endif
+
+typedef BOOL (WINAPI *sGetQueuedCompletionStatusEx)
+ (HANDLE CompletionPort,
+ LPOVERLAPPED_ENTRY lpCompletionPortEntries,
+ ULONG ulCount,
+ PULONG ulNumEntriesRemoved,
+ DWORD dwMilliseconds,
+ BOOL fAlertable);
+
+typedef BOOL (WINAPI* sSetFileCompletionNotificationModes)
+ (HANDLE FileHandle,
+ UCHAR Flags);
+
+typedef BOOLEAN (WINAPI* sCreateSymbolicLinkW)
+ (LPCWSTR lpSymlinkFileName,
+ LPCWSTR lpTargetFileName,
+ DWORD dwFlags);
+
+typedef BOOL (WINAPI* sCancelIoEx)
+ (HANDLE hFile,
+ LPOVERLAPPED lpOverlapped);
+
+typedef VOID (WINAPI* sInitializeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sSleepConditionVariableCS)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PCRITICAL_SECTION CriticalSection,
+ DWORD dwMilliseconds);
+
+typedef BOOL (WINAPI* sSleepConditionVariableSRW)
+ (PCONDITION_VARIABLE ConditionVariable,
+ PSRWLOCK SRWLock,
+ DWORD dwMilliseconds,
+ ULONG Flags);
+
+typedef VOID (WINAPI* sWakeAllConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef VOID (WINAPI* sWakeConditionVariable)
+ (PCONDITION_VARIABLE ConditionVariable);
+
+typedef BOOL (WINAPI* sCancelSynchronousIo)
+ (HANDLE hThread);
+
+typedef DWORD (WINAPI* sGetFinalPathNameByHandleW)
+ (HANDLE hFile,
+ LPWSTR lpszFilePath,
+ DWORD cchFilePath,
+ DWORD dwFlags);
+
+/* from powerbase.h */
+#ifndef DEVICE_NOTIFY_CALLBACK
+# define DEVICE_NOTIFY_CALLBACK 2
+#endif
+
+#ifndef PBT_APMRESUMEAUTOMATIC
+# define PBT_APMRESUMEAUTOMATIC 18
+#endif
+
+#ifndef PBT_APMRESUMESUSPEND
+# define PBT_APMRESUMESUSPEND 7
+#endif
+
+typedef ULONG CALLBACK _DEVICE_NOTIFY_CALLBACK_ROUTINE(
+ PVOID Context,
+ ULONG Type,
+ PVOID Setting
+);
+typedef _DEVICE_NOTIFY_CALLBACK_ROUTINE* _PDEVICE_NOTIFY_CALLBACK_ROUTINE;
+
+typedef struct _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS {
+ _PDEVICE_NOTIFY_CALLBACK_ROUTINE Callback;
+ PVOID Context;
+} _DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS, *_PDEVICE_NOTIFY_SUBSCRIBE_PARAMETERS;
+
+typedef PVOID _HPOWERNOTIFY;
+typedef _HPOWERNOTIFY *_PHPOWERNOTIFY;
+
+typedef DWORD (WINAPI *sPowerRegisterSuspendResumeNotification)
+ (DWORD Flags,
+ HANDLE Recipient,
+ _PHPOWERNOTIFY RegistrationHandle);
+
+
+/* Ntdll function pointers */
+extern sRtlNtStatusToDosError pRtlNtStatusToDosError;
+extern sNtDeviceIoControlFile pNtDeviceIoControlFile;
+extern sNtQueryInformationFile pNtQueryInformationFile;
+extern sNtSetInformationFile pNtSetInformationFile;
+extern sNtQueryVolumeInformationFile pNtQueryVolumeInformationFile;
+extern sNtQueryDirectoryFile pNtQueryDirectoryFile;
+extern sNtQuerySystemInformation pNtQuerySystemInformation;
+
+
+/* Kernel32 function pointers */
+extern sGetQueuedCompletionStatusEx pGetQueuedCompletionStatusEx;
+extern sSetFileCompletionNotificationModes pSetFileCompletionNotificationModes;
+extern sCreateSymbolicLinkW pCreateSymbolicLinkW;
+extern sCancelIoEx pCancelIoEx;
+extern sInitializeConditionVariable pInitializeConditionVariable;
+extern sSleepConditionVariableCS pSleepConditionVariableCS;
+extern sSleepConditionVariableSRW pSleepConditionVariableSRW;
+extern sWakeAllConditionVariable pWakeAllConditionVariable;
+extern sWakeConditionVariable pWakeConditionVariable;
+extern sCancelSynchronousIo pCancelSynchronousIo;
+extern sGetFinalPathNameByHandleW pGetFinalPathNameByHandleW;
+
+
+/* Powrprof.dll function pointer */
+extern sPowerRegisterSuspendResumeNotification pPowerRegisterSuspendResumeNotification;
+
+#endif /* UV_WIN_WINAPI_H_ */
diff --git a/Utilities/cmlibuv/src/win/winsock.c b/Utilities/cmlibuv/src/win/winsock.c
new file mode 100644
index 000000000..e86d76b13
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/winsock.c
@@ -0,0 +1,561 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "uv.h"
+#include "internal.h"
+
+
+/* Whether there are any non-IFS LSPs stacked on TCP */
+int uv_tcp_non_ifs_lsp_ipv4;
+int uv_tcp_non_ifs_lsp_ipv6;
+
+/* Ip address used to bind to any port at any interface */
+struct sockaddr_in uv_addr_ip4_any_;
+struct sockaddr_in6 uv_addr_ip6_any_;
+
+
+/*
+ * Retrieves the pointer to a winsock extension function.
+ */
+static BOOL uv_get_extension_function(SOCKET socket, GUID guid,
+ void **target) {
+ int result;
+ DWORD bytes;
+
+ result = WSAIoctl(socket,
+ SIO_GET_EXTENSION_FUNCTION_POINTER,
+ &guid,
+ sizeof(guid),
+ (void*)target,
+ sizeof(*target),
+ &bytes,
+ NULL,
+ NULL);
+
+ if (result == SOCKET_ERROR) {
+ *target = NULL;
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+BOOL uv_get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) {
+ const GUID wsaid_acceptex = WSAID_ACCEPTEX;
+ return uv_get_extension_function(socket, wsaid_acceptex, (void**)target);
+}
+
+
+BOOL uv_get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) {
+ const GUID wsaid_connectex = WSAID_CONNECTEX;
+ return uv_get_extension_function(socket, wsaid_connectex, (void**)target);
+}
+
+
+static int error_means_no_support(DWORD error) {
+ return error == WSAEPROTONOSUPPORT || error == WSAESOCKTNOSUPPORT ||
+ error == WSAEPFNOSUPPORT || error == WSAEAFNOSUPPORT;
+}
+
+
+void uv_winsock_init(void) {
+ WSADATA wsa_data;
+ int errorno;
+ SOCKET dummy;
+ WSAPROTOCOL_INFOW protocol_info;
+ int opt_len;
+
+ /* Initialize winsock */
+ errorno = WSAStartup(MAKEWORD(2, 2), &wsa_data);
+ if (errorno != 0) {
+ uv_fatal_error(errorno, "WSAStartup");
+ }
+
+ /* Set implicit binding address used by connectEx */
+ if (uv_ip4_addr("0.0.0.0", 0, &uv_addr_ip4_any_)) {
+ abort();
+ }
+
+ if (uv_ip6_addr("::", 0, &uv_addr_ip6_any_)) {
+ abort();
+ }
+
+ /* Detect non-IFS LSPs */
+ dummy = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv4 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+
+ /* Detect IPV6 support and non-IFS LSPs */
+ dummy = socket(AF_INET6, SOCK_STREAM, IPPROTO_IP);
+
+ if (dummy != INVALID_SOCKET) {
+ opt_len = (int) sizeof protocol_info;
+ if (getsockopt(dummy,
+ SOL_SOCKET,
+ SO_PROTOCOL_INFOW,
+ (char*) &protocol_info,
+ &opt_len) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "getsockopt");
+
+ if (!(protocol_info.dwServiceFlags1 & XP1_IFS_HANDLES))
+ uv_tcp_non_ifs_lsp_ipv6 = 1;
+
+ if (closesocket(dummy) == SOCKET_ERROR)
+ uv_fatal_error(WSAGetLastError(), "closesocket");
+
+ } else if (!error_means_no_support(WSAGetLastError())) {
+ /* Any error other than "socket type not supported" is fatal. */
+ uv_fatal_error(WSAGetLastError(), "socket");
+ }
+}
+
+
+int uv_ntstatus_to_winsock_error(NTSTATUS status) {
+ switch (status) {
+ case STATUS_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case STATUS_PENDING:
+ return ERROR_IO_PENDING;
+
+ case STATUS_INVALID_HANDLE:
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return WSAENOTSOCK;
+
+ case STATUS_INSUFFICIENT_RESOURCES:
+ case STATUS_PAGEFILE_QUOTA:
+ case STATUS_COMMITMENT_LIMIT:
+ case STATUS_WORKING_SET_QUOTA:
+ case STATUS_NO_MEMORY:
+ case STATUS_QUOTA_EXCEEDED:
+ case STATUS_TOO_MANY_PAGING_FILES:
+ case STATUS_REMOTE_RESOURCES:
+ return WSAENOBUFS;
+
+ case STATUS_TOO_MANY_ADDRESSES:
+ case STATUS_SHARING_VIOLATION:
+ case STATUS_ADDRESS_ALREADY_EXISTS:
+ return WSAEADDRINUSE;
+
+ case STATUS_LINK_TIMEOUT:
+ case STATUS_IO_TIMEOUT:
+ case STATUS_TIMEOUT:
+ return WSAETIMEDOUT;
+
+ case STATUS_GRACEFUL_DISCONNECT:
+ return WSAEDISCON;
+
+ case STATUS_REMOTE_DISCONNECT:
+ case STATUS_CONNECTION_RESET:
+ case STATUS_LINK_FAILED:
+ case STATUS_CONNECTION_DISCONNECTED:
+ case STATUS_PORT_UNREACHABLE:
+ case STATUS_HOPLIMIT_EXCEEDED:
+ return WSAECONNRESET;
+
+ case STATUS_LOCAL_DISCONNECT:
+ case STATUS_TRANSACTION_ABORTED:
+ case STATUS_CONNECTION_ABORTED:
+ return WSAECONNABORTED;
+
+ case STATUS_BAD_NETWORK_PATH:
+ case STATUS_NETWORK_UNREACHABLE:
+ case STATUS_PROTOCOL_UNREACHABLE:
+ return WSAENETUNREACH;
+
+ case STATUS_HOST_UNREACHABLE:
+ return WSAEHOSTUNREACH;
+
+ case STATUS_CANCELLED:
+ case STATUS_REQUEST_ABORTED:
+ return WSAEINTR;
+
+ case STATUS_BUFFER_OVERFLOW:
+ case STATUS_INVALID_BUFFER_SIZE:
+ return WSAEMSGSIZE;
+
+ case STATUS_BUFFER_TOO_SMALL:
+ case STATUS_ACCESS_VIOLATION:
+ return WSAEFAULT;
+
+ case STATUS_DEVICE_NOT_READY:
+ case STATUS_REQUEST_NOT_ACCEPTED:
+ return WSAEWOULDBLOCK;
+
+ case STATUS_INVALID_NETWORK_RESPONSE:
+ case STATUS_NETWORK_BUSY:
+ case STATUS_NO_SUCH_DEVICE:
+ case STATUS_NO_SUCH_FILE:
+ case STATUS_OBJECT_PATH_NOT_FOUND:
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ case STATUS_UNEXPECTED_NETWORK_ERROR:
+ return WSAENETDOWN;
+
+ case STATUS_INVALID_CONNECTION:
+ return WSAENOTCONN;
+
+ case STATUS_REMOTE_NOT_LISTENING:
+ case STATUS_CONNECTION_REFUSED:
+ return WSAECONNREFUSED;
+
+ case STATUS_PIPE_DISCONNECTED:
+ return WSAESHUTDOWN;
+
+ case STATUS_CONFLICTING_ADDRESSES:
+ case STATUS_INVALID_ADDRESS:
+ case STATUS_INVALID_ADDRESS_COMPONENT:
+ return WSAEADDRNOTAVAIL;
+
+ case STATUS_NOT_SUPPORTED:
+ case STATUS_NOT_IMPLEMENTED:
+ return WSAEOPNOTSUPP;
+
+ case STATUS_ACCESS_DENIED:
+ return WSAEACCES;
+
+ default:
+ if ((status & (FACILITY_NTWIN32 << 16)) == (FACILITY_NTWIN32 << 16) &&
+ (status & (ERROR_SEVERITY_ERROR | ERROR_SEVERITY_WARNING))) {
+ /* It's a windows error that has been previously mapped to an */
+ /* ntstatus code. */
+ return (DWORD) (status & 0xffff);
+ } else {
+ /* The default fallback for unmappable ntstatus codes. */
+ return WSAEINVAL;
+ }
+ }
+}
+
+
+/*
+ * This function provides a workaround for a bug in the winsock implementation
+ * of WSARecv. The problem is that when SetFileCompletionNotificationModes is
+ * used to avoid IOCP notifications of completed reads, WSARecv does not
+ * reliably indicate whether we can expect a completion package to be posted
+ * when the receive buffer is smaller than the received datagram.
+ *
+ * However it is desirable to use SetFileCompletionNotificationModes because
+ * it yields a massive performance increase.
+ *
+ * This function provides a workaround for that bug, but it only works for the
+ * specific case that we need it for. E.g. it assumes that the "avoid iocp"
+ * bit has been set, and supports only overlapped operation. It also requires
+ * the user to use the default msafd driver, doesn't work when other LSPs are
+ * stacked on top of it.
+ */
+int WSAAPI uv_wsarecv_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+/* See description of uv_wsarecv_workaround. */
+int WSAAPI uv_wsarecvfrom_workaround(SOCKET socket, WSABUF* buffers,
+ DWORD buffer_count, DWORD* bytes, DWORD* flags, struct sockaddr* addr,
+ int* addr_len, WSAOVERLAPPED *overlapped,
+ LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine) {
+ NTSTATUS status;
+ void* apc_context;
+ IO_STATUS_BLOCK* iosb = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ AFD_RECV_DATAGRAM_INFO info;
+ DWORD error;
+
+ if (overlapped == NULL || addr == NULL || addr_len == NULL ||
+ completion_routine != NULL) {
+ WSASetLastError(WSAEINVAL);
+ return SOCKET_ERROR;
+ }
+
+ info.BufferArray = buffers;
+ info.BufferCount = buffer_count;
+ info.AfdFlags = AFD_OVERLAPPED;
+ info.TdiFlags = TDI_RECEIVE_NORMAL;
+ info.Address = addr;
+ info.AddressLength = addr_len;
+
+ if (*flags & MSG_PEEK) {
+ info.TdiFlags |= TDI_RECEIVE_PEEK;
+ }
+
+ if (*flags & MSG_PARTIAL) {
+ info.TdiFlags |= TDI_RECEIVE_PARTIAL;
+ }
+
+ if (!((intptr_t) overlapped->hEvent & 1)) {
+ apc_context = (void*) overlapped;
+ } else {
+ apc_context = NULL;
+ }
+
+ iosb->Status = STATUS_PENDING;
+ iosb->Pointer = 0;
+
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ overlapped->hEvent,
+ NULL,
+ apc_context,
+ iosb,
+ IOCTL_AFD_RECEIVE_DATAGRAM,
+ &info,
+ sizeof(info),
+ NULL,
+ 0);
+
+ *flags = 0;
+ *bytes = (DWORD) iosb->Information;
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ case STATUS_BUFFER_OVERFLOW:
+ error = WSAEMSGSIZE;
+ break;
+
+ case STATUS_RECEIVE_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL_EXPEDITED:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL | MSG_OOB;
+ break;
+
+ case STATUS_RECEIVE_PARTIAL:
+ error = ERROR_SUCCESS;
+ *flags = MSG_PARTIAL;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
+
+
+int WSAAPI uv_msafd_poll(SOCKET socket, AFD_POLL_INFO* info_in,
+ AFD_POLL_INFO* info_out, OVERLAPPED* overlapped) {
+ IO_STATUS_BLOCK iosb;
+ IO_STATUS_BLOCK* iosb_ptr;
+ HANDLE event = NULL;
+ void* apc_context;
+ NTSTATUS status;
+ DWORD error;
+
+ if (overlapped != NULL) {
+ /* Overlapped operation. */
+ iosb_ptr = (IO_STATUS_BLOCK*) &overlapped->Internal;
+ event = overlapped->hEvent;
+
+ /* Do not report iocp completion if hEvent is tagged. */
+ if ((uintptr_t) event & 1) {
+ event = (HANDLE)((uintptr_t) event & ~(uintptr_t) 1);
+ apc_context = NULL;
+ } else {
+ apc_context = overlapped;
+ }
+
+ } else {
+ /* Blocking operation. */
+ iosb_ptr = &iosb;
+ event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (event == NULL) {
+ return SOCKET_ERROR;
+ }
+ apc_context = NULL;
+ }
+
+ iosb_ptr->Status = STATUS_PENDING;
+ status = pNtDeviceIoControlFile((HANDLE) socket,
+ event,
+ NULL,
+ apc_context,
+ iosb_ptr,
+ IOCTL_AFD_POLL,
+ info_in,
+ sizeof *info_in,
+ info_out,
+ sizeof *info_out);
+
+ if (overlapped == NULL) {
+ /* If this is a blocking operation, wait for the event to become */
+ /* signaled, and then grab the real status from the io status block. */
+ if (status == STATUS_PENDING) {
+ DWORD r = WaitForSingleObject(event, INFINITE);
+
+ if (r == WAIT_FAILED) {
+ DWORD saved_error = GetLastError();
+ CloseHandle(event);
+ WSASetLastError(saved_error);
+ return SOCKET_ERROR;
+ }
+
+ status = iosb.Status;
+ }
+
+ CloseHandle(event);
+ }
+
+ switch (status) {
+ case STATUS_SUCCESS:
+ error = ERROR_SUCCESS;
+ break;
+
+ case STATUS_PENDING:
+ error = WSA_IO_PENDING;
+ break;
+
+ default:
+ error = uv_ntstatus_to_winsock_error(status);
+ break;
+ }
+
+ WSASetLastError(error);
+
+ if (error == ERROR_SUCCESS) {
+ return 0;
+ } else {
+ return SOCKET_ERROR;
+ }
+}
diff --git a/Utilities/cmlibuv/src/win/winsock.h b/Utilities/cmlibuv/src/win/winsock.h
new file mode 100644
index 000000000..3115fe3d2
--- /dev/null
+++ b/Utilities/cmlibuv/src/win/winsock.h
@@ -0,0 +1,191 @@
+/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+
+#ifndef UV_WIN_WINSOCK_H_
+#define UV_WIN_WINSOCK_H_
+
+#include <winsock2.h>
+#include <iptypes.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <windows.h>
+
+#include "winapi.h"
+
+
+/*
+ * MinGW is missing these too
+ */
+#ifndef SO_UPDATE_CONNECT_CONTEXT
+# define SO_UPDATE_CONNECT_CONTEXT 0x7010
+#endif
+
+#ifndef TCP_KEEPALIVE
+# define TCP_KEEPALIVE 3
+#endif
+
+#ifndef IPV6_V6ONLY
+# define IPV6_V6ONLY 27
+#endif
+
+#ifndef IPV6_HOPLIMIT
+# define IPV6_HOPLIMIT 21
+#endif
+
+#ifndef SIO_BASE_HANDLE
+# define SIO_BASE_HANDLE 0x48000022
+#endif
+
+/*
+ * TDI defines that are only in the DDK.
+ * We only need receive flags so far.
+ */
+#ifndef TDI_RECEIVE_NORMAL
+ #define TDI_RECEIVE_BROADCAST 0x00000004
+ #define TDI_RECEIVE_MULTICAST 0x00000008
+ #define TDI_RECEIVE_PARTIAL 0x00000010
+ #define TDI_RECEIVE_NORMAL 0x00000020
+ #define TDI_RECEIVE_EXPEDITED 0x00000040
+ #define TDI_RECEIVE_PEEK 0x00000080
+ #define TDI_RECEIVE_NO_RESPONSE_EXP 0x00000100
+ #define TDI_RECEIVE_COPY_LOOKAHEAD 0x00000200
+ #define TDI_RECEIVE_ENTIRE_MESSAGE 0x00000400
+ #define TDI_RECEIVE_AT_DISPATCH_LEVEL 0x00000800
+ #define TDI_RECEIVE_CONTROL_INFO 0x00001000
+ #define TDI_RECEIVE_FORCE_INDICATION 0x00002000
+ #define TDI_RECEIVE_NO_PUSH 0x00004000
+#endif
+
+/*
+ * The "Auxiliary Function Driver" is the windows kernel-mode driver that does
+ * TCP, UDP etc. Winsock is just a layer that dispatches requests to it.
+ * Having these definitions allows us to bypass winsock and make an AFD kernel
+ * call directly, avoiding a bug in winsock's recvfrom implementation.
+ */
+
+#define AFD_NO_FAST_IO 0x00000001
+#define AFD_OVERLAPPED 0x00000002
+#define AFD_IMMEDIATE 0x00000004
+
+#define AFD_POLL_RECEIVE_BIT 0
+#define AFD_POLL_RECEIVE (1 << AFD_POLL_RECEIVE_BIT)
+#define AFD_POLL_RECEIVE_EXPEDITED_BIT 1
+#define AFD_POLL_RECEIVE_EXPEDITED (1 << AFD_POLL_RECEIVE_EXPEDITED_BIT)
+#define AFD_POLL_SEND_BIT 2
+#define AFD_POLL_SEND (1 << AFD_POLL_SEND_BIT)
+#define AFD_POLL_DISCONNECT_BIT 3
+#define AFD_POLL_DISCONNECT (1 << AFD_POLL_DISCONNECT_BIT)
+#define AFD_POLL_ABORT_BIT 4
+#define AFD_POLL_ABORT (1 << AFD_POLL_ABORT_BIT)
+#define AFD_POLL_LOCAL_CLOSE_BIT 5
+#define AFD_POLL_LOCAL_CLOSE (1 << AFD_POLL_LOCAL_CLOSE_BIT)
+#define AFD_POLL_CONNECT_BIT 6
+#define AFD_POLL_CONNECT (1 << AFD_POLL_CONNECT_BIT)
+#define AFD_POLL_ACCEPT_BIT 7
+#define AFD_POLL_ACCEPT (1 << AFD_POLL_ACCEPT_BIT)
+#define AFD_POLL_CONNECT_FAIL_BIT 8
+#define AFD_POLL_CONNECT_FAIL (1 << AFD_POLL_CONNECT_FAIL_BIT)
+#define AFD_POLL_QOS_BIT 9
+#define AFD_POLL_QOS (1 << AFD_POLL_QOS_BIT)
+#define AFD_POLL_GROUP_QOS_BIT 10
+#define AFD_POLL_GROUP_QOS (1 << AFD_POLL_GROUP_QOS_BIT)
+
+#define AFD_NUM_POLL_EVENTS 11
+#define AFD_POLL_ALL ((1 << AFD_NUM_POLL_EVENTS) - 1)
+
+typedef struct _AFD_RECV_DATAGRAM_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+ struct sockaddr* Address;
+ int* AddressLength;
+} AFD_RECV_DATAGRAM_INFO, *PAFD_RECV_DATAGRAM_INFO;
+
+typedef struct _AFD_RECV_INFO {
+ LPWSABUF BufferArray;
+ ULONG BufferCount;
+ ULONG AfdFlags;
+ ULONG TdiFlags;
+} AFD_RECV_INFO, *PAFD_RECV_INFO;
+
+
+#define _AFD_CONTROL_CODE(operation, method) \
+ ((FSCTL_AFD_BASE) << 12 | (operation << 2) | method)
+
+#define FSCTL_AFD_BASE FILE_DEVICE_NETWORK
+
+#define AFD_RECEIVE 5
+#define AFD_RECEIVE_DATAGRAM 6
+#define AFD_POLL 9
+
+#define IOCTL_AFD_RECEIVE \
+ _AFD_CONTROL_CODE(AFD_RECEIVE, METHOD_NEITHER)
+
+#define IOCTL_AFD_RECEIVE_DATAGRAM \
+ _AFD_CONTROL_CODE(AFD_RECEIVE_DATAGRAM, METHOD_NEITHER)
+
+#define IOCTL_AFD_POLL \
+ _AFD_CONTROL_CODE(AFD_POLL, METHOD_BUFFERED)
+
+#if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) \
+ || (defined(_MSC_VER) && _MSC_VER < 1500)
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_XP {
+ /* FIXME: __C89_NAMELESS was removed */
+ /* __C89_NAMELESS */ union {
+ ULONGLONG Alignment;
+ /* __C89_NAMELESS */ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_XP *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+} IP_ADAPTER_UNICAST_ADDRESS_XP,*PIP_ADAPTER_UNICAST_ADDRESS_XP;
+
+typedef struct _IP_ADAPTER_UNICAST_ADDRESS_LH {
+ union {
+ ULONGLONG Alignment;
+ struct {
+ ULONG Length;
+ DWORD Flags;
+ };
+ };
+ struct _IP_ADAPTER_UNICAST_ADDRESS_LH *Next;
+ SOCKET_ADDRESS Address;
+ IP_PREFIX_ORIGIN PrefixOrigin;
+ IP_SUFFIX_ORIGIN SuffixOrigin;
+ IP_DAD_STATE DadState;
+ ULONG ValidLifetime;
+ ULONG PreferredLifetime;
+ ULONG LeaseLifetime;
+ UINT8 OnLinkPrefixLength;
+} IP_ADAPTER_UNICAST_ADDRESS_LH,*PIP_ADAPTER_UNICAST_ADDRESS_LH;
+
+#endif
+
+#endif /* UV_WIN_WINSOCK_H_ */
diff --git a/Utilities/cmvssetup/.gitattributes b/Utilities/cmvssetup/.gitattributes
new file mode 100644
index 000000000..562b12e16
--- /dev/null
+++ b/Utilities/cmvssetup/.gitattributes
@@ -0,0 +1 @@
+* -whitespace
diff --git a/Utilities/cmvssetup/Setup.Configuration.h b/Utilities/cmvssetup/Setup.Configuration.h
new file mode 100644
index 000000000..6c9d8f924
--- /dev/null
+++ b/Utilities/cmvssetup/Setup.Configuration.h
@@ -0,0 +1,991 @@
+// <copyright file="Setup.Configuration.h" company="Microsoft Corporation">
+// Copyright (C) Microsoft Corporation. All rights reserved.
+// </copyright>
+
+// This file is licensed under "The MIT License(MIT)".
+// This file is released by Visual Studio setup team for consumption by external applications.
+// For more information please look at this git repo https://github.com/microsoft/vs-setup-samples
+
+#ifndef SetupConfiguration_h
+#define SetupConfiguration_h
+
+#include <objbase.h>
+
+// Constants
+//
+#ifndef E_NOTFOUND
+#define E_NOTFOUND HRESULT_FROM_WIN32(ERROR_NOT_FOUND)
+#endif
+
+#ifndef E_FILENOTFOUND
+#define E_FILENOTFOUND HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)
+
+#ifndef _Outptr_result_maybenull_
+#define _Outptr_result_maybenull_
+#endif
+#ifndef _Out_writes_to_
+#define _Out_writes_to_(x,y)
+#endif
+#ifndef _Reserved_
+#define _Reserved_
+#endif
+#ifndef MAXUINT
+#define MAXUINT ((UINT)~((UINT)0))
+#endif
+
+// Enumerations
+//
+/// <summary>
+/// The state of an instance.
+/// </summary>
+enum InstanceState
+{
+ /// <summary>
+ /// The instance state has not been determined.
+ /// </summary>
+ eNone = 0,
+
+ /// <summary>
+ /// The instance installation path exists.
+ /// </summary>
+ eLocal = 1,
+
+ /// <summary>
+ /// A product is registered to the instance.
+ /// </summary>
+ eRegistered = 2,
+
+ /// <summary>
+ /// No reboot is required for the instance.
+ /// </summary>
+ eNoRebootRequired = 4,
+
+ /// <summary>
+ /// The instance represents a complete install.
+ /// </summary>
+ eComplete = MAXUINT,
+};
+
+// Forward interface declarations
+//
+#ifndef __ISetupInstance_FWD_DEFINED__
+#define __ISetupInstance_FWD_DEFINED__
+typedef struct ISetupInstance ISetupInstance;
+#endif
+
+#ifndef __ISetupInstance2_FWD_DEFINED__
+#define __ISetupInstance2_FWD_DEFINED__
+typedef struct ISetupInstance2 ISetupInstance2;
+#endif
+
+#ifndef __IEnumSetupInstances_FWD_DEFINED__
+#define __IEnumSetupInstances_FWD_DEFINED__
+typedef struct IEnumSetupInstances IEnumSetupInstances;
+#endif
+
+#ifndef __ISetupConfiguration_FWD_DEFINED__
+#define __ISetupConfiguration_FWD_DEFINED__
+typedef struct ISetupConfiguration ISetupConfiguration;
+#endif
+
+#ifndef __ISetupConfiguration2_FWD_DEFINED__
+#define __ISetupConfiguration2_FWD_DEFINED__
+typedef struct ISetupConfiguration2 ISetupConfiguration2;
+#endif
+
+#ifndef __ISetupPackageReference_FWD_DEFINED__
+#define __ISetupPackageReference_FWD_DEFINED__
+typedef struct ISetupPackageReference ISetupPackageReference;
+#endif
+
+#ifndef __ISetupHelper_FWD_DEFINED__
+#define __ISetupHelper_FWD_DEFINED__
+typedef struct ISetupHelper ISetupHelper;
+#endif
+
+// Forward class declarations
+//
+#ifndef __SetupConfiguration_FWD_DEFINED__
+#define __SetupConfiguration_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class SetupConfiguration SetupConfiguration;
+#endif
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Interface definitions
+//
+EXTERN_C const IID IID_ISetupInstance;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Information about an instance of a product.
+/// </summary>
+struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown
+{
+ /// <summary>
+ /// Gets the instance identifier (should match the name of the parent instance directory).
+ /// </summary>
+ /// <param name="pbstrInstanceId">The instance identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetInstanceId)(
+ _Out_ BSTR* pbstrInstanceId
+ ) = 0;
+
+ /// <summary>
+ /// Gets the local date and time when the installation was originally installed.
+ /// </summary>
+ /// <param name="pInstallDate">The local date and time when the installation was originally installed.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallDate)(
+ _Out_ LPFILETIME pInstallDate
+ ) = 0;
+
+ /// <summary>
+ /// Gets the unique name of the installation, often indicating the branch and other information used for telemetry.
+ /// </summary>
+ /// <param name="pbstrInstallationName">The unique name of the installation, often indicating the branch and other information used for telemetry.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationName)(
+ _Out_ BSTR* pbstrInstallationName
+ ) = 0;
+
+ /// <summary>
+ /// Gets the path to the installation root of the product.
+ /// </summary>
+ /// <param name="pbstrInstallationPath">The path to the installation root of the product.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationPath)(
+ _Out_ BSTR* pbstrInstallationPath
+ ) = 0;
+
+ /// <summary>
+ /// Gets the version of the product installed in this instance.
+ /// </summary>
+ /// <param name="pbstrInstallationVersion">The version of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationVersion)(
+ _Out_ BSTR* pbstrInstallationVersion
+ ) = 0;
+
+ /// <summary>
+ /// Gets the display name (title) of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the display name.</param>
+ /// <param name="pbstrDisplayName">The display name (title) of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetDisplayName)(
+ _In_ LCID lcid,
+ _Out_ BSTR* pbstrDisplayName
+ ) = 0;
+
+ /// <summary>
+ /// Gets the description of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the description.</param>
+ /// <param name="pbstrDescription">The description of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetDescription)(
+ _In_ LCID lcid,
+ _Out_ BSTR* pbstrDescription
+ ) = 0;
+
+ /// <summary>
+ /// Resolves the optional relative path to the root path of the instance.
+ /// </summary>
+ /// <param name="pwszRelativePath">A relative path within the instance to resolve, or NULL to get the root path.</param>
+ /// <param name="pbstrAbsolutePath">The full path to the optional relative path within the instance. If the relative path is NULL, the root path will always terminate in a backslash.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(ResolvePath)(
+ _In_opt_z_ LPCOLESTR pwszRelativePath,
+ _Out_ BSTR* pbstrAbsolutePath
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupInstance2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Information about an instance of a product.
+/// </summary>
+struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance
+{
+ /// <summary>
+ /// Gets the state of the instance.
+ /// </summary>
+ /// <param name="pState">The state of the instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetState)(
+ _Out_ InstanceState* pState
+ ) = 0;
+
+ /// <summary>
+ /// Gets an array of package references registered to the instance.
+ /// </summary>
+ /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
+ STDMETHOD(GetPackages)(
+ _Out_ LPSAFEARRAY* ppsaPackages
+ ) = 0;
+
+ /// <summary>
+ /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents the registered product.
+ /// </summary>
+ /// <param name="ppPackage">Pointer to an instance of <see cref="ISetupPackageReference"/>. This may be NULL if <see cref="GetState"/> does not return <see cref="eComplete"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
+ STDMETHOD(GetProduct)(
+ _Outptr_result_maybenull_ ISetupPackageReference** ppPackage
+ ) = 0;
+
+ /// <summary>
+ /// Gets the relative path to the product application, if available.
+ /// </summary>
+ /// <param name="pbstrProductPath">The relative path to the product application, if available.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetProductPath)(
+ _Outptr_result_maybenull_ BSTR* pbstrProductPath
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_IEnumSetupInstances;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// A enumerator of installed <see cref="ISetupInstance"/> objects.
+/// </summary>
+struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown
+{
+ /// <summary>
+ /// Retrieves the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to retrieve.</param>
+ /// <param name="rgelt">A pointer to an array of <see cref="ISetupInstance"/>.</param>
+ /// <param name="pceltFetched">A pointer to the number of product instances retrieved. If celt is 1 this parameter may be NULL.</param>
+ /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing was fetched (at end of enumeration), E_INVALIDARG if celt is greater than 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see cref="ISetupInstance"/> could not be allocated.</returns>
+ STDMETHOD(Next)(
+ _In_ ULONG celt,
+ _Out_writes_to_(celt, *pceltFetched) ISetupInstance** rgelt,
+ _Out_opt_ _Deref_out_range_(0, celt) ULONG* pceltFetched
+ ) = 0;
+
+ /// <summary>
+ /// Skips the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to skip.</param>
+ /// <returns>S_OK if the number of elements could be skipped; otherwise, S_FALSE;</returns>
+ STDMETHOD(Skip)(
+ _In_ ULONG celt
+ ) = 0;
+
+ /// <summary>
+ /// Resets the enumeration sequence to the beginning.
+ /// </summary>
+ /// <returns>Always returns S_OK;</returns>
+ STDMETHOD(Reset)(void) = 0;
+
+ /// <summary>
+ /// Creates a new enumeration object in the same state as the current enumeration object: the new object points to the same place in the enumeration sequence.
+ /// </summary>
+ /// <param name="ppenum">A pointer to a pointer to a new <see cref="IEnumSetupInstances"/> interface. If the method fails, this parameter is undefined.</param>
+ /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
+ STDMETHOD(Clone)(
+ _Deref_out_opt_ IEnumSetupInstances** ppenum
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupConfiguration;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Gets information about product instances set up on the machine.
+/// </summary>
+struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown
+{
+ /// <summary>
+ /// Enumerates all completed product instances installed.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of completed, installed product instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumInstances)(
+ _Out_ IEnumSetupInstances** ppEnumInstances
+ ) = 0;
+
+ /// <summary>
+ /// Gets the instance for the current process path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the current process path.</param>
+ /// <returns>The instance for the current process path, or E_NOTFOUND if not found.</returns>
+ STDMETHOD(GetInstanceForCurrentProcess)(
+ _Out_ ISetupInstance** ppInstance
+ ) = 0;
+
+ /// <summary>
+ /// Gets the instance for the given path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the given path.</param>
+ /// <returns>The instance for the given path, or E_NOTFOUND if not found.</returns>
+ STDMETHOD(GetInstanceForPath)(
+ _In_z_ LPCWSTR wzPath,
+ _Out_ ISetupInstance** ppInstance
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupConfiguration2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Gets information about product instances.
+/// </summary>
+struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration
+{
+ /// <summary>
+ /// Enumerates all product instances.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of all product instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumAllInstances)(
+ _Out_ IEnumSetupInstances** ppEnumInstances
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupPackageReference;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// A reference to a package.
+/// </summary>
+struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown
+{
+ /// <summary>
+ /// Gets the general package identifier.
+ /// </summary>
+ /// <param name="pbstrId">The general package identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetId)(
+ _Out_ BSTR* pbstrId
+ ) = 0;
+
+ /// <summary>
+ /// Gets the version of the package.
+ /// </summary>
+ /// <param name="pbstrVersion">The version of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetVersion)(
+ _Out_ BSTR* pbstrVersion
+ ) = 0;
+
+ /// <summary>
+ /// Gets the target process architecture of the package.
+ /// </summary>
+ /// <param name="pbstrChip">The target process architecture of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetChip)(
+ _Out_ BSTR* pbstrChip
+ ) = 0;
+
+ /// <summary>
+ /// Gets the language and optional region identifier.
+ /// </summary>
+ /// <param name="pbstrLanguage">The language and optional region identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetLanguage)(
+ _Out_ BSTR* pbstrLanguage
+ ) = 0;
+
+ /// <summary>
+ /// Gets the build branch of the package.
+ /// </summary>
+ /// <param name="pbstrBranch">The build branch of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetBranch)(
+ _Out_ BSTR* pbstrBranch
+ ) = 0;
+
+ /// <summary>
+ /// Gets the type of the package.
+ /// </summary>
+ /// <param name="pbstrType">The type of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetType)(
+ _Out_ BSTR* pbstrType
+ ) = 0;
+
+ /// <summary>
+ /// Gets the unique identifier consisting of all defined tokens.
+ /// </summary>
+ /// <param name="pbstrUniqueId">The unique identifier consisting of all defined tokens.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns>
+ STDMETHOD(GetUniqueId)(
+ _Out_ BSTR* pbstrUniqueId
+ ) = 0;
+};
+#endif
+
+EXTERN_C const IID IID_ISetupHelper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+/// <summary>
+/// Helper functions.
+/// </summary>
+/// <remarks>
+/// You can query for this interface from the <see cref="SetupConfiguration"/> class.
+/// </remarks>
+struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown
+{
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersion">The dotted quad version string to parse, e.g. 1.2.3.4.</param>
+ /// <param name="pullVersion">A 64-bit unsigned integer representing the version. You can compare this to other versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersion)(
+ _In_ LPCOLESTR pwszVersion,
+ _Out_ PULONGLONG pullVersion
+ ) = 0;
+
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
+ /// <param name="pullMinVersion">A 64-bit unsigned integer representing the minimum version, which may be 0. You can compare this to other versions.</param>
+ /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the maximum version, which may be MAXULONGLONG. You can compare this to other versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersionRange)(
+ _In_ LPCOLESTR pwszVersionRange,
+ _Out_ PULONGLONG pullMinVersion,
+ _Out_ PULONGLONG pullMaxVersion
+ ) = 0;
+};
+#endif
+
+// Class declarations
+//
+EXTERN_C const CLSID CLSID_SetupConfiguration;
+
+#ifdef __cplusplus
+/// <summary>
+/// This class implements <see cref="ISetupConfiguration"/>, <see cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
+/// </summary>
+class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
+#endif
+
+// Function declarations
+//
+/// <summary>
+/// Gets an <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.
+/// </summary>
+/// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.</param>
+/// <param name="pReserved">Reserved for future use.</param>
+/// <returns>Standard HRESULT indicating success or failure.</returns>
+STDMETHODIMP GetSetupConfiguration(
+ _Out_ ISetupConfiguration** ppConfiguration,
+ _Reserved_ LPVOID pReserved
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#else
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
+#define VS_SETUP_GCC_DIAGNOSTIC_PUSHED
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+#endif
+
+#ifndef MAXUINT
+#define MAXUINT ((UINT)~((UINT)0))
+#endif
+
+#ifndef DECLSPEC_NOVTABLE
+#if (_MSC_VER >= 1100) && defined(__cplusplus)
+#define DECLSPEC_NOVTABLE __declspec(novtable)
+#else
+#define DECLSPEC_NOVTABLE
+#endif
+#endif
+
+// Enumerations
+//
+/// <summary>
+/// The state of an instance.
+/// </summary>
+enum InstanceState
+{
+ /// <summary>
+ /// The instance state has not been determined.
+ /// </summary>
+ eNone = 0,
+
+ /// <summary>
+ /// The instance installation path exists.
+ /// </summary>
+ eLocal = 1,
+
+ /// <summary>
+ /// A product is registered to the instance.
+ /// </summary>
+ eRegistered = 2,
+
+ /// <summary>
+ /// No reboot is required for the instance.
+ /// </summary>
+ eNoRebootRequired = 4,
+
+ /// <summary>
+ /// The instance represents a complete install.
+ /// </summary>
+ eComplete = MAXUINT,
+};
+
+// Forward interface declarations
+//
+#ifndef __ISetupInstance_FWD_DEFINED__
+#define __ISetupInstance_FWD_DEFINED__
+typedef struct ISetupInstance ISetupInstance;
+#endif
+
+#ifndef __ISetupInstance2_FWD_DEFINED__
+#define __ISetupInstance2_FWD_DEFINED__
+typedef struct ISetupInstance2 ISetupInstance2;
+#endif
+
+#ifndef __IEnumSetupInstances_FWD_DEFINED__
+#define __IEnumSetupInstances_FWD_DEFINED__
+typedef struct IEnumSetupInstances IEnumSetupInstances;
+#endif
+
+#ifndef __ISetupConfiguration_FWD_DEFINED__
+#define __ISetupConfiguration_FWD_DEFINED__
+typedef struct ISetupConfiguration ISetupConfiguration;
+#endif
+
+#ifndef __ISetupConfiguration2_FWD_DEFINED__
+#define __ISetupConfiguration2_FWD_DEFINED__
+typedef struct ISetupConfiguration2 ISetupConfiguration2;
+#endif
+
+#ifndef __ISetupPackageReference_FWD_DEFINED__
+#define __ISetupPackageReference_FWD_DEFINED__
+typedef struct ISetupPackageReference ISetupPackageReference;
+#endif
+
+#ifndef __ISetupHelper_FWD_DEFINED__
+#define __ISetupHelper_FWD_DEFINED__
+typedef struct ISetupHelper ISetupHelper;
+#endif
+
+// Forward class declarations
+//
+#ifndef __SetupConfiguration_FWD_DEFINED__
+#define __SetupConfiguration_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class SetupConfiguration SetupConfiguration;
+#endif
+
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ // Interface definitions
+ //
+ EXTERN_C const IID IID_ISetupInstance;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// Information about an instance of a product.
+ /// </summary>
+ struct DECLSPEC_UUID("B41463C3-8866-43B5-BC33-2B0676F7F42E") DECLSPEC_NOVTABLE ISetupInstance : public IUnknown
+ {
+ /// <summary>
+ /// Gets the instance identifier (should match the name of the parent instance directory).
+ /// </summary>
+ /// <param name="pbstrInstanceId">The instance identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetInstanceId)(
+ BSTR* pbstrInstanceId
+ ) = 0;
+
+ /// <summary>
+ /// Gets the local date and time when the installation was originally installed.
+ /// </summary>
+ /// <param name="pInstallDate">The local date and time when the installation was originally installed.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallDate)(
+ LPFILETIME pInstallDate
+ ) = 0;
+
+ /// <summary>
+ /// Gets the unique name of the installation, often indicating the branch and other information used for telemetry.
+ /// </summary>
+ /// <param name="pbstrInstallationName">The unique name of the installation, often indicating the branch and other information used for telemetry.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationName)(
+ BSTR* pbstrInstallationName
+ ) = 0;
+
+ /// <summary>
+ /// Gets the path to the installation root of the product.
+ /// </summary>
+ /// <param name="pbstrInstallationPath">The path to the installation root of the product.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationPath)(
+ BSTR* pbstrInstallationPath
+ ) = 0;
+
+ /// <summary>
+ /// Gets the version of the product installed in this instance.
+ /// </summary>
+ /// <param name="pbstrInstallationVersion">The version of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetInstallationVersion)(
+ BSTR* pbstrInstallationVersion
+ ) = 0;
+
+ /// <summary>
+ /// Gets the display name (title) of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the display name.</param>
+ /// <param name="pbstrDisplayName">The display name (title) of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetDisplayName)(
+ LCID lcid,
+ BSTR* pbstrDisplayName
+ ) = 0;
+
+ /// <summary>
+ /// Gets the description of the product installed in this instance.
+ /// </summary>
+ /// <param name="lcid">The LCID for the description.</param>
+ /// <param name="pbstrDescription">The description of the product installed in this instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(GetDescription)(
+ LCID lcid,
+ BSTR* pbstrDescription
+ ) = 0;
+
+ /// <summary>
+ /// Resolves the optional relative path to the root path of the instance.
+ /// </summary>
+ /// <param name="pwszRelativePath">A relative path within the instance to resolve, or NULL to get the root path.</param>
+ /// <param name="pbstrAbsolutePath">The full path to the optional relative path within the instance. If the relative path is NULL, the root path will always terminate in a backslash.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the property is not defined.</returns>
+ STDMETHOD(ResolvePath)(
+ LPCOLESTR pwszRelativePath,
+ BSTR* pbstrAbsolutePath
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_ISetupInstance2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// Information about an instance of a product.
+ /// </summary>
+ struct DECLSPEC_UUID("89143C9A-05AF-49B0-B717-72E218A2185C") DECLSPEC_NOVTABLE ISetupInstance2 : public ISetupInstance
+ {
+ /// <summary>
+ /// Gets the state of the instance.
+ /// </summary>
+ /// <param name="pState">The state of the instance.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetState)(
+ InstanceState* pState
+ ) = 0;
+
+ /// <summary>
+ /// Gets an array of package references registered to the instance.
+ /// </summary>
+ /// <param name="ppsaPackages">Pointer to an array of <see cref="ISetupPackageReference"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
+ STDMETHOD(GetPackages)(
+ LPSAFEARRAY* ppsaPackages
+ ) = 0;
+
+ /// <summary>
+ /// Gets a pointer to the <see cref="ISetupPackageReference"/> that represents the registered product.
+ /// </summary>
+ /// <param name="ppPackage">Pointer to an instance of <see cref="ISetupPackageReference"/>. This may be NULL if <see cref="GetState"/> does not return <see cref="eComplete"/>.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist and E_NOTFOUND if the packages property is not defined.</returns>
+ STDMETHOD(GetProduct)(
+ ISetupPackageReference** ppPackage
+ ) = 0;
+
+ /// <summary>
+ /// Gets the relative path to the product application, if available.
+ /// </summary>
+ /// <param name="pbstrProductPath">The relative path to the product application, if available.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_FILENOTFOUND if the instance state does not exist.</returns>
+ STDMETHOD(GetProductPath)(
+ BSTR* pbstrProductPath
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_IEnumSetupInstances;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// A enumerator of installed <see cref="ISetupInstance"/> objects.
+ /// </summary>
+ struct DECLSPEC_UUID("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848") DECLSPEC_NOVTABLE IEnumSetupInstances : public IUnknown
+ {
+ /// <summary>
+ /// Retrieves the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to retrieve.</param>
+ /// <param name="rgelt">A pointer to an array of <see cref="ISetupInstance"/>.</param>
+ /// <param name="pceltFetched">A pointer to the number of product instances retrieved. If celt is 1 this parameter may be NULL.</param>
+ /// <returns>S_OK if the number of elements were fetched, S_FALSE if nothing was fetched (at end of enumeration), E_INVALIDARG if celt is greater than 1 and pceltFetched is NULL, or E_OUTOFMEMORY if an <see cref="ISetupInstance"/> could not be allocated.</returns>
+ STDMETHOD(Next)(
+ ULONG celt,
+ ISetupInstance** rgelt,
+ ULONG* pceltFetched
+ ) = 0;
+
+ /// <summary>
+ /// Skips the next set of product instances in the enumeration sequence.
+ /// </summary>
+ /// <param name="celt">The number of product instances to skip.</param>
+ /// <returns>S_OK if the number of elements could be skipped; otherwise, S_FALSE;</returns>
+ STDMETHOD(Skip)(
+ ULONG celt
+ ) = 0;
+
+ /// <summary>
+ /// Resets the enumeration sequence to the beginning.
+ /// </summary>
+ /// <returns>Always returns S_OK;</returns>
+ STDMETHOD(Reset)(void) = 0;
+
+ /// <summary>
+ /// Creates a new enumeration object in the same state as the current enumeration object: the new object points to the same place in the enumeration sequence.
+ /// </summary>
+ /// <param name="ppenum">A pointer to a pointer to a new <see cref="IEnumSetupInstances"/> interface. If the method fails, this parameter is undefined.</param>
+ /// <returns>S_OK if a clone was returned; otherwise, E_OUTOFMEMORY.</returns>
+ STDMETHOD(Clone)(
+ IEnumSetupInstances** ppenum
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_ISetupConfiguration;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// Gets information about product instances set up on the machine.
+ /// </summary>
+ struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE ISetupConfiguration : public IUnknown
+ {
+ /// <summary>
+ /// Enumerates all completed product instances installed.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of completed, installed product instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumInstances)(
+ IEnumSetupInstances** ppEnumInstances
+ ) = 0;
+
+ /// <summary>
+ /// Gets the instance for the current process path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the current process path.</param>
+ /// <returns>The instance for the current process path, or E_NOTFOUND if not found.</returns>
+ STDMETHOD(GetInstanceForCurrentProcess)(
+ ISetupInstance** ppInstance
+ ) = 0;
+
+ /// <summary>
+ /// Gets the instance for the given path.
+ /// </summary>
+ /// <param name="ppInstance">The instance for the given path.</param>
+ /// <returns>The instance for the given path, or E_NOTFOUND if not found.</returns>
+ STDMETHOD(GetInstanceForPath)(
+ LPCWSTR wzPath,
+ ISetupInstance** ppInstance
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_ISetupConfiguration2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// Gets information about product instances.
+ /// </summary>
+ struct DECLSPEC_UUID("26AAB78C-4A60-49D6-AF3B-3C35BC93365D") DECLSPEC_NOVTABLE ISetupConfiguration2 : public ISetupConfiguration
+ {
+ /// <summary>
+ /// Enumerates all product instances.
+ /// </summary>
+ /// <param name="ppEnumInstances">An enumeration of all product instances.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(EnumAllInstances)(
+ IEnumSetupInstances** ppEnumInstances
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_ISetupPackageReference;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// A reference to a package.
+ /// </summary>
+ struct DECLSPEC_UUID("da8d8a16-b2b6-4487-a2f1-594ccccd6bf5") DECLSPEC_NOVTABLE ISetupPackageReference : public IUnknown
+ {
+ /// <summary>
+ /// Gets the general package identifier.
+ /// </summary>
+ /// <param name="pbstrId">The general package identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetId)(
+ BSTR* pbstrId
+ ) = 0;
+
+ /// <summary>
+ /// Gets the version of the package.
+ /// </summary>
+ /// <param name="pbstrVersion">The version of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetVersion)(
+ BSTR* pbstrVersion
+ ) = 0;
+
+ /// <summary>
+ /// Gets the target process architecture of the package.
+ /// </summary>
+ /// <param name="pbstrChip">The target process architecture of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetChip)(
+ BSTR* pbstrChip
+ ) = 0;
+
+ /// <summary>
+ /// Gets the language and optional region identifier.
+ /// </summary>
+ /// <param name="pbstrLanguage">The language and optional region identifier.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetLanguage)(
+ BSTR* pbstrLanguage
+ ) = 0;
+
+ /// <summary>
+ /// Gets the build branch of the package.
+ /// </summary>
+ /// <param name="pbstrBranch">The build branch of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetBranch)(
+ BSTR* pbstrBranch
+ ) = 0;
+
+ /// <summary>
+ /// Gets the type of the package.
+ /// </summary>
+ /// <param name="pbstrType">The type of the package.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(GetType)(
+ BSTR* pbstrType
+ ) = 0;
+
+ /// <summary>
+ /// Gets the unique identifier consisting of all defined tokens.
+ /// </summary>
+ /// <param name="pbstrUniqueId">The unique identifier consisting of all defined tokens.</param>
+ /// <returns>Standard HRESULT indicating success or failure, including E_UNEXPECTED if no Id was defined (required).</returns>
+ STDMETHOD(GetUniqueId)(
+ BSTR* pbstrUniqueId
+ ) = 0;
+ };
+#endif
+
+ EXTERN_C const IID IID_ISetupHelper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+ /// <summary>
+ /// Helper functions.
+ /// </summary>
+ /// <remarks>
+ /// You can query for this interface from the <see cref="SetupConfiguration"/> class.
+ /// </remarks>
+ struct DECLSPEC_UUID("42b21b78-6192-463e-87bf-d577838f1d5c") DECLSPEC_NOVTABLE ISetupHelper : public IUnknown
+ {
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersion">The dotted quad version string to parse, e.g. 1.2.3.4.</param>
+ /// <param name="pullVersion">A 64-bit unsigned integer representing the version. You can compare this to other versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersion)(
+ LPCOLESTR pwszVersion,
+ PULONGLONG pullVersion
+ ) = 0;
+
+ /// <summary>
+ /// Parses a dotted quad version string into a 64-bit unsigned integer.
+ /// </summary>
+ /// <param name="pwszVersionRange">The string containing 1 or 2 dotted quad version strings to parse, e.g. [1.0,) that means 1.0.0.0 or newer.</param>
+ /// <param name="pullMinVersion">A 64-bit unsigned integer representing the minimum version, which may be 0. You can compare this to other versions.</param>
+ /// <param name="pullMaxVersion">A 64-bit unsigned integer representing the maximum version, which may be MAXULONGLONG. You can compare this to other versions.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHOD(ParseVersionRange)(
+ LPCOLESTR pwszVersionRange,
+ PULONGLONG pullMinVersion,
+ PULONGLONG pullMaxVersion
+ ) = 0;
+ };
+#endif
+
+ // Class declarations
+ //
+ EXTERN_C const CLSID CLSID_SetupConfiguration;
+
+#ifdef __cplusplus
+ /// <summary>
+ /// This class implements <see cref="ISetupConfiguration"/>, <see cref="ISetupConfiguration2"/>, and <see cref="ISetupHelper"/>.
+ /// </summary>
+ class DECLSPEC_UUID("177F0C4A-1CD3-4DE7-A32C-71DBBB9FA36D") SetupConfiguration;
+#endif
+
+ // Function declarations
+ //
+ /// <summary>
+ /// Gets an <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.
+ /// </summary>
+ /// <param name="ppConfiguration">The <see cref="ISetupConfiguration"/> that provides information about product instances installed on the machine.</param>
+ /// <param name="pReserved">Reserved for future use.</param>
+ /// <returns>Standard HRESULT indicating success or failure.</returns>
+ STDMETHODIMP GetSetupConfiguration(
+ ISetupConfiguration** ppConfiguration,
+ LPVOID pReserved
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef VS_SETUP_GCC_DIAGNOSTIC_PUSHED
+#pragma GCC diagnostic pop
+#undef VS_SETUP_GCC_DIAGNOSTIC_PUSHED
+#endif
+
+#endif
+#endif
diff --git a/Utilities/cmzlib/CMakeLists.txt b/Utilities/cmzlib/CMakeLists.txt
index f161056e5..0be48f107 100644
--- a/Utilities/cmzlib/CMakeLists.txt
+++ b/Utilities/cmzlib/CMakeLists.txt
@@ -1,5 +1,13 @@
PROJECT(CMZLIB)
+# Disable warnings to avoid changing 3rd party code.
+if(CMAKE_C_COMPILER_ID MATCHES
+ "^(GNU|Clang|AppleClang|XL|VisualAge|SunPro|MIPSpro|HP|Intel)$")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -w")
+elseif(CMAKE_C_COMPILER_ID STREQUAL "PathScale")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -woffall")
+endif()
+
INCLUDE_DIRECTORIES(
"${CMZLIB_SOURCE_DIR}"
"${CMZLIB_SOURCE_DIR}/.."
@@ -18,12 +26,10 @@ IF(WIN32)
IF(BUILD_SHARED_LIBS)
SET(ZLIB_DLL 1)
IF(NOT UNIX)
- IF(NOT BORLAND)
- IF(NOT MINGW)
- SET(ZLIB_SRCS ${ZLIB_SRCS} zlib.def zlib.rc )
- ENDIF(NOT MINGW)
- ENDIF(NOT BORLAND)
- ENDIF(NOT UNIX)
+ IF(NOT MINGW)
+ SET(ZLIB_SRCS ${ZLIB_SRCS} zlib.def zlib.rc )
+ ENDIF(NOT MINGW)
+ ENDIF(NOT UNIX)
ENDIF(BUILD_SHARED_LIBS)
ENDIF(WIN32)
diff --git a/Utilities/cmzlib/zconf.h b/Utilities/cmzlib/zconf.h
index 6eb52d133..7a3b6fdc1 100644
--- a/Utilities/cmzlib/zconf.h
+++ b/Utilities/cmzlib/zconf.h
@@ -237,7 +237,7 @@
# endif
#endif
-#if defined (__BEOS__) && !defined (__HAIKU__)
+#if defined (__BEOS__)
# ifdef ZLIB_DLL
# ifdef ZLIB_INTERNAL
# define ZEXPORT __declspec(dllexport)
diff --git a/Utilities/cmzlib/zutil.h b/Utilities/cmzlib/zutil.h
index 74ef1f89f..3053cd8ee 100644
--- a/Utilities/cmzlib/zutil.h
+++ b/Utilities/cmzlib/zutil.h
@@ -147,12 +147,6 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */
# define OS_CODE 0x0f
#endif
-/* Haiku defines both __HAIKU__ and __BEOS__ (for now) */
-/* many BeOS workarounds are no longer needed in Haiku */
-#if defined(__HAIKU__) && defined(__BEOS__)
-#undef __BEOS__
-#endif
-
#if defined(_BEOS_) || defined(RISCOS)
# define fdopen(fd,mode) NULL /* No fdopen() */
#endif
diff --git a/Utilities/xml/docbook-4.5/ChangeLog b/Utilities/xml/docbook-4.5/ChangeLog
deleted file mode 100644
index 06f59ce5c..000000000
--- a/Utilities/xml/docbook-4.5/ChangeLog
+++ /dev/null
@@ -1,106 +0,0 @@
-2006-10-03 13:23 nwalsh
-
- * trunk/docbook/sgml/catalog.xml, trunk/docbook/sgml/docbook.cat,
- trunk/docbook/sgml/docbook.dcl, trunk/docbook/sgml/docbook.dtd,
- calstblx.dtd, catalog.xml, dbcentx.mod, dbgenent.mod,
- dbhierx.mod, dbnotnx.mod, dbpoolx.mod, docbook.cat,
- docbookx.dtd, htmltblx.mod: DocBook V4.5 released
-
-2006-06-02 11:28 nwalsh
-
- * calstblx.dtd, catalog.xml, dbcentx.mod, dbgenent.mod,
- dbhierx.mod, dbnotnx.mod, dbpoolx.mod, docbook.cat,
- docbookx.dtd, freshmeat.xsl, htmltblx.mod: Changed copyright
- dates and version numbers
-
-2006-05-30 20:58 nwalsh
-
- * htmltblx.mod: Supply tag omission markers in SGML; suppress
- xml:lang in SGML
-
-2006-03-07 13:11 nwalsh
-
- * trunk/docbook/sgml/catalog.xml, trunk/docbook/sgml/docbook.cat,
- trunk/docbook/sgml/docbook.dcl, trunk/docbook/sgml/docbook.dtd,
- calstblx.dtd, catalog.xml, dbcentx.mod, dbgenent.mod,
- dbhierx.mod, dbnotnx.mod, dbpoolx.mod, docbook.cat,
- docbookx.dtd, freshmeat.xsl, htmltblx.mod: Change version
- numbers to 4.5CR2
-
-2006-03-07 13:03 nwalsh
-
- * dbpoolx.mod: Allow citebiblioid anywhere the other citation
- elements are allowed
-
-2006-02-16 21:12 nwalsh
-
- * calstblx.dtd, catalog.xml, dbcentx.mod, dbgenent.mod,
- dbhierx.mod, dbnotnx.mod, dbpoolx.mod, docbook.cat,
- docbookx.dtd, freshmeat.xsl, htmltblx.mod: DocBook V4.5 released
-
-2005-06-29 10:59 nwalsh
-
- * trunk/docbook/sgml/docbook.dtd, docbookx.dtd: DocBook V4.5CR1
- Released
-
-2005-06-29 10:58 nwalsh
-
- * trunk/docbook/sgml/catalog.xml, trunk/docbook/sgml/docbook.cat,
- trunk/docbook/sgml/docbook.dcl, calstblx.dtd, catalog.xml,
- dbcentx.mod, dbgenent.mod, dbhierx.mod, dbnotnx.mod,
- dbpoolx.mod, docbook.cat, htmltblx.mod: Updated version number
-
-2005-06-29 10:53 nwalsh
-
- * freshmeat.xsl: Tweaked freshmeat changes
-
-2005-06-24 21:09 nwalsh
-
- * calstblx.dtd, dbhierx.mod, dbpoolx.mod, htmltblx.mod,
- soextblx.dtd: Added doc: structured comments
-
-2005-05-05 11:41 nwalsh
-
- * trunk/docbook/sgml/docbook.dtd, docbookx.dtd: DocBook V4.5b1
- Released
-
-2005-05-05 11:40 nwalsh
-
- * trunk/docbook/sgml/catalog.xml, trunk/docbook/sgml/docbook.cat,
- trunk/docbook/sgml/docbook.dcl, calstblx.dtd, catalog.xml,
- dbcentx.mod, dbgenent.mod, dbhierx.mod, dbnotnx.mod,
- dbpoolx.mod, docbook.cat, htmltblx.mod: Updated version number
-
-2005-05-05 11:37 nwalsh
-
- * freshmeat.xsl: Prepare for 4.5b1
-
-2005-05-05 10:59 nwalsh
-
- * dbpoolx.mod: RFE 1055480: Make revnumber optional
-
-2005-05-05 10:54 nwalsh
-
- * dbpoolx.mod, htmltblx.mod: Allow common attributes on HTML table
- elements
-
-2005-05-05 10:48 nwalsh
-
- * dbpoolx.mod: Added termdef
-
-2005-05-05 10:39 nwalsh
-
- * dbpoolx.mod: Added mathphrase
-
-2005-05-05 10:33 nwalsh
-
- * dbhierx.mod: RFE 1070458: Allow colophon in article
-
-2005-05-05 10:32 nwalsh
-
- * dbpoolx.mod: RFE 1070770: Allow procedure in example
-
-2005-05-05 10:21 nwalsh
-
- * dbpoolx.mod: Add isrn to list of biblioid class attribute values
-
diff --git a/Utilities/xml/docbook-4.5/README b/Utilities/xml/docbook-4.5/README
deleted file mode 100644
index 6fc60c4bf..000000000
--- a/Utilities/xml/docbook-4.5/README
+++ /dev/null
@@ -1,8 +0,0 @@
-README for the DocBook XML DTD
-
-For more information about DocBook, please see
-
- http://www.oasis-open.org/docbook/
-
-Please send all questions, comments, concerns, and bug reports to the
-DocBook mailing list: docbook@lists.oasis-open.org
diff --git a/Utilities/xml/docbook-4.5/calstblx.dtd b/Utilities/xml/docbook-4.5/calstblx.dtd
deleted file mode 100644
index fac58d77e..000000000
--- a/Utilities/xml/docbook-4.5/calstblx.dtd
+++ /dev/null
@@ -1,215 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook CALS Table Model V4.5 ........................................ -->
-<!-- File calstblx.mod .................................................... -->
-
-<!-- Copyright 1992-2002 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- This DTD is based on the CALS Table Model
- PUBLIC "-//USA-DOD//DTD Table Model 951010//EN"
-
- $Id: calstblx.dtd 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the definitions for the CALS Table Model
- converted to XML. It has been modified slightly for use in the
- combined HTML/CALS models supported by DocBook V4.5.
--->
-
-<!-- These definitions are not directly related to the table model, but are
- used in the default CALS table model and are usually defined elsewhere
- (and prior to the inclusion of this table module) in a CALS DTD. -->
-
-<!ENTITY % bodyatt "">
-<!ENTITY % secur "">
-
-<!-- no if zero(s),
- yes if any other digits value -->
-
-<!ENTITY % yesorno 'CDATA'>
-<!ENTITY % titles 'title?'>
-
-<!-- default for use in entry content -->
-
-<!ENTITY % paracon '#PCDATA'>
-
-<!--
-The parameter entities as defined below provide the CALS table model
-as published (as part of the Example DTD) in MIL-HDBK-28001.
-
-These following declarations provide the CALS-compliant default definitions
-for these entities. However, these entities can and should be redefined
-(by giving the appropriate parameter entity declaration(s) prior to the
-reference to this Table Model declaration set entity) to fit the needs
-of the current application.
--->
-
-<!ENTITY % tbl.table.name "(table|chart)">
-<!ENTITY % tbl.table-titles.mdl "%titles;,">
-<!ENTITY % tbl.table-main.mdl "(tgroup+|graphic+)">
-<!ENTITY % tbl.table.mdl "%tbl.table-titles.mdl; %tbl.table-main.mdl;">
-<!ENTITY % tbl.table.att '
- tabstyle CDATA #IMPLIED
- tocentry %yesorno; #IMPLIED
- shortentry %yesorno; #IMPLIED
- orient (port|land) #IMPLIED
- pgwide %yesorno; #IMPLIED '>
-<!ENTITY % tbl.tgroup.mdl "colspec*,spanspec*,thead?,tfoot?,tbody">
-<!ENTITY % tbl.tgroup.att '
- tgroupstyle CDATA #IMPLIED '>
-<!ENTITY % tbl.hdft.mdl "colspec*,row+">
-<!ENTITY % tbl.row.mdl "(entry|entrytbl)+">
-<!ENTITY % tbl.entrytbl.mdl "colspec*,spanspec*,thead?,tbody">
-<!ENTITY % tbl.entry.mdl "(para|warning|caution|note|legend|%paracon;)*">
-
-<!ENTITY % tbl.frame.attval "top|bottom|topbot|all|sides|none">
-<!ENTITY % tbl.tbody.mdl "row+">
-
-<!-- ===== Element and attribute declarations follow. ===== -->
-
-<!--doc:A formal table in a document.-->
-<!ELEMENT table %ho; (%tbl.table.mdl;)>
-
-<!ATTLIST table
- frame (%tbl.frame.attval;) #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- %tbl.table.att;
- %bodyatt;
- %secur;
->
-
-<!--doc:A wrapper for the main content of a table, or part of a table.-->
-<!ELEMENT tgroup %ho; (%tbl.tgroup.mdl;) >
-
-<!ATTLIST tgroup
- cols CDATA #REQUIRED
- %tbl.tgroup.att;
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED
- %secur;
->
-
-<!--doc:Specifications for a column in a table.-->
-<!ELEMENT colspec %ho; EMPTY >
-
-<!ATTLIST colspec
- colnum CDATA #IMPLIED
- colname CDATA #IMPLIED
- colwidth CDATA #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED
->
-
-<!--doc:Formatting information for a spanned column in a table.-->
-<!ELEMENT spanspec %ho; EMPTY >
-
-<!ATTLIST spanspec
- namest CDATA #REQUIRED
- nameend CDATA #REQUIRED
- spanname CDATA #REQUIRED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED
->
-
-<!--doc:A table header consisting of one or more rows.-->
-<!ELEMENT thead %ho; (%tbl.hdft.mdl;)>
-<!ATTLIST thead
- valign (top|middle|bottom) #IMPLIED
- %secur;
->
-
-<!--doc:A table footer consisting of one or more rows.-->
-<!ELEMENT tfoot %ho; (%tbl.hdft.mdl;)>
-<!ATTLIST tfoot
- valign (top|middle|bottom) #IMPLIED
- %secur;
->
-
-<!--doc:A wrapper for the rows of a table or informal table.-->
-<!ELEMENT tbody %ho; (%tbl.tbody.mdl;)>
-
-<!ATTLIST tbody
- valign (top|middle|bottom) #IMPLIED
- %secur;
->
-
-<!--doc:A row in a table.-->
-<!ELEMENT row %ho; (%tbl.row.mdl;)>
-
-<!ATTLIST row
- rowsep %yesorno; #IMPLIED
- valign (top|middle|bottom) #IMPLIED
- %secur;
->
-
-<!--doc:A subtable appearing in place of an Entry in a table.-->
-<!ELEMENT entrytbl %ho; (%tbl.entrytbl.mdl;)>
-
-<!ATTLIST entrytbl
- cols CDATA #REQUIRED
- %tbl.tgroup.att;
- colname CDATA #IMPLIED
- spanname CDATA #IMPLIED
- namest CDATA #IMPLIED
- nameend CDATA #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED
- %secur;
->
-
-<!--doc:A cell in a table.-->
-<!ELEMENT entry %ho; (%tbl.entry.mdl;)*>
-
-<!ATTLIST entry
- colname CDATA #IMPLIED
- namest CDATA #IMPLIED
- nameend CDATA #IMPLIED
- spanname CDATA #IMPLIED
- morerows CDATA #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED
- rotate %yesorno; #IMPLIED
- valign (top|middle|bottom) #IMPLIED
- %secur;
->
-
-<!-- End of DocBook CALS Table Model V4.5 ................................. -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/catalog.xml b/Utilities/xml/docbook-4.5/catalog.xml
deleted file mode 100644
index f75c1d764..000000000
--- a/Utilities/xml/docbook-4.5/catalog.xml
+++ /dev/null
@@ -1,124 +0,0 @@
-<?xml version='1.0'?>
-<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog" prefer="public">
-
-<!-- ...................................................................... -->
-<!-- XML Catalog data for DocBook XML V4.5 ................................ -->
-<!-- File catalog.xml ..................................................... -->
-
-<!-- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/.
- -->
-
-<!-- This is the catalog data file for DocBook V4.5. It is provided as
- a convenience in building your own catalog files. You need not use
- the filenames listed here, and need not use the filename method of
- identifying storage objects at all. See the documentation for
- detailed information on the files associated with the DocBook DTD.
- See XML Catalogs at http://www.oasis-open.org/committees/entity/ for
- detailed information on supplying and using catalog data.
- -->
-
-<!-- ...................................................................... -->
-<!-- DocBook driver file .................................................. -->
-
-<public publicId="-//OASIS//DTD DocBook XML V4.5//EN"
- uri="docbookx.dtd"/>
-
-<system systemId="http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
- uri="docbookx.dtd"/>
-
-<system systemId="http://docbook.org/xml/4.5/docbookx.dtd"
- uri="docbookx.dtd"/>
-
-<!-- ...................................................................... -->
-<!-- DocBook modules ...................................................... -->
-
-<public publicId="-//OASIS//DTD DocBook CALS Table Model V4.5//EN"
- uri="calstblx.dtd"/>
-
-<public publicId="-//OASIS//ELEMENTS DocBook XML HTML Tables V4.5//EN"
- uri="htmltblx.mod"/>
-
-<public publicId="-//OASIS//DTD XML Exchange Table Model 19990315//EN"
- uri="soextblx.dtd"/>
-
-<public publicId="-//OASIS//ELEMENTS DocBook Information Pool V4.5//EN"
- uri="dbpoolx.mod"/>
-
-<public publicId="-//OASIS//ELEMENTS DocBook Document Hierarchy V4.5//EN"
- uri="dbhierx.mod"/>
-
-<public publicId="-//OASIS//ENTITIES DocBook Additional General Entities V4.5//EN"
- uri="dbgenent.mod"/>
-
-<public publicId="-//OASIS//ENTITIES DocBook Notations V4.5//EN"
- uri="dbnotnx.mod"/>
-
-<public publicId="-//OASIS//ENTITIES DocBook Character Entities V4.5//EN"
- uri="dbcentx.mod"/>
-
-<!-- ...................................................................... -->
-<!-- ISO entity sets ...................................................... -->
-
-<public publicId="ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML"
- uri="ent/isodia.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML"
- uri="ent/isonum.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Publishing//EN//XML"
- uri="ent/isopub.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES General Technical//EN//XML"
- uri="ent/isotech.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
- uri="ent/isolat1.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Latin 2//EN//XML"
- uri="ent/isolat2.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Greek Letters//EN//XML"
- uri="ent/isogrk1.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML"
- uri="ent/isogrk2.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Greek Symbols//EN//XML"
- uri="ent/isogrk3.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML"
- uri="ent/isogrk4.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML"
- uri="ent/isoamsa.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML"
- uri="ent/isoamsb.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML"
- uri="ent/isoamsc.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML"
- uri="ent/isoamsn.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML"
- uri="ent/isoamso.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML"
- uri="ent/isoamsr.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML"
- uri="ent/isobox.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML"
- uri="ent/isocyr1.ent"/>
-
-<public publicId="ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML"
- uri="ent/isocyr2.ent"/>
-
-<!-- End of catalog data for DocBook XML V4.5 ............................. -->
-<!-- ...................................................................... -->
-
-</catalog>
diff --git a/Utilities/xml/docbook-4.5/dbcentx.mod b/Utilities/xml/docbook-4.5/dbcentx.mod
deleted file mode 100644
index 60de99f86..000000000
--- a/Utilities/xml/docbook-4.5/dbcentx.mod
+++ /dev/null
@@ -1,384 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook character entities module V4.5 ............................... -->
-<!-- File dbcentx.mod ..................................................... -->
-
-<!-- Copyright 1992-2004 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- $Id: dbcentx.mod 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the entity declarations for the standard ISO
- entity sets used by DocBook.
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % dbcent PUBLIC
- "-//OASIS//ENTITIES DocBook Character Entities V4.5//EN"
- "dbcentx.mod">
- %dbcent;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!-- ...................................................................... -->
-
-<![%sgml.features;[
-
-<!ENTITY % ISOamsa.module "INCLUDE">
-<![ %ISOamsa.module; [
-<!ENTITY % ISOamsa PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN">
-<!--end of ISOamsa.module-->]]>
-
-<!ENTITY % ISOamsb.module "INCLUDE">
-<![ %ISOamsb.module; [
-<!ENTITY % ISOamsb PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN">
-<!--end of ISOamsb.module-->]]>
-
-<!ENTITY % ISOamsc.module "INCLUDE">
-<![ %ISOamsc.module; [
-<!ENTITY % ISOamsc PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN">
-<!--end of ISOamsc.module-->]]>
-
-<!ENTITY % ISOamsn.module "INCLUDE">
-<![ %ISOamsn.module; [
-<!ENTITY % ISOamsn PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN">
-<!--end of ISOamsn.module-->]]>
-
-<!ENTITY % ISOamso.module "INCLUDE">
-<![ %ISOamso.module; [
-<!ENTITY % ISOamso PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN">
-<!--end of ISOamso.module-->]]>
-
-<!ENTITY % ISOamsr.module "INCLUDE">
-<![ %ISOamsr.module; [
-<!ENTITY % ISOamsr PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN">
-<!--end of ISOamsr.module-->]]>
-
-<!ENTITY % ISObox.module "INCLUDE">
-<![ %ISObox.module; [
-<!ENTITY % ISObox PUBLIC
-"ISO 8879:1986//ENTITIES Box and Line Drawing//EN">
-<!--end of ISObox.module-->]]>
-
-<!ENTITY % ISOcyr1.module "INCLUDE">
-<![ %ISOcyr1.module; [
-<!ENTITY % ISOcyr1 PUBLIC
-"ISO 8879:1986//ENTITIES Russian Cyrillic//EN">
-<!--end of ISOcyr1.module-->]]>
-
-<!ENTITY % ISOcyr2.module "INCLUDE">
-<![ %ISOcyr2.module; [
-<!ENTITY % ISOcyr2 PUBLIC
-"ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN">
-<!--end of ISOcyr2.module-->]]>
-
-<!ENTITY % ISOdia.module "INCLUDE">
-<![ %ISOdia.module; [
-<!ENTITY % ISOdia PUBLIC
-"ISO 8879:1986//ENTITIES Diacritical Marks//EN">
-<!--end of ISOdia.module-->]]>
-
-<!ENTITY % ISOgrk1.module "INCLUDE">
-<![ %ISOgrk1.module; [
-<!ENTITY % ISOgrk1 PUBLIC
-"ISO 8879:1986//ENTITIES Greek Letters//EN">
-<!--end of ISOgrk1.module-->]]>
-
-<!ENTITY % ISOgrk2.module "INCLUDE">
-<![ %ISOgrk2.module; [
-<!ENTITY % ISOgrk2 PUBLIC
-"ISO 8879:1986//ENTITIES Monotoniko Greek//EN">
-<!--end of ISOgrk2.module-->]]>
-
-<!ENTITY % ISOgrk3.module "INCLUDE">
-<![ %ISOgrk3.module; [
-<!ENTITY % ISOgrk3 PUBLIC
-"ISO 8879:1986//ENTITIES Greek Symbols//EN">
-<!--end of ISOgrk3.module-->]]>
-
-<!ENTITY % ISOgrk4.module "INCLUDE">
-<![ %ISOgrk4.module; [
-<!ENTITY % ISOgrk4 PUBLIC
-"ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN">
-<!--end of ISOgrk4.module-->]]>
-
-<!ENTITY % ISOlat1.module "INCLUDE">
-<![ %ISOlat1.module; [
-<!ENTITY % ISOlat1 PUBLIC
-"ISO 8879:1986//ENTITIES Added Latin 1//EN">
-<!--end of ISOlat1.module-->]]>
-
-<!ENTITY % ISOlat2.module "INCLUDE">
-<![ %ISOlat2.module; [
-<!ENTITY % ISOlat2 PUBLIC
-"ISO 8879:1986//ENTITIES Added Latin 2//EN">
-<!--end of ISOlat2.module-->]]>
-
-<!ENTITY % ISOnum.module "INCLUDE">
-<![ %ISOnum.module; [
-<!ENTITY % ISOnum PUBLIC
-"ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN">
-<!--end of ISOnum.module-->]]>
-
-<!ENTITY % ISOpub.module "INCLUDE">
-<![ %ISOpub.module; [
-<!ENTITY % ISOpub PUBLIC
-"ISO 8879:1986//ENTITIES Publishing//EN">
-<!--end of ISOpub.module-->]]>
-
-<!ENTITY % ISOtech.module "INCLUDE">
-<![ %ISOtech.module; [
-<!ENTITY % ISOtech PUBLIC
-"ISO 8879:1986//ENTITIES General Technical//EN">
-<!--end of ISOtech.module-->]]>
-
-<!--end of sgml.features-->]]>
-
-<![%xml.features;[
-
-<!ENTITY % ISOamsa.module "INCLUDE">
-<![%ISOamsa.module;[
-<!ENTITY % ISOamsa PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML"
-"ent/isoamsa.ent">
-<!--end of ISOamsa.module-->]]>
-
-<!ENTITY % ISOamsb.module "INCLUDE">
-<![%ISOamsb.module;[
-<!ENTITY % ISOamsb PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML"
-"ent/isoamsb.ent">
-<!--end of ISOamsb.module-->]]>
-
-<!ENTITY % ISOamsc.module "INCLUDE">
-<![%ISOamsc.module;[
-<!ENTITY % ISOamsc PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML"
-"ent/isoamsc.ent">
-<!--end of ISOamsc.module-->]]>
-
-<!ENTITY % ISOamsn.module "INCLUDE">
-<![%ISOamsn.module;[
-<!ENTITY % ISOamsn PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML"
-"ent/isoamsn.ent">
-<!--end of ISOamsn.module-->]]>
-
-<!ENTITY % ISOamso.module "INCLUDE">
-<![%ISOamso.module;[
-<!ENTITY % ISOamso PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML"
-"ent/isoamso.ent">
-<!--end of ISOamso.module-->]]>
-
-<!ENTITY % ISOamsr.module "INCLUDE">
-<![%ISOamsr.module;[
-<!ENTITY % ISOamsr PUBLIC
-"ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML"
-"ent/isoamsr.ent">
-<!--end of ISOamsr.module-->]]>
-
-<!ENTITY % ISObox.module "INCLUDE">
-<![%ISObox.module;[
-<!ENTITY % ISObox PUBLIC
-"ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML"
-"ent/isobox.ent">
-<!--end of ISObox.module-->]]>
-
-<!ENTITY % ISOcyr1.module "INCLUDE">
-<![%ISOcyr1.module;[
-<!ENTITY % ISOcyr1 PUBLIC
-"ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML"
-"ent/isocyr1.ent">
-<!--end of ISOcyr1.module-->]]>
-
-<!ENTITY % ISOcyr2.module "INCLUDE">
-<![%ISOcyr2.module;[
-<!ENTITY % ISOcyr2 PUBLIC
-"ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML"
-"ent/isocyr2.ent">
-<!--end of ISOcyr2.module-->]]>
-
-<!ENTITY % ISOdia.module "INCLUDE">
-<![%ISOdia.module;[
-<!ENTITY % ISOdia PUBLIC
-"ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML"
-"ent/isodia.ent">
-<!--end of ISOdia.module-->]]>
-
-<!ENTITY % ISOgrk1.module "INCLUDE">
-<![%ISOgrk1.module;[
-<!ENTITY % ISOgrk1 PUBLIC
-"ISO 8879:1986//ENTITIES Greek Letters//EN//XML"
-"ent/isogrk1.ent">
-<!--end of ISOgrk1.module-->]]>
-
-<!ENTITY % ISOgrk2.module "INCLUDE">
-<![%ISOgrk2.module;[
-<!ENTITY % ISOgrk2 PUBLIC
-"ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML"
-"ent/isogrk2.ent">
-<!--end of ISOgrk2.module-->]]>
-
-<!ENTITY % ISOgrk3.module "INCLUDE">
-<![%ISOgrk3.module;[
-<!ENTITY % ISOgrk3 PUBLIC
-"ISO 8879:1986//ENTITIES Greek Symbols//EN//XML"
-"ent/isogrk3.ent">
-<!--end of ISOgrk3.module-->]]>
-
-<!ENTITY % ISOgrk4.module "INCLUDE">
-<![%ISOgrk4.module;[
-<!ENTITY % ISOgrk4 PUBLIC
-"ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML"
-"ent/isogrk4.ent">
-<!--end of ISOgrk4.module-->]]>
-
-<!ENTITY % ISOlat1.module "INCLUDE">
-<![%ISOlat1.module;[
-<!ENTITY % ISOlat1 PUBLIC
-"ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
-"ent/isolat1.ent">
-<!--end of ISOlat1.module-->]]>
-
-<!ENTITY % ISOlat2.module "INCLUDE">
-<![%ISOlat2.module;[
-<!ENTITY % ISOlat2 PUBLIC
-"ISO 8879:1986//ENTITIES Added Latin 2//EN//XML"
-"ent/isolat2.ent">
-<!--end of ISOlat2.module-->]]>
-
-<!ENTITY % ISOnum.module "INCLUDE">
-<![%ISOnum.module;[
-<!ENTITY % ISOnum PUBLIC
-"ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML"
-"ent/isonum.ent">
-<!--end of ISOnum.module-->]]>
-
-<!ENTITY % ISOpub.module "INCLUDE">
-<![%ISOpub.module;[
-<!ENTITY % ISOpub PUBLIC
-"ISO 8879:1986//ENTITIES Publishing//EN//XML"
-"ent/isopub.ent">
-<!--end of ISOpub.module-->]]>
-
-<!ENTITY % ISOtech.module "INCLUDE">
-<![%ISOtech.module;[
-<!ENTITY % ISOtech PUBLIC
-"ISO 8879:1986//ENTITIES General Technical//EN//XML"
-"ent/isotech.ent">
-<!--end of ISOtech.module-->]]>
-
-<!--end of xml.features-->]]>
-
-<![ %ISOamsa.module; [
-%ISOamsa;
-]]>
-
-<![ %ISOamsb.module; [
-%ISOamsb;
-]]>
-
-<![ %ISOamsc.module; [
-%ISOamsc;
-]]>
-
-<![ %ISOamsn.module; [
-%ISOamsn;
-]]>
-
-<![ %ISOamso.module; [
-%ISOamso;
-]]>
-
-<![ %ISOamsr.module; [
-%ISOamsr;
-]]>
-
-<![ %ISObox.module; [
-%ISObox;
-]]>
-
-<![ %ISOcyr1.module; [
-%ISOcyr1;
-]]>
-
-<![ %ISOcyr2.module; [
-%ISOcyr2;
-]]>
-
-<![ %ISOdia.module; [
-%ISOdia;
-]]>
-
-<![ %ISOgrk1.module; [
-%ISOgrk1;
-]]>
-
-<![ %ISOgrk2.module; [
-%ISOgrk2;
-]]>
-
-<![ %ISOgrk3.module; [
-%ISOgrk3;
-]]>
-
-<![ %ISOgrk4.module; [
-%ISOgrk4;
-]]>
-
-<![ %ISOlat1.module; [
-%ISOlat1;
-]]>
-
-<![ %ISOlat2.module; [
-%ISOlat2;
-]]>
-
-<![ %ISOnum.module; [
-%ISOnum;
-]]>
-
-<![ %ISOpub.module; [
-%ISOpub;
-]]>
-
-<![ %ISOtech.module; [
-%ISOtech;
-]]>
-
-<!-- End of DocBook character entity sets module V4.5 ..................... -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/dbgenent.mod b/Utilities/xml/docbook-4.5/dbgenent.mod
deleted file mode 100644
index ff5ba90d1..000000000
--- a/Utilities/xml/docbook-4.5/dbgenent.mod
+++ /dev/null
@@ -1,41 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook additional general entities V4.5 ............................. -->
-
-<!-- Copyright 1992-2004 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % dbgenent PUBLIC
- "-//OASIS//ENTITIES DocBook Additional General Entities V4.5//EN"
- "dbgenent.mod">
- %dbgenent;
--->
-
-<!-- File dbgenent.mod .................................................... -->
-
-<!-- You can edit this file to add the following:
-
- o General entity declarations of any kind. For example:
-
- <!ENTITY productname "WinWidget"> (small boilerplate)
- <!ENTITY legal-notice SYSTEM "notice.sgm"> (large boilerplate)
-
- o Notation declarations. For example:
-
- <!NOTATION chicken-scratch SYSTEM>
-
- o Declarations for and references to external parameter entities
- containing collections of any of the above. For example:
-
- <!ENTITY % all-titles PUBLIC "-//DocTools//ELEMENTS Book Titles//EN"
- "booktitles.ent">
- %all-titles;
--->
-
-<!-- End of DocBook additional general entities V4.5 ...................... -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/dbhierx.mod b/Utilities/xml/docbook-4.5/dbhierx.mod
deleted file mode 100644
index 5f839f567..000000000
--- a/Utilities/xml/docbook-4.5/dbhierx.mod
+++ /dev/null
@@ -1,2193 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook document hierarchy module V4.5 ............................... -->
-<!-- File dbhierx.mod ..................................................... -->
-
-<!-- Copyright 1992-2004 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- $Id: dbhierx.mod 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the definitions for the overall document
- hierarchies of DocBook documents. It covers computer documentation
- manuals and manual fragments, as well as reference entries (such as
- man pages) and technical journals or anthologies containing
- articles.
-
- This module depends on the DocBook information pool module. All
- elements and entities referenced but not defined here are assumed
- to be defined in the information pool module.
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % dbhier PUBLIC
- "-//OASIS//ELEMENTS DocBook Document Hierarchy V4.5//EN"
- "dbhierx.mod">
- %dbhier;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!-- ...................................................................... -->
-<!-- Entities for module inclusions ....................................... -->
-
-<!ENTITY % dbhier.redecl.module "IGNORE">
-<!ENTITY % dbhier.redecl2.module "IGNORE">
-
-<!-- ...................................................................... -->
-<!-- Entities for element classes ......................................... -->
-
-<!ENTITY % local.appendix.class "">
-<!ENTITY % appendix.class "appendix %local.appendix.class;">
-
-<!ENTITY % local.article.class "">
-<!ENTITY % article.class "article %local.article.class;">
-
-<!ENTITY % local.book.class "">
-<!ENTITY % book.class "book %local.book.class;">
-
-<!ENTITY % local.chapter.class "">
-<!ENTITY % chapter.class "chapter %local.chapter.class;">
-
-<!ENTITY % local.index.class "">
-<!ENTITY % index.class "index|setindex %local.index.class;">
-
-<!ENTITY % local.refentry.class "">
-<!ENTITY % refentry.class "refentry %local.refentry.class;">
-
-<!ENTITY % local.section.class "">
-<!ENTITY % section.class "section %local.section.class;">
-
-<!ENTITY % local.nav.class "">
-<!ENTITY % nav.class "toc|lot|index|glossary|bibliography
- %local.nav.class;">
-
-<!-- Redeclaration placeholder ............................................ -->
-
-<!-- For redeclaring entities that are declared after this point while
- retaining their references to the entities that are declared before
- this point -->
-
-<![%dbhier.redecl.module;[
-<!-- Defining rdbhier here makes some buggy XML parsers happy. -->
-<!ENTITY % rdbhier "">
-%rdbhier;
-<!--end of dbhier.redecl.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Entities for element mixtures ........................................ -->
-
-<!ENTITY % local.divcomponent.mix "">
-<!ENTITY % divcomponent.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |%compound.class;
- |%genobj.class; |%descobj.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.divcomponent.mix;">
-
-<!ENTITY % local.refcomponent.mix "">
-<!ENTITY % refcomponent.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |%compound.class;
- |%genobj.class; |%descobj.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.refcomponent.mix;">
-
-<!ENTITY % local.indexdivcomponent.mix "">
-<!ENTITY % indexdivcomponent.mix
- "itemizedlist|orderedlist|variablelist|simplelist
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |anchor|remark
- |%link.char.class;
- |beginpage
- %local.indexdivcomponent.mix;">
-
-<!ENTITY % local.refname.char.mix "">
-<!ENTITY % refname.char.mix
- "#PCDATA
- |%tech.char.class;
- %local.refname.char.mix;">
-
-<!ENTITY % local.partcontent.mix "">
-<!ENTITY % partcontent.mix
- "%appendix.class;|%chapter.class;|%nav.class;|%article.class;
- |preface|%refentry.class;|reference %local.partcontent.mix;">
-
-<!ENTITY % local.refinline.char.mix "">
-<!ENTITY % refinline.char.mix
- "#PCDATA
- |%xref.char.class; |%gen.char.class;
- |%link.char.class; |%tech.char.class;
- |%base.char.class; |%docinfo.char.class;
- |%other.char.class;
- |%ndxterm.class; |beginpage
- %local.refinline.char.mix;">
-
-<!ENTITY % local.refclass.char.mix "">
-<!ENTITY % refclass.char.mix
- "#PCDATA
- |application
- %local.refclass.char.mix;">
-
-<!-- Redeclaration placeholder 2 .......................................... -->
-
-<!-- For redeclaring entities that are declared after this point while
- retaining their references to the entities that are declared before
- this point -->
-
-<![%dbhier.redecl2.module;[
-<!-- Defining rdbhier2 here makes some buggy XML parsers happy. -->
-<!ENTITY % rdbhier2 "">
-%rdbhier2;
-<!--end of dbhier.redecl2.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Entities for content models .......................................... -->
-
-<!ENTITY % div.title.content
- "title, subtitle?, titleabbrev?">
-
-<!ENTITY % bookcomponent.title.content
- "title, subtitle?, titleabbrev?">
-
-<!ENTITY % sect.title.content
- "title, subtitle?, titleabbrev?">
-
-<!ENTITY % refsect.title.content
- "title, subtitle?, titleabbrev?">
-
-<!ENTITY % bookcomponent.content
- "((%divcomponent.mix;)+,
- (sect1*|(%refentry.class;)*|simplesect*|(%section.class;)*))
- | (sect1+|(%refentry.class;)+|simplesect+|(%section.class;)+)">
-
-<!-- ...................................................................... -->
-<!-- Set and SetInfo ...................................................... -->
-
-<!ENTITY % set.content.module "INCLUDE">
-<![%set.content.module;[
-<!ENTITY % set.module "INCLUDE">
-<![%set.module;[
-<!ENTITY % local.set.attrib "">
-<!ENTITY % set.role.attrib "%role.attrib;">
-
-<!ENTITY % set.element "INCLUDE">
-<![%set.element;[
-<!--doc:A collection of books.-->
-<!ELEMENT set %ho; ((%div.title.content;)?, setinfo?, toc?, (set|%book.class;)+,
- setindex?)
- %ubiq.inclusion;>
-<!--end of set.element-->]]>
-
-<!-- FPI: SGML formal public identifier -->
-
-
-<!ENTITY % set.attlist "INCLUDE">
-<![%set.attlist;[
-<!ATTLIST set
- fpi CDATA #IMPLIED
- %status.attrib;
- %common.attrib;
- %set.role.attrib;
- %local.set.attrib;
->
-<!--end of set.attlist-->]]>
-<!--end of set.module-->]]>
-
-<!ENTITY % setinfo.module "INCLUDE">
-<![%setinfo.module;[
-<!ENTITY % local.setinfo.attrib "">
-<!ENTITY % setinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % setinfo.element "INCLUDE">
-<![%setinfo.element;[
-<!--doc:Meta-information for a Set.-->
-<!ELEMENT setinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of setinfo.element-->]]>
-
-<!-- Contents: IDs of the ToC, Books, and SetIndex that comprise
- the set, in the order of their appearance -->
-
-
-<!ENTITY % setinfo.attlist "INCLUDE">
-<![%setinfo.attlist;[
-<!ATTLIST setinfo
- contents IDREFS #IMPLIED
- %common.attrib;
- %setinfo.role.attrib;
- %local.setinfo.attrib;
->
-<!--end of setinfo.attlist-->]]>
-<!--end of setinfo.module-->]]>
-<!--end of set.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Book and BookInfo .................................................... -->
-
-<!ENTITY % book.content.module "INCLUDE">
-<![%book.content.module;[
-<!ENTITY % book.module "INCLUDE">
-<![%book.module;[
-
-<!ENTITY % local.book.attrib "">
-<!ENTITY % book.role.attrib "%role.attrib;">
-
-<!ENTITY % book.element "INCLUDE">
-<![%book.element;[
-<!--doc:A book.-->
-<!ELEMENT book %ho; ((%div.title.content;)?, bookinfo?,
- (dedication | toc | lot
- | glossary | bibliography | preface
- | %chapter.class; | reference | part
- | %article.class;
- | %appendix.class;
- | %index.class;
- | colophon)*)
- %ubiq.inclusion;>
-<!--end of book.element-->]]>
-
-<!-- FPI: SGML formal public identifier -->
-
-
-<!ENTITY % book.attlist "INCLUDE">
-<![%book.attlist;[
-<!ATTLIST book fpi CDATA #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %book.role.attrib;
- %local.book.attrib;
->
-<!--end of book.attlist-->]]>
-<!--end of book.module-->]]>
-
-<!ENTITY % bookinfo.module "INCLUDE">
-<![%bookinfo.module;[
-<!ENTITY % local.bookinfo.attrib "">
-<!ENTITY % bookinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % bookinfo.element "INCLUDE">
-<![%bookinfo.element;[
-<!--doc:Meta-information for a Book.-->
-<!ELEMENT bookinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of bookinfo.element-->]]>
-
-<!-- Contents: IDs of the ToC, LoTs, Prefaces, Parts, Chapters,
- Appendixes, References, GLossary, Bibliography, and indexes
- comprising the Book, in the order of their appearance -->
-
-
-<!ENTITY % bookinfo.attlist "INCLUDE">
-<![%bookinfo.attlist;[
-<!ATTLIST bookinfo
- contents IDREFS #IMPLIED
- %common.attrib;
- %bookinfo.role.attrib;
- %local.bookinfo.attrib;
->
-<!--end of bookinfo.attlist-->]]>
-<!--end of bookinfo.module-->]]>
-<!--end of book.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Dedication, ToC, and LoT ............................................. -->
-
-<!ENTITY % dedication.module "INCLUDE">
-<![%dedication.module;[
-<!ENTITY % local.dedication.attrib "">
-<!ENTITY % dedication.role.attrib "%role.attrib;">
-
-<!ENTITY % dedication.element "INCLUDE">
-<![%dedication.element;[
-<!--doc:A wrapper for the dedication section of a book.-->
-<!ELEMENT dedication %ho; ((%sect.title.content;)?, (%legalnotice.mix;)+)>
-<!--end of dedication.element-->]]>
-
-<!ENTITY % dedication.attlist "INCLUDE">
-<![%dedication.attlist;[
-<!ATTLIST dedication
- %status.attrib;
- %common.attrib;
- %dedication.role.attrib;
- %local.dedication.attrib;
->
-<!--end of dedication.attlist-->]]>
-<!--end of dedication.module-->]]>
-
-<!ENTITY % colophon.module "INCLUDE">
-<![ %colophon.module; [
-<!ENTITY % local.colophon.attrib "">
-<!ENTITY % colophon.role.attrib "%role.attrib;">
-
-<!ENTITY % colophon.element "INCLUDE">
-<![ %colophon.element; [
-<!--doc:Text at the back of a book describing facts about its production.-->
-<!ELEMENT colophon %ho; ((%sect.title.content;)?, (%textobject.mix;)+)>
-<!--end of colophon.element-->]]>
-
-<!ENTITY % colophon.attlist "INCLUDE">
-<![ %colophon.attlist; [
-<!ATTLIST colophon
- %status.attrib;
- %common.attrib;
- %colophon.role.attrib;
- %local.colophon.attrib;>
-<!--end of colophon.attlist-->]]>
-<!--end of colophon.module-->]]>
-
-<!ENTITY % toc.content.module "INCLUDE">
-<![%toc.content.module;[
-<!ENTITY % toc.module "INCLUDE">
-<![%toc.module;[
-<!ENTITY % local.toc.attrib "">
-<!ENTITY % toc.role.attrib "%role.attrib;">
-
-<!ENTITY % toc.element "INCLUDE">
-<![%toc.element;[
-<!--doc:A table of contents.-->
-<!ELEMENT toc %ho; (beginpage?,
- (%bookcomponent.title.content;)?,
- tocfront*,
- (tocpart | tocchap)*, tocback*)>
-<!--end of toc.element-->]]>
-
-<!ENTITY % toc.attlist "INCLUDE">
-<![%toc.attlist;[
-<!ATTLIST toc
- %pagenum.attrib;
- %common.attrib;
- %toc.role.attrib;
- %local.toc.attrib;
->
-<!--end of toc.attlist-->]]>
-<!--end of toc.module-->]]>
-
-<!ENTITY % tocfront.module "INCLUDE">
-<![%tocfront.module;[
-<!ENTITY % local.tocfront.attrib "">
-<!ENTITY % tocfront.role.attrib "%role.attrib;">
-
-<!ENTITY % tocfront.element "INCLUDE">
-<![%tocfront.element;[
-<!--doc:An entry in a table of contents for a front matter component.-->
-<!ELEMENT tocfront %ho; (%para.char.mix;)*>
-<!--end of tocfront.element-->]]>
-
-<!-- to element that this entry represents -->
-
-
-<!ENTITY % tocfront.attlist "INCLUDE">
-<![%tocfront.attlist;[
-<!ATTLIST tocfront
- %label.attrib;
- %linkend.attrib; %pagenum.attrib;
- %common.attrib;
- %tocfront.role.attrib;
- %local.tocfront.attrib;
->
-<!--end of tocfront.attlist-->]]>
-<!--end of tocfront.module-->]]>
-
-<!ENTITY % tocentry.module "INCLUDE">
-<![%tocentry.module;[
-<!ENTITY % local.tocentry.attrib "">
-<!ENTITY % tocentry.role.attrib "%role.attrib;">
-
-<!ENTITY % tocentry.element "INCLUDE">
-<![%tocentry.element;[
-<!--doc:A component title in a table of contents.-->
-<!ELEMENT tocentry %ho; (%para.char.mix;)*>
-<!--end of tocentry.element-->]]>
-
-<!-- to element that this entry represents -->
-
-
-<!ENTITY % tocentry.attlist "INCLUDE">
-<![%tocentry.attlist;[
-<!ATTLIST tocentry
- %linkend.attrib; %pagenum.attrib;
- %common.attrib;
- %tocentry.role.attrib;
- %local.tocentry.attrib;
->
-<!--end of tocentry.attlist-->]]>
-<!--end of tocentry.module-->]]>
-
-<!ENTITY % tocpart.module "INCLUDE">
-<![%tocpart.module;[
-<!ENTITY % local.tocpart.attrib "">
-<!ENTITY % tocpart.role.attrib "%role.attrib;">
-
-<!ENTITY % tocpart.element "INCLUDE">
-<![%tocpart.element;[
-<!--doc:An entry in a table of contents for a part of a book.-->
-<!ELEMENT tocpart %ho; (tocentry+, tocchap*)>
-<!--end of tocpart.element-->]]>
-
-<!ENTITY % tocpart.attlist "INCLUDE">
-<![%tocpart.attlist;[
-<!ATTLIST tocpart
- %common.attrib;
- %tocpart.role.attrib;
- %local.tocpart.attrib;
->
-<!--end of tocpart.attlist-->]]>
-<!--end of tocpart.module-->]]>
-
-<!ENTITY % tocchap.module "INCLUDE">
-<![%tocchap.module;[
-<!ENTITY % local.tocchap.attrib "">
-<!ENTITY % tocchap.role.attrib "%role.attrib;">
-
-<!ENTITY % tocchap.element "INCLUDE">
-<![%tocchap.element;[
-<!--doc:An entry in a table of contents for a component in the body of a document.-->
-<!ELEMENT tocchap %ho; (tocentry+, toclevel1*)>
-<!--end of tocchap.element-->]]>
-
-<!ENTITY % tocchap.attlist "INCLUDE">
-<![%tocchap.attlist;[
-<!ATTLIST tocchap
- %label.attrib;
- %common.attrib;
- %tocchap.role.attrib;
- %local.tocchap.attrib;
->
-<!--end of tocchap.attlist-->]]>
-<!--end of tocchap.module-->]]>
-
-<!ENTITY % toclevel1.module "INCLUDE">
-<![%toclevel1.module;[
-<!ENTITY % local.toclevel1.attrib "">
-<!ENTITY % toclevel1.role.attrib "%role.attrib;">
-
-<!ENTITY % toclevel1.element "INCLUDE">
-<![%toclevel1.element;[
-<!--doc:A top-level entry within a table of contents entry for a chapter-like component.-->
-<!ELEMENT toclevel1 %ho; (tocentry+, toclevel2*)>
-<!--end of toclevel1.element-->]]>
-
-<!ENTITY % toclevel1.attlist "INCLUDE">
-<![%toclevel1.attlist;[
-<!ATTLIST toclevel1
- %common.attrib;
- %toclevel1.role.attrib;
- %local.toclevel1.attrib;
->
-<!--end of toclevel1.attlist-->]]>
-<!--end of toclevel1.module-->]]>
-
-<!ENTITY % toclevel2.module "INCLUDE">
-<![%toclevel2.module;[
-<!ENTITY % local.toclevel2.attrib "">
-<!ENTITY % toclevel2.role.attrib "%role.attrib;">
-
-<!ENTITY % toclevel2.element "INCLUDE">
-<![%toclevel2.element;[
-<!--doc:A second-level entry within a table of contents entry for a chapter-like component.-->
-<!ELEMENT toclevel2 %ho; (tocentry+, toclevel3*)>
-<!--end of toclevel2.element-->]]>
-
-<!ENTITY % toclevel2.attlist "INCLUDE">
-<![%toclevel2.attlist;[
-<!ATTLIST toclevel2
- %common.attrib;
- %toclevel2.role.attrib;
- %local.toclevel2.attrib;
->
-<!--end of toclevel2.attlist-->]]>
-<!--end of toclevel2.module-->]]>
-
-<!ENTITY % toclevel3.module "INCLUDE">
-<![%toclevel3.module;[
-<!ENTITY % local.toclevel3.attrib "">
-<!ENTITY % toclevel3.role.attrib "%role.attrib;">
-
-<!ENTITY % toclevel3.element "INCLUDE">
-<![%toclevel3.element;[
-<!--doc:A third-level entry within a table of contents entry for a chapter-like component.-->
-<!ELEMENT toclevel3 %ho; (tocentry+, toclevel4*)>
-<!--end of toclevel3.element-->]]>
-
-<!ENTITY % toclevel3.attlist "INCLUDE">
-<![%toclevel3.attlist;[
-<!ATTLIST toclevel3
- %common.attrib;
- %toclevel3.role.attrib;
- %local.toclevel3.attrib;
->
-<!--end of toclevel3.attlist-->]]>
-<!--end of toclevel3.module-->]]>
-
-<!ENTITY % toclevel4.module "INCLUDE">
-<![%toclevel4.module;[
-<!ENTITY % local.toclevel4.attrib "">
-<!ENTITY % toclevel4.role.attrib "%role.attrib;">
-
-<!ENTITY % toclevel4.element "INCLUDE">
-<![%toclevel4.element;[
-<!--doc:A fourth-level entry within a table of contents entry for a chapter-like component.-->
-<!ELEMENT toclevel4 %ho; (tocentry+, toclevel5*)>
-<!--end of toclevel4.element-->]]>
-
-<!ENTITY % toclevel4.attlist "INCLUDE">
-<![%toclevel4.attlist;[
-<!ATTLIST toclevel4
- %common.attrib;
- %toclevel4.role.attrib;
- %local.toclevel4.attrib;
->
-<!--end of toclevel4.attlist-->]]>
-<!--end of toclevel4.module-->]]>
-
-<!ENTITY % toclevel5.module "INCLUDE">
-<![%toclevel5.module;[
-<!ENTITY % local.toclevel5.attrib "">
-<!ENTITY % toclevel5.role.attrib "%role.attrib;">
-
-<!ENTITY % toclevel5.element "INCLUDE">
-<![%toclevel5.element;[
-<!--doc:A fifth-level entry within a table of contents entry for a chapter-like component.-->
-<!ELEMENT toclevel5 %ho; (tocentry+)>
-<!--end of toclevel5.element-->]]>
-
-<!ENTITY % toclevel5.attlist "INCLUDE">
-<![%toclevel5.attlist;[
-<!ATTLIST toclevel5
- %common.attrib;
- %toclevel5.role.attrib;
- %local.toclevel5.attrib;
->
-<!--end of toclevel5.attlist-->]]>
-<!--end of toclevel5.module-->]]>
-
-<!ENTITY % tocback.module "INCLUDE">
-<![%tocback.module;[
-<!ENTITY % local.tocback.attrib "">
-<!ENTITY % tocback.role.attrib "%role.attrib;">
-
-<!ENTITY % tocback.element "INCLUDE">
-<![%tocback.element;[
-<!--doc:An entry in a table of contents for a back matter component.-->
-<!ELEMENT tocback %ho; (%para.char.mix;)*>
-<!--end of tocback.element-->]]>
-
-<!-- to element that this entry represents -->
-
-
-<!ENTITY % tocback.attlist "INCLUDE">
-<![%tocback.attlist;[
-<!ATTLIST tocback
- %label.attrib;
- %linkend.attrib; %pagenum.attrib;
- %common.attrib;
- %tocback.role.attrib;
- %local.tocback.attrib;
->
-<!--end of tocback.attlist-->]]>
-<!--end of tocback.module-->]]>
-<!--end of toc.content.module-->]]>
-
-<!ENTITY % lot.content.module "INCLUDE">
-<![%lot.content.module;[
-<!ENTITY % lot.module "INCLUDE">
-<![%lot.module;[
-<!ENTITY % local.lot.attrib "">
-<!ENTITY % lot.role.attrib "%role.attrib;">
-
-<!ENTITY % lot.element "INCLUDE">
-<![%lot.element;[
-<!--doc:A list of the titles of formal objects (as tables or figures) in a document.-->
-<!ELEMENT lot %ho; (beginpage?, (%bookcomponent.title.content;)?, lotentry*)>
-<!--end of lot.element-->]]>
-
-<!ENTITY % lot.attlist "INCLUDE">
-<![%lot.attlist;[
-<!ATTLIST lot
- %label.attrib;
- %common.attrib;
- %lot.role.attrib;
- %local.lot.attrib;
->
-<!--end of lot.attlist-->]]>
-<!--end of lot.module-->]]>
-
-<!ENTITY % lotentry.module "INCLUDE">
-<![%lotentry.module;[
-<!ENTITY % local.lotentry.attrib "">
-<!ENTITY % lotentry.role.attrib "%role.attrib;">
-
-<!ENTITY % lotentry.element "INCLUDE">
-<![%lotentry.element;[
-<!--doc:An entry in a list of titles.-->
-<!ELEMENT lotentry %ho; (%para.char.mix;)*>
-<!--end of lotentry.element-->]]>
-
-<!-- SrcCredit: Information about the source of the entry,
- as for a list of illustrations -->
-<!-- linkend: to element that this entry represents-->
-<!ENTITY % lotentry.attlist "INCLUDE">
-<![%lotentry.attlist;[
-<!ATTLIST lotentry
- %linkend.attrib;
- %pagenum.attrib;
- srccredit CDATA #IMPLIED
- %common.attrib;
- %lotentry.role.attrib;
- %local.lotentry.attrib;
->
-<!--end of lotentry.attlist-->]]>
-<!--end of lotentry.module-->]]>
-<!--end of lot.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Appendix, Chapter, Part, Preface, Reference, PartIntro ............... -->
-
-<!ENTITY % appendix.module "INCLUDE">
-<![%appendix.module;[
-<!ENTITY % local.appendix.attrib "">
-<!ENTITY % appendix.role.attrib "%role.attrib;">
-
-<!ENTITY % appendix.element "INCLUDE">
-<![%appendix.element;[
-<!--doc:An appendix in a Book or Article.-->
-<!ELEMENT appendix %ho; (beginpage?,
- appendixinfo?,
- (%bookcomponent.title.content;),
- (%nav.class;)*,
- tocchap?,
- (%bookcomponent.content;),
- (%nav.class;)*)
- %ubiq.inclusion;>
-<!--end of appendix.element-->]]>
-
-<!ENTITY % appendix.attlist "INCLUDE">
-<![%appendix.attlist;[
-<!ATTLIST appendix
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %appendix.role.attrib;
- %local.appendix.attrib;
->
-<!--end of appendix.attlist-->]]>
-<!--end of appendix.module-->]]>
-
-<!ENTITY % chapter.module "INCLUDE">
-<![%chapter.module;[
-<!ENTITY % local.chapter.attrib "">
-<!ENTITY % chapter.role.attrib "%role.attrib;">
-
-<!ENTITY % chapter.element "INCLUDE">
-<![%chapter.element;[
-<!--doc:A chapter, as of a book.-->
-<!ELEMENT chapter %ho; (beginpage?,
- chapterinfo?,
- (%bookcomponent.title.content;),
- (%nav.class;)*,
- tocchap?,
- (%bookcomponent.content;),
- (%nav.class;)*)
- %ubiq.inclusion;>
-<!--end of chapter.element-->]]>
-
-<!ENTITY % chapter.attlist "INCLUDE">
-<![%chapter.attlist;[
-<!ATTLIST chapter
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %chapter.role.attrib;
- %local.chapter.attrib;
->
-<!--end of chapter.attlist-->]]>
-<!--end of chapter.module-->]]>
-
-<!ENTITY % part.module "INCLUDE">
-<![%part.module;[
-
-<!-- Note that Part was to have its content model reduced in V4.5. This
-change will not be made after all. -->
-
-<!ENTITY % local.part.attrib "">
-<!ENTITY % part.role.attrib "%role.attrib;">
-
-<!ENTITY % part.element "INCLUDE">
-<![%part.element;[
-<!--doc:A division in a book.-->
-<!ELEMENT part %ho; (beginpage?,
- partinfo?, (%bookcomponent.title.content;), partintro?,
- (%partcontent.mix;)+)
- %ubiq.inclusion;>
-<!--end of part.element-->]]>
-
-<!ENTITY % part.attlist "INCLUDE">
-<![%part.attlist;[
-<!ATTLIST part
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %part.role.attrib;
- %local.part.attrib;
->
-<!--end of part.attlist-->]]>
-<!--ELEMENT PartIntro (defined below)-->
-<!--end of part.module-->]]>
-
-<!ENTITY % preface.module "INCLUDE">
-<![%preface.module;[
-<!ENTITY % local.preface.attrib "">
-<!ENTITY % preface.role.attrib "%role.attrib;">
-
-<!ENTITY % preface.element "INCLUDE">
-<![%preface.element;[
-<!--doc:Introductory matter preceding the first chapter of a book.-->
-<!ELEMENT preface %ho; (beginpage?,
- prefaceinfo?,
- (%bookcomponent.title.content;),
- (%nav.class;)*,
- tocchap?,
- (%bookcomponent.content;),
- (%nav.class;)*)
- %ubiq.inclusion;>
-<!--end of preface.element-->]]>
-
-<!ENTITY % preface.attlist "INCLUDE">
-<![%preface.attlist;[
-<!ATTLIST preface
- %status.attrib;
- %common.attrib;
- %preface.role.attrib;
- %local.preface.attrib;
->
-<!--end of preface.attlist-->]]>
-<!--end of preface.module-->]]>
-
-<!ENTITY % reference.module "INCLUDE">
-<![%reference.module;[
-<!ENTITY % local.reference.attrib "">
-<!ENTITY % reference.role.attrib "%role.attrib;">
-
-<!ENTITY % reference.element "INCLUDE">
-<![%reference.element;[
-<!--doc:A collection of reference entries.-->
-<!ELEMENT reference %ho; (beginpage?,
- referenceinfo?,
- (%bookcomponent.title.content;), partintro?,
- (%refentry.class;)+)
- %ubiq.inclusion;>
-<!--end of reference.element-->]]>
-
-<!ENTITY % reference.attlist "INCLUDE">
-<![%reference.attlist;[
-<!ATTLIST reference
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %reference.role.attrib;
- %local.reference.attrib;
->
-<!--end of reference.attlist-->]]>
-<!--ELEMENT PartIntro (defined below)-->
-<!--end of reference.module-->]]>
-
-<!ENTITY % partintro.module "INCLUDE">
-<![%partintro.module;[
-<!ENTITY % local.partintro.attrib "">
-<!ENTITY % partintro.role.attrib "%role.attrib;">
-
-<!ENTITY % partintro.element "INCLUDE">
-<![%partintro.element;[
-<!--doc:An introduction to the contents of a part.-->
-<!ELEMENT partintro %ho; ((%div.title.content;)?, (%bookcomponent.content;))
- %ubiq.inclusion;>
-<!--end of partintro.element-->]]>
-
-<!ENTITY % partintro.attlist "INCLUDE">
-<![%partintro.attlist;[
-<!ATTLIST partintro
- %label.attrib;
- %common.attrib;
- %partintro.role.attrib;
- %local.partintro.attrib;
->
-<!--end of partintro.attlist-->]]>
-<!--end of partintro.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Other Info elements .................................................. -->
-
-<!ENTITY % appendixinfo.module "INCLUDE">
-<![ %appendixinfo.module; [
-<!ENTITY % local.appendixinfo.attrib "">
-<!ENTITY % appendixinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % appendixinfo.element "INCLUDE">
-<![ %appendixinfo.element; [
-<!--doc:Meta-information for an Appendix.-->
-<!ELEMENT appendixinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of appendixinfo.element-->]]>
-
-<!ENTITY % appendixinfo.attlist "INCLUDE">
-<![ %appendixinfo.attlist; [
-<!ATTLIST appendixinfo
- %common.attrib;
- %appendixinfo.role.attrib;
- %local.appendixinfo.attrib;
->
-<!--end of appendixinfo.attlist-->]]>
-<!--end of appendixinfo.module-->]]>
-
-<!ENTITY % bibliographyinfo.module "INCLUDE">
-<![ %bibliographyinfo.module; [
-<!ENTITY % local.bibliographyinfo.attrib "">
-<!ENTITY % bibliographyinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliographyinfo.element "INCLUDE">
-<![ %bibliographyinfo.element; [
-<!--doc:Meta-information for a Bibliography.-->
-<!ELEMENT bibliographyinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of bibliographyinfo.element-->]]>
-
-<!ENTITY % bibliographyinfo.attlist "INCLUDE">
-<![ %bibliographyinfo.attlist; [
-<!ATTLIST bibliographyinfo
- %common.attrib;
- %bibliographyinfo.role.attrib;
- %local.bibliographyinfo.attrib;
->
-<!--end of bibliographyinfo.attlist-->]]>
-<!--end of bibliographyinfo.module-->]]>
-
-<!ENTITY % chapterinfo.module "INCLUDE">
-<![ %chapterinfo.module; [
-<!ENTITY % local.chapterinfo.attrib "">
-<!ENTITY % chapterinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % chapterinfo.element "INCLUDE">
-<![ %chapterinfo.element; [
-<!--doc:Meta-information for a Chapter.-->
-<!ELEMENT chapterinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of chapterinfo.element-->]]>
-
-<!ENTITY % chapterinfo.attlist "INCLUDE">
-<![ %chapterinfo.attlist; [
-<!ATTLIST chapterinfo
- %common.attrib;
- %chapterinfo.role.attrib;
- %local.chapterinfo.attrib;
->
-<!--end of chapterinfo.attlist-->]]>
-<!--end of chapterinfo.module-->]]>
-
-<!ENTITY % glossaryinfo.module "INCLUDE">
-<![ %glossaryinfo.module; [
-<!ENTITY % local.glossaryinfo.attrib "">
-<!ENTITY % glossaryinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % glossaryinfo.element "INCLUDE">
-<![ %glossaryinfo.element; [
-<!--doc:Meta-information for a Glossary.-->
-<!ELEMENT glossaryinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of glossaryinfo.element-->]]>
-
-<!ENTITY % glossaryinfo.attlist "INCLUDE">
-<![ %glossaryinfo.attlist; [
-<!ATTLIST glossaryinfo
- %common.attrib;
- %glossaryinfo.role.attrib;
- %local.glossaryinfo.attrib;
->
-<!--end of glossaryinfo.attlist-->]]>
-<!--end of glossaryinfo.module-->]]>
-
-<!ENTITY % indexinfo.module "INCLUDE">
-<![ %indexinfo.module; [
-<!ENTITY % local.indexinfo.attrib "">
-<!ENTITY % indexinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % indexinfo.element "INCLUDE">
-<![ %indexinfo.element; [
-<!--doc:Meta-information for an Index.-->
-<!ELEMENT indexinfo %ho; ((%info.class;)+)>
-<!--end of indexinfo.element-->]]>
-
-<!ENTITY % indexinfo.attlist "INCLUDE">
-<![ %indexinfo.attlist; [
-<!ATTLIST indexinfo
- %common.attrib;
- %indexinfo.role.attrib;
- %local.indexinfo.attrib;
->
-<!--end of indexinfo.attlist-->]]>
-<!--end of indexinfo.module-->]]>
-
-<!ENTITY % setindexinfo.module "INCLUDE">
-<![ %setindexinfo.module; [
-<!ENTITY % local.setindexinfo.attrib "">
-<!ENTITY % setindexinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % setindexinfo.element "INCLUDE">
-<![ %setindexinfo.element; [
-<!--doc:Meta-information for a SetIndex.-->
-<!ELEMENT setindexinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of setindexinfo.element-->]]>
-
-<!ENTITY % setindexinfo.attlist "INCLUDE">
-<![ %setindexinfo.attlist; [
-<!ATTLIST setindexinfo
- %common.attrib;
- %setindexinfo.role.attrib;
- %local.setindexinfo.attrib;
->
-<!--end of setindexinfo.attlist-->]]>
-<!--end of setindexinfo.module-->]]>
-
-<!ENTITY % partinfo.module "INCLUDE">
-<![ %partinfo.module; [
-<!ENTITY % local.partinfo.attrib "">
-<!ENTITY % partinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % partinfo.element "INCLUDE">
-<![ %partinfo.element; [
-<!--doc:Meta-information for a Part.-->
-<!ELEMENT partinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of partinfo.element-->]]>
-
-<!ENTITY % partinfo.attlist "INCLUDE">
-<![ %partinfo.attlist; [
-<!ATTLIST partinfo
- %common.attrib;
- %partinfo.role.attrib;
- %local.partinfo.attrib;
->
-<!--end of partinfo.attlist-->]]>
-<!--end of partinfo.module-->]]>
-
-<!ENTITY % prefaceinfo.module "INCLUDE">
-<![ %prefaceinfo.module; [
-<!ENTITY % local.prefaceinfo.attrib "">
-<!ENTITY % prefaceinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % prefaceinfo.element "INCLUDE">
-<![ %prefaceinfo.element; [
-<!--doc:Meta-information for a Preface.-->
-<!ELEMENT prefaceinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of prefaceinfo.element-->]]>
-
-<!ENTITY % prefaceinfo.attlist "INCLUDE">
-<![ %prefaceinfo.attlist; [
-<!ATTLIST prefaceinfo
- %common.attrib;
- %prefaceinfo.role.attrib;
- %local.prefaceinfo.attrib;
->
-<!--end of prefaceinfo.attlist-->]]>
-<!--end of prefaceinfo.module-->]]>
-
-<!ENTITY % refentryinfo.module "INCLUDE">
-<![ %refentryinfo.module; [
-<!ENTITY % local.refentryinfo.attrib "">
-<!ENTITY % refentryinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % refentryinfo.element "INCLUDE">
-<![ %refentryinfo.element; [
-<!--doc:Meta-information for a Refentry.-->
-<!ELEMENT refentryinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refentryinfo.element-->]]>
-
-<!ENTITY % refentryinfo.attlist "INCLUDE">
-<![ %refentryinfo.attlist; [
-<!ATTLIST refentryinfo
- %common.attrib;
- %refentryinfo.role.attrib;
- %local.refentryinfo.attrib;
->
-<!--end of refentryinfo.attlist-->]]>
-<!--end of refentryinfo.module-->]]>
-
-<!ENTITY % refsectioninfo.module "INCLUDE">
-<![ %refsectioninfo.module; [
-<!ENTITY % local.refsectioninfo.attrib "">
-<!ENTITY % refsectioninfo.role.attrib "%role.attrib;">
-
-<!ENTITY % refsectioninfo.element "INCLUDE">
-<![ %refsectioninfo.element; [
-<!--doc:Meta-information for a refsection.-->
-<!ELEMENT refsectioninfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refsectioninfo.element-->]]>
-
-<!ENTITY % refsectioninfo.attlist "INCLUDE">
-<![ %refsectioninfo.attlist; [
-<!ATTLIST refsectioninfo
- %common.attrib;
- %refsectioninfo.role.attrib;
- %local.refsectioninfo.attrib;
->
-<!--end of refsectioninfo.attlist-->]]>
-<!--end of refsectioninfo.module-->]]>
-
-<!ENTITY % refsect1info.module "INCLUDE">
-<![ %refsect1info.module; [
-<!ENTITY % local.refsect1info.attrib "">
-<!ENTITY % refsect1info.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect1info.element "INCLUDE">
-<![ %refsect1info.element; [
-<!--doc:Meta-information for a RefSect1.-->
-<!ELEMENT refsect1info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refsect1info.element-->]]>
-
-<!ENTITY % refsect1info.attlist "INCLUDE">
-<![ %refsect1info.attlist; [
-<!ATTLIST refsect1info
- %common.attrib;
- %refsect1info.role.attrib;
- %local.refsect1info.attrib;
->
-<!--end of refsect1info.attlist-->]]>
-<!--end of refsect1info.module-->]]>
-
-<!ENTITY % refsect2info.module "INCLUDE">
-<![ %refsect2info.module; [
-<!ENTITY % local.refsect2info.attrib "">
-<!ENTITY % refsect2info.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect2info.element "INCLUDE">
-<![ %refsect2info.element; [
-<!--doc:Meta-information for a RefSect2.-->
-<!ELEMENT refsect2info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refsect2info.element-->]]>
-
-<!ENTITY % refsect2info.attlist "INCLUDE">
-<![ %refsect2info.attlist; [
-<!ATTLIST refsect2info
- %common.attrib;
- %refsect2info.role.attrib;
- %local.refsect2info.attrib;
->
-<!--end of refsect2info.attlist-->]]>
-<!--end of refsect2info.module-->]]>
-
-<!ENTITY % refsect3info.module "INCLUDE">
-<![ %refsect3info.module; [
-<!ENTITY % local.refsect3info.attrib "">
-<!ENTITY % refsect3info.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect3info.element "INCLUDE">
-<![ %refsect3info.element; [
-<!--doc:Meta-information for a RefSect3.-->
-<!ELEMENT refsect3info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refsect3info.element-->]]>
-
-<!ENTITY % refsect3info.attlist "INCLUDE">
-<![ %refsect3info.attlist; [
-<!ATTLIST refsect3info
- %common.attrib;
- %refsect3info.role.attrib;
- %local.refsect3info.attrib;
->
-<!--end of refsect3info.attlist-->]]>
-<!--end of refsect3info.module-->]]>
-
-<!ENTITY % refsynopsisdivinfo.module "INCLUDE">
-<![ %refsynopsisdivinfo.module; [
-<!ENTITY % local.refsynopsisdivinfo.attrib "">
-<!ENTITY % refsynopsisdivinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % refsynopsisdivinfo.element "INCLUDE">
-<![ %refsynopsisdivinfo.element; [
-<!--doc:Meta-information for a RefSynopsisDiv.-->
-<!ELEMENT refsynopsisdivinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of refsynopsisdivinfo.element-->]]>
-
-<!ENTITY % refsynopsisdivinfo.attlist "INCLUDE">
-<![ %refsynopsisdivinfo.attlist; [
-<!ATTLIST refsynopsisdivinfo
- %common.attrib;
- %refsynopsisdivinfo.role.attrib;
- %local.refsynopsisdivinfo.attrib;
->
-<!--end of refsynopsisdivinfo.attlist-->]]>
-<!--end of refsynopsisdivinfo.module-->]]>
-
-<!ENTITY % referenceinfo.module "INCLUDE">
-<![ %referenceinfo.module; [
-<!ENTITY % local.referenceinfo.attrib "">
-<!ENTITY % referenceinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % referenceinfo.element "INCLUDE">
-<![ %referenceinfo.element; [
-<!--doc:Meta-information for a Reference.-->
-<!ELEMENT referenceinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of referenceinfo.element-->]]>
-
-<!ENTITY % referenceinfo.attlist "INCLUDE">
-<![ %referenceinfo.attlist; [
-<!ATTLIST referenceinfo
- %common.attrib;
- %referenceinfo.role.attrib;
- %local.referenceinfo.attrib;
->
-<!--end of referenceinfo.attlist-->]]>
-<!--end of referenceinfo.module-->]]>
-
-<!ENTITY % local.sect1info.attrib "">
-<!ENTITY % sect1info.role.attrib "%role.attrib;">
-
-<!ENTITY % sect1info.element "INCLUDE">
-<![%sect1info.element;[
-<!--doc:Meta-information for a Sect1.-->
-<!ELEMENT sect1info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sect1info.element-->]]>
-
-<!ENTITY % sect1info.attlist "INCLUDE">
-<![%sect1info.attlist;[
-<!ATTLIST sect1info
- %common.attrib;
- %sect1info.role.attrib;
- %local.sect1info.attrib;
->
-<!--end of sect1info.attlist-->]]>
-
-<!ENTITY % local.sect2info.attrib "">
-<!ENTITY % sect2info.role.attrib "%role.attrib;">
-
-<!ENTITY % sect2info.element "INCLUDE">
-<![%sect2info.element;[
-<!--doc:Meta-information for a Sect2.-->
-<!ELEMENT sect2info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sect2info.element-->]]>
-
-<!ENTITY % sect2info.attlist "INCLUDE">
-<![%sect2info.attlist;[
-<!ATTLIST sect2info
- %common.attrib;
- %sect2info.role.attrib;
- %local.sect2info.attrib;
->
-<!--end of sect2info.attlist-->]]>
-
-<!ENTITY % local.sect3info.attrib "">
-<!ENTITY % sect3info.role.attrib "%role.attrib;">
-
-<!ENTITY % sect3info.element "INCLUDE">
-<![%sect3info.element;[
-<!--doc:Meta-information for a Sect3.-->
-<!ELEMENT sect3info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sect3info.element-->]]>
-
-<!ENTITY % sect3info.attlist "INCLUDE">
-<![%sect3info.attlist;[
-<!ATTLIST sect3info
- %common.attrib;
- %sect3info.role.attrib;
- %local.sect3info.attrib;
->
-<!--end of sect3info.attlist-->]]>
-
-<!ENTITY % local.sect4info.attrib "">
-<!ENTITY % sect4info.role.attrib "%role.attrib;">
-
-<!ENTITY % sect4info.element "INCLUDE">
-<![%sect4info.element;[
-<!--doc:Meta-information for a Sect4.-->
-<!ELEMENT sect4info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sect4info.element-->]]>
-
-<!ENTITY % sect4info.attlist "INCLUDE">
-<![%sect4info.attlist;[
-<!ATTLIST sect4info
- %common.attrib;
- %sect4info.role.attrib;
- %local.sect4info.attrib;
->
-<!--end of sect4info.attlist-->]]>
-
-<!ENTITY % local.sect5info.attrib "">
-<!ENTITY % sect5info.role.attrib "%role.attrib;">
-
-<!ENTITY % sect5info.element "INCLUDE">
-<![%sect5info.element;[
-<!--doc:Meta-information for a Sect5.-->
-<!ELEMENT sect5info %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sect5info.element-->]]>
-
-<!ENTITY % sect5info.attlist "INCLUDE">
-<![%sect5info.attlist;[
-<!ATTLIST sect5info
- %common.attrib;
- %sect5info.role.attrib;
- %local.sect5info.attrib;
->
-<!--end of sect5info.attlist-->]]>
-
-<!-- ...................................................................... -->
-<!-- Section (parallel to Sect*) ......................................... -->
-
-<!ENTITY % section.content.module "INCLUDE">
-<![ %section.content.module; [
-<!ENTITY % section.module "INCLUDE">
-<![ %section.module; [
-<!ENTITY % local.section.attrib "">
-<!ENTITY % section.role.attrib "%role.attrib;">
-
-<!ENTITY % section.element "INCLUDE">
-<![ %section.element; [
-<!--doc:A recursive section.-->
-<!ELEMENT section %ho; (sectioninfo?,
- (%sect.title.content;),
- (%nav.class;)*,
- (((%divcomponent.mix;)+,
- ((%refentry.class;)*|(%section.class;)*|simplesect*))
- | (%refentry.class;)+|(%section.class;)+|simplesect+),
- (%nav.class;)*)
- %ubiq.inclusion;>
-<!--end of section.element-->]]>
-
-<!ENTITY % section.attlist "INCLUDE">
-<![ %section.attlist; [
-<!ATTLIST section
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %section.role.attrib;
- %local.section.attrib;
->
-<!--end of section.attlist-->]]>
-<!--end of section.module-->]]>
-
-<!ENTITY % sectioninfo.module "INCLUDE">
-<![ %sectioninfo.module; [
-<!ENTITY % sectioninfo.role.attrib "%role.attrib;">
-<!ENTITY % local.sectioninfo.attrib "">
-
-<!ENTITY % sectioninfo.element "INCLUDE">
-<![ %sectioninfo.element; [
-<!--doc:Meta-information for a recursive section.-->
-<!ELEMENT sectioninfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sectioninfo.element-->]]>
-
-<!ENTITY % sectioninfo.attlist "INCLUDE">
-<![ %sectioninfo.attlist; [
-<!ATTLIST sectioninfo
- %common.attrib;
- %sectioninfo.role.attrib;
- %local.sectioninfo.attrib;
->
-<!--end of sectioninfo.attlist-->]]>
-<!--end of sectioninfo.module-->]]>
-<!--end of section.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Sect1, Sect2, Sect3, Sect4, Sect5 .................................... -->
-
-<!ENTITY % sect1.module "INCLUDE">
-<![%sect1.module;[
-<!ENTITY % local.sect1.attrib "">
-<!ENTITY % sect1.role.attrib "%role.attrib;">
-
-<!ENTITY % sect1.element "INCLUDE">
-<![%sect1.element;[
-<!--doc:A top-level section of document.-->
-<!ELEMENT sect1 %ho; (sect1info?, (%sect.title.content;), (%nav.class;)*,
- (((%divcomponent.mix;)+,
- ((%refentry.class;)* | sect2* | simplesect*))
- | (%refentry.class;)+ | sect2+ | simplesect+), (%nav.class;)*)
- %ubiq.inclusion;>
-<!--end of sect1.element-->]]>
-
-<!-- Renderas: Indicates the format in which the heading should
- appear -->
-
-
-<!ENTITY % sect1.attlist "INCLUDE">
-<![%sect1.attlist;[
-<!ATTLIST sect1
- renderas (sect2
- |sect3
- |sect4
- |sect5) #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %sect1.role.attrib;
- %local.sect1.attrib;
->
-<!--end of sect1.attlist-->]]>
-<!--end of sect1.module-->]]>
-
-<!ENTITY % sect2.module "INCLUDE">
-<![%sect2.module;[
-<!ENTITY % local.sect2.attrib "">
-<!ENTITY % sect2.role.attrib "%role.attrib;">
-
-<!ENTITY % sect2.element "INCLUDE">
-<![%sect2.element;[
-<!--doc:A subsection within a Sect1.-->
-<!ELEMENT sect2 %ho; (sect2info?, (%sect.title.content;), (%nav.class;)*,
- (((%divcomponent.mix;)+,
- ((%refentry.class;)* | sect3* | simplesect*))
- | (%refentry.class;)+ | sect3+ | simplesect+), (%nav.class;)*)>
-<!--end of sect2.element-->]]>
-
-<!-- Renderas: Indicates the format in which the heading should
- appear -->
-
-
-<!ENTITY % sect2.attlist "INCLUDE">
-<![%sect2.attlist;[
-<!ATTLIST sect2
- renderas (sect1
- |sect3
- |sect4
- |sect5) #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %sect2.role.attrib;
- %local.sect2.attrib;
->
-<!--end of sect2.attlist-->]]>
-<!--end of sect2.module-->]]>
-
-<!ENTITY % sect3.module "INCLUDE">
-<![%sect3.module;[
-<!ENTITY % local.sect3.attrib "">
-<!ENTITY % sect3.role.attrib "%role.attrib;">
-
-<!ENTITY % sect3.element "INCLUDE">
-<![%sect3.element;[
-<!--doc:A subsection within a Sect2.-->
-<!ELEMENT sect3 %ho; (sect3info?, (%sect.title.content;), (%nav.class;)*,
- (((%divcomponent.mix;)+,
- ((%refentry.class;)* | sect4* | simplesect*))
- | (%refentry.class;)+ | sect4+ | simplesect+), (%nav.class;)*)>
-<!--end of sect3.element-->]]>
-
-<!-- Renderas: Indicates the format in which the heading should
- appear -->
-
-
-<!ENTITY % sect3.attlist "INCLUDE">
-<![%sect3.attlist;[
-<!ATTLIST sect3
- renderas (sect1
- |sect2
- |sect4
- |sect5) #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %sect3.role.attrib;
- %local.sect3.attrib;
->
-<!--end of sect3.attlist-->]]>
-<!--end of sect3.module-->]]>
-
-<!ENTITY % sect4.module "INCLUDE">
-<![%sect4.module;[
-<!ENTITY % local.sect4.attrib "">
-<!ENTITY % sect4.role.attrib "%role.attrib;">
-
-<!ENTITY % sect4.element "INCLUDE">
-<![%sect4.element;[
-<!--doc:A subsection within a Sect3.-->
-<!ELEMENT sect4 %ho; (sect4info?, (%sect.title.content;), (%nav.class;)*,
- (((%divcomponent.mix;)+,
- ((%refentry.class;)* | sect5* | simplesect*))
- | (%refentry.class;)+ | sect5+ | simplesect+), (%nav.class;)*)>
-<!--end of sect4.element-->]]>
-
-<!-- Renderas: Indicates the format in which the heading should
- appear -->
-
-
-<!ENTITY % sect4.attlist "INCLUDE">
-<![%sect4.attlist;[
-<!ATTLIST sect4
- renderas (sect1
- |sect2
- |sect3
- |sect5) #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %sect4.role.attrib;
- %local.sect4.attrib;
->
-<!--end of sect4.attlist-->]]>
-<!--end of sect4.module-->]]>
-
-<!ENTITY % sect5.module "INCLUDE">
-<![%sect5.module;[
-<!ENTITY % local.sect5.attrib "">
-<!ENTITY % sect5.role.attrib "%role.attrib;">
-
-<!ENTITY % sect5.element "INCLUDE">
-<![%sect5.element;[
-<!--doc:A subsection within a Sect4.-->
-<!ELEMENT sect5 %ho; (sect5info?, (%sect.title.content;), (%nav.class;)*,
- (((%divcomponent.mix;)+, ((%refentry.class;)* | simplesect*))
- | (%refentry.class;)+ | simplesect+), (%nav.class;)*)>
-<!--end of sect5.element-->]]>
-
-<!-- Renderas: Indicates the format in which the heading should
- appear -->
-
-
-<!ENTITY % sect5.attlist "INCLUDE">
-<![%sect5.attlist;[
-<!ATTLIST sect5
- renderas (sect1
- |sect2
- |sect3
- |sect4) #IMPLIED
- %label.attrib;
- %status.attrib;
- %common.attrib;
- %sect5.role.attrib;
- %local.sect5.attrib;
->
-<!--end of sect5.attlist-->]]>
-<!--end of sect5.module-->]]>
-
-<!ENTITY % simplesect.module "INCLUDE">
-<![%simplesect.module;[
-<!ENTITY % local.simplesect.attrib "">
-<!ENTITY % simplesect.role.attrib "%role.attrib;">
-
-<!ENTITY % simplesect.element "INCLUDE">
-<![%simplesect.element;[
-<!--doc:A section of a document with no subdivisions.-->
-<!ELEMENT simplesect %ho; ((%sect.title.content;), (%divcomponent.mix;)+)
- %ubiq.inclusion;>
-<!--end of simplesect.element-->]]>
-
-<!ENTITY % simplesect.attlist "INCLUDE">
-<![%simplesect.attlist;[
-<!ATTLIST simplesect
- %common.attrib;
- %simplesect.role.attrib;
- %local.simplesect.attrib;
->
-<!--end of simplesect.attlist-->]]>
-<!--end of simplesect.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Bibliography ......................................................... -->
-
-<!ENTITY % bibliography.content.module "INCLUDE">
-<![%bibliography.content.module;[
-<!ENTITY % bibliography.module "INCLUDE">
-<![%bibliography.module;[
-<!ENTITY % local.bibliography.attrib "">
-<!ENTITY % bibliography.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliography.element "INCLUDE">
-<![%bibliography.element;[
-<!--doc:A bibliography.-->
-<!ELEMENT bibliography %ho; (bibliographyinfo?,
- (%bookcomponent.title.content;)?,
- (%component.mix;)*,
- (bibliodiv+ | (biblioentry|bibliomixed)+))>
-<!--end of bibliography.element-->]]>
-
-<!ENTITY % bibliography.attlist "INCLUDE">
-<![%bibliography.attlist;[
-<!ATTLIST bibliography
- %status.attrib;
- %common.attrib;
- %bibliography.role.attrib;
- %local.bibliography.attrib;
->
-<!--end of bibliography.attlist-->]]>
-<!--end of bibliography.module-->]]>
-
-<!ENTITY % bibliodiv.module "INCLUDE">
-<![%bibliodiv.module;[
-<!ENTITY % local.bibliodiv.attrib "">
-<!ENTITY % bibliodiv.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliodiv.element "INCLUDE">
-<![%bibliodiv.element;[
-<!--doc:A section of a Bibliography.-->
-<!ELEMENT bibliodiv %ho; ((%sect.title.content;)?, (%component.mix;)*,
- (biblioentry|bibliomixed)+)>
-<!--end of bibliodiv.element-->]]>
-
-<!ENTITY % bibliodiv.attlist "INCLUDE">
-<![%bibliodiv.attlist;[
-<!ATTLIST bibliodiv
- %status.attrib;
- %common.attrib;
- %bibliodiv.role.attrib;
- %local.bibliodiv.attrib;
->
-<!--end of bibliodiv.attlist-->]]>
-<!--end of bibliodiv.module-->]]>
-<!--end of bibliography.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Glossary ............................................................. -->
-
-<!ENTITY % glossary.content.module "INCLUDE">
-<![%glossary.content.module;[
-<!ENTITY % glossary.module "INCLUDE">
-<![%glossary.module;[
-<!ENTITY % local.glossary.attrib "">
-<!ENTITY % glossary.role.attrib "%role.attrib;">
-
-<!ENTITY % glossary.element "INCLUDE">
-<![%glossary.element;[
-<!--doc:A glossary.-->
-<!ELEMENT glossary %ho; (glossaryinfo?,
- (%bookcomponent.title.content;)?,
- (%component.mix;)*,
- (glossdiv+ | glossentry+), bibliography?)>
-<!--end of glossary.element-->]]>
-
-<!ENTITY % glossary.attlist "INCLUDE">
-<![%glossary.attlist;[
-<!ATTLIST glossary
- %status.attrib;
- %common.attrib;
- %glossary.role.attrib;
- %local.glossary.attrib;
->
-<!--end of glossary.attlist-->]]>
-<!--end of glossary.module-->]]>
-
-<!ENTITY % glossdiv.module "INCLUDE">
-<![%glossdiv.module;[
-<!ENTITY % local.glossdiv.attrib "">
-<!ENTITY % glossdiv.role.attrib "%role.attrib;">
-
-<!ENTITY % glossdiv.element "INCLUDE">
-<![%glossdiv.element;[
-<!--doc:A division in a Glossary.-->
-<!ELEMENT glossdiv %ho; ((%sect.title.content;), (%component.mix;)*,
- glossentry+)>
-<!--end of glossdiv.element-->]]>
-
-<!ENTITY % glossdiv.attlist "INCLUDE">
-<![%glossdiv.attlist;[
-<!ATTLIST glossdiv
- %status.attrib;
- %common.attrib;
- %glossdiv.role.attrib;
- %local.glossdiv.attrib;
->
-<!--end of glossdiv.attlist-->]]>
-<!--end of glossdiv.module-->]]>
-<!--end of glossary.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Index and SetIndex ................................................... -->
-
-<!ENTITY % index.content.module "INCLUDE">
-<![%index.content.module;[
-<!ENTITY % indexes.module "INCLUDE">
-<![%indexes.module;[
-<!ENTITY % local.indexes.attrib "">
-<!ENTITY % indexes.role.attrib "%role.attrib;">
-
-<!ENTITY % index.element "INCLUDE">
-<![%index.element;[
-<!--doc:An index.-->
-<!ELEMENT index %ho; (indexinfo?,
- (%bookcomponent.title.content;)?,
- (%component.mix;)*,
- (indexdiv* | indexentry*))
- %ndxterm.exclusion;>
-<!--end of index.element-->]]>
-
-<!ENTITY % index.attlist "INCLUDE">
-<![%index.attlist;[
-<!ATTLIST index
- type CDATA #IMPLIED
- %common.attrib;
- %indexes.role.attrib;
- %local.indexes.attrib;
->
-<!--end of index.attlist-->]]>
-
-<!ENTITY % setindex.element "INCLUDE">
-<![%setindex.element;[
-<!--doc:An index to a set of books.-->
-<!ELEMENT setindex %ho; (setindexinfo?,
- (%bookcomponent.title.content;)?,
- (%component.mix;)*,
- (indexdiv* | indexentry*))
- %ndxterm.exclusion;>
-<!--end of setindex.element-->]]>
-
-<!ENTITY % setindex.attlist "INCLUDE">
-<![%setindex.attlist;[
-<!ATTLIST setindex
- %common.attrib;
- %indexes.role.attrib;
- %local.indexes.attrib;
->
-<!--end of setindex.attlist-->]]>
-<!--end of indexes.module-->]]>
-
-<!ENTITY % indexdiv.module "INCLUDE">
-<![%indexdiv.module;[
-
-<!-- SegmentedList in this content is useful for marking up permuted
- indices. -->
-
-<!ENTITY % local.indexdiv.attrib "">
-<!ENTITY % indexdiv.role.attrib "%role.attrib;">
-
-<!ENTITY % indexdiv.element "INCLUDE">
-<![%indexdiv.element;[
-<!--doc:A division in an index.-->
-<!ELEMENT indexdiv %ho; ((%sect.title.content;)?, ((%indexdivcomponent.mix;)*,
- (indexentry+ | segmentedlist)))>
-<!--end of indexdiv.element-->]]>
-
-<!ENTITY % indexdiv.attlist "INCLUDE">
-<![%indexdiv.attlist;[
-<!ATTLIST indexdiv
- %common.attrib;
- %indexdiv.role.attrib;
- %local.indexdiv.attrib;
->
-<!--end of indexdiv.attlist-->]]>
-<!--end of indexdiv.module-->]]>
-
-<!ENTITY % indexentry.module "INCLUDE">
-<![%indexentry.module;[
-<!-- Index entries appear in the index, not the text. -->
-
-<!ENTITY % local.indexentry.attrib "">
-<!ENTITY % indexentry.role.attrib "%role.attrib;">
-
-<!ENTITY % indexentry.element "INCLUDE">
-<![%indexentry.element;[
-<!--doc:An entry in an index.-->
-<!ELEMENT indexentry %ho; (primaryie, (seeie|seealsoie)*,
- (secondaryie, (seeie|seealsoie|tertiaryie)*)*)>
-<!--end of indexentry.element-->]]>
-
-<!ENTITY % indexentry.attlist "INCLUDE">
-<![%indexentry.attlist;[
-<!ATTLIST indexentry
- %common.attrib;
- %indexentry.role.attrib;
- %local.indexentry.attrib;
->
-<!--end of indexentry.attlist-->]]>
-<!--end of indexentry.module-->]]>
-
-<!ENTITY % primsecterie.module "INCLUDE">
-<![%primsecterie.module;[
-<!ENTITY % local.primsecterie.attrib "">
-<!ENTITY % primsecterie.role.attrib "%role.attrib;">
-
-<!ENTITY % primaryie.element "INCLUDE">
-<![%primaryie.element;[
-<!--doc:A primary term in an index entry, not in the text.-->
-<!ELEMENT primaryie %ho; (%ndxterm.char.mix;)*>
-<!--end of primaryie.element-->]]>
-
-<!-- to IndexTerms that these entries represent -->
-
-<!ENTITY % primaryie.attlist "INCLUDE">
-<![%primaryie.attlist;[
-<!ATTLIST primaryie
- %linkends.attrib; %common.attrib;
- %primsecterie.role.attrib;
- %local.primsecterie.attrib;
->
-<!--end of primaryie.attlist-->]]>
-
-<!ENTITY % secondaryie.element "INCLUDE">
-<![%secondaryie.element;[
-<!--doc:A secondary term in an index entry, rather than in the text.-->
-<!ELEMENT secondaryie %ho; (%ndxterm.char.mix;)*>
-<!--end of secondaryie.element-->]]>
-
-<!-- to IndexTerms that these entries represent -->
-
-<!ENTITY % secondaryie.attlist "INCLUDE">
-<![%secondaryie.attlist;[
-<!ATTLIST secondaryie
- %linkends.attrib; %common.attrib;
- %primsecterie.role.attrib;
- %local.primsecterie.attrib;
->
-<!--end of secondaryie.attlist-->]]>
-
-<!ENTITY % tertiaryie.element "INCLUDE">
-<![%tertiaryie.element;[
-<!--doc:A tertiary term in an index entry, rather than in the text.-->
-<!ELEMENT tertiaryie %ho; (%ndxterm.char.mix;)*>
-<!--end of tertiaryie.element-->]]>
-
-<!-- to IndexTerms that these entries represent -->
-
-<!ENTITY % tertiaryie.attlist "INCLUDE">
-<![%tertiaryie.attlist;[
-<!ATTLIST tertiaryie
- %linkends.attrib; %common.attrib;
- %primsecterie.role.attrib;
- %local.primsecterie.attrib;
->
-<!--end of tertiaryie.attlist-->]]>
-
-<!--end of primsecterie.module-->]]>
-
-<!ENTITY % seeie.module "INCLUDE">
-<![%seeie.module;[
-<!ENTITY % local.seeie.attrib "">
-<!ENTITY % seeie.role.attrib "%role.attrib;">
-
-<!ENTITY % seeie.element "INCLUDE">
-<![%seeie.element;[
-<!--doc:A See entry in an index, rather than in the text.-->
-<!ELEMENT seeie %ho; (%ndxterm.char.mix;)*>
-<!--end of seeie.element-->]]>
-
-<!-- to IndexEntry to look up -->
-
-
-<!ENTITY % seeie.attlist "INCLUDE">
-<![%seeie.attlist;[
-<!ATTLIST seeie
- %linkend.attrib; %common.attrib;
- %seeie.role.attrib;
- %local.seeie.attrib;
->
-<!--end of seeie.attlist-->]]>
-<!--end of seeie.module-->]]>
-
-<!ENTITY % seealsoie.module "INCLUDE">
-<![%seealsoie.module;[
-<!ENTITY % local.seealsoie.attrib "">
-<!ENTITY % seealsoie.role.attrib "%role.attrib;">
-
-<!ENTITY % seealsoie.element "INCLUDE">
-<![%seealsoie.element;[
-<!--doc:A See also entry in an index, rather than in the text.-->
-<!ELEMENT seealsoie %ho; (%ndxterm.char.mix;)*>
-<!--end of seealsoie.element-->]]>
-
-<!-- to related IndexEntries -->
-
-
-<!ENTITY % seealsoie.attlist "INCLUDE">
-<![%seealsoie.attlist;[
-<!ATTLIST seealsoie
- %linkends.attrib; %common.attrib;
- %seealsoie.role.attrib;
- %local.seealsoie.attrib;
->
-<!--end of seealsoie.attlist-->]]>
-<!--end of seealsoie.module-->]]>
-<!--end of index.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- RefEntry ............................................................. -->
-
-<!ENTITY % refentry.content.module "INCLUDE">
-<![%refentry.content.module;[
-<!ENTITY % refentry.module "INCLUDE">
-<![%refentry.module;[
-<!ENTITY % local.refentry.attrib "">
-<!ENTITY % refentry.role.attrib "%role.attrib;">
-
-<!ENTITY % refentry.element "INCLUDE">
-<![%refentry.element;[
-<!--doc:A reference page (originally a UNIX man-style reference page).-->
-<!ELEMENT refentry %ho; (beginpage?,
- (%ndxterm.class;)*,
- refentryinfo?, refmeta?, (remark|%link.char.class;)*,
- refnamediv+, refsynopsisdiv?, (refsect1+|refsection+))
- %ubiq.inclusion;>
-<!--end of refentry.element-->]]>
-
-<!ENTITY % refentry.attlist "INCLUDE">
-<![%refentry.attlist;[
-<!ATTLIST refentry
- %status.attrib;
- %common.attrib;
- %refentry.role.attrib;
- %local.refentry.attrib;
->
-<!--end of refentry.attlist-->]]>
-<!--end of refentry.module-->]]>
-
-<!ENTITY % refmeta.module "INCLUDE">
-<![%refmeta.module;[
-<!ENTITY % local.refmeta.attrib "">
-<!ENTITY % refmeta.role.attrib "%role.attrib;">
-
-<!ENTITY % refmeta.element "INCLUDE">
-<![%refmeta.element;[
-<!--doc:Meta-information for a reference entry.-->
-<!ELEMENT refmeta %ho; ((%ndxterm.class;)*,
- refentrytitle, manvolnum?, refmiscinfo*,
- (%ndxterm.class;)*)
- %beginpage.exclusion;>
-<!--end of refmeta.element-->]]>
-
-<!ENTITY % refmeta.attlist "INCLUDE">
-<![%refmeta.attlist;[
-<!ATTLIST refmeta
- %common.attrib;
- %refmeta.role.attrib;
- %local.refmeta.attrib;
->
-<!--end of refmeta.attlist-->]]>
-<!--end of refmeta.module-->]]>
-
-<!ENTITY % refmiscinfo.module "INCLUDE">
-<![%refmiscinfo.module;[
-<!ENTITY % local.refmiscinfo.attrib "">
-<!ENTITY % refmiscinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % refmiscinfo.element "INCLUDE">
-<![%refmiscinfo.element;[
-<!--doc:Meta-information for a reference entry other than the title and volume number.-->
-<!ELEMENT refmiscinfo %ho; (%docinfo.char.mix;)*>
-<!--end of refmiscinfo.element-->]]>
-
-<!-- Class: Freely assignable parameter; no default -->
-
-
-<!ENTITY % refmiscinfo.attlist "INCLUDE">
-<![%refmiscinfo.attlist;[
-<!ATTLIST refmiscinfo
- class CDATA #IMPLIED
- %common.attrib;
- %refmiscinfo.role.attrib;
- %local.refmiscinfo.attrib;
->
-<!--end of refmiscinfo.attlist-->]]>
-<!--end of refmiscinfo.module-->]]>
-
-<!ENTITY % refnamediv.module "INCLUDE">
-<![%refnamediv.module;[
-<!ENTITY % local.refnamediv.attrib "">
-<!ENTITY % refnamediv.role.attrib "%role.attrib;">
-
-<!ENTITY % refnamediv.element "INCLUDE">
-<![%refnamediv.element;[
-<!--doc:The name, purpose, and classification of a reference page.-->
-<!ELEMENT refnamediv %ho; (refdescriptor?, refname+, refpurpose, refclass*,
- (remark|%link.char.class;)*)>
-<!--end of refnamediv.element-->]]>
-
-<!ENTITY % refnamediv.attlist "INCLUDE">
-<![%refnamediv.attlist;[
-<!ATTLIST refnamediv
- %common.attrib;
- %refnamediv.role.attrib;
- %local.refnamediv.attrib;
->
-<!--end of refnamediv.attlist-->]]>
-<!--end of refnamediv.module-->]]>
-
-<!ENTITY % refdescriptor.module "INCLUDE">
-<![%refdescriptor.module;[
-<!ENTITY % local.refdescriptor.attrib "">
-<!ENTITY % refdescriptor.role.attrib "%role.attrib;">
-
-<!ENTITY % refdescriptor.element "INCLUDE">
-<![%refdescriptor.element;[
-<!--doc:A description of the topic of a reference page.-->
-<!ELEMENT refdescriptor %ho; (%refname.char.mix;)*>
-<!--end of refdescriptor.element-->]]>
-
-<!ENTITY % refdescriptor.attlist "INCLUDE">
-<![%refdescriptor.attlist;[
-<!ATTLIST refdescriptor
- %common.attrib;
- %refdescriptor.role.attrib;
- %local.refdescriptor.attrib;
->
-<!--end of refdescriptor.attlist-->]]>
-<!--end of refdescriptor.module-->]]>
-
-<!ENTITY % refname.module "INCLUDE">
-<![%refname.module;[
-<!ENTITY % local.refname.attrib "">
-<!ENTITY % refname.role.attrib "%role.attrib;">
-
-<!ENTITY % refname.element "INCLUDE">
-<![%refname.element;[
-<!--doc:The name of (one of) the subject(s) of a reference page.-->
-<!ELEMENT refname %ho; (%refname.char.mix;)*>
-<!--end of refname.element-->]]>
-
-<!ENTITY % refname.attlist "INCLUDE">
-<![%refname.attlist;[
-<!ATTLIST refname
- %common.attrib;
- %refname.role.attrib;
- %local.refname.attrib;
->
-<!--end of refname.attlist-->]]>
-<!--end of refname.module-->]]>
-
-<!ENTITY % refpurpose.module "INCLUDE">
-<![%refpurpose.module;[
-<!ENTITY % local.refpurpose.attrib "">
-<!ENTITY % refpurpose.role.attrib "%role.attrib;">
-
-<!ENTITY % refpurpose.element "INCLUDE">
-<![%refpurpose.element;[
-<!--doc:A short (one sentence) synopsis of the topic of a reference page.-->
-<!ELEMENT refpurpose %ho; (%refinline.char.mix;)*>
-<!--end of refpurpose.element-->]]>
-
-<!ENTITY % refpurpose.attlist "INCLUDE">
-<![%refpurpose.attlist;[
-<!ATTLIST refpurpose
- %common.attrib;
- %refpurpose.role.attrib;
- %local.refpurpose.attrib;
->
-<!--end of refpurpose.attlist-->]]>
-<!--end of refpurpose.module-->]]>
-
-<!ENTITY % refclass.module "INCLUDE">
-<![%refclass.module;[
-<!ENTITY % local.refclass.attrib "">
-<!ENTITY % refclass.role.attrib "%role.attrib;">
-
-<!ENTITY % refclass.element "INCLUDE">
-<![%refclass.element;[
-<!--doc:The scope or other indication of applicability of a reference entry.-->
-<!ELEMENT refclass %ho; (%refclass.char.mix;)*>
-<!--end of refclass.element-->]]>
-
-<!ENTITY % refclass.attlist "INCLUDE">
-<![%refclass.attlist;[
-<!ATTLIST refclass
- %common.attrib;
- %refclass.role.attrib;
- %local.refclass.attrib;
->
-<!--end of refclass.attlist-->]]>
-<!--end of refclass.module-->]]>
-
-<!ENTITY % refsynopsisdiv.module "INCLUDE">
-<![%refsynopsisdiv.module;[
-<!ENTITY % local.refsynopsisdiv.attrib "">
-<!ENTITY % refsynopsisdiv.role.attrib "%role.attrib;">
-
-<!ENTITY % refsynopsisdiv.element "INCLUDE">
-<![%refsynopsisdiv.element;[
-<!--doc:A syntactic synopsis of the subject of the reference page.-->
-<!ELEMENT refsynopsisdiv %ho; (refsynopsisdivinfo?, (%refsect.title.content;)?,
- (((%refcomponent.mix;)+, refsect2*) | (refsect2+)))>
-<!--end of refsynopsisdiv.element-->]]>
-
-<!ENTITY % refsynopsisdiv.attlist "INCLUDE">
-<![%refsynopsisdiv.attlist;[
-<!ATTLIST refsynopsisdiv
- %common.attrib;
- %refsynopsisdiv.role.attrib;
- %local.refsynopsisdiv.attrib;
->
-<!--end of refsynopsisdiv.attlist-->]]>
-<!--end of refsynopsisdiv.module-->]]>
-
-<!ENTITY % refsection.module "INCLUDE">
-<![%refsection.module;[
-<!ENTITY % local.refsection.attrib "">
-<!ENTITY % refsection.role.attrib "%role.attrib;">
-
-<!ENTITY % refsection.element "INCLUDE">
-<![%refsection.element;[
-<!--doc:A recursive section in a refentry.-->
-<!ELEMENT refsection %ho; (refsectioninfo?, (%refsect.title.content;),
- (((%refcomponent.mix;)+, refsection*) | refsection+))>
-<!--end of refsection.element-->]]>
-
-<!ENTITY % refsection.attlist "INCLUDE">
-<![%refsection.attlist;[
-<!ATTLIST refsection
- %status.attrib;
- %common.attrib;
- %refsection.role.attrib;
- %local.refsection.attrib;
->
-<!--end of refsection.attlist-->]]>
-<!--end of refsection.module-->]]>
-
-<!ENTITY % refsect1.module "INCLUDE">
-<![%refsect1.module;[
-<!ENTITY % local.refsect1.attrib "">
-<!ENTITY % refsect1.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect1.element "INCLUDE">
-<![%refsect1.element;[
-<!--doc:A major subsection of a reference entry.-->
-<!ELEMENT refsect1 %ho; (refsect1info?, (%refsect.title.content;),
- (((%refcomponent.mix;)+, refsect2*) | refsect2+))>
-<!--end of refsect1.element-->]]>
-
-<!ENTITY % refsect1.attlist "INCLUDE">
-<![%refsect1.attlist;[
-<!ATTLIST refsect1
- %status.attrib;
- %common.attrib;
- %refsect1.role.attrib;
- %local.refsect1.attrib;
->
-<!--end of refsect1.attlist-->]]>
-<!--end of refsect1.module-->]]>
-
-<!ENTITY % refsect2.module "INCLUDE">
-<![%refsect2.module;[
-<!ENTITY % local.refsect2.attrib "">
-<!ENTITY % refsect2.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect2.element "INCLUDE">
-<![%refsect2.element;[
-<!--doc:A subsection of a RefSect1.-->
-<!ELEMENT refsect2 %ho; (refsect2info?, (%refsect.title.content;),
- (((%refcomponent.mix;)+, refsect3*) | refsect3+))>
-<!--end of refsect2.element-->]]>
-
-<!ENTITY % refsect2.attlist "INCLUDE">
-<![%refsect2.attlist;[
-<!ATTLIST refsect2
- %status.attrib;
- %common.attrib;
- %refsect2.role.attrib;
- %local.refsect2.attrib;
->
-<!--end of refsect2.attlist-->]]>
-<!--end of refsect2.module-->]]>
-
-<!ENTITY % refsect3.module "INCLUDE">
-<![%refsect3.module;[
-<!ENTITY % local.refsect3.attrib "">
-<!ENTITY % refsect3.role.attrib "%role.attrib;">
-
-<!ENTITY % refsect3.element "INCLUDE">
-<![%refsect3.element;[
-<!--doc:A subsection of a RefSect2.-->
-<!ELEMENT refsect3 %ho; (refsect3info?, (%refsect.title.content;),
- (%refcomponent.mix;)+)>
-<!--end of refsect3.element-->]]>
-
-<!ENTITY % refsect3.attlist "INCLUDE">
-<![%refsect3.attlist;[
-<!ATTLIST refsect3
- %status.attrib;
- %common.attrib;
- %refsect3.role.attrib;
- %local.refsect3.attrib;
->
-<!--end of refsect3.attlist-->]]>
-<!--end of refsect3.module-->]]>
-<!--end of refentry.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Article .............................................................. -->
-
-<!ENTITY % article.module "INCLUDE">
-<![%article.module;[
-<!-- An Article is a chapter-level, stand-alone document that is often,
- but need not be, collected into a Book. -->
-
-<!ENTITY % local.article.attrib "">
-<!ENTITY % article.role.attrib "%role.attrib;">
-
-<!ENTITY % article.element "INCLUDE">
-<![%article.element;[
-<!--doc:An article.-->
-<!ELEMENT article %ho; ((%div.title.content;)?, articleinfo?, tocchap?, lot*,
- (%bookcomponent.content;),
- (%nav.class;|%appendix.class;|colophon|ackno)*)
- %ubiq.inclusion;>
-<!--end of article.element-->]]>
-
-<!-- Class: Indicates the type of a particular article;
- all articles have the same structure and general purpose.
- No default. -->
-<!-- ParentBook: ID of the enclosing Book -->
-
-
-<!ENTITY % article.attlist "INCLUDE">
-<![%article.attlist;[
-<!ATTLIST article
- class (journalarticle
- |productsheet
- |whitepaper
- |techreport
- |specification
- |faq) #IMPLIED
- parentbook IDREF #IMPLIED
- %status.attrib;
- %common.attrib;
- %article.role.attrib;
- %local.article.attrib;
->
-<!--end of article.attlist-->]]>
-<!--end of article.module-->]]>
-
-<!-- End of DocBook document hierarchy module V4.5 ........................ -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/dbnotnx.mod b/Utilities/xml/docbook-4.5/dbnotnx.mod
deleted file mode 100644
index 2416049bf..000000000
--- a/Utilities/xml/docbook-4.5/dbnotnx.mod
+++ /dev/null
@@ -1,101 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook notations module V4.5 ........................................ -->
-<!-- File dbnotnx.mod ..................................................... -->
-
-<!-- Copyright 1992-2004 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- $Id: dbnotnx.mod 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the notation declarations used by DocBook.
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % dbnotn PUBLIC
- "-//OASIS//ENTITIES DocBook Notations V4.5//EN"
- "dbnotnx.mod">
- %dbnotn;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!ENTITY % local.notation.class "">
-<!ENTITY % notation.class
- "BMP| CGM-CHAR | CGM-BINARY | CGM-CLEAR | DITROFF | DVI
- | EPS | EQN | FAX | GIF | GIF87a | GIF89a
- | JPG | JPEG | IGES | PCX
- | PIC | PNG | PS | SGML | TBL | TEX | TIFF | WMF | WPG
- | SVG | PDF | SWF
- | linespecific
- %local.notation.class;">
-
-<!NOTATION BMP PUBLIC
-"+//ISBN 0-7923-94.2-1::Graphic Notation//NOTATION Microsoft Windows bitmap//EN">
-<!NOTATION CGM-CHAR PUBLIC "ISO 8632/2//NOTATION Character encoding//EN">
-<!NOTATION CGM-BINARY PUBLIC "ISO 8632/3//NOTATION Binary encoding//EN">
-<!NOTATION CGM-CLEAR PUBLIC "ISO 8632/4//NOTATION Clear text encoding//EN">
-<!NOTATION DITROFF SYSTEM "DITROFF">
-<!NOTATION DVI SYSTEM "DVI">
-<!NOTATION EPS PUBLIC
-"+//ISBN 0-201-18127-4::Adobe//NOTATION PostScript Language Ref. Manual//EN">
-<!NOTATION EQN SYSTEM "EQN">
-<!NOTATION FAX PUBLIC
-"-//USA-DOD//NOTATION CCITT Group 4 Facsimile Type 1 Untiled Raster//EN">
-<!NOTATION GIF SYSTEM "GIF">
-<!NOTATION GIF87a PUBLIC
-"-//CompuServe//NOTATION Graphics Interchange Format 87a//EN">
-
-<!NOTATION GIF89a PUBLIC
-"-//CompuServe//NOTATION Graphics Interchange Format 89a//EN">
-<!NOTATION JPG SYSTEM "JPG">
-<!NOTATION JPEG SYSTEM "JPG">
-<!NOTATION IGES PUBLIC
-"-//USA-DOD//NOTATION (ASME/ANSI Y14.26M-1987) Initial Graphics Exchange Specification//EN">
-<!NOTATION PCX PUBLIC
-"+//ISBN 0-7923-94.2-1::Graphic Notation//NOTATION ZSoft PCX bitmap//EN">
-<!NOTATION PIC SYSTEM "PIC">
-<!NOTATION PNG SYSTEM "http://www.w3.org/TR/REC-png">
-<!NOTATION PS SYSTEM "PS">
-<!NOTATION SGML PUBLIC
-"ISO 8879:1986//NOTATION Standard Generalized Markup Language//EN">
-<!NOTATION TBL SYSTEM "TBL">
-<!NOTATION TEX PUBLIC
-"+//ISBN 0-201-13448-9::Knuth//NOTATION The TeXbook//EN">
-<!NOTATION TIFF SYSTEM "TIFF">
-<!NOTATION WMF PUBLIC
-"+//ISBN 0-7923-94.2-1::Graphic Notation//NOTATION Microsoft Windows Metafile//EN">
-<!NOTATION WPG SYSTEM "WPG"> <!--WordPerfect Graphic format-->
-<!NOTATION SVG SYSTEM "http://www.w3.org/TR/SVG/">
-<!NOTATION PDF SYSTEM "http://www.adobe.com/products/acrobat/adobepdf.html">
-<!NOTATION SWF SYSTEM "http://www.macromedia.com/software/flash">
-<!NOTATION linespecific SYSTEM "linespecific">
-
-<!-- End of DocBook notations module V4.5 ................................. -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/dbpoolx.mod b/Utilities/xml/docbook-4.5/dbpoolx.mod
deleted file mode 100644
index 53b07044a..000000000
--- a/Utilities/xml/docbook-4.5/dbpoolx.mod
+++ /dev/null
@@ -1,8701 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook XML information pool module V4.5 ............................. -->
-<!-- File dbpoolx.mod ..................................................... -->
-
-<!-- Copyright 1992-2004 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- $Id: dbpoolx.mod 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook XML DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook XML DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the definitions for the objects, inline
- elements, and so on that are available to be used as the main
- content of DocBook documents. Some elements are useful for general
- publishing, and others are useful specifically for computer
- documentation.
-
- This module has the following dependencies on other modules:
-
- o It assumes that a %notation.class; entity is defined by the
- driver file or other high-level module. This entity is
- referenced in the NOTATION attributes for the graphic-related and
- ModeSpec elements.
-
- o It assumes that an appropriately parameterized table module is
- available for use with the table-related elements.
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % dbpool PUBLIC
- "-//OASIS//ELEMENTS DocBook XML Information Pool V4.5//EN"
- "dbpoolx.mod">
- %dbpool;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!-- ...................................................................... -->
-<!-- Forms entities ....................................................... -->
-<!-- These PEs provide the hook by which the forms module can be inserted -->
-<!-- into the DTD. -->
-<!ENTITY % forminlines.hook "">
-<!ENTITY % forms.hook "">
-
-<!-- ...................................................................... -->
-<!-- General-purpose semantics entities ................................... -->
-
-<!ENTITY % yesorno.attvals "CDATA">
-
-<!-- ...................................................................... -->
-<!-- Entities for module inclusions ....................................... -->
-
-<!ENTITY % dbpool.redecl.module "IGNORE">
-
-<!-- ...................................................................... -->
-<!-- Entities for element classes and mixtures ............................ -->
-
-<!-- "Ubiquitous" classes: ndxterm.class and beginpage -->
-
-<!ENTITY % local.ndxterm.class "">
-<!ENTITY % ndxterm.class
- "indexterm %local.ndxterm.class;">
-
-<!-- Object-level classes ................................................. -->
-
-<!ENTITY % local.list.class "">
-<!ENTITY % list.class
- "calloutlist|glosslist|bibliolist|itemizedlist|orderedlist|segmentedlist
- |simplelist|variablelist %local.list.class;">
-
-<!ENTITY % local.admon.class "">
-<!ENTITY % admon.class
- "caution|important|note|tip|warning %local.admon.class;">
-
-<!ENTITY % local.linespecific.class "">
-<!ENTITY % linespecific.class
- "literallayout|programlisting|programlistingco|screen
- |screenco|screenshot %local.linespecific.class;">
-
-<!ENTITY % local.method.synop.class "">
-<!ENTITY % method.synop.class
- "constructorsynopsis
- |destructorsynopsis
- |methodsynopsis %local.method.synop.class;">
-
-<!ENTITY % local.synop.class "">
-<!ENTITY % synop.class
- "synopsis|cmdsynopsis|funcsynopsis
- |classsynopsis|fieldsynopsis
- |%method.synop.class; %local.synop.class;">
-
-<!ENTITY % local.para.class "">
-<!ENTITY % para.class
- "formalpara|para|simpara %local.para.class;">
-
-<!ENTITY % local.informal.class "">
-<!ENTITY % informal.class
- "address|blockquote
- |graphic|graphicco|mediaobject|mediaobjectco
- |informalequation
- |informalexample
- |informalfigure
- |informaltable %local.informal.class;">
-
-<!ENTITY % local.formal.class "">
-<!ENTITY % formal.class
- "equation|example|figure|table %local.formal.class;">
-
-<!-- The DocBook TC may produce an official EBNF module for DocBook. -->
-<!-- This PE provides the hook by which it can be inserted into the DTD. -->
-<!ENTITY % ebnf.block.hook "">
-
-<!ENTITY % local.compound.class "">
-<!ENTITY % compound.class
- "msgset|procedure|sidebar|qandaset|task
- %ebnf.block.hook;
- %local.compound.class;">
-
-<!ENTITY % local.genobj.class "">
-<!ENTITY % genobj.class
- "anchor|bridgehead|remark|highlights
- %local.genobj.class;">
-
-<!ENTITY % local.descobj.class "">
-<!ENTITY % descobj.class
- "abstract|authorblurb|epigraph
- %local.descobj.class;">
-
-<!-- Character-level classes .............................................. -->
-
-<!ENTITY % local.xref.char.class "">
-<!ENTITY % xref.char.class
- "footnoteref|xref|biblioref %local.xref.char.class;">
-
-<!ENTITY % local.gen.char.class "">
-<!ENTITY % gen.char.class
- "abbrev|acronym|citation|citerefentry|citetitle|citebiblioid|emphasis
- |firstterm|foreignphrase|glossterm|termdef|footnote|phrase
- |orgname|quote|trademark|wordasword
- |personname %local.gen.char.class;">
-
-<!ENTITY % local.link.char.class "">
-<!ENTITY % link.char.class
- "link|olink|ulink %local.link.char.class;">
-
-<!-- The DocBook TC may produce an official EBNF module for DocBook. -->
-<!-- This PE provides the hook by which it can be inserted into the DTD. -->
-<!ENTITY % ebnf.inline.hook "">
-
-<!ENTITY % local.tech.char.class "">
-<!ENTITY % tech.char.class
- "action|application
- |classname|methodname|interfacename|exceptionname
- |ooclass|oointerface|ooexception
- |package
- |command|computeroutput
- |database|email|envar|errorcode|errorname|errortype|errortext|filename
- |function|guibutton|guiicon|guilabel|guimenu|guimenuitem
- |guisubmenu|hardware|interface|keycap
- |keycode|keycombo|keysym|literal|code|constant|markup|medialabel
- |menuchoice|mousebutton|option|optional|parameter
- |prompt|property|replaceable|returnvalue|sgmltag|structfield
- |structname|symbol|systemitem|uri|token|type|userinput|varname
- %ebnf.inline.hook;
- %local.tech.char.class;">
-
-<!ENTITY % local.base.char.class "">
-<!ENTITY % base.char.class
- "anchor %local.base.char.class;">
-
-<!ENTITY % local.docinfo.char.class "">
-<!ENTITY % docinfo.char.class
- "author|authorinitials|corpauthor|corpcredit|modespec|othercredit
- |productname|productnumber|revhistory
- %local.docinfo.char.class;">
-
-<!ENTITY % local.other.char.class "">
-<!ENTITY % other.char.class
- "remark|subscript|superscript %local.other.char.class;">
-
-<!ENTITY % local.inlineobj.char.class "">
-<!ENTITY % inlineobj.char.class
- "inlinegraphic|inlinemediaobject|inlineequation %local.inlineobj.char.class;">
-
-<!-- ...................................................................... -->
-<!-- Entities for content models .......................................... -->
-
-<!ENTITY % formalobject.title.content "title, titleabbrev?">
-
-<!-- Redeclaration placeholder ............................................ -->
-
-<!-- For redeclaring entities that are declared after this point while
- retaining their references to the entities that are declared before
- this point -->
-
-<![%dbpool.redecl.module;[
-<!-- Defining rdbpool here makes some buggy XML parsers happy. -->
-<!ENTITY % rdbpool "">
-%rdbpool;
-<!--end of dbpool.redecl.module-->]]>
-
-<!-- Object-level mixtures ................................................ -->
-
-<!--
- list admn line synp para infm form cmpd gen desc
-Component mixture X X X X X X X X X X
-Sidebar mixture X X X X X X X a X
-Footnote mixture X X X X X
-Example mixture X X X X X
-Highlights mixture X X X
-Paragraph mixture X X X X
-Admonition mixture X X X X X X b c
-Figure mixture X X X
-Table entry mixture X X X X d
-Glossary def mixture X X X X X e
-Legal notice mixture X X X X f
-
-a. Just Procedure; not Sidebar itself or MsgSet.
-b. No MsgSet.
-c. No Highlights.
-d. Just Graphic; no other informal objects.
-e. No Anchor, BridgeHead, or Highlights.
-f. Just BlockQuote; no other informal objects.
--->
-
-<!ENTITY % local.component.mix "">
-<!ENTITY % component.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |%compound.class;
- |%genobj.class; |%descobj.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.component.mix;">
-
-<!ENTITY % local.sidebar.mix "">
-<!ENTITY % sidebar.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |procedure
- |%genobj.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.sidebar.mix;">
-
-<!ENTITY % local.qandaset.mix "">
-<!ENTITY % qandaset.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |procedure
- |%genobj.class;
- |%ndxterm.class;
- %forms.hook;
- %local.qandaset.mix;">
-
-<!ENTITY % local.revdescription.mix "">
-<!ENTITY % revdescription.mix
- "%list.class; |%admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |procedure
- |%genobj.class;
- |%ndxterm.class;
- %local.revdescription.mix;">
-
-<!ENTITY % local.footnote.mix "">
-<!ENTITY % footnote.mix
- "%list.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- %local.footnote.mix;">
-
-<!ENTITY % local.example.mix "">
-<!ENTITY % example.mix
- "%list.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%ndxterm.class; |beginpage
- |procedure
- %forms.hook;
- %local.example.mix;">
-
-<!ENTITY % local.highlights.mix "">
-<!ENTITY % highlights.mix
- "%list.class; |%admon.class;
- |%para.class;
- |%ndxterm.class;
- %local.highlights.mix;">
-
-<!-- %formal.class; is explicitly excluded from many contexts in which
- paragraphs are used -->
-<!ENTITY % local.para.mix "">
-<!ENTITY % para.mix
- "%list.class; |%admon.class;
- |%linespecific.class;
- |%informal.class;
- |%formal.class;
- %local.para.mix;">
-
-<!ENTITY % local.admon.mix "">
-<!ENTITY % admon.mix
- "%list.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class; |procedure|sidebar
- |anchor|bridgehead|remark
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.admon.mix;">
-
-<!ENTITY % local.figure.mix "">
-<!ENTITY % figure.mix
- "%linespecific.class; |%synop.class;
- |%informal.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.figure.mix;">
-
-<!ENTITY % local.tabentry.mix "">
-<!ENTITY % tabentry.mix
- "%list.class; |%admon.class;
- |%linespecific.class;
- |%para.class; |graphic|mediaobject
- %forms.hook;
- %local.tabentry.mix;">
-
-<!ENTITY % local.glossdef.mix "">
-<!ENTITY % glossdef.mix
- "%list.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%formal.class;
- |remark
- |%ndxterm.class; |beginpage
- %local.glossdef.mix;">
-
-<!ENTITY % local.legalnotice.mix "">
-<!ENTITY % legalnotice.mix
- "%list.class; |%admon.class;
- |%linespecific.class;
- |%para.class; |blockquote
- |%ndxterm.class; |beginpage
- %local.legalnotice.mix;">
-
-<!ENTITY % local.textobject.mix "">
-<!ENTITY % textobject.mix
- "%list.class; |%admon.class;
- |%linespecific.class;
- |%para.class; |blockquote
- %local.textobject.mix;">
-
-<!ENTITY % local.mediaobject.mix "">
-<!ENTITY % mediaobject.mix
- "videoobject|audioobject|imageobject|imageobjectco|textobject %local.mediaobject.mix;">
-
-<!ENTITY % local.listpreamble.mix "">
-<!ENTITY % listpreamble.mix
- " %admon.class;
- |%linespecific.class; |%synop.class;
- |%para.class; |%informal.class;
- |%genobj.class; |%descobj.class;
- |%ndxterm.class; |beginpage
- %forms.hook;
- %local.listpreamble.mix;">
-
-<!-- Character-level mixtures ............................................. -->
-
-<![%sgml.features;[
-<!ENTITY % local.ubiq.mix "">
-<!ENTITY % ubiq.mix "%ndxterm.class;|beginpage %local.ubiq.mix;">
-
-<!ENTITY % ubiq.exclusion "-(%ubiq.mix)">
-<!ENTITY % ubiq.inclusion "+(%ubiq.mix)">
-
-<!ENTITY % footnote.exclusion "-(footnote|%formal.class;)">
-<!ENTITY % highlights.exclusion "-(%ubiq.mix;|%formal.class;)">
-<!ENTITY % admon.exclusion "-(%admon.class;)">
-<!ENTITY % formal.exclusion "-(%formal.class;)">
-<!ENTITY % acronym.exclusion "-(acronym)">
-<!ENTITY % beginpage.exclusion "-(beginpage)">
-<!ENTITY % ndxterm.exclusion "-(%ndxterm.class;)">
-<!ENTITY % blockquote.exclusion "-(epigraph)">
-<!ENTITY % remark.exclusion "-(remark|%ubiq.mix;)">
-<!ENTITY % glossterm.exclusion "-(glossterm)">
-<!ENTITY % links.exclusion "-(link|olink|ulink|xref|biblioref)">
-]]><!-- sgml.features -->
-
-<!-- not [sgml.features[ -->
-<!ENTITY % local.ubiq.mix "">
-<!ENTITY % ubiq.mix "">
-
-<!ENTITY % ubiq.exclusion "">
-<!ENTITY % ubiq.inclusion "">
-
-<!ENTITY % footnote.exclusion "">
-<!ENTITY % highlights.exclusion "">
-<!ENTITY % admon.exclusion "">
-<!ENTITY % formal.exclusion "">
-<!ENTITY % acronym.exclusion "">
-<!ENTITY % beginpage.exclusion "">
-<!ENTITY % ndxterm.exclusion "">
-<!ENTITY % blockquote.exclusion "">
-<!ENTITY % remark.exclusion "">
-<!ENTITY % glossterm.exclusion "">
-<!ENTITY % links.exclusion "">
-<!-- ]] not sgml.features -->
-
-<!--
- #PCD xref word link cptr base dnfo othr inob (synop)
-para.char.mix X X X X X X X X X
-title.char.mix X X X X X X X X X
-ndxterm.char.mix X X X X X X X X a
-cptr.char.mix X X X X X a
-smallcptr.char.mix X b a
-word.char.mix X c X X X a
-docinfo.char.mix X d X b X a
-
-a. Just InlineGraphic; no InlineEquation.
-b. Just Replaceable; no other computer terms.
-c. Just Emphasis and Trademark; no other word elements.
-d. Just Acronym, Emphasis, and Trademark; no other word elements.
--->
-
-<!ENTITY % local.para.char.mix "">
-<!ENTITY % para.char.mix
- "#PCDATA
- |%xref.char.class; |%gen.char.class;
- |%link.char.class; |%tech.char.class;
- |%base.char.class; |%docinfo.char.class;
- |%other.char.class; |%inlineobj.char.class;
- |%synop.class;
- |%ndxterm.class; |beginpage
- %forminlines.hook;
- %local.para.char.mix;">
-
-<!ENTITY % local.title.char.mix "">
-<!ENTITY % title.char.mix
- "#PCDATA
- |%xref.char.class; |%gen.char.class;
- |%link.char.class; |%tech.char.class;
- |%base.char.class; |%docinfo.char.class;
- |%other.char.class; |%inlineobj.char.class;
- |%ndxterm.class;
- %local.title.char.mix;">
-
-<!ENTITY % local.ndxterm.char.mix "">
-<!ENTITY % ndxterm.char.mix
- "#PCDATA
- |%xref.char.class; |%gen.char.class;
- |%link.char.class; |%tech.char.class;
- |%base.char.class; |%docinfo.char.class;
- |%other.char.class; |inlinegraphic|inlinemediaobject
- %local.ndxterm.char.mix;">
-
-<!ENTITY % local.cptr.char.mix "">
-<!ENTITY % cptr.char.mix
- "#PCDATA
- |%link.char.class; |%tech.char.class;
- |%base.char.class;
- |%other.char.class; |inlinegraphic|inlinemediaobject
- |%ndxterm.class; |beginpage
- %local.cptr.char.mix;">
-
-<!ENTITY % local.smallcptr.char.mix "">
-<!ENTITY % smallcptr.char.mix
- "#PCDATA
- |replaceable
- |inlinegraphic|inlinemediaobject
- |%ndxterm.class; |beginpage
- %local.smallcptr.char.mix;">
-
-<!ENTITY % local.word.char.mix "">
-<!ENTITY % word.char.mix
- "#PCDATA
- |acronym|emphasis|trademark
- |%link.char.class;
- |%base.char.class;
- |%other.char.class; |inlinegraphic|inlinemediaobject
- |%ndxterm.class; |beginpage
- %local.word.char.mix;">
-
-<!ENTITY % local.docinfo.char.mix "">
-<!ENTITY % docinfo.char.mix
- "#PCDATA
- |%link.char.class;
- |emphasis|trademark
- |replaceable
- |%other.char.class; |inlinegraphic|inlinemediaobject
- |%ndxterm.class;
- %local.docinfo.char.mix;">
-<!--ENTITY % bibliocomponent.mix (see Bibliographic section, below)-->
-<!--ENTITY % person.ident.mix (see Bibliographic section, below)-->
-
-<!-- ...................................................................... -->
-<!-- Entities for attributes and attribute components ..................... -->
-
-<!-- Effectivity attributes ............................................... -->
-
-
-<!-- Arch: Computer or chip architecture to which element applies; no
- default -->
-
-<!ENTITY % arch.attrib
- "arch CDATA #IMPLIED">
-
-<!-- Condition: General-purpose effectivity attribute -->
-
-<!ENTITY % condition.attrib
- "condition CDATA #IMPLIED">
-
-<!-- Conformance: Standards conformance characteristics -->
-
-<!ENTITY % conformance.attrib
- "conformance NMTOKENS #IMPLIED">
-
-
-<!-- OS: Operating system to which element applies; no default -->
-
-<!ENTITY % os.attrib
- "os CDATA #IMPLIED">
-
-
-<!-- Revision: Editorial revision to which element belongs; no default -->
-
-<!ENTITY % revision.attrib
- "revision CDATA #IMPLIED">
-
-<!-- Security: Security classification; no default -->
-
-<!ENTITY % security.attrib
- "security CDATA #IMPLIED">
-
-<!-- UserLevel: Level of user experience to which element applies; no
- default -->
-
-<!ENTITY % userlevel.attrib
- "userlevel CDATA #IMPLIED">
-
-<!-- Vendor: Computer vendor to which element applies; no default -->
-
-<!ENTITY % vendor.attrib
- "vendor CDATA #IMPLIED">
-
-<!-- Wordsize: Computer word size (32 bit, 64 bit, etc.); no default -->
-
-<!ENTITY % wordsize.attrib
- "wordsize CDATA #IMPLIED">
-
-<!ENTITY % local.effectivity.attrib "">
-<!ENTITY % effectivity.attrib
- "%arch.attrib;
- %condition.attrib;
- %conformance.attrib;
- %os.attrib;
- %revision.attrib;
- %security.attrib;
- %userlevel.attrib;
- %vendor.attrib;
- %wordsize.attrib;
- %local.effectivity.attrib;"
->
-
-<!-- Common attributes .................................................... -->
-
-
-<!-- Id: Unique identifier of element; no default -->
-
-<!ENTITY % id.attrib
- "id ID #IMPLIED">
-
-
-<!-- Id: Unique identifier of element; a value must be supplied; no
- default -->
-
-<!ENTITY % idreq.attrib
- "id ID #REQUIRED">
-
-
-<!-- Lang: Indicator of language in which element is written, for
- translation, character set management, etc.; no default -->
-
-<!ENTITY % lang.attrib
- "lang CDATA #IMPLIED">
-
-
-<!-- Remap: Previous role of element before conversion; no default -->
-
-<!ENTITY % remap.attrib
- "remap CDATA #IMPLIED">
-
-
-<!-- Role: New role of element in local environment; no default -->
-
-<!ENTITY % role.attrib
- "role CDATA #IMPLIED">
-
-
-<!-- XRefLabel: Alternate labeling string for XRef text generation;
- default is usually title or other appropriate label text already
- contained in element -->
-
-<!ENTITY % xreflabel.attrib
- "xreflabel CDATA #IMPLIED">
-
-
-<!-- RevisionFlag: Revision status of element; default is that element
- wasn't revised -->
-
-<!ENTITY % revisionflag.attrib
- "revisionflag (changed
- |added
- |deleted
- |off) #IMPLIED">
-
-<!ENTITY % local.common.attrib "">
-
-<!-- dir: Bidirectional override -->
-
-<!ENTITY % dir.attrib
- "dir (ltr
- |rtl
- |lro
- |rlo) #IMPLIED">
-
-<!-- xml:base: base URI -->
-
-<![%sgml.features;[
-<!ENTITY % xml-base.attrib "">
-]]>
-<!ENTITY % xml-base.attrib
- "xml:base CDATA #IMPLIED">
-
-<!-- Role is included explicitly on each element -->
-
-<!ENTITY % common.attrib
- "%id.attrib;
- %lang.attrib;
- %remap.attrib;
- %xreflabel.attrib;
- %revisionflag.attrib;
- %effectivity.attrib;
- %dir.attrib;
- %xml-base.attrib;
- %local.common.attrib;"
->
-
-<!-- Role is included explicitly on each element -->
-
-<!ENTITY % idreq.common.attrib
- "%idreq.attrib;
- %lang.attrib;
- %remap.attrib;
- %xreflabel.attrib;
- %revisionflag.attrib;
- %effectivity.attrib;
- %dir.attrib;
- %xml-base.attrib;
- %local.common.attrib;"
->
-
-<!-- Semi-common attributes and other attribute entities .................. -->
-
-<!ENTITY % local.graphics.attrib "">
-
-<!-- EntityRef: Name of an external entity containing the content
- of the graphic -->
-<!-- FileRef: Filename, qualified by a pathname if desired,
- designating the file containing the content of the graphic -->
-<!-- Format: Notation of the element content, if any -->
-<!-- SrcCredit: Information about the source of the Graphic -->
-<!-- Width: Same as CALS reprowid (desired width) -->
-<!-- Depth: Same as CALS reprodep (desired depth) -->
-<!-- Align: Same as CALS hplace with 'none' removed; #IMPLIED means
- application-specific -->
-<!-- Scale: Conflation of CALS hscale and vscale -->
-<!-- Scalefit: Same as CALS scalefit -->
-
-<!ENTITY % graphics.attrib
- "
- entityref ENTITY #IMPLIED
- fileref CDATA #IMPLIED
- format (%notation.class;) #IMPLIED
- srccredit CDATA #IMPLIED
- width CDATA #IMPLIED
- contentwidth CDATA #IMPLIED
- depth CDATA #IMPLIED
- contentdepth CDATA #IMPLIED
- align (left
- |right
- |center) #IMPLIED
- valign (top
- |middle
- |bottom) #IMPLIED
- scale CDATA #IMPLIED
- scalefit %yesorno.attvals;
- #IMPLIED
- %local.graphics.attrib;"
->
-
-<!ENTITY % local.keyaction.attrib "">
-
-<!-- Action: Key combination type; default is unspecified if one
- child element, Simul if there is more than one; if value is
- Other, the OtherAction attribute must have a nonempty value -->
-<!-- OtherAction: User-defined key combination type -->
-
-<!ENTITY % keyaction.attrib
- "
- action (click
- |double-click
- |press
- |seq
- |simul
- |other) #IMPLIED
- otheraction CDATA #IMPLIED
- %local.keyaction.attrib;"
->
-
-
-<!-- Label: Identifying number or string; default is usually the
- appropriate number or string autogenerated by a formatter -->
-
-<!ENTITY % label.attrib
- "label CDATA #IMPLIED">
-
-
-<!-- xml:space: whitespace treatment -->
-
-<![%sgml.features;[
-<!ENTITY % xml-space.attrib "">
-]]>
-<!ENTITY % xml-space.attrib
- "xml:space (preserve) #IMPLIED">
-
-<!-- Format: whether element is assumed to contain significant white
- space -->
-
-<!ENTITY % linespecific.attrib
- "format NOTATION
- (linespecific) 'linespecific'
- %xml-space.attrib;
- linenumbering (numbered|unnumbered) #IMPLIED
- continuation (continues|restarts) #IMPLIED
- startinglinenumber CDATA #IMPLIED
- language CDATA #IMPLIED">
-
-<!-- Linkend: link to related information; no default -->
-
-<!ENTITY % linkend.attrib
- "linkend IDREF #IMPLIED">
-
-
-<!-- Linkend: required link to related information -->
-
-<!ENTITY % linkendreq.attrib
- "linkend IDREF #REQUIRED">
-
-
-<!-- Linkends: link to one or more sets of related information; no
- default -->
-
-<!ENTITY % linkends.attrib
- "linkends IDREFS #IMPLIED">
-
-
-<!ENTITY % local.mark.attrib "">
-<!ENTITY % mark.attrib
- "mark CDATA #IMPLIED
- %local.mark.attrib;"
->
-
-
-<!-- MoreInfo: whether element's content has an associated RefEntry -->
-
-<!ENTITY % moreinfo.attrib
- "moreinfo (refentry|none) 'none'">
-
-
-<!-- Pagenum: number of page on which element appears; no default -->
-
-<!ENTITY % pagenum.attrib
- "pagenum CDATA #IMPLIED">
-
-<!ENTITY % local.status.attrib "">
-
-<!-- Status: Editorial or publication status of the element
- it applies to, such as "in review" or "approved for distribution" -->
-
-<!ENTITY % status.attrib
- "status CDATA #IMPLIED
- %local.status.attrib;"
->
-
-
-<!-- Width: width of the longest line in the element to which it
- pertains, in number of characters -->
-
-<!ENTITY % width.attrib
- "width CDATA #IMPLIED">
-
-<!-- ...................................................................... -->
-<!-- Title elements ....................................................... -->
-
-<!ENTITY % title.module "INCLUDE">
-<![%title.module;[
-<!ENTITY % local.title.attrib "">
-<!ENTITY % title.role.attrib "%role.attrib;">
-
-<!ENTITY % title.element "INCLUDE">
-<![%title.element;[
-<!--doc:The text of the title of a section of a document or of a formal block-level element.-->
-<!ELEMENT title %ho; (%title.char.mix;)*>
-<!--end of title.element-->]]>
-
-<!ENTITY % title.attlist "INCLUDE">
-<![%title.attlist;[
-<!ATTLIST title
- %pagenum.attrib;
- %common.attrib;
- %title.role.attrib;
- %local.title.attrib;
->
-<!--end of title.attlist-->]]>
-<!--end of title.module-->]]>
-
-<!ENTITY % titleabbrev.module "INCLUDE">
-<![%titleabbrev.module;[
-<!ENTITY % local.titleabbrev.attrib "">
-<!ENTITY % titleabbrev.role.attrib "%role.attrib;">
-
-<!ENTITY % titleabbrev.element "INCLUDE">
-<![%titleabbrev.element;[
-<!--doc:The abbreviation of a Title.-->
-<!ELEMENT titleabbrev %ho; (%title.char.mix;)*>
-<!--end of titleabbrev.element-->]]>
-
-<!ENTITY % titleabbrev.attlist "INCLUDE">
-<![%titleabbrev.attlist;[
-<!ATTLIST titleabbrev
- %common.attrib;
- %titleabbrev.role.attrib;
- %local.titleabbrev.attrib;
->
-<!--end of titleabbrev.attlist-->]]>
-<!--end of titleabbrev.module-->]]>
-
-<!ENTITY % subtitle.module "INCLUDE">
-<![%subtitle.module;[
-<!ENTITY % local.subtitle.attrib "">
-<!ENTITY % subtitle.role.attrib "%role.attrib;">
-
-<!ENTITY % subtitle.element "INCLUDE">
-<![%subtitle.element;[
-<!--doc:The subtitle of a document.-->
-<!ELEMENT subtitle %ho; (%title.char.mix;)*>
-<!--end of subtitle.element-->]]>
-
-<!ENTITY % subtitle.attlist "INCLUDE">
-<![%subtitle.attlist;[
-<!ATTLIST subtitle
- %common.attrib;
- %subtitle.role.attrib;
- %local.subtitle.attrib;
->
-<!--end of subtitle.attlist-->]]>
-<!--end of subtitle.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Bibliographic entities and elements .................................. -->
-
-<!-- The bibliographic elements are typically used in the document
- hierarchy. They do not appear in content models of information
- pool elements. See also the document information elements,
- below. -->
-
-<!ENTITY % local.person.ident.mix "">
-<!ENTITY % person.ident.mix
- "honorific|firstname|surname|lineage|othername|affiliation
- |authorblurb|contrib %local.person.ident.mix;">
-
-<!ENTITY % local.bibliocomponent.mix "">
-<!ENTITY % bibliocomponent.mix
- "abbrev|abstract|address|artpagenums|author
- |authorgroup|authorinitials|bibliomisc|biblioset
- |collab|confgroup|contractnum|contractsponsor
- |copyright|corpauthor|corpname|corpcredit|date|edition
- |editor|invpartnumber|isbn|issn|issuenum|orgname
- |biblioid|citebiblioid|bibliosource|bibliorelation|bibliocoverage
- |othercredit|pagenums|printhistory|productname
- |productnumber|pubdate|publisher|publishername
- |pubsnumber|releaseinfo|revhistory|seriesvolnums
- |subtitle|title|titleabbrev|volumenum|citetitle
- |personname|%person.ident.mix;
- |%ndxterm.class;
- %local.bibliocomponent.mix;">
-
-<!-- I don't think this is well placed, but it needs to be here because of -->
-<!-- the reference to bibliocomponent.mix -->
-<!ENTITY % local.info.class "">
-<!ENTITY % info.class
- "graphic | mediaobject | legalnotice | modespec
- | subjectset | keywordset | itermset | %bibliocomponent.mix;
- %local.info.class;">
-
-
-<!-- BiblioList ........................ -->
-
-<!ENTITY % bibliolist.module "INCLUDE">
-<![%bibliolist.module;[
-<!ENTITY % local.bibliolist.attrib "">
-<!ENTITY % bibliolist.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliolist.element "INCLUDE">
-<![%bibliolist.element;[
-<!--doc:A wrapper for a set of bibliography entries.-->
-<!ELEMENT bibliolist %ho; (blockinfo?, (%formalobject.title.content;)?,
- (biblioentry|bibliomixed)+)>
-<!--end of bibliolist.element-->]]>
-
-<!ENTITY % bibliolist.attlist "INCLUDE">
-<![%bibliolist.attlist;[
-<!ATTLIST bibliolist
- %common.attrib;
- %bibliolist.role.attrib;
- %local.bibliolist.attrib;
->
-<!--end of bibliolist.attlist-->]]>
-<!--end of bibliolist.module-->]]>
-
-<!ENTITY % biblioentry.module "INCLUDE">
-<![%biblioentry.module;[
-<!ENTITY % local.biblioentry.attrib "">
-<!ENTITY % biblioentry.role.attrib "%role.attrib;">
-
-<!ENTITY % biblioentry.element "INCLUDE">
-<![%biblioentry.element;[
-<!--doc:An entry in a Bibliography.-->
-<!ELEMENT biblioentry %ho; ((articleinfo | (%bibliocomponent.mix;))+)
- %ubiq.exclusion;>
-<!--end of biblioentry.element-->]]>
-
-<!ENTITY % biblioentry.attlist "INCLUDE">
-<![%biblioentry.attlist;[
-<!ATTLIST biblioentry
- %common.attrib;
- %biblioentry.role.attrib;
- %local.biblioentry.attrib;
->
-<!--end of biblioentry.attlist-->]]>
-<!--end of biblioentry.module-->]]>
-
-<!ENTITY % bibliomixed.module "INCLUDE">
-<![%bibliomixed.module;[
-<!ENTITY % local.bibliomixed.attrib "">
-<!ENTITY % bibliomixed.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliomixed.element "INCLUDE">
-<![%bibliomixed.element;[
-<!--doc:An entry in a Bibliography.-->
-<!ELEMENT bibliomixed %ho; (#PCDATA | %bibliocomponent.mix; | bibliomset)*
- %ubiq.exclusion;>
-<!--end of bibliomixed.element-->]]>
-
-<!ENTITY % bibliomixed.attlist "INCLUDE">
-<![%bibliomixed.attlist;[
-<!ATTLIST bibliomixed
- %common.attrib;
- %bibliomixed.role.attrib;
- %local.bibliomixed.attrib;
->
-<!--end of bibliomixed.attlist-->]]>
-<!--end of bibliomixed.module-->]]>
-
-<!ENTITY % articleinfo.module "INCLUDE">
-<![%articleinfo.module;[
-<!ENTITY % local.articleinfo.attrib "">
-<!ENTITY % articleinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % articleinfo.element "INCLUDE">
-<![%articleinfo.element;[
-<!--doc:Meta-information for an Article.-->
-<!ELEMENT articleinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of articleinfo.element-->]]>
-
-<!ENTITY % articleinfo.attlist "INCLUDE">
-<![%articleinfo.attlist;[
-<!ATTLIST articleinfo
- %common.attrib;
- %articleinfo.role.attrib;
- %local.articleinfo.attrib;
->
-<!--end of articleinfo.attlist-->]]>
-<!--end of articleinfo.module-->]]>
-
-<!ENTITY % biblioset.module "INCLUDE">
-<![%biblioset.module;[
-<!ENTITY % local.biblioset.attrib "">
-<!ENTITY % biblioset.role.attrib "%role.attrib;">
-
-<!ENTITY % biblioset.element "INCLUDE">
-<![%biblioset.element;[
-<!--doc:A "raw" container for related bibliographic information.-->
-<!ELEMENT biblioset %ho; ((%bibliocomponent.mix;)+)
- %ubiq.exclusion;>
-<!--end of biblioset.element-->]]>
-
-<!-- Relation: Relationship of elements contained within BiblioSet -->
-
-
-<!ENTITY % biblioset.attlist "INCLUDE">
-<![%biblioset.attlist;[
-<!ATTLIST biblioset
- relation CDATA #IMPLIED
- %common.attrib;
- %biblioset.role.attrib;
- %local.biblioset.attrib;
->
-<!--end of biblioset.attlist-->]]>
-<!--end of biblioset.module-->]]>
-
-<!ENTITY % bibliomset.module "INCLUDE">
-<![%bibliomset.module;[
-<!ENTITY % bibliomset.role.attrib "%role.attrib;">
-<!ENTITY % local.bibliomset.attrib "">
-
-<!ENTITY % bibliomset.element "INCLUDE">
-<![%bibliomset.element;[
-<!--doc:A "cooked" container for related bibliographic information.-->
-<!ELEMENT bibliomset %ho; (#PCDATA | %bibliocomponent.mix; | bibliomset)*
- %ubiq.exclusion;>
-<!--end of bibliomset.element-->]]>
-
-<!-- Relation: Relationship of elements contained within BiblioMSet -->
-
-
-<!ENTITY % bibliomset.attlist "INCLUDE">
-<![%bibliomset.attlist;[
-<!ATTLIST bibliomset
- relation CDATA #IMPLIED
- %common.attrib;
- %bibliomset.role.attrib;
- %local.bibliomset.attrib;
->
-<!--end of bibliomset.attlist-->]]>
-<!--end of bibliomset.module-->]]>
-
-<!ENTITY % bibliomisc.module "INCLUDE">
-<![%bibliomisc.module;[
-<!ENTITY % local.bibliomisc.attrib "">
-<!ENTITY % bibliomisc.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliomisc.element "INCLUDE">
-<![%bibliomisc.element;[
-<!--doc:Untyped bibliographic information.-->
-<!ELEMENT bibliomisc %ho; (%para.char.mix;)*>
-<!--end of bibliomisc.element-->]]>
-
-<!ENTITY % bibliomisc.attlist "INCLUDE">
-<![%bibliomisc.attlist;[
-<!ATTLIST bibliomisc
- %common.attrib;
- %bibliomisc.role.attrib;
- %local.bibliomisc.attrib;
->
-<!--end of bibliomisc.attlist-->]]>
-<!--end of bibliomisc.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Subject, Keyword, and ITermSet elements .............................. -->
-
-<!ENTITY % subjectset.content.module "INCLUDE">
-<![%subjectset.content.module;[
-<!ENTITY % subjectset.module "INCLUDE">
-<![%subjectset.module;[
-<!ENTITY % local.subjectset.attrib "">
-<!ENTITY % subjectset.role.attrib "%role.attrib;">
-
-<!ENTITY % subjectset.element "INCLUDE">
-<![%subjectset.element;[
-<!--doc:A set of terms describing the subject matter of a document.-->
-<!ELEMENT subjectset %ho; (subject+)>
-<!--end of subjectset.element-->]]>
-
-<!-- Scheme: Controlled vocabulary employed in SubjectTerms -->
-
-
-<!ENTITY % subjectset.attlist "INCLUDE">
-<![%subjectset.attlist;[
-<!ATTLIST subjectset
- scheme NMTOKEN #IMPLIED
- %common.attrib;
- %subjectset.role.attrib;
- %local.subjectset.attrib;
->
-<!--end of subjectset.attlist-->]]>
-<!--end of subjectset.module-->]]>
-
-<!ENTITY % subject.module "INCLUDE">
-<![%subject.module;[
-<!ENTITY % local.subject.attrib "">
-<!ENTITY % subject.role.attrib "%role.attrib;">
-
-<!ENTITY % subject.element "INCLUDE">
-<![%subject.element;[
-<!--doc:One of a group of terms describing the subject matter of a document.-->
-<!ELEMENT subject %ho; (subjectterm+)>
-<!--end of subject.element-->]]>
-
-<!-- Weight: Ranking of this group of SubjectTerms relative
- to others, 0 is low, no highest value specified -->
-
-
-<!ENTITY % subject.attlist "INCLUDE">
-<![%subject.attlist;[
-<!ATTLIST subject
- weight CDATA #IMPLIED
- %common.attrib;
- %subject.role.attrib;
- %local.subject.attrib;
->
-<!--end of subject.attlist-->]]>
-<!--end of subject.module-->]]>
-
-<!ENTITY % subjectterm.module "INCLUDE">
-<![%subjectterm.module;[
-<!ENTITY % local.subjectterm.attrib "">
-<!ENTITY % subjectterm.role.attrib "%role.attrib;">
-
-<!ENTITY % subjectterm.element "INCLUDE">
-<![%subjectterm.element;[
-<!--doc:A term in a group of terms describing the subject matter of a document.-->
-<!ELEMENT subjectterm %ho; (#PCDATA)>
-<!--end of subjectterm.element-->]]>
-
-<!ENTITY % subjectterm.attlist "INCLUDE">
-<![%subjectterm.attlist;[
-<!ATTLIST subjectterm
- %common.attrib;
- %subjectterm.role.attrib;
- %local.subjectterm.attrib;
->
-<!--end of subjectterm.attlist-->]]>
-<!--end of subjectterm.module-->]]>
-<!--end of subjectset.content.module-->]]>
-
-<!ENTITY % keywordset.content.module "INCLUDE">
-<![%keywordset.content.module;[
-<!ENTITY % keywordset.module "INCLUDE">
-<![%keywordset.module;[
-<!ENTITY % local.keywordset.attrib "">
-<!ENTITY % keywordset.role.attrib "%role.attrib;">
-
-<!ENTITY % keywordset.element "INCLUDE">
-<![%keywordset.element;[
-<!--doc:A set of keywords describing the content of a document.-->
-<!ELEMENT keywordset %ho; (keyword+)>
-<!--end of keywordset.element-->]]>
-
-<!ENTITY % keywordset.attlist "INCLUDE">
-<![%keywordset.attlist;[
-<!ATTLIST keywordset
- %common.attrib;
- %keywordset.role.attrib;
- %local.keywordset.attrib;
->
-<!--end of keywordset.attlist-->]]>
-<!--end of keywordset.module-->]]>
-
-<!ENTITY % keyword.module "INCLUDE">
-<![%keyword.module;[
-<!ENTITY % local.keyword.attrib "">
-<!ENTITY % keyword.role.attrib "%role.attrib;">
-
-<!ENTITY % keyword.element "INCLUDE">
-<![%keyword.element;[
-<!--doc:One of a set of keywords describing the content of a document.-->
-<!ELEMENT keyword %ho; (#PCDATA)>
-<!--end of keyword.element-->]]>
-
-<!ENTITY % keyword.attlist "INCLUDE">
-<![%keyword.attlist;[
-<!ATTLIST keyword
- %common.attrib;
- %keyword.role.attrib;
- %local.keyword.attrib;
->
-<!--end of keyword.attlist-->]]>
-<!--end of keyword.module-->]]>
-<!--end of keywordset.content.module-->]]>
-
-<!ENTITY % itermset.module "INCLUDE">
-<![%itermset.module;[
-<!ENTITY % local.itermset.attrib "">
-<!ENTITY % itermset.role.attrib "%role.attrib;">
-
-<!ENTITY % itermset.element "INCLUDE">
-<![%itermset.element;[
-<!--doc:A set of index terms in the meta-information of a document.-->
-<!ELEMENT itermset %ho; (indexterm+)>
-<!--end of itermset.element-->]]>
-
-<!ENTITY % itermset.attlist "INCLUDE">
-<![%itermset.attlist;[
-<!ATTLIST itermset
- %common.attrib;
- %itermset.role.attrib;
- %local.itermset.attrib;
->
-<!--end of itermset.attlist-->]]>
-<!--end of itermset.module-->]]>
-
-<!-- Bibliographic info for "blocks" -->
-
-<!ENTITY % blockinfo.module "INCLUDE">
-<![ %blockinfo.module; [
-<!ENTITY % local.blockinfo.attrib "">
-<!ENTITY % blockinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % blockinfo.element "INCLUDE">
-<![ %blockinfo.element; [
-<!--doc:Meta-information for a block element.-->
-<!ELEMENT blockinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of blockinfo.element-->]]>
-
-<!ENTITY % blockinfo.attlist "INCLUDE">
-<![ %blockinfo.attlist; [
-<!ATTLIST blockinfo
- %common.attrib;
- %blockinfo.role.attrib;
- %local.blockinfo.attrib;
->
-<!--end of blockinfo.attlist-->]]>
-<!--end of blockinfo.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Compound (section-ish) elements ...................................... -->
-
-<!-- Message set ...................... -->
-
-<!ENTITY % msgset.content.module "INCLUDE">
-<![%msgset.content.module;[
-<!ENTITY % msgset.module "INCLUDE">
-<![%msgset.module;[
-<!ENTITY % local.msgset.attrib "">
-<!ENTITY % msgset.role.attrib "%role.attrib;">
-
-<!ENTITY % msgset.element "INCLUDE">
-<![%msgset.element;[
-<!--doc:A detailed set of messages, usually error messages.-->
-<!ELEMENT msgset %ho; (blockinfo?, (%formalobject.title.content;)?,
- (msgentry+|simplemsgentry+))>
-<!--end of msgset.element-->]]>
-
-<!ENTITY % msgset.attlist "INCLUDE">
-<![%msgset.attlist;[
-<!ATTLIST msgset
- %common.attrib;
- %msgset.role.attrib;
- %local.msgset.attrib;
->
-<!--end of msgset.attlist-->]]>
-<!--end of msgset.module-->]]>
-
-<!ENTITY % msgentry.module "INCLUDE">
-<![%msgentry.module;[
-<!ENTITY % local.msgentry.attrib "">
-<!ENTITY % msgentry.role.attrib "%role.attrib;">
-
-<!ENTITY % msgentry.element "INCLUDE">
-<![%msgentry.element;[
-<!--doc:A wrapper for an entry in a message set.-->
-<!ELEMENT msgentry %ho; (msg+, msginfo?, msgexplan*)>
-<!--end of msgentry.element-->]]>
-
-<!ENTITY % msgentry.attlist "INCLUDE">
-<![%msgentry.attlist;[
-<!ATTLIST msgentry
- %common.attrib;
- %msgentry.role.attrib;
- %local.msgentry.attrib;
->
-<!--end of msgentry.attlist-->]]>
-<!--end of msgentry.module-->]]>
-
-<!ENTITY % simplemsgentry.module "INCLUDE">
-<![ %simplemsgentry.module; [
-<!ENTITY % local.simplemsgentry.attrib "">
-<!ENTITY % simplemsgentry.role.attrib "%role.attrib;">
-
-<!ENTITY % simplemsgentry.element "INCLUDE">
-<![ %simplemsgentry.element; [
-<!--doc:A wrapper for a simpler entry in a message set.-->
-<!ELEMENT simplemsgentry %ho; (msgtext, msgexplan+)>
-<!--end of simplemsgentry.element-->]]>
-
-<!ENTITY % simplemsgentry.attlist "INCLUDE">
-<![ %simplemsgentry.attlist; [
-<!ATTLIST simplemsgentry
- audience CDATA #IMPLIED
- level CDATA #IMPLIED
- origin CDATA #IMPLIED
- %common.attrib;
- %simplemsgentry.role.attrib;
- %local.simplemsgentry.attrib;
->
-<!--end of simplemsgentry.attlist-->]]>
-<!--end of simplemsgentry.module-->]]>
-
-<!ENTITY % msg.module "INCLUDE">
-<![%msg.module;[
-<!ENTITY % local.msg.attrib "">
-<!ENTITY % msg.role.attrib "%role.attrib;">
-
-<!ENTITY % msg.element "INCLUDE">
-<![%msg.element;[
-<!--doc:A message in a message set.-->
-<!ELEMENT msg %ho; (title?, msgmain, (msgsub | msgrel)*)>
-<!--end of msg.element-->]]>
-
-<!ENTITY % msg.attlist "INCLUDE">
-<![%msg.attlist;[
-<!ATTLIST msg
- %common.attrib;
- %msg.role.attrib;
- %local.msg.attrib;
->
-<!--end of msg.attlist-->]]>
-<!--end of msg.module-->]]>
-
-<!ENTITY % msgmain.module "INCLUDE">
-<![%msgmain.module;[
-<!ENTITY % local.msgmain.attrib "">
-<!ENTITY % msgmain.role.attrib "%role.attrib;">
-
-<!ENTITY % msgmain.element "INCLUDE">
-<![%msgmain.element;[
-<!--doc:The primary component of a message in a message set.-->
-<!ELEMENT msgmain %ho; (title?, msgtext)>
-<!--end of msgmain.element-->]]>
-
-<!ENTITY % msgmain.attlist "INCLUDE">
-<![%msgmain.attlist;[
-<!ATTLIST msgmain
- %common.attrib;
- %msgmain.role.attrib;
- %local.msgmain.attrib;
->
-<!--end of msgmain.attlist-->]]>
-<!--end of msgmain.module-->]]>
-
-<!ENTITY % msgsub.module "INCLUDE">
-<![%msgsub.module;[
-<!ENTITY % local.msgsub.attrib "">
-<!ENTITY % msgsub.role.attrib "%role.attrib;">
-
-<!ENTITY % msgsub.element "INCLUDE">
-<![%msgsub.element;[
-<!--doc:A subcomponent of a message in a message set.-->
-<!ELEMENT msgsub %ho; (title?, msgtext)>
-<!--end of msgsub.element-->]]>
-
-<!ENTITY % msgsub.attlist "INCLUDE">
-<![%msgsub.attlist;[
-<!ATTLIST msgsub
- %common.attrib;
- %msgsub.role.attrib;
- %local.msgsub.attrib;
->
-<!--end of msgsub.attlist-->]]>
-<!--end of msgsub.module-->]]>
-
-<!ENTITY % msgrel.module "INCLUDE">
-<![%msgrel.module;[
-<!ENTITY % local.msgrel.attrib "">
-<!ENTITY % msgrel.role.attrib "%role.attrib;">
-
-<!ENTITY % msgrel.element "INCLUDE">
-<![%msgrel.element;[
-<!--doc:A related component of a message in a message set.-->
-<!ELEMENT msgrel %ho; (title?, msgtext)>
-<!--end of msgrel.element-->]]>
-
-<!ENTITY % msgrel.attlist "INCLUDE">
-<![%msgrel.attlist;[
-<!ATTLIST msgrel
- %common.attrib;
- %msgrel.role.attrib;
- %local.msgrel.attrib;
->
-<!--end of msgrel.attlist-->]]>
-<!--end of msgrel.module-->]]>
-
-<!-- MsgText (defined in the Inlines section, below)-->
-
-<!ENTITY % msginfo.module "INCLUDE">
-<![%msginfo.module;[
-<!ENTITY % local.msginfo.attrib "">
-<!ENTITY % msginfo.role.attrib "%role.attrib;">
-
-<!ENTITY % msginfo.element "INCLUDE">
-<![%msginfo.element;[
-<!--doc:Information about a message in a message set.-->
-<!ELEMENT msginfo %ho; ((msglevel | msgorig | msgaud)*)>
-<!--end of msginfo.element-->]]>
-
-<!ENTITY % msginfo.attlist "INCLUDE">
-<![%msginfo.attlist;[
-<!ATTLIST msginfo
- %common.attrib;
- %msginfo.role.attrib;
- %local.msginfo.attrib;
->
-<!--end of msginfo.attlist-->]]>
-<!--end of msginfo.module-->]]>
-
-<!ENTITY % msglevel.module "INCLUDE">
-<![%msglevel.module;[
-<!ENTITY % local.msglevel.attrib "">
-<!ENTITY % msglevel.role.attrib "%role.attrib;">
-
-<!ENTITY % msglevel.element "INCLUDE">
-<![%msglevel.element;[
-<!--doc:The level of importance or severity of a message in a message set.-->
-<!ELEMENT msglevel %ho; (%smallcptr.char.mix;)*>
-<!--end of msglevel.element-->]]>
-
-<!ENTITY % msglevel.attlist "INCLUDE">
-<![%msglevel.attlist;[
-<!ATTLIST msglevel
- %common.attrib;
- %msglevel.role.attrib;
- %local.msglevel.attrib;
->
-<!--end of msglevel.attlist-->]]>
-<!--end of msglevel.module-->]]>
-
-<!ENTITY % msgorig.module "INCLUDE">
-<![%msgorig.module;[
-<!ENTITY % local.msgorig.attrib "">
-<!ENTITY % msgorig.role.attrib "%role.attrib;">
-
-<!ENTITY % msgorig.element "INCLUDE">
-<![%msgorig.element;[
-<!--doc:The origin of a message in a message set.-->
-<!ELEMENT msgorig %ho; (%smallcptr.char.mix;)*>
-<!--end of msgorig.element-->]]>
-
-<!ENTITY % msgorig.attlist "INCLUDE">
-<![%msgorig.attlist;[
-<!ATTLIST msgorig
- %common.attrib;
- %msgorig.role.attrib;
- %local.msgorig.attrib;
->
-<!--end of msgorig.attlist-->]]>
-<!--end of msgorig.module-->]]>
-
-<!ENTITY % msgaud.module "INCLUDE">
-<![%msgaud.module;[
-<!ENTITY % local.msgaud.attrib "">
-<!ENTITY % msgaud.role.attrib "%role.attrib;">
-
-<!ENTITY % msgaud.element "INCLUDE">
-<![%msgaud.element;[
-<!--doc:The audience to which a message in a message set is relevant.-->
-<!ELEMENT msgaud %ho; (%para.char.mix;)*>
-<!--end of msgaud.element-->]]>
-
-<!ENTITY % msgaud.attlist "INCLUDE">
-<![%msgaud.attlist;[
-<!ATTLIST msgaud
- %common.attrib;
- %msgaud.role.attrib;
- %local.msgaud.attrib;
->
-<!--end of msgaud.attlist-->]]>
-<!--end of msgaud.module-->]]>
-
-<!ENTITY % msgexplan.module "INCLUDE">
-<![%msgexplan.module;[
-<!ENTITY % local.msgexplan.attrib "">
-<!ENTITY % msgexplan.role.attrib "%role.attrib;">
-
-<!ENTITY % msgexplan.element "INCLUDE">
-<![%msgexplan.element;[
-<!--doc:Explanatory material relating to a message in a message set.-->
-<!ELEMENT msgexplan %ho; (title?, (%component.mix;)+)>
-<!--end of msgexplan.element-->]]>
-
-<!ENTITY % msgexplan.attlist "INCLUDE">
-<![%msgexplan.attlist;[
-<!ATTLIST msgexplan
- %common.attrib;
- %msgexplan.role.attrib;
- %local.msgexplan.attrib;
->
-<!--end of msgexplan.attlist-->]]>
-<!--end of msgexplan.module-->]]>
-<!--end of msgset.content.module-->]]>
-
-<!ENTITY % task.content.module "INCLUDE">
-<![%task.content.module;[
-<!ENTITY % task.module "INCLUDE">
-<![%task.module;[
-<!ENTITY % local.task.attrib "">
-<!ENTITY % task.role.attrib "%role.attrib;">
-
-<!ENTITY % task.element "INCLUDE">
-<![%task.element;[
-<!--doc:A task to be completed.-->
-<!ELEMENT task %ho; (blockinfo?,(%ndxterm.class;)*,
- (%formalobject.title.content;),
- tasksummary?,
- taskprerequisites?,
- procedure,
- example*,
- taskrelated?)>
-<!--end of task.element-->]]>
-
-<!ENTITY % task.attlist "INCLUDE">
-<![%task.attlist;[
-<!ATTLIST task
- %common.attrib;
- %task.role.attrib;
- %local.task.attrib;
->
-<!--end of task.attlist-->]]>
-<!--end of task.module-->]]>
-
-<!ENTITY % tasksummary.module "INCLUDE">
-<![%tasksummary.module;[
-<!ENTITY % local.tasksummary.attrib "">
-<!ENTITY % tasksummary.role.attrib "%role.attrib;">
-
-<!ENTITY % tasksummary.element "INCLUDE">
-<![%tasksummary.element;[
-<!--doc:A summary of a task.-->
-<!ELEMENT tasksummary %ho; (blockinfo?,
- (%formalobject.title.content;)?,
- (%component.mix;)+)>
-<!--end of tasksummary.element-->]]>
-
-<!ENTITY % tasksummary.attlist "INCLUDE">
-<![%tasksummary.attlist;[
-<!ATTLIST tasksummary
- %common.attrib;
- %tasksummary.role.attrib;
- %local.tasksummary.attrib;
->
-<!--end of tasksummary.attlist-->]]>
-<!--end of tasksummary.module-->]]>
-
-<!ENTITY % taskprerequisites.module "INCLUDE">
-<![%taskprerequisites.module;[
-<!ENTITY % local.taskprerequisites.attrib "">
-<!ENTITY % taskprerequisites.role.attrib "%role.attrib;">
-
-<!ENTITY % taskprerequisites.element "INCLUDE">
-<![%taskprerequisites.element;[
-<!--doc:The prerequisites for a task.-->
-<!ELEMENT taskprerequisites %ho; (blockinfo?,
- (%formalobject.title.content;)?,
- (%component.mix;)+)>
-<!--end of taskprerequisites.element-->]]>
-
-<!ENTITY % taskprerequisites.attlist "INCLUDE">
-<![%taskprerequisites.attlist;[
-<!ATTLIST taskprerequisites
- %common.attrib;
- %taskprerequisites.role.attrib;
- %local.taskprerequisites.attrib;
->
-<!--end of taskprerequisites.attlist-->]]>
-<!--end of taskprerequisites.module-->]]>
-
-<!ENTITY % taskrelated.module "INCLUDE">
-<![%taskrelated.module;[
-<!ENTITY % local.taskrelated.attrib "">
-<!ENTITY % taskrelated.role.attrib "%role.attrib;">
-
-<!ENTITY % taskrelated.element "INCLUDE">
-<![%taskrelated.element;[
-<!--doc:Information related to a task.-->
-<!ELEMENT taskrelated %ho; (blockinfo?,
- (%formalobject.title.content;)?,
- (%component.mix;)+)>
-<!--end of taskrelated.element-->]]>
-
-<!ENTITY % taskrelated.attlist "INCLUDE">
-<![%taskrelated.attlist;[
-<!ATTLIST taskrelated
- %common.attrib;
- %taskrelated.role.attrib;
- %local.taskrelated.attrib;
->
-<!--end of taskrelated.attlist-->]]>
-<!--end of taskrelated.module-->]]>
-<!--end of task.content.module-->]]>
-
-<!-- QandASet ........................ -->
-<!ENTITY % qandaset.content.module "INCLUDE">
-<![ %qandaset.content.module; [
-<!ENTITY % qandaset.module "INCLUDE">
-<![ %qandaset.module; [
-<!ENTITY % local.qandaset.attrib "">
-<!ENTITY % qandaset.role.attrib "%role.attrib;">
-
-<!ENTITY % qandaset.element "INCLUDE">
-<![ %qandaset.element; [
-<!--doc:A question-and-answer set.-->
-<!ELEMENT qandaset %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%qandaset.mix;)*,
- (qandadiv+|qandaentry+))>
-<!--end of qandaset.element-->]]>
-
-<!ENTITY % qandaset.attlist "INCLUDE">
-<![ %qandaset.attlist; [
-<!ATTLIST qandaset
- defaultlabel (qanda|number|none) #IMPLIED
- %common.attrib;
- %qandaset.role.attrib;
- %local.qandaset.attrib;>
-<!--end of qandaset.attlist-->]]>
-<!--end of qandaset.module-->]]>
-
-<!ENTITY % qandadiv.module "INCLUDE">
-<![ %qandadiv.module; [
-<!ENTITY % local.qandadiv.attrib "">
-<!ENTITY % qandadiv.role.attrib "%role.attrib;">
-
-<!ENTITY % qandadiv.element "INCLUDE">
-<![ %qandadiv.element; [
-<!--doc:A titled division in a QandASet.-->
-<!ELEMENT qandadiv %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%qandaset.mix;)*,
- (qandadiv+|qandaentry+))>
-<!--end of qandadiv.element-->]]>
-
-<!ENTITY % qandadiv.attlist "INCLUDE">
-<![ %qandadiv.attlist; [
-<!ATTLIST qandadiv
- %common.attrib;
- %qandadiv.role.attrib;
- %local.qandadiv.attrib;>
-<!--end of qandadiv.attlist-->]]>
-<!--end of qandadiv.module-->]]>
-
-<!ENTITY % qandaentry.module "INCLUDE">
-<![ %qandaentry.module; [
-<!ENTITY % local.qandaentry.attrib "">
-<!ENTITY % qandaentry.role.attrib "%role.attrib;">
-
-<!ENTITY % qandaentry.element "INCLUDE">
-<![ %qandaentry.element; [
-<!--doc:A question/answer set within a QandASet.-->
-<!ELEMENT qandaentry %ho; (blockinfo?, revhistory?, question, answer*)>
-<!--end of qandaentry.element-->]]>
-
-<!ENTITY % qandaentry.attlist "INCLUDE">
-<![ %qandaentry.attlist; [
-<!ATTLIST qandaentry
- %common.attrib;
- %qandaentry.role.attrib;
- %local.qandaentry.attrib;>
-<!--end of qandaentry.attlist-->]]>
-<!--end of qandaentry.module-->]]>
-
-<!ENTITY % question.module "INCLUDE">
-<![ %question.module; [
-<!ENTITY % local.question.attrib "">
-<!ENTITY % question.role.attrib "%role.attrib;">
-
-<!ENTITY % question.element "INCLUDE">
-<![ %question.element; [
-<!--doc:A question in a QandASet.-->
-<!ELEMENT question %ho; (label?, (%qandaset.mix;)+)>
-<!--end of question.element-->]]>
-
-<!ENTITY % question.attlist "INCLUDE">
-<![ %question.attlist; [
-<!ATTLIST question
- %common.attrib;
- %question.role.attrib;
- %local.question.attrib;
->
-<!--end of question.attlist-->]]>
-<!--end of question.module-->]]>
-
-<!ENTITY % answer.module "INCLUDE">
-<![ %answer.module; [
-<!ENTITY % local.answer.attrib "">
-<!ENTITY % answer.role.attrib "%role.attrib;">
-
-<!ENTITY % answer.element "INCLUDE">
-<![ %answer.element; [
-<!--doc:An answer to a question posed in a QandASet.-->
-<!ELEMENT answer %ho; (label?, (%qandaset.mix;)*, qandaentry*)>
-<!--end of answer.element-->]]>
-
-<!ENTITY % answer.attlist "INCLUDE">
-<![ %answer.attlist; [
-<!ATTLIST answer
- %common.attrib;
- %answer.role.attrib;
- %local.answer.attrib;
->
-<!--end of answer.attlist-->]]>
-<!--end of answer.module-->]]>
-
-<!ENTITY % label.module "INCLUDE">
-<![ %label.module; [
-<!ENTITY % local.label.attrib "">
-<!ENTITY % label.role.attrib "%role.attrib;">
-
-<!ENTITY % label.element "INCLUDE">
-<![ %label.element; [
-<!--doc:A label on a Question or Answer.-->
-<!ELEMENT label %ho; (%word.char.mix;)*>
-<!--end of label.element-->]]>
-
-<!ENTITY % label.attlist "INCLUDE">
-<![ %label.attlist; [
-<!ATTLIST label
- %common.attrib;
- %label.role.attrib;
- %local.label.attrib;
->
-<!--end of label.attlist-->]]>
-<!--end of label.module-->]]>
-<!--end of qandaset.content.module-->]]>
-
-<!-- Procedure ........................ -->
-
-<!ENTITY % procedure.content.module "INCLUDE">
-<![%procedure.content.module;[
-<!ENTITY % procedure.module "INCLUDE">
-<![%procedure.module;[
-<!ENTITY % local.procedure.attrib "">
-<!ENTITY % procedure.role.attrib "%role.attrib;">
-
-<!ENTITY % procedure.element "INCLUDE">
-<![%procedure.element;[
-<!--doc:A list of operations to be performed in a well-defined sequence.-->
-<!ELEMENT procedure %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%component.mix;)*, step+)>
-<!--end of procedure.element-->]]>
-
-<!ENTITY % procedure.attlist "INCLUDE">
-<![%procedure.attlist;[
-<!ATTLIST procedure
- %common.attrib;
- %procedure.role.attrib;
- %local.procedure.attrib;
->
-<!--end of procedure.attlist-->]]>
-<!--end of procedure.module-->]]>
-
-<!ENTITY % step.module "INCLUDE">
-<![%step.module;[
-<!ENTITY % local.step.attrib "">
-<!ENTITY % step.role.attrib "%role.attrib;">
-
-<!ENTITY % step.element "INCLUDE">
-<![%step.element;[
-<!--doc:A unit of action in a procedure.-->
-<!ELEMENT step %ho; (title?, (((%component.mix;)+, ((substeps|stepalternatives), (%component.mix;)*)?)
- | ((substeps|stepalternatives), (%component.mix;)*)))>
-<!--end of step.element-->]]>
-
-<!-- Performance: Whether the Step must be performed -->
-<!-- not #REQUIRED! -->
-
-
-<!ENTITY % step.attlist "INCLUDE">
-<![%step.attlist;[
-<!ATTLIST step
- performance (optional
- |required) "required"
- %common.attrib;
- %step.role.attrib;
- %local.step.attrib;
->
-<!--end of step.attlist-->]]>
-<!--end of step.module-->]]>
-
-<!ENTITY % substeps.module "INCLUDE">
-<![%substeps.module;[
-<!ENTITY % local.substeps.attrib "">
-<!ENTITY % substeps.role.attrib "%role.attrib;">
-
-<!ENTITY % substeps.element "INCLUDE">
-<![%substeps.element;[
-<!--doc:A wrapper for steps that occur within steps in a procedure.-->
-<!ELEMENT substeps %ho; (step+)>
-<!--end of substeps.element-->]]>
-
-<!-- Performance: whether entire set of substeps must be performed -->
-<!-- not #REQUIRED! -->
-
-<!ENTITY % substeps.attlist "INCLUDE">
-<![%substeps.attlist;[
-<!ATTLIST substeps
- performance (optional
- |required) "required"
- %common.attrib;
- %substeps.role.attrib;
- %local.substeps.attrib;
->
-<!--end of substeps.attlist-->]]>
-<!--end of substeps.module-->]]>
-
-<!ENTITY % stepalternatives.module "INCLUDE">
-<![%stepalternatives.module;[
-<!ENTITY % local.stepalternatives.attrib "">
-<!ENTITY % stepalternatives.role.attrib "%role.attrib;">
-
-<!ENTITY % stepalternatives.element "INCLUDE">
-<![%stepalternatives.element;[
-<!--doc:Alternative steps in a procedure.-->
-<!ELEMENT stepalternatives %ho; (step+)>
-<!--end of stepalternatives.element-->]]>
-
-<!-- Performance: Whether (one of) the alternatives must be performed -->
-<!-- not #REQUIRED! -->
-
-<!ENTITY % stepalternatives.attlist "INCLUDE">
-<![%stepalternatives.attlist;[
-<!ATTLIST stepalternatives
- performance (optional
- |required) "required"
- %common.attrib;
- %stepalternatives.role.attrib;
- %local.stepalternatives.attrib;
->
-<!--end of stepalternatives.attlist-->]]>
-<!--end of stepalternatives.module-->]]>
-<!--end of procedure.content.module-->]]>
-
-<!-- Sidebar .......................... -->
-
-<!ENTITY % sidebar.content.model "INCLUDE">
-<![ %sidebar.content.model; [
-
-<!ENTITY % sidebarinfo.module "INCLUDE">
-<![ %sidebarinfo.module; [
-<!ENTITY % local.sidebarinfo.attrib "">
-<!ENTITY % sidebarinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % sidebarinfo.element "INCLUDE">
-<![ %sidebarinfo.element; [
-<!--doc:Meta-information for a Sidebar.-->
-<!ELEMENT sidebarinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of sidebarinfo.element-->]]>
-
-<!ENTITY % sidebarinfo.attlist "INCLUDE">
-<![ %sidebarinfo.attlist; [
-<!ATTLIST sidebarinfo
- %common.attrib;
- %sidebarinfo.role.attrib;
- %local.sidebarinfo.attrib;
->
-<!--end of sidebarinfo.attlist-->]]>
-<!--end of sidebarinfo.module-->]]>
-
-<!ENTITY % sidebar.module "INCLUDE">
-<![%sidebar.module;[
-<!ENTITY % local.sidebar.attrib "">
-<!ENTITY % sidebar.role.attrib "%role.attrib;">
-
-<!ENTITY % sidebar.element "INCLUDE">
-<![%sidebar.element;[
-<!--doc:A portion of a document that is isolated from the main narrative flow.-->
-<!ELEMENT sidebar %ho; (sidebarinfo?,
- (%formalobject.title.content;)?,
- (%sidebar.mix;)+)>
-<!--end of sidebar.element-->]]>
-
-<!ENTITY % sidebar.attlist "INCLUDE">
-<![%sidebar.attlist;[
-<!ATTLIST sidebar
- %common.attrib;
- %sidebar.role.attrib;
- %local.sidebar.attrib;
->
-<!--end of sidebar.attlist-->]]>
-<!--end of sidebar.module-->]]>
-<!--end of sidebar.content.model-->]]>
-
-<!-- ...................................................................... -->
-<!-- Paragraph-related elements ........................................... -->
-
-<!ENTITY % abstract.module "INCLUDE">
-<![%abstract.module;[
-<!ENTITY % local.abstract.attrib "">
-<!ENTITY % abstract.role.attrib "%role.attrib;">
-
-<!ENTITY % abstract.element "INCLUDE">
-<![%abstract.element;[
-<!--doc:A summary.-->
-<!ELEMENT abstract %ho; (title?, (%para.class;)+)>
-<!--end of abstract.element-->]]>
-
-<!ENTITY % abstract.attlist "INCLUDE">
-<![%abstract.attlist;[
-<!ATTLIST abstract
- %common.attrib;
- %abstract.role.attrib;
- %local.abstract.attrib;
->
-<!--end of abstract.attlist-->]]>
-<!--end of abstract.module-->]]>
-
-<!ENTITY % authorblurb.module "INCLUDE">
-<![%authorblurb.module;[
-<!ENTITY % local.authorblurb.attrib "">
-<!ENTITY % authorblurb.role.attrib "%role.attrib;">
-
-<!ENTITY % authorblurb.element "INCLUDE">
-<![%authorblurb.element;[
-<!--doc:A short description or note about an author.-->
-<!ELEMENT authorblurb %ho; (title?, (%para.class;)+)>
-<!--end of authorblurb.element-->]]>
-
-<!ENTITY % authorblurb.attlist "INCLUDE">
-<![%authorblurb.attlist;[
-<!ATTLIST authorblurb
- %common.attrib;
- %authorblurb.role.attrib;
- %local.authorblurb.attrib;
->
-<!--end of authorblurb.attlist-->]]>
-<!--end of authorblurb.module-->]]>
-
-<!ENTITY % personblurb.module "INCLUDE">
-<![%personblurb.module;[
-<!ENTITY % local.personblurb.attrib "">
-<!ENTITY % personblurb.role.attrib "%role.attrib;">
-
-<!ENTITY % personblurb.element "INCLUDE">
-<![%personblurb.element;[
-<!--doc:A short description or note about a person.-->
-<!ELEMENT personblurb %ho; (title?, (%para.class;)+)>
-<!--end of personblurb.element-->]]>
-
-<!ENTITY % personblurb.attlist "INCLUDE">
-<![%personblurb.attlist;[
-<!ATTLIST personblurb
- %common.attrib;
- %personblurb.role.attrib;
- %local.personblurb.attrib;
->
-<!--end of personblurb.attlist-->]]>
-<!--end of personblurb.module-->]]>
-
-<!ENTITY % blockquote.module "INCLUDE">
-<![%blockquote.module;[
-
-<!ENTITY % local.blockquote.attrib "">
-<!ENTITY % blockquote.role.attrib "%role.attrib;">
-
-<!ENTITY % blockquote.element "INCLUDE">
-<![%blockquote.element;[
-<!--doc:A quotation set off from the main text.-->
-<!ELEMENT blockquote %ho; (blockinfo?, title?, attribution?, (%component.mix;)+)
- %blockquote.exclusion;>
-<!--end of blockquote.element-->]]>
-
-<!ENTITY % blockquote.attlist "INCLUDE">
-<![%blockquote.attlist;[
-<!ATTLIST blockquote
- %common.attrib;
- %blockquote.role.attrib;
- %local.blockquote.attrib;
->
-<!--end of blockquote.attlist-->]]>
-<!--end of blockquote.module-->]]>
-
-<!ENTITY % attribution.module "INCLUDE">
-<![%attribution.module;[
-<!ENTITY % local.attribution.attrib "">
-<!ENTITY % attribution.role.attrib "%role.attrib;">
-
-<!ENTITY % attribution.element "INCLUDE">
-<![%attribution.element;[
-<!--doc:The source of a block quote or epigraph.-->
-<!ELEMENT attribution %ho; (%para.char.mix;)*>
-<!--end of attribution.element-->]]>
-
-<!ENTITY % attribution.attlist "INCLUDE">
-<![%attribution.attlist;[
-<!ATTLIST attribution
- %common.attrib;
- %attribution.role.attrib;
- %local.attribution.attrib;
->
-<!--end of attribution.attlist-->]]>
-<!--end of attribution.module-->]]>
-
-<!ENTITY % bridgehead.module "INCLUDE">
-<![%bridgehead.module;[
-<!ENTITY % local.bridgehead.attrib "">
-<!ENTITY % bridgehead.role.attrib "%role.attrib;">
-
-<!ENTITY % bridgehead.element "INCLUDE">
-<![%bridgehead.element;[
-<!--doc:A free-floating heading.-->
-<!ELEMENT bridgehead %ho; (%title.char.mix;)*>
-<!--end of bridgehead.element-->]]>
-
-<!-- Renderas: Indicates the format in which the BridgeHead
- should appear -->
-
-
-<!ENTITY % bridgehead.attlist "INCLUDE">
-<![%bridgehead.attlist;[
-<!ATTLIST bridgehead
- renderas (other
- |sect1
- |sect2
- |sect3
- |sect4
- |sect5) #IMPLIED
- %common.attrib;
- %bridgehead.role.attrib;
- %local.bridgehead.attrib;
->
-<!--end of bridgehead.attlist-->]]>
-<!--end of bridgehead.module-->]]>
-
-<!ENTITY % remark.module "INCLUDE">
-<![%remark.module;[
-<!ENTITY % local.remark.attrib "">
-<!ENTITY % remark.role.attrib "%role.attrib;">
-
-<!ENTITY % remark.element "INCLUDE">
-<![%remark.element;[
-<!--doc:A remark (or comment) intended for presentation in a draft manuscript.-->
-<!ELEMENT remark %ho; (%para.char.mix;)*
- %remark.exclusion;>
-<!--end of remark.element-->]]>
-
-<!ENTITY % remark.attlist "INCLUDE">
-<![%remark.attlist;[
-<!ATTLIST remark
- %common.attrib;
- %remark.role.attrib;
- %local.remark.attrib;
->
-<!--end of remark.attlist-->]]>
-<!--end of remark.module-->]]>
-
-<!ENTITY % epigraph.module "INCLUDE">
-<![%epigraph.module;[
-<!ENTITY % local.epigraph.attrib "">
-<!ENTITY % epigraph.role.attrib "%role.attrib;">
-
-<!ENTITY % epigraph.element "INCLUDE">
-<![%epigraph.element;[
-<!--doc:A short inscription at the beginning of a document or component.-->
-<!ELEMENT epigraph %ho; (attribution?, ((%para.class;)|literallayout)+)>
-<!--end of epigraph.element-->]]>
-
-<!ENTITY % epigraph.attlist "INCLUDE">
-<![%epigraph.attlist;[
-<!ATTLIST epigraph
- %common.attrib;
- %epigraph.role.attrib;
- %local.epigraph.attrib;
->
-<!--end of epigraph.attlist-->]]>
-<!-- Attribution (defined above)-->
-<!--end of epigraph.module-->]]>
-
-<!ENTITY % footnote.module "INCLUDE">
-<![%footnote.module;[
-<!ENTITY % local.footnote.attrib "">
-<!ENTITY % footnote.role.attrib "%role.attrib;">
-
-<!ENTITY % footnote.element "INCLUDE">
-<![%footnote.element;[
-<!--doc:A footnote.-->
-<!ELEMENT footnote %ho; ((%footnote.mix;)+)
- %footnote.exclusion;>
-<!--end of footnote.element-->]]>
-
-<!ENTITY % footnote.attlist "INCLUDE">
-<![%footnote.attlist;[
-<!ATTLIST footnote
- %label.attrib;
- %common.attrib;
- %footnote.role.attrib;
- %local.footnote.attrib;
->
-<!--end of footnote.attlist-->]]>
-<!--end of footnote.module-->]]>
-
-<!ENTITY % highlights.module "INCLUDE">
-<![%highlights.module;[
-<!ENTITY % local.highlights.attrib "">
-<!ENTITY % highlights.role.attrib "%role.attrib;">
-
-<!ENTITY % highlights.element "INCLUDE">
-<![%highlights.element;[
-<!--doc:A summary of the main points of the discussed component.-->
-<!ELEMENT highlights %ho; ((%highlights.mix;)+)
- %highlights.exclusion;>
-<!--end of highlights.element-->]]>
-
-<!ENTITY % highlights.attlist "INCLUDE">
-<![%highlights.attlist;[
-<!ATTLIST highlights
- %common.attrib;
- %highlights.role.attrib;
- %local.highlights.attrib;
->
-<!--end of highlights.attlist-->]]>
-<!--end of highlights.module-->]]>
-
-<!ENTITY % formalpara.module "INCLUDE">
-<![%formalpara.module;[
-<!ENTITY % local.formalpara.attrib "">
-<!ENTITY % formalpara.role.attrib "%role.attrib;">
-
-<!ENTITY % formalpara.element "INCLUDE">
-<![%formalpara.element;[
-<!--doc:A paragraph with a title.-->
-<!ELEMENT formalpara %ho; (title, (%ndxterm.class;)*, para)>
-<!--end of formalpara.element-->]]>
-
-<!ENTITY % formalpara.attlist "INCLUDE">
-<![%formalpara.attlist;[
-<!ATTLIST formalpara
- %common.attrib;
- %formalpara.role.attrib;
- %local.formalpara.attrib;
->
-<!--end of formalpara.attlist-->]]>
-<!--end of formalpara.module-->]]>
-
-<!ENTITY % para.module "INCLUDE">
-<![%para.module;[
-<!ENTITY % local.para.attrib "">
-<!ENTITY % para.role.attrib "%role.attrib;">
-
-<!ENTITY % para.element "INCLUDE">
-<![%para.element;[
-<!--doc:A paragraph.-->
-<!ELEMENT para %ho; (%para.char.mix; | %para.mix;)*>
-<!--end of para.element-->]]>
-
-<!ENTITY % para.attlist "INCLUDE">
-<![%para.attlist;[
-<!ATTLIST para
- %common.attrib;
- %para.role.attrib;
- %local.para.attrib;
->
-<!--end of para.attlist-->]]>
-<!--end of para.module-->]]>
-
-<!ENTITY % simpara.module "INCLUDE">
-<![%simpara.module;[
-<!ENTITY % local.simpara.attrib "">
-<!ENTITY % simpara.role.attrib "%role.attrib;">
-
-<!ENTITY % simpara.element "INCLUDE">
-<![%simpara.element;[
-<!--doc:A paragraph that contains only text and inline markup, no block elements.-->
-<!ELEMENT simpara %ho; (%para.char.mix;)*>
-<!--end of simpara.element-->]]>
-
-<!ENTITY % simpara.attlist "INCLUDE">
-<![%simpara.attlist;[
-<!ATTLIST simpara
- %common.attrib;
- %simpara.role.attrib;
- %local.simpara.attrib;
->
-<!--end of simpara.attlist-->]]>
-<!--end of simpara.module-->]]>
-
-<!ENTITY % admon.module "INCLUDE">
-<![%admon.module;[
-<!ENTITY % local.admon.attrib "">
-<!ENTITY % admon.role.attrib "%role.attrib;">
-
-
-<!ENTITY % caution.element "INCLUDE">
-<![%caution.element;[
-<!--doc:A note of caution.-->
-<!ELEMENT caution %ho; (title?, (%admon.mix;)+)
- %admon.exclusion;>
-<!--end of caution.element-->]]>
-
-<!ENTITY % caution.attlist "INCLUDE">
-<![%caution.attlist;[
-<!ATTLIST caution
- %common.attrib;
- %admon.role.attrib;
- %local.admon.attrib;
->
-<!--end of caution.attlist-->]]>
-
-
-<!ENTITY % important.element "INCLUDE">
-<![%important.element;[
-<!--doc:An admonition set off from the text.-->
-<!ELEMENT important %ho; (title?, (%admon.mix;)+)
- %admon.exclusion;>
-<!--end of important.element-->]]>
-
-<!ENTITY % important.attlist "INCLUDE">
-<![%important.attlist;[
-<!ATTLIST important
- %common.attrib;
- %admon.role.attrib;
- %local.admon.attrib;
->
-<!--end of important.attlist-->]]>
-
-
-<!ENTITY % note.element "INCLUDE">
-<![%note.element;[
-<!--doc:A message set off from the text.-->
-<!ELEMENT note %ho; (title?, (%admon.mix;)+)
- %admon.exclusion;>
-<!--end of note.element-->]]>
-
-<!ENTITY % note.attlist "INCLUDE">
-<![%note.attlist;[
-<!ATTLIST note
- %common.attrib;
- %admon.role.attrib;
- %local.admon.attrib;
->
-<!--end of note.attlist-->]]>
-
-<!ENTITY % tip.element "INCLUDE">
-<![%tip.element;[
-<!--doc:A suggestion to the user, set off from the text.-->
-<!ELEMENT tip %ho; (title?, (%admon.mix;)+)
- %admon.exclusion;>
-<!--end of tip.element-->]]>
-
-<!ENTITY % tip.attlist "INCLUDE">
-<![%tip.attlist;[
-<!ATTLIST tip
- %common.attrib;
- %admon.role.attrib;
- %local.admon.attrib;
->
-<!--end of tip.attlist-->]]>
-
-
-<!ENTITY % warning.element "INCLUDE">
-<![%warning.element;[
-<!--doc:An admonition set off from the text.-->
-<!ELEMENT warning %ho; (title?, (%admon.mix;)+)
- %admon.exclusion;>
-<!--end of warning.element-->]]>
-
-<!ENTITY % warning.attlist "INCLUDE">
-<![%warning.attlist;[
-<!ATTLIST warning
- %common.attrib;
- %admon.role.attrib;
- %local.admon.attrib;
->
-<!--end of warning.attlist-->]]>
-
-<!--end of admon.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Lists ................................................................ -->
-
-<!-- GlossList ........................ -->
-
-<!ENTITY % glosslist.module "INCLUDE">
-<![%glosslist.module;[
-<!ENTITY % local.glosslist.attrib "">
-<!ENTITY % glosslist.role.attrib "%role.attrib;">
-
-<!ENTITY % glosslist.element "INCLUDE">
-<![%glosslist.element;[
-<!--doc:A wrapper for a set of GlossEntrys.-->
-<!ELEMENT glosslist %ho; (blockinfo?, (%formalobject.title.content;)?, glossentry+)>
-<!--end of glosslist.element-->]]>
-
-<!ENTITY % glosslist.attlist "INCLUDE">
-<![%glosslist.attlist;[
-<!ATTLIST glosslist
- %common.attrib;
- %glosslist.role.attrib;
- %local.glosslist.attrib;
->
-<!--end of glosslist.attlist-->]]>
-<!--end of glosslist.module-->]]>
-
-<!ENTITY % glossentry.content.module "INCLUDE">
-<![%glossentry.content.module;[
-<!ENTITY % glossentry.module "INCLUDE">
-<![%glossentry.module;[
-<!ENTITY % local.glossentry.attrib "">
-<!ENTITY % glossentry.role.attrib "%role.attrib;">
-
-<!ENTITY % glossentry.element "INCLUDE">
-<![%glossentry.element;[
-<!--doc:An entry in a Glossary or GlossList.-->
-<!ELEMENT glossentry %ho; (glossterm, acronym?, abbrev?,
- (%ndxterm.class;)*,
- revhistory?, (glosssee|glossdef+))>
-<!--end of glossentry.element-->]]>
-
-<!-- SortAs: String by which the GlossEntry is to be sorted
- (alphabetized) in lieu of its proper content -->
-
-
-<!ENTITY % glossentry.attlist "INCLUDE">
-<![%glossentry.attlist;[
-<!ATTLIST glossentry
- sortas CDATA #IMPLIED
- %common.attrib;
- %glossentry.role.attrib;
- %local.glossentry.attrib;
->
-<!--end of glossentry.attlist-->]]>
-<!--end of glossentry.module-->]]>
-
-<!-- GlossTerm (defined in the Inlines section, below)-->
-<!ENTITY % glossdef.module "INCLUDE">
-<![%glossdef.module;[
-<!ENTITY % local.glossdef.attrib "">
-<!ENTITY % glossdef.role.attrib "%role.attrib;">
-
-<!ENTITY % glossdef.element "INCLUDE">
-<![%glossdef.element;[
-<!--doc:A definition in a GlossEntry.-->
-<!ELEMENT glossdef %ho; ((%glossdef.mix;)+, glossseealso*)>
-<!--end of glossdef.element-->]]>
-
-<!-- Subject: List of subjects; keywords for the definition -->
-
-
-<!ENTITY % glossdef.attlist "INCLUDE">
-<![%glossdef.attlist;[
-<!ATTLIST glossdef
- subject CDATA #IMPLIED
- %common.attrib;
- %glossdef.role.attrib;
- %local.glossdef.attrib;
->
-<!--end of glossdef.attlist-->]]>
-<!--end of glossdef.module-->]]>
-
-<!ENTITY % glosssee.module "INCLUDE">
-<![%glosssee.module;[
-<!ENTITY % local.glosssee.attrib "">
-<!ENTITY % glosssee.role.attrib "%role.attrib;">
-
-<!ENTITY % glosssee.element "INCLUDE">
-<![%glosssee.element;[
-<!--doc:A cross-reference from one GlossEntry to another.-->
-<!ELEMENT glosssee %ho; (%para.char.mix;)*>
-<!--end of glosssee.element-->]]>
-
-<!-- OtherTerm: Reference to the GlossEntry whose GlossTerm
- should be displayed at the point of the GlossSee -->
-
-
-<!ENTITY % glosssee.attlist "INCLUDE">
-<![%glosssee.attlist;[
-<!ATTLIST glosssee
- otherterm IDREF #IMPLIED
- %common.attrib;
- %glosssee.role.attrib;
- %local.glosssee.attrib;
->
-<!--end of glosssee.attlist-->]]>
-<!--end of glosssee.module-->]]>
-
-<!ENTITY % glossseealso.module "INCLUDE">
-<![%glossseealso.module;[
-<!ENTITY % local.glossseealso.attrib "">
-<!ENTITY % glossseealso.role.attrib "%role.attrib;">
-
-<!ENTITY % glossseealso.element "INCLUDE">
-<![%glossseealso.element;[
-<!--doc:A cross-reference from one GlossEntry to another.-->
-<!ELEMENT glossseealso %ho; (%para.char.mix;)*>
-<!--end of glossseealso.element-->]]>
-
-<!-- OtherTerm: Reference to the GlossEntry whose GlossTerm
- should be displayed at the point of the GlossSeeAlso -->
-
-
-<!ENTITY % glossseealso.attlist "INCLUDE">
-<![%glossseealso.attlist;[
-<!ATTLIST glossseealso
- otherterm IDREF #IMPLIED
- %common.attrib;
- %glossseealso.role.attrib;
- %local.glossseealso.attrib;
->
-<!--end of glossseealso.attlist-->]]>
-<!--end of glossseealso.module-->]]>
-<!--end of glossentry.content.module-->]]>
-
-<!-- ItemizedList and OrderedList ..... -->
-
-<!ENTITY % itemizedlist.module "INCLUDE">
-<![%itemizedlist.module;[
-<!ENTITY % local.itemizedlist.attrib "">
-<!ENTITY % itemizedlist.role.attrib "%role.attrib;">
-
-<!ENTITY % itemizedlist.element "INCLUDE">
-<![%itemizedlist.element;[
-<!--doc:A list in which each entry is marked with a bullet or other dingbat.-->
-<!ELEMENT itemizedlist %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%listpreamble.mix;)*, listitem+)>
-
-<!--end of itemizedlist.element-->]]>
-
-<!-- Spacing: Whether the vertical space in the list should be
- compressed -->
-<!-- Mark: Keyword, e.g., bullet, dash, checkbox, none;
- list of keywords and defaults are implementation specific -->
-
-
-<!ENTITY % itemizedlist.attlist "INCLUDE">
-<![%itemizedlist.attlist;[
-<!ATTLIST itemizedlist
- spacing (normal
- |compact) #IMPLIED
- %mark.attrib;
- %common.attrib;
- %itemizedlist.role.attrib;
- %local.itemizedlist.attrib;
->
-<!--end of itemizedlist.attlist-->]]>
-<!--end of itemizedlist.module-->]]>
-
-<!ENTITY % orderedlist.module "INCLUDE">
-<![%orderedlist.module;[
-<!ENTITY % local.orderedlist.attrib "">
-<!ENTITY % orderedlist.role.attrib "%role.attrib;">
-
-<!ENTITY % orderedlist.element "INCLUDE">
-<![%orderedlist.element;[
-<!--doc:A list in which each entry is marked with a sequentially incremented label.-->
-<!ELEMENT orderedlist %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%listpreamble.mix;)*, listitem+)>
-
-<!--end of orderedlist.element-->]]>
-
-<!-- Numeration: Style of ListItem numbered; default is expected
- to be Arabic -->
-<!-- InheritNum: Specifies for a nested list that the numbering
- of ListItems should include the number of the item
- within which they are nested (e.g., 1a and 1b within 1,
- rather than a and b) -->
-<!-- Continuation: Where list numbering begins afresh (Restarts,
- the default) or continues that of the immediately preceding
- list (Continues) -->
-<!-- Spacing: Whether the vertical space in the list should be
- compressed -->
-
-
-<!ENTITY % orderedlist.attlist "INCLUDE">
-<![%orderedlist.attlist;[
-<!ATTLIST orderedlist
- numeration (arabic
- |upperalpha
- |loweralpha
- |upperroman
- |lowerroman) #IMPLIED
- inheritnum (inherit
- |ignore) "ignore"
- continuation (continues
- |restarts) "restarts"
- spacing (normal
- |compact) #IMPLIED
- %common.attrib;
- %orderedlist.role.attrib;
- %local.orderedlist.attrib;
->
-<!--end of orderedlist.attlist-->]]>
-<!--end of orderedlist.module-->]]>
-
-<!ENTITY % listitem.module "INCLUDE">
-<![%listitem.module;[
-<!ENTITY % local.listitem.attrib "">
-<!ENTITY % listitem.role.attrib "%role.attrib;">
-
-<!ENTITY % listitem.element "INCLUDE">
-<![%listitem.element;[
-<!--doc:A wrapper for the elements of a list item.-->
-<!ELEMENT listitem %ho; ((%component.mix;)+)>
-<!--end of listitem.element-->]]>
-
-<!-- Override: Indicates the mark to be used for this ListItem
- instead of the default mark or the mark specified by
- the Mark attribute on the enclosing ItemizedList -->
-
-
-<!ENTITY % listitem.attlist "INCLUDE">
-<![%listitem.attlist;[
-<!ATTLIST listitem
- override CDATA #IMPLIED
- %common.attrib;
- %listitem.role.attrib;
- %local.listitem.attrib;
->
-<!--end of listitem.attlist-->]]>
-<!--end of listitem.module-->]]>
-
-<!-- SegmentedList .................... -->
-<!ENTITY % segmentedlist.content.module "INCLUDE">
-<![%segmentedlist.content.module;[
-<!ENTITY % segmentedlist.module "INCLUDE">
-<![%segmentedlist.module;[
-<!ENTITY % local.segmentedlist.attrib "">
-<!ENTITY % segmentedlist.role.attrib "%role.attrib;">
-
-<!ENTITY % segmentedlist.element "INCLUDE">
-<![%segmentedlist.element;[
-<!--doc:A segmented list, a list of sets of elements.-->
-<!ELEMENT segmentedlist %ho; ((%formalobject.title.content;)?,
- segtitle+,
- seglistitem+)>
-<!--end of segmentedlist.element-->]]>
-
-<!ENTITY % segmentedlist.attlist "INCLUDE">
-<![%segmentedlist.attlist;[
-<!ATTLIST segmentedlist
- %common.attrib;
- %segmentedlist.role.attrib;
- %local.segmentedlist.attrib;
->
-<!--end of segmentedlist.attlist-->]]>
-<!--end of segmentedlist.module-->]]>
-
-<!ENTITY % segtitle.module "INCLUDE">
-<![%segtitle.module;[
-<!ENTITY % local.segtitle.attrib "">
-<!ENTITY % segtitle.role.attrib "%role.attrib;">
-
-<!ENTITY % segtitle.element "INCLUDE">
-<![%segtitle.element;[
-<!--doc:The title of an element of a list item in a segmented list.-->
-<!ELEMENT segtitle %ho; (%title.char.mix;)*>
-<!--end of segtitle.element-->]]>
-
-<!ENTITY % segtitle.attlist "INCLUDE">
-<![%segtitle.attlist;[
-<!ATTLIST segtitle
- %common.attrib;
- %segtitle.role.attrib;
- %local.segtitle.attrib;
->
-<!--end of segtitle.attlist-->]]>
-<!--end of segtitle.module-->]]>
-
-<!ENTITY % seglistitem.module "INCLUDE">
-<![%seglistitem.module;[
-<!ENTITY % local.seglistitem.attrib "">
-<!ENTITY % seglistitem.role.attrib "%role.attrib;">
-
-<!ENTITY % seglistitem.element "INCLUDE">
-<![%seglistitem.element;[
-<!--doc:A list item in a segmented list.-->
-<!ELEMENT seglistitem %ho; (seg+)>
-<!--end of seglistitem.element-->]]>
-
-<!ENTITY % seglistitem.attlist "INCLUDE">
-<![%seglistitem.attlist;[
-<!ATTLIST seglistitem
- %common.attrib;
- %seglistitem.role.attrib;
- %local.seglistitem.attrib;
->
-<!--end of seglistitem.attlist-->]]>
-<!--end of seglistitem.module-->]]>
-
-<!ENTITY % seg.module "INCLUDE">
-<![%seg.module;[
-<!ENTITY % local.seg.attrib "">
-<!ENTITY % seg.role.attrib "%role.attrib;">
-
-<!ENTITY % seg.element "INCLUDE">
-<![%seg.element;[
-<!--doc:An element of a list item in a segmented list.-->
-<!ELEMENT seg %ho; (%para.char.mix;)*>
-<!--end of seg.element-->]]>
-
-<!ENTITY % seg.attlist "INCLUDE">
-<![%seg.attlist;[
-<!ATTLIST seg
- %common.attrib;
- %seg.role.attrib;
- %local.seg.attrib;
->
-<!--end of seg.attlist-->]]>
-<!--end of seg.module-->]]>
-<!--end of segmentedlist.content.module-->]]>
-
-<!-- SimpleList ....................... -->
-
-<!ENTITY % simplelist.content.module "INCLUDE">
-<![%simplelist.content.module;[
-<!ENTITY % simplelist.module "INCLUDE">
-<![%simplelist.module;[
-<!ENTITY % local.simplelist.attrib "">
-<!ENTITY % simplelist.role.attrib "%role.attrib;">
-
-<!ENTITY % simplelist.element "INCLUDE">
-<![%simplelist.element;[
-<!--doc:An undecorated list of single words or short phrases.-->
-<!ELEMENT simplelist %ho; (member+)>
-<!--end of simplelist.element-->]]>
-
-<!-- Columns: The number of columns the array should contain -->
-<!-- Type: How the Members of the SimpleList should be
- formatted: Inline (members separated with commas etc.
- inline), Vert (top to bottom in n Columns), or Horiz (in
- the direction of text flow) in n Columns. If Column
- is 1 or implied, Type=Vert and Type=Horiz give the same
- results. -->
-
-
-<!ENTITY % simplelist.attlist "INCLUDE">
-<![%simplelist.attlist;[
-<!ATTLIST simplelist
- columns CDATA #IMPLIED
- type (inline
- |vert
- |horiz) "vert"
- %common.attrib;
- %simplelist.role.attrib;
- %local.simplelist.attrib;
->
-<!--end of simplelist.attlist-->]]>
-<!--end of simplelist.module-->]]>
-
-<!ENTITY % member.module "INCLUDE">
-<![%member.module;[
-<!ENTITY % local.member.attrib "">
-<!ENTITY % member.role.attrib "%role.attrib;">
-
-<!ENTITY % member.element "INCLUDE">
-<![%member.element;[
-<!--doc:An element of a simple list.-->
-<!ELEMENT member %ho; (%para.char.mix;)*>
-<!--end of member.element-->]]>
-
-<!ENTITY % member.attlist "INCLUDE">
-<![%member.attlist;[
-<!ATTLIST member
- %common.attrib;
- %member.role.attrib;
- %local.member.attrib;
->
-<!--end of member.attlist-->]]>
-<!--end of member.module-->]]>
-<!--end of simplelist.content.module-->]]>
-
-<!-- VariableList ..................... -->
-
-<!ENTITY % variablelist.content.module "INCLUDE">
-<![%variablelist.content.module;[
-<!ENTITY % variablelist.module "INCLUDE">
-<![%variablelist.module;[
-<!ENTITY % local.variablelist.attrib "">
-<!ENTITY % variablelist.role.attrib "%role.attrib;">
-
-<!ENTITY % variablelist.element "INCLUDE">
-<![%variablelist.element;[
-<!--doc:A list in which each entry is composed of a set of one or more terms and an associated description.-->
-<!ELEMENT variablelist %ho; (blockinfo?, (%formalobject.title.content;)?,
- (%listpreamble.mix;)*, varlistentry+)>
-<!--end of variablelist.element-->]]>
-
-<!-- TermLength: Length beyond which the presentation engine
- may consider the Term too long and select an alternate
- presentation of the Term and, or, its associated ListItem. -->
-
-
-<!ENTITY % variablelist.attlist "INCLUDE">
-<![%variablelist.attlist;[
-<!ATTLIST variablelist
- termlength CDATA #IMPLIED
- spacing (normal
- |compact) #IMPLIED
- %common.attrib;
- %variablelist.role.attrib;
- %local.variablelist.attrib;
->
-<!--end of variablelist.attlist-->]]>
-<!--end of variablelist.module-->]]>
-
-<!ENTITY % varlistentry.module "INCLUDE">
-<![%varlistentry.module;[
-<!ENTITY % local.varlistentry.attrib "">
-<!ENTITY % varlistentry.role.attrib "%role.attrib;">
-
-<!ENTITY % varlistentry.element "INCLUDE">
-<![%varlistentry.element;[
-<!--doc:A wrapper for a set of terms and the associated description in a variable list.-->
-<!ELEMENT varlistentry %ho; (term+, listitem)>
-<!--end of varlistentry.element-->]]>
-
-<!ENTITY % varlistentry.attlist "INCLUDE">
-<![%varlistentry.attlist;[
-<!ATTLIST varlistentry
- %common.attrib;
- %varlistentry.role.attrib;
- %local.varlistentry.attrib;
->
-<!--end of varlistentry.attlist-->]]>
-<!--end of varlistentry.module-->]]>
-
-<!ENTITY % term.module "INCLUDE">
-<![%term.module;[
-<!ENTITY % local.term.attrib "">
-<!ENTITY % term.role.attrib "%role.attrib;">
-
-<!ENTITY % term.element "INCLUDE">
-<![%term.element;[
-<!--doc:The word or phrase being defined or described in a variable list.-->
-<!ELEMENT term %ho; (%para.char.mix;)*>
-<!--end of term.element-->]]>
-
-<!ENTITY % term.attlist "INCLUDE">
-<![%term.attlist;[
-<!ATTLIST term
- %common.attrib;
- %term.role.attrib;
- %local.term.attrib;
->
-<!--end of term.attlist-->]]>
-<!--end of term.module-->]]>
-
-<!-- ListItem (defined above)-->
-<!--end of variablelist.content.module-->]]>
-
-<!-- CalloutList ...................... -->
-
-<!ENTITY % calloutlist.content.module "INCLUDE">
-<![%calloutlist.content.module;[
-<!ENTITY % calloutlist.module "INCLUDE">
-<![%calloutlist.module;[
-<!ENTITY % local.calloutlist.attrib "">
-<!ENTITY % calloutlist.role.attrib "%role.attrib;">
-
-<!ENTITY % calloutlist.element "INCLUDE">
-<![%calloutlist.element;[
-<!--doc:A list of Callouts.-->
-<!ELEMENT calloutlist %ho; ((%formalobject.title.content;)?, callout+)>
-<!--end of calloutlist.element-->]]>
-
-<!ENTITY % calloutlist.attlist "INCLUDE">
-<![%calloutlist.attlist;[
-<!ATTLIST calloutlist
- %common.attrib;
- %calloutlist.role.attrib;
- %local.calloutlist.attrib;
->
-<!--end of calloutlist.attlist-->]]>
-<!--end of calloutlist.module-->]]>
-
-<!ENTITY % callout.module "INCLUDE">
-<![%callout.module;[
-<!ENTITY % local.callout.attrib "">
-<!ENTITY % callout.role.attrib "%role.attrib;">
-
-<!ENTITY % callout.element "INCLUDE">
-<![%callout.element;[
-<!--doc:A &ldquo;called out&rdquo; description of a marked Area.-->
-<!ELEMENT callout %ho; ((%component.mix;)+)>
-<!--end of callout.element-->]]>
-
-<!-- AreaRefs: IDs of one or more Areas or AreaSets described
- by this Callout -->
-
-
-<!ENTITY % callout.attlist "INCLUDE">
-<![%callout.attlist;[
-<!ATTLIST callout
- arearefs IDREFS #REQUIRED
- %common.attrib;
- %callout.role.attrib;
- %local.callout.attrib;
->
-<!--end of callout.attlist-->]]>
-<!--end of callout.module-->]]>
-<!--end of calloutlist.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Objects .............................................................. -->
-
-<!-- Examples etc. .................... -->
-
-<!ENTITY % example.module "INCLUDE">
-<![%example.module;[
-<!ENTITY % local.example.attrib "">
-<!ENTITY % example.role.attrib "%role.attrib;">
-
-<!ENTITY % example.element "INCLUDE">
-<![%example.element;[
-<!--doc:A formal example, with a title.-->
-<!ELEMENT example %ho; (blockinfo?, (%formalobject.title.content;), (%example.mix;)+)
- %formal.exclusion;>
-<!--end of example.element-->]]>
-
-<!ENTITY % example.attlist "INCLUDE">
-<![%example.attlist;[
-<!ATTLIST example
- floatstyle CDATA #IMPLIED
- %label.attrib;
- %width.attrib;
- %common.attrib;
- %example.role.attrib;
- %local.example.attrib;
->
-<!--end of example.attlist-->]]>
-<!--end of example.module-->]]>
-
-<!ENTITY % informalexample.module "INCLUDE">
-<![%informalexample.module;[
-<!ENTITY % local.informalexample.attrib "">
-<!ENTITY % informalexample.role.attrib "%role.attrib;">
-
-<!ENTITY % informalexample.element "INCLUDE">
-<![%informalexample.element;[
-<!--doc:A displayed example without a title.-->
-<!ELEMENT informalexample %ho; (blockinfo?, (%example.mix;)+)>
-<!--end of informalexample.element-->]]>
-
-<!ENTITY % informalexample.attlist "INCLUDE">
-<![%informalexample.attlist;[
-<!ATTLIST informalexample
- floatstyle CDATA #IMPLIED
- %width.attrib;
- %common.attrib;
- %informalexample.role.attrib;
- %local.informalexample.attrib;
->
-<!--end of informalexample.attlist-->]]>
-<!--end of informalexample.module-->]]>
-
-<!ENTITY % programlistingco.module "INCLUDE">
-<![%programlistingco.module;[
-<!ENTITY % local.programlistingco.attrib "">
-<!ENTITY % programlistingco.role.attrib "%role.attrib;">
-
-<!ENTITY % programlistingco.element "INCLUDE">
-<![%programlistingco.element;[
-<!--doc:A program listing with associated areas used in callouts.-->
-<!ELEMENT programlistingco %ho; (areaspec, programlisting, calloutlist*)>
-<!--end of programlistingco.element-->]]>
-
-<!ENTITY % programlistingco.attlist "INCLUDE">
-<![%programlistingco.attlist;[
-<!ATTLIST programlistingco
- %common.attrib;
- %programlistingco.role.attrib;
- %local.programlistingco.attrib;
->
-<!--end of programlistingco.attlist-->]]>
-<!-- CalloutList (defined above in Lists)-->
-<!--end of informalexample.module-->]]>
-
-<!ENTITY % areaspec.content.module "INCLUDE">
-<![%areaspec.content.module;[
-<!ENTITY % areaspec.module "INCLUDE">
-<![%areaspec.module;[
-<!ENTITY % local.areaspec.attrib "">
-<!ENTITY % areaspec.role.attrib "%role.attrib;">
-
-<!ENTITY % areaspec.element "INCLUDE">
-<![%areaspec.element;[
-<!--doc:A collection of regions in a graphic or code example.-->
-<!ELEMENT areaspec %ho; ((area|areaset)+)>
-<!--end of areaspec.element-->]]>
-
-<!-- Units: global unit of measure in which coordinates in
- this spec are expressed:
-
- - CALSPair "x1,y1 x2,y2": lower-left and upper-right
- coordinates in a rectangle describing repro area in which
- graphic is placed, where X and Y dimensions are each some
- number 0..10000 (taken from CALS graphic attributes)
-
- - LineColumn "line column": line number and column number
- at which to start callout text in "linespecific" content
-
- - LineRange "startline endline": whole lines from startline
- to endline in "linespecific" content
-
- - LineColumnPair "line1 col1 line2 col2": starting and ending
- points of area in "linespecific" content that starts at
- first position and ends at second position (including the
- beginnings of any intervening lines)
-
- - Other: directive to look at value of OtherUnits attribute
- to get implementation-specific keyword
-
- The default is implementation-specific; usually dependent on
- the parent element (GraphicCO gets CALSPair, ProgramListingCO
- and ScreenCO get LineColumn) -->
-<!-- OtherUnits: User-defined units -->
-
-
-<!ENTITY % areaspec.attlist "INCLUDE">
-<![%areaspec.attlist;[
-<!ATTLIST areaspec
- units (calspair
- |linecolumn
- |linerange
- |linecolumnpair
- |other) #IMPLIED
- otherunits NMTOKEN #IMPLIED
- %common.attrib;
- %areaspec.role.attrib;
- %local.areaspec.attrib;
->
-<!--end of areaspec.attlist-->]]>
-<!--end of areaspec.module-->]]>
-
-<!ENTITY % area.module "INCLUDE">
-<![%area.module;[
-<!ENTITY % local.area.attrib "">
-<!ENTITY % area.role.attrib "%role.attrib;">
-
-<!ENTITY % area.element "INCLUDE">
-<![%area.element;[
-<!--doc:A region defined for a Callout in a graphic or code example.-->
-<!ELEMENT area %ho; EMPTY>
-<!--end of area.element-->]]>
-
-<!-- bug number/symbol override or initialization -->
-<!-- to any related information -->
-<!-- Units: unit of measure in which coordinates in this
- area are expressed; inherits from AreaSet and AreaSpec -->
-<!-- OtherUnits: User-defined units -->
-
-
-<!ENTITY % area.attlist "INCLUDE">
-<![%area.attlist;[
-<!ATTLIST area
- %label.attrib;
- %linkends.attrib;
- units (calspair
- |linecolumn
- |linerange
- |linecolumnpair
- |other) #IMPLIED
- otherunits NMTOKEN #IMPLIED
- coords CDATA #REQUIRED
- %idreq.common.attrib;
- %area.role.attrib;
- %local.area.attrib;
->
-<!--end of area.attlist-->]]>
-<!--end of area.module-->]]>
-
-<!ENTITY % areaset.module "INCLUDE">
-<![%areaset.module;[
-<!ENTITY % local.areaset.attrib "">
-<!ENTITY % areaset.role.attrib "%role.attrib;">
-
-<!ENTITY % areaset.element "INCLUDE">
-<![%areaset.element;[
-<!--doc:A set of related areas in a graphic or code example.-->
-<!ELEMENT areaset %ho; (area+)>
-<!--end of areaset.element-->]]>
-
-<!-- bug number/symbol override or initialization -->
-<!-- Units: unit of measure in which coordinates in this
- area are expressed; inherits from AreaSpec -->
-
-
-<!ENTITY % areaset.attlist "INCLUDE">
-<![%areaset.attlist;[
-<!ATTLIST areaset
- %label.attrib;
- units (calspair
- |linecolumn
- |linerange
- |linecolumnpair
- |other) #IMPLIED
- otherunits NMTOKEN #IMPLIED
- coords CDATA #REQUIRED
- %idreq.common.attrib;
- %areaset.role.attrib;
- %local.areaset.attrib;
->
-<!--end of areaset.attlist-->]]>
-<!--end of areaset.module-->]]>
-<!--end of areaspec.content.module-->]]>
-
-<!ENTITY % programlisting.module "INCLUDE">
-<![%programlisting.module;[
-<!ENTITY % local.programlisting.attrib "">
-<!ENTITY % programlisting.role.attrib "%role.attrib;">
-
-<!ENTITY % programlisting.element "INCLUDE">
-<![%programlisting.element;[
-<!--doc:A literal listing of all or part of a program.-->
-<!ELEMENT programlisting %ho; (%para.char.mix;|co|coref|lineannotation|textobject)*>
-<!--end of programlisting.element-->]]>
-
-<!ENTITY % programlisting.attlist "INCLUDE">
-<![%programlisting.attlist;[
-<!ATTLIST programlisting
- %width.attrib;
- %linespecific.attrib;
- %common.attrib;
- %programlisting.role.attrib;
- %local.programlisting.attrib;
->
-<!--end of programlisting.attlist-->]]>
-<!--end of programlisting.module-->]]>
-
-<!ENTITY % literallayout.module "INCLUDE">
-<![%literallayout.module;[
-<!ENTITY % local.literallayout.attrib "">
-<!ENTITY % literallayout.role.attrib "%role.attrib;">
-
-<!ENTITY % literallayout.element "INCLUDE">
-<![%literallayout.element;[
-<!--doc:A block of text in which line breaks and white space are to be reproduced faithfully.-->
-<!ELEMENT literallayout %ho; (%para.char.mix;|co|coref|textobject|lineannotation)*>
-<!--end of literallayout.element-->]]>
-
-<!ENTITY % literallayout.attlist "INCLUDE">
-<![%literallayout.attlist;[
-<!ATTLIST literallayout
- %width.attrib;
- %linespecific.attrib;
- class (monospaced|normal) "normal"
- %common.attrib;
- %literallayout.role.attrib;
- %local.literallayout.attrib;
->
-<!--end of literallayout.attlist-->]]>
-<!-- LineAnnotation (defined in the Inlines section, below)-->
-<!--end of literallayout.module-->]]>
-
-<!ENTITY % screenco.module "INCLUDE">
-<![%screenco.module;[
-<!ENTITY % local.screenco.attrib "">
-<!ENTITY % screenco.role.attrib "%role.attrib;">
-
-<!ENTITY % screenco.element "INCLUDE">
-<![%screenco.element;[
-<!--doc:A screen with associated areas used in callouts.-->
-<!ELEMENT screenco %ho; (areaspec, screen, calloutlist*)>
-<!--end of screenco.element-->]]>
-
-<!ENTITY % screenco.attlist "INCLUDE">
-<![%screenco.attlist;[
-<!ATTLIST screenco
- %common.attrib;
- %screenco.role.attrib;
- %local.screenco.attrib;
->
-<!--end of screenco.attlist-->]]>
-<!-- AreaSpec (defined above)-->
-<!-- CalloutList (defined above in Lists)-->
-<!--end of screenco.module-->]]>
-
-<!ENTITY % screen.module "INCLUDE">
-<![%screen.module;[
-<!ENTITY % local.screen.attrib "">
-<!ENTITY % screen.role.attrib "%role.attrib;">
-
-<!ENTITY % screen.element "INCLUDE">
-<![%screen.element;[
-<!--doc:Text that a user sees or might see on a computer screen.-->
-<!ELEMENT screen %ho; (%para.char.mix;|co|coref|textobject|lineannotation)*>
-<!--end of screen.element-->]]>
-
-<!ENTITY % screen.attlist "INCLUDE">
-<![%screen.attlist;[
-<!ATTLIST screen
- %width.attrib;
- %linespecific.attrib;
- %common.attrib;
- %screen.role.attrib;
- %local.screen.attrib;
->
-<!--end of screen.attlist-->]]>
-<!--end of screen.module-->]]>
-
-<!ENTITY % screenshot.content.module "INCLUDE">
-<![%screenshot.content.module;[
-<!ENTITY % screenshot.module "INCLUDE">
-<![%screenshot.module;[
-<!ENTITY % local.screenshot.attrib "">
-<!ENTITY % screenshot.role.attrib "%role.attrib;">
-
-<!ENTITY % screenshot.element "INCLUDE">
-<![%screenshot.element;[
-<!--doc:A representation of what the user sees or might see on a computer screen.-->
-<!ELEMENT screenshot %ho; (screeninfo?,
- (graphic|graphicco
- |mediaobject|mediaobjectco))>
-<!--end of screenshot.element-->]]>
-
-<!ENTITY % screenshot.attlist "INCLUDE">
-<![%screenshot.attlist;[
-<!ATTLIST screenshot
- %common.attrib;
- %screenshot.role.attrib;
- %local.screenshot.attrib;
->
-<!--end of screenshot.attlist-->]]>
-<!--end of screenshot.module-->]]>
-
-<!ENTITY % screeninfo.module "INCLUDE">
-<![%screeninfo.module;[
-<!ENTITY % local.screeninfo.attrib "">
-<!ENTITY % screeninfo.role.attrib "%role.attrib;">
-
-<!ENTITY % screeninfo.element "INCLUDE">
-<![%screeninfo.element;[
-<!--doc:Information about how a screen shot was produced.-->
-<!ELEMENT screeninfo %ho; (%para.char.mix;)*
- %ubiq.exclusion;>
-<!--end of screeninfo.element-->]]>
-
-<!ENTITY % screeninfo.attlist "INCLUDE">
-<![%screeninfo.attlist;[
-<!ATTLIST screeninfo
- %common.attrib;
- %screeninfo.role.attrib;
- %local.screeninfo.attrib;
->
-<!--end of screeninfo.attlist-->]]>
-<!--end of screeninfo.module-->]]>
-<!--end of screenshot.content.module-->]]>
-
-<!-- Figures etc. ..................... -->
-
-<!ENTITY % figure.module "INCLUDE">
-<![%figure.module;[
-<!ENTITY % local.figure.attrib "">
-<!ENTITY % figure.role.attrib "%role.attrib;">
-
-<!ENTITY % figure.element "INCLUDE">
-<![%figure.element;[
-<!--doc:A formal figure, generally an illustration, with a title.-->
-<!ELEMENT figure %ho; (blockinfo?, (%formalobject.title.content;),
- (%figure.mix; | %link.char.class;)+)>
-<!--end of figure.element-->]]>
-
-<!-- Float: Whether the Figure is supposed to be rendered
- where convenient (yes (1) value) or at the place it occurs
- in the text (no (0) value, the default) -->
-
-
-<!ENTITY % figure.attlist "INCLUDE">
-<![%figure.attlist;[
-<!ATTLIST figure
- float %yesorno.attvals; '0'
- floatstyle CDATA #IMPLIED
- pgwide %yesorno.attvals; #IMPLIED
- %label.attrib;
- %common.attrib;
- %figure.role.attrib;
- %local.figure.attrib;
->
-<!--end of figure.attlist-->]]>
-<!--end of figure.module-->]]>
-
-<!ENTITY % informalfigure.module "INCLUDE">
-<![ %informalfigure.module; [
-<!ENTITY % local.informalfigure.attrib "">
-<!ENTITY % informalfigure.role.attrib "%role.attrib;">
-
-<!ENTITY % informalfigure.element "INCLUDE">
-<![ %informalfigure.element; [
-<!--doc:A untitled figure.-->
-<!ELEMENT informalfigure %ho; (blockinfo?, (%figure.mix; | %link.char.class;)+)>
-<!--end of informalfigure.element-->]]>
-
-<!ENTITY % informalfigure.attlist "INCLUDE">
-<![ %informalfigure.attlist; [
-<!--
-Float: Whether the Figure is supposed to be rendered
-where convenient (yes (1) value) or at the place it occurs
-in the text (no (0) value, the default)
--->
-<!ATTLIST informalfigure
- float %yesorno.attvals; "0"
- floatstyle CDATA #IMPLIED
- pgwide %yesorno.attvals; #IMPLIED
- %label.attrib;
- %common.attrib;
- %informalfigure.role.attrib;
- %local.informalfigure.attrib;
->
-<!--end of informalfigure.attlist-->]]>
-<!--end of informalfigure.module-->]]>
-
-<!ENTITY % graphicco.module "INCLUDE">
-<![%graphicco.module;[
-<!ENTITY % local.graphicco.attrib "">
-<!ENTITY % graphicco.role.attrib "%role.attrib;">
-
-<!ENTITY % graphicco.element "INCLUDE">
-<![%graphicco.element;[
-<!--doc:A graphic that contains callout areas.-->
-<!ELEMENT graphicco %ho; (areaspec, graphic, calloutlist*)>
-<!--end of graphicco.element-->]]>
-
-<!ENTITY % graphicco.attlist "INCLUDE">
-<![%graphicco.attlist;[
-<!ATTLIST graphicco
- %common.attrib;
- %graphicco.role.attrib;
- %local.graphicco.attrib;
->
-<!--end of graphicco.attlist-->]]>
-<!-- AreaSpec (defined above in Examples)-->
-<!-- CalloutList (defined above in Lists)-->
-<!--end of graphicco.module-->]]>
-
-<!-- Graphical data can be the content of Graphic, or you can reference
- an external file either as an entity (Entitref) or a filename
- (Fileref). -->
-
-<!ENTITY % graphic.module "INCLUDE">
-<![%graphic.module;[
-<!ENTITY % local.graphic.attrib "">
-<!ENTITY % graphic.role.attrib "%role.attrib;">
-
-<!ENTITY % graphic.element "INCLUDE">
-<![%graphic.element;[
-<!--doc:A displayed graphical object (not an inline).-->
-<!ELEMENT graphic %ho; EMPTY>
-<!--end of graphic.element-->]]>
-
-<!ENTITY % graphic.attlist "INCLUDE">
-<![%graphic.attlist;[
-<!ATTLIST graphic
- %graphics.attrib;
- %common.attrib;
- %graphic.role.attrib;
- %local.graphic.attrib;
->
-<!--end of graphic.attlist-->]]>
-<!--end of graphic.module-->]]>
-
-<!ENTITY % inlinegraphic.module "INCLUDE">
-<![%inlinegraphic.module;[
-<!ENTITY % local.inlinegraphic.attrib "">
-<!ENTITY % inlinegraphic.role.attrib "%role.attrib;">
-
-<!ENTITY % inlinegraphic.element "INCLUDE">
-<![%inlinegraphic.element;[
-<!--doc:An object containing or pointing to graphical data that will be rendered inline.-->
-<!ELEMENT inlinegraphic %ho; EMPTY>
-<!--end of inlinegraphic.element-->]]>
-
-<!ENTITY % inlinegraphic.attlist "INCLUDE">
-<![%inlinegraphic.attlist;[
-<!ATTLIST inlinegraphic
- %graphics.attrib;
- %common.attrib;
- %inlinegraphic.role.attrib;
- %local.inlinegraphic.attrib;
->
-<!--end of inlinegraphic.attlist-->]]>
-<!--end of inlinegraphic.module-->]]>
-
-<!ENTITY % mediaobject.content.module "INCLUDE">
-<![ %mediaobject.content.module; [
-
-<!ENTITY % mediaobject.module "INCLUDE">
-<![ %mediaobject.module; [
-<!ENTITY % local.mediaobject.attrib "">
-<!ENTITY % mediaobject.role.attrib "%role.attrib;">
-
-<!ENTITY % mediaobject.element "INCLUDE">
-<![ %mediaobject.element; [
-<!--doc:A displayed media object (video, audio, image, etc.).-->
-<!ELEMENT mediaobject %ho; (objectinfo?,
- (%mediaobject.mix;)+,
- caption?)>
-<!--end of mediaobject.element-->]]>
-
-<!ENTITY % mediaobject.attlist "INCLUDE">
-<![ %mediaobject.attlist; [
-<!ATTLIST mediaobject
- %common.attrib;
- %mediaobject.role.attrib;
- %local.mediaobject.attrib;
->
-<!--end of mediaobject.attlist-->]]>
-<!--end of mediaobject.module-->]]>
-
-<!ENTITY % inlinemediaobject.module "INCLUDE">
-<![ %inlinemediaobject.module; [
-<!ENTITY % local.inlinemediaobject.attrib "">
-<!ENTITY % inlinemediaobject.role.attrib "%role.attrib;">
-
-<!ENTITY % inlinemediaobject.element "INCLUDE">
-<![ %inlinemediaobject.element; [
-<!--doc:An inline media object (video, audio, image, and so on).-->
-<!ELEMENT inlinemediaobject %ho; (objectinfo?,
- (%mediaobject.mix;)+)>
-<!--end of inlinemediaobject.element-->]]>
-
-<!ENTITY % inlinemediaobject.attlist "INCLUDE">
-<![ %inlinemediaobject.attlist; [
-<!ATTLIST inlinemediaobject
- %common.attrib;
- %inlinemediaobject.role.attrib;
- %local.inlinemediaobject.attrib;
->
-<!--end of inlinemediaobject.attlist-->]]>
-<!--end of inlinemediaobject.module-->]]>
-
-<!ENTITY % videoobject.module "INCLUDE">
-<![ %videoobject.module; [
-<!ENTITY % local.videoobject.attrib "">
-<!ENTITY % videoobject.role.attrib "%role.attrib;">
-
-<!ENTITY % videoobject.element "INCLUDE">
-<![ %videoobject.element; [
-<!--doc:A wrapper for video data and its associated meta-information.-->
-<!ELEMENT videoobject %ho; (objectinfo?, videodata)>
-<!--end of videoobject.element-->]]>
-
-<!ENTITY % videoobject.attlist "INCLUDE">
-<![ %videoobject.attlist; [
-<!ATTLIST videoobject
- %common.attrib;
- %videoobject.role.attrib;
- %local.videoobject.attrib;
->
-<!--end of videoobject.attlist-->]]>
-<!--end of videoobject.module-->]]>
-
-<!ENTITY % audioobject.module "INCLUDE">
-<![ %audioobject.module; [
-<!ENTITY % local.audioobject.attrib "">
-<!ENTITY % audioobject.role.attrib "%role.attrib;">
-
-<!ENTITY % audioobject.element "INCLUDE">
-<![ %audioobject.element; [
-<!--doc:A wrapper for audio data and its associated meta-information.-->
-<!ELEMENT audioobject %ho; (objectinfo?, audiodata)>
-<!--end of audioobject.element-->]]>
-
-<!ENTITY % audioobject.attlist "INCLUDE">
-<![ %audioobject.attlist; [
-<!ATTLIST audioobject
- %common.attrib;
- %audioobject.role.attrib;
- %local.audioobject.attrib;
->
-<!--end of audioobject.attlist-->]]>
-<!--end of audioobject.module-->]]>
-
-<!ENTITY % imageobject.module "INCLUDE">
-<![ %imageobject.module; [
-<!ENTITY % local.imageobject.attrib "">
-<!ENTITY % imageobject.role.attrib "%role.attrib;">
-
-<!ENTITY % imageobject.element "INCLUDE">
-<![ %imageobject.element; [
-<!--doc:A wrapper for image data and its associated meta-information.-->
-<!ELEMENT imageobject %ho; (objectinfo?, imagedata)>
-<!--end of imageobject.element-->]]>
-
-<!ENTITY % imageobject.attlist "INCLUDE">
-<![ %imageobject.attlist; [
-<!ATTLIST imageobject
- %common.attrib;
- %imageobject.role.attrib;
- %local.imageobject.attrib;
->
-<!--end of imageobject.attlist-->]]>
-<!--end of imageobject.module-->]]>
-
-<!ENTITY % textobject.module "INCLUDE">
-<![ %textobject.module; [
-<!ENTITY % local.textobject.attrib "">
-<!ENTITY % textobject.role.attrib "%role.attrib;">
-
-<!ENTITY % textobject.element "INCLUDE">
-<![ %textobject.element; [
-<!--doc:A wrapper for a text description of an object and its associated meta-information.-->
-<!ELEMENT textobject %ho; (objectinfo?, (phrase|textdata|(%textobject.mix;)+))>
-<!--end of textobject.element-->]]>
-
-<!ENTITY % textobject.attlist "INCLUDE">
-<![ %textobject.attlist; [
-<!ATTLIST textobject
- %common.attrib;
- %textobject.role.attrib;
- %local.textobject.attrib;
->
-<!--end of textobject.attlist-->]]>
-<!--end of textobject.module-->]]>
-
-<!ENTITY % objectinfo.module "INCLUDE">
-<![ %objectinfo.module; [
-<!ENTITY % local.objectinfo.attrib "">
-<!ENTITY % objectinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % objectinfo.element "INCLUDE">
-<![ %objectinfo.element; [
-<!--doc:Meta-information for an object.-->
-<!ELEMENT objectinfo %ho; ((%info.class;)+)
- %beginpage.exclusion;>
-<!--end of objectinfo.element-->]]>
-
-<!ENTITY % objectinfo.attlist "INCLUDE">
-<![ %objectinfo.attlist; [
-<!ATTLIST objectinfo
- %common.attrib;
- %objectinfo.role.attrib;
- %local.objectinfo.attrib;
->
-<!--end of objectinfo.attlist-->]]>
-<!--end of objectinfo.module-->]]>
-
-<!--EntityRef: Name of an external entity containing the content
- of the object data-->
-<!--FileRef: Filename, qualified by a pathname if desired,
- designating the file containing the content of the object data-->
-<!--Format: Notation of the element content, if any-->
-<!--SrcCredit: Information about the source of the image-->
-<!ENTITY % local.objectdata.attrib "">
-<!ENTITY % objectdata.attrib
- "
- entityref ENTITY #IMPLIED
- fileref CDATA #IMPLIED
- format (%notation.class;)
- #IMPLIED
- srccredit CDATA #IMPLIED
- %local.objectdata.attrib;"
->
-
-<!ENTITY % videodata.module "INCLUDE">
-<![ %videodata.module; [
-<!ENTITY % local.videodata.attrib "">
-<!ENTITY % videodata.role.attrib "%role.attrib;">
-
-<!ENTITY % videodata.element "INCLUDE">
-<![ %videodata.element; [
-<!--doc:Pointer to external video data.-->
-<!ELEMENT videodata %ho; EMPTY>
-<!--end of videodata.element-->]]>
-
-<!ENTITY % videodata.attlist "INCLUDE">
-<![ %videodata.attlist; [
-
-<!--Width: Same as CALS reprowid (desired width)-->
-<!--Depth: Same as CALS reprodep (desired depth)-->
-<!--Align: Same as CALS hplace with 'none' removed; #IMPLIED means
- application-specific-->
-<!--Scale: Conflation of CALS hscale and vscale-->
-<!--Scalefit: Same as CALS scalefit-->
-<!ATTLIST videodata
- width CDATA #IMPLIED
- contentwidth CDATA #IMPLIED
- depth CDATA #IMPLIED
- contentdepth CDATA #IMPLIED
- align (left
- |right
- |center) #IMPLIED
- valign (top
- |middle
- |bottom) #IMPLIED
- scale CDATA #IMPLIED
- scalefit %yesorno.attvals;
- #IMPLIED
- %objectdata.attrib;
- %common.attrib;
- %videodata.role.attrib;
- %local.videodata.attrib;
->
-<!--end of videodata.attlist-->]]>
-<!--end of videodata.module-->]]>
-
-<!ENTITY % audiodata.module "INCLUDE">
-<![ %audiodata.module; [
-<!ENTITY % local.audiodata.attrib "">
-<!ENTITY % audiodata.role.attrib "%role.attrib;">
-
-<!ENTITY % audiodata.element "INCLUDE">
-<![ %audiodata.element; [
-<!--doc:Pointer to external audio data.-->
-<!ELEMENT audiodata %ho; EMPTY>
-<!--end of audiodata.element-->]]>
-
-<!ENTITY % audiodata.attlist "INCLUDE">
-<![ %audiodata.attlist; [
-<!ATTLIST audiodata
- %objectdata.attrib;
- %common.attrib;
- %audiodata.role.attrib;
- %local.audiodata.attrib;
->
-<!--end of audiodata.attlist-->]]>
-<!--end of audiodata.module-->]]>
-
-<!ENTITY % imagedata.module "INCLUDE">
-<![ %imagedata.module; [
-<!ENTITY % local.imagedata.attrib "">
-<!ENTITY % imagedata.role.attrib "%role.attrib;">
-
-<!ENTITY % imagedata.element "INCLUDE">
-<![ %imagedata.element; [
-<!--doc:Pointer to external image data.-->
-<!ELEMENT imagedata %ho; EMPTY>
-<!--end of imagedata.element-->]]>
-
-<!ENTITY % imagedata.attlist "INCLUDE">
-<![ %imagedata.attlist; [
-
-<!--Width: Same as CALS reprowid (desired width)-->
-<!--Depth: Same as CALS reprodep (desired depth)-->
-<!--Align: Same as CALS hplace with 'none' removed; #IMPLIED means
- application-specific-->
-<!--Scale: Conflation of CALS hscale and vscale-->
-<!--Scalefit: Same as CALS scalefit-->
-<!ATTLIST imagedata
- width CDATA #IMPLIED
- contentwidth CDATA #IMPLIED
- depth CDATA #IMPLIED
- contentdepth CDATA #IMPLIED
- align (left
- |right
- |center) #IMPLIED
- valign (top
- |middle
- |bottom) #IMPLIED
- scale CDATA #IMPLIED
- scalefit %yesorno.attvals;
- #IMPLIED
- %objectdata.attrib;
- %common.attrib;
- %imagedata.role.attrib;
- %local.imagedata.attrib;
->
-<!--end of imagedata.attlist-->]]>
-<!--end of imagedata.module-->]]>
-
-<!ENTITY % textdata.module "INCLUDE">
-<![ %textdata.module; [
-<!ENTITY % local.textdata.attrib "">
-<!ENTITY % textdata.role.attrib "%role.attrib;">
-
-<!ENTITY % textdata.element "INCLUDE">
-<![ %textdata.element; [
-<!--doc:Pointer to external text data.-->
-<!ELEMENT textdata %ho; EMPTY>
-<!--end of textdata.element-->]]>
-
-<!ENTITY % textdata.attlist "INCLUDE">
-<![ %textdata.attlist; [
-<!ATTLIST textdata
- encoding CDATA #IMPLIED
- %objectdata.attrib;
- %common.attrib;
- %textdata.role.attrib;
- %local.textdata.attrib;
->
-<!--end of textdata.attlist-->]]>
-<!--end of textdata.module-->]]>
-
-<!ENTITY % mediaobjectco.module "INCLUDE">
-<![ %mediaobjectco.module; [
-<!ENTITY % local.mediaobjectco.attrib "">
-<!ENTITY % mediaobjectco.role.attrib "%role.attrib;">
-
-<!ENTITY % mediaobjectco.element "INCLUDE">
-<![ %mediaobjectco.element; [
-<!--doc:A media object that contains callouts.-->
-<!ELEMENT mediaobjectco %ho; (objectinfo?, imageobjectco,
- (imageobjectco|textobject)*)>
-<!--end of mediaobjectco.element-->]]>
-
-<!ENTITY % mediaobjectco.attlist "INCLUDE">
-<![ %mediaobjectco.attlist; [
-<!ATTLIST mediaobjectco
- %common.attrib;
- %mediaobjectco.role.attrib;
- %local.mediaobjectco.attrib;
->
-<!--end of mediaobjectco.attlist-->]]>
-<!--end of mediaobjectco.module-->]]>
-
-<!ENTITY % imageobjectco.module "INCLUDE">
-<![ %imageobjectco.module; [
-<!ENTITY % local.imageobjectco.attrib "">
-<!ENTITY % imageobjectco.role.attrib "%role.attrib;">
-
-<!ENTITY % imageobjectco.element "INCLUDE">
-<![ %imageobjectco.element; [
-<!--doc:A wrapper for an image object with callouts.-->
-<!ELEMENT imageobjectco %ho; (areaspec, imageobject, calloutlist*)>
-<!--end of imageobjectco.element-->]]>
-
-<!ENTITY % imageobjectco.attlist "INCLUDE">
-<![ %imageobjectco.attlist; [
-<!ATTLIST imageobjectco
- %common.attrib;
- %imageobjectco.role.attrib;
- %local.imageobjectco.attrib;
->
-<!--end of imageobjectco.attlist-->]]>
-<!--end of imageobjectco.module-->]]>
-<!--end of mediaobject.content.module-->]]>
-
-<!-- Equations ........................ -->
-
-<!-- This PE provides a mechanism for replacing equation content, -->
-<!-- perhaps adding a new or different model (e.g., MathML) -->
-<!ENTITY % equation.content "(alt?, (graphic+|mediaobject+|mathphrase+))">
-<!ENTITY % inlineequation.content "(alt?, (graphic+|inlinemediaobject+|mathphrase+))">
-
-<!ENTITY % equation.module "INCLUDE">
-<![%equation.module;[
-<!ENTITY % local.equation.attrib "">
-<!ENTITY % equation.role.attrib "%role.attrib;">
-
-<!ENTITY % equation.element "INCLUDE">
-<![%equation.element;[
-<!--doc:A displayed mathematical equation.-->
-<!ELEMENT equation %ho; (blockinfo?, (%formalobject.title.content;)?,
- (informalequation | %equation.content;))>
-<!--end of equation.element-->]]>
-
-<!ENTITY % equation.attlist "INCLUDE">
-<![%equation.attlist;[
-<!ATTLIST equation
- floatstyle CDATA #IMPLIED
- %label.attrib;
- %common.attrib;
- %equation.role.attrib;
- %local.equation.attrib;
->
-<!--end of equation.attlist-->]]>
-<!--end of equation.module-->]]>
-
-<!ENTITY % informalequation.module "INCLUDE">
-<![%informalequation.module;[
-<!ENTITY % local.informalequation.attrib "">
-<!ENTITY % informalequation.role.attrib "%role.attrib;">
-
-<!ENTITY % informalequation.element "INCLUDE">
-<![%informalequation.element;[
-<!--doc:A displayed mathematical equation without a title.-->
-<!ELEMENT informalequation %ho; (blockinfo?, %equation.content;) >
-<!--end of informalequation.element-->]]>
-
-<!ENTITY % informalequation.attlist "INCLUDE">
-<![%informalequation.attlist;[
-<!ATTLIST informalequation
- floatstyle CDATA #IMPLIED
- %common.attrib;
- %informalequation.role.attrib;
- %local.informalequation.attrib;
->
-<!--end of informalequation.attlist-->]]>
-<!--end of informalequation.module-->]]>
-
-<!ENTITY % inlineequation.module "INCLUDE">
-<![%inlineequation.module;[
-<!ENTITY % local.inlineequation.attrib "">
-<!ENTITY % inlineequation.role.attrib "%role.attrib;">
-
-<!ENTITY % inlineequation.element "INCLUDE">
-<![%inlineequation.element;[
-<!--doc:A mathematical equation or expression occurring inline.-->
-<!ELEMENT inlineequation %ho; (%inlineequation.content;)>
-<!--end of inlineequation.element-->]]>
-
-<!ENTITY % inlineequation.attlist "INCLUDE">
-<![%inlineequation.attlist;[
-<!ATTLIST inlineequation
- %common.attrib;
- %inlineequation.role.attrib;
- %local.inlineequation.attrib;
->
-<!--end of inlineequation.attlist-->]]>
-<!--end of inlineequation.module-->]]>
-
-<!ENTITY % alt.module "INCLUDE">
-<![%alt.module;[
-<!ENTITY % local.alt.attrib "">
-<!ENTITY % alt.role.attrib "%role.attrib;">
-
-<!ENTITY % alt.element "INCLUDE">
-<![%alt.element;[
-<!--doc:Text representation for a graphical element.-->
-<!ELEMENT alt %ho; (#PCDATA)>
-<!--end of alt.element-->]]>
-
-<!ENTITY % alt.attlist "INCLUDE">
-<![%alt.attlist;[
-<!ATTLIST alt
- %common.attrib;
- %alt.role.attrib;
- %local.alt.attrib;
->
-<!--end of alt.attlist-->]]>
-<!--end of alt.module-->]]>
-
-<!ENTITY % mathphrase.module "INCLUDE">
-<![%mathphrase.module;[
-<!ENTITY % local.mathphrase.attrib "">
-<!ENTITY % mathphrase.role.attrib "%role.attrib;">
-
-<!ENTITY % mathphrase.element "INCLUDE">
-<![%mathphrase.element;[
-<!--doc:A mathematical phrase, an expression that can be represented with ordinary text and a small amount of markup.-->
-<!ELEMENT mathphrase %ho; (#PCDATA|subscript|superscript|emphasis)*>
-<!--end of mathphrase.element-->]]>
-
-<!ENTITY % mathphrase.attlist "INCLUDE">
-<![%mathphrase.attlist;[
-<!ATTLIST mathphrase
- %common.attrib;
- %mathphrase.role.attrib;
- %local.mathphrase.attrib;
->
-<!--end of mathphrase.attlist-->]]>
-<!--end of mathphrase.module-->]]>
-
-<!-- Tables ........................... -->
-
-<!ENTITY % table.module "INCLUDE">
-<![%table.module;[
-
-<!-- Choose a table model. CALS or OASIS XML Exchange -->
-
-<!ENTITY % cals.table.module "INCLUDE">
-<![%cals.table.module;[
-<!ENTITY % exchange.table.module "IGNORE">
-]]>
-<!ENTITY % exchange.table.module "INCLUDE">
-
-<!-- Do we allow the HTML table model as well? -->
-<!ENTITY % allow.html.tables "INCLUDE">
-<![%allow.html.tables;[
- <!-- ====================================================== -->
- <!-- xhtmltbl.mod defines HTML tables and sets parameter
- entities so that, when the CALS table module is read,
- we end up allowing any table to be CALS or HTML.
- i.e. This include must come first! -->
- <!-- ====================================================== -->
-
-<!ENTITY % htmltbl
- PUBLIC "-//OASIS//ELEMENTS DocBook XML HTML Tables V4.5//EN"
- "htmltblx.mod">
-%htmltbl;
-<!--end of allow.html.tables-->]]>
-
-<!ENTITY % tables.role.attrib "%role.attrib;">
-
-<![%cals.table.module;[
-<!-- Add label and role attributes to table and informaltable -->
-<!ENTITY % bodyatt "
- floatstyle CDATA #IMPLIED
- rowheader (firstcol|norowheader) #IMPLIED
- %label.attrib;"
->
-
-<!-- Add common attributes to Table, TGroup, TBody, THead, TFoot, Row,
- EntryTbl, and Entry (and InformalTable element). -->
-<!ENTITY % secur
- "%common.attrib;
- %tables.role.attrib;">
-
-<!ENTITY % common.table.attribs
- "%bodyatt;
- %secur;">
-
-<!-- Content model for Table. -->
-<!ENTITY % tbl.table.mdl
- "(blockinfo?, (%formalobject.title.content;), (%ndxterm.class;)*,
- textobject*,
- (graphic+|mediaobject+|tgroup+))">
-
-<!-- Allow either objects or inlines; beware of REs between elements. -->
-<!ENTITY % tbl.entry.mdl "%para.char.mix; | %tabentry.mix;">
-
-<!-- Reference CALS Table Model -->
-<!ENTITY % tablemodel
- PUBLIC "-//OASIS//DTD DocBook CALS Table Model V4.5//EN"
- "calstblx.dtd">
-]]>
-
-<![%exchange.table.module;[
-<!-- Add common attributes and the Label attribute to Table and -->
-<!-- InformalTable. -->
-<!ENTITY % bodyatt
- "%common.attrib;
- rowheader (firstcol|norowheader) #IMPLIED
- %label.attrib;
- %tables.role.attrib;">
-
-<!ENTITY % common.table.attribs
- "%bodyatt;">
-
-<!-- Add common attributes to TGroup, ColSpec, TBody, THead, Row, Entry -->
-
-<!ENTITY % tbl.tgroup.att "%common.attrib;">
-<!ENTITY % tbl.colspec.att "%common.attrib;">
-<!ENTITY % tbl.tbody.att "%common.attrib;">
-<!ENTITY % tbl.thead.att "%common.attrib;">
-<!ENTITY % tbl.row.att "%common.attrib;">
-<!ENTITY % tbl.entry.att "%common.attrib;">
-
-<!-- Content model for Table. -->
-<!ENTITY % tbl.table.mdl
- "(blockinfo?, (%formalobject.title.content;), (%ndxterm.class;)*,
- textobject*,
- (graphic+|mediaobject+|tgroup+))">
-
-<!-- Allow either objects or inlines; beware of REs between elements. -->
-<!ENTITY % tbl.entry.mdl "(%para.char.mix; | %tabentry.mix;)*">
-
-<!-- Reference OASIS Exchange Table Model -->
-<!ENTITY % tablemodel
- PUBLIC "-//OASIS//DTD XML Exchange Table Model 19990315//EN"
- "soextblx.dtd">
-]]>
-
-%tablemodel;
-
-<!--end of table.module-->]]>
-
-<!ENTITY % informaltable.module "INCLUDE">
-<![%informaltable.module;[
-
-<!-- Note that InformalTable is dependent on some of the entity
- declarations that customize Table. -->
-
-<!ENTITY % local.informaltable.attrib "">
-
-<!-- the following entity may have been declared by the XHTML table module -->
-<!ENTITY % informal.tbl.table.mdl "textobject*, (graphic+|mediaobject+|tgroup+)">
-
-<!ENTITY % informaltable.element "INCLUDE">
-<![%informaltable.element;[
-<!--doc:A table without a title.-->
-<!ELEMENT informaltable %ho; (blockinfo?, (%informal.tbl.table.mdl;))>
-<!--end of informaltable.element-->]]>
-
-<!-- Frame, Colsep, and Rowsep must be repeated because
- they are not in entities in the table module. -->
-<!-- includes TabStyle, ToCentry, ShortEntry,
- Orient, PgWide -->
-<!-- includes Label -->
-<!-- includes common attributes -->
-
-<!ENTITY % informaltable.attlist "INCLUDE">
-<![%informaltable.attlist;[
-<!ATTLIST informaltable
- frame (%tbl.frame.attval;) #IMPLIED
- colsep %yesorno.attvals; #IMPLIED
- rowsep %yesorno.attvals; #IMPLIED
- %common.table.attribs;
- %tbl.table.att;
- %local.informaltable.attrib;
->
-<!--end of informaltable.attlist-->]]>
-<!--end of informaltable.module-->]]>
-
-<!ENTITY % caption.module "INCLUDE">
-<![ %caption.module; [
-<!ENTITY % local.caption.attrib "">
-<!ENTITY % caption.role.attrib "%role.attrib;">
-
-<!ENTITY % caption.element "INCLUDE">
-<![ %caption.element; [
-<!--doc:A caption.-->
-<!ELEMENT caption %ho; (#PCDATA | %textobject.mix;)*>
-<!--end of caption.element-->]]>
-
-<!ENTITY % caption.attlist "INCLUDE">
-<![ %caption.attlist; [
-<!-- attrs comes from HTML tables ... -->
-
-<![ %allow.html.tables; [
-<!-- common.attrib, but without ID because ID is in attrs -->
-<!ENTITY % caption.attlist.content "
- %caption.role.attrib;
- %attrs;
- align (top|bottom|left|right) #IMPLIED
- %local.caption.attrib;
-">
-]]>
-<!ENTITY % caption.attlist.content "
- %common.attrib;
- %caption.role.attrib;
- %local.caption.attrib;
-">
-
-<!ATTLIST caption %caption.attlist.content;>
-
-<!--end of caption.attlist-->]]>
-<!--end of caption.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Synopses ............................................................. -->
-
-<!-- Synopsis ......................... -->
-
-<!ENTITY % synopsis.module "INCLUDE">
-<![%synopsis.module;[
-<!ENTITY % local.synopsis.attrib "">
-<!ENTITY % synopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % synopsis.element "INCLUDE">
-<![%synopsis.element;[
-<!--doc:A general-purpose element for representing the syntax of commands or functions.-->
-<!ELEMENT synopsis %ho; (%para.char.mix;|graphic|mediaobject|co|coref|textobject|lineannotation)*>
-<!--end of synopsis.element-->]]>
-
-<!ENTITY % synopsis.attlist "INCLUDE">
-<![%synopsis.attlist;[
-<!ATTLIST synopsis
- %label.attrib;
- %linespecific.attrib;
- %common.attrib;
- %synopsis.role.attrib;
- %local.synopsis.attrib;
->
-<!--end of synopsis.attlist-->]]>
-
-<!-- LineAnnotation (defined in the Inlines section, below)-->
-<!--end of synopsis.module-->]]>
-
-<!-- CmdSynopsis ...................... -->
-
-<!ENTITY % cmdsynopsis.content.module "INCLUDE">
-<![%cmdsynopsis.content.module;[
-<!ENTITY % cmdsynopsis.module "INCLUDE">
-<![%cmdsynopsis.module;[
-<!ENTITY % local.cmdsynopsis.attrib "">
-<!ENTITY % cmdsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % cmdsynopsis.element "INCLUDE">
-<![%cmdsynopsis.element;[
-<!--doc:A syntax summary for a software command.-->
-<!ELEMENT cmdsynopsis %ho; ((command | arg | group | sbr)+, synopfragment*)>
-<!--end of cmdsynopsis.element-->]]>
-
-<!-- Sepchar: Character that should separate command and all
- top-level arguments; alternate value might be e.g., &Delta; -->
-
-
-<!ENTITY % cmdsynopsis.attlist "INCLUDE">
-<![%cmdsynopsis.attlist;[
-<!ATTLIST cmdsynopsis
- %label.attrib;
- sepchar CDATA " "
- cmdlength CDATA #IMPLIED
- %common.attrib;
- %cmdsynopsis.role.attrib;
- %local.cmdsynopsis.attrib;
->
-<!--end of cmdsynopsis.attlist-->]]>
-<!--end of cmdsynopsis.module-->]]>
-
-<!ENTITY % arg.module "INCLUDE">
-<![%arg.module;[
-<!ENTITY % local.arg.attrib "">
-<!ENTITY % arg.role.attrib "%role.attrib;">
-
-<!ENTITY % arg.element "INCLUDE">
-<![%arg.element;[
-<!--doc:An argument in a CmdSynopsis.-->
-<!ELEMENT arg %ho; (#PCDATA
- | arg
- | group
- | option
- | synopfragmentref
- | replaceable
- | sbr)*>
-<!--end of arg.element-->]]>
-
-<!-- Choice: Whether Arg must be supplied: Opt (optional to
- supply, e.g. [arg]; the default), Req (required to supply,
- e.g. {arg}), or Plain (required to supply, e.g. arg) -->
-<!-- Rep: whether Arg is repeatable: Norepeat (e.g. arg without
- ellipsis; the default), or Repeat (e.g. arg...) -->
-
-
-<!ENTITY % arg.attlist "INCLUDE">
-<![%arg.attlist;[
-<!ATTLIST arg
- choice (opt
- |req
- |plain) 'opt'
- rep (norepeat
- |repeat) 'norepeat'
- %common.attrib;
- %arg.role.attrib;
- %local.arg.attrib;
->
-<!--end of arg.attlist-->]]>
-<!--end of arg.module-->]]>
-
-<!ENTITY % group.module "INCLUDE">
-<![%group.module;[
-
-<!ENTITY % local.group.attrib "">
-<!ENTITY % group.role.attrib "%role.attrib;">
-
-<!ENTITY % group.element "INCLUDE">
-<![%group.element;[
-<!--doc:A group of elements in a CmdSynopsis.-->
-<!ELEMENT group %ho; ((arg | group | option | synopfragmentref
- | replaceable | sbr)+)>
-<!--end of group.element-->]]>
-
-<!-- Choice: Whether Group must be supplied: Opt (optional to
- supply, e.g. [g1|g2|g3]; the default), Req (required to
- supply, e.g. {g1|g2|g3}), Plain (required to supply,
- e.g. g1|g2|g3), OptMult (can supply zero or more, e.g.
- [[g1|g2|g3]]), or ReqMult (must supply one or more, e.g.
- {{g1|g2|g3}}) -->
-<!-- Rep: whether Group is repeatable: Norepeat (e.g. group
- without ellipsis; the default), or Repeat (e.g. group...) -->
-
-
-<!ENTITY % group.attlist "INCLUDE">
-<![%group.attlist;[
-<!ATTLIST group
- choice (opt
- |req
- |plain) 'opt'
- rep (norepeat
- |repeat) 'norepeat'
- %common.attrib;
- %group.role.attrib;
- %local.group.attrib;
->
-<!--end of group.attlist-->]]>
-<!--end of group.module-->]]>
-
-<!ENTITY % sbr.module "INCLUDE">
-<![%sbr.module;[
-<!ENTITY % local.sbr.attrib "">
-<!-- Synopsis break -->
-<!ENTITY % sbr.role.attrib "%role.attrib;">
-
-<!ENTITY % sbr.element "INCLUDE">
-<![%sbr.element;[
-<!--doc:An explicit line break in a command synopsis.-->
-<!ELEMENT sbr %ho; EMPTY>
-<!--end of sbr.element-->]]>
-
-<!ENTITY % sbr.attlist "INCLUDE">
-<![%sbr.attlist;[
-<!ATTLIST sbr
- %common.attrib;
- %sbr.role.attrib;
- %local.sbr.attrib;
->
-<!--end of sbr.attlist-->]]>
-<!--end of sbr.module-->]]>
-
-<!ENTITY % synopfragmentref.module "INCLUDE">
-<![%synopfragmentref.module;[
-<!ENTITY % local.synopfragmentref.attrib "">
-<!ENTITY % synopfragmentref.role.attrib "%role.attrib;">
-
-<!ENTITY % synopfragmentref.element "INCLUDE">
-<![%synopfragmentref.element;[
-<!--doc:A reference to a fragment of a command synopsis.-->
-<!ELEMENT synopfragmentref %ho; (#PCDATA)>
-<!--end of synopfragmentref.element-->]]>
-
-<!-- to SynopFragment of complex synopsis
- material for separate referencing -->
-
-
-<!ENTITY % synopfragmentref.attlist "INCLUDE">
-<![%synopfragmentref.attlist;[
-<!ATTLIST synopfragmentref
- %linkendreq.attrib; %common.attrib;
- %synopfragmentref.role.attrib;
- %local.synopfragmentref.attrib;
->
-<!--end of synopfragmentref.attlist-->]]>
-<!--end of synopfragmentref.module-->]]>
-
-<!ENTITY % synopfragment.module "INCLUDE">
-<![%synopfragment.module;[
-<!ENTITY % local.synopfragment.attrib "">
-<!ENTITY % synopfragment.role.attrib "%role.attrib;">
-
-<!ENTITY % synopfragment.element "INCLUDE">
-<![%synopfragment.element;[
-<!--doc:A portion of a CmdSynopsis broken out from the main body of the synopsis.-->
-<!ELEMENT synopfragment %ho; ((arg | group)+)>
-<!--end of synopfragment.element-->]]>
-
-<!ENTITY % synopfragment.attlist "INCLUDE">
-<![%synopfragment.attlist;[
-<!ATTLIST synopfragment
- %idreq.common.attrib;
- %synopfragment.role.attrib;
- %local.synopfragment.attrib;
->
-<!--end of synopfragment.attlist-->]]>
-<!--end of synopfragment.module-->]]>
-
-<!-- Command (defined in the Inlines section, below)-->
-<!-- Option (defined in the Inlines section, below)-->
-<!-- Replaceable (defined in the Inlines section, below)-->
-<!--end of cmdsynopsis.content.module-->]]>
-
-<!-- FuncSynopsis ..................... -->
-
-<!ENTITY % funcsynopsis.content.module "INCLUDE">
-<![%funcsynopsis.content.module;[
-<!ENTITY % funcsynopsis.module "INCLUDE">
-<![%funcsynopsis.module;[
-
-<!ENTITY % local.funcsynopsis.attrib "">
-<!ENTITY % funcsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % funcsynopsis.element "INCLUDE">
-<![%funcsynopsis.element;[
-<!--doc:The syntax summary for a function definition.-->
-<!ELEMENT funcsynopsis %ho; ((funcsynopsisinfo | funcprototype)+)>
-<!--end of funcsynopsis.element-->]]>
-
-<!ENTITY % funcsynopsis.attlist "INCLUDE">
-<![%funcsynopsis.attlist;[
-<!ATTLIST funcsynopsis
- %label.attrib;
- %common.attrib;
- %funcsynopsis.role.attrib;
- %local.funcsynopsis.attrib;
->
-<!--end of funcsynopsis.attlist-->]]>
-<!--end of funcsynopsis.module-->]]>
-
-<!ENTITY % funcsynopsisinfo.module "INCLUDE">
-<![%funcsynopsisinfo.module;[
-<!ENTITY % local.funcsynopsisinfo.attrib "">
-<!ENTITY % funcsynopsisinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % funcsynopsisinfo.element "INCLUDE">
-<![%funcsynopsisinfo.element;[
-<!--doc:Information supplementing the FuncDefs of a FuncSynopsis.-->
-<!ELEMENT funcsynopsisinfo %ho; (%cptr.char.mix;|textobject|lineannotation)*>
-<!--end of funcsynopsisinfo.element-->]]>
-
-<!ENTITY % funcsynopsisinfo.attlist "INCLUDE">
-<![%funcsynopsisinfo.attlist;[
-<!ATTLIST funcsynopsisinfo
- %linespecific.attrib;
- %common.attrib;
- %funcsynopsisinfo.role.attrib;
- %local.funcsynopsisinfo.attrib;
->
-<!--end of funcsynopsisinfo.attlist-->]]>
-<!--end of funcsynopsisinfo.module-->]]>
-
-<!ENTITY % funcprototype.module "INCLUDE">
-<![%funcprototype.module;[
-<!ENTITY % local.funcprototype.attrib "">
-<!ENTITY % funcprototype.role.attrib "%role.attrib;">
-
-<!ENTITY % funcprototype.element "INCLUDE">
-<![%funcprototype.element;[
-<!--doc:The prototype of a function.-->
-<!ELEMENT funcprototype %ho; (modifier*,
- funcdef,
- (void|varargs|(paramdef+, varargs?)),
- modifier*)>
-
-<!--end of funcprototype.element-->]]>
-
-<!ENTITY % funcprototype.attlist "INCLUDE">
-<![%funcprototype.attlist;[
-<!ATTLIST funcprototype
- %common.attrib;
- %funcprototype.role.attrib;
- %local.funcprototype.attrib;
->
-<!--end of funcprototype.attlist-->]]>
-<!--end of funcprototype.module-->]]>
-
-<!ENTITY % funcdef.module "INCLUDE">
-<![%funcdef.module;[
-<!ENTITY % local.funcdef.attrib "">
-<!ENTITY % funcdef.role.attrib "%role.attrib;">
-
-<!ENTITY % funcdef.element "INCLUDE">
-<![%funcdef.element;[
-<!--doc:A function (subroutine) name and its return type.-->
-<!ELEMENT funcdef %ho; (#PCDATA
- | type
- | replaceable
- | function)*>
-<!--end of funcdef.element-->]]>
-
-<!ENTITY % funcdef.attlist "INCLUDE">
-<![%funcdef.attlist;[
-<!ATTLIST funcdef
- %common.attrib;
- %funcdef.role.attrib;
- %local.funcdef.attrib;
->
-<!--end of funcdef.attlist-->]]>
-<!--end of funcdef.module-->]]>
-
-<!ENTITY % void.module "INCLUDE">
-<![%void.module;[
-<!ENTITY % local.void.attrib "">
-<!ENTITY % void.role.attrib "%role.attrib;">
-
-<!ENTITY % void.element "INCLUDE">
-<![%void.element;[
-<!--doc:An empty element in a function synopsis indicating that the function in question takes no arguments.-->
-<!ELEMENT void %ho; EMPTY>
-<!--end of void.element-->]]>
-
-<!ENTITY % void.attlist "INCLUDE">
-<![%void.attlist;[
-<!ATTLIST void
- %common.attrib;
- %void.role.attrib;
- %local.void.attrib;
->
-<!--end of void.attlist-->]]>
-<!--end of void.module-->]]>
-
-<!ENTITY % varargs.module "INCLUDE">
-<![%varargs.module;[
-<!ENTITY % local.varargs.attrib "">
-<!ENTITY % varargs.role.attrib "%role.attrib;">
-
-<!ENTITY % varargs.element "INCLUDE">
-<![%varargs.element;[
-<!--doc:An empty element in a function synopsis indicating a variable number of arguments.-->
-<!ELEMENT varargs %ho; EMPTY>
-<!--end of varargs.element-->]]>
-
-<!ENTITY % varargs.attlist "INCLUDE">
-<![%varargs.attlist;[
-<!ATTLIST varargs
- %common.attrib;
- %varargs.role.attrib;
- %local.varargs.attrib;
->
-<!--end of varargs.attlist-->]]>
-<!--end of varargs.module-->]]>
-
-<!-- Processing assumes that only one Parameter will appear in a
- ParamDef, and that FuncParams will be used at most once, for
- providing information on the "inner parameters" for parameters that
- are pointers to functions. -->
-
-<!ENTITY % paramdef.module "INCLUDE">
-<![%paramdef.module;[
-<!ENTITY % local.paramdef.attrib "">
-<!ENTITY % paramdef.role.attrib "%role.attrib;">
-
-<!ENTITY % paramdef.element "INCLUDE">
-<![%paramdef.element;[
-<!--doc:Information about a function parameter in a programming language.-->
-<!ELEMENT paramdef %ho; (#PCDATA
- | initializer
- | type
- | replaceable
- | parameter
- | funcparams)*>
-<!--end of paramdef.element-->]]>
-
-<!ENTITY % paramdef.attlist "INCLUDE">
-<![%paramdef.attlist;[
-<!ATTLIST paramdef
- choice (opt
- |req) #IMPLIED
- %common.attrib;
- %paramdef.role.attrib;
- %local.paramdef.attrib;
->
-<!--end of paramdef.attlist-->]]>
-<!--end of paramdef.module-->]]>
-
-<!ENTITY % funcparams.module "INCLUDE">
-<![%funcparams.module;[
-<!ENTITY % local.funcparams.attrib "">
-<!ENTITY % funcparams.role.attrib "%role.attrib;">
-
-<!ENTITY % funcparams.element "INCLUDE">
-<![%funcparams.element;[
-<!--doc:Parameters for a function referenced through a function pointer in a synopsis.-->
-<!ELEMENT funcparams %ho; (%cptr.char.mix;)*>
-<!--end of funcparams.element-->]]>
-
-<!ENTITY % funcparams.attlist "INCLUDE">
-<![%funcparams.attlist;[
-<!ATTLIST funcparams
- %common.attrib;
- %funcparams.role.attrib;
- %local.funcparams.attrib;
->
-<!--end of funcparams.attlist-->]]>
-<!--end of funcparams.module-->]]>
-
-<!-- LineAnnotation (defined in the Inlines section, below)-->
-<!-- Replaceable (defined in the Inlines section, below)-->
-<!-- Function (defined in the Inlines section, below)-->
-<!-- Parameter (defined in the Inlines section, below)-->
-<!--end of funcsynopsis.content.module-->]]>
-
-<!-- ClassSynopsis ..................... -->
-
-<!ENTITY % classsynopsis.content.module "INCLUDE">
-<![%classsynopsis.content.module;[
-
-<!ENTITY % classsynopsis.module "INCLUDE">
-<![%classsynopsis.module;[
-<!ENTITY % local.classsynopsis.attrib "">
-<!ENTITY % classsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % classsynopsis.element "INCLUDE">
-<![%classsynopsis.element;[
-<!--doc:The syntax summary for a class definition.-->
-<!ELEMENT classsynopsis %ho; ((ooclass|oointerface|ooexception)+,
- (classsynopsisinfo
- |fieldsynopsis|%method.synop.class;)*)>
-<!--end of classsynopsis.element-->]]>
-
-<!ENTITY % classsynopsis.attlist "INCLUDE">
-<![%classsynopsis.attlist;[
-<!ATTLIST classsynopsis
- language CDATA #IMPLIED
- class (class|interface) "class"
- %common.attrib;
- %classsynopsis.role.attrib;
- %local.classsynopsis.attrib;
->
-<!--end of classsynopsis.attlist-->]]>
-<!--end of classsynopsis.module-->]]>
-
-<!ENTITY % classsynopsisinfo.module "INCLUDE">
-<![ %classsynopsisinfo.module; [
-<!ENTITY % local.classsynopsisinfo.attrib "">
-<!ENTITY % classsynopsisinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % classsynopsisinfo.element "INCLUDE">
-<![ %classsynopsisinfo.element; [
-<!--doc:Information supplementing the contents of a ClassSynopsis.-->
-<!ELEMENT classsynopsisinfo %ho; (%cptr.char.mix;|textobject|lineannotation)*>
-<!--end of classsynopsisinfo.element-->]]>
-
-<!ENTITY % classsynopsisinfo.attlist "INCLUDE">
-<![ %classsynopsisinfo.attlist; [
-<!ATTLIST classsynopsisinfo
- %linespecific.attrib;
- %common.attrib;
- %classsynopsisinfo.role.attrib;
- %local.classsynopsisinfo.attrib;
->
-<!--end of classsynopsisinfo.attlist-->]]>
-<!--end of classsynopsisinfo.module-->]]>
-
-<!ENTITY % ooclass.module "INCLUDE">
-<![%ooclass.module;[
-<!ENTITY % local.ooclass.attrib "">
-<!ENTITY % ooclass.role.attrib "%role.attrib;">
-
-<!ENTITY % ooclass.element "INCLUDE">
-<![%ooclass.element;[
-<!--doc:A class in an object-oriented programming language.-->
-<!ELEMENT ooclass %ho; ((modifier|package)*, classname)>
-<!--end of ooclass.element-->]]>
-
-<!ENTITY % ooclass.attlist "INCLUDE">
-<![%ooclass.attlist;[
-<!ATTLIST ooclass
- %common.attrib;
- %ooclass.role.attrib;
- %local.ooclass.attrib;
->
-<!--end of ooclass.attlist-->]]>
-<!--end of ooclass.module-->]]>
-
-<!ENTITY % oointerface.module "INCLUDE">
-<![%oointerface.module;[
-<!ENTITY % local.oointerface.attrib "">
-<!ENTITY % oointerface.role.attrib "%role.attrib;">
-
-<!ENTITY % oointerface.element "INCLUDE">
-<![%oointerface.element;[
-<!--doc:An interface in an object-oriented programming language.-->
-<!ELEMENT oointerface %ho; ((modifier|package)*, interfacename)>
-<!--end of oointerface.element-->]]>
-
-<!ENTITY % oointerface.attlist "INCLUDE">
-<![%oointerface.attlist;[
-<!ATTLIST oointerface
- %common.attrib;
- %oointerface.role.attrib;
- %local.oointerface.attrib;
->
-<!--end of oointerface.attlist-->]]>
-<!--end of oointerface.module-->]]>
-
-<!ENTITY % ooexception.module "INCLUDE">
-<![%ooexception.module;[
-<!ENTITY % local.ooexception.attrib "">
-<!ENTITY % ooexception.role.attrib "%role.attrib;">
-
-<!ENTITY % ooexception.element "INCLUDE">
-<![%ooexception.element;[
-<!--doc:An exception in an object-oriented programming language.-->
-<!ELEMENT ooexception %ho; ((modifier|package)*, exceptionname)>
-<!--end of ooexception.element-->]]>
-
-<!ENTITY % ooexception.attlist "INCLUDE">
-<![%ooexception.attlist;[
-<!ATTLIST ooexception
- %common.attrib;
- %ooexception.role.attrib;
- %local.ooexception.attrib;
->
-<!--end of ooexception.attlist-->]]>
-<!--end of ooexception.module-->]]>
-
-<!ENTITY % modifier.module "INCLUDE">
-<![%modifier.module;[
-<!ENTITY % local.modifier.attrib "">
-<!ENTITY % modifier.role.attrib "%role.attrib;">
-
-<!ENTITY % modifier.element "INCLUDE">
-<![%modifier.element;[
-<!--doc:Modifiers in a synopsis.-->
-<!ELEMENT modifier %ho; (%smallcptr.char.mix;)*>
-<!--end of modifier.element-->]]>
-
-<!ENTITY % modifier.attlist "INCLUDE">
-<![%modifier.attlist;[
-<!ATTLIST modifier
- %common.attrib;
- %modifier.role.attrib;
- %local.modifier.attrib;
->
-<!--end of modifier.attlist-->]]>
-<!--end of modifier.module-->]]>
-
-<!ENTITY % interfacename.module "INCLUDE">
-<![%interfacename.module;[
-<!ENTITY % local.interfacename.attrib "">
-<!ENTITY % interfacename.role.attrib "%role.attrib;">
-
-<!ENTITY % interfacename.element "INCLUDE">
-<![%interfacename.element;[
-<!--doc:The name of an interface.-->
-<!ELEMENT interfacename %ho; (%cptr.char.mix;)*>
-<!--end of interfacename.element-->]]>
-
-<!ENTITY % interfacename.attlist "INCLUDE">
-<![%interfacename.attlist;[
-<!ATTLIST interfacename
- %common.attrib;
- %interfacename.role.attrib;
- %local.interfacename.attrib;
->
-<!--end of interfacename.attlist-->]]>
-<!--end of interfacename.module-->]]>
-
-<!ENTITY % exceptionname.module "INCLUDE">
-<![%exceptionname.module;[
-<!ENTITY % local.exceptionname.attrib "">
-<!ENTITY % exceptionname.role.attrib "%role.attrib;">
-
-<!ENTITY % exceptionname.element "INCLUDE">
-<![%exceptionname.element;[
-<!--doc:The name of an exception.-->
-<!ELEMENT exceptionname %ho; (%smallcptr.char.mix;)*>
-<!--end of exceptionname.element-->]]>
-
-<!ENTITY % exceptionname.attlist "INCLUDE">
-<![%exceptionname.attlist;[
-<!ATTLIST exceptionname
- %common.attrib;
- %exceptionname.role.attrib;
- %local.exceptionname.attrib;
->
-<!--end of exceptionname.attlist-->]]>
-<!--end of exceptionname.module-->]]>
-
-<!ENTITY % fieldsynopsis.module "INCLUDE">
-<![%fieldsynopsis.module;[
-<!ENTITY % local.fieldsynopsis.attrib "">
-<!ENTITY % fieldsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % fieldsynopsis.element "INCLUDE">
-<![%fieldsynopsis.element;[
-<!--doc:The name of a field in a class definition.-->
-<!ELEMENT fieldsynopsis %ho; (modifier*, type?, varname, initializer?)>
-<!--end of fieldsynopsis.element-->]]>
-
-<!ENTITY % fieldsynopsis.attlist "INCLUDE">
-<![%fieldsynopsis.attlist;[
-<!ATTLIST fieldsynopsis
- language CDATA #IMPLIED
- %common.attrib;
- %fieldsynopsis.role.attrib;
- %local.fieldsynopsis.attrib;
->
-<!--end of fieldsynopsis.attlist-->]]>
-<!--end of fieldsynopsis.module-->]]>
-
-<!ENTITY % initializer.module "INCLUDE">
-<![%initializer.module;[
-<!ENTITY % local.initializer.attrib "">
-<!ENTITY % initializer.role.attrib "%role.attrib;">
-
-<!ENTITY % initializer.element "INCLUDE">
-<![%initializer.element;[
-<!--doc:The initializer for a FieldSynopsis.-->
-<!ELEMENT initializer %ho; (%smallcptr.char.mix;)*>
-<!--end of initializer.element-->]]>
-
-<!ENTITY % initializer.attlist "INCLUDE">
-<![%initializer.attlist;[
-<!ATTLIST initializer
- %common.attrib;
- %initializer.role.attrib;
- %local.initializer.attrib;
->
-<!--end of initializer.attlist-->]]>
-<!--end of initializer.module-->]]>
-
-<!ENTITY % constructorsynopsis.module "INCLUDE">
-<![%constructorsynopsis.module;[
-<!ENTITY % local.constructorsynopsis.attrib "">
-<!ENTITY % constructorsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % constructorsynopsis.element "INCLUDE">
-<![%constructorsynopsis.element;[
-<!--doc:A syntax summary for a constructor.-->
-<!ELEMENT constructorsynopsis %ho; (modifier*,
- methodname?,
- (methodparam+|void?),
- exceptionname*)>
-<!--end of constructorsynopsis.element-->]]>
-
-<!ENTITY % constructorsynopsis.attlist "INCLUDE">
-<![%constructorsynopsis.attlist;[
-<!ATTLIST constructorsynopsis
- language CDATA #IMPLIED
- %common.attrib;
- %constructorsynopsis.role.attrib;
- %local.constructorsynopsis.attrib;
->
-<!--end of constructorsynopsis.attlist-->]]>
-<!--end of constructorsynopsis.module-->]]>
-
-<!ENTITY % destructorsynopsis.module "INCLUDE">
-<![%destructorsynopsis.module;[
-<!ENTITY % local.destructorsynopsis.attrib "">
-<!ENTITY % destructorsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % destructorsynopsis.element "INCLUDE">
-<![%destructorsynopsis.element;[
-<!--doc:A syntax summary for a destructor.-->
-<!ELEMENT destructorsynopsis %ho; (modifier*,
- methodname?,
- (methodparam+|void?),
- exceptionname*)>
-<!--end of destructorsynopsis.element-->]]>
-
-<!ENTITY % destructorsynopsis.attlist "INCLUDE">
-<![%destructorsynopsis.attlist;[
-<!ATTLIST destructorsynopsis
- language CDATA #IMPLIED
- %common.attrib;
- %destructorsynopsis.role.attrib;
- %local.destructorsynopsis.attrib;
->
-<!--end of destructorsynopsis.attlist-->]]>
-<!--end of destructorsynopsis.module-->]]>
-
-<!ENTITY % methodsynopsis.module "INCLUDE">
-<![%methodsynopsis.module;[
-<!ENTITY % local.methodsynopsis.attrib "">
-<!ENTITY % methodsynopsis.role.attrib "%role.attrib;">
-
-<!ENTITY % methodsynopsis.element "INCLUDE">
-<![%methodsynopsis.element;[
-<!--doc:A syntax summary for a method.-->
-<!ELEMENT methodsynopsis %ho; (modifier*,
- (type|void)?,
- methodname,
- (methodparam+|void?),
- exceptionname*,
- modifier*)>
-<!--end of methodsynopsis.element-->]]>
-
-<!ENTITY % methodsynopsis.attlist "INCLUDE">
-<![%methodsynopsis.attlist;[
-<!ATTLIST methodsynopsis
- language CDATA #IMPLIED
- %common.attrib;
- %methodsynopsis.role.attrib;
- %local.methodsynopsis.attrib;
->
-<!--end of methodsynopsis.attlist-->]]>
-<!--end of methodsynopsis.module-->]]>
-
-<!ENTITY % methodname.module "INCLUDE">
-<![%methodname.module;[
-<!ENTITY % local.methodname.attrib "">
-<!ENTITY % methodname.role.attrib "%role.attrib;">
-
-<!ENTITY % methodname.element "INCLUDE">
-<![%methodname.element;[
-<!--doc:The name of a method.-->
-<!ELEMENT methodname %ho; (%smallcptr.char.mix;)*>
-<!--end of methodname.element-->]]>
-
-<!ENTITY % methodname.attlist "INCLUDE">
-<![%methodname.attlist;[
-<!ATTLIST methodname
- %common.attrib;
- %methodname.role.attrib;
- %local.methodname.attrib;
->
-<!--end of methodname.attlist-->]]>
-<!--end of methodname.module-->]]>
-
-<!ENTITY % methodparam.module "INCLUDE">
-<![%methodparam.module;[
-<!ENTITY % local.methodparam.attrib "">
-<!ENTITY % methodparam.role.attrib "%role.attrib;">
-
-<!ENTITY % methodparam.element "INCLUDE">
-<![%methodparam.element;[
-<!--doc:Parameters to a method.-->
-<!ELEMENT methodparam %ho; (modifier*,
- type?,
- ((parameter,initializer?)|funcparams),
- modifier*)>
-<!--end of methodparam.element-->]]>
-
-<!ENTITY % methodparam.attlist "INCLUDE">
-<![%methodparam.attlist;[
-<!ATTLIST methodparam
- choice (opt
- |req
- |plain) "req"
- rep (norepeat
- |repeat) "norepeat"
- %common.attrib;
- %methodparam.role.attrib;
- %local.methodparam.attrib;
->
-<!--end of methodparam.attlist-->]]>
-<!--end of methodparam.module-->]]>
-<!--end of classsynopsis.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Document information entities and elements ........................... -->
-
-<!-- The document information elements include some elements that are
- currently used only in the document hierarchy module. They are
- defined here so that they will be available for use in customized
- document hierarchies. -->
-
-<!-- .................................. -->
-
-<!ENTITY % docinfo.content.module "INCLUDE">
-<![%docinfo.content.module;[
-
-<!-- Ackno ............................ -->
-
-<!ENTITY % ackno.module "INCLUDE">
-<![%ackno.module;[
-<!ENTITY % local.ackno.attrib "">
-<!ENTITY % ackno.role.attrib "%role.attrib;">
-
-<!ENTITY % ackno.element "INCLUDE">
-<![%ackno.element;[
-<!--doc:Acknowledgements in an Article.-->
-<!ELEMENT ackno %ho; (%docinfo.char.mix;)*>
-<!--end of ackno.element-->]]>
-
-<!ENTITY % ackno.attlist "INCLUDE">
-<![%ackno.attlist;[
-<!ATTLIST ackno
- %common.attrib;
- %ackno.role.attrib;
- %local.ackno.attrib;
->
-<!--end of ackno.attlist-->]]>
-<!--end of ackno.module-->]]>
-
-<!-- Address .......................... -->
-
-<!ENTITY % address.content.module "INCLUDE">
-<![%address.content.module;[
-<!ENTITY % address.module "INCLUDE">
-<![%address.module;[
-<!ENTITY % local.address.attrib "">
-<!ENTITY % address.role.attrib "%role.attrib;">
-
-<!ENTITY % address.element "INCLUDE">
-<![%address.element;[
-<!--doc:A real-world address, generally a postal address.-->
-<!ELEMENT address %ho; (#PCDATA|personname|%person.ident.mix;
- |street|pob|postcode|city|state|country|phone
- |fax|email|otheraddr)*>
-<!--end of address.element-->]]>
-
-<!ENTITY % address.attlist "INCLUDE">
-<![%address.attlist;[
-<!ATTLIST address
- %linespecific.attrib;
- %common.attrib;
- %address.role.attrib;
- %local.address.attrib;
->
-<!--end of address.attlist-->]]>
-<!--end of address.module-->]]>
-
- <!ENTITY % street.module "INCLUDE">
- <![%street.module;[
- <!ENTITY % local.street.attrib "">
- <!ENTITY % street.role.attrib "%role.attrib;">
-
-<!ENTITY % street.element "INCLUDE">
-<![%street.element;[
-<!--doc:A street address in an address.-->
-<!ELEMENT street %ho; (%docinfo.char.mix;)*>
-<!--end of street.element-->]]>
-
-<!ENTITY % street.attlist "INCLUDE">
-<![%street.attlist;[
-<!ATTLIST street
- %common.attrib;
- %street.role.attrib;
- %local.street.attrib;
->
-<!--end of street.attlist-->]]>
- <!--end of street.module-->]]>
-
- <!ENTITY % pob.module "INCLUDE">
- <![%pob.module;[
- <!ENTITY % local.pob.attrib "">
- <!ENTITY % pob.role.attrib "%role.attrib;">
-
-<!ENTITY % pob.element "INCLUDE">
-<![%pob.element;[
-<!--doc:A post office box in an address.-->
-<!ELEMENT pob %ho; (%docinfo.char.mix;)*>
-<!--end of pob.element-->]]>
-
-<!ENTITY % pob.attlist "INCLUDE">
-<![%pob.attlist;[
-<!ATTLIST pob
- %common.attrib;
- %pob.role.attrib;
- %local.pob.attrib;
->
-<!--end of pob.attlist-->]]>
- <!--end of pob.module-->]]>
-
- <!ENTITY % postcode.module "INCLUDE">
- <![%postcode.module;[
- <!ENTITY % local.postcode.attrib "">
- <!ENTITY % postcode.role.attrib "%role.attrib;">
-
-<!ENTITY % postcode.element "INCLUDE">
-<![%postcode.element;[
-<!--doc:A postal code in an address.-->
-<!ELEMENT postcode %ho; (%docinfo.char.mix;)*>
-<!--end of postcode.element-->]]>
-
-<!ENTITY % postcode.attlist "INCLUDE">
-<![%postcode.attlist;[
-<!ATTLIST postcode
- %common.attrib;
- %postcode.role.attrib;
- %local.postcode.attrib;
->
-<!--end of postcode.attlist-->]]>
- <!--end of postcode.module-->]]>
-
- <!ENTITY % city.module "INCLUDE">
- <![%city.module;[
- <!ENTITY % local.city.attrib "">
- <!ENTITY % city.role.attrib "%role.attrib;">
-
-<!ENTITY % city.element "INCLUDE">
-<![%city.element;[
-<!--doc:The name of a city in an address.-->
-<!ELEMENT city %ho; (%docinfo.char.mix;)*>
-<!--end of city.element-->]]>
-
-<!ENTITY % city.attlist "INCLUDE">
-<![%city.attlist;[
-<!ATTLIST city
- %common.attrib;
- %city.role.attrib;
- %local.city.attrib;
->
-<!--end of city.attlist-->]]>
- <!--end of city.module-->]]>
-
- <!ENTITY % state.module "INCLUDE">
- <![%state.module;[
- <!ENTITY % local.state.attrib "">
- <!ENTITY % state.role.attrib "%role.attrib;">
-
-<!ENTITY % state.element "INCLUDE">
-<![%state.element;[
-<!--doc:A state or province in an address.-->
-<!ELEMENT state %ho; (%docinfo.char.mix;)*>
-<!--end of state.element-->]]>
-
-<!ENTITY % state.attlist "INCLUDE">
-<![%state.attlist;[
-<!ATTLIST state
- %common.attrib;
- %state.role.attrib;
- %local.state.attrib;
->
-<!--end of state.attlist-->]]>
- <!--end of state.module-->]]>
-
- <!ENTITY % country.module "INCLUDE">
- <![%country.module;[
- <!ENTITY % local.country.attrib "">
- <!ENTITY % country.role.attrib "%role.attrib;">
-
-<!ENTITY % country.element "INCLUDE">
-<![%country.element;[
-<!--doc:The name of a country.-->
-<!ELEMENT country %ho; (%docinfo.char.mix;)*>
-<!--end of country.element-->]]>
-
-<!ENTITY % country.attlist "INCLUDE">
-<![%country.attlist;[
-<!ATTLIST country
- %common.attrib;
- %country.role.attrib;
- %local.country.attrib;
->
-<!--end of country.attlist-->]]>
- <!--end of country.module-->]]>
-
- <!ENTITY % phone.module "INCLUDE">
- <![%phone.module;[
- <!ENTITY % local.phone.attrib "">
- <!ENTITY % phone.role.attrib "%role.attrib;">
-
-<!ENTITY % phone.element "INCLUDE">
-<![%phone.element;[
-<!--doc:A telephone number.-->
-<!ELEMENT phone %ho; (%docinfo.char.mix;)*>
-<!--end of phone.element-->]]>
-
-<!ENTITY % phone.attlist "INCLUDE">
-<![%phone.attlist;[
-<!ATTLIST phone
- %common.attrib;
- %phone.role.attrib;
- %local.phone.attrib;
->
-<!--end of phone.attlist-->]]>
- <!--end of phone.module-->]]>
-
- <!ENTITY % fax.module "INCLUDE">
- <![%fax.module;[
- <!ENTITY % local.fax.attrib "">
- <!ENTITY % fax.role.attrib "%role.attrib;">
-
-<!ENTITY % fax.element "INCLUDE">
-<![%fax.element;[
-<!--doc:A fax number.-->
-<!ELEMENT fax %ho; (%docinfo.char.mix;)*>
-<!--end of fax.element-->]]>
-
-<!ENTITY % fax.attlist "INCLUDE">
-<![%fax.attlist;[
-<!ATTLIST fax
- %common.attrib;
- %fax.role.attrib;
- %local.fax.attrib;
->
-<!--end of fax.attlist-->]]>
- <!--end of fax.module-->]]>
-
- <!-- Email (defined in the Inlines section, below)-->
-
- <!ENTITY % otheraddr.module "INCLUDE">
- <![%otheraddr.module;[
- <!ENTITY % local.otheraddr.attrib "">
- <!ENTITY % otheraddr.role.attrib "%role.attrib;">
-
-<!ENTITY % otheraddr.element "INCLUDE">
-<![%otheraddr.element;[
-<!--doc:Uncategorized information in address.-->
-<!ELEMENT otheraddr %ho; (%docinfo.char.mix;)*>
-<!--end of otheraddr.element-->]]>
-
-<!ENTITY % otheraddr.attlist "INCLUDE">
-<![%otheraddr.attlist;[
-<!ATTLIST otheraddr
- %common.attrib;
- %otheraddr.role.attrib;
- %local.otheraddr.attrib;
->
-<!--end of otheraddr.attlist-->]]>
- <!--end of otheraddr.module-->]]>
-<!--end of address.content.module-->]]>
-
-<!-- Affiliation ...................... -->
-
-<!ENTITY % affiliation.content.module "INCLUDE">
-<![%affiliation.content.module;[
-<!ENTITY % affiliation.module "INCLUDE">
-<![%affiliation.module;[
-<!ENTITY % local.affiliation.attrib "">
-<!ENTITY % affiliation.role.attrib "%role.attrib;">
-
-<!ENTITY % affiliation.element "INCLUDE">
-<![%affiliation.element;[
-<!--doc:The institutional affiliation of an individual.-->
-<!ELEMENT affiliation %ho; (shortaffil?, jobtitle*, orgname?, orgdiv*,
- address*)>
-<!--end of affiliation.element-->]]>
-
-<!ENTITY % affiliation.attlist "INCLUDE">
-<![%affiliation.attlist;[
-<!ATTLIST affiliation
- %common.attrib;
- %affiliation.role.attrib;
- %local.affiliation.attrib;
->
-<!--end of affiliation.attlist-->]]>
-<!--end of affiliation.module-->]]>
-
- <!ENTITY % shortaffil.module "INCLUDE">
- <![%shortaffil.module;[
- <!ENTITY % local.shortaffil.attrib "">
- <!ENTITY % shortaffil.role.attrib "%role.attrib;">
-
-<!ENTITY % shortaffil.element "INCLUDE">
-<![%shortaffil.element;[
-<!--doc:A brief description of an affiliation.-->
-<!ELEMENT shortaffil %ho; (%docinfo.char.mix;)*>
-<!--end of shortaffil.element-->]]>
-
-<!ENTITY % shortaffil.attlist "INCLUDE">
-<![%shortaffil.attlist;[
-<!ATTLIST shortaffil
- %common.attrib;
- %shortaffil.role.attrib;
- %local.shortaffil.attrib;
->
-<!--end of shortaffil.attlist-->]]>
- <!--end of shortaffil.module-->]]>
-
- <!ENTITY % jobtitle.module "INCLUDE">
- <![%jobtitle.module;[
- <!ENTITY % local.jobtitle.attrib "">
- <!ENTITY % jobtitle.role.attrib "%role.attrib;">
-
-<!ENTITY % jobtitle.element "INCLUDE">
-<![%jobtitle.element;[
-<!--doc:The title of an individual in an organization.-->
-<!ELEMENT jobtitle %ho; (%docinfo.char.mix;)*>
-<!--end of jobtitle.element-->]]>
-
-<!ENTITY % jobtitle.attlist "INCLUDE">
-<![%jobtitle.attlist;[
-<!ATTLIST jobtitle
- %common.attrib;
- %jobtitle.role.attrib;
- %local.jobtitle.attrib;
->
-<!--end of jobtitle.attlist-->]]>
- <!--end of jobtitle.module-->]]>
-
- <!-- OrgName (defined elsewhere in this section)-->
-
- <!ENTITY % orgdiv.module "INCLUDE">
- <![%orgdiv.module;[
- <!ENTITY % local.orgdiv.attrib "">
- <!ENTITY % orgdiv.role.attrib "%role.attrib;">
-
-<!ENTITY % orgdiv.element "INCLUDE">
-<![%orgdiv.element;[
-<!--doc:A division of an organization.-->
-<!ELEMENT orgdiv %ho; (%docinfo.char.mix;)*>
-<!--end of orgdiv.element-->]]>
-
-<!ENTITY % orgdiv.attlist "INCLUDE">
-<![%orgdiv.attlist;[
-<!ATTLIST orgdiv
- %common.attrib;
- %orgdiv.role.attrib;
- %local.orgdiv.attrib;
->
-<!--end of orgdiv.attlist-->]]>
- <!--end of orgdiv.module-->]]>
-
- <!-- Address (defined elsewhere in this section)-->
-<!--end of affiliation.content.module-->]]>
-
-<!-- ArtPageNums ...................... -->
-
-<!ENTITY % artpagenums.module "INCLUDE">
-<![%artpagenums.module;[
-<!ENTITY % local.artpagenums.attrib "">
-<!ENTITY % artpagenums.role.attrib "%role.attrib;">
-
-<!ENTITY % artpagenums.element "INCLUDE">
-<![%artpagenums.element;[
-<!--doc:The page numbers of an article as published.-->
-<!ELEMENT artpagenums %ho; (%docinfo.char.mix;)*>
-<!--end of artpagenums.element-->]]>
-
-<!ENTITY % artpagenums.attlist "INCLUDE">
-<![%artpagenums.attlist;[
-<!ATTLIST artpagenums
- %common.attrib;
- %artpagenums.role.attrib;
- %local.artpagenums.attrib;
->
-<!--end of artpagenums.attlist-->]]>
-<!--end of artpagenums.module-->]]>
-
-<!-- PersonName -->
-
-<!ENTITY % personname.module "INCLUDE">
-<![%personname.module;[
-<!ENTITY % local.personname.attrib "">
-<!ENTITY % personname.role.attrib "%role.attrib;">
-
-<!ENTITY % personname.element "INCLUDE">
-<![%personname.element;[
-<!--doc:The personal name of an individual.-->
-<!ELEMENT personname %ho; ((honorific|firstname|surname|lineage|othername)+)>
-<!--end of personname.element-->]]>
-
-<!ENTITY % personname.attlist "INCLUDE">
-<![%personname.attlist;[
-<!ATTLIST personname
- %common.attrib;
- %personname.role.attrib;
- %local.personname.attrib;
->
-<!--end of personname.attlist-->]]>
-<!--end of personname.module-->]]>
-
-<!-- Author ........................... -->
-
-<!ENTITY % author.module "INCLUDE">
-<![%author.module;[
-<!ENTITY % local.author.attrib "">
-<!ENTITY % author.role.attrib "%role.attrib;">
-
-<!ENTITY % author.element "INCLUDE">
-<![%author.element;[
-<!--doc:The name of an individual author.-->
-<!ELEMENT author %ho; ((personname|(%person.ident.mix;)+),(personblurb|email|address)*)>
-<!--end of author.element-->]]>
-
-<!ENTITY % author.attlist "INCLUDE">
-<![%author.attlist;[
-<!ATTLIST author
- %common.attrib;
- %author.role.attrib;
- %local.author.attrib;
->
-<!--end of author.attlist-->]]>
-<!--(see "Personal identity elements" for %person.ident.mix;)-->
-<!--end of author.module-->]]>
-
-<!-- AuthorGroup ...................... -->
-
-<!ENTITY % authorgroup.content.module "INCLUDE">
-<![%authorgroup.content.module;[
-<!ENTITY % authorgroup.module "INCLUDE">
-<![%authorgroup.module;[
-<!ENTITY % local.authorgroup.attrib "">
-<!ENTITY % authorgroup.role.attrib "%role.attrib;">
-
-<!ENTITY % authorgroup.element "INCLUDE">
-<![%authorgroup.element;[
-<!--doc:Wrapper for author information when a document has multiple authors or collabarators.-->
-<!ELEMENT authorgroup %ho; ((author|editor|collab|corpauthor|corpcredit|othercredit)+)>
-<!--end of authorgroup.element-->]]>
-
-<!ENTITY % authorgroup.attlist "INCLUDE">
-<![%authorgroup.attlist;[
-<!ATTLIST authorgroup
- %common.attrib;
- %authorgroup.role.attrib;
- %local.authorgroup.attrib;
->
-<!--end of authorgroup.attlist-->]]>
-<!--end of authorgroup.module-->]]>
-
- <!-- Author (defined elsewhere in this section)-->
- <!-- Editor (defined elsewhere in this section)-->
-
- <!ENTITY % collab.content.module "INCLUDE">
- <![%collab.content.module;[
- <!ENTITY % collab.module "INCLUDE">
- <![%collab.module;[
- <!ENTITY % local.collab.attrib "">
- <!ENTITY % collab.role.attrib "%role.attrib;">
-
-<!ENTITY % collab.element "INCLUDE">
-<![%collab.element;[
-<!--doc:Identifies a collaborator.-->
-<!ELEMENT collab %ho; (collabname, affiliation*)>
-<!--end of collab.element-->]]>
-
-<!ENTITY % collab.attlist "INCLUDE">
-<![%collab.attlist;[
-<!ATTLIST collab
- %common.attrib;
- %collab.role.attrib;
- %local.collab.attrib;
->
-<!--end of collab.attlist-->]]>
- <!--end of collab.module-->]]>
-
- <!ENTITY % collabname.module "INCLUDE">
- <![%collabname.module;[
- <!ENTITY % local.collabname.attrib "">
- <!ENTITY % collabname.role.attrib "%role.attrib;">
-
-<!ENTITY % collabname.element "INCLUDE">
-<![%collabname.element;[
-<!--doc:The name of a collaborator.-->
-<!ELEMENT collabname %ho; (%docinfo.char.mix;)*>
-<!--end of collabname.element-->]]>
-
-<!ENTITY % collabname.attlist "INCLUDE">
-<![%collabname.attlist;[
-<!ATTLIST collabname
- %common.attrib;
- %collabname.role.attrib;
- %local.collabname.attrib;
->
-<!--end of collabname.attlist-->]]>
- <!--end of collabname.module-->]]>
-
- <!-- Affiliation (defined elsewhere in this section)-->
- <!--end of collab.content.module-->]]>
-
- <!-- CorpAuthor (defined elsewhere in this section)-->
- <!-- OtherCredit (defined elsewhere in this section)-->
-
-<!--end of authorgroup.content.module-->]]>
-
-<!-- AuthorInitials ................... -->
-
-<!ENTITY % authorinitials.module "INCLUDE">
-<![%authorinitials.module;[
-<!ENTITY % local.authorinitials.attrib "">
-<!ENTITY % authorinitials.role.attrib "%role.attrib;">
-
-<!ENTITY % authorinitials.element "INCLUDE">
-<![%authorinitials.element;[
-<!--doc:The initials or other short identifier for an author.-->
-<!ELEMENT authorinitials %ho; (%docinfo.char.mix;)*>
-<!--end of authorinitials.element-->]]>
-
-<!ENTITY % authorinitials.attlist "INCLUDE">
-<![%authorinitials.attlist;[
-<!ATTLIST authorinitials
- %common.attrib;
- %authorinitials.role.attrib;
- %local.authorinitials.attrib;
->
-<!--end of authorinitials.attlist-->]]>
-<!--end of authorinitials.module-->]]>
-
-<!-- ConfGroup ........................ -->
-
-<!ENTITY % confgroup.content.module "INCLUDE">
-<![%confgroup.content.module;[
-<!ENTITY % confgroup.module "INCLUDE">
-<![%confgroup.module;[
-<!ENTITY % local.confgroup.attrib "">
-<!ENTITY % confgroup.role.attrib "%role.attrib;">
-
-<!ENTITY % confgroup.element "INCLUDE">
-<![%confgroup.element;[
-<!--doc:A wrapper for document meta-information about a conference.-->
-<!ELEMENT confgroup %ho; ((confdates|conftitle|confnum|address|confsponsor)*)>
-<!--end of confgroup.element-->]]>
-
-<!ENTITY % confgroup.attlist "INCLUDE">
-<![%confgroup.attlist;[
-<!ATTLIST confgroup
- %common.attrib;
- %confgroup.role.attrib;
- %local.confgroup.attrib;
->
-<!--end of confgroup.attlist-->]]>
-<!--end of confgroup.module-->]]>
-
- <!ENTITY % confdates.module "INCLUDE">
- <![%confdates.module;[
- <!ENTITY % local.confdates.attrib "">
- <!ENTITY % confdates.role.attrib "%role.attrib;">
-
-<!ENTITY % confdates.element "INCLUDE">
-<![%confdates.element;[
-<!--doc:The dates of a conference for which a document was written.-->
-<!ELEMENT confdates %ho; (%docinfo.char.mix;)*>
-<!--end of confdates.element-->]]>
-
-<!ENTITY % confdates.attlist "INCLUDE">
-<![%confdates.attlist;[
-<!ATTLIST confdates
- %common.attrib;
- %confdates.role.attrib;
- %local.confdates.attrib;
->
-<!--end of confdates.attlist-->]]>
- <!--end of confdates.module-->]]>
-
- <!ENTITY % conftitle.module "INCLUDE">
- <![%conftitle.module;[
- <!ENTITY % local.conftitle.attrib "">
- <!ENTITY % conftitle.role.attrib "%role.attrib;">
-
-<!ENTITY % conftitle.element "INCLUDE">
-<![%conftitle.element;[
-<!--doc:The title of a conference for which a document was written.-->
-<!ELEMENT conftitle %ho; (%docinfo.char.mix;)*>
-<!--end of conftitle.element-->]]>
-
-<!ENTITY % conftitle.attlist "INCLUDE">
-<![%conftitle.attlist;[
-<!ATTLIST conftitle
- %common.attrib;
- %conftitle.role.attrib;
- %local.conftitle.attrib;
->
-<!--end of conftitle.attlist-->]]>
- <!--end of conftitle.module-->]]>
-
- <!ENTITY % confnum.module "INCLUDE">
- <![%confnum.module;[
- <!ENTITY % local.confnum.attrib "">
- <!ENTITY % confnum.role.attrib "%role.attrib;">
-
-<!ENTITY % confnum.element "INCLUDE">
-<![%confnum.element;[
-<!--doc:An identifier, frequently numerical, associated with a conference for which a document was written.-->
-<!ELEMENT confnum %ho; (%docinfo.char.mix;)*>
-<!--end of confnum.element-->]]>
-
-<!ENTITY % confnum.attlist "INCLUDE">
-<![%confnum.attlist;[
-<!ATTLIST confnum
- %common.attrib;
- %confnum.role.attrib;
- %local.confnum.attrib;
->
-<!--end of confnum.attlist-->]]>
- <!--end of confnum.module-->]]>
-
- <!-- Address (defined elsewhere in this section)-->
-
- <!ENTITY % confsponsor.module "INCLUDE">
- <![%confsponsor.module;[
- <!ENTITY % local.confsponsor.attrib "">
- <!ENTITY % confsponsor.role.attrib "%role.attrib;">
-
-<!ENTITY % confsponsor.element "INCLUDE">
-<![%confsponsor.element;[
-<!--doc:The sponsor of a conference for which a document was written.-->
-<!ELEMENT confsponsor %ho; (%docinfo.char.mix;)*>
-<!--end of confsponsor.element-->]]>
-
-<!ENTITY % confsponsor.attlist "INCLUDE">
-<![%confsponsor.attlist;[
-<!ATTLIST confsponsor
- %common.attrib;
- %confsponsor.role.attrib;
- %local.confsponsor.attrib;
->
-<!--end of confsponsor.attlist-->]]>
- <!--end of confsponsor.module-->]]>
-<!--end of confgroup.content.module-->]]>
-
-<!-- ContractNum ...................... -->
-
-<!ENTITY % contractnum.module "INCLUDE">
-<![%contractnum.module;[
-<!ENTITY % local.contractnum.attrib "">
-<!ENTITY % contractnum.role.attrib "%role.attrib;">
-
-<!ENTITY % contractnum.element "INCLUDE">
-<![%contractnum.element;[
-<!--doc:The contract number of a document.-->
-<!ELEMENT contractnum %ho; (%docinfo.char.mix;)*>
-<!--end of contractnum.element-->]]>
-
-<!ENTITY % contractnum.attlist "INCLUDE">
-<![%contractnum.attlist;[
-<!ATTLIST contractnum
- %common.attrib;
- %contractnum.role.attrib;
- %local.contractnum.attrib;
->
-<!--end of contractnum.attlist-->]]>
-<!--end of contractnum.module-->]]>
-
-<!-- ContractSponsor .................. -->
-
-<!ENTITY % contractsponsor.module "INCLUDE">
-<![%contractsponsor.module;[
-<!ENTITY % local.contractsponsor.attrib "">
-<!ENTITY % contractsponsor.role.attrib "%role.attrib;">
-
-<!ENTITY % contractsponsor.element "INCLUDE">
-<![%contractsponsor.element;[
-<!--doc:The sponsor of a contract.-->
-<!ELEMENT contractsponsor %ho; (%docinfo.char.mix;)*>
-<!--end of contractsponsor.element-->]]>
-
-<!ENTITY % contractsponsor.attlist "INCLUDE">
-<![%contractsponsor.attlist;[
-<!ATTLIST contractsponsor
- %common.attrib;
- %contractsponsor.role.attrib;
- %local.contractsponsor.attrib;
->
-<!--end of contractsponsor.attlist-->]]>
-<!--end of contractsponsor.module-->]]>
-
-<!-- Copyright ........................ -->
-
-<!ENTITY % copyright.content.module "INCLUDE">
-<![%copyright.content.module;[
-<!ENTITY % copyright.module "INCLUDE">
-<![%copyright.module;[
-<!ENTITY % local.copyright.attrib "">
-<!ENTITY % copyright.role.attrib "%role.attrib;">
-
-<!ENTITY % copyright.element "INCLUDE">
-<![%copyright.element;[
-<!--doc:Copyright information about a document.-->
-<!ELEMENT copyright %ho; (year+, holder*)>
-<!--end of copyright.element-->]]>
-
-<!ENTITY % copyright.attlist "INCLUDE">
-<![%copyright.attlist;[
-<!ATTLIST copyright
- %common.attrib;
- %copyright.role.attrib;
- %local.copyright.attrib;
->
-<!--end of copyright.attlist-->]]>
-<!--end of copyright.module-->]]>
-
- <!ENTITY % year.module "INCLUDE">
- <![%year.module;[
- <!ENTITY % local.year.attrib "">
- <!ENTITY % year.role.attrib "%role.attrib;">
-
-<!ENTITY % year.element "INCLUDE">
-<![%year.element;[
-<!--doc:The year of publication of a document.-->
-<!ELEMENT year %ho; (%docinfo.char.mix;)*>
-<!--end of year.element-->]]>
-
-<!ENTITY % year.attlist "INCLUDE">
-<![%year.attlist;[
-<!ATTLIST year
- %common.attrib;
- %year.role.attrib;
- %local.year.attrib;
->
-<!--end of year.attlist-->]]>
- <!--end of year.module-->]]>
-
- <!ENTITY % holder.module "INCLUDE">
- <![%holder.module;[
- <!ENTITY % local.holder.attrib "">
- <!ENTITY % holder.role.attrib "%role.attrib;">
-
-<!ENTITY % holder.element "INCLUDE">
-<![%holder.element;[
-<!--doc:The name of the individual or organization that holds a copyright.-->
-<!ELEMENT holder %ho; (%docinfo.char.mix;)*>
-<!--end of holder.element-->]]>
-
-<!ENTITY % holder.attlist "INCLUDE">
-<![%holder.attlist;[
-<!ATTLIST holder
- %common.attrib;
- %holder.role.attrib;
- %local.holder.attrib;
->
-<!--end of holder.attlist-->]]>
- <!--end of holder.module-->]]>
-<!--end of copyright.content.module-->]]>
-
-<!-- CorpAuthor ....................... -->
-
-<!ENTITY % corpauthor.module "INCLUDE">
-<![%corpauthor.module;[
-<!ENTITY % local.corpauthor.attrib "">
-<!ENTITY % corpauthor.role.attrib "%role.attrib;">
-
-<!ENTITY % corpauthor.element "INCLUDE">
-<![%corpauthor.element;[
-<!--doc:A corporate author, as opposed to an individual.-->
-<!ELEMENT corpauthor %ho; (%docinfo.char.mix;)*>
-<!--end of corpauthor.element-->]]>
-
-<!ENTITY % corpauthor.attlist "INCLUDE">
-<![%corpauthor.attlist;[
-<!ATTLIST corpauthor
- %common.attrib;
- %corpauthor.role.attrib;
- %local.corpauthor.attrib;
->
-<!--end of corpauthor.attlist-->]]>
-<!--end of corpauthor.module-->]]>
-
-<!-- CorpCredit ...................... -->
-
-<!ENTITY % corpcredit.module "INCLUDE">
-<![%corpcredit.module;[
-<!ENTITY % local.corpcredit.attrib "">
-<!ENTITY % corpcredit.role.attrib "%role.attrib;">
-
-<!ENTITY % corpcredit.element "INCLUDE">
-<![%corpcredit.element;[
-<!--doc:A corporation or organization credited in a document.-->
-<!ELEMENT corpcredit %ho; (%docinfo.char.mix;)*>
-<!--end of corpcredit.element-->]]>
-
-<!ENTITY % corpcredit.attlist "INCLUDE">
-<![%corpcredit.attlist;[
-<!ATTLIST corpcredit
- class (graphicdesigner
- |productioneditor
- |copyeditor
- |technicaleditor
- |translator
- |other) #IMPLIED
- %common.attrib;
- %corpcredit.role.attrib;
- %local.corpcredit.attrib;
->
-<!--end of corpcredit.attlist-->]]>
-<!--end of corpcredit.module-->]]>
-
-<!-- CorpName ......................... -->
-
-<!ENTITY % corpname.module "INCLUDE">
-<![%corpname.module;[
-<!ENTITY % local.corpname.attrib "">
-
-<!ENTITY % corpname.element "INCLUDE">
-<![%corpname.element;[
-<!--doc:The name of a corporation.-->
-<!ELEMENT corpname %ho; (%docinfo.char.mix;)*>
-<!--end of corpname.element-->]]>
-<!ENTITY % corpname.role.attrib "%role.attrib;">
-
-<!ENTITY % corpname.attlist "INCLUDE">
-<![%corpname.attlist;[
-<!ATTLIST corpname
- %common.attrib;
- %corpname.role.attrib;
- %local.corpname.attrib;
->
-<!--end of corpname.attlist-->]]>
-<!--end of corpname.module-->]]>
-
-<!-- Date ............................. -->
-
-<!ENTITY % date.module "INCLUDE">
-<![%date.module;[
-<!ENTITY % local.date.attrib "">
-<!ENTITY % date.role.attrib "%role.attrib;">
-
-<!ENTITY % date.element "INCLUDE">
-<![%date.element;[
-<!--doc:The date of publication or revision of a document.-->
-<!ELEMENT date %ho; (%docinfo.char.mix;)*>
-<!--end of date.element-->]]>
-
-<!ENTITY % date.attlist "INCLUDE">
-<![%date.attlist;[
-<!ATTLIST date
- %common.attrib;
- %date.role.attrib;
- %local.date.attrib;
->
-<!--end of date.attlist-->]]>
-<!--end of date.module-->]]>
-
-<!-- Edition .......................... -->
-
-<!ENTITY % edition.module "INCLUDE">
-<![%edition.module;[
-<!ENTITY % local.edition.attrib "">
-<!ENTITY % edition.role.attrib "%role.attrib;">
-
-<!ENTITY % edition.element "INCLUDE">
-<![%edition.element;[
-<!--doc:The name or number of an edition of a document.-->
-<!ELEMENT edition %ho; (%docinfo.char.mix;)*>
-<!--end of edition.element-->]]>
-
-<!ENTITY % edition.attlist "INCLUDE">
-<![%edition.attlist;[
-<!ATTLIST edition
- %common.attrib;
- %edition.role.attrib;
- %local.edition.attrib;
->
-<!--end of edition.attlist-->]]>
-<!--end of edition.module-->]]>
-
-<!-- Editor ........................... -->
-
-<!ENTITY % editor.module "INCLUDE">
-<![%editor.module;[
-<!ENTITY % local.editor.attrib "">
-<!ENTITY % editor.role.attrib "%role.attrib;">
-
-<!ENTITY % editor.element "INCLUDE">
-<![%editor.element;[
-<!--doc:The name of the editor of a document.-->
-<!ELEMENT editor %ho; ((personname|(%person.ident.mix;)+),(personblurb|email|address)*)>
-<!--end of editor.element-->]]>
-
-<!ENTITY % editor.attlist "INCLUDE">
-<![%editor.attlist;[
-<!ATTLIST editor
- %common.attrib;
- %editor.role.attrib;
- %local.editor.attrib;
->
-<!--end of editor.attlist-->]]>
- <!--(see "Personal identity elements" for %person.ident.mix;)-->
-<!--end of editor.module-->]]>
-
-<!-- ISBN ............................. -->
-
-<!ENTITY % isbn.module "INCLUDE">
-<![%isbn.module;[
-<!ENTITY % local.isbn.attrib "">
-<!ENTITY % isbn.role.attrib "%role.attrib;">
-
-<!ENTITY % isbn.element "INCLUDE">
-<![%isbn.element;[
-<!--doc:The International Standard Book Number of a document.-->
-<!ELEMENT isbn %ho; (%docinfo.char.mix;)*>
-<!--end of isbn.element-->]]>
-
-<!ENTITY % isbn.attlist "INCLUDE">
-<![%isbn.attlist;[
-<!ATTLIST isbn
- %common.attrib;
- %isbn.role.attrib;
- %local.isbn.attrib;
->
-<!--end of isbn.attlist-->]]>
-<!--end of isbn.module-->]]>
-
-<!-- ISSN ............................. -->
-
-<!ENTITY % issn.module "INCLUDE">
-<![%issn.module;[
-<!ENTITY % local.issn.attrib "">
-<!ENTITY % issn.role.attrib "%role.attrib;">
-
-<!ENTITY % issn.element "INCLUDE">
-<![%issn.element;[
-<!--doc:The International Standard Serial Number of a periodical.-->
-<!ELEMENT issn %ho; (%docinfo.char.mix;)*>
-<!--end of issn.element-->]]>
-
-<!ENTITY % issn.attlist "INCLUDE">
-<![%issn.attlist;[
-<!ATTLIST issn
- %common.attrib;
- %issn.role.attrib;
- %local.issn.attrib;
->
-<!--end of issn.attlist-->]]>
-<!--end of issn.module-->]]>
-
-<!-- BiblioId ................. -->
-<!ENTITY % biblio.class.attrib
- "class (uri
- |doi
- |isbn
- |isrn
- |issn
- |libraryofcongress
- |pubnumber
- |other) #IMPLIED
- otherclass CDATA #IMPLIED"
->
-
-<!ENTITY % biblioid.module "INCLUDE">
-<![%biblioid.module;[
-<!ENTITY % local.biblioid.attrib "">
-<!ENTITY % biblioid.role.attrib "%role.attrib;">
-
-<!ENTITY % biblioid.element "INCLUDE">
-<![%biblioid.element;[
-<!--doc:An identifier for a document.-->
-<!ELEMENT biblioid %ho; (%docinfo.char.mix;)*>
-<!--end of biblioid.element-->]]>
-
-<!ENTITY % biblioid.attlist "INCLUDE">
-<![%biblioid.attlist;[
-<!ATTLIST biblioid
- %biblio.class.attrib;
- %common.attrib;
- %biblioid.role.attrib;
- %local.biblioid.attrib;
->
-<!--end of biblioid.attlist-->]]>
-<!--end of biblioid.module-->]]>
-
-<!-- CiteBiblioId ................. -->
-
-<!ENTITY % citebiblioid.module "INCLUDE">
-<![%citebiblioid.module;[
-<!ENTITY % local.citebiblioid.attrib "">
-<!ENTITY % citebiblioid.role.attrib "%role.attrib;">
-
-<!ENTITY % citebiblioid.element "INCLUDE">
-<![%citebiblioid.element;[
-<!--doc:A citation of a bibliographic identifier.-->
-<!ELEMENT citebiblioid %ho; (%docinfo.char.mix;)*>
-<!--end of citebiblioid.element-->]]>
-
-<!ENTITY % citebiblioid.attlist "INCLUDE">
-<![%citebiblioid.attlist;[
-<!ATTLIST citebiblioid
- %biblio.class.attrib;
- %common.attrib;
- %citebiblioid.role.attrib;
- %local.citebiblioid.attrib;
->
-<!--end of citebiblioid.attlist-->]]>
-<!--end of citebiblioid.module-->]]>
-
-<!-- BiblioSource ................. -->
-
-<!ENTITY % bibliosource.module "INCLUDE">
-<![%bibliosource.module;[
-<!ENTITY % local.bibliosource.attrib "">
-<!ENTITY % bibliosource.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliosource.element "INCLUDE">
-<![%bibliosource.element;[
-<!--doc:The source of a document.-->
-<!ELEMENT bibliosource %ho; (%docinfo.char.mix;)*>
-<!--end of bibliosource.element-->]]>
-
-<!ENTITY % bibliosource.attlist "INCLUDE">
-<![%bibliosource.attlist;[
-<!ATTLIST bibliosource
- %biblio.class.attrib;
- %common.attrib;
- %bibliosource.role.attrib;
- %local.bibliosource.attrib;
->
-<!--end of bibliosource.attlist-->]]>
-<!--end of bibliosource.module-->]]>
-
-<!-- BiblioRelation ................. -->
-
-<!ENTITY % bibliorelation.module "INCLUDE">
-<![%bibliorelation.module;[
-<!ENTITY % local.bibliorelation.attrib "">
-<!ENTITY % local.bibliorelation.types "">
-
-<!ENTITY % bibliorelation.type.attrib
- "type (isversionof
- |hasversion
- |isreplacedby
- |replaces
- |isrequiredby
- |requires
- |ispartof
- |haspart
- |isreferencedby
- |references
- |isformatof
- |hasformat
- |othertype
- %local.bibliorelation.types;) #IMPLIED
- othertype CDATA #IMPLIED
-">
-
-<!ENTITY % bibliorelation.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliorelation.element "INCLUDE">
-<![%bibliorelation.element;[
-<!--doc:The relationship of a document to another.-->
-<!ELEMENT bibliorelation %ho; (%docinfo.char.mix;)*>
-<!--end of bibliorelation.element-->]]>
-
-<!ENTITY % bibliorelation.attlist "INCLUDE">
-<![%bibliorelation.attlist;[
-<!ATTLIST bibliorelation
- %biblio.class.attrib;
- %bibliorelation.type.attrib;
- %common.attrib;
- %bibliorelation.role.attrib;
- %local.bibliorelation.attrib;
->
-<!--end of bibliorelation.attlist-->]]>
-<!--end of bibliorelation.module-->]]>
-
-<!-- BiblioCoverage ................. -->
-
-<!ENTITY % bibliocoverage.module "INCLUDE">
-<![%bibliocoverage.module;[
-<!ENTITY % local.bibliocoverage.attrib "">
-<!ENTITY % bibliocoverage.role.attrib "%role.attrib;">
-
-<!ENTITY % bibliocoverage.element "INCLUDE">
-<![%bibliocoverage.element;[
-<!--doc:The spatial or temporal coverage of a document.-->
-<!ELEMENT bibliocoverage %ho; (%docinfo.char.mix;)*>
-<!--end of bibliocoverage.element-->]]>
-
-<!ENTITY % bibliocoverage.attlist "INCLUDE">
-<![%bibliocoverage.attlist;[
-<!ATTLIST bibliocoverage
- spatial (dcmipoint|iso3166|dcmibox|tgn|otherspatial) #IMPLIED
- otherspatial CDATA #IMPLIED
- temporal (dcmiperiod|w3c-dtf|othertemporal) #IMPLIED
- othertemporal CDATA #IMPLIED
- %common.attrib;
- %bibliocoverage.role.attrib;
- %local.bibliocoverage.attrib;
->
-<!--end of bibliocoverage.attlist-->]]>
-<!--end of bibliocoverage.module-->]]>
-
-<!-- InvPartNumber .................... -->
-
-<!ENTITY % invpartnumber.module "INCLUDE">
-<![%invpartnumber.module;[
-<!ENTITY % local.invpartnumber.attrib "">
-<!ENTITY % invpartnumber.role.attrib "%role.attrib;">
-
-<!ENTITY % invpartnumber.element "INCLUDE">
-<![%invpartnumber.element;[
-<!--doc:An inventory part number.-->
-<!ELEMENT invpartnumber %ho; (%docinfo.char.mix;)*>
-<!--end of invpartnumber.element-->]]>
-
-<!ENTITY % invpartnumber.attlist "INCLUDE">
-<![%invpartnumber.attlist;[
-<!ATTLIST invpartnumber
- %common.attrib;
- %invpartnumber.role.attrib;
- %local.invpartnumber.attrib;
->
-<!--end of invpartnumber.attlist-->]]>
-<!--end of invpartnumber.module-->]]>
-
-<!-- IssueNum ......................... -->
-
-<!ENTITY % issuenum.module "INCLUDE">
-<![%issuenum.module;[
-<!ENTITY % local.issuenum.attrib "">
-<!ENTITY % issuenum.role.attrib "%role.attrib;">
-
-<!ENTITY % issuenum.element "INCLUDE">
-<![%issuenum.element;[
-<!--doc:The number of an issue of a journal.-->
-<!ELEMENT issuenum %ho; (%docinfo.char.mix;)*>
-<!--end of issuenum.element-->]]>
-
-<!ENTITY % issuenum.attlist "INCLUDE">
-<![%issuenum.attlist;[
-<!ATTLIST issuenum
- %common.attrib;
- %issuenum.role.attrib;
- %local.issuenum.attrib;
->
-<!--end of issuenum.attlist-->]]>
-<!--end of issuenum.module-->]]>
-
-<!-- LegalNotice ...................... -->
-
-<!ENTITY % legalnotice.module "INCLUDE">
-<![%legalnotice.module;[
-<!ENTITY % local.legalnotice.attrib "">
-<!ENTITY % legalnotice.role.attrib "%role.attrib;">
-
-<!ENTITY % legalnotice.element "INCLUDE">
-<![%legalnotice.element;[
-<!--doc:A statement of legal obligations or requirements.-->
-<!ELEMENT legalnotice %ho; (blockinfo?, title?, (%legalnotice.mix;)+)
- %formal.exclusion;>
-<!--end of legalnotice.element-->]]>
-
-<!ENTITY % legalnotice.attlist "INCLUDE">
-<![%legalnotice.attlist;[
-<!ATTLIST legalnotice
- %common.attrib;
- %legalnotice.role.attrib;
- %local.legalnotice.attrib;
->
-<!--end of legalnotice.attlist-->]]>
-<!--end of legalnotice.module-->]]>
-
-<!-- ModeSpec ......................... -->
-
-<!ENTITY % modespec.module "INCLUDE">
-<![%modespec.module;[
-<!ENTITY % local.modespec.attrib "">
-<!ENTITY % modespec.role.attrib "%role.attrib;">
-
-<!ENTITY % modespec.element "INCLUDE">
-<![%modespec.element;[
-<!--doc:Application-specific information necessary for the completion of an OLink.-->
-<!ELEMENT modespec %ho; (%docinfo.char.mix;)*
- %ubiq.exclusion;>
-<!--end of modespec.element-->]]>
-
-<!-- Application: Type of action required for completion
- of the links to which the ModeSpec is relevant (e.g.,
- retrieval query) -->
-
-
-<!ENTITY % modespec.attlist "INCLUDE">
-<![%modespec.attlist;[
-<!ATTLIST modespec
- application NOTATION
- (%notation.class;) #IMPLIED
- %common.attrib;
- %modespec.role.attrib;
- %local.modespec.attrib;
->
-<!--end of modespec.attlist-->]]>
-<!--end of modespec.module-->]]>
-
-<!-- OrgName .......................... -->
-
-<!ENTITY % orgname.module "INCLUDE">
-<![%orgname.module;[
-<!ENTITY % local.orgname.attrib "">
-<!ENTITY % orgname.role.attrib "%role.attrib;">
-
-<!ENTITY % orgname.element "INCLUDE">
-<![%orgname.element;[
-<!--doc:The name of an organization other than a corporation.-->
-<!ELEMENT orgname %ho; (%docinfo.char.mix;)*>
-<!--end of orgname.element-->]]>
-
-<!ENTITY % orgname.attlist "INCLUDE">
-<![%orgname.attlist;[
-<!ATTLIST orgname
- %common.attrib;
- class (corporation|nonprofit|consortium|informal|other) #IMPLIED
- otherclass CDATA #IMPLIED
- %orgname.role.attrib;
- %local.orgname.attrib;
->
-<!--end of orgname.attlist-->]]>
-<!--end of orgname.module-->]]>
-
-<!-- OtherCredit ...................... -->
-
-<!ENTITY % othercredit.module "INCLUDE">
-<![%othercredit.module;[
-<!ENTITY % local.othercredit.attrib "">
-<!ENTITY % othercredit.role.attrib "%role.attrib;">
-
-<!ENTITY % othercredit.element "INCLUDE">
-<![%othercredit.element;[
-<!--doc:A person or entity, other than an author or editor, credited in a document.-->
-<!ELEMENT othercredit %ho; ((personname|(%person.ident.mix;)+),
- (personblurb|email|address)*)>
-<!--end of othercredit.element-->]]>
-
-<!ENTITY % othercredit.attlist "INCLUDE">
-<![%othercredit.attlist;[
-<!ATTLIST othercredit
- class (graphicdesigner
- |productioneditor
- |copyeditor
- |technicaleditor
- |translator
- |other) #IMPLIED
- %common.attrib;
- %othercredit.role.attrib;
- %local.othercredit.attrib;
->
-<!--end of othercredit.attlist-->]]>
- <!--(see "Personal identity elements" for %person.ident.mix;)-->
-<!--end of othercredit.module-->]]>
-
-<!-- PageNums ......................... -->
-
-<!ENTITY % pagenums.module "INCLUDE">
-<![%pagenums.module;[
-<!ENTITY % local.pagenums.attrib "">
-<!ENTITY % pagenums.role.attrib "%role.attrib;">
-
-<!ENTITY % pagenums.element "INCLUDE">
-<![%pagenums.element;[
-<!--doc:The numbers of the pages in a book, for use in a bibliographic entry.-->
-<!ELEMENT pagenums %ho; (%docinfo.char.mix;)*>
-<!--end of pagenums.element-->]]>
-
-<!ENTITY % pagenums.attlist "INCLUDE">
-<![%pagenums.attlist;[
-<!ATTLIST pagenums
- %common.attrib;
- %pagenums.role.attrib;
- %local.pagenums.attrib;
->
-<!--end of pagenums.attlist-->]]>
-<!--end of pagenums.module-->]]>
-
-<!-- Personal identity elements ....... -->
-
-<!-- These elements are used only within Author, Editor, and
-OtherCredit. -->
-
-<!ENTITY % person.ident.module "INCLUDE">
-<![%person.ident.module;[
- <!ENTITY % contrib.module "INCLUDE">
- <![%contrib.module;[
- <!ENTITY % local.contrib.attrib "">
- <!ENTITY % contrib.role.attrib "%role.attrib;">
-
-<!ENTITY % contrib.element "INCLUDE">
-<![%contrib.element;[
-<!--doc:A summary of the contributions made to a document by a credited source.-->
-<!ELEMENT contrib %ho; (%docinfo.char.mix;)*>
-<!--end of contrib.element-->]]>
-
-<!ENTITY % contrib.attlist "INCLUDE">
-<![%contrib.attlist;[
-<!ATTLIST contrib
- %common.attrib;
- %contrib.role.attrib;
- %local.contrib.attrib;
->
-<!--end of contrib.attlist-->]]>
- <!--end of contrib.module-->]]>
-
- <!ENTITY % firstname.module "INCLUDE">
- <![%firstname.module;[
- <!ENTITY % local.firstname.attrib "">
- <!ENTITY % firstname.role.attrib "%role.attrib;">
-
-<!ENTITY % firstname.element "INCLUDE">
-<![%firstname.element;[
-<!--doc:The first name of a person.-->
-<!ELEMENT firstname %ho; (%docinfo.char.mix;)*>
-<!--end of firstname.element-->]]>
-
-<!ENTITY % firstname.attlist "INCLUDE">
-<![%firstname.attlist;[
-<!ATTLIST firstname
- %common.attrib;
- %firstname.role.attrib;
- %local.firstname.attrib;
->
-<!--end of firstname.attlist-->]]>
- <!--end of firstname.module-->]]>
-
- <!ENTITY % honorific.module "INCLUDE">
- <![%honorific.module;[
- <!ENTITY % local.honorific.attrib "">
- <!ENTITY % honorific.role.attrib "%role.attrib;">
-
-<!ENTITY % honorific.element "INCLUDE">
-<![%honorific.element;[
-<!--doc:The title of a person.-->
-<!ELEMENT honorific %ho; (%docinfo.char.mix;)*>
-<!--end of honorific.element-->]]>
-
-<!ENTITY % honorific.attlist "INCLUDE">
-<![%honorific.attlist;[
-<!ATTLIST honorific
- %common.attrib;
- %honorific.role.attrib;
- %local.honorific.attrib;
->
-<!--end of honorific.attlist-->]]>
- <!--end of honorific.module-->]]>
-
- <!ENTITY % lineage.module "INCLUDE">
- <![%lineage.module;[
- <!ENTITY % local.lineage.attrib "">
- <!ENTITY % lineage.role.attrib "%role.attrib;">
-
-<!ENTITY % lineage.element "INCLUDE">
-<![%lineage.element;[
-<!--doc:The portion of a person's name indicating a relationship to ancestors.-->
-<!ELEMENT lineage %ho; (%docinfo.char.mix;)*>
-<!--end of lineage.element-->]]>
-
-<!ENTITY % lineage.attlist "INCLUDE">
-<![%lineage.attlist;[
-<!ATTLIST lineage
- %common.attrib;
- %lineage.role.attrib;
- %local.lineage.attrib;
->
-<!--end of lineage.attlist-->]]>
- <!--end of lineage.module-->]]>
-
- <!ENTITY % othername.module "INCLUDE">
- <![%othername.module;[
- <!ENTITY % local.othername.attrib "">
- <!ENTITY % othername.role.attrib "%role.attrib;">
-
-<!ENTITY % othername.element "INCLUDE">
-<![%othername.element;[
-<!--doc:A component of a persons name that is not a first name, surname, or lineage.-->
-<!ELEMENT othername %ho; (%docinfo.char.mix;)*>
-<!--end of othername.element-->]]>
-
-<!ENTITY % othername.attlist "INCLUDE">
-<![%othername.attlist;[
-<!ATTLIST othername
- %common.attrib;
- %othername.role.attrib;
- %local.othername.attrib;
->
-<!--end of othername.attlist-->]]>
- <!--end of othername.module-->]]>
-
- <!ENTITY % surname.module "INCLUDE">
- <![%surname.module;[
- <!ENTITY % local.surname.attrib "">
- <!ENTITY % surname.role.attrib "%role.attrib;">
-
-<!ENTITY % surname.element "INCLUDE">
-<![%surname.element;[
-<!--doc:A family name; in western cultures the last name.-->
-<!ELEMENT surname %ho; (%docinfo.char.mix;)*>
-<!--end of surname.element-->]]>
-
-<!ENTITY % surname.attlist "INCLUDE">
-<![%surname.attlist;[
-<!ATTLIST surname
- %common.attrib;
- %surname.role.attrib;
- %local.surname.attrib;
->
-<!--end of surname.attlist-->]]>
- <!--end of surname.module-->]]>
-<!--end of person.ident.module-->]]>
-
-<!-- PrintHistory ..................... -->
-
-<!ENTITY % printhistory.module "INCLUDE">
-<![%printhistory.module;[
-<!ENTITY % local.printhistory.attrib "">
-<!ENTITY % printhistory.role.attrib "%role.attrib;">
-
-<!ENTITY % printhistory.element "INCLUDE">
-<![%printhistory.element;[
-<!--doc:The printing history of a document.-->
-<!ELEMENT printhistory %ho; ((%para.class;)+)>
-<!--end of printhistory.element-->]]>
-
-<!ENTITY % printhistory.attlist "INCLUDE">
-<![%printhistory.attlist;[
-<!ATTLIST printhistory
- %common.attrib;
- %printhistory.role.attrib;
- %local.printhistory.attrib;
->
-<!--end of printhistory.attlist-->]]>
-<!--end of printhistory.module-->]]>
-
-<!-- ProductName ...................... -->
-
-<!ENTITY % productname.module "INCLUDE">
-<![%productname.module;[
-<!ENTITY % local.productname.attrib "">
-<!ENTITY % productname.role.attrib "%role.attrib;">
-
-<!ENTITY % productname.element "INCLUDE">
-<![%productname.element;[
-<!--doc:The formal name of a product.-->
-<!ELEMENT productname %ho; (%para.char.mix;)*>
-<!--end of productname.element-->]]>
-
-<!-- Class: More precisely identifies the item the element names -->
-
-
-<!ENTITY % productname.attlist "INCLUDE">
-<![%productname.attlist;[
-<!ATTLIST productname
- class (service
- |trade
- |registered
- |copyright) 'trade'
- %common.attrib;
- %productname.role.attrib;
- %local.productname.attrib;
->
-<!--end of productname.attlist-->]]>
-<!--end of productname.module-->]]>
-
-<!-- ProductNumber .................... -->
-
-<!ENTITY % productnumber.module "INCLUDE">
-<![%productnumber.module;[
-<!ENTITY % local.productnumber.attrib "">
-<!ENTITY % productnumber.role.attrib "%role.attrib;">
-
-<!ENTITY % productnumber.element "INCLUDE">
-<![%productnumber.element;[
-<!--doc:A number assigned to a product.-->
-<!ELEMENT productnumber %ho; (%docinfo.char.mix;)*>
-<!--end of productnumber.element-->]]>
-
-<!ENTITY % productnumber.attlist "INCLUDE">
-<![%productnumber.attlist;[
-<!ATTLIST productnumber
- %common.attrib;
- %productnumber.role.attrib;
- %local.productnumber.attrib;
->
-<!--end of productnumber.attlist-->]]>
-<!--end of productnumber.module-->]]>
-
-<!-- PubDate .......................... -->
-
-<!ENTITY % pubdate.module "INCLUDE">
-<![%pubdate.module;[
-<!ENTITY % local.pubdate.attrib "">
-<!ENTITY % pubdate.role.attrib "%role.attrib;">
-
-<!ENTITY % pubdate.element "INCLUDE">
-<![%pubdate.element;[
-<!--doc:The date of publication of a document.-->
-<!ELEMENT pubdate %ho; (%docinfo.char.mix;)*>
-<!--end of pubdate.element-->]]>
-
-<!ENTITY % pubdate.attlist "INCLUDE">
-<![%pubdate.attlist;[
-<!ATTLIST pubdate
- %common.attrib;
- %pubdate.role.attrib;
- %local.pubdate.attrib;
->
-<!--end of pubdate.attlist-->]]>
-<!--end of pubdate.module-->]]>
-
-<!-- Publisher ........................ -->
-
-<!ENTITY % publisher.content.module "INCLUDE">
-<![%publisher.content.module;[
-<!ENTITY % publisher.module "INCLUDE">
-<![%publisher.module;[
-<!ENTITY % local.publisher.attrib "">
-<!ENTITY % publisher.role.attrib "%role.attrib;">
-
-<!ENTITY % publisher.element "INCLUDE">
-<![%publisher.element;[
-<!--doc:The publisher of a document.-->
-<!ELEMENT publisher %ho; (publishername, address*)>
-<!--end of publisher.element-->]]>
-
-<!ENTITY % publisher.attlist "INCLUDE">
-<![%publisher.attlist;[
-<!ATTLIST publisher
- %common.attrib;
- %publisher.role.attrib;
- %local.publisher.attrib;
->
-<!--end of publisher.attlist-->]]>
-<!--end of publisher.module-->]]>
-
- <!ENTITY % publishername.module "INCLUDE">
- <![%publishername.module;[
- <!ENTITY % local.publishername.attrib "">
- <!ENTITY % publishername.role.attrib "%role.attrib;">
-
-<!ENTITY % publishername.element "INCLUDE">
-<![%publishername.element;[
-<!--doc:The name of the publisher of a document.-->
-<!ELEMENT publishername %ho; (%docinfo.char.mix;)*>
-<!--end of publishername.element-->]]>
-
-<!ENTITY % publishername.attlist "INCLUDE">
-<![%publishername.attlist;[
-<!ATTLIST publishername
- %common.attrib;
- %publishername.role.attrib;
- %local.publishername.attrib;
->
-<!--end of publishername.attlist-->]]>
- <!--end of publishername.module-->]]>
-
- <!-- Address (defined elsewhere in this section)-->
-<!--end of publisher.content.module-->]]>
-
-<!-- PubsNumber ....................... -->
-
-<!ENTITY % pubsnumber.module "INCLUDE">
-<![%pubsnumber.module;[
-<!ENTITY % local.pubsnumber.attrib "">
-<!ENTITY % pubsnumber.role.attrib "%role.attrib;">
-
-<!ENTITY % pubsnumber.element "INCLUDE">
-<![%pubsnumber.element;[
-<!--doc:A number assigned to a publication other than an ISBN or ISSN or inventory part number.-->
-<!ELEMENT pubsnumber %ho; (%docinfo.char.mix;)*>
-<!--end of pubsnumber.element-->]]>
-
-<!ENTITY % pubsnumber.attlist "INCLUDE">
-<![%pubsnumber.attlist;[
-<!ATTLIST pubsnumber
- %common.attrib;
- %pubsnumber.role.attrib;
- %local.pubsnumber.attrib;
->
-<!--end of pubsnumber.attlist-->]]>
-<!--end of pubsnumber.module-->]]>
-
-<!-- ReleaseInfo ...................... -->
-
-<!ENTITY % releaseinfo.module "INCLUDE">
-<![%releaseinfo.module;[
-<!ENTITY % local.releaseinfo.attrib "">
-<!ENTITY % releaseinfo.role.attrib "%role.attrib;">
-
-<!ENTITY % releaseinfo.element "INCLUDE">
-<![%releaseinfo.element;[
-<!--doc:Information about a particular release of a document.-->
-<!ELEMENT releaseinfo %ho; (%docinfo.char.mix;)*>
-<!--end of releaseinfo.element-->]]>
-
-<!ENTITY % releaseinfo.attlist "INCLUDE">
-<![%releaseinfo.attlist;[
-<!ATTLIST releaseinfo
- %common.attrib;
- %releaseinfo.role.attrib;
- %local.releaseinfo.attrib;
->
-<!--end of releaseinfo.attlist-->]]>
-<!--end of releaseinfo.module-->]]>
-
-<!-- RevHistory ....................... -->
-
-<!ENTITY % revhistory.content.module "INCLUDE">
-<![%revhistory.content.module;[
-<!ENTITY % revhistory.module "INCLUDE">
-<![%revhistory.module;[
-<!ENTITY % local.revhistory.attrib "">
-<!ENTITY % revhistory.role.attrib "%role.attrib;">
-
-<!ENTITY % revhistory.element "INCLUDE">
-<![%revhistory.element;[
-<!--doc:A history of the revisions to a document.-->
-<!ELEMENT revhistory %ho; (revision+)>
-<!--end of revhistory.element-->]]>
-
-<!ENTITY % revhistory.attlist "INCLUDE">
-<![%revhistory.attlist;[
-<!ATTLIST revhistory
- %common.attrib;
- %revhistory.role.attrib;
- %local.revhistory.attrib;
->
-<!--end of revhistory.attlist-->]]>
-<!--end of revhistory.module-->]]>
-
-<!ENTITY % revision.module "INCLUDE">
-<![%revision.module;[
-<!ENTITY % local.revision.attrib "">
-<!ENTITY % revision.role.attrib "%role.attrib;">
-
-<!ENTITY % revision.element "INCLUDE">
-<![%revision.element;[
-<!--doc:An entry describing a single revision in the history of the revisions to a document.-->
-<!ELEMENT revision %ho; (revnumber?, date, (author|authorinitials)*,
- (revremark|revdescription)?)>
-<!--end of revision.element-->]]>
-
-<!ENTITY % revision.attlist "INCLUDE">
-<![%revision.attlist;[
-<!ATTLIST revision
- %common.attrib;
- %revision.role.attrib;
- %local.revision.attrib;
->
-<!--end of revision.attlist-->]]>
-<!--end of revision.module-->]]>
-
-<!ENTITY % revnumber.module "INCLUDE">
-<![%revnumber.module;[
-<!ENTITY % local.revnumber.attrib "">
-<!ENTITY % revnumber.role.attrib "%role.attrib;">
-
-<!ENTITY % revnumber.element "INCLUDE">
-<![%revnumber.element;[
-<!--doc:A document revision number.-->
-<!ELEMENT revnumber %ho; (%docinfo.char.mix;)*>
-<!--end of revnumber.element-->]]>
-
-<!ENTITY % revnumber.attlist "INCLUDE">
-<![%revnumber.attlist;[
-<!ATTLIST revnumber
- %common.attrib;
- %revnumber.role.attrib;
- %local.revnumber.attrib;
->
-<!--end of revnumber.attlist-->]]>
-<!--end of revnumber.module-->]]>
-
-<!-- Date (defined elsewhere in this section)-->
-<!-- AuthorInitials (defined elsewhere in this section)-->
-
-<!ENTITY % revremark.module "INCLUDE">
-<![%revremark.module;[
-<!ENTITY % local.revremark.attrib "">
-<!ENTITY % revremark.role.attrib "%role.attrib;">
-
-<!ENTITY % revremark.element "INCLUDE">
-<![%revremark.element;[
-<!--doc:A description of a revision to a document.-->
-<!ELEMENT revremark %ho; (%docinfo.char.mix;)*>
-<!--end of revremark.element-->]]>
-
-<!ENTITY % revremark.attlist "INCLUDE">
-<![%revremark.attlist;[
-<!ATTLIST revremark
- %common.attrib;
- %revremark.role.attrib;
- %local.revremark.attrib;
->
-<!--end of revremark.attlist-->]]>
-<!--end of revremark.module-->]]>
-
-<!ENTITY % revdescription.module "INCLUDE">
-<![ %revdescription.module; [
-<!ENTITY % local.revdescription.attrib "">
-<!ENTITY % revdescription.role.attrib "%role.attrib;">
-
-<!ENTITY % revdescription.element "INCLUDE">
-<![ %revdescription.element; [
-<!--doc:A extended description of a revision to a document.-->
-<!ELEMENT revdescription %ho; ((%revdescription.mix;)+)>
-<!--end of revdescription.element-->]]>
-
-<!ENTITY % revdescription.attlist "INCLUDE">
-<![ %revdescription.attlist; [
-<!ATTLIST revdescription
- %common.attrib;
- %revdescription.role.attrib;
- %local.revdescription.attrib;
->
-<!--end of revdescription.attlist-->]]>
-<!--end of revdescription.module-->]]>
-<!--end of revhistory.content.module-->]]>
-
-<!-- SeriesVolNums .................... -->
-
-<!ENTITY % seriesvolnums.module "INCLUDE">
-<![%seriesvolnums.module;[
-<!ENTITY % local.seriesvolnums.attrib "">
-<!ENTITY % seriesvolnums.role.attrib "%role.attrib;">
-
-<!ENTITY % seriesvolnums.element "INCLUDE">
-<![%seriesvolnums.element;[
-<!--doc:Numbers of the volumes in a series of books.-->
-<!ELEMENT seriesvolnums %ho; (%docinfo.char.mix;)*>
-<!--end of seriesvolnums.element-->]]>
-
-<!ENTITY % seriesvolnums.attlist "INCLUDE">
-<![%seriesvolnums.attlist;[
-<!ATTLIST seriesvolnums
- %common.attrib;
- %seriesvolnums.role.attrib;
- %local.seriesvolnums.attrib;
->
-<!--end of seriesvolnums.attlist-->]]>
-<!--end of seriesvolnums.module-->]]>
-
-<!-- VolumeNum ........................ -->
-
-<!ENTITY % volumenum.module "INCLUDE">
-<![%volumenum.module;[
-<!ENTITY % local.volumenum.attrib "">
-<!ENTITY % volumenum.role.attrib "%role.attrib;">
-
-<!ENTITY % volumenum.element "INCLUDE">
-<![%volumenum.element;[
-<!--doc:The volume number of a document in a set (as of books in a set or articles in a journal).-->
-<!ELEMENT volumenum %ho; (%docinfo.char.mix;)*>
-<!--end of volumenum.element-->]]>
-
-<!ENTITY % volumenum.attlist "INCLUDE">
-<![%volumenum.attlist;[
-<!ATTLIST volumenum
- %common.attrib;
- %volumenum.role.attrib;
- %local.volumenum.attrib;
->
-<!--end of volumenum.attlist-->]]>
-<!--end of volumenum.module-->]]>
-
-<!-- .................................. -->
-
-<!--end of docinfo.content.module-->]]>
-
-<!-- ...................................................................... -->
-<!-- Inline, link, and ubiquitous elements ................................ -->
-
-<!-- Technical and computer terms ......................................... -->
-
-<!ENTITY % accel.module "INCLUDE">
-<![%accel.module;[
-<!ENTITY % local.accel.attrib "">
-<!ENTITY % accel.role.attrib "%role.attrib;">
-
-<!ENTITY % accel.element "INCLUDE">
-<![%accel.element;[
-<!--doc:A graphical user interface (GUI) keyboard shortcut.-->
-<!ELEMENT accel %ho; (%smallcptr.char.mix;)*>
-<!--end of accel.element-->]]>
-
-<!ENTITY % accel.attlist "INCLUDE">
-<![%accel.attlist;[
-<!ATTLIST accel
- %common.attrib;
- %accel.role.attrib;
- %local.accel.attrib;
->
-<!--end of accel.attlist-->]]>
-<!--end of accel.module-->]]>
-
-<!ENTITY % action.module "INCLUDE">
-<![%action.module;[
-<!ENTITY % local.action.attrib "">
-<!ENTITY % action.role.attrib "%role.attrib;">
-
-<!ENTITY % action.element "INCLUDE">
-<![%action.element;[
-<!--doc:A response to a user event.-->
-<!ELEMENT action %ho; (%cptr.char.mix;)*>
-<!--end of action.element-->]]>
-
-<!ENTITY % action.attlist "INCLUDE">
-<![%action.attlist;[
-<!ATTLIST action
- %moreinfo.attrib;
- %common.attrib;
- %action.role.attrib;
- %local.action.attrib;
->
-<!--end of action.attlist-->]]>
-<!--end of action.module-->]]>
-
-<!ENTITY % application.module "INCLUDE">
-<![%application.module;[
-<!ENTITY % local.application.attrib "">
-<!ENTITY % application.role.attrib "%role.attrib;">
-
-<!ENTITY % application.element "INCLUDE">
-<![%application.element;[
-<!--doc:The name of a software program.-->
-<!ELEMENT application %ho; (%para.char.mix;)*>
-<!--end of application.element-->]]>
-
-<!ENTITY % application.attlist "INCLUDE">
-<![%application.attlist;[
-<!ATTLIST application
- class (hardware
- |software) #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %application.role.attrib;
- %local.application.attrib;
->
-<!--end of application.attlist-->]]>
-<!--end of application.module-->]]>
-
-<!ENTITY % classname.module "INCLUDE">
-<![%classname.module;[
-<!ENTITY % local.classname.attrib "">
-<!ENTITY % classname.role.attrib "%role.attrib;">
-
-<!ENTITY % classname.element "INCLUDE">
-<![%classname.element;[
-<!--doc:The name of a class, in the object-oriented programming sense.-->
-<!ELEMENT classname %ho; (%smallcptr.char.mix;)*>
-<!--end of classname.element-->]]>
-
-<!ENTITY % classname.attlist "INCLUDE">
-<![%classname.attlist;[
-<!ATTLIST classname
- %common.attrib;
- %classname.role.attrib;
- %local.classname.attrib;
->
-<!--end of classname.attlist-->]]>
-<!--end of classname.module-->]]>
-
-<!ENTITY % package.module "INCLUDE">
-<![%package.module;[
-<!ENTITY % local.package.attrib "">
-<!ENTITY % package.role.attrib "%role.attrib;">
-
-<!ENTITY % package.element "INCLUDE">
-<![%package.element;[
-<!--doc:A package.-->
-<!ELEMENT package %ho; (%smallcptr.char.mix;)*>
-<!--end of package.element-->]]>
-
-<!ENTITY % package.attlist "INCLUDE">
-<![%package.attlist;[
-<!ATTLIST package
- %common.attrib;
- %package.role.attrib;
- %local.package.attrib;
->
-<!--end of package.attlist-->]]>
-<!--end of package.module-->]]>
-
-<!ENTITY % co.module "INCLUDE">
-<![%co.module;[
-<!ENTITY % local.co.attrib "">
-<!-- CO is a callout area of the LineColumn unit type (a single character
- position); the position is directly indicated by the location of CO. -->
-<!ENTITY % co.role.attrib "%role.attrib;">
-
-<!ENTITY % co.element "INCLUDE">
-<![%co.element;[
-<!--doc:The location of a callout embedded in text.-->
-<!ELEMENT co %ho; EMPTY>
-<!--end of co.element-->]]>
-
-<!-- bug number/symbol override or initialization -->
-<!-- to any related information -->
-
-
-<!ENTITY % co.attlist "INCLUDE">
-<![%co.attlist;[
-<!ATTLIST co
- %label.attrib;
- %linkends.attrib;
- %idreq.common.attrib;
- %co.role.attrib;
- %local.co.attrib;
->
-<!--end of co.attlist-->]]>
-<!--end of co.module-->]]>
-
-<!ENTITY % coref.module "INCLUDE">
-<![%coref.module;[
-<!ENTITY % local.coref.attrib "">
-<!-- COREF is a reference to a CO -->
-<!ENTITY % coref.role.attrib "%role.attrib;">
-
-<!ENTITY % coref.element "INCLUDE">
-<![%coref.element;[
-<!--doc:A cross reference to a co.-->
-<!ELEMENT coref %ho; EMPTY>
-<!--end of coref.element-->]]>
-
-<!-- bug number/symbol override or initialization -->
-<!-- to any related information -->
-
-<!ENTITY % coref.attlist "INCLUDE">
-<![%coref.attlist;[
-<!ATTLIST coref
- %label.attrib;
- %linkendreq.attrib;
- %common.attrib;
- %coref.role.attrib;
- %local.coref.attrib;
->
-<!--end of coref.attlist-->]]>
-<!--end of coref.module-->]]>
-
-<!ENTITY % command.module "INCLUDE">
-<![%command.module;[
-<!ENTITY % local.command.attrib "">
-<!ENTITY % command.role.attrib "%role.attrib;">
-
-<!ENTITY % command.element "INCLUDE">
-<![%command.element;[
-<!--doc:The name of an executable program or other software command.-->
-<!ELEMENT command %ho; (%cptr.char.mix;)*>
-<!--end of command.element-->]]>
-
-<!ENTITY % command.attlist "INCLUDE">
-<![%command.attlist;[
-<!ATTLIST command
- %moreinfo.attrib;
- %common.attrib;
- %command.role.attrib;
- %local.command.attrib;
->
-<!--end of command.attlist-->]]>
-<!--end of command.module-->]]>
-
-<!ENTITY % computeroutput.module "INCLUDE">
-<![%computeroutput.module;[
-<!ENTITY % local.computeroutput.attrib "">
-<!ENTITY % computeroutput.role.attrib "%role.attrib;">
-
-<!ENTITY % computeroutput.element "INCLUDE">
-<![%computeroutput.element;[
-<!--doc:Data, generally text, displayed or presented by a computer.-->
-<!ELEMENT computeroutput %ho; (%cptr.char.mix;|co)*>
-<!--end of computeroutput.element-->]]>
-
-<!ENTITY % computeroutput.attlist "INCLUDE">
-<![%computeroutput.attlist;[
-<!ATTLIST computeroutput
- %moreinfo.attrib;
- %common.attrib;
- %computeroutput.role.attrib;
- %local.computeroutput.attrib;
->
-<!--end of computeroutput.attlist-->]]>
-<!--end of computeroutput.module-->]]>
-
-<!ENTITY % database.module "INCLUDE">
-<![%database.module;[
-<!ENTITY % local.database.attrib "">
-<!ENTITY % database.role.attrib "%role.attrib;">
-
-<!ENTITY % database.element "INCLUDE">
-<![%database.element;[
-<!--doc:The name of a database, or part of a database.-->
-<!ELEMENT database %ho; (%cptr.char.mix;)*>
-<!--end of database.element-->]]>
-
-<!-- Class: Type of database the element names; no default -->
-
-
-<!ENTITY % database.attlist "INCLUDE">
-<![%database.attlist;[
-<!ATTLIST database
- class (name
- |table
- |field
- |key1
- |key2
- |record
- |index
- |view
- |primarykey
- |secondarykey
- |foreignkey
- |altkey
- |procedure
- |datatype
- |constraint
- |rule
- |user
- |group) #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %database.role.attrib;
- %local.database.attrib;
->
-<!--end of database.attlist-->]]>
-<!--end of database.module-->]]>
-
-<!ENTITY % email.module "INCLUDE">
-<![%email.module;[
-<!ENTITY % local.email.attrib "">
-<!ENTITY % email.role.attrib "%role.attrib;">
-
-<!ENTITY % email.element "INCLUDE">
-<![%email.element;[
-<!--doc:An email address.-->
-<!ELEMENT email %ho; (%docinfo.char.mix;)*>
-<!--end of email.element-->]]>
-
-<!ENTITY % email.attlist "INCLUDE">
-<![%email.attlist;[
-<!ATTLIST email
- %common.attrib;
- %email.role.attrib;
- %local.email.attrib;
->
-<!--end of email.attlist-->]]>
-<!--end of email.module-->]]>
-
-<!ENTITY % envar.module "INCLUDE">
-<![%envar.module;[
-<!ENTITY % local.envar.attrib "">
-<!ENTITY % envar.role.attrib "%role.attrib;">
-
-<!ENTITY % envar.element "INCLUDE">
-<![%envar.element;[
-<!--doc:A software environment variable.-->
-<!ELEMENT envar %ho; (%smallcptr.char.mix;)*>
-<!--end of envar.element-->]]>
-
-<!ENTITY % envar.attlist "INCLUDE">
-<![%envar.attlist;[
-<!ATTLIST envar
- %common.attrib;
- %envar.role.attrib;
- %local.envar.attrib;
->
-<!--end of envar.attlist-->]]>
-<!--end of envar.module-->]]>
-
-
-<!ENTITY % errorcode.module "INCLUDE">
-<![%errorcode.module;[
-<!ENTITY % local.errorcode.attrib "">
-<!ENTITY % errorcode.role.attrib "%role.attrib;">
-
-<!ENTITY % errorcode.element "INCLUDE">
-<![%errorcode.element;[
-<!--doc:An error code.-->
-<!ELEMENT errorcode %ho; (%smallcptr.char.mix;)*>
-<!--end of errorcode.element-->]]>
-
-<!ENTITY % errorcode.attlist "INCLUDE">
-<![%errorcode.attlist;[
-<!ATTLIST errorcode
- %moreinfo.attrib;
- %common.attrib;
- %errorcode.role.attrib;
- %local.errorcode.attrib;
->
-<!--end of errorcode.attlist-->]]>
-<!--end of errorcode.module-->]]>
-
-<!ENTITY % errorname.module "INCLUDE">
-<![%errorname.module;[
-<!ENTITY % local.errorname.attrib "">
-<!ENTITY % errorname.role.attrib "%role.attrib;">
-
-<!ENTITY % errorname.element "INCLUDE">
-<![%errorname.element;[
-<!--doc:An error name.-->
-<!ELEMENT errorname %ho; (%smallcptr.char.mix;)*>
-<!--end of errorname.element-->]]>
-
-<!ENTITY % errorname.attlist "INCLUDE">
-<![%errorname.attlist;[
-<!ATTLIST errorname
- %common.attrib;
- %errorname.role.attrib;
- %local.errorname.attrib;
->
-<!--end of errorname.attlist-->]]>
-<!--end of errorname.module-->]]>
-
-<!ENTITY % errortext.module "INCLUDE">
-<![%errortext.module;[
-<!ENTITY % local.errortext.attrib "">
-<!ENTITY % errortext.role.attrib "%role.attrib;">
-
-<!ENTITY % errortext.element "INCLUDE">
-<![%errortext.element;[
-<!--doc:An error message..-->
-<!ELEMENT errortext %ho; (%smallcptr.char.mix;)*>
-<!--end of errortext.element-->]]>
-
-<!ENTITY % errortext.attlist "INCLUDE">
-<![%errortext.attlist;[
-<!ATTLIST errortext
- %common.attrib;
- %errortext.role.attrib;
- %local.errortext.attrib;
->
-<!--end of errortext.attlist-->]]>
-<!--end of errortext.module-->]]>
-
-<!ENTITY % errortype.module "INCLUDE">
-<![%errortype.module;[
-<!ENTITY % local.errortype.attrib "">
-<!ENTITY % errortype.role.attrib "%role.attrib;">
-
-<!ENTITY % errortype.element "INCLUDE">
-<![%errortype.element;[
-<!--doc:The classification of an error message.-->
-<!ELEMENT errortype %ho; (%smallcptr.char.mix;)*>
-<!--end of errortype.element-->]]>
-
-<!ENTITY % errortype.attlist "INCLUDE">
-<![%errortype.attlist;[
-<!ATTLIST errortype
- %common.attrib;
- %errortype.role.attrib;
- %local.errortype.attrib;
->
-<!--end of errortype.attlist-->]]>
-<!--end of errortype.module-->]]>
-
-<!ENTITY % filename.module "INCLUDE">
-<![%filename.module;[
-<!ENTITY % local.filename.attrib "">
-<!ENTITY % filename.role.attrib "%role.attrib;">
-
-<!ENTITY % filename.element "INCLUDE">
-<![%filename.element;[
-<!--doc:The name of a file.-->
-<!ELEMENT filename %ho; (%cptr.char.mix;)*>
-<!--end of filename.element-->]]>
-
-<!-- Class: Type of filename the element names; no default -->
-<!-- Path: Search path (possibly system-specific) in which
- file can be found -->
-
-
-<!ENTITY % filename.attlist "INCLUDE">
-<![%filename.attlist;[
-<!ATTLIST filename
- class (headerfile
- |partition
- |devicefile
- |libraryfile
- |directory
- |extension
- |symlink) #IMPLIED
- path CDATA #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %filename.role.attrib;
- %local.filename.attrib;
->
-<!--end of filename.attlist-->]]>
-<!--end of filename.module-->]]>
-
-<!ENTITY % function.module "INCLUDE">
-<![%function.module;[
-<!ENTITY % local.function.attrib "">
-<!ENTITY % function.role.attrib "%role.attrib;">
-
-<!ENTITY % function.element "INCLUDE">
-<![%function.element;[
-<!--doc:The name of a function or subroutine, as in a programming language.-->
-<!ELEMENT function %ho; (%cptr.char.mix;)*>
-<!--end of function.element-->]]>
-
-<!ENTITY % function.attlist "INCLUDE">
-<![%function.attlist;[
-<!ATTLIST function
- %moreinfo.attrib;
- %common.attrib;
- %function.role.attrib;
- %local.function.attrib;
->
-<!--end of function.attlist-->]]>
-<!--end of function.module-->]]>
-
-<!ENTITY % guibutton.module "INCLUDE">
-<![%guibutton.module;[
-<!ENTITY % local.guibutton.attrib "">
-<!ENTITY % guibutton.role.attrib "%role.attrib;">
-
-<!ENTITY % guibutton.element "INCLUDE">
-<![%guibutton.element;[
-<!--doc:The text on a button in a GUI.-->
-<!ELEMENT guibutton %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guibutton.element-->]]>
-
-<!ENTITY % guibutton.attlist "INCLUDE">
-<![%guibutton.attlist;[
-<!ATTLIST guibutton
- %moreinfo.attrib;
- %common.attrib;
- %guibutton.role.attrib;
- %local.guibutton.attrib;
->
-<!--end of guibutton.attlist-->]]>
-<!--end of guibutton.module-->]]>
-
-<!ENTITY % guiicon.module "INCLUDE">
-<![%guiicon.module;[
-<!ENTITY % local.guiicon.attrib "">
-<!ENTITY % guiicon.role.attrib "%role.attrib;">
-
-<!ENTITY % guiicon.element "INCLUDE">
-<![%guiicon.element;[
-<!--doc:Graphic and/or text appearing as a icon in a GUI.-->
-<!ELEMENT guiicon %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guiicon.element-->]]>
-
-<!ENTITY % guiicon.attlist "INCLUDE">
-<![%guiicon.attlist;[
-<!ATTLIST guiicon
- %moreinfo.attrib;
- %common.attrib;
- %guiicon.role.attrib;
- %local.guiicon.attrib;
->
-<!--end of guiicon.attlist-->]]>
-<!--end of guiicon.module-->]]>
-
-<!ENTITY % guilabel.module "INCLUDE">
-<![%guilabel.module;[
-<!ENTITY % local.guilabel.attrib "">
-<!ENTITY % guilabel.role.attrib "%role.attrib;">
-
-<!ENTITY % guilabel.element "INCLUDE">
-<![%guilabel.element;[
-<!--doc:The text of a label in a GUI.-->
-<!ELEMENT guilabel %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guilabel.element-->]]>
-
-<!ENTITY % guilabel.attlist "INCLUDE">
-<![%guilabel.attlist;[
-<!ATTLIST guilabel
- %moreinfo.attrib;
- %common.attrib;
- %guilabel.role.attrib;
- %local.guilabel.attrib;
->
-<!--end of guilabel.attlist-->]]>
-<!--end of guilabel.module-->]]>
-
-<!ENTITY % guimenu.module "INCLUDE">
-<![%guimenu.module;[
-<!ENTITY % local.guimenu.attrib "">
-<!ENTITY % guimenu.role.attrib "%role.attrib;">
-
-<!ENTITY % guimenu.element "INCLUDE">
-<![%guimenu.element;[
-<!--doc:The name of a menu in a GUI.-->
-<!ELEMENT guimenu %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guimenu.element-->]]>
-
-<!ENTITY % guimenu.attlist "INCLUDE">
-<![%guimenu.attlist;[
-<!ATTLIST guimenu
- %moreinfo.attrib;
- %common.attrib;
- %guimenu.role.attrib;
- %local.guimenu.attrib;
->
-<!--end of guimenu.attlist-->]]>
-<!--end of guimenu.module-->]]>
-
-<!ENTITY % guimenuitem.module "INCLUDE">
-<![%guimenuitem.module;[
-<!ENTITY % local.guimenuitem.attrib "">
-<!ENTITY % guimenuitem.role.attrib "%role.attrib;">
-
-<!ENTITY % guimenuitem.element "INCLUDE">
-<![%guimenuitem.element;[
-<!--doc:The name of a terminal menu item in a GUI.-->
-<!ELEMENT guimenuitem %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guimenuitem.element-->]]>
-
-<!ENTITY % guimenuitem.attlist "INCLUDE">
-<![%guimenuitem.attlist;[
-<!ATTLIST guimenuitem
- %moreinfo.attrib;
- %common.attrib;
- %guimenuitem.role.attrib;
- %local.guimenuitem.attrib;
->
-<!--end of guimenuitem.attlist-->]]>
-<!--end of guimenuitem.module-->]]>
-
-<!ENTITY % guisubmenu.module "INCLUDE">
-<![%guisubmenu.module;[
-<!ENTITY % local.guisubmenu.attrib "">
-<!ENTITY % guisubmenu.role.attrib "%role.attrib;">
-
-<!ENTITY % guisubmenu.element "INCLUDE">
-<![%guisubmenu.element;[
-<!--doc:The name of a submenu in a GUI.-->
-<!ELEMENT guisubmenu %ho; (%smallcptr.char.mix;|accel|superscript|subscript)*>
-<!--end of guisubmenu.element-->]]>
-
-<!ENTITY % guisubmenu.attlist "INCLUDE">
-<![%guisubmenu.attlist;[
-<!ATTLIST guisubmenu
- %moreinfo.attrib;
- %common.attrib;
- %guisubmenu.role.attrib;
- %local.guisubmenu.attrib;
->
-<!--end of guisubmenu.attlist-->]]>
-<!--end of guisubmenu.module-->]]>
-
-<!ENTITY % hardware.module "INCLUDE">
-<![%hardware.module;[
-<!ENTITY % local.hardware.attrib "">
-<!ENTITY % hardware.role.attrib "%role.attrib;">
-
-<!ENTITY % hardware.element "INCLUDE">
-<![%hardware.element;[
-<!--doc:A physical part of a computer system.-->
-<!ELEMENT hardware %ho; (%cptr.char.mix;)*>
-<!--end of hardware.element-->]]>
-
-<!ENTITY % hardware.attlist "INCLUDE">
-<![%hardware.attlist;[
-<!ATTLIST hardware
- %moreinfo.attrib;
- %common.attrib;
- %hardware.role.attrib;
- %local.hardware.attrib;
->
-<!--end of hardware.attlist-->]]>
-<!--end of hardware.module-->]]>
-
-<!ENTITY % interface.module "INCLUDE">
-<![%interface.module;[
-<!ENTITY % local.interface.attrib "">
-<!ENTITY % interface.role.attrib "%role.attrib;">
-
-<!ENTITY % interface.element "INCLUDE">
-<![%interface.element;[
-<!--doc:An element of a GUI.-->
-<!ELEMENT interface %ho; (%smallcptr.char.mix;|accel)*>
-<!--end of interface.element-->]]>
-
-<!-- Class: Type of the Interface item; no default -->
-
-
-<!ENTITY % interface.attlist "INCLUDE">
-<![%interface.attlist;[
-<!ATTLIST interface
- %moreinfo.attrib;
- %common.attrib;
- %interface.role.attrib;
- %local.interface.attrib;
->
-<!--end of interface.attlist-->]]>
-<!--end of interface.module-->]]>
-
-<!ENTITY % keycap.module "INCLUDE">
-<![%keycap.module;[
-<!ENTITY % local.keycap.attrib "">
-<!ENTITY % keycap.role.attrib "%role.attrib;">
-
-<!ENTITY % keycap.element "INCLUDE">
-<![%keycap.element;[
-<!--doc:The text printed on a key on a keyboard.-->
-<!ELEMENT keycap %ho; (%cptr.char.mix;)*>
-<!--end of keycap.element-->]]>
-
-<!ENTITY % keycap.attlist "INCLUDE">
-<![%keycap.attlist;[
-<!ATTLIST keycap
- function (alt
- |control
- |shift
- |meta
- |escape
- |enter
- |tab
- |backspace
- |command
- |option
- |space
- |delete
- |insert
- |up
- |down
- |left
- |right
- |home
- |end
- |pageup
- |pagedown
- |other) #IMPLIED
- otherfunction CDATA #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %keycap.role.attrib;
- %local.keycap.attrib;
->
-<!--end of keycap.attlist-->]]>
-<!--end of keycap.module-->]]>
-
-<!ENTITY % keycode.module "INCLUDE">
-<![%keycode.module;[
-<!ENTITY % local.keycode.attrib "">
-<!ENTITY % keycode.role.attrib "%role.attrib;">
-
-<!ENTITY % keycode.element "INCLUDE">
-<![%keycode.element;[
-<!--doc:The internal, frequently numeric, identifier for a key on a keyboard.-->
-<!ELEMENT keycode %ho; (%smallcptr.char.mix;)*>
-<!--end of keycode.element-->]]>
-
-<!ENTITY % keycode.attlist "INCLUDE">
-<![%keycode.attlist;[
-<!ATTLIST keycode
- %common.attrib;
- %keycode.role.attrib;
- %local.keycode.attrib;
->
-<!--end of keycode.attlist-->]]>
-<!--end of keycode.module-->]]>
-
-<!ENTITY % keycombo.module "INCLUDE">
-<![%keycombo.module;[
-<!ENTITY % local.keycombo.attrib "">
-<!ENTITY % keycombo.role.attrib "%role.attrib;">
-
-<!ENTITY % keycombo.element "INCLUDE">
-<![%keycombo.element;[
-<!--doc:A combination of input actions.-->
-<!ELEMENT keycombo %ho; ((keycap|keycombo|keysym|mousebutton)+)>
-<!--end of keycombo.element-->]]>
-
-<!ENTITY % keycombo.attlist "INCLUDE">
-<![%keycombo.attlist;[
-<!ATTLIST keycombo
- %keyaction.attrib;
- %moreinfo.attrib;
- %common.attrib;
- %keycombo.role.attrib;
- %local.keycombo.attrib;
->
-<!--end of keycombo.attlist-->]]>
-<!--end of keycombo.module-->]]>
-
-<!ENTITY % keysym.module "INCLUDE">
-<![%keysym.module;[
-<!ENTITY % local.keysym.attrib "">
-<!ENTITY % keysysm.role.attrib "%role.attrib;">
-
-<!ENTITY % keysym.element "INCLUDE">
-<![%keysym.element;[
-<!--doc:The symbolic name of a key on a keyboard.-->
-<!ELEMENT keysym %ho; (%smallcptr.char.mix;)*>
-<!--end of keysym.element-->]]>
-
-<!ENTITY % keysym.attlist "INCLUDE">
-<![%keysym.attlist;[
-<!ATTLIST keysym
- %common.attrib;
- %keysysm.role.attrib;
- %local.keysym.attrib;
->
-<!--end of keysym.attlist-->]]>
-<!--end of keysym.module-->]]>
-
-<!ENTITY % lineannotation.module "INCLUDE">
-<![%lineannotation.module;[
-<!ENTITY % local.lineannotation.attrib "">
-<!ENTITY % lineannotation.role.attrib "%role.attrib;">
-
-<!ENTITY % lineannotation.element "INCLUDE">
-<![%lineannotation.element;[
-<!--doc:A comment on a line in a verbatim listing.-->
-<!ELEMENT lineannotation %ho; (%para.char.mix;)*>
-<!--end of lineannotation.element-->]]>
-
-<!ENTITY % lineannotation.attlist "INCLUDE">
-<![%lineannotation.attlist;[
-<!ATTLIST lineannotation
- %common.attrib;
- %lineannotation.role.attrib;
- %local.lineannotation.attrib;
->
-<!--end of lineannotation.attlist-->]]>
-<!--end of lineannotation.module-->]]>
-
-<!ENTITY % literal.module "INCLUDE">
-<![%literal.module;[
-<!ENTITY % local.literal.attrib "">
-<!ENTITY % literal.role.attrib "%role.attrib;">
-
-<!ENTITY % literal.element "INCLUDE">
-<![%literal.element;[
-<!--doc:Inline text that is some literal value.-->
-<!ELEMENT literal %ho; (%cptr.char.mix;)*>
-<!--end of literal.element-->]]>
-
-<!ENTITY % literal.attlist "INCLUDE">
-<![%literal.attlist;[
-<!ATTLIST literal
- %moreinfo.attrib;
- %common.attrib;
- %literal.role.attrib;
- %local.literal.attrib;
->
-<!--end of literal.attlist-->]]>
-<!--end of literal.module-->]]>
-
-<!ENTITY % code.module "INCLUDE">
-<![%code.module;[
-<!ENTITY % local.code.attrib "">
-<!ENTITY % code.role.attrib "%role.attrib;">
-
-<!ENTITY % code.element "INCLUDE">
-<![%code.element;[
-<!--doc:An inline code fragment.-->
-<!ELEMENT code %ho; (%cptr.char.mix;)*>
-<!--end of code.element-->]]>
-
-<!ENTITY % code.attlist "INCLUDE">
-<![%code.attlist;[
-<!ATTLIST code
- language CDATA #IMPLIED
- %common.attrib;
- %code.role.attrib;
- %local.code.attrib;
->
-<!--end of code.attlist-->]]>
-<!--end of code.module-->]]>
-
-<!ENTITY % constant.module "INCLUDE">
-<![ %constant.module; [
-<!ENTITY % local.constant.attrib "">
-<!ENTITY % constant.role.attrib "%role.attrib;">
-
-<!ENTITY % constant.element "INCLUDE">
-<![ %constant.element; [
-<!--doc:A programming or system constant.-->
-<!ELEMENT constant %ho; (%smallcptr.char.mix;)*>
-<!--end of constant.element-->]]>
-
-<!ENTITY % constant.attlist "INCLUDE">
-<![ %constant.attlist; [
-<!ATTLIST constant
- class (limit) #IMPLIED
- %common.attrib;
- %constant.role.attrib;
- %local.constant.attrib;
->
-<!--end of constant.attlist-->]]>
-<!--end of constant.module-->]]>
-
-<!ENTITY % varname.module "INCLUDE">
-<![ %varname.module; [
-<!ENTITY % local.varname.attrib "">
-<!ENTITY % varname.role.attrib "%role.attrib;">
-
-<!ENTITY % varname.element "INCLUDE">
-<![ %varname.element; [
-<!--doc:The name of a variable.-->
-<!ELEMENT varname %ho; (%smallcptr.char.mix;)*>
-<!--end of varname.element-->]]>
-
-<!ENTITY % varname.attlist "INCLUDE">
-<![ %varname.attlist; [
-<!ATTLIST varname
- %common.attrib;
- %varname.role.attrib;
- %local.varname.attrib;
->
-<!--end of varname.attlist-->]]>
-<!--end of varname.module-->]]>
-
-<!ENTITY % markup.module "INCLUDE">
-<![%markup.module;[
-<!ENTITY % local.markup.attrib "">
-<!ENTITY % markup.role.attrib "%role.attrib;">
-
-<!ENTITY % markup.element "INCLUDE">
-<![%markup.element;[
-<!--doc:A string of formatting markup in text that is to be represented literally.-->
-<!ELEMENT markup %ho; (%smallcptr.char.mix;)*>
-<!--end of markup.element-->]]>
-
-<!ENTITY % markup.attlist "INCLUDE">
-<![%markup.attlist;[
-<!ATTLIST markup
- %common.attrib;
- %markup.role.attrib;
- %local.markup.attrib;
->
-<!--end of markup.attlist-->]]>
-<!--end of markup.module-->]]>
-
-<!ENTITY % medialabel.module "INCLUDE">
-<![%medialabel.module;[
-<!ENTITY % local.medialabel.attrib "">
-<!ENTITY % medialabel.role.attrib "%role.attrib;">
-
-<!ENTITY % medialabel.element "INCLUDE">
-<![%medialabel.element;[
-<!--doc:A name that identifies the physical medium on which some information resides.-->
-<!ELEMENT medialabel %ho; (%smallcptr.char.mix;)*>
-<!--end of medialabel.element-->]]>
-
-<!-- Class: Type of medium named by the element; no default -->
-
-
-<!ENTITY % medialabel.attlist "INCLUDE">
-<![%medialabel.attlist;[
-<!ATTLIST medialabel
- class (cartridge
- |cdrom
- |disk
- |tape) #IMPLIED
- %common.attrib;
- %medialabel.role.attrib;
- %local.medialabel.attrib;
->
-<!--end of medialabel.attlist-->]]>
-<!--end of medialabel.module-->]]>
-
-<!ENTITY % menuchoice.content.module "INCLUDE">
-<![%menuchoice.content.module;[
-<!ENTITY % menuchoice.module "INCLUDE">
-<![%menuchoice.module;[
-<!ENTITY % local.menuchoice.attrib "">
-<!ENTITY % menuchoice.role.attrib "%role.attrib;">
-
-<!ENTITY % menuchoice.element "INCLUDE">
-<![%menuchoice.element;[
-<!--doc:A selection or series of selections from a menu.-->
-<!ELEMENT menuchoice %ho; (shortcut?, (guibutton|guiicon|guilabel
- |guimenu|guimenuitem|guisubmenu|interface)+)>
-<!--end of menuchoice.element-->]]>
-
-<!ENTITY % menuchoice.attlist "INCLUDE">
-<![%menuchoice.attlist;[
-<!ATTLIST menuchoice
- %moreinfo.attrib;
- %common.attrib;
- %menuchoice.role.attrib;
- %local.menuchoice.attrib;
->
-<!--end of menuchoice.attlist-->]]>
-<!--end of menuchoice.module-->]]>
-
-<!ENTITY % shortcut.module "INCLUDE">
-<![%shortcut.module;[
-<!-- See also KeyCombo -->
-<!ENTITY % local.shortcut.attrib "">
-<!ENTITY % shortcut.role.attrib "%role.attrib;">
-
-<!ENTITY % shortcut.element "INCLUDE">
-<![%shortcut.element;[
-<!--doc:A key combination for an action that is also accessible through a menu.-->
-<!ELEMENT shortcut %ho; ((keycap|keycombo|keysym|mousebutton)+)>
-<!--end of shortcut.element-->]]>
-
-<!ENTITY % shortcut.attlist "INCLUDE">
-<![%shortcut.attlist;[
-<!ATTLIST shortcut
- %keyaction.attrib;
- %moreinfo.attrib;
- %common.attrib;
- %shortcut.role.attrib;
- %local.shortcut.attrib;
->
-<!--end of shortcut.attlist-->]]>
-<!--end of shortcut.module-->]]>
-<!--end of menuchoice.content.module-->]]>
-
-<!ENTITY % mousebutton.module "INCLUDE">
-<![%mousebutton.module;[
-<!ENTITY % local.mousebutton.attrib "">
-<!ENTITY % mousebutton.role.attrib "%role.attrib;">
-
-<!ENTITY % mousebutton.element "INCLUDE">
-<![%mousebutton.element;[
-<!--doc:The conventional name of a mouse button.-->
-<!ELEMENT mousebutton %ho; (%smallcptr.char.mix;)*>
-<!--end of mousebutton.element-->]]>
-
-<!ENTITY % mousebutton.attlist "INCLUDE">
-<![%mousebutton.attlist;[
-<!ATTLIST mousebutton
- %moreinfo.attrib;
- %common.attrib;
- %mousebutton.role.attrib;
- %local.mousebutton.attrib;
->
-<!--end of mousebutton.attlist-->]]>
-<!--end of mousebutton.module-->]]>
-
-<!ENTITY % msgtext.module "INCLUDE">
-<![%msgtext.module;[
-<!ENTITY % local.msgtext.attrib "">
-<!ENTITY % msgtext.role.attrib "%role.attrib;">
-
-<!ENTITY % msgtext.element "INCLUDE">
-<![%msgtext.element;[
-<!--doc:The actual text of a message component in a message set.-->
-<!ELEMENT msgtext %ho; ((%component.mix;)+)>
-<!--end of msgtext.element-->]]>
-
-<!ENTITY % msgtext.attlist "INCLUDE">
-<![%msgtext.attlist;[
-<!ATTLIST msgtext
- %common.attrib;
- %msgtext.role.attrib;
- %local.msgtext.attrib;
->
-<!--end of msgtext.attlist-->]]>
-<!--end of msgtext.module-->]]>
-
-<!ENTITY % option.module "INCLUDE">
-<![%option.module;[
-<!ENTITY % local.option.attrib "">
-<!ENTITY % option.role.attrib "%role.attrib;">
-
-<!ENTITY % option.element "INCLUDE">
-<![%option.element;[
-<!--doc:An option for a software command.-->
-<!ELEMENT option %ho; (%cptr.char.mix;)*>
-<!--end of option.element-->]]>
-
-<!ENTITY % option.attlist "INCLUDE">
-<![%option.attlist;[
-<!ATTLIST option
- %common.attrib;
- %option.role.attrib;
- %local.option.attrib;
->
-<!--end of option.attlist-->]]>
-<!--end of option.module-->]]>
-
-<!ENTITY % optional.module "INCLUDE">
-<![%optional.module;[
-<!ENTITY % local.optional.attrib "">
-<!ENTITY % optional.role.attrib "%role.attrib;">
-
-<!ENTITY % optional.element "INCLUDE">
-<![%optional.element;[
-<!--doc:Optional information.-->
-<!ELEMENT optional %ho; (%cptr.char.mix;)*>
-<!--end of optional.element-->]]>
-
-<!ENTITY % optional.attlist "INCLUDE">
-<![%optional.attlist;[
-<!ATTLIST optional
- %common.attrib;
- %optional.role.attrib;
- %local.optional.attrib;
->
-<!--end of optional.attlist-->]]>
-<!--end of optional.module-->]]>
-
-<!ENTITY % parameter.module "INCLUDE">
-<![%parameter.module;[
-<!ENTITY % local.parameter.attrib "">
-<!ENTITY % parameter.role.attrib "%role.attrib;">
-
-<!ENTITY % parameter.element "INCLUDE">
-<![%parameter.element;[
-<!--doc:A value or a symbolic reference to a value.-->
-<!ELEMENT parameter %ho; (%cptr.char.mix;)*>
-<!--end of parameter.element-->]]>
-
-<!-- Class: Type of the Parameter; no default -->
-
-
-<!ENTITY % parameter.attlist "INCLUDE">
-<![%parameter.attlist;[
-<!ATTLIST parameter
- class (command
- |function
- |option) #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %parameter.role.attrib;
- %local.parameter.attrib;
->
-<!--end of parameter.attlist-->]]>
-<!--end of parameter.module-->]]>
-
-<!ENTITY % prompt.module "INCLUDE">
-<![%prompt.module;[
-<!ENTITY % local.prompt.attrib "">
-<!ENTITY % prompt.role.attrib "%role.attrib;">
-
-<!ENTITY % prompt.element "INCLUDE">
-<![%prompt.element;[
-<!--doc:A character or string indicating the start of an input field in a computer display.-->
-<!ELEMENT prompt %ho; (%smallcptr.char.mix;|co)*>
-<!--end of prompt.element-->]]>
-
-<!ENTITY % prompt.attlist "INCLUDE">
-<![%prompt.attlist;[
-<!ATTLIST prompt
- %moreinfo.attrib;
- %common.attrib;
- %prompt.role.attrib;
- %local.prompt.attrib;
->
-<!--end of prompt.attlist-->]]>
-<!--end of prompt.module-->]]>
-
-<!ENTITY % property.module "INCLUDE">
-<![%property.module;[
-<!ENTITY % local.property.attrib "">
-<!ENTITY % property.role.attrib "%role.attrib;">
-
-<!ENTITY % property.element "INCLUDE">
-<![%property.element;[
-<!--doc:A unit of data associated with some part of a computer system.-->
-<!ELEMENT property %ho; (%cptr.char.mix;)*>
-<!--end of property.element-->]]>
-
-<!ENTITY % property.attlist "INCLUDE">
-<![%property.attlist;[
-<!ATTLIST property
- %moreinfo.attrib;
- %common.attrib;
- %property.role.attrib;
- %local.property.attrib;
->
-<!--end of property.attlist-->]]>
-<!--end of property.module-->]]>
-
-<!ENTITY % replaceable.module "INCLUDE">
-<![%replaceable.module;[
-<!ENTITY % local.replaceable.attrib "">
-<!ENTITY % replaceable.role.attrib "%role.attrib;">
-
-<!ENTITY % replaceable.element "INCLUDE">
-<![%replaceable.element;[
-<!--doc:Content that may or must be replaced by the user.-->
-<!ELEMENT replaceable %ho; (#PCDATA
- | %link.char.class;
- | optional
- | %base.char.class;
- | %other.char.class;
- | inlinegraphic
- | inlinemediaobject
- | co)*>
-<!--end of replaceable.element-->]]>
-
-<!-- Class: Type of information the element represents; no
- default -->
-
-
-<!ENTITY % replaceable.attlist "INCLUDE">
-<![%replaceable.attlist;[
-<!ATTLIST replaceable
- class (command
- |function
- |option
- |parameter) #IMPLIED
- %common.attrib;
- %replaceable.role.attrib;
- %local.replaceable.attrib;
->
-<!--end of replaceable.attlist-->]]>
-<!--end of replaceable.module-->]]>
-
-<!ENTITY % returnvalue.module "INCLUDE">
-<![%returnvalue.module;[
-<!ENTITY % local.returnvalue.attrib "">
-<!ENTITY % returnvalue.role.attrib "%role.attrib;">
-
-<!ENTITY % returnvalue.element "INCLUDE">
-<![%returnvalue.element;[
-<!--doc:The value returned by a function.-->
-<!ELEMENT returnvalue %ho; (%smallcptr.char.mix;)*>
-<!--end of returnvalue.element-->]]>
-
-<!ENTITY % returnvalue.attlist "INCLUDE">
-<![%returnvalue.attlist;[
-<!ATTLIST returnvalue
- %common.attrib;
- %returnvalue.role.attrib;
- %local.returnvalue.attrib;
->
-<!--end of returnvalue.attlist-->]]>
-<!--end of returnvalue.module-->]]>
-
-<!ENTITY % sgmltag.module "INCLUDE">
-<![%sgmltag.module;[
-<!ENTITY % local.sgmltag.attrib "">
-<!ENTITY % sgmltag.role.attrib "%role.attrib;">
-
-<!ENTITY % sgmltag.element "INCLUDE">
-<![%sgmltag.element;[
-<!--doc:A component of SGML markup.-->
-<!ELEMENT sgmltag %ho; (%smallcptr.char.mix;)*>
-<!--end of sgmltag.element-->]]>
-
-<!-- Class: Type of SGML construct the element names; no default -->
-
-
-<!ENTITY % sgmltag.attlist "INCLUDE">
-<![%sgmltag.attlist;[
-<!ATTLIST sgmltag
- class (attribute
- |attvalue
- |element
- |endtag
- |emptytag
- |genentity
- |numcharref
- |paramentity
- |pi
- |xmlpi
- |starttag
- |sgmlcomment
- |prefix
- |namespace
- |localname) #IMPLIED
- namespace CDATA #IMPLIED
- %common.attrib;
- %sgmltag.role.attrib;
- %local.sgmltag.attrib;
->
-<!--end of sgmltag.attlist-->]]>
-<!--end of sgmltag.module-->]]>
-
-<!ENTITY % structfield.module "INCLUDE">
-<![%structfield.module;[
-<!ENTITY % local.structfield.attrib "">
-<!ENTITY % structfield.role.attrib "%role.attrib;">
-
-<!ENTITY % structfield.element "INCLUDE">
-<![%structfield.element;[
-<!--doc:A field in a structure (in the programming language sense).-->
-<!ELEMENT structfield %ho; (%smallcptr.char.mix;)*>
-<!--end of structfield.element-->]]>
-
-<!ENTITY % structfield.attlist "INCLUDE">
-<![%structfield.attlist;[
-<!ATTLIST structfield
- %common.attrib;
- %structfield.role.attrib;
- %local.structfield.attrib;
->
-<!--end of structfield.attlist-->]]>
-<!--end of structfield.module-->]]>
-
-<!ENTITY % structname.module "INCLUDE">
-<![%structname.module;[
-<!ENTITY % local.structname.attrib "">
-<!ENTITY % structname.role.attrib "%role.attrib;">
-
-<!ENTITY % structname.element "INCLUDE">
-<![%structname.element;[
-<!--doc:The name of a structure (in the programming language sense).-->
-<!ELEMENT structname %ho; (%smallcptr.char.mix;)*>
-<!--end of structname.element-->]]>
-
-<!ENTITY % structname.attlist "INCLUDE">
-<![%structname.attlist;[
-<!ATTLIST structname
- %common.attrib;
- %structname.role.attrib;
- %local.structname.attrib;
->
-<!--end of structname.attlist-->]]>
-<!--end of structname.module-->]]>
-
-<!ENTITY % symbol.module "INCLUDE">
-<![%symbol.module;[
-<!ENTITY % local.symbol.attrib "">
-<!ENTITY % symbol.role.attrib "%role.attrib;">
-
-<!ENTITY % symbol.element "INCLUDE">
-<![%symbol.element;[
-<!--doc:A name that is replaced by a value before processing.-->
-<!ELEMENT symbol %ho; (%smallcptr.char.mix;)*>
-<!--end of symbol.element-->]]>
-
-<!-- Class: Type of symbol; no default -->
-
-
-<!ENTITY % symbol.attlist "INCLUDE">
-<![%symbol.attlist;[
-<!ATTLIST symbol
- class (limit) #IMPLIED
- %common.attrib;
- %symbol.role.attrib;
- %local.symbol.attrib;
->
-<!--end of symbol.attlist-->]]>
-<!--end of symbol.module-->]]>
-
-<!ENTITY % systemitem.module "INCLUDE">
-<![%systemitem.module;[
-<!ENTITY % local.systemitem.attrib "">
-<!ENTITY % systemitem.role.attrib "%role.attrib;">
-
-<!ENTITY % systemitem.element "INCLUDE">
-<![%systemitem.element;[
-<!--doc:A system-related item or term.-->
-<!ELEMENT systemitem %ho; (%cptr.char.mix; | acronym | co)*>
-<!--end of systemitem.element-->]]>
-
-<!-- Class: Type of system item the element names; no default -->
-
-<!ENTITY % systemitem.attlist "INCLUDE">
-<![%systemitem.attlist;[
-<!ATTLIST systemitem
- class (constant
- |daemon
- |domainname
- |etheraddress
- |event
- |eventhandler
- |filesystem
- |fqdomainname
- |groupname
- |ipaddress
- |library
- |macro
- |netmask
- |newsgroup
- |osname
- |protocol
- |resource
- |systemname
- |username
- |process
- |server
- |service) #IMPLIED
- %moreinfo.attrib;
- %common.attrib;
- %systemitem.role.attrib;
- %local.systemitem.attrib;
->
-<!--end of systemitem.attlist-->]]>
-<!--end of systemitem.module-->]]>
-
-<!ENTITY % uri.module "INCLUDE">
-<![%uri.module;[
-<!ENTITY % local.uri.attrib "">
-<!ENTITY % uri.role.attrib "%role.attrib;">
-
-<!ENTITY % uri.element "INCLUDE">
-<![%uri.element;[
-<!--doc:A Uniform Resource Identifier.-->
-<!ELEMENT uri %ho; (%smallcptr.char.mix;)*>
-<!--end of uri.element-->]]>
-
-<!-- Type: Type of URI; no default -->
-
-<!ENTITY % uri.attlist "INCLUDE">
-<![%uri.attlist;[
-<!ATTLIST uri
- type CDATA #IMPLIED
- %common.attrib;
- %uri.role.attrib;
- %local.uri.attrib;
->
-<!--end of uri.attlist-->]]>
-<!--end of uri.module-->]]>
-
-<!ENTITY % token.module "INCLUDE">
-<![%token.module;[
-<!ENTITY % local.token.attrib "">
-<!ENTITY % token.role.attrib "%role.attrib;">
-
-<!ENTITY % token.element "INCLUDE">
-<![%token.element;[
-<!--doc:A unit of information.-->
-<!ELEMENT token %ho; (%smallcptr.char.mix;)*>
-<!--end of token.element-->]]>
-
-<!ENTITY % token.attlist "INCLUDE">
-<![%token.attlist;[
-<!ATTLIST token
- %common.attrib;
- %token.role.attrib;
- %local.token.attrib;
->
-<!--end of token.attlist-->]]>
-<!--end of token.module-->]]>
-
-<!ENTITY % type.module "INCLUDE">
-<![%type.module;[
-<!ENTITY % local.type.attrib "">
-<!ENTITY % type.role.attrib "%role.attrib;">
-
-<!ENTITY % type.element "INCLUDE">
-<![%type.element;[
-<!--doc:The classification of a value.-->
-<!ELEMENT type %ho; (%smallcptr.char.mix;)*>
-<!--end of type.element-->]]>
-
-<!ENTITY % type.attlist "INCLUDE">
-<![%type.attlist;[
-<!ATTLIST type
- %common.attrib;
- %type.role.attrib;
- %local.type.attrib;
->
-<!--end of type.attlist-->]]>
-<!--end of type.module-->]]>
-
-<!ENTITY % userinput.module "INCLUDE">
-<![%userinput.module;[
-<!ENTITY % local.userinput.attrib "">
-<!ENTITY % userinput.role.attrib "%role.attrib;">
-
-<!ENTITY % userinput.element "INCLUDE">
-<![%userinput.element;[
-<!--doc:Data entered by the user.-->
-<!ELEMENT userinput %ho; (%cptr.char.mix;|co)*>
-<!--end of userinput.element-->]]>
-
-<!ENTITY % userinput.attlist "INCLUDE">
-<![%userinput.attlist;[
-<!ATTLIST userinput
- %moreinfo.attrib;
- %common.attrib;
- %userinput.role.attrib;
- %local.userinput.attrib;
->
-<!--end of userinput.attlist-->]]>
-<!--end of userinput.module-->]]>
-
-<!ENTITY % termdef.module "INCLUDE">
-<![%termdef.module;[
-<!ENTITY % local.termdef.attrib "">
-<!ENTITY % termdef.role.attrib "%role.attrib;">
-
-<!ENTITY % termdef.element "INCLUDE">
-<![%termdef.element;[
-<!--doc:An inline definition of a term.-->
-<!ELEMENT termdef %ho; (%para.char.mix;)*>
-<!--end of termdef.element-->]]>
-
-<!ENTITY % termdef.attlist "INCLUDE">
-<![%termdef.attlist;[
-<!ATTLIST termdef
- %common.attrib;
- %termdef.role.attrib;
- %local.termdef.attrib;
->
-<!--end of termdef.attlist-->]]>
-<!--end of termdef.module-->]]>
-
-<!-- General words and phrases ............................................ -->
-
-<!ENTITY % abbrev.module "INCLUDE">
-<![%abbrev.module;[
-<!ENTITY % local.abbrev.attrib "">
-<!ENTITY % abbrev.role.attrib "%role.attrib;">
-
-<!ENTITY % abbrev.element "INCLUDE">
-<![%abbrev.element;[
-<!--doc:An abbreviation, especially one followed by a period.-->
-<!ELEMENT abbrev %ho; (%word.char.mix;)*>
-<!--end of abbrev.element-->]]>
-
-<!ENTITY % abbrev.attlist "INCLUDE">
-<![%abbrev.attlist;[
-<!ATTLIST abbrev
- %common.attrib;
- %abbrev.role.attrib;
- %local.abbrev.attrib;
->
-<!--end of abbrev.attlist-->]]>
-<!--end of abbrev.module-->]]>
-
-<!ENTITY % acronym.module "INCLUDE">
-<![%acronym.module;[
-<!ENTITY % local.acronym.attrib "">
-<!ENTITY % acronym.role.attrib "%role.attrib;">
-
-<!ENTITY % acronym.element "INCLUDE">
-<![%acronym.element;[
-<!--doc:An often pronounceable word made from the initial (or selected) letters of a name or phrase.-->
-<!ELEMENT acronym %ho; (%word.char.mix;)*
- %acronym.exclusion;>
-<!--end of acronym.element-->]]>
-
-<!ENTITY % acronym.attlist "INCLUDE">
-<![%acronym.attlist;[
-<!ATTLIST acronym
- %common.attrib;
- %acronym.role.attrib;
- %local.acronym.attrib;
->
-<!--end of acronym.attlist-->]]>
-<!--end of acronym.module-->]]>
-
-<!ENTITY % citation.module "INCLUDE">
-<![%citation.module;[
-<!ENTITY % local.citation.attrib "">
-<!ENTITY % citation.role.attrib "%role.attrib;">
-
-<!ENTITY % citation.element "INCLUDE">
-<![%citation.element;[
-<!--doc:An inline bibliographic reference to another published work.-->
-<!ELEMENT citation %ho; (%para.char.mix;)*>
-<!--end of citation.element-->]]>
-
-<!ENTITY % citation.attlist "INCLUDE">
-<![%citation.attlist;[
-<!ATTLIST citation
- %common.attrib;
- %citation.role.attrib;
- %local.citation.attrib;
->
-<!--end of citation.attlist-->]]>
-<!--end of citation.module-->]]>
-
-<!ENTITY % citerefentry.module "INCLUDE">
-<![%citerefentry.module;[
-<!ENTITY % local.citerefentry.attrib "">
-<!ENTITY % citerefentry.role.attrib "%role.attrib;">
-
-<!ENTITY % citerefentry.element "INCLUDE">
-<![%citerefentry.element;[
-<!--doc:A citation to a reference page.-->
-<!ELEMENT citerefentry %ho; (refentrytitle, manvolnum?)>
-<!--end of citerefentry.element-->]]>
-
-<!ENTITY % citerefentry.attlist "INCLUDE">
-<![%citerefentry.attlist;[
-<!ATTLIST citerefentry
- %common.attrib;
- %citerefentry.role.attrib;
- %local.citerefentry.attrib;
->
-<!--end of citerefentry.attlist-->]]>
-<!--end of citerefentry.module-->]]>
-
-<!ENTITY % refentrytitle.module "INCLUDE">
-<![%refentrytitle.module;[
-<!ENTITY % local.refentrytitle.attrib "">
-<!ENTITY % refentrytitle.role.attrib "%role.attrib;">
-
-<!ENTITY % refentrytitle.element "INCLUDE">
-<![%refentrytitle.element;[
-<!--doc:The title of a reference page.-->
-<!ELEMENT refentrytitle %ho; (%para.char.mix;)*>
-<!--end of refentrytitle.element-->]]>
-
-<!ENTITY % refentrytitle.attlist "INCLUDE">
-<![%refentrytitle.attlist;[
-<!ATTLIST refentrytitle
- %common.attrib;
- %refentrytitle.role.attrib;
- %local.refentrytitle.attrib;
->
-<!--end of refentrytitle.attlist-->]]>
-<!--end of refentrytitle.module-->]]>
-
-<!ENTITY % manvolnum.module "INCLUDE">
-<![%manvolnum.module;[
-<!ENTITY % local.manvolnum.attrib "">
-<!ENTITY % namvolnum.role.attrib "%role.attrib;">
-
-<!ENTITY % manvolnum.element "INCLUDE">
-<![%manvolnum.element;[
-<!--doc:A reference volume number.-->
-<!ELEMENT manvolnum %ho; (%word.char.mix;)*>
-<!--end of manvolnum.element-->]]>
-
-<!ENTITY % manvolnum.attlist "INCLUDE">
-<![%manvolnum.attlist;[
-<!ATTLIST manvolnum
- %common.attrib;
- %namvolnum.role.attrib;
- %local.manvolnum.attrib;
->
-<!--end of manvolnum.attlist-->]]>
-<!--end of manvolnum.module-->]]>
-
-<!ENTITY % citetitle.module "INCLUDE">
-<![%citetitle.module;[
-<!ENTITY % local.citetitle.attrib "">
-<!ENTITY % citetitle.role.attrib "%role.attrib;">
-
-<!ENTITY % citetitle.element "INCLUDE">
-<![%citetitle.element;[
-<!--doc:The title of a cited work.-->
-<!ELEMENT citetitle %ho; (%para.char.mix;)*>
-<!--end of citetitle.element-->]]>
-
-<!-- Pubwork: Genre of published work cited; no default -->
-
-
-<!ENTITY % citetitle.attlist "INCLUDE">
-<![%citetitle.attlist;[
-<!ATTLIST citetitle
- pubwork (article
- |book
- |chapter
- |part
- |refentry
- |section
- |journal
- |series
- |set
- |manuscript
- |cdrom
- |dvd
- |wiki
- |gopher
- |bbs
- |emailmessage
- |webpage
- |newsposting) #IMPLIED
- %common.attrib;
- %citetitle.role.attrib;
- %local.citetitle.attrib;
->
-<!--end of citetitle.attlist-->]]>
-<!--end of citetitle.module-->]]>
-
-<!ENTITY % emphasis.module "INCLUDE">
-<![%emphasis.module;[
-<!ENTITY % local.emphasis.attrib "">
-<!ENTITY % emphasis.role.attrib "%role.attrib;">
-
-<!ENTITY % emphasis.element "INCLUDE">
-<![%emphasis.element;[
-<!--doc:Emphasized text.-->
-<!ELEMENT emphasis %ho; (%para.char.mix;)*>
-<!--end of emphasis.element-->]]>
-
-<!ENTITY % emphasis.attlist "INCLUDE">
-<![%emphasis.attlist;[
-<!ATTLIST emphasis
- %common.attrib;
- %emphasis.role.attrib;
- %local.emphasis.attrib;
->
-<!--end of emphasis.attlist-->]]>
-<!--end of emphasis.module-->]]>
-
-<!ENTITY % foreignphrase.module "INCLUDE">
-<![%foreignphrase.module;[
-<!ENTITY % local.foreignphrase.attrib "">
-<!ENTITY % foreignphrase.role.attrib "%role.attrib;">
-
-<!ENTITY % foreignphrase.element "INCLUDE">
-<![%foreignphrase.element;[
-<!--doc:A word or phrase in a language other than the primary language of the document.-->
-<!ELEMENT foreignphrase %ho; (%para.char.mix;)*>
-<!--end of foreignphrase.element-->]]>
-
-<!ENTITY % foreignphrase.attlist "INCLUDE">
-<![%foreignphrase.attlist;[
-<!ATTLIST foreignphrase
- %common.attrib;
- %foreignphrase.role.attrib;
- %local.foreignphrase.attrib;
->
-<!--end of foreignphrase.attlist-->]]>
-<!--end of foreignphrase.module-->]]>
-
-<!ENTITY % glossterm.module "INCLUDE">
-<![%glossterm.module;[
-<!ENTITY % local.glossterm.attrib "">
-<!ENTITY % glossterm.role.attrib "%role.attrib;">
-
-<!ENTITY % glossterm.element "INCLUDE">
-<![%glossterm.element;[
-<!--doc:A glossary term.-->
-<!ELEMENT glossterm %ho; (%para.char.mix;)*
- %glossterm.exclusion;>
-<!--end of glossterm.element-->]]>
-
-<!-- to GlossEntry if Glossterm used in text -->
-<!-- BaseForm: Provides the form of GlossTerm to be used
- for indexing -->
-
-<!ENTITY % glossterm.attlist "INCLUDE">
-<![%glossterm.attlist;[
-<!ATTLIST glossterm
- baseform CDATA #IMPLIED
- %linkend.attrib;
- %common.attrib;
- %glossterm.role.attrib;
- %local.glossterm.attrib;
->
-<!--end of glossterm.attlist-->]]>
-<!--end of glossterm.module-->]]>
-
-<!ENTITY % firstterm.module "INCLUDE">
-<![%firstterm.module;[
-<!ENTITY % local.firstterm.attrib "">
-<!ENTITY % firstterm.role.attrib "%role.attrib;">
-
-<!ENTITY % firstterm.element "INCLUDE">
-<![%firstterm.element;[
-<!--doc:The first occurrence of a term.-->
-<!ELEMENT firstterm %ho; (%para.char.mix;)*
- %glossterm.exclusion;>
-<!--end of firstterm.element-->]]>
-
-<!-- to GlossEntry or other explanation -->
-
-
-<!ENTITY % firstterm.attlist "INCLUDE">
-<![%firstterm.attlist;[
-<!ATTLIST firstterm
- baseform CDATA #IMPLIED
- %linkend.attrib;
- %common.attrib;
- %firstterm.role.attrib;
- %local.firstterm.attrib;
->
-<!--end of firstterm.attlist-->]]>
-<!--end of firstterm.module-->]]>
-
-<!ENTITY % phrase.module "INCLUDE">
-<![%phrase.module;[
-<!ENTITY % local.phrase.attrib "">
-<!ENTITY % phrase.role.attrib "%role.attrib;">
-
-<!ENTITY % phrase.element "INCLUDE">
-<![%phrase.element;[
-<!--doc:A span of text.-->
-<!ELEMENT phrase %ho; (%para.char.mix;)*>
-<!--end of phrase.element-->]]>
-
-<!ENTITY % phrase.attlist "INCLUDE">
-<![%phrase.attlist;[
-<!ATTLIST phrase
- %common.attrib;
- %phrase.role.attrib;
- %local.phrase.attrib;
->
-<!--end of phrase.attlist-->]]>
-<!--end of phrase.module-->]]>
-
-<!ENTITY % quote.module "INCLUDE">
-<![%quote.module;[
-<!ENTITY % local.quote.attrib "">
-<!ENTITY % quote.role.attrib "%role.attrib;">
-
-<!ENTITY % quote.element "INCLUDE">
-<![%quote.element;[
-<!--doc:An inline quotation.-->
-<!ELEMENT quote %ho; (%para.char.mix;)*>
-<!--end of quote.element-->]]>
-
-<!ENTITY % quote.attlist "INCLUDE">
-<![%quote.attlist;[
-<!ATTLIST quote
- %common.attrib;
- %quote.role.attrib;
- %local.quote.attrib;
->
-<!--end of quote.attlist-->]]>
-<!--end of quote.module-->]]>
-
-<!ENTITY % ssscript.module "INCLUDE">
-<![%ssscript.module;[
-<!ENTITY % local.ssscript.attrib "">
-<!ENTITY % ssscript.role.attrib "%role.attrib;">
-
-<!ENTITY % subscript.element "INCLUDE">
-<![%subscript.element;[
-<!--doc:A subscript (as in H{^2}O, the molecular formula for water).-->
-<!ELEMENT subscript %ho; (#PCDATA
- | %link.char.class;
- | emphasis
- | replaceable
- | symbol
- | inlinegraphic
- | inlinemediaobject
- | %base.char.class;
- | %other.char.class;)*
- %ubiq.exclusion;>
-<!--end of subscript.element-->]]>
-
-<!ENTITY % subscript.attlist "INCLUDE">
-<![%subscript.attlist;[
-<!ATTLIST subscript
- %common.attrib;
- %ssscript.role.attrib;
- %local.ssscript.attrib;
->
-<!--end of subscript.attlist-->]]>
-
-<!ENTITY % superscript.element "INCLUDE">
-<![%superscript.element;[
-<!--doc:A superscript (as in x^2, the mathematical notation for x multiplied by itself).-->
-<!ELEMENT superscript %ho; (#PCDATA
- | %link.char.class;
- | emphasis
- | replaceable
- | symbol
- | inlinegraphic
- | inlinemediaobject
- | %base.char.class;
- | %other.char.class;)*
- %ubiq.exclusion;>
-<!--end of superscript.element-->]]>
-
-<!ENTITY % superscript.attlist "INCLUDE">
-<![%superscript.attlist;[
-<!ATTLIST superscript
- %common.attrib;
- %ssscript.role.attrib;
- %local.ssscript.attrib;
->
-<!--end of superscript.attlist-->]]>
-<!--end of ssscript.module-->]]>
-
-<!ENTITY % trademark.module "INCLUDE">
-<![%trademark.module;[
-<!ENTITY % local.trademark.attrib "">
-<!ENTITY % trademark.role.attrib "%role.attrib;">
-
-<!ENTITY % trademark.element "INCLUDE">
-<![%trademark.element;[
-<!--doc:A trademark.-->
-<!ELEMENT trademark %ho; (#PCDATA
- | %link.char.class;
- | %tech.char.class;
- | %base.char.class;
- | %other.char.class;
- | inlinegraphic
- | inlinemediaobject
- | emphasis)*>
-<!--end of trademark.element-->]]>
-
-<!-- Class: More precisely identifies the item the element names -->
-
-
-<!ENTITY % trademark.attlist "INCLUDE">
-<![%trademark.attlist;[
-<!ATTLIST trademark
- class (service
- |trade
- |registered
- |copyright) 'trade'
- %common.attrib;
- %trademark.role.attrib;
- %local.trademark.attrib;
->
-<!--end of trademark.attlist-->]]>
-<!--end of trademark.module-->]]>
-
-<!ENTITY % wordasword.module "INCLUDE">
-<![%wordasword.module;[
-<!ENTITY % local.wordasword.attrib "">
-<!ENTITY % wordasword.role.attrib "%role.attrib;">
-
-<!ENTITY % wordasword.element "INCLUDE">
-<![%wordasword.element;[
-<!--doc:A word meant specifically as a word and not representing anything else.-->
-<!ELEMENT wordasword %ho; (%word.char.mix;)*>
-<!--end of wordasword.element-->]]>
-
-<!ENTITY % wordasword.attlist "INCLUDE">
-<![%wordasword.attlist;[
-<!ATTLIST wordasword
- %common.attrib;
- %wordasword.role.attrib;
- %local.wordasword.attrib;
->
-<!--end of wordasword.attlist-->]]>
-<!--end of wordasword.module-->]]>
-
-<!-- Links and cross-references ........................................... -->
-
-<!ENTITY % link.module "INCLUDE">
-<![%link.module;[
-<!ENTITY % local.link.attrib "">
-<!ENTITY % link.role.attrib "%role.attrib;">
-
-<!ENTITY % link.element "INCLUDE">
-<![%link.element;[
-<!--doc:A hypertext link.-->
-<!ELEMENT link %ho; (%para.char.mix;)*
- %links.exclusion;>
-<!--end of link.element-->]]>
-
-<!-- Endterm: ID of element containing text that is to be
- fetched from elsewhere in the document to appear as
- the content of this element -->
-<!-- to linked-to object -->
-<!-- Type: Freely assignable parameter -->
-
-
-<!ENTITY % link.attlist "INCLUDE">
-<![%link.attlist;[
-<!ATTLIST link
- endterm IDREF #IMPLIED
- xrefstyle CDATA #IMPLIED
- type CDATA #IMPLIED
- %linkendreq.attrib;
- %common.attrib;
- %link.role.attrib;
- %local.link.attrib;
->
-<!--end of link.attlist-->]]>
-<!--end of link.module-->]]>
-
-<!ENTITY % olink.module "INCLUDE">
-<![%olink.module;[
-<!ENTITY % local.olink.attrib "">
-<!ENTITY % olink.role.attrib "%role.attrib;">
-
-<!ENTITY % olink.element "INCLUDE">
-<![%olink.element;[
-<!--doc:A link that addresses its target indirectly, through an entity.-->
-<!ELEMENT olink %ho; (%para.char.mix;)*
- %links.exclusion;>
-<!--end of olink.element-->]]>
-
-<!-- TargetDocEnt: Name of an entity to be the target of the link -->
-<!-- LinkMode: ID of a ModeSpec containing instructions for
- operating on the entity named by TargetDocEnt -->
-<!-- LocalInfo: Information that may be passed to ModeSpec -->
-<!-- Type: Freely assignable parameter -->
-
-
-<!ENTITY % olink.attlist "INCLUDE">
-<![%olink.attlist;[
-<!ATTLIST olink
- targetdocent ENTITY #IMPLIED
- linkmode IDREF #IMPLIED
- localinfo CDATA #IMPLIED
- type CDATA #IMPLIED
- targetdoc CDATA #IMPLIED
- targetptr CDATA #IMPLIED
- xrefstyle CDATA #IMPLIED
- %common.attrib;
- %olink.role.attrib;
- %local.olink.attrib;
->
-<!--end of olink.attlist-->]]>
-<!--end of olink.module-->]]>
-
-<!ENTITY % ulink.module "INCLUDE">
-<![%ulink.module;[
-<!ENTITY % local.ulink.attrib "">
-<!ENTITY % ulink.role.attrib "%role.attrib;">
-
-<!ENTITY % ulink.element "INCLUDE">
-<![%ulink.element;[
-<!--doc:A link that addresses its target by means of a URL (Uniform Resource Locator).-->
-<!ELEMENT ulink %ho; (%para.char.mix;)*
- %links.exclusion;>
-<!--end of ulink.element-->]]>
-
-<!-- URL: uniform resource locator; the target of the ULink -->
-<!-- Type: Freely assignable parameter -->
-
-
-<!ENTITY % ulink.attlist "INCLUDE">
-<![%ulink.attlist;[
-<!ATTLIST ulink
- url CDATA #REQUIRED
- type CDATA #IMPLIED
- xrefstyle CDATA #IMPLIED
- %common.attrib;
- %ulink.role.attrib;
- %local.ulink.attrib;
->
-<!--end of ulink.attlist-->]]>
-<!--end of ulink.module-->]]>
-
-<!ENTITY % footnoteref.module "INCLUDE">
-<![%footnoteref.module;[
-<!ENTITY % local.footnoteref.attrib "">
-<!ENTITY % footnoteref.role.attrib "%role.attrib;">
-
-<!ENTITY % footnoteref.element "INCLUDE">
-<![%footnoteref.element;[
-<!--doc:A cross reference to a footnote (a footnote mark).-->
-<!ELEMENT footnoteref %ho; EMPTY>
-<!--end of footnoteref.element-->]]>
-
-<!-- to footnote content supplied elsewhere -->
-
-
-<!ENTITY % footnoteref.attlist "INCLUDE">
-<![%footnoteref.attlist;[
-<!ATTLIST footnoteref
- %linkendreq.attrib; %label.attrib;
- %common.attrib;
- %footnoteref.role.attrib;
- %local.footnoteref.attrib;
->
-<!--end of footnoteref.attlist-->]]>
-<!--end of footnoteref.module-->]]>
-
-<!ENTITY % xref.module "INCLUDE">
-<![%xref.module;[
-<!ENTITY % local.xref.attrib "">
-<!ENTITY % xref.role.attrib "%role.attrib;">
-
-<!ENTITY % xref.element "INCLUDE">
-<![%xref.element;[
-<!--doc:A cross reference to another part of the document.-->
-<!ELEMENT xref %ho; EMPTY>
-<!--end of xref.element-->]]>
-
-<!-- Endterm: ID of element containing text that is to be
- fetched from elsewhere in the document to appear as
- the content of this element -->
-<!-- to linked-to object -->
-
-
-<!ENTITY % xref.attlist "INCLUDE">
-<![%xref.attlist;[
-<!ATTLIST xref
- endterm IDREF #IMPLIED
- xrefstyle CDATA #IMPLIED
- %common.attrib;
- %linkendreq.attrib;
- %xref.role.attrib;
- %local.xref.attrib;
->
-<!--end of xref.attlist-->]]>
-<!--end of xref.module-->]]>
-
-<!ENTITY % biblioref.module "INCLUDE">
-<![%biblioref.module;[
-<!ENTITY % local.biblioref.attrib "">
-<!ENTITY % biblioref.role.attrib "%role.attrib;">
-
-<!ENTITY % biblioref.element "INCLUDE">
-<![%biblioref.element;[
-<!--doc:A cross reference to a bibliographic entry.-->
-<!ELEMENT biblioref %ho; EMPTY>
-<!--end of biblioref.element-->]]>
-
-<!ENTITY % biblioref.attlist "INCLUDE">
-<![%biblioref.attlist;[
-<!ATTLIST biblioref
- endterm IDREF #IMPLIED
- xrefstyle CDATA #IMPLIED
- units CDATA #IMPLIED
- begin CDATA #IMPLIED
- end CDATA #IMPLIED
- %common.attrib;
- %linkendreq.attrib;
- %biblioref.role.attrib;
- %local.biblioref.attrib;
->
-<!--end of biblioref.attlist-->]]>
-<!--end of biblioref.module-->]]>
-
-<!-- Ubiquitous elements .................................................. -->
-
-<!ENTITY % anchor.module "INCLUDE">
-<![%anchor.module;[
-<!ENTITY % local.anchor.attrib "">
-<!ENTITY % anchor.role.attrib "%role.attrib;">
-
-<!ENTITY % anchor.element "INCLUDE">
-<![%anchor.element;[
-<!--doc:A spot in the document.-->
-<!ELEMENT anchor %ho; EMPTY>
-<!--end of anchor.element-->]]>
-
-<!-- required -->
-<!-- replaces Lang -->
-
-
-<!ENTITY % anchor.attlist "INCLUDE">
-<![%anchor.attlist;[
-<!ATTLIST anchor
- %idreq.attrib; %pagenum.attrib; %remap.attrib;
- %xreflabel.attrib;
- %revisionflag.attrib;
- %effectivity.attrib;
- %anchor.role.attrib;
- %local.anchor.attrib;
->
-<!--end of anchor.attlist-->]]>
-<!--end of anchor.module-->]]>
-
-<!ENTITY % beginpage.module "INCLUDE">
-<![%beginpage.module;[
-<!ENTITY % local.beginpage.attrib "">
-<!ENTITY % beginpage.role.attrib "%role.attrib;">
-
-<!ENTITY % beginpage.element "INCLUDE">
-<![%beginpage.element;[
-<!--doc:The location of a page break in a print version of the document.-->
-<!ELEMENT beginpage %ho; EMPTY>
-<!--end of beginpage.element-->]]>
-
-<!-- PageNum: Number of page that begins at this point -->
-
-
-<!ENTITY % beginpage.attlist "INCLUDE">
-<![%beginpage.attlist;[
-<!ATTLIST beginpage
- %pagenum.attrib;
- %common.attrib;
- %beginpage.role.attrib;
- %local.beginpage.attrib;
->
-<!--end of beginpage.attlist-->]]>
-<!--end of beginpage.module-->]]>
-
-<!-- IndexTerms appear in the text flow for generating or linking an
- index. -->
-
-<!ENTITY % indexterm.content.module "INCLUDE">
-<![%indexterm.content.module;[
-<!ENTITY % indexterm.module "INCLUDE">
-<![%indexterm.module;[
-<!ENTITY % local.indexterm.attrib "">
-<!ENTITY % indexterm.role.attrib "%role.attrib;">
-
-<!ENTITY % indexterm.element "INCLUDE">
-<![%indexterm.element;[
-<!--doc:A wrapper for terms to be indexed.-->
-<!ELEMENT indexterm %ho; (primary?, ((secondary, ((tertiary, (see|seealso+)?)
- | see | seealso+)?) | see | seealso+)?)
- %ubiq.exclusion;>
-<!--end of indexterm.element-->]]>
-
-<!-- Scope: Indicates which generated indices the IndexTerm
- should appear in: Global (whole document set), Local (this
- document only), or All (both) -->
-<!-- Significance: Whether this IndexTerm is the most pertinent
- of its series (Preferred) or not (Normal, the default) -->
-<!-- Class: Indicates type of IndexTerm; default is Singular,
- or EndOfRange if StartRef is supplied; StartOfRange value
- must be supplied explicitly on starts of ranges -->
-<!-- StartRef: ID of the IndexTerm that starts the indexing
- range ended by this IndexTerm -->
-<!-- Zone: IDs of the elements to which the IndexTerm applies,
- and indicates that the IndexTerm applies to those entire
- elements rather than the point at which the IndexTerm
- occurs -->
-
-
-<!ENTITY % indexterm.attlist "INCLUDE">
-<![%indexterm.attlist;[
-<!ATTLIST indexterm
- %pagenum.attrib;
- scope (all
- |global
- |local) #IMPLIED
- significance (preferred
- |normal) "normal"
- class (singular
- |startofrange
- |endofrange) #IMPLIED
- startref IDREF #IMPLIED
- zone IDREFS #IMPLIED
- type CDATA #IMPLIED
- %common.attrib;
- %indexterm.role.attrib;
- %local.indexterm.attrib;
->
-<!--end of indexterm.attlist-->]]>
-<!--end of indexterm.module-->]]>
-
-<!ENTITY % primsecter.module "INCLUDE">
-<![%primsecter.module;[
-<!ENTITY % local.primsecter.attrib "">
-<!ENTITY % primsecter.role.attrib "%role.attrib;">
-
-
-<!ENTITY % primary.element "INCLUDE">
-<![%primary.element;[
-<!--doc:The primary word or phrase under which an index term should be sorted.-->
-<!ELEMENT primary %ho; (%ndxterm.char.mix;)*>
-<!--end of primary.element-->]]>
-<!-- SortAs: Alternate sort string for index sorting, e.g.,
- "fourteen" for an element containing "14" -->
-
-<!ENTITY % primary.attlist "INCLUDE">
-<![%primary.attlist;[
-<!ATTLIST primary
- sortas CDATA #IMPLIED
- %common.attrib;
- %primsecter.role.attrib;
- %local.primsecter.attrib;
->
-<!--end of primary.attlist-->]]>
-
-
-<!ENTITY % secondary.element "INCLUDE">
-<![%secondary.element;[
-<!--doc:A secondary word or phrase in an index term.-->
-<!ELEMENT secondary %ho; (%ndxterm.char.mix;)*>
-<!--end of secondary.element-->]]>
-<!-- SortAs: Alternate sort string for index sorting, e.g.,
- "fourteen" for an element containing "14" -->
-
-<!ENTITY % secondary.attlist "INCLUDE">
-<![%secondary.attlist;[
-<!ATTLIST secondary
- sortas CDATA #IMPLIED
- %common.attrib;
- %primsecter.role.attrib;
- %local.primsecter.attrib;
->
-<!--end of secondary.attlist-->]]>
-
-
-<!ENTITY % tertiary.element "INCLUDE">
-<![%tertiary.element;[
-<!--doc:A tertiary word or phrase in an index term.-->
-<!ELEMENT tertiary %ho; (%ndxterm.char.mix;)*>
-<!--end of tertiary.element-->]]>
-<!-- SortAs: Alternate sort string for index sorting, e.g.,
- "fourteen" for an element containing "14" -->
-
-<!ENTITY % tertiary.attlist "INCLUDE">
-<![%tertiary.attlist;[
-<!ATTLIST tertiary
- sortas CDATA #IMPLIED
- %common.attrib;
- %primsecter.role.attrib;
- %local.primsecter.attrib;
->
-<!--end of tertiary.attlist-->]]>
-
-<!--end of primsecter.module-->]]>
-
-<!ENTITY % seeseealso.module "INCLUDE">
-<![%seeseealso.module;[
-<!ENTITY % local.seeseealso.attrib "">
-<!ENTITY % seeseealso.role.attrib "%role.attrib;">
-
-<!ENTITY % see.element "INCLUDE">
-<![%see.element;[
-<!--doc:Part of an index term directing the reader instead to another entry in the index.-->
-<!ELEMENT see %ho; (%ndxterm.char.mix;)*>
-<!--end of see.element-->]]>
-
-<!ENTITY % see.attlist "INCLUDE">
-<![%see.attlist;[
-<!ATTLIST see
- %common.attrib;
- %seeseealso.role.attrib;
- %local.seeseealso.attrib;
->
-<!--end of see.attlist-->]]>
-
-<!ENTITY % seealso.element "INCLUDE">
-<![%seealso.element;[
-<!--doc:Part of an index term directing the reader also to another entry in the index.-->
-<!ELEMENT seealso %ho; (%ndxterm.char.mix;)*>
-<!--end of seealso.element-->]]>
-
-<!ENTITY % seealso.attlist "INCLUDE">
-<![%seealso.attlist;[
-<!ATTLIST seealso
- %common.attrib;
- %seeseealso.role.attrib;
- %local.seeseealso.attrib;
->
-<!--end of seealso.attlist-->]]>
-<!--end of seeseealso.module-->]]>
-<!--end of indexterm.content.module-->]]>
-
-<!-- End of DocBook XML information pool module V4.5 ...................... -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/docbook.cat b/Utilities/xml/docbook-4.5/docbook.cat
deleted file mode 100644
index 25ac4dff0..000000000
--- a/Utilities/xml/docbook-4.5/docbook.cat
+++ /dev/null
@@ -1,113 +0,0 @@
- -- ...................................................................... --
- -- Catalog data for DocBook XML V4.5 .................................... --
- -- File docbook.cat ..................................................... --
-
- -- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/.
- --
-
- -- This is the catalog data file for DocBook XML V4.5. It is provided as
- a convenience in building your own catalog files. You need not use
- the filenames listed here, and need not use the filename method of
- identifying storage objects at all. See the documentation for
- detailed information on the files associated with the DocBook DTD.
- See SGML Open Technical Resolution 9401 for detailed information
- on supplying and using catalog data.
- --
-
- -- ...................................................................... --
- -- DocBook driver file .................................................. --
-
-PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "docbookx.dtd"
-
- -- ...................................................................... --
- -- DocBook modules ...................................................... --
-
-PUBLIC "-//OASIS//DTD DocBook CALS Table Model V4.5//EN"
- "calstblx.dtd"
-
-PUBLIC "-//OASIS//ELEMENTS DocBook XML HTML Tables V4.5//EN"
- "htmltblx.mod"
-
-PUBLIC "-//OASIS//DTD XML Exchange Table Model 19990315//EN"
- "soextblx.dtd"
-
-PUBLIC "-//OASIS//ELEMENTS DocBook Information Pool V4.5//EN"
- "dbpoolx.mod"
-
-PUBLIC "-//OASIS//ELEMENTS DocBook Document Hierarchy V4.5//EN"
- "dbhierx.mod"
-
-PUBLIC "-//OASIS//ENTITIES DocBook Additional General Entities V4.5//EN"
- "dbgenent.mod"
-
-PUBLIC "-//OASIS//ENTITIES DocBook Notations V4.5//EN"
- "dbnotnx.mod"
-
-PUBLIC "-//OASIS//ENTITIES DocBook Character Entities V4.5//EN"
- "dbcentx.mod"
-
- -- ...................................................................... --
- -- ISO entity sets ...................................................... --
-
-PUBLIC "ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML"
- "ent/isodia.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML"
- "ent/isonum.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Publishing//EN//XML"
- "ent/isopub.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES General Technical//EN//XML"
- "ent/isotech.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
- "ent/isolat1.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Latin 2//EN//XML"
- "ent/isolat2.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Greek Letters//EN//XML"
- "ent/isogrk1.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML"
- "ent/isogrk2.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Greek Symbols//EN//XML"
- "ent/isogrk3.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML"
- "ent/isogrk4.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML"
- "ent/isoamsa.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML"
- "ent/isoamsb.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML"
- "ent/isoamsc.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML"
- "ent/isoamsn.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML"
- "ent/isoamso.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML"
- "ent/isoamsr.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML"
- "ent/isobox.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML"
- "ent/isocyr1.ent"
-
-PUBLIC "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML"
- "ent/isocyr2.ent"
-
- -- End of catalog data for DocBook XML V4.5 ............................. --
- -- ...................................................................... --
diff --git a/Utilities/xml/docbook-4.5/docbookx.dtd b/Utilities/xml/docbook-4.5/docbookx.dtd
deleted file mode 100644
index 8b43c59b6..000000000
--- a/Utilities/xml/docbook-4.5/docbookx.dtd
+++ /dev/null
@@ -1,170 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook XML DTD V4.5 ................................................. -->
-<!-- File docbookx.dtd .................................................... -->
-
-<!-- Copyright 1992-2006 HaL Computer Systems, Inc.,
- O'Reilly & Associates, Inc., ArborText, Inc., Fujitsu Software
- Corporation, Norman Walsh, Sun Microsystems, Inc., and the
- Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- See also http://docbook.org/specs/
-
- $Id: docbookx.dtd 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook XML DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This is the driver file for V4.5 of the DocBook DTD.
- Please use the following formal public identifier to identify it:
-
- "-//OASIS//DTD DocBook XML V4.5//EN"
-
- For example, if your document's top-level element is Book, and
- you are using DocBook directly, use the FPI in the DOCTYPE
- declaration:
-
- <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd"
- [...]>
-
- Or, if you have a higher-level driver file that customizes DocBook,
- use the FPI in the parameter entity declaration:
-
- <!ENTITY % DocBookDTD PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
- "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
- %DocBookDTD;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!-- ...................................................................... -->
-<!-- Enable SGML features ................................................. -->
-
-<!ENTITY % sgml.features "IGNORE">
-<![%sgml.features;[
-<!ENTITY % xml.features "IGNORE">
-]]>
-<!ENTITY % xml.features "INCLUDE">
-
-<![%sgml.features;[
-<![%xml.features;[
-
-<!-- ERROR: Exactly one of xml.features and sgml.features must be turned on! -->
-<!ENTITY % dbnotn SYSTEM "http://www.oasis-open.org/docbook/xml/configerror.txt">
-<!ENTITY % dbcent SYSTEM "http://www.oasis-open.org/docbook/xml/configerror.txt">
-<!ENTITY % dbpool SYSTEM "http://www.oasis-open.org/docbook/xml/configerror.txt">
-<!ENTITY % dbhier SYSTEM "http://www.oasis-open.org/docbook/xml/configerror.txt">
-<!ENTITY % dbgenent SYSTEM "http://www.oasis-open.org/docbook/xml/configerror.txt">
-
-]]>
-]]>
-
-<![%sgml.features;[
-<!ENTITY % ho "- O">
-<!ENTITY % hh "- -">
-]]>
-
-<![%xml.features;[
-<!ENTITY % ho "">
-<!ENTITY % hh "">
-]]>
-
-<!-- ...................................................................... -->
-<!-- Notation declarations ................................................ -->
-
-<!ENTITY % dbnotn.module "INCLUDE">
-<![%dbnotn.module;[
-<!ENTITY % dbnotn PUBLIC
-"-//OASIS//ENTITIES DocBook Notations V4.5//EN"
-"dbnotnx.mod">
-%dbnotn;
-]]>
-
-<!-- ...................................................................... -->
-<!-- ISO character entity sets ............................................ -->
-
-<!ENTITY % dbcent.module "INCLUDE">
-<![%dbcent.module;[
-
-<!ENTITY % dbcent.euro "INCLUDE">
-<![%dbcent.euro;[
-<![%sgml.features;[
-<!ENTITY euro SDATA "[euro ]"><!-- euro sign -->
-]]>
-<![%xml.features;[
-<!ENTITY euro "&#x20AC;"><!-- euro sign, U+20AC NEW -->
-]]>
-]]>
-
-<!ENTITY % dbcent PUBLIC
-"-//OASIS//ENTITIES DocBook Character Entities V4.5//EN"
-"dbcentx.mod">
-%dbcent;
-]]>
-
-<!-- ...................................................................... -->
-<!-- DTD modules .......................................................... -->
-
-<!-- Information pool .............. -->
-
-<!ENTITY % dbpool.module "INCLUDE">
-<![ %dbpool.module; [
-<!ENTITY % dbpool PUBLIC
-"-//OASIS//ELEMENTS DocBook Information Pool V4.5//EN"
-"dbpoolx.mod">
-%dbpool;
-]]>
-
-<!-- Redeclaration placeholder ..... -->
-
-<!ENTITY % intermod.redecl.module "IGNORE">
-<![%intermod.redecl.module;[
-<!-- Defining rdbmods here makes some buggy XML parsers happy. -->
-<!ENTITY % rdbmods "">
-%rdbmods;
-<!--end of intermod.redecl.module-->]]>
-
-<!-- Document hierarchy ............ -->
-
-<!ENTITY % dbhier.module "INCLUDE">
-<![ %dbhier.module; [
-<!ENTITY % dbhier PUBLIC
-"-//OASIS//ELEMENTS DocBook Document Hierarchy V4.5//EN"
-"dbhierx.mod">
-%dbhier;
-]]>
-
-<!-- ...................................................................... -->
-<!-- Other general entities ............................................... -->
-
-<!ENTITY % dbgenent.module "INCLUDE">
-<![ %dbgenent.module; [
-<!ENTITY % dbgenent PUBLIC
-"-//OASIS//ENTITIES DocBook Additional General Entities V4.5//EN"
-"dbgenent.mod">
-%dbgenent;
-]]>
-
-<!-- End of DocBook XML DTD V4.5 .......................................... -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/ent/README b/Utilities/xml/docbook-4.5/ent/README
deleted file mode 100644
index c0da542a6..000000000
--- a/Utilities/xml/docbook-4.5/ent/README
+++ /dev/null
@@ -1,14 +0,0 @@
-XML Entity Declarations for Characters
-
-The character entity sets distributed with DocBook XML are direct
-copies of the official entities located at
-
- http://www.w3.org/2003/entities/
-
-They are distributed for historical compatibility and user convenience.
-The DocBook Technical Committee no longer attempts to maintain these
-definitions and will periodically update them from the W3C site if and
-as they are updated there.
-
-Please direct all questions or comments about the entities to the
-individuals or working groups who maintain the official sets.
diff --git a/Utilities/xml/docbook-4.5/ent/isoamsa.ent b/Utilities/xml/docbook-4.5/ent/isoamsa.ent
deleted file mode 100644
index dac3e6242..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamsa.ent
+++ /dev/null
@@ -1,97 +0,0 @@
-
-<!--
- File isoamsa.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamsa.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamsa.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamsa PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Arrow Relations//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamsa.ent"
- >
- %isoamsa;
-
--->
-
-<!ENTITY cularr "&#x021B6;" ><!--ANTICLOCKWISE TOP SEMICIRCLE ARROW -->
-<!ENTITY curarr "&#x021B7;" ><!--CLOCKWISE TOP SEMICIRCLE ARROW -->
-<!ENTITY dArr "&#x021D3;" ><!--DOWNWARDS DOUBLE ARROW -->
-<!ENTITY darr2 "&#x021CA;" ><!--DOWNWARDS PAIRED ARROWS -->
-<!ENTITY dharl "&#x021C3;" ><!--DOWNWARDS HARPOON WITH BARB LEFTWARDS -->
-<!ENTITY dharr "&#x021C2;" ><!--DOWNWARDS HARPOON WITH BARB RIGHTWARDS -->
-<!ENTITY dlarr "&#x02199;" ><!--SOUTH WEST ARROW -->
-<!ENTITY drarr "&#x02198;" ><!--SOUTH EAST ARROW -->
-<!ENTITY hArr "&#x021D4;" ><!--LEFT RIGHT DOUBLE ARROW -->
-<!ENTITY harr "&#x02194;" ><!--LEFT RIGHT ARROW -->
-<!ENTITY harrw "&#x021AD;" ><!--LEFT RIGHT WAVE ARROW -->
-<!ENTITY lAarr "&#x021DA;" ><!--LEFTWARDS TRIPLE ARROW -->
-<!ENTITY Larr "&#x0219E;" ><!--LEFTWARDS TWO HEADED ARROW -->
-<!ENTITY larr2 "&#x021C7;" ><!--LEFTWARDS PAIRED ARROWS -->
-<!ENTITY larrhk "&#x021A9;" ><!--LEFTWARDS ARROW WITH HOOK -->
-<!ENTITY larrlp "&#x021AB;" ><!--LEFTWARDS ARROW WITH LOOP -->
-<!ENTITY larrtl "&#x021A2;" ><!--LEFTWARDS ARROW WITH TAIL -->
-<!ENTITY lhard "&#x021BD;" ><!--LEFTWARDS HARPOON WITH BARB DOWNWARDS -->
-<!ENTITY lharu "&#x021BC;" ><!--LEFTWARDS HARPOON WITH BARB UPWARDS -->
-<!ENTITY lrarr2 "&#x021C6;" ><!--LEFTWARDS ARROW OVER RIGHTWARDS ARROW -->
-<!ENTITY lrhar2 "&#x021CB;" ><!--LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON -->
-<!ENTITY lsh "&#x021B0;" ><!--UPWARDS ARROW WITH TIP LEFTWARDS -->
-<!ENTITY map "&#x021A6;" ><!--RIGHTWARDS ARROW FROM BAR -->
-<!ENTITY mumap "&#x022B8;" ><!--MULTIMAP -->
-<!ENTITY nearr "&#x02197;" ><!--NORTH EAST ARROW -->
-<!ENTITY nhArr "&#x021CE;" ><!--LEFT RIGHT DOUBLE ARROW WITH STROKE -->
-<!ENTITY nharr "&#x021AE;" ><!--LEFT RIGHT ARROW WITH STROKE -->
-<!ENTITY nlArr "&#x021CD;" ><!--LEFTWARDS DOUBLE ARROW WITH STROKE -->
-<!ENTITY nlarr "&#x0219A;" ><!--LEFTWARDS ARROW WITH STROKE -->
-<!ENTITY nrArr "&#x021CF;" ><!--RIGHTWARDS DOUBLE ARROW WITH STROKE -->
-<!ENTITY nrarr "&#x0219B;" ><!--RIGHTWARDS ARROW WITH STROKE -->
-<!ENTITY nwarr "&#x02196;" ><!--NORTH WEST ARROW -->
-<!ENTITY olarr "&#x021BA;" ><!--ANTICLOCKWISE OPEN CIRCLE ARROW -->
-<!ENTITY orarr "&#x021BB;" ><!--CLOCKWISE OPEN CIRCLE ARROW -->
-<!ENTITY rAarr "&#x021DB;" ><!--RIGHTWARDS TRIPLE ARROW -->
-<!ENTITY Rarr "&#x021A0;" ><!--RIGHTWARDS TWO HEADED ARROW -->
-<!ENTITY rarr2 "&#x021C9;" ><!--RIGHTWARDS PAIRED ARROWS -->
-<!ENTITY rarrhk "&#x021AA;" ><!--RIGHTWARDS ARROW WITH HOOK -->
-<!ENTITY rarrlp "&#x021AC;" ><!--RIGHTWARDS ARROW WITH LOOP -->
-<!ENTITY rarrtl "&#x021A3;" ><!--RIGHTWARDS ARROW WITH TAIL -->
-<!ENTITY rarrw "&#x0219D;" ><!--RIGHTWARDS WAVE ARROW -->
-<!ENTITY rhard "&#x021C1;" ><!--RIGHTWARDS HARPOON WITH BARB DOWNWARDS -->
-<!ENTITY rharu "&#x021C0;" ><!--RIGHTWARDS HARPOON WITH BARB UPWARDS -->
-<!ENTITY rlarr2 "&#x021C4;" ><!--RIGHTWARDS ARROW OVER LEFTWARDS ARROW -->
-<!ENTITY rlhar2 "&#x021CC;" ><!--RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON -->
-<!ENTITY rsh "&#x021B1;" ><!--UPWARDS ARROW WITH TIP RIGHTWARDS -->
-<!ENTITY uArr "&#x021D1;" ><!--UPWARDS DOUBLE ARROW -->
-<!ENTITY uarr2 "&#x021C8;" ><!--UPWARDS PAIRED ARROWS -->
-<!ENTITY uharl "&#x021BF;" ><!--UPWARDS HARPOON WITH BARB LEFTWARDS -->
-<!ENTITY uharr "&#x021BE;" ><!--UPWARDS HARPOON WITH BARB RIGHTWARDS -->
-<!ENTITY vArr "&#x021D5;" ><!--UP DOWN DOUBLE ARROW -->
-<!ENTITY varr "&#x02195;" ><!--UP DOWN ARROW -->
-<!ENTITY xhArr "&#x027FA;" ><!--LONG LEFT RIGHT DOUBLE ARROW -->
-<!ENTITY xharr "&#x027F7;" ><!--LONG LEFT RIGHT ARROW -->
-<!ENTITY xlArr "&#x027F8;" ><!--LONG LEFTWARDS DOUBLE ARROW -->
-<!ENTITY xrArr "&#x027F9;" ><!--LONG RIGHTWARDS DOUBLE ARROW -->
diff --git a/Utilities/xml/docbook-4.5/ent/isoamsb.ent b/Utilities/xml/docbook-4.5/ent/isoamsb.ent
deleted file mode 100644
index 4065b66c4..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamsb.ent
+++ /dev/null
@@ -1,83 +0,0 @@
-
-<!--
- File isoamsb.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamsb.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamsb.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamsb PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Binary Operators//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamsb.ent"
- >
- %isoamsb;
-
--->
-
-<!ENTITY amalg "&#x02A3F;" ><!--AMALGAMATION OR COPRODUCT -->
-<!ENTITY Barwed "&#x02306;" ><!--PERSPECTIVE -->
-<!ENTITY barwed "&#x02305;" ><!--PROJECTIVE -->
-<!ENTITY Cap "&#x022D2;" ><!--DOUBLE INTERSECTION -->
-<!ENTITY coprod "&#x02210;" ><!--N-ARY COPRODUCT -->
-<!ENTITY Cup "&#x022D3;" ><!--DOUBLE UNION -->
-<!ENTITY cuvee "&#x022CE;" ><!--CURLY LOGICAL OR -->
-<!ENTITY cuwed "&#x022CF;" ><!--CURLY LOGICAL AND -->
-<!ENTITY diam "&#x022C4;" ><!--DIAMOND OPERATOR -->
-<!ENTITY divonx "&#x022C7;" ><!--DIVISION TIMES -->
-<!ENTITY intcal "&#x022BA;" ><!--INTERCALATE -->
-<!ENTITY lthree "&#x022CB;" ><!--LEFT SEMIDIRECT PRODUCT -->
-<!ENTITY ltimes "&#x022C9;" ><!--LEFT NORMAL FACTOR SEMIDIRECT PRODUCT -->
-<!ENTITY minusb "&#x0229F;" ><!--SQUARED MINUS -->
-<!ENTITY oast "&#x0229B;" ><!--CIRCLED ASTERISK OPERATOR -->
-<!ENTITY ocir "&#x0229A;" ><!--CIRCLED RING OPERATOR -->
-<!ENTITY odash "&#x0229D;" ><!--CIRCLED DASH -->
-<!ENTITY odot "&#x02299;" ><!--CIRCLED DOT OPERATOR -->
-<!ENTITY ominus "&#x02296;" ><!--CIRCLED MINUS -->
-<!ENTITY oplus "&#x02295;" ><!--CIRCLED PLUS -->
-<!ENTITY osol "&#x02298;" ><!--CIRCLED DIVISION SLASH -->
-<!ENTITY otimes "&#x02297;" ><!--CIRCLED TIMES -->
-<!ENTITY plusb "&#x0229E;" ><!--SQUARED PLUS -->
-<!ENTITY plusdo "&#x02214;" ><!--DOT PLUS -->
-<!ENTITY prod "&#x0220F;" ><!--N-ARY PRODUCT -->
-<!ENTITY rthree "&#x022CC;" ><!--RIGHT SEMIDIRECT PRODUCT -->
-<!ENTITY rtimes "&#x022CA;" ><!--RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT -->
-<!ENTITY sdot "&#x022C5;" ><!--DOT OPERATOR -->
-<!ENTITY sdotb "&#x022A1;" ><!--SQUARED DOT OPERATOR -->
-<!ENTITY setmn "&#x02216;" ><!--SET MINUS -->
-<!ENTITY sqcap "&#x02293;" ><!--SQUARE CAP -->
-<!ENTITY sqcup "&#x02294;" ><!--SQUARE CUP -->
-<!ENTITY ssetmn "&#x02216;" ><!--SET MINUS -->
-<!ENTITY sstarf "&#x022C6;" ><!--STAR OPERATOR -->
-<!ENTITY sum "&#x02211;" ><!--N-ARY SUMMATION -->
-<!ENTITY timesb "&#x022A0;" ><!--SQUARED TIMES -->
-<!ENTITY top "&#x022A4;" ><!--DOWN TACK -->
-<!ENTITY uplus "&#x0228E;" ><!--MULTISET UNION -->
-<!ENTITY wreath "&#x02240;" ><!--WREATH PRODUCT -->
-<!ENTITY xcirc "&#x025EF;" ><!--LARGE CIRCLE -->
-<!ENTITY xdtri "&#x025BD;" ><!--WHITE DOWN-POINTING TRIANGLE -->
-<!ENTITY xutri "&#x025B3;" ><!--WHITE UP-POINTING TRIANGLE -->
diff --git a/Utilities/xml/docbook-4.5/ent/isoamsc.ent b/Utilities/xml/docbook-4.5/ent/isoamsc.ent
deleted file mode 100644
index 2fad41752..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamsc.ent
+++ /dev/null
@@ -1,51 +0,0 @@
-
-<!--
- File isoamsc.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamsc.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamsc.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamsc PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Delimiters//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamsc.ent"
- >
- %isoamsc;
-
--->
-
-<!ENTITY dlcorn "&#x0231E;" ><!--BOTTOM LEFT CORNER -->
-<!ENTITY drcorn "&#x0231F;" ><!--BOTTOM RIGHT CORNER -->
-<!ENTITY lceil "&#x02308;" ><!--LEFT CEILING -->
-<!ENTITY lfloor "&#x0230A;" ><!--LEFT FLOOR -->
-<!ENTITY lpargt "&#x029A0;" ><!--SPHERICAL ANGLE OPENING LEFT -->
-<!ENTITY rceil "&#x02309;" ><!--RIGHT CEILING -->
-<!ENTITY rfloor "&#x0230B;" ><!--RIGHT FLOOR -->
-<!ENTITY rpargt "&#x02994;" ><!--RIGHT ARC GREATER-THAN BRACKET -->
-<!ENTITY ulcorn "&#x0231C;" ><!--TOP LEFT CORNER -->
-<!ENTITY urcorn "&#x0231D;" ><!--TOP RIGHT CORNER -->
diff --git a/Utilities/xml/docbook-4.5/ent/isoamsn.ent b/Utilities/xml/docbook-4.5/ent/isoamsn.ent
deleted file mode 100644
index ddca8d14c..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamsn.ent
+++ /dev/null
@@ -1,103 +0,0 @@
-
-<!--
- File isoamsn.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- References to the VARIANT SELECTOR 1 character (&#x0FE00;)
- should match the uses listed in Unicode Technical Report 25.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamsn.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamsn.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamsn PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Negated Relations//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamsn.ent"
- >
- %isoamsn;
-
--->
-
-<!ENTITY gnap "&#x02A8A;" ><!--GREATER-THAN AND NOT APPROXIMATE -->
-<!ENTITY gnE "&#x02269;" ><!--GREATER-THAN BUT NOT EQUAL TO -->
-<!ENTITY gne "&#x02A88;" ><!--GREATER-THAN AND SINGLE-LINE NOT EQUAL TO -->
-<!ENTITY gnsim "&#x022E7;" ><!--GREATER-THAN BUT NOT EQUIVALENT TO -->
-<!ENTITY gvnE "&#x02269;&#x0FE00;" ><!--GREATER-THAN BUT NOT EQUAL TO - with vertical stroke -->
-<!ENTITY lnap "&#x02A89;" ><!--LESS-THAN AND NOT APPROXIMATE -->
-<!ENTITY lnE "&#x02268;" ><!--LESS-THAN BUT NOT EQUAL TO -->
-<!ENTITY lne "&#x02A87;" ><!--LESS-THAN AND SINGLE-LINE NOT EQUAL TO -->
-<!ENTITY lnsim "&#x022E6;" ><!--LESS-THAN BUT NOT EQUIVALENT TO -->
-<!ENTITY lvnE "&#x02268;&#x0FE00;" ><!--LESS-THAN BUT NOT EQUAL TO - with vertical stroke -->
-<!ENTITY nap "&#x02249;" ><!--NOT ALMOST EQUAL TO -->
-<!ENTITY ncong "&#x02247;" ><!--NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO -->
-<!ENTITY nequiv "&#x02262;" ><!--NOT IDENTICAL TO -->
-<!ENTITY ngE "&#x02267;&#x00338;" ><!--GREATER-THAN OVER EQUAL TO with slash -->
-<!ENTITY nge "&#x02271;" ><!--NEITHER GREATER-THAN NOR EQUAL TO -->
-<!ENTITY nges "&#x02A7E;&#x00338;" ><!--GREATER-THAN OR SLANTED EQUAL TO with slash -->
-<!ENTITY ngt "&#x0226F;" ><!--NOT GREATER-THAN -->
-<!ENTITY nlE "&#x02266;&#x00338;" ><!--LESS-THAN OVER EQUAL TO with slash -->
-<!ENTITY nle "&#x02270;" ><!--NEITHER LESS-THAN NOR EQUAL TO -->
-<!ENTITY nles "&#x02A7D;&#x00338;" ><!--LESS-THAN OR SLANTED EQUAL TO with slash -->
-<!ENTITY nlt "&#x0226E;" ><!--NOT LESS-THAN -->
-<!ENTITY nltri "&#x022EA;" ><!--NOT NORMAL SUBGROUP OF -->
-<!ENTITY nltrie "&#x022EC;" ><!--NOT NORMAL SUBGROUP OF OR EQUAL TO -->
-<!ENTITY nmid "&#x02224;" ><!--DOES NOT DIVIDE -->
-<!ENTITY npar "&#x02226;" ><!--NOT PARALLEL TO -->
-<!ENTITY npr "&#x02280;" ><!--DOES NOT PRECEDE -->
-<!ENTITY npre "&#x02AAF;&#x00338;" ><!--PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash -->
-<!ENTITY nrtri "&#x022EB;" ><!--DOES NOT CONTAIN AS NORMAL SUBGROUP -->
-<!ENTITY nrtrie "&#x022ED;" ><!--DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL -->
-<!ENTITY nsc "&#x02281;" ><!--DOES NOT SUCCEED -->
-<!ENTITY nsce "&#x02AB0;&#x00338;" ><!--SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash -->
-<!ENTITY nsim "&#x02241;" ><!--NOT TILDE -->
-<!ENTITY nsime "&#x02244;" ><!--NOT ASYMPTOTICALLY EQUAL TO -->
-<!ENTITY nsmid "&#x02224;" ><!--DOES NOT DIVIDE -->
-<!ENTITY nspar "&#x02226;" ><!--NOT PARALLEL TO -->
-<!ENTITY nsub "&#x02284;" ><!--NOT A SUBSET OF -->
-<!ENTITY nsubE "&#x02AC5;&#x00338;" ><!--SUBSET OF ABOVE EQUALS SIGN with slash -->
-<!ENTITY nsube "&#x02288;" ><!--NEITHER A SUBSET OF NOR EQUAL TO -->
-<!ENTITY nsup "&#x02285;" ><!--NOT A SUPERSET OF -->
-<!ENTITY nsupE "&#x02AC6;&#x00338;" ><!--SUPERSET OF ABOVE EQUALS SIGN with slash -->
-<!ENTITY nsupe "&#x02289;" ><!--NEITHER A SUPERSET OF NOR EQUAL TO -->
-<!ENTITY nVDash "&#x022AF;" ><!--NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE -->
-<!ENTITY nVdash "&#x022AE;" ><!--DOES NOT FORCE -->
-<!ENTITY nvDash "&#x022AD;" ><!--NOT TRUE -->
-<!ENTITY nvdash "&#x022AC;" ><!--DOES NOT PROVE -->
-<!ENTITY prnap "&#x02AB9;" ><!--PRECEDES ABOVE NOT ALMOST EQUAL TO -->
-<!ENTITY prnE "&#x02AB5;" ><!--PRECEDES ABOVE NOT EQUAL TO -->
-<!ENTITY prnsim "&#x022E8;" ><!--PRECEDES BUT NOT EQUIVALENT TO -->
-<!ENTITY scnap "&#x02ABA;" ><!--SUCCEEDS ABOVE NOT ALMOST EQUAL TO -->
-<!ENTITY scnE "&#x02AB6;" ><!--SUCCEEDS ABOVE NOT EQUAL TO -->
-<!ENTITY scnsim "&#x022E9;" ><!--SUCCEEDS BUT NOT EQUIVALENT TO -->
-<!ENTITY subnE "&#x02ACB;" ><!--SUBSET OF ABOVE NOT EQUAL TO -->
-<!ENTITY subne "&#x0228A;" ><!--SUBSET OF WITH NOT EQUAL TO -->
-<!ENTITY supnE "&#x02ACC;" ><!--SUPERSET OF ABOVE NOT EQUAL TO -->
-<!ENTITY supne "&#x0228B;" ><!--SUPERSET OF WITH NOT EQUAL TO -->
-<!ENTITY vsubnE "&#x02ACB;&#x0FE00;" ><!--SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -->
-<!ENTITY vsubne "&#x0228A;&#x0FE00;" ><!--SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -->
-<!ENTITY vsupnE "&#x02ACC;&#x0FE00;" ><!--SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -->
-<!ENTITY vsupne "&#x0228B;&#x0FE00;" ><!--SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -->
diff --git a/Utilities/xml/docbook-4.5/ent/isoamso.ent b/Utilities/xml/docbook-4.5/ent/isoamso.ent
deleted file mode 100644
index 278e4b409..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamso.ent
+++ /dev/null
@@ -1,59 +0,0 @@
-
-<!--
- File isoamso.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamso.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamso.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamso PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Ordinary//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamso.ent"
- >
- %isoamso;
-
--->
-
-<!ENTITY ang "&#x02220;" ><!--ANGLE -->
-<!ENTITY angmsd "&#x02221;" ><!--MEASURED ANGLE -->
-<!ENTITY beth "&#x02136;" ><!--BET SYMBOL -->
-<!ENTITY bprime "&#x02035;" ><!--REVERSED PRIME -->
-<!ENTITY comp "&#x02201;" ><!--COMPLEMENT -->
-<!ENTITY daleth "&#x02138;" ><!--DALET SYMBOL -->
-<!ENTITY ell "&#x02113;" ><!--SCRIPT SMALL L -->
-<!ENTITY empty "&#x02205;" ><!--EMPTY SET -->
-<!ENTITY gimel "&#x02137;" ><!--GIMEL SYMBOL -->
-<!ENTITY inodot "&#x00131;" ><!--LATIN SMALL LETTER DOTLESS I -->
-<!ENTITY jnodot "&#x0006A;" ><!--LATIN SMALL LETTER J -->
-<!ENTITY nexist "&#x02204;" ><!--THERE DOES NOT EXIST -->
-<!ENTITY oS "&#x024C8;" ><!--CIRCLED LATIN CAPITAL LETTER S -->
-<!ENTITY planck "&#x0210F;" ><!--PLANCK CONSTANT OVER TWO PI -->
-<!ENTITY real "&#x0211C;" ><!--BLACK-LETTER CAPITAL R -->
-<!ENTITY sbsol "&#x0FE68;" ><!--SMALL REVERSE SOLIDUS -->
-<!ENTITY vprime "&#x02032;" ><!--PRIME -->
-<!ENTITY weierp "&#x02118;" ><!--SCRIPT CAPITAL P -->
diff --git a/Utilities/xml/docbook-4.5/ent/isoamsr.ent b/Utilities/xml/docbook-4.5/ent/isoamsr.ent
deleted file mode 100644
index 18e64bffd..000000000
--- a/Utilities/xml/docbook-4.5/ent/isoamsr.ent
+++ /dev/null
@@ -1,125 +0,0 @@
-
-<!--
- File isoamsr.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isoamsr.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isoamsr.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isoamsr PUBLIC
- "ISO 8879:1986//ENTITIES Added Math Symbols: Relations//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isoamsr.ent"
- >
- %isoamsr;
-
--->
-
-<!ENTITY ape "&#x0224A;" ><!--ALMOST EQUAL OR EQUAL TO -->
-<!ENTITY asymp "&#x02248;" ><!--ALMOST EQUAL TO -->
-<!ENTITY bcong "&#x0224C;" ><!--ALL EQUAL TO -->
-<!ENTITY bepsi "&#x003F6;" ><!--GREEK REVERSED LUNATE EPSILON SYMBOL -->
-<!ENTITY bowtie "&#x022C8;" ><!--BOWTIE -->
-<!ENTITY bsim "&#x0223D;" ><!--REVERSED TILDE -->
-<!ENTITY bsime "&#x022CD;" ><!--REVERSED TILDE EQUALS -->
-<!ENTITY bump "&#x0224E;" ><!--GEOMETRICALLY EQUIVALENT TO -->
-<!ENTITY bumpe "&#x0224F;" ><!--DIFFERENCE BETWEEN -->
-<!ENTITY cire "&#x02257;" ><!--RING EQUAL TO -->
-<!ENTITY colone "&#x02254;" ><!--COLON EQUALS -->
-<!ENTITY cuepr "&#x022DE;" ><!--EQUAL TO OR PRECEDES -->
-<!ENTITY cuesc "&#x022DF;" ><!--EQUAL TO OR SUCCEEDS -->
-<!ENTITY cupre "&#x0227C;" ><!--PRECEDES OR EQUAL TO -->
-<!ENTITY dashv "&#x022A3;" ><!--LEFT TACK -->
-<!ENTITY ecir "&#x02256;" ><!--RING IN EQUAL TO -->
-<!ENTITY ecolon "&#x02255;" ><!--EQUALS COLON -->
-<!ENTITY eDot "&#x02251;" ><!--GEOMETRICALLY EQUAL TO -->
-<!ENTITY efDot "&#x02252;" ><!--APPROXIMATELY EQUAL TO OR THE IMAGE OF -->
-<!ENTITY egs "&#x02A96;" ><!--SLANTED EQUAL TO OR GREATER-THAN -->
-<!ENTITY els "&#x02A95;" ><!--SLANTED EQUAL TO OR LESS-THAN -->
-<!ENTITY erDot "&#x02253;" ><!--IMAGE OF OR APPROXIMATELY EQUAL TO -->
-<!ENTITY esdot "&#x02250;" ><!--APPROACHES THE LIMIT -->
-<!ENTITY fork "&#x022D4;" ><!--PITCHFORK -->
-<!ENTITY frown "&#x02322;" ><!--FROWN -->
-<!ENTITY gap "&#x02A86;" ><!--GREATER-THAN OR APPROXIMATE -->
-<!ENTITY gE "&#x02267;" ><!--GREATER-THAN OVER EQUAL TO -->
-<!ENTITY gEl "&#x02A8C;" ><!--GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN -->
-<!ENTITY gel "&#x022DB;" ><!--GREATER-THAN EQUAL TO OR LESS-THAN -->
-<!ENTITY ges "&#x02A7E;" ><!--GREATER-THAN OR SLANTED EQUAL TO -->
-<!ENTITY Gg "&#x022D9;" ><!--VERY MUCH GREATER-THAN -->
-<!ENTITY gl "&#x02277;" ><!--GREATER-THAN OR LESS-THAN -->
-<!ENTITY gsdot "&#x022D7;" ><!--GREATER-THAN WITH DOT -->
-<!ENTITY gsim "&#x02273;" ><!--GREATER-THAN OR EQUIVALENT TO -->
-<!ENTITY Gt "&#x0226B;" ><!--MUCH GREATER-THAN -->
-<!ENTITY lap "&#x02A85;" ><!--LESS-THAN OR APPROXIMATE -->
-<!ENTITY ldot "&#x022D6;" ><!--LESS-THAN WITH DOT -->
-<!ENTITY lE "&#x02266;" ><!--LESS-THAN OVER EQUAL TO -->
-<!ENTITY lEg "&#x02A8B;" ><!--LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN -->
-<!ENTITY leg "&#x022DA;" ><!--LESS-THAN EQUAL TO OR GREATER-THAN -->
-<!ENTITY les "&#x02A7D;" ><!--LESS-THAN OR SLANTED EQUAL TO -->
-<!ENTITY lg "&#x02276;" ><!--LESS-THAN OR GREATER-THAN -->
-<!ENTITY Ll "&#x022D8;" ><!--VERY MUCH LESS-THAN -->
-<!ENTITY lsim "&#x02272;" ><!--LESS-THAN OR EQUIVALENT TO -->
-<!ENTITY Lt "&#x0226A;" ><!--MUCH LESS-THAN -->
-<!ENTITY ltrie "&#x022B4;" ><!--NORMAL SUBGROUP OF OR EQUAL TO -->
-<!ENTITY mid "&#x02223;" ><!--DIVIDES -->
-<!ENTITY models "&#x022A7;" ><!--MODELS -->
-<!ENTITY pr "&#x0227A;" ><!--PRECEDES -->
-<!ENTITY prap "&#x02AB7;" ><!--PRECEDES ABOVE ALMOST EQUAL TO -->
-<!ENTITY pre "&#x02AAF;" ><!--PRECEDES ABOVE SINGLE-LINE EQUALS SIGN -->
-<!ENTITY prsim "&#x0227E;" ><!--PRECEDES OR EQUIVALENT TO -->
-<!ENTITY rtrie "&#x022B5;" ><!--CONTAINS AS NORMAL SUBGROUP OR EQUAL TO -->
-<!ENTITY samalg "&#x02210;" ><!--N-ARY COPRODUCT -->
-<!ENTITY sc "&#x0227B;" ><!--SUCCEEDS -->
-<!ENTITY scap "&#x02AB8;" ><!--SUCCEEDS ABOVE ALMOST EQUAL TO -->
-<!ENTITY sccue "&#x0227D;" ><!--SUCCEEDS OR EQUAL TO -->
-<!ENTITY sce "&#x02AB0;" ><!--SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN -->
-<!ENTITY scsim "&#x0227F;" ><!--SUCCEEDS OR EQUIVALENT TO -->
-<!ENTITY sfrown "&#x02322;" ><!--FROWN -->
-<!ENTITY smid "&#x02223;" ><!--DIVIDES -->
-<!ENTITY smile "&#x02323;" ><!--SMILE -->
-<!ENTITY spar "&#x02225;" ><!--PARALLEL TO -->
-<!ENTITY sqsub "&#x0228F;" ><!--SQUARE IMAGE OF -->
-<!ENTITY sqsube "&#x02291;" ><!--SQUARE IMAGE OF OR EQUAL TO -->
-<!ENTITY sqsup "&#x02290;" ><!--SQUARE ORIGINAL OF -->
-<!ENTITY sqsupe "&#x02292;" ><!--SQUARE ORIGINAL OF OR EQUAL TO -->
-<!ENTITY ssmile "&#x02323;" ><!--SMILE -->
-<!ENTITY Sub "&#x022D0;" ><!--DOUBLE SUBSET -->
-<!ENTITY subE "&#x02AC5;" ><!--SUBSET OF ABOVE EQUALS SIGN -->
-<!ENTITY Sup "&#x022D1;" ><!--DOUBLE SUPERSET -->
-<!ENTITY supE "&#x02AC6;" ><!--SUPERSET OF ABOVE EQUALS SIGN -->
-<!ENTITY thkap "&#x02248;" ><!--ALMOST EQUAL TO -->
-<!ENTITY thksim "&#x0223C;" ><!--TILDE OPERATOR -->
-<!ENTITY trie "&#x0225C;" ><!--DELTA EQUAL TO -->
-<!ENTITY twixt "&#x0226C;" ><!--BETWEEN -->
-<!ENTITY Vdash "&#x022A9;" ><!--FORCES -->
-<!ENTITY vDash "&#x022A8;" ><!--TRUE -->
-<!ENTITY vdash "&#x022A2;" ><!--RIGHT TACK -->
-<!ENTITY veebar "&#x022BB;" ><!--XOR -->
-<!ENTITY vltri "&#x022B2;" ><!--NORMAL SUBGROUP OF -->
-<!ENTITY vprop "&#x0221D;" ><!--PROPORTIONAL TO -->
-<!ENTITY vrtri "&#x022B3;" ><!--CONTAINS AS NORMAL SUBGROUP -->
-<!ENTITY Vvdash "&#x022AA;" ><!--TRIPLE VERTICAL BAR RIGHT TURNSTILE -->
diff --git a/Utilities/xml/docbook-4.5/ent/isobox.ent b/Utilities/xml/docbook-4.5/ent/isobox.ent
deleted file mode 100644
index 9ae27d4fa..000000000
--- a/Utilities/xml/docbook-4.5/ent/isobox.ent
+++ /dev/null
@@ -1,81 +0,0 @@
-
-<!--
- File isobox.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isobox.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isobox.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isobox PUBLIC
- "ISO 8879:1986//ENTITIES Box and Line Drawing//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isobox.ent"
- >
- %isobox;
-
--->
-
-<!ENTITY boxDL "&#x02557;" ><!--BOX DRAWINGS DOUBLE DOWN AND LEFT -->
-<!ENTITY boxDl "&#x02556;" ><!--BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE -->
-<!ENTITY boxdL "&#x02555;" ><!--BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE -->
-<!ENTITY boxdl "&#x02510;" ><!--BOX DRAWINGS LIGHT DOWN AND LEFT -->
-<!ENTITY boxDR "&#x02554;" ><!--BOX DRAWINGS DOUBLE DOWN AND RIGHT -->
-<!ENTITY boxDr "&#x02553;" ><!--BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE -->
-<!ENTITY boxdR "&#x02552;" ><!--BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE -->
-<!ENTITY boxdr "&#x0250C;" ><!--BOX DRAWINGS LIGHT DOWN AND RIGHT -->
-<!ENTITY boxH "&#x02550;" ><!--BOX DRAWINGS DOUBLE HORIZONTAL -->
-<!ENTITY boxh "&#x02500;" ><!--BOX DRAWINGS LIGHT HORIZONTAL -->
-<!ENTITY boxHD "&#x02566;" ><!--BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL -->
-<!ENTITY boxHd "&#x02564;" ><!--BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE -->
-<!ENTITY boxhD "&#x02565;" ><!--BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE -->
-<!ENTITY boxhd "&#x0252C;" ><!--BOX DRAWINGS LIGHT DOWN AND HORIZONTAL -->
-<!ENTITY boxHU "&#x02569;" ><!--BOX DRAWINGS DOUBLE UP AND HORIZONTAL -->
-<!ENTITY boxHu "&#x02567;" ><!--BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE -->
-<!ENTITY boxhU "&#x02568;" ><!--BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE -->
-<!ENTITY boxhu "&#x02534;" ><!--BOX DRAWINGS LIGHT UP AND HORIZONTAL -->
-<!ENTITY boxUL "&#x0255D;" ><!--BOX DRAWINGS DOUBLE UP AND LEFT -->
-<!ENTITY boxUl "&#x0255C;" ><!--BOX DRAWINGS UP DOUBLE AND LEFT SINGLE -->
-<!ENTITY boxuL "&#x0255B;" ><!--BOX DRAWINGS UP SINGLE AND LEFT DOUBLE -->
-<!ENTITY boxul "&#x02518;" ><!--BOX DRAWINGS LIGHT UP AND LEFT -->
-<!ENTITY boxUR "&#x0255A;" ><!--BOX DRAWINGS DOUBLE UP AND RIGHT -->
-<!ENTITY boxUr "&#x02559;" ><!--BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE -->
-<!ENTITY boxuR "&#x02558;" ><!--BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE -->
-<!ENTITY boxur "&#x02514;" ><!--BOX DRAWINGS LIGHT UP AND RIGHT -->
-<!ENTITY boxV "&#x02551;" ><!--BOX DRAWINGS DOUBLE VERTICAL -->
-<!ENTITY boxv "&#x02502;" ><!--BOX DRAWINGS LIGHT VERTICAL -->
-<!ENTITY boxVH "&#x0256C;" ><!--BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL -->
-<!ENTITY boxVh "&#x0256B;" ><!--BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE -->
-<!ENTITY boxvH "&#x0256A;" ><!--BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE -->
-<!ENTITY boxvh "&#x0253C;" ><!--BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL -->
-<!ENTITY boxVL "&#x02563;" ><!--BOX DRAWINGS DOUBLE VERTICAL AND LEFT -->
-<!ENTITY boxVl "&#x02562;" ><!--BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE -->
-<!ENTITY boxvL "&#x02561;" ><!--BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE -->
-<!ENTITY boxvl "&#x02524;" ><!--BOX DRAWINGS LIGHT VERTICAL AND LEFT -->
-<!ENTITY boxVR "&#x02560;" ><!--BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -->
-<!ENTITY boxVr "&#x0255F;" ><!--BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE -->
-<!ENTITY boxvR "&#x0255E;" ><!--BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE -->
-<!ENTITY boxvr "&#x0251C;" ><!--BOX DRAWINGS LIGHT VERTICAL AND RIGHT -->
diff --git a/Utilities/xml/docbook-4.5/ent/isocyr1.ent b/Utilities/xml/docbook-4.5/ent/isocyr1.ent
deleted file mode 100644
index 364b6d841..000000000
--- a/Utilities/xml/docbook-4.5/ent/isocyr1.ent
+++ /dev/null
@@ -1,108 +0,0 @@
-
-<!--
- File isocyr1.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isocyr1.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isocyr1.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isocyr1 PUBLIC
- "ISO 8879:1986//ENTITIES Russian Cyrillic//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isocyr1.ent"
- >
- %isocyr1;
-
--->
-
-<!ENTITY Acy "&#x00410;" ><!--CYRILLIC CAPITAL LETTER A -->
-<!ENTITY acy "&#x00430;" ><!--CYRILLIC SMALL LETTER A -->
-<!ENTITY Bcy "&#x00411;" ><!--CYRILLIC CAPITAL LETTER BE -->
-<!ENTITY bcy "&#x00431;" ><!--CYRILLIC SMALL LETTER BE -->
-<!ENTITY CHcy "&#x00427;" ><!--CYRILLIC CAPITAL LETTER CHE -->
-<!ENTITY chcy "&#x00447;" ><!--CYRILLIC SMALL LETTER CHE -->
-<!ENTITY Dcy "&#x00414;" ><!--CYRILLIC CAPITAL LETTER DE -->
-<!ENTITY dcy "&#x00434;" ><!--CYRILLIC SMALL LETTER DE -->
-<!ENTITY Ecy "&#x0042D;" ><!--CYRILLIC CAPITAL LETTER E -->
-<!ENTITY ecy "&#x0044D;" ><!--CYRILLIC SMALL LETTER E -->
-<!ENTITY Fcy "&#x00424;" ><!--CYRILLIC CAPITAL LETTER EF -->
-<!ENTITY fcy "&#x00444;" ><!--CYRILLIC SMALL LETTER EF -->
-<!ENTITY Gcy "&#x00413;" ><!--CYRILLIC CAPITAL LETTER GHE -->
-<!ENTITY gcy "&#x00433;" ><!--CYRILLIC SMALL LETTER GHE -->
-<!ENTITY HARDcy "&#x0042A;" ><!--CYRILLIC CAPITAL LETTER HARD SIGN -->
-<!ENTITY hardcy "&#x0044A;" ><!--CYRILLIC SMALL LETTER HARD SIGN -->
-<!ENTITY Icy "&#x00418;" ><!--CYRILLIC CAPITAL LETTER I -->
-<!ENTITY icy "&#x00438;" ><!--CYRILLIC SMALL LETTER I -->
-<!ENTITY IEcy "&#x00415;" ><!--CYRILLIC CAPITAL LETTER IE -->
-<!ENTITY iecy "&#x00435;" ><!--CYRILLIC SMALL LETTER IE -->
-<!ENTITY IOcy "&#x00401;" ><!--CYRILLIC CAPITAL LETTER IO -->
-<!ENTITY iocy "&#x00451;" ><!--CYRILLIC SMALL LETTER IO -->
-<!ENTITY Jcy "&#x00419;" ><!--CYRILLIC CAPITAL LETTER SHORT I -->
-<!ENTITY jcy "&#x00439;" ><!--CYRILLIC SMALL LETTER SHORT I -->
-<!ENTITY Kcy "&#x0041A;" ><!--CYRILLIC CAPITAL LETTER KA -->
-<!ENTITY kcy "&#x0043A;" ><!--CYRILLIC SMALL LETTER KA -->
-<!ENTITY KHcy "&#x00425;" ><!--CYRILLIC CAPITAL LETTER HA -->
-<!ENTITY khcy "&#x00445;" ><!--CYRILLIC SMALL LETTER HA -->
-<!ENTITY Lcy "&#x0041B;" ><!--CYRILLIC CAPITAL LETTER EL -->
-<!ENTITY lcy "&#x0043B;" ><!--CYRILLIC SMALL LETTER EL -->
-<!ENTITY Mcy "&#x0041C;" ><!--CYRILLIC CAPITAL LETTER EM -->
-<!ENTITY mcy "&#x0043C;" ><!--CYRILLIC SMALL LETTER EM -->
-<!ENTITY Ncy "&#x0041D;" ><!--CYRILLIC CAPITAL LETTER EN -->
-<!ENTITY ncy "&#x0043D;" ><!--CYRILLIC SMALL LETTER EN -->
-<!ENTITY numero "&#x02116;" ><!--NUMERO SIGN -->
-<!ENTITY Ocy "&#x0041E;" ><!--CYRILLIC CAPITAL LETTER O -->
-<!ENTITY ocy "&#x0043E;" ><!--CYRILLIC SMALL LETTER O -->
-<!ENTITY Pcy "&#x0041F;" ><!--CYRILLIC CAPITAL LETTER PE -->
-<!ENTITY pcy "&#x0043F;" ><!--CYRILLIC SMALL LETTER PE -->
-<!ENTITY Rcy "&#x00420;" ><!--CYRILLIC CAPITAL LETTER ER -->
-<!ENTITY rcy "&#x00440;" ><!--CYRILLIC SMALL LETTER ER -->
-<!ENTITY Scy "&#x00421;" ><!--CYRILLIC CAPITAL LETTER ES -->
-<!ENTITY scy "&#x00441;" ><!--CYRILLIC SMALL LETTER ES -->
-<!ENTITY SHCHcy "&#x00429;" ><!--CYRILLIC CAPITAL LETTER SHCHA -->
-<!ENTITY shchcy "&#x00449;" ><!--CYRILLIC SMALL LETTER SHCHA -->
-<!ENTITY SHcy "&#x00428;" ><!--CYRILLIC CAPITAL LETTER SHA -->
-<!ENTITY shcy "&#x00448;" ><!--CYRILLIC SMALL LETTER SHA -->
-<!ENTITY SOFTcy "&#x0042C;" ><!--CYRILLIC CAPITAL LETTER SOFT SIGN -->
-<!ENTITY softcy "&#x0044C;" ><!--CYRILLIC SMALL LETTER SOFT SIGN -->
-<!ENTITY Tcy "&#x00422;" ><!--CYRILLIC CAPITAL LETTER TE -->
-<!ENTITY tcy "&#x00442;" ><!--CYRILLIC SMALL LETTER TE -->
-<!ENTITY TScy "&#x00426;" ><!--CYRILLIC CAPITAL LETTER TSE -->
-<!ENTITY tscy "&#x00446;" ><!--CYRILLIC SMALL LETTER TSE -->
-<!ENTITY Ucy "&#x00423;" ><!--CYRILLIC CAPITAL LETTER U -->
-<!ENTITY ucy "&#x00443;" ><!--CYRILLIC SMALL LETTER U -->
-<!ENTITY Vcy "&#x00412;" ><!--CYRILLIC CAPITAL LETTER VE -->
-<!ENTITY vcy "&#x00432;" ><!--CYRILLIC SMALL LETTER VE -->
-<!ENTITY YAcy "&#x0042F;" ><!--CYRILLIC CAPITAL LETTER YA -->
-<!ENTITY yacy "&#x0044F;" ><!--CYRILLIC SMALL LETTER YA -->
-<!ENTITY Ycy "&#x0042B;" ><!--CYRILLIC CAPITAL LETTER YERU -->
-<!ENTITY ycy "&#x0044B;" ><!--CYRILLIC SMALL LETTER YERU -->
-<!ENTITY YUcy "&#x0042E;" ><!--CYRILLIC CAPITAL LETTER YU -->
-<!ENTITY yucy "&#x0044E;" ><!--CYRILLIC SMALL LETTER YU -->
-<!ENTITY Zcy "&#x00417;" ><!--CYRILLIC CAPITAL LETTER ZE -->
-<!ENTITY zcy "&#x00437;" ><!--CYRILLIC SMALL LETTER ZE -->
-<!ENTITY ZHcy "&#x00416;" ><!--CYRILLIC CAPITAL LETTER ZHE -->
-<!ENTITY zhcy "&#x00436;" ><!--CYRILLIC SMALL LETTER ZHE -->
diff --git a/Utilities/xml/docbook-4.5/ent/isocyr2.ent b/Utilities/xml/docbook-4.5/ent/isocyr2.ent
deleted file mode 100644
index 6432d74c4..000000000
--- a/Utilities/xml/docbook-4.5/ent/isocyr2.ent
+++ /dev/null
@@ -1,67 +0,0 @@
-
-<!--
- File isocyr2.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isocyr2.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isocyr2.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isocyr2 PUBLIC
- "ISO 8879:1986//ENTITIES Non-Russian Cyrillic//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isocyr2.ent"
- >
- %isocyr2;
-
--->
-
-<!ENTITY DJcy "&#x00402;" ><!--CYRILLIC CAPITAL LETTER DJE -->
-<!ENTITY djcy "&#x00452;" ><!--CYRILLIC SMALL LETTER DJE -->
-<!ENTITY DScy "&#x00405;" ><!--CYRILLIC CAPITAL LETTER DZE -->
-<!ENTITY dscy "&#x00455;" ><!--CYRILLIC SMALL LETTER DZE -->
-<!ENTITY DZcy "&#x0040F;" ><!--CYRILLIC CAPITAL LETTER DZHE -->
-<!ENTITY dzcy "&#x0045F;" ><!--CYRILLIC SMALL LETTER DZHE -->
-<!ENTITY GJcy "&#x00403;" ><!--CYRILLIC CAPITAL LETTER GJE -->
-<!ENTITY gjcy "&#x00453;" ><!--CYRILLIC SMALL LETTER GJE -->
-<!ENTITY Iukcy "&#x00406;" ><!--CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I -->
-<!ENTITY iukcy "&#x00456;" ><!--CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I -->
-<!ENTITY Jsercy "&#x00408;" ><!--CYRILLIC CAPITAL LETTER JE -->
-<!ENTITY jsercy "&#x00458;" ><!--CYRILLIC SMALL LETTER JE -->
-<!ENTITY Jukcy "&#x00404;" ><!--CYRILLIC CAPITAL LETTER UKRAINIAN IE -->
-<!ENTITY jukcy "&#x00454;" ><!--CYRILLIC SMALL LETTER UKRAINIAN IE -->
-<!ENTITY KJcy "&#x0040C;" ><!--CYRILLIC CAPITAL LETTER KJE -->
-<!ENTITY kjcy "&#x0045C;" ><!--CYRILLIC SMALL LETTER KJE -->
-<!ENTITY LJcy "&#x00409;" ><!--CYRILLIC CAPITAL LETTER LJE -->
-<!ENTITY ljcy "&#x00459;" ><!--CYRILLIC SMALL LETTER LJE -->
-<!ENTITY NJcy "&#x0040A;" ><!--CYRILLIC CAPITAL LETTER NJE -->
-<!ENTITY njcy "&#x0045A;" ><!--CYRILLIC SMALL LETTER NJE -->
-<!ENTITY TSHcy "&#x0040B;" ><!--CYRILLIC CAPITAL LETTER TSHE -->
-<!ENTITY tshcy "&#x0045B;" ><!--CYRILLIC SMALL LETTER TSHE -->
-<!ENTITY Ubrcy "&#x0040E;" ><!--CYRILLIC CAPITAL LETTER SHORT U -->
-<!ENTITY ubrcy "&#x0045E;" ><!--CYRILLIC SMALL LETTER SHORT U -->
-<!ENTITY YIcy "&#x00407;" ><!--CYRILLIC CAPITAL LETTER YI -->
-<!ENTITY yicy "&#x00457;" ><!--CYRILLIC SMALL LETTER YI -->
diff --git a/Utilities/xml/docbook-4.5/ent/isodia.ent b/Utilities/xml/docbook-4.5/ent/isodia.ent
deleted file mode 100644
index b49c30947..000000000
--- a/Utilities/xml/docbook-4.5/ent/isodia.ent
+++ /dev/null
@@ -1,55 +0,0 @@
-
-<!--
- File isodia.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isodia.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isodia.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isodia PUBLIC
- "ISO 8879:1986//ENTITIES Diacritical Marks//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isodia.ent"
- >
- %isodia;
-
--->
-
-<!ENTITY acute "&#x000B4;" ><!--ACUTE ACCENT -->
-<!ENTITY breve "&#x002D8;" ><!--BREVE -->
-<!ENTITY caron "&#x002C7;" ><!--CARON -->
-<!ENTITY cedil "&#x000B8;" ><!--CEDILLA -->
-<!ENTITY circ "&#x002C6;" ><!--MODIFIER LETTER CIRCUMFLEX ACCENT -->
-<!ENTITY dblac "&#x002DD;" ><!--DOUBLE ACUTE ACCENT -->
-<!ENTITY die "&#x000A8;" ><!--DIAERESIS -->
-<!ENTITY dot "&#x002D9;" ><!--DOT ABOVE -->
-<!ENTITY grave "&#x00060;" ><!--GRAVE ACCENT -->
-<!ENTITY macr "&#x000AF;" ><!--MACRON -->
-<!ENTITY ogon "&#x002DB;" ><!--OGONEK -->
-<!ENTITY ring "&#x002DA;" ><!--RING ABOVE -->
-<!ENTITY tilde "&#x002DC;" ><!--SMALL TILDE -->
-<!ENTITY uml "&#x000A8;" ><!--DIAERESIS -->
diff --git a/Utilities/xml/docbook-4.5/ent/isogrk1.ent b/Utilities/xml/docbook-4.5/ent/isogrk1.ent
deleted file mode 100644
index 7826f8109..000000000
--- a/Utilities/xml/docbook-4.5/ent/isogrk1.ent
+++ /dev/null
@@ -1,90 +0,0 @@
-
-<!--
- File isogrk1.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isogrk1.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Greek Letters//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isogrk1.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isogrk1 PUBLIC
- "ISO 8879:1986//ENTITIES Greek Letters//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isogrk1.ent"
- >
- %isogrk1;
-
--->
-
-<!ENTITY Agr "&#x00391;" ><!--GREEK CAPITAL LETTER ALPHA -->
-<!ENTITY agr "&#x003B1;" ><!--GREEK SMALL LETTER ALPHA -->
-<!ENTITY Bgr "&#x00392;" ><!--GREEK CAPITAL LETTER BETA -->
-<!ENTITY bgr "&#x003B2;" ><!--GREEK SMALL LETTER BETA -->
-<!ENTITY Dgr "&#x00394;" ><!--GREEK CAPITAL LETTER DELTA -->
-<!ENTITY dgr "&#x003B4;" ><!--GREEK SMALL LETTER DELTA -->
-<!ENTITY EEgr "&#x00397;" ><!--GREEK CAPITAL LETTER ETA -->
-<!ENTITY eegr "&#x003B7;" ><!--GREEK SMALL LETTER ETA -->
-<!ENTITY Egr "&#x00395;" ><!--GREEK CAPITAL LETTER EPSILON -->
-<!ENTITY egr "&#x003B5;" ><!--GREEK SMALL LETTER EPSILON -->
-<!ENTITY Ggr "&#x00393;" ><!--GREEK CAPITAL LETTER GAMMA -->
-<!ENTITY ggr "&#x003B3;" ><!--GREEK SMALL LETTER GAMMA -->
-<!ENTITY Igr "&#x00399;" ><!--GREEK CAPITAL LETTER IOTA -->
-<!ENTITY igr "&#x003B9;" ><!--GREEK SMALL LETTER IOTA -->
-<!ENTITY Kgr "&#x0039A;" ><!--GREEK CAPITAL LETTER KAPPA -->
-<!ENTITY kgr "&#x003BA;" ><!--GREEK SMALL LETTER KAPPA -->
-<!ENTITY KHgr "&#x003A7;" ><!--GREEK CAPITAL LETTER CHI -->
-<!ENTITY khgr "&#x003C7;" ><!--GREEK SMALL LETTER CHI -->
-<!ENTITY Lgr "&#x0039B;" ><!--GREEK CAPITAL LETTER LAMDA -->
-<!ENTITY lgr "&#x003BB;" ><!--GREEK SMALL LETTER LAMDA -->
-<!ENTITY Mgr "&#x0039C;" ><!--GREEK CAPITAL LETTER MU -->
-<!ENTITY mgr "&#x003BC;" ><!--GREEK SMALL LETTER MU -->
-<!ENTITY Ngr "&#x0039D;" ><!--GREEK CAPITAL LETTER NU -->
-<!ENTITY ngr "&#x003BD;" ><!--GREEK SMALL LETTER NU -->
-<!ENTITY Ogr "&#x0039F;" ><!--GREEK CAPITAL LETTER OMICRON -->
-<!ENTITY ogr "&#x003BF;" ><!--GREEK SMALL LETTER OMICRON -->
-<!ENTITY OHgr "&#x003A9;" ><!--GREEK CAPITAL LETTER OMEGA -->
-<!ENTITY ohgr "&#x003C9;" ><!--GREEK SMALL LETTER OMEGA -->
-<!ENTITY Pgr "&#x003A0;" ><!--GREEK CAPITAL LETTER PI -->
-<!ENTITY pgr "&#x003C0;" ><!--GREEK SMALL LETTER PI -->
-<!ENTITY PHgr "&#x003A6;" ><!--GREEK CAPITAL LETTER PHI -->
-<!ENTITY phgr "&#x003C6;" ><!--GREEK SMALL LETTER PHI -->
-<!ENTITY PSgr "&#x003A8;" ><!--GREEK CAPITAL LETTER PSI -->
-<!ENTITY psgr "&#x003C8;" ><!--GREEK SMALL LETTER PSI -->
-<!ENTITY Rgr "&#x003A1;" ><!--GREEK CAPITAL LETTER RHO -->
-<!ENTITY rgr "&#x003C1;" ><!--GREEK SMALL LETTER RHO -->
-<!ENTITY sfgr "&#x003C2;" ><!--GREEK SMALL LETTER FINAL SIGMA -->
-<!ENTITY Sgr "&#x003A3;" ><!--GREEK CAPITAL LETTER SIGMA -->
-<!ENTITY sgr "&#x003C3;" ><!--GREEK SMALL LETTER SIGMA -->
-<!ENTITY Tgr "&#x003A4;" ><!--GREEK CAPITAL LETTER TAU -->
-<!ENTITY tgr "&#x003C4;" ><!--GREEK SMALL LETTER TAU -->
-<!ENTITY THgr "&#x00398;" ><!--GREEK CAPITAL LETTER THETA -->
-<!ENTITY thgr "&#x003B8;" ><!--GREEK SMALL LETTER THETA -->
-<!ENTITY Ugr "&#x003A5;" ><!--GREEK CAPITAL LETTER UPSILON -->
-<!ENTITY ugr "&#x003C5;" ><!--GREEK SMALL LETTER UPSILON -->
-<!ENTITY Xgr "&#x0039E;" ><!--GREEK CAPITAL LETTER XI -->
-<!ENTITY xgr "&#x003BE;" ><!--GREEK SMALL LETTER XI -->
-<!ENTITY Zgr "&#x00396;" ><!--GREEK CAPITAL LETTER ZETA -->
-<!ENTITY zgr "&#x003B6;" ><!--GREEK SMALL LETTER ZETA -->
diff --git a/Utilities/xml/docbook-4.5/ent/isogrk2.ent b/Utilities/xml/docbook-4.5/ent/isogrk2.ent
deleted file mode 100644
index 726b7dd70..000000000
--- a/Utilities/xml/docbook-4.5/ent/isogrk2.ent
+++ /dev/null
@@ -1,61 +0,0 @@
-
-<!--
- File isogrk2.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isogrk2.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isogrk2.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isogrk2 PUBLIC
- "ISO 8879:1986//ENTITIES Monotoniko Greek//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isogrk2.ent"
- >
- %isogrk2;
-
--->
-
-<!ENTITY Aacgr "&#x00386;" ><!--GREEK CAPITAL LETTER ALPHA WITH TONOS -->
-<!ENTITY aacgr "&#x003AC;" ><!--GREEK SMALL LETTER ALPHA WITH TONOS -->
-<!ENTITY Eacgr "&#x00388;" ><!--GREEK CAPITAL LETTER EPSILON WITH TONOS -->
-<!ENTITY eacgr "&#x003AD;" ><!--GREEK SMALL LETTER EPSILON WITH TONOS -->
-<!ENTITY EEacgr "&#x00389;" ><!--GREEK CAPITAL LETTER ETA WITH TONOS -->
-<!ENTITY eeacgr "&#x003AE;" ><!--GREEK SMALL LETTER ETA WITH TONOS -->
-<!ENTITY Iacgr "&#x0038A;" ><!--GREEK CAPITAL LETTER IOTA WITH TONOS -->
-<!ENTITY iacgr "&#x003AF;" ><!--GREEK SMALL LETTER IOTA WITH TONOS -->
-<!ENTITY idiagr "&#x00390;" ><!--GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS -->
-<!ENTITY Idigr "&#x003AA;" ><!--GREEK CAPITAL LETTER IOTA WITH DIALYTIKA -->
-<!ENTITY idigr "&#x003CA;" ><!--GREEK SMALL LETTER IOTA WITH DIALYTIKA -->
-<!ENTITY Oacgr "&#x0038C;" ><!--GREEK CAPITAL LETTER OMICRON WITH TONOS -->
-<!ENTITY oacgr "&#x003CC;" ><!--GREEK SMALL LETTER OMICRON WITH TONOS -->
-<!ENTITY OHacgr "&#x0038F;" ><!--GREEK CAPITAL LETTER OMEGA WITH TONOS -->
-<!ENTITY ohacgr "&#x003CE;" ><!--GREEK SMALL LETTER OMEGA WITH TONOS -->
-<!ENTITY Uacgr "&#x0038E;" ><!--GREEK CAPITAL LETTER UPSILON WITH TONOS -->
-<!ENTITY uacgr "&#x003CD;" ><!--GREEK SMALL LETTER UPSILON WITH TONOS -->
-<!ENTITY udiagr "&#x003B0;" ><!--GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS -->
-<!ENTITY Udigr "&#x003AB;" ><!--GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA -->
-<!ENTITY udigr "&#x003CB;" ><!--GREEK SMALL LETTER UPSILON WITH DIALYTIKA -->
diff --git a/Utilities/xml/docbook-4.5/ent/isogrk3.ent b/Utilities/xml/docbook-4.5/ent/isogrk3.ent
deleted file mode 100644
index 28b5c2766..000000000
--- a/Utilities/xml/docbook-4.5/ent/isogrk3.ent
+++ /dev/null
@@ -1,84 +0,0 @@
-
-<!--
- File isogrk3.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isogrk3.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Greek Symbols//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isogrk3.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isogrk3 PUBLIC
- "ISO 8879:1986//ENTITIES Greek Symbols//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isogrk3.ent"
- >
- %isogrk3;
-
--->
-
-<!ENTITY alpha "&#x003B1;" ><!--GREEK SMALL LETTER ALPHA -->
-<!ENTITY beta "&#x003B2;" ><!--GREEK SMALL LETTER BETA -->
-<!ENTITY chi "&#x003C7;" ><!--GREEK SMALL LETTER CHI -->
-<!ENTITY Delta "&#x00394;" ><!--GREEK CAPITAL LETTER DELTA -->
-<!ENTITY delta "&#x003B4;" ><!--GREEK SMALL LETTER DELTA -->
-<!ENTITY epsi "&#x003F5;" ><!--GREEK LUNATE EPSILON SYMBOL -->
-<!ENTITY epsis "&#x003F5;" ><!--GREEK LUNATE EPSILON SYMBOL -->
-<!ENTITY epsiv "&#x003B5;" ><!--GREEK SMALL LETTER EPSILON -->
-<!ENTITY eta "&#x003B7;" ><!--GREEK SMALL LETTER ETA -->
-<!ENTITY Gamma "&#x00393;" ><!--GREEK CAPITAL LETTER GAMMA -->
-<!ENTITY gamma "&#x003B3;" ><!--GREEK SMALL LETTER GAMMA -->
-<!ENTITY gammad "&#x003DD;" ><!--GREEK SMALL LETTER DIGAMMA -->
-<!ENTITY iota "&#x003B9;" ><!--GREEK SMALL LETTER IOTA -->
-<!ENTITY kappa "&#x003BA;" ><!--GREEK SMALL LETTER KAPPA -->
-<!ENTITY kappav "&#x003F0;" ><!--GREEK KAPPA SYMBOL -->
-<!ENTITY Lambda "&#x0039B;" ><!--GREEK CAPITAL LETTER LAMDA -->
-<!ENTITY lambda "&#x003BB;" ><!--GREEK SMALL LETTER LAMDA -->
-<!ENTITY mu "&#x003BC;" ><!--GREEK SMALL LETTER MU -->
-<!ENTITY nu "&#x003BD;" ><!--GREEK SMALL LETTER NU -->
-<!ENTITY Omega "&#x003A9;" ><!--GREEK CAPITAL LETTER OMEGA -->
-<!ENTITY omega "&#x003C9;" ><!--GREEK SMALL LETTER OMEGA -->
-<!ENTITY Phi "&#x003A6;" ><!--GREEK CAPITAL LETTER PHI -->
-<!ENTITY phis "&#x003D5;" ><!--GREEK PHI SYMBOL -->
-<!ENTITY phiv "&#x003C6;" ><!--GREEK SMALL LETTER PHI -->
-<!ENTITY Pi "&#x003A0;" ><!--GREEK CAPITAL LETTER PI -->
-<!ENTITY pi "&#x003C0;" ><!--GREEK SMALL LETTER PI -->
-<!ENTITY piv "&#x003D6;" ><!--GREEK PI SYMBOL -->
-<!ENTITY Psi "&#x003A8;" ><!--GREEK CAPITAL LETTER PSI -->
-<!ENTITY psi "&#x003C8;" ><!--GREEK SMALL LETTER PSI -->
-<!ENTITY rho "&#x003C1;" ><!--GREEK SMALL LETTER RHO -->
-<!ENTITY rhov "&#x003F1;" ><!--GREEK RHO SYMBOL -->
-<!ENTITY Sigma "&#x003A3;" ><!--GREEK CAPITAL LETTER SIGMA -->
-<!ENTITY sigma "&#x003C3;" ><!--GREEK SMALL LETTER SIGMA -->
-<!ENTITY sigmav "&#x003C2;" ><!--GREEK SMALL LETTER FINAL SIGMA -->
-<!ENTITY tau "&#x003C4;" ><!--GREEK SMALL LETTER TAU -->
-<!ENTITY Theta "&#x00398;" ><!--GREEK CAPITAL LETTER THETA -->
-<!ENTITY thetas "&#x003B8;" ><!--GREEK SMALL LETTER THETA -->
-<!ENTITY thetav "&#x003D1;" ><!--GREEK THETA SYMBOL -->
-<!ENTITY Upsi "&#x003D2;" ><!--GREEK UPSILON WITH HOOK SYMBOL -->
-<!ENTITY upsi "&#x003C5;" ><!--GREEK SMALL LETTER UPSILON -->
-<!ENTITY Xi "&#x0039E;" ><!--GREEK CAPITAL LETTER XI -->
-<!ENTITY xi "&#x003BE;" ><!--GREEK SMALL LETTER XI -->
-<!ENTITY zeta "&#x003B6;" ><!--GREEK SMALL LETTER ZETA -->
diff --git a/Utilities/xml/docbook-4.5/ent/isogrk4.ent b/Utilities/xml/docbook-4.5/ent/isogrk4.ent
deleted file mode 100644
index 27c6a514f..000000000
--- a/Utilities/xml/docbook-4.5/ent/isogrk4.ent
+++ /dev/null
@@ -1,84 +0,0 @@
-
-<!--
- File isogrk4.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isogrk4.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isogrk4.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isogrk4 PUBLIC
- "ISO 8879:1986//ENTITIES Alternative Greek Symbols//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isogrk4.ent"
- >
- %isogrk4;
-
--->
-
-<!ENTITY b.alpha "&#x1D6C2;" ><!--MATHEMATICAL BOLD SMALL ALPHA -->
-<!ENTITY b.beta "&#x1D6C3;" ><!--MATHEMATICAL BOLD SMALL BETA -->
-<!ENTITY b.chi "&#x1D6D8;" ><!--MATHEMATICAL BOLD SMALL CHI -->
-<!ENTITY b.Delta "&#x1D6AB;" ><!--MATHEMATICAL BOLD CAPITAL DELTA -->
-<!ENTITY b.delta "&#x1D6C5;" ><!--MATHEMATICAL BOLD SMALL DELTA -->
-<!ENTITY b.epsi "&#x1D6C6;" ><!--MATHEMATICAL BOLD SMALL EPSILON -->
-<!ENTITY b.epsiv "&#x1D6DC;" ><!--MATHEMATICAL BOLD EPSILON SYMBOL -->
-<!ENTITY b.eta "&#x1D6C8;" ><!--MATHEMATICAL BOLD SMALL ETA -->
-<!ENTITY b.Gamma "&#x1D6AA;" ><!--MATHEMATICAL BOLD CAPITAL GAMMA -->
-<!ENTITY b.gamma "&#x1D6C4;" ><!--MATHEMATICAL BOLD SMALL GAMMA -->
-<!ENTITY b.Gammad "&#x003DC;" ><!--GREEK LETTER DIGAMMA -->
-<!ENTITY b.gammad "&#x003DD;" ><!--GREEK SMALL LETTER DIGAMMA -->
-<!ENTITY b.iota "&#x1D6CA;" ><!--MATHEMATICAL BOLD SMALL IOTA -->
-<!ENTITY b.kappa "&#x1D6CB;" ><!--MATHEMATICAL BOLD SMALL KAPPA -->
-<!ENTITY b.kappav "&#x1D6DE;" ><!--MATHEMATICAL BOLD KAPPA SYMBOL -->
-<!ENTITY b.Lambda "&#x1D6B2;" ><!--MATHEMATICAL BOLD CAPITAL LAMDA -->
-<!ENTITY b.lambda "&#x1D6CC;" ><!--MATHEMATICAL BOLD SMALL LAMDA -->
-<!ENTITY b.mu "&#x1D6CD;" ><!--MATHEMATICAL BOLD SMALL MU -->
-<!ENTITY b.nu "&#x1D6CE;" ><!--MATHEMATICAL BOLD SMALL NU -->
-<!ENTITY b.Omega "&#x1D6C0;" ><!--MATHEMATICAL BOLD CAPITAL OMEGA -->
-<!ENTITY b.omega "&#x1D6DA;" ><!--MATHEMATICAL BOLD SMALL OMEGA -->
-<!ENTITY b.Phi "&#x1D6BD;" ><!--MATHEMATICAL BOLD CAPITAL PHI -->
-<!ENTITY b.phi "&#x1D6D7;" ><!--MATHEMATICAL BOLD SMALL PHI -->
-<!ENTITY b.phiv "&#x1D6DF;" ><!--MATHEMATICAL BOLD PHI SYMBOL -->
-<!ENTITY b.Pi "&#x1D6B7;" ><!--MATHEMATICAL BOLD CAPITAL PI -->
-<!ENTITY b.pi "&#x1D6D1;" ><!--MATHEMATICAL BOLD SMALL PI -->
-<!ENTITY b.piv "&#x1D6E1;" ><!--MATHEMATICAL BOLD PI SYMBOL -->
-<!ENTITY b.Psi "&#x1D6BF;" ><!--MATHEMATICAL BOLD CAPITAL PSI -->
-<!ENTITY b.psi "&#x1D6D9;" ><!--MATHEMATICAL BOLD SMALL PSI -->
-<!ENTITY b.rho "&#x1D6D2;" ><!--MATHEMATICAL BOLD SMALL RHO -->
-<!ENTITY b.rhov "&#x1D6E0;" ><!--MATHEMATICAL BOLD RHO SYMBOL -->
-<!ENTITY b.Sigma "&#x1D6BA;" ><!--MATHEMATICAL BOLD CAPITAL SIGMA -->
-<!ENTITY b.sigma "&#x1D6D4;" ><!--MATHEMATICAL BOLD SMALL SIGMA -->
-<!ENTITY b.sigmav "&#x1D6D3;" ><!--MATHEMATICAL BOLD SMALL FINAL SIGMA -->
-<!ENTITY b.tau "&#x1D6D5;" ><!--MATHEMATICAL BOLD SMALL TAU -->
-<!ENTITY b.Theta "&#x1D6AF;" ><!--MATHEMATICAL BOLD CAPITAL THETA -->
-<!ENTITY b.thetas "&#x1D6C9;" ><!--MATHEMATICAL BOLD SMALL THETA -->
-<!ENTITY b.thetav "&#x1D6DD;" ><!--MATHEMATICAL BOLD THETA SYMBOL -->
-<!ENTITY b.Upsi "&#x1D6BC;" ><!--MATHEMATICAL BOLD CAPITAL UPSILON -->
-<!ENTITY b.upsi "&#x1D6D6;" ><!--MATHEMATICAL BOLD SMALL UPSILON -->
-<!ENTITY b.Xi "&#x1D6B5;" ><!--MATHEMATICAL BOLD CAPITAL XI -->
-<!ENTITY b.xi "&#x1D6CF;" ><!--MATHEMATICAL BOLD SMALL XI -->
-<!ENTITY b.zeta "&#x1D6C7;" ><!--MATHEMATICAL BOLD SMALL ZETA -->
diff --git a/Utilities/xml/docbook-4.5/ent/isolat1.ent b/Utilities/xml/docbook-4.5/ent/isolat1.ent
deleted file mode 100644
index 381bd0900..000000000
--- a/Utilities/xml/docbook-4.5/ent/isolat1.ent
+++ /dev/null
@@ -1,103 +0,0 @@
-
-<!--
- File isolat1.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isolat1.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Latin 1//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isolat1.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isolat1 PUBLIC
- "ISO 8879:1986//ENTITIES Added Latin 1//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isolat1.ent"
- >
- %isolat1;
-
--->
-
-<!ENTITY Aacute "&#x000C1;" ><!--LATIN CAPITAL LETTER A WITH ACUTE -->
-<!ENTITY aacute "&#x000E1;" ><!--LATIN SMALL LETTER A WITH ACUTE -->
-<!ENTITY Acirc "&#x000C2;" ><!--LATIN CAPITAL LETTER A WITH CIRCUMFLEX -->
-<!ENTITY acirc "&#x000E2;" ><!--LATIN SMALL LETTER A WITH CIRCUMFLEX -->
-<!ENTITY AElig "&#x000C6;" ><!--LATIN CAPITAL LETTER AE -->
-<!ENTITY aelig "&#x000E6;" ><!--LATIN SMALL LETTER AE -->
-<!ENTITY Agrave "&#x000C0;" ><!--LATIN CAPITAL LETTER A WITH GRAVE -->
-<!ENTITY agrave "&#x000E0;" ><!--LATIN SMALL LETTER A WITH GRAVE -->
-<!ENTITY Aring "&#x000C5;" ><!--LATIN CAPITAL LETTER A WITH RING ABOVE -->
-<!ENTITY aring "&#x000E5;" ><!--LATIN SMALL LETTER A WITH RING ABOVE -->
-<!ENTITY Atilde "&#x000C3;" ><!--LATIN CAPITAL LETTER A WITH TILDE -->
-<!ENTITY atilde "&#x000E3;" ><!--LATIN SMALL LETTER A WITH TILDE -->
-<!ENTITY Auml "&#x000C4;" ><!--LATIN CAPITAL LETTER A WITH DIAERESIS -->
-<!ENTITY auml "&#x000E4;" ><!--LATIN SMALL LETTER A WITH DIAERESIS -->
-<!ENTITY Ccedil "&#x000C7;" ><!--LATIN CAPITAL LETTER C WITH CEDILLA -->
-<!ENTITY ccedil "&#x000E7;" ><!--LATIN SMALL LETTER C WITH CEDILLA -->
-<!ENTITY Eacute "&#x000C9;" ><!--LATIN CAPITAL LETTER E WITH ACUTE -->
-<!ENTITY eacute "&#x000E9;" ><!--LATIN SMALL LETTER E WITH ACUTE -->
-<!ENTITY Ecirc "&#x000CA;" ><!--LATIN CAPITAL LETTER E WITH CIRCUMFLEX -->
-<!ENTITY ecirc "&#x000EA;" ><!--LATIN SMALL LETTER E WITH CIRCUMFLEX -->
-<!ENTITY Egrave "&#x000C8;" ><!--LATIN CAPITAL LETTER E WITH GRAVE -->
-<!ENTITY egrave "&#x000E8;" ><!--LATIN SMALL LETTER E WITH GRAVE -->
-<!ENTITY ETH "&#x000D0;" ><!--LATIN CAPITAL LETTER ETH -->
-<!ENTITY eth "&#x000F0;" ><!--LATIN SMALL LETTER ETH -->
-<!ENTITY Euml "&#x000CB;" ><!--LATIN CAPITAL LETTER E WITH DIAERESIS -->
-<!ENTITY euml "&#x000EB;" ><!--LATIN SMALL LETTER E WITH DIAERESIS -->
-<!ENTITY Iacute "&#x000CD;" ><!--LATIN CAPITAL LETTER I WITH ACUTE -->
-<!ENTITY iacute "&#x000ED;" ><!--LATIN SMALL LETTER I WITH ACUTE -->
-<!ENTITY Icirc "&#x000CE;" ><!--LATIN CAPITAL LETTER I WITH CIRCUMFLEX -->
-<!ENTITY icirc "&#x000EE;" ><!--LATIN SMALL LETTER I WITH CIRCUMFLEX -->
-<!ENTITY Igrave "&#x000CC;" ><!--LATIN CAPITAL LETTER I WITH GRAVE -->
-<!ENTITY igrave "&#x000EC;" ><!--LATIN SMALL LETTER I WITH GRAVE -->
-<!ENTITY Iuml "&#x000CF;" ><!--LATIN CAPITAL LETTER I WITH DIAERESIS -->
-<!ENTITY iuml "&#x000EF;" ><!--LATIN SMALL LETTER I WITH DIAERESIS -->
-<!ENTITY Ntilde "&#x000D1;" ><!--LATIN CAPITAL LETTER N WITH TILDE -->
-<!ENTITY ntilde "&#x000F1;" ><!--LATIN SMALL LETTER N WITH TILDE -->
-<!ENTITY Oacute "&#x000D3;" ><!--LATIN CAPITAL LETTER O WITH ACUTE -->
-<!ENTITY oacute "&#x000F3;" ><!--LATIN SMALL LETTER O WITH ACUTE -->
-<!ENTITY Ocirc "&#x000D4;" ><!--LATIN CAPITAL LETTER O WITH CIRCUMFLEX -->
-<!ENTITY ocirc "&#x000F4;" ><!--LATIN SMALL LETTER O WITH CIRCUMFLEX -->
-<!ENTITY Ograve "&#x000D2;" ><!--LATIN CAPITAL LETTER O WITH GRAVE -->
-<!ENTITY ograve "&#x000F2;" ><!--LATIN SMALL LETTER O WITH GRAVE -->
-<!ENTITY Oslash "&#x000D8;" ><!--LATIN CAPITAL LETTER O WITH STROKE -->
-<!ENTITY oslash "&#x000F8;" ><!--LATIN SMALL LETTER O WITH STROKE -->
-<!ENTITY Otilde "&#x000D5;" ><!--LATIN CAPITAL LETTER O WITH TILDE -->
-<!ENTITY otilde "&#x000F5;" ><!--LATIN SMALL LETTER O WITH TILDE -->
-<!ENTITY Ouml "&#x000D6;" ><!--LATIN CAPITAL LETTER O WITH DIAERESIS -->
-<!ENTITY ouml "&#x000F6;" ><!--LATIN SMALL LETTER O WITH DIAERESIS -->
-<!ENTITY szlig "&#x000DF;" ><!--LATIN SMALL LETTER SHARP S -->
-<!ENTITY THORN "&#x000DE;" ><!--LATIN CAPITAL LETTER THORN -->
-<!ENTITY thorn "&#x000FE;" ><!--LATIN SMALL LETTER THORN -->
-<!ENTITY Uacute "&#x000DA;" ><!--LATIN CAPITAL LETTER U WITH ACUTE -->
-<!ENTITY uacute "&#x000FA;" ><!--LATIN SMALL LETTER U WITH ACUTE -->
-<!ENTITY Ucirc "&#x000DB;" ><!--LATIN CAPITAL LETTER U WITH CIRCUMFLEX -->
-<!ENTITY ucirc "&#x000FB;" ><!--LATIN SMALL LETTER U WITH CIRCUMFLEX -->
-<!ENTITY Ugrave "&#x000D9;" ><!--LATIN CAPITAL LETTER U WITH GRAVE -->
-<!ENTITY ugrave "&#x000F9;" ><!--LATIN SMALL LETTER U WITH GRAVE -->
-<!ENTITY Uuml "&#x000DC;" ><!--LATIN CAPITAL LETTER U WITH DIAERESIS -->
-<!ENTITY uuml "&#x000FC;" ><!--LATIN SMALL LETTER U WITH DIAERESIS -->
-<!ENTITY Yacute "&#x000DD;" ><!--LATIN CAPITAL LETTER Y WITH ACUTE -->
-<!ENTITY yacute "&#x000FD;" ><!--LATIN SMALL LETTER Y WITH ACUTE -->
-<!ENTITY yuml "&#x000FF;" ><!--LATIN SMALL LETTER Y WITH DIAERESIS -->
diff --git a/Utilities/xml/docbook-4.5/ent/isolat2.ent b/Utilities/xml/docbook-4.5/ent/isolat2.ent
deleted file mode 100644
index e91ffdbee..000000000
--- a/Utilities/xml/docbook-4.5/ent/isolat2.ent
+++ /dev/null
@@ -1,162 +0,0 @@
-
-<!--
- File isolat2.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isolat2.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Added Latin 2//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isolat2.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isolat2 PUBLIC
- "ISO 8879:1986//ENTITIES Added Latin 2//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isolat2.ent"
- >
- %isolat2;
-
--->
-
-<!ENTITY Abreve "&#x00102;" ><!--LATIN CAPITAL LETTER A WITH BREVE -->
-<!ENTITY abreve "&#x00103;" ><!--LATIN SMALL LETTER A WITH BREVE -->
-<!ENTITY Amacr "&#x00100;" ><!--LATIN CAPITAL LETTER A WITH MACRON -->
-<!ENTITY amacr "&#x00101;" ><!--LATIN SMALL LETTER A WITH MACRON -->
-<!ENTITY Aogon "&#x00104;" ><!--LATIN CAPITAL LETTER A WITH OGONEK -->
-<!ENTITY aogon "&#x00105;" ><!--LATIN SMALL LETTER A WITH OGONEK -->
-<!ENTITY Cacute "&#x00106;" ><!--LATIN CAPITAL LETTER C WITH ACUTE -->
-<!ENTITY cacute "&#x00107;" ><!--LATIN SMALL LETTER C WITH ACUTE -->
-<!ENTITY Ccaron "&#x0010C;" ><!--LATIN CAPITAL LETTER C WITH CARON -->
-<!ENTITY ccaron "&#x0010D;" ><!--LATIN SMALL LETTER C WITH CARON -->
-<!ENTITY Ccirc "&#x00108;" ><!--LATIN CAPITAL LETTER C WITH CIRCUMFLEX -->
-<!ENTITY ccirc "&#x00109;" ><!--LATIN SMALL LETTER C WITH CIRCUMFLEX -->
-<!ENTITY Cdot "&#x0010A;" ><!--LATIN CAPITAL LETTER C WITH DOT ABOVE -->
-<!ENTITY cdot "&#x0010B;" ><!--LATIN SMALL LETTER C WITH DOT ABOVE -->
-<!ENTITY Dcaron "&#x0010E;" ><!--LATIN CAPITAL LETTER D WITH CARON -->
-<!ENTITY dcaron "&#x0010F;" ><!--LATIN SMALL LETTER D WITH CARON -->
-<!ENTITY Dstrok "&#x00110;" ><!--LATIN CAPITAL LETTER D WITH STROKE -->
-<!ENTITY dstrok "&#x00111;" ><!--LATIN SMALL LETTER D WITH STROKE -->
-<!ENTITY Ecaron "&#x0011A;" ><!--LATIN CAPITAL LETTER E WITH CARON -->
-<!ENTITY ecaron "&#x0011B;" ><!--LATIN SMALL LETTER E WITH CARON -->
-<!ENTITY Edot "&#x00116;" ><!--LATIN CAPITAL LETTER E WITH DOT ABOVE -->
-<!ENTITY edot "&#x00117;" ><!--LATIN SMALL LETTER E WITH DOT ABOVE -->
-<!ENTITY Emacr "&#x00112;" ><!--LATIN CAPITAL LETTER E WITH MACRON -->
-<!ENTITY emacr "&#x00113;" ><!--LATIN SMALL LETTER E WITH MACRON -->
-<!ENTITY ENG "&#x0014A;" ><!--LATIN CAPITAL LETTER ENG -->
-<!ENTITY eng "&#x0014B;" ><!--LATIN SMALL LETTER ENG -->
-<!ENTITY Eogon "&#x00118;" ><!--LATIN CAPITAL LETTER E WITH OGONEK -->
-<!ENTITY eogon "&#x00119;" ><!--LATIN SMALL LETTER E WITH OGONEK -->
-<!ENTITY gacute "&#x001F5;" ><!--LATIN SMALL LETTER G WITH ACUTE -->
-<!ENTITY Gbreve "&#x0011E;" ><!--LATIN CAPITAL LETTER G WITH BREVE -->
-<!ENTITY gbreve "&#x0011F;" ><!--LATIN SMALL LETTER G WITH BREVE -->
-<!ENTITY Gcedil "&#x00122;" ><!--LATIN CAPITAL LETTER G WITH CEDILLA -->
-<!ENTITY Gcirc "&#x0011C;" ><!--LATIN CAPITAL LETTER G WITH CIRCUMFLEX -->
-<!ENTITY gcirc "&#x0011D;" ><!--LATIN SMALL LETTER G WITH CIRCUMFLEX -->
-<!ENTITY Gdot "&#x00120;" ><!--LATIN CAPITAL LETTER G WITH DOT ABOVE -->
-<!ENTITY gdot "&#x00121;" ><!--LATIN SMALL LETTER G WITH DOT ABOVE -->
-<!ENTITY Hcirc "&#x00124;" ><!--LATIN CAPITAL LETTER H WITH CIRCUMFLEX -->
-<!ENTITY hcirc "&#x00125;" ><!--LATIN SMALL LETTER H WITH CIRCUMFLEX -->
-<!ENTITY Hstrok "&#x00126;" ><!--LATIN CAPITAL LETTER H WITH STROKE -->
-<!ENTITY hstrok "&#x00127;" ><!--LATIN SMALL LETTER H WITH STROKE -->
-<!ENTITY Idot "&#x00130;" ><!--LATIN CAPITAL LETTER I WITH DOT ABOVE -->
-<!ENTITY IJlig "&#x00132;" ><!--LATIN CAPITAL LIGATURE IJ -->
-<!ENTITY ijlig "&#x00133;" ><!--LATIN SMALL LIGATURE IJ -->
-<!ENTITY Imacr "&#x0012A;" ><!--LATIN CAPITAL LETTER I WITH MACRON -->
-<!ENTITY imacr "&#x0012B;" ><!--LATIN SMALL LETTER I WITH MACRON -->
-<!ENTITY inodot "&#x00131;" ><!--LATIN SMALL LETTER DOTLESS I -->
-<!ENTITY Iogon "&#x0012E;" ><!--LATIN CAPITAL LETTER I WITH OGONEK -->
-<!ENTITY iogon "&#x0012F;" ><!--LATIN SMALL LETTER I WITH OGONEK -->
-<!ENTITY Itilde "&#x00128;" ><!--LATIN CAPITAL LETTER I WITH TILDE -->
-<!ENTITY itilde "&#x00129;" ><!--LATIN SMALL LETTER I WITH TILDE -->
-<!ENTITY Jcirc "&#x00134;" ><!--LATIN CAPITAL LETTER J WITH CIRCUMFLEX -->
-<!ENTITY jcirc "&#x00135;" ><!--LATIN SMALL LETTER J WITH CIRCUMFLEX -->
-<!ENTITY Kcedil "&#x00136;" ><!--LATIN CAPITAL LETTER K WITH CEDILLA -->
-<!ENTITY kcedil "&#x00137;" ><!--LATIN SMALL LETTER K WITH CEDILLA -->
-<!ENTITY kgreen "&#x00138;" ><!--LATIN SMALL LETTER KRA -->
-<!ENTITY Lacute "&#x00139;" ><!--LATIN CAPITAL LETTER L WITH ACUTE -->
-<!ENTITY lacute "&#x0013A;" ><!--LATIN SMALL LETTER L WITH ACUTE -->
-<!ENTITY Lcaron "&#x0013D;" ><!--LATIN CAPITAL LETTER L WITH CARON -->
-<!ENTITY lcaron "&#x0013E;" ><!--LATIN SMALL LETTER L WITH CARON -->
-<!ENTITY Lcedil "&#x0013B;" ><!--LATIN CAPITAL LETTER L WITH CEDILLA -->
-<!ENTITY lcedil "&#x0013C;" ><!--LATIN SMALL LETTER L WITH CEDILLA -->
-<!ENTITY Lmidot "&#x0013F;" ><!--LATIN CAPITAL LETTER L WITH MIDDLE DOT -->
-<!ENTITY lmidot "&#x00140;" ><!--LATIN SMALL LETTER L WITH MIDDLE DOT -->
-<!ENTITY Lstrok "&#x00141;" ><!--LATIN CAPITAL LETTER L WITH STROKE -->
-<!ENTITY lstrok "&#x00142;" ><!--LATIN SMALL LETTER L WITH STROKE -->
-<!ENTITY Nacute "&#x00143;" ><!--LATIN CAPITAL LETTER N WITH ACUTE -->
-<!ENTITY nacute "&#x00144;" ><!--LATIN SMALL LETTER N WITH ACUTE -->
-<!ENTITY napos "&#x00149;" ><!--LATIN SMALL LETTER N PRECEDED BY APOSTROPHE -->
-<!ENTITY Ncaron "&#x00147;" ><!--LATIN CAPITAL LETTER N WITH CARON -->
-<!ENTITY ncaron "&#x00148;" ><!--LATIN SMALL LETTER N WITH CARON -->
-<!ENTITY Ncedil "&#x00145;" ><!--LATIN CAPITAL LETTER N WITH CEDILLA -->
-<!ENTITY ncedil "&#x00146;" ><!--LATIN SMALL LETTER N WITH CEDILLA -->
-<!ENTITY Odblac "&#x00150;" ><!--LATIN CAPITAL LETTER O WITH DOUBLE ACUTE -->
-<!ENTITY odblac "&#x00151;" ><!--LATIN SMALL LETTER O WITH DOUBLE ACUTE -->
-<!ENTITY OElig "&#x00152;" ><!--LATIN CAPITAL LIGATURE OE -->
-<!ENTITY oelig "&#x00153;" ><!--LATIN SMALL LIGATURE OE -->
-<!ENTITY Omacr "&#x0014C;" ><!--LATIN CAPITAL LETTER O WITH MACRON -->
-<!ENTITY omacr "&#x0014D;" ><!--LATIN SMALL LETTER O WITH MACRON -->
-<!ENTITY Racute "&#x00154;" ><!--LATIN CAPITAL LETTER R WITH ACUTE -->
-<!ENTITY racute "&#x00155;" ><!--LATIN SMALL LETTER R WITH ACUTE -->
-<!ENTITY Rcaron "&#x00158;" ><!--LATIN CAPITAL LETTER R WITH CARON -->
-<!ENTITY rcaron "&#x00159;" ><!--LATIN SMALL LETTER R WITH CARON -->
-<!ENTITY Rcedil "&#x00156;" ><!--LATIN CAPITAL LETTER R WITH CEDILLA -->
-<!ENTITY rcedil "&#x00157;" ><!--LATIN SMALL LETTER R WITH CEDILLA -->
-<!ENTITY Sacute "&#x0015A;" ><!--LATIN CAPITAL LETTER S WITH ACUTE -->
-<!ENTITY sacute "&#x0015B;" ><!--LATIN SMALL LETTER S WITH ACUTE -->
-<!ENTITY Scaron "&#x00160;" ><!--LATIN CAPITAL LETTER S WITH CARON -->
-<!ENTITY scaron "&#x00161;" ><!--LATIN SMALL LETTER S WITH CARON -->
-<!ENTITY Scedil "&#x0015E;" ><!--LATIN CAPITAL LETTER S WITH CEDILLA -->
-<!ENTITY scedil "&#x0015F;" ><!--LATIN SMALL LETTER S WITH CEDILLA -->
-<!ENTITY Scirc "&#x0015C;" ><!--LATIN CAPITAL LETTER S WITH CIRCUMFLEX -->
-<!ENTITY scirc "&#x0015D;" ><!--LATIN SMALL LETTER S WITH CIRCUMFLEX -->
-<!ENTITY Tcaron "&#x00164;" ><!--LATIN CAPITAL LETTER T WITH CARON -->
-<!ENTITY tcaron "&#x00165;" ><!--LATIN SMALL LETTER T WITH CARON -->
-<!ENTITY Tcedil "&#x00162;" ><!--LATIN CAPITAL LETTER T WITH CEDILLA -->
-<!ENTITY tcedil "&#x00163;" ><!--LATIN SMALL LETTER T WITH CEDILLA -->
-<!ENTITY Tstrok "&#x00166;" ><!--LATIN CAPITAL LETTER T WITH STROKE -->
-<!ENTITY tstrok "&#x00167;" ><!--LATIN SMALL LETTER T WITH STROKE -->
-<!ENTITY Ubreve "&#x0016C;" ><!--LATIN CAPITAL LETTER U WITH BREVE -->
-<!ENTITY ubreve "&#x0016D;" ><!--LATIN SMALL LETTER U WITH BREVE -->
-<!ENTITY Udblac "&#x00170;" ><!--LATIN CAPITAL LETTER U WITH DOUBLE ACUTE -->
-<!ENTITY udblac "&#x00171;" ><!--LATIN SMALL LETTER U WITH DOUBLE ACUTE -->
-<!ENTITY Umacr "&#x0016A;" ><!--LATIN CAPITAL LETTER U WITH MACRON -->
-<!ENTITY umacr "&#x0016B;" ><!--LATIN SMALL LETTER U WITH MACRON -->
-<!ENTITY Uogon "&#x00172;" ><!--LATIN CAPITAL LETTER U WITH OGONEK -->
-<!ENTITY uogon "&#x00173;" ><!--LATIN SMALL LETTER U WITH OGONEK -->
-<!ENTITY Uring "&#x0016E;" ><!--LATIN CAPITAL LETTER U WITH RING ABOVE -->
-<!ENTITY uring "&#x0016F;" ><!--LATIN SMALL LETTER U WITH RING ABOVE -->
-<!ENTITY Utilde "&#x00168;" ><!--LATIN CAPITAL LETTER U WITH TILDE -->
-<!ENTITY utilde "&#x00169;" ><!--LATIN SMALL LETTER U WITH TILDE -->
-<!ENTITY Wcirc "&#x00174;" ><!--LATIN CAPITAL LETTER W WITH CIRCUMFLEX -->
-<!ENTITY wcirc "&#x00175;" ><!--LATIN SMALL LETTER W WITH CIRCUMFLEX -->
-<!ENTITY Ycirc "&#x00176;" ><!--LATIN CAPITAL LETTER Y WITH CIRCUMFLEX -->
-<!ENTITY ycirc "&#x00177;" ><!--LATIN SMALL LETTER Y WITH CIRCUMFLEX -->
-<!ENTITY Yuml "&#x00178;" ><!--LATIN CAPITAL LETTER Y WITH DIAERESIS -->
-<!ENTITY Zacute "&#x00179;" ><!--LATIN CAPITAL LETTER Z WITH ACUTE -->
-<!ENTITY zacute "&#x0017A;" ><!--LATIN SMALL LETTER Z WITH ACUTE -->
-<!ENTITY Zcaron "&#x0017D;" ><!--LATIN CAPITAL LETTER Z WITH CARON -->
-<!ENTITY zcaron "&#x0017E;" ><!--LATIN SMALL LETTER Z WITH CARON -->
-<!ENTITY Zdot "&#x0017B;" ><!--LATIN CAPITAL LETTER Z WITH DOT ABOVE -->
-<!ENTITY zdot "&#x0017C;" ><!--LATIN SMALL LETTER Z WITH DOT ABOVE -->
diff --git a/Utilities/xml/docbook-4.5/ent/isonum.ent b/Utilities/xml/docbook-4.5/ent/isonum.ent
deleted file mode 100644
index 884c0c4d0..000000000
--- a/Utilities/xml/docbook-4.5/ent/isonum.ent
+++ /dev/null
@@ -1,117 +0,0 @@
-
-<!--
- File isonum.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isonum.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isonum.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isonum PUBLIC
- "ISO 8879:1986//ENTITIES Numeric and Special Graphic//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isonum.ent"
- >
- %isonum;
-
--->
-
-<!ENTITY amp "&#38;#38;" ><!--AMPERSAND -->
-<!ENTITY apos "&#x00027;" ><!--APOSTROPHE -->
-<!ENTITY ast "&#x0002A;" ><!--ASTERISK -->
-<!ENTITY brvbar "&#x000A6;" ><!--BROKEN BAR -->
-<!ENTITY bsol "&#x0005C;" ><!--REVERSE SOLIDUS -->
-<!ENTITY cent "&#x000A2;" ><!--CENT SIGN -->
-<!ENTITY colon "&#x0003A;" ><!--COLON -->
-<!ENTITY comma "&#x0002C;" ><!--COMMA -->
-<!ENTITY commat "&#x00040;" ><!--COMMERCIAL AT -->
-<!ENTITY copy "&#x000A9;" ><!--COPYRIGHT SIGN -->
-<!ENTITY curren "&#x000A4;" ><!--CURRENCY SIGN -->
-<!ENTITY darr "&#x02193;" ><!--DOWNWARDS ARROW -->
-<!ENTITY deg "&#x000B0;" ><!--DEGREE SIGN -->
-<!ENTITY divide "&#x000F7;" ><!--DIVISION SIGN -->
-<!ENTITY dollar "&#x00024;" ><!--DOLLAR SIGN -->
-<!ENTITY equals "&#x0003D;" ><!--EQUALS SIGN -->
-<!ENTITY excl "&#x00021;" ><!--EXCLAMATION MARK -->
-<!ENTITY frac12 "&#x000BD;" ><!--VULGAR FRACTION ONE HALF -->
-<!ENTITY frac14 "&#x000BC;" ><!--VULGAR FRACTION ONE QUARTER -->
-<!ENTITY frac18 "&#x0215B;" ><!--VULGAR FRACTION ONE EIGHTH -->
-<!ENTITY frac34 "&#x000BE;" ><!--VULGAR FRACTION THREE QUARTERS -->
-<!ENTITY frac38 "&#x0215C;" ><!--VULGAR FRACTION THREE EIGHTHS -->
-<!ENTITY frac58 "&#x0215D;" ><!--VULGAR FRACTION FIVE EIGHTHS -->
-<!ENTITY frac78 "&#x0215E;" ><!--VULGAR FRACTION SEVEN EIGHTHS -->
-<!ENTITY gt "&#x0003E;" ><!--GREATER-THAN SIGN -->
-<!ENTITY half "&#x000BD;" ><!--VULGAR FRACTION ONE HALF -->
-<!ENTITY horbar "&#x02015;" ><!--HORIZONTAL BAR -->
-<!ENTITY hyphen "&#x02010;" ><!--HYPHEN -->
-<!ENTITY iexcl "&#x000A1;" ><!--INVERTED EXCLAMATION MARK -->
-<!ENTITY iquest "&#x000BF;" ><!--INVERTED QUESTION MARK -->
-<!ENTITY laquo "&#x000AB;" ><!--LEFT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-<!ENTITY larr "&#x02190;" ><!--LEFTWARDS ARROW -->
-<!ENTITY lcub "&#x0007B;" ><!--LEFT CURLY BRACKET -->
-<!ENTITY ldquo "&#x0201C;" ><!--LEFT DOUBLE QUOTATION MARK -->
-<!ENTITY lowbar "&#x0005F;" ><!--LOW LINE -->
-<!ENTITY lpar "&#x00028;" ><!--LEFT PARENTHESIS -->
-<!ENTITY lsqb "&#x0005B;" ><!--LEFT SQUARE BRACKET -->
-<!ENTITY lsquo "&#x02018;" ><!--LEFT SINGLE QUOTATION MARK -->
-<!ENTITY lt "&#38;#60;" ><!--LESS-THAN SIGN -->
-<!ENTITY micro "&#x000B5;" ><!--MICRO SIGN -->
-<!ENTITY middot "&#x000B7;" ><!--MIDDLE DOT -->
-<!ENTITY nbsp "&#x000A0;" ><!--NO-BREAK SPACE -->
-<!ENTITY not "&#x000AC;" ><!--NOT SIGN -->
-<!ENTITY num "&#x00023;" ><!--NUMBER SIGN -->
-<!ENTITY ohm "&#x02126;" ><!--OHM SIGN -->
-<!ENTITY ordf "&#x000AA;" ><!--FEMININE ORDINAL INDICATOR -->
-<!ENTITY ordm "&#x000BA;" ><!--MASCULINE ORDINAL INDICATOR -->
-<!ENTITY para "&#x000B6;" ><!--PILCROW SIGN -->
-<!ENTITY percnt "&#x00025;" ><!--PERCENT SIGN -->
-<!ENTITY period "&#x0002E;" ><!--FULL STOP -->
-<!ENTITY plus "&#x0002B;" ><!--PLUS SIGN -->
-<!ENTITY plusmn "&#x000B1;" ><!--PLUS-MINUS SIGN -->
-<!ENTITY pound "&#x000A3;" ><!--POUND SIGN -->
-<!ENTITY quest "&#x0003F;" ><!--QUESTION MARK -->
-<!ENTITY quot "&#x00022;" ><!--QUOTATION MARK -->
-<!ENTITY raquo "&#x000BB;" ><!--RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK -->
-<!ENTITY rarr "&#x02192;" ><!--RIGHTWARDS ARROW -->
-<!ENTITY rcub "&#x0007D;" ><!--RIGHT CURLY BRACKET -->
-<!ENTITY rdquo "&#x0201D;" ><!--RIGHT DOUBLE QUOTATION MARK -->
-<!ENTITY reg "&#x000AE;" ><!--REGISTERED SIGN -->
-<!ENTITY rpar "&#x00029;" ><!--RIGHT PARENTHESIS -->
-<!ENTITY rsqb "&#x0005D;" ><!--RIGHT SQUARE BRACKET -->
-<!ENTITY rsquo "&#x02019;" ><!--RIGHT SINGLE QUOTATION MARK -->
-<!ENTITY sect "&#x000A7;" ><!--SECTION SIGN -->
-<!ENTITY semi "&#x0003B;" ><!--SEMICOLON -->
-<!ENTITY shy "&#x000AD;" ><!--SOFT HYPHEN -->
-<!ENTITY sol "&#x0002F;" ><!--SOLIDUS -->
-<!ENTITY sung "&#x0266A;" ><!--EIGHTH NOTE -->
-<!ENTITY sup1 "&#x000B9;" ><!--SUPERSCRIPT ONE -->
-<!ENTITY sup2 "&#x000B2;" ><!--SUPERSCRIPT TWO -->
-<!ENTITY sup3 "&#x000B3;" ><!--SUPERSCRIPT THREE -->
-<!ENTITY times "&#x000D7;" ><!--MULTIPLICATION SIGN -->
-<!ENTITY trade "&#x02122;" ><!--TRADE MARK SIGN -->
-<!ENTITY uarr "&#x02191;" ><!--UPWARDS ARROW -->
-<!ENTITY verbar "&#x0007C;" ><!--VERTICAL LINE -->
-<!ENTITY yen "&#x000A5;" ><!--YEN SIGN -->
diff --git a/Utilities/xml/docbook-4.5/ent/isopub.ent b/Utilities/xml/docbook-4.5/ent/isopub.ent
deleted file mode 100644
index a11787828..000000000
--- a/Utilities/xml/docbook-4.5/ent/isopub.ent
+++ /dev/null
@@ -1,125 +0,0 @@
-
-<!--
- File isopub.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isopub.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES Publishing//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isopub.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isopub PUBLIC
- "ISO 8879:1986//ENTITIES Publishing//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isopub.ent"
- >
- %isopub;
-
--->
-
-<!ENTITY blank "&#x02423;" ><!--OPEN BOX -->
-<!ENTITY blk12 "&#x02592;" ><!--MEDIUM SHADE -->
-<!ENTITY blk14 "&#x02591;" ><!--LIGHT SHADE -->
-<!ENTITY blk34 "&#x02593;" ><!--DARK SHADE -->
-<!ENTITY block "&#x02588;" ><!--FULL BLOCK -->
-<!ENTITY bull "&#x02022;" ><!--BULLET -->
-<!ENTITY caret "&#x02041;" ><!--CARET INSERTION POINT -->
-<!ENTITY check "&#x02713;" ><!--CHECK MARK -->
-<!ENTITY cir "&#x025CB;" ><!--WHITE CIRCLE -->
-<!ENTITY clubs "&#x02663;" ><!--BLACK CLUB SUIT -->
-<!ENTITY copysr "&#x02117;" ><!--SOUND RECORDING COPYRIGHT -->
-<!ENTITY cross "&#x02717;" ><!--BALLOT X -->
-<!ENTITY Dagger "&#x02021;" ><!--DOUBLE DAGGER -->
-<!ENTITY dagger "&#x02020;" ><!--DAGGER -->
-<!ENTITY dash "&#x02010;" ><!--HYPHEN -->
-<!ENTITY diams "&#x02666;" ><!--BLACK DIAMOND SUIT -->
-<!ENTITY dlcrop "&#x0230D;" ><!--BOTTOM LEFT CROP -->
-<!ENTITY drcrop "&#x0230C;" ><!--BOTTOM RIGHT CROP -->
-<!ENTITY dtri "&#x025BF;" ><!--WHITE DOWN-POINTING SMALL TRIANGLE -->
-<!ENTITY dtrif "&#x025BE;" ><!--BLACK DOWN-POINTING SMALL TRIANGLE -->
-<!ENTITY emsp "&#x02003;" ><!--EM SPACE -->
-<!ENTITY emsp13 "&#x02004;" ><!--THREE-PER-EM SPACE -->
-<!ENTITY emsp14 "&#x02005;" ><!--FOUR-PER-EM SPACE -->
-<!ENTITY ensp "&#x02002;" ><!--EN SPACE -->
-<!ENTITY female "&#x02640;" ><!--FEMALE SIGN -->
-<!ENTITY ffilig "&#x0FB03;" ><!--LATIN SMALL LIGATURE FFI -->
-<!ENTITY fflig "&#x0FB00;" ><!--LATIN SMALL LIGATURE FF -->
-<!ENTITY ffllig "&#x0FB04;" ><!--LATIN SMALL LIGATURE FFL -->
-<!ENTITY filig "&#x0FB01;" ><!--LATIN SMALL LIGATURE FI -->
-<!ENTITY flat "&#x0266D;" ><!--MUSIC FLAT SIGN -->
-<!ENTITY fllig "&#x0FB02;" ><!--LATIN SMALL LIGATURE FL -->
-<!ENTITY frac13 "&#x02153;" ><!--VULGAR FRACTION ONE THIRD -->
-<!ENTITY frac15 "&#x02155;" ><!--VULGAR FRACTION ONE FIFTH -->
-<!ENTITY frac16 "&#x02159;" ><!--VULGAR FRACTION ONE SIXTH -->
-<!ENTITY frac23 "&#x02154;" ><!--VULGAR FRACTION TWO THIRDS -->
-<!ENTITY frac25 "&#x02156;" ><!--VULGAR FRACTION TWO FIFTHS -->
-<!ENTITY frac35 "&#x02157;" ><!--VULGAR FRACTION THREE FIFTHS -->
-<!ENTITY frac45 "&#x02158;" ><!--VULGAR FRACTION FOUR FIFTHS -->
-<!ENTITY frac56 "&#x0215A;" ><!--VULGAR FRACTION FIVE SIXTHS -->
-<!ENTITY hairsp "&#x0200A;" ><!--HAIR SPACE -->
-<!ENTITY hearts "&#x02665;" ><!--BLACK HEART SUIT -->
-<!ENTITY hellip "&#x02026;" ><!--HORIZONTAL ELLIPSIS -->
-<!ENTITY hybull "&#x02043;" ><!--HYPHEN BULLET -->
-<!ENTITY incare "&#x02105;" ><!--CARE OF -->
-<!ENTITY ldquor "&#x0201E;" ><!--DOUBLE LOW-9 QUOTATION MARK -->
-<!ENTITY lhblk "&#x02584;" ><!--LOWER HALF BLOCK -->
-<!ENTITY loz "&#x025CA;" ><!--LOZENGE -->
-<!ENTITY lozf "&#x029EB;" ><!--BLACK LOZENGE -->
-<!ENTITY lsquor "&#x0201A;" ><!--SINGLE LOW-9 QUOTATION MARK -->
-<!ENTITY ltri "&#x025C3;" ><!--WHITE LEFT-POINTING SMALL TRIANGLE -->
-<!ENTITY ltrif "&#x025C2;" ><!--BLACK LEFT-POINTING SMALL TRIANGLE -->
-<!ENTITY male "&#x02642;" ><!--MALE SIGN -->
-<!ENTITY malt "&#x02720;" ><!--MALTESE CROSS -->
-<!ENTITY marker "&#x025AE;" ><!--BLACK VERTICAL RECTANGLE -->
-<!ENTITY mdash "&#x02014;" ><!--EM DASH -->
-<!ENTITY mldr "&#x02026;" ><!--HORIZONTAL ELLIPSIS -->
-<!ENTITY natur "&#x0266E;" ><!--MUSIC NATURAL SIGN -->
-<!ENTITY ndash "&#x02013;" ><!--EN DASH -->
-<!ENTITY nldr "&#x02025;" ><!--TWO DOT LEADER -->
-<!ENTITY numsp "&#x02007;" ><!--FIGURE SPACE -->
-<!ENTITY phone "&#x0260E;" ><!--BLACK TELEPHONE -->
-<!ENTITY puncsp "&#x02008;" ><!--PUNCTUATION SPACE -->
-<!ENTITY rdquor "&#x0201D;" ><!--RIGHT DOUBLE QUOTATION MARK -->
-<!ENTITY rect "&#x025AD;" ><!--WHITE RECTANGLE -->
-<!ENTITY rsquor "&#x02019;" ><!--RIGHT SINGLE QUOTATION MARK -->
-<!ENTITY rtri "&#x025B9;" ><!--WHITE RIGHT-POINTING SMALL TRIANGLE -->
-<!ENTITY rtrif "&#x025B8;" ><!--BLACK RIGHT-POINTING SMALL TRIANGLE -->
-<!ENTITY rx "&#x0211E;" ><!--PRESCRIPTION TAKE -->
-<!ENTITY sext "&#x02736;" ><!--SIX POINTED BLACK STAR -->
-<!ENTITY sharp "&#x0266F;" ><!--MUSIC SHARP SIGN -->
-<!ENTITY spades "&#x02660;" ><!--BLACK SPADE SUIT -->
-<!ENTITY squ "&#x025A1;" ><!--WHITE SQUARE -->
-<!ENTITY squf "&#x025AA;" ><!--BLACK SMALL SQUARE -->
-<!ENTITY star "&#x02606;" ><!--WHITE STAR -->
-<!ENTITY starf "&#x02605;" ><!--BLACK STAR -->
-<!ENTITY target "&#x02316;" ><!--POSITION INDICATOR -->
-<!ENTITY telrec "&#x02315;" ><!--TELEPHONE RECORDER -->
-<!ENTITY thinsp "&#x02009;" ><!--THIN SPACE -->
-<!ENTITY uhblk "&#x02580;" ><!--UPPER HALF BLOCK -->
-<!ENTITY ulcrop "&#x0230F;" ><!--TOP LEFT CROP -->
-<!ENTITY urcrop "&#x0230E;" ><!--TOP RIGHT CROP -->
-<!ENTITY utri "&#x025B5;" ><!--WHITE UP-POINTING SMALL TRIANGLE -->
-<!ENTITY utrif "&#x025B4;" ><!--BLACK UP-POINTING SMALL TRIANGLE -->
-<!ENTITY vellip "&#x022EE;" ><!--VERTICAL ELLIPSIS -->
diff --git a/Utilities/xml/docbook-4.5/ent/isotech.ent b/Utilities/xml/docbook-4.5/ent/isotech.ent
deleted file mode 100644
index 07e81008d..000000000
--- a/Utilities/xml/docbook-4.5/ent/isotech.ent
+++ /dev/null
@@ -1,103 +0,0 @@
-
-<!--
- File isotech.ent produced by the XSL script entities.xsl
- from input data in unicode.xml.
-
- Please report any errors to David Carlisle
- via the public W3C list www-math@w3.org.
-
- The numeric character values assigned to each entity
- (should) match the Unicode assignments in Unicode 4.0.
-
- Entity names in this file are derived from files carrying the
- following notice:
-
- (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
-
--->
-
-
-<!--
- Version: $Id: isotech.ent,v 1.2 2003/12/08 15:14:43 davidc Exp $
-
- Public identifier: ISO 8879:1986//ENTITIES General Technical//EN//XML
- System identifier: http://www.w3.org/2003/entities/iso8879/isotech.ent
-
- The public identifier should always be used verbatim.
- The system identifier may be changed to suit local requirements.
-
- Typical invocation:
-
- <!ENTITY % isotech PUBLIC
- "ISO 8879:1986//ENTITIES General Technical//EN//XML"
- "http://www.w3.org/2003/entities/iso8879/isotech.ent"
- >
- %isotech;
-
--->
-
-<!ENTITY aleph "&#x02135;" ><!--ALEF SYMBOL -->
-<!ENTITY and "&#x02227;" ><!--LOGICAL AND -->
-<!ENTITY ang90 "&#x0221F;" ><!--RIGHT ANGLE -->
-<!ENTITY angsph "&#x02222;" ><!--SPHERICAL ANGLE -->
-<!ENTITY angst "&#x0212B;" ><!--ANGSTROM SIGN -->
-<!ENTITY ap "&#x02248;" ><!--ALMOST EQUAL TO -->
-<!ENTITY becaus "&#x02235;" ><!--BECAUSE -->
-<!ENTITY bernou "&#x0212C;" ><!--SCRIPT CAPITAL B -->
-<!ENTITY bottom "&#x022A5;" ><!--UP TACK -->
-<!ENTITY cap "&#x02229;" ><!--INTERSECTION -->
-<!ENTITY compfn "&#x02218;" ><!--RING OPERATOR -->
-<!ENTITY cong "&#x02245;" ><!--APPROXIMATELY EQUAL TO -->
-<!ENTITY conint "&#x0222E;" ><!--CONTOUR INTEGRAL -->
-<!ENTITY cup "&#x0222A;" ><!--UNION -->
-<!ENTITY Dot "&#x000A8;" ><!--DIAERESIS -->
-<!ENTITY DotDot " &#x020DC;" ><!--COMBINING FOUR DOTS ABOVE -->
-<!ENTITY equiv "&#x02261;" ><!--IDENTICAL TO -->
-<!ENTITY exist "&#x02203;" ><!--THERE EXISTS -->
-<!ENTITY fnof "&#x00192;" ><!--LATIN SMALL LETTER F WITH HOOK -->
-<!ENTITY forall "&#x02200;" ><!--FOR ALL -->
-<!ENTITY ge "&#x02265;" ><!--GREATER-THAN OR EQUAL TO -->
-<!ENTITY hamilt "&#x0210B;" ><!--SCRIPT CAPITAL H -->
-<!ENTITY iff "&#x021D4;" ><!--LEFT RIGHT DOUBLE ARROW -->
-<!ENTITY infin "&#x0221E;" ><!--INFINITY -->
-<!ENTITY int "&#x0222B;" ><!--INTEGRAL -->
-<!ENTITY isin "&#x02208;" ><!--ELEMENT OF -->
-<!ENTITY lagran "&#x02112;" ><!--SCRIPT CAPITAL L -->
-<!ENTITY lang "&#x02329;" ><!--LEFT-POINTING ANGLE BRACKET -->
-<!ENTITY lArr "&#x021D0;" ><!--LEFTWARDS DOUBLE ARROW -->
-<!ENTITY le "&#x02264;" ><!--LESS-THAN OR EQUAL TO -->
-<!ENTITY lowast "&#x02217;" ><!--ASTERISK OPERATOR -->
-<!ENTITY minus "&#x02212;" ><!--MINUS SIGN -->
-<!ENTITY mnplus "&#x02213;" ><!--MINUS-OR-PLUS SIGN -->
-<!ENTITY nabla "&#x02207;" ><!--NABLA -->
-<!ENTITY ne "&#x02260;" ><!--NOT EQUAL TO -->
-<!ENTITY ni "&#x0220B;" ><!--CONTAINS AS MEMBER -->
-<!ENTITY notin "&#x02209;" ><!--NOT AN ELEMENT OF -->
-<!ENTITY or "&#x02228;" ><!--LOGICAL OR -->
-<!ENTITY order "&#x02134;" ><!--SCRIPT SMALL O -->
-<!ENTITY par "&#x02225;" ><!--PARALLEL TO -->
-<!ENTITY part "&#x02202;" ><!--PARTIAL DIFFERENTIAL -->
-<!ENTITY permil "&#x02030;" ><!--PER MILLE SIGN -->
-<!ENTITY perp "&#x022A5;" ><!--UP TACK -->
-<!ENTITY phmmat "&#x02133;" ><!--SCRIPT CAPITAL M -->
-<!ENTITY Prime "&#x02033;" ><!--DOUBLE PRIME -->
-<!ENTITY prime "&#x02032;" ><!--PRIME -->
-<!ENTITY prop "&#x0221D;" ><!--PROPORTIONAL TO -->
-<!ENTITY radic "&#x0221A;" ><!--SQUARE ROOT -->
-<!ENTITY rang "&#x0232A;" ><!--RIGHT-POINTING ANGLE BRACKET -->
-<!ENTITY rArr "&#x021D2;" ><!--RIGHTWARDS DOUBLE ARROW -->
-<!ENTITY sim "&#x0223C;" ><!--TILDE OPERATOR -->
-<!ENTITY sime "&#x02243;" ><!--ASYMPTOTICALLY EQUAL TO -->
-<!ENTITY square "&#x025A1;" ><!--WHITE SQUARE -->
-<!ENTITY sub "&#x02282;" ><!--SUBSET OF -->
-<!ENTITY sube "&#x02286;" ><!--SUBSET OF OR EQUAL TO -->
-<!ENTITY sup "&#x02283;" ><!--SUPERSET OF -->
-<!ENTITY supe "&#x02287;" ><!--SUPERSET OF OR EQUAL TO -->
-<!ENTITY tdot " &#x020DB;" ><!--COMBINING THREE DOTS ABOVE -->
-<!ENTITY there4 "&#x02234;" ><!--THEREFORE -->
-<!ENTITY tprime "&#x02034;" ><!--TRIPLE PRIME -->
-<!ENTITY Verbar "&#x02016;" ><!--DOUBLE VERTICAL LINE -->
-<!ENTITY wedgeq "&#x02259;" ><!--ESTIMATES -->
diff --git a/Utilities/xml/docbook-4.5/htmltblx.mod b/Utilities/xml/docbook-4.5/htmltblx.mod
deleted file mode 100644
index cdaefed41..000000000
--- a/Utilities/xml/docbook-4.5/htmltblx.mod
+++ /dev/null
@@ -1,245 +0,0 @@
-<!-- ...................................................................... -->
-<!-- DocBook XML HTML Table Module V4.5 ................................... -->
-<!-- File htmltblx.mod .................................................... -->
-
-<!-- Copyright 2003-2006 ArborText, Inc., Norman Walsh, Sun Microsystems,
- Inc., and the Organization for the Advancement of Structured Information
- Standards (OASIS).
-
- $Id: htmltblx.mod 6340 2006-10-03 13:23:24Z nwalsh $
-
- Permission to use, copy, modify and distribute the DocBook XML DTD
- and its accompanying documentation for any purpose and without fee
- is hereby granted in perpetuity, provided that the above copyright
- notice and this paragraph appear in all copies. The copyright
- holders make no representation about the suitability of the DTD for
- any purpose. It is provided "as is" without expressed or implied
- warranty.
-
- If you modify the DocBook XML DTD in any way, except for declaring and
- referencing additional sets of general entities and declaring
- additional notations, label your DTD as a variant of DocBook. See
- the maintenance documentation for more information.
-
- Please direct all questions, bug reports, or suggestions for
- changes to the docbook@lists.oasis-open.org mailing list. For more
- information, see http://www.oasis-open.org/docbook/.
--->
-
-<!-- ...................................................................... -->
-
-<!-- This module contains the definitions for elements that are
- isomorphic to the HTML elements. One could argue we should
- instead have based ourselves on the XHTML Table Module, but the
- HTML one is more like what browsers are likely to accept today
- and users are likely to use.
-
- This module has been developed for use with the DocBook V4.5
- "union table model" in which elements and attlists common to both
- models are defined (as the union) in the CALS table module by
- setting various parameter entities appropriately in this file.
-
- In DTD driver files referring to this module, please use an entity
- declaration that uses the public identifier shown below:
-
- <!ENTITY % htmltbl PUBLIC
- "-//OASIS//ELEMENTS DocBook XML HTML Tables V4.5//EN"
- "htmltblx.mod">
- %htmltbl;
-
- See the documentation for detailed information on the parameter
- entity and module scheme used in DocBook, customizing DocBook and
- planning for interchange, and changes made since the last release
- of DocBook.
--->
-
-<!--======================= XHTML Tables =======================================-->
-
-<!ENTITY % html.coreattrs
- "%common.attrib;
- class CDATA #IMPLIED
- style CDATA #IMPLIED
- title CDATA #IMPLIED"
- >
-
-<!-- Does not contain lang or dir because they are in %common.attribs -->
-<![%sgml.features;[
-<!ENTITY % i18n "">
-]]>
-<!ENTITY % i18n
- "xml:lang NMTOKEN #IMPLIED"
- >
-
-<!ENTITY % events
- "onclick CDATA #IMPLIED
- ondblclick CDATA #IMPLIED
- onmousedown CDATA #IMPLIED
- onmouseup CDATA #IMPLIED
- onmouseover CDATA #IMPLIED
- onmousemove CDATA #IMPLIED
- onmouseout CDATA #IMPLIED
- onkeypress CDATA #IMPLIED
- onkeydown CDATA #IMPLIED
- onkeyup CDATA #IMPLIED"
- >
-
-<!ENTITY % attrs "%html.coreattrs; %i18n; %events;">
-
-<!ENTITY % cellhalign
- "align (left|center|right|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff CDATA #IMPLIED"
- >
-
-<!ENTITY % cellvalign
- "valign (top|middle|bottom|baseline) #IMPLIED"
- >
-
-<!--doc:A group of columns in an HTML table.-->
-<!ELEMENT colgroup %ho; (col)*>
-<!--doc:Specifications for a column in an HTML table.-->
-<!ELEMENT col %ho; EMPTY>
-<!--doc:A row in an HTML table.-->
-<!ELEMENT tr %ho; (th|td)+>
-<!--doc:A table header entry in an HTML table.-->
-<!ELEMENT th %ho; (%para.char.mix; | %tabentry.mix; | table | informaltable)*>
-<!--doc:A table ntry in an HTML table.-->
-<!ELEMENT td %ho; (%para.char.mix; | %tabentry.mix; | table | informaltable)*>
-
-<!ATTLIST colgroup
- %attrs;
- span CDATA "1"
- width CDATA #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST col
- %attrs;
- span CDATA "1"
- width CDATA #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tr
- %attrs;
- %cellhalign;
- %cellvalign;
- bgcolor CDATA #IMPLIED
- >
-
-<!ATTLIST th
- %attrs;
- abbr CDATA #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope (row|col|rowgroup|colgroup) #IMPLIED
- rowspan CDATA "1"
- colspan CDATA "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor CDATA #IMPLIED
- width CDATA #IMPLIED
- height CDATA #IMPLIED
- >
-
-<!ATTLIST td
- %attrs;
- abbr CDATA #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope (row|col|rowgroup|colgroup) #IMPLIED
- rowspan CDATA "1"
- colspan CDATA "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor CDATA #IMPLIED
- width CDATA #IMPLIED
- height CDATA #IMPLIED
- >
-
-<!-- ====================================================== -->
-<!-- Set up to read in the CALS model configured to
- merge with the XHTML table model -->
-<!-- ====================================================== -->
-
-<!ENTITY % tables.role.attrib "%role.attrib;">
-
-<!-- Add label and role attributes to table and informaltable -->
-<!ENTITY % bodyatt "
- floatstyle CDATA #IMPLIED
- rowheader (firstcol|norowheader) #IMPLIED
- %label.attrib;"
->
-
-<!-- Add common attributes to Table, TGroup, TBody, THead, TFoot, Row,
- EntryTbl, and Entry (and InformalTable element). -->
-
-<!ENTITY % secur "
- %common.attrib;
- class CDATA #IMPLIED
- style CDATA #IMPLIED
- title CDATA #IMPLIED
- %i18n;
- %events;
- %tables.role.attrib;">
-
-<!ENTITY % common.table.attribs
- "%bodyatt;
- %secur;">
-
-<!-- Content model for Table (that also allows HTML tables) -->
-<!ENTITY % tbl.table.mdl
- "((blockinfo?,
- (%formalobject.title.content;),
- (%ndxterm.class;)*,
- textobject*,
- (graphic+|mediaobject+|tgroup+))
- |(caption, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+)))">
-
-<!ENTITY % informal.tbl.table.mdl
- "(textobject*,
- (graphic+|mediaobject+|tgroup+))
- | ((col*|colgroup*), thead?, tfoot?, (tbody+|tr+))">
-
-<!-- Attributes for Table (including HTML ones) -->
-
-<!-- N.B. rules = (none | groups | rows | cols | all) but it can't be spec'd -->
-<!-- that way because 'all' already occurs in a different enumeration in -->
-<!-- CALS tables (frame). -->
-
-<!ENTITY % tbl.table.att '
- tabstyle CDATA #IMPLIED
- tocentry %yesorno.attvals; #IMPLIED
- shortentry %yesorno.attvals; #IMPLIED
- orient (port|land) #IMPLIED
- pgwide %yesorno.attvals; #IMPLIED
- summary CDATA #IMPLIED
- width CDATA #IMPLIED
- border CDATA #IMPLIED
- rules CDATA #IMPLIED
- cellspacing CDATA #IMPLIED
- cellpadding CDATA #IMPLIED
- align (left|center|right) #IMPLIED
- bgcolor CDATA #IMPLIED
-'>
-
-<!ENTITY % tbl.frame.attval "void|above|below|hsides|lhs|rhs|vsides|box|border|
-top|bottom|topbot|all|sides|none">
-
-<!-- Allow either objects or inlines; beware of REs between elements. -->
-<!ENTITY % tbl.entry.mdl "%para.char.mix; | %tabentry.mix;">
-
-<!-- thead, tfoot, and tbody are defined in both table models,
- so we set up parameter entities to define union models for them
- -->
-
-<!ENTITY % tbl.hdft.mdl "(tr+|(colspec*,row+))">
-<!ENTITY % tbl.tbody.mdl "(tr+|row+)">
-<!ENTITY % tbl.valign.attval "top|middle|bottom|baseline">
-
-<!-- End of DocBook XML HTML Table Module V4.5 ............................ -->
-<!-- ...................................................................... -->
diff --git a/Utilities/xml/docbook-4.5/soextblx.dtd b/Utilities/xml/docbook-4.5/soextblx.dtd
deleted file mode 100644
index 4a92e1162..000000000
--- a/Utilities/xml/docbook-4.5/soextblx.dtd
+++ /dev/null
@@ -1,321 +0,0 @@
-<!-- XML EXCHANGE TABLE MODEL DECLARATION MODULE -->
-
-<!-- This set of declarations defines the XML version of the Exchange
- Table Model as of the date shown in the Formal Public Identifier
- (FPI) for this entity.
-
- This set of declarations may be referred to using a public external
- entity declaration and reference as shown in the following three
- lines:
-
- <!ENTITY % calstblx
- PUBLIC "-//OASIS//DTD XML Exchange Table Model 19990315//EN">
- %calstblx;
-
- If various parameter entities used within this set of declarations
- are to be given non-default values, the appropriate declarations
- should be given before calling in this package (i.e., before the
- "%calstblx;" reference).
--->
-
-<!-- The motivation for this XML version of the Exchange Table Model
- is simply to create an XML version of the SGML Exchange Table
- Model. By design, no effort has been made to "improve" the model.
-
- This XML version incorporates the logical bare minimum changes
- necessary to make the Exchange Table Model a valid XML DTD.
-
- It has been modified slightly for use in the combined HTML/CALS models
- supported by DocBook V4.3 and later.
--->
-
-<!-- The XML version of the Exchange Table Model differs from
- the SGML version in the following ways:
-
- The following parameter entities have been removed:
-
- - tbl.table.excep, tbl.hdft.excep, tbl.row.excep, tbl.entry.excep
- There are no exceptions in XML. The following normative statement
- is made in lieu of exceptions: the exchange table model explicitly
- forbids a table from occurring within another table. If the
- content model of an entry includes a table element, then this
- cannot be enforced by the DTD, but it is a deviation from the
- exchange table model to include a table within a table.
-
- - tbl.hdft.name, tbl.hdft.mdl, tbl.hdft.excep, tbl.hdft.att
- The motivation for these elements was to change the table
- header/footer elements. Since XML does not allow element declarations
- to contain name groups, and the exchange table model does not
- allow a table to contain footers, the continued presence of these
- attributes seems unnecessary.
-
- The following parameter entity has been added:
-
- - tbl.thead.att
- This entity parameterizes the attributes on thead. It replaces
- the tbl.hdft.att parameter entity.
-
- Other miscellaneous changes:
-
- - Tag ommission indicators have been removed
- - Comments have been removed from declarations
- - NUMBER attributes have been changed to NMTOKEN
- - NUTOKEN attributes have been to changed to NMTOKEN
- - Removed the grouping characters around the content model
- parameter entry for the 'entry' element. This is necessary
- so that an entry can contain #PCDATA and be defined as an
- optional, repeatable OR group beginning with #PCDATA.
--->
-
-<!-- This entity includes a set of element and attribute declarations
- that partially defines the Exchange table model. However, the model
- is not well-defined without the accompanying natural language
- description of the semantics (meanings) of these various elements,
- attributes, and attribute values. The semantic writeup, also available
- from SGML Open, should be used in conjunction with this entity.
--->
-
-<!-- In order to use the Exchange table model, various parameter entity
- declarations are required. A brief description is as follows:
-
- ENTITY NAME WHERE USED WHAT IT IS
-
- %yesorno In ATTLIST of: An attribute declared value
- almost all elements for a "boolean" attribute
-
- %paracon In content model of: The "text" (logical content)
- <entry> of the model group for <entry>
-
- %titles In content model of: The "title" part of the model
- table element group for the table element
-
- %tbl.table.name In declaration of: The name of the "table"
- table element element
-
- %tbl.table-titles.mdl In content model of: The model group for the title
- table elements part of the content model for
- table element
-
- %tbl.table.mdl In content model of: The model group for the content
- table elements model for table element,
- often (and by default) defined
- in terms of %tbl.table-titles.mdl
- and tgroup
-
- %tbl.table.att In ATTLIST of: Additional attributes on the
- table element table element
-
- %bodyatt In ATTLIST of: Additional attributes on the
- table element table element (for backward
- compatibility with the SGML
- model)
-
- %tbl.tgroup.mdl In content model of: The model group for the content
- <tgroup> model for <tgroup>
-
- %tbl.tgroup.att In ATTLIST of: Additional attributes on the
- <tgroup> <tgroup> element
-
- %tbl.thead.att In ATTLIST of: Additional attributes on the
- <thead> <thead> element
-
- %tbl.tbody.att In ATTLIST of: Additional attributes on the
- <tbody> <tbody> element
-
- %tbl.colspec.att In ATTLIST of: Additional attributes on the
- <colspec> <colspec> element
-
- %tbl.row.mdl In content model of: The model group for the content
- <row> model for <row>
-
- %tbl.row.att In ATTLIST of: Additional attributes on the
- <row> <row> element
-
- %tbl.entry.mdl In content model of: The model group for the content
- <entry> model for <entry>
-
- %tbl.entry.att In ATTLIST of: Additional attributes on the
- <entry> <entry> element
-
- This set of declarations will use the default definitions shown below
- for any of these parameter entities that are not declared before this
- set of declarations is referenced.
--->
-
-<!-- These definitions are not directly related to the table model, but are
- used in the default CALS table model and may be defined elsewhere (and
- prior to the inclusion of this table module) in the referencing DTD. -->
-
-<!ENTITY % yesorno 'NMTOKEN'> <!-- no if zero(s), yes if any other value -->
-<!ENTITY % titles 'title?'>
-<!ENTITY % pcd "#PCDATA">
-<!ENTITY % paracon '%pcd;'> <!-- default for use in entry content -->
-
-<!--
-The parameter entities as defined below change and simplify the CALS table
-model as published (as part of the Example DTD) in MIL-HDBK-28001. The
-resulting simplified DTD has support from the SGML Open vendors and is
-therefore more interoperable among different systems.
-
-These following declarations provide the Exchange default definitions
-for these entities. However, these entities can be redefined (by giving
-the appropriate parameter entity declaration(s) prior to the reference
-to this Table Model declaration set entity) to fit the needs of the
-current application.
-
-Note, however, that changes may have significant effect on the ability to
-interchange table information. These changes may manifest themselves
-in useability, presentation, and possible structure information degradation.
--->
-
-<!ENTITY % tbl.table.name "table">
-<!ENTITY % tbl.table-titles.mdl "%titles;,">
-<!ENTITY % tbl.table-main.mdl "tgroup+">
-<!ENTITY % tbl.table.mdl "%tbl.table-titles.mdl; %tbl.table-main.mdl;">
-<!ENTITY % tbl.table.att "
- pgwide %yesorno; #IMPLIED ">
-<!ENTITY % bodyatt "">
-<!ENTITY % tbl.tgroup.mdl "colspec*,thead?,tbody">
-<!ENTITY % tbl.tgroup.att "">
-<!ENTITY % tbl.thead.att "">
-<!ENTITY % tbl.tbody.att "">
-<!ENTITY % tbl.colspec.att "">
-<!ENTITY % tbl.row.mdl "entry+">
-<!ENTITY % tbl.row.att "">
-<!ENTITY % tbl.entry.mdl "(%paracon;)*">
-<!ENTITY % tbl.entry.att "">
-
-<!ENTITY % tbl.frame.attval "top|bottom|topbot|all|sides|none">
-<!ENTITY % tbl.tbody.mdl "row+">
-
-<!-- ===== Element and attribute declarations follow. ===== -->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.table.name "table"
- ENTITY % tbl.table-titles.mdl "%titles;,"
- ENTITY % tbl.table.mdl "%tbl.table-titles; tgroup+"
- ENTITY % tbl.table.att "
- pgwide %yesorno; #IMPLIED "
--->
-
-<!--doc:???-->
-<!ELEMENT %tbl.table.name; (%tbl.table.mdl;)>
-
-<!ATTLIST %tbl.table.name;
- frame (%tbl.frame.attval;) #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- %tbl.table.att;
- %bodyatt;
->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.tgroup.mdl "colspec*,thead?,tbody"
- ENTITY % tbl.tgroup.att ""
--->
-
-<!--doc:A wrapper for the main content of a table, or part of a table.-->
-<!ELEMENT tgroup (%tbl.tgroup.mdl;) >
-
-<!ATTLIST tgroup
- cols NMTOKEN #REQUIRED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- %tbl.tgroup.att;
->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.colspec.att ""
--->
-
-<!--doc:Specifications for a column in a table.-->
-<!ELEMENT colspec EMPTY >
-
-<!ATTLIST colspec
- colnum NMTOKEN #IMPLIED
- colname NMTOKEN #IMPLIED
- colwidth CDATA #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff NMTOKEN #IMPLIED
- %tbl.colspec.att;
->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.thead.att ""
--->
-
-<!--doc:A table header consisting of one or more rows.-->
-<!ELEMENT thead (row+)>
-
-<!ATTLIST thead
- valign (top|middle|bottom) #IMPLIED
- %tbl.thead.att;
->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.tbody.att ""
--->
-
-<!--doc:A wrapper for the rows of a table or informal table.-->
-<!ELEMENT tbody (%tbl.tbody.mdl;)>
-
-<!ATTLIST tbody
- valign (top|middle|bottom) #IMPLIED
- %tbl.tbody.att;
->
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % tbl.row.mdl "entry+"
- ENTITY % tbl.row.att ""
--->
-
-<!--doc:A row in a table.-->
-<!ELEMENT row (%tbl.row.mdl;)>
-
-<!ATTLIST row
- rowsep %yesorno; #IMPLIED
- valign (top|middle|bottom) #IMPLIED
- %tbl.row.att;
->
-
-
-<!--
- Default declarations previously defined in this entity and
- referenced below include:
- ENTITY % paracon "#PCDATA"
- ENTITY % tbl.entry.mdl "(%paracon;)*"
- ENTITY % tbl.entry.att ""
--->
-
-<!--doc:A cell in a table.-->
-<!ELEMENT entry (%tbl.entry.mdl;)*>
-
-<!ATTLIST entry
- colname NMTOKEN #IMPLIED
- namest NMTOKEN #IMPLIED
- nameend NMTOKEN #IMPLIED
- morerows NMTOKEN #IMPLIED
- colsep %yesorno; #IMPLIED
- rowsep %yesorno; #IMPLIED
- align (left|right|center|justify|char) #IMPLIED
- char CDATA #IMPLIED
- charoff NMTOKEN #IMPLIED
- valign (top|middle|bottom) #IMPLIED
- %tbl.entry.att;
->
diff --git a/Utilities/xml/xhtml1/xhtml-lat1.ent b/Utilities/xml/xhtml1/xhtml-lat1.ent
deleted file mode 100644
index ffee223eb..000000000
--- a/Utilities/xml/xhtml1/xhtml-lat1.ent
+++ /dev/null
@@ -1,196 +0,0 @@
-<!-- Portions (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
--->
-<!-- Character entity set. Typical invocation:
- <!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
- %HTMLlat1;
--->
-
-<!ENTITY nbsp "&#160;"> <!-- no-break space = non-breaking space,
- U+00A0 ISOnum -->
-<!ENTITY iexcl "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
-<!ENTITY cent "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
-<!ENTITY pound "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
-<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
-<!ENTITY yen "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
-<!ENTITY brvbar "&#166;"> <!-- broken bar = broken vertical bar,
- U+00A6 ISOnum -->
-<!ENTITY sect "&#167;"> <!-- section sign, U+00A7 ISOnum -->
-<!ENTITY uml "&#168;"> <!-- diaeresis = spacing diaeresis,
- U+00A8 ISOdia -->
-<!ENTITY copy "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
-<!ENTITY ordf "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
-<!ENTITY laquo "&#171;"> <!-- left-pointing double angle quotation mark
- = left pointing guillemet, U+00AB ISOnum -->
-<!ENTITY not "&#172;"> <!-- not sign = angled dash,
- U+00AC ISOnum -->
-<!ENTITY shy "&#173;"> <!-- soft hyphen = discretionary hyphen,
- U+00AD ISOnum -->
-<!ENTITY reg "&#174;"> <!-- registered sign = registered trade mark sign,
- U+00AE ISOnum -->
-<!ENTITY macr "&#175;"> <!-- macron = spacing macron = overline
- = APL overbar, U+00AF ISOdia -->
-<!ENTITY deg "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
-<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign,
- U+00B1 ISOnum -->
-<!ENTITY sup2 "&#178;"> <!-- superscript two = superscript digit two
- = squared, U+00B2 ISOnum -->
-<!ENTITY sup3 "&#179;"> <!-- superscript three = superscript digit three
- = cubed, U+00B3 ISOnum -->
-<!ENTITY acute "&#180;"> <!-- acute accent = spacing acute,
- U+00B4 ISOdia -->
-<!ENTITY micro "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
-<!ENTITY para "&#182;"> <!-- pilcrow sign = paragraph sign,
- U+00B6 ISOnum -->
-<!ENTITY middot "&#183;"> <!-- middle dot = Georgian comma
- = Greek middle dot, U+00B7 ISOnum -->
-<!ENTITY cedil "&#184;"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
-<!ENTITY sup1 "&#185;"> <!-- superscript one = superscript digit one,
- U+00B9 ISOnum -->
-<!ENTITY ordm "&#186;"> <!-- masculine ordinal indicator,
- U+00BA ISOnum -->
-<!ENTITY raquo "&#187;"> <!-- right-pointing double angle quotation mark
- = right pointing guillemet, U+00BB ISOnum -->
-<!ENTITY frac14 "&#188;"> <!-- vulgar fraction one quarter
- = fraction one quarter, U+00BC ISOnum -->
-<!ENTITY frac12 "&#189;"> <!-- vulgar fraction one half
- = fraction one half, U+00BD ISOnum -->
-<!ENTITY frac34 "&#190;"> <!-- vulgar fraction three quarters
- = fraction three quarters, U+00BE ISOnum -->
-<!ENTITY iquest "&#191;"> <!-- inverted question mark
- = turned question mark, U+00BF ISOnum -->
-<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave
- = latin capital letter A grave,
- U+00C0 ISOlat1 -->
-<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute,
- U+00C1 ISOlat1 -->
-<!ENTITY Acirc "&#194;"> <!-- latin capital letter A with circumflex,
- U+00C2 ISOlat1 -->
-<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde,
- U+00C3 ISOlat1 -->
-<!ENTITY Auml "&#196;"> <!-- latin capital letter A with diaeresis,
- U+00C4 ISOlat1 -->
-<!ENTITY Aring "&#197;"> <!-- latin capital letter A with ring above
- = latin capital letter A ring,
- U+00C5 ISOlat1 -->
-<!ENTITY AElig "&#198;"> <!-- latin capital letter AE
- = latin capital ligature AE,
- U+00C6 ISOlat1 -->
-<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla,
- U+00C7 ISOlat1 -->
-<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave,
- U+00C8 ISOlat1 -->
-<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute,
- U+00C9 ISOlat1 -->
-<!ENTITY Ecirc "&#202;"> <!-- latin capital letter E with circumflex,
- U+00CA ISOlat1 -->
-<!ENTITY Euml "&#203;"> <!-- latin capital letter E with diaeresis,
- U+00CB ISOlat1 -->
-<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave,
- U+00CC ISOlat1 -->
-<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute,
- U+00CD ISOlat1 -->
-<!ENTITY Icirc "&#206;"> <!-- latin capital letter I with circumflex,
- U+00CE ISOlat1 -->
-<!ENTITY Iuml "&#207;"> <!-- latin capital letter I with diaeresis,
- U+00CF ISOlat1 -->
-<!ENTITY ETH "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
-<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde,
- U+00D1 ISOlat1 -->
-<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave,
- U+00D2 ISOlat1 -->
-<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute,
- U+00D3 ISOlat1 -->
-<!ENTITY Ocirc "&#212;"> <!-- latin capital letter O with circumflex,
- U+00D4 ISOlat1 -->
-<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde,
- U+00D5 ISOlat1 -->
-<!ENTITY Ouml "&#214;"> <!-- latin capital letter O with diaeresis,
- U+00D6 ISOlat1 -->
-<!ENTITY times "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
-<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke
- = latin capital letter O slash,
- U+00D8 ISOlat1 -->
-<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave,
- U+00D9 ISOlat1 -->
-<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute,
- U+00DA ISOlat1 -->
-<!ENTITY Ucirc "&#219;"> <!-- latin capital letter U with circumflex,
- U+00DB ISOlat1 -->
-<!ENTITY Uuml "&#220;"> <!-- latin capital letter U with diaeresis,
- U+00DC ISOlat1 -->
-<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute,
- U+00DD ISOlat1 -->
-<!ENTITY THORN "&#222;"> <!-- latin capital letter THORN,
- U+00DE ISOlat1 -->
-<!ENTITY szlig "&#223;"> <!-- latin small letter sharp s = ess-zed,
- U+00DF ISOlat1 -->
-<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave
- = latin small letter a grave,
- U+00E0 ISOlat1 -->
-<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute,
- U+00E1 ISOlat1 -->
-<!ENTITY acirc "&#226;"> <!-- latin small letter a with circumflex,
- U+00E2 ISOlat1 -->
-<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde,
- U+00E3 ISOlat1 -->
-<!ENTITY auml "&#228;"> <!-- latin small letter a with diaeresis,
- U+00E4 ISOlat1 -->
-<!ENTITY aring "&#229;"> <!-- latin small letter a with ring above
- = latin small letter a ring,
- U+00E5 ISOlat1 -->
-<!ENTITY aelig "&#230;"> <!-- latin small letter ae
- = latin small ligature ae, U+00E6 ISOlat1 -->
-<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla,
- U+00E7 ISOlat1 -->
-<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave,
- U+00E8 ISOlat1 -->
-<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute,
- U+00E9 ISOlat1 -->
-<!ENTITY ecirc "&#234;"> <!-- latin small letter e with circumflex,
- U+00EA ISOlat1 -->
-<!ENTITY euml "&#235;"> <!-- latin small letter e with diaeresis,
- U+00EB ISOlat1 -->
-<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave,
- U+00EC ISOlat1 -->
-<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute,
- U+00ED ISOlat1 -->
-<!ENTITY icirc "&#238;"> <!-- latin small letter i with circumflex,
- U+00EE ISOlat1 -->
-<!ENTITY iuml "&#239;"> <!-- latin small letter i with diaeresis,
- U+00EF ISOlat1 -->
-<!ENTITY eth "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
-<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde,
- U+00F1 ISOlat1 -->
-<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave,
- U+00F2 ISOlat1 -->
-<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute,
- U+00F3 ISOlat1 -->
-<!ENTITY ocirc "&#244;"> <!-- latin small letter o with circumflex,
- U+00F4 ISOlat1 -->
-<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde,
- U+00F5 ISOlat1 -->
-<!ENTITY ouml "&#246;"> <!-- latin small letter o with diaeresis,
- U+00F6 ISOlat1 -->
-<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
-<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke,
- = latin small letter o slash,
- U+00F8 ISOlat1 -->
-<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave,
- U+00F9 ISOlat1 -->
-<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute,
- U+00FA ISOlat1 -->
-<!ENTITY ucirc "&#251;"> <!-- latin small letter u with circumflex,
- U+00FB ISOlat1 -->
-<!ENTITY uuml "&#252;"> <!-- latin small letter u with diaeresis,
- U+00FC ISOlat1 -->
-<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute,
- U+00FD ISOlat1 -->
-<!ENTITY thorn "&#254;"> <!-- latin small letter thorn,
- U+00FE ISOlat1 -->
-<!ENTITY yuml "&#255;"> <!-- latin small letter y with diaeresis,
- U+00FF ISOlat1 -->
diff --git a/Utilities/xml/xhtml1/xhtml-special.ent b/Utilities/xml/xhtml1/xhtml-special.ent
deleted file mode 100644
index 3a83fb656..000000000
--- a/Utilities/xml/xhtml1/xhtml-special.ent
+++ /dev/null
@@ -1,80 +0,0 @@
-<!-- Special characters for XHTML -->
-
-<!-- Character entity set. Typical invocation:
- <!ENTITY % HTMLspecial PUBLIC
- "-//W3C//ENTITIES Special for XHTML//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent">
- %HTMLspecial;
--->
-
-<!-- Portions (C) International Organization for Standardization 1986:
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
--->
-
-<!-- Relevant ISO entity set is given unless names are newly introduced.
- New names (i.e., not in ISO 8879 list) do not clash with any
- existing ISO 8879 entity names. ISO 10646 character numbers
- are given for each character, in hex. values are decimal
- conversions of the ISO 10646 values and refer to the document
- character set. Names are Unicode names.
--->
-
-<!-- C0 Controls and Basic Latin -->
-<!ENTITY quot "&#34;"> <!-- quotation mark, U+0022 ISOnum -->
-<!ENTITY amp "&#38;#38;"> <!-- ampersand, U+0026 ISOnum -->
-<!ENTITY lt "&#38;#60;"> <!-- less-than sign, U+003C ISOnum -->
-<!ENTITY gt "&#62;"> <!-- greater-than sign, U+003E ISOnum -->
-<!ENTITY apos "&#39;"> <!-- apostrophe = APL quote, U+0027 ISOnum -->
-
-<!-- Latin Extended-A -->
-<!ENTITY OElig "&#338;"> <!-- latin capital ligature OE,
- U+0152 ISOlat2 -->
-<!ENTITY oelig "&#339;"> <!-- latin small ligature oe, U+0153 ISOlat2 -->
-<!-- ligature is a misnomer, this is a separate character in some languages -->
-<!ENTITY Scaron "&#352;"> <!-- latin capital letter S with caron,
- U+0160 ISOlat2 -->
-<!ENTITY scaron "&#353;"> <!-- latin small letter s with caron,
- U+0161 ISOlat2 -->
-<!ENTITY Yuml "&#376;"> <!-- latin capital letter Y with diaeresis,
- U+0178 ISOlat2 -->
-
-<!-- Spacing Modifier Letters -->
-<!ENTITY circ "&#710;"> <!-- modifier letter circumflex accent,
- U+02C6 ISOpub -->
-<!ENTITY tilde "&#732;"> <!-- small tilde, U+02DC ISOdia -->
-
-<!-- General Punctuation -->
-<!ENTITY ensp "&#8194;"> <!-- en space, U+2002 ISOpub -->
-<!ENTITY emsp "&#8195;"> <!-- em space, U+2003 ISOpub -->
-<!ENTITY thinsp "&#8201;"> <!-- thin space, U+2009 ISOpub -->
-<!ENTITY zwnj "&#8204;"> <!-- zero width non-joiner,
- U+200C NEW RFC 2070 -->
-<!ENTITY zwj "&#8205;"> <!-- zero width joiner, U+200D NEW RFC 2070 -->
-<!ENTITY lrm "&#8206;"> <!-- left-to-right mark, U+200E NEW RFC 2070 -->
-<!ENTITY rlm "&#8207;"> <!-- right-to-left mark, U+200F NEW RFC 2070 -->
-<!ENTITY ndash "&#8211;"> <!-- en dash, U+2013 ISOpub -->
-<!ENTITY mdash "&#8212;"> <!-- em dash, U+2014 ISOpub -->
-<!ENTITY lsquo "&#8216;"> <!-- left single quotation mark,
- U+2018 ISOnum -->
-<!ENTITY rsquo "&#8217;"> <!-- right single quotation mark,
- U+2019 ISOnum -->
-<!ENTITY sbquo "&#8218;"> <!-- single low-9 quotation mark, U+201A NEW -->
-<!ENTITY ldquo "&#8220;"> <!-- left double quotation mark,
- U+201C ISOnum -->
-<!ENTITY rdquo "&#8221;"> <!-- right double quotation mark,
- U+201D ISOnum -->
-<!ENTITY bdquo "&#8222;"> <!-- double low-9 quotation mark, U+201E NEW -->
-<!ENTITY dagger "&#8224;"> <!-- dagger, U+2020 ISOpub -->
-<!ENTITY Dagger "&#8225;"> <!-- double dagger, U+2021 ISOpub -->
-<!ENTITY permil "&#8240;"> <!-- per mille sign, U+2030 ISOtech -->
-<!ENTITY lsaquo "&#8249;"> <!-- single left-pointing angle quotation mark,
- U+2039 ISO proposed -->
-<!-- lsaquo is proposed but not yet ISO standardized -->
-<!ENTITY rsaquo "&#8250;"> <!-- single right-pointing angle quotation mark,
- U+203A ISO proposed -->
-<!-- rsaquo is proposed but not yet ISO standardized -->
-
-<!-- Currency Symbols -->
-<!ENTITY euro "&#8364;"> <!-- euro sign, U+20AC NEW -->
diff --git a/Utilities/xml/xhtml1/xhtml-symbol.ent b/Utilities/xml/xhtml1/xhtml-symbol.ent
deleted file mode 100644
index d0c77eebc..000000000
--- a/Utilities/xml/xhtml1/xhtml-symbol.ent
+++ /dev/null
@@ -1,237 +0,0 @@
-<!-- Mathematical, Greek and Symbolic characters for XHTML -->
-
-<!-- Character entity set. Typical invocation:
- <!ENTITY % HTMLsymbol PUBLIC
- "-//W3C//ENTITIES Symbols for XHTML//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent">
- %HTMLsymbol;
--->
-
-<!-- Portions (C) International Organization for Standardization 1986:
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
--->
-
-<!-- Relevant ISO entity set is given unless names are newly introduced.
- New names (i.e., not in ISO 8879 list) do not clash with any
- existing ISO 8879 entity names. ISO 10646 character numbers
- are given for each character, in hex. values are decimal
- conversions of the ISO 10646 values and refer to the document
- character set. Names are Unicode names.
--->
-
-<!-- Latin Extended-B -->
-<!ENTITY fnof "&#402;"> <!-- latin small letter f with hook = function
- = florin, U+0192 ISOtech -->
-
-<!-- Greek -->
-<!ENTITY Alpha "&#913;"> <!-- greek capital letter alpha, U+0391 -->
-<!ENTITY Beta "&#914;"> <!-- greek capital letter beta, U+0392 -->
-<!ENTITY Gamma "&#915;"> <!-- greek capital letter gamma,
- U+0393 ISOgrk3 -->
-<!ENTITY Delta "&#916;"> <!-- greek capital letter delta,
- U+0394 ISOgrk3 -->
-<!ENTITY Epsilon "&#917;"> <!-- greek capital letter epsilon, U+0395 -->
-<!ENTITY Zeta "&#918;"> <!-- greek capital letter zeta, U+0396 -->
-<!ENTITY Eta "&#919;"> <!-- greek capital letter eta, U+0397 -->
-<!ENTITY Theta "&#920;"> <!-- greek capital letter theta,
- U+0398 ISOgrk3 -->
-<!ENTITY Iota "&#921;"> <!-- greek capital letter iota, U+0399 -->
-<!ENTITY Kappa "&#922;"> <!-- greek capital letter kappa, U+039A -->
-<!ENTITY Lambda "&#923;"> <!-- greek capital letter lamda,
- U+039B ISOgrk3 -->
-<!ENTITY Mu "&#924;"> <!-- greek capital letter mu, U+039C -->
-<!ENTITY Nu "&#925;"> <!-- greek capital letter nu, U+039D -->
-<!ENTITY Xi "&#926;"> <!-- greek capital letter xi, U+039E ISOgrk3 -->
-<!ENTITY Omicron "&#927;"> <!-- greek capital letter omicron, U+039F -->
-<!ENTITY Pi "&#928;"> <!-- greek capital letter pi, U+03A0 ISOgrk3 -->
-<!ENTITY Rho "&#929;"> <!-- greek capital letter rho, U+03A1 -->
-<!-- there is no Sigmaf, and no U+03A2 character either -->
-<!ENTITY Sigma "&#931;"> <!-- greek capital letter sigma,
- U+03A3 ISOgrk3 -->
-<!ENTITY Tau "&#932;"> <!-- greek capital letter tau, U+03A4 -->
-<!ENTITY Upsilon "&#933;"> <!-- greek capital letter upsilon,
- U+03A5 ISOgrk3 -->
-<!ENTITY Phi "&#934;"> <!-- greek capital letter phi,
- U+03A6 ISOgrk3 -->
-<!ENTITY Chi "&#935;"> <!-- greek capital letter chi, U+03A7 -->
-<!ENTITY Psi "&#936;"> <!-- greek capital letter psi,
- U+03A8 ISOgrk3 -->
-<!ENTITY Omega "&#937;"> <!-- greek capital letter omega,
- U+03A9 ISOgrk3 -->
-
-<!ENTITY alpha "&#945;"> <!-- greek small letter alpha,
- U+03B1 ISOgrk3 -->
-<!ENTITY beta "&#946;"> <!-- greek small letter beta, U+03B2 ISOgrk3 -->
-<!ENTITY gamma "&#947;"> <!-- greek small letter gamma,
- U+03B3 ISOgrk3 -->
-<!ENTITY delta "&#948;"> <!-- greek small letter delta,
- U+03B4 ISOgrk3 -->
-<!ENTITY epsilon "&#949;"> <!-- greek small letter epsilon,
- U+03B5 ISOgrk3 -->
-<!ENTITY zeta "&#950;"> <!-- greek small letter zeta, U+03B6 ISOgrk3 -->
-<!ENTITY eta "&#951;"> <!-- greek small letter eta, U+03B7 ISOgrk3 -->
-<!ENTITY theta "&#952;"> <!-- greek small letter theta,
- U+03B8 ISOgrk3 -->
-<!ENTITY iota "&#953;"> <!-- greek small letter iota, U+03B9 ISOgrk3 -->
-<!ENTITY kappa "&#954;"> <!-- greek small letter kappa,
- U+03BA ISOgrk3 -->
-<!ENTITY lambda "&#955;"> <!-- greek small letter lamda,
- U+03BB ISOgrk3 -->
-<!ENTITY mu "&#956;"> <!-- greek small letter mu, U+03BC ISOgrk3 -->
-<!ENTITY nu "&#957;"> <!-- greek small letter nu, U+03BD ISOgrk3 -->
-<!ENTITY xi "&#958;"> <!-- greek small letter xi, U+03BE ISOgrk3 -->
-<!ENTITY omicron "&#959;"> <!-- greek small letter omicron, U+03BF NEW -->
-<!ENTITY pi "&#960;"> <!-- greek small letter pi, U+03C0 ISOgrk3 -->
-<!ENTITY rho "&#961;"> <!-- greek small letter rho, U+03C1 ISOgrk3 -->
-<!ENTITY sigmaf "&#962;"> <!-- greek small letter final sigma,
- U+03C2 ISOgrk3 -->
-<!ENTITY sigma "&#963;"> <!-- greek small letter sigma,
- U+03C3 ISOgrk3 -->
-<!ENTITY tau "&#964;"> <!-- greek small letter tau, U+03C4 ISOgrk3 -->
-<!ENTITY upsilon "&#965;"> <!-- greek small letter upsilon,
- U+03C5 ISOgrk3 -->
-<!ENTITY phi "&#966;"> <!-- greek small letter phi, U+03C6 ISOgrk3 -->
-<!ENTITY chi "&#967;"> <!-- greek small letter chi, U+03C7 ISOgrk3 -->
-<!ENTITY psi "&#968;"> <!-- greek small letter psi, U+03C8 ISOgrk3 -->
-<!ENTITY omega "&#969;"> <!-- greek small letter omega,
- U+03C9 ISOgrk3 -->
-<!ENTITY thetasym "&#977;"> <!-- greek theta symbol,
- U+03D1 NEW -->
-<!ENTITY upsih "&#978;"> <!-- greek upsilon with hook symbol,
- U+03D2 NEW -->
-<!ENTITY piv "&#982;"> <!-- greek pi symbol, U+03D6 ISOgrk3 -->
-
-<!-- General Punctuation -->
-<!ENTITY bull "&#8226;"> <!-- bullet = black small circle,
- U+2022 ISOpub -->
-<!-- bullet is NOT the same as bullet operator, U+2219 -->
-<!ENTITY hellip "&#8230;"> <!-- horizontal ellipsis = three dot leader,
- U+2026 ISOpub -->
-<!ENTITY prime "&#8242;"> <!-- prime = minutes = feet, U+2032 ISOtech -->
-<!ENTITY Prime "&#8243;"> <!-- double prime = seconds = inches,
- U+2033 ISOtech -->
-<!ENTITY oline "&#8254;"> <!-- overline = spacing overscore,
- U+203E NEW -->
-<!ENTITY frasl "&#8260;"> <!-- fraction slash, U+2044 NEW -->
-
-<!-- Letterlike Symbols -->
-<!ENTITY weierp "&#8472;"> <!-- script capital P = power set
- = Weierstrass p, U+2118 ISOamso -->
-<!ENTITY image "&#8465;"> <!-- black-letter capital I = imaginary part,
- U+2111 ISOamso -->
-<!ENTITY real "&#8476;"> <!-- black-letter capital R = real part symbol,
- U+211C ISOamso -->
-<!ENTITY trade "&#8482;"> <!-- trade mark sign, U+2122 ISOnum -->
-<!ENTITY alefsym "&#8501;"> <!-- alef symbol = first transfinite cardinal,
- U+2135 NEW -->
-<!-- alef symbol is NOT the same as hebrew letter alef,
- U+05D0 although the same glyph could be used to depict both characters -->
-
-<!-- Arrows -->
-<!ENTITY larr "&#8592;"> <!-- leftwards arrow, U+2190 ISOnum -->
-<!ENTITY uarr "&#8593;"> <!-- upwards arrow, U+2191 ISOnum-->
-<!ENTITY rarr "&#8594;"> <!-- rightwards arrow, U+2192 ISOnum -->
-<!ENTITY darr "&#8595;"> <!-- downwards arrow, U+2193 ISOnum -->
-<!ENTITY harr "&#8596;"> <!-- left right arrow, U+2194 ISOamsa -->
-<!ENTITY crarr "&#8629;"> <!-- downwards arrow with corner leftwards
- = carriage return, U+21B5 NEW -->
-<!ENTITY lArr "&#8656;"> <!-- leftwards double arrow, U+21D0 ISOtech -->
-<!-- Unicode does not say that lArr is the same as the 'is implied by' arrow
- but also does not have any other character for that function. So lArr can
- be used for 'is implied by' as ISOtech suggests -->
-<!ENTITY uArr "&#8657;"> <!-- upwards double arrow, U+21D1 ISOamsa -->
-<!ENTITY rArr "&#8658;"> <!-- rightwards double arrow,
- U+21D2 ISOtech -->
-<!-- Unicode does not say this is the 'implies' character but does not have
- another character with this function so rArr can be used for 'implies'
- as ISOtech suggests -->
-<!ENTITY dArr "&#8659;"> <!-- downwards double arrow, U+21D3 ISOamsa -->
-<!ENTITY hArr "&#8660;"> <!-- left right double arrow,
- U+21D4 ISOamsa -->
-
-<!-- Mathematical Operators -->
-<!ENTITY forall "&#8704;"> <!-- for all, U+2200 ISOtech -->
-<!ENTITY part "&#8706;"> <!-- partial differential, U+2202 ISOtech -->
-<!ENTITY exist "&#8707;"> <!-- there exists, U+2203 ISOtech -->
-<!ENTITY empty "&#8709;"> <!-- empty set = null set, U+2205 ISOamso -->
-<!ENTITY nabla "&#8711;"> <!-- nabla = backward difference,
- U+2207 ISOtech -->
-<!ENTITY isin "&#8712;"> <!-- element of, U+2208 ISOtech -->
-<!ENTITY notin "&#8713;"> <!-- not an element of, U+2209 ISOtech -->
-<!ENTITY ni "&#8715;"> <!-- contains as member, U+220B ISOtech -->
-<!ENTITY prod "&#8719;"> <!-- n-ary product = product sign,
- U+220F ISOamsb -->
-<!-- prod is NOT the same character as U+03A0 'greek capital letter pi' though
- the same glyph might be used for both -->
-<!ENTITY sum "&#8721;"> <!-- n-ary summation, U+2211 ISOamsb -->
-<!-- sum is NOT the same character as U+03A3 'greek capital letter sigma'
- though the same glyph might be used for both -->
-<!ENTITY minus "&#8722;"> <!-- minus sign, U+2212 ISOtech -->
-<!ENTITY lowast "&#8727;"> <!-- asterisk operator, U+2217 ISOtech -->
-<!ENTITY radic "&#8730;"> <!-- square root = radical sign,
- U+221A ISOtech -->
-<!ENTITY prop "&#8733;"> <!-- proportional to, U+221D ISOtech -->
-<!ENTITY infin "&#8734;"> <!-- infinity, U+221E ISOtech -->
-<!ENTITY ang "&#8736;"> <!-- angle, U+2220 ISOamso -->
-<!ENTITY and "&#8743;"> <!-- logical and = wedge, U+2227 ISOtech -->
-<!ENTITY or "&#8744;"> <!-- logical or = vee, U+2228 ISOtech -->
-<!ENTITY cap "&#8745;"> <!-- intersection = cap, U+2229 ISOtech -->
-<!ENTITY cup "&#8746;"> <!-- union = cup, U+222A ISOtech -->
-<!ENTITY int "&#8747;"> <!-- integral, U+222B ISOtech -->
-<!ENTITY there4 "&#8756;"> <!-- therefore, U+2234 ISOtech -->
-<!ENTITY sim "&#8764;"> <!-- tilde operator = varies with = similar to,
- U+223C ISOtech -->
-<!-- tilde operator is NOT the same character as the tilde, U+007E,
- although the same glyph might be used to represent both -->
-<!ENTITY cong "&#8773;"> <!-- approximately equal to, U+2245 ISOtech -->
-<!ENTITY asymp "&#8776;"> <!-- almost equal to = asymptotic to,
- U+2248 ISOamsr -->
-<!ENTITY ne "&#8800;"> <!-- not equal to, U+2260 ISOtech -->
-<!ENTITY equiv "&#8801;"> <!-- identical to, U+2261 ISOtech -->
-<!ENTITY le "&#8804;"> <!-- less-than or equal to, U+2264 ISOtech -->
-<!ENTITY ge "&#8805;"> <!-- greater-than or equal to,
- U+2265 ISOtech -->
-<!ENTITY sub "&#8834;"> <!-- subset of, U+2282 ISOtech -->
-<!ENTITY sup "&#8835;"> <!-- superset of, U+2283 ISOtech -->
-<!ENTITY nsub "&#8836;"> <!-- not a subset of, U+2284 ISOamsn -->
-<!ENTITY sube "&#8838;"> <!-- subset of or equal to, U+2286 ISOtech -->
-<!ENTITY supe "&#8839;"> <!-- superset of or equal to,
- U+2287 ISOtech -->
-<!ENTITY oplus "&#8853;"> <!-- circled plus = direct sum,
- U+2295 ISOamsb -->
-<!ENTITY otimes "&#8855;"> <!-- circled times = vector product,
- U+2297 ISOamsb -->
-<!ENTITY perp "&#8869;"> <!-- up tack = orthogonal to = perpendicular,
- U+22A5 ISOtech -->
-<!ENTITY sdot "&#8901;"> <!-- dot operator, U+22C5 ISOamsb -->
-<!-- dot operator is NOT the same character as U+00B7 middle dot -->
-
-<!-- Miscellaneous Technical -->
-<!ENTITY lceil "&#8968;"> <!-- left ceiling = APL upstile,
- U+2308 ISOamsc -->
-<!ENTITY rceil "&#8969;"> <!-- right ceiling, U+2309 ISOamsc -->
-<!ENTITY lfloor "&#8970;"> <!-- left floor = APL downstile,
- U+230A ISOamsc -->
-<!ENTITY rfloor "&#8971;"> <!-- right floor, U+230B ISOamsc -->
-<!ENTITY lang "&#9001;"> <!-- left-pointing angle bracket = bra,
- U+2329 ISOtech -->
-<!-- lang is NOT the same character as U+003C 'less than sign'
- or U+2039 'single left-pointing angle quotation mark' -->
-<!ENTITY rang "&#9002;"> <!-- right-pointing angle bracket = ket,
- U+232A ISOtech -->
-<!-- rang is NOT the same character as U+003E 'greater than sign'
- or U+203A 'single right-pointing angle quotation mark' -->
-
-<!-- Geometric Shapes -->
-<!ENTITY loz "&#9674;"> <!-- lozenge, U+25CA ISOpub -->
-
-<!-- Miscellaneous Symbols -->
-<!ENTITY spades "&#9824;"> <!-- black spade suit, U+2660 ISOpub -->
-<!-- black here seems to mean filled as opposed to hollow -->
-<!ENTITY clubs "&#9827;"> <!-- black club suit = shamrock,
- U+2663 ISOpub -->
-<!ENTITY hearts "&#9829;"> <!-- black heart suit = valentine,
- U+2665 ISOpub -->
-<!ENTITY diams "&#9830;"> <!-- black diamond suit, U+2666 ISOpub -->
diff --git a/Utilities/xml/xhtml1/xhtml1-strict.dtd b/Utilities/xml/xhtml1/xhtml1-strict.dtd
deleted file mode 100644
index e48fbea6e..000000000
--- a/Utilities/xml/xhtml1/xhtml1-strict.dtd
+++ /dev/null
@@ -1,977 +0,0 @@
-<!--
- Extensible HTML version 1.0 Strict DTD
-
- This is the same as HTML 4 Strict except for
- changes due to the differences between XML and SGML.
-
- Namespace = http://www.w3.org/1999/xhtml
-
- For further information, see: http://www.w3.org/TR/xhtml1
-
- Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
- All Rights Reserved.
-
- This DTD module is identified by the PUBLIC and SYSTEM identifiers:
-
- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
-
- $Revision: 1.1 $
- $Date: 2002/08/01 13:56:03 $
-
--->
-
-<!--================ Character mnemonic entities =========================-->
-
-<!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "xhtml-lat1.ent">
-%HTMLlat1;
-
-<!ENTITY % HTMLsymbol PUBLIC
- "-//W3C//ENTITIES Symbols for XHTML//EN"
- "xhtml-symbol.ent">
-%HTMLsymbol;
-
-<!ENTITY % HTMLspecial PUBLIC
- "-//W3C//ENTITIES Special for XHTML//EN"
- "xhtml-special.ent">
-%HTMLspecial;
-
-<!--================== Imported Names ====================================-->
-
-<!ENTITY % ContentType "CDATA">
- <!-- media type, as per [RFC2045] -->
-
-<!ENTITY % ContentTypes "CDATA">
- <!-- comma-separated list of media types, as per [RFC2045] -->
-
-<!ENTITY % Charset "CDATA">
- <!-- a character encoding, as per [RFC2045] -->
-
-<!ENTITY % Charsets "CDATA">
- <!-- a space separated list of character encodings, as per [RFC2045] -->
-
-<!ENTITY % LanguageCode "NMTOKEN">
- <!-- a language code, as per [RFC3066] -->
-
-<!ENTITY % Character "CDATA">
- <!-- a single character, as per section 2.2 of [XML] -->
-
-<!ENTITY % Number "CDATA">
- <!-- one or more digits -->
-
-<!ENTITY % LinkTypes "CDATA">
- <!-- space-separated list of link types -->
-
-<!ENTITY % MediaDesc "CDATA">
- <!-- single or comma-separated list of media descriptors -->
-
-<!ENTITY % URI "CDATA">
- <!-- a Uniform Resource Identifier, see [RFC2396] -->
-
-<!ENTITY % UriList "CDATA">
- <!-- a space separated list of Uniform Resource Identifiers -->
-
-<!ENTITY % Datetime "CDATA">
- <!-- date and time information. ISO date format -->
-
-<!ENTITY % Script "CDATA">
- <!-- script expression -->
-
-<!ENTITY % StyleSheet "CDATA">
- <!-- style sheet data -->
-
-<!ENTITY % Text "CDATA">
- <!-- used for titles etc. -->
-
-<!ENTITY % Length "CDATA">
- <!-- nn for pixels or nn% for percentage length -->
-
-<!ENTITY % MultiLength "CDATA">
- <!-- pixel, percentage, or relative -->
-
-<!ENTITY % Pixels "CDATA">
- <!-- integer representing length in pixels -->
-
-<!-- these are used for image maps -->
-
-<!ENTITY % Shape "(rect|circle|poly|default)">
-
-<!ENTITY % Coords "CDATA">
- <!-- comma separated list of lengths -->
-
-<!--=================== Generic Attributes ===============================-->
-
-<!-- core attributes common to most elements
- id document-wide unique id
- class space separated list of classes
- style associated style info
- title advisory title/amplification
--->
-<!ENTITY % coreattrs
- "id ID #IMPLIED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED"
- >
-
-<!-- internationalization attributes
- lang language code (backwards compatible)
- xml:lang language code (as per XML 1.0 spec)
- dir direction for weak/neutral text
--->
-<!ENTITY % i18n
- "lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #IMPLIED"
- >
-
-<!-- attributes for common UI events
- onclick a pointer button was clicked
- ondblclick a pointer button was double clicked
- onmousedown a pointer button was pressed down
- onmouseup a pointer button was released
- onmousemove a pointer was moved onto the element
- onmouseout a pointer was moved away from the element
- onkeypress a key was pressed and released
- onkeydown a key was pressed down
- onkeyup a key was released
--->
-<!ENTITY % events
- "onclick %Script; #IMPLIED
- ondblclick %Script; #IMPLIED
- onmousedown %Script; #IMPLIED
- onmouseup %Script; #IMPLIED
- onmouseover %Script; #IMPLIED
- onmousemove %Script; #IMPLIED
- onmouseout %Script; #IMPLIED
- onkeypress %Script; #IMPLIED
- onkeydown %Script; #IMPLIED
- onkeyup %Script; #IMPLIED"
- >
-
-<!-- attributes for elements that can get the focus
- accesskey accessibility key character
- tabindex position in tabbing order
- onfocus the element got the focus
- onblur the element lost the focus
--->
-<!ENTITY % focus
- "accesskey %Character; #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED"
- >
-
-<!ENTITY % attrs "%coreattrs; %i18n; %events;">
-
-<!--=================== Text Elements ====================================-->
-
-<!ENTITY % special.pre
- "br | span | bdo | map">
-
-
-<!ENTITY % special
- "%special.pre; | object | img ">
-
-<!ENTITY % fontstyle "tt | i | b | big | small ">
-
-<!ENTITY % phrase "em | strong | dfn | code | q |
- samp | kbd | var | cite | abbr | acronym | sub | sup ">
-
-<!ENTITY % inline.forms "input | select | textarea | label | button">
-
-<!-- these can occur at block or inline level -->
-<!ENTITY % misc.inline "ins | del | script">
-
-<!-- these can only occur at block level -->
-<!ENTITY % misc "noscript | %misc.inline;">
-
-<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
-
-<!-- %Inline; covers inline or "text-level" elements -->
-<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
-
-<!--================== Block level elements ==============================-->
-
-<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
-<!ENTITY % lists "ul | ol | dl">
-<!ENTITY % blocktext "pre | hr | blockquote | address">
-
-<!ENTITY % block
- "p | %heading; | div | %lists; | %blocktext; | fieldset | table">
-
-<!ENTITY % Block "(%block; | form | %misc;)*">
-
-<!-- %Flow; mixes block and inline and is used for list items etc. -->
-<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
-
-<!--================== Content models for exclusions =====================-->
-
-<!-- a elements use %Inline; excluding a -->
-
-<!ENTITY % a.content
- "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
-
-<!-- pre uses %Inline excluding big, small, sup or sup -->
-
-<!ENTITY % pre.content
- "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline;
- | %inline.forms;)*">
-
-<!-- form uses %Block; excluding form -->
-
-<!ENTITY % form.content "(%block; | %misc;)*">
-
-<!-- button uses %Flow; but excludes a, form and form controls -->
-
-<!ENTITY % button.content
- "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
- table | %special; | %fontstyle; | %phrase; | %misc;)*">
-
-<!--================ Document Structure ==================================-->
-
-<!-- the namespace URI designates the document profile -->
-
-<!ELEMENT html (head, body)>
-<!ATTLIST html
- %i18n;
- id ID #IMPLIED
- xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
- >
-
-<!--================ Document Head =======================================-->
-
-<!ENTITY % head.misc "(script|style|meta|link|object)*">
-
-<!-- content model is %head.misc; combined with a single
- title and an optional base element in any order -->
-
-<!ELEMENT head (%head.misc;,
- ((title, %head.misc;, (base, %head.misc;)?) |
- (base, %head.misc;, (title, %head.misc;))))>
-
-<!ATTLIST head
- %i18n;
- id ID #IMPLIED
- profile %URI; #IMPLIED
- >
-
-<!-- The title element is not considered part of the flow of text.
- It should be displayed, for example as the page header or
- window title. Exactly one title is required per document.
- -->
-<!ELEMENT title (#PCDATA)>
-<!ATTLIST title
- %i18n;
- id ID #IMPLIED
- >
-
-<!-- document base URI -->
-
-<!ELEMENT base EMPTY>
-<!ATTLIST base
- href %URI; #REQUIRED
- id ID #IMPLIED
- >
-
-<!-- generic metainformation -->
-<!ELEMENT meta EMPTY>
-<!ATTLIST meta
- %i18n;
- id ID #IMPLIED
- http-equiv CDATA #IMPLIED
- name CDATA #IMPLIED
- content CDATA #REQUIRED
- scheme CDATA #IMPLIED
- >
-
-<!--
- Relationship values can be used in principle:
-
- a) for document specific toolbars/menus when used
- with the link element in document head e.g.
- start, contents, previous, next, index, end, help
- b) to link to a separate style sheet (rel="stylesheet")
- c) to make a link to a script (rel="script")
- d) by stylesheets to control how collections of
- html nodes are rendered into printed documents
- e) to make a link to a printable version of this document
- e.g. a PostScript or PDF version (rel="alternate" media="print")
--->
-
-<!ELEMENT link EMPTY>
-<!ATTLIST link
- %attrs;
- charset %Charset; #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- type %ContentType; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- media %MediaDesc; #IMPLIED
- >
-
-<!-- style info, which may include CDATA sections -->
-<!ELEMENT style (#PCDATA)>
-<!ATTLIST style
- %i18n;
- id ID #IMPLIED
- type %ContentType; #REQUIRED
- media %MediaDesc; #IMPLIED
- title %Text; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- script statements, which may include CDATA sections -->
-<!ELEMENT script (#PCDATA)>
-<!ATTLIST script
- id ID #IMPLIED
- charset %Charset; #IMPLIED
- type %ContentType; #REQUIRED
- src %URI; #IMPLIED
- defer (defer) #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- alternate content container for non script-based rendering -->
-
-<!ELEMENT noscript %Block;>
-<!ATTLIST noscript
- %attrs;
- >
-
-<!--=================== Document Body ====================================-->
-
-<!ELEMENT body %Block;>
-<!ATTLIST body
- %attrs;
- onload %Script; #IMPLIED
- onunload %Script; #IMPLIED
- >
-
-<!ELEMENT div %Flow;> <!-- generic language/style container -->
-<!ATTLIST div
- %attrs;
- >
-
-<!--=================== Paragraphs =======================================-->
-
-<!ELEMENT p %Inline;>
-<!ATTLIST p
- %attrs;
- >
-
-<!--=================== Headings =========================================-->
-
-<!--
- There are six levels of headings from h1 (the most important)
- to h6 (the least important).
--->
-
-<!ELEMENT h1 %Inline;>
-<!ATTLIST h1
- %attrs;
- >
-
-<!ELEMENT h2 %Inline;>
-<!ATTLIST h2
- %attrs;
- >
-
-<!ELEMENT h3 %Inline;>
-<!ATTLIST h3
- %attrs;
- >
-
-<!ELEMENT h4 %Inline;>
-<!ATTLIST h4
- %attrs;
- >
-
-<!ELEMENT h5 %Inline;>
-<!ATTLIST h5
- %attrs;
- >
-
-<!ELEMENT h6 %Inline;>
-<!ATTLIST h6
- %attrs;
- >
-
-<!--=================== Lists ============================================-->
-
-<!-- Unordered list -->
-
-<!ELEMENT ul (li)+>
-<!ATTLIST ul
- %attrs;
- >
-
-<!-- Ordered (numbered) list -->
-
-<!ELEMENT ol (li)+>
-<!ATTLIST ol
- %attrs;
- >
-
-<!-- list item -->
-
-<!ELEMENT li %Flow;>
-<!ATTLIST li
- %attrs;
- >
-
-<!-- definition lists - dt for term, dd for its definition -->
-
-<!ELEMENT dl (dt|dd)+>
-<!ATTLIST dl
- %attrs;
- >
-
-<!ELEMENT dt %Inline;>
-<!ATTLIST dt
- %attrs;
- >
-
-<!ELEMENT dd %Flow;>
-<!ATTLIST dd
- %attrs;
- >
-
-<!--=================== Address ==========================================-->
-
-<!-- information on author -->
-
-<!ELEMENT address %Inline;>
-<!ATTLIST address
- %attrs;
- >
-
-<!--=================== Horizontal Rule ==================================-->
-
-<!ELEMENT hr EMPTY>
-<!ATTLIST hr
- %attrs;
- >
-
-<!--=================== Preformatted Text ================================-->
-
-<!-- content is %Inline; excluding "img|object|big|small|sub|sup" -->
-
-<!ELEMENT pre %pre.content;>
-<!ATTLIST pre
- %attrs;
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!--=================== Block-like Quotes ================================-->
-
-<!ELEMENT blockquote %Block;>
-<!ATTLIST blockquote
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!--=================== Inserted/Deleted Text ============================-->
-
-<!--
- ins/del are allowed in block and inline content, but its
- inappropriate to include block content within an ins element
- occurring in inline content.
--->
-<!ELEMENT ins %Flow;>
-<!ATTLIST ins
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!ELEMENT del %Flow;>
-<!ATTLIST del
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!--================== The Anchor Element ================================-->
-
-<!-- content is %Inline; except that anchors shouldn't be nested -->
-
-<!ELEMENT a %a.content;>
-<!ATTLIST a
- %attrs;
- %focus;
- charset %Charset; #IMPLIED
- type %ContentType; #IMPLIED
- name NMTOKEN #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- >
-
-<!--===================== Inline Elements ================================-->
-
-<!ELEMENT span %Inline;> <!-- generic language/style container -->
-<!ATTLIST span
- %attrs;
- >
-
-<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
-<!ATTLIST bdo
- %coreattrs;
- %events;
- lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #REQUIRED
- >
-
-<!ELEMENT br EMPTY> <!-- forced line break -->
-<!ATTLIST br
- %coreattrs;
- >
-
-<!ELEMENT em %Inline;> <!-- emphasis -->
-<!ATTLIST em %attrs;>
-
-<!ELEMENT strong %Inline;> <!-- strong emphasis -->
-<!ATTLIST strong %attrs;>
-
-<!ELEMENT dfn %Inline;> <!-- definitional -->
-<!ATTLIST dfn %attrs;>
-
-<!ELEMENT code %Inline;> <!-- program code -->
-<!ATTLIST code %attrs;>
-
-<!ELEMENT samp %Inline;> <!-- sample -->
-<!ATTLIST samp %attrs;>
-
-<!ELEMENT kbd %Inline;> <!-- something user would type -->
-<!ATTLIST kbd %attrs;>
-
-<!ELEMENT var %Inline;> <!-- variable -->
-<!ATTLIST var %attrs;>
-
-<!ELEMENT cite %Inline;> <!-- citation -->
-<!ATTLIST cite %attrs;>
-
-<!ELEMENT abbr %Inline;> <!-- abbreviation -->
-<!ATTLIST abbr %attrs;>
-
-<!ELEMENT acronym %Inline;> <!-- acronym -->
-<!ATTLIST acronym %attrs;>
-
-<!ELEMENT q %Inline;> <!-- inlined quote -->
-<!ATTLIST q
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!ELEMENT sub %Inline;> <!-- subscript -->
-<!ATTLIST sub %attrs;>
-
-<!ELEMENT sup %Inline;> <!-- superscript -->
-<!ATTLIST sup %attrs;>
-
-<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
-<!ATTLIST tt %attrs;>
-
-<!ELEMENT i %Inline;> <!-- italic font -->
-<!ATTLIST i %attrs;>
-
-<!ELEMENT b %Inline;> <!-- bold font -->
-<!ATTLIST b %attrs;>
-
-<!ELEMENT big %Inline;> <!-- bigger font -->
-<!ATTLIST big %attrs;>
-
-<!ELEMENT small %Inline;> <!-- smaller font -->
-<!ATTLIST small %attrs;>
-
-<!--==================== Object ======================================-->
-<!--
- object is used to embed objects as part of HTML pages.
- param elements should precede other content. Parameters
- can also be expressed as attribute/value pairs on the
- object element itself when brevity is desired.
--->
-
-<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
-<!ATTLIST object
- %attrs;
- declare (declare) #IMPLIED
- classid %URI; #IMPLIED
- codebase %URI; #IMPLIED
- data %URI; #IMPLIED
- type %ContentType; #IMPLIED
- codetype %ContentType; #IMPLIED
- archive %UriList; #IMPLIED
- standby %Text; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- tabindex %Number; #IMPLIED
- >
-
-<!--
- param is used to supply a named property value.
- In XML it would seem natural to follow RDF and support an
- abbreviated syntax where the param elements are replaced
- by attribute value pairs on the object start tag.
--->
-<!ELEMENT param EMPTY>
-<!ATTLIST param
- id ID #IMPLIED
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- valuetype (data|ref|object) "data"
- type %ContentType; #IMPLIED
- >
-
-<!--=================== Images ===========================================-->
-
-<!--
- To avoid accessibility problems for people who aren't
- able to see the image, you should provide a text
- description using the alt and longdesc attributes.
- In addition, avoid the use of server-side image maps.
- Note that in this DTD there is no name attribute. That
- is only available in the transitional and frameset DTD.
--->
-
-<!ELEMENT img EMPTY>
-<!ATTLIST img
- %attrs;
- src %URI; #REQUIRED
- alt %Text; #REQUIRED
- longdesc %URI; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- ismap (ismap) #IMPLIED
- >
-
-<!-- usemap points to a map element which may be in this document
- or an external document, although the latter is not widely supported -->
-
-<!--================== Client-side image maps ============================-->
-
-<!-- These can be placed in the same document or grouped in a
- separate document although this isn't yet widely supported -->
-
-<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
-<!ATTLIST map
- %i18n;
- %events;
- id ID #REQUIRED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED
- name NMTOKEN #IMPLIED
- >
-
-<!ELEMENT area EMPTY>
-<!ATTLIST area
- %attrs;
- %focus;
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- href %URI; #IMPLIED
- nohref (nohref) #IMPLIED
- alt %Text; #REQUIRED
- >
-
-<!--================ Forms ===============================================-->
-<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
-
-<!ATTLIST form
- %attrs;
- action %URI; #REQUIRED
- method (get|post) "get"
- enctype %ContentType; "application/x-www-form-urlencoded"
- onsubmit %Script; #IMPLIED
- onreset %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- accept-charset %Charsets; #IMPLIED
- >
-
-<!--
- Each label must not contain more than ONE field
- Label elements shouldn't be nested.
--->
-<!ELEMENT label %Inline;>
-<!ATTLIST label
- %attrs;
- for IDREF #IMPLIED
- accesskey %Character; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- >
-
-<!ENTITY % InputType
- "(text | password | checkbox |
- radio | submit | reset |
- file | hidden | image | button)"
- >
-
-<!-- the name attribute is required for all but submit & reset -->
-
-<!ELEMENT input EMPTY> <!-- form control -->
-<!ATTLIST input
- %attrs;
- %focus;
- type %InputType; "text"
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- checked (checked) #IMPLIED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- size CDATA #IMPLIED
- maxlength %Number; #IMPLIED
- src %URI; #IMPLIED
- alt CDATA #IMPLIED
- usemap %URI; #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- >
-
-<!ELEMENT select (optgroup|option)+> <!-- option selector -->
-<!ATTLIST select
- %attrs;
- name CDATA #IMPLIED
- size %Number; #IMPLIED
- multiple (multiple) #IMPLIED
- disabled (disabled) #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!ELEMENT optgroup (option)+> <!-- option group -->
-<!ATTLIST optgroup
- %attrs;
- disabled (disabled) #IMPLIED
- label %Text; #REQUIRED
- >
-
-<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
-<!ATTLIST option
- %attrs;
- selected (selected) #IMPLIED
- disabled (disabled) #IMPLIED
- label %Text; #IMPLIED
- value CDATA #IMPLIED
- >
-
-<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
-<!ATTLIST textarea
- %attrs;
- %focus;
- name CDATA #IMPLIED
- rows %Number; #REQUIRED
- cols %Number; #REQUIRED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!--
- The fieldset element is used to group form fields.
- Only one legend element should occur in the content
- and if present should only be preceded by whitespace.
--->
-<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
-<!ATTLIST fieldset
- %attrs;
- >
-
-<!ELEMENT legend %Inline;> <!-- fieldset label -->
-<!ATTLIST legend
- %attrs;
- accesskey %Character; #IMPLIED
- >
-
-<!--
- Content is %Flow; excluding a, form and form controls
--->
-<!ELEMENT button %button.content;> <!-- push button -->
-<!ATTLIST button
- %attrs;
- %focus;
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- type (button|submit|reset) "submit"
- disabled (disabled) #IMPLIED
- >
-
-<!--======================= Tables =======================================-->
-
-<!-- Derived from IETF HTML table standard, see [RFC1942] -->
-
-<!--
- The border attribute sets the thickness of the frame around the
- table. The default units are screen pixels.
-
- The frame attribute specifies which parts of the frame around
- the table should be rendered. The values are not the same as
- CALS to avoid a name clash with the valign attribute.
--->
-<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
-
-<!--
- The rules attribute defines which rules to draw between cells:
-
- If rules is absent then assume:
- "none" if border is absent or border="0" otherwise "all"
--->
-
-<!ENTITY % TRules "(none | groups | rows | cols | all)">
-
-<!-- horizontal alignment attributes for cell contents
-
- char alignment char, e.g. char=':'
- charoff offset for alignment char
--->
-<!ENTITY % cellhalign
- "align (left|center|right|justify|char) #IMPLIED
- char %Character; #IMPLIED
- charoff %Length; #IMPLIED"
- >
-
-<!-- vertical alignment attributes for cell contents -->
-<!ENTITY % cellvalign
- "valign (top|middle|bottom|baseline) #IMPLIED"
- >
-
-<!ELEMENT table
- (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
-<!ELEMENT caption %Inline;>
-<!ELEMENT thead (tr)+>
-<!ELEMENT tfoot (tr)+>
-<!ELEMENT tbody (tr)+>
-<!ELEMENT colgroup (col)*>
-<!ELEMENT col EMPTY>
-<!ELEMENT tr (th|td)+>
-<!ELEMENT th %Flow;>
-<!ELEMENT td %Flow;>
-
-<!ATTLIST table
- %attrs;
- summary %Text; #IMPLIED
- width %Length; #IMPLIED
- border %Pixels; #IMPLIED
- frame %TFrame; #IMPLIED
- rules %TRules; #IMPLIED
- cellspacing %Length; #IMPLIED
- cellpadding %Length; #IMPLIED
- >
-
-<!ATTLIST caption
- %attrs;
- >
-
-<!--
-colgroup groups a set of col elements. It allows you to group
-several semantically related columns together.
--->
-<!ATTLIST colgroup
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- col elements define the alignment properties for cells in
- one or more columns.
-
- The width attribute specifies the width of the columns, e.g.
-
- width=64 width in screen pixels
- width=0.5* relative width of 0.5
-
- The span attribute causes the attributes of one
- col element to apply to more than one column.
--->
-<!ATTLIST col
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- Use thead to duplicate headers when breaking table
- across page boundaries, or for static headers when
- tbody sections are rendered in scrolling panel.
-
- Use tfoot to duplicate footers when breaking table
- across page boundaries, or for static footers when
- tbody sections are rendered in scrolling panel.
-
- Use multiple tbody sections when rules are needed
- between groups of table rows.
--->
-<!ATTLIST thead
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tfoot
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tbody
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tr
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-
-<!-- Scope is simpler than headers attribute for common tables -->
-<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
-
-<!-- th is for headers, td for data and for cells acting as both -->
-
-<!ATTLIST th
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST td
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- >